@kolisachint/hoocode-agent 0.4.78 → 0.4.79
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/CHANGELOG.md +38 -0
- package/dist/core/agent-frontmatter.d.ts +5 -7
- package/dist/core/agent-frontmatter.d.ts.map +1 -1
- package/dist/core/agent-frontmatter.js +2 -4
- package/dist/core/agent-frontmatter.js.map +1 -1
- package/dist/core/agent-registry.d.ts +12 -1
- package/dist/core/agent-registry.d.ts.map +1 -1
- package/dist/core/agent-registry.js +38 -3
- package/dist/core/agent-registry.js.map +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +3 -3
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/dispatch-evaluator.d.ts +1 -1
- package/dist/core/dispatch-evaluator.d.ts.map +1 -1
- package/dist/core/dispatch-evaluator.js +1 -1
- package/dist/core/dispatch-evaluator.js.map +1 -1
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +24 -6
- package/dist/core/messages.js.map +1 -1
- package/dist/core/model-categories.d.ts +14 -8
- package/dist/core/model-categories.d.ts.map +1 -1
- package/dist/core/model-categories.js +13 -24
- package/dist/core/model-categories.js.map +1 -1
- package/dist/core/provider-health.d.ts +1 -1
- package/dist/core/provider-health.d.ts.map +1 -1
- package/dist/core/provider-health.js +1 -1
- package/dist/core/provider-health.js.map +1 -1
- package/dist/core/settings-manager.d.ts +3 -2
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/subagent-inbox.d.ts +92 -0
- package/dist/core/subagent-inbox.d.ts.map +1 -0
- package/dist/core/subagent-inbox.js +245 -0
- package/dist/core/subagent-inbox.js.map +1 -0
- package/dist/core/subagent-pool.d.ts +3 -7
- package/dist/core/subagent-pool.d.ts.map +1 -1
- package/dist/core/subagent-pool.js +9 -62
- package/dist/core/subagent-pool.js.map +1 -1
- package/dist/core/system-prompt.d.ts +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +8 -8
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/task-store.d.ts +6 -5
- package/dist/core/task-store.d.ts.map +1 -1
- package/dist/core/task-store.js +4 -3
- package/dist/core/task-store.js.map +1 -1
- package/dist/core/tools/index.d.ts +1 -1
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +1 -1
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/subagent.d.ts +23 -20
- package/dist/core/tools/subagent.d.ts.map +1 -1
- package/dist/core/tools/subagent.js +267 -163
- package/dist/core/tools/subagent.js.map +1 -1
- package/dist/core/tools/todo.d.ts.map +1 -1
- package/dist/core/tools/todo.js +10 -6
- package/dist/core/tools/todo.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/init-templates.generated.d.ts.map +1 -1
- package/dist/init-templates.generated.js +1 -1
- package/dist/init-templates.generated.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +5 -5
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/task-panel.d.ts.map +1 -1
- package/dist/modes/interactive/components/task-panel.js +11 -1
- package/dist/modes/interactive/components/task-panel.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +1 -1
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +4 -4
- package/templates/agents/general-purpose.md +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Subagent dispatch guard + lightweight task telemetry.
|
|
3
3
|
*
|
|
4
|
-
* The parent agent selects which subagent to delegate to (via the
|
|
4
|
+
* The parent agent selects which subagent to delegate to (via the Task tool),
|
|
5
5
|
* so this module performs NO keyword routing. It survives for two narrow
|
|
6
6
|
* responsibilities, both cheap and LLM-free:
|
|
7
7
|
* 1. Depth guard — a process may only delegate while its depth is below the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatch-evaluator.d.ts","sourceRoot":"","sources":["../../src/core/dispatch-evaluator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,MAAM,WAAW,YAAY;IAC5B,yDAAyD;IACzD,eAAe,EAAE,OAAO,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,oBAAoB,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;CAChD;AAoBD,qBAAa,iBAAiB;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CAiBnC;CACD","sourcesContent":["/**\n * Subagent dispatch guard + lightweight task telemetry.\n *\n * The parent agent selects which subagent to delegate to (via the
|
|
1
|
+
{"version":3,"file":"dispatch-evaluator.d.ts","sourceRoot":"","sources":["../../src/core/dispatch-evaluator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,MAAM,WAAW,YAAY;IAC5B,yDAAyD;IACzD,eAAe,EAAE,OAAO,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,oBAAoB,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;CAChD;AAoBD,qBAAa,iBAAiB;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CAiBnC;CACD","sourcesContent":["/**\n * Subagent dispatch guard + lightweight task telemetry.\n *\n * The parent agent selects which subagent to delegate to (via the Task tool),\n * so this module performs NO keyword routing. It survives for two narrow\n * responsibilities, both cheap and LLM-free:\n * 1. Depth guard — a process may only delegate while its depth is below the\n * tree-wide cap (HOOCODE_SUBAGENT_MAX_DEPTH, default 1). At the default cap\n * this means a subagent cannot spawn further subagents.\n * 2. Complexity estimate — a heuristic recorded in the dispatch log for\n * diagnostics only.\n */\n\nimport { canSpawnSubagent, resolveMaxSubagentDepth } from \"./subagent-depth.js\";\n\nexport interface TaskAnalysis {\n\t/** False only when the depth guard blocks delegation. */\n\tshould_delegate: boolean;\n\treason: string;\n\testimated_complexity: \"low\" | \"medium\" | \"high\";\n}\n\n/** Heuristic complexity estimate from file/line/scope mentions in the task. */\nfunction estimateComplexity(task: string): \"low\" | \"medium\" | \"high\" {\n\tconst fileMatches = task.match(/\\b[\\w/-]+\\.(ts|js|tsx|jsx|py|go|rs|java|cpp|c|h|md|json|yaml|yml|toml)\\b/g);\n\tconst fileCount = fileMatches ? fileMatches.length : 0;\n\n\tconst lineMatch = task.match(/(\\d+)\\s*(lines?|loc)\\b/i);\n\tconst lineCount = lineMatch ? Number.parseInt(lineMatch[1], 10) : 0;\n\n\tconst highScope = /\\b(across|multiple|many|several|all files|rearchitect|redesign|migrate|restructure)\\b/i.test(\n\t\ttask,\n\t);\n\tconst mediumScope = /\\b(2|3|4|5)\\s*files?\\b/i.test(task) || /\\b(few|some|couple)\\b/i.test(task);\n\n\tif (lineCount > 200 || fileCount >= 4 || highScope) return \"high\";\n\tif (lineCount > 50 || fileCount >= 2 || mediumScope) return \"medium\";\n\treturn \"low\";\n}\n\nexport class DispatchEvaluator {\n\tevaluate(task: string): TaskAnalysis {\n\t\tif (!canSpawnSubagent()) {\n\t\t\tconst maxDepth = resolveMaxSubagentDepth();\n\t\t\treturn {\n\t\t\t\tshould_delegate: false,\n\t\t\t\t// Preserve the original message at the default cap; report the depth\n\t\t\t\t// reached when nesting has been opted into.\n\t\t\t\treason: maxDepth <= 1 ? \"Subagents cannot spawn subagents\" : `Maximum subagent depth (${maxDepth}) reached`,\n\t\t\t\testimated_complexity: \"low\",\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tshould_delegate: true,\n\t\t\treason: \"delegated to subagent\",\n\t\t\testimated_complexity: estimateComplexity(task),\n\t\t};\n\t}\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Subagent dispatch guard + lightweight task telemetry.
|
|
3
3
|
*
|
|
4
|
-
* The parent agent selects which subagent to delegate to (via the
|
|
4
|
+
* The parent agent selects which subagent to delegate to (via the Task tool),
|
|
5
5
|
* so this module performs NO keyword routing. It survives for two narrow
|
|
6
6
|
* responsibilities, both cheap and LLM-free:
|
|
7
7
|
* 1. Depth guard — a process may only delegate while its depth is below the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatch-evaluator.js","sourceRoot":"","sources":["../../src/core/dispatch-evaluator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAShF,+EAA+E;AAC/E,SAAS,kBAAkB,CAAC,IAAY,EAA6B;IACpE,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,2EAA2E,CAAC,CAAC;IAC5G,MAAM,SAAS,GAAG,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAEvD,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;IACxD,MAAM,SAAS,GAAG,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAEpE,MAAM,SAAS,GAAG,wFAAwF,CAAC,IAAI,CAC9G,IAAI,CACJ,CAAC;IACF,MAAM,WAAW,GAAG,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,wBAAwB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEhG,IAAI,SAAS,GAAG,GAAG,IAAI,SAAS,IAAI,CAAC,IAAI,SAAS;QAAE,OAAO,MAAM,CAAC;IAClE,IAAI,SAAS,GAAG,EAAE,IAAI,SAAS,IAAI,CAAC,IAAI,WAAW;QAAE,OAAO,QAAQ,CAAC;IACrE,OAAO,KAAK,CAAC;AAAA,CACb;AAED,MAAM,OAAO,iBAAiB;IAC7B,QAAQ,CAAC,IAAY,EAAgB;QACpC,IAAI,CAAC,gBAAgB,EAAE,EAAE,CAAC;YACzB,MAAM,QAAQ,GAAG,uBAAuB,EAAE,CAAC;YAC3C,OAAO;gBACN,eAAe,EAAE,KAAK;gBACtB,qEAAqE;gBACrE,4CAA4C;gBAC5C,MAAM,EAAE,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,kCAAkC,CAAC,CAAC,CAAC,2BAA2B,QAAQ,WAAW;gBAC3G,oBAAoB,EAAE,KAAK;aAC3B,CAAC;QACH,CAAC;QAED,OAAO;YACN,eAAe,EAAE,IAAI;YACrB,MAAM,EAAE,uBAAuB;YAC/B,oBAAoB,EAAE,kBAAkB,CAAC,IAAI,CAAC;SAC9C,CAAC;IAAA,CACF;CACD","sourcesContent":["/**\n * Subagent dispatch guard + lightweight task telemetry.\n *\n * The parent agent selects which subagent to delegate to (via the
|
|
1
|
+
{"version":3,"file":"dispatch-evaluator.js","sourceRoot":"","sources":["../../src/core/dispatch-evaluator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAShF,+EAA+E;AAC/E,SAAS,kBAAkB,CAAC,IAAY,EAA6B;IACpE,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,2EAA2E,CAAC,CAAC;IAC5G,MAAM,SAAS,GAAG,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAEvD,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;IACxD,MAAM,SAAS,GAAG,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAEpE,MAAM,SAAS,GAAG,wFAAwF,CAAC,IAAI,CAC9G,IAAI,CACJ,CAAC;IACF,MAAM,WAAW,GAAG,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,wBAAwB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEhG,IAAI,SAAS,GAAG,GAAG,IAAI,SAAS,IAAI,CAAC,IAAI,SAAS;QAAE,OAAO,MAAM,CAAC;IAClE,IAAI,SAAS,GAAG,EAAE,IAAI,SAAS,IAAI,CAAC,IAAI,WAAW;QAAE,OAAO,QAAQ,CAAC;IACrE,OAAO,KAAK,CAAC;AAAA,CACb;AAED,MAAM,OAAO,iBAAiB;IAC7B,QAAQ,CAAC,IAAY,EAAgB;QACpC,IAAI,CAAC,gBAAgB,EAAE,EAAE,CAAC;YACzB,MAAM,QAAQ,GAAG,uBAAuB,EAAE,CAAC;YAC3C,OAAO;gBACN,eAAe,EAAE,KAAK;gBACtB,qEAAqE;gBACrE,4CAA4C;gBAC5C,MAAM,EAAE,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,kCAAkC,CAAC,CAAC,CAAC,2BAA2B,QAAQ,WAAW;gBAC3G,oBAAoB,EAAE,KAAK;aAC3B,CAAC;QACH,CAAC;QAED,OAAO;YACN,eAAe,EAAE,IAAI;YACrB,MAAM,EAAE,uBAAuB;YAC/B,oBAAoB,EAAE,kBAAkB,CAAC,IAAI,CAAC;SAC9C,CAAC;IAAA,CACF;CACD","sourcesContent":["/**\n * Subagent dispatch guard + lightweight task telemetry.\n *\n * The parent agent selects which subagent to delegate to (via the Task tool),\n * so this module performs NO keyword routing. It survives for two narrow\n * responsibilities, both cheap and LLM-free:\n * 1. Depth guard — a process may only delegate while its depth is below the\n * tree-wide cap (HOOCODE_SUBAGENT_MAX_DEPTH, default 1). At the default cap\n * this means a subagent cannot spawn further subagents.\n * 2. Complexity estimate — a heuristic recorded in the dispatch log for\n * diagnostics only.\n */\n\nimport { canSpawnSubagent, resolveMaxSubagentDepth } from \"./subagent-depth.js\";\n\nexport interface TaskAnalysis {\n\t/** False only when the depth guard blocks delegation. */\n\tshould_delegate: boolean;\n\treason: string;\n\testimated_complexity: \"low\" | \"medium\" | \"high\";\n}\n\n/** Heuristic complexity estimate from file/line/scope mentions in the task. */\nfunction estimateComplexity(task: string): \"low\" | \"medium\" | \"high\" {\n\tconst fileMatches = task.match(/\\b[\\w/-]+\\.(ts|js|tsx|jsx|py|go|rs|java|cpp|c|h|md|json|yaml|yml|toml)\\b/g);\n\tconst fileCount = fileMatches ? fileMatches.length : 0;\n\n\tconst lineMatch = task.match(/(\\d+)\\s*(lines?|loc)\\b/i);\n\tconst lineCount = lineMatch ? Number.parseInt(lineMatch[1], 10) : 0;\n\n\tconst highScope = /\\b(across|multiple|many|several|all files|rearchitect|redesign|migrate|restructure)\\b/i.test(\n\t\ttask,\n\t);\n\tconst mediumScope = /\\b(2|3|4|5)\\s*files?\\b/i.test(task) || /\\b(few|some|couple)\\b/i.test(task);\n\n\tif (lineCount > 200 || fileCount >= 4 || highScope) return \"high\";\n\tif (lineCount > 50 || fileCount >= 2 || mediumScope) return \"medium\";\n\treturn \"low\";\n}\n\nexport class DispatchEvaluator {\n\tevaluate(task: string): TaskAnalysis {\n\t\tif (!canSpawnSubagent()) {\n\t\t\tconst maxDepth = resolveMaxSubagentDepth();\n\t\t\treturn {\n\t\t\t\tshould_delegate: false,\n\t\t\t\t// Preserve the original message at the default cap; report the depth\n\t\t\t\t// reached when nesting has been opted into.\n\t\t\t\treason: maxDepth <= 1 ? \"Subagents cannot spawn subagents\" : `Maximum subagent depth (${maxDepth}) reached`,\n\t\t\t\testimated_complexity: \"low\",\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tshould_delegate: true,\n\t\t\treason: \"delegated to subagent\",\n\t\t\testimated_complexity: estimateComplexity(task),\n\t\t};\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/core/messages.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Custom message types and transformers for the coding agent.\n *\n * Extends the base AgentMessage type with coding-agent specific message types,\n * and provides a transformer to convert them to LLM-compatible messages.\n */\n\nimport type { AgentMessage, BackgroundToolResult } from \"@kolisachint/hoocode-agent-core\";\nimport type { ImageContent, Message, TextContent } from \"@kolisachint/hoocode-ai\";\n\nexport const COMPACTION_SUMMARY_PREFIX = `The conversation history before this point was compacted into the following summary:\n\n<summary>\n`;\n\nexport const COMPACTION_SUMMARY_SUFFIX = `\n</summary>`;\n\nexport const BRANCH_SUMMARY_PREFIX = `The following is a summary of a branch that this conversation came back from:\n\n<summary>\n`;\n\nexport const BRANCH_SUMMARY_SUFFIX = `</summary>`;\n\n/**\n * Message type for bash executions via the ! command.\n */\nexport interface BashExecutionMessage {\n\trole: \"bashExecution\";\n\tcommand: string;\n\toutput: string;\n\texitCode: number | undefined;\n\tcancelled: boolean;\n\ttruncated: boolean;\n\tfullOutputPath?: string;\n\ttimestamp: number;\n\t/** If true, this message is excluded from LLM context (!! prefix) */\n\texcludeFromContext?: boolean;\n}\n\n/**\n * Message type for extension-injected messages via sendMessage().\n * These are custom messages that extensions can inject into the conversation.\n */\nexport interface CustomMessage<T = unknown> {\n\trole: \"custom\";\n\tcustomType: string;\n\tcontent: string | (TextContent | ImageContent)[];\n\tdisplay: boolean;\n\tdetails?: T;\n\ttimestamp: number;\n}\n\nexport interface BranchSummaryMessage {\n\trole: \"branchSummary\";\n\tsummary: string;\n\tfromId: string;\n\ttimestamp: number;\n}\n\nexport interface CompactionSummaryMessage {\n\trole: \"compactionSummary\";\n\tsummary: string;\n\ttokensBefore: number;\n\t/** Estimated context tokens after compaction; absent on entries written before this field existed. */\n\ttokensAfter?: number;\n\ttimestamp: number;\n}\n\n// Extend CustomAgentMessages via declaration merging\ndeclare module \"@kolisachint/hoocode-agent-core\" {\n\tinterface CustomAgentMessages {\n\t\tbashExecution: BashExecutionMessage;\n\t\tcustom: CustomMessage;\n\t\tbranchSummary: BranchSummaryMessage;\n\t\tcompactionSummary: CompactionSummaryMessage;\n\t}\n}\n\n/**\n * Convert a BashExecutionMessage to user message text for LLM context.\n */\nexport function bashExecutionToText(msg: BashExecutionMessage): string {\n\tlet text = `Ran \\`${msg.command}\\`\\n`;\n\tif (msg.output) {\n\t\ttext += `\\`\\`\\`\\n${msg.output}\\n\\`\\`\\``;\n\t} else {\n\t\ttext += \"(no output)\";\n\t}\n\tif (msg.cancelled) {\n\t\ttext += \"\\n\\n(command cancelled)\";\n\t} else if (msg.exitCode !== null && msg.exitCode !== undefined && msg.exitCode !== 0) {\n\t\ttext += `\\n\\nCommand exited with code ${msg.exitCode}`;\n\t}\n\tif (msg.truncated && msg.fullOutputPath) {\n\t\ttext += `\\n\\n[Output truncated. Full output: ${msg.fullOutputPath}]`;\n\t}\n\treturn text;\n}\n\nexport function createBranchSummaryMessage(summary: string, fromId: string, timestamp: string): BranchSummaryMessage {\n\treturn {\n\t\trole: \"branchSummary\",\n\t\tsummary,\n\t\tfromId,\n\t\ttimestamp: new Date(timestamp).getTime(),\n\t};\n}\n\nexport function createCompactionSummaryMessage(\n\tsummary: string,\n\ttokensBefore: number,\n\ttimestamp: string,\n\ttokensAfter?: number,\n): CompactionSummaryMessage {\n\treturn {\n\t\trole: \"compactionSummary\",\n\t\tsummary: summary,\n\t\ttokensBefore,\n\t\ttokensAfter,\n\t\ttimestamp: new Date(timestamp).getTime(),\n\t};\n}\n\n/** customType used for the follow-up message a finished background tool injects. */\nexport const BACKGROUND_TASK_CUSTOM_TYPE = \"backgroundTask\";\n\n/** Minimal shape of a tool call, shared by the placeholder and follow-up builders. */\ninterface BackgroundToolCall {\n\tname: string;\n\targuments?: Record<string, unknown>;\n}\n\n/** A consistent, human-readable description of a background tool call. */\nexport interface BackgroundToolInfo {\n\t/** True for MCP server tools (registered as `mcp_<server>_<tool>`). */\n\tisMcpTool: boolean;\n\t/** The subagent type for `Task` calls; the tool name otherwise. */\n\tsubagentType: string;\n\t/** Short label used verbatim in both the start and finish messages (kept in sync). */\n\tlabel: string;\n\t/** One-line summary of what the call is doing, derived from its arguments. */\n\tsummary?: string;\n}\n\n/** First non-empty line of a string, trimmed and capped for one-line display. */\nfunction firstLine(text: string, max = 120): string {\n\tconst line = (text.split(\"\\n\").find((l) => l.trim().length > 0) ?? \"\").trim();\n\treturn line.length > max ? `${line.slice(0, max - 1).trimEnd()}…` : line;\n}\n\n/** Summarize a tool's arguments as up to three `key: value` pairs for a one-liner. */\nexport function summarizeArgs(args: Record<string, unknown>): string | undefined {\n\tconst parts: string[] = [];\n\tfor (const [key, value] of Object.entries(args)) {\n\t\tif (value === undefined || value === null || value === \"\") continue;\n\t\tconst rendered = typeof value === \"string\" ? value : JSON.stringify(value);\n\t\tparts.push(`${key}: ${firstLine(rendered, 48)}`);\n\t\tif (parts.length === 3) break;\n\t}\n\treturn parts.length > 0 ? parts.join(\", \") : undefined;\n}\n\n/**\n * Describe a background tool call consistently, so the \"started\" placeholder, the\n * \"finished\" follow-up message, and any UI all read the same way. Subagent `Task`\n * calls are keyed off their `subagent_type`; MCP server tools off their `mcp_`\n * prefix.\n */\nexport function describeBackgroundTool(toolCall: BackgroundToolCall): BackgroundToolInfo {\n\tconst args = toolCall.arguments ?? {};\n\tconst isMcpTool = toolCall.name.startsWith(\"mcp_\");\n\n\tif (isMcpTool) {\n\t\t// Registered name is `mcp_<server>_<tool>`; drop the prefix for display.\n\t\tconst pretty = toolCall.name.replace(/^mcp_/, \"\");\n\t\treturn { isMcpTool, subagentType: toolCall.name, label: `MCP tool \\`${pretty}\\``, summary: summarizeArgs(args) };\n\t}\n\n\tconst subagentType = typeof args.subagent_type === \"string\" ? args.subagent_type : toolCall.name;\n\tconst summary =\n\t\ttypeof args.description === \"string\" && args.description.trim()\n\t\t\t? args.description.trim()\n\t\t\t: typeof args.prompt === \"string\"\n\t\t\t\t? firstLine(args.prompt)\n\t\t\t\t: undefined;\n\treturn { isMcpTool, subagentType, label: `subagent \\`${subagentType}\\``, summary };\n}\n\n/**\n * Verbose, human-readable placeholder shown the moment a background tool is\n * dispatched (before its result is known). Wired into the agent loop via\n * `createBackgroundPlaceholder`, it replaces the generic \"Started X in the\n * background\" line so the demo legibly explains what each background agent / MCP\n * tool is doing. Kept in sync with the finish message via {@link describeBackgroundTool}.\n */\nexport function createBackgroundPlaceholderText(toolCall: BackgroundToolCall): string {\n\tconst info = describeBackgroundTool(toolCall);\n\tconst lead = info.isMcpTool\n\t\t? `Started ${info.label} in the background — it runs on an external MCP server and may take a while.`\n\t\t: `Delegated to ${info.label} in the background — it runs in its own isolated context and cannot see this conversation.`;\n\tconst what = info.summary ? `\\nTask: ${info.summary}` : \"\";\n\treturn `${lead}${what}\\nIts result will arrive here as a follow-up message once it finishes — keep working in the meantime; you do not need to poll for it.`;\n}\n\n/**\n * Build the follow-up message injected when a background tool finishes.\n *\n * Handles both subagent `Task` calls and MCP tools, described consistently with\n * the start placeholder via {@link describeBackgroundTool}. Rendered as a distinct\n * custom message rather than a plain user message, and converted to a user message\n * for the LLM.\n */\nexport function createBackgroundTaskMessage(result: BackgroundToolResult): CustomMessage {\n\tconst info = describeBackgroundTool(result.toolCall);\n\tconst verb = result.isError ? \"failed\" : \"finished\";\n\tconst summary = info.summary ? ` (${info.summary})` : \"\";\n\tconst header = `Background ${info.label}${summary} ${verb}:`;\n\treturn {\n\t\trole: \"custom\",\n\t\tcustomType: BACKGROUND_TASK_CUSTOM_TYPE,\n\t\tcontent: [{ type: \"text\", text: header }, ...result.result.content],\n\t\tdisplay: true,\n\t\tdetails: { subagentType: info.subagentType, isMcpTool: info.isMcpTool, isError: result.isError },\n\t\ttimestamp: Date.now(),\n\t};\n}\n\n/** Convert CustomMessageEntry to AgentMessage format */\nexport function createCustomMessage(\n\tcustomType: string,\n\tcontent: string | (TextContent | ImageContent)[],\n\tdisplay: boolean,\n\tdetails: unknown | undefined,\n\ttimestamp: string,\n): CustomMessage {\n\treturn {\n\t\trole: \"custom\",\n\t\tcustomType,\n\t\tcontent,\n\t\tdisplay,\n\t\tdetails,\n\t\ttimestamp: new Date(timestamp).getTime(),\n\t};\n}\n\n/**\n * Transform AgentMessages (including custom types) to LLM-compatible Messages.\n *\n * This is used by:\n * - Agent's transormToLlm option (for prompt calls and queued messages)\n * - Compaction's generateSummary (for summarization)\n * - Custom extensions and tools\n */\nexport function convertToLlm(messages: AgentMessage[]): Message[] {\n\treturn messages\n\t\t.map((m): Message | undefined => {\n\t\t\tswitch (m.role) {\n\t\t\t\tcase \"bashExecution\":\n\t\t\t\t\t// Skip messages excluded from context (!! prefix)\n\t\t\t\t\tif (m.excludeFromContext) {\n\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t}\n\t\t\t\t\treturn {\n\t\t\t\t\t\trole: \"user\",\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: bashExecutionToText(m) }],\n\t\t\t\t\t\ttimestamp: m.timestamp,\n\t\t\t\t\t};\n\t\t\t\tcase \"custom\": {\n\t\t\t\t\tconst content = typeof m.content === \"string\" ? [{ type: \"text\" as const, text: m.content }] : m.content;\n\t\t\t\t\treturn {\n\t\t\t\t\t\trole: \"user\",\n\t\t\t\t\t\tcontent,\n\t\t\t\t\t\ttimestamp: m.timestamp,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tcase \"branchSummary\":\n\t\t\t\t\treturn {\n\t\t\t\t\t\trole: \"user\",\n\t\t\t\t\t\tcontent: [{ type: \"text\" as const, text: BRANCH_SUMMARY_PREFIX + m.summary + BRANCH_SUMMARY_SUFFIX }],\n\t\t\t\t\t\ttimestamp: m.timestamp,\n\t\t\t\t\t};\n\t\t\t\tcase \"compactionSummary\":\n\t\t\t\t\treturn {\n\t\t\t\t\t\trole: \"user\",\n\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t{ type: \"text\" as const, text: COMPACTION_SUMMARY_PREFIX + m.summary + COMPACTION_SUMMARY_SUFFIX },\n\t\t\t\t\t\t],\n\t\t\t\t\t\ttimestamp: m.timestamp,\n\t\t\t\t\t};\n\t\t\t\tcase \"user\":\n\t\t\t\tcase \"assistant\":\n\t\t\t\tcase \"toolResult\":\n\t\t\t\t\treturn m;\n\t\t\t\tdefault:\n\t\t\t\t\t// biome-ignore lint/correctness/noSwitchDeclarations: fine\n\t\t\t\t\tconst _exhaustiveCheck: never = m;\n\t\t\t\t\treturn undefined;\n\t\t\t}\n\t\t})\n\t\t.filter((m) => m !== undefined);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/core/messages.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Custom message types and transformers for the coding agent.\n *\n * Extends the base AgentMessage type with coding-agent specific message types,\n * and provides a transformer to convert them to LLM-compatible messages.\n */\n\nimport type { AgentMessage, BackgroundToolResult } from \"@kolisachint/hoocode-agent-core\";\nimport type { ImageContent, Message, TextContent } from \"@kolisachint/hoocode-ai\";\n\nexport const COMPACTION_SUMMARY_PREFIX = `The conversation history before this point was compacted into the following summary:\n\n<summary>\n`;\n\nexport const COMPACTION_SUMMARY_SUFFIX = `\n</summary>`;\n\nexport const BRANCH_SUMMARY_PREFIX = `The following is a summary of a branch that this conversation came back from:\n\n<summary>\n`;\n\nexport const BRANCH_SUMMARY_SUFFIX = `</summary>`;\n\n/**\n * Message type for bash executions via the ! command.\n */\nexport interface BashExecutionMessage {\n\trole: \"bashExecution\";\n\tcommand: string;\n\toutput: string;\n\texitCode: number | undefined;\n\tcancelled: boolean;\n\ttruncated: boolean;\n\tfullOutputPath?: string;\n\ttimestamp: number;\n\t/** If true, this message is excluded from LLM context (!! prefix) */\n\texcludeFromContext?: boolean;\n}\n\n/**\n * Message type for extension-injected messages via sendMessage().\n * These are custom messages that extensions can inject into the conversation.\n */\nexport interface CustomMessage<T = unknown> {\n\trole: \"custom\";\n\tcustomType: string;\n\tcontent: string | (TextContent | ImageContent)[];\n\tdisplay: boolean;\n\tdetails?: T;\n\ttimestamp: number;\n}\n\nexport interface BranchSummaryMessage {\n\trole: \"branchSummary\";\n\tsummary: string;\n\tfromId: string;\n\ttimestamp: number;\n}\n\nexport interface CompactionSummaryMessage {\n\trole: \"compactionSummary\";\n\tsummary: string;\n\ttokensBefore: number;\n\t/** Estimated context tokens after compaction; absent on entries written before this field existed. */\n\ttokensAfter?: number;\n\ttimestamp: number;\n}\n\n// Extend CustomAgentMessages via declaration merging\ndeclare module \"@kolisachint/hoocode-agent-core\" {\n\tinterface CustomAgentMessages {\n\t\tbashExecution: BashExecutionMessage;\n\t\tcustom: CustomMessage;\n\t\tbranchSummary: BranchSummaryMessage;\n\t\tcompactionSummary: CompactionSummaryMessage;\n\t}\n}\n\n/**\n * Convert a BashExecutionMessage to user message text for LLM context.\n */\nexport function bashExecutionToText(msg: BashExecutionMessage): string {\n\tlet text = `Ran \\`${msg.command}\\`\\n`;\n\tif (msg.output) {\n\t\ttext += `\\`\\`\\`\\n${msg.output}\\n\\`\\`\\``;\n\t} else {\n\t\ttext += \"(no output)\";\n\t}\n\tif (msg.cancelled) {\n\t\ttext += \"\\n\\n(command cancelled)\";\n\t} else if (msg.exitCode !== null && msg.exitCode !== undefined && msg.exitCode !== 0) {\n\t\ttext += `\\n\\nCommand exited with code ${msg.exitCode}`;\n\t}\n\tif (msg.truncated && msg.fullOutputPath) {\n\t\ttext += `\\n\\n[Output truncated. Full output: ${msg.fullOutputPath}]`;\n\t}\n\treturn text;\n}\n\nexport function createBranchSummaryMessage(summary: string, fromId: string, timestamp: string): BranchSummaryMessage {\n\treturn {\n\t\trole: \"branchSummary\",\n\t\tsummary,\n\t\tfromId,\n\t\ttimestamp: new Date(timestamp).getTime(),\n\t};\n}\n\nexport function createCompactionSummaryMessage(\n\tsummary: string,\n\ttokensBefore: number,\n\ttimestamp: string,\n\ttokensAfter?: number,\n): CompactionSummaryMessage {\n\treturn {\n\t\trole: \"compactionSummary\",\n\t\tsummary: summary,\n\t\ttokensBefore,\n\t\ttokensAfter,\n\t\ttimestamp: new Date(timestamp).getTime(),\n\t};\n}\n\n/** customType used for the follow-up message a finished background tool injects. */\nexport const BACKGROUND_TASK_CUSTOM_TYPE = \"backgroundTask\";\n\n/** Minimal shape of a tool call, shared by the placeholder and follow-up builders. */\ninterface BackgroundToolCall {\n\tname: string;\n\targuments?: Record<string, unknown>;\n}\n\n/** A consistent, human-readable description of a background tool call. */\nexport interface BackgroundToolInfo {\n\t/** True for MCP server tools (registered as `mcp_<server>_<tool>`). */\n\tisMcpTool: boolean;\n\t/** The subagent type for `Task` calls; the tool name otherwise. */\n\tsubagentType: string;\n\t/** Short label used verbatim in both the start and finish messages (kept in sync). */\n\tlabel: string;\n\t/** One-line summary of what the call is doing, derived from its arguments. */\n\tsummary?: string;\n}\n\n/** First non-empty line of a string, trimmed and capped for one-line display. */\nfunction firstLine(text: string, max = 120): string {\n\tconst line = (text.split(\"\\n\").find((l) => l.trim().length > 0) ?? \"\").trim();\n\treturn line.length > max ? `${line.slice(0, max - 1).trimEnd()}…` : line;\n}\n\n/** Summarize a tool's arguments as up to three `key: value` pairs for a one-liner. */\nexport function summarizeArgs(args: Record<string, unknown>): string | undefined {\n\tconst parts: string[] = [];\n\tfor (const [key, value] of Object.entries(args)) {\n\t\tif (value === undefined || value === null || value === \"\") continue;\n\t\tconst rendered = typeof value === \"string\" ? value : JSON.stringify(value);\n\t\tparts.push(`${key}: ${firstLine(rendered, 48)}`);\n\t\tif (parts.length === 3) break;\n\t}\n\treturn parts.length > 0 ? parts.join(\", \") : undefined;\n}\n\n/**\n * Describe a background tool call consistently, so the \"started\" placeholder, the\n * \"finished\" follow-up message, and any UI all read the same way. Subagent `Task`\n * calls are keyed off their `subagent_type`; MCP server tools off their `mcp_`\n * prefix.\n */\nexport function describeBackgroundTool(toolCall: BackgroundToolCall): BackgroundToolInfo {\n\tconst args = toolCall.arguments ?? {};\n\tconst isMcpTool = toolCall.name.startsWith(\"mcp_\");\n\n\tif (isMcpTool) {\n\t\t// Registered name is `mcp_<server>_<tool>`; drop the prefix for display.\n\t\tconst pretty = toolCall.name.replace(/^mcp_/, \"\");\n\t\treturn { isMcpTool, subagentType: toolCall.name, label: `MCP tool \\`${pretty}\\``, summary: summarizeArgs(args) };\n\t}\n\n\tconst subagentType = typeof args.subagent_type === \"string\" ? args.subagent_type : toolCall.name;\n\tconst summary =\n\t\ttypeof args.description === \"string\" && args.description.trim()\n\t\t\t? args.description.trim()\n\t\t\t: typeof args.prompt === \"string\"\n\t\t\t\t? firstLine(args.prompt)\n\t\t\t\t: undefined;\n\treturn { isMcpTool, subagentType, label: `subagent \\`${subagentType}\\``, summary };\n}\n\n/**\n * Verbose, human-readable placeholder shown the moment a background tool is\n * dispatched (before its result is known). Wired into the agent loop via\n * `createBackgroundPlaceholder`, it replaces the generic \"Started X in the\n * background\" line so the demo legibly explains what each background agent / MCP\n * tool is doing. Kept in sync with the finish message via {@link describeBackgroundTool}.\n */\nexport function createBackgroundPlaceholderText(toolCall: BackgroundToolCall): string {\n\tconst info = describeBackgroundTool(toolCall);\n\tconst what = info.summary ? ` — ${firstLine(info.summary, 80)}` : \"\";\n\tif (info.isMcpTool) {\n\t\treturn `Started ${info.label} in the background${what}. Its result arrives as a follow-up; keep working.`;\n\t}\n\t// One compact line: a verbose multi-line placeholder per dispatch floods the\n\t// transcript when several subagents spin up at once. The finish notification\n\t// names the task and the body is pulled with TaskOutput; TaskOutput(list) shows\n\t// progress meanwhile.\n\treturn `Delegated to ${info.label} in the background${what}. I'll be notified when it finishes; use TaskOutput to check progress or read the result.`;\n}\n\n/**\n * Build the follow-up message injected when a background tool finishes.\n *\n * Handles both subagent `Task` calls and MCP tools, described consistently with\n * the start placeholder via {@link describeBackgroundTool}. Rendered as a distinct\n * custom message rather than a plain user message, and converted to a user message\n * for the LLM.\n */\nexport function createBackgroundTaskMessage(result: BackgroundToolResult): CustomMessage {\n\tconst info = describeBackgroundTool(result.toolCall);\n\t// Subagent `Task`: the tool already returns a compact, self-contained\n\t// notification (the full body is retained in the inbox for TaskOutput to pull),\n\t// so the follow-up is exactly that line — no second header, no inlined body.\n\tif (!info.isMcpTool) {\n\t\treturn {\n\t\t\trole: \"custom\",\n\t\t\tcustomType: BACKGROUND_TASK_CUSTOM_TYPE,\n\t\t\tcontent: result.result.content,\n\t\t\tdisplay: true,\n\t\t\tdetails: { subagentType: info.subagentType, isMcpTool: false, isError: result.isError },\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\t}\n\t// MCP background tool: no inbox, so deliver the header + full result body.\n\tconst verb = result.isError ? \"failed\" : \"finished\";\n\tconst summary = info.summary ? ` (${info.summary})` : \"\";\n\tconst header = `Background ${info.label}${summary} ${verb}:`;\n\treturn {\n\t\trole: \"custom\",\n\t\tcustomType: BACKGROUND_TASK_CUSTOM_TYPE,\n\t\tcontent: [{ type: \"text\", text: header }, ...result.result.content],\n\t\tdisplay: true,\n\t\tdetails: { subagentType: info.subagentType, isMcpTool: true, isError: result.isError },\n\t\ttimestamp: Date.now(),\n\t};\n}\n\n/** Convert CustomMessageEntry to AgentMessage format */\nexport function createCustomMessage(\n\tcustomType: string,\n\tcontent: string | (TextContent | ImageContent)[],\n\tdisplay: boolean,\n\tdetails: unknown | undefined,\n\ttimestamp: string,\n): CustomMessage {\n\treturn {\n\t\trole: \"custom\",\n\t\tcustomType,\n\t\tcontent,\n\t\tdisplay,\n\t\tdetails,\n\t\ttimestamp: new Date(timestamp).getTime(),\n\t};\n}\n\n/**\n * Transform AgentMessages (including custom types) to LLM-compatible Messages.\n *\n * This is used by:\n * - Agent's transormToLlm option (for prompt calls and queued messages)\n * - Compaction's generateSummary (for summarization)\n * - Custom extensions and tools\n */\nexport function convertToLlm(messages: AgentMessage[]): Message[] {\n\treturn messages\n\t\t.map((m): Message | undefined => {\n\t\t\tswitch (m.role) {\n\t\t\t\tcase \"bashExecution\":\n\t\t\t\t\t// Skip messages excluded from context (!! prefix)\n\t\t\t\t\tif (m.excludeFromContext) {\n\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t}\n\t\t\t\t\treturn {\n\t\t\t\t\t\trole: \"user\",\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: bashExecutionToText(m) }],\n\t\t\t\t\t\ttimestamp: m.timestamp,\n\t\t\t\t\t};\n\t\t\t\tcase \"custom\": {\n\t\t\t\t\tconst content = typeof m.content === \"string\" ? [{ type: \"text\" as const, text: m.content }] : m.content;\n\t\t\t\t\treturn {\n\t\t\t\t\t\trole: \"user\",\n\t\t\t\t\t\tcontent,\n\t\t\t\t\t\ttimestamp: m.timestamp,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tcase \"branchSummary\":\n\t\t\t\t\treturn {\n\t\t\t\t\t\trole: \"user\",\n\t\t\t\t\t\tcontent: [{ type: \"text\" as const, text: BRANCH_SUMMARY_PREFIX + m.summary + BRANCH_SUMMARY_SUFFIX }],\n\t\t\t\t\t\ttimestamp: m.timestamp,\n\t\t\t\t\t};\n\t\t\t\tcase \"compactionSummary\":\n\t\t\t\t\treturn {\n\t\t\t\t\t\trole: \"user\",\n\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t{ type: \"text\" as const, text: COMPACTION_SUMMARY_PREFIX + m.summary + COMPACTION_SUMMARY_SUFFIX },\n\t\t\t\t\t\t],\n\t\t\t\t\t\ttimestamp: m.timestamp,\n\t\t\t\t\t};\n\t\t\t\tcase \"user\":\n\t\t\t\tcase \"assistant\":\n\t\t\t\tcase \"toolResult\":\n\t\t\t\t\treturn m;\n\t\t\t\tdefault:\n\t\t\t\t\t// biome-ignore lint/correctness/noSwitchDeclarations: fine\n\t\t\t\t\tconst _exhaustiveCheck: never = m;\n\t\t\t\t\treturn undefined;\n\t\t\t}\n\t\t})\n\t\t.filter((m) => m !== undefined);\n}\n"]}
|
package/dist/core/messages.js
CHANGED
|
@@ -105,11 +105,15 @@ export function describeBackgroundTool(toolCall) {
|
|
|
105
105
|
*/
|
|
106
106
|
export function createBackgroundPlaceholderText(toolCall) {
|
|
107
107
|
const info = describeBackgroundTool(toolCall);
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
108
|
+
const what = info.summary ? ` — ${firstLine(info.summary, 80)}` : "";
|
|
109
|
+
if (info.isMcpTool) {
|
|
110
|
+
return `Started ${info.label} in the background${what}. Its result arrives as a follow-up; keep working.`;
|
|
111
|
+
}
|
|
112
|
+
// One compact line: a verbose multi-line placeholder per dispatch floods the
|
|
113
|
+
// transcript when several subagents spin up at once. The finish notification
|
|
114
|
+
// names the task and the body is pulled with TaskOutput; TaskOutput(list) shows
|
|
115
|
+
// progress meanwhile.
|
|
116
|
+
return `Delegated to ${info.label} in the background${what}. I'll be notified when it finishes; use TaskOutput to check progress or read the result.`;
|
|
113
117
|
}
|
|
114
118
|
/**
|
|
115
119
|
* Build the follow-up message injected when a background tool finishes.
|
|
@@ -121,6 +125,20 @@ export function createBackgroundPlaceholderText(toolCall) {
|
|
|
121
125
|
*/
|
|
122
126
|
export function createBackgroundTaskMessage(result) {
|
|
123
127
|
const info = describeBackgroundTool(result.toolCall);
|
|
128
|
+
// Subagent `Task`: the tool already returns a compact, self-contained
|
|
129
|
+
// notification (the full body is retained in the inbox for TaskOutput to pull),
|
|
130
|
+
// so the follow-up is exactly that line — no second header, no inlined body.
|
|
131
|
+
if (!info.isMcpTool) {
|
|
132
|
+
return {
|
|
133
|
+
role: "custom",
|
|
134
|
+
customType: BACKGROUND_TASK_CUSTOM_TYPE,
|
|
135
|
+
content: result.result.content,
|
|
136
|
+
display: true,
|
|
137
|
+
details: { subagentType: info.subagentType, isMcpTool: false, isError: result.isError },
|
|
138
|
+
timestamp: Date.now(),
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
// MCP background tool: no inbox, so deliver the header + full result body.
|
|
124
142
|
const verb = result.isError ? "failed" : "finished";
|
|
125
143
|
const summary = info.summary ? ` (${info.summary})` : "";
|
|
126
144
|
const header = `Background ${info.label}${summary} ${verb}:`;
|
|
@@ -129,7 +147,7 @@ export function createBackgroundTaskMessage(result) {
|
|
|
129
147
|
customType: BACKGROUND_TASK_CUSTOM_TYPE,
|
|
130
148
|
content: [{ type: "text", text: header }, ...result.result.content],
|
|
131
149
|
display: true,
|
|
132
|
-
details: { subagentType: info.subagentType, isMcpTool:
|
|
150
|
+
details: { subagentType: info.subagentType, isMcpTool: true, isError: result.isError },
|
|
133
151
|
timestamp: Date.now(),
|
|
134
152
|
};
|
|
135
153
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/core/messages.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Custom message types and transformers for the coding agent.\n *\n * Extends the base AgentMessage type with coding-agent specific message types,\n * and provides a transformer to convert them to LLM-compatible messages.\n */\n\nimport type { AgentMessage, BackgroundToolResult } from \"@kolisachint/hoocode-agent-core\";\nimport type { ImageContent, Message, TextContent } from \"@kolisachint/hoocode-ai\";\n\nexport const COMPACTION_SUMMARY_PREFIX = `The conversation history before this point was compacted into the following summary:\n\n<summary>\n`;\n\nexport const COMPACTION_SUMMARY_SUFFIX = `\n</summary>`;\n\nexport const BRANCH_SUMMARY_PREFIX = `The following is a summary of a branch that this conversation came back from:\n\n<summary>\n`;\n\nexport const BRANCH_SUMMARY_SUFFIX = `</summary>`;\n\n/**\n * Message type for bash executions via the ! command.\n */\nexport interface BashExecutionMessage {\n\trole: \"bashExecution\";\n\tcommand: string;\n\toutput: string;\n\texitCode: number | undefined;\n\tcancelled: boolean;\n\ttruncated: boolean;\n\tfullOutputPath?: string;\n\ttimestamp: number;\n\t/** If true, this message is excluded from LLM context (!! prefix) */\n\texcludeFromContext?: boolean;\n}\n\n/**\n * Message type for extension-injected messages via sendMessage().\n * These are custom messages that extensions can inject into the conversation.\n */\nexport interface CustomMessage<T = unknown> {\n\trole: \"custom\";\n\tcustomType: string;\n\tcontent: string | (TextContent | ImageContent)[];\n\tdisplay: boolean;\n\tdetails?: T;\n\ttimestamp: number;\n}\n\nexport interface BranchSummaryMessage {\n\trole: \"branchSummary\";\n\tsummary: string;\n\tfromId: string;\n\ttimestamp: number;\n}\n\nexport interface CompactionSummaryMessage {\n\trole: \"compactionSummary\";\n\tsummary: string;\n\ttokensBefore: number;\n\t/** Estimated context tokens after compaction; absent on entries written before this field existed. */\n\ttokensAfter?: number;\n\ttimestamp: number;\n}\n\n// Extend CustomAgentMessages via declaration merging\ndeclare module \"@kolisachint/hoocode-agent-core\" {\n\tinterface CustomAgentMessages {\n\t\tbashExecution: BashExecutionMessage;\n\t\tcustom: CustomMessage;\n\t\tbranchSummary: BranchSummaryMessage;\n\t\tcompactionSummary: CompactionSummaryMessage;\n\t}\n}\n\n/**\n * Convert a BashExecutionMessage to user message text for LLM context.\n */\nexport function bashExecutionToText(msg: BashExecutionMessage): string {\n\tlet text = `Ran \\`${msg.command}\\`\\n`;\n\tif (msg.output) {\n\t\ttext += `\\`\\`\\`\\n${msg.output}\\n\\`\\`\\``;\n\t} else {\n\t\ttext += \"(no output)\";\n\t}\n\tif (msg.cancelled) {\n\t\ttext += \"\\n\\n(command cancelled)\";\n\t} else if (msg.exitCode !== null && msg.exitCode !== undefined && msg.exitCode !== 0) {\n\t\ttext += `\\n\\nCommand exited with code ${msg.exitCode}`;\n\t}\n\tif (msg.truncated && msg.fullOutputPath) {\n\t\ttext += `\\n\\n[Output truncated. Full output: ${msg.fullOutputPath}]`;\n\t}\n\treturn text;\n}\n\nexport function createBranchSummaryMessage(summary: string, fromId: string, timestamp: string): BranchSummaryMessage {\n\treturn {\n\t\trole: \"branchSummary\",\n\t\tsummary,\n\t\tfromId,\n\t\ttimestamp: new Date(timestamp).getTime(),\n\t};\n}\n\nexport function createCompactionSummaryMessage(\n\tsummary: string,\n\ttokensBefore: number,\n\ttimestamp: string,\n\ttokensAfter?: number,\n): CompactionSummaryMessage {\n\treturn {\n\t\trole: \"compactionSummary\",\n\t\tsummary: summary,\n\t\ttokensBefore,\n\t\ttokensAfter,\n\t\ttimestamp: new Date(timestamp).getTime(),\n\t};\n}\n\n/** customType used for the follow-up message a finished background tool injects. */\nexport const BACKGROUND_TASK_CUSTOM_TYPE = \"backgroundTask\";\n\n/** Minimal shape of a tool call, shared by the placeholder and follow-up builders. */\ninterface BackgroundToolCall {\n\tname: string;\n\targuments?: Record<string, unknown>;\n}\n\n/** A consistent, human-readable description of a background tool call. */\nexport interface BackgroundToolInfo {\n\t/** True for MCP server tools (registered as `mcp_<server>_<tool>`). */\n\tisMcpTool: boolean;\n\t/** The subagent type for `Task` calls; the tool name otherwise. */\n\tsubagentType: string;\n\t/** Short label used verbatim in both the start and finish messages (kept in sync). */\n\tlabel: string;\n\t/** One-line summary of what the call is doing, derived from its arguments. */\n\tsummary?: string;\n}\n\n/** First non-empty line of a string, trimmed and capped for one-line display. */\nfunction firstLine(text: string, max = 120): string {\n\tconst line = (text.split(\"\\n\").find((l) => l.trim().length > 0) ?? \"\").trim();\n\treturn line.length > max ? `${line.slice(0, max - 1).trimEnd()}…` : line;\n}\n\n/** Summarize a tool's arguments as up to three `key: value` pairs for a one-liner. */\nexport function summarizeArgs(args: Record<string, unknown>): string | undefined {\n\tconst parts: string[] = [];\n\tfor (const [key, value] of Object.entries(args)) {\n\t\tif (value === undefined || value === null || value === \"\") continue;\n\t\tconst rendered = typeof value === \"string\" ? value : JSON.stringify(value);\n\t\tparts.push(`${key}: ${firstLine(rendered, 48)}`);\n\t\tif (parts.length === 3) break;\n\t}\n\treturn parts.length > 0 ? parts.join(\", \") : undefined;\n}\n\n/**\n * Describe a background tool call consistently, so the \"started\" placeholder, the\n * \"finished\" follow-up message, and any UI all read the same way. Subagent `Task`\n * calls are keyed off their `subagent_type`; MCP server tools off their `mcp_`\n * prefix.\n */\nexport function describeBackgroundTool(toolCall: BackgroundToolCall): BackgroundToolInfo {\n\tconst args = toolCall.arguments ?? {};\n\tconst isMcpTool = toolCall.name.startsWith(\"mcp_\");\n\n\tif (isMcpTool) {\n\t\t// Registered name is `mcp_<server>_<tool>`; drop the prefix for display.\n\t\tconst pretty = toolCall.name.replace(/^mcp_/, \"\");\n\t\treturn { isMcpTool, subagentType: toolCall.name, label: `MCP tool \\`${pretty}\\``, summary: summarizeArgs(args) };\n\t}\n\n\tconst subagentType = typeof args.subagent_type === \"string\" ? args.subagent_type : toolCall.name;\n\tconst summary =\n\t\ttypeof args.description === \"string\" && args.description.trim()\n\t\t\t? args.description.trim()\n\t\t\t: typeof args.prompt === \"string\"\n\t\t\t\t? firstLine(args.prompt)\n\t\t\t\t: undefined;\n\treturn { isMcpTool, subagentType, label: `subagent \\`${subagentType}\\``, summary };\n}\n\n/**\n * Verbose, human-readable placeholder shown the moment a background tool is\n * dispatched (before its result is known). Wired into the agent loop via\n * `createBackgroundPlaceholder`, it replaces the generic \"Started X in the\n * background\" line so the demo legibly explains what each background agent / MCP\n * tool is doing. Kept in sync with the finish message via {@link describeBackgroundTool}.\n */\nexport function createBackgroundPlaceholderText(toolCall: BackgroundToolCall): string {\n\tconst info = describeBackgroundTool(toolCall);\n\tconst lead = info.isMcpTool\n\t\t? `Started ${info.label} in the background — it runs on an external MCP server and may take a while.`\n\t\t: `Delegated to ${info.label} in the background — it runs in its own isolated context and cannot see this conversation.`;\n\tconst what = info.summary ? `\\nTask: ${info.summary}` : \"\";\n\treturn `${lead}${what}\\nIts result will arrive here as a follow-up message once it finishes — keep working in the meantime; you do not need to poll for it.`;\n}\n\n/**\n * Build the follow-up message injected when a background tool finishes.\n *\n * Handles both subagent `Task` calls and MCP tools, described consistently with\n * the start placeholder via {@link describeBackgroundTool}. Rendered as a distinct\n * custom message rather than a plain user message, and converted to a user message\n * for the LLM.\n */\nexport function createBackgroundTaskMessage(result: BackgroundToolResult): CustomMessage {\n\tconst info = describeBackgroundTool(result.toolCall);\n\tconst verb = result.isError ? \"failed\" : \"finished\";\n\tconst summary = info.summary ? ` (${info.summary})` : \"\";\n\tconst header = `Background ${info.label}${summary} ${verb}:`;\n\treturn {\n\t\trole: \"custom\",\n\t\tcustomType: BACKGROUND_TASK_CUSTOM_TYPE,\n\t\tcontent: [{ type: \"text\", text: header }, ...result.result.content],\n\t\tdisplay: true,\n\t\tdetails: { subagentType: info.subagentType, isMcpTool: info.isMcpTool, isError: result.isError },\n\t\ttimestamp: Date.now(),\n\t};\n}\n\n/** Convert CustomMessageEntry to AgentMessage format */\nexport function createCustomMessage(\n\tcustomType: string,\n\tcontent: string | (TextContent | ImageContent)[],\n\tdisplay: boolean,\n\tdetails: unknown | undefined,\n\ttimestamp: string,\n): CustomMessage {\n\treturn {\n\t\trole: \"custom\",\n\t\tcustomType,\n\t\tcontent,\n\t\tdisplay,\n\t\tdetails,\n\t\ttimestamp: new Date(timestamp).getTime(),\n\t};\n}\n\n/**\n * Transform AgentMessages (including custom types) to LLM-compatible Messages.\n *\n * This is used by:\n * - Agent's transormToLlm option (for prompt calls and queued messages)\n * - Compaction's generateSummary (for summarization)\n * - Custom extensions and tools\n */\nexport function convertToLlm(messages: AgentMessage[]): Message[] {\n\treturn messages\n\t\t.map((m): Message | undefined => {\n\t\t\tswitch (m.role) {\n\t\t\t\tcase \"bashExecution\":\n\t\t\t\t\t// Skip messages excluded from context (!! prefix)\n\t\t\t\t\tif (m.excludeFromContext) {\n\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t}\n\t\t\t\t\treturn {\n\t\t\t\t\t\trole: \"user\",\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: bashExecutionToText(m) }],\n\t\t\t\t\t\ttimestamp: m.timestamp,\n\t\t\t\t\t};\n\t\t\t\tcase \"custom\": {\n\t\t\t\t\tconst content = typeof m.content === \"string\" ? [{ type: \"text\" as const, text: m.content }] : m.content;\n\t\t\t\t\treturn {\n\t\t\t\t\t\trole: \"user\",\n\t\t\t\t\t\tcontent,\n\t\t\t\t\t\ttimestamp: m.timestamp,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tcase \"branchSummary\":\n\t\t\t\t\treturn {\n\t\t\t\t\t\trole: \"user\",\n\t\t\t\t\t\tcontent: [{ type: \"text\" as const, text: BRANCH_SUMMARY_PREFIX + m.summary + BRANCH_SUMMARY_SUFFIX }],\n\t\t\t\t\t\ttimestamp: m.timestamp,\n\t\t\t\t\t};\n\t\t\t\tcase \"compactionSummary\":\n\t\t\t\t\treturn {\n\t\t\t\t\t\trole: \"user\",\n\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t{ type: \"text\" as const, text: COMPACTION_SUMMARY_PREFIX + m.summary + COMPACTION_SUMMARY_SUFFIX },\n\t\t\t\t\t\t],\n\t\t\t\t\t\ttimestamp: m.timestamp,\n\t\t\t\t\t};\n\t\t\t\tcase \"user\":\n\t\t\t\tcase \"assistant\":\n\t\t\t\tcase \"toolResult\":\n\t\t\t\t\treturn m;\n\t\t\t\tdefault:\n\t\t\t\t\t// biome-ignore lint/correctness/noSwitchDeclarations: fine\n\t\t\t\t\tconst _exhaustiveCheck: never = m;\n\t\t\t\t\treturn undefined;\n\t\t\t}\n\t\t})\n\t\t.filter((m) => m !== undefined);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/core/messages.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Custom message types and transformers for the coding agent.\n *\n * Extends the base AgentMessage type with coding-agent specific message types,\n * and provides a transformer to convert them to LLM-compatible messages.\n */\n\nimport type { AgentMessage, BackgroundToolResult } from \"@kolisachint/hoocode-agent-core\";\nimport type { ImageContent, Message, TextContent } from \"@kolisachint/hoocode-ai\";\n\nexport const COMPACTION_SUMMARY_PREFIX = `The conversation history before this point was compacted into the following summary:\n\n<summary>\n`;\n\nexport const COMPACTION_SUMMARY_SUFFIX = `\n</summary>`;\n\nexport const BRANCH_SUMMARY_PREFIX = `The following is a summary of a branch that this conversation came back from:\n\n<summary>\n`;\n\nexport const BRANCH_SUMMARY_SUFFIX = `</summary>`;\n\n/**\n * Message type for bash executions via the ! command.\n */\nexport interface BashExecutionMessage {\n\trole: \"bashExecution\";\n\tcommand: string;\n\toutput: string;\n\texitCode: number | undefined;\n\tcancelled: boolean;\n\ttruncated: boolean;\n\tfullOutputPath?: string;\n\ttimestamp: number;\n\t/** If true, this message is excluded from LLM context (!! prefix) */\n\texcludeFromContext?: boolean;\n}\n\n/**\n * Message type for extension-injected messages via sendMessage().\n * These are custom messages that extensions can inject into the conversation.\n */\nexport interface CustomMessage<T = unknown> {\n\trole: \"custom\";\n\tcustomType: string;\n\tcontent: string | (TextContent | ImageContent)[];\n\tdisplay: boolean;\n\tdetails?: T;\n\ttimestamp: number;\n}\n\nexport interface BranchSummaryMessage {\n\trole: \"branchSummary\";\n\tsummary: string;\n\tfromId: string;\n\ttimestamp: number;\n}\n\nexport interface CompactionSummaryMessage {\n\trole: \"compactionSummary\";\n\tsummary: string;\n\ttokensBefore: number;\n\t/** Estimated context tokens after compaction; absent on entries written before this field existed. */\n\ttokensAfter?: number;\n\ttimestamp: number;\n}\n\n// Extend CustomAgentMessages via declaration merging\ndeclare module \"@kolisachint/hoocode-agent-core\" {\n\tinterface CustomAgentMessages {\n\t\tbashExecution: BashExecutionMessage;\n\t\tcustom: CustomMessage;\n\t\tbranchSummary: BranchSummaryMessage;\n\t\tcompactionSummary: CompactionSummaryMessage;\n\t}\n}\n\n/**\n * Convert a BashExecutionMessage to user message text for LLM context.\n */\nexport function bashExecutionToText(msg: BashExecutionMessage): string {\n\tlet text = `Ran \\`${msg.command}\\`\\n`;\n\tif (msg.output) {\n\t\ttext += `\\`\\`\\`\\n${msg.output}\\n\\`\\`\\``;\n\t} else {\n\t\ttext += \"(no output)\";\n\t}\n\tif (msg.cancelled) {\n\t\ttext += \"\\n\\n(command cancelled)\";\n\t} else if (msg.exitCode !== null && msg.exitCode !== undefined && msg.exitCode !== 0) {\n\t\ttext += `\\n\\nCommand exited with code ${msg.exitCode}`;\n\t}\n\tif (msg.truncated && msg.fullOutputPath) {\n\t\ttext += `\\n\\n[Output truncated. Full output: ${msg.fullOutputPath}]`;\n\t}\n\treturn text;\n}\n\nexport function createBranchSummaryMessage(summary: string, fromId: string, timestamp: string): BranchSummaryMessage {\n\treturn {\n\t\trole: \"branchSummary\",\n\t\tsummary,\n\t\tfromId,\n\t\ttimestamp: new Date(timestamp).getTime(),\n\t};\n}\n\nexport function createCompactionSummaryMessage(\n\tsummary: string,\n\ttokensBefore: number,\n\ttimestamp: string,\n\ttokensAfter?: number,\n): CompactionSummaryMessage {\n\treturn {\n\t\trole: \"compactionSummary\",\n\t\tsummary: summary,\n\t\ttokensBefore,\n\t\ttokensAfter,\n\t\ttimestamp: new Date(timestamp).getTime(),\n\t};\n}\n\n/** customType used for the follow-up message a finished background tool injects. */\nexport const BACKGROUND_TASK_CUSTOM_TYPE = \"backgroundTask\";\n\n/** Minimal shape of a tool call, shared by the placeholder and follow-up builders. */\ninterface BackgroundToolCall {\n\tname: string;\n\targuments?: Record<string, unknown>;\n}\n\n/** A consistent, human-readable description of a background tool call. */\nexport interface BackgroundToolInfo {\n\t/** True for MCP server tools (registered as `mcp_<server>_<tool>`). */\n\tisMcpTool: boolean;\n\t/** The subagent type for `Task` calls; the tool name otherwise. */\n\tsubagentType: string;\n\t/** Short label used verbatim in both the start and finish messages (kept in sync). */\n\tlabel: string;\n\t/** One-line summary of what the call is doing, derived from its arguments. */\n\tsummary?: string;\n}\n\n/** First non-empty line of a string, trimmed and capped for one-line display. */\nfunction firstLine(text: string, max = 120): string {\n\tconst line = (text.split(\"\\n\").find((l) => l.trim().length > 0) ?? \"\").trim();\n\treturn line.length > max ? `${line.slice(0, max - 1).trimEnd()}…` : line;\n}\n\n/** Summarize a tool's arguments as up to three `key: value` pairs for a one-liner. */\nexport function summarizeArgs(args: Record<string, unknown>): string | undefined {\n\tconst parts: string[] = [];\n\tfor (const [key, value] of Object.entries(args)) {\n\t\tif (value === undefined || value === null || value === \"\") continue;\n\t\tconst rendered = typeof value === \"string\" ? value : JSON.stringify(value);\n\t\tparts.push(`${key}: ${firstLine(rendered, 48)}`);\n\t\tif (parts.length === 3) break;\n\t}\n\treturn parts.length > 0 ? parts.join(\", \") : undefined;\n}\n\n/**\n * Describe a background tool call consistently, so the \"started\" placeholder, the\n * \"finished\" follow-up message, and any UI all read the same way. Subagent `Task`\n * calls are keyed off their `subagent_type`; MCP server tools off their `mcp_`\n * prefix.\n */\nexport function describeBackgroundTool(toolCall: BackgroundToolCall): BackgroundToolInfo {\n\tconst args = toolCall.arguments ?? {};\n\tconst isMcpTool = toolCall.name.startsWith(\"mcp_\");\n\n\tif (isMcpTool) {\n\t\t// Registered name is `mcp_<server>_<tool>`; drop the prefix for display.\n\t\tconst pretty = toolCall.name.replace(/^mcp_/, \"\");\n\t\treturn { isMcpTool, subagentType: toolCall.name, label: `MCP tool \\`${pretty}\\``, summary: summarizeArgs(args) };\n\t}\n\n\tconst subagentType = typeof args.subagent_type === \"string\" ? args.subagent_type : toolCall.name;\n\tconst summary =\n\t\ttypeof args.description === \"string\" && args.description.trim()\n\t\t\t? args.description.trim()\n\t\t\t: typeof args.prompt === \"string\"\n\t\t\t\t? firstLine(args.prompt)\n\t\t\t\t: undefined;\n\treturn { isMcpTool, subagentType, label: `subagent \\`${subagentType}\\``, summary };\n}\n\n/**\n * Verbose, human-readable placeholder shown the moment a background tool is\n * dispatched (before its result is known). Wired into the agent loop via\n * `createBackgroundPlaceholder`, it replaces the generic \"Started X in the\n * background\" line so the demo legibly explains what each background agent / MCP\n * tool is doing. Kept in sync with the finish message via {@link describeBackgroundTool}.\n */\nexport function createBackgroundPlaceholderText(toolCall: BackgroundToolCall): string {\n\tconst info = describeBackgroundTool(toolCall);\n\tconst what = info.summary ? ` — ${firstLine(info.summary, 80)}` : \"\";\n\tif (info.isMcpTool) {\n\t\treturn `Started ${info.label} in the background${what}. Its result arrives as a follow-up; keep working.`;\n\t}\n\t// One compact line: a verbose multi-line placeholder per dispatch floods the\n\t// transcript when several subagents spin up at once. The finish notification\n\t// names the task and the body is pulled with TaskOutput; TaskOutput(list) shows\n\t// progress meanwhile.\n\treturn `Delegated to ${info.label} in the background${what}. I'll be notified when it finishes; use TaskOutput to check progress or read the result.`;\n}\n\n/**\n * Build the follow-up message injected when a background tool finishes.\n *\n * Handles both subagent `Task` calls and MCP tools, described consistently with\n * the start placeholder via {@link describeBackgroundTool}. Rendered as a distinct\n * custom message rather than a plain user message, and converted to a user message\n * for the LLM.\n */\nexport function createBackgroundTaskMessage(result: BackgroundToolResult): CustomMessage {\n\tconst info = describeBackgroundTool(result.toolCall);\n\t// Subagent `Task`: the tool already returns a compact, self-contained\n\t// notification (the full body is retained in the inbox for TaskOutput to pull),\n\t// so the follow-up is exactly that line — no second header, no inlined body.\n\tif (!info.isMcpTool) {\n\t\treturn {\n\t\t\trole: \"custom\",\n\t\t\tcustomType: BACKGROUND_TASK_CUSTOM_TYPE,\n\t\t\tcontent: result.result.content,\n\t\t\tdisplay: true,\n\t\t\tdetails: { subagentType: info.subagentType, isMcpTool: false, isError: result.isError },\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\t}\n\t// MCP background tool: no inbox, so deliver the header + full result body.\n\tconst verb = result.isError ? \"failed\" : \"finished\";\n\tconst summary = info.summary ? ` (${info.summary})` : \"\";\n\tconst header = `Background ${info.label}${summary} ${verb}:`;\n\treturn {\n\t\trole: \"custom\",\n\t\tcustomType: BACKGROUND_TASK_CUSTOM_TYPE,\n\t\tcontent: [{ type: \"text\", text: header }, ...result.result.content],\n\t\tdisplay: true,\n\t\tdetails: { subagentType: info.subagentType, isMcpTool: true, isError: result.isError },\n\t\ttimestamp: Date.now(),\n\t};\n}\n\n/** Convert CustomMessageEntry to AgentMessage format */\nexport function createCustomMessage(\n\tcustomType: string,\n\tcontent: string | (TextContent | ImageContent)[],\n\tdisplay: boolean,\n\tdetails: unknown | undefined,\n\ttimestamp: string,\n): CustomMessage {\n\treturn {\n\t\trole: \"custom\",\n\t\tcustomType,\n\t\tcontent,\n\t\tdisplay,\n\t\tdetails,\n\t\ttimestamp: new Date(timestamp).getTime(),\n\t};\n}\n\n/**\n * Transform AgentMessages (including custom types) to LLM-compatible Messages.\n *\n * This is used by:\n * - Agent's transormToLlm option (for prompt calls and queued messages)\n * - Compaction's generateSummary (for summarization)\n * - Custom extensions and tools\n */\nexport function convertToLlm(messages: AgentMessage[]): Message[] {\n\treturn messages\n\t\t.map((m): Message | undefined => {\n\t\t\tswitch (m.role) {\n\t\t\t\tcase \"bashExecution\":\n\t\t\t\t\t// Skip messages excluded from context (!! prefix)\n\t\t\t\t\tif (m.excludeFromContext) {\n\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t}\n\t\t\t\t\treturn {\n\t\t\t\t\t\trole: \"user\",\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: bashExecutionToText(m) }],\n\t\t\t\t\t\ttimestamp: m.timestamp,\n\t\t\t\t\t};\n\t\t\t\tcase \"custom\": {\n\t\t\t\t\tconst content = typeof m.content === \"string\" ? [{ type: \"text\" as const, text: m.content }] : m.content;\n\t\t\t\t\treturn {\n\t\t\t\t\t\trole: \"user\",\n\t\t\t\t\t\tcontent,\n\t\t\t\t\t\ttimestamp: m.timestamp,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tcase \"branchSummary\":\n\t\t\t\t\treturn {\n\t\t\t\t\t\trole: \"user\",\n\t\t\t\t\t\tcontent: [{ type: \"text\" as const, text: BRANCH_SUMMARY_PREFIX + m.summary + BRANCH_SUMMARY_SUFFIX }],\n\t\t\t\t\t\ttimestamp: m.timestamp,\n\t\t\t\t\t};\n\t\t\t\tcase \"compactionSummary\":\n\t\t\t\t\treturn {\n\t\t\t\t\t\trole: \"user\",\n\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t{ type: \"text\" as const, text: COMPACTION_SUMMARY_PREFIX + m.summary + COMPACTION_SUMMARY_SUFFIX },\n\t\t\t\t\t\t],\n\t\t\t\t\t\ttimestamp: m.timestamp,\n\t\t\t\t\t};\n\t\t\t\tcase \"user\":\n\t\t\t\tcase \"assistant\":\n\t\t\t\tcase \"toolResult\":\n\t\t\t\t\treturn m;\n\t\t\t\tdefault:\n\t\t\t\t\t// biome-ignore lint/correctness/noSwitchDeclarations: fine\n\t\t\t\t\tconst _exhaustiveCheck: never = m;\n\t\t\t\t\treturn undefined;\n\t\t\t}\n\t\t})\n\t\t.filter((m) => m !== undefined);\n}\n"]}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Model categories for subagent model selection.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* A category (`fast` | `standard` | `capable`) is a provider-neutral indirection
|
|
5
|
+
* that maps to an explicit model id via `settings.modelCategories`. No concrete
|
|
6
|
+
* model names are baked in here, so the feature never assumes a particular
|
|
7
|
+
* provider. When a category is not configured, it resolves to `undefined` —
|
|
8
|
+
* callers treat that as "no override" and fall back to the agent's or parent's
|
|
9
|
+
* default model.
|
|
6
10
|
*/
|
|
7
11
|
import type { Settings } from "./settings-manager.js";
|
|
8
12
|
/** Valid model category names */
|
|
@@ -10,19 +14,21 @@ export type ModelCategory = "fast" | "standard" | "capable";
|
|
|
10
14
|
/** Check if a string is a valid model category */
|
|
11
15
|
export declare function isModelCategory(value: string): value is ModelCategory;
|
|
12
16
|
/**
|
|
13
|
-
* Resolve a model category to
|
|
17
|
+
* Resolve a model category to the model id configured for it in settings, or
|
|
18
|
+
* `undefined` when the category is not configured. There is no built-in default:
|
|
19
|
+
* an unconfigured category is a no-op so the caller keeps its existing model.
|
|
14
20
|
*
|
|
15
21
|
* @param category - The model category (fast, standard, capable)
|
|
16
22
|
* @param settings - The current settings (may contain modelCategories config)
|
|
17
|
-
* @returns The resolved model ID or pattern
|
|
18
23
|
*/
|
|
19
|
-
export declare function resolveModelCategory(category: ModelCategory, settings?: Settings): string;
|
|
24
|
+
export declare function resolveModelCategory(category: ModelCategory, settings?: Settings): string | undefined;
|
|
20
25
|
/**
|
|
21
|
-
* Resolve a model string that might be a category reference.
|
|
26
|
+
* Resolve a model string that might be a category reference. A category resolves
|
|
27
|
+
* to its configured model id (or `undefined` when unconfigured); any other string
|
|
28
|
+
* is already a concrete model id or alias and is returned as-is.
|
|
22
29
|
*
|
|
23
30
|
* @param model - The model string (could be a category, alias, or full model ID)
|
|
24
31
|
* @param settings - The current settings (may contain modelCategories config)
|
|
25
|
-
* @returns The resolved model ID or pattern
|
|
26
32
|
*/
|
|
27
|
-
export declare function resolveModelReference(model: string, settings?: Settings): string;
|
|
33
|
+
export declare function resolveModelReference(model: string, settings?: Settings): string | undefined;
|
|
28
34
|
//# sourceMappingURL=model-categories.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-categories.d.ts","sourceRoot":"","sources":["../../src/core/model-categories.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"model-categories.d.ts","sourceRoot":"","sources":["../../src/core/model-categories.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEtD,iCAAiC;AACjC,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;AAE5D,kDAAkD;AAClD,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,aAAa,CAErE;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,aAAa,EAAE,QAAQ,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS,CAErG;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS,CAK5F","sourcesContent":["/**\n * Model categories for subagent model selection.\n *\n * A category (`fast` | `standard` | `capable`) is a provider-neutral indirection\n * that maps to an explicit model id via `settings.modelCategories`. No concrete\n * model names are baked in here, so the feature never assumes a particular\n * provider. When a category is not configured, it resolves to `undefined` —\n * callers treat that as \"no override\" and fall back to the agent's or parent's\n * default model.\n */\n\nimport type { Settings } from \"./settings-manager.js\";\n\n/** Valid model category names */\nexport type ModelCategory = \"fast\" | \"standard\" | \"capable\";\n\n/** Check if a string is a valid model category */\nexport function isModelCategory(value: string): value is ModelCategory {\n\treturn value === \"fast\" || value === \"standard\" || value === \"capable\";\n}\n\n/**\n * Resolve a model category to the model id configured for it in settings, or\n * `undefined` when the category is not configured. There is no built-in default:\n * an unconfigured category is a no-op so the caller keeps its existing model.\n *\n * @param category - The model category (fast, standard, capable)\n * @param settings - The current settings (may contain modelCategories config)\n */\nexport function resolveModelCategory(category: ModelCategory, settings?: Settings): string | undefined {\n\treturn settings?.modelCategories?.[category];\n}\n\n/**\n * Resolve a model string that might be a category reference. A category resolves\n * to its configured model id (or `undefined` when unconfigured); any other string\n * is already a concrete model id or alias and is returned as-is.\n *\n * @param model - The model string (could be a category, alias, or full model ID)\n * @param settings - The current settings (may contain modelCategories config)\n */\nexport function resolveModelReference(model: string, settings?: Settings): string | undefined {\n\tif (isModelCategory(model)) {\n\t\treturn resolveModelCategory(model, settings);\n\t}\n\treturn model;\n}\n"]}
|
|
@@ -1,51 +1,40 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Model categories for subagent model selection.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* A category (`fast` | `standard` | `capable`) is a provider-neutral indirection
|
|
5
|
+
* that maps to an explicit model id via `settings.modelCategories`. No concrete
|
|
6
|
+
* model names are baked in here, so the feature never assumes a particular
|
|
7
|
+
* provider. When a category is not configured, it resolves to `undefined` —
|
|
8
|
+
* callers treat that as "no override" and fall back to the agent's or parent's
|
|
9
|
+
* default model.
|
|
6
10
|
*/
|
|
7
11
|
/** Check if a string is a valid model category */
|
|
8
12
|
export function isModelCategory(value) {
|
|
9
13
|
return value === "fast" || value === "standard" || value === "capable";
|
|
10
14
|
}
|
|
11
15
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
|
|
15
|
-
const CATEGORY_FALLBACKS = {
|
|
16
|
-
fast: "haiku",
|
|
17
|
-
standard: "sonnet",
|
|
18
|
-
capable: "opus",
|
|
19
|
-
};
|
|
20
|
-
/**
|
|
21
|
-
* Resolve a model category to an actual model ID.
|
|
16
|
+
* Resolve a model category to the model id configured for it in settings, or
|
|
17
|
+
* `undefined` when the category is not configured. There is no built-in default:
|
|
18
|
+
* an unconfigured category is a no-op so the caller keeps its existing model.
|
|
22
19
|
*
|
|
23
20
|
* @param category - The model category (fast, standard, capable)
|
|
24
21
|
* @param settings - The current settings (may contain modelCategories config)
|
|
25
|
-
* @returns The resolved model ID or pattern
|
|
26
22
|
*/
|
|
27
23
|
export function resolveModelCategory(category, settings) {
|
|
28
|
-
|
|
29
|
-
const configured = settings?.modelCategories?.[category];
|
|
30
|
-
if (configured) {
|
|
31
|
-
return configured;
|
|
32
|
-
}
|
|
33
|
-
// Use fallback default
|
|
34
|
-
return CATEGORY_FALLBACKS[category];
|
|
24
|
+
return settings?.modelCategories?.[category];
|
|
35
25
|
}
|
|
36
26
|
/**
|
|
37
|
-
* Resolve a model string that might be a category reference.
|
|
27
|
+
* Resolve a model string that might be a category reference. A category resolves
|
|
28
|
+
* to its configured model id (or `undefined` when unconfigured); any other string
|
|
29
|
+
* is already a concrete model id or alias and is returned as-is.
|
|
38
30
|
*
|
|
39
31
|
* @param model - The model string (could be a category, alias, or full model ID)
|
|
40
32
|
* @param settings - The current settings (may contain modelCategories config)
|
|
41
|
-
* @returns The resolved model ID or pattern
|
|
42
33
|
*/
|
|
43
34
|
export function resolveModelReference(model, settings) {
|
|
44
|
-
// If it's a category, resolve it
|
|
45
35
|
if (isModelCategory(model)) {
|
|
46
36
|
return resolveModelCategory(model, settings);
|
|
47
37
|
}
|
|
48
|
-
// Otherwise return as-is (it's already a model ID or alias)
|
|
49
38
|
return model;
|
|
50
39
|
}
|
|
51
40
|
//# sourceMappingURL=model-categories.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-categories.js","sourceRoot":"","sources":["../../src/core/model-categories.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"model-categories.js","sourceRoot":"","sources":["../../src/core/model-categories.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH,kDAAkD;AAClD,MAAM,UAAU,eAAe,CAAC,KAAa,EAA0B;IACtE,OAAO,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,UAAU,IAAI,KAAK,KAAK,SAAS,CAAC;AAAA,CACvE;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB,CAAC,QAAuB,EAAE,QAAmB,EAAsB;IACtG,OAAO,QAAQ,EAAE,eAAe,EAAE,CAAC,QAAQ,CAAC,CAAC;AAAA,CAC7C;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAa,EAAE,QAAmB,EAAsB;IAC7F,IAAI,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,oBAAoB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IAC9C,CAAC;IACD,OAAO,KAAK,CAAC;AAAA,CACb","sourcesContent":["/**\n * Model categories for subagent model selection.\n *\n * A category (`fast` | `standard` | `capable`) is a provider-neutral indirection\n * that maps to an explicit model id via `settings.modelCategories`. No concrete\n * model names are baked in here, so the feature never assumes a particular\n * provider. When a category is not configured, it resolves to `undefined` —\n * callers treat that as \"no override\" and fall back to the agent's or parent's\n * default model.\n */\n\nimport type { Settings } from \"./settings-manager.js\";\n\n/** Valid model category names */\nexport type ModelCategory = \"fast\" | \"standard\" | \"capable\";\n\n/** Check if a string is a valid model category */\nexport function isModelCategory(value: string): value is ModelCategory {\n\treturn value === \"fast\" || value === \"standard\" || value === \"capable\";\n}\n\n/**\n * Resolve a model category to the model id configured for it in settings, or\n * `undefined` when the category is not configured. There is no built-in default:\n * an unconfigured category is a no-op so the caller keeps its existing model.\n *\n * @param category - The model category (fast, standard, capable)\n * @param settings - The current settings (may contain modelCategories config)\n */\nexport function resolveModelCategory(category: ModelCategory, settings?: Settings): string | undefined {\n\treturn settings?.modelCategories?.[category];\n}\n\n/**\n * Resolve a model string that might be a category reference. A category resolves\n * to its configured model id (or `undefined` when unconfigured); any other string\n * is already a concrete model id or alias and is returned as-is.\n *\n * @param model - The model string (could be a category, alias, or full model ID)\n * @param settings - The current settings (may contain modelCategories config)\n */\nexport function resolveModelReference(model: string, settings?: Settings): string | undefined {\n\tif (isModelCategory(model)) {\n\t\treturn resolveModelCategory(model, settings);\n\t}\n\treturn model;\n}\n"]}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* When the main session's turn fails with a usage/quota/rate-limit error that
|
|
5
5
|
* does not recover (retries exhausted or disabled), the session records the
|
|
6
|
-
* provider as "exhausted" for a short window. The subagent
|
|
6
|
+
* provider as "exhausted" for a short window. The subagent Task tool reads this
|
|
7
7
|
* to skip pointless spawns: subagents inherit the parent's provider, so they
|
|
8
8
|
* would hit the same wall. The signal is cleared on the next successful response
|
|
9
9
|
* and self-expires after a TTL so it never sticks longer than necessary.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider-health.d.ts","sourceRoot":"","sources":["../../src/core/provider-health.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,yEAAyE;AACzE,eAAO,MAAM,0BAA0B,QAAS,CAAC;AAEjD,MAAM,WAAW,kBAAkB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,EAAE,EAAE,MAAM,CAAC;IACX,4EAA4E;IAC5E,OAAO,EAAE,MAAM,CAAC;CAChB;AAID;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAKzE;AAED,kEAAkE;AAClE,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAO7E;AAED,qFAAqF;AACrF,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAE9D;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACpC,QAAQ,EAAE,MAAM,EAChB,KAAK,GAAE,MAAmC,GACxC,kBAAkB,GAAG,SAAS,CAQhC;AAED,0DAA0D;AAC1D,wBAAgB,6BAA6B,IAAI,IAAI,CAEpD","sourcesContent":["/**\n * Process-wide provider health signal.\n *\n * When the main session's turn fails with a usage/quota/rate-limit error that\n * does not recover (retries exhausted or disabled), the session records the\n * provider as \"exhausted\" for a short window. The subagent
|
|
1
|
+
{"version":3,"file":"provider-health.d.ts","sourceRoot":"","sources":["../../src/core/provider-health.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,yEAAyE;AACzE,eAAO,MAAM,0BAA0B,QAAS,CAAC;AAEjD,MAAM,WAAW,kBAAkB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,EAAE,EAAE,MAAM,CAAC;IACX,4EAA4E;IAC5E,OAAO,EAAE,MAAM,CAAC;CAChB;AAID;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAKzE;AAED,kEAAkE;AAClE,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAO7E;AAED,qFAAqF;AACrF,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAE9D;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACpC,QAAQ,EAAE,MAAM,EAChB,KAAK,GAAE,MAAmC,GACxC,kBAAkB,GAAG,SAAS,CAQhC;AAED,0DAA0D;AAC1D,wBAAgB,6BAA6B,IAAI,IAAI,CAEpD","sourcesContent":["/**\n * Process-wide provider health signal.\n *\n * When the main session's turn fails with a usage/quota/rate-limit error that\n * does not recover (retries exhausted or disabled), the session records the\n * provider as \"exhausted\" for a short window. The subagent Task tool reads this\n * to skip pointless spawns: subagents inherit the parent's provider, so they\n * would hit the same wall. The signal is cleared on the next successful response\n * and self-expires after a TTL so it never sticks longer than necessary.\n */\n\n/** How long an exhaustion signal stays active before it self-expires. */\nexport const PROVIDER_EXHAUSTION_TTL_MS = 45_000;\n\nexport interface ProviderExhaustion {\n\tprovider: string;\n\t/** Epoch ms when the exhaustion was recorded. */\n\tat: number;\n\t/** The provider error message that triggered it (truncated for display). */\n\tmessage: string;\n}\n\nconst records = new Map<string, ProviderExhaustion>();\n\n/**\n * Heuristic: does this provider error indicate quota/credit/rate-limit\n * exhaustion (as opposed to a transient network/overload blip)?\n */\nexport function isProviderQuotaError(message: string | undefined): boolean {\n\tif (!message) return false;\n\treturn /usage limit|quota|rate.?limit|too many requests|429|insufficient|out of credit|credit balance|billing|payment required|402|exceeded/i.test(\n\t\tmessage,\n\t);\n}\n\n/** Record that a provider is currently exhausted/rate-limited. */\nexport function markProviderExhausted(provider: string, message: string): void {\n\tconst trimmed = message.trim();\n\trecords.set(provider, {\n\t\tprovider,\n\t\tat: Date.now(),\n\t\tmessage: trimmed.length > 200 ? `${trimmed.slice(0, 199)}\\u2026` : trimmed,\n\t});\n}\n\n/** Clear any exhaustion signal for a provider (e.g. after a successful response). */\nexport function clearProviderExhaustion(provider: string): void {\n\trecords.delete(provider);\n}\n\n/**\n * Return the active exhaustion record for a provider, or undefined when none is\n * active or it has expired. Expired records are pruned on read.\n */\nexport function getProviderExhaustion(\n\tprovider: string,\n\tttlMs: number = PROVIDER_EXHAUSTION_TTL_MS,\n): ProviderExhaustion | undefined {\n\tconst record = records.get(provider);\n\tif (!record) return undefined;\n\tif (Date.now() - record.at >= ttlMs) {\n\t\trecords.delete(provider);\n\t\treturn undefined;\n\t}\n\treturn record;\n}\n\n/** Test helper: clear all recorded exhaustion signals. */\nexport function resetProviderHealthForTesting(): void {\n\trecords.clear();\n}\n"]}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* When the main session's turn fails with a usage/quota/rate-limit error that
|
|
5
5
|
* does not recover (retries exhausted or disabled), the session records the
|
|
6
|
-
* provider as "exhausted" for a short window. The subagent
|
|
6
|
+
* provider as "exhausted" for a short window. The subagent Task tool reads this
|
|
7
7
|
* to skip pointless spawns: subagents inherit the parent's provider, so they
|
|
8
8
|
* would hit the same wall. The signal is cleared on the next successful response
|
|
9
9
|
* and self-expires after a TTL so it never sticks longer than necessary.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider-health.js","sourceRoot":"","sources":["../../src/core/provider-health.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,yEAAyE;AACzE,MAAM,CAAC,MAAM,0BAA0B,GAAG,MAAM,CAAC;AAUjD,MAAM,OAAO,GAAG,IAAI,GAAG,EAA8B,CAAC;AAEtD;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAA2B,EAAW;IAC1E,IAAI,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC;IAC3B,OAAO,sIAAsI,CAAC,IAAI,CACjJ,OAAO,CACP,CAAC;AAAA,CACF;AAED,kEAAkE;AAClE,MAAM,UAAU,qBAAqB,CAAC,QAAgB,EAAE,OAAe,EAAQ;IAC9E,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAC/B,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE;QACrB,QAAQ;QACR,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;QACd,OAAO,EAAE,OAAO,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO;KAC1E,CAAC,CAAC;AAAA,CACH;AAED,qFAAqF;AACrF,MAAM,UAAU,uBAAuB,CAAC,QAAgB,EAAQ;IAC/D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAAA,CACzB;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CACpC,QAAgB,EAChB,KAAK,GAAW,0BAA0B,EACT;IACjC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACrC,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAC9B,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,EAAE,IAAI,KAAK,EAAE,CAAC;QACrC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACzB,OAAO,SAAS,CAAC;IAClB,CAAC;IACD,OAAO,MAAM,CAAC;AAAA,CACd;AAED,0DAA0D;AAC1D,MAAM,UAAU,6BAA6B,GAAS;IACrD,OAAO,CAAC,KAAK,EAAE,CAAC;AAAA,CAChB","sourcesContent":["/**\n * Process-wide provider health signal.\n *\n * When the main session's turn fails with a usage/quota/rate-limit error that\n * does not recover (retries exhausted or disabled), the session records the\n * provider as \"exhausted\" for a short window. The subagent
|
|
1
|
+
{"version":3,"file":"provider-health.js","sourceRoot":"","sources":["../../src/core/provider-health.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,yEAAyE;AACzE,MAAM,CAAC,MAAM,0BAA0B,GAAG,MAAM,CAAC;AAUjD,MAAM,OAAO,GAAG,IAAI,GAAG,EAA8B,CAAC;AAEtD;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAA2B,EAAW;IAC1E,IAAI,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC;IAC3B,OAAO,sIAAsI,CAAC,IAAI,CACjJ,OAAO,CACP,CAAC;AAAA,CACF;AAED,kEAAkE;AAClE,MAAM,UAAU,qBAAqB,CAAC,QAAgB,EAAE,OAAe,EAAQ;IAC9E,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAC/B,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE;QACrB,QAAQ;QACR,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;QACd,OAAO,EAAE,OAAO,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO;KAC1E,CAAC,CAAC;AAAA,CACH;AAED,qFAAqF;AACrF,MAAM,UAAU,uBAAuB,CAAC,QAAgB,EAAQ;IAC/D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAAA,CACzB;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CACpC,QAAgB,EAChB,KAAK,GAAW,0BAA0B,EACT;IACjC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACrC,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAC9B,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,EAAE,IAAI,KAAK,EAAE,CAAC;QACrC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACzB,OAAO,SAAS,CAAC;IAClB,CAAC;IACD,OAAO,MAAM,CAAC;AAAA,CACd;AAED,0DAA0D;AAC1D,MAAM,UAAU,6BAA6B,GAAS;IACrD,OAAO,CAAC,KAAK,EAAE,CAAC;AAAA,CAChB","sourcesContent":["/**\n * Process-wide provider health signal.\n *\n * When the main session's turn fails with a usage/quota/rate-limit error that\n * does not recover (retries exhausted or disabled), the session records the\n * provider as \"exhausted\" for a short window. The subagent Task tool reads this\n * to skip pointless spawns: subagents inherit the parent's provider, so they\n * would hit the same wall. The signal is cleared on the next successful response\n * and self-expires after a TTL so it never sticks longer than necessary.\n */\n\n/** How long an exhaustion signal stays active before it self-expires. */\nexport const PROVIDER_EXHAUSTION_TTL_MS = 45_000;\n\nexport interface ProviderExhaustion {\n\tprovider: string;\n\t/** Epoch ms when the exhaustion was recorded. */\n\tat: number;\n\t/** The provider error message that triggered it (truncated for display). */\n\tmessage: string;\n}\n\nconst records = new Map<string, ProviderExhaustion>();\n\n/**\n * Heuristic: does this provider error indicate quota/credit/rate-limit\n * exhaustion (as opposed to a transient network/overload blip)?\n */\nexport function isProviderQuotaError(message: string | undefined): boolean {\n\tif (!message) return false;\n\treturn /usage limit|quota|rate.?limit|too many requests|429|insufficient|out of credit|credit balance|billing|payment required|402|exceeded/i.test(\n\t\tmessage,\n\t);\n}\n\n/** Record that a provider is currently exhausted/rate-limited. */\nexport function markProviderExhausted(provider: string, message: string): void {\n\tconst trimmed = message.trim();\n\trecords.set(provider, {\n\t\tprovider,\n\t\tat: Date.now(),\n\t\tmessage: trimmed.length > 200 ? `${trimmed.slice(0, 199)}\\u2026` : trimmed,\n\t});\n}\n\n/** Clear any exhaustion signal for a provider (e.g. after a successful response). */\nexport function clearProviderExhaustion(provider: string): void {\n\trecords.delete(provider);\n}\n\n/**\n * Return the active exhaustion record for a provider, or undefined when none is\n * active or it has expired. Expired records are pruned on read.\n */\nexport function getProviderExhaustion(\n\tprovider: string,\n\tttlMs: number = PROVIDER_EXHAUSTION_TTL_MS,\n): ProviderExhaustion | undefined {\n\tconst record = records.get(provider);\n\tif (!record) return undefined;\n\tif (Date.now() - record.at >= ttlMs) {\n\t\trecords.delete(provider);\n\t\treturn undefined;\n\t}\n\treturn record;\n}\n\n/** Test helper: clear all recorded exhaustion signals. */\nexport function resetProviderHealthForTesting(): void {\n\trecords.clear();\n}\n"]}
|
|
@@ -43,8 +43,9 @@ export interface WarningSettings {
|
|
|
43
43
|
}
|
|
44
44
|
/**
|
|
45
45
|
* Model categories for subagent model selection.
|
|
46
|
-
* Categories map to explicit model IDs (e.g., "
|
|
47
|
-
* When a category is not configured,
|
|
46
|
+
* Categories map to explicit model IDs (e.g., "<provider>/<model-id>").
|
|
47
|
+
* When a category is not configured, no override is applied and the agent's or
|
|
48
|
+
* parent's default model is used.
|
|
48
49
|
*/
|
|
49
50
|
export interface ModelCategories {
|
|
50
51
|
/** Quick, cheap models for read-only exploration (grep, find, file discovery) */
|