@botbotgo/agent-harness 0.0.100 → 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 +79 -240
- 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.d.ts +1 -12
- package/dist/runtime/agent-runtime-adapter.js +122 -312
- package/dist/runtime/harness/run/recovery.d.ts +42 -0
- package/dist/runtime/harness/run/recovery.js +139 -0
- 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.d.ts +2 -17
- package/dist/runtime/harness.js +157 -773
- package/dist/runtime/support/runtime-factories.js +2 -2
- package/dist/workspace/object-loader.d.ts +1 -8
- package/dist/workspace/object-loader.js +43 -275
- package/dist/workspace/yaml-object-reader.d.ts +15 -0
- package/dist/workspace/yaml-object-reader.js +202 -0
- package/package.json +1 -1
- package/dist/runtime/checkpoint-maintenance.d.ts +0 -1
- package/dist/runtime/checkpoint-maintenance.js +0 -1
- package/dist/runtime/file-checkpoint-saver.d.ts +0 -1
- package/dist/runtime/file-checkpoint-saver.js +0 -1
- package/dist/runtime/sqlite-maintained-checkpoint-saver.d.ts +0 -1
- package/dist/runtime/sqlite-maintained-checkpoint-saver.js +0 -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() {
|
|
@@ -81,13 +77,14 @@ function listProviderTools(provider) {
|
|
|
81
77
|
toolPath: tool.toolPath ?? tool.builtinPath ?? "",
|
|
82
78
|
}));
|
|
83
79
|
}
|
|
80
|
+
function preferProviderValue(provider, primary, fallback) {
|
|
81
|
+
return provider ? (primary(provider) ?? fallback(provider)) : undefined;
|
|
82
|
+
}
|
|
84
83
|
function createProviderToolResolver(provider, workspace, options) {
|
|
85
|
-
return (provider
|
|
86
|
-
provider?.createBuiltinToolResolver?.(workspace, options));
|
|
84
|
+
return preferProviderValue(provider, (candidate) => candidate.createResourceToolResolver?.(workspace, options), (candidate) => candidate.createBuiltinToolResolver?.(workspace, options));
|
|
87
85
|
}
|
|
88
86
|
function createProviderBackendResolver(provider, workspace) {
|
|
89
|
-
return (provider
|
|
90
|
-
provider?.createBuiltinBackendResolver?.(workspace));
|
|
87
|
+
return preferProviderValue(provider, (candidate) => candidate.createResourceBackendResolver?.(workspace), (candidate) => candidate.createBuiltinBackendResolver?.(workspace));
|
|
91
88
|
}
|
|
92
89
|
class CompatibleCompositeBackend {
|
|
93
90
|
id;
|
|
@@ -133,69 +130,66 @@ class CompatibleCompositeBackend {
|
|
|
133
130
|
return this.composite.downloadFiles(paths);
|
|
134
131
|
}
|
|
135
132
|
}
|
|
133
|
+
const INLINE_BACKEND_ERROR = 'Unsupported DeepAgent backend kind "%s". Supported inline kinds: LocalShellBackend, VfsSandbox, StateBackend, StoreBackend, CompositeBackend.';
|
|
134
|
+
function unsupportedInlineBackend(kind) {
|
|
135
|
+
throw new Error(INLINE_BACKEND_ERROR.replace("%s", kind));
|
|
136
|
+
}
|
|
137
|
+
function resolveInlineBackendRootDir(workspaceRoot, configuredRootDir) {
|
|
138
|
+
if (typeof configuredRootDir === "string" && configuredRootDir.trim().length > 0) {
|
|
139
|
+
return path.isAbsolute(configuredRootDir)
|
|
140
|
+
? configuredRootDir
|
|
141
|
+
: path.resolve(workspaceRoot, configuredRootDir);
|
|
142
|
+
}
|
|
143
|
+
return workspaceRoot;
|
|
144
|
+
}
|
|
145
|
+
function createLocalShellStyleBackend(workspaceRoot, config, options) {
|
|
146
|
+
const rootDir = resolveInlineBackendRootDir(workspaceRoot, config?.rootDir);
|
|
147
|
+
mkdirSync(rootDir, { recursive: true });
|
|
148
|
+
const inheritedEnv = config?.inheritEnv === false ? {} : process.env;
|
|
149
|
+
return new LocalShellBackend({
|
|
150
|
+
rootDir,
|
|
151
|
+
virtualMode: options.virtualMode,
|
|
152
|
+
timeout: typeof config?.timeout === "number" ? config.timeout : undefined,
|
|
153
|
+
maxOutputBytes: typeof config?.maxOutputBytes === "number" ? config.maxOutputBytes : undefined,
|
|
154
|
+
env: createRuntimeEnv(readStringRecord(config?.env), inheritedEnv),
|
|
155
|
+
inheritEnv: config?.inheritEnv !== false,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
function createInlineBackendInstance(workspaceRoot, kind, config, runtimeLike) {
|
|
159
|
+
switch (kind) {
|
|
160
|
+
case "LocalShellBackend":
|
|
161
|
+
return createLocalShellStyleBackend(workspaceRoot, config, {
|
|
162
|
+
virtualMode: config?.virtualMode === true,
|
|
163
|
+
});
|
|
164
|
+
case "VfsSandbox":
|
|
165
|
+
return createLocalShellStyleBackend(workspaceRoot, config, {
|
|
166
|
+
virtualMode: config?.virtualMode === false ? false : true,
|
|
167
|
+
});
|
|
168
|
+
case "StateBackend":
|
|
169
|
+
return new StateBackend(runtimeLike);
|
|
170
|
+
case "StoreBackend":
|
|
171
|
+
return new StoreBackend(runtimeLike);
|
|
172
|
+
default:
|
|
173
|
+
return unsupportedInlineBackend(kind);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
136
176
|
function createInlineBackendResolver(workspace) {
|
|
137
177
|
return (binding) => {
|
|
138
178
|
const backendConfig = binding.deepAgentParams?.backend;
|
|
139
179
|
if (!backendConfig || typeof backendConfig !== "object") {
|
|
140
180
|
return undefined;
|
|
141
181
|
}
|
|
142
|
-
const resolveBackendRootDir = (configuredRootDir) => {
|
|
143
|
-
if (typeof configuredRootDir === "string" && configuredRootDir.trim().length > 0) {
|
|
144
|
-
return path.isAbsolute(configuredRootDir)
|
|
145
|
-
? configuredRootDir
|
|
146
|
-
: path.resolve(workspace.workspaceRoot, configuredRootDir);
|
|
147
|
-
}
|
|
148
|
-
return workspace.workspaceRoot;
|
|
149
|
-
};
|
|
150
|
-
const createBackend = (kind, config, runtimeLike) => {
|
|
151
|
-
const configuredEnv = typeof config?.env === "object" && config.env
|
|
152
|
-
? Object.fromEntries(Object.entries(config.env).filter((entry) => typeof entry[1] === "string"))
|
|
153
|
-
: undefined;
|
|
154
|
-
const inheritedEnv = config?.inheritEnv === false ? {} : process.env;
|
|
155
|
-
switch (kind) {
|
|
156
|
-
case "LocalShellBackend": {
|
|
157
|
-
const rootDir = resolveBackendRootDir(config?.rootDir);
|
|
158
|
-
mkdirSync(rootDir, { recursive: true });
|
|
159
|
-
return new LocalShellBackend({
|
|
160
|
-
rootDir,
|
|
161
|
-
virtualMode: config?.virtualMode === true,
|
|
162
|
-
timeout: typeof config?.timeout === "number" ? config.timeout : undefined,
|
|
163
|
-
maxOutputBytes: typeof config?.maxOutputBytes === "number" ? config.maxOutputBytes : undefined,
|
|
164
|
-
env: createRuntimeEnv(configuredEnv, inheritedEnv),
|
|
165
|
-
inheritEnv: config?.inheritEnv !== false,
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
case "VfsSandbox": {
|
|
169
|
-
const rootDir = resolveBackendRootDir(config?.rootDir);
|
|
170
|
-
mkdirSync(rootDir, { recursive: true });
|
|
171
|
-
return new LocalShellBackend({
|
|
172
|
-
rootDir,
|
|
173
|
-
virtualMode: config?.virtualMode === false ? false : true,
|
|
174
|
-
timeout: typeof config?.timeout === "number" ? config.timeout : undefined,
|
|
175
|
-
maxOutputBytes: typeof config?.maxOutputBytes === "number" ? config.maxOutputBytes : undefined,
|
|
176
|
-
env: createRuntimeEnv(configuredEnv, inheritedEnv),
|
|
177
|
-
inheritEnv: config?.inheritEnv !== false,
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
case "StateBackend":
|
|
181
|
-
return new StateBackend(runtimeLike);
|
|
182
|
-
case "StoreBackend":
|
|
183
|
-
return new StoreBackend(runtimeLike);
|
|
184
|
-
default:
|
|
185
|
-
throw new Error(`Unsupported DeepAgent backend kind "${kind}". Supported inline kinds: LocalShellBackend, VfsSandbox, StateBackend, StoreBackend, CompositeBackend.`);
|
|
186
|
-
}
|
|
187
|
-
};
|
|
188
182
|
return (runtimeLike) => {
|
|
189
183
|
const kind = typeof backendConfig.kind === "string" ? backendConfig.kind : "CompositeBackend";
|
|
190
184
|
switch (kind) {
|
|
191
185
|
case "LocalShellBackend":
|
|
192
|
-
return
|
|
186
|
+
return createInlineBackendInstance(workspace.workspaceRoot, "LocalShellBackend", backendConfig, runtimeLike);
|
|
193
187
|
case "VfsSandbox":
|
|
194
|
-
return
|
|
188
|
+
return createInlineBackendInstance(workspace.workspaceRoot, "VfsSandbox", backendConfig, runtimeLike);
|
|
195
189
|
case "StateBackend":
|
|
196
|
-
return
|
|
190
|
+
return createInlineBackendInstance(workspace.workspaceRoot, "StateBackend", backendConfig, runtimeLike);
|
|
197
191
|
case "StoreBackend":
|
|
198
|
-
return
|
|
192
|
+
return createInlineBackendInstance(workspace.workspaceRoot, "StoreBackend", backendConfig, runtimeLike);
|
|
199
193
|
case "CompositeBackend": {
|
|
200
194
|
const stateConfig = typeof backendConfig.state === "object" && backendConfig.state
|
|
201
195
|
? backendConfig.state
|
|
@@ -206,12 +200,12 @@ function createInlineBackendResolver(workspace) {
|
|
|
206
200
|
: { "/memories/": { kind: "StoreBackend" } };
|
|
207
201
|
const mappedRoutes = Object.fromEntries(Object.entries(routes).map(([route, routeConfig]) => {
|
|
208
202
|
const routeKind = typeof routeConfig?.kind === "string" ? routeConfig.kind : "StoreBackend";
|
|
209
|
-
return [route,
|
|
203
|
+
return [route, createInlineBackendInstance(workspace.workspaceRoot, routeKind, routeConfig, runtimeLike)];
|
|
210
204
|
}));
|
|
211
|
-
return new CompatibleCompositeBackend(
|
|
205
|
+
return new CompatibleCompositeBackend(createInlineBackendInstance(workspace.workspaceRoot, defaultBackendKind, stateConfig, runtimeLike), mappedRoutes);
|
|
212
206
|
}
|
|
213
207
|
default:
|
|
214
|
-
|
|
208
|
+
return unsupportedInlineBackend(kind);
|
|
215
209
|
}
|
|
216
210
|
};
|
|
217
211
|
};
|
|
@@ -239,7 +233,23 @@ async function findPackageRoot(startPath) {
|
|
|
239
233
|
}
|
|
240
234
|
}
|
|
241
235
|
const functionToolModuleCache = new Map();
|
|
242
|
-
|
|
236
|
+
function readStringRecord(value) {
|
|
237
|
+
if (typeof value !== "object" || !value) {
|
|
238
|
+
return undefined;
|
|
239
|
+
}
|
|
240
|
+
const entries = Object.entries(value).filter((entry) => typeof entry[1] === "string");
|
|
241
|
+
return entries.length > 0 ? Object.fromEntries(entries) : undefined;
|
|
242
|
+
}
|
|
243
|
+
function listWorkspaceResourceProviders(workspace) {
|
|
244
|
+
return (workspace.resourceSources ?? [])
|
|
245
|
+
.map((source) => remoteResourceCache.get(source))
|
|
246
|
+
.filter((provider) => Boolean(provider));
|
|
247
|
+
}
|
|
248
|
+
function createWorkspaceProviderResolvers(workspace, factory) {
|
|
249
|
+
return listWorkspaceResourceProviders(workspace)
|
|
250
|
+
.map((provider) => factory(provider))
|
|
251
|
+
.filter((resolver) => Boolean(resolver));
|
|
252
|
+
}
|
|
243
253
|
async function loadFunctionToolModule(tool) {
|
|
244
254
|
const cacheKey = `${tool.sourcePath}:${tool.implementationName ?? tool.id}`;
|
|
245
255
|
const cached = functionToolModuleCache.get(cacheKey);
|
|
@@ -257,132 +267,6 @@ async function loadFunctionToolModule(tool) {
|
|
|
257
267
|
functionToolModuleCache.set(cacheKey, loading);
|
|
258
268
|
return loading;
|
|
259
269
|
}
|
|
260
|
-
function normalizeMcpTransport(value) {
|
|
261
|
-
if (value === "stdio" || value === "http" || value === "sse" || value === "websocket") {
|
|
262
|
-
return value;
|
|
263
|
-
}
|
|
264
|
-
return undefined;
|
|
265
|
-
}
|
|
266
|
-
function readMcpServerConfig(workspace, tool) {
|
|
267
|
-
const mcpConfig = typeof tool.config?.mcp === "object" && tool.config?.mcp
|
|
268
|
-
? tool.config.mcp
|
|
269
|
-
: undefined;
|
|
270
|
-
const serverRef = typeof mcpConfig?.serverRef === "string" ? mcpConfig.serverRef : undefined;
|
|
271
|
-
if (serverRef) {
|
|
272
|
-
const serverId = serverRef.startsWith("mcp/") ? serverRef.slice(4) : serverRef;
|
|
273
|
-
const server = workspace.mcpServers.get(serverId);
|
|
274
|
-
if (!server) {
|
|
275
|
-
throw new Error(`MCP tool ${tool.id} references missing MCP server ${serverRef}`);
|
|
276
|
-
}
|
|
277
|
-
return {
|
|
278
|
-
transport: server.transport,
|
|
279
|
-
command: server.command,
|
|
280
|
-
args: server.args,
|
|
281
|
-
env: server.env,
|
|
282
|
-
cwd: server.cwd,
|
|
283
|
-
url: server.url,
|
|
284
|
-
token: server.token,
|
|
285
|
-
headers: server.headers,
|
|
286
|
-
};
|
|
287
|
-
}
|
|
288
|
-
const config = typeof tool.config === "object" && tool.config
|
|
289
|
-
? tool.config
|
|
290
|
-
: undefined;
|
|
291
|
-
const mcpServer = typeof config?.mcpServer === "object" && config.mcpServer
|
|
292
|
-
? config.mcpServer
|
|
293
|
-
: config;
|
|
294
|
-
if (!mcpServer) {
|
|
295
|
-
return null;
|
|
296
|
-
}
|
|
297
|
-
const envRecord = typeof mcpServer.env === "object" && mcpServer.env
|
|
298
|
-
? Object.fromEntries(Object.entries(mcpServer.env).filter((entry) => typeof entry[1] === "string"))
|
|
299
|
-
: undefined;
|
|
300
|
-
return {
|
|
301
|
-
transport: normalizeMcpTransport(mcpServer.transport) ?? ((typeof mcpServer.url === "string" && mcpServer.url.trim()) ? "http" : "stdio"),
|
|
302
|
-
command: typeof mcpServer.command === "string" ? mcpServer.command.trim() : undefined,
|
|
303
|
-
args: Array.isArray(mcpServer.args) ? mcpServer.args.filter((item) => typeof item === "string") : undefined,
|
|
304
|
-
env: envRecord,
|
|
305
|
-
cwd: typeof mcpServer.cwd === "string" ? mcpServer.cwd : undefined,
|
|
306
|
-
url: typeof mcpServer.url === "string" ? mcpServer.url.trim() : undefined,
|
|
307
|
-
token: typeof mcpServer.token === "string" ? mcpServer.token : undefined,
|
|
308
|
-
headers: typeof mcpServer.headers === "object" && mcpServer.headers
|
|
309
|
-
? Object.fromEntries(Object.entries(mcpServer.headers).filter((entry) => typeof entry[1] === "string"))
|
|
310
|
-
: undefined,
|
|
311
|
-
};
|
|
312
|
-
}
|
|
313
|
-
function createMcpCacheKey(config) {
|
|
314
|
-
return JSON.stringify({
|
|
315
|
-
transport: config.transport ?? "stdio",
|
|
316
|
-
command: config.command,
|
|
317
|
-
args: config.args ?? [],
|
|
318
|
-
env: config.env ?? {},
|
|
319
|
-
cwd: config.cwd ?? "",
|
|
320
|
-
url: config.url ?? "",
|
|
321
|
-
token: config.token ?? "",
|
|
322
|
-
headers: config.headers ?? {},
|
|
323
|
-
});
|
|
324
|
-
}
|
|
325
|
-
export async function getOrCreateMcpClient(config) {
|
|
326
|
-
const cacheKey = createMcpCacheKey(config);
|
|
327
|
-
const cached = mcpClientCache.get(cacheKey);
|
|
328
|
-
if (cached) {
|
|
329
|
-
return cached;
|
|
330
|
-
}
|
|
331
|
-
const loading = (async () => {
|
|
332
|
-
const client = new Client({
|
|
333
|
-
name: "agent-harness",
|
|
334
|
-
version: AGENT_HARNESS_VERSION,
|
|
335
|
-
});
|
|
336
|
-
const headers = {
|
|
337
|
-
...(config.headers ?? {}),
|
|
338
|
-
...(config.token ? { Authorization: `Bearer ${config.token}` } : {}),
|
|
339
|
-
};
|
|
340
|
-
const transport = config.transport === "http"
|
|
341
|
-
? new StreamableHTTPClientTransport(new URL(config.url ?? ""), {
|
|
342
|
-
requestInit: Object.keys(headers).length > 0 ? { headers } : undefined,
|
|
343
|
-
})
|
|
344
|
-
: config.transport === "sse"
|
|
345
|
-
? new SSEClientTransport(new URL(config.url ?? ""), {
|
|
346
|
-
requestInit: Object.keys(headers).length > 0 ? { headers } : undefined,
|
|
347
|
-
})
|
|
348
|
-
: config.transport === "websocket"
|
|
349
|
-
? new WebSocketClientTransport(new URL(config.url ?? ""))
|
|
350
|
-
: new StdioClientTransport({
|
|
351
|
-
command: config.command ?? "",
|
|
352
|
-
args: config.args,
|
|
353
|
-
env: createRuntimeEnv(config.env),
|
|
354
|
-
cwd: config.cwd,
|
|
355
|
-
});
|
|
356
|
-
await client.connect(transport);
|
|
357
|
-
return client;
|
|
358
|
-
})();
|
|
359
|
-
mcpClientCache.set(cacheKey, loading);
|
|
360
|
-
return loading;
|
|
361
|
-
}
|
|
362
|
-
async function getRemoteMcpToolDescriptor(config, remoteToolName) {
|
|
363
|
-
const client = await getOrCreateMcpClient(config);
|
|
364
|
-
const result = await client.listTools();
|
|
365
|
-
const tool = result.tools.find((item) => typeof item.name === "string" && item.name === remoteToolName);
|
|
366
|
-
if (!tool || typeof tool.name !== "string") {
|
|
367
|
-
return null;
|
|
368
|
-
}
|
|
369
|
-
return {
|
|
370
|
-
name: tool.name,
|
|
371
|
-
description: typeof tool.description === "string" ? tool.description : undefined,
|
|
372
|
-
inputSchema: typeof tool.inputSchema === "object" && tool.inputSchema ? tool.inputSchema : undefined,
|
|
373
|
-
};
|
|
374
|
-
}
|
|
375
|
-
export async function listRemoteMcpTools(config) {
|
|
376
|
-
const client = await getOrCreateMcpClient(config);
|
|
377
|
-
const result = await client.listTools();
|
|
378
|
-
return result.tools
|
|
379
|
-
.filter((tool) => typeof tool.name === "string")
|
|
380
|
-
.map((tool) => ({
|
|
381
|
-
name: tool.name,
|
|
382
|
-
description: typeof tool.description === "string" ? tool.description : undefined,
|
|
383
|
-
inputSchema: typeof tool.inputSchema === "object" && tool.inputSchema ? tool.inputSchema : undefined,
|
|
384
|
-
}));
|
|
385
|
-
}
|
|
386
270
|
function createFunctionToolResolver(workspace) {
|
|
387
271
|
const functionTools = new Map(Array.from(workspace.tools.values())
|
|
388
272
|
.filter((tool) => tool.type === "function" && isSupportedToolModulePath(tool.sourcePath))
|
|
@@ -411,43 +295,6 @@ function createFunctionToolResolver(workspace) {
|
|
|
411
295
|
];
|
|
412
296
|
});
|
|
413
297
|
}
|
|
414
|
-
function createMcpToolResolver(workspace) {
|
|
415
|
-
const mcpTools = new Map(Array.from(workspace.tools.values())
|
|
416
|
-
.filter((tool) => tool.type === "mcp")
|
|
417
|
-
.map((tool) => [tool.id, tool]));
|
|
418
|
-
return (toolIds) => toolIds.flatMap((toolId) => {
|
|
419
|
-
const tool = mcpTools.get(toolId);
|
|
420
|
-
if (!tool) {
|
|
421
|
-
return [];
|
|
422
|
-
}
|
|
423
|
-
const serverConfig = readMcpServerConfig(workspace, tool);
|
|
424
|
-
if (!serverConfig) {
|
|
425
|
-
throw new Error(`MCP tool ${tool.id} must define mcp.serverRef or inline MCP server config.`);
|
|
426
|
-
}
|
|
427
|
-
const remoteToolName = tool.mcpRef ?? tool.name;
|
|
428
|
-
const descriptorPromise = getRemoteMcpToolDescriptor(serverConfig, remoteToolName);
|
|
429
|
-
return [
|
|
430
|
-
{
|
|
431
|
-
name: tool.name,
|
|
432
|
-
description: tool.description,
|
|
433
|
-
inputSchemaPromise: descriptorPromise.then((descriptor) => descriptor?.inputSchema),
|
|
434
|
-
async invoke(input) {
|
|
435
|
-
const client = await getOrCreateMcpClient(serverConfig);
|
|
436
|
-
const result = await client.callTool({
|
|
437
|
-
name: remoteToolName,
|
|
438
|
-
arguments: typeof input === "object" && input !== null ? input : {},
|
|
439
|
-
});
|
|
440
|
-
const textParts = Array.isArray(result.content)
|
|
441
|
-
? result.content
|
|
442
|
-
.filter((item) => typeof item === "object" && item !== null && "type" in item)
|
|
443
|
-
.flatMap((item) => item.type === "text" && typeof item.text === "string" ? [item.text] : [])
|
|
444
|
-
: [];
|
|
445
|
-
return textParts.length > 0 ? textParts.join("\n\n") : JSON.stringify(result);
|
|
446
|
-
},
|
|
447
|
-
},
|
|
448
|
-
];
|
|
449
|
-
});
|
|
450
|
-
}
|
|
451
298
|
function resolvePackageEntry(packageRoot, pkg) {
|
|
452
299
|
const exportsField = pkg.exports;
|
|
453
300
|
if (typeof exportsField === "string") {
|
|
@@ -514,11 +361,11 @@ export async function ensureResourceSources(sources = [], workspaceRoot = proces
|
|
|
514
361
|
}
|
|
515
362
|
export function defaultResourceSkillsRoot() {
|
|
516
363
|
const provider = requireLocalResource("default resource skill resolution");
|
|
517
|
-
return provider.defaultResourceSkillsRoot?.()
|
|
364
|
+
return preferProviderValue(provider, (candidate) => candidate.defaultResourceSkillsRoot?.(), (candidate) => candidate.builtinSkillsRoot?.()) ?? "";
|
|
518
365
|
}
|
|
519
366
|
export function defaultResourceConfigRoot() {
|
|
520
367
|
const provider = requireLocalResource("default resource config resolution");
|
|
521
|
-
return provider.defaultResourceConfigRoot?.()
|
|
368
|
+
return (preferProviderValue(provider, (candidate) => candidate.defaultResourceConfigRoot?.(), (candidate) => candidate.builtinConfigRoot?.() ?? candidate.builtinDefaultsRoot?.()) ?? "");
|
|
522
369
|
}
|
|
523
370
|
export async function listResourceTools(sources = [], workspaceRoot = process.cwd()) {
|
|
524
371
|
await ensureResourceSources(sources, workspaceRoot);
|
|
@@ -539,11 +386,7 @@ export async function listResourceToolsForSource(source, workspaceRoot = process
|
|
|
539
386
|
}
|
|
540
387
|
export function createResourceBackendResolver(workspace) {
|
|
541
388
|
const localResolver = createProviderBackendResolver(localResource, workspace);
|
|
542
|
-
const remoteResolvers = (workspace
|
|
543
|
-
.map((source) => remoteResourceCache.get(source))
|
|
544
|
-
.filter((provider) => Boolean(provider))
|
|
545
|
-
.map((provider) => createProviderBackendResolver(provider, workspace))
|
|
546
|
-
.filter((resolver) => Boolean(resolver));
|
|
389
|
+
const remoteResolvers = createWorkspaceProviderResolvers(workspace, (provider) => createProviderBackendResolver(provider, workspace));
|
|
547
390
|
const inlineResolver = createInlineBackendResolver(workspace);
|
|
548
391
|
return (binding) => {
|
|
549
392
|
const providerResolved = localResolver?.(binding) ??
|
|
@@ -555,11 +398,7 @@ export function createResourceToolResolver(workspace, options = {}) {
|
|
|
555
398
|
const functionResolver = createFunctionToolResolver(workspace);
|
|
556
399
|
const mcpResolver = createMcpToolResolver(workspace);
|
|
557
400
|
const localResolver = createProviderToolResolver(localResource, workspace, options);
|
|
558
|
-
const remoteResolvers = (workspace
|
|
559
|
-
.map((source) => remoteResourceCache.get(source))
|
|
560
|
-
.filter((provider) => Boolean(provider))
|
|
561
|
-
.map((provider) => createProviderToolResolver(provider, workspace, options))
|
|
562
|
-
.filter((resolver) => Boolean(resolver));
|
|
401
|
+
const remoteResolvers = createWorkspaceProviderResolvers(workspace, (provider) => createProviderToolResolver(provider, workspace, options));
|
|
563
402
|
return (toolIds, binding) => {
|
|
564
403
|
const resolved = [
|
|
565
404
|
...functionResolver(toolIds, binding),
|
|
@@ -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
|
+
}
|