agentix-cli 0.22.0 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +102 -103
- package/agentx.example.json +9 -3
- package/dist/App-6Y7B3YQH.js +8 -0
- package/dist/App-6Y7B3YQH.js.map +1 -0
- package/dist/ChatApp-KIEUJ2DS.js +7 -0
- package/dist/ChatApp-KIEUJ2DS.js.map +1 -0
- package/dist/{agent-Y4U4R3ZZ.js → agent-QGZIAZMY.js} +2 -2
- package/dist/architect-SEPWMWS4.js +2 -0
- package/dist/{board-dashboard-2CPBWFOB.js → board-dashboard-CQ5F4GPD.js} +3756 -1010
- package/dist/board-dashboard-CQ5F4GPD.js.map +1 -0
- package/dist/builtin-FRKAQMFS.js +2 -0
- package/dist/chunk-2WVX3LEC.js +2 -0
- package/dist/chunk-2WVX3LEC.js.map +1 -0
- package/dist/chunk-3WQFCIB6.js +24 -0
- package/dist/chunk-3WQFCIB6.js.map +1 -0
- package/dist/chunk-53GCFZPR.js +116 -0
- package/dist/chunk-53GCFZPR.js.map +1 -0
- package/dist/{chunk-IKBHHTIT.js → chunk-5U35WAZF.js} +2 -2
- package/dist/chunk-67Q4DCPS.js +54 -0
- package/dist/chunk-67Q4DCPS.js.map +1 -0
- package/dist/chunk-76Z4VHDX.js +8 -0
- package/dist/chunk-76Z4VHDX.js.map +1 -0
- package/dist/{chunk-7P5QRX5W.js → chunk-BFXONUUN.js} +2 -2
- package/dist/{chunk-P3TJHGO5.js → chunk-FDMWOPEL.js} +2 -2
- package/dist/chunk-FDWOECJY.js +54 -0
- package/dist/chunk-FDWOECJY.js.map +1 -0
- package/dist/chunk-G57RZCXM.js +5 -0
- package/dist/chunk-G57RZCXM.js.map +1 -0
- package/dist/{chunk-NOF4HSGK.js → chunk-H5D7ATXS.js} +2 -2
- package/dist/chunk-HA3XI7Z2.js +155 -0
- package/dist/chunk-HA3XI7Z2.js.map +1 -0
- package/dist/chunk-HR4JSRZS.js +3 -0
- package/dist/{chunk-A6BKSZQA.js.map → chunk-HR4JSRZS.js.map} +1 -1
- package/dist/chunk-I3SIXTJO.js +44 -0
- package/dist/chunk-I3SIXTJO.js.map +1 -0
- package/dist/chunk-ISEBLHWX.js +118 -0
- package/dist/chunk-ISEBLHWX.js.map +1 -0
- package/dist/{chunk-4ITQP3XL.js → chunk-JP5IEXR7.js} +2 -2
- package/dist/chunk-JXWAGMI2.js +13 -0
- package/dist/chunk-JXWAGMI2.js.map +1 -0
- package/dist/chunk-KUCCW2VG.js +431 -0
- package/dist/chunk-KUCCW2VG.js.map +1 -0
- package/dist/chunk-LDHPMJ7M.js +257 -0
- package/dist/chunk-LDHPMJ7M.js.map +1 -0
- package/dist/{chunk-WHP4I44J.js → chunk-LNXCJWOU.js} +29 -30
- package/dist/chunk-LNXCJWOU.js.map +1 -0
- package/dist/chunk-M4AMWP3H.js +178 -0
- package/dist/chunk-M4AMWP3H.js.map +1 -0
- package/dist/chunk-NGSIRE4X.js +126 -0
- package/dist/chunk-NGSIRE4X.js.map +1 -0
- package/dist/{chunk-CNNLREHD.js → chunk-P4VWIVKN.js} +268 -410
- package/dist/chunk-P4VWIVKN.js.map +1 -0
- package/dist/chunk-Q6YO7LYE.js +47 -0
- package/dist/chunk-Q6YO7LYE.js.map +1 -0
- package/dist/chunk-TMKLHTCG.js +971 -0
- package/dist/chunk-TMKLHTCG.js.map +1 -0
- package/dist/chunk-TRJTTBE2.js +7 -0
- package/dist/chunk-TRJTTBE2.js.map +1 -0
- package/dist/chunk-U2CKL755.js +4 -0
- package/dist/chunk-U2CKL755.js.map +1 -0
- package/dist/chunk-UCQ2N3KO.js +9 -0
- package/dist/chunk-UCQ2N3KO.js.map +1 -0
- package/dist/chunk-W4YR2RO2.js +2 -0
- package/dist/chunk-W4YR2RO2.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/client-GGVVLOOF.js +2 -0
- package/dist/{compaction-BTUJJ3LJ.js → compaction-NWEMOSHA.js} +3 -3
- package/dist/config-7FSZFRTQ.js +2 -0
- package/dist/config-mutator-POCOYYJ4.js +2 -0
- package/dist/{context-planner-I7ID7XF3.js → context-planner-45GEWKGL.js} +2 -2
- package/dist/doctor-DHLBEKA4.js +2 -0
- package/dist/heal-HZ3EQD52.js +2 -0
- package/dist/index.d.ts +1244 -225
- package/dist/index.js +12 -12
- package/dist/index.js.map +1 -1
- package/dist/memory-extract-AENFVVO5.js +2 -0
- package/dist/processes-UIC4XXA6.js +2 -0
- package/dist/program-WVAVJFND.js +2 -0
- package/dist/projects-api-KRME2YKZ.js +2 -0
- package/dist/projects-api-KRME2YKZ.js.map +1 -0
- package/dist/projects-mutate-3NHVG437.js +7 -0
- package/dist/projects-mutate-3NHVG437.js.map +1 -0
- package/dist/providers-L27BJ5A6.js +2 -0
- package/dist/registry-T36ZIAWV.js +2 -0
- package/dist/rotation-memo-B3EXXSEH.js +13 -0
- package/dist/rotation-memo-B3EXXSEH.js.map +1 -0
- package/dist/scheduler-GH7TIKYS.js +2 -0
- package/dist/surface-usage-PRL6Z4U3.js +2 -0
- package/dist/wiki-M6YNRFC4.js +2 -0
- package/dist/workflows/templates/branching.yaml +75 -0
- package/dist/workflows/templates/extract.yaml +59 -0
- package/dist/workflows/templates/linear.yaml +37 -0
- package/dist/workflows/templates/retry.yaml +61 -0
- package/dist/workspace-setup-TBQAHYHJ.js +2 -0
- package/package.json +11 -3
- package/dist/board-dashboard-2CPBWFOB.js.map +0 -1
- package/dist/chunk-2HXSJYAJ.js +0 -15
- package/dist/chunk-2HXSJYAJ.js.map +0 -1
- package/dist/chunk-5F3J55LG.js +0 -2
- package/dist/chunk-5F3J55LG.js.map +0 -1
- package/dist/chunk-A6BKSZQA.js +0 -3
- package/dist/chunk-ABVZHJUO.js +0 -7
- package/dist/chunk-ABVZHJUO.js.map +0 -1
- package/dist/chunk-BHSPAP4U.js +0 -44
- package/dist/chunk-BHSPAP4U.js.map +0 -1
- package/dist/chunk-CDNWCYF7.js +0 -2
- package/dist/chunk-CDNWCYF7.js.map +0 -1
- package/dist/chunk-CNNLREHD.js.map +0 -1
- package/dist/chunk-CO4YCIIA.js +0 -13
- package/dist/chunk-CO4YCIIA.js.map +0 -1
- package/dist/chunk-EW27SCCC.js +0 -2
- package/dist/chunk-EW27SCCC.js.map +0 -1
- package/dist/chunk-GOLZ6NEL.js +0 -111
- package/dist/chunk-GOLZ6NEL.js.map +0 -1
- package/dist/chunk-JGXE2YNV.js +0 -46
- package/dist/chunk-JGXE2YNV.js.map +0 -1
- package/dist/chunk-KX626FN4.js +0 -6
- package/dist/chunk-KX626FN4.js.map +0 -1
- package/dist/chunk-MTRWXRFF.js +0 -380
- package/dist/chunk-MTRWXRFF.js.map +0 -1
- package/dist/chunk-N67JZAXU.js +0 -2
- package/dist/chunk-N67JZAXU.js.map +0 -1
- package/dist/chunk-OPKQNLGX.js +0 -450
- package/dist/chunk-OPKQNLGX.js.map +0 -1
- package/dist/chunk-OZOQKPJV.js +0 -102
- package/dist/chunk-OZOQKPJV.js.map +0 -1
- package/dist/chunk-VYLZ7UYM.js +0 -118
- package/dist/chunk-VYLZ7UYM.js.map +0 -1
- package/dist/chunk-WHP4I44J.js.map +0 -1
- package/dist/chunk-WJXU5F4Z.js +0 -53
- package/dist/chunk-WJXU5F4Z.js.map +0 -1
- package/dist/chunk-X5D5AV5N.js +0 -833
- package/dist/chunk-X5D5AV5N.js.map +0 -1
- package/dist/config-BLOKGMER.js +0 -2
- package/dist/config-mutator-RG7QY2EL.js +0 -2
- package/dist/doctor-ZTECTUHX.js +0 -2
- package/dist/editor-chat-RVLCKKB7.js +0 -137
- package/dist/editor-chat-RVLCKKB7.js.map +0 -1
- package/dist/heal-YEQYWX2L.js +0 -2
- package/dist/inbox-BIN2S5XN.js +0 -2
- package/dist/memory-extract-KRCHD3OP.js +0 -2
- package/dist/processes-RJ6RDP32.js +0 -2
- package/dist/program-GZOJIWTB.js +0 -2
- package/dist/providers-WVCMIW67.js +0 -2
- package/dist/registry-QZIUSQ5J.js +0 -2
- package/dist/rotation-memo-GMTZPMNE.js +0 -13
- package/dist/rotation-memo-GMTZPMNE.js.map +0 -1
- package/dist/scheduler-B2BQPV4M.js +0 -2
- package/dist/slack-6P7ZJ32Y.js +0 -3
- package/dist/slack-6P7ZJ32Y.js.map +0 -1
- package/dist/store-BAPDZHXE.js +0 -2
- package/dist/task-store-RHISEU6V.js +0 -2
- package/dist/telegram-PIYDRM46.js +0 -3
- package/dist/telegram-PIYDRM46.js.map +0 -1
- package/dist/types-ZRLHHCGB.js +0 -2
- package/dist/web/workflow-editor.global.js +0 -1452
- package/dist/web/workflow-editor.global.js.map +0 -1
- package/dist/whatsapp-PFRDMUMT.js +0 -3
- package/dist/whatsapp-PFRDMUMT.js.map +0 -1
- package/dist/wiki-53W5NLZV.js +0 -2
- package/dist/workspace-setup-DQCZX2NE.js +0 -2
- /package/dist/{agent-Y4U4R3ZZ.js.map → agent-QGZIAZMY.js.map} +0 -0
- /package/dist/{config-BLOKGMER.js.map → architect-SEPWMWS4.js.map} +0 -0
- /package/dist/{config-mutator-RG7QY2EL.js.map → builtin-FRKAQMFS.js.map} +0 -0
- /package/dist/{chunk-IKBHHTIT.js.map → chunk-5U35WAZF.js.map} +0 -0
- /package/dist/{chunk-7P5QRX5W.js.map → chunk-BFXONUUN.js.map} +0 -0
- /package/dist/{chunk-P3TJHGO5.js.map → chunk-FDMWOPEL.js.map} +0 -0
- /package/dist/{chunk-NOF4HSGK.js.map → chunk-H5D7ATXS.js.map} +0 -0
- /package/dist/{chunk-4ITQP3XL.js.map → chunk-JP5IEXR7.js.map} +0 -0
- /package/dist/{doctor-ZTECTUHX.js.map → client-GGVVLOOF.js.map} +0 -0
- /package/dist/{compaction-BTUJJ3LJ.js.map → compaction-NWEMOSHA.js.map} +0 -0
- /package/dist/{heal-YEQYWX2L.js.map → config-7FSZFRTQ.js.map} +0 -0
- /package/dist/{inbox-BIN2S5XN.js.map → config-mutator-POCOYYJ4.js.map} +0 -0
- /package/dist/{context-planner-I7ID7XF3.js.map → context-planner-45GEWKGL.js.map} +0 -0
- /package/dist/{memory-extract-KRCHD3OP.js.map → doctor-DHLBEKA4.js.map} +0 -0
- /package/dist/{processes-RJ6RDP32.js.map → heal-HZ3EQD52.js.map} +0 -0
- /package/dist/{program-GZOJIWTB.js.map → memory-extract-AENFVVO5.js.map} +0 -0
- /package/dist/{providers-WVCMIW67.js.map → processes-UIC4XXA6.js.map} +0 -0
- /package/dist/{registry-QZIUSQ5J.js.map → program-WVAVJFND.js.map} +0 -0
- /package/dist/{scheduler-B2BQPV4M.js.map → providers-L27BJ5A6.js.map} +0 -0
- /package/dist/{store-BAPDZHXE.js.map → registry-T36ZIAWV.js.map} +0 -0
- /package/dist/{task-store-RHISEU6V.js.map → scheduler-GH7TIKYS.js.map} +0 -0
- /package/dist/{types-ZRLHHCGB.js.map → surface-usage-PRL6Z4U3.js.map} +0 -0
- /package/dist/{wiki-53W5NLZV.js.map → wiki-M6YNRFC4.js.map} +0 -0
- /package/dist/{workspace-setup-DQCZX2NE.js.map → workspace-setup-TBQAHYHJ.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/actions/builtin/registry.ts","../src/actions/builtin/agent.ts","../src/agents/registry-instance.ts","../src/actions/builtin/channel.ts","../src/actions/builtin/extract.ts","../src/actions/builtin/file.ts","../src/actions/builtin/http.ts","../src/actions/builtin/mesh.ts","../src/a2a/mesh-instance.ts","../src/actions/builtin/rag.ts","../src/rag/lexical-index.ts","../src/actions/builtin/index.ts"],"sourcesContent":["import type { BuiltinAction, BuiltinActionMetadata } from \"./types\"\n\n// --- Built-in action registry ---\n//\n// Process-global. Built-ins register at module-load time via the\n// barrel in ./index.ts; the daemon never has to wire them up\n// explicitly. Lookup is O(1).\n\nconst _registry = new Map<string, BuiltinAction>()\n\nconst NAME_PATTERN = /^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)*$/\n\n/**\n * Register a built-in. Idempotent — re-registering the same name\n * overwrites (useful for tests). Throws on malformed names so the\n * dotted-namespace contract stays consistent across the codebase.\n */\nexport function registerBuiltin<I, O>(action: BuiltinAction<I, O>): void {\n if (!NAME_PATTERN.test(action.name)) {\n throw new Error(`built-in action name must be dotted lowercase identifier (got \"${action.name}\")`)\n }\n _registry.set(action.name, action as BuiltinAction)\n}\n\nexport function getBuiltin(name: string): BuiltinAction | undefined {\n return _registry.get(name)\n}\n\n/** List metadata for every registered built-in, sorted by name. The\n * full schemas aren't included here — operators fetch the JSON-schema\n * rendering separately to keep the list response small. */\nexport function listBuiltins(): BuiltinActionMetadata[] {\n const out: BuiltinActionMetadata[] = []\n for (const [name, a] of _registry.entries()) {\n out.push({ name, description: a.description, timeoutMs: a.timeoutMs })\n }\n out.sort((a, b) => a.name.localeCompare(b.name))\n return out\n}\n\n/** Test-only — wipe the registry between cases. Production never clears. */\nexport function _resetBuiltinsForTesting(): void {\n _registry.clear()\n}\n\nconst DEFAULT_TIMEOUT_MS = 60_000\n\n/**\n * Run a built-in. Wraps the handler in:\n * - input validation (Zod parse — throws on bad shape)\n * - per-action timeout (with daemon-default fallback)\n * - output validation (Zod parse — log on mismatch but pass through;\n * output drift shouldn't break callers, just signal)\n *\n * Returns the validated output, or rejects on timeout / handler error.\n * Callers (HTTP route, CLI) catch and translate to error responses.\n */\nexport async function runBuiltin<I, O>(name: string, rawInput: unknown): Promise<O> {\n const action = _registry.get(name) as BuiltinAction<I, O> | undefined\n if (!action) {\n throw new Error(`unknown built-in action: ${name}`)\n }\n const input = action.inputSchema.parse(rawInput) as I\n const timeoutMs = action.timeoutMs ?? DEFAULT_TIMEOUT_MS\n\n const handlerPromise = action.handler(input)\n const timeoutPromise = new Promise<O>((_, reject) => {\n setTimeout(() => reject(new Error(`built-in action ${name} timed out after ${timeoutMs}ms`)), timeoutMs)\n })\n\n const output = await Promise.race([handlerPromise, timeoutPromise])\n\n // Soft validation on output — log mismatches but pass the value\n // through. A handler that drifts from its schema shouldn't break\n // production; surfacing the drift in the daemon log is enough signal.\n const parsed = action.outputSchema.safeParse(output)\n if (!parsed.success) {\n process.stderr.write(`[builtin-action] ${name} output failed schema validation: ${parsed.error.message}\\n`)\n }\n return output\n}\n","import { z } from \"zod\"\nimport { getAgentRegistry } from \"@/agents/registry-instance\"\nimport type { BuiltinAction } from \"./types\"\n\n// --- agent.call ---\n//\n// Same-node sub-agent delegation, typed and traceable. Counterpart to\n// `mesh.delegate`: that one calls a remote peer's agent over HTTP+mesh,\n// this one calls a local agent on the same daemon — the common case for\n// triage/router patterns where one agent classifies + dispatches to a\n// specialized worker on the same machine.\n//\n// Why this exists separately from the daemon's POST /task endpoint:\n// - Going through HTTP for a same-node call is wasteful and harder\n// to trace (the action becomes a Bash + curl + parse-JSON dance,\n// exactly what AGENTX_HANDOFF.md item #1 flagged).\n// - Calling registry.execute() directly captures the call as a\n// structured action step in /traces (action=agent.call,\n// input=<typed>, output=<reply>) instead of opaque shell text.\n// - freshSession defaults to TRUE — the run-3/run-4 stickiness bug\n// was triage's curl reusing a warm pool; this default makes\n// \"safe\" the easy path.\n//\n// Architecturally this is a documented cross-tier seam: a Tier-3\n// procedure reaches into the Tier-1 agent registry via the explicit\n// getAgentRegistry() singleton (see registry-instance.ts and\n// test/tier-discipline.test.ts:DOCUMENTED_SEAMS).\n\nconst agentCallInput = z.object({\n /** Local agent id to dispatch the task to. */\n agentId: z.string().min(1),\n /** The task message — verbatim user message or a synthesized prompt. */\n message: z.string().min(1),\n /** Force a fresh session on the receiving agent. Defaults to TRUE so\n * that triage/router agents don't accidentally inherit a previous\n * visitor's conversation state. Pass `false` only when you genuinely\n * want continuity (rare for delegation). */\n freshSession: z.boolean().default(true),\n /** Optional channel + chatId. Defaults to a synthetic per-call chatId\n * so multiple concurrent delegations don't share a session. */\n channel: z.string().default(\"api\"),\n chatId: z.string().optional(),\n /** Identity of the calling agent — passed through to the receiving\n * agent's context for trace-stitching and (eventually) capability\n * validation. */\n senderAgentId: z.string().optional(),\n /** Per-call timeout. Default 90s — long enough for most agent\n * reasoning; capped at 10min. */\n timeoutMs: z.number().int().min(1).max(600_000).default(90_000),\n})\ntype AgentCallInput = z.infer<typeof agentCallInput>\n\nconst agentCallOutput = z.object({\n agentId: z.string(),\n /** The agent's reply. Same shape as POST /task's `content`. */\n reply: z.string(),\n /** Optional structured error if the underlying agent run failed.\n * Surfaced so callers can branch on auth/billing/tool-required. */\n error: z.string().optional(),\n errorKind: z.string().optional(),\n /** Token usage for cost accounting. */\n usage: z.object({\n inputTokens: z.number().int().default(0),\n outputTokens: z.number().int().default(0),\n cacheReadTokens: z.number().int().default(0),\n cacheCreateTokens: z.number().int().default(0),\n }).default({ inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheCreateTokens: 0 }),\n durationMs: z.number().int().default(0),\n})\ntype AgentCallOutput = z.infer<typeof agentCallOutput>\n\nexport const agentCall: BuiltinAction<AgentCallInput, AgentCallOutput> = {\n name: \"agent.call\",\n description: \"Dispatch a task to a local agent on the same daemon (fresh session by default — replaces ad-hoc 'Bash curl /task' delegation)\",\n inputSchema: agentCallInput,\n outputSchema: agentCallOutput,\n timeoutMs: 600_000,\n handler: async (input) => {\n const registry = getAgentRegistry()\n if (!registry) {\n throw new Error(\"agent registry not wired (daemon not started or running in a non-daemon process)\")\n }\n // Synthesize a per-call chatId by default so concurrent delegations\n // don't share a session. Caller can override for explicit continuity.\n const chatId = input.chatId ?? `agent-call-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`\n const started = Date.now()\n // senderAgentId is intentionally NOT placed in context (the\n // standard AgentTask context shape doesn't include it). The receiving\n // agent's prompt can reference {{trigger.input.senderAgentId}} if\n // configured; for trace stitching, the action's invocation already\n // creates a parent step so children land under the same task tree.\n const response = await registry.execute({\n agentId: input.agentId,\n message: input.message,\n freshSession: input.freshSession,\n context: {\n channel: input.channel,\n chatId,\n },\n })\n return {\n agentId: input.agentId,\n reply: response.content ?? \"\",\n error: response.error,\n errorKind: (response as any).errorKind,\n usage: {\n inputTokens: response.usage?.inputTokens ?? 0,\n outputTokens: response.usage?.outputTokens ?? 0,\n cacheReadTokens: (response.usage as any)?.cacheReadTokens ?? 0,\n cacheCreateTokens: (response.usage as any)?.cacheCreateTokens ?? 0,\n },\n durationMs: response.duration ?? (Date.now() - started),\n }\n },\n}\n","import type { AgentRegistry } from \"./registry\"\n\n// --- Singleton accessor for the live AgentRegistry ---\n//\n// Mirrors src/agents/process-registry-instance.ts and src/a2a/mesh-instance.ts.\n// Daemon registers the registry at boot; cross-tier composition seams (e.g.\n// the agent.call built-in action that needs to dispatch a local task without\n// going through HTTP) read it via getAgentRegistry().\n//\n// This is a DOCUMENTED SEAM under the three-tier discipline rule — listed in\n// test/tier-discipline.test.ts:DOCUMENTED_SEAMS so a procedure module can\n// import this without violating \"procedures must not import the agent\n// registry runtime\". The escape hatch is intentional: local delegation\n// reuses the registry's session management + permission resolution + trace\n// recording, which would otherwise need to be duplicated in the action.\n\nlet _registry: AgentRegistry | null = null\n\nexport function getAgentRegistry(): AgentRegistry | null {\n return _registry\n}\n\nexport function setAgentRegistry(r: AgentRegistry | null): void {\n _registry = r\n}\n\n/** Test-only — guarantees a clean slate between cases. */\nexport function resetAgentRegistryForTesting(): void {\n _registry = null\n}\n","import { z } from \"zod\"\nimport { getMessageRouter } from \"@/channels/router-instance\"\nimport type { BuiltinAction } from \"./types\"\n\n// --- channel.reply / channel.label / channel.assign ---\n//\n// Canonical channel-output surface for agents. Replaces the raw-curl\n// playbook in agent skills with a typed action that:\n//\n// - posts through the live MessageRouter -> adapter chain (so the\n// adapter's marker + identity resolution + ledger recording all\n// fire automatically — no per-agent token in workspace files)\n// - dedupes within a 60s window keyed on (channel, chatId, body)\n// via router.sendOutbound's idempotency layer — so the same\n// dedupe protects every caller (HTTP /send, channel.reply,\n// cron notifications, cross-channel routing)\n// - returns the posted message id, or null when dedupe suppressed\n// the post (the messageId from the prior post)\n//\n// Architecturally this is the cleanest decoupling we can offer right\n// now: agent reasoning produces structured actions; the actions touch\n// the world through agentx; agentx owns cross-cutting concerns\n// (dedupe, marker, audit, rate limiting, identity) at the router\n// layer where every send-out converges.\n//\n// `auto_reply_legacy` (separate flag, on the channel config) preserves\n// today's \"router auto-posts response.content\" until every agent skill\n// has migrated to channel.reply. Once migration is complete the flag\n// gets removed and the agent's response.content stops being auto-\n// relayed entirely.\n\n// --- channel.reply ---\n\nconst channelReplyInput = z.object({\n /** Channel name (gitlab | github | telegram | whatsapp | discord | slack). */\n channel: z.string().min(1),\n /** Stable chat id — for gitlab: `org/repo:issue:123` or `org/repo:merge_request:123`.\n * For telegram/whatsapp: the chat or sender id. The format is the same one\n * the agent received in its task context as `chatId`. */\n chatId: z.string().min(1),\n /** Message body. Markdown for gitlab/github/discord; plain for sms/whatsapp. */\n text: z.string().min(1),\n /** Posting identity. When omitted, the channel adapter resolves identity\n * from agentMappings — for gitlab that's the per-agent gitlab token.\n * For telegram/discord it picks an account that's in the chat. */\n agentId: z.string().optional(),\n /** Multi-account adapters (telegram) need this when the chat is reachable\n * from more than one bot. Falls back to the adapter's chatAccountMap. */\n accountId: z.string().optional(),\n /** Optional reply-to message id for threaded channels. */\n replyTo: z.string().optional(),\n /** Custom dedupe key. When provided, replaces the default body-hash\n * scheme — useful for \"I want to overwrite my last status update\"\n * patterns where the body changes but the intent is the same post. */\n idempotencyKey: z.string().optional(),\n /** Optional rich payloads (telegram/whatsapp). URL buttons render as an\n * inline keyboard; poll/media send as their own message. */\n buttons: z.array(z.object({ label: z.string(), url: z.string() })).optional(),\n poll: z.object({ name: z.string(), values: z.array(z.string()), selectableCount: z.number().optional() }).optional(),\n media: z.object({\n type: z.enum([\"image\", \"document\", \"audio\", \"video\"]),\n url: z.string(),\n caption: z.string().optional(),\n }).optional(),\n})\ntype ChannelReplyInput = z.infer<typeof channelReplyInput>\n\nconst channelReplyOutput = z.object({\n /** Adapter-returned id, or null when the adapter couldn't surface one\n * (or the call was suppressed by the router's 60s dedupe window — in\n * which case this returns the prior post's id when known). */\n messageId: z.string().nullable(),\n})\ntype ChannelReplyOutput = z.infer<typeof channelReplyOutput>\n\nexport const channelReply: BuiltinAction<ChannelReplyInput, ChannelReplyOutput> = {\n name: \"channel.reply\",\n description: \"Post a reply to a channel (gitlab/github comment, telegram/whatsapp message, …) through the canonical adapter — auto-marker, auto-dedupe within 60s, identity resolved from agentMappings.\",\n inputSchema: channelReplyInput,\n outputSchema: channelReplyOutput,\n timeoutMs: 30_000,\n handler: async (input) => {\n const router = getMessageRouter()\n if (!router) {\n throw new Error(\"message router not wired (daemon not started or running in a non-daemon process)\")\n }\n // Empty-string idempotencyKey tells the router to use a body-hash\n // dedupe key. Caller can override with their own key for \"overwrite\n // last status\" patterns where the body changes but intent matches.\n const idempotencyKey = input.idempotencyKey ?? \"\"\n const messageId = await router.sendOutbound(\n {\n channel: input.channel,\n chatId: input.chatId,\n text: input.text,\n agentId: input.agentId,\n accountId: input.accountId,\n replyTo: input.replyTo,\n buttons: input.buttons,\n poll: input.poll,\n media: input.media,\n },\n { idempotencyKey, dedupeWindowMs: 60_000 },\n )\n return { messageId: typeof messageId === \"string\" ? messageId : null }\n },\n}\n\n// --- channel.label ---\n//\n// Add and/or remove labels on the inbound entity. GitLab + GitHub both\n// expose this; other channels error politely. Like channel.reply this\n// goes through the live adapter chain (per-agent token, marker, ledger).\n\nconst channelLabelInput = z.object({\n /** Currently supports \"gitlab\"; \"github\" wired when the github adapter\n * surfaces a typed label call (today the adapter-level setLabels is\n * gitlab-only). Pass the channel that owns the entity. */\n channel: z.literal(\"gitlab\"),\n /** GitLab project path — `org/repo`. */\n project: z.string().min(1),\n /** \"issue\" or \"merge_request\". */\n kind: z.enum([\"issue\", \"merge_request\"]),\n /** Numeric iid as a string. */\n iid: z.string().min(1),\n add: z.array(z.string()).default([]),\n remove: z.array(z.string()).default([]),\n /** Posting identity — defaults to channel-adapter resolution. */\n agentId: z.string().optional(),\n})\ntype ChannelLabelInput = z.infer<typeof channelLabelInput>\n\nconst channelLabelOutput = z.object({\n labels: z.array(z.string()),\n})\ntype ChannelLabelOutput = z.infer<typeof channelLabelOutput>\n\nexport const channelLabel: BuiltinAction<ChannelLabelInput, ChannelLabelOutput> = {\n name: \"channel.label\",\n description: \"Add and/or remove labels on a GitLab issue/MR through the adapter (per-agent token, ledger, no raw curl).\",\n inputSchema: channelLabelInput,\n outputSchema: channelLabelOutput,\n timeoutMs: 30_000,\n handler: async (input) => {\n const router = getMessageRouter()\n if (!router) throw new Error(\"message router not wired\")\n const adapter = (router as any).getChannel?.(input.channel) as\n | { setLabels?: (args: { project: string; kind?: \"issue\" | \"merge_request\"; iid: string; add?: string[]; remove?: string[]; agentId?: string }) => Promise<string[] | null> }\n | undefined\n if (!adapter?.setLabels) {\n throw new Error(`channel \"${input.channel}\" does not expose setLabels`)\n }\n const labels = await adapter.setLabels({\n project: input.project,\n kind: input.kind,\n iid: input.iid,\n add: input.add,\n remove: input.remove,\n agentId: input.agentId,\n })\n return { labels: Array.isArray(labels) ? labels : [] }\n },\n}\n\n// --- channel.assign ---\n//\n// Replace the assignees on a GitLab issue or MR. PM uses this to assign\n// the coding agent when flipping Triage→To Do; coders use it to assign\n// reviewers/mergers; QA uses it to assign testers. Same identity model\n// as channel.label — per-agent token, ledger.\n\nconst channelAssignInput = z.object({\n channel: z.literal(\"gitlab\"),\n project: z.string().min(1),\n kind: z.enum([\"issue\", \"merge_request\"]),\n iid: z.string().min(1),\n /** GitLab usernames. Empty array = unassign all. */\n assignees: z.array(z.string()).default([]),\n agentId: z.string().optional(),\n})\ntype ChannelAssignInput = z.infer<typeof channelAssignInput>\n\nconst channelAssignOutput = z.object({\n /** Numeric user_ids assigned (post-resolution from usernames). */\n assigneeIds: z.array(z.number()),\n})\ntype ChannelAssignOutput = z.infer<typeof channelAssignOutput>\n\nexport const channelAssign: BuiltinAction<ChannelAssignInput, ChannelAssignOutput> = {\n name: \"channel.assign\",\n description: \"Set assignees on a GitLab issue or MR (replaces the assignee list). Pass empty array to unassign. Use during Triage→To Do flip to assign the coding agent, or to designate reviewer/merger on an MR.\",\n inputSchema: channelAssignInput,\n outputSchema: channelAssignOutput,\n timeoutMs: 30_000,\n handler: async (input) => {\n const router = getMessageRouter()\n if (!router) throw new Error(\"message router not wired\")\n const adapter = (router as any).getChannel?.(input.channel) as\n | { setAssignees?: (args: { project: string; kind?: \"issue\" | \"merge_request\"; iid: string; assignees: string[]; agentId?: string }) => Promise<number[] | null> }\n | undefined\n if (!adapter?.setAssignees) {\n throw new Error(`channel \"${input.channel}\" does not expose setAssignees`)\n }\n const ids = await adapter.setAssignees({\n project: input.project,\n kind: input.kind,\n iid: input.iid,\n assignees: input.assignees,\n agentId: input.agentId,\n })\n return { assigneeIds: Array.isArray(ids) ? ids : [] }\n },\n}\n\n// --- channel.create_issue ---\n//\n// Create a GitLab issue from inside an agent task. PM uses this to spin\n// off test-case issues from the parent dev issue; CX uses it to file\n// issues from WhatsApp/email client requests. The /relate cross-link\n// happens on a follow-up call — the GitLab API doesn't take it inline.\n\nconst channelCreateIssueInput = z.object({\n channel: z.literal(\"gitlab\"),\n project: z.string().min(1),\n title: z.string().min(1),\n description: z.string().default(\"\"),\n labels: z.array(z.string()).default([]),\n /** Usernames to assign on creation. */\n assignees: z.array(z.string()).default([]),\n agentId: z.string().optional(),\n /** Optional: when set, the new issue is /relate'd to this iid via a\n * follow-up POST to /issues/:src/links — same project. Caller-friendly\n * shortcut so the test-case-create flow is one call, not two. */\n relateToIid: z.string().optional(),\n})\ntype ChannelCreateIssueInput = z.infer<typeof channelCreateIssueInput>\n\nconst channelCreateIssueOutput = z.object({\n iid: z.number(),\n url: z.string(),\n related: z.boolean().default(false),\n})\ntype ChannelCreateIssueOutput = z.infer<typeof channelCreateIssueOutput>\n\nexport const channelCreateIssue: BuiltinAction<ChannelCreateIssueInput, ChannelCreateIssueOutput> = {\n name: \"channel.create_issue\",\n description: \"Create a GitLab issue from an agent (PM test cases, CX client requests). Honors per-agent identity; resolves assignee usernames to ids; optional /relate to a parent issue.\",\n inputSchema: channelCreateIssueInput,\n outputSchema: channelCreateIssueOutput,\n timeoutMs: 60_000,\n handler: async (input) => {\n const router = getMessageRouter()\n if (!router) throw new Error(\"message router not wired\")\n const adapter = (router as any).getChannel?.(input.channel) as\n | {\n createIssue?: (args: {\n project: string; title: string; description?: string;\n labels?: string[]; assignees?: string[]; agentId?: string;\n }) => Promise<{ iid: number; url: string } | null>\n relateIssue?: (args: { project: string; sourceIid: string; targetIid: string; agentId?: string }) => Promise<boolean>\n }\n | undefined\n if (!adapter?.createIssue) {\n throw new Error(`channel \"${input.channel}\" does not expose createIssue`)\n }\n const created = await adapter.createIssue({\n project: input.project,\n title: input.title,\n description: input.description,\n labels: input.labels,\n assignees: input.assignees,\n agentId: input.agentId,\n })\n if (!created) {\n throw new Error(\"createIssue returned null — see daemon log for details\")\n }\n let related = false\n if (input.relateToIid && adapter.relateIssue) {\n related = await adapter.relateIssue({\n project: input.project,\n sourceIid: String(created.iid),\n targetIid: input.relateToIid,\n agentId: input.agentId,\n })\n }\n return { iid: created.iid, url: created.url, related }\n },\n}\n","import { z } from \"zod\"\nimport type { BuiltinAction } from \"./types\"\n\n// --- extract.structured ---\n//\n// Single-call structured extraction: ask Claude for a JSON value\n// matching a caller-supplied JSON-Schema. The agent / workflow gets\n// typed structured data back — no parser needed downstream.\n//\n// Implementation: Anthropic Messages API with a forced tool_use whose\n// input_schema is the caller's schema. Forced tool use guarantees the\n// model's response is the structured value, not free-form text. We\n// extract the tool's `input` and return it verbatim.\n//\n// Why we hit the API directly instead of routing through the\n// claude-code subprocess (or the SDK):\n// - The persistent-process path keeps a turn slot busy for >2s\n// even on warm cache; for a single extraction this is overkill.\n// - The SDK adds a 10MB+ dependency; raw fetch needs zero new deps.\n// - The model + auth are the same — ANTHROPIC_API_KEY env var.\n//\n// Input shape:\n// model: Anthropic model id (\"claude-sonnet-4-6\" / \"claude-haiku-4-5\" / etc.)\n// prompt: User-message text the model extracts from.\n// schema: JSON-Schema-shaped object (NOT a Zod schema) — this is what\n// the model is told to fill in. Caller-defined.\n// maxTokens: Output-token cap, default 1024.\n//\n// Output shape:\n// data: The structured value, exactly as the model returned it.\n// Validated only against \"is an object/array/scalar\" — the\n// caller's schema is the contract; we don't re-validate\n// because that would require shipping a JSON-Schema validator.\n// usage: Token counts for cost accounting.\n// model: Model that actually billed (echoed from the response).\n\nconst extractInput = z.object({\n model: z.string().default(\"claude-haiku-4-5\"),\n prompt: z.string().min(1),\n /** JSON-Schema describing the output shape. Passed to the Claude\n * API as the input_schema of a forced tool_use. */\n schema: z.record(z.string(), z.unknown()),\n /** Optional system prompt prepended to the conversation. */\n systemPrompt: z.string().optional(),\n maxTokens: z.number().int().min(1).max(8_000).default(1024),\n /** Per-call timeout. Default 60s. */\n timeoutMs: z.number().int().min(1).max(120_000).default(60_000),\n})\ntype ExtractInput = z.infer<typeof extractInput>\n\nconst extractOutput = z.object({\n data: z.unknown(),\n model: z.string(),\n usage: z.object({\n inputTokens: z.number().int(),\n outputTokens: z.number().int(),\n }),\n})\ntype ExtractOutput = z.infer<typeof extractOutput>\n\nconst ANTHROPIC_API = \"https://api.anthropic.com/v1/messages\"\nconst ANTHROPIC_VERSION = \"2023-06-01\"\n\nexport const extractStructured: BuiltinAction<ExtractInput, ExtractOutput> = {\n name: \"extract.structured\",\n description: \"Single-call typed extraction: prompt + JSON-Schema → structured data via forced tool_use\",\n inputSchema: extractInput,\n outputSchema: extractOutput,\n timeoutMs: 120_000,\n handler: async (input) => {\n const apiKey = process.env.ANTHROPIC_API_KEY\n if (!apiKey) {\n throw new Error(\"ANTHROPIC_API_KEY env var is not set — extract.structured needs direct API access\")\n }\n\n // Use a forced tool_use with input_schema = the caller's schema.\n // tool_choice: { type: \"tool\", name: \"respond_with_structure\" }\n // makes the model produce a tool_use block as the entire reply,\n // whose `input` field IS the structured value.\n const requestBody: Record<string, unknown> = {\n model: input.model,\n max_tokens: input.maxTokens,\n messages: [{ role: \"user\", content: input.prompt }],\n tools: [{\n name: \"respond_with_structure\",\n description: \"Return a structured value matching the schema\",\n input_schema: input.schema,\n }],\n tool_choice: { type: \"tool\", name: \"respond_with_structure\" },\n }\n if (input.systemPrompt) {\n requestBody.system = input.systemPrompt\n }\n\n const ctrl = new AbortController()\n const t = setTimeout(() => ctrl.abort(), input.timeoutMs)\n let res: Response\n try {\n res = await fetch(ANTHROPIC_API, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": apiKey,\n \"anthropic-version\": ANTHROPIC_VERSION,\n },\n body: JSON.stringify(requestBody),\n signal: ctrl.signal,\n })\n } finally {\n clearTimeout(t)\n }\n\n if (!res.ok) {\n const errBody = await res.text().catch(() => \"\")\n throw new Error(`anthropic API ${res.status}: ${errBody.slice(0, 500)}`)\n }\n const body: any = await res.json()\n const blocks = Array.isArray(body.content) ? body.content : []\n const toolUse = blocks.find((b: any) => b?.type === \"tool_use\" && b?.name === \"respond_with_structure\")\n if (!toolUse || toolUse.input === undefined) {\n throw new Error(`anthropic API returned no respond_with_structure tool_use (got ${blocks.length} blocks)`)\n }\n\n const usage = body.usage ?? {}\n return {\n data: toolUse.input,\n model: typeof body.model === \"string\" ? body.model : input.model,\n usage: {\n inputTokens: typeof usage.input_tokens === \"number\" ? usage.input_tokens : 0,\n outputTokens: typeof usage.output_tokens === \"number\" ? usage.output_tokens : 0,\n },\n }\n },\n}\n","import { z } from \"zod\"\nimport { existsSync, readFileSync, appendFileSync, mkdirSync, statSync } from \"fs\"\nimport { resolve, dirname, isAbsolute } from \"path\"\nimport type { BuiltinAction } from \"./types\"\n\n// --- Built-in file actions ---\n//\n// file.read_lines — read a text file, return up to maxLines string lines\n// file.write_jsonl — append N JSON objects as newline-delimited records\n//\n// Both are workspace-scoped: paths must resolve under one of the\n// allowed roots set via AGENTX_BUILTIN_FILE_ROOTS env var (or the cwd\n// by default). This is the boundary that keeps an agent from reading\n// /etc/passwd or writing into the daemon's own .agentx state. Path\n// traversal (../..) is rejected via the resolved-path containment\n// check, not regex on the input.\n//\n// Why these two specifically (per improvement plan #6 catalog):\n// - read_lines: typed plumbing for \"give me the last N log lines\"\n// pattern that workflows currently shell out to `tail` for.\n// - write_jsonl: typed plumbing for \"log a structured event into\n// this agent's working file\" — the workflow-as-program framing\n// wants this as a primitive, not as `echo {} >> file`.\n\nconst MAX_FILE_BYTES = 8 * 1024 * 1024 // 8 MB cap on read\n\n/**\n * Resolve and validate a target path against the allowed roots.\n * Returns the absolute path on success; throws otherwise. Allowed\n * roots default to process.cwd() unless the operator overrides via\n * AGENTX_BUILTIN_FILE_ROOTS (colon-separated). This mirrors how\n * Claude Code's own --add-dir flag is applied at spawn.\n */\nfunction resolveAllowed(input: string): string {\n const abs = isAbsolute(input) ? input : resolve(process.cwd(), input)\n const rootsEnv = process.env.AGENTX_BUILTIN_FILE_ROOTS || process.cwd()\n const roots = rootsEnv.split(\":\").map((r) => resolve(r))\n for (const root of roots) {\n if (abs === root || abs.startsWith(root + \"/\")) return abs\n }\n throw new Error(`path \"${input}\" is outside the allowed roots`)\n}\n\nconst readLinesInput = z.object({\n path: z.string().min(1),\n /** Cap the returned line count. Default 200, hard cap 10000. */\n maxLines: z.number().int().min(1).max(10_000).default(200),\n /** When true, return only the LAST maxLines (tail-style). Default false (head). */\n fromEnd: z.boolean().default(false),\n})\ntype ReadLinesInput = z.infer<typeof readLinesInput>\n\nconst readLinesOutput = z.object({\n path: z.string(),\n lines: z.array(z.string()),\n totalLines: z.number().int(),\n truncated: z.boolean(),\n})\ntype ReadLinesOutput = z.infer<typeof readLinesOutput>\n\nexport const fileReadLines: BuiltinAction<ReadLinesInput, ReadLinesOutput> = {\n name: \"file.read_lines\",\n description: \"Read a text file as an array of lines (utf-8, 8MB cap, scoped to allowed roots)\",\n inputSchema: readLinesInput,\n outputSchema: readLinesOutput,\n timeoutMs: 10_000,\n handler: async (input) => {\n const abs = resolveAllowed(input.path)\n if (!existsSync(abs)) throw new Error(`file not found: ${input.path}`)\n const stat = statSync(abs)\n if (!stat.isFile()) throw new Error(`not a regular file: ${input.path}`)\n if (stat.size > MAX_FILE_BYTES) {\n throw new Error(`file too large (${stat.size} > ${MAX_FILE_BYTES} bytes)`)\n }\n const content = readFileSync(abs, \"utf8\")\n // Split on \\n but drop a trailing empty token if the file ended in \\n —\n // the canonical \"logs end with a newline\" case.\n const all = content.split(\"\\n\")\n if (all.length > 0 && all[all.length - 1] === \"\") all.pop()\n const totalLines = all.length\n let lines: string[]\n let truncated: boolean\n if (totalLines <= input.maxLines) {\n lines = all\n truncated = false\n } else {\n truncated = true\n lines = input.fromEnd ? all.slice(totalLines - input.maxLines) : all.slice(0, input.maxLines)\n }\n return { path: abs, lines, totalLines, truncated }\n },\n}\n\nconst writeJsonlInput = z.object({\n path: z.string().min(1),\n /** Records to append, one JSON line each. Each must be a JSON-serializable\n * value; non-serializable inputs are rejected before any FS write. */\n records: z.array(z.unknown()).min(1),\n /** When true, ensure the parent directory exists (mkdir -p). Default false. */\n createDirs: z.boolean().default(false),\n})\ntype WriteJsonlInput = z.infer<typeof writeJsonlInput>\n\nconst writeJsonlOutput = z.object({\n path: z.string(),\n written: z.number().int(),\n bytesAppended: z.number().int(),\n})\ntype WriteJsonlOutput = z.infer<typeof writeJsonlOutput>\n\nexport const fileWriteJsonl: BuiltinAction<WriteJsonlInput, WriteJsonlOutput> = {\n name: \"file.write_jsonl\",\n description: \"Append JSON records to a file as newline-delimited JSON (utf-8, scoped to allowed roots)\",\n inputSchema: writeJsonlInput,\n outputSchema: writeJsonlOutput,\n timeoutMs: 10_000,\n handler: async (input) => {\n const abs = resolveAllowed(input.path)\n\n // Pre-serialize EVERYTHING before opening the file so a bad\n // record can't leave a half-written file behind. Each record\n // becomes one JSON line; embedded newlines in strings are\n // escaped naturally by JSON.stringify.\n const lines: string[] = []\n for (const r of input.records) {\n try {\n lines.push(JSON.stringify(r))\n } catch (e: any) {\n throw new Error(`record ${lines.length} not JSON-serializable: ${e?.message || String(e)}`)\n }\n }\n const payload = lines.join(\"\\n\") + \"\\n\"\n\n if (input.createDirs) {\n mkdirSync(dirname(abs), { recursive: true })\n }\n appendFileSync(abs, payload, \"utf8\")\n return { path: abs, written: lines.length, bytesAppended: Buffer.byteLength(payload, \"utf8\") }\n },\n}\n","import { z } from \"zod\"\nimport type { BuiltinAction } from \"./types\"\n\n// --- Built-in HTTP actions ---\n//\n// http.fetch — typed GET, returns body+status+headers\n// http.post — typed POST with JSON body, same response shape\n//\n// Why bake these in when agents already have Bash + curl: the typed\n// shape lets workflows pipe response data into structured downstream\n// nodes without parsing curl output. Headers and status are\n// first-class. Errors are returned as a result, not thrown — so\n// workflow conditional nodes can branch on them.\n//\n// Body size is capped at 1MB to keep responses bounded; truncate is\n// reported back. Allowed schemes are http and https only — file:// /\n// data:// / etc. would let an agent read arbitrary local resources\n// through this action, which violates the \"agents talk over the\n// network\" boundary.\n\nconst MAX_BODY_BYTES = 1024 * 1024 // 1 MB\n\nconst HEADER_RECORD = z.record(z.string(), z.string())\n\nconst allowedSchemes = [\"http:\", \"https:\"] as const\n\nfunction assertAllowed(url: string): URL {\n let u: URL\n try { u = new URL(url) }\n catch { throw new Error(`invalid url: ${url}`) }\n if (!(allowedSchemes as readonly string[]).includes(u.protocol)) {\n throw new Error(`scheme not allowed (only http/https): ${u.protocol}`)\n }\n return u\n}\n\nconst fetchInput = z.object({\n url: z.string().min(1),\n headers: HEADER_RECORD.optional(),\n /** Per-call timeout in ms. Default 30s. Capped at the registry's\n * 60s ceiling regardless. */\n timeoutMs: z.number().int().min(1).max(60_000).default(30_000),\n})\ntype FetchInput = z.infer<typeof fetchInput>\n\nconst fetchOutput = z.object({\n status: z.number().int(),\n statusText: z.string(),\n headers: HEADER_RECORD,\n body: z.string(),\n truncated: z.boolean(),\n url: z.string(),\n})\ntype FetchOutput = z.infer<typeof fetchOutput>\n\nasync function readCappedText(res: Response): Promise<{ body: string; truncated: boolean }> {\n if (!res.body) return { body: \"\", truncated: false }\n const reader = res.body.getReader()\n const dec = new TextDecoder()\n let total = 0\n let body = \"\"\n let truncated = false\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n if (value) {\n total += value.length\n if (total > MAX_BODY_BYTES) {\n // Keep what we have, mark truncated, stop reading.\n body += dec.decode(value.slice(0, MAX_BODY_BYTES - (total - value.length)), { stream: false })\n truncated = true\n try { await reader.cancel() } catch { /* */ }\n break\n }\n body += dec.decode(value, { stream: true })\n }\n }\n body += dec.decode()\n return { body, truncated }\n}\n\nfunction headersToObject(h: Headers): Record<string, string> {\n const out: Record<string, string> = {}\n h.forEach((v, k) => { out[k] = v })\n return out\n}\n\nexport const httpFetch: BuiltinAction<FetchInput, FetchOutput> = {\n name: \"http.fetch\",\n description: \"GET a URL, return body + status + headers (1MB cap, http/https only)\",\n inputSchema: fetchInput,\n outputSchema: fetchOutput,\n timeoutMs: 35_000,\n handler: async (input) => {\n assertAllowed(input.url)\n const ctrl = new AbortController()\n const t = setTimeout(() => ctrl.abort(), input.timeoutMs)\n try {\n const res = await fetch(input.url, { method: \"GET\", headers: input.headers ?? {}, signal: ctrl.signal })\n const { body, truncated } = await readCappedText(res)\n return {\n status: res.status,\n statusText: res.statusText,\n headers: headersToObject(res.headers),\n body,\n truncated,\n url: res.url,\n }\n } finally {\n clearTimeout(t)\n }\n },\n}\n\nconst postInput = z.object({\n url: z.string().min(1),\n /** JSON body, serialized to string at request time. Caller passes\n * any JSON-serializable value here — strings, objects, arrays. */\n body: z.unknown(),\n headers: HEADER_RECORD.optional(),\n timeoutMs: z.number().int().min(1).max(60_000).default(30_000),\n})\ntype PostInput = z.infer<typeof postInput>\n\nexport const httpPost: BuiltinAction<PostInput, FetchOutput> = {\n name: \"http.post\",\n description: \"POST a JSON body to a URL, return body + status + headers (1MB cap, http/https only)\",\n inputSchema: postInput,\n outputSchema: fetchOutput,\n timeoutMs: 35_000,\n handler: async (input) => {\n assertAllowed(input.url)\n const ctrl = new AbortController()\n const t = setTimeout(() => ctrl.abort(), input.timeoutMs)\n try {\n const headers = { \"Content-Type\": \"application/json\", ...(input.headers ?? {}) }\n const res = await fetch(input.url, {\n method: \"POST\",\n headers,\n body: JSON.stringify(input.body ?? {}),\n signal: ctrl.signal,\n })\n const { body, truncated } = await readCappedText(res)\n return {\n status: res.status,\n statusText: res.statusText,\n headers: headersToObject(res.headers),\n body,\n truncated,\n url: res.url,\n }\n } finally {\n clearTimeout(t)\n }\n },\n}\n","import { z } from \"zod\"\nimport { getMesh } from \"@/a2a/mesh-instance\"\nimport type { BuiltinAction } from \"./types\"\n\n// --- mesh.delegate ---\n//\n// Send a task to a remote agentx peer (mesh node) and return the\n// peer's response text. Same wire as the legacy POST /mesh/task HTTP\n// route, but typed and callable directly from agents and workflows\n// without a Bash shell-out — exactly the \"mesh.delegate (peer call,\n// no shell required)\" line item from improvement plan #6.\n//\n// Why this matters even though POST /mesh/task already exists:\n// - Workflows can pipe the response into a typed downstream node.\n// - Agent-side, the call is one /api/actions/builtin POST instead\n// of \"shell out, parse JSON, hope you wrote the curl right\".\n// - The action interface advertises peer-name + agent-name shape\n// so authoring tools can validate before dispatch.\n\nconst meshDelegateInput = z.object({\n /** Mesh peer name as configured in mesh.peers[].name. */\n peer: z.string().min(1),\n /** Optional remote agent id; falls back to first agent on the peer. */\n agent: z.string().optional(),\n message: z.string().min(1),\n /** Per-call timeout. Default 90s; capped by the registry's 60s\n * ceiling unless the action declares a larger timeoutMs. */\n timeoutMs: z.number().int().min(1).max(600_000).default(90_000),\n /** Identity of the agent making the delegated call. Forwarded to\n * the receiving daemon for route-trace + (eventually) capability\n * validation. Optional during the log-warn rollout. */\n senderAgentId: z.string().optional(),\n /** Force a fresh session on the receiving agent. Defaults to TRUE\n * for cross-agent delegation — without this, a triage agent's\n * delegation reuses whatever conversation the worker pool last\n * served, leaking the previous visitor's context (run-3 / run-4\n * benchmark finding). Pass `false` only when you genuinely want\n * the worker to keep state across delegations. */\n freshSession: z.boolean().default(true),\n})\ntype MeshDelegateInput = z.infer<typeof meshDelegateInput>\n\nconst meshDelegateOutput = z.object({\n peer: z.string(),\n agent: z.string().nullable(),\n response: z.string(),\n})\ntype MeshDelegateOutput = z.infer<typeof meshDelegateOutput>\n\nexport const meshDelegate: BuiltinAction<MeshDelegateInput, MeshDelegateOutput> = {\n name: \"mesh.delegate\",\n description: \"Send a task to a remote mesh peer's agent and return the response text\",\n inputSchema: meshDelegateInput,\n outputSchema: meshDelegateOutput,\n // Allow the action's max well above the registry default so a\n // long peer task isn't capped at 60s.\n timeoutMs: 600_000,\n handler: async (input) => {\n const mesh = getMesh()\n if (!mesh) {\n throw new Error(\"mesh not enabled on this daemon (config.mesh.enabled = false)\")\n }\n const response = await mesh.sendTask(input.peer, input.message, input.agent, {\n timeoutMs: input.timeoutMs,\n senderAgentId: input.senderAgentId,\n freshSession: input.freshSession,\n })\n return {\n peer: input.peer,\n agent: input.agent ?? null,\n response,\n }\n },\n}\n","import type { A2AMesh } from \"./mesh\"\n\n// --- Singleton accessor for the live A2AMesh ---\n//\n// Mirrors src/agents/process-registry-instance.ts. The daemon\n// instantiates A2AMesh in its boot sequence and registers it here so\n// process-global consumers (built-in actions, mesh.delegate) can reach\n// it without changing every call site's signature. Setter is null-able\n// because mesh-disabled deployments still need a valid module.\n\nlet _mesh: A2AMesh | null = null\n\nexport function getMesh(): A2AMesh | null {\n return _mesh\n}\n\nexport function setMesh(m: A2AMesh | null): void {\n _mesh = m\n}\n\n/** Test-only — clears the reference between cases. */\nexport function _resetMeshForTesting(): void {\n _mesh = null\n}\n","import { z } from \"zod\"\nimport { lexicalSearch } from \"@/rag/lexical-index\"\nimport type { BuiltinAction } from \"./types\"\n\n// --- rag.lexical ---\n//\n// Improvement plan #7 — embedding-free retrieval-augmented context.\n// Looks up an agent's lexical (BM25) index built via `agentx rag add`\n// and returns the top hits with score + path + body excerpt. No\n// embedding API call, no key, deterministic.\n\nconst ragLexicalInput = z.object({\n /** Agent whose index to query. Each agent has its own index at\n * .agentx/rag/<agentId>/. */\n agentId: z.string().min(1),\n query: z.string().min(1),\n /** Top-k results. Default 5, hard cap 50. */\n k: z.number().int().min(1).max(50).default(5),\n})\ntype RagLexicalInput = z.infer<typeof ragLexicalInput>\n\nconst ragLexicalOutput = z.object({\n hits: z.array(z.object({\n id: z.string(),\n title: z.string(),\n path: z.string(),\n score: z.number(),\n snippet: z.string(),\n })),\n})\ntype RagLexicalOutput = z.infer<typeof ragLexicalOutput>\n\nexport const ragLexical: BuiltinAction<RagLexicalInput, RagLexicalOutput> = {\n name: \"rag.lexical\",\n description: \"BM25-style lexical search over an agent's pre-built index (no embeddings, deterministic)\",\n inputSchema: ragLexicalInput,\n outputSchema: ragLexicalOutput,\n timeoutMs: 5_000,\n handler: async (input) => {\n const hits = lexicalSearch(input.agentId, input.query, { k: input.k })\n return { hits }\n },\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync, statSync } from \"fs\"\nimport { resolve, basename, relative } from \"path\"\nimport fg from \"fast-glob\"\n// minisearch ships both CJS and ESM; tsup transpiles either way.\nimport MiniSearch from \"minisearch\"\n\n// --- Lexical RAG index per agent ---\n//\n// Improvement plan #7 — embedding-free retrieval-augmented context for\n// agents. BM25-style scoring via the minisearch library (~30KB pure\n// JS, no native deps). Each agent gets its own index at\n// `.agentx/rag/<agentId>/index.json`; `agentx rag add` builds it from\n// a glob, the rag.lexical built-in action queries it.\n//\n// Fields indexed: title (extracted from first H1 or filename) + body\n// (full file text). Title is boosted 2× at search time so a\n// well-titled doc beats a body-only mention. Path is stored as a\n// non-indexed field so query results can cite the source file.\n//\n// Why not use embeddings: zero new keys, deterministic results, fast\n// (sub-ms search even with hundreds of docs), works offline. The\n// trade is no semantic synonymy — but for the kinds of operator\n// docs / wiki entries / playbook lookups agents typically need,\n// keyword recall is enough. Embedding-backed mode is opt-in\n// future work.\n\nexport interface IndexedDoc {\n /** Stable id within an index — usually the workspace-relative path. */\n id: string\n title: string\n body: string\n /** Absolute path on disk. Stored, not indexed. */\n path: string\n /** ISO timestamp when this doc was indexed. */\n indexedAt: string\n}\n\nexport interface RagSearchHit {\n id: string\n title: string\n path: string\n score: number\n /** A short body excerpt around the highest-scoring term. Useful for\n * citation-style \"here's what we found\" responses. */\n snippet: string\n}\n\nconst FIELDS_INDEXED = [\"title\", \"body\"]\nconst FIELDS_STORED = [\"title\", \"body\", \"path\", \"indexedAt\"]\n\nfunction indexFilePath(agentId: string, baseDir: string = \".agentx/rag\"): string {\n return resolve(process.cwd(), baseDir, agentId, \"index.json\")\n}\n\nfunction newSearchEngine(): MiniSearch<IndexedDoc> {\n return new MiniSearch<IndexedDoc>({\n fields: FIELDS_INDEXED,\n storeFields: FIELDS_STORED,\n searchOptions: { boost: { title: 2 }, fuzzy: 0.2, prefix: true },\n })\n}\n\n/**\n * Read a markdown / text file and split into indexable fields. Title\n * comes from the first H1 line (`# ...`); falls back to the filename\n * stem when there isn't one. Body is the full text.\n */\nfunction fileToDoc(absPath: string, idBase: string): IndexedDoc {\n const text = readFileSync(absPath, \"utf8\")\n const h1Match = text.match(/^\\s*#\\s+(.+)$/m)\n const title = h1Match ? h1Match[1].trim() : basename(absPath).replace(/\\.[^.]+$/, \"\")\n return {\n id: idBase,\n title,\n body: text,\n path: absPath,\n indexedAt: new Date().toISOString(),\n }\n}\n\n/**\n * Build an index from one or more globs. Globs resolve from cwd. The\n * resulting index is persisted under .agentx/rag/<agentId>/index.json\n * and returned to the caller for synchronous use.\n */\nexport async function buildIndex(\n agentId: string,\n globs: string[],\n opts: { baseDir?: string; cwd?: string; verbose?: boolean } = {},\n): Promise<{ docs: number; path: string }> {\n const cwd = opts.cwd ?? process.cwd()\n const files = (await fg(globs, { cwd, absolute: true, dot: false }))\n .filter((p) => {\n try { return statSync(p).isFile() } catch { return false }\n })\n\n const ms = newSearchEngine()\n for (const abs of files) {\n const idBase = relative(cwd, abs)\n const doc = fileToDoc(abs, idBase)\n ms.add(doc)\n if (opts.verbose) process.stderr.write(`[rag] indexed ${idBase} (${doc.body.length} bytes)\\n`)\n }\n\n const out = indexFilePath(agentId, opts.baseDir)\n mkdirSync(resolve(out, \"..\"), { recursive: true })\n writeFileSync(out, JSON.stringify(ms.toJSON()), \"utf8\")\n return { docs: files.length, path: out }\n}\n\n/**\n * Load a previously-built index. Returns null when no index exists for\n * this agent (caller can fall back to \"no RAG\" gracefully). Loading is\n * a small JSON parse + minisearch deserialize — sub-millisecond on\n * typical operator-doc indices.\n */\nexport function loadIndex(\n agentId: string,\n opts: { baseDir?: string } = {},\n): MiniSearch<IndexedDoc> | null {\n const path = indexFilePath(agentId, opts.baseDir)\n if (!existsSync(path)) return null\n try {\n const raw = readFileSync(path, \"utf8\")\n return MiniSearch.loadJSON<IndexedDoc>(raw, {\n fields: FIELDS_INDEXED,\n storeFields: FIELDS_STORED,\n searchOptions: { boost: { title: 2 }, fuzzy: 0.2, prefix: true },\n })\n } catch (e: any) {\n process.stderr.write(`[rag] failed to load ${path}: ${e?.message || String(e)}\\n`)\n return null\n }\n}\n\nconst SNIPPET_RADIUS = 80\nconst SNIPPET_MAX = SNIPPET_RADIUS * 2 + 60\n\n/** Extract a snippet around the FIRST occurrence of any of `terms` in\n * `body`. Returns the head of the body when no term hits. */\nfunction makeSnippet(body: string, terms: string[]): string {\n const lc = body.toLowerCase()\n let bestPos = -1\n for (const t of terms) {\n const i = lc.indexOf(t.toLowerCase())\n if (i >= 0 && (bestPos === -1 || i < bestPos)) bestPos = i\n }\n if (bestPos === -1) {\n return body.slice(0, SNIPPET_MAX).replace(/\\s+/g, \" \").trim()\n }\n const start = Math.max(0, bestPos - SNIPPET_RADIUS)\n const end = Math.min(body.length, bestPos + SNIPPET_RADIUS)\n const slice = body.slice(start, end).replace(/\\s+/g, \" \").trim()\n return (start > 0 ? \"…\" : \"\") + slice + (end < body.length ? \"…\" : \"\")\n}\n\nexport interface SearchOpts {\n /** How many top hits to return. Default 5, capped at 50. */\n k?: number\n baseDir?: string\n}\n\n/**\n * Lexical query against an agent's index. Returns at most `k` results,\n * each with a score, the title, the source path, and a snippet around\n * the matched term. Empty array when no index exists or no hits.\n */\nexport function lexicalSearch(\n agentId: string,\n query: string,\n opts: SearchOpts = {},\n): RagSearchHit[] {\n const ms = loadIndex(agentId, { baseDir: opts.baseDir })\n if (!ms) return []\n const k = Math.max(1, Math.min(50, opts.k ?? 5))\n const raw = ms.search(query) as unknown as Array<{\n id: string\n score: number\n title: string\n body: string\n path: string\n terms: string[]\n }>\n return raw.slice(0, k).map((r) => ({\n id: r.id,\n title: r.title,\n path: r.path,\n score: r.score,\n snippet: makeSnippet(r.body || \"\", r.terms || []),\n }))\n}\n\n/** List metadata about an agent's index without loading the full thing. */\nexport function indexInfo(agentId: string, opts: { baseDir?: string } = {}): {\n exists: boolean\n path: string\n docs: number\n} {\n const path = indexFilePath(agentId, opts.baseDir)\n if (!existsSync(path)) return { exists: false, path, docs: 0 }\n try {\n const raw = JSON.parse(readFileSync(path, \"utf8\"))\n // minisearch v7 puts the stored fields under `storedFields` (no\n // leading underscore), keyed by internal numeric doc id. Earlier\n // versions used `_storedFields`. Honour both for robustness across\n // minor minisearch upgrades.\n const sf = raw?.storedFields ?? raw?._storedFields\n if (typeof raw?.documentCount === \"number\") return { exists: true, path, docs: raw.documentCount }\n const docs = sf && typeof sf === \"object\" ? Object.keys(sf).length : 0\n return { exists: true, path, docs }\n } catch {\n return { exists: true, path, docs: 0 }\n }\n}\n","// --- Built-in actions barrel ---\n//\n// Importing this module registers every shipped built-in into the\n// process-global registry. The daemon imports it once at startup so\n// callers (HTTP routes, CLI, workflows) can look actions up by name.\n//\n// To add a new built-in: define it in a sibling file, import here,\n// pass it to registerBuiltin(). Keep the imports alphabetical for\n// human review.\n\nimport { registerBuiltin, _resetBuiltinsForTesting as _registryReset } from \"./registry\"\nimport { agentCall } from \"./agent\"\nimport { channelAssign, channelCreateIssue, channelLabel, channelReply } from \"./channel\"\nimport { extractStructured } from \"./extract\"\nimport { fileReadLines, fileWriteJsonl } from \"./file\"\nimport { httpFetch, httpPost } from \"./http\"\nimport { meshDelegate } from \"./mesh\"\nimport { ragLexical } from \"./rag\"\n\n/**\n * Register every shipped built-in. Idempotent — re-registering the\n * same name overwrites with the latest handler (registerBuiltin's\n * own contract), so calling this multiple times is safe and matches\n * the in-memory registry's current state.\n */\nexport function registerAllBuiltins(): void {\n registerBuiltin(agentCall)\n registerBuiltin(channelAssign)\n registerBuiltin(channelCreateIssue)\n registerBuiltin(channelLabel)\n registerBuiltin(channelReply)\n registerBuiltin(extractStructured)\n registerBuiltin(fileReadLines)\n registerBuiltin(fileWriteJsonl)\n registerBuiltin(httpFetch)\n registerBuiltin(httpPost)\n registerBuiltin(meshDelegate)\n registerBuiltin(ragLexical)\n}\n\n/** Test-only — clears the registry. Re-call registerAllBuiltins to repopulate. */\nexport function _resetBuiltinsForTesting(): void {\n _registryReset()\n}\n\nexport { getBuiltin, listBuiltins, runBuiltin } from \"./registry\"\nexport type { BuiltinAction, BuiltinActionMetadata } from \"./types\"\n"],"mappings":"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","names":["_registry","NAME_PATTERN","registerBuiltin","action","getBuiltin","name","listBuiltins","out","a","b","_resetBuiltinsForTesting","DEFAULT_TIMEOUT_MS","runBuiltin","rawInput","input","timeoutMs","handlerPromise","timeoutPromise","_","reject","output","parsed","z","_registry","getAgentRegistry","setAgentRegistry","r","agentCallInput","z","agentCallOutput","agentCall","input","registry","getAgentRegistry","chatId","started","response","z","channelReplyInput","z","channelReplyOutput","channelReply","input","router","getMessageRouter","idempotencyKey","messageId","channelLabelInput","channelLabelOutput","channelLabel","adapter","labels","channelAssignInput","channelAssignOutput","channelAssign","ids","channelCreateIssueInput","channelCreateIssueOutput","channelCreateIssue","created","related","z","extractInput","extractOutput","ANTHROPIC_API","ANTHROPIC_VERSION","extractStructured","input","apiKey","requestBody","ctrl","t","res","errBody","body","blocks","toolUse","usage","z","existsSync","readFileSync","appendFileSync","mkdirSync","statSync","resolve","dirname","isAbsolute","MAX_FILE_BYTES","resolveAllowed","input","abs","roots","r","root","readLinesInput","readLinesOutput","fileReadLines","stat","all","totalLines","lines","truncated","writeJsonlInput","writeJsonlOutput","fileWriteJsonl","e","payload","z","MAX_BODY_BYTES","HEADER_RECORD","allowedSchemes","assertAllowed","url","u","fetchInput","fetchOutput","readCappedText","res","reader","dec","total","body","truncated","done","value","headersToObject","h","out","v","k","httpFetch","input","ctrl","postInput","httpPost","headers","z","_mesh","getMesh","setMesh","m","meshDelegateInput","z","meshDelegateOutput","meshDelegate","input","mesh","getMesh","response","z","existsSync","mkdirSync","readFileSync","writeFileSync","statSync","resolve","basename","relative","fg","MiniSearch","FIELDS_INDEXED","FIELDS_STORED","indexFilePath","agentId","baseDir","newSearchEngine","fileToDoc","absPath","idBase","text","h1Match","title","buildIndex","globs","opts","cwd","files","p","ms","abs","doc","out","loadIndex","path","raw","e","SNIPPET_RADIUS","SNIPPET_MAX","makeSnippet","body","terms","lc","bestPos","t","i","start","end","slice","lexicalSearch","query","k","r","indexInfo","sf","docs","ragLexicalInput","z","ragLexicalOutput","ragLexical","input","lexicalSearch","registerAllBuiltins","registerBuiltin","agentCall","channelAssign","channelCreateIssue","channelLabel","channelReply","extractStructured","fileReadLines","fileWriteJsonl","httpFetch","httpPost","meshDelegate","ragLexical","_resetBuiltinsForTesting"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{a as _,b as P,c as T,d as G}from"./chunk-JTJIPNXY.js";import{b as Q}from"./chunk-64P4QHSZ.js";import{
|
|
1
|
+
import{a as _,b as P,c as T,d as G}from"./chunk-JTJIPNXY.js";import{b as Q}from"./chunk-64P4QHSZ.js";import{m as X}from"./chunk-FDWOECJY.js";import{c as M,d as L}from"./chunk-QOYAX2FT.js";var A={version:2,levels:[{id:"category",description:"Top-level kind of work. Closed set \u2014 pick the closest fit.",axes:[{name:"kind",type:"enum",values:["code","ops","support","admin","knowledge","social","system"],description:"Which category this work belongs in."}]},{id:"verb",description:"Specific intent \u2014 verb-level only, NOT client/project-bound.",axes:[{name:"name",type:"free",description:"Lower-kebab dot-namespaced verb. Examples: review.merge-request, fix.bug, investigate.error, deploy.staging, deploy.production, rollback.release, spec.feature, triage.issue, document.feature, chat.greeting, chat.support-request, schedule.add, config.change, ingest.contact, transcribe.audio, brief.daily, summarize.thread, plan.work."}]}],leafInput:{name:"input",type:"enum",values:["telegram","whatsapp","slack","discord","gitlab-mr","gitlab-issue","github-issue","github-pr","cron","webhook","mesh","http"],description:"Where the message entered the system."},leafOutput:{name:"output",type:"free",description:"One short sentence describing what the agent is expected to produce. Generic \u2014 refers to the verb's outcome, not the specific client/project (those are on the event metadata already)."}},F=[{category:"code",verb:"review.merge-request",description:"Review a GitLab MR or GitHub PR"},{category:"code",verb:"review.code-change",description:"General code review (snippet, diff)"},{category:"code",verb:"fix.bug",description:"Fix a reported bug"},{category:"code",verb:"implement.feature",description:"Build a new feature"},{category:"code",verb:"investigate.error",description:"Investigate a failing test, exception, pipeline"},{category:"code",verb:"refactor.code",description:"Restructure existing code without behaviour change"},{category:"code",verb:"spec.feature",description:"Write or update a feature spec / RFC"},{category:"code",verb:"triage.issue",description:"Classify, label, or assign an issue"},{category:"code",verb:"answer.code-question",description:"Answer a code-related question"},{category:"ops",verb:"deploy.staging",description:"Deploy to a staging/preview environment"},{category:"ops",verb:"deploy.production",description:"Deploy to production"},{category:"ops",verb:"rollback.release",description:"Roll back a release"},{category:"ops",verb:"investigate.incident",description:"Investigate a production incident"},{category:"ops",verb:"monitor.system",description:"Check system status / metrics"},{category:"ops",verb:"rotate.credential",description:"Rotate a token, key, certificate"},{category:"ops",verb:"audit.security",description:"Review for security issues"},{category:"support",verb:"chat.greeting",description:"A casual hello, no actionable request"},{category:"support",verb:"chat.support-request",description:"End-user / customer asking for help"},{category:"support",verb:"chat.casual",description:"Informal back-and-forth chat"},{category:"support",verb:"answer.question",description:"Answer an open-ended question"},{category:"support",verb:"route.request",description:"Forward a request to the right agent"},{category:"admin",verb:"config.change",description:"Change agentx.json / environment / config"},{category:"admin",verb:"schedule.add",description:"Add a new cron / scheduled task"},{category:"admin",verb:"schedule.remove",description:"Remove or disable a schedule"},{category:"admin",verb:"token.create",description:"Mint a scoped API token"},{category:"admin",verb:"agent.add",description:"Configure a new agent"},{category:"admin",verb:"channel.add",description:"Wire up a new channel"},{category:"knowledge",verb:"document.feature",description:"Write or update documentation"},{category:"knowledge",verb:"summarize.thread",description:"Summarize a long conversation/thread"},{category:"knowledge",verb:"research.topic",description:"Investigate / gather info on a topic"},{category:"knowledge",verb:"wiki.absorb",description:"Roll raw entries into typed wiki articles"},{category:"social",verb:"brief.daily",description:"Compose a daily brief / digest"},{category:"social",verb:"draft.post",description:"Draft a marketing post / announcement"},{category:"social",verb:"report.weekly",description:"Compose a weekly status report"},{category:"system",verb:"classify.intent",description:"Internal: graph-classifier sub-call"}];import{readFileSync as D,writeFileSync as J,appendFileSync as re,existsSync as I,mkdirSync as q,renameSync as ie}from"fs";import{resolve as E,dirname as ee}from"path";import{createHash as ne}from"crypto";var U=class{baseDir;log;constructor(e={}){this.baseDir=e.baseDir??E(process.cwd(),".agentx/graph"),this.log=e.log??console.error.bind(console,"[graph]"),q(this.baseDir,{recursive:!0})}schemaPath(){return E(this.baseDir,"schema.json")}nodesPath(){return E(this.baseDir,"nodes.json")}indexPath(){return E(this.baseDir,"index.json")}classificationsPath(){return E(this.baseDir,"classifications.jsonl")}loadSchema(){let e=this.schemaPath();if(!I(e))return this.saveSchema(A),this.log("seeded starter schema at",e),A;let t=D(e,"utf-8"),s=_.safeParse(JSON.parse(t));if(!s.success)throw new Error(`Invalid ${e}: ${s.error.issues.map(r=>r.message).join("; ")}`);if((s.data.version??1)<(A.version??2)){let r=e.replace(/\.json$/,`.v${s.data.version??1}.bak.json`);try{J(r,t),this.log(`migrated graph schema v${s.data.version??1} -> v${A.version}; old saved at ${r}`)}catch(o){this.log(`could not back up old schema: ${o?.message??o}`)}this.saveSchema(A);let n=this.nodesPath();if(I(n)){let o=n.replace(/\.json$/,".v1.bak.json");try{J(o,D(n,"utf-8")),this.log(`archived v1 nodes.json -> ${o}`)}catch(i){this.log(`could not back up old nodes: ${i?.message??i}`)}try{let i=Z();this.saveNodes(i)}catch(i){this.log(`could not seed v2 nodes: ${i?.message??i}`)}}return A}return s.data}saveSchema(e){let t=_.safeParse(e);if(!t.success)throw new Error(`Refusing to save invalid schema: ${t.error.issues.map(s=>s.message).join("; ")}`);B(this.schemaPath(),t.data)}loadNodes(){let e=this.nodesPath();if(!I(e)){let r=Z();return this.saveNodes(r),r}let t=D(e,"utf-8"),s=T.safeParse(JSON.parse(t));if(!s.success)throw new Error(`Invalid ${e}: ${s.error.issues.map(r=>r.message).join("; ")}`);return s.data}saveNodes(e){let t=T.safeParse(e);if(!t.success)throw new Error(`Refusing to save invalid nodes file: ${t.error.issues.map(s=>s.message).join("; ")}`);B(this.nodesPath(),t.data)}validateNode(e,t,s){let r=t.levels.find(i=>i.id===e.level);if(!r)throw new Error(`Unknown level: "${e.level}"`);let n=r.axes.filter(i=>!i.optional).filter(i=>!(i.name in e.axes));if(n.length)throw new Error(`Node ${e.id} (${e.level}) missing required axes: ${n.map(i=>i.name).join(", ")}`);for(let i of r.axes){let a=e.axes[i.name];if(a!=null){if(i.type==="enum"&&i.values&&!i.values.includes(a))throw new Error(`Node ${e.id}: axis ${i.name}="${a}" not in enum ${JSON.stringify(i.values)}`);if(i.type==="ref"){if(!s.some(c=>c.id===a))throw new Error(`Node ${e.id}: axis ${i.name}="${a}" refers to unknown node`);if(i.refLevel){let c=s.find(h=>h.id===a);if(c.level!==i.refLevel)throw new Error(`Node ${e.id}: axis ${i.name} expected level "${i.refLevel}" but got "${c.level}"`)}}}}let o=t.levels.findIndex(i=>i.id===e.level);if(o===0){if(e.parentId!==null)throw new Error(`Root-level node ${e.id} must have parentId: null`)}else{if(!e.parentId)throw new Error(`Non-root node ${e.id} must have a parentId`);let i=s.find(c=>c.id===e.parentId);if(!i)throw new Error(`Node ${e.id}: parent "${e.parentId}" not found`);let a=t.levels.findIndex(c=>c.id===i.level);if(a<0||a>=o)throw new Error(`Node ${e.id} at level "${e.level}" has parent at level "${i.level}" \u2014 parent must be at a higher level`)}}commitNodesAlongPath(e,t,s,r){let n=[],o=[],i=new Date().toISOString();for(let a=0;a<e.length;a++){let c=e[a],h=this.loadNodes().nodes;if(h.find(v=>v.id===c)){o.push(c);continue}let d=0;for(let v=a-1;v>=0;v--){let w=e[v],N=h.find(k=>k.id===w)||n.find(k=>k.id===w);if(N){d=s.levels.findIndex(k=>k.id===N.level)+1;break}}let u=t[c]??{},l=null;for(let v=d;v<s.levels.length;v++){let w=s.levels[v];if(w.axes.filter(k=>!k.optional).filter(k=>!(k.name in u)).length===0){l=w.id,d=v+1;break}}if(!l&&d<s.levels.length&&(l=s.levels[d].id,d++),!l)throw new Error(`Can't place node ${c} \u2014 no schema level left (cursor=${d}, levels=${s.levels.length})`);let p=null,m=s.levels.findIndex(v=>v.id===l);for(let v=a-1;v>=0;v--){let w=e[v],N=h.find(C=>C.id===w)||n.find(C=>C.id===w);if(!N)continue;let k=s.levels.findIndex(C=>C.id===N.level);if(k>=0&&k<m){p=w;break}}let f={id:c,level:l,parentId:p,axes:u,createdAt:i,createdBy:r};this.addNode(f),n.push(f)}return{added:n,skipped:o}}addNode(e){let t=this.loadSchema(),s=this.loadNodes();if(s.nodes.some(r=>r.id===e.id))throw new Error(`Node id already exists: ${e.id}`);return this.validateNode(e,t,[...s.nodes,e]),s.nodes.push(e),this.saveNodes(s),e}appendClassification(e){let t=P.safeParse(e);if(!t.success){let n=t.error.issues.map(o=>`${o.path.join(".")}: ${o.message}`).join(" \xB7 ");return this.log(`skipped invalid classification \u2014 ${n} \xB7`,`path=${JSON.stringify(e.path)}`,`axes-keys=${JSON.stringify(Object.keys(e.proposedAxes||{}))}`),!1}let s=JSON.stringify(t.data)+`
|
|
2
2
|
`,r=this.classificationsPath();return I(r)||q(ee(r),{recursive:!0}),re(r,s),!0}listPendingClassifications(e=200){return this.listByStatus("pending",e)}listByStatus(e,t=200){return this.readAllCollapsed().filter(r=>r.status===e).slice(0,t)}readAllCollapsed(){let e=this.classificationsPath();if(!I(e))return[];let s=D(e,"utf-8").split(`
|
|
3
3
|
`).filter(Boolean),r=new Map;for(let n of s)try{let o=P.safeParse(JSON.parse(n));if(!o.success)continue;r.set(o.data.msgHash,o.data)}catch{}return Array.from(r.values()).sort((n,o)=>n.ts<o.ts?1:-1)}updateClassificationStatus(e,t){let r=this.readAllCollapsed().find(o=>o.msgHash===e);if(!r)return null;let n={...r,status:t.status,ts:new Date().toISOString()};if(t.reviewer||t.reviewReason){let o=` \xB7 ${t.reviewer?`reviewer=${t.reviewer}`:""}${t.reviewReason?` \xB7 ${t.reviewReason}`:""}`;n.preview=((r.preview||"")+o).slice(0,500)}return this.appendClassification(n),n}readRecentClassifications(e=50){let t=this.classificationsPath();if(!I(t))return[];let r=D(t,"utf-8").split(`
|
|
4
4
|
`).filter(Boolean),n=[];for(let o=r.length-1;o>=0&&n.length<e;o--)try{let i=P.safeParse(JSON.parse(r[o]));i.success&&n.push(i.data)}catch{}return n}fingerprint(e){let s=[e.text.toLowerCase().replace(/\s+/g," ").trim(),e.channel??"",e.sender??""].join("");return ne("sha256").update(s).digest("hex").slice(0,32)}loadIndex(){let e=this.indexPath();if(!I(e))return{version:1,entries:{}};let t=D(e,"utf-8"),s=G.safeParse(JSON.parse(t));if(!s.success)throw new Error(`Invalid ${e}: ${s.error.issues.map(r=>r.message).join("; ")}`);return s.data}saveIndex(e){let t=G.safeParse(e);if(!t.success)throw new Error(`Refusing to save invalid index: ${t.error.issues.map(s=>s.message).join("; ")}`);B(this.indexPath(),t.data)}getFingerprint(e){return this.loadIndex().entries[e]}setFingerprint(e,t){let s=this.loadIndex();s.entries[e]={...t,fingerprint:e,updatedAt:new Date().toISOString()},this.saveIndex(s)}updateNodeAxes(e,t){let s=this.loadSchema(),r=this.loadNodes(),n=r.nodes.find(i=>i.id===e);if(!n)throw new Error(`Node not found: ${e}`);let o={...n,axes:t};return this.validateNode(o,s,r.nodes.map(i=>i.id===e?o:i)),r.nodes=r.nodes.map(i=>i.id===e?o:i),this.saveNodes(r),o}deleteNode(e){let t=this.loadNodes(),s=t.nodes.find(n=>n.parentId===e);if(s)throw new Error(`Cannot delete "${e}" \u2014 child node "${s.id}" still points to it`);let r=t.nodes.find(n=>Object.values(n.axes).some(o=>o===e));if(r)throw new Error(`Cannot delete "${e}" \u2014 node "${r.id}" references it via an axis`);t.nodes=t.nodes.filter(n=>n.id!==e),this.saveNodes(t)}approveClassification(e){if(this.getFingerprint(e.msgHash))return;let t=this.loadSchema(),s=new Set(this.loadNodes().nodes.map(r=>r.id));for(let r=0;r<e.path.length;r++){let n=e.path[r];if(s.has(n))continue;let o=t.levels[r]?.id;if(!o)break;let i=e.proposedAxes?.[n]??{},a=r===0?null:e.path[r-1];this.addNode({id:n,level:o,parentId:a,axes:i,createdAt:new Date().toISOString(),createdBy:e.agentId}),s.add(n)}this.setFingerprint(e.msgHash,{path:e.path,leaf:e.leaf}),this.appendClassification({...e,status:"approved",ts:new Date().toISOString()})}rejectClassification(e){this.appendClassification({...e,status:"rejected",ts:new Date().toISOString()})}};function B(g,e){q(ee(g),{recursive:!0});let t=`${g}.tmp-${process.pid}`;J(t,JSON.stringify(e,null,2)),ie(t,g)}function Z(){let g=new Date().toISOString(),e=[],t=new Set;for(let s of F)t.has(s.category)||(e.push({id:s.category,level:"category",parentId:null,axes:{kind:s.category},createdAt:g,createdBy:"starter"}),t.add(s.category));for(let s of F)e.push({id:s.verb,level:"verb",parentId:s.category,axes:{name:s.verb,...s.description?{description:s.description}:{}},createdAt:g,createdBy:"starter"});return{version:1,nodes:e}}import{createHash as oe}from"crypto";var H=class{store;daemonUrl;token;draftAgent;autoApprove;autoApproveStructure;classifierModel;classifierProviderName;providerInstance;log;constructor(e){this.store=e.store,this.daemonUrl=e.daemonUrl.replace(/\/+$/,""),this.token=e.token,this.draftAgent=e.draftAgent,this.autoApprove=e.autoApproveConfidence??1,this.autoApproveStructure=e.autoApproveStructure??"extend-leaves",this.classifierModel=e.classifierModel??"claude-haiku-4-5-20251001",this.classifierProviderName=e.classifierProvider??"claude-code",this.log=e.log??console.error.bind(console,"[classifier]")}getProvider(){return this.providerInstance||(this.providerInstance=X(this.classifierProviderName)),this.providerInstance}async classify(e){let t=this.store.fingerprint({text:e.text,channel:e.channel,sender:e.sender}),s=this.store.getFingerprint(t);if(s)return this.store.appendClassification({ts:new Date().toISOString(),msgHash:t,agentId:e.agentId,channel:e.channel,sender:e.sender,path:s.path,proposedAxes:{},leaf:s.leaf,source:"cache",status:"approved",preview:e.text.slice(0,200)}),{path:s.path,pathId:z(s.path),pathLabel:V(s.path,this.store.loadNodes().nodes),axes:{},leaf:s.leaf,source:"cache",status:"approved"};let r=this.store.loadSchema(),n=this.store.loadNodes().nodes,o=await this.proposePath(e,r,n).catch(f=>(this.log("LLM proposal failed:",f?.message||f),null));if(!o)return null;let{path:i,proposedAxes:a,confidence:c,leaf:h}=o;if(i.length===0)return null;let b={ts:new Date().toISOString(),msgHash:t,agentId:e.agentId,channel:e.channel,sender:e.sender,path:i,proposedAxes:a,leaf:h,source:"llm",status:"pending",confidence:c,preview:e.text.slice(0,200)},d=new Set(n.map(f=>f.id)),u=i.map((f,v)=>d.has(f)?-1:v).filter(f=>f>=0),l=!1;if(this.autoApproveStructure==="any")l=!0;else if(this.autoApproveStructure==="extend-leaves"){let f=u.length===0,v=u.length===1&&u[0]===i.length-1;l=f||v}let p=c!==void 0&&c>=this.autoApprove,m="pending";if(l||p)try{this.commitNewNodes(i,a,r,n,e.sender),this.store.setFingerprint(t,{path:i,leaf:h}),m="approved"}catch(f){this.log("auto-approve failed \u2014 staying pending \xB7",`path=${JSON.stringify(i)}`,`reason=${(f?.message||f).toString().slice(0,200)}`)}return b.status=m,this.store.appendClassification(b),{path:i,pathId:z(i),pathLabel:V(i,this.store.loadNodes().nodes),axes:a,leaf:h,source:"llm",status:m,confidence:c}}async proposePath(e,t,s){let r=s.map(l=>({id:l.id,level:l.level,parentId:l.parentId,axes:l.axes})),n=["You are the intent classifier for AgentX. You answer ONE question:",'"what kind of work does this message describe?" \u2014 verb-level only.',"","IMPORTANT \u2014 what NOT to encode in the path:","- Client / company / project / team names. Those are already on the event"," metadata (project, channel, agentId). Embedding them in the path causes"," duplicate nodes (one per client) for the same verb.","- The specific subject (issue number, file name, person name). Same reason.","- The agent's name or role. Pick the verb the *requester* intended.","","SCHEMA (fixed levels \u2014 pick one node per level):","```json",JSON.stringify(t,null,2),"```","","EXISTING NODES (prefer reusing these; only invent a new node when no","existing one fits):","```json",JSON.stringify(r,null,2),"```","","MESSAGE:","```",e.text.slice(0,2e3),"```",`channel: ${e.channel??"?"}`,`sender: ${e.sender??"?"}`,"","TASK:","1. Classify into 'category' (closed enum): code, ops, support, admin,"," knowledge, social, system. Pick the closest fit.","2. Pick or propose a 'verb' node. Verb ids are dot-namespaced lower-kebab,",' e.g. "review.merge-request", "deploy.staging", "investigate.error",',' "chat.greeting", "fix.bug". Reuse an existing verb when the message is'," the same kind of work as something already classified, even when the"," client / project / subject differs.","","Examples (right vs wrong):",'- "Please review MR #957 on mtgl/system" \u2192 ["code", "review.merge-request"]',' NOT ["business", "noqta", "mtgl-v2", "review-mr-957-system"]','- "Deploy ksi-v2 to staging please" \u2192 ["ops", "deploy.staging"]',' NOT ["business", "noqta", "ksi-v2", "deploy-ksi-v2-to-staging"]','- "Hello Atlas" \u2192 ["support", "chat.greeting"]',"","NODE ID RULES (strict \u2014 invalid ids get dropped):","- lowercase-kebab + dots only: [a-z0-9][a-z0-9._-]*","- no spaces, no uppercase, no Arabic/other non-Latin",'- verb ids should use a "category.specific" or "verb.modifier" shape',"","Return ONE JSON object on one line, no prose, no fences:",' { "path": string[], "proposedAxes": { [nodeId]: { [axisName]: string } }, "leaf": { "input"?: string, "output"?: string }, "confidence": number }',"confidence in [0,1]. Prefer low confidence over guessing."].join(`
|
|
@@ -105,4 +105,4 @@ We use GitLab for version control.
|
|
|
105
105
|
There are ${t.length} unprocessed entries. Read each, understand what it means, and create or update wiki articles.
|
|
106
106
|
|
|
107
107
|
${s}`}walkDir(e,t){if(x(e))for(let s of O(e)){let r=de(e,s);le(r).isDirectory()?this.walkDir(r,t):t(r)}}};import{resolve as K}from"path";import{existsSync as he,readdirSync as ge,mkdirSync as ue}from"fs";var se=class{baseDir;agentsDir;mode;sharedStore;agentStores=new Map;log;constructor(e=K(process.cwd(),".agentx/wiki"),t=console.error.bind(console,"[wiki-hub]"),s="graph"){this.baseDir=e,this.agentsDir=K(e,"agents"),this.mode=s,this.log=t,ue(this.agentsDir,{recursive:!0}),this.sharedStore=new R(e,t)}getMode(){return this.mode}getAgentWiki(e){let t=`${e}:${this.mode}`;if(this.agentStores.has(t))return this.agentStores.get(t);let s=K(this.agentsDir,e,this.mode),r=new R(s,this.log);return this.agentStores.set(t,r),r}getSharedStore(){return this.sharedStore}listAgents(){let e=new Set,t=this.sharedStore.listEntries();for(let s of t)e.add(s.agentId);if(he(this.agentsDir))for(let s of ge(this.agentsDir))!s.startsWith("_")&&!s.startsWith(".")&&e.add(s);return[...e].sort()}getAgentEntries(e){return this.sharedStore.listEntries({agentId:e})}getUnabsorbedEntries(e){let t=this.getAgentWiki(e),s=this.getAgentEntries(e),r=new Set,n=t.rebuildIndex();for(let o of n.articles)if(o.sources)for(let i of o.sources)r.add(i);return s.filter(o=>!r.has(o.id))}summary(){return this.listAgents().map(t=>{let s=this.getAgentEntries(t),n=this.getAgentWiki(t).rebuildIndex(),o=this.getUnabsorbedEntries(t);return{agentId:t,totalEntries:s.length,totalArticles:n.articles.length,unabsorbed:o.length,articles:n.articles}})}};export{A as a,U as b,H as c,V as d,R as e,se as f};
|
|
108
|
-
//# sourceMappingURL=chunk-
|
|
108
|
+
//# sourceMappingURL=chunk-BFXONUUN.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{d as m,e as $}from"./chunk-JXWAGMI2.js";import{readFileSync as S,writeFileSync as x,existsSync as b}from"fs";import{resolve as f}from"path";function P(r){if(r)return f(r);let e=[f(process.cwd(),"agentx.json"),f(process.cwd(),".agentx/config.json")];for(let n of e)if(b(n))return n;return e[0]}function w(r){return JSON.parse(JSON.stringify(r))}async function v(r){try{let e=await fetch(`${r.replace(/\/$/,"")}/reload`,{method:"POST",signal:AbortSignal.timeout(3e3)});return e.ok?{ok:!0}:{ok:!1,reason:`HTTP ${e.status}`}}catch(e){return{ok:!1,reason:e?.cause?.code||e?.message||"unreachable"}}}async function T(r,e={}){let{validate:n=!0,dryRun:t=!1,reload:s=!0,configPath:u,daemonUrl:c}=e,o=P(u);if(!b(o))return{success:!1,path:o,error:`Config not found at ${o}. Run \`agentx init\` first.`};let d;try{d=S(o,"utf-8")}catch(a){return{success:!1,path:o,error:`Cannot read ${o}: ${a.message}`}}let g;try{g=JSON.parse(d)}catch(a){return{success:!1,path:o,error:`Invalid JSON in ${o}: ${a.message}`}}let i=w(g);try{await r(i)}catch(a){return{success:!1,path:o,error:`Mutator threw: ${a.message}`}}if(n){let a=$(i),l=m.safeParse(a);if(!l.success){let k=l.error.issues.map(y=>` ${y.path.join(".")||"<root>"}: ${y.message}`).join(`
|
|
2
2
|
`);return{success:!1,path:o,error:`Validation failed:
|
|
3
3
|
${k}`,after:i}}}if(t)return{success:!0,path:o,after:i,dryRun:!0};try{x(o,JSON.stringify(i,null,2)+`
|
|
4
4
|
`)}catch(a){return{success:!1,path:o,error:`Write failed: ${a.message}`,after:i}}let p=!1,h;if(s){let a=c||O(i),l=await v(a);l.ok?p=!0:h=l.reason}return{success:!0,path:o,after:i,reloaded:p,reloadSkipped:h}}function O(r){let e=r?.node?.bind;if(!e)return"http://127.0.0.1:18800";let[n,t]=e.split(":");return`http://${n==="0.0.0.0"||n==="::"?"127.0.0.1":n}:${t}`}function J(r,e,n){let t=e.split("."),s=r;for(let u=0;u<t.length-1;u++){let c=t[u];(s[c]===void 0||s[c]===null)&&(s[c]={}),s=s[c]}s[t[t.length-1]]=n}function N(r,e){let n=e.split("."),t=r;for(let s of n){if(t==null)return;t=t[s]}return t}function j(r,e){let n=e.split("."),t=r;for(let s=0;s<n.length-1;s++){if(t==null)return;t=t[n[s]]}t!=null&&delete t[n[n.length-1]]}export{T as a,J as b,N as c,j as d};
|
|
5
|
-
//# sourceMappingURL=chunk-
|
|
5
|
+
//# sourceMappingURL=chunk-FDMWOPEL.js.map
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import{a as N}from"./chunk-VJUTQAPJ.js";import{existsSync as te,readFileSync as ie,writeFileSync as ue,mkdirSync as de}from"fs";import S from"path";import ae from"os";import J from"chalk";import I from"prompts";var Q=S.join(ae.homedir(),".agentx"),Z=S.join(Q,"auth.json");function E(){if(!te(Z))return null;try{let a=JSON.parse(ie(Z,"utf8"));return a.provider&&a.authType&&a.token&&a.model?a:null}catch{return null}}function me(a){te(Q)||de(Q,{recursive:!0}),ue(Z,JSON.stringify(a,null,2),"utf8")}function F(a){if(a?.trim()){let p=a.startsWith("sk-ant-oat")?"oauth":"api-key";return{token:a.trim(),authType:p}}let e=process.env.ANTHROPIC_OAUTH_TOKEN;if(e?.trim())return{token:e.trim(),authType:"oauth"};let t=process.env.CLAUDE_CODE_OAUTH_TOKEN;if(t?.trim())return{token:t.trim(),authType:"oauth"};let r=process.env.ANTHROPIC_API_KEY;if(r?.trim())return{token:r.trim(),authType:"api-key"};let n=E();if(n)return{token:n.token,authType:n.authType};let o=ae.homedir(),l=[S.join(o,".openclaw","agents","main","agent","auth-profiles.json"),S.join(o,".openclaw","auth-profiles.json"),S.join(o,".openclaw","credentials","oauth.json"),S.join(o,".claude","oauth.json"),S.join(o,".config","claude","oauth.json"),S.join(o,".config","anthropic","oauth.json")];for(let p of l){let y=fe(p);if(y)return{token:y,authType:"oauth"}}return null}function fe(a){if(!te(a))return"";try{let e=JSON.parse(ie(a,"utf8"));if(e.profiles){let t="";for(let[r,n]of Object.entries(e.profiles))if(r.startsWith("anthropic")){if(n.type==="oauth"&&n.access){if(n.expires&&Date.now()>n.expires)continue;return n.access}n.type==="token"&&n.token&&(t=n.token)}if(t)return t}return e.anthropic?.access?e.anthropic.access:e.anthropic?.token?e.anthropic.token:""}catch{return""}}var ee=[{id:"claude-sonnet-4-20250514",label:"anthropic/claude-sonnet-4",hint:"Claude Sonnet 4 \xB7 ctx 200k \xB7 recommended"},{id:"claude-opus-4-20250514",label:"anthropic/claude-opus-4-5",hint:"Claude Opus 4.5 \xB7 ctx 200k \xB7 reasoning"},{id:"claude-haiku-4-20250514",label:"anthropic/claude-haiku-4",hint:"Claude Haiku 4 \xB7 ctx 200k \xB7 fast"}];async function ye(){let a=process.env.ANTHROPIC_API_KEY;if(a?.trim()){let r=a.slice(0,10)+"..."+a.slice(-4),{useExisting:n}=await I({type:"confirm",name:"useExisting",message:`Use existing ANTHROPIC_API_KEY (env, ${r})?`,initial:!0});if(n)return{token:a.trim(),authType:"api-key"}}let e=E();if(e?.authType==="api-key"&&e.token){let r=e.token.slice(0,10)+"..."+e.token.slice(-4),{useExisting:n}=await I({type:"confirm",name:"useExisting",message:`Use stored API key (${r})?`,initial:!0});if(n)return{token:e.token,authType:"api-key"}}let{apiKey:t}=await I({type:"password",name:"apiKey",message:"Enter Anthropic API key",validate:r=>r.startsWith("sk-ant-api")?r.length<40?"API key seems too short":!0:"API key must start with sk-ant-api"});return t?{token:t,authType:"api-key"}:null}async function ge(){N.break();let a=46,e="Run `claude setup-token` in your terminal.",t="Then paste the generated token below.";console.log(` ${J.cyan("Anthropic setup-token")} ${"\u2500".repeat(a-21-1)}\u256E`),console.log(` ${" ".repeat(a)}\u2502`),console.log(` ${e}${" ".repeat(a-e.length)}\u2502`),console.log(` ${t}${" ".repeat(a-t.length)}\u2502`),console.log(` ${" ".repeat(a)}\u2502`),console.log(` ${"\u2500".repeat(a)}\u256F`),N.break();let{token:r}=await I({type:"password",name:"token",message:"Paste Anthropic setup-token",validate:o=>o.trim()?o.length<40?"Token seems too short":!0:"Token is required"});if(!r)return null;let{tokenName:n}=await I({type:"text",name:"tokenName",message:"Token name (blank = default)"});return{token:r,authType:"oauth"}}async function he(){for(;;){let{provider:a}=await I({type:"select",name:"provider",message:"Model/auth provider",choices:[{title:"Anthropic",value:"anthropic",description:"setup-token + API key"}]});if(a===void 0)return null;let{method:e}=await I({type:"select",name:"method",message:"Anthropic auth method",choices:[{title:"Anthropic token (paste setup-token)",value:"setup-token",description:"run `claude setup-token` elsewhere, then paste the token here"},{title:"Anthropic API key",value:"api-key"},{title:J.dim("Back"),value:"back"}]});if(e===void 0)return null;if(e!=="back")return e==="api-key"?ye():e==="setup-token"?ge():null}}async function ke(){let a=E(),e=ee.map(r=>({title:r.label,value:r.id,description:r.hint+(a?.model===r.id?" \xB7 current":"")}));if(a?.model){let r=ee.find(o=>o.id===a.model),n=r?r.label:a.model;e.unshift({title:`Keep current (${n})`,value:a.model,description:"no change"})}let{modelId:t}=await I({type:"select",name:"modelId",message:"Default model",choices:e});return t||null}async function _e(){let a=await he();if(!a)return null;let e=await ke();if(!e)return null;let t={provider:a.authType==="oauth"?"claude-code":"claude",authType:a.authType,token:a.token,model:e};return me(t),N.break(),N.success("Configuration saved to ~/.agentx/auth.json"),console.log(` Provider: ${J.bold("anthropic")} (${t.authType})`),console.log(` Model: ${J.bold(ee.find(r=>r.id===t.model)?.label||t.model)}`),t}async function Se(a){return F(a)?!0:(N.warn("No AI credentials configured."),N.break(),await _e()!==null)}var B=[{name:"create_files",description:"Create one or more files as output. Use this when you need to generate code, documents, configs, or any file-based output.",input_schema:{type:"object",properties:{files:{type:"array",items:{type:"object",properties:{path:{type:"string",description:"Relative file path from project root (e.g., src/components/Button.tsx)"},content:{type:"string",description:"The full content of the file"},language:{type:"string",description:"Programming language or file type"},description:{type:"string",description:"Brief description of what this file does"}},required:["path","content"]}},summary:{type:"string",description:"Brief summary of all generated files"}},required:["files"]},permission:"file-write"},{name:"ask_user",description:"Ask the user a clarifying question when you need more information to proceed. Use this when the request is ambiguous or you need to confirm important decisions.",input_schema:{type:"object",properties:{question:{type:"string",description:"The question to ask the user"},options:{type:"array",items:{type:"string"},description:"Optional list of choices for the user"}},required:["question"]},permission:"none"},{name:"read_file",description:"Read the contents of a file. Use this to inspect existing code, understand patterns, check implementations, or gather context before generating code.",input_schema:{type:"object",properties:{path:{type:"string",description:"Relative file path from project root"},max_lines:{type:"number",description:"Maximum number of lines to read. Defaults to 500. Use for large files."}},required:["path"]},permission:"file-read"},{name:"search_files",description:"Search for files matching a pattern and optionally search their content with a regex. Use this to find relevant code, understand project structure, or locate specific patterns.",input_schema:{type:"object",properties:{pattern:{type:"string",description:"Glob pattern to match files (e.g., 'src/**/*.ts', '*.json')"},content_regex:{type:"string",description:"Optional regex to search within matched files. Returns matching lines."},max_results:{type:"number",description:"Maximum number of results to return. Default: 50."}},required:["pattern"]},permission:"none"},{name:"list_directory",description:"List files and directories at a given path. Use this to explore project structure.",input_schema:{type:"object",properties:{path:{type:"string",description:"Relative directory path from project root. Defaults to '.' (root)."},recursive:{type:"boolean",description:"List recursively. Default: false."},max_depth:{type:"number",description:"Maximum depth for recursive listing. Default: 3."}}},permission:"none"},{name:"run_command",description:"Execute a shell command. Use this to run build tools, test commands, linters, or inspect the environment. Commands run in the project root directory.",input_schema:{type:"object",properties:{command:{type:"string",description:"The shell command to execute"},timeout:{type:"number",description:"Timeout in milliseconds. Default: 30000 (30 seconds)."}},required:["command"]},permission:"command"},{name:"edit_file",description:"Apply search-and-replace edits to an existing file. Use this for targeted modifications to existing code rather than rewriting entire files.",input_schema:{type:"object",properties:{path:{type:"string",description:"Relative file path from project root"},edits:{type:"array",items:{type:"object",properties:{old_text:{type:"string",description:"The exact text to find in the file"},new_text:{type:"string",description:"The replacement text"}},required:["old_text","new_text"]},description:"List of search/replace pairs to apply in order"}},required:["path","edits"]},permission:"file-write"},{name:"spawn_agent",description:"Spawn a sub-agent to handle a task in the background. The sub-agent runs in its own session and returns results. Use this for parallel research, long-running tasks, or delegating work to a specialized agent.",input_schema:{type:"object",properties:{agent_id:{type:"string",description:"The ID of the agent to spawn (must be a registered agent)"},prompt:{type:"string",description:"The task description for the sub-agent"},timeout_seconds:{type:"number",description:"Maximum time to wait for completion in seconds. Default: 300 (5 minutes)."}},required:["agent_id","prompt"]},permission:"none"}];function Ae(a){return(a?B.filter(t=>a.includes(t.name)):B).map(({name:t,description:r,input_schema:n})=>({name:t,description:r,input_schema:n}))}function M(){return Ae(["create_files","ask_user"])}function Me(){let a=B.filter(t=>t.name!=="create_files"&&t.name!=="ask_user");if(a.length===0)return"";let e=["# Available Capabilities","In addition to generating files, you have the following capabilities:",""];for(let t of a)e.push(`## ${t.name}`),e.push(t.description),e.push("");return e.join(`
|
|
2
|
+
`)}var je=B.map(a=>a.name);var H="claude-sonnet-4-20250514",Y=8192,we=4*1024;function W(a){return!a||a.length<we?a:[{type:"text",text:a,cache_control:{type:"ephemeral"}}]}var L=class{name="claude";apiKey;authType="api-key";constructor(e){if(this.apiKey=e||process.env.ANTHROPIC_API_KEY||"",!this.apiKey){let t=F();t&&(this.apiKey=t.token,this.authType=t.authType)}if(!this.apiKey)throw new Error("Anthropic API key required. Run `agentx model` to configure, set ANTHROPIC_API_KEY, or pass --api-key.")}async generate(e,t){let r=t?.model||H,n=t?.maxTokens||Y,o=e.find(c=>c.role==="system"),l=e.filter(c=>c.role!=="system").map(c=>({role:c.role,content:c.content})),p={model:r,max_tokens:n,messages:l,tools:M()};o&&(p.system=W(o.content)),t?.temperature!==void 0&&(p.temperature=t.temperature);let y=await this.callApi(p);return this.parseResponse(y)}async generateRaw(e,t,r,n){let o=n?.model||H,l=n?.maxTokens||Y,p={model:o,max_tokens:l,system:W(t),messages:e,tools:r};n?.temperature!==void 0&&(p.temperature=n.temperature);let y=await this.callApi(p);return{content:y.content.map(g=>g.type==="text"?{type:"text",text:g.text||""}:g.type==="tool_use"?{type:"tool_use",id:g.id||"",name:g.name||"",input:g.input||{}}:{type:"text",text:""}),stop_reason:y.stop_reason,usage:y.usage}}async*stream(e,t){let r=t?.model||H,n=t?.maxTokens||Y,o=e.find(m=>m.role==="system"),l=e.filter(m=>m.role!=="system").map(m=>({role:m.role,content:m.content})),p={model:r,max_tokens:n,messages:l,stream:!0,tools:M()};o&&(p.system=W(o.content));let y=this.buildHeaders(),c=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:y,body:JSON.stringify(p)});if(!c.ok){let m=await c.text();yield{type:"error",error:`Anthropic API error (${c.status}): ${m}`};return}let g=c.body?.getReader();if(!g){yield{type:"error",error:"No response body"};return}let k=new TextDecoder,d="",h=[],w="",A,b=0,s=null,f=m=>{let R=(m||"").trim();if(!R||R.includes("```"))return;let O=R.replace(/\r\n/g,`
|
|
3
|
+
`).split(`
|
|
4
|
+
`),x=O.slice(Math.max(0,O.length-20)),u=x.join(`
|
|
5
|
+
`);if(/\b(plan|proposal)\b/i.test(u)&&/(ready for your review|review (the )?plan|requesting plan approval|awaiting approval|waiting for (your )?approval|approve (the )?plan|approval to proceed)/i.test(u))return`The provider is requesting plan approval.
|
|
6
|
+
Reply with:
|
|
7
|
+
- approve
|
|
8
|
+
- revise: <what to change>
|
|
9
|
+
- cancel`;let _=P=>/^(question|clarification|clarify|i need|need more|before i proceed|to proceed|please (confirm|clarify)|which|what|where|when|how|do you)/i.test(P.trim()),T=-1;for(let P=x.length-1;P>=0;P--){let G=x[P].trim();if(G&&(_(G)||G.includes("?"))){T=P;break}}if(T===-1)return;let v=[];for(let P=T;P<x.length&&v.length<8;P++){let G=x[P],X=G.trim();if(v.length>0&&!X||v.length>0&&!/^(options?:|[-*]\s|\d+[\).]\s)/i.test(X)&&!X.includes("?"))break;v.push(G.trimEnd())}let C=v.join(`
|
|
10
|
+
`).trim();if(!(C.length<5))return C.length>800?C.slice(0,800).trimEnd():C};try{for(;;){let{done:m,value:R}=await g.read();if(m)break;d+=k.decode(R,{stream:!0});let O=d.split(`
|
|
11
|
+
`);d=O.pop()||"";for(let x of O){if(!x.startsWith("data: "))continue;let u=x.slice(6).trim();if(u!=="[DONE]")try{let i=JSON.parse(u);if(i.type==="content_block_start"&&i.content_block?.type==="tool_use"){if(s){yield{type:"tool_use_end",name:s.name};try{let _=JSON.parse(s.json||"{}");s.name==="create_files"&&_&&(Array.isArray(_.files)&&h.push(..._.files),typeof _.summary=="string"&&_.summary.trim()&&(w+=`
|
|
12
|
+
${_.summary}`)),s.name==="ask_user"&&_&&typeof _.question=="string"&&_.question.trim()&&(A=_.question,Array.isArray(_.options)&&_.options.length&&(A+=`
|
|
13
|
+
Options: ${_.options.join(", ")}`))}catch{}finally{s=null}}s={name:i.content_block.name,id:i.content_block.id,json:""},yield{type:"tool_use_start",name:i.content_block.name,id:i.content_block.id}}if(i.type==="content_block_delta"&&(i.delta?.type==="text_delta"&&(w+=i.delta.text,yield{type:"text_delta",text:i.delta.text}),i.delta?.type==="input_json_delta"&&(s&&(s.json+=i.delta.partial_json||""),yield{type:"tool_use_delta",json:i.delta.partial_json})),i.type==="content_block_stop"&&s){yield{type:"tool_use_end",name:s.name};try{let _=JSON.parse(s.json||"{}");s.name==="create_files"&&_&&(Array.isArray(_.files)&&h.push(..._.files),typeof _.summary=="string"&&_.summary.trim()&&(w+=`
|
|
14
|
+
${_.summary}`)),s.name==="ask_user"&&_&&typeof _.question=="string"&&_.question.trim()&&(A=_.question,Array.isArray(_.options)&&_.options.length&&(A+=`
|
|
15
|
+
Options: ${_.options.join(", ")}`))}catch{}finally{s=null}}i.type==="message_delta"&&i.usage&&(b=(i.usage.input_tokens||0)+(i.usage.output_tokens||0)),i.type}catch{}}}}finally{g.releaseLock()}if(s){yield{type:"tool_use_end",name:s.name};try{let m=JSON.parse(s.json||"{}");s.name==="create_files"&&m&&(Array.isArray(m.files)&&h.push(...m.files),typeof m.summary=="string"&&m.summary.trim()&&(w+=`
|
|
16
|
+
${m.summary}`)),s.name==="ask_user"&&m&&typeof m.question=="string"&&m.question.trim()&&(A=m.question,Array.isArray(m.options)&&m.options.length&&(A+=`
|
|
17
|
+
Options: ${m.options.join(", ")}`))}catch{}s=null}!A&&h.length===0&&(A=f(w)),yield{type:"done",result:{content:w,files:h,followUp:A,tokensUsed:b}}}async*generateRawStream(e,t,r,n){let o=n?.model||H,l=n?.maxTokens||Y,p={model:o,max_tokens:l,system:W(t),messages:e,tools:r,stream:!0};n?.temperature!==void 0&&(p.temperature=n.temperature);let y=this.buildHeaders(),c;try{c=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:y,body:JSON.stringify(p)})}catch(f){yield{type:"error",error:`Anthropic stream init failed: ${f?.message??f}`};return}if(!c.ok){let f=await c.text().catch(()=>"");yield{type:"error",error:`Anthropic API error (${c.status}): ${f.slice(0,500)}`};return}let g=c.body?.getReader();if(!g){yield{type:"error",error:"No response body on Anthropic stream"};return}let k=new TextDecoder,d="",h=[],w=null,A="end_turn",b=0,s=0;try{for(;;){let{done:f,value:m}=await g.read();if(f)break;d+=k.decode(m,{stream:!0});let R=d.split(`
|
|
18
|
+
`);d=R.pop()||"";for(let O of R){if(!O.startsWith("data: "))continue;let x=O.slice(6).trim();if(!x||x==="[DONE]")continue;let u;try{u=JSON.parse(x)}catch{continue}if(u.type==="message_start"&&u.message?.usage&&(b=u.message.usage.input_tokens||0),u.type==="content_block_start"){let i=u.content_block;i?.type==="text"?(w=h.length,h.push({type:"text",text:""})):i?.type==="tool_use"?(w=h.length,h.push({type:"tool_use",id:i.id||"",name:i.name||"",input:{}}),h[w]._rawJson=""):w=null}if(u.type==="content_block_delta"&&w!=null){let i=h[w];u.delta?.type==="text_delta"&&i.type==="text"?(i.text+=u.delta.text,yield{type:"text_delta",text:u.delta.text}):u.delta?.type==="input_json_delta"&&i.type==="tool_use"&&(i._rawJson+=u.delta.partial_json||"")}if(u.type==="content_block_stop"&&w!=null){let i=h[w];if(i.type==="tool_use"){let _=i._rawJson||"{}";try{i.input=JSON.parse(_)}catch{i.input={}}delete i._rawJson}w=null}u.type==="message_delta"&&(u.delta?.stop_reason&&(A=u.delta.stop_reason),u.usage&&(s=u.usage.output_tokens||0))}}}catch(f){yield{type:"error",error:`Anthropic stream read failed: ${f?.message??f}`};return}finally{g.releaseLock()}yield{type:"raw_result",result:{content:h,stop_reason:A,usage:{input_tokens:b,output_tokens:s}}}}buildHeaders(){let e={"Content-Type":"application/json","anthropic-version":"2023-06-01"};return this.authType==="oauth"?(e.Authorization=`Bearer ${this.apiKey}`,e["anthropic-beta"]="claude-code-20250219,oauth-2025-04-20",e["user-agent"]="claude-cli/2.1.2 (external, cli)",e["x-app"]="cli",e["anthropic-dangerous-direct-browser-access"]="true"):e["x-api-key"]=this.apiKey,e}async callApi(e){let t=this.buildHeaders(),r=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:t,body:JSON.stringify(e)});if(!r.ok){let n=await r.text();throw new Error(`Anthropic API error (${r.status}): ${n}`)}return await r.json()}parseResponse(e){let t=[],r="",n;for(let o of e.content)if(o.type==="text"&&(r+=o.text||""),o.type==="tool_use"){if(o.name==="create_files"&&o.input){let l=o.input;t.push(...l.files||[]),l.summary&&(r+=`
|
|
19
|
+
${l.summary}`)}if(o.name==="ask_user"&&o.input){let l=o.input;n=l.question,l.options?.length&&(n+=`
|
|
20
|
+
Options: ${l.options.join(", ")}`)}}return{content:r,files:t,followUp:n,tokensUsed:e.usage.input_tokens+e.usage.output_tokens}}};import{execa as ce}from"execa";var q="claude-sonnet-4-20250514",ne=8192,le={"claude-sonnet-4-20250514":"sonnet","claude-opus-4-20250514":"opus","claude-haiku-4-20250514":"haiku"},K=class{name="claude-code";credential;constructor(){let e=E();if(e){this.credential={type:e.authType,token:e.token};return}let t=F();if(!t)throw new Error(`No Claude credentials found.
|
|
21
|
+
Options:
|
|
22
|
+
1. Run \`agentx model\` to configure credentials
|
|
23
|
+
2. Set ANTHROPIC_API_KEY environment variable
|
|
24
|
+
3. Set ANTHROPIC_OAUTH_TOKEN environment variable`);this.credential={type:t.authType,token:t.token}}async generate(e,t){return this.credential.type==="oauth"?this.generateViaCli(e,t):this.generateViaApi(e,t)}async generateRaw(e,t,r,n){if(this.credential.type==="oauth")throw new Error("generateRaw() not available for OAuth/CLI mode");let o=n?.model||q,l=n?.maxTokens||ne,p={model:o,max_tokens:l,system:t,messages:e,tools:r};n?.temperature!==void 0&&(p.temperature=n.temperature);let y={"Content-Type":"application/json","anthropic-version":"2023-06-01","x-api-key":this.credential.token},c=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:y,body:JSON.stringify(p)});if(!c.ok){let d=await c.text();throw new Error(`Anthropic API error (${c.status}): ${d}`)}let g=await c.json();return{content:g.content.map(d=>d.type==="text"?{type:"text",text:d.text||""}:d.type==="tool_use"?{type:"tool_use",id:d.id||"",name:d.name||"",input:d.input||{}}:{type:"text",text:""}),stop_reason:g.stop_reason,usage:g.usage}}get supportsAgenticLoop(){return this.credential.type==="api-key"}async generateViaCli(e,t){let r=t?.model||E()?.model||q,n=le[r]||r,o=e.find(d=>d.role==="system"),p=e.filter(d=>d.role==="user").map(d=>d.content).join(`
|
|
25
|
+
|
|
26
|
+
`),y=["-p","--output-format","json","--model",n,"--dangerously-skip-permissions"];o&&y.push("--append-system-prompt",o.content),y.push(p);let c={...process.env};delete c.ANTHROPIC_API_KEY,delete c.ANTHROPIC_API_KEY_OLD;let g=await ce("claude",y,{env:c,extendEnv:!1,reject:!1,timeout:3e5,stdin:"ignore"});if(g.exitCode!==0){let d=g.stderr||g.stdout||"Claude CLI failed";throw new Error(`Claude CLI error: ${d}`)}let k=g.stdout.trim();try{let d=JSON.parse(k);if(d.is_error&&d.result)throw new Error(d.result)}catch(d){if(d.message&&!d.message.includes("JSON"))throw d}return this.parseCliOutput(k)}async generateViaApi(e,t){let r=t?.model||q,n=t?.maxTokens||ne,o=e.find(k=>k.role==="system"),l=e.filter(k=>k.role!=="system").map(k=>({role:k.role,content:k.content})),p={model:r,max_tokens:n,messages:l,tools:M()};o&&(p.system=o.content),t?.temperature!==void 0&&(p.temperature=t.temperature);let y={"Content-Type":"application/json","anthropic-version":"2023-06-01","x-api-key":this.credential.token},c=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:y,body:JSON.stringify(p)});if(!c.ok){let k=await c.text();throw new Error(`Anthropic API error (${c.status}): ${k}`)}let g=await c.json();return this.parseApiResponse(g)}async*stream(e,t){this.credential.type==="oauth"?yield*this.streamViaCli(e,t):yield*this.streamViaApi(e,t)}async*streamViaCli(e,t){let r=t?.model||E()?.model||q,n=le[r]||r,o=e.find(s=>s.role==="system"),p=e.filter(s=>s.role==="user").map(s=>s.content).join(`
|
|
27
|
+
|
|
28
|
+
`),y=["-p","--output-format","stream-json","--model",n,"--dangerously-skip-permissions"];o&&y.push("--append-system-prompt",o.content),y.push(p);let c={...process.env};delete c.ANTHROPIC_API_KEY,delete c.ANTHROPIC_API_KEY_OLD;let g=ce("claude",y,{env:c,extendEnv:!1,reject:!1,timeout:3e5,stdin:"ignore"}),k="",d="",h;if(g.stderr&&g.stderr.on("data",s=>{d+=Buffer.isBuffer(s)?s.toString("utf8"):String(s)}),g.stdout){let s=new TextDecoder,f=g.stdout;for await(let m of f){let O=(typeof m=="string"?m:s.decode(m,{stream:!0})).split(`
|
|
29
|
+
`).filter(Boolean);for(let x of O)try{let u=JSON.parse(x);if(u.type==="error"){h=String(u.error||u.message||"Claude CLI error");continue}if(u.is_error&&(u.result||u.message)){h=String(u.result||u.message);continue}u.type==="assistant"&&u.message?(k+=u.message,yield{type:"text_delta",text:u.message}):u.type==="result"&&(k=u.result||k)}catch{k+=x,yield{type:"text_delta",text:x}}}}let w=await g;if(w.exitCode!==0&&!h&&(h=(d||w.stderr||w.stdout||"Claude CLI failed").toString().trim()),h){yield{type:"error",error:`Claude CLI error: ${h}`};return}let A=this.extractFilesFromText(k),b=A.length===0?this.inferFollowUpFromText(k):void 0;yield{type:"done",result:{content:k,files:A,followUp:b,tokensUsed:0}}}async*streamViaApi(e,t){let r=t?.model||q,n=t?.maxTokens||ne,o=e.find(f=>f.role==="system"),l=e.filter(f=>f.role!=="system").map(f=>({role:f.role,content:f.content})),p={model:r,max_tokens:n,messages:l,tools:M(),stream:!0};o&&(p.system=o.content);let y={"Content-Type":"application/json","anthropic-version":"2023-06-01","x-api-key":this.credential.token},c=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:y,body:JSON.stringify(p)});if(!c.ok){let f=await c.text();yield{type:"error",error:`Anthropic API error (${c.status}): ${f}`};return}let g=c.body?.getReader();if(!g){yield{type:"error",error:"No response body"};return}let k=new TextDecoder,d="",h="",w=0,A=[],b,s=null;try{for(;;){let{done:f,value:m}=await g.read();if(f)break;d+=k.decode(m,{stream:!0});let R=d.split(`
|
|
30
|
+
`);d=R.pop()||"";for(let O of R){if(!O.startsWith("data: "))continue;let x=O.slice(6).trim();if(x!=="[DONE]")try{let u=JSON.parse(x);if(u.type==="content_block_start"&&u.content_block?.type==="tool_use"){if(s){yield{type:"tool_use_end",name:s.name};try{let i=JSON.parse(s.json||"{}");s.name==="create_files"&&i&&(Array.isArray(i.files)&&A.push(...i.files),typeof i.summary=="string"&&i.summary.trim()&&(h+=`
|
|
31
|
+
${i.summary}`)),s.name==="ask_user"&&i&&typeof i.question=="string"&&i.question.trim()&&(b=i.question,Array.isArray(i.options)&&i.options.length&&(b+=`
|
|
32
|
+
Options: ${i.options.join(", ")}`))}catch{}finally{s=null}}s={name:u.content_block.name,id:u.content_block.id,json:""},yield{type:"tool_use_start",name:s.name,id:s.id}}if(u.type==="content_block_delta"&&u.delta?.type==="text_delta"&&(h+=u.delta.text,yield{type:"text_delta",text:u.delta.text}),u.type==="content_block_delta"&&u.delta?.type==="input_json_delta"&&(s&&(s.json+=u.delta.partial_json||""),yield{type:"tool_use_delta",json:u.delta.partial_json}),u.type==="content_block_stop"&&s){yield{type:"tool_use_end",name:s.name};try{let i=JSON.parse(s.json||"{}");s.name==="create_files"&&i&&(Array.isArray(i.files)&&A.push(...i.files),typeof i.summary=="string"&&i.summary.trim()&&(h+=`
|
|
33
|
+
${i.summary}`)),s.name==="ask_user"&&i&&typeof i.question=="string"&&i.question.trim()&&(b=i.question,Array.isArray(i.options)&&i.options.length&&(b+=`
|
|
34
|
+
Options: ${i.options.join(", ")}`))}catch{}finally{s=null}}u.type==="message_delta"&&u.usage&&(w=(u.usage.input_tokens||0)+(u.usage.output_tokens||0))}catch{}}}}finally{g.releaseLock()}if(s){yield{type:"tool_use_end",name:s.name};try{let f=JSON.parse(s.json||"{}");s.name==="create_files"&&f&&(Array.isArray(f.files)&&A.push(...f.files),typeof f.summary=="string"&&f.summary.trim()&&(h+=`
|
|
35
|
+
${f.summary}`)),s.name==="ask_user"&&f&&typeof f.question=="string"&&f.question.trim()&&(b=f.question,Array.isArray(f.options)&&f.options.length&&(b+=`
|
|
36
|
+
Options: ${f.options.join(", ")}`))}catch{}s=null}A.length===0&&A.push(...this.extractFilesFromText(h)),!b&&A.length===0&&(b=this.inferFollowUpFromText(h)),yield{type:"done",result:{content:h,files:A,followUp:b,tokensUsed:w}}}parseCliOutput(e){let t;try{t=JSON.parse(e)}catch{let l=this.inferFollowUpFromText(e.trim());return{content:e.trim(),files:[],followUp:l,tokensUsed:0}}let r=t.result||t.text||t.content||"",n=this.extractFilesFromText(r),o=n.length===0?this.inferFollowUpFromText(r):void 0;return{content:r,files:n,followUp:o,tokensUsed:t.usage?(t.usage.input_tokens||0)+(t.usage.output_tokens||0):0}}extractFilesFromText(e){let t=[],r=/```[\w]*\s*([\w/._-]+\.\w+)\n([\s\S]*?)```/g,n;for(;(n=r.exec(e))!==null;){let o=n[1],l=n[2];o&&l&&t.push({path:o,content:l.trimEnd()})}return t}inferFollowUpFromText(e){let t=(e||"").trim();if(!t||t.includes("```"))return;let r=t.replace(/\r\n/g,`
|
|
37
|
+
`).split(`
|
|
38
|
+
`),n=r.slice(Math.max(0,r.length-20)),o=n.join(`
|
|
39
|
+
`);if(/\b(plan|proposal)\b/i.test(o)&&/(ready for your review|review (the )?plan|requesting plan approval|awaiting approval|waiting for (your )?approval|approve (the )?plan|approval to proceed)/i.test(o))return`The provider is requesting plan approval.
|
|
40
|
+
Reply with:
|
|
41
|
+
- approve
|
|
42
|
+
- revise: <what to change>
|
|
43
|
+
- cancel`;let p=k=>/^(question|clarification|clarify|i need|need more|before i proceed|to proceed|please (confirm|clarify)|which|what|where|when|how|do you)/i.test(k.trim()),y=-1;for(let k=n.length-1;k>=0;k--){let d=n[k].trim();if(d&&(p(d)||d.includes("?"))){y=k;break}}if(y===-1)return;let c=[];for(let k=y;k<n.length&&c.length<8;k++){let d=n[k],h=d.trim();if(c.length>0&&!h||c.length>0&&!/^(options?:|[-*]\s|\d+[\).]\s)/i.test(h)&&!h.includes("?"))break;c.push(d.trimEnd())}let g=c.join(`
|
|
44
|
+
`).trim();if(!(g.length<5))return g.length>800?g.slice(0,800).trimEnd():g}parseApiResponse(e){let t=[],r="",n;for(let o of e.content)if(o.type==="text"&&(r+=o.text||""),o.type==="tool_use"){if(o.name==="create_files"&&o.input){let l=o.input;t.push(...l.files||[]),l.summary&&(r+=`
|
|
45
|
+
${l.summary}`)}if(o.name==="ask_user"&&o.input){let l=o.input;n=l.question,l.options?.length&&(n+=`
|
|
46
|
+
Options: ${l.options.join(", ")}`)}}return{content:r,files:t,followUp:n,tokensUsed:e.usage.input_tokens+e.usage.output_tokens}}};var re="gpt-4o-mini",oe=8192,$=class{name="openai";apiKey;baseUrl;thinkingEnabled;constructor(e,t,r={}){this.apiKey=e||process.env.OPENAI_API_KEY||"",this.baseUrl=(t||process.env.OPENAI_BASE_URL||"https://api.openai.com/v1").replace(/\/$/,"");let n=this.baseUrl.includes("deepseek.com");if(this.thinkingEnabled=n?r.thinking!==!1:null,!this.apiKey)throw new Error("OpenAI-compatible API key required. Set OPENAI_API_KEY (or pass --api-key). For DeepSeek, also set OPENAI_BASE_URL=https://api.deepseek.com/v1.")}async generate(e,t){let r=t?.model||process.env.OPENAI_MODEL||re,n=t?.maxTokens||oe,o=e.map(y=>({role:y.role,content:y.content})),l={model:r,max_tokens:n,messages:o,tools:this.legacyToolsAsOpenAI()};t?.temperature!==void 0&&(l.temperature=t.temperature);let p=await this.callApi(l);return this.parseHighLevelResponse(p)}async generateRaw(e,t,r,n){let o=this.buildRawBody(e,t,r,n),l=await this.callApi(o,n?.abortSignal);return this.parseRawResponse(l)}async*generateRawStream(e,t,r,n){let o={...this.buildRawBody(e,t,r,n),stream:!0,stream_options:{include_usage:!0}},l;try{l=await fetch(`${this.baseUrl}/chat/completions`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`},body:JSON.stringify(this.maybeDeepseekExtras(o)),signal:n?.abortSignal})}catch(m){if(m?.name==="AbortError"||n?.abortSignal?.aborted){yield{type:"error",error:"cancelled"};return}yield{type:"error",error:`OpenAI-compat raw stream init failed: ${m?.message??m}`};return}if(!l.ok){let m=await l.text().catch(()=>"");yield{type:"error",error:`OpenAI-compat API error (${l.status}): ${m.slice(0,500)}`};return}let p=l.body?.getReader();if(!p){yield{type:"error",error:"No response body on OpenAI-compat raw stream"};return}let y=()=>{p.cancel(new Error("aborted")).catch(()=>{})};n?.abortSignal&&(n.abortSignal.aborted?y():n.abortSignal.addEventListener("abort",y,{once:!0}));let c=new TextDecoder,g="",k="",d="",h=0,w=0,A=null,b={};try{for(;;){if(n?.abortSignal?.aborted){yield{type:"error",error:"cancelled"};return}let{done:m,value:R}=await p.read();if(m)break;g+=c.decode(R,{stream:!0});let O=g.split(`
|
|
47
|
+
`);g=O.pop()||"";for(let x of O){if(!x.startsWith("data: "))continue;let u=x.slice(6).trim();if(!u||u==="[DONE]")continue;let i;try{i=JSON.parse(u)}catch{continue}let _=i.choices?.[0],T=_?.delta;if(_?.finish_reason&&(A=_.finish_reason),typeof T?.reasoning_content=="string"&&T.reasoning_content&&(d+=T.reasoning_content,yield{type:"thinking_delta",text:T.reasoning_content}),typeof T?.content=="string"&&T.content&&(k+=T.content,yield{type:"text_delta",text:T.content}),Array.isArray(T?.tool_calls))for(let v of T.tool_calls){let C=v.index;if(C==null)continue;let P=b[C]||={id:"",name:"",argumentsRaw:""};v.id&&(P.id=v.id),v.function?.name&&(P.name=v.function.name),v.function?.arguments&&(P.argumentsRaw+=v.function.arguments)}i.usage&&(h=i.usage.prompt_tokens||0,w=i.usage.completion_tokens||0)}}}catch(m){if(m?.name==="AbortError"||n?.abortSignal?.aborted){yield{type:"error",error:"cancelled"};return}yield{type:"error",error:`OpenAI-compat raw stream read failed: ${m?.message??m}`};return}finally{n?.abortSignal&&n.abortSignal.removeEventListener("abort",y)}let s=[];d&&s.push({type:"reasoning",text:d}),k&&s.push({type:"text",text:k});for(let m of Object.values(b)){if(!m.id||!m.name)continue;let R={};try{R=m.argumentsRaw?JSON.parse(m.argumentsRaw):{}}catch{}s.push({type:"tool_use",id:m.id,name:m.name,input:R})}let f="end_turn";switch(A){case"tool_calls":case"function_call":f="tool_use";break;case"length":f="max_tokens";break}yield{type:"raw_result",result:{content:s,stop_reason:f,usage:{input_tokens:h,output_tokens:w}}}}buildRawBody(e,t,r,n){let o=n?.model||process.env.OPENAI_MODEL||re,l=n?.maxTokens||oe,p=t?[{role:"system",content:t}]:[];for(let c of e){let g=Array.isArray(c.content)?c.content:[{type:"text",text:c.content}];if(c.role==="user"){let k=g.filter(h=>h.type==="tool_result"),d=g.filter(h=>h.type==="text").map(h=>h.text).join("");for(let h of k)p.push({role:"tool",tool_call_id:h.tool_use_id,content:h.is_error?`[error] ${h.content}`:h.content});d?p.push({role:"user",content:d}):k.length===0&&p.push({role:"user",content:c.content})}else{let k=g.filter(A=>A.type==="tool_use"),d=g.filter(A=>A.type==="text").map(A=>A.text).join(""),h=g.filter(A=>A.type==="reasoning").map(A=>A.text).join(""),w={role:"assistant",content:d||null};k.length>0&&(w.tool_calls=k.map(A=>({id:A.id,type:"function",function:{name:A.name,arguments:JSON.stringify(A.input||{})}}))),h&&(w.reasoning_content=h),p.push(w)}}let y={model:o,max_tokens:l,messages:p,tools:r.map(c=>({type:"function",function:{name:c.name,description:c.description,parameters:c.input_schema}})),tool_choice:"auto"};return n?.temperature!==void 0&&(y.temperature=n.temperature),y}async*stream(e,t){let r=t?.model||process.env.OPENAI_MODEL||re,n=t?.maxTokens||oe,o=e.map(s=>({role:s.role,content:s.content})),l={model:r,max_tokens:n,messages:o,tools:this.legacyToolsAsOpenAI(),stream:!0,stream_options:{include_usage:!0}};t?.temperature!==void 0&&(l.temperature=t.temperature);let p;try{p=await fetch(`${this.baseUrl}/chat/completions`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`},body:JSON.stringify(this.maybeDeepseekExtras(l))})}catch(s){yield{type:"error",error:`OpenAI-compat stream init failed: ${s.message}`};return}if(!p.ok){let s=await p.text().catch(()=>"");yield{type:"error",error:`OpenAI-compat API error (${p.status}): ${s.slice(0,500)}`};return}let y=p.body?.getReader();if(!y){yield{type:"error",error:"No response body on OpenAI-compat stream"};return}let c=new TextDecoder,g="",k="",d,h=0,w=[],A={},b={};try{for(;;){let{done:s,value:f}=await y.read();if(s)break;g+=c.decode(f,{stream:!0});let m=g.split(`
|
|
48
|
+
`);g=m.pop()||"";for(let R of m){if(!R.startsWith("data: "))continue;let O=R.slice(6).trim();if(O==="[DONE]")continue;let x;try{x=JSON.parse(O)}catch{continue}let i=x.choices?.[0]?.delta;if(typeof i?.reasoning_content=="string"&&i.reasoning_content&&(yield{type:"thinking_delta",text:i.reasoning_content}),typeof i?.content=="string"&&i.content&&(k+=i.content,yield{type:"text_delta",text:i.content}),Array.isArray(i?.tool_calls))for(let _ of i.tool_calls){let T=_.index;if(T==null)continue;let v=A[T]||={id:"",name:"",argumentsRaw:""};_.id&&(v.id=_.id),_.function?.name&&(v.name=_.function.name),_.function?.arguments&&(v.argumentsRaw+=_.function.arguments),v.id&&v.name&&!b[T]&&(b[T]=!0,yield{type:"tool_use_start",name:v.name,id:v.id}),b[T]&&_.function?.arguments&&(yield{type:"tool_use_delta",json:_.function.arguments})}x.usage&&(h=(x.usage.prompt_tokens||0)+(x.usage.completion_tokens||0))}}}catch(s){yield{type:"error",error:`OpenAI-compat stream read failed: ${s.message}`};return}for(let s of Object.values(A))if(s.name){yield{type:"tool_use_end",name:s.name};try{let f=s.argumentsRaw?JSON.parse(s.argumentsRaw):{};s.name==="create_files"&&Array.isArray(f.files)?(w.push(...f.files),typeof f.summary=="string"&&f.summary.trim()&&(k+=(k?`
|
|
49
|
+
`:"")+f.summary)):s.name==="ask_user"&&typeof f.question=="string"&&(d=f.question,Array.isArray(f.options)&&f.options.length&&(d+=`
|
|
50
|
+
Options: ${f.options.join(", ")}`))}catch{}}yield{type:"done",result:{content:k,files:w,followUp:d,tokensUsed:h}}}async callApi(e,t){let r=await fetch(`${this.baseUrl}/chat/completions`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`},body:JSON.stringify(this.maybeDeepseekExtras(e)),signal:t});if(!r.ok){let n=await r.text().catch(()=>"");throw new Error(`OpenAI-compatible API error (${r.status}) ${this.baseUrl}: ${n.slice(0,500)}`)}return await r.json()}maybeDeepseekExtras(e){return this.thinkingEnabled===null?e:this.thinkingEnabled===!1?{...e,enable_thinking:!1}:e}parseHighLevelResponse(e){let r=e.choices?.[0]?.message,n=[],o=r?.content||"",l;for(let y of r?.tool_calls||[]){let c={};try{c=JSON.parse(y.function.arguments||"{}")}catch{}y.function.name==="create_files"&&Array.isArray(c.files)?(n.push(...c.files),typeof c.summary=="string"&&c.summary.trim()&&(o+=(o?`
|
|
51
|
+
`:"")+c.summary)):y.function.name==="ask_user"&&typeof c.question=="string"&&(l=c.question,Array.isArray(c.options)&&c.options.length&&(l+=`
|
|
52
|
+
Options: ${c.options.join(", ")}`))}let p=e.usage;return{content:o,files:n,followUp:l,tokensUsed:p?(p.prompt_tokens||0)+(p.completion_tokens||0):void 0}}parseRawResponse(e){let t=e.choices?.[0],r=t?.message,n=[];r?.reasoning_content&&n.push({type:"reasoning",text:r.reasoning_content}),r?.content&&n.push({type:"text",text:r.content});for(let p of r?.tool_calls||[]){let y={};try{y=p.function.arguments?JSON.parse(p.function.arguments):{}}catch{}n.push({type:"tool_use",id:p.id,name:p.function.name,input:y})}let o="end_turn";switch(t?.finish_reason){case"tool_calls":case"function_call":o="tool_use";break;case"length":o="max_tokens";break;case"stop":case null:case void 0:default:o="end_turn"}let l=e.usage;return{content:n,stop_reason:o,usage:{input_tokens:l?.prompt_tokens||0,output_tokens:l?.completion_tokens||0}}}legacyToolsAsOpenAI(){return M().map(e=>({type:"function",function:{name:e.name,description:e.description,parameters:e.input_schema}}))}};import{readFileSync as xe}from"fs";var se={reply:"This is demo mode \u2014 I answer from a script, not a live model. Run `agentx setup` to connect a real provider."};function be(){let a=process.env.AGENTX_DEMO_SCRIPT;if(!a)return{steps:[],fallback:se};try{let e=JSON.parse(xe(a,"utf-8"));return{steps:Array.isArray(e.steps)?e.steps:[],fallback:e.fallback||se}}catch(e){return{steps:[],fallback:{reply:`Demo script unreadable (${e.message}) \u2014 check AGENTX_DEMO_SCRIPT.`}}}}function D(a){for(let e=a.length-1;e>=0;e--){if(a[e].role!=="user")continue;let t=a[e].content;if(typeof t=="string")return t;if(Array.isArray(t))return t.map(r=>r?.type==="text"?r.text:r?.type==="tool_result"?r.content:"").filter(Boolean).join(`
|
|
53
|
+
`)}return""}function j(a,e){return new Promise((t,r)=>{if(e?.aborted)return r(new Error("aborted"));let n=setTimeout(t,a);e?.addEventListener("abort",()=>{clearTimeout(n),r(new Error("aborted"))},{once:!0})})}function V(a){return a.match(/\S+\s*/g)||[a]}var U=a=>Math.max(1,Math.round(a.length/4)),z=class{name="demo";script;constructor(){this.script=be()}pick(e){let t,r=-1;for(let o of this.script.steps)try{let l=new RegExp(o.match,"ig"),p,y=-1;for(;(p=l.exec(e))!==null;)y=p.index,p.index===l.lastIndex&&l.lastIndex++;y>r&&(r=y,t=o)}catch{}if(t)return{reply:t.reply,thinking:t.thinking,delayMs:t.delayMs??700,chunkMs:t.chunkMs??35};let n=this.script.fallback||se;return{reply:n.reply,thinking:n.thinking,delayMs:n.delayMs??700,chunkMs:n.chunkMs??35}}async generate(e,t){let r=this.pick(D(e));return await j(r.delayMs,t?.abortSignal),{content:r.reply,files:[],tokensUsed:U(r.reply)}}async*stream(e,t){let r=this.pick(D(e));if(await j(r.delayMs,t?.abortSignal),r.thinking)for(let n of V(r.thinking))yield{type:"thinking_delta",text:n},await j(r.chunkMs,t?.abortSignal);for(let n of V(r.reply))yield{type:"text_delta",text:n},await j(r.chunkMs,t?.abortSignal);yield{type:"done",result:{content:r.reply,files:[],tokensUsed:U(r.reply)}}}async generateRaw(e,t,r,n){let o=this.pick(D(e));return await j(o.delayMs,n?.abortSignal),{content:[{type:"text",text:o.reply}],stop_reason:"end_turn",usage:{input_tokens:U(D(e)),output_tokens:U(o.reply)}}}async*generateRawStream(e,t,r,n){let o=this.pick(D(e));if(await j(o.delayMs,n?.abortSignal),o.thinking)for(let l of V(o.thinking))yield{type:"thinking_delta",text:l},await j(o.chunkMs,n?.abortSignal);for(let l of V(o.reply))yield{type:"text_delta",text:l},await j(o.chunkMs,n?.abortSignal);yield{type:"raw_result",result:{content:[{type:"text",text:o.reply}],stop_reason:"end_turn",usage:{input_tokens:U(D(e)),output_tokens:U(o.reply)}}}}};var pe={baseUrl:"https://api.deepseek.com/v1",envKey:"DEEPSEEK_API_KEY"};function Xe(a="claude-code",e,t={}){let r=a;if(a==="claude-code"&&!e){let n=E();n&&(r=n.provider)}switch(r){case"claude-code":return new K;case"claude":return new L(e);case"openai":return new $(e,void 0,{thinking:t.thinking});case"deepseek":return new $(e||process.env[pe.envKey]||process.env.OPENAI_API_KEY,pe.baseUrl,{thinking:t.thinking});case"demo":return new z;case"ollama":throw new Error("Ollama provider coming soon. Workaround: set provider to 'openai' with OPENAI_BASE_URL=http://localhost:11434/v1 (Ollama exposes an OpenAI-compatible endpoint). Or contribute at github.com/anis-marrouchi/agentx");default:throw new Error(`Unknown provider: ${r}. Supported: claude-code, claude, openai, deepseek`)}}export{E as a,me as b,F as c,_e as d,Se as e,Ae as f,M as g,Me as h,je as i,L as j,K as k,$ as l,Xe as m};
|
|
54
|
+
//# sourceMappingURL=chunk-FDWOECJY.js.map
|