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/sessions adapter;
  • official POST /api/v1/agent-chat/:session_id adapter;
  • fail-closed SSE parsing for references, answer, error, and terminal done;
  • 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/qa ingress endpoint.
  • unauthenticated read-only GET /version runtime 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 shared policy).
  • Replies are sent via the callback's sessionWebhook, which is fail-closed: only https URLs 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_ID enables 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_ID
  • DINGTALK_QUESTION_TABLE_SHEET_ID
  • DINGTALK_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_ID
  • DINGTALK_FAQ_TABLE_SHEET_ID
  • DINGTALK_FAQ_TABLE_VIEW_ID
  • DINGTALK_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

  1. Create an independent PostgreSQL database named dobotai.
  2. Apply db/migrations/000001_core.up.sql to that database only.
  3. Copy .env.example to a local .env and supply secrets outside Git.
  4. 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.

S
Description
No description provided
Readme 1.5 MiB
Languages
Go 96.3%
Shell 2%
Python 1.6%