@botbotgo/agent-harness 0.0.210 → 0.0.211

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
@@ -14,11 +14,11 @@
14
14
  # @botbotgo/agent-harness
15
15
 
16
16
  <p align="center">
17
- <strong>The application runtime for multi-agent products with approvals, recovery, and operator control built in.</strong>
17
+ <strong>Build a stable, enterprise-grade, operable runtime for multi-agent productswith approvals, recovery, and operator control built in.</strong>
18
18
  </p>
19
19
 
20
20
  <p align="center">
21
- <strong>Turn one agent workspace into one operable product runtime.</strong>
21
+ <strong>Ship quickly: one workspace assembles into one production-ready product runtime.</strong>
22
22
  </p>
23
23
 
24
24
  <p align="center">
@@ -44,9 +44,9 @@
44
44
  >
45
45
  </p>
46
46
 
47
- ## Start In A Few Lines
47
+ ## Start in a few lines
48
48
 
49
- You can start one agent runtime in a few lines of code:
49
+ You can boot an agent runtime in a few lines of code:
50
50
 
51
51
  ```ts
52
52
  import { createAgentHarness, request, stop } from "@botbotgo/agent-harness";
@@ -65,16 +65,17 @@ try {
65
65
  }
66
66
  ```
67
67
 
68
- If your team already has a LangChain v1 or DeepAgents workspace, the point is to keep that stack and add approvals,
69
- recovery, inspection, and operator control around it instead of rewriting into a second framework.
68
+ The goal is an **operable** runtime: approvals, recovery, inspection, and governance—ready for production operations.
69
+ Where you already use LangChain v1 or DeepAgents for execution, agent-harness adds the product runtime layer around
70
+ them without forcing a rewrite.
70
71
 
71
72
  ## Documentation Paths
72
73
 
73
74
  Read the repository in this order:
74
75
 
75
- - **Technology:** boundary judgment, side-by-side comparison, runtime model, protocol surfaces, API, recovery, approvals, and operator control
76
+ - **Technology:** capability comparison, runtime model, protocol surfaces, API, recovery, approvals, and operator control
76
77
  - **Product:** what the stable runtime surface already is, which product scenarios it fits, and why it is not another agent framework
77
- - **Commercial:** deployment support, launch help, hardening, and handoff after the technical and product story is already clear
78
+ - **Commercial:** deployment support, launch help, hardening, and handoff once the technical fit and product scope are clear
78
79
 
79
80
  Recommended entry points:
80
81
 
@@ -89,15 +90,15 @@ Recommended entry points:
89
90
  This repository is licensed under **Apache License 2.0**.
90
91
  [LICENSE](./LICENSE)
91
92
 
92
- Core runtime is open source, so you can inspect and run it freely.
93
- Commercial support comes after adoption and focuses on helping teams get to a production-ready handoff, including:
93
+ Core runtime is open source: inspect and run it freely.
94
+ Commercial support focuses on helping teams reach a production-ready handoff, including:
94
95
 
95
96
  - Deployment and integration guidance for your environment
96
97
  - Initial deployment setup and launch assistance
97
98
  - Priority issue triage and troubleshooting
98
99
  - Runtime governance, approval flow, and recovery hardening support
99
100
  - Custom tools, connectors, and protocol integrations
100
- - Operator runbooks and handoff guidance for the client team
101
+ - Operator runbooks and handoff guidance for your team
101
102
 
102
103
  Production operations, managed hosting, on-call coverage, and long-term run-the-system support are not included by default.
103
104
  If a team wants us to take on that responsibility, we scope it separately based on environment complexity and SLA expectations.
@@ -108,11 +109,11 @@ If your team needs a scalable enterprise setup, please contact:
108
109
  Additional docs:
109
110
 
110
111
  - [Commercial service offerings](./docs/commercial-pricing.md)
111
- - [Lead-to-paid process](./docs/enterprise-process.md)
112
+ - [Commercial engagement process](./docs/enterprise-process.md)
112
113
 
113
114
  ## Easy to start · Full runtime · Configure and extend
114
115
 
115
- **At a glance:** the onboarding path stays thin, the runtime capabilities ship as a complete layer, and most ongoing work moves into **YAML configuration** plus **extensions** (local tools, SKILL packages, MCP) instead of bespoke runtime infrastructure.
116
+ **At a glance:** onboarding stays thin, the runtime ships as a full layer, and day-to-day work lives in **YAML** plus **extensions** (local tools, SKILL packages, MCP)—not bespoke runtime plumbing.
116
117
 
117
118
  - **Easy to start:** `createAgentHarness` → `request` → `stop`, plus inspection helpers such as `subscribe`, `listSessions`, `listApprovals`, and `resolveApproval`.
118
119
  - **Configure:** routing, models, tools, stores, backends, MCP, recovery, and maintenance in declarative workspace YAML (see [Quick Start](#quick-start) and [How To Configure](#how-to-configure)).
@@ -121,7 +122,7 @@ Additional docs:
121
122
 
122
123
  ## Current Public Surface
123
124
 
124
- The repository now ships more than a thin runtime bootstrap. The public surface is already broad enough that the homepage and docs need to describe it as a product runtime with external protocol boundaries, not only as YAML plus tools.
125
+ The package is more than a thin bootstrap: the public surface is broad enough to describe as a full product runtime with external protocol boundariesnot just YAML plus tools.
125
126
 
126
127
  - **Core runtime API:** `createAgentHarness`, `request`, `subscribe`, `resolveApproval`, inspection helpers, and stable persisted runtime records for `requests`, `sessions`, `approvals`, `events`, and artifacts.
127
128
  - **Runtime memory and evidence:** `memorize`, `recall`, `listMemories`, memory policy hooks, `listArtifacts`, `getArtifact`, `exportEvaluationBundle`, `replayEvaluationBundle`, and request/session evidence export helpers.
@@ -164,7 +165,7 @@ Teams still need clear answers to the runtime questions that appear after that s
164
165
 
165
166
  `agent-harness` solves that layer. It keeps agent execution upstream while turning the application runtime into something teams can operate, recover, and govern.
166
167
 
167
- That makes the product story easier to explain:
168
+ In short:
168
169
 
169
170
  - you bring the workspace, agents, tools, and prompts
170
171
  - `agent-harness` brings persisted `requests`, `sessions`, `approvals`, `events`, recovery, and operator visibility
@@ -241,7 +242,7 @@ Start with these user-facing docs:
241
242
  - `docs/long-term-memory.md`
242
243
  - `docs/memory-policy-reference.md`
243
244
 
244
- Maintainer notes and internal product-boundary discussions remain in the repository, but they are intentionally not part of the primary public reading path.
245
+ Additional contributor-oriented design notes live in the repository; you do not need them for everyday integration and operations.
245
246
 
246
247
  `deepagents-acp` is the required external protocol direction when external tools need a standard runtime boundary. The harness should conform to `deepagents-acp` semantics at that boundary while keeping runtime lifecycle, persistence, recovery, and governance harness-owned.
247
248
 
@@ -274,9 +275,9 @@ Real products need a runtime that can answer harder questions:
274
275
  - It lets YAML own assembly and operating policy while code keeps a small, stable surface
275
276
  - It goes deep on runtime concerns that upstream libraries do not fully productize
276
277
 
277
- ## What To Sell First
278
+ ## Primary use cases
278
279
 
279
- The product story should stay scenario-shaped instead of drifting back to a generic "multi-agent runtime" pitch.
280
+ These scenarios map most directly to what the runtime is built for:
280
281
 
281
282
  - Enterprise internal agent runtime: approvals, restart-safe recovery, operator evidence, and policy-owned MCP access.
282
283
  - Code modernization runtime: long-running coding flows, approval checkpoints, resumable runs, and exported evidence packages.
@@ -367,7 +368,7 @@ Three-minute mental model:
367
368
  2. Call `request(runtime, { ... })` to execute one request.
368
369
  3. Inspect persisted runtime records instead of treating the final answer as the only product artifact.
369
370
 
370
- This is the shortest product pitch:
371
+ In brief:
371
372
 
372
373
  - your team builds the agent app
373
374
  - `agent-harness` makes that app operable
@@ -748,6 +749,8 @@ Important fields:
748
749
  - `maintenance.checkpoints` trims backend checkpoint state used for resume/recovery
749
750
  - `maintenance.records` trims harness-owned terminal session/request records stored in `runtime.sqlite`
750
751
 
752
+ When libSQL reports an error against harness runtime persistence, the message is prefixed with the absolute path to `runtime.sqlite`. For constraint-class failures (or whenever you set `AGENT_HARNESS_RUNTIME_SQLITE_DEBUG=1`), the message also includes a truncated copy of the failing SQL so you can tell harness persistence apart from other SQLite databases in the same process.
753
+
751
754
  Example:
752
755
 
753
756
  ```yaml
@@ -963,7 +966,7 @@ spec:
963
966
  middleware: []
964
967
  ```
965
968
 
966
- For backend-specific options, prefer the upstream concept directly inside `spec.config`. Keep the public runtime contract in the main developer docs and API reference rather than relying on maintainer-only comparison notes.
969
+ For backend-specific options, prefer the upstream concept directly inside `spec.config`. Keep the public runtime contract in the main developer docs and API reference rather than relying only on informal comparison notes.
967
970
 
968
971
  ## Design Notes
969
972
 
package/README.zh.md CHANGED
@@ -14,11 +14,11 @@
14
14
  # @botbotgo/agent-harness
15
15
 
16
16
  <p align="center">
17
- <strong>面向多 agent 产品的应用运行时:内建审批、恢复与运维控制,而不只是执行。</strong>
17
+ <strong>快速搭建稳定、可运维的企业级多智能体运行时:内置审批、恢复与运维能力,不止于「能跑通执行」。</strong>
18
18
  </p>
19
19
 
20
20
  <p align="center">
21
- <strong>把一个 agent 工作区直接变成一套可运行的产品级 runtime。</strong>
21
+ <strong>一个工作区即可装配成面向生产的运行时(产品级能力)。</strong>
22
22
  </p>
23
23
 
24
24
  <p align="center">
@@ -46,7 +46,7 @@
46
46
 
47
47
  ## 几行代码启动
48
48
 
49
- 几行代码就可以把一个 workspace 启动成 agent runtime:
49
+ 几行代码即可把工作区跑成智能体运行时:
50
50
 
51
51
  ```ts
52
52
  import { createAgentHarness, request, stop } from "@botbotgo/agent-harness";
@@ -65,52 +65,51 @@ try {
65
65
  }
66
66
  ```
67
67
 
68
- 如果你的团队已经有 LangChain v1 或 DeepAgents 的 workspace,重点不是重写,而是在现有栈外面补上 approvals、
69
- recovery、inspection 和 operator control。
68
+ 目标是交付<strong>可运维</strong>的运行时:审批、恢复、可观测与治理默认就绪。若执行层已采用 LangChain v1 或 DeepAgents,可在其之上衔接产品级运行时,无需推倒重来。
70
69
 
71
70
  ## 阅读路径
72
71
 
73
72
  建议按这个顺序理解仓库:
74
73
 
75
- - **技术:** 边界判断、并列对比、runtime 模型、协议接面、API、恢复、审批和 operator control
76
- - **产品:** 当前已经稳定公开的 runtime 能力面、适合的产品场景,以及为什么它不是另一个 agent framework
77
- - **商业:** 在技术和产品叙事已经清晰之后,再提供部署支持、上线协助、加固和交接服务
74
+ - **技术:** 能力对比、运行模型、协议接入、API、恢复、审批与运维控制
75
+ - **产品:** 稳定的公开运行时能力、适用场景,以及它为何不是又一个 agent 框架
76
+ - **商业:** 在技术与产品范围理清之后,再谈部署支持、上线协助、加固与交接
78
77
 
79
78
  推荐入口:
80
79
 
81
80
  - [开发文档入口](./docs/development/index.html)
82
81
  - [并列对比页](./docs/development/comparison.html)
83
82
  - [API 参考](./docs/development/api-reference.html)
84
- - [协议接面](./docs/development/protocol-surfaces.html)
83
+ - [协议接入说明](./docs/development/protocol-surfaces.html)
85
84
  - [商业服务价格说明](./docs/commercial-pricing.md)
86
85
 
87
86
  ## 许可证与商业支持
88
87
 
89
88
  本仓库采用 **Apache License 2.0** 开源许可。[查看 LICENSE](./LICENSE)
90
89
 
91
- 核心运行时保持开源,方便你自由查看与试用。
92
- 商业支持放在 adoption 之后,聚焦“帮助团队完成生产落地与交接”的能力,包括:
90
+ 核心运行时开源,可自由查看与试用。
91
+ 商业支持侧重帮助团队完成生产落地与交接,例如:
93
92
 
94
- - 你的环境中的部署与接入咨询
95
- - 初期 deployment 搭建与上线协助
93
+ - 部署与接入咨询(面向你的环境)
94
+ - 初期环境搭建与上线协助
96
95
  - 优先故障响应与问题排查
97
96
  - 运行时治理、审批流和恢复能力加固支持
98
97
  - 定制工具、连接器与协议接入开发
99
- - 面向客户团队的操作手册与交接说明
98
+ - 操作手册与交接说明(面向接手团队)
100
99
 
101
- 正式生产运维、托管、值班响应和长期代运营不属于默认服务内容。
102
- 如果客户希望我们承担这部分责任,会根据环境复杂度和 SLA 要求单独评估与报价。
100
+ 正式生产运维、托管、值班与长期代运营不在默认范围内。
101
+ 若需要我方承担上述职责,将按环境与 SLA 单独评估与报价。
103
102
 
104
- 如果你需要企业级合作方案,请联系:**[info@easynet.world](mailto:info@easynet.world)**。
103
+ 企业级合作请联络:**[info@easynet.world](mailto:info@easynet.world)**。
105
104
 
106
105
  相关资料:
107
106
 
108
107
  - [商业服务价格说明](./docs/commercial-pricing.md)
109
- - [咨询到签约流程](./docs/enterprise-process.md)
108
+ - [商业合作流程](./docs/enterprise-process.md)
110
109
 
111
110
  ## 容易上手 · 能力齐全 · 配置与扩展
112
111
 
113
- **一句话:** 接入面保持很薄,运行时能力整层交付,日常主要工作集中在 **YAML 配置** 与 **扩展**(本地工具、SKILL 包、MCP),而不是反复自建运行时基础设施。
112
+ **一句话:** 对外接口保持精简、运行时能力一次备齐,日常工作落在 **YAML 配置** 与 **扩展**(本地工具、SKILLMCP)上,而不是反复搭建运行时底座。
114
113
 
115
114
  - **容易上手:** `createAgentHarness` → `request` → `stop`,以及 `subscribe`、`listSessions`、`listApprovals`、`resolveApproval` 等查询与控制能力。
116
115
  - **配置:** 路由、模型、工具、存储、后端、MCP、恢复与维护写在声明式工作区 YAML 里(见[快速开始](#快速开始)与[如何配置](#如何配置))。
@@ -119,20 +118,20 @@ recovery、inspection 和 operator control。
119
118
 
120
119
  ## 当前公开能力面
121
120
 
122
- 如果你想先知道今天能直接用什么,可以先看这一节。`agent-harness` 已经提供完整的运行时能力,而不只是一个启动脚手架。
121
+ 想先了解「今天能直接用什么」,可从本节读起。`agent-harness` 提供完整运行时能力,而不只是启动脚手架。
123
122
 
124
- - **核心 runtime API:** `createAgentHarness`、`request`、`subscribe`、`resolveApproval`、各类 inspection helper,以及稳定持久化的 `requests`、`sessions`、`approvals`、`events` artifacts 记录。
125
- - **运行时 memory 与证据能力:** `memorize`、`recall`、`listMemories`、memory policy hooks、`listArtifacts`、`getArtifact`、`exportEvaluationBundle`、`replayEvaluationBundle`,以及 request / session 级证据导出 helper。
126
- - **协议与传输接面:** `createAcpServer`、`serveAcpStdio`、`serveAcpHttp`、`serveA2aHttp`、`serveAgUiHttp`、以及 `createRuntimeMcpServer` / `serveRuntimeMcpOverStdio`。
123
+ - **核心 runtime API:** `createAgentHarness`、`request`、`subscribe`、`resolveApproval`、各类查询与检查辅助 API,以及稳定持久化的 `requests`、`sessions`、`approvals`、`events` artifacts 记录。
124
+ - **运行时 memory 与证据能力:** `memorize`、`recall`、`listMemories`、memory policy hooks、`listArtifacts`、`getArtifact`、`exportEvaluationBundle`、`replayEvaluationBundle`,以及 request / session 级证据导出辅助函数。
125
+ - **协议与传输层:** `createAcpServer`、`serveAcpStdio`、`serveAcpHttp`、`serveA2aHttp`、`serveAgUiHttp`,以及 `createRuntimeMcpServer` / `serveRuntimeMcpOverStdio`。
127
126
  - **受治理的工作区运行时:** 由 YAML 持有的路由、并发、维护、MCP 策略、runtime governance bundles,以及针对敏感 memory 或写类 MCP 副作用的默认审批门槛。
128
127
 
129
128
  如果你的产品需要对接外部客户端,也可以从这里理解边界:`deepagents-acp` 是主要的外部协议方向,而持久化、恢复、审批和运行控制仍由 `agent-harness` 负责。
130
129
 
131
130
  ## 我们解决什么问题
132
131
 
133
- 一句话概括:`agent-harness` 把通常在 demo 之后才暴露出来的运行时工作,提前做成产品 runtime 的一部分。
132
+ 一句话概括:`agent-harness` 把通常在 demo 之后才不得不补上的运行时工作,提前做成产品运行时的一部分。
134
133
 
135
- 如果团队已经有 agents、prompts、tools 和 workflows,真正缺的通常不是再多一层执行,而是把这些能力变成“可运维软件”的运行时层。
134
+ 如果团队已经有 agents、prompts、tools 和 workflows,真正缺的通常不是再多一层执行,而是把这些能力沉淀成**可长期运维的软件**所需的运行时层。
136
135
 
137
136
  第一天就能直接拿到的东西:
138
137
 
@@ -239,7 +238,7 @@ AI 让 agent 逻辑、工具调用和工作流代码更容易生成,真正更
239
238
  - `docs/long-term-memory.md`
240
239
  - `docs/memory-policy-reference.md`
241
240
 
242
- 仓库里仍然保留了部分设计说明和边界讨论,但日常使用时不需要先读这些内容。
241
+ 仓库中也包含面向贡献者的设计说明与边界讨论;日常接入与运维不必先读这些内容。
243
242
 
244
243
  当外部工具需要标准运行时边界时,`deepagents-acp` 是必须遵循的外部协议方向。`agent-harness` 应在该边界上严格契合 `deepagents-acp` 语义,同时继续把运行时生命周期、持久化、恢复与治理保留在 harness 内部。
245
244
 
@@ -265,20 +264,20 @@ AI 让 agent 逻辑、工具调用和工作流代码更容易生成,真正更
265
264
 
266
265
  ## 有何不同
267
266
 
268
- - 将 `requests`、`sessions`、`approvals`、`events` 与恢复视为一等产品记录
269
- - 给运维侧提供运行时控制面,而不是暴露原始后端内部结构
267
+ - 将 `requests`、`sessions`、`approvals`、`events` 与恢复视为核心产品数据(长期可查、可治理)
268
+ - 给运维侧提供运行时控制面,而不是把原始后端内部结构直接暴露出去
270
269
  - 将可观测性与治理留在运行时:包括 trace correlation、continuity metadata,以及高风险副作用的默认审批
271
270
  - 将 checkpoint 恢复作为系统管理的行为,而不是把 checkpoint 细节抬成主 API
272
271
  - 复杂装配与运行策略交给 YAML,代码面保持小而稳
273
272
  - 在上游库未充分产品化的运行时问题上做深做透
274
273
 
275
- ## 先卖哪三类场景
274
+ ## 典型应用场景
276
275
 
277
- 如果你在评估落地场景,可以先从下面三类最直接的用法理解它。
276
+ 下面三类用法与 runtime 的设计目标最直接对应:
278
277
 
279
- - 企业内部 agent 运行时:审批、重启恢复、operator 证据链,以及由策略持有的 MCP 访问控制。
278
+ - 企业内部智能体运行时:审批、重启恢复、运维侧证据链,以及由策略约束的 MCP 访问控制。
280
279
  - 代码现代化运行时:长链路 coding flow、审批检查点、可恢复 runs,以及可导出的运行证据包。
281
- - 协议桥接运行时:ACP、A2A、AG-UI 与 runtime MCP 共用一套稳定控制面,而不是每个对外接面各写一层胶水。
280
+ - 协议桥接运行时:ACP、A2A、AG-UI 与 runtime MCP 共用一套稳定控制面,而不是为每个对外入口各写一层集成胶水。
282
281
 
283
282
  一套常见的 runtime 治理默认值大致如下:
284
283
 
@@ -365,7 +364,7 @@ try {
365
364
  2. 用 `request(runtime, { ... })` 执行一次请求。
366
365
  3. 把持久化的运行时记录当成产品资产,而不是只盯着最终回答。
367
366
 
368
- 如果再压缩成最短产品表述,就是:
367
+ 一句话概括:
369
368
 
370
369
  - 你的团队负责构建 agent app
371
370
  - `agent-harness` 负责让这个 app 可运维
@@ -505,7 +504,7 @@ const recalled = await recall(runtime, {
505
504
 
506
505
  - `memorize(...)` 返回稳定的 `MemoryRecord` 与 `MemoryDecision` 结果,而 merge、review、archive 与存储布局仍由 runtime 内部托管
507
506
  - `recall(...)` 返回按相关性排序、并按 scope / kind 过滤后的 `MemoryRecord`
508
- - `listMemories(...)` 返回稳定的 `MemoryRecord`,用于 inspection / admin 场景;如果不传 status 过滤器,默认只返回 `active`
507
+ - `listMemories(...)` 返回稳定的 `MemoryRecord`,用于排查与管理场景;如果不传 status 过滤器,默认只返回 `active`
509
508
  - `updateMemory(...)` 通过 `memoryId` 更新单条 durable memory,而不暴露内部 store namespace
510
509
  - `removeMemory(...)` 通过 `memoryId` 删除单条 durable memory,并重建运行时托管的 projection
511
510
  - 业务知识分类、review UI 与管理后台仍应留在应用层
@@ -661,12 +660,12 @@ await stop(runtime);
661
660
  本地 function tool 如果在模块里声明了 schema,runtime governance 会直接把该模块 schema 视为事实来源;不需要为了 schema-bound 元数据再额外复制一份 YAML `inputSchema.ref`。
662
661
  若本地工具使用 Zod schema,请让工作区或隔离的 `resources` 包统一使用 `zod@^4`,避免 raw shape validator 与 runtime 解析落在不同 major 版本上。
663
662
 
664
- 主要有三层配置:
663
+ 配置大致分这几层(由下至上叠加):
665
664
 
666
- - 先由 workspace 启动时扫描本地和附加的 `resources` 包,建立统一 registry
667
- - agent 再按名字白名单选择 tools 与 skills
668
- - `config/runtime/workspace.yaml` 中的运行时策略
669
- - `config/catalogs/*.yaml` 中的可复用对象目录
665
+ - workspace 启动时扫描本地与附加的 `resources` 包,建立统一 registry
666
+ - agent 再按名称白名单选用 tools 与 skills
667
+ - `config/runtime/workspace.yaml` 承载运行时策略
668
+ - `config/catalogs/*.yaml` 承载可复用对象目录
670
669
  - `config/**/*.yaml` 中的 agent 装配
671
670
 
672
671
  ### Backend 选择建议
@@ -709,6 +708,8 @@ await stop(runtime);
709
708
  - `maintenance.checkpoints` 清理后端用于 resume/recovery 的 checkpoint 状态
710
709
  - `maintenance.records` 清理 harness 自己保存在 `runtime.sqlite` 中、已结束的 session/request 记录
711
710
 
711
+ 当 libSQL 对 harness 运行时持久化报错时,错误信息会带上 `runtime.sqlite` 的绝对路径。对约束类错误(或设置环境变量 `AGENT_HARNESS_RUNTIME_SQLITE_DEBUG=1` 时),信息中还会包含被截断的失败 SQL,便于在同一进程里区分 harness 与其它 SQLite 数据库。
712
+
712
713
  示例:
713
714
 
714
715
  ```yaml
@@ -1 +1 @@
1
- export declare const AGENT_HARNESS_VERSION = "0.0.209";
1
+ export declare const AGENT_HARNESS_VERSION = "0.0.210";
@@ -1 +1 @@
1
- export const AGENT_HARNESS_VERSION = "0.0.209";
1
+ export const AGENT_HARNESS_VERSION = "0.0.210";
@@ -27,6 +27,27 @@ function toSqliteUrl(filePath) {
27
27
  function nowIso() {
28
28
  return new Date(Date.now()).toISOString();
29
29
  }
30
+ function runtimeSqliteErrorShouldIncludeSql(baseMessage) {
31
+ if (process.env.AGENT_HARNESS_RUNTIME_SQLITE_DEBUG === "1") {
32
+ return true;
33
+ }
34
+ return /SQLITE_CONSTRAINT|FOREIGN KEY|UNIQUE constraint|NOT NULL/i.test(baseMessage);
35
+ }
36
+ function formatRuntimeSqliteErrorMessage(dbPath, sql, baseMessage) {
37
+ let detail = `agent-harness runtime SQLite (${dbPath}): ${baseMessage}`;
38
+ if (sql && runtimeSqliteErrorShouldIncludeSql(baseMessage)) {
39
+ const sqlPreview = sql.replace(/\s+/g, " ").trim();
40
+ const truncated = sqlPreview.length > 220 ? `${sqlPreview.slice(0, 220)}…` : sqlPreview;
41
+ detail += ` [sql=${truncated}]`;
42
+ }
43
+ return detail;
44
+ }
45
+ function throwWrappedRuntimeSqliteError(dbPath, sql, error) {
46
+ const base = error instanceof Error ? error.message : String(error);
47
+ const wrapped = new Error(formatRuntimeSqliteErrorMessage(dbPath, sql, base));
48
+ wrapped.cause = error;
49
+ throw wrapped;
50
+ }
30
51
  function buildWhereClause(filters) {
31
52
  const active = filters.filter(([, value]) => value !== undefined);
32
53
  if (active.length === 0) {
@@ -42,12 +63,18 @@ async function selectProtectedThreadIds(dbPath) {
42
63
  return [];
43
64
  }
44
65
  const client = createClient({ url: toSqliteUrl(dbPath) });
45
- const result = await client.execute(`SELECT DISTINCT thread_id
66
+ const sql = `SELECT DISTINCT thread_id
46
67
  FROM runs
47
68
  WHERE checkpoint_ref IS NOT NULL
48
69
  AND checkpoint_ref != ''
49
- AND (resumable = 1 OR state NOT IN ('completed', 'failed'))`);
50
- return result.rows.map((row) => asString(asRow(row).thread_id)).filter((value) => value.length > 0);
70
+ AND (resumable = 1 OR state NOT IN ('completed', 'failed'))`;
71
+ try {
72
+ const result = await client.execute(sql);
73
+ return result.rows.map((row) => asString(asRow(row).thread_id)).filter((value) => value.length > 0);
74
+ }
75
+ catch (error) {
76
+ throwWrappedRuntimeSqliteError(dbPath, sql, error);
77
+ }
51
78
  }
52
79
  export async function listProtectedCheckpointThreadIds(dbPath) {
53
80
  return new Set(await selectProtectedThreadIds(dbPath));
@@ -83,16 +110,26 @@ export class SqlitePersistence {
83
110
  }
84
111
  async rawExecute(sql, args) {
85
112
  const client = await this.getClient();
86
- if (args) {
87
- await client.execute(sql, args);
88
- return;
113
+ try {
114
+ if (args) {
115
+ await client.execute(sql, args);
116
+ return;
117
+ }
118
+ await client.execute(sql);
119
+ }
120
+ catch (error) {
121
+ throwWrappedRuntimeSqliteError(this.dbPath, sql, error);
89
122
  }
90
- await client.execute(sql);
91
123
  }
92
124
  async rawSelectAll(sql, args) {
93
125
  const client = await this.getClient();
94
- const result = args ? await client.execute(sql, args) : await client.execute(sql);
95
- return result.rows.map((row) => asRow(row));
126
+ try {
127
+ const result = args ? await client.execute(sql, args) : await client.execute(sql);
128
+ return result.rows.map((row) => asRow(row));
129
+ }
130
+ catch (error) {
131
+ throwWrappedRuntimeSqliteError(this.dbPath, sql, error);
132
+ }
96
133
  }
97
134
  async ensureInitialized() {
98
135
  if (this.initialized) {
@@ -286,18 +323,25 @@ export class SqlitePersistence {
286
323
  async execute(sql, args) {
287
324
  await this.ensureInitialized();
288
325
  const client = await this.getClient();
289
- if (args) {
290
- await client.execute(sql, args);
291
- return;
326
+ try {
327
+ if (args) {
328
+ await client.execute(sql, args);
329
+ return;
330
+ }
331
+ await client.execute(sql);
332
+ }
333
+ catch (error) {
334
+ throwWrappedRuntimeSqliteError(this.dbPath, sql, error);
292
335
  }
293
- await client.execute(sql);
294
336
  }
295
337
  async executeTransaction(steps) {
296
338
  await this.ensureInitialized();
297
339
  const client = await this.getClient();
298
- await client.execute("BEGIN IMMEDIATE");
340
+ let lastSql = "BEGIN IMMEDIATE";
299
341
  try {
342
+ await client.execute("BEGIN IMMEDIATE");
300
343
  for (const step of steps) {
344
+ lastSql = step.sql;
301
345
  if (step.args) {
302
346
  await client.execute(step.sql, step.args);
303
347
  }
@@ -305,6 +349,7 @@ export class SqlitePersistence {
305
349
  await client.execute(step.sql);
306
350
  }
307
351
  }
352
+ lastSql = "COMMIT";
308
353
  await client.execute("COMMIT");
309
354
  }
310
355
  catch (error) {
@@ -314,21 +359,31 @@ export class SqlitePersistence {
314
359
  catch {
315
360
  // Ignore rollback failures and preserve the original error.
316
361
  }
317
- throw error;
362
+ throwWrappedRuntimeSqliteError(this.dbPath, lastSql, error);
318
363
  }
319
364
  }
320
365
  async selectOne(sql, args) {
321
366
  await this.ensureInitialized();
322
367
  const client = await this.getClient();
323
- const result = args ? await client.execute(sql, args) : await client.execute(sql);
324
- const first = result.rows[0];
325
- return first ? asRow(first) : null;
368
+ try {
369
+ const result = args ? await client.execute(sql, args) : await client.execute(sql);
370
+ const first = result.rows[0];
371
+ return first ? asRow(first) : null;
372
+ }
373
+ catch (error) {
374
+ throwWrappedRuntimeSqliteError(this.dbPath, sql, error);
375
+ }
326
376
  }
327
377
  async selectAll(sql, args) {
328
378
  await this.ensureInitialized();
329
379
  const client = await this.getClient();
330
- const result = args ? await client.execute(sql, args) : await client.execute(sql);
331
- return result.rows.map((row) => asRow(row));
380
+ try {
381
+ const result = args ? await client.execute(sql, args) : await client.execute(sql);
382
+ return result.rows.map((row) => asRow(row));
383
+ }
384
+ catch (error) {
385
+ throwWrappedRuntimeSqliteError(this.dbPath, sql, error);
386
+ }
332
387
  }
333
388
  mapThreadSummary(row) {
334
389
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botbotgo/agent-harness",
3
- "version": "0.0.210",
3
+ "version": "0.0.211",
4
4
  "description": "Workspace runtime for multi-agent applications",
5
5
  "license": "MIT",
6
6
  "type": "module",