@botbotgo/agent-harness 0.0.101 → 0.0.102
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/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/persistence/sqlite-run-context-store.d.ts +22 -0
- package/dist/persistence/sqlite-run-context-store.js +64 -0
- package/dist/persistence/sqlite-run-queue-store.d.ts +41 -0
- package/dist/persistence/sqlite-run-queue-store.js +120 -0
- package/dist/persistence/sqlite-store.d.ts +2 -2
- package/dist/persistence/sqlite-store.js +31 -117
- package/dist/resource/mcp-tool-support.d.ts +21 -0
- package/dist/resource/mcp-tool-support.js +173 -0
- package/dist/resource/resource-impl.d.ts +1 -18
- package/dist/resource/resource-impl.js +3 -166
- package/dist/runtime/adapter/invoke-runtime.d.ts +22 -0
- package/dist/runtime/adapter/invoke-runtime.js +18 -0
- package/dist/runtime/adapter/stream-runtime.d.ts +46 -0
- package/dist/runtime/adapter/stream-runtime.js +93 -0
- package/dist/runtime/agent-runtime-adapter.js +93 -168
- package/dist/runtime/harness/run/run-operations.d.ts +50 -0
- package/dist/runtime/harness/run/run-operations.js +113 -0
- package/dist/runtime/harness/run/run-slot-acquisition.d.ts +64 -0
- package/dist/runtime/harness/run/run-slot-acquisition.js +157 -0
- package/dist/runtime/harness/run/stream-run.d.ts +53 -0
- package/dist/runtime/harness/run/stream-run.js +304 -0
- package/dist/runtime/harness.js +79 -528
- package/dist/workspace/object-loader.d.ts +1 -8
- package/dist/workspace/object-loader.js +3 -197
- package/dist/workspace/yaml-object-reader.d.ts +15 -0
- package/dist/workspace/yaml-object-reader.js +202 -0
- package/package.json +1 -1
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
|
+
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
|
3
|
+
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
4
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
5
|
+
import { WebSocketClientTransport } from "@modelcontextprotocol/sdk/client/websocket.js";
|
|
6
|
+
import { AGENT_HARNESS_VERSION } from "../package-version.js";
|
|
7
|
+
import { createRuntimeEnv } from "../runtime/support/runtime-env.js";
|
|
8
|
+
const mcpClientCache = new Map();
|
|
9
|
+
function readStringRecord(value) {
|
|
10
|
+
if (typeof value !== "object" || !value) {
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
const entries = Object.entries(value).filter((entry) => typeof entry[1] === "string");
|
|
14
|
+
return entries.length > 0 ? Object.fromEntries(entries) : undefined;
|
|
15
|
+
}
|
|
16
|
+
function normalizeMcpTransport(value) {
|
|
17
|
+
if (value === "stdio" || value === "http" || value === "sse" || value === "websocket") {
|
|
18
|
+
return value;
|
|
19
|
+
}
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
export function readMcpServerConfig(workspace, tool) {
|
|
23
|
+
const mcpConfig = typeof tool.config?.mcp === "object" && tool.config?.mcp
|
|
24
|
+
? tool.config.mcp
|
|
25
|
+
: undefined;
|
|
26
|
+
const serverRef = typeof mcpConfig?.serverRef === "string" ? mcpConfig.serverRef : undefined;
|
|
27
|
+
if (serverRef) {
|
|
28
|
+
const serverId = serverRef.startsWith("mcp/") ? serverRef.slice(4) : serverRef;
|
|
29
|
+
const server = workspace.mcpServers.get(serverId);
|
|
30
|
+
if (!server) {
|
|
31
|
+
throw new Error(`MCP tool ${tool.id} references missing MCP server ${serverRef}`);
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
transport: server.transport,
|
|
35
|
+
command: server.command,
|
|
36
|
+
args: server.args,
|
|
37
|
+
env: server.env,
|
|
38
|
+
cwd: server.cwd,
|
|
39
|
+
url: server.url,
|
|
40
|
+
token: server.token,
|
|
41
|
+
headers: server.headers,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
const config = typeof tool.config === "object" && tool.config
|
|
45
|
+
? tool.config
|
|
46
|
+
: undefined;
|
|
47
|
+
const mcpServer = typeof config?.mcpServer === "object" && config.mcpServer
|
|
48
|
+
? config.mcpServer
|
|
49
|
+
: config;
|
|
50
|
+
if (!mcpServer) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
transport: normalizeMcpTransport(mcpServer.transport) ?? ((typeof mcpServer.url === "string" && mcpServer.url.trim()) ? "http" : "stdio"),
|
|
55
|
+
command: typeof mcpServer.command === "string" ? mcpServer.command.trim() : undefined,
|
|
56
|
+
args: Array.isArray(mcpServer.args) ? mcpServer.args.filter((item) => typeof item === "string") : undefined,
|
|
57
|
+
env: readStringRecord(mcpServer.env),
|
|
58
|
+
cwd: typeof mcpServer.cwd === "string" ? mcpServer.cwd : undefined,
|
|
59
|
+
url: typeof mcpServer.url === "string" ? mcpServer.url.trim() : undefined,
|
|
60
|
+
token: typeof mcpServer.token === "string" ? mcpServer.token : undefined,
|
|
61
|
+
headers: readStringRecord(mcpServer.headers),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function createMcpCacheKey(config) {
|
|
65
|
+
return JSON.stringify({
|
|
66
|
+
transport: config.transport ?? "stdio",
|
|
67
|
+
command: config.command,
|
|
68
|
+
args: config.args ?? [],
|
|
69
|
+
env: config.env ?? {},
|
|
70
|
+
cwd: config.cwd ?? "",
|
|
71
|
+
url: config.url ?? "",
|
|
72
|
+
token: config.token ?? "",
|
|
73
|
+
headers: config.headers ?? {},
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
export async function getOrCreateMcpClient(config) {
|
|
77
|
+
const cacheKey = createMcpCacheKey(config);
|
|
78
|
+
const cached = mcpClientCache.get(cacheKey);
|
|
79
|
+
if (cached) {
|
|
80
|
+
return cached;
|
|
81
|
+
}
|
|
82
|
+
const loading = (async () => {
|
|
83
|
+
const client = new Client({
|
|
84
|
+
name: "agent-harness",
|
|
85
|
+
version: AGENT_HARNESS_VERSION,
|
|
86
|
+
});
|
|
87
|
+
const headers = {
|
|
88
|
+
...(config.headers ?? {}),
|
|
89
|
+
...(config.token ? { Authorization: `Bearer ${config.token}` } : {}),
|
|
90
|
+
};
|
|
91
|
+
const transport = config.transport === "http"
|
|
92
|
+
? new StreamableHTTPClientTransport(new URL(config.url ?? ""), {
|
|
93
|
+
requestInit: Object.keys(headers).length > 0 ? { headers } : undefined,
|
|
94
|
+
})
|
|
95
|
+
: config.transport === "sse"
|
|
96
|
+
? new SSEClientTransport(new URL(config.url ?? ""), {
|
|
97
|
+
requestInit: Object.keys(headers).length > 0 ? { headers } : undefined,
|
|
98
|
+
})
|
|
99
|
+
: config.transport === "websocket"
|
|
100
|
+
? new WebSocketClientTransport(new URL(config.url ?? ""))
|
|
101
|
+
: new StdioClientTransport({
|
|
102
|
+
command: config.command ?? "",
|
|
103
|
+
args: config.args,
|
|
104
|
+
env: createRuntimeEnv(config.env),
|
|
105
|
+
cwd: config.cwd,
|
|
106
|
+
});
|
|
107
|
+
await client.connect(transport);
|
|
108
|
+
return client;
|
|
109
|
+
})();
|
|
110
|
+
mcpClientCache.set(cacheKey, loading);
|
|
111
|
+
return loading;
|
|
112
|
+
}
|
|
113
|
+
async function getRemoteMcpToolDescriptor(config, remoteToolName) {
|
|
114
|
+
const client = await getOrCreateMcpClient(config);
|
|
115
|
+
const result = await client.listTools();
|
|
116
|
+
const tool = result.tools.find((item) => typeof item.name === "string" && item.name === remoteToolName);
|
|
117
|
+
if (!tool || typeof tool.name !== "string") {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
name: tool.name,
|
|
122
|
+
description: typeof tool.description === "string" ? tool.description : undefined,
|
|
123
|
+
inputSchema: typeof tool.inputSchema === "object" && tool.inputSchema ? tool.inputSchema : undefined,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
export async function listRemoteMcpTools(config) {
|
|
127
|
+
const client = await getOrCreateMcpClient(config);
|
|
128
|
+
const result = await client.listTools();
|
|
129
|
+
return result.tools
|
|
130
|
+
.filter((tool) => typeof tool.name === "string")
|
|
131
|
+
.map((tool) => ({
|
|
132
|
+
name: tool.name,
|
|
133
|
+
description: typeof tool.description === "string" ? tool.description : undefined,
|
|
134
|
+
inputSchema: typeof tool.inputSchema === "object" && tool.inputSchema ? tool.inputSchema : undefined,
|
|
135
|
+
}));
|
|
136
|
+
}
|
|
137
|
+
export function createMcpToolResolver(workspace) {
|
|
138
|
+
const mcpTools = new Map(Array.from(workspace.tools.values())
|
|
139
|
+
.filter((tool) => tool.type === "mcp")
|
|
140
|
+
.map((tool) => [tool.id, tool]));
|
|
141
|
+
return (toolIds) => toolIds.flatMap((toolId) => {
|
|
142
|
+
const tool = mcpTools.get(toolId);
|
|
143
|
+
if (!tool) {
|
|
144
|
+
return [];
|
|
145
|
+
}
|
|
146
|
+
const serverConfig = readMcpServerConfig(workspace, tool);
|
|
147
|
+
if (!serverConfig) {
|
|
148
|
+
throw new Error(`MCP tool ${tool.id} must define mcp.serverRef or inline MCP server config.`);
|
|
149
|
+
}
|
|
150
|
+
const remoteToolName = tool.mcpRef ?? tool.name;
|
|
151
|
+
const descriptorPromise = getRemoteMcpToolDescriptor(serverConfig, remoteToolName);
|
|
152
|
+
return [
|
|
153
|
+
{
|
|
154
|
+
name: tool.name,
|
|
155
|
+
description: tool.description,
|
|
156
|
+
inputSchemaPromise: descriptorPromise.then((descriptor) => descriptor?.inputSchema),
|
|
157
|
+
async invoke(input) {
|
|
158
|
+
const client = await getOrCreateMcpClient(serverConfig);
|
|
159
|
+
const result = await client.callTool({
|
|
160
|
+
name: remoteToolName,
|
|
161
|
+
arguments: typeof input === "object" && input !== null ? input : {},
|
|
162
|
+
});
|
|
163
|
+
const textParts = Array.isArray(result.content)
|
|
164
|
+
? result.content
|
|
165
|
+
.filter((item) => typeof item === "object" && item !== null && "type" in item)
|
|
166
|
+
.flatMap((item) => item.type === "text" && typeof item.text === "string" ? [item.text] : [])
|
|
167
|
+
: [];
|
|
168
|
+
return textParts.length > 0 ? textParts.join("\n\n") : JSON.stringify(result);
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
];
|
|
172
|
+
});
|
|
173
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
1
|
import type { RuntimeAdapterOptions, WorkspaceBundle } from "../contracts/types.js";
|
|
2
|
+
export { getOrCreateMcpClient, listRemoteMcpTools, readMcpServerConfig, type McpServerConfig, type McpToolDescriptor, } from "./mcp-tool-support.js";
|
|
3
3
|
export declare function resolveLocalResourceProviderEntry(currentResourceDir: string, resolveInstalledEntry?: () => string | null): string;
|
|
4
4
|
export type ResourceToolInfo = {
|
|
5
5
|
toolPath: string;
|
|
@@ -12,23 +12,6 @@ export type ResourceToolInfo = {
|
|
|
12
12
|
allow: Array<"approve" | "edit" | "reject">;
|
|
13
13
|
};
|
|
14
14
|
};
|
|
15
|
-
export type McpServerConfig = {
|
|
16
|
-
transport?: "stdio" | "http" | "sse" | "websocket";
|
|
17
|
-
command?: string;
|
|
18
|
-
args?: string[];
|
|
19
|
-
env?: Record<string, string>;
|
|
20
|
-
cwd?: string;
|
|
21
|
-
url?: string;
|
|
22
|
-
token?: string;
|
|
23
|
-
headers?: Record<string, string>;
|
|
24
|
-
};
|
|
25
|
-
export type McpToolDescriptor = {
|
|
26
|
-
name: string;
|
|
27
|
-
description?: string;
|
|
28
|
-
inputSchema?: Record<string, unknown>;
|
|
29
|
-
};
|
|
30
|
-
export declare function getOrCreateMcpClient(config: McpServerConfig): Promise<Client>;
|
|
31
|
-
export declare function listRemoteMcpTools(config: McpServerConfig): Promise<McpToolDescriptor[]>;
|
|
32
15
|
export declare function ensureResourceSources(sources?: string[], workspaceRoot?: string): Promise<void>;
|
|
33
16
|
export declare function defaultResourceSkillsRoot(): string;
|
|
34
17
|
export declare function defaultResourceConfigRoot(): string;
|
|
@@ -5,16 +5,12 @@ import { stat } from "node:fs/promises";
|
|
|
5
5
|
import { readFile } from "node:fs/promises";
|
|
6
6
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
7
7
|
import { CompositeBackend, LocalShellBackend, StateBackend, StoreBackend } from "deepagents";
|
|
8
|
-
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
9
|
-
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
|
10
|
-
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
11
|
-
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
12
|
-
import { WebSocketClientTransport } from "@modelcontextprotocol/sdk/client/websocket.js";
|
|
13
|
-
import { AGENT_HARNESS_VERSION } from "../package-version.js";
|
|
14
|
-
import { isSupportedToolModulePath, loadToolModuleDefinition } from "../tool-modules.js";
|
|
15
8
|
import { createRuntimeEnv } from "../runtime/support/runtime-env.js";
|
|
9
|
+
import { isSupportedToolModulePath, loadToolModuleDefinition } from "../tool-modules.js";
|
|
10
|
+
import { createMcpToolResolver, } from "./mcp-tool-support.js";
|
|
16
11
|
import { resolveIsolatedResourceModulePath } from "./isolation.js";
|
|
17
12
|
import { ensureExternalResourceSource, ensureExternalSource, isExternalSourceLocator, parseExternalSourceLocator } from "./sources.js";
|
|
13
|
+
export { getOrCreateMcpClient, listRemoteMcpTools, readMcpServerConfig, } from "./mcp-tool-support.js";
|
|
18
14
|
const resourceDir = path.dirname(fileURLToPath(import.meta.url));
|
|
19
15
|
const require = createRequire(import.meta.url);
|
|
20
16
|
function installedResourceProviderEntry() {
|
|
@@ -237,7 +233,6 @@ async function findPackageRoot(startPath) {
|
|
|
237
233
|
}
|
|
238
234
|
}
|
|
239
235
|
const functionToolModuleCache = new Map();
|
|
240
|
-
const mcpClientCache = new Map();
|
|
241
236
|
function readStringRecord(value) {
|
|
242
237
|
if (typeof value !== "object" || !value) {
|
|
243
238
|
return undefined;
|
|
@@ -272,127 +267,6 @@ async function loadFunctionToolModule(tool) {
|
|
|
272
267
|
functionToolModuleCache.set(cacheKey, loading);
|
|
273
268
|
return loading;
|
|
274
269
|
}
|
|
275
|
-
function normalizeMcpTransport(value) {
|
|
276
|
-
if (value === "stdio" || value === "http" || value === "sse" || value === "websocket") {
|
|
277
|
-
return value;
|
|
278
|
-
}
|
|
279
|
-
return undefined;
|
|
280
|
-
}
|
|
281
|
-
function readMcpServerConfig(workspace, tool) {
|
|
282
|
-
const mcpConfig = typeof tool.config?.mcp === "object" && tool.config?.mcp
|
|
283
|
-
? tool.config.mcp
|
|
284
|
-
: undefined;
|
|
285
|
-
const serverRef = typeof mcpConfig?.serverRef === "string" ? mcpConfig.serverRef : undefined;
|
|
286
|
-
if (serverRef) {
|
|
287
|
-
const serverId = serverRef.startsWith("mcp/") ? serverRef.slice(4) : serverRef;
|
|
288
|
-
const server = workspace.mcpServers.get(serverId);
|
|
289
|
-
if (!server) {
|
|
290
|
-
throw new Error(`MCP tool ${tool.id} references missing MCP server ${serverRef}`);
|
|
291
|
-
}
|
|
292
|
-
return {
|
|
293
|
-
transport: server.transport,
|
|
294
|
-
command: server.command,
|
|
295
|
-
args: server.args,
|
|
296
|
-
env: server.env,
|
|
297
|
-
cwd: server.cwd,
|
|
298
|
-
url: server.url,
|
|
299
|
-
token: server.token,
|
|
300
|
-
headers: server.headers,
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
const config = typeof tool.config === "object" && tool.config
|
|
304
|
-
? tool.config
|
|
305
|
-
: undefined;
|
|
306
|
-
const mcpServer = typeof config?.mcpServer === "object" && config.mcpServer
|
|
307
|
-
? config.mcpServer
|
|
308
|
-
: config;
|
|
309
|
-
if (!mcpServer) {
|
|
310
|
-
return null;
|
|
311
|
-
}
|
|
312
|
-
return {
|
|
313
|
-
transport: normalizeMcpTransport(mcpServer.transport) ?? ((typeof mcpServer.url === "string" && mcpServer.url.trim()) ? "http" : "stdio"),
|
|
314
|
-
command: typeof mcpServer.command === "string" ? mcpServer.command.trim() : undefined,
|
|
315
|
-
args: Array.isArray(mcpServer.args) ? mcpServer.args.filter((item) => typeof item === "string") : undefined,
|
|
316
|
-
env: readStringRecord(mcpServer.env),
|
|
317
|
-
cwd: typeof mcpServer.cwd === "string" ? mcpServer.cwd : undefined,
|
|
318
|
-
url: typeof mcpServer.url === "string" ? mcpServer.url.trim() : undefined,
|
|
319
|
-
token: typeof mcpServer.token === "string" ? mcpServer.token : undefined,
|
|
320
|
-
headers: readStringRecord(mcpServer.headers),
|
|
321
|
-
};
|
|
322
|
-
}
|
|
323
|
-
function createMcpCacheKey(config) {
|
|
324
|
-
return JSON.stringify({
|
|
325
|
-
transport: config.transport ?? "stdio",
|
|
326
|
-
command: config.command,
|
|
327
|
-
args: config.args ?? [],
|
|
328
|
-
env: config.env ?? {},
|
|
329
|
-
cwd: config.cwd ?? "",
|
|
330
|
-
url: config.url ?? "",
|
|
331
|
-
token: config.token ?? "",
|
|
332
|
-
headers: config.headers ?? {},
|
|
333
|
-
});
|
|
334
|
-
}
|
|
335
|
-
export async function getOrCreateMcpClient(config) {
|
|
336
|
-
const cacheKey = createMcpCacheKey(config);
|
|
337
|
-
const cached = mcpClientCache.get(cacheKey);
|
|
338
|
-
if (cached) {
|
|
339
|
-
return cached;
|
|
340
|
-
}
|
|
341
|
-
const loading = (async () => {
|
|
342
|
-
const client = new Client({
|
|
343
|
-
name: "agent-harness",
|
|
344
|
-
version: AGENT_HARNESS_VERSION,
|
|
345
|
-
});
|
|
346
|
-
const headers = {
|
|
347
|
-
...(config.headers ?? {}),
|
|
348
|
-
...(config.token ? { Authorization: `Bearer ${config.token}` } : {}),
|
|
349
|
-
};
|
|
350
|
-
const transport = config.transport === "http"
|
|
351
|
-
? new StreamableHTTPClientTransport(new URL(config.url ?? ""), {
|
|
352
|
-
requestInit: Object.keys(headers).length > 0 ? { headers } : undefined,
|
|
353
|
-
})
|
|
354
|
-
: config.transport === "sse"
|
|
355
|
-
? new SSEClientTransport(new URL(config.url ?? ""), {
|
|
356
|
-
requestInit: Object.keys(headers).length > 0 ? { headers } : undefined,
|
|
357
|
-
})
|
|
358
|
-
: config.transport === "websocket"
|
|
359
|
-
? new WebSocketClientTransport(new URL(config.url ?? ""))
|
|
360
|
-
: new StdioClientTransport({
|
|
361
|
-
command: config.command ?? "",
|
|
362
|
-
args: config.args,
|
|
363
|
-
env: createRuntimeEnv(config.env),
|
|
364
|
-
cwd: config.cwd,
|
|
365
|
-
});
|
|
366
|
-
await client.connect(transport);
|
|
367
|
-
return client;
|
|
368
|
-
})();
|
|
369
|
-
mcpClientCache.set(cacheKey, loading);
|
|
370
|
-
return loading;
|
|
371
|
-
}
|
|
372
|
-
async function getRemoteMcpToolDescriptor(config, remoteToolName) {
|
|
373
|
-
const client = await getOrCreateMcpClient(config);
|
|
374
|
-
const result = await client.listTools();
|
|
375
|
-
const tool = result.tools.find((item) => typeof item.name === "string" && item.name === remoteToolName);
|
|
376
|
-
if (!tool || typeof tool.name !== "string") {
|
|
377
|
-
return null;
|
|
378
|
-
}
|
|
379
|
-
return {
|
|
380
|
-
name: tool.name,
|
|
381
|
-
description: typeof tool.description === "string" ? tool.description : undefined,
|
|
382
|
-
inputSchema: typeof tool.inputSchema === "object" && tool.inputSchema ? tool.inputSchema : undefined,
|
|
383
|
-
};
|
|
384
|
-
}
|
|
385
|
-
export async function listRemoteMcpTools(config) {
|
|
386
|
-
const client = await getOrCreateMcpClient(config);
|
|
387
|
-
const result = await client.listTools();
|
|
388
|
-
return result.tools
|
|
389
|
-
.filter((tool) => typeof tool.name === "string")
|
|
390
|
-
.map((tool) => ({
|
|
391
|
-
name: tool.name,
|
|
392
|
-
description: typeof tool.description === "string" ? tool.description : undefined,
|
|
393
|
-
inputSchema: typeof tool.inputSchema === "object" && tool.inputSchema ? tool.inputSchema : undefined,
|
|
394
|
-
}));
|
|
395
|
-
}
|
|
396
270
|
function createFunctionToolResolver(workspace) {
|
|
397
271
|
const functionTools = new Map(Array.from(workspace.tools.values())
|
|
398
272
|
.filter((tool) => tool.type === "function" && isSupportedToolModulePath(tool.sourcePath))
|
|
@@ -421,43 +295,6 @@ function createFunctionToolResolver(workspace) {
|
|
|
421
295
|
];
|
|
422
296
|
});
|
|
423
297
|
}
|
|
424
|
-
function createMcpToolResolver(workspace) {
|
|
425
|
-
const mcpTools = new Map(Array.from(workspace.tools.values())
|
|
426
|
-
.filter((tool) => tool.type === "mcp")
|
|
427
|
-
.map((tool) => [tool.id, tool]));
|
|
428
|
-
return (toolIds) => toolIds.flatMap((toolId) => {
|
|
429
|
-
const tool = mcpTools.get(toolId);
|
|
430
|
-
if (!tool) {
|
|
431
|
-
return [];
|
|
432
|
-
}
|
|
433
|
-
const serverConfig = readMcpServerConfig(workspace, tool);
|
|
434
|
-
if (!serverConfig) {
|
|
435
|
-
throw new Error(`MCP tool ${tool.id} must define mcp.serverRef or inline MCP server config.`);
|
|
436
|
-
}
|
|
437
|
-
const remoteToolName = tool.mcpRef ?? tool.name;
|
|
438
|
-
const descriptorPromise = getRemoteMcpToolDescriptor(serverConfig, remoteToolName);
|
|
439
|
-
return [
|
|
440
|
-
{
|
|
441
|
-
name: tool.name,
|
|
442
|
-
description: tool.description,
|
|
443
|
-
inputSchemaPromise: descriptorPromise.then((descriptor) => descriptor?.inputSchema),
|
|
444
|
-
async invoke(input) {
|
|
445
|
-
const client = await getOrCreateMcpClient(serverConfig);
|
|
446
|
-
const result = await client.callTool({
|
|
447
|
-
name: remoteToolName,
|
|
448
|
-
arguments: typeof input === "object" && input !== null ? input : {},
|
|
449
|
-
});
|
|
450
|
-
const textParts = Array.isArray(result.content)
|
|
451
|
-
? result.content
|
|
452
|
-
.filter((item) => typeof item === "object" && item !== null && "type" in item)
|
|
453
|
-
.flatMap((item) => item.type === "text" && typeof item.text === "string" ? [item.text] : [])
|
|
454
|
-
: [];
|
|
455
|
-
return textParts.length > 0 ? textParts.join("\n\n") : JSON.stringify(result);
|
|
456
|
-
},
|
|
457
|
-
},
|
|
458
|
-
];
|
|
459
|
-
});
|
|
460
|
-
}
|
|
461
298
|
function resolvePackageEntry(packageRoot, pkg) {
|
|
462
299
|
const exportsField = pkg.exports;
|
|
463
300
|
if (typeof exportsField === "string") {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { CompiledAgentBinding, CompiledTool } from "../../contracts/types.js";
|
|
2
|
+
import type { ExecutedToolResult } from "./invocation-result.js";
|
|
3
|
+
import type { ToolNameMapping } from "./tool/tool-name-mapping.js";
|
|
4
|
+
export type ExecutableTool = {
|
|
5
|
+
name: string;
|
|
6
|
+
schema: unknown;
|
|
7
|
+
invoke: (input: unknown) => Promise<unknown>;
|
|
8
|
+
};
|
|
9
|
+
export declare function invokeRuntimeWithLocalTools(options: {
|
|
10
|
+
binding: CompiledAgentBinding;
|
|
11
|
+
request: unknown;
|
|
12
|
+
resumePayload?: unknown;
|
|
13
|
+
primaryTools: CompiledTool[];
|
|
14
|
+
defersToUpstreamHitlExecution: boolean;
|
|
15
|
+
toolNameMapping: ToolNameMapping;
|
|
16
|
+
executableTools: Map<string, ExecutableTool>;
|
|
17
|
+
builtinExecutableTools: Map<string, ExecutableTool>;
|
|
18
|
+
callRuntimeWithToolParseRecovery: (request: unknown) => Promise<Record<string, unknown>>;
|
|
19
|
+
}): Promise<{
|
|
20
|
+
result: Record<string, unknown>;
|
|
21
|
+
executedToolResults: ExecutedToolResult[];
|
|
22
|
+
}>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { runLocalToolInvocationLoop } from "./local-tool-invocation.js";
|
|
2
|
+
export async function invokeRuntimeWithLocalTools(options) {
|
|
3
|
+
if (options.resumePayload !== undefined || options.defersToUpstreamHitlExecution) {
|
|
4
|
+
return {
|
|
5
|
+
result: await options.callRuntimeWithToolParseRecovery(options.request),
|
|
6
|
+
executedToolResults: [],
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
return runLocalToolInvocationLoop({
|
|
10
|
+
binding: options.binding,
|
|
11
|
+
request: options.request,
|
|
12
|
+
primaryTools: options.primaryTools,
|
|
13
|
+
toolNameMapping: options.toolNameMapping,
|
|
14
|
+
executableTools: options.executableTools,
|
|
15
|
+
builtinExecutableTools: options.builtinExecutableTools,
|
|
16
|
+
callRuntimeWithToolParseRecovery: options.callRuntimeWithToolParseRecovery,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { CompiledAgentBinding, CompiledTool, MessageContent, TranscriptMessage } from "../../contracts/types.js";
|
|
2
|
+
import type { RuntimeStreamChunk } from "../parsing/stream-event-parsing.js";
|
|
3
|
+
import type { ToolNameMapping } from "./tool/tool-name-mapping.js";
|
|
4
|
+
type RunnableLike = {
|
|
5
|
+
stream?: (input: unknown, config?: Record<string, unknown>) => Promise<AsyncIterable<unknown>>;
|
|
6
|
+
streamEvents?: (input: unknown, config?: Record<string, unknown>) => Promise<AsyncIterable<unknown>>;
|
|
7
|
+
};
|
|
8
|
+
export declare function streamRuntimeExecution(options: {
|
|
9
|
+
binding: CompiledAgentBinding;
|
|
10
|
+
input: MessageContent;
|
|
11
|
+
threadId: string;
|
|
12
|
+
history: TranscriptMessage[];
|
|
13
|
+
runtimeOptions: {
|
|
14
|
+
context?: Record<string, unknown>;
|
|
15
|
+
state?: Record<string, unknown>;
|
|
16
|
+
files?: Record<string, unknown>;
|
|
17
|
+
runId?: string;
|
|
18
|
+
};
|
|
19
|
+
primaryTools: CompiledTool[];
|
|
20
|
+
toolNameMapping: ToolNameMapping;
|
|
21
|
+
forceInvokeFallback: boolean;
|
|
22
|
+
canUseDirectModelStream: boolean;
|
|
23
|
+
langChainStreamModel?: {
|
|
24
|
+
stream?: (input: unknown) => Promise<AsyncIterable<unknown>>;
|
|
25
|
+
};
|
|
26
|
+
createRunnable: () => Promise<RunnableLike>;
|
|
27
|
+
withTimeout: <T>(producer: () => T | Promise<T>, timeoutMs: number | undefined, operation: string, stage?: "stream" | "invoke") => Promise<T>;
|
|
28
|
+
iterateWithTimeout: <T>(iterable: AsyncIterable<T>, timeoutMs: number | undefined, operation: string, deadlineAt?: number, deadlineTimeoutMs?: number) => AsyncGenerator<T>;
|
|
29
|
+
invokeTimeoutMs?: number;
|
|
30
|
+
streamIdleTimeoutMs?: number;
|
|
31
|
+
streamDeadlineAt?: number;
|
|
32
|
+
invoke: (binding: CompiledAgentBinding, input: MessageContent, threadId: string, runId: string, resumePayload?: unknown, history?: TranscriptMessage[], options?: {
|
|
33
|
+
context?: Record<string, unknown>;
|
|
34
|
+
state?: Record<string, unknown>;
|
|
35
|
+
files?: Record<string, unknown>;
|
|
36
|
+
}) => Promise<{
|
|
37
|
+
output: string;
|
|
38
|
+
metadata?: Record<string, unknown>;
|
|
39
|
+
}>;
|
|
40
|
+
applyStrictToolJsonInstruction: (binding: CompiledAgentBinding) => CompiledAgentBinding;
|
|
41
|
+
getSystemPrompt: (binding: CompiledAgentBinding) => string | undefined;
|
|
42
|
+
isLangChainBinding: (binding: CompiledAgentBinding) => boolean;
|
|
43
|
+
isDeepAgentBinding: (binding: CompiledAgentBinding) => boolean;
|
|
44
|
+
countConfiguredTools: (binding: CompiledAgentBinding) => number;
|
|
45
|
+
}): AsyncGenerator<RuntimeStreamChunk | string>;
|
|
46
|
+
export {};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { isToolCallParseFailure, sanitizeVisibleText, } from "../parsing/output-parsing.js";
|
|
2
|
+
import { buildInvocationRequest } from "./model/invocation-request.js";
|
|
3
|
+
import { buildRawModelMessages } from "./model/message-assembly.js";
|
|
4
|
+
import { projectRuntimeStreamEvent, createStreamEventProjectionState } from "./stream-event-projection.js";
|
|
5
|
+
import { projectTextStreamChunks } from "./stream-text-consumption.js";
|
|
6
|
+
import { computeRemainingTimeoutMs } from "./resilience.js";
|
|
7
|
+
export async function* streamRuntimeExecution(options) {
|
|
8
|
+
const request = buildInvocationRequest(options.binding, options.history, options.input, options.runtimeOptions);
|
|
9
|
+
try {
|
|
10
|
+
if (options.isLangChainBinding(options.binding) && options.canUseDirectModelStream && options.langChainStreamModel?.stream) {
|
|
11
|
+
const stream = await options.withTimeout(() => options.langChainStreamModel.stream(buildRawModelMessages(options.binding, options.getSystemPrompt(options.binding), options.history, options.input)), computeRemainingTimeoutMs(options.streamDeadlineAt, options.invokeTimeoutMs), "model stream start", "stream");
|
|
12
|
+
let emitted = false;
|
|
13
|
+
const projected = projectTextStreamChunks(options.iterateWithTimeout(stream, options.streamIdleTimeoutMs, "model stream", options.streamDeadlineAt, options.invokeTimeoutMs));
|
|
14
|
+
let nextChunk = await projected.next();
|
|
15
|
+
while (!nextChunk.done) {
|
|
16
|
+
if (nextChunk.value.kind === "content") {
|
|
17
|
+
emitted = true;
|
|
18
|
+
}
|
|
19
|
+
yield nextChunk.value;
|
|
20
|
+
nextChunk = await projected.next();
|
|
21
|
+
}
|
|
22
|
+
if (nextChunk.value.emittedContent || emitted) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const runnable = await options.createRunnable();
|
|
27
|
+
if (!options.forceInvokeFallback && typeof runnable.streamEvents === "function") {
|
|
28
|
+
const events = await options.withTimeout(() => runnable.streamEvents(request, { configurable: { thread_id: options.threadId, run_id: options.runtimeOptions.runId }, version: "v2", ...(options.runtimeOptions.context ? { context: options.runtimeOptions.context } : {}) }), computeRemainingTimeoutMs(options.streamDeadlineAt, options.invokeTimeoutMs), "agent streamEvents start", "stream");
|
|
29
|
+
const projectionState = createStreamEventProjectionState();
|
|
30
|
+
for await (const event of options.iterateWithTimeout(events, options.streamIdleTimeoutMs, "agent streamEvents", options.streamDeadlineAt, options.invokeTimeoutMs)) {
|
|
31
|
+
const projectedChunks = projectRuntimeStreamEvent({
|
|
32
|
+
event,
|
|
33
|
+
allowVisibleStreamDeltas: options.isLangChainBinding(options.binding),
|
|
34
|
+
includeStateStreamOutput: options.isDeepAgentBinding(options.binding),
|
|
35
|
+
toolNameMapping: options.toolNameMapping,
|
|
36
|
+
primaryTools: options.primaryTools,
|
|
37
|
+
state: projectionState,
|
|
38
|
+
});
|
|
39
|
+
for (const chunk of projectedChunks) {
|
|
40
|
+
yield chunk;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (projectionState.emittedOutput || projectionState.emittedToolResult || projectionState.emittedToolError) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (!options.forceInvokeFallback && options.isLangChainBinding(options.binding) && typeof runnable.stream === "function") {
|
|
48
|
+
const stream = await options.withTimeout(() => runnable.stream(request, { configurable: { thread_id: options.threadId, run_id: options.runtimeOptions.runId } }), computeRemainingTimeoutMs(options.streamDeadlineAt, options.invokeTimeoutMs), "agent stream start", "stream");
|
|
49
|
+
let emitted = false;
|
|
50
|
+
const projected = projectTextStreamChunks(options.iterateWithTimeout(stream, options.streamIdleTimeoutMs, "agent stream", options.streamDeadlineAt, options.invokeTimeoutMs));
|
|
51
|
+
let nextChunk = await projected.next();
|
|
52
|
+
while (!nextChunk.done) {
|
|
53
|
+
if (nextChunk.value.kind === "content") {
|
|
54
|
+
emitted = true;
|
|
55
|
+
}
|
|
56
|
+
yield nextChunk.value;
|
|
57
|
+
nextChunk = await projected.next();
|
|
58
|
+
}
|
|
59
|
+
if (nextChunk.value.emittedContent || emitted) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const result = await options.invoke(options.binding, options.input, options.threadId, options.runtimeOptions.runId ?? options.threadId, undefined, options.history, options.runtimeOptions);
|
|
64
|
+
const executedToolResults = Array.isArray(result.metadata?.executedToolResults)
|
|
65
|
+
? result.metadata.executedToolResults
|
|
66
|
+
: [];
|
|
67
|
+
for (const toolResult of executedToolResults) {
|
|
68
|
+
yield {
|
|
69
|
+
kind: "tool-result",
|
|
70
|
+
toolName: toolResult.toolName,
|
|
71
|
+
output: toolResult.output,
|
|
72
|
+
isError: toolResult.isError,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
if (result.output) {
|
|
76
|
+
yield { kind: "content", content: sanitizeVisibleText(result.output) };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
if (options.countConfiguredTools(options.binding) > 0 &&
|
|
81
|
+
error instanceof Error &&
|
|
82
|
+
error.message.includes("does not support tool binding")) {
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
if (!isToolCallParseFailure(error)) {
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
const retried = await options.invoke(options.applyStrictToolJsonInstruction(options.binding), options.input, options.threadId, options.runtimeOptions.runId ?? options.threadId, undefined, options.history, options.runtimeOptions);
|
|
89
|
+
if (retried.output) {
|
|
90
|
+
yield { kind: "content", content: sanitizeVisibleText(retried.output) };
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|