@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 +23 -20
- package/README.zh.md +40 -39
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/persistence/sqlite-store.js +75 -20
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,11 +14,11 @@
|
|
|
14
14
|
# @botbotgo/agent-harness
|
|
15
15
|
|
|
16
16
|
<p align="center">
|
|
17
|
-
<strong>
|
|
17
|
+
<strong>Build a stable, enterprise-grade, operable runtime for multi-agent products—with approvals, recovery, and operator control built in.</strong>
|
|
18
18
|
</p>
|
|
19
19
|
|
|
20
20
|
<p align="center">
|
|
21
|
-
<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
|
|
47
|
+
## Start in a few lines
|
|
48
48
|
|
|
49
|
-
You can
|
|
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
|
-
|
|
69
|
-
|
|
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:**
|
|
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
|
|
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
|
|
93
|
-
Commercial support
|
|
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
|
|
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
|
-
- [
|
|
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:**
|
|
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
|
|
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 boundaries—not 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
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
278
|
+
## Primary use cases
|
|
278
279
|
|
|
279
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
17
|
+
<strong>快速搭建稳定、可运维的企业级多智能体运行时:内置审批、恢复与运维能力,不止于「能跑通执行」。</strong>
|
|
18
18
|
</p>
|
|
19
19
|
|
|
20
20
|
<p align="center">
|
|
21
|
-
<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
|
-
|
|
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
|
-
|
|
69
|
-
recovery、inspection 和 operator control。
|
|
68
|
+
目标是交付<strong>可运维</strong>的运行时:审批、恢复、可观测与治理默认就绪。若执行层已采用 LangChain v1 或 DeepAgents,可在其之上衔接产品级运行时,无需推倒重来。
|
|
70
69
|
|
|
71
70
|
## 阅读路径
|
|
72
71
|
|
|
73
72
|
建议按这个顺序理解仓库:
|
|
74
73
|
|
|
75
|
-
- **技术:**
|
|
76
|
-
- **产品:**
|
|
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
|
-
- [
|
|
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
|
-
|
|
90
|
+
核心运行时开源,可自由查看与试用。
|
|
91
|
+
商业支持侧重帮助团队完成生产落地与交接,例如:
|
|
93
92
|
|
|
94
|
-
-
|
|
95
|
-
-
|
|
93
|
+
- 部署与接入咨询(面向你的环境)
|
|
94
|
+
- 初期环境搭建与上线协助
|
|
96
95
|
- 优先故障响应与问题排查
|
|
97
96
|
- 运行时治理、审批流和恢复能力加固支持
|
|
98
97
|
- 定制工具、连接器与协议接入开发
|
|
99
|
-
-
|
|
98
|
+
- 操作手册与交接说明(面向接手团队)
|
|
100
99
|
|
|
101
|
-
|
|
102
|
-
|
|
100
|
+
正式生产运维、托管、值班与长期代运营不在默认范围内。
|
|
101
|
+
若需要我方承担上述职责,将按环境与 SLA 单独评估与报价。
|
|
103
102
|
|
|
104
|
-
|
|
103
|
+
企业级合作请联络:**[info@easynet.world](mailto:info@easynet.world)**。
|
|
105
104
|
|
|
106
105
|
相关资料:
|
|
107
106
|
|
|
108
107
|
- [商业服务价格说明](./docs/commercial-pricing.md)
|
|
109
|
-
- [
|
|
108
|
+
- [商业合作流程](./docs/enterprise-process.md)
|
|
110
109
|
|
|
111
110
|
## 容易上手 · 能力齐全 · 配置与扩展
|
|
112
111
|
|
|
113
|
-
**一句话:**
|
|
112
|
+
**一句话:** 对外接口保持精简、运行时能力一次备齐,日常工作落在 **YAML 配置** 与 **扩展**(本地工具、SKILL、MCP)上,而不是反复搭建运行时底座。
|
|
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
|
-
|
|
121
|
+
想先了解「今天能直接用什么」,可从本节读起。`agent-harness` 提供完整运行时能力,而不只是启动脚手架。
|
|
123
122
|
|
|
124
|
-
- **核心 runtime API:** `createAgentHarness`、`request`、`subscribe`、`resolveApproval
|
|
125
|
-
- **运行时 memory 与证据能力:** `memorize`、`recall`、`listMemories`、memory policy hooks、`listArtifacts`、`getArtifact`、`exportEvaluationBundle`、`replayEvaluationBundle`,以及 request / session
|
|
126
|
-
-
|
|
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
|
|
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
|
-
-
|
|
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
|
|
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
|
-
-
|
|
667
|
-
- agent
|
|
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.
|
|
1
|
+
export declare const AGENT_HARNESS_VERSION = "0.0.210";
|
package/dist/package-version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const AGENT_HARNESS_VERSION = "0.0.
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
-
|
|
95
|
-
|
|
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
|
-
|
|
290
|
-
|
|
291
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
324
|
-
|
|
325
|
-
|
|
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
|
-
|
|
331
|
-
|
|
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 {
|