DobotAI Platform
DobotAI is the external enterprise integration layer for official WeKnora. It does not import WeKnora packages, modify WeKnora source, or access the WeKnora database.
Current milestone: channel-bound Agent QA core.
Implemented:
- official
POST /api/v1/sessionsadapter; - official
POST /api/v1/agent-chat/:session_idadapter; - fail-closed SSE parsing for
references,answer,error, and terminaldone; - per-channel/per-conversation Agent binding;
- long-lived direct-user sessions;
- shared-group sessions, with optional group+user policy;
- external-message idempotency;
- independent PostgreSQL session/turn storage;
- authenticated internal
POST /v1/qaingress endpoint. - unauthenticated read-only
GET /versionruntime build identity endpoint. - DingTalk Stream text ingress (official SDK) wired into
cmd/dobotai. - v1 knowledge coverage decisions, durable support cases, and optional DingTalk support-group notifications.
DingTalk channel (Stream, text only)
- Uses the official DingTalk Stream SDK (
dingtalk-stream-sdk-go); no public webhook endpoint is exposed. - Text messages only for now. Images, OpenAPI fallback, and card replies are not implemented yet.
- Group chats are handled only when the bot is @-mentioned; other group messages are ignored.
- Sessions: direct chats use one long-lived session per user; group chats share one session per group (default
sharedpolicy). - Replies are sent via the callback's
sessionWebhook, which is fail-closed: onlyhttpsURLs on*.dingtalk.com(port 443, no redirects) are accepted. - Required env vars to enable (all three or none):
DINGTALK_CLIENT_ID,DINGTALK_CLIENT_SECRET,DOBOTAI_TENANT_KEY. Partial configuration is a fatal startup error. - Optional
DINGTALK_SUPPORT_GROUP_OPEN_CONVERSATION_IDenables durable uncovered-answer ActionCard notifications through the official group-message API. It requires the FAQ table workflow below so every “去回答” button targets an exact record. When empty, coverage decisions and support cases are still recorded but no group message is sent.
DingTalk question table sync (Notable v1)
Successful DingTalk QA turns can be appended asynchronously to a DingTalk Notable AI table through a durable PostgreSQL outbox. Notable failures never change the successful QA result; the worker retries with bounded backoff and stores only stable failure codes.
Apply db/migrations/000010_question_table_exports.up.sql before enabling the worker. The three table settings are optional as a group: all blank disables dispatch, while a partial configuration fails startup closed.
DINGTALK_QUESTION_TABLE_BASE_IDDINGTALK_QUESTION_TABLE_SHEET_IDDINGTALK_QUESTION_TABLE_OPERATOR_ID(DingTalk unionId)
The worker reuses DINGTALK_CLIENT_ID and DINGTALK_CLIENT_SECRET. The DingTalk application must have Notable.Base.Read.All and Notable.Base.Write.All. Only successful channel=dingtalk turns are enqueued; other channels are excluded. The first release writes the nine basic text/date/user fields and omits the five select-classification fields.
Uncovered-question FAQ workflow
Apply db/migrations/000011_faq_exports.up.sql before enabling this workflow. Existing support cases are marked not_applicable and are not backfilled; only support cases created after the migration default to pending FAQ export.
Set all four values together, or leave all four blank to disable FAQ export. Partial configuration fails startup closed:
DINGTALK_FAQ_TABLE_BASE_IDDINGTALK_FAQ_TABLE_SHEET_IDDINGTALK_FAQ_TABLE_VIEW_IDDINGTALK_FAQ_TABLE_OPERATOR_ID(DingTalk unionId)
For every newly detected uncovered answer, the asynchronous worker creates one FAQ record with standard question, original question, detected language, and asker. After DingTalk returns the recordId, DobotAI stores it and sends a built-in sampleActionCard containing only the current question and up to five earlier questions from the same stable actor. The “去回答” button opens that exact FAQ record. FAQ insert failures are retried with bounded backoff and never block the customer reply.
WeKnora baseline
Target policy: latest stable official Release/Tag. The newest locally fetched stable tag is v0.6.3. Online GitHub verification is pending because DNS/proxy access was unavailable during initialization.
Run
- Create an independent PostgreSQL database named
dobotai. - Apply
db/migrations/000001_core.up.sqlto that database only. - Copy
.env.exampleto a local.envand supply secrets outside Git. - Export the variables and run:
go run ./cmd/dobotai
Health check:
curl http://127.0.0.1:8090/healthz
Runtime version check:
curl http://127.0.0.1:8090/version
scripts/deploy-local.sh builds from its own worktree (or the explicit
DOBOTAI_SOURCE_ROOT), injects version, commit_sha, and build_time, and
accepts the deployment only when /version reports the exact source commit.
It refuses dirty worktrees so the reported SHA cannot hide uncommitted source.
Internal QA request:
curl -X POST http://127.0.0.1:8090/v1/qa \
-H "Authorization: Bearer $DOBOTAI_INGRESS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"tenant_key":"default",
"channel":"dingtalk",
"conversation_type":"direct",
"external_user_id":"user-1",
"external_message_id":"message-1",
"query":"hello"
}'
Hard boundaries
- No WeKnora source modifications.
- No custom WeKnora tables or columns.
- No direct WeKnora database access.
- No private WeKnora package imports.
- All compatibility logic stays in
internal/weknora. - Business data stays in DobotAI PostgreSQL.
- Redis will be used only for queues, retries, idempotency leases, and temporary state.
See docs/architecture.md for ownership and migration decisions.