@botbotgo/agent-harness 0.0.134 → 0.0.136
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 +110 -49
- package/README.zh.md +102 -49
- package/dist/config/agents/direct.yaml +70 -71
- package/dist/config/agents/orchestra.yaml +90 -91
- package/dist/contracts/workspace.d.ts +12 -2
- package/dist/extensions.js +13 -1
- package/dist/init-project.js +19 -21
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/resource/mcp-tool-support.d.ts +4 -0
- package/dist/resource/mcp-tool-support.js +112 -35
- package/dist/resource/resource-impl.js +199 -7
- package/dist/runtime/adapter/runtime-shell.d.ts +3 -1
- package/dist/runtime/adapter/runtime-shell.js +2 -1
- package/dist/runtime/adapter/tool/tool-arguments.js +1 -0
- package/dist/runtime/adapter/tool/tool-hitl.js +3 -0
- package/dist/runtime/agent-runtime-adapter.d.ts +6 -0
- package/dist/runtime/agent-runtime-adapter.js +32 -2
- package/dist/runtime/harness.js +2 -0
- package/dist/tool-modules.d.ts +5 -0
- package/dist/tool-modules.js +10 -0
- package/dist/workspace/agent-binding-compiler.d.ts +2 -2
- package/dist/workspace/agent-binding-compiler.js +78 -6
- package/dist/workspace/compile.js +150 -6
- package/dist/workspace/object-loader.js +148 -53
- package/dist/workspace/resource-compilers.js +6 -0
- package/dist/workspace/support/source-collectors.js +1 -1
- package/dist/workspace/support/workspace-ref-utils.d.ts +1 -0
- package/dist/workspace/support/workspace-ref-utils.js +9 -0
- package/dist/workspace/tool-hydration.js +87 -13
- package/dist/workspace/yaml-object-reader.js +40 -13
- package/package.json +1 -1
|
@@ -1,11 +1,16 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { readdir } from "node:fs/promises";
|
|
1
4
|
import { ensureResourceSources } from "../resource/resource.js";
|
|
2
|
-
import {
|
|
5
|
+
import { ensureExternalResourceSource, isExternalSourceLocator, resolveResourcePackageRoot } from "../resource/sources.js";
|
|
6
|
+
import { loadWorkspaceObjects, readToolModuleItems, readYamlItems } from "./object-loader.js";
|
|
7
|
+
import { validateSkillMetadata } from "../runtime/support/skill-metadata.js";
|
|
3
8
|
import { parseEmbeddingModelObject, parseMcpServerObject, parseModelObject, parseToolObject, parseVectorStoreObject, validateEmbeddingModelObject, validateMcpServerObject, validateModelObject, validateToolObject, validateVectorStoreObject, } from "./resource-compilers.js";
|
|
4
9
|
import { validateAgent, validateTopology } from "./validate.js";
|
|
5
10
|
import { compileBinding } from "./agent-binding-compiler.js";
|
|
6
11
|
import { discoverSubagents, ensureDiscoverySources } from "./support/discovery.js";
|
|
7
12
|
import { collectAgentDiscoverySourceRefs, collectToolSourceRefs } from "./support/source-collectors.js";
|
|
8
|
-
import { getRoutingDefaultAgentId, getRoutingRules, resolveRefId, } from "./support/workspace-ref-utils.js";
|
|
13
|
+
import { getRoutingDefaultAgentId, getRuntimeResources, getRoutingRules, resolveRefId, } from "./support/workspace-ref-utils.js";
|
|
9
14
|
import { hydrateAgentMcpTools, hydrateResourceAndExternalTools } from "./tool-hydration.js";
|
|
10
15
|
function collectParsedResources(refs) {
|
|
11
16
|
const embeddings = new Map();
|
|
@@ -42,6 +47,17 @@ function validateWorkspaceResources(embeddings, mcpServers, models, vectorStores
|
|
|
42
47
|
models.forEach((model) => validateModelObject(model, models));
|
|
43
48
|
vectorStores.forEach((vectorStore) => validateVectorStoreObject(vectorStore));
|
|
44
49
|
tools.forEach((tool) => validateToolObject(tool, tools));
|
|
50
|
+
tools.forEach((tool) => {
|
|
51
|
+
if (!tool.embeddingModelRef) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const embeddingModelId = tool.embeddingModelRef.startsWith("embedding-model/")
|
|
55
|
+
? tool.embeddingModelRef.slice("embedding-model/".length)
|
|
56
|
+
: tool.embeddingModelRef;
|
|
57
|
+
if (!embeddings.has(embeddingModelId)) {
|
|
58
|
+
throw new Error(`Tool ${tool.id} references missing embedding model ${tool.embeddingModelRef}`);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
45
61
|
agents.forEach(validateAgent);
|
|
46
62
|
validateTopology(agents);
|
|
47
63
|
tools.forEach((tool) => {
|
|
@@ -82,6 +98,109 @@ function validateRoutingTargets(refs, agentsList) {
|
|
|
82
98
|
}
|
|
83
99
|
}
|
|
84
100
|
}
|
|
101
|
+
function resolveLocalResourceRoot(candidate, workspaceRoot) {
|
|
102
|
+
const resolved = path.resolve(workspaceRoot, candidate);
|
|
103
|
+
const resourceRoot = resolveResourcePackageRoot(resolved);
|
|
104
|
+
if (!resourceRoot) {
|
|
105
|
+
throw new Error(`Workspace resource ${candidate} is missing resources/package.json.`);
|
|
106
|
+
}
|
|
107
|
+
return resourceRoot;
|
|
108
|
+
}
|
|
109
|
+
async function resolveConfiguredResources(entries, workspaceRoot) {
|
|
110
|
+
const resolved = [];
|
|
111
|
+
for (const entry of entries) {
|
|
112
|
+
const key = entry.trim();
|
|
113
|
+
if (!key) {
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
const root = isExternalSourceLocator(key)
|
|
117
|
+
? await ensureExternalResourceSource(key, workspaceRoot)
|
|
118
|
+
: resolveLocalResourceRoot(key, workspaceRoot);
|
|
119
|
+
resolved.push({ key, root });
|
|
120
|
+
}
|
|
121
|
+
return resolved;
|
|
122
|
+
}
|
|
123
|
+
async function registerAttachedResourceTools(tools, resourceRoot) {
|
|
124
|
+
const toolsRoot = path.join(resourceRoot, "tools");
|
|
125
|
+
for (const { item, sourcePath } of await readYamlItems(toolsRoot, undefined, { recursive: true })) {
|
|
126
|
+
const parsed = parseToolObject({
|
|
127
|
+
id: typeof item.id === "string" ? item.id : path.basename(sourcePath).replace(/\.(yaml|yml|json)$/i, ""),
|
|
128
|
+
kind: "tool",
|
|
129
|
+
sourcePath,
|
|
130
|
+
value: item,
|
|
131
|
+
});
|
|
132
|
+
tools.set(parsed.id, parsed);
|
|
133
|
+
}
|
|
134
|
+
for (const { item, sourcePath } of await readToolModuleItems(toolsRoot)) {
|
|
135
|
+
const parsed = parseToolObject({
|
|
136
|
+
id: String(item.id),
|
|
137
|
+
kind: "tool",
|
|
138
|
+
sourcePath,
|
|
139
|
+
value: item,
|
|
140
|
+
});
|
|
141
|
+
tools.set(parsed.id, parsed);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
async function collectSkillRoots(root) {
|
|
145
|
+
try {
|
|
146
|
+
const entries = await readdir(root, { withFileTypes: true });
|
|
147
|
+
const skillDocument = entries.find((entry) => entry.isFile() && entry.name === "SKILL.md");
|
|
148
|
+
if (skillDocument) {
|
|
149
|
+
return [root];
|
|
150
|
+
}
|
|
151
|
+
const nested = await Promise.all(entries
|
|
152
|
+
.filter((entry) => entry.isDirectory())
|
|
153
|
+
.map((entry) => collectSkillRoots(path.join(root, entry.name))));
|
|
154
|
+
return nested.flat();
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
return [];
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
async function registerWorkspaceSkillRegistry(skillCollectionRoots) {
|
|
161
|
+
const registry = new Map();
|
|
162
|
+
for (const skillsRoot of skillCollectionRoots) {
|
|
163
|
+
for (const skillRoot of await collectSkillRoots(skillsRoot)) {
|
|
164
|
+
const metadata = validateSkillMetadata(skillRoot);
|
|
165
|
+
const existing = registry.get(metadata.name);
|
|
166
|
+
if (existing && existing !== skillRoot) {
|
|
167
|
+
throw new Error(`Duplicate skill name ${metadata.name} found in ${existing} and ${skillRoot}`);
|
|
168
|
+
}
|
|
169
|
+
registry.set(metadata.name, skillRoot);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return registry;
|
|
173
|
+
}
|
|
174
|
+
function validateToolNameConflicts(tools) {
|
|
175
|
+
const seen = new Map();
|
|
176
|
+
for (const tool of tools.values()) {
|
|
177
|
+
const existing = seen.get(tool.name);
|
|
178
|
+
if (existing && existing !== tool.sourcePath) {
|
|
179
|
+
throw new Error(`Duplicate tool name ${tool.name} found in ${existing} and ${tool.sourcePath}`);
|
|
180
|
+
}
|
|
181
|
+
seen.set(tool.name, tool.sourcePath);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
function resolveAgentSkillNames(agents, skillRegistry, skillCollectionRoots) {
|
|
185
|
+
for (const agent of agents) {
|
|
186
|
+
agent.skillPathRefs = agent.skillPathRefs.map((entry) => {
|
|
187
|
+
const registered = skillRegistry.get(entry);
|
|
188
|
+
if (registered) {
|
|
189
|
+
return registered;
|
|
190
|
+
}
|
|
191
|
+
if (path.isAbsolute(entry) || entry.includes("/") || entry.startsWith("builtin://")) {
|
|
192
|
+
return entry;
|
|
193
|
+
}
|
|
194
|
+
for (const skillsRoot of skillCollectionRoots) {
|
|
195
|
+
const candidate = path.join(skillsRoot, entry);
|
|
196
|
+
if (existsSync(path.join(candidate, "SKILL.md"))) {
|
|
197
|
+
return candidate;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return entry;
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}
|
|
85
204
|
export async function loadWorkspace(workspaceRoot, options = {}) {
|
|
86
205
|
const loaded = await loadWorkspaceObjects(workspaceRoot, options);
|
|
87
206
|
loaded.agents = await discoverSubagents(loaded.agents, workspaceRoot);
|
|
@@ -92,14 +211,39 @@ export async function loadWorkspace(workspaceRoot, options = {}) {
|
|
|
92
211
|
}
|
|
93
212
|
const { embeddings, mcpServers, models, vectorStores, tools } = collectParsedResources(loaded.refs);
|
|
94
213
|
await hydrateAgentMcpTools(loaded.agents, mcpServers, tools);
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
214
|
+
const configuredResources = Array.from(new Set([
|
|
215
|
+
...getRuntimeResources(loaded.refs),
|
|
216
|
+
...(options.resources ?? []),
|
|
217
|
+
]));
|
|
218
|
+
const resolvedConfiguredResources = await resolveConfiguredResources(configuredResources, workspaceRoot);
|
|
219
|
+
for (const resource of resolvedConfiguredResources) {
|
|
220
|
+
await registerAttachedResourceTools(tools, resource.root);
|
|
221
|
+
}
|
|
222
|
+
const localResourceRoot = resolveResourcePackageRoot(workspaceRoot);
|
|
223
|
+
const skillCollectionRoots = [
|
|
224
|
+
path.join(workspaceRoot, "modules", "skills"),
|
|
225
|
+
...(localResourceRoot ? [path.join(localResourceRoot, "skills")] : []),
|
|
226
|
+
...resolvedConfiguredResources.map((resource) => path.join(resource.root, "skills")),
|
|
227
|
+
];
|
|
228
|
+
const skillRegistry = await registerWorkspaceSkillRegistry(skillCollectionRoots);
|
|
229
|
+
resolveAgentSkillNames(loaded.agents, skillRegistry, skillCollectionRoots);
|
|
230
|
+
const collectedResources = collectToolSourceRefs(tools, loaded.agents, {
|
|
231
|
+
...options,
|
|
232
|
+
resources: configuredResources,
|
|
233
|
+
});
|
|
234
|
+
const externalResources = collectedResources.filter((resource) => isExternalSourceLocator(resource));
|
|
235
|
+
await ensureResourceSources(externalResources, workspaceRoot);
|
|
236
|
+
await hydrateResourceAndExternalTools(tools, externalResources, workspaceRoot);
|
|
237
|
+
validateToolNameConflicts(tools);
|
|
238
|
+
const resources = Array.from(new Set([
|
|
239
|
+
...(localResourceRoot ? [localResourceRoot] : []),
|
|
240
|
+
...collectedResources,
|
|
241
|
+
]));
|
|
98
242
|
validateWorkspaceResources(embeddings, mcpServers, models, vectorStores, tools, loaded.agents);
|
|
99
243
|
validateRoutingTargets(loaded.refs, loaded.agents);
|
|
100
244
|
return {
|
|
101
245
|
workspaceRoot,
|
|
102
|
-
|
|
246
|
+
resources,
|
|
103
247
|
refs: loaded.refs,
|
|
104
248
|
embeddings,
|
|
105
249
|
mcpServers,
|
|
@@ -93,6 +93,55 @@ function readRefArray(items) {
|
|
|
93
93
|
: undefined)
|
|
94
94
|
.filter((item) => Boolean(item));
|
|
95
95
|
}
|
|
96
|
+
function normalizeToolUsageOverrides(value) {
|
|
97
|
+
const record = asMutableObject(value);
|
|
98
|
+
if (!record) {
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
101
|
+
const directKeys = new Set(["config", "hitl", "retryable", "subprocess", "embeddingModelRef"]);
|
|
102
|
+
const directOverrides = {};
|
|
103
|
+
const configOverrides = {};
|
|
104
|
+
for (const [key, entry] of Object.entries(record)) {
|
|
105
|
+
if (directKeys.has(key)) {
|
|
106
|
+
directOverrides[key] = cloneConfigValue(entry);
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
configOverrides[key] = cloneConfigValue(entry);
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
...directOverrides,
|
|
113
|
+
...(Object.keys(configOverrides).length > 0
|
|
114
|
+
? {
|
|
115
|
+
config: {
|
|
116
|
+
...(asMutableObject(directOverrides.config) ?? {}),
|
|
117
|
+
...configOverrides,
|
|
118
|
+
},
|
|
119
|
+
}
|
|
120
|
+
: {}),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
function readToolBindingArray(items) {
|
|
124
|
+
return toArray(items)
|
|
125
|
+
.map((item) => {
|
|
126
|
+
if (typeof item === "string") {
|
|
127
|
+
return { ref: item };
|
|
128
|
+
}
|
|
129
|
+
if (typeof item !== "object" || !item || Array.isArray(item)) {
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
|
132
|
+
const entries = Object.entries(item);
|
|
133
|
+
if (entries.length !== 1 || typeof entries[0]?.[0] !== "string") {
|
|
134
|
+
throw new Error("Agent tools entries must be either a tool name string or a single-key override object");
|
|
135
|
+
}
|
|
136
|
+
const [ref, rawOverride] = entries[0];
|
|
137
|
+
const overrides = normalizeToolUsageOverrides(rawOverride);
|
|
138
|
+
return {
|
|
139
|
+
ref,
|
|
140
|
+
...(overrides ? { overrides } : {}),
|
|
141
|
+
};
|
|
142
|
+
})
|
|
143
|
+
.filter((item) => Boolean(item));
|
|
144
|
+
}
|
|
96
145
|
function readPathArray(items) {
|
|
97
146
|
return toArray(items)
|
|
98
147
|
.map((item) => typeof item === "string"
|
|
@@ -102,6 +151,11 @@ function readPathArray(items) {
|
|
|
102
151
|
: undefined)
|
|
103
152
|
.filter((item) => Boolean(item));
|
|
104
153
|
}
|
|
154
|
+
function readStringArray(items) {
|
|
155
|
+
return toArray(items)
|
|
156
|
+
.filter((item) => typeof item === "string" && item.trim().length > 0)
|
|
157
|
+
.map((item) => item.trim());
|
|
158
|
+
}
|
|
105
159
|
function readSingleRef(value) {
|
|
106
160
|
if (typeof value === "string" && value.trim()) {
|
|
107
161
|
return value;
|
|
@@ -151,7 +205,16 @@ const CONSUMED_AGENT_CONFIG_KEYS = [
|
|
|
151
205
|
"generalPurposeAgent",
|
|
152
206
|
"filesystem",
|
|
153
207
|
];
|
|
154
|
-
const
|
|
208
|
+
const NON_AGENT_CONFIG_ITEM_KEYS = [
|
|
209
|
+
"id",
|
|
210
|
+
"kind",
|
|
211
|
+
"description",
|
|
212
|
+
"capabilities",
|
|
213
|
+
"runtime",
|
|
214
|
+
"executionMode",
|
|
215
|
+
"sourcePath",
|
|
216
|
+
];
|
|
217
|
+
const RESERVED_AGENT_KEYS = [
|
|
155
218
|
"backend",
|
|
156
219
|
"modelRef",
|
|
157
220
|
"tools",
|
|
@@ -161,7 +224,7 @@ const RESERVED_EXECUTION_KEYS = [
|
|
|
161
224
|
"mcpServers",
|
|
162
225
|
"config",
|
|
163
226
|
];
|
|
164
|
-
const
|
|
227
|
+
const MIGRATED_AGENT_CONFIG_KEYS = [
|
|
165
228
|
"systemPrompt",
|
|
166
229
|
"checkpointer",
|
|
167
230
|
"interruptOn",
|
|
@@ -176,23 +239,19 @@ const MIGRATED_EXECUTION_CONFIG_KEYS = [
|
|
|
176
239
|
"generalPurposeAgent",
|
|
177
240
|
"filesystem",
|
|
178
241
|
];
|
|
179
|
-
function readExecutionConfig(value) {
|
|
180
|
-
return asMutableObject(value);
|
|
181
|
-
}
|
|
182
242
|
function normalizeAgentItemForMerge(item) {
|
|
183
243
|
const normalized = { ...item };
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
return normalized;
|
|
244
|
+
if (normalized.execution !== undefined) {
|
|
245
|
+
throw new Error("Agent spec.execution is no longer supported; move backend, modelRef, tools, skills, memory, subagents, mcpServers, and config directly under spec");
|
|
187
246
|
}
|
|
188
|
-
const config = asMutableObject(
|
|
247
|
+
const config = asMutableObject(normalized.config);
|
|
189
248
|
const runtime = readRuntimeConfig(normalized);
|
|
190
249
|
if (config) {
|
|
191
|
-
for (const key of
|
|
192
|
-
if (!(key in config) ||
|
|
250
|
+
for (const key of MIGRATED_AGENT_CONFIG_KEYS) {
|
|
251
|
+
if (!(key in config) || normalized[key] !== undefined) {
|
|
193
252
|
continue;
|
|
194
253
|
}
|
|
195
|
-
|
|
254
|
+
normalized[key] = cloneConfigValue(config[key]);
|
|
196
255
|
delete config[key];
|
|
197
256
|
}
|
|
198
257
|
if (config.runtimeMemory !== undefined && runtime?.runtimeMemory === undefined) {
|
|
@@ -203,26 +262,24 @@ function normalizeAgentItemForMerge(item) {
|
|
|
203
262
|
}
|
|
204
263
|
}
|
|
205
264
|
if (config && Object.keys(config).length > 0) {
|
|
206
|
-
|
|
265
|
+
normalized.config = config;
|
|
207
266
|
}
|
|
208
267
|
else {
|
|
209
|
-
delete
|
|
268
|
+
delete normalized.config;
|
|
210
269
|
}
|
|
211
|
-
normalized.execution = execution;
|
|
212
270
|
return normalized;
|
|
213
271
|
}
|
|
214
272
|
function readExecutionAgentConfig(item) {
|
|
215
|
-
const
|
|
216
|
-
const
|
|
217
|
-
|
|
273
|
+
const config = asMutableObject(item.config) ?? {};
|
|
274
|
+
const directExecutionConfig = Object.fromEntries(Object.entries(item).filter(([key]) => !RESERVED_AGENT_KEYS.includes(key) &&
|
|
275
|
+
!NON_AGENT_CONFIG_ITEM_KEYS.includes(key)));
|
|
218
276
|
return {
|
|
219
277
|
...config,
|
|
220
278
|
...directExecutionConfig,
|
|
221
279
|
};
|
|
222
280
|
}
|
|
223
281
|
function readExecutionValue(item, key, reader) {
|
|
224
|
-
|
|
225
|
-
return reader(execution?.[key]);
|
|
282
|
+
return reader(item[key]);
|
|
226
283
|
}
|
|
227
284
|
function readRuntimeConfig(item) {
|
|
228
285
|
return asMutableObject(item.runtime);
|
|
@@ -285,13 +342,22 @@ function readPassthroughConfig(item, consumedKeys) {
|
|
|
285
342
|
return Object.keys(passthrough).length > 0 ? passthrough : undefined;
|
|
286
343
|
}
|
|
287
344
|
function resolveExecutionBackend(item, current) {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
345
|
+
if (item.execution !== undefined || current?.execution !== undefined) {
|
|
346
|
+
throw new Error("Agent spec.execution is no longer supported; move backend, modelRef, tools, skills, memory, subagents, mcpServers, and config directly under spec");
|
|
347
|
+
}
|
|
348
|
+
const mode = typeof item.mode === "string"
|
|
349
|
+
? item.mode
|
|
350
|
+
: typeof current?.mode === "string"
|
|
351
|
+
? current.mode
|
|
352
|
+
: undefined;
|
|
353
|
+
if (typeof mode === "string" && mode.trim().length > 0) {
|
|
354
|
+
throw new Error("Agent mode is no longer supported; use backend");
|
|
355
|
+
}
|
|
356
|
+
const backend = typeof item.backend === "string"
|
|
357
|
+
? item.backend.trim().toLowerCase()
|
|
358
|
+
: typeof current?.backend === "string"
|
|
359
|
+
? current.backend.trim().toLowerCase()
|
|
360
|
+
: undefined;
|
|
295
361
|
if (backend === "langchain-v1") {
|
|
296
362
|
return "langchain-v1";
|
|
297
363
|
}
|
|
@@ -299,7 +365,7 @@ function resolveExecutionBackend(item, current) {
|
|
|
299
365
|
return "deepagent";
|
|
300
366
|
}
|
|
301
367
|
if (backend === "langgraph") {
|
|
302
|
-
throw new Error("Agent
|
|
368
|
+
throw new Error("Agent backend=langgraph is no longer supported; use backend=langchain-v1 or backend=deepagent");
|
|
303
369
|
}
|
|
304
370
|
return undefined;
|
|
305
371
|
}
|
|
@@ -345,29 +411,33 @@ function readAgentConfig(item, options = {}) {
|
|
|
345
411
|
};
|
|
346
412
|
}
|
|
347
413
|
export function parseAgentItem(item, sourcePath) {
|
|
414
|
+
const normalizedItem = normalizeAgentItemForMerge(item);
|
|
348
415
|
const moduleRoot = moduleRootForSourcePath(sourcePath, "agents");
|
|
349
|
-
const subagentRefs = readExecutionValue(
|
|
350
|
-
const
|
|
351
|
-
const
|
|
352
|
-
const
|
|
416
|
+
const subagentRefs = readExecutionValue(normalizedItem, "subagents", readRefArray);
|
|
417
|
+
const toolBindings = readExecutionValue(normalizedItem, "tools", readToolBindingArray);
|
|
418
|
+
const subagentPathRefs = readExecutionValue(normalizedItem, "subagents", readPathArray).map((entry) => resolveModuleRelativePath(entry, moduleRoot));
|
|
419
|
+
const executionMode = String(resolveExecutionBackend(normalizedItem) ?? "deepagent");
|
|
420
|
+
const runtime = readRuntimeConfig(normalizedItem);
|
|
353
421
|
return {
|
|
354
|
-
id: String(
|
|
422
|
+
id: String(normalizedItem.id),
|
|
355
423
|
executionMode: executionMode,
|
|
356
|
-
runtimeMemory: readRuntimeMemoryConfig(
|
|
357
|
-
capabilities: readCapabilities(
|
|
424
|
+
runtimeMemory: readRuntimeMemoryConfig(normalizedItem, runtime),
|
|
425
|
+
capabilities: readCapabilities(normalizedItem.capabilities) ?? (executionMode === "deepagent"
|
|
358
426
|
? { delegation: true, memory: true }
|
|
359
427
|
: { delegation: true, memory: true }),
|
|
360
|
-
description: String(
|
|
361
|
-
modelRef: readExecutionValue(
|
|
428
|
+
description: String(normalizedItem.description ?? ""),
|
|
429
|
+
modelRef: readExecutionValue(normalizedItem, "modelRef", readSingleRef) ?? "",
|
|
362
430
|
runRoot: typeof runtime?.runRoot === "string" ? runtime.runRoot : undefined,
|
|
363
|
-
toolRefs:
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
431
|
+
toolRefs: toolBindings.map((binding) => binding.ref),
|
|
432
|
+
toolBindings,
|
|
433
|
+
inlineTools: undefined,
|
|
434
|
+
mcpServers: readExecutionValue(normalizedItem, "mcpServers", readObjectArray),
|
|
435
|
+
skillPathRefs: readExecutionValue(normalizedItem, "skills", readStringArray),
|
|
436
|
+
memorySources: readExecutionValue(normalizedItem, "memory", readPathArray).map((entry) => resolveModuleRelativePath(entry, moduleRoot)),
|
|
367
437
|
subagentRefs,
|
|
368
438
|
subagentPathRefs,
|
|
369
|
-
langchainAgentConfig: normalizeModuleAgentConfig(readAgentConfig(
|
|
370
|
-
deepAgentConfig: normalizeModuleAgentConfig(readAgentConfig(
|
|
439
|
+
langchainAgentConfig: normalizeModuleAgentConfig(readAgentConfig(normalizedItem, { includeDelegationControls: true }), moduleRoot),
|
|
440
|
+
deepAgentConfig: normalizeModuleAgentConfig(readAgentConfig(normalizedItem, {
|
|
371
441
|
includeObjectBackend: true,
|
|
372
442
|
includeDelegationControls: false,
|
|
373
443
|
}), moduleRoot),
|
|
@@ -409,9 +479,19 @@ function mergeValues(base, override) {
|
|
|
409
479
|
}
|
|
410
480
|
function mergeRawItemRecord(records, key, item, sourcePath) {
|
|
411
481
|
const current = records.get(key);
|
|
482
|
+
const mergedItem = current ? mergeValues(current.item, item) : item;
|
|
483
|
+
const kind = typeof mergedItem.kind === "string" ? mergedItem.kind : undefined;
|
|
484
|
+
const type = typeof mergedItem.type === "string" ? mergedItem.type : undefined;
|
|
485
|
+
const resolvedSourcePath = current &&
|
|
486
|
+
kind === "tool" &&
|
|
487
|
+
type === "function" &&
|
|
488
|
+
isSupportedToolModulePath(current.sourcePath) &&
|
|
489
|
+
!isSupportedToolModulePath(sourcePath)
|
|
490
|
+
? current.sourcePath
|
|
491
|
+
: sourcePath;
|
|
412
492
|
const mergedRecord = {
|
|
413
|
-
item:
|
|
414
|
-
sourcePath,
|
|
493
|
+
item: mergedItem,
|
|
494
|
+
sourcePath: resolvedSourcePath,
|
|
415
495
|
};
|
|
416
496
|
records.set(key, mergedRecord);
|
|
417
497
|
return mergedRecord;
|
|
@@ -463,7 +543,7 @@ async function loadConventionalObjectsForRoot(root, mergedObjects) {
|
|
|
463
543
|
for (const objectRoot of conventionalDirectoryRoots(root, directory)) {
|
|
464
544
|
for (const { item, sourcePath } of await readYamlItems(objectRoot, undefined, { recursive: true })) {
|
|
465
545
|
const workspaceObject = parseWorkspaceObject(item, sourcePath);
|
|
466
|
-
if (!workspaceObject
|
|
546
|
+
if (!workspaceObject) {
|
|
467
547
|
continue;
|
|
468
548
|
}
|
|
469
549
|
mergeWorkspaceObjectRecord(mergedObjects, workspaceObject, item, sourcePath);
|
|
@@ -567,24 +647,39 @@ function isAgentKind(kind) {
|
|
|
567
647
|
return kind === "agent";
|
|
568
648
|
}
|
|
569
649
|
async function readConfigAgentItems(configRoot) {
|
|
570
|
-
const records = await readYamlItems(configRoot,
|
|
650
|
+
const records = await readYamlItems(configRoot, undefined, { recursive: true });
|
|
571
651
|
return records.filter(({ item, sourcePath }) => {
|
|
572
652
|
const kind = typeof item.kind === "string" ? item.kind : undefined;
|
|
573
653
|
if (!isAgentKind(kind)) {
|
|
574
654
|
return false;
|
|
575
655
|
}
|
|
576
|
-
|
|
656
|
+
const relativePath = path.relative(configRoot, sourcePath);
|
|
657
|
+
if (!relativePath || relativePath.startsWith("..")) {
|
|
658
|
+
return false;
|
|
659
|
+
}
|
|
660
|
+
return !relativePath.includes(path.sep) || relativePath.startsWith(`agents${path.sep}`);
|
|
577
661
|
});
|
|
578
662
|
}
|
|
579
663
|
export async function readToolModuleItems(root) {
|
|
580
664
|
if (!(await fileExists(root))) {
|
|
581
665
|
return [];
|
|
582
666
|
}
|
|
583
|
-
const
|
|
584
|
-
const
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
667
|
+
const files = [];
|
|
668
|
+
const pending = [root];
|
|
669
|
+
while (pending.length > 0) {
|
|
670
|
+
const current = pending.shift();
|
|
671
|
+
const entries = await readdir(current, { withFileTypes: true });
|
|
672
|
+
for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
|
|
673
|
+
const entryPath = path.join(current, entry.name);
|
|
674
|
+
if (entry.isDirectory()) {
|
|
675
|
+
pending.push(entryPath);
|
|
676
|
+
continue;
|
|
677
|
+
}
|
|
678
|
+
if (entry.isFile() && isSupportedToolModulePath(entry.name)) {
|
|
679
|
+
files.push(entryPath);
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
}
|
|
588
683
|
const records = [];
|
|
589
684
|
for (const filePath of files) {
|
|
590
685
|
const sourceText = await readFile(filePath, "utf8");
|
|
@@ -248,7 +248,13 @@ export function parseToolObject(object) {
|
|
|
248
248
|
...(mcpServerConfig && Object.keys(mcpServerConfig).length > 0 ? { mcpServer: mcpServerConfig } : {}),
|
|
249
249
|
}
|
|
250
250
|
: undefined),
|
|
251
|
+
subprocess: value.subprocess === true,
|
|
251
252
|
inputSchemaRef: typeof asObject(value.inputSchema)?.ref === "string" ? String(asObject(value.inputSchema)?.ref) : undefined,
|
|
253
|
+
embeddingModelRef: typeof value.embeddingModelRef === "string"
|
|
254
|
+
? value.embeddingModelRef
|
|
255
|
+
: typeof asObject(value.embeddingModel)?.ref === "string"
|
|
256
|
+
? String(asObject(value.embeddingModel)?.ref)
|
|
257
|
+
: undefined,
|
|
252
258
|
backendOperation: typeof backend?.operation === "string"
|
|
253
259
|
? backend.operation
|
|
254
260
|
: typeof value.operation === "string"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isExternalSourceLocator } from "../../resource/sources.js";
|
|
2
2
|
export function collectToolSourceRefs(tools, agents, options) {
|
|
3
|
-
const refs = new Set(options.
|
|
3
|
+
const refs = new Set(options.resources ?? []);
|
|
4
4
|
for (const tool of tools.values()) {
|
|
5
5
|
for (const ref of tool.bundleRefs) {
|
|
6
6
|
if (isExternalSourceLocator(ref)) {
|
|
@@ -33,6 +33,7 @@ export type ResilienceConfig = {
|
|
|
33
33
|
};
|
|
34
34
|
export declare function getWorkspaceObject(refs: Map<string, WorkspaceObject | ParsedAgentObject>, ref: string | undefined): WorkspaceObject | undefined;
|
|
35
35
|
export declare function getRuntimeDefaults(refs: Map<string, WorkspaceObject | ParsedAgentObject>): Record<string, unknown> | undefined;
|
|
36
|
+
export declare function getRuntimeResources(refs: Map<string, WorkspaceObject | ParsedAgentObject>): string[];
|
|
36
37
|
export declare function getRuntimeMemoryDefaults(refs: Map<string, WorkspaceObject | ParsedAgentObject>): Record<string, unknown> | undefined;
|
|
37
38
|
export declare function getRecoveryConfig(refs: Map<string, WorkspaceObject | ParsedAgentObject>): RecoveryConfig;
|
|
38
39
|
export declare function getConcurrencyConfig(refs: Map<string, WorkspaceObject | ParsedAgentObject>): ConcurrencyConfig;
|
|
@@ -26,6 +26,15 @@ export function getRuntimeDefaults(refs) {
|
|
|
26
26
|
}
|
|
27
27
|
return runtimes[0].value;
|
|
28
28
|
}
|
|
29
|
+
export function getRuntimeResources(refs) {
|
|
30
|
+
const runtimeDefaults = getRuntimeDefaults(refs);
|
|
31
|
+
if (!Array.isArray(runtimeDefaults?.resources)) {
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
return runtimeDefaults.resources
|
|
35
|
+
.filter((value) => typeof value === "string" && value.trim().length > 0)
|
|
36
|
+
.map((value) => value.trim());
|
|
37
|
+
}
|
|
29
38
|
export function getRuntimeMemoryDefaults(refs) {
|
|
30
39
|
const runtimeMemories = Array.from(refs.values()).filter((object) => !("executionMode" in object) && object.kind === "runtime-memory");
|
|
31
40
|
if (runtimeMemories.length === 0) {
|