Host embed
Directory: sdk/host-embed
Source docs/en/site/sdk-host-embed.md
Directory: sdk/host-embed Who this is for: third parties who put a Cadau embed assistant into their own business system. This folder is a complete handover pack.
Handover: this directory (
sdk/host-embed/) is the main doc pack for third-party integration (overview, contract, website integration, knowledge writing, HR walkthrough, legacy-host enhancement). Give this folder to the integrating team and they can start. Runnable full-stack examples and some mechanism source-of-truth still live elsewhere in the repo (see the links below); those links break if you copy only this folder.Audience: teams embedding a Cadau conversation assistant in their own system (ERP, OA, industry SaaS, and similar) — business admins, backend and frontend developers, and ops.
After this page you can: mount the assistant on a host page, assign different agents per signed-in user, let the assistant guide people to open business pages from the reply, and confirm that signed-in users cannot see each other's conversation history, live support, or tickets.
Technical contract (fields, SSE, error codes):
Embed contract(V1.5.12). Copy-paste frontend notes:Website integration. Path A static example:examples/cadau-embed-site/. Path B full-stack example:examples/hr-multi-tenant/andHR embed example.Sibling SDKs: appsdk · platform-plugin · agent-capability · this directory. Overview:
sdk/README.md.Note: the script the browser loads is still
/embed/mindlink-widget.min.json the site (HTTP route; independent of this doc folder name).
Documents in this directory
| Document | What it is |
|---|---|
| README.md (this page) | Third-party integration overview and rollout path |
Embed contract | TypeScript types, SSE, error codes, delivered-capability table |
Website integration | Host-page init, env vars, in-reply navigation (hand to frontend) |
Host knowledge writing | How to write agent knowledge and navigation links |
HR embed example | HR multi-tenant example: APIs, tables, config |
Host LLM service | Host backend asks a chosen agent to answer (instead of calling a model directly) |
Host agent run and data scope | Legacy-host user model, workspace split, data-connection row/column policy |
| Generate predefined queries from host code | Generate query JSON from host lists/modules and import into Cadau (in-repo; not part of this folder handover) |
1. What you get
On your business pages:
- A conversation assistant in the bottom-right corner (or inline), talking to a Cadau My agent you already configured;
- Conversation goes through the Cadau server, so you can gate access, audit, and revoke;
- The assistant can put clickable navigation links in replies; one click opens the matching page in your system with filters (for example “pending orders” or “this employee’s file”);
- When the user says “open such-and-such page for me”, the widget can run the first registered navigation automatically after the reply finishes (you can turn this off; see §8.3).
- (Optional) The host backend can also ask a chosen agent to answer (approval summaries, suggest jobs by department, and similar — the user need not see the widget). See
Host LLM service.
Cadau does not own: your sign-in users, business permissions, or business database. Who the user is and which menus they see is still the host system’s job.
2. Who does what
flowchart LR
subgraph ML["Cadau (agent provider)"]
UA["Configure agents and knowledge"]
ET["Issue embed access tokens"]
CHAT["Conversation and retrieval"]
end
subgraph Host["Third-party host (your system)"]
ADM["Register agents, assign users"]
BFF["Backend mints tokens"]
UI["Business page + conversation widget"]
end
ADM --> BFF
BFF -->|"integration account"| ET
UI -->|"short-lived token"| CHAT
UA --> CHAT| Role | Owns | Does not own |
|---|---|---|
| Cadau admin | Create agents, mount knowledge documents, agree on an app id, provide public URLs, (production) prepare a dedicated integration account | Host business users, host menu permissions |
| Host admin | In the host admin UI, register the agent IDs to connect, and assign assistants and operation scopes by signed-in user | Click “generate token” in Cadau for every end user |
| Host developer | Embed-session API, mount the widget, navigation whitelist, network proxy | Put Cadau passwords or long-lived tokens in the browser |
| End user | Talk to the assistant on the business page | Sign in to the Cadau main site (not needed for embed) |
3. Which of the two paths to use
| A: public site support | B: host business system | |
|---|---|---|
| Typical case | Official site / landing-page support assistant | Assistant inside ERP, OA, or industry SaaS |
| Host config | Cadau site URL, agent ID, website-embed token | Register/assign + backend mint + must pass the signed-in user (host_actor) |
| Host backend needed? | No | Yes (at least an embed-session style API) |
| Different agent per person | Usually one config for the whole site | Yes (assign by signed-in user) |
| Click “generate token” in Cadau? | Yes (token can be short- or long-lived; can be revoked) | Production: backend mints; UI generate is mostly for local testing |
| Live support | Widget “Live support” (must be on and someone on duty) and “Submit a ticket” | Same widget; do not build your own support desk. Cadau uses seats in this workspace or a support team — see HR embed example §10.4 |
| Who can see conversations / live support / tickets | Website visitors in the same browser (not signed in) | The current signed-in user (must pass host_actor); A cannot see B’s |
| Cadau workspace | Decided by the embed token (usually one agent for the site) | This phase: the whole host shares one workspace. One workspace per tenant is Host agent run and data scope §0.3 — not built yet |
Recommendation:
- Any website, no business sign-in → use A; static walkthrough:
examples/cadau-embed-site/. - Real business system, assign by user, tokens not in the frontend repo → use B (HR example:
HR embed example).
Minting (B): the host backend uses a Cadau integration account to call
POST /api/v1/user-agents/{agentId}/embed-token, then hands the short-lived embed token to the browser. End users do not sign in to the Cadau main site.
4. Cadau-side prep (agent owner)
Before you change the host, finish this table in Cadau (align with the host side first if needed):
| Step | Action | Output |
|---|---|---|
| 1 | Sign in to Cadau, enter the target workspace | Workspace ID |
| 2 | My agents → create or pick an assistant, mount knowledge documents (business notes, list of pages that can be opened) | Agent ID (UUID) |
| 3 | Agree with the host on app id app_id (for example your-corp-hr, mindlink-embed) | Globally unique string; distinguishes integrators |
| 4 | (Path B) Prepare a dedicated Cadau integration account (email or phone + password) | Store on the server only |
| 5 | Add the integration account to the agent’s workspace (it need not own the agent) | Can switch into that workspace before minting |
| 6 | Confirm public URLs: widget script, API prefix | See the table below |
| Item | Typical path |
|---|---|
| Widget script | https://<your Cadau host>/embed/mindlink-widget.min.js |
| API prefix | https://<your Cadau host>/api/v1 |
Path B does not need you to click “generate token” in Cadau for every host user. The host backend mints with the same API as the UI button.
(Path A required) On that assistant, Manage → Website embed generate a token. The page only needs site URL + agent ID + token (no workspace ID). For widget “Live support” and “Submit a ticket”, turn them on under the same agent’s Live support, and assign seats in this workspace or authorize a support team (when nobody is on duty, only submit-ticket remains). Full copy can be taken from Copy website integration notes on that page.
5. Host side: what admins do
In your admin UI (or ops scripts):
5.1 Register agents to connect
Create one registration row per Cadau agent you will connect. Store the agent ID only, not the embed token:
| Field | What it is |
|---|---|
| Display name | Name admins and users see |
| Cadau agent ID | UUID from §4 step 2 |
| App id | Same as Cadau and the mint request; may default from global config |
| Workspace ID | This phase: same Cadau workspace as MINDLINK_WORKSPACE_ID (the whole host shares one). One workspace per tenant: Host agent run and data scope §0.3 — not built yet |
(Optional) generate/analyze agent: when the host backend runs jobs such as “suggest jobs”, point at another agent already configured in Cadau — MINDLINK_GENERATE_USER_AGENT_ID in .env, or pick it on the “embed assistant registry” admin page (overrides the env var). This is not the bottom-right conversation assistant. See Host LLM service §5.1.
5.2 Assign by signed-in user
- The assignment subject is the host signed-in user (the account behind a phone / employee number), not the employee file id (unless they are the same).
- For each user choose: which registration row, and which operation scopes (query only, whether create/edit/delete is allowed — host-defined enums).
- Users with no assignment: the business page does not show the assistant, or the embed-session API returns “no assistant yet”.
HR multi-tenant example: sidebar User management → Connected agents / Configure agent; details in HR embed example §8.
6. Host side: developer checklist
6.1 Data layer (path B)
At least two tables (names are yours):
- Registered agents (§5.1 fields)
- User–agent assignments (tenant + user → registration row + permission scopes)
6.2 Embed-session API (path B core)
Provide an API like this (path is yours; keep the meaning):
GET /api/v1/.../me/embed-session
Authorization: Bearer <host sign-in token>
Server logic:
- Confirm the host user is signed in;
- Look up whether they have a valid assignment;
- No assignment → return
200, body withavailable: falseand a reason (do not use 404, which browsers treat as a hard error); - Has assignment → sign in to Cadau with the integration account → switch workspace → call
POST /api/v1/user-agents/{agentId}/embed-token body example: { "app_id": "your-app", "ttl_seconds": 3600 };
- Return these fields to the frontend (names may match the example):
| Response field | Use |
|---|---|
access_token | Widget auth.token |
expires_at | Widget auth.expires_at (ISO 8601) |
user_agent_id | Agent ID |
workspace_id | Workspace ID |
app_id | App id |
host_actor | Current signed-in user → init.host_actor (path B isolates history / live support / tickets by this person; host data queries use it too) |
widget_script | Script URL the browser loads |
api_base_url | API prefix the browser uses to call Cadau (prefer same origin as the page; see §6.4) |
Integration-account password and Cadau internal URL live only in server env vars. Do not commit them to the frontend repo.
Cadau mint order (server calls, not the browser):
POST /api/v1/auth/login
POST /api/v1/workspaces/{workspaceId}/switch
POST /api/v1/user-agents/{userAgentId}/embed-token
6.3 Mount the widget on the frontend
- The user opens a business page that should have the assistant;
- (B) Request embed-session with the host sign-in token; or (A) read static config;
- Load
widget_scriptdynamically; - Initialize:
<script src="https://<Cadau host>/embed/mindlink-widget.min.js"></script>
<script>
const widget = window.MindLinkWidget.init({
app_id: "your-app-id",
api_base_url: "https://<public API prefix>/api/v1",
user_agent_id: "<agent UUID>",
workspace_id: "<workspace UUID>",
auth: {
token: "<embed access_token>",
expires_at: "<ISO 8601>"
},
// Path B required: same host_actor as embed-session (isolates history / support / tickets; also host data queries)
// The widget sends X-Host-External-User-Id automatically; the host page does not set that header
host_actor: { external_user_id: "…", actor_kind: "employee" },
theme: "auto",
position: "bottom-right",
locale: "zh-CN",
entry: {
auto_open: false,
auto_execute_navigation: true
// hide_launcher: true skips the corner button; a host button calls widget.open()
}
});
widget.on("action", function (ev) {
if (ev.type !== "action") return;
handleHostNavigation(ev.action);
});
</script>
- Before the token expires: mint again on the backend, then
widget.updateAuth({ token, expires_at }). When the signed-in user changes,widget.updateHostActor(hostActor)(orinitagain).
Inline embed: position: "inline" + container: "#your-container-selector". Web Component: see Website integration §4.1.
Reference code (in the Cadau repo; not part of this folder handover):
- HR example mount:
examples/hr-multi-tenant/web/src/mindlinkOrgEmbed.ts - HR example navigation:
examples/hr-multi-tenant/web/src/mindlinkHostActions.ts
6.4 Network and security
| Requirement | Notes |
|---|---|
| Browser access to Cadau | Production: prefer a same-origin reverse proxy (for example https://your-host/mindlink-api/v1), or configure CORS |
| Do not mix hostnames | In development, do not mix localhost and 127.0.0.1; that often breaks CORS |
| Tokens not in the repo | Production: never commit long-lived tokens in .env to Git; path A only in dev |
| Revoke access | That assistant Manage → Website embed can revoke a registration; after revoke the API returns embed_token_revoked |
Server env example (path B):
MINDLINK_API_BASE=https://mindlink.internal/api/v1
MINDLINK_API_BASE_PUBLIC=https://your-host.com/mindlink-api/v1
MINDLINK_WIDGET_SCRIPT=https://mindlink.internal/embed/mindlink-widget.min.js
MINDLINK_INTEGRATION_EMAIL=integration@your-corp.com
MINDLINK_INTEGRATION_PHONE=
MINDLINK_INTEGRATION_PASSWORD=<server only>
MINDLINK_APP_ID=your-corp-app
MINDLINK_WORKSPACE_ID=<workspace UUID shared by the whole host>
MINDLINK_GENERATE_USER_AGENT_ID=<optional: generate/analyze agent UUID>
Embed token TTL and whether the widget is inline have code defaults; they need not go in .env. The integration account can sign in to Cadau with email or phone (same as the HR example server/.env).
7. In-reply navigation: let the assistant open business pages
7.1 How it works
- In the agent knowledge documents, agree: when a jump is needed, use a Markdown link with protocol
mindlink://action/; - The user clicks the link (or the widget fires it when auto-navigation is on) → the host page receives an
actionevent; - The host page whitelists the action name and params, then routes or opens a drawer.
7.2 Link syntax (put this in knowledge documents)
`Open pending orders`
`View org chart`
- Action name: a business action you register on the host page; prefer
page.<module>; - Query params: passed through to the host page (
status,id,label, and similar);labelmay be display-only.
7.3 Host-page whitelist (required)
const HOST_ACTIONS = {
"page.orders": (params) => {
app.navigate("/orders", { status: params.status || "" });
},
"page.org": (params) => {
app.navigate("/org", { tab: params.tab || "tree" });
},
};
function executeHostAction(action, params) {
const fn = HOST_ACTIONS[action];
if (!fn) {
app.toast("This navigation is not supported yet");
return;
}
fn(params);
}
Do not run unsafe protocols such as javascript:. Unknown actions should say “not supported yet”.
7.4 Auto-navigation
entry.auto_execute_navigation defaults to true: when the user clearly says “open / jump to…”, after the streamed reply ends the widget automatically runs the first host-executable mindlink://action/ link in the body (same filter as clicks). To require a manual click, set it to false.
Knowledge documents must say: when the user asks to open a page, put 1–3 registered links at the end of the reply, and the first host-executable link must be the most relevant target.
Writing spec: Host knowledge writing.
8. Recommended rollout order
| Phase | Goal | Focus |
|---|---|---|
| 1. Prove the widget (1–2 days) | Any page can converse | Path A or HR example smoke:embed; confirm script and API are reachable |
| 2. BFF + assignment | Different assistants per user | Tables, embed-session, admin UI, frontend fetches session then inits |
| 3. Legacy-host enhancement (optional) | Backend asks an agent to answer; row/column isolation on the business DB | See Host LLM service, Host agent run and data scope |
| 4. Production | Operable and auditable | Dedicated integration account, short TTL, HTTPS, knowledge documents, §10 acceptance |
8.1 Automated smoke (HR example)
A smoke test is a scripted minimum integration check in real API order: no browser, fail fast on any step. Use it after config changes or a release to confirm “we can even start testing”.
In examples/hr-multi-tenant/web (Cadau :8080 and HR backend :18089 already running, server/.env has MINDLINK_*):
| Command | What it checks |
|---|---|
npm run smoke:embed | Embed path: Cadau widget script → HR sign-in → embed-session → use the embed token against Cadau conversation/chat |
npm run smoke:host-agent | Legacy-host enhancement: compile mindlink-access-policy, embed-session has the right host_actor (admin/manager/employee), agent-run conversation isolation |
Not a substitute for full acceptance: SQLite data connections, writing access policy, and UI still need a manual pass (HR example: examples/hr-multi-tenant/docs/ACCEPTANCE_HOST_LEGACY.md in the repo).
8.2 Local HR example
# See examples/hr-multi-tenant/README.md
cd examples/hr-multi-tenant/web
npm run setup:mindlink # registers the integration account and writes ../server/.env
cd ../server && go run ./cmd/hrms-server # separate terminal
cd ../web && npm run dev
# Browser http://localhost:5180 ; demo login 13800138000 / Demo-HR-2026
npm run smoke:embed # optional: embed smoke
npm run smoke:host-agent # optional: legacy-host enhancement smoke
Register an existing Cadau agent into the HR example:
cd examples/hr-multi-tenant/web
npm run link:mindlink-agent -- <MindLink agent UUID>
Note:
link:mindlink-agentreads/writes local SQLitebackend/mindlink.dbby default. If Cadau’s main DB is Postgres (common in local development), invite the integration account into the workspace in the Cadau UI, and checkmindlink_workspace_idon the registration row; or re-runsetup:mindlink.
9. Observability: how the agent owner sees embed conversations
Embed conversations are stored under the Cadau identity used to mint, and do not appear in that identity’s personal Messages list.
The agent owner on the Cadau main site:
- My agents → Run history;
- Pick the assistant on the left;
- Source: Embed (filter by app id);
- Open a conversation read-only.
From the agent Manage → Overview you can click View run history to jump to that assistant’s embed records.
10. Integration and acceptance checklist
Cadau
- [ ] Agent created, knowledge documents mounted (including the list of pages that can be opened)
- [ ]
app_idmatches the host - [ ] B: integration account can sign in, is in the agent’s workspace, and can mint
- [ ] Workspace ID on the registration row matches the agent’s real workspace (this phase: the whole host shares one Cadau workspace)
- [ ] (Optional) that agent has Live support on (seats in this workspace or an authorized support team); support covering this workspace is on duty; the widget shows “Live support / Submit a ticket”
Host backend
- [ ] Register and assign APIs work
- [ ] Assigned users: embed-session returns
available: trueandaccess_token - [ ] Unassigned users:
available: false(HTTP 200) - [ ] Integration password is not in the frontend or a public repo
Host frontend
- [ ] After sign-in the assistant appears and can stream a conversation
- [ ] When different users are assigned different agents, conversation identity is correct (B)
- [ ] (B)
initreceivedhost_actor; two signed-in users cannot see each other’s history, live support, or tickets - [ ] (A) two website visitors cannot see each other’s history, live support, or tickets (a new browser or cleared site data is a new visitor)
- [ ] Two visitors can ask at the same time and each get a reply; when overloaded the widget says “Too many people talking right now. Try again in a moment.”
- [ ] Before the token expires,
updateAuthor re-entering the page can mint again - [ ] (Optional) navigation links in replies jump correctly; auto-navigation matches expectations
- [ ] Unknown navigation has a friendly message
Legacy-host enhancement (if you connect Host Agent Run / business-DB queries)
- [ ] Host BFF sends a complete
host_actoron embed-session / agent-run - [ ] Workspace data connection is configured and
access_policy_jsonis written - [ ] Employee self-service sees only their own rows; manager/admin scope matches expectations; conversations do not leak across users
- [ ] (Optional)
npm run smoke:host-agentpasses
Security and ops
- [ ] Production is mainly B; A is dev-only
- [ ] Cadau API is same-origin proxied or CORS is compliant
- [ ] Integration-account rotation and token revoke are documented
- [ ] Production uses a self-created integration account, not the HR example demo email
11. FAQ
| Symptom | Check |
|---|---|
| Widget does not appear | No assignment, embed-session 503, network/CORS, api_base_url not same origin as the page |
| Embed-session 502 | Integration account not in the workspace; wrong agent ID; app_id mismatch; wrong workspace ID |
| Assistant opens but conversation fails | user_agent_id / app_id / workspace differ from mint time; token expired |
embed_token_revoked | Cadau revoked the registration; mint again |
unauthorized | Token invalid or expired; call updateAuth or fetch embed-session again |
| A/B behavior differs | Align on the same agent ID and knowledge documents |
| After switching accounts you still see the previous user’s history / support / tickets | Path B must pass the current signed-in user into init.host_actor; after switch, updateHostActor or init again. Unsigned website visitors in the same browser are isolated by browser, not by account |
| Embed conversations are missing from Cadau Messages | Expected; the owner looks under Run history → Embed |
| Do I click “generate token” in Cadau for every agent? | No (path B); register the ID, mint at runtime |
| Does the host backend still need its own model connection? | No. Ask a chosen agent to answer; see Host LLM service |
12. Document index (this directory)
| Resource | What it is |
|---|---|
Website integration | Host-page init, env vars, navigation examples (hand to frontend) |
Embed contract | TypeScript types, SSE, error codes, delivered-capability table |
Host knowledge writing | Knowledge documents and in-reply navigation (including mindlink://action/) |
HR embed example | HR example APIs, tables, config |
Host LLM service | Host backend asks a chosen agent to answer |
Host agent run and data scope | Legacy-host user model, new-host checklist, data-connection policy |
| Generate predefined queries from host code | Generate query JSON from host code and import (in-repo) |
| Cadau UI | That assistant Manage → Website embed (generate notes, token register and revoke) |
13. Maintenance
| Item | Value |
|---|---|
| Doc type | Third-party host integration overview |
| Aligned contract | SDK契约.md V1.5.12 |
| Reference example | examples/hr-multi-tenant (in-repo; not part of this folder handover) |
| Updated | 2026-08-17 (docs aligned with implementation: contract version, relative paths, concurrent-reply-limit semantics, next-step chips) |