{"slug":"triage/03-TRIAGE_AGENTS","title":"03 — Triage Agents","section":"triage","sectionLabel":"Triage","status":"canon","type":"document","path":"triage/03-TRIAGE_AGENTS.mdx","bytes":4985,"description":"The triage agents: their roles, scopes, and boundaries inside the governed classification path.","updated":"2026-08-24","source":"integratewise/Integratewise-docs-wiki","content":"\n\nThe triage system uses three distinct agents, each with a specific role.\n\n## Agent Registry\n\n| Agent | Service | Role | Authority |\n|---|---|---|---|\n| **TriageAgent (runtime)** | iw-agent-runtime | Intake classifier | Operational state only |\n| **TriageAgent (cognitive)** | intelligence | Deep evaluation | Candidate staging only |\n| **Triage Bot** | knowledge | AI extraction + Slack | Pending candidates only |\n\n## 1. Runtime TriageAgent (iw-agent-runtime)\n\n**File:** `services/iw-agent-runtime/src/agents/triage-agent.ts`\n\n**Type:** Durable Object Agent (extends `Agent<Env, TriageState>`)\n\n**Role:** First-line intake classifier. Receives raw events and routes them by simple pattern matching.\n\n### State Model\n\n```typescript\ninterface TriageState {\n  tenant_id: string;\n  rules: TriageRule[];\n  items: TriageItem[];\n  last_sweep_at?: string;\n  updated_at: string;\n}\n\ninterface TriageItem {\n  id: string;\n  kind: \"ai_chat\" | \"twin_session\" | \"worker_handoff\" | \"ingest\" | \"manual\";\n  content: string;\n  route: \"memory\" | \"proposal\" | \"signal\" | \"governance\";\n  status: \"open\" | \"resolved\" | \"escalated\";\n  created_at: string;\n  resolved_at?: string;\n}\n```\n\n### Classification Rules\n\nDefault rules (configurable via `addRule()`):\n\n| Rule ID | Pattern | Priority | Route |\n|---|---|---|---|\n| approval | \"approve\" | 100 | governance |\n| decision | \"decide\" | 90 | proposal |\n| signal | \"signal\" | 50 | signal |\n| *(default)* | *(no match)* | — | memory |\n\n### Execution Flow\n\n1. `triage()` receives input (kind, content, source, metadata)\n2. `classify(content)` matches against rules → determines route\n3. Writes `triage_item` to SQLite (operational state)\n4. If route is `memory` or `signal`, calls `emitTriageInput()` to Continuity service\n5. Returns `{ itemId, route, status: \"open\" }`\n\n### What It Writes\n\n- `triage_items` table (Durable Object SQLite) — operational state only\n- Continuity event via `emitTriageInput()` — evidence emission\n\n### What It Never Writes\n\n- Canonical organizational memory\n- Approved knowledge\n- Entity state\n\n## 2. Cognitive TriageAgent (intelligence)\n\n**File:** `services/intelligence/src/agents/specialized/triage.ts`\n\n**Type:** Workflow agent (extends `BaseAgent`)\n\n**Role:** Deep cognitive evaluation of high-stakes content. Uses LLM reasoning across 4 dimensions.\n\n### Cognitive Dimensions\n\n1. **Intelligent Categorization** — What is the true intent?\n2. **Contextual Linking** — How does this relate to canonical memory?\n3. **Canonical Review** — Stale? Duplicate? Conflicts?\n4. **Guardrails & Governance** — Sensitivity → stage or reject?\n\n### Output Schema\n\n```json\n{\n  \"classification\": {\n    \"doc_type\": \"<string>\",\n    \"workflow_type\": \"<string>\",\n    \"intent\": \"<string>\"\n  },\n  \"canonical_review\": {\n    \"is_duplicate\": boolean,\n    \"has_conflict\": boolean,\n    \"conflict_reason\": \"<string or null>\"\n  },\n  \"linking\": {\n    \"primary_entity\": \"<string>\",\n    \"related_entities\": [\"<string>\"]\n  },\n  \"governance\": {\n    \"action\": \"STAGE_FOR_REVIEW\" | \"REJECT\",\n    \"reasoning\": \"<detailed explanation>\"\n  }\n}\n```\n\n**Critical:** The only valid governance actions are `STAGE_FOR_REVIEW` and `REJECT`. `AUTO_APPROVE` is deprecated and prohibited for organizational memory.\n\n### Final Status Mapping\n\n```typescript\nlet finalStatus = \"pending_approval\";\nif (evaluation.governance.action === \"REJECT\") {\n  finalStatus = \"rejected\";\n}\n```\n\nThe agent returns a candidate and reasoning, not authority.\n\n## 3. Triage Bot (knowledge)\n\n**File:** `services/knowledge/src/triage-bot.ts`\n\n**Type:** Function module (not an agent class)\n\n**Role:** AI-powered knowledge extraction from conversations. Uses Workers AI for extraction, Slack for review notification.\n\n### Extraction Categories\n\n| Category | Meaning |\n|---|---|\n| insight | Business insight or observation |\n| fact | Concrete fact about customer, product, market |\n| decision | Decision that was made |\n| action_item | Task or follow-up committed to |\n| preference | User or customer preference |\n| relationship | Relationship between entities |\n\n### AI Provider Priority\n\n1. Cloudflare Workers AI (`env.AI`) — edge-native, zero external calls\n2. OpenRouter (`env.OPENROUTER_API_KEY`) — fallback for larger models\n\n### What It Writes\n\n- `triage_results` table (Neon/D1) with `approval_status = 'pending'`\n- Slack notification (review channel only, not authority bypass)\n\n### What It Never Writes\n\n- Approved organizational memory\n- Canonical entity state\n- Direct promotions\n\n### Slack Integration\n\nSlack is a **review channel**, not an authority bypass. A Slack reaction must become a verified approval event bound to the triage item, tenant, principal, and candidate version before promotion.\n\nReaction mapping:\n- ✅ → Approve\n- ❌ → Discard\n- ⏰ → Defer\n"}