Host agent run and data scope
For legacy / existing business systems (host enhancement; see product spec §4.2.4). Runnable example and API walkthrough: examples/hr-multi-tenant/docs/HOST_LEGACY_INTEGRATION.md i
Source docs/en/site/sdk-host-agent-run.md
For legacy / existing business systems (host enhancement; see product spec §4.2.4). Runnable example and API walkthrough: examples/hr-multi-tenant/docs/HOST_LEGACY_INTEGRATION.md in the repo.
0. Legacy-host user model (three kinds of account)
A common question when connecting a legacy host: “Do we create a Cadau account for every business user?” — No. Keep three identities distinct:
| Identity | Where it lives | How many | Use |
|---|---|---|---|
| Cadau integration account | Cadau | One set per legacy-host deploy (or one per customer, per ops policy) | Host backend mints embed-token, calls Host Agent Run; password only in MINDLINK_* env vars |
| Legacy-host signed-in user | Host business DB | Real headcount | Admin, manager, employee self-service, and similar; they sign in on the host page and do not register on the Cadau main site |
| Cadau end user | — | Not needed | Conversation and query identity is the host_actor on each request |
Mapping (user view):
| Legacy-host concept | Cadau (currently delivered) |
|---|---|
| One host system (may contain several business tenants) | One workspace |
| Assistants used by role | A few template agents (for example admin assistant, manager assistant, employee self-service) |
| Each conversation / server-side run | Carries host_actor (legacy-host user identity); history, live support, tickets, and data queries are isolated by this person |
Do not clone a Cadau agent per signed-in user. Person-to-person isolation is host_actor (history / live support / tickets) plus row/column policy on the workspace data connection (queries can also narrow by tenant key). “One Cadau workspace per host tenant” is §0.3 — not built in this phase.
0.1 Two kinds of legacy-host signed-in user
| Type | actor_kind | Typical scene | host_actor essentials |
|---|---|---|---|
| Business user | business | Admin, HR, manager running org / other people | roles; a manager may include managed departments and subordinate employee ids |
| Employee user | employee | Look up self only | Must include employee_id (bound to this tenant’s employee file) |
host_actor fields (aligned with backend/internal/datasource/host_actor.go):
| Field | Required | Meaning |
|---|---|---|
external_user_id | Yes | Host signed-in user id; without it identity is invalid |
actor_kind | No (can be inferred) | business or employee. If omitted: employee when employee_id is present, otherwise business |
employee_id | Required when employee | Employee file id in this tenant |
display_name | No | Display name |
tenant_external_id | No | Host tenant id (often used in query policy) |
emp_no | No | Employee number |
roles | No | For example tenant_admin, manager, employee |
managed_org_unit_ids | No | Managed department id list |
managed_employee_ids | No | Subordinate employee id list |
org_unit_id / org_unit_name | No | Own department |
Data-connection policy placeholders: {{host_actor.external_user_id}}, {{host_actor.actor_kind}}, {{host_actor.display_name}}, {{host_actor.tenant_external_id}}, {{host_actor.employee_id}}, {{host_actor.emp_no}}, {{host_actor.org_unit_id}}, {{host_actor.org_unit_name}}, {{host_actor.managed_org_unit_ids}}, {{host_actor.managed_employee_ids}} (the last two are comma-joined).
Silent provisioning: when the legacy host creates a business user or turns on employee self-service, write “user → template agent” assignment by role. If there is still no assignment the first time the assistant opens, the host BFF can backfill a default by role (HR example EnsureDefaultAgentAssignment).
0.2 Where the integration account comes from
| Scene | What to do |
|---|---|
| Local testing (HR example) | In the web directory, npm run setup:mindlink: the script calls Cadau POST /auth/register for hr-embed-demo@mindlink.local (or signs in if it exists), probes workspace and agent IDs, writes MINDLINK_* into server/.env |
| Production / new legacy host | Create a dedicated integration account by hand in Cadau (email or phone + strong password), invite it into the matching workspace; do not use the example demo email |
The integration account and a legacy-host demo signed-in user (for example HR example 13800138000) are not the same person: the former only mints on the server; the latter is the business user who signs in on the page.
0.3 Path B workspaces: two ways (this phase only does the first)
Path B can split by how Cadau workspaces are drawn:
| Way 1: host shares one workspace (this phase) | Way 2: one workspace per tenant (later, if needed) | |
|---|---|---|
| How to configure | The whole host system (including several business tenants) maps to one Cadau workspace; registration and MINDLINK_WORKSPACE_ID point at the same workspace | Each isolated host tenant maps to one Cadau workspace; the registration table stores different workspace IDs per tenant |
| Person to person | host_actor: history / live support / tickets isolated by signed-in user | Same as left |
| Tenant to tenant | Queries can narrow by tenant key in data-connection policy; support desk, seats, knowledge, standards/assets are still one copy per workspace. If one Cadau support group should serve several customer workspaces, use a support team (authorize support rights only; members need not join each customer workspace) — do not split workspaces the way 2 does | Support queues and knowledge split naturally by workspace; you can still use a support team to take work across workspaces without adding members to every customer workspace |
| This phase | Only this way (the HR example is this) | Auto-create workspace on tenant open, copy assistants per tenant, and similar are not built; the notes below are explanation only |
Way 2 (reserved; not this phase’s checklist)
If you do it later: each time you open a host tenant, create a Cadau workspace → invite the same (or per-customer) integration account → in that workspace create/copy assistants, knowledge, seats, data connections → host registration table stores that workspace ID. Mint switches to the workspace on the registration row, instead of every tenant falling back to one env var. Conversations and tickets in the old workspace do not migrate automatically.
Until you actually need it, do not rebuild production around way 2, and do not write way 2 as a required integration step.
1. New legacy-host connection checklist
When connecting a new legacy host or a new customer tenant, check in this order (concept layer; HR example script paths: HR embed example §7.3).
Cadau side (this phase: one workspace for the whole host)
- [ ] Create a workspace (or confirm an existing one)
- [ ] Prepare template agents in the workspace (admin / manager / employee self-service, or one shared)
- [ ] Create a dedicated integration account and add it to that workspace (need not own the agents)
- [ ] Configure a data connection (pointing at the legacy-host business DB, for example SQLite / MySQL / Postgres)
- [ ] Write
access_policy_json(you may compile a draft from hostGET …/mindlink-access-policythenPUTit on the data connection)
Legacy-host side
- [ ] Server env:
MINDLINK_API_BASE,MINDLINK_INTEGRATION_*,MINDLINK_WORKSPACE_ID,MINDLINK_APP_ID; generate/analyze separately viaMINDLINK_GENERATE_USER_AGENT_ID(or host settings). HR example local demo only usesHRMS_SEED_MINDLINK_USER_AGENT_ID(backfills assignment for the demo account at startup; not runtime widget config) - [ ] Host DB registers template agents (Cadau workspace ID + agent ID +
app_id) - [ ] BFF:
GET …/me/embed-sessionandPOST …/me/agent-runboth carry a completehost_actor - [ ] Legacy-host account-open flow stays the same: new users still register/import on the host; assign template agents by role
Automated and manual acceptance
- [ ]
npm run smoke:embed— embed path (see [README.md](/docs/sdk-host-embed) §8.1) - [ ]
npm run smoke:host-agent—host_actor, policy compile, conversation isolation (legacy-host enhancement) - [ ] Manual: employees see only self, manager subordinates and column trimming; two accounts cannot see each other’s history, live support, or tickets (HR example:
ACCEPTANCE_HOST_LEGACY.mdin the repo)
2. Host LLM service (chosen agent answers)
Do not have the host backend call a large model directly; ask a chosen agent in the workspace to answer. Full integration (call chain, fields, conversation isolation, checklist): Host LLM service.
Summary: POST /api/v1/host/agent-runs (integration account; required user_agent_id, message, host_actor). Page widget and answer-on-behalf share identity and data policy. HR example wraps everyday Q&A as POST …/me/agent-run; generate jobs use the chosen analyze agent (.env / host settings, fresh: true) — see Host LLM service §5.1.
3. Data connection access_policy_json
Stored on the workspace data connection. Shape overview:
{
"require_host_actor": true,
"rules": [
{
"when": { "actor_kind": "employee" },
"queries": {
"employees_directory": {
"force_params": {
"employee_id": "{{host_actor.employee_id}}",
"tenant_id": "{{host_actor.tenant_external_id}}"
},
"allowed_columns": ["id", "emp_no", "full_name", "org_unit_id", "lifecycle_status"]
}
},
"tables": {
"hr_employees": {
"row_filter_params": {
"id": "{{host_actor.employee_id}}",
"tenant_id": "{{host_actor.tenant_external_id}}"
},
"allowed_columns": ["id", "emp_no", "full_name", "org_unit_id", "lifecycle_status"]
}
}
}
]
}
Placeholders: see the §0.1 field table. Enforced at: query.run / table.preview / select.run. If there is no host_actor and the policy requires one, queries are refused.