@botbotgo/agent-harness 0.0.108 → 0.0.110

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 (39) 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.d.ts +1 -0
  11. package/dist/runtime/agent-runtime-adapter.js +37 -20
  12. package/dist/runtime/harness/events/listener-runtime.d.ts +18 -0
  13. package/dist/runtime/harness/events/listener-runtime.js +9 -0
  14. package/dist/runtime/harness/events/runtime-event-operations.d.ts +17 -0
  15. package/dist/runtime/harness/events/runtime-event-operations.js +9 -0
  16. package/dist/runtime/harness/run/recovery.d.ts +1 -1
  17. package/dist/runtime/harness/run/recovery.js +65 -47
  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 +108 -6
  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.d.ts +5 -3
  27. package/dist/runtime/harness.js +163 -238
  28. package/dist/runtime/support/runtime-adapter-options.d.ts +17 -0
  29. package/dist/runtime/support/runtime-adapter-options.js +29 -0
  30. package/dist/workspace/agent-binding-compiler.js +24 -88
  31. package/dist/workspace/support/agent-capabilities.js +2 -6
  32. package/dist/workspace/support/agent-execution-config.d.ts +18 -0
  33. package/dist/workspace/support/agent-execution-config.js +35 -0
  34. package/dist/workspace/validate.js +6 -11
  35. package/package.json +1 -1
  36. package/dist/runtime/adapter/deepagent-runnable-config.d.ts +0 -13
  37. package/dist/runtime/adapter/deepagent-runnable-config.js +0 -29
  38. package/dist/runtime/adapter/langchain-runnable-config.d.ts +0 -11
  39. package/dist/runtime/adapter/langchain-runnable-config.js +0 -24
@@ -1,34 +1,34 @@
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";
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";
17
15
  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";
16
+ import { createListenerDispatchRuntime } from "./harness/events/listener-runtime.js";
19
17
  import { buildResumePayload as buildHarnessResumePayload, resolveApprovalRecord as resolveHarnessApprovalRecord, } from "./harness/run/resume.js";
20
- import { cancelRunOperation, resumeRun } from "./harness/run/run-operations.js";
18
+ import { cancelRunOperation, executeQueuedRunOperation, resumeRun } from "./harness/run/run-operations.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 { defaultRequestedAgentId, prepareRunStart } from "./harness/run/start-run.js";
32
32
  import { deleteThreadRecord, getPublicApproval, getThreadRecord, listPublicApprovals, } from "./harness/run/thread-records.js";
33
33
  export class AgentHarnessRuntime {
34
34
  workspace;
@@ -67,7 +67,10 @@ export class AgentHarnessRuntime {
67
67
  pendingRunInsertionOrder = 0;
68
68
  pendingRunSlots = [];
69
69
  runtimeEventSequence = 0;
70
+ initialized = false;
71
+ closed = false;
70
72
  backgroundEventRuntime;
73
+ runtimeEventOperations;
71
74
  defaultRunRoot() {
72
75
  return this.defaultRunRootValue;
73
76
  }
@@ -84,6 +87,16 @@ export class AgentHarnessRuntime {
84
87
  getThreadSummary: (currentThreadId) => this.getSession(currentThreadId),
85
88
  });
86
89
  }
90
+ createPrepareRunStartRuntime() {
91
+ return {
92
+ workspace: this.workspace,
93
+ policyEngine: this.policyEngine,
94
+ persistence: this.persistence,
95
+ resolveSelectedAgentId: (input, requestedAgentId, threadId) => this.resolveSelectedAgentId(input, requestedAgentId, threadId),
96
+ emitRunCreated: (threadId, runId, payload) => this.runtimeEventOperations.emitRunCreated(threadId, runId, payload),
97
+ acquireRunSlot: (threadId, runId, activeState, priority) => this.acquireRunSlot(threadId, runId, activeState, priority),
98
+ };
99
+ }
87
100
  constructor(workspace, runtimeAdapterOptions = {}) {
88
101
  this.workspace = workspace;
89
102
  this.runtimeAdapterOptions = runtimeAdapterOptions;
@@ -99,21 +112,16 @@ export class AgentHarnessRuntime {
99
112
  ? this.defaultHostBinding.harnessRuntime.runtimeMemory.store
100
113
  : undefined;
101
114
  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
- };
115
+ this.resolvedRuntimeAdapterOptions = resolveRuntimeAdapterOptions({
116
+ workspace,
117
+ runtimeAdapterOptions,
118
+ checkpointers: this.checkpointers,
119
+ stores: this.stores,
120
+ defaultStore: this.defaultStore,
121
+ embeddingModels: this.embeddingModels,
122
+ vectorStores: this.vectorStores,
123
+ getDefaultRunRoot: () => this.defaultRunRoot(),
124
+ });
117
125
  this.runtimeAdapter = new AgentRuntimeAdapter(this.resolvedRuntimeAdapterOptions);
118
126
  this.backgroundEventRuntime = createBackgroundEventRuntime({
119
127
  persistence: this.persistence,
@@ -121,6 +129,7 @@ export class AgentHarnessRuntime {
121
129
  trackBackgroundTask: (task) => this.trackBackgroundTask(task),
122
130
  backgroundEventTypes: AgentHarnessRuntime.BACKGROUND_EVENT_TYPES,
123
131
  });
132
+ this.runtimeEventOperations = createRuntimeEventOperations(this.backgroundEventRuntime);
124
133
  this.routingRules = getRoutingRules(workspace.refs);
125
134
  this.routingDefaultAgentId = getRoutingDefaultAgentId(workspace.refs);
126
135
  if (isThreadMemorySyncEnabled(workspace)) {
@@ -156,10 +165,18 @@ export class AgentHarnessRuntime {
156
165
  this.healthMonitor?.recordLlmFailure(Date.now() - startedAt);
157
166
  }
158
167
  async initialize() {
168
+ if (this.closed) {
169
+ throw new Error("AgentHarnessRuntime has been closed and cannot be reinitialized");
170
+ }
171
+ if (this.initialized) {
172
+ return;
173
+ }
159
174
  await initializeHarnessRuntime({
160
175
  persistence: this.persistence,
161
176
  healthMonitor: this.healthMonitor,
162
177
  });
178
+ await this.recoverStartupRuns();
179
+ this.initialized = true;
163
180
  }
164
181
  subscribe(listener) {
165
182
  return this.eventBus.subscribe(listener);
@@ -236,45 +253,21 @@ export class AgentHarnessRuntime {
236
253
  }, threadId);
237
254
  }
238
255
  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
- }));
256
+ const tools = this.resolveToolMcpServerTools(options.agentId);
248
257
  return createToolMcpServerFromTools(tools, options);
249
258
  }
250
259
  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
- }));
260
+ const tools = this.resolveToolMcpServerTools(options.agentId);
260
261
  return serveToolsOverStdioFromHarness(tools, options);
261
262
  }
262
263
  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();
264
+ return routeAgentId({
265
+ workspace: this.workspace,
266
+ input,
267
+ routingRules: this.routingRules,
268
+ routingDefaultAgentId: this.routingDefaultAgentId,
269
+ threadId: options.threadId,
270
+ });
278
271
  }
279
272
  async emit(threadId, runId, sequence, eventType, payload, source = "runtime") {
280
273
  return emitHarnessEvent({
@@ -290,55 +283,16 @@ export class AgentHarnessRuntime {
290
283
  this.backgroundTasks.delete(task);
291
284
  });
292
285
  }
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 };
286
+ resolveToolMcpServerTools(agentId) {
287
+ return resolveWorkspaceAgentTools({
288
+ workspace: this.workspace,
289
+ agentId,
290
+ toolResolver: this.resolvedRuntimeAdapterOptions.toolResolver,
291
+ }).map(({ compiledTool, resolvedTool }) => ({
292
+ compiledTool,
293
+ resolvedTool,
294
+ sourceTool: this.workspace.tools.get(compiledTool.id),
295
+ }));
342
296
  }
343
297
  async loadPriorHistory(threadId, runId) {
344
298
  const history = await this.persistence.listThreadMessages(threadId);
@@ -384,71 +338,33 @@ export class AgentHarnessRuntime {
384
338
  return enqueuePendingRunSlot(this.pendingRunSlots, entry, this.pendingRunInsertionOrder++);
385
339
  }
386
340
  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
- }
341
+ return executeQueuedRunOperation({
342
+ persistence: this.persistence,
343
+ getRunCancellation: (currentRunId) => this.getRunCancellation(currentRunId),
344
+ finalizeCancelledRun: (currentThreadId, currentRunId, previousRunState, reason) => this.finalizeCancelledRun(currentThreadId, currentRunId, previousRunState, reason),
345
+ emit: (currentThreadId, currentRunId, sequence, eventType, payload) => {
346
+ if (eventType === "run.dequeued") {
347
+ return this.emit(currentThreadId, currentRunId, sequence, eventType, {
348
+ ...payload,
349
+ activeRunCount: this.activeRunSlots,
350
+ maxConcurrentRuns: this.concurrencyConfig.maxConcurrentRuns,
351
+ });
352
+ }
353
+ return this.emit(currentThreadId, currentRunId, sequence, eventType, payload);
354
+ },
355
+ setRunStateAndEmit: (currentThreadId, currentRunId, sequence, state, stateOptions) => this.setRunStateAndEmit(currentThreadId, currentRunId, sequence, state, stateOptions),
356
+ invokeWithHistory: (activeBinding, activeInput, currentThreadId, currentRunId, resumePayload, priorHistory, invokeOptions) => this.invokeWithHistory(activeBinding, activeInput, currentThreadId, currentRunId, resumePayload, priorHistory, invokeOptions),
357
+ finalizeContinuedRun: (activeBinding, currentThreadId, currentRunId, currentInput, actual, finalizeOptions) => this.finalizeContinuedRun(activeBinding, currentThreadId, currentRunId, currentInput, actual, finalizeOptions),
358
+ emitSyntheticFallback: (currentThreadId, currentRunId, currentAgentId, error) => this.runtimeEventOperations.emitSyntheticFallback(currentThreadId, currentRunId, currentAgentId, error, 103),
359
+ renderRuntimeFailure,
360
+ }, {
361
+ binding,
362
+ message: input,
363
+ threadId,
364
+ runId,
365
+ agentId,
366
+ options,
367
+ });
452
368
  }
453
369
  async finalizeContinuedRun(binding, threadId, runId, input, actual, options) {
454
370
  return finalizeLifecycleContinuedRun({
@@ -459,14 +375,10 @@ export class AgentHarnessRuntime {
459
375
  }, binding, threadId, runId, input, actual, options);
460
376
  }
461
377
  async setRunStateAndEmit(threadId, runId, sequence, state, options) {
462
- return setRunStateAndEmitEvent({
463
- ...this.backgroundEventRuntime,
464
- }, threadId, runId, sequence, state, options);
378
+ return this.runtimeEventOperations.setRunStateAndEmit(threadId, runId, sequence, state, options);
465
379
  }
466
380
  async requestApprovalAndEmit(threadId, runId, input, interruptContent, checkpointRef, sequence) {
467
- return requestApprovalAndEmitEvent({
468
- ...this.backgroundEventRuntime,
469
- }, threadId, runId, input, interruptContent, checkpointRef, sequence);
381
+ return this.runtimeEventOperations.requestApprovalAndEmit(threadId, runId, input, interruptContent, checkpointRef, sequence);
470
382
  }
471
383
  isDecisionRun(options) {
472
384
  return "decision" in options;
@@ -477,29 +389,6 @@ export class AgentHarnessRuntime {
477
389
  }
478
390
  await listener(value);
479
391
  }
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
392
  async acquireRunSlot(threadId, runId, activeState = "running", priority = 0) {
504
393
  return acquireHarnessRunSlot({
505
394
  persistence: this.persistence,
@@ -523,12 +412,6 @@ export class AgentHarnessRuntime {
523
412
  dropPendingRunSlot(runId) {
524
413
  return dropPendingRunSlot(this.pendingRunSlots, runId);
525
414
  }
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
415
  async run(options) {
533
416
  if (this.isDecisionRun(options)) {
534
417
  const resumeOptions = {
@@ -542,15 +425,22 @@ export class AgentHarnessRuntime {
542
425
  }
543
426
  const resolvedListeners = resolveRunListeners(options);
544
427
  if (resolvedListeners) {
545
- return this.dispatchRunListeners(this.streamEvents(options), resolvedListeners);
428
+ return createListenerDispatchRuntime({
429
+ notifyListener: (listener, value) => this.notifyListener(listener, value),
430
+ getThread: (threadId) => this.getThread(threadId),
431
+ }).dispatchRunListeners(this.streamEvents(options), resolvedListeners);
546
432
  }
547
433
  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
- }));
434
+ const { binding, selectedAgentId, threadId, runId, isNewThread, runCreatedEventPromise, releaseRunSlotPromise, } = await prepareRunStart(this.createPrepareRunStartRuntime(), {
435
+ options,
436
+ invocation,
437
+ runCreatedPayload: (activeBinding, activeSelectedAgentId) => ({
438
+ agentId: activeBinding.agent.id,
439
+ requestedAgentId: defaultRequestedAgentId(options.agentId),
440
+ selectedAgentId: activeSelectedAgentId,
441
+ executionMode: getBindingAdapterKind(activeBinding),
442
+ }),
443
+ });
554
444
  await runCreatedEventPromise;
555
445
  const releaseRunSlot = await releaseRunSlotPromise;
556
446
  try {
@@ -585,13 +475,17 @@ export class AgentHarnessRuntime {
585
475
  }
586
476
  return;
587
477
  }
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
- }));
478
+ const { threadId, runId, isNewThread, runCreatedEventPromise, releaseRunSlotPromise, } = await prepareRunStart(this.createPrepareRunStartRuntime(), {
479
+ options,
480
+ invocation,
481
+ runCreatedPayload: (_binding, activeSelectedAgentId) => ({
482
+ agentId: activeSelectedAgentId,
483
+ requestedAgentId: defaultRequestedAgentId(options.agentId),
484
+ selectedAgentId: activeSelectedAgentId,
485
+ input: options.input,
486
+ state: "running",
487
+ }),
488
+ });
595
489
  yield* streamHarnessRun({
596
490
  binding,
597
491
  input: options.input,
@@ -602,17 +496,15 @@ export class AgentHarnessRuntime {
602
496
  isNewThread,
603
497
  runCreatedEventPromise,
604
498
  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),
499
+ loadPriorHistory: (threadId, runId) => this.loadPriorHistory(threadId, runId),
500
+ stream: (binding, message, threadId, priorHistory, streamOptions) => this.runtimeAdapter.stream(binding, message, threadId, priorHistory, streamOptions),
501
+ invokeWithHistory: (binding, input, threadId, runId) => this.invokeWithHistory(binding, input, threadId, runId),
502
+ emit: (threadId, runId, sequence, eventType, payload) => this.emit(threadId, runId, sequence, eventType, payload),
503
+ setRunStateAndEmit: (threadId, runId, sequence, state, stateOptions) => this.setRunStateAndEmit(threadId, runId, sequence, state, stateOptions),
504
+ requestApprovalAndEmit: (threadId, runId, input, interruptContent, checkpointRef, sequence) => this.requestApprovalAndEmit(threadId, runId, input, interruptContent, checkpointRef, sequence),
505
+ appendAssistantMessage: (threadId, runId, content) => appendLifecycleAssistantMessage(this.persistence, threadId, runId, content),
506
+ clearRunRequest: (threadId, runId) => this.persistence.clearRunRequest(threadId, runId),
507
+ emitSyntheticFallback: (threadId, runId, selectedAgentId, error) => this.runtimeEventOperations.emitSyntheticFallback(threadId, runId, selectedAgentId, error),
616
508
  });
617
509
  }
618
510
  async resume(options) {
@@ -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
+ }