@mcoda/codali 0.1.108 → 0.1.110
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/dist/agents/AgentInventory.d.ts +56 -0
- package/dist/agents/AgentInventory.d.ts.map +1 -0
- package/dist/agents/AgentInventory.js +131 -0
- package/dist/agents/RoleResolution.d.ts +49 -0
- package/dist/agents/RoleResolution.d.ts.map +1 -0
- package/dist/agents/RoleResolution.js +166 -0
- package/dist/api/ChatCompletionsAdapter.d.ts +76 -0
- package/dist/api/ChatCompletionsAdapter.d.ts.map +1 -0
- package/dist/api/ChatCompletionsAdapter.js +54 -0
- package/dist/api/CodaliApi.d.ts +78 -0
- package/dist/api/CodaliApi.d.ts.map +1 -0
- package/dist/api/CodaliApi.js +273 -0
- package/dist/api/CodaliServer.d.ts +42 -0
- package/dist/api/CodaliServer.d.ts.map +1 -0
- package/dist/api/CodaliServer.js +118 -0
- package/dist/cli/AskCommand.d.ts +66 -0
- package/dist/cli/AskCommand.d.ts.map +1 -0
- package/dist/cli/AskCommand.js +536 -0
- package/dist/cli/AuthCommand.d.ts +19 -0
- package/dist/cli/AuthCommand.d.ts.map +1 -0
- package/dist/cli/AuthCommand.js +161 -0
- package/dist/cli/ServeCommand.d.ts +5 -0
- package/dist/cli/ServeCommand.d.ts.map +1 -0
- package/dist/cli/ServeCommand.js +87 -0
- package/dist/cli/ToolsCommand.d.ts +22 -0
- package/dist/cli/ToolsCommand.d.ts.map +1 -0
- package/dist/cli/ToolsCommand.js +208 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +29 -1
- package/dist/connectors/http/HttpToolDefinition.d.ts +74 -0
- package/dist/connectors/http/HttpToolDefinition.d.ts.map +1 -0
- package/dist/connectors/http/HttpToolDefinition.js +190 -0
- package/dist/connectors/http/HttpToolSource.d.ts +18 -0
- package/dist/connectors/http/HttpToolSource.d.ts.map +1 -0
- package/dist/connectors/http/HttpToolSource.js +29 -0
- package/dist/connectors/mcp/McpClient.d.ts +132 -0
- package/dist/connectors/mcp/McpClient.d.ts.map +1 -0
- package/dist/connectors/mcp/McpClient.js +215 -0
- package/dist/connectors/mcp/McpServerRegistry.d.ts +75 -0
- package/dist/connectors/mcp/McpServerRegistry.d.ts.map +1 -0
- package/dist/connectors/mcp/McpServerRegistry.js +180 -0
- package/dist/connectors/mcp/McpToolAdapter.d.ts +48 -0
- package/dist/connectors/mcp/McpToolAdapter.d.ts.map +1 -0
- package/dist/connectors/mcp/McpToolAdapter.js +101 -0
- package/dist/connectors/mcp/McpToolSource.d.ts +27 -0
- package/dist/connectors/mcp/McpToolSource.d.ts.map +1 -0
- package/dist/connectors/mcp/McpToolSource.js +33 -0
- package/dist/connectors/media/ImageGenerationTool.d.ts +43 -0
- package/dist/connectors/media/ImageGenerationTool.d.ts.map +1 -0
- package/dist/connectors/media/ImageGenerationTool.js +122 -0
- package/dist/connectors/oauth/DeviceCodeAuth.d.ts +74 -0
- package/dist/connectors/oauth/DeviceCodeAuth.d.ts.map +1 -0
- package/dist/connectors/oauth/DeviceCodeAuth.js +153 -0
- package/dist/docdex/DocdexClient.d.ts +2 -0
- package/dist/docdex/DocdexClient.d.ts.map +1 -1
- package/dist/docdex/DocdexClient.js +4 -0
- package/dist/gateway/CodaliGateway.d.ts +51 -3
- package/dist/gateway/CodaliGateway.d.ts.map +1 -1
- package/dist/gateway/CodaliGateway.js +241 -3
- package/dist/gateway/CodaliGatewayTypes.d.ts +34 -0
- package/dist/gateway/CodaliGatewayTypes.d.ts.map +1 -1
- package/dist/gateway/EvidenceNormalizer.d.ts.map +1 -1
- package/dist/gateway/EvidenceNormalizer.js +98 -1
- package/dist/gateway/Finalizer.d.ts +50 -0
- package/dist/gateway/Finalizer.d.ts.map +1 -0
- package/dist/gateway/Finalizer.js +79 -0
- package/dist/gateway/GatewayPlanner.d.ts +13 -0
- package/dist/gateway/GatewayPlanner.d.ts.map +1 -1
- package/dist/gateway/GatewayPlanner.js +81 -16
- package/dist/gateway/GatewayStateMachine.d.ts.map +1 -1
- package/dist/gateway/GatewayStateMachine.js +6 -0
- package/dist/gateway/GatewayTracer.d.ts +93 -0
- package/dist/gateway/GatewayTracer.d.ts.map +1 -0
- package/dist/gateway/GatewayTracer.js +214 -0
- package/dist/gateway/LocalGatewayProvider.d.ts +59 -0
- package/dist/gateway/LocalGatewayProvider.d.ts.map +1 -0
- package/dist/gateway/LocalGatewayProvider.js +195 -0
- package/dist/gateway/LocalGatewayTaskRunner.d.ts +79 -0
- package/dist/gateway/LocalGatewayTaskRunner.d.ts.map +1 -0
- package/dist/gateway/LocalGatewayTaskRunner.js +361 -0
- package/dist/gateway/RelevanceJudge.d.ts +25 -0
- package/dist/gateway/RelevanceJudge.d.ts.map +1 -0
- package/dist/gateway/RelevanceJudge.js +124 -0
- package/dist/gateway/ResponseSchema.d.ts +32 -0
- package/dist/gateway/ResponseSchema.d.ts.map +1 -0
- package/dist/gateway/ResponseSchema.js +120 -0
- package/dist/gateway/TemporalContext.d.ts +36 -0
- package/dist/gateway/TemporalContext.d.ts.map +1 -0
- package/dist/gateway/TemporalContext.js +115 -0
- package/dist/gateway/ToolCapabilityCompiler.d.ts +5 -0
- package/dist/gateway/ToolCapabilityCompiler.d.ts.map +1 -1
- package/dist/gateway/ToolCapabilityCompiler.js +27 -2
- package/dist/gateway/ToolDescriptorSource.d.ts +6 -0
- package/dist/gateway/ToolDescriptorSource.d.ts.map +1 -0
- package/dist/gateway/ToolDescriptorSource.js +30 -0
- package/dist/gateway/ToolExposure.d.ts +36 -0
- package/dist/gateway/ToolExposure.d.ts.map +1 -0
- package/dist/gateway/ToolExposure.js +154 -0
- package/dist/index.d.ts +57 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +45 -0
- package/dist/providers/ClaudeCliProvider.d.ts +2 -0
- package/dist/providers/ClaudeCliProvider.d.ts.map +1 -1
- package/dist/providers/ClaudeCliProvider.js +2 -0
- package/dist/providers/CodexCliProvider.d.ts +2 -0
- package/dist/providers/CodexCliProvider.d.ts.map +1 -1
- package/dist/providers/CodexCliProvider.js +2 -0
- package/dist/providers/MswarmWorkerProvider.d.ts +2 -0
- package/dist/providers/MswarmWorkerProvider.d.ts.map +1 -1
- package/dist/providers/MswarmWorkerProvider.js +2 -0
- package/dist/providers/OllamaRemoteProvider.d.ts +2 -0
- package/dist/providers/OllamaRemoteProvider.d.ts.map +1 -1
- package/dist/providers/OllamaRemoteProvider.js +2 -0
- package/dist/providers/OpenAiCompatibleProvider.d.ts +2 -0
- package/dist/providers/OpenAiCompatibleProvider.d.ts.map +1 -1
- package/dist/providers/OpenAiCompatibleProvider.js +2 -0
- package/dist/providers/ProviderTypes.d.ts +13 -0
- package/dist/providers/ProviderTypes.d.ts.map +1 -1
- package/dist/providers/ProviderTypes.js +1 -1
- package/dist/runcontext/CredentialFile.d.ts +12 -0
- package/dist/runcontext/CredentialFile.d.ts.map +1 -0
- package/dist/runcontext/CredentialFile.js +81 -0
- package/dist/runcontext/RunContextResolver.d.ts +126 -0
- package/dist/runcontext/RunContextResolver.d.ts.map +1 -0
- package/dist/runcontext/RunContextResolver.js +389 -0
- package/dist/storage/CodaliDatasetPrivacyEngine.d.ts +1 -1
- package/dist/storage/CodaliDatasetPrivacyEngine.d.ts.map +1 -1
- package/dist/storage/CodaliDatasetPrivacyEngine.js +12 -0
- package/dist/tools/ToolRegistry.d.ts +14 -1
- package/dist/tools/ToolRegistry.d.ts.map +1 -1
- package/dist/tools/ToolRegistry.js +38 -1
- package/dist/tools/ToolTypes.d.ts +35 -0
- package/dist/tools/ToolTypes.d.ts.map +1 -1
- package/dist/tools/ToolTypes.js +21 -0
- package/dist/tools/TruncateResult.d.ts +29 -0
- package/dist/tools/TruncateResult.d.ts.map +1 -0
- package/dist/tools/TruncateResult.js +91 -0
- package/dist/tools/diff/DiffTool.d.ts.map +1 -1
- package/dist/tools/diff/DiffTool.js +2 -0
- package/dist/tools/docdex/DocdexTools.d.ts +21 -1
- package/dist/tools/docdex/DocdexTools.d.ts.map +1 -1
- package/dist/tools/docdex/DocdexTools.js +151 -17
- package/dist/tools/filesystem/FileTools.d.ts.map +1 -1
- package/dist/tools/filesystem/FileTools.js +8 -0
- package/dist/tools/search/SearchTool.d.ts.map +1 -1
- package/dist/tools/search/SearchTool.js +3 -1
- package/dist/tools/shell/ShellTool.d.ts.map +1 -1
- package/dist/tools/shell/ShellTool.js +2 -0
- package/package.json +4 -3
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loads the mcoda agent inventory that {@link resolveCodaliGatewayAgentTiers}
|
|
3
|
+
* resolves roles against.
|
|
4
|
+
*
|
|
5
|
+
* Loaded **once** and cached for the process lifetime. Shelling out to
|
|
6
|
+
* `mcoda agent list` costs hundreds of milliseconds and the inventory does not
|
|
7
|
+
* change mid-request, so doing it per query would put a subprocess spawn on the
|
|
8
|
+
* critical path of every question asked.
|
|
9
|
+
*/
|
|
10
|
+
export interface AgentInventoryEntry extends Record<string, unknown> {
|
|
11
|
+
id?: string;
|
|
12
|
+
slug?: string;
|
|
13
|
+
adapter?: string;
|
|
14
|
+
defaultModel?: string;
|
|
15
|
+
model?: string;
|
|
16
|
+
contextWindow?: number;
|
|
17
|
+
maxOutputTokens?: number;
|
|
18
|
+
supportsTools?: boolean;
|
|
19
|
+
capabilities?: string[];
|
|
20
|
+
rating?: number;
|
|
21
|
+
reasoningRating?: number;
|
|
22
|
+
costPerMillion?: number;
|
|
23
|
+
maxComplexity?: number;
|
|
24
|
+
health?: {
|
|
25
|
+
status?: string;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export interface AgentInventoryLoadOptions {
|
|
29
|
+
command?: string;
|
|
30
|
+
timeoutMs?: number;
|
|
31
|
+
/** Include agents whose health is unknown. Unhealthy is always excluded. */
|
|
32
|
+
includeUnknownHealth?: boolean;
|
|
33
|
+
/** Injected in tests. */
|
|
34
|
+
runCommand?: (command: string, args: string[], timeoutMs: number) => Promise<{
|
|
35
|
+
code: number;
|
|
36
|
+
stdout: string;
|
|
37
|
+
stderr: string;
|
|
38
|
+
}>;
|
|
39
|
+
}
|
|
40
|
+
export interface AgentInventoryLoadResult {
|
|
41
|
+
agents: AgentInventoryEntry[];
|
|
42
|
+
warnings: string[];
|
|
43
|
+
source: "mcoda" | "empty";
|
|
44
|
+
}
|
|
45
|
+
export declare const loadAgentInventory: (options?: AgentInventoryLoadOptions) => Promise<AgentInventoryLoadResult>;
|
|
46
|
+
export declare const isLocallyDrivable: (agent: AgentInventoryEntry) => boolean;
|
|
47
|
+
/** Narrows an inventory to agents the in-process CLI can actually call. */
|
|
48
|
+
export declare const filterLocallyDrivable: (agents: readonly AgentInventoryEntry[]) => AgentInventoryEntry[];
|
|
49
|
+
/**
|
|
50
|
+
* Process-lifetime cached inventory. Call once at startup; every later caller
|
|
51
|
+
* gets the same promise rather than spawning another subprocess.
|
|
52
|
+
*/
|
|
53
|
+
export declare const getAgentInventory: (options?: AgentInventoryLoadOptions) => Promise<AgentInventoryLoadResult>;
|
|
54
|
+
/** Test-only: drops the cache so a fresh load can be exercised. */
|
|
55
|
+
export declare const resetAgentInventoryCache: () => void;
|
|
56
|
+
//# sourceMappingURL=AgentInventory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AgentInventory.d.ts","sourceRoot":"","sources":["../../src/agents/AgentInventory.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AAEH,MAAM,WAAW,mBAAoB,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAClE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9B;AAED,MAAM,WAAW,yBAAyB;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4EAA4E;IAC5E,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,yBAAyB;IACzB,UAAU,CAAC,EAAE,CACX,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,SAAS,EAAE,MAAM,KACd,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChE;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,mBAAmB,EAAE,CAAC;IAC9B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC;CAC3B;AA0ED,eAAO,MAAM,kBAAkB,GAC7B,UAAS,yBAA8B,KACtC,OAAO,CAAC,wBAAwB,CAiClC,CAAC;AAwBF,eAAO,MAAM,iBAAiB,GAAI,OAAO,mBAAmB,KAAG,OAG9D,CAAC;AAEF,2EAA2E;AAC3E,eAAO,MAAM,qBAAqB,GAChC,QAAQ,SAAS,mBAAmB,EAAE,KACrC,mBAAmB,EAAsC,CAAC;AAI7D;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAC5B,UAAS,yBAA8B,KACtC,OAAO,CAAC,wBAAwB,CAGlC,CAAC;AAEF,mEAAmE;AACnE,eAAO,MAAM,wBAAwB,QAAO,IAE3C,CAAC"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
const DEFAULT_COMMAND = "mcoda";
|
|
3
|
+
const DEFAULT_TIMEOUT_MS = 20000;
|
|
4
|
+
const runCommandImpl = (command, args, timeoutMs) => new Promise((resolve) => {
|
|
5
|
+
const child = spawn(command, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
6
|
+
let stdout = "";
|
|
7
|
+
let stderr = "";
|
|
8
|
+
let settled = false;
|
|
9
|
+
const timer = setTimeout(() => {
|
|
10
|
+
if (settled)
|
|
11
|
+
return;
|
|
12
|
+
settled = true;
|
|
13
|
+
child.kill("SIGKILL");
|
|
14
|
+
resolve({ code: -1, stdout, stderr: `${stderr}\ntimed out after ${timeoutMs}ms` });
|
|
15
|
+
}, timeoutMs);
|
|
16
|
+
child.stdout?.on("data", (chunk) => {
|
|
17
|
+
stdout += String(chunk);
|
|
18
|
+
});
|
|
19
|
+
child.stderr?.on("data", (chunk) => {
|
|
20
|
+
stderr += String(chunk);
|
|
21
|
+
});
|
|
22
|
+
child.on("error", (error) => {
|
|
23
|
+
if (settled)
|
|
24
|
+
return;
|
|
25
|
+
settled = true;
|
|
26
|
+
clearTimeout(timer);
|
|
27
|
+
resolve({ code: -1, stdout, stderr: `${stderr}\n${error.message}` });
|
|
28
|
+
});
|
|
29
|
+
child.on("close", (code) => {
|
|
30
|
+
if (settled)
|
|
31
|
+
return;
|
|
32
|
+
settled = true;
|
|
33
|
+
clearTimeout(timer);
|
|
34
|
+
resolve({ code: code ?? 0, stdout, stderr });
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
const parseInventory = (stdout) => {
|
|
38
|
+
try {
|
|
39
|
+
const parsed = JSON.parse(stdout);
|
|
40
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return [];
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
const isUsable = (agent, includeUnknownHealth) => {
|
|
47
|
+
const status = agent.health?.status;
|
|
48
|
+
if (status === "healthy")
|
|
49
|
+
return true;
|
|
50
|
+
// An agent reporting `limited` has exhausted its quota; `unhealthy` is
|
|
51
|
+
// self-explanatory. Both would fail at call time, so exclude them here where
|
|
52
|
+
// the reason can still be reported.
|
|
53
|
+
if (status === "unhealthy" || status === "limited")
|
|
54
|
+
return false;
|
|
55
|
+
return includeUnknownHealth;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Normalizes to the shape AgentTierResolver reads, so an entry always exposes a
|
|
59
|
+
* `model` even when mcoda only reports `defaultModel`.
|
|
60
|
+
*/
|
|
61
|
+
const normalize = (agent) => ({
|
|
62
|
+
...agent,
|
|
63
|
+
model: agent.model ?? agent.defaultModel,
|
|
64
|
+
});
|
|
65
|
+
export const loadAgentInventory = async (options = {}) => {
|
|
66
|
+
const command = options.command ?? DEFAULT_COMMAND;
|
|
67
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
68
|
+
const run = options.runCommand ?? runCommandImpl;
|
|
69
|
+
const warnings = [];
|
|
70
|
+
// Prefer fresh health; fall back for older mcoda builds without the flag.
|
|
71
|
+
let result = await run(command, ["agent", "list", "--json", "--refresh-health"], timeoutMs);
|
|
72
|
+
if (result.code !== 0) {
|
|
73
|
+
warnings.push("agent_inventory_refresh_health_unavailable");
|
|
74
|
+
result = await run(command, ["agent", "list", "--json"], timeoutMs);
|
|
75
|
+
}
|
|
76
|
+
if (result.code !== 0) {
|
|
77
|
+
warnings.push(`agent_inventory_unavailable:${(result.stderr || "unknown error").trim().slice(0, 200)}`);
|
|
78
|
+
return { agents: [], warnings, source: "empty" };
|
|
79
|
+
}
|
|
80
|
+
const parsed = parseInventory(result.stdout);
|
|
81
|
+
if (parsed.length === 0) {
|
|
82
|
+
warnings.push("agent_inventory_empty");
|
|
83
|
+
return { agents: [], warnings, source: "empty" };
|
|
84
|
+
}
|
|
85
|
+
const usable = parsed.filter((agent) => isUsable(agent, options.includeUnknownHealth ?? true));
|
|
86
|
+
const excluded = parsed.length - usable.length;
|
|
87
|
+
if (excluded > 0) {
|
|
88
|
+
warnings.push(`agent_inventory_excluded_unhealthy:${excluded}`);
|
|
89
|
+
}
|
|
90
|
+
return { agents: usable.map(normalize), warnings, source: "mcoda" };
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Adapters the local CLI can drive in-process.
|
|
94
|
+
*
|
|
95
|
+
* mswarm self-hosted agents were excluded here until 2026-08-05: the gateway's
|
|
96
|
+
* dedicated self-hosted route reused the generic chat handler, so a local model
|
|
97
|
+
* id missed the catalog lookup and was forwarded to OpenRouter, which rejected
|
|
98
|
+
* it. That is fixed (gateway runtime 0e9e877) — the route is self-hosted-only,
|
|
99
|
+
* serves the exact ids from `/v1/swarm/self-hosted/openai/models`, and returns
|
|
100
|
+
* 404/503 instead of falling through to a cloud provider. They are drivable now.
|
|
101
|
+
*/
|
|
102
|
+
const LOCAL_DRIVABLE_ADAPTERS = new Set([
|
|
103
|
+
"claude-cli",
|
|
104
|
+
"codex-cli",
|
|
105
|
+
"gemini-cli",
|
|
106
|
+
"openai-cli",
|
|
107
|
+
"ollama-cli",
|
|
108
|
+
"ollama-remote",
|
|
109
|
+
"openai-api",
|
|
110
|
+
"anthropic-api",
|
|
111
|
+
"zhipu-api",
|
|
112
|
+
]);
|
|
113
|
+
export const isLocallyDrivable = (agent) => {
|
|
114
|
+
const adapter = typeof agent.adapter === "string" ? agent.adapter.toLowerCase() : "";
|
|
115
|
+
return LOCAL_DRIVABLE_ADAPTERS.has(adapter);
|
|
116
|
+
};
|
|
117
|
+
/** Narrows an inventory to agents the in-process CLI can actually call. */
|
|
118
|
+
export const filterLocallyDrivable = (agents) => agents.filter(isLocallyDrivable);
|
|
119
|
+
let cached;
|
|
120
|
+
/**
|
|
121
|
+
* Process-lifetime cached inventory. Call once at startup; every later caller
|
|
122
|
+
* gets the same promise rather than spawning another subprocess.
|
|
123
|
+
*/
|
|
124
|
+
export const getAgentInventory = (options = {}) => {
|
|
125
|
+
cached ?? (cached = loadAgentInventory(options));
|
|
126
|
+
return cached;
|
|
127
|
+
};
|
|
128
|
+
/** Test-only: drops the cache so a fresh load can be exercised. */
|
|
129
|
+
export const resetAgentInventoryCache = () => {
|
|
130
|
+
cached = undefined;
|
|
131
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { type AgentTierResolution, type CodaliGatewayAgentAssignment } from "../gateway/AgentTierResolver.js";
|
|
2
|
+
import type { RunContextAgentRoles } from "../runcontext/RunContextResolver.js";
|
|
3
|
+
import type { AgentInventoryEntry } from "./AgentInventory.js";
|
|
4
|
+
/**
|
|
5
|
+
* Codali's configurable model roles.
|
|
6
|
+
*
|
|
7
|
+
* `AgentTierResolver` knows twelve internal roles, each with a working default.
|
|
8
|
+
* Requiring an operator to configure twelve agents to ask one question is a
|
|
9
|
+
* burden with no payoff, so only three are exposed:
|
|
10
|
+
*
|
|
11
|
+
* orchestrator — routes, plans, assesses completeness, repairs
|
|
12
|
+
* synthesizer — produces multi-source answers
|
|
13
|
+
* media — generates images and other artifacts
|
|
14
|
+
*
|
|
15
|
+
* "Classifier", "planner", "verifier" and "repair" remain distinct *prompts*,
|
|
16
|
+
* but they run against the orchestrator model. The internal roles are still
|
|
17
|
+
* available for advanced tuning; they simply are not part of configuration.
|
|
18
|
+
*/
|
|
19
|
+
export type CodaliConfigurableRole = "orchestrator" | "worker" | "synthesizer" | "media";
|
|
20
|
+
/** Phase 1 resolves only these; media arrives with image generation. */
|
|
21
|
+
export declare const PHASE_ONE_ROLES: CodaliConfigurableRole[];
|
|
22
|
+
export interface RoleResolutionInput {
|
|
23
|
+
inventory: AgentInventoryEntry[];
|
|
24
|
+
/** Explicit slug bindings from run context, e.g. `synthesizer = "suku-large"`. */
|
|
25
|
+
bindings?: RunContextAgentRoles;
|
|
26
|
+
roles?: CodaliConfigurableRole[];
|
|
27
|
+
allowImageWorker?: boolean;
|
|
28
|
+
}
|
|
29
|
+
export interface RoleResolutionResult {
|
|
30
|
+
resolution: AgentTierResolution;
|
|
31
|
+
/** Configurable role -> the assignment that will serve it. */
|
|
32
|
+
assignments: Partial<Record<CodaliConfigurableRole, CodaliGatewayAgentAssignment>>;
|
|
33
|
+
/** Configurable role -> agent slug, for display in `codali doctor`. */
|
|
34
|
+
bindings: Partial<Record<CodaliConfigurableRole, string>>;
|
|
35
|
+
/**
|
|
36
|
+
* An assignment whose agent can actually emit tool calls.
|
|
37
|
+
*
|
|
38
|
+
* The orchestrator model is chosen for planning quality, and plenty of
|
|
39
|
+
* capable small models report `supportsTools: false`. Running worker tasks on
|
|
40
|
+
* one of those produces a plan full of correct tool tasks and then zero tool
|
|
41
|
+
* calls — the run "succeeds" having gathered nothing. So tool execution gets
|
|
42
|
+
* its own assignment, and its absence is reported rather than discovered
|
|
43
|
+
* through an empty answer.
|
|
44
|
+
*/
|
|
45
|
+
toolCapable?: CodaliGatewayAgentAssignment;
|
|
46
|
+
warnings: string[];
|
|
47
|
+
}
|
|
48
|
+
export declare const resolveConfigurableRoles: (input: RoleResolutionInput) => RoleResolutionResult;
|
|
49
|
+
//# sourceMappingURL=RoleResolution.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RoleResolution.d.ts","sourceRoot":"","sources":["../../src/agents/RoleResolution.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,4BAA4B,EAClC,MAAM,iCAAiC,CAAC;AAKzC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qCAAqC,CAAC;AAChF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE/D;;;;;;;;;;;;;;GAcG;AAEH,MAAM,MAAM,sBAAsB,GAC9B,cAAc,GACd,QAAQ,GACR,aAAa,GACb,OAAO,CAAC;AAuBZ,wEAAwE;AACxE,eAAO,MAAM,eAAe,EAAE,sBAAsB,EAInD,CAAC;AAEF,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,mBAAmB,EAAE,CAAC;IACjC,kFAAkF;IAClF,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAChC,KAAK,CAAC,EAAE,sBAAsB,EAAE,CAAC;IACjC,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,mBAAmB,CAAC;IAChC,8DAA8D;IAC9D,WAAW,EAAE,OAAO,CAAC,MAAM,CAAC,sBAAsB,EAAE,4BAA4B,CAAC,CAAC,CAAC;IACnF,uEAAuE;IACvE,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,sBAAsB,EAAE,MAAM,CAAC,CAAC,CAAC;IAC1D;;;;;;;;;OASG;IACH,WAAW,CAAC,EAAE,4BAA4B,CAAC;IAC3C,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAmFD,eAAO,MAAM,wBAAwB,GACnC,OAAO,mBAAmB,KACzB,oBA8FF,CAAC"}
|
|
@@ -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"}
|