@botbotgo/agent-harness 0.0.135 → 0.0.137

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.
@@ -6,7 +6,6 @@ import { resolveIsolatedResourceModulePath } from "../resource/isolation.js";
6
6
  import { isExternalSourceLocator, resolveResourcePackageRoot } from "../resource/sources.js";
7
7
  import { discoverToolModuleDefinitions, isSupportedToolModulePath } from "../tool-modules.js";
8
8
  import { fileExists } from "../utils/fs.js";
9
- import { parseToolObject } from "./resource-compilers.js";
10
9
  import { readNamedModelItems, readNamedYamlItems, readYamlItems, } from "./yaml-object-reader.js";
11
10
  export { normalizeYamlItem, readYamlItems } from "./yaml-object-reader.js";
12
11
  const CONVENTIONAL_OBJECT_DIRECTORIES = ["tools"];
@@ -94,19 +93,66 @@ function readRefArray(items) {
94
93
  : undefined)
95
94
  .filter((item) => Boolean(item));
96
95
  }
96
+ function readPrefixedRefArray(items, prefix) {
97
+ return toArray(items)
98
+ .map((item) => {
99
+ if (typeof item === "string") {
100
+ const value = item.trim();
101
+ if (!value) {
102
+ return undefined;
103
+ }
104
+ return value.startsWith(`${prefix}/`) ? value : `${prefix}/${value}`;
105
+ }
106
+ if (typeof item === "object" && item && "ref" in item && typeof item.ref === "string") {
107
+ const value = String(item.ref).trim();
108
+ return value || undefined;
109
+ }
110
+ return undefined;
111
+ })
112
+ .filter((item) => Boolean(item));
113
+ }
114
+ function normalizeToolUsageOverrides(value) {
115
+ const record = asMutableObject(value);
116
+ if (!record) {
117
+ return undefined;
118
+ }
119
+ const directKeys = new Set(["config", "hitl", "retryable", "subprocess", "embeddingModel", "embeddingModelRef"]);
120
+ const directOverrides = {};
121
+ const configOverrides = {};
122
+ for (const [key, entry] of Object.entries(record)) {
123
+ if (directKeys.has(key)) {
124
+ directOverrides[key] = cloneConfigValue(entry);
125
+ continue;
126
+ }
127
+ configOverrides[key] = cloneConfigValue(entry);
128
+ }
129
+ return {
130
+ ...directOverrides,
131
+ ...(Object.keys(configOverrides).length > 0
132
+ ? {
133
+ config: {
134
+ ...(asMutableObject(directOverrides.config) ?? {}),
135
+ ...configOverrides,
136
+ },
137
+ }
138
+ : {}),
139
+ };
140
+ }
97
141
  function readToolBindingArray(items) {
98
142
  return toArray(items)
99
143
  .map((item) => {
100
144
  if (typeof item === "string") {
101
145
  return { ref: item };
102
146
  }
103
- if (typeof item !== "object" || !item || !("ref" in item) || typeof item.ref !== "string") {
147
+ if (typeof item !== "object" || !item || Array.isArray(item)) {
104
148
  return undefined;
105
149
  }
106
- const { ref, ...rest } = item;
107
- const overrides = Object.keys(rest).length > 0
108
- ? cloneConfigValue(rest)
109
- : undefined;
150
+ const entries = Object.entries(item);
151
+ if (entries.length !== 1 || typeof entries[0]?.[0] !== "string") {
152
+ throw new Error("Agent tools entries must be either a tool name string or a single-key override object");
153
+ }
154
+ const [ref, rawOverride] = entries[0];
155
+ const overrides = normalizeToolUsageOverrides(rawOverride);
110
156
  return {
111
157
  ref,
112
158
  ...(overrides ? { overrides } : {}),
@@ -114,69 +160,6 @@ function readToolBindingArray(items) {
114
160
  })
115
161
  .filter((item) => Boolean(item));
116
162
  }
117
- function readInlineToolObjects(items, sourcePath, agentId) {
118
- const sourceDir = path.dirname(sourcePath);
119
- const bindings = [];
120
- const inlineTools = [];
121
- toArray(items).forEach((item, index) => {
122
- if (typeof item === "string") {
123
- bindings.push({ ref: item });
124
- return;
125
- }
126
- if (typeof item !== "object" || !item) {
127
- return;
128
- }
129
- if ("ref" in item && typeof item.ref === "string") {
130
- const { ref, ...rest } = item;
131
- const overrides = Object.keys(rest).length > 0
132
- ? cloneConfigValue(rest)
133
- : undefined;
134
- bindings.push({ ref, ...(overrides ? { overrides } : {}) });
135
- return;
136
- }
137
- const raw = cloneConfigValue(item);
138
- const implementation = asObject(raw.implementation);
139
- const name = typeof raw.name === "string" && raw.name.trim().length > 0
140
- ? raw.name.trim()
141
- : typeof raw.id === "string" && raw.id.trim().length > 0
142
- ? raw.id.trim()
143
- : `tool-${index + 1}`;
144
- const syntheticId = `${agentId}__${name}`;
145
- const implementationPath = typeof implementation?.path === "string"
146
- ? resolveModuleRelativePath(path.resolve(sourceDir, implementation.path), undefined)
147
- : undefined;
148
- const inferredType = typeof raw.type === "string"
149
- ? raw.type
150
- : raw.refs !== undefined || raw.bundle !== undefined
151
- ? "bundle"
152
- : raw.providerTool !== undefined || raw.provider !== undefined
153
- ? "provider"
154
- : raw.backend !== undefined || raw.operation !== undefined
155
- ? "backend"
156
- : raw.mcp !== undefined
157
- ? "mcp"
158
- : "function";
159
- if (inferredType === "function" && !implementationPath) {
160
- throw new Error(`Inline tool ${name} must define implementation.path`);
161
- }
162
- const workspaceObject = {
163
- id: syntheticId,
164
- kind: "tool",
165
- sourcePath: implementationPath ?? sourcePath,
166
- value: {
167
- id: syntheticId,
168
- ...raw,
169
- ...(typeof implementation?.export === "string" && typeof raw.implementationName !== "string"
170
- ? { implementationName: implementation.export }
171
- : {}),
172
- },
173
- };
174
- const parsedTool = parseToolObject(workspaceObject);
175
- inlineTools.push(parsedTool);
176
- bindings.push({ ref: `tool/${syntheticId}` });
177
- });
178
- return { bindings, inlineTools };
179
- }
180
163
  function readPathArray(items) {
181
164
  return toArray(items)
182
165
  .map((item) => typeof item === "string"
@@ -186,6 +169,11 @@ function readPathArray(items) {
186
169
  : undefined)
187
170
  .filter((item) => Boolean(item));
188
171
  }
172
+ function readStringArray(items) {
173
+ return toArray(items)
174
+ .filter((item) => typeof item === "string" && item.trim().length > 0)
175
+ .map((item) => item.trim());
176
+ }
189
177
  function readSingleRef(value) {
190
178
  if (typeof value === "string" && value.trim()) {
191
179
  return value;
@@ -207,6 +195,20 @@ function readObjectArray(items) {
207
195
  .map((item) => ({ ...item }));
208
196
  return records.length > 0 ? records : undefined;
209
197
  }
198
+ function readMcpServerArray(items) {
199
+ const records = toArray(items)
200
+ .map((item) => {
201
+ if (typeof item === "string" && item.trim()) {
202
+ return { ref: item.startsWith("mcp/") ? item : `mcp/${item.trim()}` };
203
+ }
204
+ if (typeof item === "object" && item !== null && !Array.isArray(item)) {
205
+ return { ...item };
206
+ }
207
+ return undefined;
208
+ })
209
+ .filter((item) => Boolean(item));
210
+ return records.length > 0 ? records : undefined;
211
+ }
210
212
  function readCapabilities(value) {
211
213
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
212
214
  return undefined;
@@ -235,7 +237,16 @@ const CONSUMED_AGENT_CONFIG_KEYS = [
235
237
  "generalPurposeAgent",
236
238
  "filesystem",
237
239
  ];
238
- const RESERVED_EXECUTION_KEYS = [
240
+ const NON_AGENT_CONFIG_ITEM_KEYS = [
241
+ "id",
242
+ "kind",
243
+ "description",
244
+ "capabilities",
245
+ "runtime",
246
+ "executionMode",
247
+ "sourcePath",
248
+ ];
249
+ const RESERVED_AGENT_KEYS = [
239
250
  "backend",
240
251
  "modelRef",
241
252
  "tools",
@@ -245,7 +256,7 @@ const RESERVED_EXECUTION_KEYS = [
245
256
  "mcpServers",
246
257
  "config",
247
258
  ];
248
- const MIGRATED_EXECUTION_CONFIG_KEYS = [
259
+ const MIGRATED_AGENT_CONFIG_KEYS = [
249
260
  "systemPrompt",
250
261
  "checkpointer",
251
262
  "interruptOn",
@@ -260,23 +271,19 @@ const MIGRATED_EXECUTION_CONFIG_KEYS = [
260
271
  "generalPurposeAgent",
261
272
  "filesystem",
262
273
  ];
263
- function readExecutionConfig(value) {
264
- return asMutableObject(value);
265
- }
266
274
  function normalizeAgentItemForMerge(item) {
267
275
  const normalized = { ...item };
268
- const execution = readExecutionConfig(normalized.execution);
269
- if (!execution) {
270
- return normalized;
276
+ if (normalized.execution !== undefined) {
277
+ throw new Error("Agent spec.execution is no longer supported; move backend, modelRef, tools, skills, memory, subagents, mcpServers, and config directly under spec");
271
278
  }
272
- const config = asMutableObject(execution.config);
279
+ const config = asMutableObject(normalized.config);
273
280
  const runtime = readRuntimeConfig(normalized);
274
281
  if (config) {
275
- for (const key of MIGRATED_EXECUTION_CONFIG_KEYS) {
276
- if (!(key in config) || execution[key] !== undefined) {
282
+ for (const key of MIGRATED_AGENT_CONFIG_KEYS) {
283
+ if (!(key in config) || normalized[key] !== undefined) {
277
284
  continue;
278
285
  }
279
- execution[key] = cloneConfigValue(config[key]);
286
+ normalized[key] = cloneConfigValue(config[key]);
280
287
  delete config[key];
281
288
  }
282
289
  if (config.runtimeMemory !== undefined && runtime?.runtimeMemory === undefined) {
@@ -287,35 +294,47 @@ function normalizeAgentItemForMerge(item) {
287
294
  }
288
295
  }
289
296
  if (config && Object.keys(config).length > 0) {
290
- execution.config = config;
297
+ normalized.config = config;
291
298
  }
292
299
  else {
293
- delete execution.config;
300
+ delete normalized.config;
294
301
  }
295
- normalized.execution = execution;
296
302
  return normalized;
297
303
  }
298
304
  function readExecutionAgentConfig(item) {
299
- const execution = readExecutionConfig(item.execution) ?? {};
300
- const config = asMutableObject(execution.config) ?? {};
301
- const directExecutionConfig = Object.fromEntries(Object.entries(execution).filter(([key]) => !RESERVED_EXECUTION_KEYS.includes(key)));
305
+ const config = asMutableObject(item.config) ?? {};
306
+ const directExecutionConfig = Object.fromEntries(Object.entries(item).filter(([key]) => !RESERVED_AGENT_KEYS.includes(key) &&
307
+ !NON_AGENT_CONFIG_ITEM_KEYS.includes(key)));
302
308
  return {
303
309
  ...config,
304
310
  ...directExecutionConfig,
305
311
  };
306
312
  }
307
313
  function readExecutionValue(item, key, reader) {
308
- const execution = readExecutionConfig(item.execution);
309
- return reader(execution?.[key]);
314
+ return reader(item[key]);
310
315
  }
311
316
  function readRuntimeConfig(item) {
312
317
  return asMutableObject(item.runtime);
313
318
  }
314
319
  function readRuntimeMemoryConfig(item, runtime) {
320
+ if (typeof runtime?.runtimeMemory === "string" && runtime.runtimeMemory.trim()) {
321
+ return {
322
+ ref: runtime.runtimeMemory.startsWith("runtime-memory/")
323
+ ? runtime.runtimeMemory
324
+ : `runtime-memory/${runtime.runtimeMemory.trim()}`,
325
+ };
326
+ }
315
327
  if (typeof runtime?.runtimeMemory === "object" && runtime.runtimeMemory && !Array.isArray(runtime.runtimeMemory)) {
316
328
  return cloneConfigValue(runtime.runtimeMemory);
317
329
  }
318
330
  const legacyExecutionConfig = readExecutionAgentConfig(item);
331
+ if (typeof legacyExecutionConfig.runtimeMemory === "string" && legacyExecutionConfig.runtimeMemory.trim()) {
332
+ return {
333
+ ref: legacyExecutionConfig.runtimeMemory.startsWith("runtime-memory/")
334
+ ? legacyExecutionConfig.runtimeMemory
335
+ : `runtime-memory/${legacyExecutionConfig.runtimeMemory.trim()}`,
336
+ };
337
+ }
319
338
  if (typeof legacyExecutionConfig.runtimeMemory === "object" &&
320
339
  legacyExecutionConfig.runtimeMemory &&
321
340
  !Array.isArray(legacyExecutionConfig.runtimeMemory)) {
@@ -369,13 +388,22 @@ function readPassthroughConfig(item, consumedKeys) {
369
388
  return Object.keys(passthrough).length > 0 ? passthrough : undefined;
370
389
  }
371
390
  function resolveExecutionBackend(item, current) {
372
- const execution = readExecutionConfig(item.execution) ?? readExecutionConfig(current?.execution);
373
- if (typeof execution?.mode === "string" && execution.mode.trim().length > 0) {
374
- throw new Error("Agent execution.mode is no longer supported; use execution.backend");
391
+ if (item.execution !== undefined || current?.execution !== undefined) {
392
+ throw new Error("Agent spec.execution is no longer supported; move backend, modelRef, tools, skills, memory, subagents, mcpServers, and config directly under spec");
375
393
  }
376
- const backend = typeof execution?.backend === "string"
377
- ? execution.backend.trim().toLowerCase()
378
- : undefined;
394
+ const mode = typeof item.mode === "string"
395
+ ? item.mode
396
+ : typeof current?.mode === "string"
397
+ ? current.mode
398
+ : undefined;
399
+ if (typeof mode === "string" && mode.trim().length > 0) {
400
+ throw new Error("Agent mode is no longer supported; use backend");
401
+ }
402
+ const backend = typeof item.backend === "string"
403
+ ? item.backend.trim().toLowerCase()
404
+ : typeof current?.backend === "string"
405
+ ? current.backend.trim().toLowerCase()
406
+ : undefined;
379
407
  if (backend === "langchain-v1") {
380
408
  return "langchain-v1";
381
409
  }
@@ -383,7 +411,7 @@ function resolveExecutionBackend(item, current) {
383
411
  return "deepagent";
384
412
  }
385
413
  if (backend === "langgraph") {
386
- throw new Error("Agent execution.backend=langgraph is no longer supported; use execution.backend=langchain-v1 or execution.backend=deepagent");
414
+ throw new Error("Agent backend=langgraph is no longer supported; use backend=langchain-v1 or backend=deepagent");
387
415
  }
388
416
  return undefined;
389
417
  }
@@ -400,14 +428,27 @@ function readSharedAgentConfigFields(config, options = {}) {
400
428
  }
401
429
  function readSharedAgentConfig(config) {
402
430
  const middleware = readMiddlewareArray(config.middleware);
431
+ const backend = typeof config.backend === "string" && config.backend.trim()
432
+ ? { ref: config.backend.startsWith("backend/") ? config.backend : `backend/${config.backend.trim()}` }
433
+ : typeof config.backend === "object" && config.backend
434
+ ? config.backend
435
+ : undefined;
436
+ const checkpointer = typeof config.checkpointer === "string" && config.checkpointer.trim()
437
+ ? { ref: config.checkpointer.startsWith("checkpointer/") ? config.checkpointer : `checkpointer/${config.checkpointer.trim()}` }
438
+ : (typeof config.checkpointer === "object" && config.checkpointer) || typeof config.checkpointer === "boolean"
439
+ ? config.checkpointer
440
+ : undefined;
441
+ const store = typeof config.store === "string" && config.store.trim()
442
+ ? { ref: config.store.startsWith("store/") ? config.store : `store/${config.store.trim()}` }
443
+ : typeof config.store === "object" && config.store
444
+ ? config.store
445
+ : undefined;
403
446
  return {
404
447
  ...((typeof config.systemPrompt === "string" && config.systemPrompt)
405
448
  || (typeof config.systemPrompt === "object" && config.systemPrompt && !Array.isArray(config.systemPrompt))
406
449
  ? { systemPrompt: cloneConfigValue(config.systemPrompt) }
407
450
  : {}),
408
- ...((typeof config.checkpointer === "object" && config.checkpointer) || typeof config.checkpointer === "boolean"
409
- ? { checkpointer: config.checkpointer }
410
- : {}),
451
+ ...(checkpointer !== undefined ? { checkpointer } : {}),
411
452
  ...(typeof config.interruptOn === "object" && config.interruptOn ? { interruptOn: config.interruptOn } : {}),
412
453
  ...(config.stateSchema !== undefined ? { stateSchema: config.stateSchema } : {}),
413
454
  ...(config.responseFormat !== undefined ? { responseFormat: config.responseFormat } : {}),
@@ -415,6 +456,8 @@ function readSharedAgentConfig(config) {
415
456
  ...(config.includeAgentName === "inline" ? { includeAgentName: "inline" } : {}),
416
457
  ...(config.version === "v1" || config.version === "v2" ? { version: config.version } : {}),
417
458
  ...(typeof config.filesystem === "object" && config.filesystem ? { filesystem: config.filesystem } : {}),
459
+ ...(backend ? { backend } : {}),
460
+ ...(store ? { store } : {}),
418
461
  ...(middleware ? { middleware } : {}),
419
462
  };
420
463
  }
@@ -424,37 +467,39 @@ function readAgentConfig(item, options = {}) {
424
467
  return {
425
468
  ...readSharedAgentConfig(config),
426
469
  ...readSharedAgentConfigFields(config, { includeDelegationControls: options.includeDelegationControls }),
427
- ...(options.includeObjectBackend && typeof config.backend === "object" && config.backend ? { backend: config.backend } : {}),
428
470
  ...(passthrough ? { passthrough } : {}),
429
471
  };
430
472
  }
431
473
  export function parseAgentItem(item, sourcePath) {
474
+ const normalizedItem = normalizeAgentItemForMerge(item);
432
475
  const moduleRoot = moduleRootForSourcePath(sourcePath, "agents");
433
- const subagentRefs = readExecutionValue(item, "subagents", readRefArray);
434
- const { bindings: toolBindings, inlineTools } = readInlineToolObjects(readExecutionValue(item, "tools", toArray), sourcePath, String(item.id));
435
- const subagentPathRefs = readExecutionValue(item, "subagents", readPathArray).map((entry) => resolveModuleRelativePath(entry, moduleRoot));
436
- const executionMode = String(resolveExecutionBackend(item) ?? "deepagent");
437
- const runtime = readRuntimeConfig(item);
476
+ const subagentRefs = readExecutionValue(normalizedItem, "subagents", readRefArray);
477
+ const toolBindings = readExecutionValue(normalizedItem, "tools", readToolBindingArray);
478
+ const subagentPathRefs = readExecutionValue(normalizedItem, "subagents", readPathArray)
479
+ .filter((entry) => path.isAbsolute(entry) || entry.startsWith("./") || entry.startsWith("../"))
480
+ .map((entry) => resolveModuleRelativePath(entry, moduleRoot));
481
+ const executionMode = String(resolveExecutionBackend(normalizedItem) ?? "deepagent");
482
+ const runtime = readRuntimeConfig(normalizedItem);
438
483
  return {
439
- id: String(item.id),
484
+ id: String(normalizedItem.id),
440
485
  executionMode: executionMode,
441
- runtimeMemory: readRuntimeMemoryConfig(item, runtime),
442
- capabilities: readCapabilities(item.capabilities) ?? (executionMode === "deepagent"
486
+ runtimeMemory: readRuntimeMemoryConfig(normalizedItem, runtime),
487
+ capabilities: readCapabilities(normalizedItem.capabilities) ?? (executionMode === "deepagent"
443
488
  ? { delegation: true, memory: true }
444
489
  : { delegation: true, memory: true }),
445
- description: String(item.description ?? ""),
446
- modelRef: readExecutionValue(item, "modelRef", readSingleRef) ?? "",
490
+ description: String(normalizedItem.description ?? ""),
491
+ modelRef: readExecutionValue(normalizedItem, "modelRef", readSingleRef) ?? "",
447
492
  runRoot: typeof runtime?.runRoot === "string" ? runtime.runRoot : undefined,
448
493
  toolRefs: toolBindings.map((binding) => binding.ref),
449
494
  toolBindings,
450
- inlineTools,
451
- mcpServers: readExecutionValue(item, "mcpServers", readObjectArray),
452
- skillPathRefs: readExecutionValue(item, "skills", readPathArray).map((entry) => resolveModuleRelativePath(entry, moduleRoot)),
453
- memorySources: readExecutionValue(item, "memory", readPathArray).map((entry) => resolveModuleRelativePath(entry, moduleRoot)),
495
+ inlineTools: undefined,
496
+ mcpServers: readExecutionValue(normalizedItem, "mcpServers", readMcpServerArray),
497
+ skillPathRefs: readExecutionValue(normalizedItem, "skills", (value) => readPrefixedRefArray(value, "skill")),
498
+ memorySources: readExecutionValue(normalizedItem, "memory", readPathArray).map((entry) => resolveModuleRelativePath(entry, moduleRoot)),
454
499
  subagentRefs,
455
500
  subagentPathRefs,
456
- langchainAgentConfig: normalizeModuleAgentConfig(readAgentConfig(item, { includeDelegationControls: true }), moduleRoot),
457
- deepAgentConfig: normalizeModuleAgentConfig(readAgentConfig(item, {
501
+ langchainAgentConfig: normalizeModuleAgentConfig(readAgentConfig(normalizedItem, { includeDelegationControls: true }), moduleRoot),
502
+ deepAgentConfig: normalizeModuleAgentConfig(readAgentConfig(normalizedItem, {
458
503
  includeObjectBackend: true,
459
504
  includeDelegationControls: false,
460
505
  }), moduleRoot),
@@ -560,7 +605,7 @@ async function loadConventionalObjectsForRoot(root, mergedObjects) {
560
605
  for (const objectRoot of conventionalDirectoryRoots(root, directory)) {
561
606
  for (const { item, sourcePath } of await readYamlItems(objectRoot, undefined, { recursive: true })) {
562
607
  const workspaceObject = parseWorkspaceObject(item, sourcePath);
563
- if (!workspaceObject || workspaceObject.kind === "tool") {
608
+ if (!workspaceObject) {
564
609
  continue;
565
610
  }
566
611
  mergeWorkspaceObjectRecord(mergedObjects, workspaceObject, item, sourcePath);
@@ -664,24 +709,39 @@ function isAgentKind(kind) {
664
709
  return kind === "agent";
665
710
  }
666
711
  async function readConfigAgentItems(configRoot) {
667
- const records = await readYamlItems(configRoot, "agents", { recursive: true });
712
+ const records = await readYamlItems(configRoot, undefined, { recursive: true });
668
713
  return records.filter(({ item, sourcePath }) => {
669
714
  const kind = typeof item.kind === "string" ? item.kind : undefined;
670
715
  if (!isAgentKind(kind)) {
671
716
  return false;
672
717
  }
673
- return sourcePath.includes(`${path.sep}agents${path.sep}`);
718
+ const relativePath = path.relative(configRoot, sourcePath);
719
+ if (!relativePath || relativePath.startsWith("..")) {
720
+ return false;
721
+ }
722
+ return !relativePath.includes(path.sep) || relativePath.startsWith(`agents${path.sep}`);
674
723
  });
675
724
  }
676
725
  export async function readToolModuleItems(root) {
677
726
  if (!(await fileExists(root))) {
678
727
  return [];
679
728
  }
680
- const entries = await readdir(root, { withFileTypes: true });
681
- const files = entries
682
- .filter((entry) => entry.isFile() && isSupportedToolModulePath(entry.name))
683
- .map((entry) => path.join(root, entry.name))
684
- .sort();
729
+ const files = [];
730
+ const pending = [root];
731
+ while (pending.length > 0) {
732
+ const current = pending.shift();
733
+ const entries = await readdir(current, { withFileTypes: true });
734
+ for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
735
+ const entryPath = path.join(current, entry.name);
736
+ if (entry.isDirectory()) {
737
+ pending.push(entryPath);
738
+ continue;
739
+ }
740
+ if (entry.isFile() && isSupportedToolModulePath(entry.name)) {
741
+ files.push(entryPath);
742
+ }
743
+ }
744
+ }
685
745
  const records = [];
686
746
  for (const filePath of files) {
687
747
  const sourceText = await readFile(filePath, "utf8");
@@ -220,7 +220,7 @@ export function parseToolObject(object) {
220
220
  const mcpServerConfig = mcp
221
221
  ? Object.fromEntries(Object.entries(mcp).filter(([key]) => key !== "ref" && key !== "serverRef" && key !== "tool"))
222
222
  : undefined;
223
- const bundleRefs = asRefArray(value.refs ?? value.bundle);
223
+ const bundleRefs = asRefArray(value.tools ?? value.refs ?? value.bundle);
224
224
  const inferredType = typeof value.type === "string"
225
225
  ? value.type
226
226
  : bundleRefs.length > 0
@@ -252,9 +252,11 @@ export function parseToolObject(object) {
252
252
  inputSchemaRef: typeof asObject(value.inputSchema)?.ref === "string" ? String(asObject(value.inputSchema)?.ref) : undefined,
253
253
  embeddingModelRef: typeof value.embeddingModelRef === "string"
254
254
  ? value.embeddingModelRef
255
- : typeof asObject(value.embeddingModel)?.ref === "string"
256
- ? String(asObject(value.embeddingModel)?.ref)
257
- : undefined,
255
+ : typeof value.embeddingModel === "string"
256
+ ? `embedding-model/${String(value.embeddingModel).trim()}`
257
+ : typeof asObject(value.embeddingModel)?.ref === "string"
258
+ ? String(asObject(value.embeddingModel)?.ref)
259
+ : undefined,
258
260
  backendOperation: typeof backend?.operation === "string"
259
261
  ? backend.operation
260
262
  : 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.resourceSources ?? []);
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) {
@@ -104,7 +104,7 @@ function normalizeKind(kind) {
104
104
  }
105
105
  export function normalizeYamlItem(item) {
106
106
  if (item.kind === "DeepAgent" || item.kind === "LangChainAgent") {
107
- throw new Error(`YAML object kind ${String(item.kind)} is no longer supported; use kind: Agent with spec.execution.backend instead`);
107
+ throw new Error(`YAML object kind ${String(item.kind)} is no longer supported; use kind: Agent with spec.backend instead`);
108
108
  }
109
109
  const metadata = asObject(item.metadata);
110
110
  const spec = asObject(item.spec);
@@ -144,7 +144,7 @@ async function objectItemsFromDocument(document, sourcePath) {
144
144
  ? normalizeCatalogSpec(document)
145
145
  : catalogKind === "Backends"
146
146
  ? normalizeCatalogSpec(document, { defaultKind: "Backend" })
147
- : catalogKind === "Tools"
147
+ : catalogKind === "Tools" || catalogKind === "ToolSets"
148
148
  ? normalizeCatalogSpec(document, { defaultKind: "Tool" })
149
149
  : catalogKind === "McpServers"
150
150
  ? normalizeCatalogSpec(document, { defaultKind: "McpServer" })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botbotgo/agent-harness",
3
- "version": "0.0.135",
3
+ "version": "0.0.137",
4
4
  "description": "Workspace runtime for multi-agent applications",
5
5
  "type": "module",
6
6
  "packageManager": "npm@10.9.2",