@botbotgo/agent-harness 0.0.46 → 0.0.47

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/dist/api.d.ts CHANGED
@@ -13,6 +13,7 @@ export declare function run(runtime: AgentHarnessRuntime, options: RunOptions):
13
13
  export declare function subscribe(runtime: AgentHarnessRuntime, listener: Parameters<AgentHarnessRuntime["subscribe"]>[0]): () => void;
14
14
  export declare function listThreads(runtime: AgentHarnessRuntime, filter?: Parameters<AgentHarnessRuntime["listThreads"]>[0]): Promise<ThreadSummary[]>;
15
15
  export declare function getThread(runtime: AgentHarnessRuntime, threadId: string): Promise<ThreadRecord | null>;
16
+ export declare function deleteThread(runtime: AgentHarnessRuntime, threadId: string): Promise<boolean>;
16
17
  export declare function listApprovals(runtime: AgentHarnessRuntime, filter?: Parameters<AgentHarnessRuntime["listApprovals"]>[0]): Promise<ApprovalRecord[]>;
17
18
  export declare function getApproval(runtime: AgentHarnessRuntime, approvalId: string): Promise<ApprovalRecord | null>;
18
19
  export declare function stop(runtime: AgentHarnessRuntime): Promise<void>;
package/dist/api.js CHANGED
@@ -21,6 +21,9 @@ export async function listThreads(runtime, filter) {
21
21
  export async function getThread(runtime, threadId) {
22
22
  return runtime.getThread(threadId);
23
23
  }
24
+ export async function deleteThread(runtime, threadId) {
25
+ return runtime.deleteThread(threadId);
26
+ }
24
27
  export async function listApprovals(runtime, filter) {
25
28
  return runtime.listApprovals(filter);
26
29
  }
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { AgentHarnessRuntime, createAgentHarness, createToolMcpServer, getApproval, getThread, listApprovals, listThreads, run, serveToolsOverStdio, subscribe, stop, } from "./api.js";
1
+ export { AgentHarnessRuntime, createAgentHarness, createToolMcpServer, deleteThread, getApproval, getThread, listApprovals, listThreads, run, serveToolsOverStdio, subscribe, stop, } from "./api.js";
2
2
  export type { ToolMcpServerOptions } from "./mcp.js";
3
3
  export { tool } from "./tools.js";
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- export { AgentHarnessRuntime, createAgentHarness, createToolMcpServer, getApproval, getThread, listApprovals, listThreads, run, serveToolsOverStdio, subscribe, stop, } from "./api.js";
1
+ export { AgentHarnessRuntime, createAgentHarness, createToolMcpServer, deleteThread, getApproval, getThread, listApprovals, listThreads, run, serveToolsOverStdio, subscribe, stop, } from "./api.js";
2
2
  export { tool } from "./tools.js";
@@ -1 +1 @@
1
- export declare const AGENT_HARNESS_VERSION = "0.0.45";
1
+ export declare const AGENT_HARNESS_VERSION = "0.0.46";
@@ -1 +1 @@
1
- export const AGENT_HARNESS_VERSION = "0.0.45";
1
+ export const AGENT_HARNESS_VERSION = "0.0.46";
@@ -47,6 +47,10 @@ type PersistedRunRequest = {
47
47
  export declare class FilePersistence {
48
48
  private readonly runRoot;
49
49
  constructor(runRoot: string);
50
+ private threadIndexPath;
51
+ private runIndexPath;
52
+ private approvalIndexPath;
53
+ private delegationIndexPath;
50
54
  initialize(): Promise<void>;
51
55
  threadDir(threadId: string): string;
52
56
  runDir(threadId: string, runId: string): string;
@@ -78,6 +82,7 @@ export declare class FilePersistence {
78
82
  getRunApprovals(threadId: string, runId: string): Promise<InternalApprovalRecord[]>;
79
83
  getRunMeta(threadId: string, runId: string): Promise<RunMeta>;
80
84
  getRunLifecycle(threadId: string, runId: string): Promise<Lifecycle>;
85
+ deleteThread(threadId: string): Promise<boolean>;
81
86
  saveRunRequest(threadId: string, runId: string, request: PersistedRunRequest): Promise<void>;
82
87
  getRunRequest(threadId: string, runId: string): Promise<PersistedRunRequest | null>;
83
88
  clearRunRequest(threadId: string, runId: string): Promise<void>;
@@ -7,6 +7,18 @@ export class FilePersistence {
7
7
  constructor(runRoot) {
8
8
  this.runRoot = runRoot;
9
9
  }
10
+ threadIndexPath(threadId) {
11
+ return path.join(this.runRoot, "indexes", "threads", `${threadId}.json`);
12
+ }
13
+ runIndexPath(runId) {
14
+ return path.join(this.runRoot, "indexes", "runs", `${runId}.json`);
15
+ }
16
+ approvalIndexPath(approvalId) {
17
+ return path.join(this.runRoot, "indexes", "approvals", `${approvalId}.json`);
18
+ }
19
+ delegationIndexPath(delegationId) {
20
+ return path.join(this.runRoot, "indexes", "delegations", `${delegationId}.json`);
21
+ }
10
22
  async initialize() {
11
23
  await Promise.all([
12
24
  "indexes/threads",
@@ -266,6 +278,32 @@ export class FilePersistence {
266
278
  async getRunLifecycle(threadId, runId) {
267
279
  return readJson(path.join(this.runDir(threadId, runId), "lifecycle.json"));
268
280
  }
281
+ async deleteThread(threadId) {
282
+ const threadDir = this.threadDir(threadId);
283
+ const threadIndexPath = this.threadIndexPath(threadId);
284
+ if (!(await fileExists(threadDir)) && !(await fileExists(threadIndexPath))) {
285
+ return false;
286
+ }
287
+ const [runIndexes, approvals, delegations] = await Promise.all([
288
+ this.listRunIndexes(),
289
+ this.listApprovals(),
290
+ this.listDelegations(),
291
+ ]);
292
+ await Promise.all([
293
+ ...runIndexes
294
+ .filter((record) => record.threadId === threadId)
295
+ .map((record) => rm(this.runIndexPath(record.runId), { force: true })),
296
+ ...approvals
297
+ .filter((record) => record.threadId === threadId)
298
+ .map((record) => rm(this.approvalIndexPath(record.approvalId), { force: true })),
299
+ ...delegations
300
+ .filter((record) => record.threadId === threadId)
301
+ .map((record) => rm(this.delegationIndexPath(record.delegationId), { force: true })),
302
+ rm(threadIndexPath, { force: true }),
303
+ rm(threadDir, { recursive: true, force: true }),
304
+ ]);
305
+ return true;
306
+ }
269
307
  async saveRunRequest(threadId, runId, request) {
270
308
  await writeJson(path.join(this.runDir(threadId, runId), "request.json"), request);
271
309
  }
@@ -26,6 +26,7 @@ export declare class AgentHarnessRuntime {
26
26
  private readonly pendingRunSlots;
27
27
  private toPublicApprovalRecord;
28
28
  private normalizeInvocationEnvelope;
29
+ private isTerminalRunState;
29
30
  private listHostBindings;
30
31
  private defaultRunRoot;
31
32
  private heuristicRoute;
@@ -52,6 +53,8 @@ export declare class AgentHarnessRuntime {
52
53
  runId?: string;
53
54
  }): Promise<ApprovalRecord[]>;
54
55
  getApproval(approvalId: string): Promise<ApprovalRecord | null>;
56
+ private deleteThreadCheckpoints;
57
+ deleteThread(threadId: string): Promise<boolean>;
55
58
  createToolMcpServer(options: ToolMcpServerOptions): Promise<import("@modelcontextprotocol/sdk/server/mcp.js").McpServer>;
56
59
  serveToolsOverStdio(options: ToolMcpServerOptions): Promise<import("@modelcontextprotocol/sdk/server/mcp.js").McpServer>;
57
60
  routeAgent(input: MessageContent, options?: {
@@ -53,6 +53,9 @@ export class AgentHarnessRuntime {
53
53
  invocation,
54
54
  };
55
55
  }
56
+ isTerminalRunState(state) {
57
+ return state === "completed" || state === "failed";
58
+ }
56
59
  listHostBindings() {
57
60
  return inferRoutingBindings(this.workspace).hostBindings;
58
61
  }
@@ -283,6 +286,39 @@ export class AgentHarnessRuntime {
283
286
  const approval = await this.persistence.getApproval(approvalId);
284
287
  return approval ? this.toPublicApprovalRecord(approval) : null;
285
288
  }
289
+ async deleteThreadCheckpoints(threadId) {
290
+ const resolver = this.resolvedRuntimeAdapterOptions.checkpointerResolver;
291
+ if (!resolver) {
292
+ return;
293
+ }
294
+ const seen = new Set();
295
+ for (const binding of this.workspace.bindings.values()) {
296
+ const saver = resolver(binding);
297
+ if (!saver || seen.has(saver)) {
298
+ continue;
299
+ }
300
+ seen.add(saver);
301
+ const maybeDeleteThread = saver.deleteThread;
302
+ if (typeof maybeDeleteThread === "function") {
303
+ await maybeDeleteThread.call(saver, threadId);
304
+ }
305
+ }
306
+ }
307
+ async deleteThread(threadId) {
308
+ const thread = await this.getThread(threadId);
309
+ if (!thread) {
310
+ return false;
311
+ }
312
+ const activeRun = thread.runs.find((run) => !this.isTerminalRunState(run.state));
313
+ if (activeRun) {
314
+ throw new Error(`Cannot delete thread ${threadId} while run ${activeRun.runId} is ${activeRun.state}`);
315
+ }
316
+ const deleted = await this.persistence.deleteThread(threadId);
317
+ if (deleted) {
318
+ await this.deleteThreadCheckpoints(threadId);
319
+ }
320
+ return deleted;
321
+ }
286
322
  async createToolMcpServer(options) {
287
323
  const tools = this.resolveAgentTools(options.agentId).map(({ compiledTool, resolvedTool }) => ({
288
324
  compiledTool,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botbotgo/agent-harness",
3
- "version": "0.0.46",
3
+ "version": "0.0.47",
4
4
  "description": "Workspace runtime for multi-agent applications",
5
5
  "type": "module",
6
6
  "packageManager": "npm@10.9.2",