@mcoda/codali 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 (149) hide show
  1. package/dist/agents/AgentInventory.d.ts +56 -0
  2. package/dist/agents/AgentInventory.d.ts.map +1 -0
  3. package/dist/agents/AgentInventory.js +131 -0
  4. package/dist/agents/RoleResolution.d.ts +49 -0
  5. package/dist/agents/RoleResolution.d.ts.map +1 -0
  6. package/dist/agents/RoleResolution.js +166 -0
  7. package/dist/api/ChatCompletionsAdapter.d.ts +76 -0
  8. package/dist/api/ChatCompletionsAdapter.d.ts.map +1 -0
  9. package/dist/api/ChatCompletionsAdapter.js +54 -0
  10. package/dist/api/CodaliApi.d.ts +78 -0
  11. package/dist/api/CodaliApi.d.ts.map +1 -0
  12. package/dist/api/CodaliApi.js +273 -0
  13. package/dist/api/CodaliServer.d.ts +42 -0
  14. package/dist/api/CodaliServer.d.ts.map +1 -0
  15. package/dist/api/CodaliServer.js +118 -0
  16. package/dist/cli/AskCommand.d.ts +66 -0
  17. package/dist/cli/AskCommand.d.ts.map +1 -0
  18. package/dist/cli/AskCommand.js +536 -0
  19. package/dist/cli/AuthCommand.d.ts +19 -0
  20. package/dist/cli/AuthCommand.d.ts.map +1 -0
  21. package/dist/cli/AuthCommand.js +161 -0
  22. package/dist/cli/ServeCommand.d.ts +5 -0
  23. package/dist/cli/ServeCommand.d.ts.map +1 -0
  24. package/dist/cli/ServeCommand.js +87 -0
  25. package/dist/cli/ToolsCommand.d.ts +22 -0
  26. package/dist/cli/ToolsCommand.d.ts.map +1 -0
  27. package/dist/cli/ToolsCommand.js +208 -0
  28. package/dist/cli.d.ts.map +1 -1
  29. package/dist/cli.js +29 -1
  30. package/dist/connectors/http/HttpToolDefinition.d.ts +74 -0
  31. package/dist/connectors/http/HttpToolDefinition.d.ts.map +1 -0
  32. package/dist/connectors/http/HttpToolDefinition.js +190 -0
  33. package/dist/connectors/http/HttpToolSource.d.ts +18 -0
  34. package/dist/connectors/http/HttpToolSource.d.ts.map +1 -0
  35. package/dist/connectors/http/HttpToolSource.js +29 -0
  36. package/dist/connectors/mcp/McpClient.d.ts +132 -0
  37. package/dist/connectors/mcp/McpClient.d.ts.map +1 -0
  38. package/dist/connectors/mcp/McpClient.js +215 -0
  39. package/dist/connectors/mcp/McpServerRegistry.d.ts +75 -0
  40. package/dist/connectors/mcp/McpServerRegistry.d.ts.map +1 -0
  41. package/dist/connectors/mcp/McpServerRegistry.js +180 -0
  42. package/dist/connectors/mcp/McpToolAdapter.d.ts +48 -0
  43. package/dist/connectors/mcp/McpToolAdapter.d.ts.map +1 -0
  44. package/dist/connectors/mcp/McpToolAdapter.js +101 -0
  45. package/dist/connectors/mcp/McpToolSource.d.ts +27 -0
  46. package/dist/connectors/mcp/McpToolSource.d.ts.map +1 -0
  47. package/dist/connectors/mcp/McpToolSource.js +33 -0
  48. package/dist/connectors/media/ImageGenerationTool.d.ts +43 -0
  49. package/dist/connectors/media/ImageGenerationTool.d.ts.map +1 -0
  50. package/dist/connectors/media/ImageGenerationTool.js +122 -0
  51. package/dist/connectors/oauth/DeviceCodeAuth.d.ts +74 -0
  52. package/dist/connectors/oauth/DeviceCodeAuth.d.ts.map +1 -0
  53. package/dist/connectors/oauth/DeviceCodeAuth.js +153 -0
  54. package/dist/docdex/DocdexClient.d.ts +2 -0
  55. package/dist/docdex/DocdexClient.d.ts.map +1 -1
  56. package/dist/docdex/DocdexClient.js +4 -0
  57. package/dist/gateway/CodaliGateway.d.ts +51 -3
  58. package/dist/gateway/CodaliGateway.d.ts.map +1 -1
  59. package/dist/gateway/CodaliGateway.js +226 -2
  60. package/dist/gateway/CodaliGatewayTypes.d.ts +34 -0
  61. package/dist/gateway/CodaliGatewayTypes.d.ts.map +1 -1
  62. package/dist/gateway/EvidenceNormalizer.d.ts.map +1 -1
  63. package/dist/gateway/EvidenceNormalizer.js +90 -1
  64. package/dist/gateway/Finalizer.d.ts +50 -0
  65. package/dist/gateway/Finalizer.d.ts.map +1 -0
  66. package/dist/gateway/Finalizer.js +79 -0
  67. package/dist/gateway/GatewayPlanner.d.ts +13 -0
  68. package/dist/gateway/GatewayPlanner.d.ts.map +1 -1
  69. package/dist/gateway/GatewayPlanner.js +81 -16
  70. package/dist/gateway/GatewayStateMachine.d.ts.map +1 -1
  71. package/dist/gateway/GatewayStateMachine.js +6 -0
  72. package/dist/gateway/GatewayTracer.d.ts +93 -0
  73. package/dist/gateway/GatewayTracer.d.ts.map +1 -0
  74. package/dist/gateway/GatewayTracer.js +214 -0
  75. package/dist/gateway/LocalGatewayProvider.d.ts +46 -0
  76. package/dist/gateway/LocalGatewayProvider.d.ts.map +1 -0
  77. package/dist/gateway/LocalGatewayProvider.js +161 -0
  78. package/dist/gateway/LocalGatewayTaskRunner.d.ts +79 -0
  79. package/dist/gateway/LocalGatewayTaskRunner.d.ts.map +1 -0
  80. package/dist/gateway/LocalGatewayTaskRunner.js +354 -0
  81. package/dist/gateway/RelevanceJudge.d.ts +14 -0
  82. package/dist/gateway/RelevanceJudge.d.ts.map +1 -0
  83. package/dist/gateway/RelevanceJudge.js +87 -0
  84. package/dist/gateway/ResponseSchema.d.ts +32 -0
  85. package/dist/gateway/ResponseSchema.d.ts.map +1 -0
  86. package/dist/gateway/ResponseSchema.js +120 -0
  87. package/dist/gateway/TemporalContext.d.ts +36 -0
  88. package/dist/gateway/TemporalContext.d.ts.map +1 -0
  89. package/dist/gateway/TemporalContext.js +115 -0
  90. package/dist/gateway/ToolCapabilityCompiler.d.ts +5 -0
  91. package/dist/gateway/ToolCapabilityCompiler.d.ts.map +1 -1
  92. package/dist/gateway/ToolCapabilityCompiler.js +27 -2
  93. package/dist/gateway/ToolDescriptorSource.d.ts +6 -0
  94. package/dist/gateway/ToolDescriptorSource.d.ts.map +1 -0
  95. package/dist/gateway/ToolDescriptorSource.js +30 -0
  96. package/dist/gateway/ToolExposure.d.ts +36 -0
  97. package/dist/gateway/ToolExposure.d.ts.map +1 -0
  98. package/dist/gateway/ToolExposure.js +154 -0
  99. package/dist/index.d.ts +57 -0
  100. package/dist/index.d.ts.map +1 -1
  101. package/dist/index.js +45 -0
  102. package/dist/providers/ClaudeCliProvider.d.ts +2 -0
  103. package/dist/providers/ClaudeCliProvider.d.ts.map +1 -1
  104. package/dist/providers/ClaudeCliProvider.js +2 -0
  105. package/dist/providers/CodexCliProvider.d.ts +2 -0
  106. package/dist/providers/CodexCliProvider.d.ts.map +1 -1
  107. package/dist/providers/CodexCliProvider.js +2 -0
  108. package/dist/providers/MswarmWorkerProvider.d.ts +2 -0
  109. package/dist/providers/MswarmWorkerProvider.d.ts.map +1 -1
  110. package/dist/providers/MswarmWorkerProvider.js +2 -0
  111. package/dist/providers/OllamaRemoteProvider.d.ts +2 -0
  112. package/dist/providers/OllamaRemoteProvider.d.ts.map +1 -1
  113. package/dist/providers/OllamaRemoteProvider.js +2 -0
  114. package/dist/providers/OpenAiCompatibleProvider.d.ts +2 -0
  115. package/dist/providers/OpenAiCompatibleProvider.d.ts.map +1 -1
  116. package/dist/providers/OpenAiCompatibleProvider.js +2 -0
  117. package/dist/providers/ProviderTypes.d.ts +13 -0
  118. package/dist/providers/ProviderTypes.d.ts.map +1 -1
  119. package/dist/providers/ProviderTypes.js +1 -1
  120. package/dist/runcontext/CredentialFile.d.ts +12 -0
  121. package/dist/runcontext/CredentialFile.d.ts.map +1 -0
  122. package/dist/runcontext/CredentialFile.js +81 -0
  123. package/dist/runcontext/RunContextResolver.d.ts +126 -0
  124. package/dist/runcontext/RunContextResolver.d.ts.map +1 -0
  125. package/dist/runcontext/RunContextResolver.js +389 -0
  126. package/dist/storage/CodaliDatasetPrivacyEngine.d.ts +1 -1
  127. package/dist/storage/CodaliDatasetPrivacyEngine.d.ts.map +1 -1
  128. package/dist/storage/CodaliDatasetPrivacyEngine.js +12 -0
  129. package/dist/tools/ToolRegistry.d.ts +14 -1
  130. package/dist/tools/ToolRegistry.d.ts.map +1 -1
  131. package/dist/tools/ToolRegistry.js +38 -1
  132. package/dist/tools/ToolTypes.d.ts +35 -0
  133. package/dist/tools/ToolTypes.d.ts.map +1 -1
  134. package/dist/tools/ToolTypes.js +21 -0
  135. package/dist/tools/TruncateResult.d.ts +29 -0
  136. package/dist/tools/TruncateResult.d.ts.map +1 -0
  137. package/dist/tools/TruncateResult.js +91 -0
  138. package/dist/tools/diff/DiffTool.d.ts.map +1 -1
  139. package/dist/tools/diff/DiffTool.js +2 -0
  140. package/dist/tools/docdex/DocdexTools.d.ts +21 -1
  141. package/dist/tools/docdex/DocdexTools.d.ts.map +1 -1
  142. package/dist/tools/docdex/DocdexTools.js +108 -16
  143. package/dist/tools/filesystem/FileTools.d.ts.map +1 -1
  144. package/dist/tools/filesystem/FileTools.js +8 -0
  145. package/dist/tools/search/SearchTool.d.ts.map +1 -1
  146. package/dist/tools/search/SearchTool.js +3 -1
  147. package/dist/tools/shell/ShellTool.d.ts.map +1 -1
  148. package/dist/tools/shell/ShellTool.js +2 -0
  149. package/package.json +4 -3
@@ -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
+ };
@@ -0,0 +1,42 @@
1
+ import { type Server } from "node:http";
2
+ import { runCodali } from "./CodaliApi.js";
3
+ import type { RunContext, RunContextTenant } from "../runcontext/RunContextResolver.js";
4
+ /**
5
+ * Local HTTP surface for Codali.
6
+ *
7
+ * Exposes the same result contract the CLI produces, so a product integrating
8
+ * over HTTP and an engineer debugging on a terminal are exercising one
9
+ * implementation.
10
+ *
11
+ * ## Tenant identity
12
+ *
13
+ * Tenant is derived from the **authenticated caller**, never read from a
14
+ * request body or a client-supplied header. A tenant id in a body field is an
15
+ * assertion by an untrusted party; honouring it would let any caller read
16
+ * another tenant's tools and credentials by editing one JSON value.
17
+ */
18
+ export interface CodaliServerPrincipal {
19
+ tenant: RunContextTenant;
20
+ /** Tools, credentials and limits this principal's tenant may use. */
21
+ runContext?: RunContext;
22
+ requesterId?: string;
23
+ }
24
+ export interface CodaliServerOptions {
25
+ port?: number;
26
+ host?: string;
27
+ /**
28
+ * Resolves an API key to a principal. Returning undefined rejects the
29
+ * request. There is no anonymous mode: an unauthenticated caller has no
30
+ * tenant, and a run without a tenant scope has no business reaching
31
+ * connectors.
32
+ */
33
+ authenticate: (apiKey: string | undefined) => Promise<CodaliServerPrincipal | undefined>;
34
+ workspaceRoot?: string;
35
+ run?: typeof runCodali;
36
+ }
37
+ export declare const createCodaliServer: (options: CodaliServerOptions) => Server;
38
+ export declare const startCodaliServer: (options: CodaliServerOptions) => Promise<{
39
+ server: Server;
40
+ port: number;
41
+ }>;
42
+ //# sourceMappingURL=CodaliServer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CodaliServer.d.ts","sourceRoot":"","sources":["../../src/api/CodaliServer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsC,KAAK,MAAM,EAAuB,MAAM,WAAW,CAAC;AAEjG,OAAO,EAAE,SAAS,EAAsB,MAAM,gBAAgB,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AAExF;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,gBAAgB,CAAC;IACzB,qEAAqE;IACrE,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,KAAK,OAAO,CAAC,qBAAqB,GAAG,SAAS,CAAC,CAAC;IACzF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,GAAG,CAAC,EAAE,OAAO,SAAS,CAAC;CACxB;AAuDD,eAAO,MAAM,kBAAkB,GAAI,SAAS,mBAAmB,KAAG,MAyEjE,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC5B,SAAS,mBAAmB,KAC3B,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAW1C,CAAC"}
@@ -0,0 +1,118 @@
1
+ import { createServer } from "node:http";
2
+ import { handleChatCompletion } from "./ChatCompletionsAdapter.js";
3
+ import { runCodali } from "./CodaliApi.js";
4
+ const readBody = async (request) => {
5
+ const chunks = [];
6
+ for await (const chunk of request)
7
+ chunks.push(chunk);
8
+ if (chunks.length === 0)
9
+ return undefined;
10
+ try {
11
+ return JSON.parse(Buffer.concat(chunks).toString("utf8"));
12
+ }
13
+ catch {
14
+ return undefined;
15
+ }
16
+ };
17
+ const send = (response, status, payload) => {
18
+ const body = JSON.stringify(payload);
19
+ response.writeHead(status, {
20
+ "Content-Type": "application/json",
21
+ "Content-Length": Buffer.byteLength(body),
22
+ });
23
+ response.end(body);
24
+ };
25
+ const readApiKey = (request) => {
26
+ const header = request.headers.authorization;
27
+ if (typeof header === "string" && header.toLowerCase().startsWith("bearer ")) {
28
+ return header.slice(7).trim();
29
+ }
30
+ const apiKey = request.headers["x-api-key"];
31
+ return typeof apiKey === "string" ? apiKey.trim() : undefined;
32
+ };
33
+ const isRecord = (value) => Boolean(value && typeof value === "object" && !Array.isArray(value));
34
+ /**
35
+ * Strips any caller-supplied tenant or run context and substitutes what the
36
+ * authenticated principal is actually entitled to. This is the single point
37
+ * where cross-tenant access is prevented, so it is deliberately unconditional
38
+ * rather than a validation the caller could satisfy.
39
+ */
40
+ const applyPrincipalScope = (payload, principal) => ({
41
+ ...payload,
42
+ runContext: {
43
+ ...(principal.runContext ?? {}),
44
+ tenant: principal.tenant,
45
+ },
46
+ });
47
+ export const createCodaliServer = (options) => {
48
+ const run = options.run ?? runCodali;
49
+ return createServer(async (request, response) => {
50
+ const url = new URL(request.url ?? "/", "http://localhost");
51
+ if (request.method === "GET" && url.pathname === "/healthz") {
52
+ send(response, 200, { ok: true });
53
+ return;
54
+ }
55
+ if (request.method !== "POST") {
56
+ send(response, 405, { error: { code: "method_not_allowed" } });
57
+ return;
58
+ }
59
+ const principal = await options.authenticate(readApiKey(request));
60
+ if (!principal) {
61
+ send(response, 401, { error: { code: "unauthorized" } });
62
+ return;
63
+ }
64
+ const body = await readBody(request);
65
+ if (!isRecord(body)) {
66
+ send(response, 400, { error: { code: "invalid_request_body" } });
67
+ return;
68
+ }
69
+ try {
70
+ if (url.pathname === "/v1/chat/completions") {
71
+ const chatRequest = body;
72
+ const scoped = {
73
+ ...chatRequest,
74
+ codali: {
75
+ ...(chatRequest.codali ?? {}),
76
+ // Caller-supplied context is discarded, not merged.
77
+ runContext: {
78
+ ...(principal.runContext ?? {}),
79
+ tenant: principal.tenant,
80
+ },
81
+ workspaceRoot: options.workspaceRoot ?? chatRequest.codali?.workspaceRoot,
82
+ },
83
+ };
84
+ send(response, 200, await handleChatCompletion(scoped, { run }));
85
+ return;
86
+ }
87
+ if (url.pathname === "/v1/codali/run") {
88
+ const codaliRequest = applyPrincipalScope(body, principal);
89
+ send(response, 200, await run({
90
+ ...codaliRequest,
91
+ workspaceRoot: options.workspaceRoot ?? codaliRequest.workspaceRoot,
92
+ }));
93
+ return;
94
+ }
95
+ send(response, 404, { error: { code: "not_found" } });
96
+ }
97
+ catch (error) {
98
+ send(response, 500, {
99
+ error: {
100
+ code: "internal_error",
101
+ message: error instanceof Error ? error.message : String(error),
102
+ },
103
+ });
104
+ }
105
+ });
106
+ };
107
+ export const startCodaliServer = async (options) => {
108
+ const server = createCodaliServer(options);
109
+ const port = options.port ?? 8787;
110
+ await new Promise((resolve) => {
111
+ server.listen(port, options.host ?? "127.0.0.1", resolve);
112
+ });
113
+ const address = server.address();
114
+ return {
115
+ server,
116
+ port: typeof address === "object" && address ? address.port : port,
117
+ };
118
+ };
@@ -0,0 +1,66 @@
1
+ import { getAgentInventory } from "../agents/AgentInventory.js";
2
+ import { attachMcpTools } from "../connectors/mcp/McpToolSource.js";
3
+ import { createProviderForAssignment } from "../gateway/LocalGatewayProvider.js";
4
+ import { GatewayTracer } from "../gateway/GatewayTracer.js";
5
+ import { ToolRegistry } from "../tools/ToolRegistry.js";
6
+ import type { RunContext } from "../runcontext/RunContextResolver.js";
7
+ import type { CodaliGatewayMode, CodaliGatewayResult } from "../gateway/CodaliGatewayTypes.js";
8
+ import type { Provider } from "../providers/ProviderTypes.js";
9
+ /**
10
+ * `codali ask` — the terminal entry point to the orchestration gateway.
11
+ *
12
+ * Until this existed the gateway had exactly one caller (mswarm's cloud job
13
+ * path) and could not be exercised locally at all, which made every other
14
+ * improvement unverifiable.
15
+ */
16
+ /**
17
+ * Default budgets. Deliberately small: an orchestrator that can quietly spend
18
+ * fifty tool calls on one question is not one you can put in front of users.
19
+ */
20
+ export declare const DEFAULT_MAX_ROUNDS = 3;
21
+ export declare const DEFAULT_MAX_TOOL_CALLS = 20;
22
+ export declare const DEFAULT_MAX_MODEL_CALLS = 12;
23
+ /**
24
+ * Wall-clock budget. Generous because CLI-backed agents (codex, claude,
25
+ * gemini) commonly take 30-90s per call, and several tasks run per question.
26
+ */
27
+ export declare const DEFAULT_DEADLINE_MS = 600000;
28
+ /**
29
+ * Independent worker tasks executed concurrently. Bounded rather than
30
+ * unlimited: each task holds a model call, and a tenant's connectors have their
31
+ * own rate limits.
32
+ */
33
+ export declare const DEFAULT_MAX_PARALLEL_WORKERS = 3;
34
+ export interface AskOptions {
35
+ query: string;
36
+ workspaceRoot: string;
37
+ mode: CodaliGatewayMode;
38
+ trace: boolean;
39
+ json: boolean;
40
+ maxRounds: number;
41
+ maxToolCalls: number;
42
+ deadlineMs: number;
43
+ docdexBaseUrl?: string;
44
+ responseSchemaPath?: string;
45
+ responseFormat?: "text" | "json";
46
+ noTools: boolean;
47
+ }
48
+ export declare const parseAskArgs: (argv: string[]) => AskOptions;
49
+ export interface AskDependencies {
50
+ loadInventory?: typeof getAgentInventory;
51
+ resolveRunContext?: (workspaceRoot: string) => Promise<RunContext>;
52
+ buildRegistry?: (options: AskOptions, context: RunContext) => ToolRegistry;
53
+ createProvider?: (assignment: Parameters<typeof createProviderForAssignment>[0]) => Provider;
54
+ attachMcp?: typeof attachMcpTools;
55
+ write?: (line: string) => void;
56
+ }
57
+ export interface AskOutcome {
58
+ result?: CodaliGatewayResult;
59
+ tracer: GatewayTracer;
60
+ exitCode: number;
61
+ }
62
+ export declare const runAsk: (argv: string[], deps?: AskDependencies) => Promise<AskOutcome>;
63
+ export declare const AskCommand: {
64
+ run(argv: string[]): Promise<void>;
65
+ };
66
+ //# sourceMappingURL=AskCommand.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AskCommand.d.ts","sourceRoot":"","sources":["../../src/cli/AskCommand.ts"],"names":[],"mappings":"AACA,OAAO,EAAyB,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAGvF,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAIpE,OAAO,EACL,2BAA2B,EAE5B,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAE5D,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAGxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAC;AACtE,OAAO,KAAK,EACV,iBAAiB,EAEjB,mBAAmB,EACpB,MAAM,kCAAkC,CAAC;AAE1C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAE9D;;;;;;GAMG;AAEH;;;GAGG;AACH,eAAO,MAAM,kBAAkB,IAAI,CAAC;AACpC,eAAO,MAAM,sBAAsB,KAAK,CAAC;AACzC,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAC1C;;;GAGG;AACH,eAAO,MAAM,mBAAmB,SAAU,CAAC;AAE3C;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAe9C,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,iBAAiB,CAAC;IACxB,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,OAAO,EAAE,OAAO,CAAC;CAClB;AA+BD,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,EAAE,KAAG,UAuE7C,CAAC;AAEF,MAAM,WAAW,eAAe;IAC9B,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,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,KAAK,YAAY,CAAC;IAC3E,cAAc,CAAC,EAAE,CACf,UAAU,EAAE,UAAU,CAAC,OAAO,2BAA2B,CAAC,CAAC,CAAC,CAAC,KAC1D,QAAQ,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,cAAc,CAAC;IAClC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AA6BD,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B,MAAM,EAAE,aAAa,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,MAAM,GACjB,MAAM,MAAM,EAAE,EACd,OAAM,eAAoB,KACzB,OAAO,CAAC,UAAU,CAwXpB,CAAC;AAEF,eAAO,MAAM,UAAU;cACL,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAMzC,CAAC"}