@gea-ai/agent-sdk 0.1.261002-alpha.0 → 0.1.261003-alpha.1
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/agent-channel-author-runtime.d.ts +13 -13
- package/dist/agent-worker.d.ts +1 -0
- package/dist/agent-worker.js +61 -5
- package/dist/code-mode-discovery.d.ts +38 -0
- package/dist/code-mode-discovery.js +259 -0
- package/dist/code-mode.d.ts +575 -0
- package/dist/code-mode.js +224 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +35 -0
- package/dist/script-source.d.ts +10 -0
- package/dist/script-source.js +23 -0
- package/dist/script-tools.d.ts +10 -0
- package/dist/script-tools.js +33 -23
- package/dist/skill-tool.js +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/worker-script-runner.d.ts +1 -0
- package/dist/worker-script-runner.js +97 -0
- package/dist/worker-script.d.ts +17 -0
- package/dist/worker-script.js +154 -0
- package/package.json +6 -2
- package/script-runtime/javascript.mjs +9 -2
- package/script-runtime/typescript.mjs +7 -2
|
@@ -19,6 +19,19 @@ export declare function executeChannelBehavior(input: {
|
|
|
19
19
|
environment: AgentChannelFetchEnvironment;
|
|
20
20
|
signal: AbortSignal;
|
|
21
21
|
}): Promise<{
|
|
22
|
+
sequence: number;
|
|
23
|
+
duplicate: boolean;
|
|
24
|
+
} | {
|
|
25
|
+
state: AgentChannelJson;
|
|
26
|
+
intents: {
|
|
27
|
+
key: string;
|
|
28
|
+
payload: AgentChannelJson;
|
|
29
|
+
eventId: string;
|
|
30
|
+
operationId: string;
|
|
31
|
+
}[];
|
|
32
|
+
cursor: number;
|
|
33
|
+
idempotencyWindowMs?: number | undefined;
|
|
34
|
+
} | {
|
|
22
35
|
status: "sent";
|
|
23
36
|
receipt?: AgentChannelJson | undefined;
|
|
24
37
|
} | {
|
|
@@ -43,19 +56,6 @@ export declare function executeChannelBehavior(input: {
|
|
|
43
56
|
message: string;
|
|
44
57
|
retryable: boolean;
|
|
45
58
|
};
|
|
46
|
-
} | {
|
|
47
|
-
sequence: number;
|
|
48
|
-
duplicate: boolean;
|
|
49
|
-
} | {
|
|
50
|
-
state: AgentChannelJson;
|
|
51
|
-
intents: {
|
|
52
|
-
key: string;
|
|
53
|
-
payload: AgentChannelJson;
|
|
54
|
-
eventId: string;
|
|
55
|
-
operationId: string;
|
|
56
|
-
}[];
|
|
57
|
-
cursor: number;
|
|
58
|
-
idempotencyWindowMs?: number | undefined;
|
|
59
59
|
} | {
|
|
60
60
|
events: {
|
|
61
61
|
id: string;
|
package/dist/agent-worker.d.ts
CHANGED
|
@@ -135,6 +135,7 @@ export type AgentToolRuntimeDefinition = {
|
|
|
135
135
|
input: unknown;
|
|
136
136
|
sdk: AgentToolRuntimeSdk;
|
|
137
137
|
}): Promise<unknown>;
|
|
138
|
+
scriptRuntime?: ReturnType<typeof import("./script-tools").getScriptToolRuntime>;
|
|
138
139
|
inputSchema: z.ZodType;
|
|
139
140
|
toModelOutput?: import("./index").DefinedCustomTool["toModelOutput"];
|
|
140
141
|
}>;
|
package/dist/agent-worker.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { AGENT_WORKER_TOOL_METADATA_HEADER, AGENT_WORKER_TOOL_METADATA_VERSION, } from "@gea-ai/contract/agent-worker-tools";
|
|
2
|
+
import { isAgentConnectorExposed } from "@gea-ai/contract/agent-packages";
|
|
3
|
+
import { createCodeMode } from "./code-mode.js";
|
|
1
4
|
import { AGENT_SUBAGENT_CONCURRENCY_HEADER } from "@gea-ai/contract/agent-worker-tools";
|
|
2
5
|
import { DEFAULT_MAX_CONCURRENT_SUBAGENTS } from "@gea-ai/contract/agent-packages";
|
|
3
6
|
import { batchAgentStreamEvents, coalesceAgentTextDeltas, } from "./agent-stream-coalescing.js";
|
|
@@ -185,7 +188,11 @@ async function runPreparedConnectorAuthorization(input, environment) {
|
|
|
185
188
|
}
|
|
186
189
|
const [identityValue, initializationValue] = await Promise.all([
|
|
187
190
|
requireHostJson(environment.IDENTITY, "/context"),
|
|
188
|
-
requireHostJson(environment.TOOLS, "/tools/initialize"
|
|
191
|
+
requireHostJson(environment.TOOLS, "/tools/initialize", {
|
|
192
|
+
headers: {
|
|
193
|
+
[AGENT_WORKER_TOOL_METADATA_HEADER]: AGENT_WORKER_TOOL_METADATA_VERSION,
|
|
194
|
+
},
|
|
195
|
+
}),
|
|
189
196
|
]);
|
|
190
197
|
const identity = agentToolIdentitySchema.parse(identityValue);
|
|
191
198
|
const initialization = agentWorkerToolInitializationSchema.parse(initializationValue);
|
|
@@ -300,6 +307,7 @@ async function runPreparedAgent(runtime, agentKey, request, environment, startup
|
|
|
300
307
|
"content-type": "application/json",
|
|
301
308
|
"x-gea-agent-runs": "1",
|
|
302
309
|
"x-gea-session-inbox": "1",
|
|
310
|
+
[AGENT_WORKER_TOOL_METADATA_HEADER]: AGENT_WORKER_TOOL_METADATA_VERSION,
|
|
303
311
|
...Object.fromEntries([...request.headers.entries()].filter(([name]) => ["traceparent", "tracestate", "x-gea-request-id"].includes(name))),
|
|
304
312
|
},
|
|
305
313
|
body: JSON.stringify({ metadata: parsed.data.metadata }),
|
|
@@ -2185,6 +2193,7 @@ function createHostBackedAgentTools(input) {
|
|
|
2185
2193
|
execute: async (toolInput, options) => await invokeHostTool({
|
|
2186
2194
|
host: input.host,
|
|
2187
2195
|
messages: options.messages,
|
|
2196
|
+
signal: options.abortSignal,
|
|
2188
2197
|
toolCallId: options.toolCallId,
|
|
2189
2198
|
toolInput,
|
|
2190
2199
|
toolName: definition.hostToolName ?? name,
|
|
@@ -2251,7 +2260,7 @@ function createHostBackedAgentTools(input) {
|
|
|
2251
2260
|
continue;
|
|
2252
2261
|
}
|
|
2253
2262
|
const declaredOperation = grant.definition.operations.find((operation) => operation.name === descriptor.operation);
|
|
2254
|
-
if (!grant.
|
|
2263
|
+
if (!isAgentConnectorExposed(grant, input.snapshot.codeMode) ||
|
|
2255
2264
|
(grant.definition.runtime.type !== "mcp" && !declaredOperation)) {
|
|
2256
2265
|
throw new Error("Agent Worker Connector operation is not granted.");
|
|
2257
2266
|
}
|
|
@@ -2265,11 +2274,21 @@ function createHostBackedAgentTools(input) {
|
|
|
2265
2274
|
.join("\n"),
|
|
2266
2275
|
inputSchema: jsonSchema(descriptor.inputSchema),
|
|
2267
2276
|
...(grant.definition.runtime.type === "mcp"
|
|
2268
|
-
? {
|
|
2277
|
+
? {
|
|
2278
|
+
toModelOutput: mcpToolModelOutput,
|
|
2279
|
+
...(descriptor.outputSchema === undefined
|
|
2280
|
+
? {}
|
|
2281
|
+
: {
|
|
2282
|
+
providerOptions: {
|
|
2283
|
+
gea: { mcpOutputSchema: descriptor.outputSchema },
|
|
2284
|
+
},
|
|
2285
|
+
}),
|
|
2286
|
+
}
|
|
2269
2287
|
: {}),
|
|
2270
2288
|
execute: async (toolInput, options) => await invokeHostTool({
|
|
2271
2289
|
host: input.host,
|
|
2272
2290
|
messages: options.messages,
|
|
2291
|
+
signal: options.abortSignal,
|
|
2273
2292
|
toolCallId: options.toolCallId,
|
|
2274
2293
|
toolInput,
|
|
2275
2294
|
toolName,
|
|
@@ -3090,7 +3109,10 @@ async function executeAgentWorkerRequest(input, waitUntil, ownComputer, ownSessi
|
|
|
3090
3109
|
!!Object.keys(input.snapshot.agentReferences ?? {}).length ||
|
|
3091
3110
|
requiresToolInitialization(input.snapshot, input.hookRuntime)
|
|
3092
3111
|
? startupTracing.withSpan("agent.startup.tools", () => requireHostJson(host, "/tools/initialize", {
|
|
3093
|
-
headers: {
|
|
3112
|
+
headers: {
|
|
3113
|
+
"x-gea-agent-runs": "1",
|
|
3114
|
+
[AGENT_WORKER_TOOL_METADATA_HEADER]: AGENT_WORKER_TOOL_METADATA_VERSION,
|
|
3115
|
+
},
|
|
3094
3116
|
}).then((value) => agentWorkerToolInitializationSchema.parse(value)))
|
|
3095
3117
|
: Promise.resolve(agentWorkerToolInitializationSchema.parse({
|
|
3096
3118
|
connectors: [],
|
|
@@ -3247,6 +3269,11 @@ async function executeAgentWorkerRequest(input, waitUntil, ownComputer, ownSessi
|
|
|
3247
3269
|
mountedRoot: mountedSkillRoot,
|
|
3248
3270
|
snapshot: input.snapshot,
|
|
3249
3271
|
});
|
|
3272
|
+
const skills = skillTool
|
|
3273
|
+
? {
|
|
3274
|
+
readText: ({ name, path }) => skillTool.execute({ skill: name, path }).content,
|
|
3275
|
+
}
|
|
3276
|
+
: undefined;
|
|
3250
3277
|
const agentEnvironment = Object.fromEntries(input.snapshot.environment.flatMap((definition) => {
|
|
3251
3278
|
const value = initialization.runtime.variables[definition.name];
|
|
3252
3279
|
if (value !== undefined)
|
|
@@ -3313,7 +3340,7 @@ async function executeAgentWorkerRequest(input, waitUntil, ownComputer, ownSessi
|
|
|
3313
3340
|
if (!runtime) {
|
|
3314
3341
|
throw new Error(`Custom Connector runtime is missing: ${definition.alias}`);
|
|
3315
3342
|
}
|
|
3316
|
-
if (!definition.
|
|
3343
|
+
if (!isAgentConnectorExposed(definition, input.snapshot.codeMode))
|
|
3317
3344
|
continue;
|
|
3318
3345
|
if (definition.authorization === "interactive") {
|
|
3319
3346
|
registerAgentWorkerTool(tools, `${definition.alias}__connect`, tool({
|
|
@@ -3440,6 +3467,7 @@ async function executeAgentWorkerRequest(input, waitUntil, ownComputer, ownSessi
|
|
|
3440
3467
|
}),
|
|
3441
3468
|
}
|
|
3442
3469
|
: {}),
|
|
3470
|
+
skills,
|
|
3443
3471
|
auth: initialization.runtime.auth,
|
|
3444
3472
|
agentTools: {
|
|
3445
3473
|
commands: createComputerCommands({
|
|
@@ -4298,6 +4326,34 @@ async function executeAgentWorkerRequest(input, waitUntil, ownComputer, ownSessi
|
|
|
4298
4326
|
},
|
|
4299
4327
|
};
|
|
4300
4328
|
};
|
|
4329
|
+
if (input.snapshot.codeMode) {
|
|
4330
|
+
const configured = await createCodeMode({
|
|
4331
|
+
skills,
|
|
4332
|
+
scriptRuntime: input.toolRuntime.actions.executeJavaScript?.scriptRuntime,
|
|
4333
|
+
scriptToolNames: Object.entries(input.toolRuntime.actions)
|
|
4334
|
+
.filter(([, action]) => action.scriptRuntime)
|
|
4335
|
+
.map(([name]) => name),
|
|
4336
|
+
readArtifact: artifactScope
|
|
4337
|
+
? async (id, execution) => createAgentArtifacts({
|
|
4338
|
+
scope: artifactScope,
|
|
4339
|
+
invoke: (operation) => invokeArtifact(operation, "executeJavaScript", execution),
|
|
4340
|
+
}).readText({ id })
|
|
4341
|
+
: undefined,
|
|
4342
|
+
tools,
|
|
4343
|
+
snapshot: input.snapshot,
|
|
4344
|
+
approval: toolApproval,
|
|
4345
|
+
messages: () => context.messages,
|
|
4346
|
+
guardrail: engine?.guardrail,
|
|
4347
|
+
sdk: {
|
|
4348
|
+
tracing: createAgentTracing(),
|
|
4349
|
+
auth: initialization.runtime.auth,
|
|
4350
|
+
env: agentEnvironment,
|
|
4351
|
+
environment: initialization.runtime.environment,
|
|
4352
|
+
identity,
|
|
4353
|
+
},
|
|
4354
|
+
});
|
|
4355
|
+
tools = configured.tools;
|
|
4356
|
+
}
|
|
4301
4357
|
let stream;
|
|
4302
4358
|
if (engine) {
|
|
4303
4359
|
if (!coreConnection || !coreModule)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { AgentToolNamespace } from "@gea-ai/contract/agent-packages";
|
|
2
|
+
export type CodeModeCatalogEntry = {
|
|
3
|
+
name: string;
|
|
4
|
+
namespace: string;
|
|
5
|
+
description: string;
|
|
6
|
+
inputSchema: unknown;
|
|
7
|
+
outputSchema?: unknown;
|
|
8
|
+
structuredContentSchema?: unknown;
|
|
9
|
+
declaration: string;
|
|
10
|
+
mcp: boolean;
|
|
11
|
+
};
|
|
12
|
+
type Namespace = AgentToolNamespace & {
|
|
13
|
+
name: string;
|
|
14
|
+
};
|
|
15
|
+
/** Bounded hints, never a substitute for validation by the original tool schema. */
|
|
16
|
+
export declare function codeModeDeclaration(name: string, input: unknown, output: unknown, mcp: boolean): string;
|
|
17
|
+
/** Pi-compatible helper shapes, implemented against the GEA callable snapshot. */
|
|
18
|
+
export declare function createCodeModeDiscovery(catalog: CodeModeCatalogEntry[], namespaces: Namespace[]): {
|
|
19
|
+
allTools: {
|
|
20
|
+
name: string;
|
|
21
|
+
description: string;
|
|
22
|
+
}[];
|
|
23
|
+
searchTools(query: string, options?: {
|
|
24
|
+
limit?: number;
|
|
25
|
+
namespace?: string | null;
|
|
26
|
+
} | null): {
|
|
27
|
+
name: string;
|
|
28
|
+
description: string;
|
|
29
|
+
}[];
|
|
30
|
+
describeTool(name: string): string | undefined;
|
|
31
|
+
describeNamespace(name: string): {
|
|
32
|
+
description?: string | undefined;
|
|
33
|
+
instructions?: string | undefined;
|
|
34
|
+
name: string;
|
|
35
|
+
tools: string[];
|
|
36
|
+
} | undefined;
|
|
37
|
+
};
|
|
38
|
+
export {};
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const encoder = new TextEncoder();
|
|
3
|
+
const bytes = (value) => encoder.encode(JSON.stringify(value)).length;
|
|
4
|
+
const nameSchema = z.string().max(256);
|
|
5
|
+
const searchSchema = z.object({
|
|
6
|
+
query: z.string().max(512),
|
|
7
|
+
options: z
|
|
8
|
+
.object({
|
|
9
|
+
limit: z.number().int().positive().optional(),
|
|
10
|
+
namespace: nameSchema.nullish(),
|
|
11
|
+
})
|
|
12
|
+
.nullish(),
|
|
13
|
+
});
|
|
14
|
+
/** Bounded hints, never a substitute for validation by the original tool schema. */
|
|
15
|
+
export function codeModeDeclaration(name, input, output, mcp) {
|
|
16
|
+
let remaining = 256;
|
|
17
|
+
function type(value, depth = 0) {
|
|
18
|
+
if (--remaining < 0 || depth > 8 || !value || typeof value !== "object")
|
|
19
|
+
return "unknown";
|
|
20
|
+
const schema = value;
|
|
21
|
+
if (schema.$ref || schema.allOf || schema.not || schema.if)
|
|
22
|
+
return "unknown";
|
|
23
|
+
if ("const" in schema) {
|
|
24
|
+
const literal = JSON.stringify(schema.const);
|
|
25
|
+
return literal.length <= 1024 ? literal : "unknown";
|
|
26
|
+
}
|
|
27
|
+
if (Array.isArray(schema.enum)) {
|
|
28
|
+
const text = schema.enum.length <= 32
|
|
29
|
+
? schema.enum.map((value) => JSON.stringify(value)).join(" | ")
|
|
30
|
+
: "unknown";
|
|
31
|
+
return text.length <= 1024 ? text || "never" : "unknown";
|
|
32
|
+
}
|
|
33
|
+
const union = schema.anyOf ?? schema.oneOf;
|
|
34
|
+
if (Array.isArray(union))
|
|
35
|
+
return union.length <= 16
|
|
36
|
+
? union.map((value) => type(value, depth + 1)).join(" | ")
|
|
37
|
+
: "unknown";
|
|
38
|
+
if (Array.isArray(schema.type))
|
|
39
|
+
return schema.type.length <= 8
|
|
40
|
+
? schema.type
|
|
41
|
+
.map((kind) => type({ ...schema, type: kind }, depth + 1))
|
|
42
|
+
.join(" | ")
|
|
43
|
+
: "unknown";
|
|
44
|
+
switch (schema.type) {
|
|
45
|
+
case "string":
|
|
46
|
+
case "boolean":
|
|
47
|
+
case "null":
|
|
48
|
+
return schema.type;
|
|
49
|
+
case "integer":
|
|
50
|
+
case "number":
|
|
51
|
+
return "number";
|
|
52
|
+
case "array":
|
|
53
|
+
return `Array<${type(schema.items, depth + 1)}>`;
|
|
54
|
+
case "object": {
|
|
55
|
+
const required = new Set(Array.isArray(schema.required) ? schema.required : []);
|
|
56
|
+
const properties = schema.properties && typeof schema.properties === "object"
|
|
57
|
+
? Object.entries(schema.properties)
|
|
58
|
+
: [];
|
|
59
|
+
if (properties.length > 64 ||
|
|
60
|
+
properties.some(([key]) => key.length > 128))
|
|
61
|
+
return "Record<string, unknown>";
|
|
62
|
+
const fields = properties.map(([key, value]) => `${JSON.stringify(key)}${required.has(key) ? "" : "?"}: ${type(value, depth + 1)}`);
|
|
63
|
+
if (schema.additionalProperties !== false)
|
|
64
|
+
fields.push("[key: string]: unknown");
|
|
65
|
+
return `{ ${fields.join("; ")} }`;
|
|
66
|
+
}
|
|
67
|
+
default:
|
|
68
|
+
return "unknown";
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const result = mcp
|
|
72
|
+
? "{ content: Array<unknown>; structuredContent?: unknown; isError?: boolean }"
|
|
73
|
+
: type(output);
|
|
74
|
+
const prefix = `tools[${JSON.stringify(name)}]`;
|
|
75
|
+
const text = `${prefix}(input: ${type(input)}): Promise<${result}>`;
|
|
76
|
+
return text.length <= 4096
|
|
77
|
+
? text
|
|
78
|
+
: `${prefix}(input: unknown): Promise<unknown>`;
|
|
79
|
+
}
|
|
80
|
+
/** No semantic search: ASCII words/identifier pieces, plus Han unigrams and bigrams. */
|
|
81
|
+
function terms(text) {
|
|
82
|
+
const normalized = text
|
|
83
|
+
.slice(0, 16384)
|
|
84
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1 $2")
|
|
85
|
+
.replace(/([A-Z])([A-Z][a-z])/g, "$1 $2")
|
|
86
|
+
.toLowerCase();
|
|
87
|
+
const stop = new Set("a an and are as at be by for from in is it of on or that the this to with".split(" "));
|
|
88
|
+
const result = [];
|
|
89
|
+
for (const part of normalized.match(/[a-z0-9]+|\p{Script=Han}+/gu) ?? []) {
|
|
90
|
+
if (/\p{Script=Han}/u.test(part)) {
|
|
91
|
+
const chars = [...part];
|
|
92
|
+
for (let i = 0; i < chars.length; i++) {
|
|
93
|
+
result.push(chars[i]);
|
|
94
|
+
if (i + 1 < chars.length)
|
|
95
|
+
result.push(chars[i] + chars[i + 1]);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else if (!stop.has(part)) {
|
|
99
|
+
result.push(part.length > 4 && part.endsWith("ies")
|
|
100
|
+
? part.slice(0, -3) + "y"
|
|
101
|
+
: part.length > 4 && /(?:ches|shes|sses|xes|zes)$/.test(part)
|
|
102
|
+
? part.slice(0, -2)
|
|
103
|
+
: part.length > 3 && part.endsWith("s") && !part.endsWith("ss")
|
|
104
|
+
? part.slice(0, -1)
|
|
105
|
+
: part);
|
|
106
|
+
}
|
|
107
|
+
if (result.length >= 2048)
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
return result.slice(0, 2048);
|
|
111
|
+
}
|
|
112
|
+
/** Only parameter names/descriptions; bounded traversal of untrusted MCP schemas. */
|
|
113
|
+
function parameterText(input) {
|
|
114
|
+
const pieces = [];
|
|
115
|
+
let visited = 0, length = 0;
|
|
116
|
+
function visit(value, depth) {
|
|
117
|
+
if (++visited > 256 ||
|
|
118
|
+
depth > 8 ||
|
|
119
|
+
length >= 8192 ||
|
|
120
|
+
!value ||
|
|
121
|
+
typeof value !== "object")
|
|
122
|
+
return;
|
|
123
|
+
const schema = value;
|
|
124
|
+
if (typeof schema.description === "string") {
|
|
125
|
+
const text = schema.description.slice(0, 512);
|
|
126
|
+
pieces.push(text);
|
|
127
|
+
length += text.length;
|
|
128
|
+
}
|
|
129
|
+
if (schema.properties && typeof schema.properties === "object") {
|
|
130
|
+
for (const [key, property] of Object.entries(schema.properties).slice(0, 64)) {
|
|
131
|
+
if (visited > 256 || length >= 8192)
|
|
132
|
+
break;
|
|
133
|
+
pieces.push(key.slice(0, 128));
|
|
134
|
+
length += Math.min(key.length, 128);
|
|
135
|
+
visit(property, depth + 1);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
visit(schema.items, depth + 1);
|
|
139
|
+
for (const key of ["anyOf", "oneOf", "allOf"]) {
|
|
140
|
+
const variants = schema[key];
|
|
141
|
+
if (Array.isArray(variants))
|
|
142
|
+
for (const variant of variants.slice(0, 16))
|
|
143
|
+
visit(variant, depth + 1);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
visit(input, 0);
|
|
147
|
+
return pieces.join(" ").slice(0, 8192);
|
|
148
|
+
}
|
|
149
|
+
/** Pi-compatible helper shapes, implemented against the GEA callable snapshot. */
|
|
150
|
+
export function createCodeModeDiscovery(catalog, namespaces) {
|
|
151
|
+
const summary = (entry) => ({
|
|
152
|
+
name: entry.name,
|
|
153
|
+
description: `${entry.description.slice(0, 1024)}\n\n${entry.declaration}\n${entry.mcp ? "Returns the full MCP result envelope (content, optional structuredContent/isError)." : "Returns the original JSON tool result; unknown means no known output schema."}`,
|
|
154
|
+
});
|
|
155
|
+
const allTools = catalog.map(summary);
|
|
156
|
+
if (bytes(allTools) > 256 * 1024)
|
|
157
|
+
throw new Error("Code mode catalog exceeds the 256 KiB discovery budget; expose fewer tools.");
|
|
158
|
+
const documents = catalog.map((entry) => {
|
|
159
|
+
const namespace = namespaces.find((item) => item.name === entry.namespace);
|
|
160
|
+
const text = [
|
|
161
|
+
entry.name,
|
|
162
|
+
entry.name.replaceAll("_", " "),
|
|
163
|
+
entry.description.slice(0, 2048),
|
|
164
|
+
namespace?.name,
|
|
165
|
+
namespace?.description,
|
|
166
|
+
namespace?.instructions,
|
|
167
|
+
parameterText(entry.inputSchema),
|
|
168
|
+
].join(" ");
|
|
169
|
+
const tokens = terms(text);
|
|
170
|
+
const frequencies = new Map();
|
|
171
|
+
for (const token of tokens)
|
|
172
|
+
frequencies.set(token, (frequencies.get(token) ?? 0) + 1);
|
|
173
|
+
return { entry, frequencies, length: tokens.length };
|
|
174
|
+
});
|
|
175
|
+
function resolveNamespace(name) {
|
|
176
|
+
const exact = namespaces.find((item) => item.name === name);
|
|
177
|
+
if (exact)
|
|
178
|
+
return exact;
|
|
179
|
+
const identifier = (value) => value.replace(/[^a-zA-Z0-9_$]/g, "_");
|
|
180
|
+
const matches = namespaces.filter((item) => identifier(item.name) === identifier(name) ||
|
|
181
|
+
(item.name.includes("__") &&
|
|
182
|
+
identifier(item.name.slice(item.name.lastIndexOf("__") + 2)) ===
|
|
183
|
+
identifier(name)));
|
|
184
|
+
if (matches.length > 1)
|
|
185
|
+
throw new Error("Ambiguous namespace; use its full alias.");
|
|
186
|
+
return matches[0];
|
|
187
|
+
}
|
|
188
|
+
return {
|
|
189
|
+
allTools,
|
|
190
|
+
searchTools(query, options) {
|
|
191
|
+
const parsed = searchSchema.parse({ query, options });
|
|
192
|
+
const queryTerms = [...new Set(terms(parsed.query))].slice(0, 32);
|
|
193
|
+
if (!queryTerms.length)
|
|
194
|
+
return [];
|
|
195
|
+
const namespace = parsed.options?.namespace
|
|
196
|
+
? resolveNamespace(parsed.options.namespace)
|
|
197
|
+
: undefined;
|
|
198
|
+
const candidates = parsed.options?.namespace
|
|
199
|
+
? documents.filter((doc) => doc.entry.namespace === namespace?.name)
|
|
200
|
+
: documents;
|
|
201
|
+
if (!candidates.length)
|
|
202
|
+
return [];
|
|
203
|
+
const average = candidates.reduce((sum, doc) => sum + doc.length, 0) /
|
|
204
|
+
candidates.length || 1;
|
|
205
|
+
const weights = new Map(queryTerms.map((term) => {
|
|
206
|
+
const frequency = candidates.filter((doc) => doc.frequencies.has(term)).length;
|
|
207
|
+
return [
|
|
208
|
+
term,
|
|
209
|
+
Math.log(1 + (candidates.length - frequency + 0.5) / (frequency + 0.5)),
|
|
210
|
+
];
|
|
211
|
+
}));
|
|
212
|
+
const ranked = candidates
|
|
213
|
+
.map((doc) => ({
|
|
214
|
+
doc,
|
|
215
|
+
score: queryTerms.reduce((score, term) => {
|
|
216
|
+
const tf = doc.frequencies.get(term) ?? 0;
|
|
217
|
+
return (score +
|
|
218
|
+
((weights.get(term) ?? 0) * tf * 2.2) /
|
|
219
|
+
(tf + 1.2 * (0.25 + (0.75 * doc.length) / average)));
|
|
220
|
+
}, 0),
|
|
221
|
+
}))
|
|
222
|
+
.filter((item) => item.score > 0)
|
|
223
|
+
.sort((a, b) => b.score - a.score);
|
|
224
|
+
const results = [];
|
|
225
|
+
for (const { doc } of ranked.slice(0, Math.min(parsed.options?.limit ?? 8, 20))) {
|
|
226
|
+
const next = summary(doc.entry);
|
|
227
|
+
if (bytes([...results, next]) > 32 * 1024)
|
|
228
|
+
break;
|
|
229
|
+
results.push(next);
|
|
230
|
+
}
|
|
231
|
+
return results;
|
|
232
|
+
},
|
|
233
|
+
describeTool(name) {
|
|
234
|
+
nameSchema.parse(name);
|
|
235
|
+
const entry = catalog.find((item) => item.name === name);
|
|
236
|
+
if (!entry)
|
|
237
|
+
return undefined;
|
|
238
|
+
const detail = `${summary(entry).description}\nInput JSON Schema: ${JSON.stringify(entry.inputSchema)}${entry.outputSchema === undefined ? "" : `\nOutput JSON Schema: ${JSON.stringify(entry.outputSchema)}`}${entry.structuredContentSchema === undefined ? "" : `\nMCP structuredContent JSON Schema: ${JSON.stringify(entry.structuredContentSchema)}`}`;
|
|
239
|
+
if (bytes(detail) > 64 * 1024)
|
|
240
|
+
throw new Error("Tool description exceeds the 64 KiB discovery budget; use searchTools for its bounded declaration.");
|
|
241
|
+
return detail;
|
|
242
|
+
},
|
|
243
|
+
describeNamespace(name) {
|
|
244
|
+
nameSchema.parse(name);
|
|
245
|
+
const namespace = resolveNamespace(name);
|
|
246
|
+
if (!namespace)
|
|
247
|
+
return undefined;
|
|
248
|
+
const result = {
|
|
249
|
+
...namespace,
|
|
250
|
+
tools: catalog
|
|
251
|
+
.filter((entry) => entry.namespace === namespace.name)
|
|
252
|
+
.map((entry) => entry.name),
|
|
253
|
+
};
|
|
254
|
+
if (bytes(result) > 32 * 1024)
|
|
255
|
+
throw new Error("Namespace exceeds the 32 KiB discovery budget; use searchTools with its full namespace.");
|
|
256
|
+
return result;
|
|
257
|
+
},
|
|
258
|
+
};
|
|
259
|
+
}
|