@mcoda/mswarm 0.1.57 → 0.1.60
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/README.md +19 -0
- package/dist/codali-executor.d.ts +266 -0
- package/dist/codali-executor.d.ts.map +1 -0
- package/dist/codali-executor.js +227 -0
- package/dist/codali-executor.js.map +1 -0
- package/dist/runtime.d.ts +36 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +219 -30
- package/dist/runtime.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +54 -0
- package/dist/server.js.map +1 -1
- package/dist/vendor/codali/agents/AgentProtocol.d.ts +287 -0
- package/dist/vendor/codali/agents/AgentProtocol.d.ts.map +1 -0
- package/dist/vendor/codali/agents/AgentProtocol.js +365 -0
- package/dist/vendor/codali/agents/AgentResolver.d.ts +23 -0
- package/dist/vendor/codali/agents/AgentResolver.d.ts.map +1 -0
- package/dist/vendor/codali/agents/AgentResolver.js +77 -0
- package/dist/vendor/codali/agents/PhaseAgentSelector.d.ts +23 -0
- package/dist/vendor/codali/agents/PhaseAgentSelector.d.ts.map +1 -0
- package/dist/vendor/codali/agents/PhaseAgentSelector.js +287 -0
- package/dist/vendor/codali/cli/EvalCommand.d.ts +37 -0
- package/dist/vendor/codali/cli/EvalCommand.d.ts.map +1 -0
- package/dist/vendor/codali/cli/EvalCommand.js +333 -0
- package/dist/vendor/codali/cli/FeedbackCommand.d.ts +22 -0
- package/dist/vendor/codali/cli/FeedbackCommand.d.ts.map +1 -0
- package/dist/vendor/codali/cli/FeedbackCommand.js +163 -0
- package/dist/vendor/codali/cli/RunCommand.d.ts +78 -0
- package/dist/vendor/codali/cli/RunCommand.d.ts.map +1 -0
- package/dist/vendor/codali/cli/RunCommand.js +2261 -0
- package/dist/vendor/codali/cli.d.ts +3 -0
- package/dist/vendor/codali/cli.d.ts.map +1 -0
- package/dist/vendor/codali/cli.js +109 -0
- package/dist/vendor/codali/cognitive/ArchitectPlanner.d.ts +107 -0
- package/dist/vendor/codali/cognitive/ArchitectPlanner.d.ts.map +1 -0
- package/dist/vendor/codali/cognitive/ArchitectPlanner.js +1726 -0
- package/dist/vendor/codali/cognitive/BuilderOutputParser.d.ts +25 -0
- package/dist/vendor/codali/cognitive/BuilderOutputParser.d.ts.map +1 -0
- package/dist/vendor/codali/cognitive/BuilderOutputParser.js +164 -0
- package/dist/vendor/codali/cognitive/BuilderRunner.d.ts +76 -0
- package/dist/vendor/codali/cognitive/BuilderRunner.d.ts.map +1 -0
- package/dist/vendor/codali/cognitive/BuilderRunner.js +1159 -0
- package/dist/vendor/codali/cognitive/ContextAssembler.d.ts +91 -0
- package/dist/vendor/codali/cognitive/ContextAssembler.d.ts.map +1 -0
- package/dist/vendor/codali/cognitive/ContextAssembler.js +4547 -0
- package/dist/vendor/codali/cognitive/ContextBudget.d.ts +19 -0
- package/dist/vendor/codali/cognitive/ContextBudget.d.ts.map +1 -0
- package/dist/vendor/codali/cognitive/ContextBudget.js +35 -0
- package/dist/vendor/codali/cognitive/ContextFileLoader.d.ts +30 -0
- package/dist/vendor/codali/cognitive/ContextFileLoader.d.ts.map +1 -0
- package/dist/vendor/codali/cognitive/ContextFileLoader.js +307 -0
- package/dist/vendor/codali/cognitive/ContextManager.d.ts +47 -0
- package/dist/vendor/codali/cognitive/ContextManager.d.ts.map +1 -0
- package/dist/vendor/codali/cognitive/ContextManager.js +272 -0
- package/dist/vendor/codali/cognitive/ContextRedactor.d.ts +18 -0
- package/dist/vendor/codali/cognitive/ContextRedactor.d.ts.map +1 -0
- package/dist/vendor/codali/cognitive/ContextRedactor.js +53 -0
- package/dist/vendor/codali/cognitive/ContextSelector.d.ts +22 -0
- package/dist/vendor/codali/cognitive/ContextSelector.d.ts.map +1 -0
- package/dist/vendor/codali/cognitive/ContextSelector.js +431 -0
- package/dist/vendor/codali/cognitive/ContextSerializer.d.ts +8 -0
- package/dist/vendor/codali/cognitive/ContextSerializer.d.ts.map +1 -0
- package/dist/vendor/codali/cognitive/ContextSerializer.js +882 -0
- package/dist/vendor/codali/cognitive/ContextStore.d.ts +27 -0
- package/dist/vendor/codali/cognitive/ContextStore.d.ts.map +1 -0
- package/dist/vendor/codali/cognitive/ContextStore.js +79 -0
- package/dist/vendor/codali/cognitive/ContextSummarizer.d.ts +16 -0
- package/dist/vendor/codali/cognitive/ContextSummarizer.d.ts.map +1 -0
- package/dist/vendor/codali/cognitive/ContextSummarizer.js +45 -0
- package/dist/vendor/codali/cognitive/CostEstimator.d.ts +31 -0
- package/dist/vendor/codali/cognitive/CostEstimator.d.ts.map +1 -0
- package/dist/vendor/codali/cognitive/CostEstimator.js +66 -0
- package/dist/vendor/codali/cognitive/CriticEvaluator.d.ts +32 -0
- package/dist/vendor/codali/cognitive/CriticEvaluator.d.ts.map +1 -0
- package/dist/vendor/codali/cognitive/CriticEvaluator.js +297 -0
- package/dist/vendor/codali/cognitive/EvidenceGate.d.ts +9 -0
- package/dist/vendor/codali/cognitive/EvidenceGate.d.ts.map +1 -0
- package/dist/vendor/codali/cognitive/EvidenceGate.js +75 -0
- package/dist/vendor/codali/cognitive/GoldenExampleIndexer.d.ts +12 -0
- package/dist/vendor/codali/cognitive/GoldenExampleIndexer.d.ts.map +1 -0
- package/dist/vendor/codali/cognitive/GoldenExampleIndexer.js +34 -0
- package/dist/vendor/codali/cognitive/GoldenSetStore.d.ts +33 -0
- package/dist/vendor/codali/cognitive/GoldenSetStore.d.ts.map +1 -0
- package/dist/vendor/codali/cognitive/GoldenSetStore.js +159 -0
- package/dist/vendor/codali/cognitive/IntentSignals.d.ts +7 -0
- package/dist/vendor/codali/cognitive/IntentSignals.d.ts.map +1 -0
- package/dist/vendor/codali/cognitive/IntentSignals.js +285 -0
- package/dist/vendor/codali/cognitive/LearningGovernance.d.ts +100 -0
- package/dist/vendor/codali/cognitive/LearningGovernance.d.ts.map +1 -0
- package/dist/vendor/codali/cognitive/LearningGovernance.js +276 -0
- package/dist/vendor/codali/cognitive/MemoryWriteback.d.ts +64 -0
- package/dist/vendor/codali/cognitive/MemoryWriteback.d.ts.map +1 -0
- package/dist/vendor/codali/cognitive/MemoryWriteback.js +287 -0
- package/dist/vendor/codali/cognitive/PatchApplier.d.ts +49 -0
- package/dist/vendor/codali/cognitive/PatchApplier.d.ts.map +1 -0
- package/dist/vendor/codali/cognitive/PatchApplier.js +199 -0
- package/dist/vendor/codali/cognitive/PatchInterpreter.d.ts +35 -0
- package/dist/vendor/codali/cognitive/PatchInterpreter.d.ts.map +1 -0
- package/dist/vendor/codali/cognitive/PatchInterpreter.js +100 -0
- package/dist/vendor/codali/cognitive/PatchOutputNormalizer.d.ts +7 -0
- package/dist/vendor/codali/cognitive/PatchOutputNormalizer.d.ts.map +1 -0
- package/dist/vendor/codali/cognitive/PatchOutputNormalizer.js +59 -0
- package/dist/vendor/codali/cognitive/PostMortemAnalyzer.d.ts +17 -0
- package/dist/vendor/codali/cognitive/PostMortemAnalyzer.d.ts.map +1 -0
- package/dist/vendor/codali/cognitive/PostMortemAnalyzer.js +131 -0
- package/dist/vendor/codali/cognitive/PreferenceExtraction.d.ts +3 -0
- package/dist/vendor/codali/cognitive/PreferenceExtraction.d.ts.map +1 -0
- package/dist/vendor/codali/cognitive/PreferenceExtraction.js +85 -0
- package/dist/vendor/codali/cognitive/Prompts.d.ts +15 -0
- package/dist/vendor/codali/cognitive/Prompts.d.ts.map +1 -0
- package/dist/vendor/codali/cognitive/Prompts.js +326 -0
- package/dist/vendor/codali/cognitive/ProviderRouting.d.ts +16 -0
- package/dist/vendor/codali/cognitive/ProviderRouting.d.ts.map +1 -0
- package/dist/vendor/codali/cognitive/ProviderRouting.js +24 -0
- package/dist/vendor/codali/cognitive/QueryExtraction.d.ts +12 -0
- package/dist/vendor/codali/cognitive/QueryExtraction.d.ts.map +1 -0
- package/dist/vendor/codali/cognitive/QueryExtraction.js +262 -0
- package/dist/vendor/codali/cognitive/RunHistoryIndexer.d.ts +13 -0
- package/dist/vendor/codali/cognitive/RunHistoryIndexer.d.ts.map +1 -0
- package/dist/vendor/codali/cognitive/RunHistoryIndexer.js +125 -0
- package/dist/vendor/codali/cognitive/SmartPipeline.d.ts +92 -0
- package/dist/vendor/codali/cognitive/SmartPipeline.d.ts.map +1 -0
- package/dist/vendor/codali/cognitive/SmartPipeline.js +4804 -0
- package/dist/vendor/codali/cognitive/Types.d.ts +474 -0
- package/dist/vendor/codali/cognitive/Types.d.ts.map +1 -0
- package/dist/vendor/codali/cognitive/Types.js +7 -0
- package/dist/vendor/codali/cognitive/ValidationRunner.d.ts +57 -0
- package/dist/vendor/codali/cognitive/ValidationRunner.d.ts.map +1 -0
- package/dist/vendor/codali/cognitive/ValidationRunner.js +515 -0
- package/dist/vendor/codali/config/Config.d.ts +249 -0
- package/dist/vendor/codali/config/Config.d.ts.map +1 -0
- package/dist/vendor/codali/config/Config.js +200 -0
- package/dist/vendor/codali/config/ConfigLoader.d.ts +56 -0
- package/dist/vendor/codali/config/ConfigLoader.d.ts.map +1 -0
- package/dist/vendor/codali/config/ConfigLoader.js +1246 -0
- package/dist/vendor/codali/docdex/DocdexClient.d.ts +113 -0
- package/dist/vendor/codali/docdex/DocdexClient.d.ts.map +1 -0
- package/dist/vendor/codali/docdex/DocdexClient.js +524 -0
- package/dist/vendor/codali/eval/EvalRunner.d.ts +35 -0
- package/dist/vendor/codali/eval/EvalRunner.d.ts.map +1 -0
- package/dist/vendor/codali/eval/EvalRunner.js +38 -0
- package/dist/vendor/codali/eval/EvalTaskExecutor.d.ts +81 -0
- package/dist/vendor/codali/eval/EvalTaskExecutor.d.ts.map +1 -0
- package/dist/vendor/codali/eval/EvalTaskExecutor.js +371 -0
- package/dist/vendor/codali/eval/GateEvaluator.d.ts +31 -0
- package/dist/vendor/codali/eval/GateEvaluator.d.ts.map +1 -0
- package/dist/vendor/codali/eval/GateEvaluator.js +134 -0
- package/dist/vendor/codali/eval/MetricTypes.d.ts +28 -0
- package/dist/vendor/codali/eval/MetricTypes.d.ts.map +1 -0
- package/dist/vendor/codali/eval/MetricTypes.js +1 -0
- package/dist/vendor/codali/eval/MetricsAggregator.d.ts +4 -0
- package/dist/vendor/codali/eval/MetricsAggregator.d.ts.map +1 -0
- package/dist/vendor/codali/eval/MetricsAggregator.js +97 -0
- package/dist/vendor/codali/eval/RegressionComparator.d.ts +29 -0
- package/dist/vendor/codali/eval/RegressionComparator.d.ts.map +1 -0
- package/dist/vendor/codali/eval/RegressionComparator.js +155 -0
- package/dist/vendor/codali/eval/ReportInputAdapter.d.ts +52 -0
- package/dist/vendor/codali/eval/ReportInputAdapter.d.ts.map +1 -0
- package/dist/vendor/codali/eval/ReportInputAdapter.js +229 -0
- package/dist/vendor/codali/eval/ReportSerializer.d.ts +32 -0
- package/dist/vendor/codali/eval/ReportSerializer.d.ts.map +1 -0
- package/dist/vendor/codali/eval/ReportSerializer.js +33 -0
- package/dist/vendor/codali/eval/ReportStore.d.ts +18 -0
- package/dist/vendor/codali/eval/ReportStore.d.ts.map +1 -0
- package/dist/vendor/codali/eval/ReportStore.js +96 -0
- package/dist/vendor/codali/eval/SuiteLoader.d.ts +12 -0
- package/dist/vendor/codali/eval/SuiteLoader.d.ts.map +1 -0
- package/dist/vendor/codali/eval/SuiteLoader.js +51 -0
- package/dist/vendor/codali/eval/SuiteSchema.d.ts +56 -0
- package/dist/vendor/codali/eval/SuiteSchema.d.ts.map +1 -0
- package/dist/vendor/codali/eval/SuiteSchema.js +357 -0
- package/dist/vendor/codali/index.d.ts +11 -0
- package/dist/vendor/codali/index.d.ts.map +1 -0
- package/dist/vendor/codali/index.js +5 -0
- package/dist/vendor/codali/providers/CodexCliProvider.d.ts +8 -0
- package/dist/vendor/codali/providers/CodexCliProvider.d.ts.map +1 -0
- package/dist/vendor/codali/providers/CodexCliProvider.js +282 -0
- package/dist/vendor/codali/providers/OllamaRemoteProvider.d.ts +8 -0
- package/dist/vendor/codali/providers/OllamaRemoteProvider.d.ts.map +1 -0
- package/dist/vendor/codali/providers/OllamaRemoteProvider.js +300 -0
- package/dist/vendor/codali/providers/OpenAiCompatibleProvider.d.ts +8 -0
- package/dist/vendor/codali/providers/OpenAiCompatibleProvider.d.ts.map +1 -0
- package/dist/vendor/codali/providers/OpenAiCompatibleProvider.js +192 -0
- package/dist/vendor/codali/providers/ProviderRegistry.d.ts +12 -0
- package/dist/vendor/codali/providers/ProviderRegistry.d.ts.map +1 -0
- package/dist/vendor/codali/providers/ProviderRegistry.js +28 -0
- package/dist/vendor/codali/providers/ProviderTypes.d.ts +81 -0
- package/dist/vendor/codali/providers/ProviderTypes.d.ts.map +1 -0
- package/dist/vendor/codali/providers/ProviderTypes.js +1 -0
- package/dist/vendor/codali/runtime/CodaliRuntime.d.ts +183 -0
- package/dist/vendor/codali/runtime/CodaliRuntime.d.ts.map +1 -0
- package/dist/vendor/codali/runtime/CodaliRuntime.js +1363 -0
- package/dist/vendor/codali/runtime/DeepInvestigationErrors.d.ts +39 -0
- package/dist/vendor/codali/runtime/DeepInvestigationErrors.d.ts.map +1 -0
- package/dist/vendor/codali/runtime/DeepInvestigationErrors.js +57 -0
- package/dist/vendor/codali/runtime/RunContext.d.ts +27 -0
- package/dist/vendor/codali/runtime/RunContext.d.ts.map +1 -0
- package/dist/vendor/codali/runtime/RunContext.js +51 -0
- package/dist/vendor/codali/runtime/RunLogQuery.d.ts +48 -0
- package/dist/vendor/codali/runtime/RunLogQuery.d.ts.map +1 -0
- package/dist/vendor/codali/runtime/RunLogQuery.js +36 -0
- package/dist/vendor/codali/runtime/RunLogReader.d.ts +19 -0
- package/dist/vendor/codali/runtime/RunLogReader.d.ts.map +1 -0
- package/dist/vendor/codali/runtime/RunLogReader.js +361 -0
- package/dist/vendor/codali/runtime/RunLogger.d.ts +71 -0
- package/dist/vendor/codali/runtime/RunLogger.d.ts.map +1 -0
- package/dist/vendor/codali/runtime/RunLogger.js +100 -0
- package/dist/vendor/codali/runtime/RunTelemetryTypes.d.ts +117 -0
- package/dist/vendor/codali/runtime/RunTelemetryTypes.d.ts.map +1 -0
- package/dist/vendor/codali/runtime/RunTelemetryTypes.js +299 -0
- package/dist/vendor/codali/runtime/Runner.d.ts +66 -0
- package/dist/vendor/codali/runtime/Runner.d.ts.map +1 -0
- package/dist/vendor/codali/runtime/Runner.js +215 -0
- package/dist/vendor/codali/runtime/StoragePaths.d.ts +3 -0
- package/dist/vendor/codali/runtime/StoragePaths.d.ts.map +1 -0
- package/dist/vendor/codali/runtime/StoragePaths.js +19 -0
- package/dist/vendor/codali/runtime/WorkspaceLock.d.ts +30 -0
- package/dist/vendor/codali/runtime/WorkspaceLock.d.ts.map +1 -0
- package/dist/vendor/codali/runtime/WorkspaceLock.js +141 -0
- package/dist/vendor/codali/session/InstructionLoader.d.ts +14 -0
- package/dist/vendor/codali/session/InstructionLoader.d.ts.map +1 -0
- package/dist/vendor/codali/session/InstructionLoader.js +107 -0
- package/dist/vendor/codali/session/SessionStore.d.ts +81 -0
- package/dist/vendor/codali/session/SessionStore.d.ts.map +1 -0
- package/dist/vendor/codali/session/SessionStore.js +244 -0
- package/dist/vendor/codali/subagents/SubagentOrchestrator.d.ts +68 -0
- package/dist/vendor/codali/subagents/SubagentOrchestrator.d.ts.map +1 -0
- package/dist/vendor/codali/subagents/SubagentOrchestrator.js +150 -0
- package/dist/vendor/codali/tools/ToolRegistry.d.ts +9 -0
- package/dist/vendor/codali/tools/ToolRegistry.d.ts.map +1 -0
- package/dist/vendor/codali/tools/ToolRegistry.js +263 -0
- package/dist/vendor/codali/tools/ToolTypes.d.ts +66 -0
- package/dist/vendor/codali/tools/ToolTypes.d.ts.map +1 -0
- package/dist/vendor/codali/tools/ToolTypes.js +32 -0
- package/dist/vendor/codali/tools/diff/DiffTool.d.ts +3 -0
- package/dist/vendor/codali/tools/diff/DiffTool.d.ts.map +1 -0
- package/dist/vendor/codali/tools/diff/DiffTool.js +34 -0
- package/dist/vendor/codali/tools/docdex/DocdexTools.d.ts +4 -0
- package/dist/vendor/codali/tools/docdex/DocdexTools.d.ts.map +1 -0
- package/dist/vendor/codali/tools/docdex/DocdexTools.js +453 -0
- package/dist/vendor/codali/tools/filesystem/FileTools.d.ts +3 -0
- package/dist/vendor/codali/tools/filesystem/FileTools.d.ts.map +1 -0
- package/dist/vendor/codali/tools/filesystem/FileTools.js +141 -0
- package/dist/vendor/codali/tools/search/SearchTool.d.ts +3 -0
- package/dist/vendor/codali/tools/search/SearchTool.d.ts.map +1 -0
- package/dist/vendor/codali/tools/search/SearchTool.js +46 -0
- package/dist/vendor/codali/tools/shell/ShellTool.d.ts +3 -0
- package/dist/vendor/codali/tools/shell/ShellTool.d.ts.map +1 -0
- package/dist/vendor/codali/tools/shell/ShellTool.js +104 -0
- package/package.json +5 -3
|
@@ -0,0 +1,1363 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { normalizeAgentRequest, parseAgentRequest, } from "../agents/AgentProtocol.js";
|
|
3
|
+
import { createProvider } from "../providers/ProviderRegistry.js";
|
|
4
|
+
import { OpenAiCompatibleProvider } from "../providers/OpenAiCompatibleProvider.js";
|
|
5
|
+
import { OllamaRemoteProvider } from "../providers/OllamaRemoteProvider.js";
|
|
6
|
+
import { CodexCliProvider } from "../providers/CodexCliProvider.js";
|
|
7
|
+
import { DocdexClient } from "../docdex/DocdexClient.js";
|
|
8
|
+
import { createDiffTool } from "../tools/diff/DiffTool.js";
|
|
9
|
+
import { createDocdexTools } from "../tools/docdex/DocdexTools.js";
|
|
10
|
+
import { createFileTools } from "../tools/filesystem/FileTools.js";
|
|
11
|
+
import { createSearchTool } from "../tools/search/SearchTool.js";
|
|
12
|
+
import { createShellTool } from "../tools/shell/ShellTool.js";
|
|
13
|
+
import { ToolRegistry } from "../tools/ToolRegistry.js";
|
|
14
|
+
import { formatInstructionBlocks, loadInstructionBlocks } from "../session/InstructionLoader.js";
|
|
15
|
+
import { SessionStore } from "../session/SessionStore.js";
|
|
16
|
+
import { SubagentOrchestrator, } from "../subagents/SubagentOrchestrator.js";
|
|
17
|
+
import { Runner, RunnerBudgetError } from "./Runner.js";
|
|
18
|
+
const DEFAULT_DOCDEX_BASE_URL = "http://127.0.0.1:28491";
|
|
19
|
+
const WRITE_TOOL_NAMES = new Set([
|
|
20
|
+
"write_file",
|
|
21
|
+
"docdex_memory_save",
|
|
22
|
+
"docdex_save_preference",
|
|
23
|
+
"docdex_index_rebuild",
|
|
24
|
+
"docdex_index_ingest",
|
|
25
|
+
"docdex_delegate",
|
|
26
|
+
"docdex_hooks_validate",
|
|
27
|
+
]);
|
|
28
|
+
const WEB_TOOL_NAMES = new Set(["docdex_web_research"]);
|
|
29
|
+
const MEMORY_WRITE_TOOL_NAMES = new Set(["docdex_memory_save"]);
|
|
30
|
+
const PROFILE_WRITE_TOOL_NAMES = new Set(["docdex_save_preference"]);
|
|
31
|
+
const INDEX_REBUILD_TOOL_NAMES = new Set(["docdex_index_rebuild", "docdex_index_ingest"]);
|
|
32
|
+
const RUNTIME_TO_PROTOCOL_NEEDS = new Map([
|
|
33
|
+
["docdex_search", ["docdex.search"]],
|
|
34
|
+
["docdex_open", ["docdex.open", "docdex.snippet"]],
|
|
35
|
+
["docdex_open_file", ["docdex.open"]],
|
|
36
|
+
["docdex_symbols", ["docdex.symbols"]],
|
|
37
|
+
["docdex_ast", ["docdex.ast"]],
|
|
38
|
+
["docdex_web_research", ["docdex.web"]],
|
|
39
|
+
["docdex_impact_graph", ["docdex.impact"]],
|
|
40
|
+
["docdex_impact_diagnostics", ["docdex.impact_diagnostics"]],
|
|
41
|
+
["docdex_tree", ["docdex.tree"]],
|
|
42
|
+
["docdex_dag_export", ["docdex.dag_export"]],
|
|
43
|
+
["read_file", ["file.read"]],
|
|
44
|
+
["list_files", ["file.list"]],
|
|
45
|
+
["diff_summary", ["file.diff"]],
|
|
46
|
+
]);
|
|
47
|
+
const PROTOCOL_TO_RUNTIME_TOOL_NAMES = new Map([
|
|
48
|
+
["docdex.search", ["docdex_search"]],
|
|
49
|
+
["docdex.open", ["docdex_open", "docdex_open_file"]],
|
|
50
|
+
["docdex.snippet", ["docdex_open"]],
|
|
51
|
+
["docdex.symbols", ["docdex_symbols"]],
|
|
52
|
+
["docdex.ast", ["docdex_ast"]],
|
|
53
|
+
["docdex.web", ["docdex_web_research"]],
|
|
54
|
+
["docdex.impact", ["docdex_impact_graph"]],
|
|
55
|
+
["docdex.impact_diagnostics", ["docdex_impact_diagnostics"]],
|
|
56
|
+
["docdex.tree", ["docdex_tree"]],
|
|
57
|
+
["docdex.dag_export", ["docdex_dag_export"]],
|
|
58
|
+
["file.read", ["read_file"]],
|
|
59
|
+
["file.list", ["list_files"]],
|
|
60
|
+
["file.diff", ["diff_summary"]],
|
|
61
|
+
]);
|
|
62
|
+
const PROTOCOL_REQUEST_HEADER = "AGENT_REQUEST v1";
|
|
63
|
+
const stripUndefined = (input) => {
|
|
64
|
+
const output = {};
|
|
65
|
+
for (const [key, value] of Object.entries(input)) {
|
|
66
|
+
if (value !== undefined)
|
|
67
|
+
output[key] = value;
|
|
68
|
+
}
|
|
69
|
+
return output;
|
|
70
|
+
};
|
|
71
|
+
const isRecord = (value) => {
|
|
72
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
73
|
+
};
|
|
74
|
+
const parseJsonPayload = (output) => {
|
|
75
|
+
const trimmed = output.trim();
|
|
76
|
+
if (!trimmed || (!trimmed.startsWith("{") && !trimmed.startsWith("[")))
|
|
77
|
+
return undefined;
|
|
78
|
+
try {
|
|
79
|
+
return JSON.parse(trimmed);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
const payloadForToolResult = (result) => {
|
|
86
|
+
if (!result.ok) {
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
return result.data ?? parseJsonPayload(result.output) ?? result.output;
|
|
90
|
+
};
|
|
91
|
+
const toolResultContent = (result) => {
|
|
92
|
+
if (result.ok) {
|
|
93
|
+
return result.output;
|
|
94
|
+
}
|
|
95
|
+
return `ERROR[${result.error?.code ?? "tool_execution_failed"}]: ${result.error?.message ?? "tool failed"}`;
|
|
96
|
+
};
|
|
97
|
+
const arrayFromPayload = (payload, keys) => {
|
|
98
|
+
if (Array.isArray(payload))
|
|
99
|
+
return payload;
|
|
100
|
+
if (isRecord(payload)) {
|
|
101
|
+
for (const key of keys) {
|
|
102
|
+
const value = payload[key];
|
|
103
|
+
if (Array.isArray(value))
|
|
104
|
+
return value;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return payload === undefined ? [] : [payload];
|
|
108
|
+
};
|
|
109
|
+
const stringFromPayload = (payload, keys, fallback) => {
|
|
110
|
+
if (typeof payload === "string")
|
|
111
|
+
return payload;
|
|
112
|
+
if (isRecord(payload)) {
|
|
113
|
+
for (const key of keys) {
|
|
114
|
+
const value = payload[key];
|
|
115
|
+
if (typeof value === "string")
|
|
116
|
+
return value;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return fallback;
|
|
120
|
+
};
|
|
121
|
+
const truncateProtocolString = (value, maxLength = 1200) => {
|
|
122
|
+
return value.length > maxLength ? `${value.slice(0, maxLength)}... [truncated]` : value;
|
|
123
|
+
};
|
|
124
|
+
const compactProtocolPayload = (value, depth = 0) => {
|
|
125
|
+
if (typeof value === "string")
|
|
126
|
+
return truncateProtocolString(value);
|
|
127
|
+
if (typeof value !== "object" || value === null)
|
|
128
|
+
return value;
|
|
129
|
+
if (Array.isArray(value)) {
|
|
130
|
+
return value.slice(0, 5).map((entry) => compactProtocolPayload(entry, depth + 1));
|
|
131
|
+
}
|
|
132
|
+
if (depth > 2)
|
|
133
|
+
return "[object truncated]";
|
|
134
|
+
const input = value;
|
|
135
|
+
const preferredKeys = [
|
|
136
|
+
"type",
|
|
137
|
+
"query",
|
|
138
|
+
"doc_id",
|
|
139
|
+
"rel_path",
|
|
140
|
+
"path",
|
|
141
|
+
"title",
|
|
142
|
+
"url",
|
|
143
|
+
"line_start",
|
|
144
|
+
"line_end",
|
|
145
|
+
"score",
|
|
146
|
+
"summary",
|
|
147
|
+
"snippet",
|
|
148
|
+
"content",
|
|
149
|
+
"status",
|
|
150
|
+
"id",
|
|
151
|
+
"role",
|
|
152
|
+
"goal",
|
|
153
|
+
"toolCallsExecuted",
|
|
154
|
+
"touchedFiles",
|
|
155
|
+
"warnings",
|
|
156
|
+
"error",
|
|
157
|
+
"metadata",
|
|
158
|
+
];
|
|
159
|
+
const keys = preferredKeys.some((key) => key in input)
|
|
160
|
+
? preferredKeys.filter((key) => key in input)
|
|
161
|
+
: Object.keys(input).slice(0, 12);
|
|
162
|
+
const output = {};
|
|
163
|
+
for (const key of keys) {
|
|
164
|
+
output[key] = compactProtocolPayload(input[key], depth + 1);
|
|
165
|
+
}
|
|
166
|
+
const omitted = Object.keys(input).length - keys.length;
|
|
167
|
+
if (omitted > 0)
|
|
168
|
+
output._omitted_keys = omitted;
|
|
169
|
+
return output;
|
|
170
|
+
};
|
|
171
|
+
const compactSubagentResultForProtocol = (result) => ({
|
|
172
|
+
id: result.id,
|
|
173
|
+
role: result.role,
|
|
174
|
+
goal: result.goal,
|
|
175
|
+
status: result.status,
|
|
176
|
+
summary: truncateProtocolString(result.summary, 600),
|
|
177
|
+
toolCallsExecuted: result.toolCallsExecuted,
|
|
178
|
+
touchedFiles: result.touchedFiles,
|
|
179
|
+
warnings: result.warnings.slice(0, 5),
|
|
180
|
+
error: result.error,
|
|
181
|
+
metadata: result.metadata,
|
|
182
|
+
});
|
|
183
|
+
const matchesSimplePattern = (entry, pattern) => {
|
|
184
|
+
if (!pattern.includes("*"))
|
|
185
|
+
return entry.includes(pattern);
|
|
186
|
+
const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
|
|
187
|
+
return new RegExp(`^${escaped}$`).test(entry);
|
|
188
|
+
};
|
|
189
|
+
const extractAgentRequestText = (content) => {
|
|
190
|
+
const trimmed = content.trim();
|
|
191
|
+
if (!trimmed)
|
|
192
|
+
return undefined;
|
|
193
|
+
if (trimmed.startsWith("{") &&
|
|
194
|
+
/"request_id"\s*:/.test(trimmed) &&
|
|
195
|
+
/"needs"\s*:/.test(trimmed)) {
|
|
196
|
+
return trimmed;
|
|
197
|
+
}
|
|
198
|
+
const markerMatch = /^AGENT_REQUEST\s+v1$/im.exec(trimmed);
|
|
199
|
+
if (!markerMatch || markerMatch.index === undefined)
|
|
200
|
+
return undefined;
|
|
201
|
+
let requestText = trimmed.slice(markerMatch.index).trim();
|
|
202
|
+
const fenceEnd = requestText.indexOf("```", PROTOCOL_REQUEST_HEADER.length);
|
|
203
|
+
if (fenceEnd !== -1) {
|
|
204
|
+
requestText = requestText.slice(0, fenceEnd).trim();
|
|
205
|
+
}
|
|
206
|
+
return requestText;
|
|
207
|
+
};
|
|
208
|
+
const allowedProtocolNeedTypes = (registry, allowDelegation) => {
|
|
209
|
+
const needs = new Set();
|
|
210
|
+
for (const tool of registry.list()) {
|
|
211
|
+
for (const need of RUNTIME_TO_PROTOCOL_NEEDS.get(tool.name) ?? []) {
|
|
212
|
+
needs.add(need);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
if (allowDelegation)
|
|
216
|
+
needs.add("agent.delegate");
|
|
217
|
+
return Array.from(needs).sort();
|
|
218
|
+
};
|
|
219
|
+
const buildProtocolSystemPrompt = (registry, options = {}) => {
|
|
220
|
+
const needs = allowedProtocolNeedTypes(registry, options.allowDelegation === true);
|
|
221
|
+
const needList = needs.length ? needs.join(", ") : "none";
|
|
222
|
+
const lines = [
|
|
223
|
+
"You are running inside Codali, a local orchestration client that can execute tools for you between model turns.",
|
|
224
|
+
"You cannot call tools directly. When you need repo files, Docdex index data, local graph context, web research, or workspace state, respond with exactly one AGENT_REQUEST v1 message and no prose.",
|
|
225
|
+
`Allowed need types for this run: ${needList}.`,
|
|
226
|
+
"After Codali replies with CODALI_RESPONSE v1, use those results, decide whether another AGENT_REQUEST is needed, and continue until you can answer the user.",
|
|
227
|
+
"Do not invent tool results. Use docdex.search/open/symbols/ast/tree/impact for repo truth, docdex.web for external/current facts, and file.read/list/diff for workspace state.",
|
|
228
|
+
"Request format:",
|
|
229
|
+
"AGENT_REQUEST v1",
|
|
230
|
+
"role: agent",
|
|
231
|
+
"request_id: short-unique-id",
|
|
232
|
+
"needs:",
|
|
233
|
+
" - type: docdex.search",
|
|
234
|
+
' query: "search query"',
|
|
235
|
+
" limit: 5",
|
|
236
|
+
"context:",
|
|
237
|
+
' summary: "why this context is needed"',
|
|
238
|
+
...(options.allowDelegation
|
|
239
|
+
? [
|
|
240
|
+
"Delegation format:",
|
|
241
|
+
"AGENT_REQUEST v1",
|
|
242
|
+
"role: agent",
|
|
243
|
+
"request_id: delegate-1",
|
|
244
|
+
"needs:",
|
|
245
|
+
" - type: agent.delegate",
|
|
246
|
+
" role: explorer",
|
|
247
|
+
' goal: "inspect the repo context needed for this task"',
|
|
248
|
+
" tools: docdex.search, docdex.open, file.read",
|
|
249
|
+
" allowed_paths: packages/codali/src",
|
|
250
|
+
]
|
|
251
|
+
: []),
|
|
252
|
+
"When you have enough information, answer normally without AGENT_REQUEST.",
|
|
253
|
+
];
|
|
254
|
+
const instructionText = formatInstructionBlocks(options.instructionBlocks ?? []);
|
|
255
|
+
if (instructionText) {
|
|
256
|
+
lines.push("Loaded project instructions:", instructionText);
|
|
257
|
+
}
|
|
258
|
+
if (options.resumeBundle) {
|
|
259
|
+
lines.push("Resume context:", JSON.stringify({
|
|
260
|
+
session_id: options.resumeBundle.metadata.sessionId,
|
|
261
|
+
task: options.resumeBundle.metadata.task,
|
|
262
|
+
latest_summary: options.resumeBundle.latestSummary?.summary,
|
|
263
|
+
recent_events: options.resumeBundle.recentEvents.map((event) => ({
|
|
264
|
+
type: event.type,
|
|
265
|
+
run_id: event.runId,
|
|
266
|
+
data: event.data,
|
|
267
|
+
})),
|
|
268
|
+
}, null, 2));
|
|
269
|
+
}
|
|
270
|
+
return lines.join("\n");
|
|
271
|
+
};
|
|
272
|
+
const protocolToolExecutionForNeed = (need, input, runId) => {
|
|
273
|
+
if (need.tool === "docdex.search") {
|
|
274
|
+
return { need, toolName: "docdex_search", args: stripUndefined(need.params) };
|
|
275
|
+
}
|
|
276
|
+
if (need.tool === "docdex.open") {
|
|
277
|
+
return {
|
|
278
|
+
need,
|
|
279
|
+
toolName: "docdex_open",
|
|
280
|
+
args: stripUndefined({
|
|
281
|
+
path: need.params.path,
|
|
282
|
+
startLine: need.params.start_line,
|
|
283
|
+
endLine: need.params.end_line,
|
|
284
|
+
head: need.params.head,
|
|
285
|
+
clamp: need.params.clamp,
|
|
286
|
+
}),
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
if (need.tool === "docdex.snippet") {
|
|
290
|
+
return {
|
|
291
|
+
need,
|
|
292
|
+
toolName: "docdex_open",
|
|
293
|
+
args: stripUndefined({ docId: need.params.doc_id, window: need.params.window, textOnly: true }),
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
if (need.tool === "docdex.symbols") {
|
|
297
|
+
return { need, toolName: "docdex_symbols", args: { path: need.params.file } };
|
|
298
|
+
}
|
|
299
|
+
if (need.tool === "docdex.ast") {
|
|
300
|
+
return {
|
|
301
|
+
need,
|
|
302
|
+
toolName: "docdex_ast",
|
|
303
|
+
args: stripUndefined({ path: need.params.file, maxNodes: need.params.max_nodes }),
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
if (need.tool === "docdex.web") {
|
|
307
|
+
return {
|
|
308
|
+
need,
|
|
309
|
+
toolName: "docdex_web_research",
|
|
310
|
+
args: stripUndefined({
|
|
311
|
+
query: need.params.query,
|
|
312
|
+
forceWeb: need.params.force_web ?? true,
|
|
313
|
+
}),
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
if (need.tool === "docdex.impact") {
|
|
317
|
+
return { need, toolName: "docdex_impact_graph", args: { file: need.params.file } };
|
|
318
|
+
}
|
|
319
|
+
if (need.tool === "docdex.impact_diagnostics") {
|
|
320
|
+
return {
|
|
321
|
+
need,
|
|
322
|
+
toolName: "docdex_impact_diagnostics",
|
|
323
|
+
args: stripUndefined(need.params),
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
if (need.tool === "docdex.tree") {
|
|
327
|
+
return {
|
|
328
|
+
need,
|
|
329
|
+
toolName: "docdex_tree",
|
|
330
|
+
args: stripUndefined({
|
|
331
|
+
path: need.params.path,
|
|
332
|
+
maxDepth: need.params.max_depth,
|
|
333
|
+
dirsOnly: need.params.dirs_only,
|
|
334
|
+
includeHidden: need.params.include_hidden,
|
|
335
|
+
}),
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
if (need.tool === "docdex.dag_export") {
|
|
339
|
+
return {
|
|
340
|
+
need,
|
|
341
|
+
toolName: "docdex_dag_export",
|
|
342
|
+
args: stripUndefined({
|
|
343
|
+
sessionId: need.params.session_id ?? input.docdex?.dagSessionId ?? input.metadata?.requestId ?? runId,
|
|
344
|
+
format: need.params.format,
|
|
345
|
+
maxNodes: need.params.max_nodes,
|
|
346
|
+
}),
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
if (need.tool === "file.list") {
|
|
350
|
+
return { need, toolName: "list_files", args: { path: need.params.root, maxDepth: 3 } };
|
|
351
|
+
}
|
|
352
|
+
if (need.tool === "file.diff") {
|
|
353
|
+
return { need, toolName: "diff_summary", args: { maxLines: 200 } };
|
|
354
|
+
}
|
|
355
|
+
if (need.tool === "file.read") {
|
|
356
|
+
return { need, toolName: "read_file", args: { path: need.params.path } };
|
|
357
|
+
}
|
|
358
|
+
throw new Error(`Unsupported protocol need for tool execution: ${need.tool}`);
|
|
359
|
+
};
|
|
360
|
+
const protocolResultFromToolResult = (execution, result, warnings) => {
|
|
361
|
+
const payload = payloadForToolResult(result);
|
|
362
|
+
const content = toolResultContent(result);
|
|
363
|
+
if (!result.ok) {
|
|
364
|
+
warnings.push(`${execution.need.tool} via ${execution.toolName} failed: ${result.error?.message ?? "tool failed"}`);
|
|
365
|
+
}
|
|
366
|
+
const need = execution.need;
|
|
367
|
+
if (need.tool === "docdex.search") {
|
|
368
|
+
return {
|
|
369
|
+
type: "docdex.search",
|
|
370
|
+
query: need.params.query,
|
|
371
|
+
hits: result.ok
|
|
372
|
+
? arrayFromPayload(payload, ["results", "hits"]).map((entry) => compactProtocolPayload(entry))
|
|
373
|
+
: [{ error: content }],
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
if (need.tool === "docdex.open") {
|
|
377
|
+
return {
|
|
378
|
+
type: "docdex.open",
|
|
379
|
+
path: need.params.path,
|
|
380
|
+
content: truncateProtocolString(stringFromPayload(payload, ["content", "text", "snippet"], content), 4000),
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
if (need.tool === "docdex.snippet") {
|
|
384
|
+
return {
|
|
385
|
+
type: "docdex.snippet",
|
|
386
|
+
doc_id: need.params.doc_id,
|
|
387
|
+
content: truncateProtocolString(stringFromPayload(payload, ["content", "text", "snippet"], content), 4000),
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
if (need.tool === "docdex.symbols") {
|
|
391
|
+
return {
|
|
392
|
+
type: "docdex.symbols",
|
|
393
|
+
file: need.params.file,
|
|
394
|
+
symbols: result.ok ? compactProtocolPayload(payload) : { error: content },
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
if (need.tool === "docdex.ast") {
|
|
398
|
+
return {
|
|
399
|
+
type: "docdex.ast",
|
|
400
|
+
file: need.params.file,
|
|
401
|
+
nodes: result.ok
|
|
402
|
+
? compactProtocolPayload(isRecord(payload) && payload.nodes ? payload.nodes : payload)
|
|
403
|
+
: { error: content },
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
if (need.tool === "docdex.web") {
|
|
407
|
+
return {
|
|
408
|
+
type: "docdex.web",
|
|
409
|
+
query: need.params.query,
|
|
410
|
+
results: result.ok
|
|
411
|
+
? arrayFromPayload(payload, ["results", "web_results", "hits"]).map((entry) => compactProtocolPayload(entry))
|
|
412
|
+
: [{ error: content }],
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
if (need.tool === "docdex.impact") {
|
|
416
|
+
return {
|
|
417
|
+
type: "docdex.impact",
|
|
418
|
+
file: need.params.file,
|
|
419
|
+
inbound: result.ok ? arrayFromPayload(payload, ["inbound"]).map((entry) => compactProtocolPayload(entry)) : [],
|
|
420
|
+
outbound: result.ok ? arrayFromPayload(payload, ["outbound"]).map((entry) => compactProtocolPayload(entry)) : [],
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
if (need.tool === "docdex.impact_diagnostics") {
|
|
424
|
+
return {
|
|
425
|
+
type: "docdex.impact_diagnostics",
|
|
426
|
+
file: need.params.file,
|
|
427
|
+
diagnostics: result.ok ? compactProtocolPayload(payload) : { error: content },
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
if (need.tool === "docdex.tree") {
|
|
431
|
+
return {
|
|
432
|
+
type: "docdex.tree",
|
|
433
|
+
tree: stringFromPayload(payload, ["tree"], content),
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
if (need.tool === "docdex.dag_export") {
|
|
437
|
+
return {
|
|
438
|
+
type: "docdex.dag_export",
|
|
439
|
+
session_id: String(execution.args.sessionId ?? need.params.session_id ?? ""),
|
|
440
|
+
format: need.params.format,
|
|
441
|
+
content: result.ok ? compactProtocolPayload(payload) : { error: content },
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
if (need.tool === "file.list") {
|
|
445
|
+
const entries = arrayFromPayload(payload, ["entries", "files"]).filter((entry) => typeof entry === "string");
|
|
446
|
+
const files = need.params.pattern
|
|
447
|
+
? entries.filter((entry) => matchesSimplePattern(entry, need.params.pattern))
|
|
448
|
+
: entries;
|
|
449
|
+
return { type: "file.list", root: need.params.root, files };
|
|
450
|
+
}
|
|
451
|
+
if (need.tool === "file.diff") {
|
|
452
|
+
return { type: "file.diff", paths: need.params.paths, diff: content };
|
|
453
|
+
}
|
|
454
|
+
if (need.tool === "file.read") {
|
|
455
|
+
return {
|
|
456
|
+
type: "file.read",
|
|
457
|
+
path: need.params.path,
|
|
458
|
+
content,
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
return {
|
|
462
|
+
type: "agent.delegate",
|
|
463
|
+
role: "unknown",
|
|
464
|
+
goal: "unsupported",
|
|
465
|
+
results: [{ error: `Unsupported protocol result: ${need.tool}` }],
|
|
466
|
+
};
|
|
467
|
+
};
|
|
468
|
+
const formatCodaliResponse = (response) => {
|
|
469
|
+
return `CODALI_RESPONSE v1\n${JSON.stringify(response, null, 2)}`;
|
|
470
|
+
};
|
|
471
|
+
const mergeUsage = (current, next) => {
|
|
472
|
+
if (!next)
|
|
473
|
+
return current;
|
|
474
|
+
const merged = current ? { ...current } : {};
|
|
475
|
+
if (next.inputTokens !== undefined) {
|
|
476
|
+
merged.inputTokens = (merged.inputTokens ?? 0) + next.inputTokens;
|
|
477
|
+
}
|
|
478
|
+
if (next.outputTokens !== undefined) {
|
|
479
|
+
merged.outputTokens = (merged.outputTokens ?? 0) + next.outputTokens;
|
|
480
|
+
}
|
|
481
|
+
if (next.totalTokens !== undefined) {
|
|
482
|
+
merged.totalTokens = (merged.totalTokens ?? 0) + next.totalTokens;
|
|
483
|
+
}
|
|
484
|
+
return merged;
|
|
485
|
+
};
|
|
486
|
+
const createRuntimeProvider = (input) => {
|
|
487
|
+
const config = {
|
|
488
|
+
model: input.model,
|
|
489
|
+
apiKey: input.apiKey,
|
|
490
|
+
baseUrl: input.baseUrl,
|
|
491
|
+
timeoutMs: input.timeoutMs,
|
|
492
|
+
};
|
|
493
|
+
if (input.name === "openai-compatible") {
|
|
494
|
+
return new OpenAiCompatibleProvider(config);
|
|
495
|
+
}
|
|
496
|
+
if (input.name === "ollama-remote") {
|
|
497
|
+
return new OllamaRemoteProvider(config);
|
|
498
|
+
}
|
|
499
|
+
if (input.name === "codex-cli") {
|
|
500
|
+
return new CodexCliProvider(config);
|
|
501
|
+
}
|
|
502
|
+
return createProvider(input.name, config);
|
|
503
|
+
};
|
|
504
|
+
const isRuntimeToolAllowed = (toolName, policy) => {
|
|
505
|
+
if (policy.deniedTools?.includes(toolName)) {
|
|
506
|
+
return false;
|
|
507
|
+
}
|
|
508
|
+
if (policy.allowedTools && !policy.allowedTools.includes(toolName)) {
|
|
509
|
+
return false;
|
|
510
|
+
}
|
|
511
|
+
if (!policy.allowShell && toolName === "run_shell") {
|
|
512
|
+
return false;
|
|
513
|
+
}
|
|
514
|
+
if (!policy.allowWrites && WRITE_TOOL_NAMES.has(toolName)) {
|
|
515
|
+
return false;
|
|
516
|
+
}
|
|
517
|
+
return true;
|
|
518
|
+
};
|
|
519
|
+
const isDocdexToolAllowed = (toolName, docdex) => {
|
|
520
|
+
if (!toolName.startsWith("docdex_")) {
|
|
521
|
+
return true;
|
|
522
|
+
}
|
|
523
|
+
if (docdex?.allowWeb === false && WEB_TOOL_NAMES.has(toolName)) {
|
|
524
|
+
return false;
|
|
525
|
+
}
|
|
526
|
+
if (docdex?.allowMemoryWrite === false && MEMORY_WRITE_TOOL_NAMES.has(toolName)) {
|
|
527
|
+
return false;
|
|
528
|
+
}
|
|
529
|
+
if (docdex?.allowProfileWrite === false && PROFILE_WRITE_TOOL_NAMES.has(toolName)) {
|
|
530
|
+
return false;
|
|
531
|
+
}
|
|
532
|
+
if (docdex?.allowIndexRebuild === false && INDEX_REBUILD_TOOL_NAMES.has(toolName)) {
|
|
533
|
+
return false;
|
|
534
|
+
}
|
|
535
|
+
return true;
|
|
536
|
+
};
|
|
537
|
+
const registerRuntimeTool = (registry, tool, policy, docdex) => {
|
|
538
|
+
if (isRuntimeToolAllowed(tool.name, policy) && isDocdexToolAllowed(tool.name, docdex)) {
|
|
539
|
+
registry.register(tool);
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
const buildRuntimeToolRegistry = (input) => {
|
|
543
|
+
if (input.toolRegistry) {
|
|
544
|
+
return input.toolRegistry;
|
|
545
|
+
}
|
|
546
|
+
const registry = new ToolRegistry();
|
|
547
|
+
const register = (tool) => registerRuntimeTool(registry, tool, input.policy, input.docdex);
|
|
548
|
+
const explicitTools = input.tools;
|
|
549
|
+
if (explicitTools) {
|
|
550
|
+
for (const tool of explicitTools)
|
|
551
|
+
register(tool);
|
|
552
|
+
return registry;
|
|
553
|
+
}
|
|
554
|
+
for (const tool of createFileTools())
|
|
555
|
+
register(tool);
|
|
556
|
+
register(createDiffTool());
|
|
557
|
+
register(createSearchTool());
|
|
558
|
+
if (input.policy.allowShell) {
|
|
559
|
+
register(createShellTool());
|
|
560
|
+
}
|
|
561
|
+
const docdexClient = new DocdexClient({
|
|
562
|
+
baseUrl: input.docdex?.baseUrl ?? DEFAULT_DOCDEX_BASE_URL,
|
|
563
|
+
repoId: input.docdex?.repoId,
|
|
564
|
+
repoRoot: input.docdex?.repoRoot ?? input.workspace.root,
|
|
565
|
+
dagSessionId: input.docdex?.dagSessionId ?? input.metadata?.requestId,
|
|
566
|
+
});
|
|
567
|
+
for (const tool of createDocdexTools(docdexClient))
|
|
568
|
+
register(tool);
|
|
569
|
+
return registry;
|
|
570
|
+
};
|
|
571
|
+
const buildResponseFormat = (response) => {
|
|
572
|
+
if (!response?.format)
|
|
573
|
+
return undefined;
|
|
574
|
+
return {
|
|
575
|
+
type: response.format,
|
|
576
|
+
schema: response.schema,
|
|
577
|
+
grammar: response.grammar,
|
|
578
|
+
};
|
|
579
|
+
};
|
|
580
|
+
const initializeRuntimeSession = async (input, runId, warnings) => {
|
|
581
|
+
if (!input.session)
|
|
582
|
+
return undefined;
|
|
583
|
+
const store = new SessionStore({
|
|
584
|
+
workspaceRoot: input.workspace.root,
|
|
585
|
+
storageDir: input.session.storageDir,
|
|
586
|
+
});
|
|
587
|
+
const instructionBlocks = input.session.loadInstructions === false
|
|
588
|
+
? []
|
|
589
|
+
: await loadInstructionBlocks({
|
|
590
|
+
workspaceRoot: input.workspace.root,
|
|
591
|
+
focusPaths: input.session.focusPaths,
|
|
592
|
+
includeLocal: input.session.includeLocalInstructions,
|
|
593
|
+
}).catch((error) => {
|
|
594
|
+
warnings.push(`Instruction loading failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
595
|
+
return [];
|
|
596
|
+
});
|
|
597
|
+
const instructionSources = instructionBlocks.map((block) => block.sourcePath);
|
|
598
|
+
const metadata = await store.getOrCreateSession({
|
|
599
|
+
sessionId: input.session.id,
|
|
600
|
+
repoRoot: input.workspace.root,
|
|
601
|
+
task: input.task,
|
|
602
|
+
instructionSources,
|
|
603
|
+
});
|
|
604
|
+
const updatedSources = Array.from(new Set([...metadata.instructionSources, ...instructionSources]));
|
|
605
|
+
const updated = await store.updateSession(metadata.sessionId, {
|
|
606
|
+
status: "active",
|
|
607
|
+
instructionSources: updatedSources,
|
|
608
|
+
});
|
|
609
|
+
await store.addRun(updated.sessionId, runId);
|
|
610
|
+
await store.appendTranscript(updated.sessionId, {
|
|
611
|
+
type: "run_started",
|
|
612
|
+
runId,
|
|
613
|
+
data: {
|
|
614
|
+
task: input.task,
|
|
615
|
+
mode: input.policy.mode,
|
|
616
|
+
agent: input.agent?.slug,
|
|
617
|
+
model: input.provider.model,
|
|
618
|
+
},
|
|
619
|
+
});
|
|
620
|
+
return {
|
|
621
|
+
store,
|
|
622
|
+
metadata: await store.readSession(updated.sessionId),
|
|
623
|
+
resumeBundle: input.session.resume && input.session.id
|
|
624
|
+
? await store.buildResumeBundle(updated.sessionId, { recentEvents: 12 })
|
|
625
|
+
: undefined,
|
|
626
|
+
instructionBlocks,
|
|
627
|
+
};
|
|
628
|
+
};
|
|
629
|
+
const appendSessionEvent = async (session, runId, type, data, warnings) => {
|
|
630
|
+
if (!session)
|
|
631
|
+
return;
|
|
632
|
+
try {
|
|
633
|
+
await session.store.appendTranscript(session.metadata.sessionId, { type, runId, data });
|
|
634
|
+
}
|
|
635
|
+
catch (error) {
|
|
636
|
+
warnings.push(`Session transcript write failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
637
|
+
}
|
|
638
|
+
};
|
|
639
|
+
const compactRuntimeSession = async (session, finalStatus, warnings) => {
|
|
640
|
+
if (!session)
|
|
641
|
+
return undefined;
|
|
642
|
+
try {
|
|
643
|
+
if (session.store && session.metadata.sessionId) {
|
|
644
|
+
if (session.metadata.status !== finalStatus) {
|
|
645
|
+
await session.store.updateSession(session.metadata.sessionId, { status: finalStatus });
|
|
646
|
+
}
|
|
647
|
+
if (finalStatus !== "active") {
|
|
648
|
+
await session.store.compactSession(session.metadata.sessionId);
|
|
649
|
+
}
|
|
650
|
+
return session.store.readSession(session.metadata.sessionId);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
catch (error) {
|
|
654
|
+
warnings.push(`Session compaction failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
655
|
+
}
|
|
656
|
+
return session.metadata;
|
|
657
|
+
};
|
|
658
|
+
const runtimeToolNamesForProtocolTools = (tools) => {
|
|
659
|
+
if (!tools?.length)
|
|
660
|
+
return undefined;
|
|
661
|
+
const names = new Set();
|
|
662
|
+
for (const tool of tools) {
|
|
663
|
+
const trimmed = tool.trim();
|
|
664
|
+
if (!trimmed)
|
|
665
|
+
continue;
|
|
666
|
+
for (const runtimeName of PROTOCOL_TO_RUNTIME_TOOL_NAMES.get(trimmed) ?? [trimmed]) {
|
|
667
|
+
names.add(runtimeName);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
return Array.from(names).sort();
|
|
671
|
+
};
|
|
672
|
+
const isSubagentDelegationEnabled = (input) => {
|
|
673
|
+
return input.subagents?.enabled !== false;
|
|
674
|
+
};
|
|
675
|
+
const subagentSpecFromNeed = (need) => ({
|
|
676
|
+
role: need.params.role,
|
|
677
|
+
goal: need.params.goal,
|
|
678
|
+
tools: need.params.tools,
|
|
679
|
+
permissions: {
|
|
680
|
+
readOnly: need.params.read_only ?? need.params.role !== "worker",
|
|
681
|
+
allowedPaths: need.params.allowed_paths,
|
|
682
|
+
writePaths: need.params.write_paths,
|
|
683
|
+
},
|
|
684
|
+
maxSteps: need.params.max_steps,
|
|
685
|
+
maxToolCalls: need.params.max_tool_calls,
|
|
686
|
+
timeoutMs: need.params.timeout_ms,
|
|
687
|
+
});
|
|
688
|
+
const toSessionSummary = (session) => {
|
|
689
|
+
if (!session)
|
|
690
|
+
return undefined;
|
|
691
|
+
return {
|
|
692
|
+
id: session.sessionId,
|
|
693
|
+
summaryRefs: session.summaryRefs,
|
|
694
|
+
instructionSources: session.instructionSources,
|
|
695
|
+
};
|
|
696
|
+
};
|
|
697
|
+
const normalizeAgentEvent = (event, id, at) => {
|
|
698
|
+
if (event.type === "token") {
|
|
699
|
+
return { type: "token", content: event.content, at };
|
|
700
|
+
}
|
|
701
|
+
if (event.type === "status") {
|
|
702
|
+
return { type: "status", phase: event.phase, message: event.message, at };
|
|
703
|
+
}
|
|
704
|
+
if (event.type === "tool_call") {
|
|
705
|
+
return { type: "tool_call", id, name: event.name, args: event.args, at };
|
|
706
|
+
}
|
|
707
|
+
if (event.type === "tool_result") {
|
|
708
|
+
return {
|
|
709
|
+
type: "tool_result",
|
|
710
|
+
id,
|
|
711
|
+
name: event.name,
|
|
712
|
+
ok: event.ok ?? true,
|
|
713
|
+
output: event.output,
|
|
714
|
+
errorCode: event.errorCode,
|
|
715
|
+
retryable: event.retryable,
|
|
716
|
+
at,
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
return { type: "error", message: event.message, at };
|
|
720
|
+
};
|
|
721
|
+
export const codaliEventToOpenAIChatCompletionChunk = (event, options) => {
|
|
722
|
+
const id = options.id ?? `chatcmpl-${options.requestId ?? "codali"}`;
|
|
723
|
+
const created = options.created ?? Math.floor(Date.now() / 1000);
|
|
724
|
+
if (event.type === "token") {
|
|
725
|
+
return {
|
|
726
|
+
id,
|
|
727
|
+
object: "chat.completion.chunk",
|
|
728
|
+
created,
|
|
729
|
+
model: options.model,
|
|
730
|
+
choices: [
|
|
731
|
+
{
|
|
732
|
+
index: 0,
|
|
733
|
+
delta: { content: event.content },
|
|
734
|
+
finish_reason: null,
|
|
735
|
+
},
|
|
736
|
+
],
|
|
737
|
+
};
|
|
738
|
+
}
|
|
739
|
+
if (event.type === "final") {
|
|
740
|
+
return {
|
|
741
|
+
id,
|
|
742
|
+
object: "chat.completion.chunk",
|
|
743
|
+
created,
|
|
744
|
+
model: options.model,
|
|
745
|
+
choices: [
|
|
746
|
+
{
|
|
747
|
+
index: 0,
|
|
748
|
+
delta: {},
|
|
749
|
+
finish_reason: "stop",
|
|
750
|
+
},
|
|
751
|
+
],
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
if (!options.includeInternalEvents) {
|
|
755
|
+
return null;
|
|
756
|
+
}
|
|
757
|
+
if (event.type === "status") {
|
|
758
|
+
return {
|
|
759
|
+
id,
|
|
760
|
+
object: "chat.completion.chunk",
|
|
761
|
+
created,
|
|
762
|
+
model: options.model,
|
|
763
|
+
choices: [
|
|
764
|
+
{
|
|
765
|
+
index: 0,
|
|
766
|
+
delta: {},
|
|
767
|
+
finish_reason: null,
|
|
768
|
+
},
|
|
769
|
+
],
|
|
770
|
+
metadata: {
|
|
771
|
+
event: "status",
|
|
772
|
+
phase: event.phase,
|
|
773
|
+
message: event.message,
|
|
774
|
+
at: event.at,
|
|
775
|
+
},
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
if (event.type === "tool_call" || event.type === "tool_result") {
|
|
779
|
+
return {
|
|
780
|
+
id,
|
|
781
|
+
object: "chat.completion.chunk",
|
|
782
|
+
created,
|
|
783
|
+
model: options.model,
|
|
784
|
+
choices: [
|
|
785
|
+
{
|
|
786
|
+
index: 0,
|
|
787
|
+
delta: {},
|
|
788
|
+
finish_reason: null,
|
|
789
|
+
},
|
|
790
|
+
],
|
|
791
|
+
metadata: {
|
|
792
|
+
event: event.type,
|
|
793
|
+
id: event.id,
|
|
794
|
+
name: event.name,
|
|
795
|
+
ok: event.type === "tool_result" ? event.ok : undefined,
|
|
796
|
+
error_code: event.type === "tool_result" ? event.errorCode : undefined,
|
|
797
|
+
at: event.at,
|
|
798
|
+
},
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
if (event.type === "subagent_start" || event.type === "subagent_result") {
|
|
802
|
+
return {
|
|
803
|
+
id,
|
|
804
|
+
object: "chat.completion.chunk",
|
|
805
|
+
created,
|
|
806
|
+
model: options.model,
|
|
807
|
+
choices: [
|
|
808
|
+
{
|
|
809
|
+
index: 0,
|
|
810
|
+
delta: {},
|
|
811
|
+
finish_reason: null,
|
|
812
|
+
},
|
|
813
|
+
],
|
|
814
|
+
metadata: {
|
|
815
|
+
event: event.type,
|
|
816
|
+
id: event.id,
|
|
817
|
+
role: event.role,
|
|
818
|
+
status: event.type === "subagent_result" ? event.status : undefined,
|
|
819
|
+
summary: event.type === "subagent_result" ? event.summary : undefined,
|
|
820
|
+
at: event.at,
|
|
821
|
+
},
|
|
822
|
+
};
|
|
823
|
+
}
|
|
824
|
+
return null;
|
|
825
|
+
};
|
|
826
|
+
export const codaliEventToOpenAISseData = (event, options) => {
|
|
827
|
+
const chunk = codaliEventToOpenAIChatCompletionChunk(event, options);
|
|
828
|
+
return chunk ? `data: ${JSON.stringify(chunk)}\n\n` : null;
|
|
829
|
+
};
|
|
830
|
+
const emitRuntimeEvent = (event, sink, warnings) => {
|
|
831
|
+
try {
|
|
832
|
+
const maybePromise = sink?.(event);
|
|
833
|
+
if (maybePromise && typeof maybePromise.catch === "function") {
|
|
834
|
+
maybePromise.catch((error) => {
|
|
835
|
+
warnings.push(error instanceof Error ? error.message : String(error));
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
catch (error) {
|
|
840
|
+
warnings.push(error instanceof Error ? error.message : String(error));
|
|
841
|
+
}
|
|
842
|
+
};
|
|
843
|
+
const createSubagentRunner = (options) => {
|
|
844
|
+
const { input, registry, toolContext, runId, remainingToolBudget } = options;
|
|
845
|
+
return async ({ spec }) => {
|
|
846
|
+
const readOnly = spec.permissions?.readOnly ?? spec.role !== "worker";
|
|
847
|
+
const allowedTools = runtimeToolNamesForProtocolTools(spec.tools ?? input.subagents?.defaultTools);
|
|
848
|
+
const maxToolCalls = Math.max(0, Math.min(spec.maxToolCalls ?? remainingToolBudget, remainingToolBudget));
|
|
849
|
+
const childRunId = `${runId}:${spec.id}`;
|
|
850
|
+
const mode = input.policy.mode === "freeform"
|
|
851
|
+
? "freeform"
|
|
852
|
+
: input.agent?.supportsTools === false
|
|
853
|
+
? "protocol_loop"
|
|
854
|
+
: "tool_loop";
|
|
855
|
+
const result = await runCodaliTask({
|
|
856
|
+
...input,
|
|
857
|
+
task: spec.goal,
|
|
858
|
+
messages: [
|
|
859
|
+
{
|
|
860
|
+
role: "user",
|
|
861
|
+
content: [
|
|
862
|
+
`You are a Codali ${spec.role} subagent.`,
|
|
863
|
+
`Goal: ${spec.goal}`,
|
|
864
|
+
readOnly
|
|
865
|
+
? "Work read-only. Do not request writes or destructive operations."
|
|
866
|
+
: `Write scope: ${(spec.permissions?.writePaths ?? []).join(", ") || "none declared"}`,
|
|
867
|
+
"Use available tools when needed and return a concise handoff with findings, evidence, and blockers.",
|
|
868
|
+
].join("\n"),
|
|
869
|
+
},
|
|
870
|
+
],
|
|
871
|
+
policy: {
|
|
872
|
+
...input.policy,
|
|
873
|
+
mode,
|
|
874
|
+
allowWrites: input.policy.allowWrites &&
|
|
875
|
+
input.subagents?.allowWrites === true &&
|
|
876
|
+
!readOnly &&
|
|
877
|
+
(spec.permissions?.writePaths?.length ?? 0) > 0,
|
|
878
|
+
allowShell: false,
|
|
879
|
+
allowDestructiveOperations: false,
|
|
880
|
+
allowOutsideWorkspace: false,
|
|
881
|
+
allowedTools,
|
|
882
|
+
maxSteps: Math.max(1, Math.min(spec.maxSteps ?? 6, input.policy.maxSteps)),
|
|
883
|
+
maxToolCalls,
|
|
884
|
+
timeoutMs: spec.timeoutMs ?? input.subagents?.defaultTimeoutMs ?? Math.min(input.policy.timeoutMs, 120000),
|
|
885
|
+
},
|
|
886
|
+
metadata: {
|
|
887
|
+
...input.metadata,
|
|
888
|
+
requestId: childRunId,
|
|
889
|
+
},
|
|
890
|
+
providerInstance: input.providerInstance,
|
|
891
|
+
toolRegistry: undefined,
|
|
892
|
+
tools: registry.list(),
|
|
893
|
+
toolContext: {
|
|
894
|
+
...toolContext,
|
|
895
|
+
runId: childRunId,
|
|
896
|
+
allowedReadPaths: spec.permissions?.allowedPaths,
|
|
897
|
+
allowedWritePaths: spec.permissions?.writePaths,
|
|
898
|
+
},
|
|
899
|
+
subagents: { enabled: false },
|
|
900
|
+
session: undefined,
|
|
901
|
+
onEvent: undefined,
|
|
902
|
+
logger: input.logger,
|
|
903
|
+
});
|
|
904
|
+
return {
|
|
905
|
+
output: result.finalMessage,
|
|
906
|
+
toolCallsExecuted: result.toolCallsExecuted,
|
|
907
|
+
touchedFiles: result.touchedFiles,
|
|
908
|
+
warnings: result.warnings,
|
|
909
|
+
metadata: { runId: result.runId },
|
|
910
|
+
};
|
|
911
|
+
};
|
|
912
|
+
};
|
|
913
|
+
const executeDelegatedNeed = async (options) => {
|
|
914
|
+
const { need, input, registry, toolContext, runId, remainingToolBudget, emit } = options;
|
|
915
|
+
const spec = subagentSpecFromNeed(need);
|
|
916
|
+
if (!isSubagentDelegationEnabled(input)) {
|
|
917
|
+
const result = {
|
|
918
|
+
id: "delegation-disabled",
|
|
919
|
+
role: spec.role ?? "explorer",
|
|
920
|
+
goal: spec.goal,
|
|
921
|
+
status: "failed",
|
|
922
|
+
summary: "Subagent delegation is disabled for this run.",
|
|
923
|
+
output: "",
|
|
924
|
+
toolCallsExecuted: 0,
|
|
925
|
+
touchedFiles: [],
|
|
926
|
+
warnings: [],
|
|
927
|
+
startedAt: new Date().toISOString(),
|
|
928
|
+
endedAt: new Date().toISOString(),
|
|
929
|
+
durationMs: 0,
|
|
930
|
+
error: "subagent_delegation_disabled",
|
|
931
|
+
};
|
|
932
|
+
return {
|
|
933
|
+
result: {
|
|
934
|
+
type: "agent.delegate",
|
|
935
|
+
role: spec.role ?? "explorer",
|
|
936
|
+
goal: spec.goal,
|
|
937
|
+
results: [compactSubagentResultForProtocol(result)],
|
|
938
|
+
},
|
|
939
|
+
subagentResults: [result],
|
|
940
|
+
};
|
|
941
|
+
}
|
|
942
|
+
const orchestrator = new SubagentOrchestrator({
|
|
943
|
+
parentRunId: runId,
|
|
944
|
+
maxParallel: input.subagents?.maxParallel ?? 2,
|
|
945
|
+
maxSubagents: input.subagents?.maxSubagents ?? 4,
|
|
946
|
+
defaultTimeoutMs: input.subagents?.defaultTimeoutMs ?? Math.min(input.policy.timeoutMs, 120000),
|
|
947
|
+
runner: createSubagentRunner({ input, registry, toolContext, runId, remainingToolBudget }),
|
|
948
|
+
onEvent: (event) => {
|
|
949
|
+
if (event.type === "subagent_start" && event.spec) {
|
|
950
|
+
emit({
|
|
951
|
+
type: "subagent_start",
|
|
952
|
+
id: event.spec.id ?? event.spec.role,
|
|
953
|
+
role: event.spec.role,
|
|
954
|
+
goal: event.spec.goal,
|
|
955
|
+
at: new Date().toISOString(),
|
|
956
|
+
});
|
|
957
|
+
}
|
|
958
|
+
if (event.type === "subagent_result" && event.result) {
|
|
959
|
+
emit({
|
|
960
|
+
type: "subagent_result",
|
|
961
|
+
id: event.result.id,
|
|
962
|
+
role: event.result.role,
|
|
963
|
+
status: event.result.status,
|
|
964
|
+
summary: event.result.summary,
|
|
965
|
+
at: new Date().toISOString(),
|
|
966
|
+
});
|
|
967
|
+
}
|
|
968
|
+
},
|
|
969
|
+
});
|
|
970
|
+
const subagentResults = await orchestrator.run([spec]);
|
|
971
|
+
return {
|
|
972
|
+
result: {
|
|
973
|
+
type: "agent.delegate",
|
|
974
|
+
role: spec.role ?? "explorer",
|
|
975
|
+
goal: spec.goal,
|
|
976
|
+
results: subagentResults.map((result) => compactSubagentResultForProtocol(result)),
|
|
977
|
+
},
|
|
978
|
+
subagentResults,
|
|
979
|
+
};
|
|
980
|
+
};
|
|
981
|
+
const runProtocolLoop = async (options) => {
|
|
982
|
+
const { input, provider, registry, toolContext, runId, session, warnings, emit, emitAgentEvent } = options;
|
|
983
|
+
const messages = [
|
|
984
|
+
{
|
|
985
|
+
role: "system",
|
|
986
|
+
content: buildProtocolSystemPrompt(registry, {
|
|
987
|
+
allowDelegation: isSubagentDelegationEnabled(input),
|
|
988
|
+
resumeBundle: session?.resumeBundle,
|
|
989
|
+
instructionBlocks: session?.instructionBlocks,
|
|
990
|
+
}),
|
|
991
|
+
},
|
|
992
|
+
...(input.messages ?? [{ role: "user", content: input.task }]),
|
|
993
|
+
];
|
|
994
|
+
let toolCallsExecuted = 0;
|
|
995
|
+
let usageTotals;
|
|
996
|
+
const deadline = input.policy.timeoutMs ? Date.now() + input.policy.timeoutMs : undefined;
|
|
997
|
+
if (input.response?.format) {
|
|
998
|
+
warnings.push("protocol_loop does not enforce provider response_format because it must allow AGENT_REQUEST text turns");
|
|
999
|
+
}
|
|
1000
|
+
const timeRemaining = () => {
|
|
1001
|
+
if (!deadline)
|
|
1002
|
+
return undefined;
|
|
1003
|
+
return deadline - Date.now();
|
|
1004
|
+
};
|
|
1005
|
+
const throwBudgetError = async (code, step) => {
|
|
1006
|
+
const error = new RunnerBudgetError(code, {
|
|
1007
|
+
step,
|
|
1008
|
+
tool_calls_executed: toolCallsExecuted,
|
|
1009
|
+
max_steps: input.policy.maxSteps,
|
|
1010
|
+
max_tool_calls: input.policy.maxToolCalls,
|
|
1011
|
+
timeout_ms: input.policy.timeoutMs,
|
|
1012
|
+
});
|
|
1013
|
+
if (input.logger) {
|
|
1014
|
+
await input.logger.log("runner_budget_failure", error.metadata);
|
|
1015
|
+
}
|
|
1016
|
+
throw error;
|
|
1017
|
+
};
|
|
1018
|
+
const withTimeout = async (promise, step) => {
|
|
1019
|
+
const remaining = timeRemaining();
|
|
1020
|
+
if (remaining === undefined)
|
|
1021
|
+
return promise;
|
|
1022
|
+
if (remaining <= 0) {
|
|
1023
|
+
await throwBudgetError("runner_timeout_exceeded", step);
|
|
1024
|
+
}
|
|
1025
|
+
let timeoutId;
|
|
1026
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
1027
|
+
timeoutId = setTimeout(() => reject(new Error("Runner timeout exceeded")), remaining);
|
|
1028
|
+
});
|
|
1029
|
+
try {
|
|
1030
|
+
return await Promise.race([promise, timeoutPromise]);
|
|
1031
|
+
}
|
|
1032
|
+
catch (error) {
|
|
1033
|
+
if (error instanceof Error && /Runner timeout exceeded/i.test(error.message)) {
|
|
1034
|
+
await throwBudgetError("runner_timeout_exceeded", step);
|
|
1035
|
+
}
|
|
1036
|
+
throw error;
|
|
1037
|
+
}
|
|
1038
|
+
finally {
|
|
1039
|
+
if (timeoutId)
|
|
1040
|
+
clearTimeout(timeoutId);
|
|
1041
|
+
}
|
|
1042
|
+
};
|
|
1043
|
+
for (let step = 0; step < input.policy.maxSteps; step += 1) {
|
|
1044
|
+
if (deadline && timeRemaining() <= 0) {
|
|
1045
|
+
await throwBudgetError("runner_timeout_exceeded", step);
|
|
1046
|
+
}
|
|
1047
|
+
emit({ type: "status", phase: "thinking", at: new Date().toISOString() });
|
|
1048
|
+
if (input.logger) {
|
|
1049
|
+
await input.logger.log("provider_request", {
|
|
1050
|
+
provider: provider.name,
|
|
1051
|
+
protocolLoop: true,
|
|
1052
|
+
messages,
|
|
1053
|
+
tools: [],
|
|
1054
|
+
toolChoice: "none",
|
|
1055
|
+
temperature: undefined,
|
|
1056
|
+
maxTokens: input.policy.maxTokens,
|
|
1057
|
+
stream: input.streaming?.enabled ?? false,
|
|
1058
|
+
});
|
|
1059
|
+
}
|
|
1060
|
+
await appendSessionEvent(session, runId, "provider_request", {
|
|
1061
|
+
provider: provider.name,
|
|
1062
|
+
protocolLoop: true,
|
|
1063
|
+
messages,
|
|
1064
|
+
maxTokens: input.policy.maxTokens,
|
|
1065
|
+
}, warnings);
|
|
1066
|
+
const response = await withTimeout(provider.generate({
|
|
1067
|
+
messages: [...messages],
|
|
1068
|
+
maxTokens: input.policy.maxTokens,
|
|
1069
|
+
stream: input.streaming?.enabled,
|
|
1070
|
+
onEvent: emitAgentEvent,
|
|
1071
|
+
onToken: (token) => emitAgentEvent({ type: "token", content: token }),
|
|
1072
|
+
streamFlushMs: input.streaming?.flushEveryMs,
|
|
1073
|
+
}), step);
|
|
1074
|
+
usageTotals = mergeUsage(usageTotals, response.usage);
|
|
1075
|
+
messages.push(response.message);
|
|
1076
|
+
if (input.logger) {
|
|
1077
|
+
await input.logger.log("provider_response", {
|
|
1078
|
+
protocolLoop: true,
|
|
1079
|
+
message: response.message,
|
|
1080
|
+
usage: response.usage,
|
|
1081
|
+
});
|
|
1082
|
+
}
|
|
1083
|
+
await appendSessionEvent(session, runId, "provider_response", { protocolLoop: true, message: response.message, usage: response.usage }, warnings);
|
|
1084
|
+
const requestText = extractAgentRequestText(response.message.content);
|
|
1085
|
+
if (!requestText) {
|
|
1086
|
+
return {
|
|
1087
|
+
finalMessage: response.message,
|
|
1088
|
+
messages,
|
|
1089
|
+
toolCallsExecuted,
|
|
1090
|
+
usage: usageTotals,
|
|
1091
|
+
};
|
|
1092
|
+
}
|
|
1093
|
+
let request;
|
|
1094
|
+
try {
|
|
1095
|
+
request = parseAgentRequest(requestText, { defaultRequestId: `${runId}:step-${step}` });
|
|
1096
|
+
}
|
|
1097
|
+
catch (error) {
|
|
1098
|
+
const warning = `Invalid AGENT_REQUEST: ${error instanceof Error ? error.message : String(error)}`;
|
|
1099
|
+
warnings.push(warning);
|
|
1100
|
+
messages.push({
|
|
1101
|
+
role: "user",
|
|
1102
|
+
content: formatCodaliResponse({
|
|
1103
|
+
version: "v1",
|
|
1104
|
+
request_id: "invalid",
|
|
1105
|
+
results: [],
|
|
1106
|
+
meta: {
|
|
1107
|
+
repo_root: input.workspace.root,
|
|
1108
|
+
warnings: [warning, "Return a valid AGENT_REQUEST v1 or answer normally."],
|
|
1109
|
+
},
|
|
1110
|
+
}),
|
|
1111
|
+
});
|
|
1112
|
+
continue;
|
|
1113
|
+
}
|
|
1114
|
+
const responseWarnings = [];
|
|
1115
|
+
const results = [];
|
|
1116
|
+
const needs = normalizeAgentRequest(request);
|
|
1117
|
+
for (let index = 0; index < needs.length; index += 1) {
|
|
1118
|
+
if (toolCallsExecuted >= input.policy.maxToolCalls) {
|
|
1119
|
+
await throwBudgetError("runner_tool_call_limit_exceeded", step);
|
|
1120
|
+
}
|
|
1121
|
+
const normalizedNeed = needs[index];
|
|
1122
|
+
if (normalizedNeed.tool === "agent.delegate") {
|
|
1123
|
+
const callId = `${request.request_id}:${index + 1}`;
|
|
1124
|
+
toolCallsExecuted += 1;
|
|
1125
|
+
emit({
|
|
1126
|
+
type: "tool_call",
|
|
1127
|
+
id: callId,
|
|
1128
|
+
name: "agent.delegate",
|
|
1129
|
+
args: normalizedNeed.params,
|
|
1130
|
+
at: new Date().toISOString(),
|
|
1131
|
+
});
|
|
1132
|
+
const delegation = await withTimeout(executeDelegatedNeed({
|
|
1133
|
+
need: normalizedNeed,
|
|
1134
|
+
input,
|
|
1135
|
+
registry,
|
|
1136
|
+
toolContext,
|
|
1137
|
+
runId,
|
|
1138
|
+
remainingToolBudget: Math.max(0, input.policy.maxToolCalls - toolCallsExecuted),
|
|
1139
|
+
emit,
|
|
1140
|
+
}), step);
|
|
1141
|
+
const nestedToolCalls = delegation.subagentResults.reduce((sum, result) => sum + result.toolCallsExecuted, 0);
|
|
1142
|
+
toolCallsExecuted += nestedToolCalls;
|
|
1143
|
+
if (toolCallsExecuted > input.policy.maxToolCalls) {
|
|
1144
|
+
await throwBudgetError("runner_tool_call_limit_exceeded", step);
|
|
1145
|
+
}
|
|
1146
|
+
emit({
|
|
1147
|
+
type: "tool_result",
|
|
1148
|
+
id: callId,
|
|
1149
|
+
name: "agent.delegate",
|
|
1150
|
+
ok: delegation.subagentResults.every((result) => result.status === "completed"),
|
|
1151
|
+
output: JSON.stringify(delegation.subagentResults, null, 2),
|
|
1152
|
+
at: new Date().toISOString(),
|
|
1153
|
+
});
|
|
1154
|
+
await appendSessionEvent(session, runId, "subagent_result", {
|
|
1155
|
+
role: normalizedNeed.params.role,
|
|
1156
|
+
goal: normalizedNeed.params.goal,
|
|
1157
|
+
results: delegation.subagentResults,
|
|
1158
|
+
}, warnings);
|
|
1159
|
+
results.push(delegation.result);
|
|
1160
|
+
continue;
|
|
1161
|
+
}
|
|
1162
|
+
const execution = protocolToolExecutionForNeed(needs[index], input, runId);
|
|
1163
|
+
const callId = `${request.request_id}:${index + 1}`;
|
|
1164
|
+
toolCallsExecuted += 1;
|
|
1165
|
+
emit({
|
|
1166
|
+
type: "status",
|
|
1167
|
+
phase: "executing",
|
|
1168
|
+
message: execution.toolName,
|
|
1169
|
+
at: new Date().toISOString(),
|
|
1170
|
+
});
|
|
1171
|
+
emit({
|
|
1172
|
+
type: "tool_call",
|
|
1173
|
+
id: callId,
|
|
1174
|
+
name: execution.toolName,
|
|
1175
|
+
args: execution.args,
|
|
1176
|
+
at: new Date().toISOString(),
|
|
1177
|
+
});
|
|
1178
|
+
const toolResult = await withTimeout(registry.execute(execution.toolName, execution.args, toolContext), step);
|
|
1179
|
+
const content = toolResultContent(toolResult);
|
|
1180
|
+
emit({
|
|
1181
|
+
type: "tool_result",
|
|
1182
|
+
id: callId,
|
|
1183
|
+
name: execution.toolName,
|
|
1184
|
+
ok: toolResult.ok,
|
|
1185
|
+
output: content,
|
|
1186
|
+
errorCode: toolResult.error?.code,
|
|
1187
|
+
retryable: toolResult.error?.retryable,
|
|
1188
|
+
at: new Date().toISOString(),
|
|
1189
|
+
});
|
|
1190
|
+
if (input.logger) {
|
|
1191
|
+
await input.logger.log("tool_call", {
|
|
1192
|
+
protocolLoop: true,
|
|
1193
|
+
name: execution.toolName,
|
|
1194
|
+
logical_tool: execution.need.tool,
|
|
1195
|
+
ok: toolResult.ok,
|
|
1196
|
+
error: toolResult.error?.message,
|
|
1197
|
+
error_code: toolResult.error?.code,
|
|
1198
|
+
error_category: toolResult.error?.category,
|
|
1199
|
+
error_retryable: toolResult.error?.retryable,
|
|
1200
|
+
error_details: toolResult.error?.details,
|
|
1201
|
+
});
|
|
1202
|
+
}
|
|
1203
|
+
await appendSessionEvent(session, runId, "tool_result", {
|
|
1204
|
+
name: execution.toolName,
|
|
1205
|
+
logical_tool: execution.need.tool,
|
|
1206
|
+
ok: toolResult.ok,
|
|
1207
|
+
error: toolResult.error?.message,
|
|
1208
|
+
output: content,
|
|
1209
|
+
}, warnings);
|
|
1210
|
+
results.push(protocolResultFromToolResult(execution, toolResult, responseWarnings));
|
|
1211
|
+
}
|
|
1212
|
+
const codaliResponse = {
|
|
1213
|
+
version: "v1",
|
|
1214
|
+
request_id: request.request_id,
|
|
1215
|
+
results,
|
|
1216
|
+
meta: responseWarnings.length
|
|
1217
|
+
? { repo_root: input.workspace.root, warnings: responseWarnings }
|
|
1218
|
+
: { repo_root: input.workspace.root },
|
|
1219
|
+
};
|
|
1220
|
+
warnings.push(...responseWarnings);
|
|
1221
|
+
await appendSessionEvent(session, runId, "codali_response", { request_id: request.request_id, results, warnings: responseWarnings }, warnings);
|
|
1222
|
+
messages.push({ role: "user", content: formatCodaliResponse(codaliResponse) });
|
|
1223
|
+
}
|
|
1224
|
+
await throwBudgetError("runner_step_limit_exceeded", input.policy.maxSteps);
|
|
1225
|
+
throw new Error("unreachable_protocol_loop_budget_path");
|
|
1226
|
+
};
|
|
1227
|
+
export const createCodaliRuntime = (input) => ({
|
|
1228
|
+
run: () => runCodaliTask(input),
|
|
1229
|
+
});
|
|
1230
|
+
export const runCodaliTask = async (input) => {
|
|
1231
|
+
const runId = input.metadata?.requestId ?? randomUUID();
|
|
1232
|
+
const touchedFiles = new Set();
|
|
1233
|
+
const warnings = [];
|
|
1234
|
+
const events = [];
|
|
1235
|
+
let eventSequence = 0;
|
|
1236
|
+
const session = await initializeRuntimeSession(input, runId, warnings);
|
|
1237
|
+
const emit = (event) => {
|
|
1238
|
+
events.push(event);
|
|
1239
|
+
emitRuntimeEvent(event, input.onEvent, warnings);
|
|
1240
|
+
};
|
|
1241
|
+
const provider = input.providerInstance ?? createRuntimeProvider(input.provider);
|
|
1242
|
+
const registry = buildRuntimeToolRegistry(input);
|
|
1243
|
+
const originalRecordTouchedFile = input.toolContext?.recordTouchedFile;
|
|
1244
|
+
const toolContext = {
|
|
1245
|
+
...input.toolContext,
|
|
1246
|
+
workspaceRoot: input.workspace.root,
|
|
1247
|
+
runId: input.toolContext?.runId ?? runId,
|
|
1248
|
+
allowOutsideWorkspace: input.policy.allowOutsideWorkspace,
|
|
1249
|
+
allowShell: input.policy.allowShell,
|
|
1250
|
+
allowDestructiveOperations: input.policy.allowDestructiveOperations,
|
|
1251
|
+
recordTouchedFile: (filePath) => {
|
|
1252
|
+
touchedFiles.add(filePath);
|
|
1253
|
+
originalRecordTouchedFile?.(filePath);
|
|
1254
|
+
},
|
|
1255
|
+
};
|
|
1256
|
+
if (input.policy.mode === "smart_pipeline") {
|
|
1257
|
+
warnings.push("CodaliRuntime smart_pipeline mode is not implemented in the direct runtime wrapper yet");
|
|
1258
|
+
}
|
|
1259
|
+
if (input.policy.mode === "patch_json") {
|
|
1260
|
+
warnings.push("CodaliRuntime patch_json mode is running as a direct no-tool provider call");
|
|
1261
|
+
}
|
|
1262
|
+
const emitAgentEvent = (event) => {
|
|
1263
|
+
eventSequence += 1;
|
|
1264
|
+
emit(normalizeAgentEvent(event, `event-${eventSequence}`, new Date().toISOString()));
|
|
1265
|
+
};
|
|
1266
|
+
if (input.policy.mode === "protocol_loop") {
|
|
1267
|
+
try {
|
|
1268
|
+
const result = await runProtocolLoop({
|
|
1269
|
+
input,
|
|
1270
|
+
provider,
|
|
1271
|
+
registry,
|
|
1272
|
+
toolContext,
|
|
1273
|
+
runId,
|
|
1274
|
+
session,
|
|
1275
|
+
warnings,
|
|
1276
|
+
emit,
|
|
1277
|
+
emitAgentEvent,
|
|
1278
|
+
});
|
|
1279
|
+
if (result.usage) {
|
|
1280
|
+
emit({ type: "usage", usage: result.usage, at: new Date().toISOString() });
|
|
1281
|
+
}
|
|
1282
|
+
emit({
|
|
1283
|
+
type: "final",
|
|
1284
|
+
content: result.finalMessage.content,
|
|
1285
|
+
at: new Date().toISOString(),
|
|
1286
|
+
});
|
|
1287
|
+
await appendSessionEvent(session, runId, "final", { content: result.finalMessage.content }, warnings);
|
|
1288
|
+
const finalSession = await compactRuntimeSession(session, "completed", warnings);
|
|
1289
|
+
return {
|
|
1290
|
+
finalMessage: result.finalMessage.content,
|
|
1291
|
+
messages: result.messages,
|
|
1292
|
+
toolCallsExecuted: result.toolCallsExecuted,
|
|
1293
|
+
usage: result.usage,
|
|
1294
|
+
touchedFiles: Array.from(touchedFiles),
|
|
1295
|
+
warnings,
|
|
1296
|
+
events,
|
|
1297
|
+
runId,
|
|
1298
|
+
session: toSessionSummary(finalSession),
|
|
1299
|
+
};
|
|
1300
|
+
}
|
|
1301
|
+
catch (error) {
|
|
1302
|
+
emit({
|
|
1303
|
+
type: "error",
|
|
1304
|
+
message: error instanceof Error ? error.message : String(error),
|
|
1305
|
+
code: error instanceof Error ? error.name : undefined,
|
|
1306
|
+
at: new Date().toISOString(),
|
|
1307
|
+
});
|
|
1308
|
+
await appendSessionEvent(session, runId, "error", { message: error instanceof Error ? error.message : String(error) }, warnings);
|
|
1309
|
+
await compactRuntimeSession(session, "failed", warnings);
|
|
1310
|
+
throw error;
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
const runner = new Runner({
|
|
1314
|
+
provider,
|
|
1315
|
+
tools: registry,
|
|
1316
|
+
context: toolContext,
|
|
1317
|
+
maxSteps: input.policy.maxSteps,
|
|
1318
|
+
maxToolCalls: input.policy.maxToolCalls,
|
|
1319
|
+
maxTokens: input.policy.maxTokens,
|
|
1320
|
+
timeoutMs: input.policy.timeoutMs,
|
|
1321
|
+
stream: input.streaming?.enabled,
|
|
1322
|
+
streamFlushMs: input.streaming?.flushEveryMs,
|
|
1323
|
+
responseFormat: buildResponseFormat(input.response),
|
|
1324
|
+
toolChoice: input.policy.mode === "tool_loop" ? "auto" : "none",
|
|
1325
|
+
logger: input.logger,
|
|
1326
|
+
onEvent: emitAgentEvent,
|
|
1327
|
+
});
|
|
1328
|
+
try {
|
|
1329
|
+
const result = await runner.run(input.messages ?? [{ role: "user", content: input.task }]);
|
|
1330
|
+
if (result.usage) {
|
|
1331
|
+
emit({ type: "usage", usage: result.usage, at: new Date().toISOString() });
|
|
1332
|
+
}
|
|
1333
|
+
emit({
|
|
1334
|
+
type: "final",
|
|
1335
|
+
content: result.finalMessage.content,
|
|
1336
|
+
at: new Date().toISOString(),
|
|
1337
|
+
});
|
|
1338
|
+
await appendSessionEvent(session, runId, "final", { content: result.finalMessage.content }, warnings);
|
|
1339
|
+
const finalSession = await compactRuntimeSession(session, "completed", warnings);
|
|
1340
|
+
return {
|
|
1341
|
+
finalMessage: result.finalMessage.content,
|
|
1342
|
+
messages: result.messages,
|
|
1343
|
+
toolCallsExecuted: result.toolCallsExecuted,
|
|
1344
|
+
usage: result.usage,
|
|
1345
|
+
touchedFiles: Array.from(touchedFiles),
|
|
1346
|
+
warnings,
|
|
1347
|
+
events,
|
|
1348
|
+
runId,
|
|
1349
|
+
session: toSessionSummary(finalSession),
|
|
1350
|
+
};
|
|
1351
|
+
}
|
|
1352
|
+
catch (error) {
|
|
1353
|
+
emit({
|
|
1354
|
+
type: "error",
|
|
1355
|
+
message: error instanceof Error ? error.message : String(error),
|
|
1356
|
+
code: error instanceof Error ? error.name : undefined,
|
|
1357
|
+
at: new Date().toISOString(),
|
|
1358
|
+
});
|
|
1359
|
+
await appendSessionEvent(session, runId, "error", { message: error instanceof Error ? error.message : String(error) }, warnings);
|
|
1360
|
+
await compactRuntimeSession(session, "failed", warnings);
|
|
1361
|
+
throw error;
|
|
1362
|
+
}
|
|
1363
|
+
};
|