@mcoda/mswarm 0.1.107 → 0.1.109

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.
Files changed (162) hide show
  1. package/README.md +17 -0
  2. package/dist/codali-executor.d.ts.map +1 -1
  3. package/dist/codali-executor.js +17 -3
  4. package/dist/codali-executor.js.map +1 -1
  5. package/dist/runtime.d.ts +16 -5
  6. package/dist/runtime.d.ts.map +1 -1
  7. package/dist/runtime.js +292 -36
  8. package/dist/runtime.js.map +1 -1
  9. package/dist/server.d.ts.map +1 -1
  10. package/dist/server.js +4 -0
  11. package/dist/server.js.map +1 -1
  12. package/dist/vendor/codali/agents/AgentInventory.d.ts +56 -0
  13. package/dist/vendor/codali/agents/AgentInventory.d.ts.map +1 -0
  14. package/dist/vendor/codali/agents/AgentInventory.js +131 -0
  15. package/dist/vendor/codali/agents/RoleResolution.d.ts +49 -0
  16. package/dist/vendor/codali/agents/RoleResolution.d.ts.map +1 -0
  17. package/dist/vendor/codali/agents/RoleResolution.js +166 -0
  18. package/dist/vendor/codali/api/ChatCompletionsAdapter.d.ts +76 -0
  19. package/dist/vendor/codali/api/ChatCompletionsAdapter.d.ts.map +1 -0
  20. package/dist/vendor/codali/api/ChatCompletionsAdapter.js +54 -0
  21. package/dist/vendor/codali/api/CodaliApi.d.ts +78 -0
  22. package/dist/vendor/codali/api/CodaliApi.d.ts.map +1 -0
  23. package/dist/vendor/codali/api/CodaliApi.js +273 -0
  24. package/dist/vendor/codali/api/CodaliServer.d.ts +42 -0
  25. package/dist/vendor/codali/api/CodaliServer.d.ts.map +1 -0
  26. package/dist/vendor/codali/api/CodaliServer.js +118 -0
  27. package/dist/vendor/codali/cli/AskCommand.d.ts +66 -0
  28. package/dist/vendor/codali/cli/AskCommand.d.ts.map +1 -0
  29. package/dist/vendor/codali/cli/AskCommand.js +536 -0
  30. package/dist/vendor/codali/cli/AuthCommand.d.ts +19 -0
  31. package/dist/vendor/codali/cli/AuthCommand.d.ts.map +1 -0
  32. package/dist/vendor/codali/cli/AuthCommand.js +161 -0
  33. package/dist/vendor/codali/cli/ServeCommand.d.ts +5 -0
  34. package/dist/vendor/codali/cli/ServeCommand.d.ts.map +1 -0
  35. package/dist/vendor/codali/cli/ServeCommand.js +87 -0
  36. package/dist/vendor/codali/cli/ToolsCommand.d.ts +22 -0
  37. package/dist/vendor/codali/cli/ToolsCommand.d.ts.map +1 -0
  38. package/dist/vendor/codali/cli/ToolsCommand.js +208 -0
  39. package/dist/vendor/codali/cli.d.ts.map +1 -1
  40. package/dist/vendor/codali/cli.js +29 -1
  41. package/dist/vendor/codali/connectors/http/HttpToolDefinition.d.ts +74 -0
  42. package/dist/vendor/codali/connectors/http/HttpToolDefinition.d.ts.map +1 -0
  43. package/dist/vendor/codali/connectors/http/HttpToolDefinition.js +190 -0
  44. package/dist/vendor/codali/connectors/http/HttpToolSource.d.ts +18 -0
  45. package/dist/vendor/codali/connectors/http/HttpToolSource.d.ts.map +1 -0
  46. package/dist/vendor/codali/connectors/http/HttpToolSource.js +29 -0
  47. package/dist/vendor/codali/connectors/mcp/McpClient.d.ts +132 -0
  48. package/dist/vendor/codali/connectors/mcp/McpClient.d.ts.map +1 -0
  49. package/dist/vendor/codali/connectors/mcp/McpClient.js +215 -0
  50. package/dist/vendor/codali/connectors/mcp/McpServerRegistry.d.ts +75 -0
  51. package/dist/vendor/codali/connectors/mcp/McpServerRegistry.d.ts.map +1 -0
  52. package/dist/vendor/codali/connectors/mcp/McpServerRegistry.js +180 -0
  53. package/dist/vendor/codali/connectors/mcp/McpToolAdapter.d.ts +48 -0
  54. package/dist/vendor/codali/connectors/mcp/McpToolAdapter.d.ts.map +1 -0
  55. package/dist/vendor/codali/connectors/mcp/McpToolAdapter.js +101 -0
  56. package/dist/vendor/codali/connectors/mcp/McpToolSource.d.ts +27 -0
  57. package/dist/vendor/codali/connectors/mcp/McpToolSource.d.ts.map +1 -0
  58. package/dist/vendor/codali/connectors/mcp/McpToolSource.js +33 -0
  59. package/dist/vendor/codali/connectors/media/ImageGenerationTool.d.ts +43 -0
  60. package/dist/vendor/codali/connectors/media/ImageGenerationTool.d.ts.map +1 -0
  61. package/dist/vendor/codali/connectors/media/ImageGenerationTool.js +122 -0
  62. package/dist/vendor/codali/connectors/oauth/DeviceCodeAuth.d.ts +74 -0
  63. package/dist/vendor/codali/connectors/oauth/DeviceCodeAuth.d.ts.map +1 -0
  64. package/dist/vendor/codali/connectors/oauth/DeviceCodeAuth.js +153 -0
  65. package/dist/vendor/codali/docdex/DocdexClient.d.ts +2 -0
  66. package/dist/vendor/codali/docdex/DocdexClient.d.ts.map +1 -1
  67. package/dist/vendor/codali/docdex/DocdexClient.js +4 -0
  68. package/dist/vendor/codali/gateway/CodaliGateway.d.ts +51 -3
  69. package/dist/vendor/codali/gateway/CodaliGateway.d.ts.map +1 -1
  70. package/dist/vendor/codali/gateway/CodaliGateway.js +226 -2
  71. package/dist/vendor/codali/gateway/CodaliGatewayTypes.d.ts +34 -0
  72. package/dist/vendor/codali/gateway/CodaliGatewayTypes.d.ts.map +1 -1
  73. package/dist/vendor/codali/gateway/EvidenceNormalizer.d.ts.map +1 -1
  74. package/dist/vendor/codali/gateway/EvidenceNormalizer.js +90 -1
  75. package/dist/vendor/codali/gateway/Finalizer.d.ts +50 -0
  76. package/dist/vendor/codali/gateway/Finalizer.d.ts.map +1 -0
  77. package/dist/vendor/codali/gateway/Finalizer.js +79 -0
  78. package/dist/vendor/codali/gateway/GatewayPlanner.d.ts +13 -0
  79. package/dist/vendor/codali/gateway/GatewayPlanner.d.ts.map +1 -1
  80. package/dist/vendor/codali/gateway/GatewayPlanner.js +81 -16
  81. package/dist/vendor/codali/gateway/GatewayStateMachine.d.ts.map +1 -1
  82. package/dist/vendor/codali/gateway/GatewayStateMachine.js +6 -0
  83. package/dist/vendor/codali/gateway/GatewayTracer.d.ts +93 -0
  84. package/dist/vendor/codali/gateway/GatewayTracer.d.ts.map +1 -0
  85. package/dist/vendor/codali/gateway/GatewayTracer.js +214 -0
  86. package/dist/vendor/codali/gateway/LocalGatewayProvider.d.ts +46 -0
  87. package/dist/vendor/codali/gateway/LocalGatewayProvider.d.ts.map +1 -0
  88. package/dist/vendor/codali/gateway/LocalGatewayProvider.js +161 -0
  89. package/dist/vendor/codali/gateway/LocalGatewayTaskRunner.d.ts +79 -0
  90. package/dist/vendor/codali/gateway/LocalGatewayTaskRunner.d.ts.map +1 -0
  91. package/dist/vendor/codali/gateway/LocalGatewayTaskRunner.js +354 -0
  92. package/dist/vendor/codali/gateway/RelevanceJudge.d.ts +14 -0
  93. package/dist/vendor/codali/gateway/RelevanceJudge.d.ts.map +1 -0
  94. package/dist/vendor/codali/gateway/RelevanceJudge.js +87 -0
  95. package/dist/vendor/codali/gateway/ResponseSchema.d.ts +32 -0
  96. package/dist/vendor/codali/gateway/ResponseSchema.d.ts.map +1 -0
  97. package/dist/vendor/codali/gateway/ResponseSchema.js +120 -0
  98. package/dist/vendor/codali/gateway/TemporalContext.d.ts +36 -0
  99. package/dist/vendor/codali/gateway/TemporalContext.d.ts.map +1 -0
  100. package/dist/vendor/codali/gateway/TemporalContext.js +115 -0
  101. package/dist/vendor/codali/gateway/ToolCapabilityCompiler.d.ts +5 -0
  102. package/dist/vendor/codali/gateway/ToolCapabilityCompiler.d.ts.map +1 -1
  103. package/dist/vendor/codali/gateway/ToolCapabilityCompiler.js +27 -2
  104. package/dist/vendor/codali/gateway/ToolDescriptorSource.d.ts +6 -0
  105. package/dist/vendor/codali/gateway/ToolDescriptorSource.d.ts.map +1 -0
  106. package/dist/vendor/codali/gateway/ToolDescriptorSource.js +30 -0
  107. package/dist/vendor/codali/gateway/ToolExposure.d.ts +36 -0
  108. package/dist/vendor/codali/gateway/ToolExposure.d.ts.map +1 -0
  109. package/dist/vendor/codali/gateway/ToolExposure.js +154 -0
  110. package/dist/vendor/codali/index.d.ts +57 -0
  111. package/dist/vendor/codali/index.d.ts.map +1 -1
  112. package/dist/vendor/codali/index.js +45 -0
  113. package/dist/vendor/codali/providers/ClaudeCliProvider.d.ts +2 -0
  114. package/dist/vendor/codali/providers/ClaudeCliProvider.d.ts.map +1 -1
  115. package/dist/vendor/codali/providers/ClaudeCliProvider.js +2 -0
  116. package/dist/vendor/codali/providers/CodexCliProvider.d.ts +2 -0
  117. package/dist/vendor/codali/providers/CodexCliProvider.d.ts.map +1 -1
  118. package/dist/vendor/codali/providers/CodexCliProvider.js +2 -0
  119. package/dist/vendor/codali/providers/MswarmWorkerProvider.d.ts +2 -0
  120. package/dist/vendor/codali/providers/MswarmWorkerProvider.d.ts.map +1 -1
  121. package/dist/vendor/codali/providers/MswarmWorkerProvider.js +2 -0
  122. package/dist/vendor/codali/providers/OllamaRemoteProvider.d.ts +2 -0
  123. package/dist/vendor/codali/providers/OllamaRemoteProvider.d.ts.map +1 -1
  124. package/dist/vendor/codali/providers/OllamaRemoteProvider.js +2 -0
  125. package/dist/vendor/codali/providers/OpenAiCompatibleProvider.d.ts +2 -0
  126. package/dist/vendor/codali/providers/OpenAiCompatibleProvider.d.ts.map +1 -1
  127. package/dist/vendor/codali/providers/OpenAiCompatibleProvider.js +2 -0
  128. package/dist/vendor/codali/providers/ProviderTypes.d.ts +13 -0
  129. package/dist/vendor/codali/providers/ProviderTypes.d.ts.map +1 -1
  130. package/dist/vendor/codali/providers/ProviderTypes.js +1 -1
  131. package/dist/vendor/codali/runcontext/CredentialFile.d.ts +12 -0
  132. package/dist/vendor/codali/runcontext/CredentialFile.d.ts.map +1 -0
  133. package/dist/vendor/codali/runcontext/CredentialFile.js +81 -0
  134. package/dist/vendor/codali/runcontext/RunContextResolver.d.ts +126 -0
  135. package/dist/vendor/codali/runcontext/RunContextResolver.d.ts.map +1 -0
  136. package/dist/vendor/codali/runcontext/RunContextResolver.js +389 -0
  137. package/dist/vendor/codali/storage/CodaliDatasetPrivacyEngine.d.ts +1 -1
  138. package/dist/vendor/codali/storage/CodaliDatasetPrivacyEngine.d.ts.map +1 -1
  139. package/dist/vendor/codali/storage/CodaliDatasetPrivacyEngine.js +12 -0
  140. package/dist/vendor/codali/tools/ToolRegistry.d.ts +14 -1
  141. package/dist/vendor/codali/tools/ToolRegistry.d.ts.map +1 -1
  142. package/dist/vendor/codali/tools/ToolRegistry.js +38 -1
  143. package/dist/vendor/codali/tools/ToolTypes.d.ts +35 -0
  144. package/dist/vendor/codali/tools/ToolTypes.d.ts.map +1 -1
  145. package/dist/vendor/codali/tools/ToolTypes.js +21 -0
  146. package/dist/vendor/codali/tools/TruncateResult.d.ts +29 -0
  147. package/dist/vendor/codali/tools/TruncateResult.d.ts.map +1 -0
  148. package/dist/vendor/codali/tools/TruncateResult.js +91 -0
  149. package/dist/vendor/codali/tools/diff/DiffTool.d.ts.map +1 -1
  150. package/dist/vendor/codali/tools/diff/DiffTool.js +2 -0
  151. package/dist/vendor/codali/tools/docdex/DocdexTools.d.ts +21 -1
  152. package/dist/vendor/codali/tools/docdex/DocdexTools.d.ts.map +1 -1
  153. package/dist/vendor/codali/tools/docdex/DocdexTools.js +108 -16
  154. package/dist/vendor/codali/tools/filesystem/FileTools.d.ts.map +1 -1
  155. package/dist/vendor/codali/tools/filesystem/FileTools.js +8 -0
  156. package/dist/vendor/codali/tools/search/SearchTool.d.ts.map +1 -1
  157. package/dist/vendor/codali/tools/search/SearchTool.js +3 -1
  158. package/dist/vendor/codali/tools/shell/ShellTool.d.ts.map +1 -1
  159. package/dist/vendor/codali/tools/shell/ShellTool.js +2 -0
  160. package/package.json +3 -3
  161. package/scripts/stable-diffusion-cpp-auth-guard.py +475 -0
  162. package/scripts/stable-diffusion-cpp-openai-server.py +44 -0
@@ -0,0 +1,166 @@
1
+ import { resolveCodaliGatewayAgentTiers, } from "../gateway/AgentTierResolver.js";
2
+ /** Internal roles each configurable role stands in for. */
3
+ const ROLE_EXPANSION = {
4
+ // Thinking stages: JSON in, JSON out, no tool calls. A small fast model is
5
+ // usually enough, and these run on every question.
6
+ orchestrator: [
7
+ "router",
8
+ "classifier",
9
+ "planner",
10
+ "query_expander",
11
+ "context_refiner",
12
+ "verifier",
13
+ "repair",
14
+ ],
15
+ // Tool-calling stages. Accuracy here decides whether a run gathers anything:
16
+ // a weak model invents dates and empty ids. Split out so a bigger model can
17
+ // be put exactly here without slowing down planning.
18
+ worker: ["rag_worker", "tool_worker", "extractor"],
19
+ synthesizer: ["final_synthesizer"],
20
+ media: ["image_worker"],
21
+ };
22
+ /** Phase 1 resolves only these; media arrives with image generation. */
23
+ export const PHASE_ONE_ROLES = [
24
+ "orchestrator",
25
+ "worker",
26
+ "synthesizer",
27
+ ];
28
+ /** Internal roles whose policies already demand tool support, best first. */
29
+ const TOOL_CAPABLE_PREFERENCE = ["tool_worker", "rag_worker"];
30
+ /**
31
+ * Adapters driven through a text CLI. They advertise `supportsTools: true`
32
+ * because the CLI itself has tools, but Codali's provider for them cannot
33
+ * surface a structured tool call — so choosing one as the tool worker yields a
34
+ * correct plan and zero tool calls.
35
+ */
36
+ const NON_TOOL_CALLING_ADAPTERS = new Set(["claude-cli", "codex-cli", "gemini-cli"]);
37
+ const canEmitToolCalls = (assignment) => assignment?.candidate.supportsTools === true &&
38
+ !NON_TOOL_CALLING_ADAPTERS.has((assignment.candidate.adapter ?? "").toLowerCase());
39
+ const findToolCapableAssignment = (resolution, preferred) => {
40
+ if (canEmitToolCalls(preferred))
41
+ return preferred;
42
+ for (const role of TOOL_CAPABLE_PREFERENCE) {
43
+ const assignment = resolution.assignments[role];
44
+ if (canEmitToolCalls(assignment))
45
+ return assignment;
46
+ }
47
+ return Object.values(resolution.assignments).find((assignment) => canEmitToolCalls(assignment));
48
+ };
49
+ const findBySlug = (inventory, slug) => inventory.find((agent) => agent.slug === slug || agent.id === slug);
50
+ /**
51
+ * Builds the tier policy the resolver consumes. An explicitly bound slug is
52
+ * honoured for every internal role the configurable role stands in for, so
53
+ * binding `orchestrator` really does move planning, verification and repair
54
+ * onto that agent.
55
+ */
56
+ const buildAgentPolicy = (bindings, inventory, warnings) => {
57
+ if (!bindings)
58
+ return undefined;
59
+ const roles = {};
60
+ let hasBinding = false;
61
+ for (const [role, slug] of Object.entries(bindings)) {
62
+ if (!slug)
63
+ continue;
64
+ const agent = findBySlug(inventory, slug);
65
+ if (!agent) {
66
+ warnings.push(`agent_binding_not_found:${role}:${slug}`);
67
+ continue;
68
+ }
69
+ hasBinding = true;
70
+ // Use the bound agent's *own* tier for the role. Imposing the role's
71
+ // nominal tier here silently discards the operator's choice: binding
72
+ // `orchestrator` to a large agent left it failing a "medium" requirement
73
+ // and falling back to whatever the resolver preferred, with the config
74
+ // appearing to have no effect.
75
+ const boundTier = (typeof agent.tier === "string" ? agent.tier : undefined) ??
76
+ (role === "synthesizer" ? "large" : role === "media" ? "image" : "medium");
77
+ for (const internalRole of ROLE_EXPANSION[role] ?? []) {
78
+ roles[internalRole] = {
79
+ tier: boundTier,
80
+ preferredRunnerKinds: undefined,
81
+ };
82
+ }
83
+ }
84
+ return hasBinding ? { resolver: "mcoda_inventory", roles } : undefined;
85
+ };
86
+ export const resolveConfigurableRoles = (input) => {
87
+ const warnings = [];
88
+ const roles = input.roles ?? PHASE_ONE_ROLES;
89
+ const internalRoles = roles.flatMap((role) => ROLE_EXPANSION[role] ?? []);
90
+ const agentPolicy = buildAgentPolicy(input.bindings, input.inventory, warnings);
91
+ const resolution = resolveCodaliGatewayAgentTiers({
92
+ inventory: input.inventory,
93
+ agentPolicy,
94
+ roles: internalRoles,
95
+ allowImageWorker: input.allowImageWorker ?? roles.includes("media"),
96
+ });
97
+ const assignments = {};
98
+ const bindingsOut = {};
99
+ for (const role of roles) {
100
+ // An explicit binding is the operator's decision and overrides tier
101
+ // matching outright. Routing it through the tier policy silently discarded
102
+ // the choice: mcoda's inventory carries no `tier` field — the resolver
103
+ // infers one — so a bound large agent failed a nominal "medium"
104
+ // requirement and the config appeared to do nothing.
105
+ const boundSlug = input.bindings?.[role];
106
+ if (boundSlug) {
107
+ const candidate = resolution.candidates.find((entry) => entry.slug === boundSlug || entry.id === boundSlug);
108
+ if (candidate) {
109
+ const existing = Object.values(resolution.assignments).find((assignment) => assignment.candidate.slug === candidate.slug);
110
+ assignments[role] = existing ?? {
111
+ role,
112
+ policy: { tier: candidate.tier },
113
+ candidate,
114
+ agent: {
115
+ slug: candidate.slug,
116
+ adapter: candidate.adapter ?? "",
117
+ model: candidate.model ?? "",
118
+ supportsTools: candidate.supportsTools,
119
+ contextWindow: candidate.contextWindow,
120
+ maxOutputTokens: candidate.maxOutputTokens,
121
+ },
122
+ score: 0,
123
+ reasons: ["explicit_binding"],
124
+ };
125
+ bindingsOut[role] = candidate.slug;
126
+ continue;
127
+ }
128
+ warnings.push(`agent_binding_unavailable:${role}:${boundSlug}`);
129
+ }
130
+ // Otherwise the role is served by the first of its internal roles that
131
+ // resolved. They share a tier, so any is a valid stand-in.
132
+ for (const internalRole of ROLE_EXPANSION[role] ?? []) {
133
+ const assignment = resolution.assignments[internalRole];
134
+ if (assignment) {
135
+ assignments[role] = assignment;
136
+ bindingsOut[role] = assignment.candidate.slug;
137
+ break;
138
+ }
139
+ }
140
+ if (!assignments[role]) {
141
+ warnings.push(`agent_role_unresolved:${role}`);
142
+ }
143
+ }
144
+ // An internal role that failed to resolve is only worth reporting when the
145
+ // configurable role standing in for it also failed. Otherwise every run on a
146
+ // sparse inventory emits a wall of errors for roles that fell back correctly
147
+ // and never affected the answer.
148
+ const servedInternalRoles = new Set(roles
149
+ .filter((role) => assignments[role])
150
+ .flatMap((role) => ROLE_EXPANSION[role] ?? []));
151
+ for (const error of resolution.errors) {
152
+ if (error.role && servedInternalRoles.has(error.role))
153
+ continue;
154
+ warnings.push(`agent_resolution_error:${error.code}${error.role ? `:${error.role}` : ""}`);
155
+ }
156
+ const toolCapable = findToolCapableAssignment(resolution,
157
+ // An explicitly bound worker wins; otherwise fall back to the orchestrator.
158
+ assignments.worker ?? assignments.orchestrator);
159
+ if (!toolCapable) {
160
+ warnings.push("no_tool_capable_agent");
161
+ }
162
+ else if (toolCapable !== assignments.orchestrator) {
163
+ warnings.push(`tool_worker_substituted:${toolCapable.candidate.slug}`);
164
+ }
165
+ return { resolution, assignments, bindings: bindingsOut, toolCapable, warnings };
166
+ };
@@ -0,0 +1,76 @@
1
+ import { runCodali, type CodaliMessage, type CodaliRequest, type CodaliResult } from "./CodaliApi.js";
2
+ import type { RunContext } from "../runcontext/RunContextResolver.js";
3
+ /**
4
+ * OpenAI-compatible chat-completions adapter.
5
+ *
6
+ * okacam AI chat already speaks this shape. Rather than changing AI chat to
7
+ * learn Codali's contract, Codali speaks AI chat's — the product points its
8
+ * existing client at a different base URL and gets orchestration, tools, and
9
+ * citations without a rewrite.
10
+ *
11
+ * The adapter is deliberately thin. It maps message shapes and nothing else;
12
+ * all routing, tool selection and budget enforcement stay in the one code path
13
+ * `runCodali` provides, so the adapter cannot drift from the CLI's behaviour.
14
+ */
15
+ export interface ChatCompletionMessage {
16
+ role: string;
17
+ content: string | null;
18
+ }
19
+ export interface ChatCompletionRequest {
20
+ model?: string;
21
+ messages: ChatCompletionMessage[];
22
+ stream?: boolean;
23
+ response_format?: {
24
+ type?: string;
25
+ json_schema?: {
26
+ schema?: Record<string, unknown>;
27
+ };
28
+ };
29
+ /** Codali-specific extras, ignored by a plain OpenAI client. */
30
+ codali?: {
31
+ runContext?: RunContext;
32
+ workspaceRoot?: string;
33
+ mode?: CodaliRequest["mode"];
34
+ media?: CodaliRequest["media"];
35
+ budgets?: CodaliRequest["budgets"];
36
+ };
37
+ }
38
+ export interface ChatCompletionResponse {
39
+ id: string;
40
+ object: "chat.completion";
41
+ created: number;
42
+ model: string;
43
+ choices: Array<{
44
+ index: number;
45
+ message: {
46
+ role: "assistant";
47
+ content: string;
48
+ };
49
+ finish_reason: "stop" | "length" | "content_filter";
50
+ }>;
51
+ usage?: {
52
+ prompt_tokens: number;
53
+ completion_tokens: number;
54
+ total_tokens: number;
55
+ };
56
+ /**
57
+ * Codali's provenance, carried alongside the OpenAI shape. A plain client
58
+ * ignores this; a product that wants citations reads it. Without it the
59
+ * adapter would throw away the very thing that makes an orchestrated answer
60
+ * trustworthy.
61
+ */
62
+ codali: {
63
+ status: CodaliResult["status"];
64
+ sources: CodaliResult["sources"];
65
+ artifacts: CodaliResult["artifacts"];
66
+ warnings: string[];
67
+ traceId: string;
68
+ output?: unknown;
69
+ };
70
+ }
71
+ export declare const toCodaliMessages: (messages: readonly ChatCompletionMessage[]) => CodaliMessage[];
72
+ export interface ChatAdapterDependencies {
73
+ run?: typeof runCodali;
74
+ }
75
+ export declare const handleChatCompletion: (request: ChatCompletionRequest, deps?: ChatAdapterDependencies) => Promise<ChatCompletionResponse>;
76
+ //# sourceMappingURL=ChatCompletionsAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatCompletionsAdapter.d.ts","sourceRoot":"","sources":["../../src/api/ChatCompletionsAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,aAAa,EAAE,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACtG,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAC;AAEtE;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,qBAAqB,EAAE,CAAC;IAClC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,eAAe,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE;YAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;SAAE,CAAA;KAAE,CAAC;IACxF,gEAAgE;IAChE,MAAM,CAAC,EAAE;QACP,UAAU,CAAC,EAAE,UAAU,CAAC;QACxB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,IAAI,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;QAC7B,KAAK,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;QAC/B,OAAO,CAAC,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;KACpC,CAAC;CACH;AAED,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,iBAAiB,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,KAAK,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE;YAAE,IAAI,EAAE,WAAW,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC;QAChD,aAAa,EAAE,MAAM,GAAG,QAAQ,GAAG,gBAAgB,CAAC;KACrD,CAAC,CAAC;IACH,KAAK,CAAC,EAAE;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,iBAAiB,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;IACnF;;;;;OAKG;IACH,MAAM,EAAE;QACN,MAAM,EAAE,YAAY,CAAC,QAAQ,CAAC,CAAC;QAC/B,OAAO,EAAE,YAAY,CAAC,SAAS,CAAC,CAAC;QACjC,SAAS,EAAE,YAAY,CAAC,WAAW,CAAC,CAAC;QACrC,QAAQ,EAAE,MAAM,EAAE,CAAC;QACnB,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,OAAO,CAAC;KAClB,CAAC;CACH;AAID,eAAO,MAAM,gBAAgB,GAC3B,UAAU,SAAS,qBAAqB,EAAE,KACzC,aAAa,EAMT,CAAC;AAWR,MAAM,WAAW,uBAAuB;IACtC,GAAG,CAAC,EAAE,OAAO,SAAS,CAAC;CACxB;AAED,eAAO,MAAM,oBAAoB,GAC/B,SAAS,qBAAqB,EAC9B,OAAM,uBAA4B,KACjC,OAAO,CAAC,sBAAsB,CAsChC,CAAC"}
@@ -0,0 +1,54 @@
1
+ import { runCodali } from "./CodaliApi.js";
2
+ const CHAT_ROLES = new Set(["system", "user", "assistant"]);
3
+ export const toCodaliMessages = (messages) => messages
4
+ .filter((message) => CHAT_ROLES.has(message.role) && typeof message.content === "string")
5
+ .map((message) => ({
6
+ role: message.role,
7
+ content: message.content,
8
+ }));
9
+ const readResponseSchema = (request) => {
10
+ const format = request.response_format;
11
+ if (!format)
12
+ return undefined;
13
+ if (format.type === "json_schema")
14
+ return format.json_schema?.schema;
15
+ return undefined;
16
+ };
17
+ export const handleChatCompletion = async (request, deps = {}) => {
18
+ const run = deps.run ?? runCodali;
19
+ const result = await run({
20
+ messages: toCodaliMessages(request.messages),
21
+ runContext: request.codali?.runContext,
22
+ workspaceRoot: request.codali?.workspaceRoot,
23
+ mode: request.codali?.mode,
24
+ media: request.codali?.media,
25
+ budgets: request.codali?.budgets,
26
+ responseSchema: readResponseSchema(request),
27
+ responseMode: request.response_format?.type === "json_object" ? "json" : "text",
28
+ product: { name: "chat-completions" },
29
+ });
30
+ return {
31
+ id: `chatcmpl-${result.traceId}`,
32
+ object: "chat.completion",
33
+ created: Math.floor(Date.now() / 1000),
34
+ model: request.model ?? "codali",
35
+ choices: [
36
+ {
37
+ index: 0,
38
+ message: { role: "assistant", content: result.answer },
39
+ // A partial or clarification-seeking answer is not a normal stop. A
40
+ // client that only inspects finish_reason must not mistake it for a
41
+ // complete response.
42
+ finish_reason: result.status === "succeeded" ? "stop" : "length",
43
+ },
44
+ ],
45
+ codali: {
46
+ status: result.status,
47
+ sources: result.sources,
48
+ artifacts: result.artifacts,
49
+ warnings: result.warnings,
50
+ traceId: result.traceId,
51
+ output: result.output,
52
+ },
53
+ };
54
+ };
@@ -0,0 +1,78 @@
1
+ import { attachMcpTools } from "../connectors/mcp/McpToolSource.js";
2
+ import { type ImageGenerationConfig } from "../connectors/media/ImageGenerationTool.js";
3
+ import { createProviderForAssignment } from "../gateway/LocalGatewayProvider.js";
4
+ import { getAgentInventory } from "../agents/AgentInventory.js";
5
+ import { ToolRegistry } from "../tools/ToolRegistry.js";
6
+ import type { RunContext } from "../runcontext/RunContextResolver.js";
7
+ import type { CodaliArtifactRef, CodaliGatewayMode, CodaliGatewaySource, CodaliGatewayStatus } from "../gateway/CodaliGatewayTypes.js";
8
+ /**
9
+ * The canonical Codali API.
10
+ *
11
+ * This is the contract products integrate against — okacam AI chat, line items,
12
+ * badges, employee daily-log review. One entry point, one result shape, the
13
+ * same behaviour the CLI gets, so a product never has to reimplement routing,
14
+ * tool selection, evidence handling, or budget enforcement.
15
+ *
16
+ * Everything a run is allowed to touch arrives on the request as `runContext`.
17
+ * Codali does not call back into the host to fetch tenant configuration: the
18
+ * authenticated host already holds it, and a callback would make every request
19
+ * a circular distributed dependency.
20
+ */
21
+ export interface CodaliMessage {
22
+ role: "system" | "user" | "assistant";
23
+ content: string;
24
+ }
25
+ export interface CodaliRequest {
26
+ messages: CodaliMessage[];
27
+ /** Tenant scope, tools, credentials, agent bindings, limits. */
28
+ runContext?: RunContext;
29
+ /** JSON Schema the answer must satisfy. Enforced, with one repair attempt. */
30
+ responseSchema?: Record<string, unknown>;
31
+ responseMode?: "text" | "json" | "artifact";
32
+ mode?: CodaliGatewayMode;
33
+ /** Workspace the run resolves paths against. Defaults to `process.cwd()`. */
34
+ workspaceRoot?: string;
35
+ requestId?: string;
36
+ product?: {
37
+ name?: string;
38
+ version?: string;
39
+ surface?: string;
40
+ };
41
+ /** Image generation config; absent means the media tool is not offered. */
42
+ media?: ImageGenerationConfig;
43
+ budgets?: {
44
+ maxRounds?: number;
45
+ maxToolCalls?: number;
46
+ maxModelCalls?: number;
47
+ deadlineMs?: number;
48
+ };
49
+ }
50
+ export interface CodaliSourceRef extends CodaliGatewaySource {
51
+ }
52
+ export interface CodaliResult {
53
+ status: CodaliGatewayStatus;
54
+ /** Text answer, or the clarifying question when status is needs_clarification. */
55
+ answer: string;
56
+ /** Schema-conformant structured output when a responseSchema was supplied. */
57
+ output: unknown;
58
+ sources: CodaliSourceRef[];
59
+ artifacts: CodaliArtifactRef[];
60
+ warnings: string[];
61
+ traceId: string;
62
+ }
63
+ /** Flattens a message list into the single query the gateway plans against. */
64
+ export declare const messagesToQuery: (messages: readonly CodaliMessage[]) => string;
65
+ export interface CodaliRunDependencies {
66
+ loadInventory?: typeof getAgentInventory;
67
+ resolveRunContext?: (workspaceRoot: string) => Promise<RunContext>;
68
+ buildRegistry?: (workspaceRoot: string, context: RunContext) => ToolRegistry;
69
+ createProvider?: typeof createProviderForAssignment;
70
+ attachMcp?: typeof attachMcpTools;
71
+ }
72
+ /**
73
+ * Runs one Codali request end to end.
74
+ *
75
+ * The same code path the CLI uses, so a product and the terminal cannot drift.
76
+ */
77
+ export declare const runCodali: (request: CodaliRequest, deps?: CodaliRunDependencies) => Promise<CodaliResult>;
78
+ //# sourceMappingURL=CodaliApi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CodaliApi.d.ts","sourceRoot":"","sources":["../../src/api/CodaliApi.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACpE,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,4CAA4C,CAAC;AAIpD,OAAO,EAAE,2BAA2B,EAAE,MAAM,oCAAoC,CAAC;AAGjF,OAAO,EAAE,iBAAiB,EAAyB,MAAM,6BAA6B,CAAC;AAGvF,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAGxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAC;AACtE,OAAO,KAAK,EACV,iBAAiB,EACjB,iBAAiB,EAEjB,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,kCAAkC,CAAC;AAE1C;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,gEAAgE;IAChE,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,8EAA8E;IAC9E,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACzC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,UAAU,CAAC;IAC5C,IAAI,CAAC,EAAE,iBAAiB,CAAC;IACzB,6EAA6E;IAC7E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAChE,2EAA2E;IAC3E,KAAK,CAAC,EAAE,qBAAqB,CAAC;IAC9B,OAAO,CAAC,EAAE;QACR,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;CACH;AAED,MAAM,WAAW,eAAgB,SAAQ,mBAAmB;CAAG;AAE/D,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,mBAAmB,CAAC;IAC5B,kFAAkF;IAClF,MAAM,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,SAAS,EAAE,iBAAiB,EAAE,CAAC;IAC/B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAsBD,+EAA+E;AAC/E,eAAO,MAAM,eAAe,GAAI,UAAU,SAAS,aAAa,EAAE,KAAG,MAWpE,CAAC;AAEF,MAAM,WAAW,qBAAqB;IACpC,aAAa,CAAC,EAAE,OAAO,iBAAiB,CAAC;IACzC,iBAAiB,CAAC,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IACnE,aAAa,CAAC,EAAE,CAAC,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,KAAK,YAAY,CAAC;IAC7E,cAAc,CAAC,EAAE,OAAO,2BAA2B,CAAC;IACpD,SAAS,CAAC,EAAE,OAAO,cAAc,CAAC;CACnC;AAED;;;;GAIG;AACH,eAAO,MAAM,SAAS,GACpB,SAAS,aAAa,EACtB,OAAM,qBAA0B,KAC/B,OAAO,CAAC,YAAY,CAkOtB,CAAC"}
@@ -0,0 +1,273 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { attachHttpTools } from "../connectors/http/HttpToolSource.js";
3
+ import { attachMcpTools } from "../connectors/mcp/McpToolSource.js";
4
+ import { createImageGenerationTool, } from "../connectors/media/ImageGenerationTool.js";
5
+ import { DocdexClient } from "../docdex/DocdexClient.js";
6
+ import { createCodaliGateway } from "../gateway/CodaliGateway.js";
7
+ import { createLocalGatewayTaskRunner } from "../gateway/LocalGatewayTaskRunner.js";
8
+ import { createProviderForAssignment } from "../gateway/LocalGatewayProvider.js";
9
+ import { gatewayToolDescriptorsFromRegistry } from "../gateway/ToolDescriptorSource.js";
10
+ import { GatewayTracer } from "../gateway/GatewayTracer.js";
11
+ import { getAgentInventory, filterLocallyDrivable } from "../agents/AgentInventory.js";
12
+ import { resolveConfigurableRoles } from "../agents/RoleResolution.js";
13
+ import { providerSupportsToolCalls } from "../providers/ProviderTypes.js";
14
+ import { ToolRegistry } from "../tools/ToolRegistry.js";
15
+ import { createDocdexTools } from "../tools/docdex/DocdexTools.js";
16
+ import { LocalConfigRunContextResolver } from "../runcontext/RunContextResolver.js";
17
+ const DEFAULTS = {
18
+ maxRounds: 3,
19
+ maxToolCalls: 20,
20
+ maxModelCalls: 12,
21
+ deadlineMs: 600000,
22
+ maxParallelWorkers: 3,
23
+ };
24
+ const DEFAULT_DOCDEX_TOOLS = [
25
+ "docdex_search",
26
+ "docdex_open",
27
+ "docdex_symbols",
28
+ "docdex_tree",
29
+ "docdex_files",
30
+ "docdex_impact_graph",
31
+ "docdex_batch_search",
32
+ "docdex_web_research",
33
+ "docdex_stats",
34
+ ];
35
+ /** Flattens a message list into the single query the gateway plans against. */
36
+ export const messagesToQuery = (messages) => {
37
+ const lastUser = [...messages].reverse().find((message) => message.role === "user");
38
+ if (!lastUser)
39
+ return "";
40
+ const priorContext = messages
41
+ .slice(0, messages.indexOf(lastUser))
42
+ .filter((message) => message.role !== "system")
43
+ .slice(-4)
44
+ .map((message) => `${message.role}: ${message.content}`);
45
+ return priorContext.length > 0
46
+ ? `${priorContext.join("\n")}\n\nCurrent question: ${lastUser.content}`
47
+ : lastUser.content;
48
+ };
49
+ /**
50
+ * Runs one Codali request end to end.
51
+ *
52
+ * The same code path the CLI uses, so a product and the terminal cannot drift.
53
+ */
54
+ export const runCodali = async (request, deps = {}) => {
55
+ const workspaceRoot = request.workspaceRoot ?? process.cwd();
56
+ const query = messagesToQuery(request.messages);
57
+ const tracer = new GatewayTracer(query);
58
+ if (!query.trim()) {
59
+ return {
60
+ status: "failed",
61
+ answer: "The request contained no user message.",
62
+ output: undefined,
63
+ sources: [],
64
+ artifacts: [],
65
+ warnings: ["empty_request"],
66
+ traceId: request.requestId ?? randomUUID(),
67
+ };
68
+ }
69
+ // Host-supplied context wins; otherwise fall back to local trusted config.
70
+ const context = request.runContext ??
71
+ (deps.resolveRunContext
72
+ ? await deps.resolveRunContext(workspaceRoot)
73
+ : await new LocalConfigRunContextResolver().resolve({ workspaceRoot }));
74
+ for (const warning of context.warnings ?? [])
75
+ tracer.addWarning(warning);
76
+ const inventory = await (deps.loadInventory ?? getAgentInventory)();
77
+ const drivable = filterLocallyDrivable(inventory.agents);
78
+ const roles = resolveConfigurableRoles({
79
+ inventory: drivable,
80
+ bindings: context.agentRoles,
81
+ roles: request.media ? ["orchestrator", "synthesizer", "media"] : undefined,
82
+ });
83
+ for (const warning of roles.warnings)
84
+ tracer.addWarning(warning);
85
+ const orchestrator = roles.assignments.orchestrator;
86
+ const synthesizer = roles.assignments.synthesizer;
87
+ if (!orchestrator && !synthesizer) {
88
+ return {
89
+ status: "failed",
90
+ answer: "No usable model agent could be resolved for this run.",
91
+ output: undefined,
92
+ sources: [],
93
+ artifacts: [],
94
+ warnings: [...tracer.snapshot().warnings, "no_agents_resolved"],
95
+ traceId: request.requestId ?? randomUUID(),
96
+ };
97
+ }
98
+ const makeProvider = deps.createProvider ?? createProviderForAssignment;
99
+ const primary = makeProvider((synthesizer ?? orchestrator));
100
+ const orchestratorProvider = orchestrator ? makeProvider(orchestrator) : undefined;
101
+ const workerCandidates = [roles.toolCapable, orchestrator, synthesizer].filter(Boolean);
102
+ let worker = primary;
103
+ for (const candidate of workerCandidates) {
104
+ const provider = makeProvider(candidate);
105
+ if (providerSupportsToolCalls(provider)) {
106
+ worker = provider;
107
+ break;
108
+ }
109
+ }
110
+ const toolsExecutable = providerSupportsToolCalls(worker);
111
+ // ---- Tools ------------------------------------------------------------
112
+ const registry = deps.buildRegistry?.(workspaceRoot, context) ?? buildDefaultRegistry(workspaceRoot, context);
113
+ const mcp = await (deps.attachMcp ?? attachMcpTools)({ context, toolRegistry: registry });
114
+ for (const warning of mcp.warnings)
115
+ tracer.addWarning(warning);
116
+ const http = attachHttpTools({ context, toolRegistry: registry });
117
+ for (const warning of http.warnings)
118
+ tracer.addWarning(warning);
119
+ const artifacts = [];
120
+ const runId = request.requestId ?? `codali-${randomUUID()}`;
121
+ if (request.media) {
122
+ registry.register(createImageGenerationTool({
123
+ config: request.media,
124
+ workspaceRoot,
125
+ runId,
126
+ onArtifact: (artifact) => artifacts.push(artifact),
127
+ }));
128
+ }
129
+ const registered = registry.list().map((tool) => tool.name);
130
+ const readOnlyMcpTools = registry
131
+ .catalog(mcp.registered)
132
+ .filter((descriptor) => descriptor.readOnly)
133
+ .map((descriptor) => descriptor.name);
134
+ const defaultAllowed = [
135
+ ...DEFAULT_DOCDEX_TOOLS,
136
+ ...readOnlyMcpTools,
137
+ ...http.registered,
138
+ ...(request.media ? ["media_generate_image"] : []),
139
+ ];
140
+ const allowedTools = toolsExecutable
141
+ ? (context.allowedTools ?? defaultAllowed).filter((tool) => registered.includes(tool))
142
+ : [];
143
+ // Every allowed tool must be declared to the capability compiler, which
144
+ // otherwise discards it as `not_declared` — including docdex tools outside
145
+ // its hardcoded backing-tool set, such as `docdex_web_research`. That
146
+ // omission kept the "web" capability off the classifier's list entirely, so
147
+ // no question could ever reach the public web.
148
+ const connectorTools = allowedTools;
149
+ // ---- Budgets ----------------------------------------------------------
150
+ const min = (a, b) => (b === undefined ? a : Math.min(a, b));
151
+ const maxRounds = min(request.budgets?.maxRounds ?? DEFAULTS.maxRounds, context.limits?.maxRounds);
152
+ const maxToolCalls = min(request.budgets?.maxToolCalls ?? DEFAULTS.maxToolCalls, context.limits?.maxToolCalls);
153
+ const deadlineMs = min(request.budgets?.deadlineMs ?? DEFAULTS.deadlineMs, context.limits?.deadlineMs);
154
+ const gatewayRequest = {
155
+ id: runId,
156
+ query,
157
+ mode: request.mode ?? "balanced",
158
+ product: request.product ?? { name: "codali-api" },
159
+ tenant: context.tenant,
160
+ tools: connectorTools.length > 0
161
+ ? { actualTools: connectorTools, readOnlyTools: connectorTools }
162
+ : undefined,
163
+ docdex: {
164
+ enabled: true,
165
+ baseUrl: context.docdex?.baseUrl,
166
+ repoRoot: context.repo?.root ?? workspaceRoot,
167
+ repoId: context.docdex?.repoId,
168
+ },
169
+ policy: {
170
+ allowedTools,
171
+ deniedTools: context.deniedTools,
172
+ maxIterations: maxRounds,
173
+ maxRuntimeMs: deadlineMs,
174
+ maxToolCalls,
175
+ maxModelCalls: request.budgets?.maxModelCalls ?? DEFAULTS.maxModelCalls,
176
+ maxEvidenceItems: 40,
177
+ maxImageArtifacts: request.media ? 4 : 0,
178
+ maxContextPackTokens: 16000,
179
+ allowWrites: false,
180
+ allowShell: false,
181
+ allowDestructiveOperations: false,
182
+ allowOutsideWorkspace: false,
183
+ requireFinalLargeModel: false,
184
+ allowDegradedFinalAnswer: true,
185
+ allowImageWorker: Boolean(request.media),
186
+ },
187
+ response: {
188
+ format: request.responseSchema ? "json" : (request.responseMode === "json" ? "json" : "text"),
189
+ schema: request.responseSchema,
190
+ },
191
+ };
192
+ const gateway = createCodaliGateway({
193
+ provider: primary,
194
+ // Classify and plan on the orchestrator model; only the final answer pays
195
+ // for the large one.
196
+ plannerProvider: orchestratorProvider ?? primary,
197
+ // So the trace names the model that actually ran.
198
+ finalAgent: synthesizer ?? orchestrator,
199
+ agentInventory: drivable,
200
+ toolDescriptors: gatewayToolDescriptorsFromRegistry(registry, allowedTools),
201
+ taskRunner: createLocalGatewayTaskRunner({
202
+ provider: worker,
203
+ registry,
204
+ toolContext: {
205
+ workspaceRoot,
206
+ allowShell: false,
207
+ allowDestructiveOperations: false,
208
+ allowOutsideWorkspace: false,
209
+ },
210
+ onEvent: (event) => {
211
+ if (event.type === "tool_call") {
212
+ tracer.recordToolCall({ taskId: event.taskId, tool: event.tool, args: event.args });
213
+ }
214
+ else if (event.type === "tool_result") {
215
+ tracer.recordToolResult({
216
+ taskId: event.taskId,
217
+ tool: event.tool,
218
+ ok: event.ok,
219
+ latencyMs: event.latencyMs,
220
+ errorCode: event.errorCode,
221
+ });
222
+ }
223
+ },
224
+ }),
225
+ workerOptions: {
226
+ maxRuntimeMs: deadlineMs,
227
+ maxToolCalls,
228
+ perTaskTimeoutMs: Math.max(60000, Math.floor(deadlineMs / 2)),
229
+ maxParallelWorkers: DEFAULTS.maxParallelWorkers,
230
+ },
231
+ });
232
+ try {
233
+ const result = await gateway.run(gatewayRequest);
234
+ return {
235
+ status: result.status,
236
+ answer: result.answer,
237
+ output: result.output ?? result.answer,
238
+ sources: result.sources,
239
+ // Artifacts collected by the media tool are authoritative; the gateway's
240
+ // own list covers anything a worker persisted directly.
241
+ artifacts: artifacts.length > 0 ? artifacts : result.artifacts,
242
+ warnings: [...tracer.snapshot().warnings, ...result.warnings],
243
+ traceId: result.runId,
244
+ };
245
+ }
246
+ catch (error) {
247
+ return {
248
+ status: "failed",
249
+ answer: `Codali run failed: ${error instanceof Error ? error.message : String(error)}`,
250
+ output: undefined,
251
+ sources: [],
252
+ artifacts,
253
+ warnings: tracer.snapshot().warnings,
254
+ traceId: runId,
255
+ };
256
+ }
257
+ finally {
258
+ await mcp.registry?.close();
259
+ }
260
+ };
261
+ const buildDefaultRegistry = (workspaceRoot, context) => {
262
+ const registry = new ToolRegistry();
263
+ const client = new DocdexClient({
264
+ baseUrl: context.docdex?.baseUrl ?? "http://127.0.0.1:28491",
265
+ repoRoot: context.repo?.root ?? workspaceRoot,
266
+ repoId: context.docdex?.repoId,
267
+ apiKey: context.docdex?.apiKey,
268
+ allowedOperations: context.docdex?.allowedOperations,
269
+ });
270
+ for (const tool of createDocdexTools(client))
271
+ registry.register(tool);
272
+ return registry;
273
+ };