@botbotgo/agent-harness 0.0.155 → 0.0.157

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.
@@ -1,4 +1,4 @@
1
- import type { ApprovalRecord, CancelOptions, HarnessEvent, HarnessStreamItem, RuntimeHealthSnapshot, MessageContent, RunRecord, RunStartOptions, RestartConversationOptions, RuntimeAdapterOptions, ResumeOptions, RunOptions, RunResult, RunSummary, MemorizeInput, MemorizeResult, RecallInput, RecallResult, ThreadSummary, ThreadRecord, WorkspaceBundle } from "../contracts/types.js";
1
+ import type { ApprovalRecord, ArtifactListing, CancelOptions, HarnessEvent, HarnessStreamItem, RuntimeHealthSnapshot, ListMemoriesInput, ListMemoriesResult, MessageContent, RemoveMemoryInput, RunRecord, RunStartOptions, RestartConversationOptions, RuntimeAdapterOptions, RuntimeEvaluationExport, RuntimeEvaluationExportInput, ResumeOptions, RunOptions, RunResult, RunSummary, MemoryRecord, MemorizeInput, MemorizeResult, RecallInput, RecallResult, UpdateMemoryInput, ThreadSummary, ThreadRecord, WorkspaceBundle } from "../contracts/types.js";
2
2
  import { type ToolMcpServerOptions } from "../mcp.js";
3
3
  import { type InventoryAgentRecord, type InventorySkillRecord } from "./harness/system/inventory.js";
4
4
  import type { RequirementAssessmentOptions } from "./harness/system/skill-requirements.js";
@@ -70,6 +70,9 @@ export declare class AgentHarnessRuntime {
70
70
  }): Promise<RunSummary[]>;
71
71
  memorize(input: MemorizeInput): Promise<MemorizeResult>;
72
72
  recall(input: RecallInput): Promise<RecallResult>;
73
+ listMemories(input?: ListMemoriesInput): Promise<ListMemoriesResult>;
74
+ updateMemory(input: UpdateMemoryInput): Promise<MemoryRecord>;
75
+ removeMemory(input: RemoveMemoryInput): Promise<MemoryRecord>;
73
76
  getRun(runId: string): Promise<RunRecord | null>;
74
77
  private getSession;
75
78
  getThread(threadId: string): Promise<ThreadRecord | null>;
@@ -79,6 +82,10 @@ export declare class AgentHarnessRuntime {
79
82
  runId?: string;
80
83
  }): Promise<ApprovalRecord[]>;
81
84
  getApproval(approvalId: string): Promise<ApprovalRecord | null>;
85
+ listArtifacts(threadId: string, runId: string): Promise<ArtifactListing>;
86
+ readArtifact(threadId: string, runId: string, artifactPath: string): Promise<unknown>;
87
+ listRunEvents(threadId: string, runId: string): Promise<HarnessEvent[]>;
88
+ exportEvaluationBundle(input: RuntimeEvaluationExportInput): Promise<RuntimeEvaluationExport>;
82
89
  listAgentSkills(agentId: string, options?: RequirementAssessmentOptions): InventorySkillRecord[];
83
90
  getAgent(agentId: string, options?: RequirementAssessmentOptions): InventoryAgentRecord | null;
84
91
  describeWorkspaceInventory(options?: RequirementAssessmentOptions): {
@@ -102,6 +109,8 @@ export declare class AgentHarnessRuntime {
102
109
  private invokeWithHistory;
103
110
  private resolveMemoryNamespace;
104
111
  private getWorkspaceId;
112
+ private summarizeMemoryContent;
113
+ private matchesMemoryFilters;
105
114
  private resolveRecallScopes;
106
115
  private matchesRecallScope;
107
116
  private getMemoryScopeBoost;
@@ -113,6 +122,7 @@ export declare class AgentHarnessRuntime {
113
122
  private createMem0MemoryRecord;
114
123
  private rankRecallCandidates;
115
124
  private rebuildRuntimeMemoryVectorIndex;
125
+ private refreshStructuredMemoryScope;
116
126
  private buildRuntimeMemoryContext;
117
127
  private persistRuntimeMemoryCandidates;
118
128
  private persistStructuredMemoryCandidates;
@@ -31,7 +31,7 @@ import { createDefaultHealthSnapshot, isInventoryEnabled, isThreadMemorySyncEnab
31
31
  import { Mem0IngestionSync, Mem0SemanticRecall, readMem0RuntimeConfig, } from "./harness/system/mem0-ingestion-sync.js";
32
32
  import { createRuntimeMemoryManager, RuntimeMemoryFormationSync, readRuntimeMemoryFormationConfig, } from "./harness/system/runtime-memory-manager.js";
33
33
  import { renderMemoryCandidatesMarkdown } from "./harness/system/runtime-memory-candidates.js";
34
- import { getMemoryRecord, listMemoryRecordsForScopes, persistStructuredMemoryRecords, } from "./harness/system/runtime-memory-records.js";
34
+ import { findMemoryRecordById, getMemoryRecord, listMemoryRecordsForScopes, persistStructuredMemoryRecords, removeMemoryRecord, updateMemoryRecord, } from "./harness/system/runtime-memory-records.js";
35
35
  import { consolidateStructuredMemoryScope } from "./harness/system/runtime-memory-consolidation.js";
36
36
  import { normalizeLangMemMemoryKind, readRuntimeMemoryMaintenanceConfig, readRuntimeMemoryPolicyConfig, resolveMemoryNamespace, scoreMemoryText, } from "./harness/system/runtime-memory-policy.js";
37
37
  import { resolveRuntimeAdapterOptions } from "./support/runtime-adapter-options.js";
@@ -361,6 +361,98 @@ export class AgentHarnessRuntime {
361
361
  .map(({ record }) => record);
362
362
  return { items };
363
363
  }
364
+ async listMemories(input = {}) {
365
+ const binding = this.defaultRuntimeEntryBinding;
366
+ if (!binding) {
367
+ throw new Error("listMemories requires a runtime entry binding.");
368
+ }
369
+ const workspaceId = this.getWorkspaceId(binding);
370
+ const scopes = Array.isArray(input.scopes) && input.scopes.length > 0
371
+ ? Array.from(new Set(input.scopes))
372
+ : ["thread", "agent", "workspace", "user", "project"];
373
+ const kinds = input.kinds?.length ? new Set(input.kinds) : null;
374
+ const statuses = input.status?.length ? new Set(input.status) : new Set(["active"]);
375
+ const limit = typeof input.limit === "number" && Number.isInteger(input.limit) && input.limit > 0
376
+ ? input.limit
377
+ : Number.POSITIVE_INFINITY;
378
+ const items = (await listMemoryRecordsForScopes(this.runtimeMemoryStore, scopes))
379
+ .filter((record) => statuses.has(record.status))
380
+ .filter((record) => !kinds || kinds.has(record.kind))
381
+ .filter((record) => this.matchesMemoryFilters(record, {
382
+ threadId: input.threadId,
383
+ agentId: input.agentId,
384
+ workspaceId: input.workspaceId ?? workspaceId,
385
+ userId: input.userId,
386
+ projectId: input.projectId,
387
+ }))
388
+ .sort((left, right) => right.lastConfirmedAt.localeCompare(left.lastConfirmedAt))
389
+ .slice(0, limit);
390
+ return { items };
391
+ }
392
+ async updateMemory(input) {
393
+ const binding = this.defaultRuntimeEntryBinding;
394
+ if (!binding) {
395
+ throw new Error("updateMemory requires a runtime entry binding.");
396
+ }
397
+ if (typeof input.memoryId !== "string" || input.memoryId.trim().length === 0) {
398
+ throw new Error("updateMemory requires a non-empty memoryId.");
399
+ }
400
+ const existing = await findMemoryRecordById(this.runtimeMemoryStore, input.memoryId.trim());
401
+ if (!existing) {
402
+ throw new Error(`Memory record not found: ${input.memoryId}`);
403
+ }
404
+ const updatedAt = new Date().toISOString();
405
+ const nextContent = typeof input.content === "string"
406
+ ? input.content.trim()
407
+ : existing.content;
408
+ if (nextContent.length === 0) {
409
+ throw new Error("updateMemory requires content to remain non-empty.");
410
+ }
411
+ const next = {
412
+ ...existing,
413
+ content: nextContent,
414
+ summary: typeof input.summary === "string"
415
+ ? input.summary.trim() || this.summarizeMemoryContent(nextContent)
416
+ : (typeof input.content === "string" ? this.summarizeMemoryContent(nextContent) : existing.summary),
417
+ status: input.status ?? existing.status,
418
+ confidence: typeof input.confidence === "number" ? Math.max(0, Math.min(1, input.confidence)) : existing.confidence,
419
+ expiresAt: input.expiresAt === undefined ? existing.expiresAt : (input.expiresAt ?? undefined),
420
+ sourceType: typeof input.sourceType === "string" && input.sourceType.trim().length > 0 ? input.sourceType.trim() : existing.sourceType,
421
+ sourceRefs: Array.isArray(input.sourceRefs)
422
+ ? Array.from(new Set(input.sourceRefs.map((item) => item.trim()).filter((item) => item.length > 0)))
423
+ : existing.sourceRefs,
424
+ tags: Array.isArray(input.tags)
425
+ ? Array.from(new Set(input.tags.map((item) => item.trim()).filter((item) => item.length > 0)))
426
+ : existing.tags,
427
+ observedAt: typeof input.observedAt === "string" && input.observedAt.trim().length > 0 ? input.observedAt : existing.observedAt,
428
+ lastConfirmedAt: typeof input.lastConfirmedAt === "string" && input.lastConfirmedAt.trim().length > 0
429
+ ? input.lastConfirmedAt
430
+ : updatedAt,
431
+ provenance: input.provenance ? { ...existing.provenance, ...input.provenance } : existing.provenance,
432
+ revision: existing.revision + 1,
433
+ };
434
+ await updateMemoryRecord(this.runtimeMemoryStore, next, updatedAt);
435
+ await this.rebuildRuntimeMemoryVectorIndex();
436
+ await this.refreshStructuredMemoryScope(binding, next);
437
+ return next;
438
+ }
439
+ async removeMemory(input) {
440
+ const binding = this.defaultRuntimeEntryBinding;
441
+ if (!binding) {
442
+ throw new Error("removeMemory requires a runtime entry binding.");
443
+ }
444
+ if (typeof input.memoryId !== "string" || input.memoryId.trim().length === 0) {
445
+ throw new Error("removeMemory requires a non-empty memoryId.");
446
+ }
447
+ const existing = await findMemoryRecordById(this.runtimeMemoryStore, input.memoryId.trim());
448
+ if (!existing) {
449
+ throw new Error(`Memory record not found: ${input.memoryId}`);
450
+ }
451
+ await removeMemoryRecord(this.runtimeMemoryStore, existing.scope, existing.id);
452
+ await this.rebuildRuntimeMemoryVectorIndex();
453
+ await this.refreshStructuredMemoryScope(binding, existing);
454
+ return existing;
455
+ }
364
456
  async getRun(runId) {
365
457
  return this.persistence.getRun(runId);
366
458
  }
@@ -383,6 +475,51 @@ export class AgentHarnessRuntime {
383
475
  persistence: this.persistence,
384
476
  }, approvalId);
385
477
  }
478
+ async listArtifacts(threadId, runId) {
479
+ return this.persistence.listArtifacts(threadId, runId);
480
+ }
481
+ async readArtifact(threadId, runId, artifactPath) {
482
+ return this.persistence.readArtifact(threadId, runId, artifactPath);
483
+ }
484
+ async listRunEvents(threadId, runId) {
485
+ return this.persistence.listRunEvents(threadId, runId);
486
+ }
487
+ async exportEvaluationBundle(input) {
488
+ const thread = await this.getThread(input.sessionId);
489
+ const run = await this.getRun(input.requestId);
490
+ const approvals = await this.listApprovals({ threadId: input.sessionId, runId: input.requestId });
491
+ const transcript = await this.persistence.listThreadMessages(input.sessionId, 500);
492
+ const events = await this.persistence.listRunEvents(input.sessionId, input.requestId);
493
+ const runtimeHealth = await this.getHealth();
494
+ const artifactsListing = input.includeArtifacts === false
495
+ ? { items: [] }
496
+ : await this.persistence.listArtifacts(input.sessionId, input.requestId);
497
+ const artifacts = await Promise.all(artifactsListing.items.map(async (artifact) => ({
498
+ ...artifact,
499
+ ...(input.includeArtifactContents === true
500
+ ? { content: await this.persistence.readArtifact(input.sessionId, input.requestId, artifact.path) }
501
+ : {}),
502
+ })));
503
+ return {
504
+ session: thread ? toSessionRecord(thread) : null,
505
+ request: run ? toRequestRecord(run) : null,
506
+ approvals,
507
+ transcript,
508
+ events,
509
+ artifacts,
510
+ runtimeHealth,
511
+ ...(typeof input.expectedOutput === "string" && input.expectedOutput.trim().length > 0
512
+ ? { expectedOutput: input.expectedOutput.trim() }
513
+ : {}),
514
+ rubric: Array.isArray(input.rubric)
515
+ ? input.rubric.filter((item) => typeof item === "string" && item.trim().length > 0).map((item) => item.trim())
516
+ : [],
517
+ tags: Array.isArray(input.tags)
518
+ ? input.tags.filter((item) => typeof item === "string" && item.trim().length > 0).map((item) => item.trim())
519
+ : [],
520
+ ...(input.metadata ? { metadata: { ...input.metadata } } : {}),
521
+ };
522
+ }
386
523
  listAgentSkills(agentId, options = {}) {
387
524
  return listWorkspaceAgentSkills(this.workspace, agentId, {
388
525
  assessRequirements: isInventoryEnabled(this.workspace),
@@ -514,7 +651,7 @@ export class AgentHarnessRuntime {
514
651
  const template = this.runtimeMemoryPolicy?.namespaces[scope] ?? `memories/${scope}s/{${scope}Id}`;
515
652
  return resolveMemoryNamespace(template, {
516
653
  threadId: options.threadId,
517
- agentId: binding.agent.id,
654
+ agentId: options.agentId ?? binding.agent.id,
518
655
  workspaceId,
519
656
  userId: options.userId ?? "default",
520
657
  projectId: options.projectId ?? workspaceId,
@@ -524,6 +661,27 @@ export class AgentHarnessRuntime {
524
661
  const workspaceRoot = binding.harnessRuntime.workspaceRoot ?? this.workspace.workspaceRoot;
525
662
  return path.basename(workspaceRoot) || "default";
526
663
  }
664
+ summarizeMemoryContent(content) {
665
+ return (content.trim().split("\n")[0] || content.trim()).slice(0, 240);
666
+ }
667
+ matchesMemoryFilters(record, filters) {
668
+ if (filters.threadId && record.provenance.threadId !== filters.threadId) {
669
+ return false;
670
+ }
671
+ if (filters.agentId && record.provenance.agentId !== filters.agentId) {
672
+ return false;
673
+ }
674
+ if (filters.workspaceId && record.provenance.workspaceId !== filters.workspaceId) {
675
+ return false;
676
+ }
677
+ if (filters.userId && record.provenance.userId !== filters.userId) {
678
+ return false;
679
+ }
680
+ if (filters.projectId && record.provenance.projectId !== filters.projectId) {
681
+ return false;
682
+ }
683
+ return true;
684
+ }
527
685
  resolveRecallScopes(input) {
528
686
  if (Array.isArray(input.scopes) && input.scopes.length > 0) {
529
687
  return Array.from(new Set(input.scopes));
@@ -755,6 +913,30 @@ export class AgentHarnessRuntime {
755
913
  // Fail open: vector indexing must not break durable memory writes.
756
914
  }
757
915
  }
916
+ async refreshStructuredMemoryScope(binding, record) {
917
+ const provenance = record.provenance;
918
+ const maxEntries = record.scope === "thread" ? 12 : 20;
919
+ const titleByScope = {
920
+ thread: "Thread Structured Memory",
921
+ agent: "Agent Structured Memory",
922
+ workspace: "Workspace Structured Memory",
923
+ user: "User Structured Memory",
924
+ project: "Project Structured Memory",
925
+ };
926
+ await consolidateStructuredMemoryScope({
927
+ store: this.runtimeMemoryStore,
928
+ namespace: this.resolveMemoryNamespace(record.scope, binding, {
929
+ threadId: provenance.threadId,
930
+ agentId: provenance.agentId,
931
+ userId: provenance.userId,
932
+ projectId: provenance.projectId,
933
+ }),
934
+ title: titleByScope[record.scope],
935
+ scope: record.scope,
936
+ maxEntries,
937
+ config: this.runtimeMemoryMaintenanceConfig ?? undefined,
938
+ });
939
+ }
758
940
  async buildRuntimeMemoryContext(binding, threadId, input) {
759
941
  const query = typeof input === "string" ? input : JSON.stringify(input ?? "");
760
942
  const workspaceId = this.getWorkspaceId(binding);
@@ -1256,3 +1438,40 @@ export class AgentHarnessRuntime {
1256
1438
  }, thread, nowMs);
1257
1439
  }
1258
1440
  }
1441
+ function toRequestSummary(summary) {
1442
+ return {
1443
+ requestId: summary.runId,
1444
+ sessionId: summary.threadId,
1445
+ agentId: summary.agentId,
1446
+ executionMode: summary.executionMode,
1447
+ adapterKind: summary.adapterKind,
1448
+ createdAt: summary.createdAt,
1449
+ updatedAt: summary.updatedAt,
1450
+ state: summary.state,
1451
+ checkpointRef: summary.checkpointRef,
1452
+ resumable: summary.resumable,
1453
+ startedAt: summary.startedAt,
1454
+ endedAt: summary.endedAt,
1455
+ lastActivityAt: summary.lastActivityAt,
1456
+ currentAgentId: summary.currentAgentId,
1457
+ delegationChain: summary.delegationChain,
1458
+ runtimeSnapshot: summary.runtimeSnapshot,
1459
+ };
1460
+ }
1461
+ function toSessionRecord(record) {
1462
+ return {
1463
+ sessionId: record.threadId,
1464
+ entryAgentId: record.entryAgentId,
1465
+ currentAgentId: record.currentAgentId,
1466
+ currentState: record.currentState,
1467
+ latestRequestId: record.latestRunId,
1468
+ createdAt: record.createdAt,
1469
+ updatedAt: record.updatedAt,
1470
+ messages: record.messages,
1471
+ requests: record.runs.map(toRequestSummary),
1472
+ pendingDecision: record.pendingDecision,
1473
+ };
1474
+ }
1475
+ function toRequestRecord(record) {
1476
+ return toRequestSummary(record);
1477
+ }
@@ -337,6 +337,12 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
337
337
  const store = resolveStoreConfig(agent, refs);
338
338
  const checkpointer = resolveCheckpointerConfig(agent, refs);
339
339
  const runtimeMemory = resolveRuntimeMemoryConfig(agent, refs);
340
+ const runtimeFilesystemDefaults = agent.executionMode === "langchain-v1"
341
+ ? asObject(runtimeDefaults?.filesystem)
342
+ : undefined;
343
+ const compiledFilesystemConfig = agent.executionMode === "langchain-v1"
344
+ ? mergeConfigObjects(runtimeFilesystemDefaults, getAgentExecutionObject(agent, "filesystem", { executionMode: "langchain-v1" }))
345
+ : undefined;
340
346
  const runRoot = typeof agent.runRoot === "string" && agent.runRoot.trim().length > 0
341
347
  ? path.resolve(workspaceRoot, agent.runRoot)
342
348
  : typeof runtimeDefaults?.runRoot === "string" && runtimeDefaults.runRoot.trim().length > 0
@@ -362,7 +368,7 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
362
368
  langchain: {
363
369
  passthrough,
364
370
  interruptOn: resolveInterruptOn(agent),
365
- filesystem: getAgentExecutionObject(agent, "filesystem", { executionMode: "langchain-v1" }),
371
+ filesystem: compiledFilesystemConfig,
366
372
  subagents: compileSubagents(agent, agents, workspaceRoot, models, tools, compiledAgentSkills, compiledAgentModel),
367
373
  memory: compiledAgentMemory,
368
374
  skills: compiledAgentSkills,
@@ -6,7 +6,7 @@ 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 { readNamedModelItems, readNamedYamlItems, readYamlItems, } from "./yaml-object-reader.js";
9
+ import { readNamedYamlItems, readYamlItems, } from "./yaml-object-reader.js";
10
10
  export { normalizeYamlItem, readYamlItems } from "./yaml-object-reader.js";
11
11
  const CONVENTIONAL_OBJECT_DIRECTORIES = ["tools"];
12
12
  const MODULE_AGENT_FILENAMES = ["agent.yaml", "agent.yml"];
@@ -39,16 +39,10 @@ function conventionalConfigRoot(root) {
39
39
  }
40
40
  function conventionalDirectoryRoots(root, relativeDir) {
41
41
  const resourceRoot = resolveResourcePackageRoot(root);
42
- const configRoot = conventionalConfigRoot(root);
43
- const candidates = relativeDir === "agents"
44
- ? [
45
- ...(configRoot ? [path.join(configRoot, "agents")] : []),
46
- path.join(root, "agents"),
47
- ]
48
- : [
49
- ...(resourceRoot ? [path.join(resourceRoot, relativeDir)] : []),
50
- path.join(root, relativeDir),
51
- ];
42
+ const candidates = [
43
+ ...(resourceRoot ? [path.join(resourceRoot, relativeDir)] : []),
44
+ path.join(root, relativeDir),
45
+ ];
52
46
  return Array.from(new Set(candidates));
53
47
  }
54
48
  export function conventionalPackageRoots(root, relativeDir) {
@@ -569,20 +563,6 @@ function mergeAgentRecord(records, item, sourcePath) {
569
563
  function mergeWorkspaceObjectRecord(records, workspaceObject, item, sourcePath) {
570
564
  mergeRawItemRecord(records, `${workspaceObject.kind}/${workspaceObject.id}`, item, sourcePath);
571
565
  }
572
- async function loadNamedModelsForRoot(configRoot, mergedObjects) {
573
- for (const { item, sourcePath } of await readNamedModelItems(configRoot)) {
574
- const workspaceObject = parseWorkspaceObject(item, sourcePath);
575
- if (!workspaceObject || workspaceObject.kind !== "model") {
576
- continue;
577
- }
578
- mergeWorkspaceObjectRecord(mergedObjects, workspaceObject, item, sourcePath);
579
- }
580
- }
581
- async function loadConfigAgentsForRoot(configRoot, mergedAgents) {
582
- for (const { item, sourcePath } of await readConfigAgentItems(configRoot)) {
583
- mergeAgentRecord(mergedAgents, item, sourcePath);
584
- }
585
- }
586
566
  async function loadModuleAgentsForRoot(root, mergedAgents) {
587
567
  const modulesRoot = moduleCollectionRoot(root, "agents");
588
568
  if (!(await fileExists(modulesRoot))) {
@@ -675,7 +655,7 @@ async function loadModuleObjectsForRoot(root, mergedObjects) {
675
655
  mergeWorkspaceObjectRecord(mergedObjects, workspaceObject, item, sourcePath);
676
656
  }
677
657
  }
678
- async function loadConfigObjectsForRoot(root, configRoot, mergedObjects) {
658
+ async function loadConfigYamlForRoot(root, configRoot, mergedAgents, mergedObjects) {
679
659
  if (!conventionalConfigRoot(root)) {
680
660
  return;
681
661
  }
@@ -684,7 +664,8 @@ async function loadConfigObjectsForRoot(root, configRoot, mergedObjects) {
684
664
  if (!workspaceObject) {
685
665
  continue;
686
666
  }
687
- if (isAgentKind(workspaceObject.kind) || workspaceObject.kind === "model") {
667
+ if (isAgentKind(workspaceObject.kind)) {
668
+ mergeAgentRecord(mergedAgents, item, sourcePath);
688
669
  continue;
689
670
  }
690
671
  mergeWorkspaceObjectRecord(mergedObjects, workspaceObject, item, sourcePath);
@@ -708,20 +689,6 @@ async function loadRootObjects(root, mergedObjects) {
708
689
  function isAgentKind(kind) {
709
690
  return kind === "agent";
710
691
  }
711
- async function readConfigAgentItems(configRoot) {
712
- const records = await readYamlItems(configRoot, undefined, { recursive: true });
713
- return records.filter(({ item, sourcePath }) => {
714
- const kind = typeof item.kind === "string" ? item.kind : undefined;
715
- if (!isAgentKind(kind)) {
716
- return false;
717
- }
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}`);
723
- });
724
- }
725
692
  export async function readToolModuleItems(root) {
726
693
  if (!(await fileExists(root))) {
727
694
  return [];
@@ -792,11 +759,9 @@ export async function loadWorkspaceObjects(workspaceRoot, options = {}) {
792
759
  const roots = [frameworkWorkspaceRoot(), ...(options.overlayRoots ?? []), workspaceRoot];
793
760
  for (const root of roots) {
794
761
  const configRoot = conventionalConfigRoot(root) ?? root;
795
- await loadNamedModelsForRoot(configRoot, mergedObjects);
796
- await loadConfigAgentsForRoot(configRoot, mergedAgents);
762
+ await loadConfigYamlForRoot(root, configRoot, mergedAgents, mergedObjects);
797
763
  await loadModuleAgentsForRoot(root, mergedAgents);
798
764
  await loadConventionalObjectsForRoot(root, mergedObjects);
799
- await loadConfigObjectsForRoot(root, configRoot, mergedObjects);
800
765
  await loadModuleObjectsForRoot(root, mergedObjects);
801
766
  await loadRootObjects(root, mergedObjects);
802
767
  }
@@ -9,7 +9,3 @@ export declare function readNamedYamlItems(root: string, filenames: string[]): P
9
9
  item: Record<string, unknown>;
10
10
  sourcePath: string;
11
11
  }>>;
12
- export declare function readNamedModelItems(root: string): Promise<Array<{
13
- item: Record<string, unknown>;
14
- sourcePath: string;
15
- }>>;
@@ -2,7 +2,6 @@ import path from "node:path";
2
2
  import { readdir } from "node:fs/promises";
3
3
  import { parseAllDocuments } from "yaml";
4
4
  import { fileExists, listFilesRecursive, readYamlOrJson } from "../utils/fs.js";
5
- const MODEL_FILENAMES = ["models.yaml", "models.yml"];
6
5
  const ENV_PLACEHOLDER_PATTERN = /\$\{env:([A-Za-z_][A-Za-z0-9_]*)\}/g;
7
6
  function asObject(value) {
8
7
  return typeof value === "object" && value ? value : undefined;
@@ -165,7 +164,10 @@ export async function readYamlItems(root, relativeDir, options = {}) {
165
164
  return [];
166
165
  }
167
166
  const files = options.recursive
168
- ? await listFilesRecursive(targetRoot, ".yaml")
167
+ ? Array.from(new Set([
168
+ ...(await listFilesRecursive(targetRoot, ".yaml")),
169
+ ...(await listFilesRecursive(targetRoot, ".yml")),
170
+ ])).sort()
169
171
  : (await readdir(targetRoot, { withFileTypes: true }))
170
172
  .filter((entry) => entry.isFile() && /\.ya?ml$/i.test(entry.name))
171
173
  .map((entry) => path.join(targetRoot, entry.name))
@@ -199,33 +201,3 @@ export async function readNamedYamlItems(root, filenames) {
199
201
  }
200
202
  return records;
201
203
  }
202
- export async function readNamedModelItems(root) {
203
- const filePaths = new Set();
204
- for (const filename of MODEL_FILENAMES) {
205
- const directPath = path.join(root, filename);
206
- if (await fileExists(directPath)) {
207
- filePaths.add(directPath);
208
- }
209
- }
210
- for (const extension of [".yaml", ".yml"]) {
211
- for (const filePath of await listFilesRecursive(root, extension)) {
212
- if (MODEL_FILENAMES.includes(path.basename(filePath))) {
213
- filePaths.add(filePath);
214
- }
215
- }
216
- }
217
- const records = [];
218
- for (const filePath of [...filePaths].sort()) {
219
- const parsedDocuments = parseAllDocuments(await readYamlOrJson(filePath));
220
- for (const parsedDocument of parsedDocuments) {
221
- const resolvedDocument = interpolateEnvPlaceholders(parsedDocument.toJSON(), filePath);
222
- for (const item of await objectItemsFromDocument(resolvedDocument, filePath)) {
223
- const normalized = normalizeYamlItem(item);
224
- if (normalized.kind === "model" && typeof normalized.id === "string" && normalized.id.trim()) {
225
- records.push({ item: normalized, sourcePath: filePath });
226
- }
227
- }
228
- }
229
- }
230
- return records;
231
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botbotgo/agent-harness",
3
- "version": "0.0.155",
3
+ "version": "0.0.157",
4
4
  "description": "Workspace runtime for multi-agent applications",
5
5
  "type": "module",
6
6
  "packageManager": "npm@10.9.2",
@@ -28,6 +28,11 @@
28
28
  "import": "./dist/index.js",
29
29
  "default": "./dist/index.js"
30
30
  },
31
+ "./acp": {
32
+ "types": "./dist/acp.d.ts",
33
+ "import": "./dist/acp.js",
34
+ "default": "./dist/acp.js"
35
+ },
31
36
  "./tools": {
32
37
  "types": "./dist/tools.d.ts",
33
38
  "import": "./dist/tools.js",