@botbotgo/agent-harness 0.0.22 → 0.0.24
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 +60 -3
- package/dist/config/models.yaml +29 -0
- package/dist/mcp.js +2 -1
- package/dist/package-version.d.ts +1 -0
- package/dist/package-version.js +1 -0
- package/dist/resource/resource-impl.js +2 -1
- package/dist/runtime/harness.d.ts +9 -0
- package/dist/runtime/harness.js +124 -176
- package/dist/workspace/compile.js +3 -154
- package/dist/workspace/object-loader.js +113 -204
- package/dist/workspace/tool-hydration.d.ts +3 -0
- package/dist/workspace/tool-hydration.js +158 -0
- package/package.json +1 -1
- package/dist/config/model.yaml +0 -44
- /package/dist/config/{direct.yaml → agents/direct.yaml} +0 -0
- /package/dist/config/{orchestra.yaml → agents/orchestra.yaml} +0 -0
|
@@ -1,15 +1,12 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import { ensureResourceSources, listResourceTools, listResourceToolsForSource } from "../resource/resource.js";
|
|
4
|
-
import { listRemoteMcpTools } from "../resource/resource-impl.js";
|
|
5
|
-
import { ensureExternalResourceSource, isExternalSourceLocator } from "../resource/sources.js";
|
|
6
|
-
import { loadWorkspaceObjects, readToolModuleItems } from "./object-loader.js";
|
|
1
|
+
import { ensureResourceSources } from "../resource/resource.js";
|
|
2
|
+
import { loadWorkspaceObjects } from "./object-loader.js";
|
|
7
3
|
import { parseEmbeddingModelObject, parseMcpServerObject, parseModelObject, parseToolObject, parseVectorStoreObject, validateEmbeddingModelObject, validateMcpServerObject, validateModelObject, validateToolObject, validateVectorStoreObject, } from "./resource-compilers.js";
|
|
8
4
|
import { validateAgent, validateTopology } from "./validate.js";
|
|
9
5
|
import { compileBinding } from "./agent-binding-compiler.js";
|
|
10
6
|
import { discoverSubagents, ensureDiscoverySources } from "./support/discovery.js";
|
|
11
7
|
import { collectAgentDiscoverySourceRefs, collectToolSourceRefs } from "./support/source-collectors.js";
|
|
12
8
|
import { resolveRefId } from "./support/workspace-ref-utils.js";
|
|
9
|
+
import { hydrateAgentMcpTools, hydrateResourceAndExternalTools } from "./tool-hydration.js";
|
|
13
10
|
function collectParsedResources(refs) {
|
|
14
11
|
const embeddings = new Map();
|
|
15
12
|
const mcpServers = new Map();
|
|
@@ -39,154 +36,6 @@ function collectParsedResources(refs) {
|
|
|
39
36
|
}
|
|
40
37
|
return { embeddings, mcpServers, models, vectorStores, tools };
|
|
41
38
|
}
|
|
42
|
-
async function hydrateResourceAndExternalTools(tools, toolSourceRefs, workspaceRoot) {
|
|
43
|
-
for (const source of toolSourceRefs) {
|
|
44
|
-
if (isExternalSourceLocator(source)) {
|
|
45
|
-
const externalRoot = await ensureExternalResourceSource(source, workspaceRoot);
|
|
46
|
-
const discoveredToolRefs = [];
|
|
47
|
-
const sourcePrefix = `external.${createHash("sha256").update(source).digest("hex").slice(0, 12)}`;
|
|
48
|
-
for (const { item, sourcePath } of await readToolModuleItems(path.join(externalRoot, "tools"))) {
|
|
49
|
-
const toolId = typeof item.id === "string" ? item.id : undefined;
|
|
50
|
-
if (!toolId) {
|
|
51
|
-
continue;
|
|
52
|
-
}
|
|
53
|
-
const namespacedId = `${sourcePrefix}.${toolId}`;
|
|
54
|
-
const parsed = parseToolObject({
|
|
55
|
-
id: namespacedId,
|
|
56
|
-
kind: "tool",
|
|
57
|
-
sourcePath,
|
|
58
|
-
value: {
|
|
59
|
-
...item,
|
|
60
|
-
id: namespacedId,
|
|
61
|
-
},
|
|
62
|
-
});
|
|
63
|
-
tools.set(parsed.id, parsed);
|
|
64
|
-
discoveredToolRefs.push(`tool/${parsed.id}`);
|
|
65
|
-
}
|
|
66
|
-
const sourceTools = await listResourceToolsForSource(source, workspaceRoot);
|
|
67
|
-
const bundleRefs = [...sourceTools.map((tool) => tool.toolPath), ...discoveredToolRefs];
|
|
68
|
-
if (bundleRefs.length > 0) {
|
|
69
|
-
tools.set(source, {
|
|
70
|
-
id: source,
|
|
71
|
-
type: "bundle",
|
|
72
|
-
name: source,
|
|
73
|
-
description: `External tool resource loaded from ${source}`,
|
|
74
|
-
bundleRefs,
|
|
75
|
-
sourcePath: source,
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
for (const resourceTool of await listResourceTools(toolSourceRefs, workspaceRoot)) {
|
|
81
|
-
const existing = tools.get(resourceTool.toolPath);
|
|
82
|
-
tools.set(resourceTool.toolPath, {
|
|
83
|
-
id: resourceTool.toolPath,
|
|
84
|
-
type: existing?.type ?? "backend",
|
|
85
|
-
name: existing?.name || resourceTool.name,
|
|
86
|
-
description: existing?.description || resourceTool.description,
|
|
87
|
-
config: existing?.config,
|
|
88
|
-
backendOperation: existing?.backendOperation ?? resourceTool.backendOperation,
|
|
89
|
-
bundleRefs: existing?.bundleRefs ?? [],
|
|
90
|
-
hitl: existing?.hitl ?? resourceTool.hitl,
|
|
91
|
-
sourcePath: existing?.sourcePath ?? resourceTool.toolPath,
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
function toMcpServerConfig(server) {
|
|
96
|
-
return {
|
|
97
|
-
transport: server.transport,
|
|
98
|
-
command: server.command,
|
|
99
|
-
args: server.args,
|
|
100
|
-
env: server.env,
|
|
101
|
-
cwd: server.cwd,
|
|
102
|
-
url: server.url,
|
|
103
|
-
token: server.token,
|
|
104
|
-
headers: server.headers,
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
function readStringArray(value) {
|
|
108
|
-
return Array.isArray(value) ? value.filter((item) => typeof item === "string" && item.trim().length > 0) : [];
|
|
109
|
-
}
|
|
110
|
-
function compileRegexList(value, label) {
|
|
111
|
-
return readStringArray(value).map((pattern) => {
|
|
112
|
-
try {
|
|
113
|
-
return new RegExp(pattern);
|
|
114
|
-
}
|
|
115
|
-
catch (error) {
|
|
116
|
-
throw new Error(`${label} contains invalid regex ${JSON.stringify(pattern)}: ${error instanceof Error ? error.message : String(error)}`);
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
function compileMcpToolFilter(serverItem) {
|
|
121
|
-
return {
|
|
122
|
-
includeNames: new Set(readStringArray(serverItem.tools)),
|
|
123
|
-
excludeNames: new Set(readStringArray(serverItem.excludeTools)),
|
|
124
|
-
includePatterns: compileRegexList(serverItem.toolFilters ?? serverItem.toolFilter, "toolFilter"),
|
|
125
|
-
excludePatterns: compileRegexList(serverItem.excludeToolFilters ?? serverItem.excludeToolFilter, "excludeToolFilter"),
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
function shouldIncludeRemoteMcpTool(filter, toolName) {
|
|
129
|
-
const { includeNames, excludeNames, includePatterns, excludePatterns } = filter;
|
|
130
|
-
const includedByName = includeNames.size === 0 || includeNames.has(toolName);
|
|
131
|
-
const includedByPattern = includePatterns.length === 0 || includePatterns.some((pattern) => pattern.test(toolName));
|
|
132
|
-
if (!includedByName || !includedByPattern) {
|
|
133
|
-
return false;
|
|
134
|
-
}
|
|
135
|
-
if (excludeNames.has(toolName)) {
|
|
136
|
-
return false;
|
|
137
|
-
}
|
|
138
|
-
if (excludePatterns.some((pattern) => pattern.test(toolName))) {
|
|
139
|
-
return false;
|
|
140
|
-
}
|
|
141
|
-
return true;
|
|
142
|
-
}
|
|
143
|
-
async function hydrateAgentMcpTools(agents, mcpServers, tools) {
|
|
144
|
-
for (const agent of agents) {
|
|
145
|
-
const discoveredRefs = new Set(agent.toolRefs);
|
|
146
|
-
for (const item of agent.mcpServers ?? []) {
|
|
147
|
-
const name = typeof item.name === "string" && item.name.trim()
|
|
148
|
-
? item.name.trim()
|
|
149
|
-
: typeof item.id === "string" && item.id.trim()
|
|
150
|
-
? item.id.trim()
|
|
151
|
-
: "";
|
|
152
|
-
if (!name) {
|
|
153
|
-
throw new Error(`Agent ${agent.id} has an MCP server entry without a name`);
|
|
154
|
-
}
|
|
155
|
-
const serverId = `${agent.id}.${name}`;
|
|
156
|
-
const parsedServer = parseMcpServerObject({
|
|
157
|
-
id: serverId,
|
|
158
|
-
kind: "mcp",
|
|
159
|
-
sourcePath: agent.sourcePath,
|
|
160
|
-
value: item,
|
|
161
|
-
});
|
|
162
|
-
const filter = compileMcpToolFilter(item);
|
|
163
|
-
mcpServers.set(serverId, parsedServer);
|
|
164
|
-
const remoteTools = await listRemoteMcpTools(toMcpServerConfig(parsedServer));
|
|
165
|
-
for (const remoteTool of remoteTools) {
|
|
166
|
-
if (!shouldIncludeRemoteMcpTool(filter, remoteTool.name)) {
|
|
167
|
-
continue;
|
|
168
|
-
}
|
|
169
|
-
const toolId = `mcp.${agent.id}.${name}.${remoteTool.name}`;
|
|
170
|
-
tools.set(toolId, {
|
|
171
|
-
id: toolId,
|
|
172
|
-
type: "mcp",
|
|
173
|
-
name: remoteTool.name,
|
|
174
|
-
description: remoteTool.description ?? remoteTool.name,
|
|
175
|
-
config: {
|
|
176
|
-
mcp: {
|
|
177
|
-
serverRef: `mcp/${serverId}`,
|
|
178
|
-
},
|
|
179
|
-
},
|
|
180
|
-
mcpRef: remoteTool.name,
|
|
181
|
-
bundleRefs: [],
|
|
182
|
-
sourcePath: agent.sourcePath,
|
|
183
|
-
});
|
|
184
|
-
discoveredRefs.add(`tool/${toolId}`);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
agent.toolRefs = Array.from(discoveredRefs);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
39
|
function validateWorkspaceResources(embeddings, mcpServers, models, vectorStores, tools, agents) {
|
|
191
40
|
embeddings.forEach((embedding) => validateEmbeddingModelObject(embedding));
|
|
192
41
|
mcpServers.forEach((server) => validateMcpServerObject(server));
|
|
@@ -7,18 +7,7 @@ import { resolveIsolatedResourceModulePath } from "../resource/isolation.js";
|
|
|
7
7
|
import { resolveResourcePackageRoot } from "../resource/sources.js";
|
|
8
8
|
import { discoverToolModuleDefinitions, isSupportedToolModulePath } from "../tool-modules.js";
|
|
9
9
|
import { fileExists, listFilesRecursive, readYamlOrJson } from "../utils/fs.js";
|
|
10
|
-
const ROOT_AGENT_FILENAMES = [
|
|
11
|
-
"agent.yaml",
|
|
12
|
-
"agent.yml",
|
|
13
|
-
"orchestra.yaml",
|
|
14
|
-
"orchestra.yml",
|
|
15
|
-
"direct.yaml",
|
|
16
|
-
"direct.yml",
|
|
17
|
-
"research.yaml",
|
|
18
|
-
"research.yml",
|
|
19
|
-
];
|
|
20
10
|
const MODEL_FILENAMES = ["models.yaml", "models.yml"];
|
|
21
|
-
const LEGACY_GLOBAL_AGENT_FILENAMES = ["agent.yaml", "agent.yml"];
|
|
22
11
|
const CONVENTIONAL_OBJECT_DIRECTORIES = ["tools"];
|
|
23
12
|
function conventionalConfigRoot(root) {
|
|
24
13
|
if (path.basename(root) === "config" && existsSync(root) && statSync(root).isDirectory()) {
|
|
@@ -220,6 +209,27 @@ function readObjectArray(items) {
|
|
|
220
209
|
.map((item) => ({ ...item }));
|
|
221
210
|
return records.length > 0 ? records : undefined;
|
|
222
211
|
}
|
|
212
|
+
function readSharedAgentConfig(item) {
|
|
213
|
+
const middleware = readMiddlewareArray(item.middleware);
|
|
214
|
+
return {
|
|
215
|
+
...(typeof item.systemPrompt === "string" ? { systemPrompt: item.systemPrompt } : {}),
|
|
216
|
+
...(typeof item.checkpointer === "object" && item.checkpointer ? { checkpointer: item.checkpointer } : {}),
|
|
217
|
+
...(typeof item.interruptOn === "object" && item.interruptOn ? { interruptOn: item.interruptOn } : {}),
|
|
218
|
+
...(item.responseFormat !== undefined ? { responseFormat: item.responseFormat } : {}),
|
|
219
|
+
...(item.contextSchema !== undefined ? { contextSchema: item.contextSchema } : {}),
|
|
220
|
+
...(middleware ? { middleware } : {}),
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
function readLangchainAgentConfig(item) {
|
|
224
|
+
return readSharedAgentConfig(item);
|
|
225
|
+
}
|
|
226
|
+
function readDeepAgentConfig(item) {
|
|
227
|
+
return {
|
|
228
|
+
...readSharedAgentConfig(item),
|
|
229
|
+
...(typeof item.backend === "object" && item.backend ? { backend: item.backend } : {}),
|
|
230
|
+
...(typeof item.store === "object" && item.store ? { store: item.store } : {}),
|
|
231
|
+
};
|
|
232
|
+
}
|
|
223
233
|
export function parseAgentItem(item, sourcePath) {
|
|
224
234
|
const subagentRefs = readRefArray(item.subagents);
|
|
225
235
|
const subagentPathRefs = readPathArray(item.subagents);
|
|
@@ -239,44 +249,8 @@ export function parseAgentItem(item, sourcePath) {
|
|
|
239
249
|
memorySources: readPathArray(item.memory),
|
|
240
250
|
subagentRefs,
|
|
241
251
|
subagentPathRefs,
|
|
242
|
-
langchainAgentConfig:
|
|
243
|
-
|
|
244
|
-
typeof item.interruptOn === "object" ||
|
|
245
|
-
typeof item.checkpointer === "object" ||
|
|
246
|
-
item.responseFormat !== undefined ||
|
|
247
|
-
item.contextSchema !== undefined ||
|
|
248
|
-
item.middleware !== undefined
|
|
249
|
-
? {
|
|
250
|
-
...(typeof item.systemPrompt === "string" ? { systemPrompt: item.systemPrompt } : {}),
|
|
251
|
-
...(typeof item.interruptOn === "object" && item.interruptOn ? { interruptOn: item.interruptOn } : {}),
|
|
252
|
-
...(typeof item.checkpointer === "object" && item.checkpointer ? { checkpointer: item.checkpointer } : {}),
|
|
253
|
-
...(item.responseFormat !== undefined ? { responseFormat: item.responseFormat } : {}),
|
|
254
|
-
...(item.contextSchema !== undefined ? { contextSchema: item.contextSchema } : {}),
|
|
255
|
-
...(readMiddlewareArray(item.middleware) ? { middleware: readMiddlewareArray(item.middleware) } : {}),
|
|
256
|
-
}
|
|
257
|
-
: {}),
|
|
258
|
-
},
|
|
259
|
-
deepAgentConfig: {
|
|
260
|
-
...(typeof item.systemPrompt === "string" ||
|
|
261
|
-
typeof item.backend === "object" ||
|
|
262
|
-
typeof item.store === "object" ||
|
|
263
|
-
typeof item.checkpointer === "object" ||
|
|
264
|
-
typeof item.interruptOn === "object" ||
|
|
265
|
-
item.responseFormat !== undefined ||
|
|
266
|
-
item.contextSchema !== undefined ||
|
|
267
|
-
item.middleware !== undefined
|
|
268
|
-
? {
|
|
269
|
-
...(typeof item.systemPrompt === "string" ? { systemPrompt: item.systemPrompt } : {}),
|
|
270
|
-
...(typeof item.backend === "object" && item.backend ? { backend: item.backend } : {}),
|
|
271
|
-
...(typeof item.store === "object" && item.store ? { store: item.store } : {}),
|
|
272
|
-
...(typeof item.checkpointer === "object" && item.checkpointer ? { checkpointer: item.checkpointer } : {}),
|
|
273
|
-
...(typeof item.interruptOn === "object" && item.interruptOn ? { interruptOn: item.interruptOn } : {}),
|
|
274
|
-
...(item.responseFormat !== undefined ? { responseFormat: item.responseFormat } : {}),
|
|
275
|
-
...(item.contextSchema !== undefined ? { contextSchema: item.contextSchema } : {}),
|
|
276
|
-
...(readMiddlewareArray(item.middleware) ? { middleware: readMiddlewareArray(item.middleware) } : {}),
|
|
277
|
-
}
|
|
278
|
-
: {}),
|
|
279
|
-
},
|
|
252
|
+
langchainAgentConfig: readLangchainAgentConfig(item),
|
|
253
|
+
deepAgentConfig: readDeepAgentConfig(item),
|
|
280
254
|
sourcePath,
|
|
281
255
|
};
|
|
282
256
|
}
|
|
@@ -346,6 +320,89 @@ function mergeValues(base, override) {
|
|
|
346
320
|
}
|
|
347
321
|
return override;
|
|
348
322
|
}
|
|
323
|
+
function mergeRawItemRecord(records, key, item, sourcePath) {
|
|
324
|
+
const current = records.get(key);
|
|
325
|
+
const mergedRecord = {
|
|
326
|
+
item: current ? mergeValues(current.item, item) : item,
|
|
327
|
+
sourcePath,
|
|
328
|
+
};
|
|
329
|
+
records.set(key, mergedRecord);
|
|
330
|
+
return mergedRecord;
|
|
331
|
+
}
|
|
332
|
+
function mergeAgentRecord(records, item, sourcePath) {
|
|
333
|
+
const id = typeof item.id === "string" ? item.id : undefined;
|
|
334
|
+
if (!id) {
|
|
335
|
+
return null;
|
|
336
|
+
}
|
|
337
|
+
return mergeRawItemRecord(records, id, item, sourcePath);
|
|
338
|
+
}
|
|
339
|
+
function mergeWorkspaceObjectRecord(records, workspaceObject, item, sourcePath) {
|
|
340
|
+
mergeRawItemRecord(records, `${workspaceObject.kind}/${workspaceObject.id}`, item, sourcePath);
|
|
341
|
+
}
|
|
342
|
+
async function loadNamedModelsForRoot(configRoot, mergedObjects) {
|
|
343
|
+
for (const { item, sourcePath } of await readNamedModelItems(configRoot)) {
|
|
344
|
+
const workspaceObject = parseWorkspaceObject(item, sourcePath);
|
|
345
|
+
if (!workspaceObject || workspaceObject.kind !== "model") {
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
mergeWorkspaceObjectRecord(mergedObjects, workspaceObject, item, sourcePath);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
async function loadConfigAgentsForRoot(configRoot, mergedAgents) {
|
|
352
|
+
for (const { item, sourcePath } of await readConfigAgentItems(configRoot)) {
|
|
353
|
+
mergeAgentRecord(mergedAgents, item, sourcePath);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
async function loadConventionalObjectsForRoot(root, mergedObjects) {
|
|
357
|
+
for (const directory of CONVENTIONAL_OBJECT_DIRECTORIES) {
|
|
358
|
+
for (const objectRoot of conventionalDirectoryRoots(root, directory)) {
|
|
359
|
+
for (const { item, sourcePath } of await readYamlItems(objectRoot, undefined, { recursive: true })) {
|
|
360
|
+
const workspaceObject = parseWorkspaceObject(item, sourcePath);
|
|
361
|
+
if (!workspaceObject || workspaceObject.kind === "tool") {
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
mergeWorkspaceObjectRecord(mergedObjects, workspaceObject, item, sourcePath);
|
|
365
|
+
}
|
|
366
|
+
for (const { item, sourcePath } of await readToolModuleItems(objectRoot)) {
|
|
367
|
+
const workspaceObject = parseWorkspaceObject(item, sourcePath);
|
|
368
|
+
if (!workspaceObject) {
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
mergeWorkspaceObjectRecord(mergedObjects, workspaceObject, item, sourcePath);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
async function loadConfigObjectsForRoot(root, configRoot, mergedObjects) {
|
|
377
|
+
if (!conventionalConfigRoot(root)) {
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
for (const { item, sourcePath } of await readYamlItems(configRoot, undefined, { recursive: true })) {
|
|
381
|
+
const workspaceObject = parseWorkspaceObject(item, sourcePath);
|
|
382
|
+
if (!workspaceObject) {
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
if (isAgentKind(workspaceObject.kind) || workspaceObject.kind === "model") {
|
|
386
|
+
continue;
|
|
387
|
+
}
|
|
388
|
+
mergeWorkspaceObjectRecord(mergedObjects, workspaceObject, item, sourcePath);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
async function loadRootObjects(root, mergedObjects) {
|
|
392
|
+
for (const { item, sourcePath } of (await readYamlItems(root)).filter(({ sourcePath: fullPath }) => !fullPath.includes(`${path.sep}config${path.sep}`) &&
|
|
393
|
+
!fullPath.includes(`${path.sep}resources${path.sep}`) &&
|
|
394
|
+
!fullPath.includes(`${path.sep}agents${path.sep}`) &&
|
|
395
|
+
!CONVENTIONAL_OBJECT_DIRECTORIES.some((directory) => fullPath.includes(`${path.sep}${directory}${path.sep}`)))) {
|
|
396
|
+
const workspaceObject = parseWorkspaceObject(item, sourcePath);
|
|
397
|
+
if (!workspaceObject) {
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
if (workspaceObject.kind === "tool" || workspaceObject.kind === "mcp" || workspaceObject.kind === "model") {
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
mergeWorkspaceObjectRecord(mergedObjects, workspaceObject, item, sourcePath);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
349
406
|
export async function readYamlItems(root, relativeDir, options = {}) {
|
|
350
407
|
const targetRoot = relativeDir ? path.join(root, relativeDir) : root;
|
|
351
408
|
if (!(await fileExists(targetRoot))) {
|
|
@@ -405,15 +462,13 @@ function isAgentKind(kind) {
|
|
|
405
462
|
return kind === "deepagent" || kind === "langchain-agent";
|
|
406
463
|
}
|
|
407
464
|
async function readConfigAgentItems(configRoot) {
|
|
408
|
-
const records = await readYamlItems(configRoot,
|
|
465
|
+
const records = await readYamlItems(configRoot, "agents", { recursive: true });
|
|
409
466
|
return records.filter(({ item, sourcePath }) => {
|
|
410
467
|
const kind = typeof item.kind === "string" ? item.kind : undefined;
|
|
411
468
|
if (!isAgentKind(kind)) {
|
|
412
469
|
return false;
|
|
413
470
|
}
|
|
414
|
-
|
|
415
|
-
const filename = path.basename(sourcePath).toLowerCase();
|
|
416
|
-
return !(parentDir === configRoot && ROOT_AGENT_FILENAMES.includes(filename));
|
|
471
|
+
return sourcePath.includes(`${path.sep}agents${path.sep}`);
|
|
417
472
|
});
|
|
418
473
|
}
|
|
419
474
|
export async function readToolModuleItems(root) {
|
|
@@ -451,10 +506,6 @@ export async function readToolModuleItems(root) {
|
|
|
451
506
|
}
|
|
452
507
|
return records;
|
|
453
508
|
}
|
|
454
|
-
function isPrimaryAgentFile(sourcePath) {
|
|
455
|
-
const base = path.basename(sourcePath).toLowerCase();
|
|
456
|
-
return ROOT_AGENT_FILENAMES.includes(base);
|
|
457
|
-
}
|
|
458
509
|
function inferExecutionMode(item, current) {
|
|
459
510
|
const kind = typeof item.kind === "string" ? item.kind : typeof current?.kind === "string" ? current.kind : undefined;
|
|
460
511
|
if (kind === "langchain-agent") {
|
|
@@ -465,160 +516,18 @@ function inferExecutionMode(item, current) {
|
|
|
465
516
|
}
|
|
466
517
|
return undefined;
|
|
467
518
|
}
|
|
468
|
-
function extractSharedAgentDefaults(item) {
|
|
469
|
-
const defaults = {};
|
|
470
|
-
for (const key of ["modelRef", "runRoot", "checkpointer", "interruptOn"]) {
|
|
471
|
-
if (key in item) {
|
|
472
|
-
defaults[key] = item[key];
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
return defaults;
|
|
476
|
-
}
|
|
477
|
-
function applySharedAgentDefaults(globalDefaults, defaultsByMode, item, current) {
|
|
478
|
-
const executionMode = inferExecutionMode(item, current);
|
|
479
|
-
const defaults = {
|
|
480
|
-
...globalDefaults,
|
|
481
|
-
...(executionMode ? defaultsByMode[executionMode] : {}),
|
|
482
|
-
};
|
|
483
|
-
const merged = { ...item };
|
|
484
|
-
for (const [key, value] of Object.entries(defaults)) {
|
|
485
|
-
if (key in merged) {
|
|
486
|
-
continue;
|
|
487
|
-
}
|
|
488
|
-
if (current && key in current) {
|
|
489
|
-
continue;
|
|
490
|
-
}
|
|
491
|
-
merged[key] = value;
|
|
492
|
-
}
|
|
493
|
-
return merged;
|
|
494
|
-
}
|
|
495
519
|
export async function loadWorkspaceObjects(workspaceRoot, options = {}) {
|
|
496
520
|
const refs = new Map();
|
|
497
521
|
const mergedAgents = new Map();
|
|
498
522
|
const mergedObjects = new Map();
|
|
499
523
|
const roots = [frameworkWorkspaceRoot(), ...(options.overlayRoots ?? []), workspaceRoot];
|
|
500
|
-
let sharedAgentDefaults = {};
|
|
501
|
-
let sharedAgentDefaultsByMode = {};
|
|
502
524
|
for (const root of roots) {
|
|
503
525
|
const configRoot = conventionalConfigRoot(root) ?? root;
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
continue;
|
|
510
|
-
}
|
|
511
|
-
const current = mergedAgents.get(id);
|
|
512
|
-
mergedAgents.set(id, {
|
|
513
|
-
item: current ? mergeValues(current.item, item) : item,
|
|
514
|
-
sourcePath,
|
|
515
|
-
});
|
|
516
|
-
const filename = path.basename(sourcePath).toLowerCase();
|
|
517
|
-
if (LEGACY_GLOBAL_AGENT_FILENAMES.includes(filename)) {
|
|
518
|
-
sharedAgentDefaults = mergeValues(sharedAgentDefaults, extractSharedAgentDefaults(item));
|
|
519
|
-
}
|
|
520
|
-
else {
|
|
521
|
-
const executionMode = inferExecutionMode(item, current?.item);
|
|
522
|
-
if (executionMode) {
|
|
523
|
-
sharedAgentDefaultsByMode = {
|
|
524
|
-
...sharedAgentDefaultsByMode,
|
|
525
|
-
[executionMode]: mergeValues(sharedAgentDefaultsByMode[executionMode] ?? {}, extractSharedAgentDefaults(item)),
|
|
526
|
-
};
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
|
-
for (const modelRoot of Array.from(new Set([configRoot]))) {
|
|
532
|
-
for (const { item, sourcePath } of await readNamedModelItems(modelRoot)) {
|
|
533
|
-
const workspaceObject = parseWorkspaceObject(item, sourcePath);
|
|
534
|
-
if (!workspaceObject || workspaceObject.kind !== "model") {
|
|
535
|
-
continue;
|
|
536
|
-
}
|
|
537
|
-
const ref = `${workspaceObject.kind}/${workspaceObject.id}`;
|
|
538
|
-
const current = mergedObjects.get(ref);
|
|
539
|
-
mergedObjects.set(ref, {
|
|
540
|
-
item: current ? mergeValues(current.item, item) : item,
|
|
541
|
-
sourcePath,
|
|
542
|
-
});
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
for (const { item, sourcePath } of await readConfigAgentItems(configRoot)) {
|
|
546
|
-
const id = typeof item.id === "string" ? item.id : undefined;
|
|
547
|
-
if (!id) {
|
|
548
|
-
continue;
|
|
549
|
-
}
|
|
550
|
-
const current = mergedAgents.get(id);
|
|
551
|
-
const itemWithDefaults = applySharedAgentDefaults(sharedAgentDefaults, sharedAgentDefaultsByMode, item, current?.item);
|
|
552
|
-
mergedAgents.set(id, {
|
|
553
|
-
item: current ? mergeValues(current.item, itemWithDefaults) : itemWithDefaults,
|
|
554
|
-
sourcePath,
|
|
555
|
-
});
|
|
556
|
-
}
|
|
557
|
-
for (const directory of CONVENTIONAL_OBJECT_DIRECTORIES) {
|
|
558
|
-
for (const objectRoot of conventionalDirectoryRoots(root, directory)) {
|
|
559
|
-
for (const { item, sourcePath } of await readYamlItems(objectRoot, undefined, { recursive: true })) {
|
|
560
|
-
const workspaceObject = parseWorkspaceObject(item, sourcePath);
|
|
561
|
-
if (!workspaceObject || workspaceObject.kind === "tool") {
|
|
562
|
-
continue;
|
|
563
|
-
}
|
|
564
|
-
const ref = `${workspaceObject.kind}/${workspaceObject.id}`;
|
|
565
|
-
const current = mergedObjects.get(ref);
|
|
566
|
-
mergedObjects.set(ref, {
|
|
567
|
-
item: current ? mergeValues(current.item, item) : item,
|
|
568
|
-
sourcePath,
|
|
569
|
-
});
|
|
570
|
-
}
|
|
571
|
-
for (const { item, sourcePath } of await readToolModuleItems(objectRoot)) {
|
|
572
|
-
const workspaceObject = parseWorkspaceObject(item, sourcePath);
|
|
573
|
-
if (!workspaceObject) {
|
|
574
|
-
continue;
|
|
575
|
-
}
|
|
576
|
-
const ref = `${workspaceObject.kind}/${workspaceObject.id}`;
|
|
577
|
-
const current = mergedObjects.get(ref);
|
|
578
|
-
mergedObjects.set(ref, {
|
|
579
|
-
item: current ? mergeValues(current.item, item) : item,
|
|
580
|
-
sourcePath,
|
|
581
|
-
});
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
if (conventionalConfigRoot(root)) {
|
|
586
|
-
for (const { item, sourcePath } of await readYamlItems(configRoot, undefined, { recursive: true })) {
|
|
587
|
-
const workspaceObject = parseWorkspaceObject(item, sourcePath);
|
|
588
|
-
if (!workspaceObject) {
|
|
589
|
-
continue;
|
|
590
|
-
}
|
|
591
|
-
if (isAgentKind(workspaceObject.kind) ||
|
|
592
|
-
workspaceObject.kind === "model") {
|
|
593
|
-
continue;
|
|
594
|
-
}
|
|
595
|
-
const ref = `${workspaceObject.kind}/${workspaceObject.id}`;
|
|
596
|
-
const current = mergedObjects.get(ref);
|
|
597
|
-
mergedObjects.set(ref, {
|
|
598
|
-
item: current ? mergeValues(current.item, item) : item,
|
|
599
|
-
sourcePath,
|
|
600
|
-
});
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
for (const { item, sourcePath } of (await readYamlItems(root)).filter(({ sourcePath: fullPath }) => !fullPath.includes(`${path.sep}config${path.sep}`) &&
|
|
604
|
-
!fullPath.includes(`${path.sep}resources${path.sep}`) &&
|
|
605
|
-
!fullPath.includes(`${path.sep}agents${path.sep}`) &&
|
|
606
|
-
!CONVENTIONAL_OBJECT_DIRECTORIES.some((directory) => fullPath.includes(`${path.sep}${directory}${path.sep}`)) &&
|
|
607
|
-
!isPrimaryAgentFile(fullPath))) {
|
|
608
|
-
const workspaceObject = parseWorkspaceObject(item, sourcePath);
|
|
609
|
-
if (!workspaceObject) {
|
|
610
|
-
continue;
|
|
611
|
-
}
|
|
612
|
-
if (workspaceObject.kind === "tool" || workspaceObject.kind === "mcp" || workspaceObject.kind === "model") {
|
|
613
|
-
continue;
|
|
614
|
-
}
|
|
615
|
-
const ref = `${workspaceObject.kind}/${workspaceObject.id}`;
|
|
616
|
-
const current = mergedObjects.get(ref);
|
|
617
|
-
mergedObjects.set(ref, {
|
|
618
|
-
item: current ? mergeValues(current.item, item) : item,
|
|
619
|
-
sourcePath,
|
|
620
|
-
});
|
|
621
|
-
}
|
|
526
|
+
await loadNamedModelsForRoot(configRoot, mergedObjects);
|
|
527
|
+
await loadConfigAgentsForRoot(configRoot, mergedAgents);
|
|
528
|
+
await loadConventionalObjectsForRoot(root, mergedObjects);
|
|
529
|
+
await loadConfigObjectsForRoot(root, configRoot, mergedObjects);
|
|
530
|
+
await loadRootObjects(root, mergedObjects);
|
|
622
531
|
}
|
|
623
532
|
const agents = Array.from(mergedAgents.values()).map(({ item, sourcePath }) => parseAgentItem(item, sourcePath));
|
|
624
533
|
for (const [ref, { item, sourcePath }] of mergedObjects) {
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { ParsedAgentObject, ParsedMcpServerObject, ParsedToolObject } from "../contracts/types.js";
|
|
2
|
+
export declare function hydrateResourceAndExternalTools(tools: Map<string, ParsedToolObject>, toolSourceRefs: string[], workspaceRoot: string): Promise<void>;
|
|
3
|
+
export declare function hydrateAgentMcpTools(agents: ParsedAgentObject[], mcpServers: Map<string, ParsedMcpServerObject>, tools: Map<string, ParsedToolObject>): Promise<void>;
|