@mcoda/codali 0.1.108 → 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.
- 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 +226 -2
- 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 +90 -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 +46 -0
- package/dist/gateway/LocalGatewayProvider.d.ts.map +1 -0
- package/dist/gateway/LocalGatewayProvider.js +161 -0
- package/dist/gateway/LocalGatewayTaskRunner.d.ts +79 -0
- package/dist/gateway/LocalGatewayTaskRunner.d.ts.map +1 -0
- package/dist/gateway/LocalGatewayTaskRunner.js +354 -0
- package/dist/gateway/RelevanceJudge.d.ts +14 -0
- package/dist/gateway/RelevanceJudge.d.ts.map +1 -0
- package/dist/gateway/RelevanceJudge.js +87 -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 +108 -16
- 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,126 @@
|
|
|
1
|
+
import type { McpServerDefinition } from "../connectors/mcp/McpClient.js";
|
|
2
|
+
import type { HttpConnectorDefinition } from "../connectors/http/HttpToolDefinition.js";
|
|
3
|
+
/**
|
|
4
|
+
* The one seam through which Codali learns what a request is allowed to touch.
|
|
5
|
+
*
|
|
6
|
+
* Codali is meant to serve many products, and a multi-tenant product like
|
|
7
|
+
* okacam has a different tool set, different credentials, and different limits
|
|
8
|
+
* for every tenant. So the tool configuration is never read from a file at run
|
|
9
|
+
* time — it is *resolved* per request.
|
|
10
|
+
*
|
|
11
|
+
* A config file is simply one implementation of this interface, used by the
|
|
12
|
+
* local CLI and single-tenant deployments. An embedded product implements its
|
|
13
|
+
* own, or passes a `RunContext` directly on the request; either way the host
|
|
14
|
+
* supplies the context, and Codali never calls back into the product to fetch
|
|
15
|
+
* it. That callback would create a circular dependency
|
|
16
|
+
* (product -> codali -> product) plus the caching, invalidation, and
|
|
17
|
+
* failure-mode machinery that comes with it, and the authenticated host already
|
|
18
|
+
* holds this data.
|
|
19
|
+
*/
|
|
20
|
+
export interface RunContextRepo {
|
|
21
|
+
root?: string;
|
|
22
|
+
repoId?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface RunContextDocdex {
|
|
25
|
+
baseUrl?: string;
|
|
26
|
+
apiKey?: string;
|
|
27
|
+
repoRoot?: string;
|
|
28
|
+
repoId?: string;
|
|
29
|
+
allowedOperations?: string[];
|
|
30
|
+
}
|
|
31
|
+
export interface RunContextTenant {
|
|
32
|
+
id?: string;
|
|
33
|
+
slug?: string;
|
|
34
|
+
realm?: string;
|
|
35
|
+
}
|
|
36
|
+
export interface RunContextLimits {
|
|
37
|
+
maxRounds?: number;
|
|
38
|
+
maxToolCalls?: number;
|
|
39
|
+
maxModelCalls?: number;
|
|
40
|
+
deadlineMs?: number;
|
|
41
|
+
}
|
|
42
|
+
export interface RunContextAgentRoles {
|
|
43
|
+
/** Routes, plans, assesses completeness, repairs. Runs on every question. */
|
|
44
|
+
orchestrator?: string;
|
|
45
|
+
/** Makes the tool calls. Defaults to the orchestrator when unset. */
|
|
46
|
+
worker?: string;
|
|
47
|
+
/** Produces multi-source answers. */
|
|
48
|
+
synthesizer?: string;
|
|
49
|
+
/** Generates images and other media. */
|
|
50
|
+
media?: string;
|
|
51
|
+
}
|
|
52
|
+
export interface RunContext {
|
|
53
|
+
tenant?: RunContextTenant;
|
|
54
|
+
repo?: RunContextRepo;
|
|
55
|
+
docdex?: RunContextDocdex;
|
|
56
|
+
agentRoles?: RunContextAgentRoles;
|
|
57
|
+
limits?: RunContextLimits;
|
|
58
|
+
/**
|
|
59
|
+
* MCP servers this run may connect to.
|
|
60
|
+
*
|
|
61
|
+
* Only ever populated from user/host config or a host-supplied context —
|
|
62
|
+
* never from repository config. See {@link scrubRepoConfig}.
|
|
63
|
+
*/
|
|
64
|
+
mcpServers?: McpServerDefinition[];
|
|
65
|
+
/**
|
|
66
|
+
* Hand-declared HTTP connectors. Same trust rules as MCP servers: trusted
|
|
67
|
+
* layers only, never repository config.
|
|
68
|
+
*/
|
|
69
|
+
httpConnectors?: HttpConnectorDefinition[];
|
|
70
|
+
/** Tool names permitted for this run. Absent means "registry default". */
|
|
71
|
+
allowedTools?: string[];
|
|
72
|
+
deniedTools?: string[];
|
|
73
|
+
/** Non-fatal problems encountered while resolving, surfaced in the trace. */
|
|
74
|
+
warnings?: string[];
|
|
75
|
+
}
|
|
76
|
+
export interface RunContextResolveInput {
|
|
77
|
+
workspaceRoot: string;
|
|
78
|
+
tenant?: RunContextTenant;
|
|
79
|
+
/** Context supplied directly by an embedding host, taking precedence. */
|
|
80
|
+
provided?: RunContext;
|
|
81
|
+
}
|
|
82
|
+
export interface RunContextResolver {
|
|
83
|
+
readonly id: string;
|
|
84
|
+
resolve(input: RunContextResolveInput): Promise<RunContext>;
|
|
85
|
+
}
|
|
86
|
+
export interface RepoConfigScrubResult {
|
|
87
|
+
value: Record<string, unknown>;
|
|
88
|
+
rejectedKeys: string[];
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Strips forbidden keys from a repository config, recording what was dropped.
|
|
92
|
+
* Rejection is loud rather than silent: the keys land in run warnings so a
|
|
93
|
+
* repository that tries to widen its own permissions is visible.
|
|
94
|
+
*/
|
|
95
|
+
export declare const scrubRepoConfig: (config: Record<string, unknown>, pathPrefix?: string) => RepoConfigScrubResult;
|
|
96
|
+
/**
|
|
97
|
+
* Merges a narrower context over a broader one. Allow-lists intersect and
|
|
98
|
+
* deny-lists union, so a later layer can only ever restrict what an earlier one
|
|
99
|
+
* permitted — never widen it.
|
|
100
|
+
*/
|
|
101
|
+
export declare const mergeRunContexts: (base: RunContext, override: RunContext) => RunContext;
|
|
102
|
+
export interface LocalConfigResolverOptions {
|
|
103
|
+
/** Overridden in tests; defaults to `~/.codali`. */
|
|
104
|
+
userConfigDir?: string;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Resolves run context from trusted user config, then applies the repository's
|
|
108
|
+
* narrowing config on top. Used by the CLI and any single-tenant deployment.
|
|
109
|
+
*/
|
|
110
|
+
export declare class LocalConfigRunContextResolver implements RunContextResolver {
|
|
111
|
+
private readonly options;
|
|
112
|
+
readonly id = "local_config";
|
|
113
|
+
constructor(options?: LocalConfigResolverOptions);
|
|
114
|
+
resolve(input: RunContextResolveInput): Promise<RunContext>;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Uses context handed over by an embedding host. This is the okacam path: the
|
|
118
|
+
* product resolves the tenant's tools and credentials from its own database and
|
|
119
|
+
* passes them on the request.
|
|
120
|
+
*/
|
|
121
|
+
export declare class ProvidedRunContextResolver implements RunContextResolver {
|
|
122
|
+
readonly id = "provided";
|
|
123
|
+
resolve(input: RunContextResolveInput): Promise<RunContext>;
|
|
124
|
+
}
|
|
125
|
+
export declare const resolveRunContext: (input: RunContextResolveInput, resolver?: RunContextResolver) => Promise<RunContext>;
|
|
126
|
+
//# sourceMappingURL=RunContextResolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RunContextResolver.d.ts","sourceRoot":"","sources":["../../src/runcontext/RunContextResolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { readFile } from "node:fs/promises";
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
import { resolveCredential } from "./CredentialFile.js";
|
|
6
|
+
/**
|
|
7
|
+
* Keys a repository-level config file is forbidden to set.
|
|
8
|
+
*
|
|
9
|
+
* A checked-out repository is untrusted input. If `.codali/config.toml` could
|
|
10
|
+
* define an MCP server command, a base URL, or a credential reference, then
|
|
11
|
+
* cloning a repository and running `codali ask` inside it would be enough to
|
|
12
|
+
* execute an arbitrary binary or redirect traffic to an attacker's endpoint.
|
|
13
|
+
*
|
|
14
|
+
* The boundary is therefore: user/host config may define what runs and where
|
|
15
|
+
* it connects; repository config may only *narrow* what is already permitted,
|
|
16
|
+
* identify the repository, and set harmless presentation defaults.
|
|
17
|
+
*/
|
|
18
|
+
const REPO_FORBIDDEN_KEYS = new Set([
|
|
19
|
+
"command",
|
|
20
|
+
"args",
|
|
21
|
+
"env",
|
|
22
|
+
"url",
|
|
23
|
+
"base_url",
|
|
24
|
+
"baseurl",
|
|
25
|
+
"api_key",
|
|
26
|
+
"apikey",
|
|
27
|
+
"token",
|
|
28
|
+
"secret",
|
|
29
|
+
"credential",
|
|
30
|
+
"credentials",
|
|
31
|
+
"password",
|
|
32
|
+
"headers",
|
|
33
|
+
// Every reader below accepts both snake_case and camelCase, so both spellings
|
|
34
|
+
// must be forbidden. Listing only one is a hole, not a style preference.
|
|
35
|
+
"mcp_servers",
|
|
36
|
+
"mcpservers",
|
|
37
|
+
"api_connectors",
|
|
38
|
+
"apiconnectors",
|
|
39
|
+
"http_connectors",
|
|
40
|
+
"httpconnectors",
|
|
41
|
+
"agents",
|
|
42
|
+
"agent_roles",
|
|
43
|
+
"agentroles",
|
|
44
|
+
"docdex",
|
|
45
|
+
]);
|
|
46
|
+
/**
|
|
47
|
+
* Strips forbidden keys from a repository config, recording what was dropped.
|
|
48
|
+
* Rejection is loud rather than silent: the keys land in run warnings so a
|
|
49
|
+
* repository that tries to widen its own permissions is visible.
|
|
50
|
+
*/
|
|
51
|
+
export const scrubRepoConfig = (config, pathPrefix = "") => {
|
|
52
|
+
const value = {};
|
|
53
|
+
const rejectedKeys = [];
|
|
54
|
+
for (const [key, entry] of Object.entries(config)) {
|
|
55
|
+
const qualified = pathPrefix ? `${pathPrefix}.${key}` : key;
|
|
56
|
+
if (REPO_FORBIDDEN_KEYS.has(key.toLowerCase())) {
|
|
57
|
+
rejectedKeys.push(qualified);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (entry && typeof entry === "object" && !Array.isArray(entry)) {
|
|
61
|
+
const nested = scrubRepoConfig(entry, qualified);
|
|
62
|
+
value[key] = nested.value;
|
|
63
|
+
rejectedKeys.push(...nested.rejectedKeys);
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
value[key] = entry;
|
|
67
|
+
}
|
|
68
|
+
return { value, rejectedKeys };
|
|
69
|
+
};
|
|
70
|
+
const readJsonFile = async (filePath) => {
|
|
71
|
+
if (!existsSync(filePath))
|
|
72
|
+
return undefined;
|
|
73
|
+
try {
|
|
74
|
+
const raw = await readFile(filePath, "utf8");
|
|
75
|
+
const parsed = JSON.parse(raw);
|
|
76
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed)
|
|
77
|
+
? parsed
|
|
78
|
+
: undefined;
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
const asStringArray = (value) => Array.isArray(value)
|
|
85
|
+
? value.filter((entry) => typeof entry === "string")
|
|
86
|
+
: undefined;
|
|
87
|
+
const asString = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
88
|
+
const asNumber = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
89
|
+
const readAgentRoles = (value) => {
|
|
90
|
+
if (!value || typeof value !== "object")
|
|
91
|
+
return undefined;
|
|
92
|
+
const record = value;
|
|
93
|
+
const roles = {
|
|
94
|
+
orchestrator: asString(record.orchestrator),
|
|
95
|
+
worker: asString(record.worker),
|
|
96
|
+
synthesizer: asString(record.synthesizer),
|
|
97
|
+
media: asString(record.media),
|
|
98
|
+
};
|
|
99
|
+
return Object.values(roles).some(Boolean) ? roles : undefined;
|
|
100
|
+
};
|
|
101
|
+
const readLimits = (value) => {
|
|
102
|
+
if (!value || typeof value !== "object")
|
|
103
|
+
return undefined;
|
|
104
|
+
const record = value;
|
|
105
|
+
const limits = {
|
|
106
|
+
maxRounds: asNumber(record.maxRounds ?? record.max_rounds),
|
|
107
|
+
maxToolCalls: asNumber(record.maxToolCalls ?? record.max_tool_calls),
|
|
108
|
+
maxModelCalls: asNumber(record.maxModelCalls ?? record.max_model_calls),
|
|
109
|
+
deadlineMs: asNumber(record.deadlineMs ?? record.deadline_ms),
|
|
110
|
+
};
|
|
111
|
+
return Object.values(limits).some((entry) => entry !== undefined) ? limits : undefined;
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* Reads MCP server definitions from a *trusted* config layer. Never called on
|
|
115
|
+
* repository config: `scrubRepoConfig` removes the keys first.
|
|
116
|
+
*/
|
|
117
|
+
const readMcpServers = (value) => {
|
|
118
|
+
if (!Array.isArray(value))
|
|
119
|
+
return undefined;
|
|
120
|
+
const servers = [];
|
|
121
|
+
for (const entry of value) {
|
|
122
|
+
if (!entry || typeof entry !== "object")
|
|
123
|
+
continue;
|
|
124
|
+
const record = entry;
|
|
125
|
+
const name = asString(record.name);
|
|
126
|
+
if (!name)
|
|
127
|
+
continue;
|
|
128
|
+
const transport = asString(record.transport) ?? (record.command ? "stdio" : "http");
|
|
129
|
+
const common = {
|
|
130
|
+
name,
|
|
131
|
+
enabled: typeof record.enabled === "boolean" ? record.enabled : undefined,
|
|
132
|
+
readOnly: record.readOnly === true || record.read_only === true,
|
|
133
|
+
timeoutMs: asNumber(record.timeoutMs ?? record.timeout_ms),
|
|
134
|
+
allowTools: asStringArray(record.allowTools ?? record.allow_tools),
|
|
135
|
+
denyTools: asStringArray(record.denyTools ?? record.deny_tools),
|
|
136
|
+
};
|
|
137
|
+
if (transport === "stdio") {
|
|
138
|
+
const command = asString(record.command);
|
|
139
|
+
if (!command)
|
|
140
|
+
continue;
|
|
141
|
+
servers.push({
|
|
142
|
+
...common,
|
|
143
|
+
transport: "stdio",
|
|
144
|
+
command,
|
|
145
|
+
args: asStringArray(record.args),
|
|
146
|
+
cwd: asString(record.cwd),
|
|
147
|
+
env: resolveEnvRefs(record.env),
|
|
148
|
+
});
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
const url = asString(record.url);
|
|
152
|
+
if (!url)
|
|
153
|
+
continue;
|
|
154
|
+
servers.push({
|
|
155
|
+
...common,
|
|
156
|
+
transport: "http",
|
|
157
|
+
url,
|
|
158
|
+
headers: resolveEnvRefs(record.headers),
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
return servers.length > 0 ? servers : undefined;
|
|
162
|
+
};
|
|
163
|
+
/**
|
|
164
|
+
* Reads HTTP connector declarations from a *trusted* config layer. Credentials
|
|
165
|
+
* are resolved through the same `env:` indirection as MCP servers, so a config
|
|
166
|
+
* file never has to hold a literal secret.
|
|
167
|
+
*/
|
|
168
|
+
const readHttpConnectors = (value) => {
|
|
169
|
+
if (!Array.isArray(value))
|
|
170
|
+
return undefined;
|
|
171
|
+
const connectors = [];
|
|
172
|
+
for (const entry of value) {
|
|
173
|
+
if (!entry || typeof entry !== "object")
|
|
174
|
+
continue;
|
|
175
|
+
const record = entry;
|
|
176
|
+
const name = asString(record.name);
|
|
177
|
+
// Base URLs resolve `env:` references too. A site hostname is not secret,
|
|
178
|
+
// but keeping every connector detail in one credentials file beats
|
|
179
|
+
// splitting it across two places for no reason.
|
|
180
|
+
const baseUrl = resolveEnvRef(record.baseUrl ?? record.base_url);
|
|
181
|
+
if (!name || !baseUrl || !Array.isArray(record.tools))
|
|
182
|
+
continue;
|
|
183
|
+
const tools = record.tools
|
|
184
|
+
.filter((tool) => Boolean(tool && typeof tool === "object"))
|
|
185
|
+
.map((tool) => ({
|
|
186
|
+
id: asString(tool.id) ?? "",
|
|
187
|
+
description: asString(tool.description) ?? "",
|
|
188
|
+
method: (asString(tool.method) ?? "GET").toUpperCase(),
|
|
189
|
+
urlTemplate: asString(tool.urlTemplate ?? tool.url_template) ?? "",
|
|
190
|
+
inputSchema: tool.inputSchema,
|
|
191
|
+
responseSelector: asString(tool.responseSelector ?? tool.response_selector),
|
|
192
|
+
maxResponseChars: asNumber(tool.maxResponseChars ?? tool.max_response_chars),
|
|
193
|
+
}))
|
|
194
|
+
.filter((tool) => tool.id && tool.urlTemplate);
|
|
195
|
+
if (tools.length === 0)
|
|
196
|
+
continue;
|
|
197
|
+
const authRecord = record.auth && typeof record.auth === "object"
|
|
198
|
+
? record.auth
|
|
199
|
+
: undefined;
|
|
200
|
+
connectors.push({
|
|
201
|
+
name,
|
|
202
|
+
baseUrl,
|
|
203
|
+
enabled: typeof record.enabled === "boolean" ? record.enabled : undefined,
|
|
204
|
+
timeoutMs: asNumber(record.timeoutMs ?? record.timeout_ms),
|
|
205
|
+
headers: resolveEnvRefs(record.headers),
|
|
206
|
+
tools,
|
|
207
|
+
auth: authRecord
|
|
208
|
+
? {
|
|
209
|
+
type: (asString(authRecord.type) ?? "none"),
|
|
210
|
+
token: resolveEnvRef(authRecord.token),
|
|
211
|
+
username: resolveEnvRef(authRecord.username),
|
|
212
|
+
password: resolveEnvRef(authRecord.password),
|
|
213
|
+
headerName: asString(authRecord.headerName ?? authRecord.header_name),
|
|
214
|
+
tokenUrl: resolveEnvRef(authRecord.tokenUrl ?? authRecord.token_url),
|
|
215
|
+
clientId: resolveEnvRef(authRecord.clientId ?? authRecord.client_id),
|
|
216
|
+
refreshToken: resolveEnvRef(authRecord.refreshToken ?? authRecord.refresh_token),
|
|
217
|
+
scope: asString(authRecord.scope),
|
|
218
|
+
}
|
|
219
|
+
: undefined,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
return connectors.length > 0 ? connectors : undefined;
|
|
223
|
+
};
|
|
224
|
+
/**
|
|
225
|
+
* Substitutes `env:NAME` references, including when embedded in a larger
|
|
226
|
+
* string. Header values are the common case — `"Bearer env:GITHUB_TOKEN"` is
|
|
227
|
+
* what anyone would write, and requiring the reference to sit at the start of
|
|
228
|
+
* the value would silently transmit the literal text as a credential.
|
|
229
|
+
*
|
|
230
|
+
* An unresolvable reference yields `undefined` for the whole value rather than
|
|
231
|
+
* a half-substituted string: sending `Bearer env:GITHUB_TOKEN` to an API is
|
|
232
|
+
* worse than sending nothing, because the failure looks like a bad token
|
|
233
|
+
* instead of a missing one.
|
|
234
|
+
*/
|
|
235
|
+
const ENV_REF_PATTERN = /env:([A-Za-z_][A-Za-z0-9_]*)/g;
|
|
236
|
+
const substituteEnvRefs = (value) => {
|
|
237
|
+
if (!value.includes("env:"))
|
|
238
|
+
return value;
|
|
239
|
+
let missing = false;
|
|
240
|
+
const output = value.replace(ENV_REF_PATTERN, (_match, name) => {
|
|
241
|
+
const resolved = resolveCredential(name);
|
|
242
|
+
if (resolved === undefined) {
|
|
243
|
+
missing = true;
|
|
244
|
+
return "";
|
|
245
|
+
}
|
|
246
|
+
return resolved;
|
|
247
|
+
});
|
|
248
|
+
return missing ? undefined : output;
|
|
249
|
+
};
|
|
250
|
+
const resolveEnvRef = (value) => {
|
|
251
|
+
if (typeof value !== "string")
|
|
252
|
+
return undefined;
|
|
253
|
+
return substituteEnvRefs(value);
|
|
254
|
+
};
|
|
255
|
+
/**
|
|
256
|
+
* Resolves `env:NAME` references so a config file never has to contain a
|
|
257
|
+
* literal secret. Local-CLI convenience only: an embedded multi-tenant host
|
|
258
|
+
* supplies credentials directly and must not be able to name host env vars.
|
|
259
|
+
*/
|
|
260
|
+
const resolveEnvRefs = (value) => {
|
|
261
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
262
|
+
return undefined;
|
|
263
|
+
const output = {};
|
|
264
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
265
|
+
if (typeof entry !== "string")
|
|
266
|
+
continue;
|
|
267
|
+
// Resolved from the process environment first, then ~/.codali/.creds.
|
|
268
|
+
const resolved = substituteEnvRefs(entry);
|
|
269
|
+
if (resolved !== undefined)
|
|
270
|
+
output[key] = resolved;
|
|
271
|
+
}
|
|
272
|
+
return Object.keys(output).length > 0 ? output : undefined;
|
|
273
|
+
};
|
|
274
|
+
const contextFromConfig = (config) => ({
|
|
275
|
+
agentRoles: readAgentRoles(config.agents ?? config.agent_roles),
|
|
276
|
+
mcpServers: readMcpServers(config.mcpServers ?? config.mcp_servers),
|
|
277
|
+
httpConnectors: readHttpConnectors(config.httpConnectors ?? config.http_connectors),
|
|
278
|
+
limits: readLimits(config.limits),
|
|
279
|
+
allowedTools: asStringArray(config.allowedTools ?? config.allowed_tools),
|
|
280
|
+
deniedTools: asStringArray(config.deniedTools ?? config.denied_tools),
|
|
281
|
+
docdex: (() => {
|
|
282
|
+
const raw = config.docdex;
|
|
283
|
+
if (!raw || typeof raw !== "object")
|
|
284
|
+
return undefined;
|
|
285
|
+
const record = raw;
|
|
286
|
+
return {
|
|
287
|
+
baseUrl: asString(record.baseUrl ?? record.base_url),
|
|
288
|
+
apiKey: asString(record.apiKey ?? record.api_key),
|
|
289
|
+
repoRoot: asString(record.repoRoot ?? record.repo_root),
|
|
290
|
+
repoId: asString(record.repoId ?? record.repo_id),
|
|
291
|
+
allowedOperations: asStringArray(record.allowedOperations ?? record.allowed_operations),
|
|
292
|
+
};
|
|
293
|
+
})(),
|
|
294
|
+
});
|
|
295
|
+
/**
|
|
296
|
+
* Merges a narrower context over a broader one. Allow-lists intersect and
|
|
297
|
+
* deny-lists union, so a later layer can only ever restrict what an earlier one
|
|
298
|
+
* permitted — never widen it.
|
|
299
|
+
*/
|
|
300
|
+
export const mergeRunContexts = (base, override) => {
|
|
301
|
+
const allowedTools = base.allowedTools && override.allowedTools
|
|
302
|
+
? base.allowedTools.filter((tool) => override.allowedTools?.includes(tool))
|
|
303
|
+
: (override.allowedTools ?? base.allowedTools);
|
|
304
|
+
const deniedTools = [
|
|
305
|
+
...new Set([...(base.deniedTools ?? []), ...(override.deniedTools ?? [])]),
|
|
306
|
+
];
|
|
307
|
+
const minDefined = (a, b) => {
|
|
308
|
+
if (a === undefined)
|
|
309
|
+
return b;
|
|
310
|
+
if (b === undefined)
|
|
311
|
+
return a;
|
|
312
|
+
return Math.min(a, b);
|
|
313
|
+
};
|
|
314
|
+
return {
|
|
315
|
+
tenant: override.tenant ?? base.tenant,
|
|
316
|
+
repo: { ...base.repo, ...override.repo },
|
|
317
|
+
// Servers come from a trusted layer only; a narrower layer cannot add one.
|
|
318
|
+
mcpServers: override.mcpServers ?? base.mcpServers,
|
|
319
|
+
httpConnectors: override.httpConnectors ?? base.httpConnectors,
|
|
320
|
+
docdex: { ...base.docdex, ...override.docdex },
|
|
321
|
+
agentRoles: { ...base.agentRoles, ...override.agentRoles },
|
|
322
|
+
limits: {
|
|
323
|
+
maxRounds: minDefined(base.limits?.maxRounds, override.limits?.maxRounds),
|
|
324
|
+
maxToolCalls: minDefined(base.limits?.maxToolCalls, override.limits?.maxToolCalls),
|
|
325
|
+
maxModelCalls: minDefined(base.limits?.maxModelCalls, override.limits?.maxModelCalls),
|
|
326
|
+
deadlineMs: minDefined(base.limits?.deadlineMs, override.limits?.deadlineMs),
|
|
327
|
+
},
|
|
328
|
+
allowedTools,
|
|
329
|
+
deniedTools: deniedTools.length > 0 ? deniedTools : undefined,
|
|
330
|
+
warnings: [...(base.warnings ?? []), ...(override.warnings ?? [])],
|
|
331
|
+
};
|
|
332
|
+
};
|
|
333
|
+
/**
|
|
334
|
+
* Resolves run context from trusted user config, then applies the repository's
|
|
335
|
+
* narrowing config on top. Used by the CLI and any single-tenant deployment.
|
|
336
|
+
*/
|
|
337
|
+
export class LocalConfigRunContextResolver {
|
|
338
|
+
constructor(options = {}) {
|
|
339
|
+
this.options = options;
|
|
340
|
+
this.id = "local_config";
|
|
341
|
+
}
|
|
342
|
+
async resolve(input) {
|
|
343
|
+
const warnings = [];
|
|
344
|
+
const userDir = this.options.userConfigDir ?? path.join(homedir(), ".codali");
|
|
345
|
+
const userConfig = await readJsonFile(path.join(userDir, "config.json"));
|
|
346
|
+
const base = userConfig ? contextFromConfig(userConfig) : {};
|
|
347
|
+
const repoConfigRaw = await readJsonFile(path.join(input.workspaceRoot, ".codali", "config.json"));
|
|
348
|
+
let repoContext = {};
|
|
349
|
+
if (repoConfigRaw) {
|
|
350
|
+
const scrubbed = scrubRepoConfig(repoConfigRaw);
|
|
351
|
+
if (scrubbed.rejectedKeys.length > 0) {
|
|
352
|
+
warnings.push(`repo_config_keys_rejected:${scrubbed.rejectedKeys.join(",")}`);
|
|
353
|
+
}
|
|
354
|
+
repoContext = contextFromConfig(scrubbed.value);
|
|
355
|
+
}
|
|
356
|
+
const merged = mergeRunContexts(base, repoContext);
|
|
357
|
+
return {
|
|
358
|
+
...merged,
|
|
359
|
+
tenant: input.tenant ?? merged.tenant,
|
|
360
|
+
repo: { root: input.workspaceRoot, ...merged.repo },
|
|
361
|
+
warnings: [...(merged.warnings ?? []), ...warnings],
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Uses context handed over by an embedding host. This is the okacam path: the
|
|
367
|
+
* product resolves the tenant's tools and credentials from its own database and
|
|
368
|
+
* passes them on the request.
|
|
369
|
+
*/
|
|
370
|
+
export class ProvidedRunContextResolver {
|
|
371
|
+
constructor() {
|
|
372
|
+
this.id = "provided";
|
|
373
|
+
}
|
|
374
|
+
async resolve(input) {
|
|
375
|
+
if (!input.provided) {
|
|
376
|
+
throw new Error("ProvidedRunContextResolver requires a RunContext on the request.");
|
|
377
|
+
}
|
|
378
|
+
return {
|
|
379
|
+
...input.provided,
|
|
380
|
+
repo: { root: input.workspaceRoot, ...input.provided.repo },
|
|
381
|
+
tenant: input.tenant ?? input.provided.tenant,
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
export const resolveRunContext = async (input, resolver) => {
|
|
386
|
+
const active = resolver ??
|
|
387
|
+
(input.provided ? new ProvidedRunContextResolver() : new LocalConfigRunContextResolver());
|
|
388
|
+
return active.resolve(input);
|
|
389
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type CodaliStorageObjectPrivacyFlags, type CodaliStorageObjectRef, type CodaliStorageObjectRetentionClass, type CodaliStoragePrivacyClassification, type CodaliStoragePrivacyMetadata } from "./CodaliStorageContracts.js";
|
|
2
2
|
export type CodaliDatasetPrivacyPurpose = "training" | "export" | "eval" | "replay" | "durable_persistence";
|
|
3
|
-
export type CodaliDatasetSecretFindingKind = "sensitive_key" | "bearer_token" | "openai_api_key" | "cloud_access_key" | "github_token" | "jwt" | "private_key" | "env_secret_assignment";
|
|
3
|
+
export type CodaliDatasetSecretFindingKind = "sensitive_key" | "bearer_token" | "openai_api_key" | "cloud_access_key" | "github_token" | "jwt" | "private_key" | "env_secret_assignment" | "connector_api_key";
|
|
4
4
|
export type CodaliDatasetEligibilityBlockerCode = "secrets_detected" | "privacy_training_not_allowed" | "privacy_export_not_allowed" | "object_training_not_allowed" | "object_export_not_allowed" | "object_eval_not_allowed" | "object_replay_not_allowed" | "retention_do_not_store" | "redaction_required" | "policy_override_requires_admin_audit" | "policy_override_not_requested" | "policy_override_hard_blocked";
|
|
5
5
|
export interface CodaliDatasetSecretFinding {
|
|
6
6
|
kind: CodaliDatasetSecretFindingKind;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodaliDatasetPrivacyEngine.d.ts","sourceRoot":"","sources":["../../src/storage/CodaliDatasetPrivacyEngine.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,+BAA+B,EACpC,KAAK,sBAAsB,EAC3B,KAAK,iCAAiC,EACtC,KAAK,kCAAkC,EACvC,KAAK,4BAA4B,EAClC,MAAM,6BAA6B,CAAC;AAErC,MAAM,MAAM,2BAA2B,GACnC,UAAU,GACV,QAAQ,GACR,MAAM,GACN,QAAQ,GACR,qBAAqB,CAAC;AAE1B,MAAM,MAAM,8BAA8B,GACtC,eAAe,GACf,cAAc,GACd,gBAAgB,GAChB,kBAAkB,GAClB,cAAc,GACd,KAAK,GACL,aAAa,GACb,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"CodaliDatasetPrivacyEngine.d.ts","sourceRoot":"","sources":["../../src/storage/CodaliDatasetPrivacyEngine.ts"],"names":[],"mappings":"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"}
|
|
@@ -30,6 +30,18 @@ const SECRET_VALUE_PATTERNS = [
|
|
|
30
30
|
kind: "env_secret_assignment",
|
|
31
31
|
pattern: /\b(?:API[_-]?KEY|TOKEN|SECRET|PASSWORD|PRIVATE[_-]?KEY)=["']?[^"'\s]{8,}["']?/gi,
|
|
32
32
|
},
|
|
33
|
+
// Connector credentials. Added alongside the first MCP connector, because
|
|
34
|
+
// that is the point at which third-party secrets first flow through a run.
|
|
35
|
+
// The `sk-` rule above does not match underscore-delimited keys such as
|
|
36
|
+
// mswarm's `sk_prod_mswarm_...`, so those need their own rule.
|
|
37
|
+
{
|
|
38
|
+
kind: "connector_api_key",
|
|
39
|
+
pattern: /\bsk_[A-Za-z0-9]+_[A-Za-z0-9_]{8,}\b/g,
|
|
40
|
+
},
|
|
41
|
+
{ kind: "connector_api_key", pattern: /\bglpat-[A-Za-z0-9_-]{16,}\b/g },
|
|
42
|
+
{ kind: "connector_api_key", pattern: /\bxox[abprs]-[A-Za-z0-9-]{10,}\b/g },
|
|
43
|
+
{ kind: "connector_api_key", pattern: /\bAIza[0-9A-Za-z_-]{30,}\b/g },
|
|
44
|
+
{ kind: "connector_api_key", pattern: /\bnpm_[A-Za-z0-9]{30,}\b/g },
|
|
33
45
|
];
|
|
34
46
|
const PERSONAL_KEY_PATTERNS = [
|
|
35
47
|
/(^|[_-])(email|phone|ssn|person|user[_-]?id|requester)([_-]|$)/i,
|
|
@@ -1,9 +1,22 @@
|
|
|
1
|
-
import { type ToolContext, type ToolDefinition, type ToolExecutionResult } from "./ToolTypes.js";
|
|
1
|
+
import { type ToolCapability, type ToolContext, type ToolDefinition, type ToolDescriptor, type ToolExecutionResult } from "./ToolTypes.js";
|
|
2
|
+
/**
|
|
3
|
+
* Projects a registered tool into its model-facing descriptor. Kept as a free
|
|
4
|
+
* function so connector adapters can reuse the same defaulting rules.
|
|
5
|
+
*/
|
|
6
|
+
export declare const toolDescriptorFor: (tool: ToolDefinition) => ToolDescriptor;
|
|
2
7
|
export declare class ToolRegistry {
|
|
3
8
|
private tools;
|
|
4
9
|
register(tool: ToolDefinition): void;
|
|
5
10
|
list(): ToolDefinition[];
|
|
6
11
|
describe(): Array<Pick<ToolDefinition, "name" | "description" | "inputSchema">>;
|
|
12
|
+
/**
|
|
13
|
+
* Model-facing view of the registry, optionally narrowed to a set of tool
|
|
14
|
+
* names. This is derived on every call rather than cached so the planner can
|
|
15
|
+
* never see a schema the executor would not honour.
|
|
16
|
+
*/
|
|
17
|
+
catalog(names?: readonly string[]): ToolDescriptor[];
|
|
18
|
+
/** Capability -> tools, for the first stage of two-level tool exposure. */
|
|
19
|
+
capabilities(names?: readonly string[]): Map<ToolCapability, ToolDescriptor[]>;
|
|
7
20
|
execute(name: string, args: unknown, context: ToolContext): Promise<ToolExecutionResult>;
|
|
8
21
|
}
|
|
9
22
|
//# sourceMappingURL=ToolRegistry.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToolRegistry.d.ts","sourceRoot":"","sources":["../../src/tools/ToolRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"ToolRegistry.d.ts","sourceRoot":"","sources":["../../src/tools/ToolRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,cAAc,EAGnB,KAAK,mBAAmB,EAGzB,MAAM,gBAAgB,CAAC;AAExB;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,MAAM,cAAc,KAAG,cAOvD,CAAC;AA4QH,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAAqC;IAElD,QAAQ,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI;IAOpC,IAAI,IAAI,cAAc,EAAE;IAIxB,QAAQ,IAAI,KAAK,CAAC,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,aAAa,GAAG,aAAa,CAAC,CAAC;IAQ/E;;;;OAIG;IACH,OAAO,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,cAAc,EAAE;IAOpD,2EAA2E;IAC3E,YAAY,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,GAAG,CAAC,cAAc,EAAE,cAAc,EAAE,CAAC;IAaxE,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,mBAAmB,CAAC;CAkC/F"}
|
|
@@ -1,4 +1,16 @@
|
|
|
1
|
-
import { ToolExecutionError, toolErrorCategoryForCode, } from "./ToolTypes.js";
|
|
1
|
+
import { ToolExecutionError, toolCapabilityForName, toolErrorCategoryForCode, } from "./ToolTypes.js";
|
|
2
|
+
/**
|
|
3
|
+
* Projects a registered tool into its model-facing descriptor. Kept as a free
|
|
4
|
+
* function so connector adapters can reuse the same defaulting rules.
|
|
5
|
+
*/
|
|
6
|
+
export const toolDescriptorFor = (tool) => ({
|
|
7
|
+
name: tool.name,
|
|
8
|
+
description: tool.description,
|
|
9
|
+
inputSchema: tool.inputSchema,
|
|
10
|
+
outputSchema: tool.outputSchema,
|
|
11
|
+
readOnly: tool.readOnly ?? false,
|
|
12
|
+
capability: tool.capability ?? toolCapabilityForName(tool.name),
|
|
13
|
+
});
|
|
2
14
|
const isObject = (value) => {
|
|
3
15
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4
16
|
};
|
|
@@ -262,6 +274,31 @@ export class ToolRegistry {
|
|
|
262
274
|
inputSchema: tool.inputSchema,
|
|
263
275
|
}));
|
|
264
276
|
}
|
|
277
|
+
/**
|
|
278
|
+
* Model-facing view of the registry, optionally narrowed to a set of tool
|
|
279
|
+
* names. This is derived on every call rather than cached so the planner can
|
|
280
|
+
* never see a schema the executor would not honour.
|
|
281
|
+
*/
|
|
282
|
+
catalog(names) {
|
|
283
|
+
const filter = names ? new Set(names) : undefined;
|
|
284
|
+
return this.list()
|
|
285
|
+
.filter((tool) => !filter || filter.has(tool.name))
|
|
286
|
+
.map((tool) => toolDescriptorFor(tool));
|
|
287
|
+
}
|
|
288
|
+
/** Capability -> tools, for the first stage of two-level tool exposure. */
|
|
289
|
+
capabilities(names) {
|
|
290
|
+
const grouped = new Map();
|
|
291
|
+
for (const descriptor of this.catalog(names)) {
|
|
292
|
+
const bucket = grouped.get(descriptor.capability);
|
|
293
|
+
if (bucket) {
|
|
294
|
+
bucket.push(descriptor);
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
grouped.set(descriptor.capability, [descriptor]);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return grouped;
|
|
301
|
+
}
|
|
265
302
|
async execute(name, args, context) {
|
|
266
303
|
const tool = this.tools.get(name);
|
|
267
304
|
if (!tool) {
|