All docs

Host LLM service

If the host backend used to call a large model directly, switch to: a chosen work agent in Cadau answers instead. Users need not sign in to Cadau or open the page widget.

Source docs/en/site/sdk-host-llm.md

If the host backend used to call a large model directly, switch to: a chosen work agent in Cadau answers instead. Users need not sign in to Cadau or open the page widget.

This phase: the whole host shares one Cadau workspace (see Host agent run and data scope §0.3).

Reference implementation: examples/hr-multi-tenant POST …/me/agent-run (Q&A) and POST …/positions/suggest-for-org (staffing suggestions).


1. How this differs from the page widget

Page assistant (embed widget)Host LLM service (this page)
Who starts itWidget in the browserHost backend
What the user seesBottom-right conversation overlayYou decide (approval summary, bot API, batch job… the user may never see Cadau)
Which agentThe one assigned to the signed-in userChosen on the server: everyday Q&A can use the same assignment; generate/analyze uses a task agent (§5.1), not the page assistant
Who is speakinghost_actor passed to the widgetSame host_actor in the request body
Where the conversation landsEmbed conversationThe same kind of embed conversation (isolated by signed-in user)

Both paths share agent knowledge, data-connection policy, and “who this is”. Do not run one permission model on the page and another on the server.

Do not expose this API to the browser; page conversation still goes through the widget. The integration-account password stays on the host server only.


2. Call chain (user view)

sequenceDiagram
  participant App as Host business (server)
  participant BFF as Host integration layer
  participant ML as Cadau
  participant Agent as Chosen work agent

  App->>BFF: Signed-in user needs one answer
  BFF->>BFF: Look up this user's assigned agent + assemble current-user identity
  BFF->>ML: Integration account signs in and enters the workspace
  BFF->>ML: Ask this agent to answer (message + current-user identity)
  ML->>Agent: Answer using knowledge, tools, and data policy
  Agent-->>ML: Reply
  ML-->>BFF: Reply + conversation id
  BFF-->>App: Return as your business API already does

The agent is assigned by the host admin. End users do not pick “which model”.


3. What to prepare on Cadau

Same as path B embed; you do not need a second account:

  • Workspace + template agent (knowledge already mounted)
  • Integration account already in that workspace (need not own the agent)
  • (If you query a business DB) workspace data connection and access policy already written

Details: Host agent run and data scope §1.


4. Integration: Cadau API

Call from the host server only. Auth is the access token after the integration account signs in (first login, then switch workspace as needed).

POST /api/v1/host/agent-runs
Authorization: Bearer <integration-account access token>
Content-Type: application/json
{
  "user_agent_id": "<agent UUID>",
  "app_id": "your-app-id",
  "workspace_id": "<workspace UUID; omit to use the token's current workspace>",
  "message": "What is my job level this month?",
  "session_id": "",
  "stream": false,
  "fresh": false,
  "host_actor": {
    "external_user_id": "host user id",
    "actor_kind": "employee",
    "display_name": "Chen Chen",
    "tenant_external_id": "host tenant id",
    "employee_id": "employee file id",
    "roles": ["employee"]
  }
}

4.1 Request fields

FieldRequiredMeaning
user_agent_idYesThe work agent that answers; must be in that workspace
messageYesUser question or task description
host_actorYesCurrent host signed-in user. When actor_kind is employee, employee_id is required
app_idNoDefault mindlink-embed; match embed registration so conversations can be grouped
workspace_idNoDefault: integration account’s current workspace; this phase same as MINDLINK_WORKSPACE_ID
session_idNoFor follow-up, pass the id from last time; empty defaults to this user’s latest under this agent, or creates one
freshNoWhen true and no session_id, always create a new conversation (fits one-shot jobs such as “generate jobs for a department”, so department A’s context does not continue into department B)
streamNoSee §4.3

4.2 Non-stream response (stream false or omitted)

{
  "session_id": "…",
  "request_id": "…",
  "reply": "full assistant text",
  "message_id": "…",
  "user_agent_id": "…",
  "workspace_id": "…",
  "app_id": "…",
  "host_actor": { }
}
FieldMeaning
replyFull answer for the business side to show or store
session_idPass on the next follow-up; the same signed-in user will not continue someone else’s
request_idTrace id for this turn

Common failures: unauthorized (not signed in), forbidden_embed_token (used an embed token by mistake), validation_error (missing message / agent / invalid identity), workspace_required, not_found (agent not in that workspace), host_agent_run_failed (answer failed).

4.3 About stream: true

The API accepts the field, but it is not token-by-token like the page widget: the server still finishes the run, then emits SSE session, delta (the whole reply), done in order.

The HR example integration layer always takes the full reply non-streaming. For real streaming, use the page widget conversation channel.


5. How the host should wrap this

Do not let every business module take the integration account and call Cadau itself. Wrap it as “one Q&A for the current signed-in user”:

  1. Check host sign-in and permissions
  2. Look up this user’s assigned agent (if none, fail clearly; do not silently pick another)
  3. Assemble the same current-user identity as embed-session
  4. After the integration account enters the workspace, call the API above
  5. Return reply / session_id to the business

HR example:

  • Everyday Q&A: POST /api/v1/tenants/{tenant}/me/agent-run (uses this user’s assigned conversation assistant)
  • Task-style generate: POST /api/v1/tenants/{tenant}/positions/suggest-for-org (calls the chosen generate/analyze agent)
  • How to choose: MINDLINK_GENERATE_USER_AGENT_ID in server .env, or host “User management → Embed assistant registry”
  • Client: mint/run helpers in examples/hr-multi-tenant/server/internal/mindlinkclient/
  • Acceptance: npm run smoke:host-agent in examples/hr-multi-tenant/web (Q&A path); job suggestions accepted by hand on the Jobs and levels page

5.1 Conversation assistant vs generate/analyze agent

The page widget uses a conversation assistant (admin / manager / employee self-service): people chat, live support can be on. Generate, analyze, fill forms are called by the host backend on another chosen agent (may differ from the conversation assistant, or reuse an existing one).

Create and configure it in Cadau first (knowledge, data connection, and similar), then point at it on the host. Do not have a script silently create one. There are only these two places to point; all analyze calls go here:

  1. Server .env: MINDLINK_GENERATE_USER_AGENT_ID=<Cadau agent UUID> (deploy default)
  2. Host settings: “User management → Embed assistant registry → Generate and analyze agent” (after save, overrides the env var)

Do not confuse with HRMS_SEED_MINDLINK_USER_AGENT_ID: that only backfills register/assign for the demo account when the HR example starts. It is not the generate/analyze agent.

Conversation assistantGenerate / analyze
Who uses itSigned-in user asks on the pageA host button / batch job
How it is chosenAssigned per user.env or host settings: one
App idWidget MINDLINK_APP_IDDefault mindlink-embed-hr-generate (conversations stay separate from chat; HR example can override with MINDLINK_GENERATE_APP_ID, need not put it in .env)
ConversationFollow-up allowed by defaultEach job passes fresh: true
Write to DBAssistant only answersHost previews first; a person confirms before writing business tables

HR example: pick a department → suggest which jobs that department should have (Jobs and levels page). Results are shown only; they are not written to the job catalog automatically.


6. Conversations and isolation

  • Conversations are stored in Cadau, owned by the integration account, tagged with the current host user id.
  • Under the same agent, user A’s and user B’s answer history do not continue into each other.
  • Follow-up: pass last session_id back; if the conversation already belongs to another user, the API rejects.
  • Without session_id: default is this user’s latest under “same workspace + same agent + same app id”; if none, create one.
  • One-shot generate jobs: pass fresh: true (and do not send session_id); create new each time so the previous department’s suggestions do not pollute this run.

Page-widget conversations and answer-on-behalf conversations are isolated by the same user id, but they are not forced onto one timeline. If you want “continue on the page what the server just asked”, agree whether to share session_id (usually keep the two entries separate).


7. What the agent actually does

Answering uses that agent’s knowledge, skills, and data connections — the same as asking the same assistant on the page:

  • The system includes “which host user this is” (name, roles, employee file, and similar), so it does not ask the user for an employee number to “confirm identity”
  • Business-DB queries must go through the data connection; rows/columns are forced by access policy; the model cannot drop them
  • Employee self-service can only help look up self (policy + identity hint together)

How to write policy: Host agent run and data scope §3.


8. Integration checklist

  • [ ] Integration account can sign in and enter the agent’s workspace
  • [ ] The chosen agent ID is in that workspace
  • [ ] Request carries full current-user identity; employee self-service includes employee file id
  • [ ] Users with no assigned assistant: host API fails clearly, instead of picking a random agent
  • [ ] Two signed-in users answering in sequence get different session_ids and content does not leak
  • [ ] The same user on a second call with session_id (or without, using auto-continue) can continue
  • [ ] Task-style calls use a separate agent + separate app_id + fresh: true; preview before writing to the DB
  • [ ] (Optional) npm run smoke:host-agent passes
  • [ ] Integration password is not in the frontend or a public repo

9. FAQ

SymptomCheck
Forbidden / agent not foundIntegration account not in the workspace; agent ID and workspace mismatch; did not switch
Provide a valid host user identityMissing host_actor or external_user_id; employee missing employee_id
Employee user must bind an employee fileSelf-service account is not yet bound to a person file in this tenant
Calling the assistant failed / model not configuredCadau-side model is not ready
Answered rows or columns they should not seeData-connection access policy not written or not narrowed by current-user identity
Browser calling this API directlyDon’t; the page uses the widget, answering on behalf is host-server only

10. Maintenance

ItemValue
Doc typeHost-backend LLM answer-on-behalf integration notes
Cadau APIPOST /api/v1/host/agent-runs
Reference exampleexamples/hr-multi-tenantPOST …/me/agent-run; generate/analyze POST …/positions/suggest-for-org (agent chosen by .env / host settings)
RelatedHost agent run and data scope, HR embed example, Embed contract V1.5.12