@botbotgo/agent-harness 0.0.69 → 0.0.70

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 CHANGED
@@ -53,7 +53,7 @@ The runtime provides:
53
53
  - `createAgentHarness(workspaceRoot)`, `run(...)`, `resolveApproval(...)`, `subscribe(...)`, inspection methods, and `stop(...)`
54
54
  - YAML-defined workspace assembly for routing, models, tools, stores, backends, MCP, recovery, and maintenance
55
55
  - backend-adapted execution with current LangChain v1 and DeepAgents adapters
56
- - local `resources/tools/` and `resources/skills/` discovery
56
+ - local `resources/tools/` `tool({...})` modules and `resources/skills/` discovery
57
57
  - persisted threads, runs, approvals, events, queue state, and recovery metadata
58
58
 
59
59
  The repository-owned default config layer is intentionally full-shaped. The shipped YAML keeps explicit defaults for the important runtime and agent knobs so teams can start from concrete config instead of reverse-engineering adapter behavior from source.
@@ -157,7 +157,7 @@ If you want the shortest possible mental model:
157
157
  - Small public runtime contract
158
158
  - YAML-defined host routing and runtime policy
159
159
  - LangChain v1 and DeepAgents backend adaptation
160
- - Auto-discovered local tools and SKILL packages
160
+ - Auto-discovered local `tool({...})` tools and SKILL packages
161
161
  - provider-native tools, MCP tools, and workspace-local tool modules
162
162
  - persisted threads, runs, approvals, lifecycle events, and queued runs
163
163
  - runtime-managed recovery and checkpoint maintenance
@@ -345,6 +345,9 @@ Core workspace files:
345
345
  - `resources/tools/`
346
346
  - `resources/skills/`
347
347
 
348
+ Workspace-local tool modules in `resources/tools/` should be exported with `tool({...})`.
349
+ Any other local module shape is not supported, and unsupported shapes are rejected at load time.
350
+
348
351
  There are three main configuration layers:
349
352
 
350
353
  - runtime policy in `config/workspace.yaml`
@@ -379,12 +382,18 @@ Important fields:
379
382
  - `routing.systemPrompt`
380
383
  - `routing.modelRouting`
381
384
  - `maintenance.checkpoints`
385
+ - `maintenance.records`
382
386
  - `recovery.enabled`
383
387
  - `recovery.resumeResumingRunsOnStartup`
384
388
  - `recovery.maxRecoveryAttempts`
385
389
 
386
390
  `recovery.resumeResumingRunsOnStartup` keeps checkpoint resume a runtime-owned lifecycle behavior instead of exposing checkpoint orchestration as public API.
387
391
 
392
+ `maintenance.checkpoints` and `maintenance.records` are separate retention layers:
393
+
394
+ - `maintenance.checkpoints` trims backend checkpoint state used for resume/recovery
395
+ - `maintenance.records` trims harness-owned terminal thread/run records stored in `runtime.sqlite`
396
+
388
397
  Example:
389
398
 
390
399
  ```yaml
@@ -402,6 +411,8 @@ spec:
402
411
  maintenance:
403
412
  checkpoints:
404
413
  enabled: true
414
+ records:
415
+ enabled: false
405
416
  recovery:
406
417
  enabled: true
407
418
  resumeResumingRunsOnStartup: true
package/README.zh.md CHANGED
@@ -53,7 +53,7 @@
53
53
  - `createAgentHarness(workspaceRoot)`、`run(...)`、`resolveApproval(...)`、`subscribe(...)`、各类查询方法,以及 `stop(...)`
54
54
  - 以 YAML 描述的工作区装配:路由、模型、工具、存储、后端、MCP、恢复与维护等
55
55
  - 通过适配器对接当前的 LangChain v1 与 DeepAgents 执行
56
- - 本地 `resources/tools/` `resources/skills/` 的发现
56
+ - 本地 `resources/tools/` `tool({...})` 工具模块与 `resources/skills/` 的发现
57
57
  - 持久化的线程、运行、审批、事件、队列状态与恢复元数据
58
58
 
59
59
  仓库自带的默认配置刻意做成「形状完整」。随仓库提供的 YAML 对重要的运行时与 agent 开关给出显式默认值,便于从具体配置起步,而不必从源码反推适配器行为。
@@ -343,6 +343,9 @@ await stop(runtime);
343
343
  - `resources/tools/`
344
344
  - `resources/skills/`
345
345
 
346
+ `resources/tools/` 下的工作区本地工具模块应统一用 `tool({...})` 导出。
347
+ 不支持历史/兼容写法,任何不带该导出形式的工具模块都会在工作区加载时被拒绝。
348
+
346
349
  主要有三层配置:
347
350
 
348
351
  - `config/workspace.yaml` 中的运行时策略
@@ -377,12 +380,18 @@ await stop(runtime);
377
380
  - `routing.systemPrompt`
378
381
  - `routing.modelRouting`
379
382
  - `maintenance.checkpoints`
383
+ - `maintenance.records`
380
384
  - `recovery.enabled`
381
385
  - `recovery.resumeResumingRunsOnStartup`
382
386
  - `recovery.maxRecoveryAttempts`
383
387
 
384
388
  `recovery.resumeResumingRunsOnStartup` 将 checkpoint 恢复保持为运行时拥有的生命周期行为,而不是把 checkpoint 编排暴露为主 API。
385
389
 
390
+ `maintenance.checkpoints` 与 `maintenance.records` 是两层独立的保留策略:
391
+
392
+ - `maintenance.checkpoints` 清理后端用于 resume/recovery 的 checkpoint 状态
393
+ - `maintenance.records` 清理 harness 自己保存在 `runtime.sqlite` 中、已结束的 thread/run 记录
394
+
386
395
  示例:
387
396
 
388
397
  ```yaml
@@ -400,6 +409,8 @@ spec:
400
409
  maintenance:
401
410
  checkpoints:
402
411
  enabled: true
412
+ records:
413
+ enabled: false
403
414
  recovery:
404
415
  enabled: true
405
416
  resumeResumingRunsOnStartup: true
@@ -1 +1 @@
1
- export declare const AGENT_HARNESS_VERSION = "0.0.68";
1
+ export declare const AGENT_HARNESS_VERSION = "0.0.69";
@@ -1 +1 @@
1
- export const AGENT_HARNESS_VERSION = "0.0.68";
1
+ export const AGENT_HARNESS_VERSION = "0.0.69";
@@ -1,18 +1,13 @@
1
+ import { normalizeToolSchema } from "./tools.js";
1
2
  type ImportedToolModule = Record<string, unknown>;
2
- type SchemaLike = {
3
- parse: (input: unknown) => unknown;
4
- description?: string;
5
- shape?: Record<string, unknown>;
6
- };
7
3
  export type LoadedToolModule = {
8
4
  implementationName: string;
9
5
  invoke: (input: unknown, context?: Record<string, unknown>) => Promise<unknown> | unknown;
10
- schema: SchemaLike;
6
+ schema: ReturnType<typeof normalizeToolSchema>;
11
7
  description: string;
12
8
  retryable?: boolean;
13
9
  };
14
10
  export declare function isSupportedToolModulePath(filePath: string): boolean;
15
- export declare function discoverAnnotatedFunctionNames(sourceText: string): string[];
16
- export declare function discoverToolModuleDefinitions(sourceText: string, imported: ImportedToolModule): LoadedToolModule[];
11
+ export declare function discoverToolModuleDefinitions(_sourceText: string, imported: ImportedToolModule): LoadedToolModule[];
17
12
  export declare function loadToolModuleDefinition(imported: ImportedToolModule, implementationName: string): LoadedToolModule;
18
13
  export {};
@@ -1,65 +1,9 @@
1
1
  import path from "node:path";
2
- import { z } from "zod";
3
2
  import { TOOL_DEFINITION_MARKER, normalizeToolSchema } from "./tools.js";
4
3
  const TOOL_MODULE_EXTENSIONS = new Set([".mjs", ".js", ".cjs"]);
5
- const ANNOTATED_TOOL_EXPORT_PATTERN = /(?:\/\*\*?[\s\S]*?@tool[\s\S]*?\*\/\s*|\/\/[^\n]*@tool[^\n]*\n\s*)export\s+(?:async\s+)?(?:function\s+([A-Za-z_][A-Za-z0-9_]*)\s*\(|const\s+([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(?:async\s*)?(?:function\b|\())/g;
6
- function asRecord(value) {
7
- return typeof value === "object" && value !== null && !Array.isArray(value)
8
- ? value
9
- : undefined;
10
- }
11
- function isSchemaLike(value) {
12
- return typeof value === "object" && value !== null && typeof value.parse === "function";
13
- }
14
4
  function isToolDefinitionObject(value) {
15
5
  return typeof value === "object" && value !== null && value[TOOL_DEFINITION_MARKER] === true;
16
6
  }
17
- function buildSchemaFromShape(shape, description) {
18
- const record = asRecord(shape);
19
- if (!record) {
20
- return null;
21
- }
22
- const schema = z.object(record);
23
- return description ? schema.describe(description) : schema;
24
- }
25
- function readToolDescription(imported, implementationName, schema) {
26
- const explicit = typeof imported[`${implementationName}Description`] === "string"
27
- ? String(imported[`${implementationName}Description`])
28
- : typeof imported.description === "string"
29
- ? String(imported.description)
30
- : undefined;
31
- return explicit?.trim() || schema.description?.trim() || `Auto-discovered tool ${implementationName}`;
32
- }
33
- function resolveToolSchema(imported, implementationName, allowGenericExports) {
34
- const namedSchema = imported[`${implementationName}Schema`];
35
- if (isSchemaLike(namedSchema)) {
36
- return namedSchema;
37
- }
38
- const namedShape = imported[`${implementationName}SchemaShape`];
39
- const namedDescription = typeof imported[`${implementationName}Description`] === "string"
40
- ? String(imported[`${implementationName}Description`])
41
- : undefined;
42
- const schemaFromNamedShape = buildSchemaFromShape(namedShape, namedDescription);
43
- if (schemaFromNamedShape) {
44
- return schemaFromNamedShape;
45
- }
46
- if (!allowGenericExports) {
47
- return null;
48
- }
49
- const genericSchema = imported.schema;
50
- if (isSchemaLike(genericSchema)) {
51
- return genericSchema;
52
- }
53
- const genericShape = imported.schemaShape ?? imported.schema;
54
- const genericDescription = typeof imported.description === "string" ? String(imported.description) : undefined;
55
- return buildSchemaFromShape(genericShape, genericDescription);
56
- }
57
- function discoverExportedFunctionNames(imported) {
58
- return Object.entries(imported)
59
- .filter(([name, value]) => name !== "default" && typeof value === "function")
60
- .map(([name]) => name)
61
- .sort();
62
- }
63
7
  function discoverExportedToolObjectNames(imported) {
64
8
  return Object.entries(imported)
65
9
  .filter(([name, value]) => name !== "default" && isToolDefinitionObject(value))
@@ -82,46 +26,10 @@ function loadToolObjectDefinition(imported, exportName) {
82
26
  export function isSupportedToolModulePath(filePath) {
83
27
  return TOOL_MODULE_EXTENSIONS.has(path.extname(filePath));
84
28
  }
85
- export function discoverAnnotatedFunctionNames(sourceText) {
86
- const matches = sourceText.matchAll(ANNOTATED_TOOL_EXPORT_PATTERN);
87
- return Array.from(matches, (match) => match[1] ?? match[2]).filter((name) => Boolean(name));
88
- }
89
- export function discoverToolModuleDefinitions(sourceText, imported) {
90
- const objectDefinitions = discoverExportedToolObjectNames(imported)
29
+ export function discoverToolModuleDefinitions(_sourceText, imported) {
30
+ return discoverExportedToolObjectNames(imported)
91
31
  .map((exportName) => loadToolObjectDefinition(imported, exportName))
92
32
  .filter((definition) => Boolean(definition));
93
- if (objectDefinitions.length > 0) {
94
- return objectDefinitions;
95
- }
96
- const annotatedNames = new Set(discoverAnnotatedFunctionNames(sourceText));
97
- const functionNames = discoverExportedFunctionNames(imported);
98
- const allowGenericExports = functionNames.length === 1;
99
- const discovered = [];
100
- for (const implementationName of functionNames) {
101
- const invoke = imported[implementationName];
102
- if (typeof invoke !== "function") {
103
- continue;
104
- }
105
- const schema = resolveToolSchema(imported, implementationName, allowGenericExports);
106
- if (!schema && !annotatedNames.has(implementationName)) {
107
- continue;
108
- }
109
- if (!schema) {
110
- throw new Error(`Tool module must export ${implementationName}Schema, ${implementationName}SchemaShape, or generic schema/schemaShape metadata.`);
111
- }
112
- discovered.push({
113
- implementationName,
114
- invoke: invoke,
115
- schema,
116
- description: readToolDescription(imported, implementationName, schema),
117
- retryable: typeof imported[`${implementationName}Retryable`] === "boolean"
118
- ? imported[`${implementationName}Retryable`] === true
119
- : typeof imported.retryable === "boolean"
120
- ? imported.retryable === true
121
- : undefined,
122
- });
123
- }
124
- return discovered;
125
33
  }
126
34
  export function loadToolModuleDefinition(imported, implementationName) {
127
35
  for (const exportName of discoverExportedToolObjectNames(imported)) {
@@ -130,25 +38,5 @@ export function loadToolModuleDefinition(imported, implementationName) {
130
38
  return loaded;
131
39
  }
132
40
  }
133
- const functionNames = discoverExportedFunctionNames(imported);
134
- const allowGenericExports = functionNames.length === 1;
135
- const invoke = imported[implementationName];
136
- if (typeof invoke !== "function") {
137
- throw new Error(`Tool module must export function ${implementationName}.`);
138
- }
139
- const schema = resolveToolSchema(imported, implementationName, allowGenericExports);
140
- if (!schema) {
141
- throw new Error(`Tool module must export ${implementationName}Schema, ${implementationName}SchemaShape, or generic schema/schemaShape metadata.`);
142
- }
143
- return {
144
- implementationName,
145
- invoke: invoke,
146
- schema,
147
- description: readToolDescription(imported, implementationName, schema),
148
- retryable: typeof imported[`${implementationName}Retryable`] === "boolean"
149
- ? imported[`${implementationName}Retryable`] === true
150
- : typeof imported.retryable === "boolean"
151
- ? imported.retryable === true
152
- : undefined,
153
- };
41
+ throw new Error(`Tool module must export a tool({...}) definition named ${implementationName}.`);
154
42
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botbotgo/agent-harness",
3
- "version": "0.0.69",
3
+ "version": "0.0.70",
4
4
  "description": "Workspace runtime for multi-agent applications",
5
5
  "type": "module",
6
6
  "packageManager": "npm@10.9.2",