@botbotgo/agent-harness 0.0.108 → 0.0.109

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.
Files changed (36) hide show
  1. package/dist/package-version.d.ts +1 -1
  2. package/dist/package-version.js +1 -1
  3. package/dist/runtime/adapter/execution-context.d.ts +7 -0
  4. package/dist/runtime/adapter/execution-context.js +9 -2
  5. package/dist/runtime/adapter/middleware-assembly.js +2 -2
  6. package/dist/runtime/adapter/runnable-config.d.ts +44 -0
  7. package/dist/runtime/adapter/runnable-config.js +51 -0
  8. package/dist/runtime/adapter/runtime-adapter-support.d.ts +0 -1
  9. package/dist/runtime/adapter/runtime-adapter-support.js +1 -4
  10. package/dist/runtime/agent-runtime-adapter.js +3 -5
  11. package/dist/runtime/harness/events/listener-runtime.d.ts +18 -0
  12. package/dist/runtime/harness/events/listener-runtime.js +9 -0
  13. package/dist/runtime/harness/events/runtime-event-operations.d.ts +17 -0
  14. package/dist/runtime/harness/events/runtime-event-operations.js +9 -0
  15. package/dist/runtime/harness/run/recovery.d.ts +1 -1
  16. package/dist/runtime/harness/run/resume-runtime.d.ts +55 -0
  17. package/dist/runtime/harness/run/resume-runtime.js +26 -0
  18. package/dist/runtime/harness/run/routing.d.ts +8 -0
  19. package/dist/runtime/harness/run/routing.js +21 -0
  20. package/dist/runtime/harness/run/run-operations.d.ts +47 -0
  21. package/dist/runtime/harness/run/run-operations.js +67 -0
  22. package/dist/runtime/harness/run/start-run.d.ts +82 -0
  23. package/dist/runtime/harness/run/start-run.js +88 -0
  24. package/dist/runtime/harness/run/startup-runtime.d.ts +2 -1
  25. package/dist/runtime/harness/run/startup-runtime.js +38 -3
  26. package/dist/runtime/harness/run/stream-runtime.d.ts +48 -0
  27. package/dist/runtime/harness/run/stream-runtime.js +14 -0
  28. package/dist/runtime/harness.d.ts +4 -3
  29. package/dist/runtime/harness.js +177 -252
  30. package/dist/runtime/support/runtime-adapter-options.d.ts +17 -0
  31. package/dist/runtime/support/runtime-adapter-options.js +29 -0
  32. package/package.json +1 -1
  33. package/dist/runtime/adapter/deepagent-runnable-config.d.ts +0 -13
  34. package/dist/runtime/adapter/deepagent-runnable-config.js +0 -29
  35. package/dist/runtime/adapter/langchain-runnable-config.d.ts +0 -11
  36. package/dist/runtime/adapter/langchain-runnable-config.js +0 -24
@@ -1,34 +1,35 @@
1
- import { AUTO_AGENT_ID } from "../contracts/types.js";
2
1
  import { SqlitePersistence } from "../persistence/sqlite-store.js";
3
2
  import { createPersistentId } from "../utils/id.js";
4
3
  import { AgentRuntimeAdapter } from "./agent-runtime-adapter.js";
5
- import { createResourceBackendResolver, createResourceToolResolver } from "../resource/resource.js";
6
4
  import { EventBus } from "./harness/events/event-bus.js";
7
5
  import { createBackgroundEventRuntime } from "./harness/background-runtime.js";
8
6
  import { PolicyEngine } from "./harness/system/policy-engine.js";
9
- import { getConcurrencyConfig, getRecoveryConfig, getRoutingDefaultAgentId, getRoutingRules, matchRoutingRule, } from "../workspace/support/workspace-ref-utils.js";
7
+ import { getConcurrencyConfig, getRecoveryConfig, getRoutingDefaultAgentId, getRoutingRules, } from "../workspace/support/workspace-ref-utils.js";
10
8
  import { createHarnessEvent, inferRoutingBindings, renderRuntimeFailure, } from "./support/harness-support.js";
11
9
  import { ThreadMemorySync } from "./harness/system/thread-memory-sync.js";
12
10
  import { FileBackedStore } from "./harness/system/store.js";
13
11
  import { HealthMonitor, readHealthMonitorConfig, } from "./harness/system/health-monitor.js";
14
- import { extractMessageText, normalizeMessageContent } from "../utils/message-content.js";
15
- import { buildPersistedRunRequest, normalizeInvocationEnvelope, normalizeRunPriority, resolveRunListeners, } from "./harness/run/helpers.js";
16
- import { emitHarnessEvent, emitRunCreatedEvent, emitSyntheticFallbackEvent, requestApprovalAndEmitEvent, setRunStateAndEmitEvent, } from "./harness/events/events.js";
17
- import { appendAssistantMessage as appendLifecycleAssistantMessage, finalizeCancelledRun as finalizeLifecycleCancelledRun, finalizeContinuedRun as finalizeLifecycleContinuedRun, } from "./harness/run/run-lifecycle.js";
18
- import { dispatchRunListeners as dispatchStreamingRunListeners, } from "./harness/events/streaming.js";
19
- import { buildResumePayload as buildHarnessResumePayload, resolveApprovalRecord as resolveHarnessApprovalRecord, } from "./harness/run/resume.js";
20
- import { cancelRunOperation, resumeRun } from "./harness/run/run-operations.js";
12
+ import { normalizeInvocationEnvelope, normalizeRunPriority, resolveRunListeners, } from "./harness/run/helpers.js";
13
+ import { emitHarnessEvent, } from "./harness/events/events.js";
14
+ import { createRuntimeEventOperations } from "./harness/events/runtime-event-operations.js";
15
+ import { finalizeCancelledRun as finalizeLifecycleCancelledRun, finalizeContinuedRun as finalizeLifecycleContinuedRun, } from "./harness/run/run-lifecycle.js";
16
+ import { createListenerDispatchRuntime } from "./harness/events/listener-runtime.js";
17
+ import { cancelRunOperation, executeQueuedRunOperation, resumeRun } from "./harness/run/run-operations.js";
18
+ import { createResumeRunRuntime } from "./harness/run/resume-runtime.js";
21
19
  import { acquireRunSlot as acquireHarnessRunSlot } from "./harness/run/run-slot-acquisition.js";
22
20
  import { dropPendingRunSlot, enqueuePendingRunSlot } from "./harness/run/run-queue.js";
23
- import { getDefaultHostAgentId, resolveSelectedAgentId } from "./harness/run/routing.js";
24
- import { resolveCheckpointer, resolveEmbeddingModel, resolveStore, resolveStoreFromConfig, resolveVectorStore, } from "./harness/run/resources.js";
21
+ import { getDefaultHostAgentId, resolveSelectedAgentId, routeAgentId } from "./harness/run/routing.js";
22
+ import { resolveStoreFromConfig, } from "./harness/run/resources.js";
25
23
  import { createToolMcpServerFromTools, serveToolsOverStdioFromHarness } from "../mcp.js";
26
- import { getBindingAdapterKind, getBindingStoreConfig } from "./support/compiled-binding.js";
27
- import { getRequiredWorkspaceBinding, getWorkspaceBinding, resolveWorkspaceAgentTools, } from "./harness/bindings.js";
24
+ import { getBindingAdapterKind } from "./support/compiled-binding.js";
25
+ import { bindingSupportsRunningReplay, getWorkspaceBinding, resolveWorkspaceAgentTools, } from "./harness/bindings.js";
28
26
  import { describeWorkspaceInventory, listAgentSkills as listWorkspaceAgentSkills, } from "./harness/system/inventory.js";
29
27
  import { createDefaultHealthSnapshot, isInventoryEnabled, isThreadMemorySyncEnabled, } from "./harness/runtime-defaults.js";
30
- import { initializeHarnessRuntime, isStaleRunningRun as isHarnessStaleRunningRun, } from "./harness/run/startup-runtime.js";
28
+ import { resolveRuntimeAdapterOptions } from "./support/runtime-adapter-options.js";
29
+ import { initializeHarnessRuntime, reclaimExpiredClaimedRuns as reclaimHarnessExpiredClaimedRuns, recoverStartupRuns as recoverHarnessStartupRuns, isStaleRunningRun as isHarnessStaleRunningRun, } from "./harness/run/startup-runtime.js";
31
30
  import { streamHarnessRun } from "./harness/run/stream-run.js";
31
+ import { createStreamRunRuntime } from "./harness/run/stream-runtime.js";
32
+ import { defaultRequestedAgentId, prepareRunStart } from "./harness/run/start-run.js";
32
33
  import { deleteThreadRecord, getPublicApproval, getThreadRecord, listPublicApprovals, } from "./harness/run/thread-records.js";
33
34
  export class AgentHarnessRuntime {
34
35
  workspace;
@@ -67,7 +68,10 @@ export class AgentHarnessRuntime {
67
68
  pendingRunInsertionOrder = 0;
68
69
  pendingRunSlots = [];
69
70
  runtimeEventSequence = 0;
71
+ initialized = false;
72
+ closed = false;
70
73
  backgroundEventRuntime;
74
+ runtimeEventOperations;
71
75
  defaultRunRoot() {
72
76
  return this.defaultRunRootValue;
73
77
  }
@@ -99,21 +103,16 @@ export class AgentHarnessRuntime {
99
103
  ? this.defaultHostBinding.harnessRuntime.runtimeMemory.store
100
104
  : undefined;
101
105
  this.runtimeMemoryStore = resolveStoreFromConfig(this.stores, runtimeMemoryStoreConfig, runRoot) ?? this.defaultStore;
102
- this.resolvedRuntimeAdapterOptions = {
103
- ...runtimeAdapterOptions,
104
- toolResolver: runtimeAdapterOptions.toolResolver ??
105
- createResourceToolResolver(workspace, {
106
- getStore: (binding) => resolveStore(this.stores, this.defaultStore, this.defaultRunRoot(), (currentBinding) => currentBinding ? getBindingStoreConfig(currentBinding) : undefined, binding),
107
- getEmbeddingModel: (embeddingModelRef) => resolveEmbeddingModel(this.workspace, this.embeddingModels, embeddingModelRef, this.runtimeAdapterOptions),
108
- getVectorStore: (vectorStoreRef) => resolveVectorStore(this.workspace, this.vectorStores, vectorStoreRef, this.runtimeAdapterOptions),
109
- }),
110
- checkpointerResolver: runtimeAdapterOptions.checkpointerResolver ??
111
- ((binding) => resolveCheckpointer(this.checkpointers, binding)),
112
- storeResolver: runtimeAdapterOptions.storeResolver ??
113
- ((binding) => resolveStore(this.stores, this.defaultStore, this.defaultRunRoot(), (currentBinding) => currentBinding ? getBindingStoreConfig(currentBinding) : undefined, binding)),
114
- backendResolver: runtimeAdapterOptions.backendResolver ??
115
- ((binding) => createResourceBackendResolver(workspace)(binding)),
116
- };
106
+ this.resolvedRuntimeAdapterOptions = resolveRuntimeAdapterOptions({
107
+ workspace,
108
+ runtimeAdapterOptions,
109
+ checkpointers: this.checkpointers,
110
+ stores: this.stores,
111
+ defaultStore: this.defaultStore,
112
+ embeddingModels: this.embeddingModels,
113
+ vectorStores: this.vectorStores,
114
+ getDefaultRunRoot: () => this.defaultRunRoot(),
115
+ });
117
116
  this.runtimeAdapter = new AgentRuntimeAdapter(this.resolvedRuntimeAdapterOptions);
118
117
  this.backgroundEventRuntime = createBackgroundEventRuntime({
119
118
  persistence: this.persistence,
@@ -121,6 +120,7 @@ export class AgentHarnessRuntime {
121
120
  trackBackgroundTask: (task) => this.trackBackgroundTask(task),
122
121
  backgroundEventTypes: AgentHarnessRuntime.BACKGROUND_EVENT_TYPES,
123
122
  });
123
+ this.runtimeEventOperations = createRuntimeEventOperations(this.backgroundEventRuntime);
124
124
  this.routingRules = getRoutingRules(workspace.refs);
125
125
  this.routingDefaultAgentId = getRoutingDefaultAgentId(workspace.refs);
126
126
  if (isThreadMemorySyncEnabled(workspace)) {
@@ -156,10 +156,18 @@ export class AgentHarnessRuntime {
156
156
  this.healthMonitor?.recordLlmFailure(Date.now() - startedAt);
157
157
  }
158
158
  async initialize() {
159
+ if (this.closed) {
160
+ throw new Error("AgentHarnessRuntime has been closed and cannot be reinitialized");
161
+ }
162
+ if (this.initialized) {
163
+ return;
164
+ }
159
165
  await initializeHarnessRuntime({
160
166
  persistence: this.persistence,
161
167
  healthMonitor: this.healthMonitor,
162
168
  });
169
+ await this.recoverStartupRuns();
170
+ this.initialized = true;
163
171
  }
164
172
  subscribe(listener) {
165
173
  return this.eventBus.subscribe(listener);
@@ -236,45 +244,21 @@ export class AgentHarnessRuntime {
236
244
  }, threadId);
237
245
  }
238
246
  async createToolMcpServer(options) {
239
- const tools = resolveWorkspaceAgentTools({
240
- workspace: this.workspace,
241
- agentId: options.agentId,
242
- toolResolver: this.resolvedRuntimeAdapterOptions.toolResolver,
243
- }).map(({ compiledTool, resolvedTool }) => ({
244
- compiledTool,
245
- resolvedTool,
246
- sourceTool: this.workspace.tools.get(compiledTool.id),
247
- }));
247
+ const tools = this.resolveToolMcpServerTools(options.agentId);
248
248
  return createToolMcpServerFromTools(tools, options);
249
249
  }
250
250
  async serveToolsOverStdio(options) {
251
- const tools = resolveWorkspaceAgentTools({
252
- workspace: this.workspace,
253
- agentId: options.agentId,
254
- toolResolver: this.resolvedRuntimeAdapterOptions.toolResolver,
255
- }).map(({ compiledTool, resolvedTool }) => ({
256
- compiledTool,
257
- resolvedTool,
258
- sourceTool: this.workspace.tools.get(compiledTool.id),
259
- }));
251
+ const tools = this.resolveToolMcpServerTools(options.agentId);
260
252
  return serveToolsOverStdioFromHarness(tools, options);
261
253
  }
262
254
  async routeAgent(input, options = {}) {
263
- const rawInput = extractMessageText(input);
264
- const configuredRule = this.routingRules.find((rule) => matchRoutingRule(rawInput, rule, options));
265
- if (configuredRule) {
266
- const configuredBinding = getWorkspaceBinding(this.workspace, configuredRule.agentId);
267
- if (configuredBinding) {
268
- return configuredBinding.agent.id;
269
- }
270
- }
271
- const defaultBinding = this.routingDefaultAgentId
272
- ? getWorkspaceBinding(this.workspace, this.routingDefaultAgentId)
273
- : undefined;
274
- if (defaultBinding) {
275
- return defaultBinding.agent.id;
276
- }
277
- return this.getDefaultHostAgentId();
255
+ return routeAgentId({
256
+ workspace: this.workspace,
257
+ input,
258
+ routingRules: this.routingRules,
259
+ routingDefaultAgentId: this.routingDefaultAgentId,
260
+ threadId: options.threadId,
261
+ });
278
262
  }
279
263
  async emit(threadId, runId, sequence, eventType, payload, source = "runtime") {
280
264
  return emitHarnessEvent({
@@ -290,55 +274,16 @@ export class AgentHarnessRuntime {
290
274
  this.backgroundTasks.delete(task);
291
275
  });
292
276
  }
293
- async ensureThreadStarted(selectedAgentId, binding, input, runRequest, existingThreadId) {
294
- const threadId = existingThreadId ?? createPersistentId();
295
- const runId = createPersistentId();
296
- const createdAt = new Date().toISOString();
297
- const isNewThread = !existingThreadId;
298
- const userMessage = {
299
- role: "user",
300
- content: normalizeMessageContent(input),
301
- runId,
302
- createdAt,
303
- };
304
- if (typeof this.persistence.bootstrapRun === "function") {
305
- await this.persistence.bootstrapRun({
306
- threadId,
307
- agentId: binding.agent.id,
308
- runId,
309
- status: "running",
310
- createdAt,
311
- executionMode: getBindingAdapterKind(binding),
312
- adapterKind: getBindingAdapterKind(binding),
313
- userMessage,
314
- runRequest,
315
- createThread: isNewThread,
316
- });
317
- }
318
- else {
319
- if (isNewThread) {
320
- await this.persistence.createThread({
321
- threadId,
322
- agentId: selectedAgentId,
323
- runId,
324
- status: "running",
325
- createdAt,
326
- });
327
- }
328
- await Promise.all([
329
- this.persistence.appendThreadMessage(threadId, userMessage),
330
- this.persistence.createRun({
331
- threadId,
332
- runId,
333
- agentId: binding.agent.id,
334
- executionMode: getBindingAdapterKind(binding),
335
- adapterKind: getBindingAdapterKind(binding),
336
- createdAt,
337
- }),
338
- this.persistence.saveRunRequest(threadId, runId, runRequest),
339
- ]);
340
- }
341
- return { threadId, runId, createdAt, isNewThread };
277
+ resolveToolMcpServerTools(agentId) {
278
+ return resolveWorkspaceAgentTools({
279
+ workspace: this.workspace,
280
+ agentId,
281
+ toolResolver: this.resolvedRuntimeAdapterOptions.toolResolver,
282
+ }).map(({ compiledTool, resolvedTool }) => ({
283
+ compiledTool,
284
+ resolvedTool,
285
+ sourceTool: this.workspace.tools.get(compiledTool.id),
286
+ }));
342
287
  }
343
288
  async loadPriorHistory(threadId, runId) {
344
289
  const history = await this.persistence.listThreadMessages(threadId);
@@ -384,71 +329,33 @@ export class AgentHarnessRuntime {
384
329
  return enqueuePendingRunSlot(this.pendingRunSlots, entry, this.pendingRunInsertionOrder++);
385
330
  }
386
331
  async executeQueuedRun(binding, input, threadId, runId, agentId, options = {}) {
387
- const previousState = options.previousState ?? "running";
388
- const currentRun = await this.persistence.getRun(runId);
389
- if (currentRun?.state === "cancelled") {
390
- return {
391
- threadId,
392
- runId,
393
- agentId,
394
- state: "cancelled",
395
- output: "cancelled",
396
- };
397
- }
398
- const cancellation = await this.getRunCancellation(runId);
399
- if (cancellation.requested) {
400
- return this.finalizeCancelledRun(threadId, runId, previousState, cancellation.reason);
401
- }
402
- if (previousState === "queued") {
403
- await this.emit(threadId, runId, 101, "run.dequeued", {
404
- queuePosition: 0,
405
- activeRunCount: this.activeRunSlots,
406
- maxConcurrentRuns: this.concurrencyConfig.maxConcurrentRuns,
407
- recoveredOnStartup: true,
408
- });
409
- await this.setRunStateAndEmit(threadId, runId, 102, "running", {
410
- previousState: "queued",
411
- });
412
- }
413
- try {
414
- const actual = await this.invokeWithHistory(binding, input, threadId, runId, undefined, options.priorHistory, {
415
- context: options.context,
416
- state: options.state,
417
- files: options.files,
418
- });
419
- const cancelledAfterInvoke = await this.getRunCancellation(runId);
420
- if (cancelledAfterInvoke.requested) {
421
- return this.finalizeCancelledRun(threadId, runId, previousState === "queued" ? "running" : previousState, cancelledAfterInvoke.reason);
422
- }
423
- const finalized = await this.finalizeContinuedRun(binding, threadId, runId, input, actual, {
424
- previousState: previousState === "queued" ? "running" : previousState,
425
- stateSequence: options.stateSequence ?? 103,
426
- approvalSequence: options.approvalSequence ?? 104,
427
- });
428
- return {
429
- ...finalized,
430
- agentId,
431
- };
432
- }
433
- catch (error) {
434
- await emitSyntheticFallbackEvent({
435
- ...this.backgroundEventRuntime,
436
- }, threadId, runId, agentId, error, 103);
437
- await this.setRunStateAndEmit(threadId, runId, 104, "failed", {
438
- previousState: previousState === "queued" ? "running" : previousState,
439
- error: error instanceof Error ? error.message : String(error),
440
- });
441
- return {
442
- threadId,
443
- runId,
444
- agentId,
445
- state: "failed",
446
- output: renderRuntimeFailure(error),
447
- };
448
- }
449
- finally {
450
- await this.persistence.clearRunRequest(threadId, runId);
451
- }
332
+ return executeQueuedRunOperation({
333
+ persistence: this.persistence,
334
+ getRunCancellation: (currentRunId) => this.getRunCancellation(currentRunId),
335
+ finalizeCancelledRun: (currentThreadId, currentRunId, previousRunState, reason) => this.finalizeCancelledRun(currentThreadId, currentRunId, previousRunState, reason),
336
+ emit: (currentThreadId, currentRunId, sequence, eventType, payload) => {
337
+ if (eventType === "run.dequeued") {
338
+ return this.emit(currentThreadId, currentRunId, sequence, eventType, {
339
+ ...payload,
340
+ activeRunCount: this.activeRunSlots,
341
+ maxConcurrentRuns: this.concurrencyConfig.maxConcurrentRuns,
342
+ });
343
+ }
344
+ return this.emit(currentThreadId, currentRunId, sequence, eventType, payload);
345
+ },
346
+ setRunStateAndEmit: (currentThreadId, currentRunId, sequence, state, stateOptions) => this.setRunStateAndEmit(currentThreadId, currentRunId, sequence, state, stateOptions),
347
+ invokeWithHistory: (activeBinding, activeInput, currentThreadId, currentRunId, resumePayload, priorHistory, invokeOptions) => this.invokeWithHistory(activeBinding, activeInput, currentThreadId, currentRunId, resumePayload, priorHistory, invokeOptions),
348
+ finalizeContinuedRun: (activeBinding, currentThreadId, currentRunId, currentInput, actual, finalizeOptions) => this.finalizeContinuedRun(activeBinding, currentThreadId, currentRunId, currentInput, actual, finalizeOptions),
349
+ emitSyntheticFallback: (currentThreadId, currentRunId, currentAgentId, error) => this.runtimeEventOperations.emitSyntheticFallback(currentThreadId, currentRunId, currentAgentId, error, 103),
350
+ renderRuntimeFailure,
351
+ }, {
352
+ binding,
353
+ message: input,
354
+ threadId,
355
+ runId,
356
+ agentId,
357
+ options,
358
+ });
452
359
  }
453
360
  async finalizeContinuedRun(binding, threadId, runId, input, actual, options) {
454
361
  return finalizeLifecycleContinuedRun({
@@ -459,14 +366,10 @@ export class AgentHarnessRuntime {
459
366
  }, binding, threadId, runId, input, actual, options);
460
367
  }
461
368
  async setRunStateAndEmit(threadId, runId, sequence, state, options) {
462
- return setRunStateAndEmitEvent({
463
- ...this.backgroundEventRuntime,
464
- }, threadId, runId, sequence, state, options);
369
+ return this.runtimeEventOperations.setRunStateAndEmit(threadId, runId, sequence, state, options);
465
370
  }
466
371
  async requestApprovalAndEmit(threadId, runId, input, interruptContent, checkpointRef, sequence) {
467
- return requestApprovalAndEmitEvent({
468
- ...this.backgroundEventRuntime,
469
- }, threadId, runId, input, interruptContent, checkpointRef, sequence);
372
+ return this.runtimeEventOperations.requestApprovalAndEmit(threadId, runId, input, interruptContent, checkpointRef, sequence);
470
373
  }
471
374
  isDecisionRun(options) {
472
375
  return "decision" in options;
@@ -477,29 +380,6 @@ export class AgentHarnessRuntime {
477
380
  }
478
381
  await listener(value);
479
382
  }
480
- async prepareRunStart(options, invocation, runCreatedPayload) {
481
- const selectedAgentId = await this.resolveSelectedAgentId(options.input, options.agentId, options.threadId);
482
- const binding = getRequiredWorkspaceBinding(this.workspace, selectedAgentId);
483
- const policyDecision = this.policyEngine.evaluate(binding);
484
- if (!policyDecision.allowed) {
485
- throw new Error(`Policy evaluation blocked agent ${selectedAgentId}: ${policyDecision.reasons.join(", ")}`);
486
- }
487
- const priority = normalizeRunPriority(options.priority);
488
- const runRequest = buildPersistedRunRequest(options.input, invocation, priority);
489
- const { threadId, runId, isNewThread } = await this.ensureThreadStarted(selectedAgentId, binding, options.input, runRequest, options.threadId);
490
- return {
491
- binding,
492
- selectedAgentId,
493
- priority,
494
- threadId,
495
- runId,
496
- isNewThread,
497
- runCreatedEventPromise: emitRunCreatedEvent({
498
- ...this.backgroundEventRuntime,
499
- }, threadId, runId, runCreatedPayload(binding, selectedAgentId)),
500
- releaseRunSlotPromise: this.acquireRunSlot(threadId, runId, "running", priority),
501
- };
502
- }
503
383
  async acquireRunSlot(threadId, runId, activeState = "running", priority = 0) {
504
384
  return acquireHarnessRunSlot({
505
385
  persistence: this.persistence,
@@ -523,12 +403,6 @@ export class AgentHarnessRuntime {
523
403
  dropPendingRunSlot(runId) {
524
404
  return dropPendingRunSlot(this.pendingRunSlots, runId);
525
405
  }
526
- async dispatchRunListeners(stream, listeners) {
527
- return dispatchStreamingRunListeners(stream, listeners, {
528
- notifyListener: (listener, value) => this.notifyListener(listener, value),
529
- getThread: (threadId) => this.getThread(threadId),
530
- });
531
- }
532
406
  async run(options) {
533
407
  if (this.isDecisionRun(options)) {
534
408
  const resumeOptions = {
@@ -542,15 +416,29 @@ export class AgentHarnessRuntime {
542
416
  }
543
417
  const resolvedListeners = resolveRunListeners(options);
544
418
  if (resolvedListeners) {
545
- return this.dispatchRunListeners(this.streamEvents(options), resolvedListeners);
419
+ return createListenerDispatchRuntime({
420
+ notifyListener: (listener, value) => this.notifyListener(listener, value),
421
+ getThread: (threadId) => this.getThread(threadId),
422
+ }).dispatchRunListeners(this.streamEvents(options), resolvedListeners);
546
423
  }
547
424
  const invocation = normalizeInvocationEnvelope(options);
548
- const { binding, selectedAgentId, threadId, runId, isNewThread, runCreatedEventPromise, releaseRunSlotPromise, } = await this.prepareRunStart(options, invocation, (activeBinding, activeSelectedAgentId) => ({
549
- agentId: activeBinding.agent.id,
550
- requestedAgentId: options.agentId ?? AUTO_AGENT_ID,
551
- selectedAgentId: activeSelectedAgentId,
552
- executionMode: getBindingAdapterKind(activeBinding),
553
- }));
425
+ const { binding, selectedAgentId, threadId, runId, isNewThread, runCreatedEventPromise, releaseRunSlotPromise, } = await prepareRunStart({
426
+ workspace: this.workspace,
427
+ policyEngine: this.policyEngine,
428
+ persistence: this.persistence,
429
+ resolveSelectedAgentId: (input, requestedAgentId, threadId) => this.resolveSelectedAgentId(input, requestedAgentId, threadId),
430
+ emitRunCreated: (threadId, runId, payload) => this.runtimeEventOperations.emitRunCreated(threadId, runId, payload),
431
+ acquireRunSlot: (threadId, runId, activeState, priority) => this.acquireRunSlot(threadId, runId, activeState, priority),
432
+ }, {
433
+ options,
434
+ invocation,
435
+ runCreatedPayload: (activeBinding, activeSelectedAgentId) => ({
436
+ agentId: activeBinding.agent.id,
437
+ requestedAgentId: defaultRequestedAgentId(options.agentId),
438
+ selectedAgentId: activeSelectedAgentId,
439
+ executionMode: getBindingAdapterKind(activeBinding),
440
+ }),
441
+ });
554
442
  await runCreatedEventPromise;
555
443
  const releaseRunSlot = await releaseRunSlotPromise;
556
444
  try {
@@ -585,13 +473,34 @@ export class AgentHarnessRuntime {
585
473
  }
586
474
  return;
587
475
  }
588
- const { threadId, runId, isNewThread, runCreatedEventPromise, releaseRunSlotPromise, } = await this.prepareRunStart(options, invocation, (_binding, activeSelectedAgentId) => ({
589
- agentId: activeSelectedAgentId,
590
- requestedAgentId: options.agentId ?? AUTO_AGENT_ID,
591
- selectedAgentId: activeSelectedAgentId,
592
- input: options.input,
593
- state: "running",
594
- }));
476
+ const { threadId, runId, isNewThread, runCreatedEventPromise, releaseRunSlotPromise, } = await prepareRunStart({
477
+ workspace: this.workspace,
478
+ policyEngine: this.policyEngine,
479
+ persistence: this.persistence,
480
+ resolveSelectedAgentId: (input, requestedAgentId, threadId) => this.resolveSelectedAgentId(input, requestedAgentId, threadId),
481
+ emitRunCreated: (threadId, runId, payload) => this.runtimeEventOperations.emitRunCreated(threadId, runId, payload),
482
+ acquireRunSlot: (threadId, runId, activeState, priority) => this.acquireRunSlot(threadId, runId, activeState, priority),
483
+ }, {
484
+ options,
485
+ invocation,
486
+ runCreatedPayload: (_binding, activeSelectedAgentId) => ({
487
+ agentId: activeSelectedAgentId,
488
+ requestedAgentId: defaultRequestedAgentId(options.agentId),
489
+ selectedAgentId: activeSelectedAgentId,
490
+ input: options.input,
491
+ state: "running",
492
+ }),
493
+ });
494
+ const streamRuntime = createStreamRunRuntime({
495
+ persistence: this.persistence,
496
+ runtimeAdapter: this.runtimeAdapter,
497
+ emit: (threadId, runId, sequence, eventType, payload) => this.emit(threadId, runId, sequence, eventType, payload),
498
+ setRunStateAndEmit: (threadId, runId, sequence, state, stateOptions) => this.setRunStateAndEmit(threadId, runId, sequence, state, stateOptions),
499
+ requestApprovalAndEmit: (threadId, runId, input, interruptContent, checkpointRef, sequence) => this.requestApprovalAndEmit(threadId, runId, input, interruptContent, checkpointRef, sequence),
500
+ loadPriorHistory: (threadId, runId) => this.loadPriorHistory(threadId, runId),
501
+ invokeWithHistory: (binding, input, threadId, runId) => this.invokeWithHistory(binding, input, threadId, runId),
502
+ emitSyntheticFallback: (threadId, runId, selectedAgentId, error) => this.runtimeEventOperations.emitSyntheticFallback(threadId, runId, selectedAgentId, error),
503
+ });
595
504
  yield* streamHarnessRun({
596
505
  binding,
597
506
  input: options.input,
@@ -602,42 +511,25 @@ export class AgentHarnessRuntime {
602
511
  isNewThread,
603
512
  runCreatedEventPromise,
604
513
  releaseRunSlotPromise,
605
- loadPriorHistory: (currentThreadId, currentRunId) => this.loadPriorHistory(currentThreadId, currentRunId),
606
- stream: (activeBinding, input, currentThreadId, priorHistory, streamOptions) => this.runtimeAdapter.stream(activeBinding, input, currentThreadId, priorHistory, streamOptions),
607
- invokeWithHistory: (activeBinding, input, currentThreadId, currentRunId) => this.invokeWithHistory(activeBinding, input, currentThreadId, currentRunId),
608
- emit: (currentThreadId, currentRunId, sequence, eventType, payload) => this.emit(currentThreadId, currentRunId, sequence, eventType, payload),
609
- setRunStateAndEmit: (currentThreadId, currentRunId, sequence, state, stateOptions) => this.setRunStateAndEmit(currentThreadId, currentRunId, sequence, state, stateOptions),
610
- requestApprovalAndEmit: (currentThreadId, currentRunId, input, interruptContent, checkpointRef, sequence) => this.requestApprovalAndEmit(currentThreadId, currentRunId, input, interruptContent, checkpointRef, sequence),
611
- appendAssistantMessage: (currentThreadId, currentRunId, content) => appendLifecycleAssistantMessage(this.persistence, currentThreadId, currentRunId, content),
612
- clearRunRequest: (currentThreadId, currentRunId) => this.persistence.clearRunRequest(currentThreadId, currentRunId),
613
- emitSyntheticFallback: (currentThreadId, currentRunId, currentSelectedAgentId, error) => emitSyntheticFallbackEvent({
614
- ...this.backgroundEventRuntime,
615
- }, currentThreadId, currentRunId, currentSelectedAgentId, error),
514
+ ...streamRuntime,
616
515
  });
617
516
  }
618
517
  async resume(options) {
619
- return resumeRun({
620
- getApprovalById: (approvalId) => this.persistence.getApproval(approvalId),
518
+ return resumeRun(createResumeRunRuntime({
519
+ persistence: this.persistence,
520
+ workspace: this.workspace,
521
+ runtimeAdapter: this.runtimeAdapter,
621
522
  getSession: (threadId) => this.getSession(threadId),
622
- resolveApprovalRecord: (resumeOptions, thread) => resolveHarnessApprovalRecord(this.persistence, resumeOptions, thread),
623
- getBinding: (agentId) => getWorkspaceBinding(this.workspace, agentId),
624
- buildResumePayload: (binding, approval, resumeOptions) => buildHarnessResumePayload(binding, approval, resumeOptions),
625
523
  getRunCancellation: (runId) => this.getRunCancellation(runId),
626
524
  finalizeCancelledRun: (threadId, runId, previousState, reason) => this.finalizeCancelledRun(threadId, runId, previousState, reason),
627
- setRunState: (threadId, runId, state, checkpointRef) => this.persistence.setRunState(threadId, runId, state, checkpointRef),
628
525
  acquireRunSlot: (threadId, runId, activeState, priority) => this.acquireRunSlot(threadId, runId, activeState, priority),
629
526
  resolvePersistedRunPriority: (threadId, runId) => this.resolvePersistedRunPriority(threadId, runId),
630
- saveRecoveryIntent: (threadId, runId, payload) => this.persistence.saveRecoveryIntent(threadId, runId, payload),
631
527
  emit: (threadId, runId, sequence, eventType, payload) => this.emit(threadId, runId, sequence, eventType, payload),
632
- resolveApproval: (threadId, runId, approvalId, resolution) => this.persistence.resolveApproval(threadId, runId, approvalId, resolution),
633
- listThreadMessages: (threadId) => this.persistence.listThreadMessages(threadId),
634
528
  loadRunInput: (threadId, runId) => this.loadRunInput(threadId, runId),
635
- invoke: (binding, input, threadId, runId, resumePayload, priorHistory) => this.runtimeAdapter.invoke(binding, input, threadId, runId, resumePayload, priorHistory),
636
529
  recordLlmSuccess: (startedAt) => this.recordLlmSuccess(startedAt),
637
530
  recordLlmFailure: (startedAt) => this.recordLlmFailure(startedAt),
638
- clearRecoveryIntent: (threadId, runId) => this.persistence.clearRecoveryIntent(threadId, runId),
639
531
  finalizeContinuedRun: (binding, threadId, runId, input, actual, operationOptions) => this.finalizeContinuedRun(binding, threadId, runId, input, actual, operationOptions),
640
- }, options);
532
+ }), options);
641
533
  }
642
534
  async restartConversation(options) {
643
535
  const thread = await this.getSession(options.threadId);
@@ -665,10 +557,15 @@ export class AgentHarnessRuntime {
665
557
  };
666
558
  }
667
559
  async close() {
560
+ if (this.closed) {
561
+ return;
562
+ }
563
+ this.closed = true;
668
564
  await this.healthMonitor?.stop();
669
565
  this.unregisterThreadMemorySync();
670
566
  await Promise.allSettled(Array.from(this.backgroundTasks));
671
567
  await this.threadMemorySync?.close();
568
+ this.initialized = false;
672
569
  }
673
570
  async stop() {
674
571
  await this.close();
@@ -683,10 +580,38 @@ export class AgentHarnessRuntime {
683
580
  }, options);
684
581
  }
685
582
  async recoverStartupRuns() {
686
- return;
583
+ await recoverHarnessStartupRuns({
584
+ recoveryConfig: this.recoveryConfig,
585
+ persistence: this.persistence,
586
+ createStartupRecoveryContext: () => ({
587
+ persistence: this.persistence,
588
+ workspace: this.workspace,
589
+ runtimeAdapter: this.runtimeAdapter,
590
+ recoveryConfig: this.recoveryConfig,
591
+ concurrencyConfig: this.concurrencyConfig,
592
+ getBinding: (agentId) => getWorkspaceBinding(this.workspace, agentId),
593
+ acquireRunSlot: (threadId, runId, activeState, priority) => this.acquireRunSlot(threadId, runId, activeState, priority),
594
+ executeQueuedRun: (binding, input, threadId, runId, agentId, options) => this.executeQueuedRun(binding, input, threadId, runId, agentId, options),
595
+ setRunStateAndEmit: (threadId, runId, sequence, state, options) => this.setRunStateAndEmit(threadId, runId, sequence, state, options),
596
+ emit: (threadId, runId, sequence, eventType, payload) => this.emit(threadId, runId, sequence, eventType, payload),
597
+ loadRunInput: (threadId, runId) => this.loadRunInput(threadId, runId),
598
+ finalizeContinuedRun: (binding, threadId, runId, input, actual, options) => this.finalizeContinuedRun(binding, threadId, runId, input, actual, options),
599
+ supportsRunningReplay: (binding) => bindingSupportsRunningReplay(binding),
600
+ isStaleRunningRun: (thread, nowMs) => this.isStaleRunningRun(thread, nowMs),
601
+ recordLlmSuccess: (startedAt) => this.recordLlmSuccess(startedAt),
602
+ recordLlmFailure: (startedAt) => this.recordLlmFailure(startedAt),
603
+ }),
604
+ reclaimExpiredClaimedRuns: (nowIso) => this.reclaimExpiredClaimedRuns(nowIso),
605
+ });
687
606
  }
688
- async reclaimExpiredClaimedRuns(_nowIso = new Date().toISOString()) {
689
- return;
607
+ async reclaimExpiredClaimedRuns(nowIso = new Date().toISOString()) {
608
+ await reclaimHarnessExpiredClaimedRuns({
609
+ persistence: this.persistence,
610
+ setRunStateAndEmit: (threadId, runId, sequence, state, options) => this.setRunStateAndEmit(threadId, runId, sequence, state, options),
611
+ emit: (threadId, runId, sequence, eventType, payload) => this.emit(threadId, runId, sequence, eventType, payload),
612
+ concurrencyConfig: this.concurrencyConfig,
613
+ getActiveRunSlots: () => this.activeRunSlots,
614
+ }, nowIso);
690
615
  }
691
616
  async isStaleRunningRun(thread, nowMs = Date.now()) {
692
617
  return isHarnessStaleRunningRun({
@@ -0,0 +1,17 @@
1
+ import type { CompiledAgentBinding, RuntimeAdapterOptions, WorkspaceBundle } from "../../contracts/types.js";
2
+ import type { StoreLike } from "../harness/system/store.js";
3
+ export declare function createBindingStoreResolver(input: {
4
+ stores: Map<string, StoreLike>;
5
+ defaultStore: StoreLike;
6
+ getDefaultRunRoot: () => string;
7
+ }): (binding?: CompiledAgentBinding) => StoreLike;
8
+ export declare function resolveRuntimeAdapterOptions(input: {
9
+ workspace: WorkspaceBundle;
10
+ runtimeAdapterOptions: RuntimeAdapterOptions;
11
+ checkpointers: Map<string, unknown>;
12
+ stores: Map<string, StoreLike>;
13
+ defaultStore: StoreLike;
14
+ embeddingModels: Map<string, unknown>;
15
+ vectorStores: Map<string, unknown>;
16
+ getDefaultRunRoot: () => string;
17
+ }): RuntimeAdapterOptions;
@@ -0,0 +1,29 @@
1
+ import { createResourceBackendResolver, createResourceToolResolver } from "../../resource/resource.js";
2
+ import { resolveCheckpointer, resolveEmbeddingModel, resolveStore, resolveVectorStore, } from "../harness/run/resources.js";
3
+ import { getBindingStoreConfig } from "./compiled-binding.js";
4
+ export function createBindingStoreResolver(input) {
5
+ return (binding) => resolveStore(input.stores, input.defaultStore, input.getDefaultRunRoot(), (currentBinding) => currentBinding ? getBindingStoreConfig(currentBinding) : undefined, binding);
6
+ }
7
+ export function resolveRuntimeAdapterOptions(input) {
8
+ const { workspace, runtimeAdapterOptions, checkpointers, stores, defaultStore, embeddingModels, vectorStores, getDefaultRunRoot, } = input;
9
+ const storeResolver = runtimeAdapterOptions.storeResolver ??
10
+ createBindingStoreResolver({
11
+ stores,
12
+ defaultStore,
13
+ getDefaultRunRoot,
14
+ });
15
+ return {
16
+ ...runtimeAdapterOptions,
17
+ toolResolver: runtimeAdapterOptions.toolResolver ??
18
+ createResourceToolResolver(workspace, {
19
+ getStore: (binding) => binding ? storeResolver(binding) : defaultStore,
20
+ getEmbeddingModel: (embeddingModelRef) => resolveEmbeddingModel(workspace, embeddingModels, embeddingModelRef, runtimeAdapterOptions),
21
+ getVectorStore: (vectorStoreRef) => resolveVectorStore(workspace, vectorStores, vectorStoreRef, runtimeAdapterOptions),
22
+ }),
23
+ checkpointerResolver: runtimeAdapterOptions.checkpointerResolver ??
24
+ ((binding) => resolveCheckpointer(checkpointers, binding)),
25
+ storeResolver,
26
+ backendResolver: runtimeAdapterOptions.backendResolver ??
27
+ ((binding) => createResourceBackendResolver(workspace)(binding)),
28
+ };
29
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botbotgo/agent-harness",
3
- "version": "0.0.108",
3
+ "version": "0.0.109",
4
4
  "description": "Workspace runtime for multi-agent applications",
5
5
  "type": "module",
6
6
  "packageManager": "npm@10.9.2",