@botbotgo/agent-harness 0.0.150 → 0.0.152

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
@@ -33,11 +33,20 @@
33
33
  >
34
34
  </p>
35
35
 
36
+ ## Easy to start · Full runtime · Configure and extend
37
+
38
+ **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.
39
+
40
+ - **Easy to start:** `createAgentHarness` → `run` → `stop`, plus inspection helpers such as `subscribe`, `listSessions`, `listApprovals`, and `resolveApproval`.
41
+ - **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)).
42
+ - **Extend:** drop `tool({...})` modules and SKILL trees under `resources/`, wire shared tools and MCP in catalogs, and let agents whitelist what they use.
43
+ - **Built into the runtime:** persisted `runs`, `threads`, `approvals`, and `events`; recovery and queueing; streaming listeners; MCP in/out; LangChain v1 and DeepAgents adapters—so you do not rebuild that layer per app.
44
+
36
45
  ## What Problem We Solve
37
46
 
38
- In one line: `agent-harness` takes the runtime work that appears after the demo and makes it part of the product runtime from day one.
47
+ In one line: `agent-harness` productizes the runtime work that usually appears after the demo.
39
48
 
40
- If your team already has agents, prompts, tools, and workflows, the missing layer is usually not more execution. It is the runtime that makes those pieces operable as software.
49
+ If your team already has agents, prompts, tools, and workflows, the missing layer is usually not more execution. The missing layer is the runtime that makes those pieces operable, inspectable, and recoverable in production.
41
50
 
42
51
  What you get on day one:
43
52
 
@@ -48,7 +57,7 @@ What you get on day one:
48
57
  - one workspace-shaped assembly model instead of app-specific runtime glue
49
58
  - one stable runtime contract even when execution backends change underneath
50
59
 
51
- AI makes it much easier to generate agent logic, tool calls, and workflow code. The hard part moves to operations.
60
+ AI makes it much easier to generate agent logic, tool calls, and workflow code. The harder problem shifts to operations.
52
61
 
53
62
  Once the demo works, the real software problem changes shape:
54
63
 
@@ -57,7 +66,7 @@ Once the demo works, the real software problem changes shape:
57
66
  - backend, prompt, and tool changes happen faster, but product-facing behavior still needs one stable control surface
58
67
  - MCP and provider-native tooling expand what agents can reach, which raises the bar for governance
59
68
 
60
- Teams still need answers to the runtime questions that appear after that shift:
69
+ Teams still need clear answers to the runtime questions that appear after that shift:
61
70
 
62
71
  - how approvals are resolved and audited
63
72
  - how runs, threads, and events stay inspectable
@@ -65,15 +74,15 @@ Teams still need answers to the runtime questions that appear after that shift:
65
74
  - how routing, concurrency, and maintenance policy stay consistent
66
75
  - how backend churn does not leak into the product model
67
76
 
68
- `agent-harness` solves that layer. It keeps agent execution upstream while making the application runtime operable, recoverable, and governable.
77
+ `agent-harness` solves that layer. It keeps agent execution upstream while turning the application runtime into something teams can operate, recover, and govern.
69
78
 
70
- That means the product story becomes easier to explain:
79
+ That makes the product story easier to explain:
71
80
 
72
81
  - you bring the workspace, agents, tools, and prompts
73
82
  - `agent-harness` brings persisted `runs`, `threads`, `approvals`, `events`, recovery, and operator visibility
74
83
  - your application gets one stable runtime contract instead of backend-specific runtime plumbing
75
84
 
76
- Concretely, that means:
85
+ In concrete terms:
77
86
 
78
87
  - a product-facing approval and operator surface instead of backend-specific middleware state
79
88
  - persisted `runs`, `threads`, `approvals`, and `events` as stable runtime records
@@ -89,7 +98,7 @@ Concretely, that means:
89
98
 
90
99
  It is not a new agent framework. It is the runtime layer around LangChain v1 and DeepAgents that turns one workspace into one operable application runtime.
91
100
 
92
- The point is simple:
101
+ The positioning is simple:
93
102
 
94
103
  - Codex, Claude Code, and Cursor are products for people using agents
95
104
  - LangChain v1 and DeepAgents are frameworks for defining agent execution semantics
@@ -115,7 +124,7 @@ The runtime provides:
115
124
  - local `resources/tools/` `tool({...})` modules and `resources/skills/` discovery
116
125
  - persisted threads, runs, approvals, events, queue state, and recovery metadata
117
126
 
118
- In practice, the harness exists for the parts that are painful to rebuild inside every agent app:
127
+ In practice, the harness exists for the parts that are expensive and repetitive to rebuild inside every agent app:
119
128
 
120
129
  - approval inboxes and human decision flow
121
130
  - persisted runs, threads, and inspectable event history
@@ -124,7 +133,7 @@ In practice, the harness exists for the parts that are painful to rebuild inside
124
133
  - queueing, concurrency, maintenance, and operational policy
125
134
  - stable runtime records that stay usable even if the backend changes
126
135
 
127
- 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.
136
+ 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 configuration instead of reverse-engineering adapter behavior from source.
128
137
 
129
138
  The default rule is:
130
139
 
@@ -162,7 +171,7 @@ Recommended orchestration shape for long-running flows:
162
171
 
163
172
  ## Why This Exists
164
173
 
165
- Most agent tooling stops at execution.
174
+ Most agent tooling stops at execution. Production software does not.
166
175
 
167
176
  Real products need a runtime that can answer harder questions:
168
177
 
@@ -180,7 +189,7 @@ Real products need a runtime that can answer harder questions:
180
189
  - It gives operators a runtime control surface instead of exposing raw backend internals
181
190
  - It keeps observability and governance runtime-owned with trace correlation, continuity metadata, and approval defaults for sensitive side effects
182
191
  - It keeps checkpoint resume system-managed instead of promoting checkpoint internals into the primary API
183
- - It lets YAML own assembly and operating policy while code keeps a tiny surface
192
+ - It lets YAML own assembly and operating policy while code keeps a small, stable surface
184
193
  - It goes deep on runtime concerns that upstream libraries do not fully productize
185
194
 
186
195
  ## When To Use It
package/README.zh.md CHANGED
@@ -33,11 +33,20 @@
33
33
  >
34
34
  </p>
35
35
 
36
+ ## 容易上手 · 能力齐全 · 配置与扩展
37
+
38
+ **一句话:** 接入面保持很薄,运行时能力整层交付,日常主要工作集中在 **YAML 配置** 与 **扩展**(本地工具、SKILL 包、MCP),而不是反复自建运行时基础设施。
39
+
40
+ - **容易上手:** `createAgentHarness` → `run` → `stop`,以及 `subscribe`、`listSessions`、`listApprovals`、`resolveApproval` 等查询与控制能力。
41
+ - **配置:** 路由、模型、工具、存储、后端、MCP、恢复与维护写在声明式工作区 YAML 里(见[快速开始](#快速开始)与[如何配置](#如何配置))。
42
+ - **扩展:** 在 `resources/` 下放置 `tool({...})` 模块与 SKILL 目录,在目录里声明共享工具与 MCP,再由各 agent 按名字白名单启用。
43
+ - **内建运行时:** 持久化 `runs`、`threads`、`approvals` 与 `events`;恢复与排队;流式监听;MCP 接入与对外暴露;LangChain v1 与 DeepAgents 适配——避免每个应用重复造这一层。
44
+
36
45
  ## 我们解决什么问题
37
46
 
38
- 一句话概括:`agent-harness` demo 之后才暴露出来的运行时问题,提前收进产品 runtime 本身。
47
+ 一句话概括:`agent-harness` 把通常在 demo 之后才暴露出来的运行时工作,提前做成产品 runtime 的一部分。
39
48
 
40
- 如果团队已经有 agents、prompts、tools 和 workflows,真正缺的通常不是再来一层执行,而是把这些东西变成“可运维的软件”的运行时层。
49
+ 如果团队已经有 agents、prompts、tools 和 workflows,真正缺的通常不是再多一层执行,而是把这些能力变成“可运维软件”的运行时层。
41
50
 
42
51
  第一天就能直接拿到的东西:
43
52
 
@@ -48,7 +57,7 @@
48
57
  - 一个工作区形态的装配模型,而不是每个应用各写一套运行时胶水
49
58
  - 即使底层 execution backend 变化,也尽量保持稳定的 runtime 契约
50
59
 
51
- AI 让 agent 逻辑、工具调用和工作流代码更容易生成,真正变难的是运行时运维。
60
+ AI 让 agent 逻辑、工具调用和工作流代码更容易生成,真正更难的是运行时运维。
52
61
 
53
62
  当 demo 跑起来之后,真正的软件问题会换一种形状出现:
54
63
 
@@ -57,7 +66,7 @@ AI 让 agent 逻辑、工具调用和工作流代码更容易生成,真正变
57
66
  - backend、prompt 和工具变化更快了,但面向产品的控制面仍然必须稳定
58
67
  - MCP 与 provider 原生工具扩展了 agent 的可触达范围,也同步抬高了治理要求
59
68
 
60
- 团队仍然要回答这些运行时问题:
69
+ 团队仍然要正面回答这些运行时问题:
61
70
 
62
71
  - 审批怎么决策、怎么审计
63
72
  - runs、threads、events 怎么稳定可查
@@ -65,7 +74,7 @@ AI 让 agent 逻辑、工具调用和工作流代码更容易生成,真正变
65
74
  - 路由、并发和维护策略怎么保持一致
66
75
  - 后端频繁变化时,怎么不让产品模型跟着漂移
67
76
 
68
- `agent-harness` 解决的就是这一层。它把 agent 执行留在上游,同时把应用运行时做成可运维、可恢复、可治理的系统。
77
+ `agent-harness` 解决的就是这一层。它把 agent 执行留在上游,同时把应用运行时做成真正可运维、可恢复、可治理的系统。
69
78
 
70
79
  换成更直接的产品语言,就是:
71
80
 
@@ -89,7 +98,7 @@ AI 让 agent 逻辑、工具调用和工作流代码更容易生成,真正变
89
98
 
90
99
  它不是又一个 agent 框架,而是围绕 LangChain v1 与 DeepAgents 的运行时层:把一个工作区变成一套可运维的应用运行时。
91
100
 
92
- 关系可以概括为:
101
+ 产品定位可以概括为:
93
102
 
94
103
  - Codex、Claude Code、Cursor 是「人用 agent」的产品
95
104
  - LangChain v1 与 DeepAgents 是定义 agent 执行语义的框架
@@ -115,7 +124,7 @@ AI 让 agent 逻辑、工具调用和工作流代码更容易生成,真正变
115
124
  - 本地 `resources/tools/` 中 `tool({...})` 工具模块与 `resources/skills/` 的发现
116
125
  - 持久化的线程、运行、审批、事件、队列状态与恢复元数据
117
126
 
118
- 落到实际系统里,harness 主要解决那些每个 agent 应用都不想重复造一遍的运行时难题:
127
+ 落到实际系统里,harness 主要解决那些每个 agent 应用都不应该重复造一遍的运行时难题:
119
128
 
120
129
  - 审批收件箱与人工决策流
121
130
  - 持久化的 runs、threads 与可查询事件历史
@@ -124,7 +133,7 @@ AI 让 agent 逻辑、工具调用和工作流代码更容易生成,真正变
124
133
  - 队列、并发、维护与运维策略
125
134
  - 即使后端变更也保持稳定的运行时记录模型
126
135
 
127
- 仓库自带的默认配置刻意做成「形状完整」。随仓库提供的 YAML 对重要的运行时与 agent 开关给出显式默认值,便于从具体配置起步,而不必从源码反推适配器行为。
136
+ 仓库自带的默认配置刻意做成「形状完整」。随仓库提供的 YAML 对关键运行时与 agent 开关给出显式默认值,便于从具体配置起步,而不必从源码反推适配器行为。
128
137
 
129
138
  默认原则是:
130
139
 
@@ -159,7 +168,7 @@ AI 让 agent 逻辑、工具调用和工作流代码更容易生成,真正变
159
168
 
160
169
  ## 为何需要它
161
170
 
162
- 多数 agent 工具停在「能跑」。
171
+ 多数 agent 工具停在「能跑」,但生产软件不能只停在这里。
163
172
 
164
173
  真实产品需要能回答更难问题的运行时:
165
174
 
@@ -169,7 +178,7 @@ AI 让 agent 逻辑、工具调用和工作流代码更容易生成,真正变
169
178
  - 如何在不暴露原始后端状态的前提下检查线程与事件?
170
179
  - 如何在不大改产品模型的前提下替换后端实现?
171
180
 
172
- `agent-harness` 在不把应用 API 变成 LangChain v1 / DeepAgents 翻版的前提下,回答这些问题。
181
+ `agent-harness` 在不把应用 API 做成 LangChain v1 / DeepAgents 翻版的前提下,回答这些问题。
173
182
 
174
183
  ## 有何不同
175
184
 
@@ -177,7 +186,7 @@ AI 让 agent 逻辑、工具调用和工作流代码更容易生成,真正变
177
186
  - 给运维侧提供运行时控制面,而不是暴露原始后端内部结构
178
187
  - 将可观测性与治理留在运行时:包括 trace correlation、continuity metadata,以及高风险副作用的默认审批
179
188
  - 将 checkpoint 恢复作为系统管理的行为,而不是把 checkpoint 细节抬成主 API
180
- - 复杂装配与运行策略交给 YAML,代码面保持极小
189
+ - 复杂装配与运行策略交给 YAML,代码面保持小而稳
181
190
  - 在上游库未充分产品化的运行时问题上做深做透
182
191
 
183
192
  ## 什么时候该用
@@ -66,6 +66,10 @@ spec:
66
66
  writeOnApprovalResolution: true
67
67
  writeOnRunCompletion: true
68
68
 
69
+ # agent-harness feature: optional thread snapshot projection for operational state and pending approvals.
70
+ threadMemorySync:
71
+ enabled: true
72
+
69
73
  # agent-harness feature: optional Mem0 OSS ingestion engine for automatic long-term knowledge extraction.
70
74
  mem0:
71
75
  enabled: false
@@ -162,6 +162,8 @@ spec:
162
162
  backgroundConsolidation: true
163
163
  writeOnApprovalResolution: true
164
164
  writeOnRunCompletion: true
165
+ threadMemorySync:
166
+ enabled: true
165
167
  mem0:
166
168
  enabled: false
167
169
  apiKeyEnv: MEM0_API_KEY
@@ -1 +1 @@
1
- export declare const AGENT_HARNESS_VERSION = "0.0.149";
1
+ export declare const AGENT_HARNESS_VERSION = "0.0.151";
@@ -1 +1 @@
1
- export const AGENT_HARNESS_VERSION = "0.0.149";
1
+ export const AGENT_HARNESS_VERSION = "0.0.151";
@@ -8,17 +8,25 @@ export type ResolvedRuntimeMemorySyncConfig = {
8
8
  backgroundConsolidation: boolean;
9
9
  maxMessagesPerRun: number;
10
10
  };
11
+ type RuntimeMemorySyncOptions = {
12
+ resolveThreadNamespace?: (threadId: string) => string[];
13
+ resolveRunNamespace?: (threadId: string) => string[];
14
+ };
11
15
  export declare function readRuntimeMemorySyncConfig(runtimeMemory: Record<string, unknown> | undefined): ResolvedRuntimeMemorySyncConfig | undefined;
12
16
  export declare class RuntimeMemorySync implements HarnessEventProjection {
13
17
  private readonly persistence;
14
18
  readonly store: StoreLike;
15
19
  private readonly config;
20
+ private readonly options;
16
21
  private readonly pending;
17
22
  private syncChain;
18
23
  readonly name = "runtime-memory-sync";
19
- constructor(persistence: RuntimePersistence, store: StoreLike, config: ResolvedRuntimeMemorySyncConfig);
24
+ constructor(persistence: RuntimePersistence, store: StoreLike, config: ResolvedRuntimeMemorySyncConfig, options?: RuntimeMemorySyncOptions);
20
25
  shouldHandle(event: HarnessEvent): boolean;
21
26
  handleEvent(event: HarnessEvent): Promise<void>;
22
27
  private syncRun;
28
+ private resolveThreadNamespace;
29
+ private resolveRunNamespace;
23
30
  close(): Promise<void>;
24
31
  }
32
+ export {};
@@ -100,13 +100,15 @@ export class RuntimeMemorySync {
100
100
  persistence;
101
101
  store;
102
102
  config;
103
+ options;
103
104
  pending = new Set();
104
105
  syncChain = Promise.resolve();
105
106
  name = "runtime-memory-sync";
106
- constructor(persistence, store, config) {
107
+ constructor(persistence, store, config, options = {}) {
107
108
  this.persistence = persistence;
108
109
  this.store = store;
109
110
  this.config = config;
111
+ this.options = options;
110
112
  }
111
113
  shouldHandle(event) {
112
114
  if (!RUNTIME_MEMORY_EVENT_TYPES.has(event.eventType)) {
@@ -161,8 +163,8 @@ export class RuntimeMemorySync {
161
163
  approvals,
162
164
  });
163
165
  await Promise.all([
164
- this.store.put(["memories", "runs", threadId], `${runId}.summary.md`, { content: `${summaryMarkdown}\n` }),
165
- this.store.put(["memories", "runs", threadId], `${runId}.record.json`, {
166
+ this.store.put(this.resolveRunNamespace(threadId), `${runId}.summary.md`, { content: `${summaryMarkdown}\n` }),
167
+ this.store.put(this.resolveRunNamespace(threadId), `${runId}.record.json`, {
166
168
  kind: "summary",
167
169
  scope: "thread",
168
170
  threadId,
@@ -185,7 +187,13 @@ export class RuntimeMemorySync {
185
187
  capturedAt,
186
188
  messages,
187
189
  });
188
- await this.store.put(["memories", "threads", threadId], "durable-summary.md", { content: `${digestMarkdown}\n` });
190
+ await this.store.put(this.resolveThreadNamespace(threadId), "durable-summary.md", { content: `${digestMarkdown}\n` });
191
+ }
192
+ resolveThreadNamespace(threadId) {
193
+ return this.options.resolveThreadNamespace ? this.options.resolveThreadNamespace(threadId) : ["memories", "threads", threadId];
194
+ }
195
+ resolveRunNamespace(threadId) {
196
+ return this.options.resolveRunNamespace ? this.options.resolveRunNamespace(threadId) : ["memories", "runs", threadId];
189
197
  }
190
198
  async close() {
191
199
  await Promise.allSettled(Array.from(this.pending));
@@ -1,14 +1,18 @@
1
1
  import type { HarnessEvent, HarnessEventProjection } from "../../../contracts/types.js";
2
2
  import type { RuntimePersistence } from "../../../persistence/types.js";
3
+ type ThreadMemorySyncOptions = {
4
+ resolveThreadNamespace?: (threadId: string) => string[];
5
+ };
3
6
  export declare class ThreadMemorySync implements HarnessEventProjection {
4
7
  private readonly persistence;
5
8
  private readonly store?;
9
+ private readonly options;
6
10
  private readonly pending;
7
11
  private syncChain;
8
12
  readonly name = "thread-memory-sync";
9
13
  constructor(persistence: RuntimePersistence, store?: {
10
14
  put: (namespace: string[], key: string, value: Record<string, any>) => Promise<void>;
11
- } | undefined);
15
+ } | undefined, options?: ThreadMemorySyncOptions);
12
16
  shouldHandle(event: HarnessEvent): boolean;
13
17
  handleEvent(event: HarnessEvent): Promise<void>;
14
18
  private syncThread;
@@ -6,11 +6,11 @@ function excerpt(message) {
6
6
  const normalized = extractMessageText(message.content).replace(/\s+/g, " ").trim();
7
7
  return normalized.length > 240 ? `${normalized.slice(0, 237)}...` : normalized;
8
8
  }
9
- function renderStatusMarkdown(thread, messages) {
9
+ function renderThreadSnapshotMarkdown(thread, messages, approvals) {
10
10
  const userMessages = messages.filter((message) => message.role === "user");
11
11
  const assistantMessages = messages.filter((message) => message.role === "assistant");
12
12
  return [
13
- "# Thread Status",
13
+ "# Thread Snapshot",
14
14
  "",
15
15
  `- thread_id: ${thread.threadId}`,
16
16
  `- latest_run_id: ${thread.latestRunId}`,
@@ -24,15 +24,17 @@ function renderStatusMarkdown(thread, messages) {
24
24
  "## Recent Assistant Message",
25
25
  excerpt(assistantMessages.at(-1)),
26
26
  "",
27
+ ...formatOpenApprovalsSection(approvals),
27
28
  ].join("\n");
28
29
  }
29
- function renderOpenApprovalsMarkdown(approvals) {
30
+ function formatOpenApprovalsSection(approvals) {
31
+ const lines = ["## Open Approvals", ""];
30
32
  if (approvals.length === 0) {
31
- return ["# Open Approvals", "", "(none)", ""].join("\n");
33
+ lines.push("(none)", "");
34
+ return lines;
32
35
  }
33
- const lines = ["# Open Approvals", ""];
34
36
  for (const approval of approvals) {
35
- lines.push(`## ${approval.approvalId}`);
37
+ lines.push(`### ${approval.approvalId}`);
36
38
  lines.push(`- pending_action_id: ${approval.pendingActionId}`);
37
39
  lines.push(`- tool: ${approval.toolName}`);
38
40
  lines.push(`- run_id: ${approval.runId}`);
@@ -40,7 +42,10 @@ function renderOpenApprovalsMarkdown(approvals) {
40
42
  lines.push(`- allowed: ${approval.allowedDecisions.join(", ")}`);
41
43
  lines.push("");
42
44
  }
43
- return lines.join("\n");
45
+ return lines;
46
+ }
47
+ function resolveThreadNamespace(threadId, resolver) {
48
+ return resolver ? resolver(threadId) : ["memories", "threads", threadId];
44
49
  }
45
50
  const THREAD_MEMORY_EVENT_TYPES = new Set([
46
51
  "run.state.changed",
@@ -52,12 +57,14 @@ const THREAD_MEMORY_EVENT_TYPES = new Set([
52
57
  export class ThreadMemorySync {
53
58
  persistence;
54
59
  store;
60
+ options;
55
61
  pending = new Set();
56
62
  syncChain = Promise.resolve();
57
63
  name = "thread-memory-sync";
58
- constructor(persistence, store) {
64
+ constructor(persistence, store, options = {}) {
59
65
  this.persistence = persistence;
60
66
  this.store = store;
67
+ this.options = options;
61
68
  }
62
69
  shouldHandle(event) {
63
70
  return THREAD_MEMORY_EVENT_TYPES.has(event.eventType);
@@ -93,10 +100,9 @@ export class ThreadMemorySync {
93
100
  if (!this.store) {
94
101
  return;
95
102
  }
96
- await Promise.all([
97
- this.store.put(["memories", "threads", threadId], "status.md", { content: `${renderStatusMarkdown(thread, messages)}\n` }),
98
- this.store.put(["memories", "threads", threadId], "open-approvals.md", { content: `${renderOpenApprovalsMarkdown(pendingApprovals)}\n` }),
99
- ]);
103
+ await this.store.put(resolveThreadNamespace(threadId, this.options.resolveThreadNamespace), "snapshot.md", {
104
+ content: `${renderThreadSnapshotMarkdown(thread, messages, pendingApprovals)}\n`,
105
+ });
100
106
  }
101
107
  async close() {
102
108
  await Promise.allSettled(Array.from(this.pending));
@@ -144,7 +144,15 @@ export class AgentHarnessRuntime {
144
144
  this.routingRules = getRoutingRules(workspace.refs);
145
145
  this.routingDefaultAgentId = getRoutingDefaultAgentId(workspace.refs);
146
146
  if (isThreadMemorySyncEnabled(workspace)) {
147
- this.threadMemorySync = new ThreadMemorySync(this.persistence, this.runtimeMemoryStore);
147
+ this.threadMemorySync = new ThreadMemorySync(this.persistence, this.runtimeMemoryStore, {
148
+ resolveThreadNamespace: (threadId) => {
149
+ const binding = this.defaultRuntimeEntryBinding;
150
+ if (!binding) {
151
+ return ["memories", "threads", threadId];
152
+ }
153
+ return this.resolveMemoryNamespace("thread", binding, { threadId });
154
+ },
155
+ });
148
156
  this.unregisterThreadMemorySync = this.eventBus.registerProjection(this.threadMemorySync);
149
157
  }
150
158
  else {
@@ -153,7 +161,15 @@ export class AgentHarnessRuntime {
153
161
  }
154
162
  const runtimeMemorySyncConfig = readRuntimeMemorySyncConfig(this.defaultRuntimeEntryBinding?.harnessRuntime.runtimeMemory);
155
163
  if (runtimeMemorySyncConfig) {
156
- this.runtimeMemorySync = new RuntimeMemorySync(this.persistence, this.runtimeMemoryStore, runtimeMemorySyncConfig);
164
+ this.runtimeMemorySync = new RuntimeMemorySync(this.persistence, this.runtimeMemoryStore, runtimeMemorySyncConfig, {
165
+ resolveThreadNamespace: (threadId) => {
166
+ const binding = this.defaultRuntimeEntryBinding;
167
+ if (!binding) {
168
+ return ["memories", "threads", threadId];
169
+ }
170
+ return this.resolveMemoryNamespace("thread", binding, { threadId });
171
+ },
172
+ });
157
173
  this.unregisterRuntimeMemorySync = this.eventBus.registerProjection(this.runtimeMemorySync);
158
174
  }
159
175
  else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botbotgo/agent-harness",
3
- "version": "0.0.150",
3
+ "version": "0.0.152",
4
4
  "description": "Workspace runtime for multi-agent applications",
5
5
  "type": "module",
6
6
  "packageManager": "npm@10.9.2",