@botbotgo/agent-harness 0.0.309 → 0.0.310
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/README.md +14 -0
- package/README.zh.md +14 -0
- package/dist/acp.d.ts +1 -116
- package/dist/acp.js +1 -310
- package/dist/api.d.ts +1 -1
- package/dist/api.js +1 -1
- package/dist/cli/chat-interactive.d.ts +24 -0
- package/dist/cli/chat-interactive.js +244 -0
- package/dist/cli/chat-rendering.d.ts +9 -0
- package/dist/cli/chat-rendering.js +102 -0
- package/dist/cli/chat-stream.d.ts +23 -0
- package/dist/cli/chat-stream.js +330 -0
- package/dist/cli/chat-ui.d.ts +20 -0
- package/dist/cli/chat-ui.js +198 -0
- package/dist/cli/chat-workspace.d.ts +15 -0
- package/dist/cli/chat-workspace.js +205 -0
- package/dist/cli/main.d.ts +52 -0
- package/dist/cli/main.js +323 -0
- package/dist/cli/managed-service-commands.d.ts +23 -0
- package/dist/cli/managed-service-commands.js +63 -0
- package/dist/cli/managed-service.d.ts +27 -0
- package/dist/cli/managed-service.js +61 -0
- package/dist/cli/options-init-chat.d.ts +16 -0
- package/dist/cli/options-init-chat.js +108 -0
- package/dist/cli/options-runtime.d.ts +27 -0
- package/dist/cli/options-runtime.js +158 -0
- package/dist/cli/options-serve.d.ts +24 -0
- package/dist/cli/options-serve.js +166 -0
- package/dist/cli/options.d.ts +5 -0
- package/dist/cli/options.js +47 -0
- package/dist/cli/process-guards.d.ts +14 -0
- package/dist/cli/process-guards.js +139 -0
- package/dist/cli/request-tree.d.ts +12 -0
- package/dist/cli/request-tree.js +296 -0
- package/dist/cli/runtime-commands.d.ts +15 -0
- package/dist/cli/runtime-commands.js +247 -0
- package/dist/cli/runtime-output.d.ts +5 -0
- package/dist/cli/runtime-output.js +124 -0
- package/dist/cli/server-commands.d.ts +36 -0
- package/dist/cli/server-commands.js +250 -0
- package/dist/cli/workspace.d.ts +6 -0
- package/dist/cli/workspace.js +71 -0
- package/dist/cli.d.ts +1 -78
- package/dist/cli.js +2 -3024
- package/dist/client/acp.d.ts +1 -50
- package/dist/client/acp.js +1 -219
- package/dist/client/in-process.d.ts +5 -5
- package/dist/client/index.d.ts +2 -2
- package/dist/client/index.js +1 -1
- package/dist/contracts/runtime-evaluation.d.ts +103 -0
- package/dist/contracts/runtime-evaluation.js +1 -0
- package/dist/contracts/runtime-memory.d.ts +162 -0
- package/dist/contracts/runtime-memory.js +1 -0
- package/dist/contracts/runtime-observability.d.ts +248 -0
- package/dist/contracts/runtime-observability.js +1 -0
- package/dist/contracts/runtime-requests.d.ts +342 -0
- package/dist/contracts/runtime-requests.js +1 -0
- package/dist/contracts/runtime-scheduling.d.ts +146 -0
- package/dist/contracts/runtime-scheduling.js +1 -0
- package/dist/contracts/runtime.d.ts +5 -1042
- package/dist/contracts/runtime.js +27 -1
- package/dist/flow/build-flow-graph.js +4 -875
- package/dist/flow/flow-graph-normalization.d.ts +56 -0
- package/dist/flow/flow-graph-normalization.js +214 -0
- package/dist/flow/flow-graph-runtime.d.ts +8 -0
- package/dist/flow/flow-graph-runtime.js +107 -0
- package/dist/flow/flow-graph-upstream.d.ts +18 -0
- package/dist/flow/flow-graph-upstream.js +498 -0
- package/dist/flow/types.d.ts +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -1
- package/dist/init-project.d.ts +1 -12
- package/dist/init-project.js +1 -651
- package/dist/{procedural → knowledge/procedural}/manager.d.ts +3 -3
- package/dist/{procedural → knowledge/procedural}/manager.js +6 -6
- package/dist/mcp.d.ts +2 -76
- package/dist/mcp.js +2 -428
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/persistence/file-store.js +1 -1
- package/dist/persistence/sqlite-runtime.d.ts +19 -0
- package/dist/persistence/sqlite-runtime.js +86 -0
- package/dist/persistence/sqlite-store.js +11 -99
- package/dist/{request-events.d.ts → projections/request-events.d.ts} +1 -1
- package/dist/{upstream-events.js → projections/upstream-events.js} +1 -1
- package/dist/protocol/a2a/http-discovery.d.ts +39 -0
- package/dist/protocol/a2a/http-discovery.js +178 -0
- package/dist/protocol/a2a/http-rpc.d.ts +28 -0
- package/dist/protocol/a2a/http-rpc.js +623 -0
- package/dist/protocol/a2a/http.d.ts +72 -1
- package/dist/protocol/a2a/http.js +14 -1124
- package/dist/protocol/a2a/task-state.d.ts +29 -0
- package/dist/protocol/a2a/task-state.js +317 -0
- package/dist/protocol/acp/client.js +1 -1
- package/dist/protocol/acp/harness-client.d.ts +50 -0
- package/dist/protocol/acp/harness-client.js +219 -0
- package/dist/protocol/acp/server.d.ts +116 -0
- package/dist/protocol/acp/server.js +310 -0
- package/dist/protocol/ag-ui/http.js +1 -1
- package/dist/protocol/mcp/server.d.ts +76 -0
- package/dist/protocol/mcp/server.js +428 -0
- package/dist/resource/backend/workspace-scoped-backend.d.ts +40 -0
- package/dist/resource/backend/workspace-scoped-backend.js +296 -0
- package/dist/resource/mcp/tool-support.d.ts +35 -0
- package/dist/resource/mcp/tool-support.js +296 -0
- package/dist/resource/mcp-tool-support.d.ts +2 -35
- package/dist/resource/mcp-tool-support.js +2 -296
- package/dist/resource/providers/resource-provider.d.ts +22 -0
- package/dist/resource/providers/resource-provider.js +215 -0
- package/dist/resource/resource-impl.d.ts +3 -33
- package/dist/resource/resource-impl.js +2 -808
- package/dist/resource/resource-types.d.ts +33 -0
- package/dist/resource/resource-types.js +1 -0
- package/dist/resource/tools/function-tool-resolver.d.ts +2 -0
- package/dist/resource/tools/function-tool-resolver.js +306 -0
- package/dist/runtime/adapter/middleware-assembly.js +1 -1
- package/dist/runtime/adapter/model/invocation-request.js +2 -2
- package/dist/runtime/adapter/model/message-assembly.js +1 -1
- package/dist/runtime/agent-runtime-adapter.d.ts +3 -63
- package/dist/runtime/agent-runtime-adapter.js +5 -233
- package/dist/runtime/agent-runtime-assembly.d.ts +67 -0
- package/dist/runtime/agent-runtime-assembly.js +211 -0
- package/dist/runtime/harness/background-runtime.d.ts +1 -1
- package/dist/runtime/harness/events/event-sink.js +1 -1
- package/dist/runtime/harness/events/runtime-event-operations.d.ts +1 -1
- package/dist/runtime/harness/events/streaming.js +1 -1
- package/dist/runtime/harness/public-shapes.d.ts +43 -0
- package/dist/runtime/harness/public-shapes.js +186 -0
- package/dist/runtime/harness/run/inspection.js +2 -2
- package/dist/runtime/harness/run/resources.js +1 -1
- package/dist/runtime/harness/run/surface-semantics.js +1 -1
- package/dist/runtime/harness/system/inventory.d.ts +1 -1
- package/dist/runtime/harness/system/inventory.js +2 -2
- package/dist/runtime/harness/system/policy-engine.js +1 -1
- package/dist/runtime/harness/system/runtime-memory-manager.js +1 -1
- package/dist/runtime/harness/system/skill-requirements.d.ts +1 -1
- package/dist/runtime/harness/system/skill-requirements.js +1 -1
- package/dist/runtime/harness.d.ts +2 -2
- package/dist/runtime/harness.js +7 -191
- package/dist/runtime/maintenance/checkpoint-maintenance.js +1 -1
- package/dist/runtime/maintenance/runtime-record-maintenance.js +1 -1
- package/dist/runtime/parsing/output-content.d.ts +11 -0
- package/dist/runtime/parsing/output-content.js +442 -0
- package/dist/runtime/parsing/output-parsing.d.ts +3 -29
- package/dist/runtime/parsing/output-parsing.js +3 -806
- package/dist/runtime/parsing/output-recovery.d.ts +14 -0
- package/dist/runtime/parsing/output-recovery.js +288 -0
- package/dist/runtime/parsing/output-tool-args.d.ts +4 -0
- package/dist/runtime/parsing/output-tool-args.js +120 -0
- package/dist/runtime/support/runtime-factories.js +1 -1
- package/dist/scaffold/init-project.d.ts +12 -0
- package/dist/scaffold/init-project.js +651 -0
- package/dist/{extensions.d.ts → tooling/extensions.d.ts} +1 -1
- package/dist/{extensions.js → tooling/extensions.js} +3 -3
- package/dist/{tool-modules.d.ts → tooling/module-loader.d.ts} +1 -1
- package/dist/{tool-modules.js → tooling/module-loader.js} +2 -2
- package/dist/workspace/agent-binding-compiler.js +2 -2
- package/dist/workspace/compile.js +2 -2
- package/dist/workspace/object-loader-paths.d.ts +11 -0
- package/dist/workspace/object-loader-paths.js +75 -0
- package/dist/workspace/object-loader-readers.d.ts +21 -0
- package/dist/workspace/object-loader-readers.js +187 -0
- package/dist/workspace/object-loader.d.ts +0 -1
- package/dist/workspace/object-loader.js +6 -260
- package/dist/workspace/resource-compilers.js +1 -1
- package/dist/workspace/support/discovery.js +1 -1
- package/package.json +1 -1
- package/dist/runtime/adapter/index.d.ts +0 -13
- package/dist/runtime/adapter/index.js +0 -13
- package/dist/runtime/harness/index.d.ts +0 -19
- package/dist/runtime/harness/index.js +0 -19
- package/dist/runtime/maintenance/index.d.ts +0 -4
- package/dist/runtime/maintenance/index.js +0 -4
- package/dist/runtime/parsing/index.d.ts +0 -2
- package/dist/runtime/parsing/index.js +0 -2
- package/dist/runtime/support/index.d.ts +0 -4
- package/dist/runtime/support/index.js +0 -4
- package/dist/workspace/support/index.d.ts +0 -2
- package/dist/workspace/support/index.js +0 -2
- /package/dist/{procedural → knowledge/procedural}/config.d.ts +0 -0
- /package/dist/{procedural → knowledge/procedural}/config.js +0 -0
- /package/dist/{procedural → knowledge/procedural}/index.d.ts +0 -0
- /package/dist/{procedural → knowledge/procedural}/index.js +0 -0
- /package/dist/{presentation.d.ts → projections/presentation.d.ts} +0 -0
- /package/dist/{presentation.js → projections/presentation.js} +0 -0
- /package/dist/{request-events.js → projections/request-events.js} +0 -0
- /package/dist/{upstream-events.d.ts → projections/upstream-events.d.ts} +0 -0
- /package/dist/runtime/{support → env}/runtime-env.d.ts +0 -0
- /package/dist/runtime/{support → env}/runtime-env.js +0 -0
- /package/dist/runtime/{support → layout}/runtime-layout.d.ts +0 -0
- /package/dist/runtime/{support → layout}/runtime-layout.js +0 -0
- /package/dist/runtime/{support → prompts}/runtime-prompts.d.ts +0 -0
- /package/dist/runtime/{support → prompts}/runtime-prompts.js +0 -0
- /package/dist/runtime/{support → skills}/skill-metadata.d.ts +0 -0
- /package/dist/runtime/{support → skills}/skill-metadata.js +0 -0
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import { mkdirSync, readdirSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { CompositeBackend, LangSmithSandbox, LocalShellBackend, StateBackend, StoreBackend } from "deepagents";
|
|
4
|
+
import { getBindingBackendConfig } from "../../runtime/support/compiled-binding.js";
|
|
5
|
+
import { createRuntimeEnv } from "../../runtime/env/runtime-env.js";
|
|
6
|
+
function listVirtualRootEntries(rootDir) {
|
|
7
|
+
try {
|
|
8
|
+
return new Set(readdirSync(rootDir, { withFileTypes: true }).map((entry) => entry.name));
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return new Set();
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function normalizeVirtualExecuteCommand(command, rootDir) {
|
|
15
|
+
if (typeof command !== "string" || command.length === 0) {
|
|
16
|
+
return command;
|
|
17
|
+
}
|
|
18
|
+
const rootEntries = listVirtualRootEntries(rootDir);
|
|
19
|
+
if (rootEntries.size === 0) {
|
|
20
|
+
return command;
|
|
21
|
+
}
|
|
22
|
+
return command.replace(/(^|[\s=:(\[{,;|&])(?<quote>["']?)(?<virtualPath>\/(?:[^\s"'`;|&()<>]+))(?:\k<quote>)/g, (match, prefix, quote = "", virtualPath) => {
|
|
23
|
+
const normalizedVirtualPath = virtualPath.replace(/\/+/g, "/");
|
|
24
|
+
const segments = normalizedVirtualPath.split("/").filter((segment) => segment.length > 0);
|
|
25
|
+
const firstSegment = segments[0];
|
|
26
|
+
if (!firstSegment || !rootEntries.has(firstSegment)) {
|
|
27
|
+
return match;
|
|
28
|
+
}
|
|
29
|
+
const translatedPath = path.resolve(rootDir, ...segments);
|
|
30
|
+
return `${prefix}${quote}${translatedPath}${quote}`;
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
export function normalizeWorkspaceScopedPath(rootDir, inputPath) {
|
|
34
|
+
if (typeof inputPath !== "string" || inputPath.length === 0 || !path.isAbsolute(inputPath)) {
|
|
35
|
+
return inputPath;
|
|
36
|
+
}
|
|
37
|
+
if (inputPath === "/") {
|
|
38
|
+
return ".";
|
|
39
|
+
}
|
|
40
|
+
const virtualSegments = inputPath.replace(/\/+/g, "/").split("/").filter((segment) => segment.length > 0);
|
|
41
|
+
if (virtualSegments.length > 0) {
|
|
42
|
+
const rootEntries = listVirtualRootEntries(rootDir);
|
|
43
|
+
const firstSegment = virtualSegments[0];
|
|
44
|
+
if (rootEntries.has(firstSegment)) {
|
|
45
|
+
return path.join(...virtualSegments);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const normalizedRootDir = path.resolve(rootDir);
|
|
49
|
+
const normalizedInputPath = path.resolve(inputPath);
|
|
50
|
+
if (normalizedInputPath === normalizedRootDir || normalizedInputPath.startsWith(`${normalizedRootDir}${path.sep}`)) {
|
|
51
|
+
return path.relative(normalizedRootDir, normalizedInputPath) || ".";
|
|
52
|
+
}
|
|
53
|
+
throw new Error(`Path '${inputPath}' is outside the workspace root '${normalizedRootDir}'. Use a workspace-relative path instead.`);
|
|
54
|
+
}
|
|
55
|
+
function normalizeWorkspaceScopedNullablePath(rootDir, inputPath) {
|
|
56
|
+
return typeof inputPath === "string" ? normalizeWorkspaceScopedPath(rootDir, inputPath) : inputPath;
|
|
57
|
+
}
|
|
58
|
+
export class WorkspaceScopedBackend {
|
|
59
|
+
backend;
|
|
60
|
+
id;
|
|
61
|
+
cwd;
|
|
62
|
+
rootDir;
|
|
63
|
+
root;
|
|
64
|
+
virtualMode;
|
|
65
|
+
execute;
|
|
66
|
+
constructor(backend, rootDir) {
|
|
67
|
+
this.backend = backend;
|
|
68
|
+
this.rootDir = path.resolve(rootDir);
|
|
69
|
+
this.root = this.rootDir;
|
|
70
|
+
this.cwd = this.rootDir;
|
|
71
|
+
this.id = typeof backend.id === "string" ? backend.id : undefined;
|
|
72
|
+
this.virtualMode = backend.virtualMode === true;
|
|
73
|
+
this.execute = typeof backend.execute === "function"
|
|
74
|
+
? (command) => backend.execute(command)
|
|
75
|
+
: undefined;
|
|
76
|
+
}
|
|
77
|
+
ls(filePath) {
|
|
78
|
+
return this.backend.ls(normalizeWorkspaceScopedPath(this.rootDir, filePath));
|
|
79
|
+
}
|
|
80
|
+
read(filePath, offset, limit) {
|
|
81
|
+
return this.backend.read(normalizeWorkspaceScopedPath(this.rootDir, filePath), offset, limit);
|
|
82
|
+
}
|
|
83
|
+
readRaw(filePath) {
|
|
84
|
+
return this.backend.readRaw(normalizeWorkspaceScopedPath(this.rootDir, filePath));
|
|
85
|
+
}
|
|
86
|
+
grep(pattern, filePath, glob) {
|
|
87
|
+
return this.backend.grep(pattern, normalizeWorkspaceScopedNullablePath(this.rootDir, filePath), glob);
|
|
88
|
+
}
|
|
89
|
+
grepRaw(pattern, filePath, glob) {
|
|
90
|
+
return this.backend.grepRaw(pattern, normalizeWorkspaceScopedNullablePath(this.rootDir, filePath), glob);
|
|
91
|
+
}
|
|
92
|
+
glob(pattern, filePath) {
|
|
93
|
+
return this.backend.glob(pattern, typeof filePath === "string" ? normalizeWorkspaceScopedPath(this.rootDir, filePath) : filePath);
|
|
94
|
+
}
|
|
95
|
+
write(filePath, content) {
|
|
96
|
+
return this.backend.write(normalizeWorkspaceScopedPath(this.rootDir, filePath), content);
|
|
97
|
+
}
|
|
98
|
+
edit(filePath, oldString, newString, replaceAll) {
|
|
99
|
+
return this.backend.edit(normalizeWorkspaceScopedPath(this.rootDir, filePath), oldString, newString, replaceAll);
|
|
100
|
+
}
|
|
101
|
+
uploadFiles(files) {
|
|
102
|
+
return this.backend.uploadFiles(files);
|
|
103
|
+
}
|
|
104
|
+
downloadFiles(paths) {
|
|
105
|
+
const normalizedPaths = Array.isArray(paths) ? paths.map((currentPath) => normalizeWorkspaceScopedPath(this.rootDir, currentPath)) : paths;
|
|
106
|
+
return this.backend.downloadFiles(normalizedPaths);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
class CompatibleCompositeBackend {
|
|
110
|
+
id;
|
|
111
|
+
execute;
|
|
112
|
+
composite;
|
|
113
|
+
constructor(defaultBackend, routes) {
|
|
114
|
+
this.composite = new CompositeBackend(defaultBackend, routes);
|
|
115
|
+
const sandboxLike = defaultBackend;
|
|
116
|
+
if (typeof sandboxLike.id === "string" && typeof sandboxLike.execute === "function") {
|
|
117
|
+
this.id = sandboxLike.id;
|
|
118
|
+
const virtualCwd = typeof sandboxLike.cwd === "string" && sandboxLike.virtualMode === true ? sandboxLike.cwd : null;
|
|
119
|
+
this.execute =
|
|
120
|
+
virtualCwd
|
|
121
|
+
? (command) => this.composite.execute(normalizeVirtualExecuteCommand(command, virtualCwd))
|
|
122
|
+
: (command) => this.composite.execute(command);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
ls(filePath) {
|
|
126
|
+
return this.composite.ls(filePath);
|
|
127
|
+
}
|
|
128
|
+
read(filePath, offset, limit) {
|
|
129
|
+
return this.composite.read(filePath, offset, limit);
|
|
130
|
+
}
|
|
131
|
+
readRaw(filePath) {
|
|
132
|
+
return this.composite.readRaw(filePath);
|
|
133
|
+
}
|
|
134
|
+
grep(pattern, filePath, glob) {
|
|
135
|
+
return this.composite.grep(pattern, filePath ?? undefined, glob ?? undefined);
|
|
136
|
+
}
|
|
137
|
+
glob(pattern, filePath) {
|
|
138
|
+
return this.composite.glob(pattern, filePath);
|
|
139
|
+
}
|
|
140
|
+
write(filePath, content) {
|
|
141
|
+
return this.composite.write(filePath, content);
|
|
142
|
+
}
|
|
143
|
+
edit(filePath, oldString, newString, replaceAll) {
|
|
144
|
+
return this.composite.edit(filePath, oldString, newString, replaceAll);
|
|
145
|
+
}
|
|
146
|
+
uploadFiles(files) {
|
|
147
|
+
return this.composite.uploadFiles(files);
|
|
148
|
+
}
|
|
149
|
+
downloadFiles(paths) {
|
|
150
|
+
return this.composite.downloadFiles(paths);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function omitKind(config) {
|
|
154
|
+
const { kind: _kind, ...rest } = config ?? {};
|
|
155
|
+
return rest;
|
|
156
|
+
}
|
|
157
|
+
class LazyLangSmithSandbox {
|
|
158
|
+
config;
|
|
159
|
+
sandboxPromise = null;
|
|
160
|
+
constructor(config) {
|
|
161
|
+
this.config = config;
|
|
162
|
+
}
|
|
163
|
+
get id() {
|
|
164
|
+
return "langsmith-pending";
|
|
165
|
+
}
|
|
166
|
+
get isRunning() {
|
|
167
|
+
return this.sandboxPromise !== null;
|
|
168
|
+
}
|
|
169
|
+
getSandbox() {
|
|
170
|
+
if (!this.sandboxPromise) {
|
|
171
|
+
this.sandboxPromise = LangSmithSandbox.create(omitKind(this.config));
|
|
172
|
+
}
|
|
173
|
+
return this.sandboxPromise;
|
|
174
|
+
}
|
|
175
|
+
async read(filePath, offset, limit) {
|
|
176
|
+
return (await this.getSandbox()).read(filePath, offset, limit);
|
|
177
|
+
}
|
|
178
|
+
async edit(filePath, oldString, newString, replaceAll) {
|
|
179
|
+
return (await this.getSandbox()).edit(filePath, oldString, newString, replaceAll);
|
|
180
|
+
}
|
|
181
|
+
async ls(dirPath) {
|
|
182
|
+
return (await this.getSandbox()).ls(dirPath);
|
|
183
|
+
}
|
|
184
|
+
async glob(pattern, searchPath) {
|
|
185
|
+
return (await this.getSandbox()).glob(pattern, searchPath);
|
|
186
|
+
}
|
|
187
|
+
async write(filePath, content) {
|
|
188
|
+
return (await this.getSandbox()).write(filePath, content);
|
|
189
|
+
}
|
|
190
|
+
async execute(command) {
|
|
191
|
+
return (await this.getSandbox()).execute(command);
|
|
192
|
+
}
|
|
193
|
+
async uploadFiles(files) {
|
|
194
|
+
return (await this.getSandbox()).uploadFiles(files);
|
|
195
|
+
}
|
|
196
|
+
async downloadFiles(paths) {
|
|
197
|
+
return (await this.getSandbox()).downloadFiles(paths);
|
|
198
|
+
}
|
|
199
|
+
async close() {
|
|
200
|
+
if (!this.sandboxPromise) {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
await (await this.sandboxPromise).close();
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
const INLINE_BACKEND_ERROR = 'Unsupported DeepAgent backend kind "%s". Supported inline kinds: LocalShellBackend, VfsSandbox, StateBackend, StoreBackend, CompositeBackend, LangSmithSandbox.';
|
|
207
|
+
function unsupportedInlineBackend(kind) {
|
|
208
|
+
throw new Error(INLINE_BACKEND_ERROR.replace("%s", kind));
|
|
209
|
+
}
|
|
210
|
+
function resolveInlineBackendRootDir(workspaceRoot, configuredRootDir) {
|
|
211
|
+
if (typeof configuredRootDir === "string" && configuredRootDir.trim().length > 0) {
|
|
212
|
+
return path.isAbsolute(configuredRootDir)
|
|
213
|
+
? configuredRootDir
|
|
214
|
+
: path.resolve(workspaceRoot, configuredRootDir);
|
|
215
|
+
}
|
|
216
|
+
return workspaceRoot;
|
|
217
|
+
}
|
|
218
|
+
function readStringRecord(value) {
|
|
219
|
+
if (typeof value !== "object" || !value) {
|
|
220
|
+
return undefined;
|
|
221
|
+
}
|
|
222
|
+
const entries = Object.entries(value).filter((entry) => typeof entry[1] === "string");
|
|
223
|
+
return entries.length > 0 ? Object.fromEntries(entries) : undefined;
|
|
224
|
+
}
|
|
225
|
+
function createLocalShellStyleBackend(workspaceRoot, config, options) {
|
|
226
|
+
const rootDir = resolveInlineBackendRootDir(workspaceRoot, config?.rootDir);
|
|
227
|
+
mkdirSync(rootDir, { recursive: true });
|
|
228
|
+
const inheritedEnv = config?.inheritEnv === false ? {} : process.env;
|
|
229
|
+
return new WorkspaceScopedBackend(new LocalShellBackend({
|
|
230
|
+
rootDir,
|
|
231
|
+
virtualMode: options.virtualMode,
|
|
232
|
+
timeout: typeof config?.timeout === "number" ? config.timeout : undefined,
|
|
233
|
+
maxOutputBytes: typeof config?.maxOutputBytes === "number" ? config.maxOutputBytes : undefined,
|
|
234
|
+
env: createRuntimeEnv(readStringRecord(config?.env), inheritedEnv),
|
|
235
|
+
inheritEnv: config?.inheritEnv !== false,
|
|
236
|
+
}), rootDir);
|
|
237
|
+
}
|
|
238
|
+
function createInlineBackendInstance(workspaceRoot, kind, config, runtimeLike) {
|
|
239
|
+
switch (kind) {
|
|
240
|
+
case "LocalShellBackend":
|
|
241
|
+
return createLocalShellStyleBackend(workspaceRoot, config, {
|
|
242
|
+
virtualMode: config?.virtualMode === true,
|
|
243
|
+
});
|
|
244
|
+
case "VfsSandbox":
|
|
245
|
+
return createLocalShellStyleBackend(workspaceRoot, config, {
|
|
246
|
+
virtualMode: config?.virtualMode === false ? false : true,
|
|
247
|
+
});
|
|
248
|
+
case "StateBackend":
|
|
249
|
+
return new StateBackend(runtimeLike);
|
|
250
|
+
case "StoreBackend":
|
|
251
|
+
return new StoreBackend(runtimeLike);
|
|
252
|
+
case "LangSmithSandbox":
|
|
253
|
+
return new LazyLangSmithSandbox(config);
|
|
254
|
+
default:
|
|
255
|
+
return unsupportedInlineBackend(kind);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
export function createInlineBackendResolver(workspace) {
|
|
259
|
+
return (binding) => {
|
|
260
|
+
const backendConfig = getBindingBackendConfig(binding);
|
|
261
|
+
if (!backendConfig || typeof backendConfig !== "object") {
|
|
262
|
+
return undefined;
|
|
263
|
+
}
|
|
264
|
+
return (runtimeLike) => {
|
|
265
|
+
const kind = typeof backendConfig.kind === "string" ? backendConfig.kind : "CompositeBackend";
|
|
266
|
+
switch (kind) {
|
|
267
|
+
case "LocalShellBackend":
|
|
268
|
+
return createInlineBackendInstance(workspace.workspaceRoot, "LocalShellBackend", backendConfig, runtimeLike);
|
|
269
|
+
case "VfsSandbox":
|
|
270
|
+
return createInlineBackendInstance(workspace.workspaceRoot, "VfsSandbox", backendConfig, runtimeLike);
|
|
271
|
+
case "StateBackend":
|
|
272
|
+
return createInlineBackendInstance(workspace.workspaceRoot, "StateBackend", backendConfig, runtimeLike);
|
|
273
|
+
case "StoreBackend":
|
|
274
|
+
return createInlineBackendInstance(workspace.workspaceRoot, "StoreBackend", backendConfig, runtimeLike);
|
|
275
|
+
case "LangSmithSandbox":
|
|
276
|
+
return createInlineBackendInstance(workspace.workspaceRoot, "LangSmithSandbox", backendConfig, runtimeLike);
|
|
277
|
+
case "CompositeBackend": {
|
|
278
|
+
const stateConfig = typeof backendConfig.state === "object" && backendConfig.state
|
|
279
|
+
? backendConfig.state
|
|
280
|
+
: { kind: "StateBackend" };
|
|
281
|
+
const defaultBackendKind = typeof stateConfig.kind === "string" ? stateConfig.kind : "StateBackend";
|
|
282
|
+
const routes = typeof backendConfig.routes === "object" && backendConfig.routes
|
|
283
|
+
? backendConfig.routes
|
|
284
|
+
: { "/memories/": { kind: "StoreBackend" } };
|
|
285
|
+
const mappedRoutes = Object.fromEntries(Object.entries(routes).map(([route, routeConfig]) => {
|
|
286
|
+
const routeKind = typeof routeConfig?.kind === "string" ? routeConfig.kind : "StoreBackend";
|
|
287
|
+
return [route, createInlineBackendInstance(workspace.workspaceRoot, routeKind, routeConfig, runtimeLike)];
|
|
288
|
+
}));
|
|
289
|
+
return new WorkspaceScopedBackend(new CompatibleCompositeBackend(createInlineBackendInstance(workspace.workspaceRoot, defaultBackendKind, stateConfig, runtimeLike), mappedRoutes), workspace.workspaceRoot);
|
|
290
|
+
}
|
|
291
|
+
default:
|
|
292
|
+
return unsupportedInlineBackend(kind);
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
};
|
|
296
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
|
+
import type { RuntimeAdapterOptions, WorkspaceBundle } from "../../contracts/types.js";
|
|
3
|
+
export type McpServerConfig = {
|
|
4
|
+
transport?: "stdio" | "http" | "sse" | "websocket";
|
|
5
|
+
command?: string;
|
|
6
|
+
args?: string[];
|
|
7
|
+
env?: Record<string, string>;
|
|
8
|
+
cwd?: string;
|
|
9
|
+
url?: string;
|
|
10
|
+
token?: string;
|
|
11
|
+
headers?: Record<string, string>;
|
|
12
|
+
trustTier?: "trusted" | "reviewed" | "untrusted";
|
|
13
|
+
access?: "read-only" | "read-write";
|
|
14
|
+
tenantScope?: "workspace" | "project" | "tenant" | "cross-tenant";
|
|
15
|
+
approvalPolicy?: "always" | "write" | "never";
|
|
16
|
+
promptInjectionRisk?: "low" | "medium" | "high";
|
|
17
|
+
oauth?: {
|
|
18
|
+
provider?: string;
|
|
19
|
+
scopes?: string[];
|
|
20
|
+
};
|
|
21
|
+
labels?: string[];
|
|
22
|
+
};
|
|
23
|
+
export type McpToolDescriptor = {
|
|
24
|
+
name: string;
|
|
25
|
+
description?: string;
|
|
26
|
+
inputSchema?: Record<string, unknown>;
|
|
27
|
+
};
|
|
28
|
+
export declare function readMcpServerConfig(workspace: WorkspaceBundle, tool: WorkspaceBundle["tools"] extends Map<any, infer T> ? T : never): McpServerConfig | null;
|
|
29
|
+
export declare function getOrCreateMcpClient(config: McpServerConfig): Promise<Client>;
|
|
30
|
+
export declare function closeMcpClientsForWorkspace(workspace: WorkspaceBundle): Promise<void>;
|
|
31
|
+
export declare function __resetMcpClientCacheForTests(): void;
|
|
32
|
+
export declare function __setMcpClientCacheEntryForTests(config: McpServerConfig, clientPromise: Promise<Client>): void;
|
|
33
|
+
export declare function __setMcpClientLoaderForTests(loader: (config: McpServerConfig) => Promise<Client>): void;
|
|
34
|
+
export declare function listRemoteMcpTools(config: McpServerConfig): Promise<McpToolDescriptor[]>;
|
|
35
|
+
export declare function createMcpToolResolver(workspace: WorkspaceBundle): NonNullable<RuntimeAdapterOptions["toolResolver"]>;
|
|
@@ -0,0 +1,296 @@
|
|
|
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/env/runtime-env.js";
|
|
8
|
+
const mcpClientCache = new Map();
|
|
9
|
+
let mcpClientLoader = createConnectedMcpClient;
|
|
10
|
+
function readStringRecord(value) {
|
|
11
|
+
if (typeof value !== "object" || !value) {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
const entries = Object.entries(value).filter((entry) => typeof entry[1] === "string");
|
|
15
|
+
return entries.length > 0 ? Object.fromEntries(entries) : undefined;
|
|
16
|
+
}
|
|
17
|
+
function readStringArray(value) {
|
|
18
|
+
if (!Array.isArray(value)) {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
const entries = value.filter((item) => typeof item === "string" && item.trim().length > 0).map((item) => item.trim());
|
|
22
|
+
return entries.length > 0 ? entries : undefined;
|
|
23
|
+
}
|
|
24
|
+
function normalizeMcpTransport(value) {
|
|
25
|
+
if (value === "stdio" || value === "http" || value === "sse" || value === "websocket") {
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
export function readMcpServerConfig(workspace, tool) {
|
|
31
|
+
const mcpConfig = typeof tool.config?.mcp === "object" && tool.config?.mcp
|
|
32
|
+
? tool.config.mcp
|
|
33
|
+
: undefined;
|
|
34
|
+
const serverRef = typeof mcpConfig?.serverRef === "string" ? mcpConfig.serverRef : undefined;
|
|
35
|
+
if (serverRef) {
|
|
36
|
+
const serverId = serverRef.startsWith("mcp/") ? serverRef.slice(4) : serverRef;
|
|
37
|
+
const server = workspace.mcpServers.get(serverId);
|
|
38
|
+
if (!server) {
|
|
39
|
+
throw new Error(`MCP tool ${tool.id} references missing MCP server ${serverRef}`);
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
transport: server.transport,
|
|
43
|
+
command: server.command,
|
|
44
|
+
args: server.args,
|
|
45
|
+
env: server.env,
|
|
46
|
+
cwd: server.cwd,
|
|
47
|
+
url: server.url,
|
|
48
|
+
token: server.token,
|
|
49
|
+
headers: server.headers,
|
|
50
|
+
trustTier: server.trustTier,
|
|
51
|
+
access: server.access,
|
|
52
|
+
tenantScope: server.tenantScope,
|
|
53
|
+
approvalPolicy: server.approvalPolicy,
|
|
54
|
+
promptInjectionRisk: server.promptInjectionRisk,
|
|
55
|
+
oauth: server.oauth,
|
|
56
|
+
labels: server.labels,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
const config = typeof tool.config === "object" && tool.config
|
|
60
|
+
? tool.config
|
|
61
|
+
: undefined;
|
|
62
|
+
const mcpServer = typeof config?.mcpServer === "object" && config.mcpServer
|
|
63
|
+
? config.mcpServer
|
|
64
|
+
: config;
|
|
65
|
+
if (!mcpServer) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
transport: normalizeMcpTransport(mcpServer.transport) ?? ((typeof mcpServer.url === "string" && mcpServer.url.trim()) ? "http" : "stdio"),
|
|
70
|
+
command: typeof mcpServer.command === "string" ? mcpServer.command.trim() : undefined,
|
|
71
|
+
args: Array.isArray(mcpServer.args) ? mcpServer.args.filter((item) => typeof item === "string") : undefined,
|
|
72
|
+
env: readStringRecord(mcpServer.env),
|
|
73
|
+
cwd: typeof mcpServer.cwd === "string" ? mcpServer.cwd : undefined,
|
|
74
|
+
url: typeof mcpServer.url === "string" ? mcpServer.url.trim() : undefined,
|
|
75
|
+
token: typeof mcpServer.token === "string" ? mcpServer.token : undefined,
|
|
76
|
+
headers: readStringRecord(mcpServer.headers),
|
|
77
|
+
trustTier: mcpServer.trustTier === "trusted" || mcpServer.trustTier === "reviewed" || mcpServer.trustTier === "untrusted"
|
|
78
|
+
? mcpServer.trustTier
|
|
79
|
+
: undefined,
|
|
80
|
+
access: mcpServer.access === "read-only" || mcpServer.access === "read-write" ? mcpServer.access : undefined,
|
|
81
|
+
tenantScope: mcpServer.tenantScope === "workspace" ||
|
|
82
|
+
mcpServer.tenantScope === "project" ||
|
|
83
|
+
mcpServer.tenantScope === "tenant" ||
|
|
84
|
+
mcpServer.tenantScope === "cross-tenant"
|
|
85
|
+
? mcpServer.tenantScope
|
|
86
|
+
: undefined,
|
|
87
|
+
approvalPolicy: mcpServer.approvalPolicy === "always" || mcpServer.approvalPolicy === "write" || mcpServer.approvalPolicy === "never"
|
|
88
|
+
? mcpServer.approvalPolicy
|
|
89
|
+
: undefined,
|
|
90
|
+
promptInjectionRisk: mcpServer.promptInjectionRisk === "low" || mcpServer.promptInjectionRisk === "medium" || mcpServer.promptInjectionRisk === "high"
|
|
91
|
+
? mcpServer.promptInjectionRisk
|
|
92
|
+
: undefined,
|
|
93
|
+
oauth: typeof mcpServer.oauth === "object" && mcpServer.oauth
|
|
94
|
+
? {
|
|
95
|
+
provider: typeof mcpServer.oauth.provider === "string"
|
|
96
|
+
? mcpServer.oauth.provider
|
|
97
|
+
: undefined,
|
|
98
|
+
scopes: readStringArray(mcpServer.oauth.scopes),
|
|
99
|
+
}
|
|
100
|
+
: undefined,
|
|
101
|
+
labels: readStringArray(mcpServer.labels),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function createMcpCacheKey(config) {
|
|
105
|
+
return JSON.stringify({
|
|
106
|
+
transport: config.transport ?? "stdio",
|
|
107
|
+
command: config.command,
|
|
108
|
+
args: config.args ?? [],
|
|
109
|
+
env: config.env ?? {},
|
|
110
|
+
cwd: config.cwd ?? "",
|
|
111
|
+
url: config.url ?? "",
|
|
112
|
+
token: config.token ?? "",
|
|
113
|
+
headers: config.headers ?? {},
|
|
114
|
+
trustTier: config.trustTier ?? "",
|
|
115
|
+
access: config.access ?? "",
|
|
116
|
+
tenantScope: config.tenantScope ?? "",
|
|
117
|
+
approvalPolicy: config.approvalPolicy ?? "",
|
|
118
|
+
promptInjectionRisk: config.promptInjectionRisk ?? "",
|
|
119
|
+
oauth: config.oauth ?? {},
|
|
120
|
+
labels: config.labels ?? [],
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
async function createConnectedMcpClient(config) {
|
|
124
|
+
const client = new Client({
|
|
125
|
+
name: "agent-harness",
|
|
126
|
+
version: AGENT_HARNESS_VERSION,
|
|
127
|
+
});
|
|
128
|
+
const headers = {
|
|
129
|
+
...(config.headers ?? {}),
|
|
130
|
+
...(config.token ? { Authorization: `Bearer ${config.token}` } : {}),
|
|
131
|
+
};
|
|
132
|
+
const transport = config.transport === "http"
|
|
133
|
+
? new StreamableHTTPClientTransport(new URL(config.url ?? ""), {
|
|
134
|
+
requestInit: Object.keys(headers).length > 0 ? { headers } : undefined,
|
|
135
|
+
})
|
|
136
|
+
: config.transport === "sse"
|
|
137
|
+
? new SSEClientTransport(new URL(config.url ?? ""), {
|
|
138
|
+
requestInit: Object.keys(headers).length > 0 ? { headers } : undefined,
|
|
139
|
+
})
|
|
140
|
+
: config.transport === "websocket"
|
|
141
|
+
? new WebSocketClientTransport(new URL(config.url ?? ""))
|
|
142
|
+
: new StdioClientTransport({
|
|
143
|
+
command: config.command ?? "",
|
|
144
|
+
args: config.args,
|
|
145
|
+
env: createRuntimeEnv(config.env),
|
|
146
|
+
cwd: config.cwd,
|
|
147
|
+
});
|
|
148
|
+
await client.connect(transport);
|
|
149
|
+
return client;
|
|
150
|
+
}
|
|
151
|
+
function isRecoverableMcpError(error) {
|
|
152
|
+
if (typeof error !== "object" || error === null) {
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
const message = typeof error.message === "string"
|
|
156
|
+
? (error.message).toLowerCase()
|
|
157
|
+
: "";
|
|
158
|
+
const code = typeof error.code === "string"
|
|
159
|
+
? (error.code).toLowerCase()
|
|
160
|
+
: "";
|
|
161
|
+
return [
|
|
162
|
+
"connection closed",
|
|
163
|
+
"transport closed",
|
|
164
|
+
"socket closed",
|
|
165
|
+
"stream closed",
|
|
166
|
+
"network socket disconnected",
|
|
167
|
+
].some((pattern) => message.includes(pattern))
|
|
168
|
+
|| ["econnreset", "epipe", "ehostunreach", "ecancelled"].includes(code);
|
|
169
|
+
}
|
|
170
|
+
async function closeCachedMcpClient(cacheKey) {
|
|
171
|
+
const cached = mcpClientCache.get(cacheKey);
|
|
172
|
+
mcpClientCache.delete(cacheKey);
|
|
173
|
+
if (!cached) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
try {
|
|
177
|
+
const client = await cached;
|
|
178
|
+
await client.close();
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
// Ignore teardown failures for clients that never connected successfully.
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
async function invalidateMcpClient(config) {
|
|
185
|
+
await closeCachedMcpClient(createMcpCacheKey(config));
|
|
186
|
+
}
|
|
187
|
+
async function withRecoveredMcpClient(config, operation) {
|
|
188
|
+
const client = await getOrCreateMcpClient(config);
|
|
189
|
+
try {
|
|
190
|
+
return await operation(client);
|
|
191
|
+
}
|
|
192
|
+
catch (error) {
|
|
193
|
+
if (!isRecoverableMcpError(error)) {
|
|
194
|
+
throw error;
|
|
195
|
+
}
|
|
196
|
+
await invalidateMcpClient(config);
|
|
197
|
+
return operation(await getOrCreateMcpClient(config));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
export async function getOrCreateMcpClient(config) {
|
|
201
|
+
const cacheKey = createMcpCacheKey(config);
|
|
202
|
+
const cached = mcpClientCache.get(cacheKey);
|
|
203
|
+
if (cached) {
|
|
204
|
+
return cached;
|
|
205
|
+
}
|
|
206
|
+
const loading = mcpClientLoader(config).catch((error) => {
|
|
207
|
+
if (mcpClientCache.get(cacheKey) === loading) {
|
|
208
|
+
mcpClientCache.delete(cacheKey);
|
|
209
|
+
}
|
|
210
|
+
throw error;
|
|
211
|
+
});
|
|
212
|
+
mcpClientCache.set(cacheKey, loading);
|
|
213
|
+
return loading;
|
|
214
|
+
}
|
|
215
|
+
export async function closeMcpClientsForWorkspace(workspace) {
|
|
216
|
+
const cacheKeys = new Set();
|
|
217
|
+
for (const tool of workspace.tools.values()) {
|
|
218
|
+
if (tool.type !== "mcp") {
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
const config = readMcpServerConfig(workspace, tool);
|
|
222
|
+
if (!config) {
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
cacheKeys.add(createMcpCacheKey(config));
|
|
226
|
+
}
|
|
227
|
+
await Promise.all(Array.from(cacheKeys, (cacheKey) => closeCachedMcpClient(cacheKey)));
|
|
228
|
+
}
|
|
229
|
+
export function __resetMcpClientCacheForTests() {
|
|
230
|
+
mcpClientCache.clear();
|
|
231
|
+
mcpClientLoader = createConnectedMcpClient;
|
|
232
|
+
}
|
|
233
|
+
export function __setMcpClientCacheEntryForTests(config, clientPromise) {
|
|
234
|
+
mcpClientCache.set(createMcpCacheKey(config), clientPromise);
|
|
235
|
+
}
|
|
236
|
+
export function __setMcpClientLoaderForTests(loader) {
|
|
237
|
+
mcpClientLoader = loader;
|
|
238
|
+
}
|
|
239
|
+
async function getRemoteMcpToolDescriptor(config, remoteToolName) {
|
|
240
|
+
const result = await withRecoveredMcpClient(config, (client) => client.listTools());
|
|
241
|
+
const tool = result.tools.find((item) => typeof item.name === "string" && item.name === remoteToolName);
|
|
242
|
+
if (!tool || typeof tool.name !== "string") {
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
return {
|
|
246
|
+
name: tool.name,
|
|
247
|
+
description: typeof tool.description === "string" ? tool.description : undefined,
|
|
248
|
+
inputSchema: typeof tool.inputSchema === "object" && tool.inputSchema ? tool.inputSchema : undefined,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
export async function listRemoteMcpTools(config) {
|
|
252
|
+
const result = await withRecoveredMcpClient(config, (client) => client.listTools());
|
|
253
|
+
return result.tools
|
|
254
|
+
.filter((tool) => typeof tool.name === "string")
|
|
255
|
+
.map((tool) => ({
|
|
256
|
+
name: tool.name,
|
|
257
|
+
description: typeof tool.description === "string" ? tool.description : undefined,
|
|
258
|
+
inputSchema: typeof tool.inputSchema === "object" && tool.inputSchema ? tool.inputSchema : undefined,
|
|
259
|
+
}));
|
|
260
|
+
}
|
|
261
|
+
export function createMcpToolResolver(workspace) {
|
|
262
|
+
const mcpTools = new Map(Array.from(workspace.tools.values())
|
|
263
|
+
.filter((tool) => tool.type === "mcp")
|
|
264
|
+
.map((tool) => [tool.id, tool]));
|
|
265
|
+
return (toolIds) => toolIds.flatMap((toolId) => {
|
|
266
|
+
const tool = mcpTools.get(toolId);
|
|
267
|
+
if (!tool) {
|
|
268
|
+
return [];
|
|
269
|
+
}
|
|
270
|
+
const serverConfig = readMcpServerConfig(workspace, tool);
|
|
271
|
+
if (!serverConfig) {
|
|
272
|
+
throw new Error(`MCP tool ${tool.id} must define mcp.serverRef or inline MCP server config.`);
|
|
273
|
+
}
|
|
274
|
+
const remoteToolName = tool.mcpRef ?? tool.name;
|
|
275
|
+
const descriptorPromise = getRemoteMcpToolDescriptor(serverConfig, remoteToolName);
|
|
276
|
+
return [
|
|
277
|
+
{
|
|
278
|
+
name: tool.name,
|
|
279
|
+
description: tool.description,
|
|
280
|
+
inputSchemaPromise: descriptorPromise.then((descriptor) => descriptor?.inputSchema),
|
|
281
|
+
async invoke(input) {
|
|
282
|
+
const result = await withRecoveredMcpClient(serverConfig, (client) => client.callTool({
|
|
283
|
+
name: remoteToolName,
|
|
284
|
+
arguments: typeof input === "object" && input !== null ? input : {},
|
|
285
|
+
}));
|
|
286
|
+
const textParts = Array.isArray(result.content)
|
|
287
|
+
? result.content
|
|
288
|
+
.filter((item) => typeof item === "object" && item !== null && "type" in item)
|
|
289
|
+
.flatMap((item) => item.type === "text" && typeof item.text === "string" ? [item.text] : [])
|
|
290
|
+
: [];
|
|
291
|
+
return textParts.length > 0 ? textParts.join("\n\n") : JSON.stringify(result);
|
|
292
|
+
},
|
|
293
|
+
},
|
|
294
|
+
];
|
|
295
|
+
});
|
|
296
|
+
}
|
|
@@ -1,35 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export type McpServerConfig = {
|
|
4
|
-
transport?: "stdio" | "http" | "sse" | "websocket";
|
|
5
|
-
command?: string;
|
|
6
|
-
args?: string[];
|
|
7
|
-
env?: Record<string, string>;
|
|
8
|
-
cwd?: string;
|
|
9
|
-
url?: string;
|
|
10
|
-
token?: string;
|
|
11
|
-
headers?: Record<string, string>;
|
|
12
|
-
trustTier?: "trusted" | "reviewed" | "untrusted";
|
|
13
|
-
access?: "read-only" | "read-write";
|
|
14
|
-
tenantScope?: "workspace" | "project" | "tenant" | "cross-tenant";
|
|
15
|
-
approvalPolicy?: "always" | "write" | "never";
|
|
16
|
-
promptInjectionRisk?: "low" | "medium" | "high";
|
|
17
|
-
oauth?: {
|
|
18
|
-
provider?: string;
|
|
19
|
-
scopes?: string[];
|
|
20
|
-
};
|
|
21
|
-
labels?: string[];
|
|
22
|
-
};
|
|
23
|
-
export type McpToolDescriptor = {
|
|
24
|
-
name: string;
|
|
25
|
-
description?: string;
|
|
26
|
-
inputSchema?: Record<string, unknown>;
|
|
27
|
-
};
|
|
28
|
-
export declare function readMcpServerConfig(workspace: WorkspaceBundle, tool: WorkspaceBundle["tools"] extends Map<any, infer T> ? T : never): McpServerConfig | null;
|
|
29
|
-
export declare function getOrCreateMcpClient(config: McpServerConfig): Promise<Client>;
|
|
30
|
-
export declare function closeMcpClientsForWorkspace(workspace: WorkspaceBundle): Promise<void>;
|
|
31
|
-
export declare function __resetMcpClientCacheForTests(): void;
|
|
32
|
-
export declare function __setMcpClientCacheEntryForTests(config: McpServerConfig, clientPromise: Promise<Client>): void;
|
|
33
|
-
export declare function __setMcpClientLoaderForTests(loader: (config: McpServerConfig) => Promise<Client>): void;
|
|
34
|
-
export declare function listRemoteMcpTools(config: McpServerConfig): Promise<McpToolDescriptor[]>;
|
|
35
|
-
export declare function createMcpToolResolver(workspace: WorkspaceBundle): NonNullable<RuntimeAdapterOptions["toolResolver"]>;
|
|
1
|
+
export { AGENT_HARNESS_VERSION } from "../package-version.js";
|
|
2
|
+
export * from "./mcp/tool-support.js";
|