@botbotgo/agent-harness 0.0.95 → 0.0.97
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 +1 -114
- package/README.zh.md +1 -70
- package/dist/api.d.ts +5 -5
- package/dist/config/workflows/langgraph-workflows.yaml +363 -111
- package/dist/config/workflows/runtime-profiles.yaml +94 -0
- package/dist/contracts/core.d.ts +9 -0
- package/dist/contracts/core.js +1 -0
- package/dist/contracts/runtime.d.ts +421 -0
- package/dist/contracts/runtime.js +1 -0
- package/dist/contracts/types.d.ts +3 -571
- package/dist/contracts/types.js +3 -1
- package/dist/contracts/workspace.d.ts +229 -0
- package/dist/contracts/workspace.js +1 -0
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/runtime/adapter/compat/deepagent-compat.d.ts +16 -0
- package/dist/runtime/adapter/compat/deepagent-compat.js +45 -0
- package/dist/runtime/adapter/compat/openai-compatible.d.ts +2 -0
- package/dist/runtime/adapter/compat/openai-compatible.js +43 -0
- package/dist/runtime/adapter/index.d.ts +15 -0
- package/dist/runtime/adapter/index.js +15 -0
- package/dist/runtime/adapter/langgraph/presets.js +165 -0
- package/dist/runtime/{langgraph-profiles.d.ts → adapter/langgraph/profiles.d.ts} +1 -1
- package/dist/runtime/adapter/langgraph/profiles.js +206 -0
- package/dist/runtime/adapter/model/invocation-request.d.ts +10 -0
- package/dist/runtime/adapter/model/invocation-request.js +46 -0
- package/dist/runtime/adapter/model/message-assembly.d.ts +6 -0
- package/dist/runtime/adapter/model/message-assembly.js +21 -0
- package/dist/runtime/adapter/model/model-providers.d.ts +2 -0
- package/dist/runtime/adapter/model/model-providers.js +27 -0
- package/dist/runtime/adapter/resilience.d.ts +12 -0
- package/dist/runtime/adapter/resilience.js +60 -0
- package/dist/runtime/{declared-middleware.d.ts → adapter/tool/declared-middleware.d.ts} +1 -1
- package/dist/runtime/adapter/tool/interrupt-policy.d.ts +8 -0
- package/dist/runtime/adapter/tool/interrupt-policy.js +34 -0
- package/dist/runtime/adapter/tool/provider-tool.d.ts +2 -0
- package/dist/runtime/adapter/tool/provider-tool.js +25 -0
- package/dist/runtime/adapter/tool/resolved-tool.d.ts +18 -0
- package/dist/runtime/adapter/tool/resolved-tool.js +62 -0
- package/dist/runtime/adapter/tool/tool-arguments.d.ts +7 -0
- package/dist/runtime/adapter/tool/tool-arguments.js +87 -0
- package/dist/runtime/{tool-hitl.d.ts → adapter/tool/tool-hitl.d.ts} +2 -2
- package/dist/runtime/adapter/tool/tool-name-mapping.d.ts +13 -0
- package/dist/runtime/adapter/tool/tool-name-mapping.js +101 -0
- package/dist/runtime/agent-runtime-adapter.d.ts +5 -20
- package/dist/runtime/agent-runtime-adapter.js +42 -544
- package/dist/runtime/checkpoint-maintenance.d.ts +1 -45
- package/dist/runtime/checkpoint-maintenance.js +1 -259
- package/dist/runtime/file-checkpoint-saver.d.ts +1 -20
- package/dist/runtime/file-checkpoint-saver.js +1 -106
- package/dist/runtime/{event-bus.d.ts → harness/events/event-bus.d.ts} +1 -1
- package/dist/runtime/{event-sink.d.ts → harness/events/event-sink.d.ts} +1 -1
- package/dist/runtime/{event-sink.js → harness/events/event-sink.js} +1 -1
- package/dist/runtime/harness/events/events.d.ts +23 -0
- package/dist/runtime/harness/events/events.js +61 -0
- package/dist/runtime/harness/events/streaming.d.ts +19 -0
- package/dist/runtime/harness/events/streaming.js +96 -0
- package/dist/runtime/harness/index.d.ts +16 -0
- package/dist/runtime/harness/index.js +16 -0
- package/dist/runtime/harness/run/helpers.d.ts +33 -0
- package/dist/runtime/harness/run/helpers.js +74 -0
- package/dist/runtime/harness/run/resources.d.ts +7 -0
- package/dist/runtime/harness/run/resources.js +58 -0
- package/dist/runtime/harness/run/resume.d.ts +6 -0
- package/dist/runtime/harness/run/resume.js +56 -0
- package/dist/runtime/harness/run/routing.d.ts +12 -0
- package/dist/runtime/harness/run/routing.js +47 -0
- package/dist/runtime/harness/run/run-lifecycle.d.ts +37 -0
- package/dist/runtime/harness/run/run-lifecycle.js +109 -0
- package/dist/runtime/harness/run/run-queue.d.ts +17 -0
- package/dist/runtime/harness/run/run-queue.js +43 -0
- package/dist/runtime/{health-monitor.d.ts → harness/system/health-monitor.d.ts} +3 -3
- package/dist/runtime/{health-monitor.js → harness/system/health-monitor.js} +2 -2
- package/dist/runtime/{inventory.d.ts → harness/system/inventory.d.ts} +2 -2
- package/dist/runtime/{inventory.js → harness/system/inventory.js} +4 -4
- package/dist/runtime/{policy-engine.d.ts → harness/system/policy-engine.d.ts} +1 -1
- package/dist/runtime/{policy-engine.js → harness/system/policy-engine.js} +1 -1
- package/dist/runtime/{skill-requirements.d.ts → harness/system/skill-requirements.d.ts} +1 -1
- package/dist/runtime/{skill-requirements.js → harness/system/skill-requirements.js} +1 -1
- package/dist/runtime/{thread-memory-sync.d.ts → harness/system/thread-memory-sync.d.ts} +2 -2
- package/dist/runtime/{thread-memory-sync.js → harness/system/thread-memory-sync.js} +1 -1
- package/dist/runtime/harness.d.ts +2 -7
- package/dist/runtime/harness.js +158 -477
- package/dist/runtime/index.d.ts +7 -7
- package/dist/runtime/index.js +7 -7
- package/dist/runtime/maintenance/checkpoint-maintenance.d.ts +45 -0
- package/dist/runtime/maintenance/checkpoint-maintenance.js +259 -0
- package/dist/runtime/maintenance/file-checkpoint-saver.d.ts +20 -0
- package/dist/runtime/maintenance/file-checkpoint-saver.js +106 -0
- package/dist/runtime/maintenance/index.d.ts +4 -0
- package/dist/runtime/maintenance/index.js +4 -0
- package/dist/runtime/{runtime-record-maintenance.d.ts → maintenance/runtime-record-maintenance.d.ts} +1 -1
- package/dist/runtime/{runtime-record-maintenance.js → maintenance/runtime-record-maintenance.js} +2 -2
- package/dist/runtime/maintenance/sqlite-maintained-checkpoint-saver.d.ts +9 -0
- package/dist/runtime/maintenance/sqlite-maintained-checkpoint-saver.js +39 -0
- package/dist/runtime/parsing/stream-event-parsing.d.ts +6 -0
- package/dist/runtime/parsing/stream-event-parsing.js +231 -0
- package/dist/runtime/sqlite-maintained-checkpoint-saver.d.ts +1 -9
- package/dist/runtime/sqlite-maintained-checkpoint-saver.js +1 -39
- package/dist/runtime/support/harness-support.d.ts +4 -4
- package/dist/runtime/support/harness-support.js +14 -3
- package/dist/runtime/support/runtime-factories.d.ts +1 -1
- package/dist/runtime/support/runtime-factories.js +1 -1
- package/dist/workspace/agent-binding-compiler.js +39 -3
- package/dist/workspace/object-loader.js +5 -1
- package/package.json +4 -4
- package/dist/runtime/langgraph-presets.js +0 -165
- package/dist/runtime/langgraph-profiles.js +0 -206
- /package/dist/runtime/{langgraph-presets.d.ts → adapter/langgraph/presets.d.ts} +0 -0
- /package/dist/runtime/{declared-middleware.js → adapter/tool/declared-middleware.js} +0 -0
- /package/dist/runtime/{tool-hitl.js → adapter/tool/tool-hitl.js} +0 -0
- /package/dist/runtime/{event-bus.js → harness/events/event-bus.js} +0 -0
- /package/dist/runtime/{store.d.ts → harness/system/store.d.ts} +0 -0
- /package/dist/runtime/{store.js → harness/system/store.js} +0 -0
package/dist/runtime/harness.js
CHANGED
|
@@ -2,24 +2,30 @@ import { AUTO_AGENT_ID } from "../contracts/types.js";
|
|
|
2
2
|
import { SqlitePersistence } from "../persistence/sqlite-store.js";
|
|
3
3
|
import { createPersistentId } from "../utils/id.js";
|
|
4
4
|
import { AGENT_INTERRUPT_SENTINEL_PREFIX, AgentRuntimeAdapter, RuntimeOperationTimeoutError } from "./agent-runtime-adapter.js";
|
|
5
|
+
import { normalizeUpstreamRuntimeEvent } from "./parsing/stream-event-parsing.js";
|
|
5
6
|
import { createResourceBackendResolver, createResourceToolResolver } from "../resource/resource.js";
|
|
6
|
-
import { EventBus } from "./event-bus.js";
|
|
7
|
-
import { PolicyEngine } from "./policy-engine.js";
|
|
7
|
+
import { EventBus } from "./harness/events/event-bus.js";
|
|
8
|
+
import { PolicyEngine } from "./harness/system/policy-engine.js";
|
|
8
9
|
import { getConcurrencyConfig, getRecoveryConfig, getRoutingDefaultAgentId, getRoutingRules, getRoutingSystemPrompt, isModelRoutingEnabled, matchRoutingRule, } from "../workspace/support/workspace-ref-utils.js";
|
|
9
|
-
import { createHarnessEvent,
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import { resolveCompiledVectorStore, resolveCompiledVectorStoreRef } from "./support/vector-stores.js";
|
|
13
|
-
import { ThreadMemorySync } from "./thread-memory-sync.js";
|
|
14
|
-
import { FileBackedStore } from "./store.js";
|
|
10
|
+
import { createHarnessEvent, inferRoutingBindings, renderRuntimeFailure, renderToolFailure, } from "./support/harness-support.js";
|
|
11
|
+
import { ThreadMemorySync } from "./harness/system/thread-memory-sync.js";
|
|
12
|
+
import { FileBackedStore } from "./harness/system/store.js";
|
|
15
13
|
import { CheckpointMaintenanceLoop, discoverCheckpointMaintenanceTargets, readCheckpointMaintenanceConfig, } from "./checkpoint-maintenance.js";
|
|
16
|
-
import { RuntimeRecordMaintenanceLoop, discoverRuntimeRecordMaintenanceTargets, readRuntimeRecordMaintenanceConfig, } from "./runtime-record-maintenance.js";
|
|
17
|
-
import { HealthMonitor } from "./health-monitor.js";
|
|
14
|
+
import { RuntimeRecordMaintenanceLoop, discoverRuntimeRecordMaintenanceTargets, readRuntimeRecordMaintenanceConfig, } from "./maintenance/runtime-record-maintenance.js";
|
|
15
|
+
import { HealthMonitor } from "./harness/system/health-monitor.js";
|
|
18
16
|
import { extractMessageText, normalizeMessageContent } from "../utils/message-content.js";
|
|
17
|
+
import { buildPersistedRunRequest, isTerminalRunState, normalizeInvocationEnvelope, normalizeRunPriority, resolveRunListeners, toPublicApprovalRecord, } from "./harness/run/helpers.js";
|
|
18
|
+
import { emitHarnessEvent, emitRunCreatedEvent, emitSyntheticFallbackEvent, persistApproval, requestApprovalAndEmitEvent, setRunStateAndEmitEvent, } from "./harness/events/events.js";
|
|
19
|
+
import { appendAssistantMessage as appendLifecycleAssistantMessage, checkpointRefForState as getCheckpointRefForRunState, expirePendingApprovals as expireLifecyclePendingApprovals, finalizeCancelledRun as finalizeLifecycleCancelledRun, finalizeContinuedRun as finalizeLifecycleContinuedRun, reviewCompletedRun as reviewLifecycleCompletedRun, synthesizeCompletedRun as synthesizeLifecycleCompletedRun, } from "./harness/run/run-lifecycle.js";
|
|
20
|
+
import { createContentBlocksItem as createStreamingContentBlocksItem, createToolResultKey as createStreamingToolResultKey, dispatchRunListeners as dispatchStreamingRunListeners, emitOutputDeltaAndCreateItem as emitStreamingOutputDeltaAndCreateItem, } from "./harness/events/streaming.js";
|
|
21
|
+
import { buildResumePayload as buildHarnessResumePayload, resolveApprovalRecord as resolveHarnessApprovalRecord, } from "./harness/run/resume.js";
|
|
22
|
+
import { dropPendingRunSlot, enqueuePendingRunSlot, shiftNextPendingRunSlot } from "./harness/run/run-queue.js";
|
|
23
|
+
import { buildRoutingInput, getDefaultHostAgentId, heuristicHostRoute, resolveSelectedAgentId } from "./harness/run/routing.js";
|
|
24
|
+
import { resolveCheckpointer, resolveEmbeddingModel, resolveStore, resolveStoreFromConfig, resolveVectorStore, } from "./harness/run/resources.js";
|
|
19
25
|
import { createToolMcpServerFromTools, serveToolsOverStdioFromHarness } from "../mcp.js";
|
|
20
|
-
import { getBindingAdapterKind, getBindingPrimaryTools, getBindingStoreConfig
|
|
26
|
+
import { getBindingAdapterKind, getBindingPrimaryTools, getBindingStoreConfig } from "./support/compiled-binding.js";
|
|
21
27
|
import { isRuntimeEntryBinding } from "./support/runtime-entry.js";
|
|
22
|
-
import { describeWorkspaceInventory, listAgentSkills as listWorkspaceAgentSkills, } from "./inventory.js";
|
|
28
|
+
import { describeWorkspaceInventory, listAgentSkills as listWorkspaceAgentSkills, } from "./harness/system/inventory.js";
|
|
23
29
|
export class AgentHarnessRuntime {
|
|
24
30
|
workspace;
|
|
25
31
|
runtimeAdapterOptions;
|
|
@@ -59,22 +65,6 @@ export class AgentHarnessRuntime {
|
|
|
59
65
|
pendingRunInsertionOrder = 0;
|
|
60
66
|
pendingRunSlots = [];
|
|
61
67
|
runtimeEventSequence = 0;
|
|
62
|
-
toPublicApprovalRecord(approval) {
|
|
63
|
-
const { toolCallId: _toolCallId, checkpointRef: _checkpointRef, eventRefs: _eventRefs, ...publicApproval } = approval;
|
|
64
|
-
return publicApproval;
|
|
65
|
-
}
|
|
66
|
-
normalizeInvocationEnvelope(options) {
|
|
67
|
-
const invocation = options.invocation;
|
|
68
|
-
return {
|
|
69
|
-
context: invocation?.context,
|
|
70
|
-
state: invocation?.inputs,
|
|
71
|
-
files: invocation?.attachments,
|
|
72
|
-
invocation,
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
isTerminalRunState(state) {
|
|
76
|
-
return state === "completed" || state === "failed";
|
|
77
|
-
}
|
|
78
68
|
listHostBindings() {
|
|
79
69
|
return inferRoutingBindings(this.workspace).hostBindings;
|
|
80
70
|
}
|
|
@@ -83,90 +73,36 @@ export class AgentHarnessRuntime {
|
|
|
83
73
|
`${this.workspace.workspaceRoot}/run-data`);
|
|
84
74
|
}
|
|
85
75
|
heuristicRoute(input) {
|
|
86
|
-
|
|
87
|
-
return heuristicRoute(extractMessageText(input), primaryBinding, secondaryBinding);
|
|
76
|
+
return heuristicHostRoute(this.workspace, input);
|
|
88
77
|
}
|
|
89
78
|
getDefaultHostAgentId() {
|
|
90
|
-
|
|
91
|
-
if (orchestraBinding && isRuntimeEntryBinding(orchestraBinding)) {
|
|
92
|
-
return orchestraBinding.agent.id;
|
|
93
|
-
}
|
|
94
|
-
return this.heuristicRoute("");
|
|
79
|
+
return getDefaultHostAgentId(this.workspace, AgentHarnessRuntime.DEFAULT_HOST_AGENT_ID);
|
|
95
80
|
}
|
|
96
81
|
async buildRoutingInput(input, threadId) {
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
return inputText;
|
|
100
|
-
}
|
|
101
|
-
const history = await this.persistence.listThreadMessages(threadId);
|
|
102
|
-
const priorHistory = history.filter((message) => extractMessageText(message.content).trim());
|
|
103
|
-
if (priorHistory.length === 0) {
|
|
104
|
-
return inputText;
|
|
105
|
-
}
|
|
106
|
-
const recentTurns = priorHistory.slice(-6).map((message) => {
|
|
107
|
-
const role = message.role === "assistant" ? "assistant" : "user";
|
|
108
|
-
const compact = extractMessageText(message.content).replace(/\s+/g, " ").trim();
|
|
109
|
-
return `${role}: ${compact.slice(0, 240)}`;
|
|
110
|
-
});
|
|
111
|
-
return [
|
|
112
|
-
"Recent conversation context:",
|
|
113
|
-
...recentTurns,
|
|
114
|
-
"",
|
|
115
|
-
`Current user request: ${inputText}`,
|
|
116
|
-
].join("\n");
|
|
82
|
+
const history = threadId ? await this.persistence.listThreadMessages(threadId) : [];
|
|
83
|
+
return buildRoutingInput(input, history);
|
|
117
84
|
}
|
|
118
85
|
async resolveSelectedAgentId(input, requestedAgentId, threadId) {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
return this.getDefaultHostAgentId();
|
|
128
|
-
}
|
|
129
|
-
return requestedAgentId;
|
|
86
|
+
return resolveSelectedAgentId({
|
|
87
|
+
workspace: this.workspace,
|
|
88
|
+
input,
|
|
89
|
+
requestedAgentId,
|
|
90
|
+
threadId,
|
|
91
|
+
preferredHostAgentId: AgentHarnessRuntime.DEFAULT_HOST_AGENT_ID,
|
|
92
|
+
getThreadSummary: (currentThreadId) => this.getSession(currentThreadId),
|
|
93
|
+
});
|
|
130
94
|
}
|
|
131
95
|
resolveStore(binding) {
|
|
132
|
-
|
|
133
|
-
return this.resolveStoreFromConfig(storeConfig, binding?.harnessRuntime.runRoot ?? this.defaultRunRoot()) ?? this.defaultStore;
|
|
96
|
+
return resolveStore(this.stores, this.defaultStore, this.defaultRunRoot(), (currentBinding) => currentBinding ? getBindingStoreConfig(currentBinding) : undefined, binding);
|
|
134
97
|
}
|
|
135
98
|
resolveStoreFromConfig(storeConfig, runRoot) {
|
|
136
|
-
|
|
137
|
-
if (!storeConfig || !cacheKey) {
|
|
138
|
-
return undefined;
|
|
139
|
-
}
|
|
140
|
-
const existing = this.stores.get(cacheKey);
|
|
141
|
-
if (existing) {
|
|
142
|
-
return existing;
|
|
143
|
-
}
|
|
144
|
-
const created = createStoreForConfig(storeConfig, runRoot);
|
|
145
|
-
this.stores.set(cacheKey, created);
|
|
146
|
-
return created;
|
|
99
|
+
return resolveStoreFromConfig(this.stores, storeConfig, runRoot);
|
|
147
100
|
}
|
|
148
101
|
async resolveEmbeddingModel(embeddingModelRef) {
|
|
149
|
-
|
|
150
|
-
const existing = this.embeddingModels.get(compiled.id);
|
|
151
|
-
if (existing) {
|
|
152
|
-
return existing;
|
|
153
|
-
}
|
|
154
|
-
const resolved = await resolveCompiledEmbeddingModel(compiled, this.runtimeAdapterOptions.embeddingModelResolver);
|
|
155
|
-
this.embeddingModels.set(compiled.id, resolved);
|
|
156
|
-
return resolved;
|
|
102
|
+
return resolveEmbeddingModel(this.workspace, this.embeddingModels, embeddingModelRef, this.runtimeAdapterOptions);
|
|
157
103
|
}
|
|
158
104
|
async resolveVectorStore(vectorStoreRef) {
|
|
159
|
-
|
|
160
|
-
const existing = this.vectorStores.get(compiled.id);
|
|
161
|
-
if (existing) {
|
|
162
|
-
return existing;
|
|
163
|
-
}
|
|
164
|
-
const resolved = await resolveCompiledVectorStore(this.workspace, compiled, {
|
|
165
|
-
embeddingModelResolver: this.runtimeAdapterOptions.embeddingModelResolver,
|
|
166
|
-
vectorStoreResolver: this.runtimeAdapterOptions.vectorStoreResolver,
|
|
167
|
-
});
|
|
168
|
-
this.vectorStores.set(compiled.id, resolved);
|
|
169
|
-
return resolved;
|
|
105
|
+
return resolveVectorStore(this.workspace, this.vectorStores, vectorStoreRef, this.runtimeAdapterOptions);
|
|
170
106
|
}
|
|
171
107
|
constructor(workspace, runtimeAdapterOptions = {}) {
|
|
172
108
|
this.workspace = workspace;
|
|
@@ -189,21 +125,7 @@ export class AgentHarnessRuntime {
|
|
|
189
125
|
getVectorStore: (vectorStoreRef) => this.resolveVectorStore(vectorStoreRef),
|
|
190
126
|
}),
|
|
191
127
|
checkpointerResolver: runtimeAdapterOptions.checkpointerResolver ??
|
|
192
|
-
((binding) =>
|
|
193
|
-
const key = `${binding.harnessRuntime.runRoot}:${JSON.stringify(binding.harnessRuntime.checkpointer ?? { kind: "FileCheckpointer", path: "checkpoints.json" })}`;
|
|
194
|
-
const existing = this.checkpointers.get(key);
|
|
195
|
-
if (existing) {
|
|
196
|
-
return existing;
|
|
197
|
-
}
|
|
198
|
-
const resolvedConfig = binding.harnessRuntime.checkpointer ?? { kind: "FileCheckpointer", path: "checkpoints.json" };
|
|
199
|
-
if (typeof resolvedConfig === "boolean") {
|
|
200
|
-
this.checkpointers.set(key, resolvedConfig);
|
|
201
|
-
return resolvedConfig;
|
|
202
|
-
}
|
|
203
|
-
const saver = createCheckpointerForConfig(resolvedConfig, binding.harnessRuntime.runRoot);
|
|
204
|
-
this.checkpointers.set(key, saver);
|
|
205
|
-
return saver;
|
|
206
|
-
}),
|
|
128
|
+
((binding) => resolveCheckpointer(this.checkpointers, binding)),
|
|
207
129
|
storeResolver: runtimeAdapterOptions.storeResolver ??
|
|
208
130
|
((binding) => this.resolveStore(binding)),
|
|
209
131
|
backendResolver: runtimeAdapterOptions.backendResolver ??
|
|
@@ -327,11 +249,11 @@ export class AgentHarnessRuntime {
|
|
|
327
249
|
}
|
|
328
250
|
async listApprovals(filter) {
|
|
329
251
|
const approvals = await this.persistence.listApprovals(filter);
|
|
330
|
-
return approvals.map((approval) =>
|
|
252
|
+
return approvals.map((approval) => toPublicApprovalRecord(approval));
|
|
331
253
|
}
|
|
332
254
|
async getApproval(approvalId) {
|
|
333
255
|
const approval = await this.persistence.getApproval(approvalId);
|
|
334
|
-
return approval ?
|
|
256
|
+
return approval ? toPublicApprovalRecord(approval) : null;
|
|
335
257
|
}
|
|
336
258
|
listAgentSkills(agentId, options = {}) {
|
|
337
259
|
return listWorkspaceAgentSkills(this.workspace, agentId, options);
|
|
@@ -362,7 +284,7 @@ export class AgentHarnessRuntime {
|
|
|
362
284
|
if (!thread) {
|
|
363
285
|
return false;
|
|
364
286
|
}
|
|
365
|
-
const activeRun = thread.runs.find((run) => !
|
|
287
|
+
const activeRun = thread.runs.find((run) => !isTerminalRunState(run.state));
|
|
366
288
|
if (activeRun) {
|
|
367
289
|
throw new Error(`Cannot delete thread ${threadId} while run ${activeRun.runId} is ${activeRun.state}`);
|
|
368
290
|
}
|
|
@@ -389,7 +311,8 @@ export class AgentHarnessRuntime {
|
|
|
389
311
|
return serveToolsOverStdioFromHarness(tools, options);
|
|
390
312
|
}
|
|
391
313
|
async routeAgent(input, options = {}) {
|
|
392
|
-
const
|
|
314
|
+
const routingHistory = options.threadId ? await this.persistence.listThreadMessages(options.threadId) : [];
|
|
315
|
+
const routingInput = buildRoutingInput(input, routingHistory);
|
|
393
316
|
const rawInput = extractMessageText(input);
|
|
394
317
|
const { primaryBinding, secondaryBinding } = inferRoutingBindings(this.workspace);
|
|
395
318
|
const configuredRule = this.routingRules.find((rule) => matchRoutingRule(rawInput, rule, options));
|
|
@@ -408,7 +331,7 @@ export class AgentHarnessRuntime {
|
|
|
408
331
|
}
|
|
409
332
|
}
|
|
410
333
|
if (!primaryBinding || !secondaryBinding) {
|
|
411
|
-
return
|
|
334
|
+
return heuristicHostRoute(this.workspace, rawInput);
|
|
412
335
|
}
|
|
413
336
|
try {
|
|
414
337
|
return await this.runtimeAdapter.route(routingInput, primaryBinding, secondaryBinding, {
|
|
@@ -416,21 +339,16 @@ export class AgentHarnessRuntime {
|
|
|
416
339
|
});
|
|
417
340
|
}
|
|
418
341
|
catch {
|
|
419
|
-
return
|
|
342
|
+
return heuristicHostRoute(this.workspace, rawInput);
|
|
420
343
|
}
|
|
421
344
|
}
|
|
422
345
|
async emit(threadId, runId, sequence, eventType, payload, source = "runtime") {
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
}
|
|
429
|
-
else {
|
|
430
|
-
await this.persistence.appendEvent(event);
|
|
431
|
-
}
|
|
432
|
-
this.eventBus.publish(event);
|
|
433
|
-
return event;
|
|
346
|
+
return emitHarnessEvent({
|
|
347
|
+
persistence: this.persistence,
|
|
348
|
+
publishEvent: (event) => this.eventBus.publish(event),
|
|
349
|
+
trackBackgroundTask: (task) => this.trackBackgroundTask(task),
|
|
350
|
+
backgroundEventTypes: AgentHarnessRuntime.BACKGROUND_EVENT_TYPES,
|
|
351
|
+
}, threadId, runId, sequence, eventType, payload, source);
|
|
434
352
|
}
|
|
435
353
|
trackBackgroundTask(task) {
|
|
436
354
|
this.backgroundTasks.add(task);
|
|
@@ -498,15 +416,7 @@ export class AgentHarnessRuntime {
|
|
|
498
416
|
return userTurn?.content ?? "";
|
|
499
417
|
}
|
|
500
418
|
async appendAssistantMessage(threadId, runId, content) {
|
|
501
|
-
|
|
502
|
-
return;
|
|
503
|
-
}
|
|
504
|
-
await this.persistence.appendThreadMessage(threadId, {
|
|
505
|
-
role: "assistant",
|
|
506
|
-
content,
|
|
507
|
-
runId,
|
|
508
|
-
createdAt: new Date().toISOString(),
|
|
509
|
-
});
|
|
419
|
+
return appendLifecycleAssistantMessage(this.persistence, threadId, runId, content);
|
|
510
420
|
}
|
|
511
421
|
async getRunCancellation(runId) {
|
|
512
422
|
const control = await this.persistence.getRunControl(runId);
|
|
@@ -516,37 +426,17 @@ export class AgentHarnessRuntime {
|
|
|
516
426
|
};
|
|
517
427
|
}
|
|
518
428
|
async expirePendingApprovals(threadId, runId) {
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
}
|
|
524
|
-
await this.persistence.resolveApproval(threadId, runId, approval.approvalId, "expired");
|
|
525
|
-
await this.emit(threadId, runId, 6, "approval.resolved", {
|
|
526
|
-
approvalId: approval.approvalId,
|
|
527
|
-
pendingActionId: approval.pendingActionId,
|
|
528
|
-
decision: "cancel",
|
|
529
|
-
toolName: approval.toolName,
|
|
530
|
-
});
|
|
531
|
-
}
|
|
429
|
+
return expireLifecyclePendingApprovals({
|
|
430
|
+
persistence: this.persistence,
|
|
431
|
+
emit: (currentThreadId, currentRunId, sequence, eventType, payload, source) => this.emit(currentThreadId, currentRunId, sequence, eventType, payload, source),
|
|
432
|
+
}, threadId, runId);
|
|
532
433
|
}
|
|
533
434
|
async finalizeCancelledRun(threadId, runId, previousState, reason) {
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
previousState,
|
|
540
|
-
...(reason ? { error: reason } : {}),
|
|
541
|
-
});
|
|
542
|
-
const runMeta = await this.persistence.getRunMeta(threadId, runId);
|
|
543
|
-
return {
|
|
544
|
-
threadId,
|
|
545
|
-
runId,
|
|
546
|
-
agentId: runMeta.agentId,
|
|
547
|
-
state: "cancelled",
|
|
548
|
-
output: reason ? `cancelled: ${reason}` : "cancelled",
|
|
549
|
-
};
|
|
435
|
+
return finalizeLifecycleCancelledRun({
|
|
436
|
+
persistence: this.persistence,
|
|
437
|
+
emit: (currentThreadId, currentRunId, sequence, eventType, payload, source) => this.emit(currentThreadId, currentRunId, sequence, eventType, payload, source),
|
|
438
|
+
setRunStateAndEmit: (currentThreadId, currentRunId, sequence, state, options) => this.setRunStateAndEmit(currentThreadId, currentRunId, sequence, state, options),
|
|
439
|
+
}, threadId, runId, previousState, reason);
|
|
550
440
|
}
|
|
551
441
|
async invokeWithHistory(binding, input, threadId, runId, resumePayload, priorHistory, options = {}) {
|
|
552
442
|
const history = priorHistory ?? await this.loadPriorHistory(threadId, runId);
|
|
@@ -561,67 +451,12 @@ export class AgentHarnessRuntime {
|
|
|
561
451
|
throw error;
|
|
562
452
|
}
|
|
563
453
|
}
|
|
564
|
-
buildPersistedRunRequest(input, invocation, priority) {
|
|
565
|
-
const envelope = invocation.invocation ?? {
|
|
566
|
-
...(invocation.context ? { context: invocation.context } : {}),
|
|
567
|
-
...(invocation.state ? { inputs: invocation.state } : {}),
|
|
568
|
-
...(invocation.files ? { attachments: invocation.files } : {}),
|
|
569
|
-
};
|
|
570
|
-
return {
|
|
571
|
-
input: normalizeMessageContent(input),
|
|
572
|
-
priority: Number.isFinite(priority) ? Math.trunc(priority) : undefined,
|
|
573
|
-
invocation: envelope && Object.keys(envelope).length > 0
|
|
574
|
-
? {
|
|
575
|
-
...(envelope.context ? { context: envelope.context } : {}),
|
|
576
|
-
...(envelope.inputs ? { inputs: envelope.inputs } : {}),
|
|
577
|
-
...(envelope.attachments ? { attachments: envelope.attachments } : {}),
|
|
578
|
-
...(envelope.capabilities ? { capabilities: envelope.capabilities } : {}),
|
|
579
|
-
}
|
|
580
|
-
: undefined,
|
|
581
|
-
savedAt: new Date().toISOString(),
|
|
582
|
-
};
|
|
583
|
-
}
|
|
584
|
-
normalizeRunPriority(priority) {
|
|
585
|
-
if (!Number.isFinite(priority)) {
|
|
586
|
-
return 0;
|
|
587
|
-
}
|
|
588
|
-
return Math.trunc(priority);
|
|
589
|
-
}
|
|
590
454
|
async resolvePersistedRunPriority(threadId, runId) {
|
|
591
455
|
const persisted = await this.persistence.getRunRequest(threadId, runId);
|
|
592
|
-
return
|
|
456
|
+
return normalizeRunPriority(persisted?.priority);
|
|
593
457
|
}
|
|
594
458
|
enqueuePendingRunSlot(entry) {
|
|
595
|
-
|
|
596
|
-
.filter((candidate) => Boolean(candidate.threadId && candidate.runId))
|
|
597
|
-
.map((candidate, index) => [candidate.runId, index + 1]));
|
|
598
|
-
const queuedEntry = {
|
|
599
|
-
...entry,
|
|
600
|
-
insertionOrder: this.pendingRunInsertionOrder++,
|
|
601
|
-
};
|
|
602
|
-
this.pendingRunSlots.push(queuedEntry);
|
|
603
|
-
this.pendingRunSlots.sort((left, right) => {
|
|
604
|
-
if (right.priority !== left.priority) {
|
|
605
|
-
return right.priority - left.priority;
|
|
606
|
-
}
|
|
607
|
-
return left.insertionOrder - right.insertionOrder;
|
|
608
|
-
});
|
|
609
|
-
return this.pendingRunSlots.flatMap((candidate, index) => {
|
|
610
|
-
if (!candidate.threadId || !candidate.runId) {
|
|
611
|
-
return [];
|
|
612
|
-
}
|
|
613
|
-
const previousPosition = previousPositions.get(candidate.runId);
|
|
614
|
-
const queuePosition = index + 1;
|
|
615
|
-
if (previousPosition === undefined || previousPosition === queuePosition) {
|
|
616
|
-
return [];
|
|
617
|
-
}
|
|
618
|
-
return [{
|
|
619
|
-
threadId: candidate.threadId,
|
|
620
|
-
runId: candidate.runId,
|
|
621
|
-
priority: candidate.priority,
|
|
622
|
-
queuePosition,
|
|
623
|
-
}];
|
|
624
|
-
});
|
|
459
|
+
return enqueuePendingRunSlot(this.pendingRunSlots, entry, this.pendingRunInsertionOrder++);
|
|
625
460
|
}
|
|
626
461
|
async executeQueuedRun(binding, input, threadId, runId, agentId, options = {}) {
|
|
627
462
|
const previousState = options.previousState ?? "running";
|
|
@@ -689,164 +524,80 @@ export class AgentHarnessRuntime {
|
|
|
689
524
|
}
|
|
690
525
|
}
|
|
691
526
|
checkpointRefForState(threadId, runId, state) {
|
|
692
|
-
return
|
|
527
|
+
return getCheckpointRefForRunState(threadId, runId, state);
|
|
693
528
|
}
|
|
694
529
|
async finalizeContinuedRun(binding, threadId, runId, input, actual, options) {
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
:
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
checkpointRef,
|
|
704
|
-
});
|
|
705
|
-
if (finalizedActual.state === "waiting_for_approval" && options.approvalSequence) {
|
|
706
|
-
approval = (await this.requestApprovalAndEmit(threadId, runId, input, finalizedActual.interruptContent, checkpointRef, options.approvalSequence)).approval;
|
|
707
|
-
}
|
|
708
|
-
if (finalizedActual.state === "completed") {
|
|
709
|
-
await this.reviewCompletedRun(binding, threadId, runId, input, finalizedActual);
|
|
710
|
-
}
|
|
711
|
-
return {
|
|
712
|
-
...finalizedActual,
|
|
713
|
-
threadId,
|
|
714
|
-
runId,
|
|
715
|
-
approvalId: approval?.approvalId ?? finalizedActual.approvalId,
|
|
716
|
-
pendingActionId: approval?.pendingActionId ?? finalizedActual.pendingActionId,
|
|
717
|
-
};
|
|
530
|
+
return finalizeLifecycleContinuedRun({
|
|
531
|
+
persistence: this.persistence,
|
|
532
|
+
emit: (currentThreadId, currentRunId, sequence, eventType, payload, source) => this.emit(currentThreadId, currentRunId, sequence, eventType, payload, source),
|
|
533
|
+
setRunStateAndEmit: (currentThreadId, currentRunId, sequence, state, lifecycleOptions) => this.setRunStateAndEmit(currentThreadId, currentRunId, sequence, state, lifecycleOptions),
|
|
534
|
+
requestApprovalAndEmit: (currentThreadId, currentRunId, lifecycleInput, interruptContent, checkpointRef, sequence) => this.requestApprovalAndEmit(currentThreadId, currentRunId, lifecycleInput, interruptContent, checkpointRef, sequence),
|
|
535
|
+
synthesizeFinalResult: (currentBinding, lifecycleInput, lifecycleActual) => this.runtimeAdapter.synthesizeFinalResult(currentBinding, lifecycleInput, lifecycleActual),
|
|
536
|
+
reviewRunResult: (currentBinding, lifecycleInput, lifecycleActual) => this.runtimeAdapter.reviewRunResult(currentBinding, lifecycleInput, lifecycleActual),
|
|
537
|
+
}, binding, threadId, runId, input, actual, options);
|
|
718
538
|
}
|
|
719
539
|
async synthesizeCompletedRun(binding, input, actual) {
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
return actual;
|
|
724
|
-
}
|
|
725
|
-
return {
|
|
726
|
-
...actual,
|
|
727
|
-
output: synthesized.output,
|
|
728
|
-
finalMessageText: synthesized.finalMessageText,
|
|
729
|
-
metadata: {
|
|
730
|
-
...(typeof actual.metadata === "object" && actual.metadata ? actual.metadata : {}),
|
|
731
|
-
finalSynthesis: {
|
|
732
|
-
modelId: synthesized.modelId,
|
|
733
|
-
},
|
|
734
|
-
},
|
|
735
|
-
};
|
|
736
|
-
}
|
|
737
|
-
catch {
|
|
738
|
-
return actual;
|
|
739
|
-
}
|
|
540
|
+
return synthesizeLifecycleCompletedRun({
|
|
541
|
+
synthesizeFinalResult: (currentBinding, lifecycleInput, lifecycleActual) => this.runtimeAdapter.synthesizeFinalResult(currentBinding, lifecycleInput, lifecycleActual),
|
|
542
|
+
}, binding, input, actual);
|
|
740
543
|
}
|
|
741
544
|
async reviewCompletedRun(binding, threadId, runId, input, actual) {
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
}
|
|
747
|
-
await this.emit(threadId, runId, 7, "run.reviewed", {
|
|
748
|
-
modelId: review.modelId,
|
|
749
|
-
assessment: review.assessment,
|
|
750
|
-
});
|
|
751
|
-
}
|
|
752
|
-
catch {
|
|
753
|
-
// Review is advisory; do not fail the completed run if the review pass fails.
|
|
754
|
-
}
|
|
545
|
+
return reviewLifecycleCompletedRun({
|
|
546
|
+
reviewRunResult: (currentBinding, lifecycleInput, lifecycleActual) => this.runtimeAdapter.reviewRunResult(currentBinding, lifecycleInput, lifecycleActual),
|
|
547
|
+
emit: (currentThreadId, currentRunId, sequence, eventType, payload, source) => this.emit(currentThreadId, currentRunId, sequence, eventType, payload, source),
|
|
548
|
+
}, binding, threadId, runId, input, actual);
|
|
755
549
|
}
|
|
756
550
|
async emitOutputDeltaAndCreateItem(threadId, runId, agentId, content) {
|
|
757
|
-
|
|
758
|
-
content,
|
|
759
|
-
});
|
|
760
|
-
return {
|
|
761
|
-
type: "content",
|
|
762
|
-
threadId,
|
|
763
|
-
runId,
|
|
764
|
-
agentId,
|
|
765
|
-
content,
|
|
766
|
-
};
|
|
551
|
+
return emitStreamingOutputDeltaAndCreateItem((currentThreadId, currentRunId, sequence, eventType, payload) => this.emit(currentThreadId, currentRunId, sequence, eventType, payload), threadId, runId, agentId, content);
|
|
767
552
|
}
|
|
768
553
|
createContentBlocksItem(threadId, runId, agentId, contentBlocks) {
|
|
769
|
-
return
|
|
770
|
-
type: "content-blocks",
|
|
771
|
-
threadId,
|
|
772
|
-
runId,
|
|
773
|
-
agentId,
|
|
774
|
-
contentBlocks,
|
|
775
|
-
};
|
|
554
|
+
return createStreamingContentBlocksItem(threadId, runId, agentId, contentBlocks);
|
|
776
555
|
}
|
|
777
556
|
createToolResultKey(toolName, output, isError) {
|
|
778
|
-
|
|
779
|
-
try {
|
|
780
|
-
serializedOutput = JSON.stringify(output);
|
|
781
|
-
}
|
|
782
|
-
catch {
|
|
783
|
-
serializedOutput = String(output);
|
|
784
|
-
}
|
|
785
|
-
return JSON.stringify([toolName, serializedOutput, isError === true]);
|
|
557
|
+
return createStreamingToolResultKey(toolName, output, isError);
|
|
786
558
|
}
|
|
787
559
|
async emitRunCreated(threadId, runId, payload) {
|
|
788
|
-
return
|
|
560
|
+
return emitRunCreatedEvent({
|
|
561
|
+
persistence: this.persistence,
|
|
562
|
+
publishEvent: (event) => this.eventBus.publish(event),
|
|
563
|
+
trackBackgroundTask: (task) => this.trackBackgroundTask(task),
|
|
564
|
+
backgroundEventTypes: AgentHarnessRuntime.BACKGROUND_EVENT_TYPES,
|
|
565
|
+
}, threadId, runId, payload);
|
|
789
566
|
}
|
|
790
567
|
async setRunStateAndEmit(threadId, runId, sequence, state, options) {
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
});
|
|
568
|
+
return setRunStateAndEmitEvent({
|
|
569
|
+
persistence: this.persistence,
|
|
570
|
+
publishEvent: (event) => this.eventBus.publish(event),
|
|
571
|
+
trackBackgroundTask: (task) => this.trackBackgroundTask(task),
|
|
572
|
+
backgroundEventTypes: AgentHarnessRuntime.BACKGROUND_EVENT_TYPES,
|
|
573
|
+
}, threadId, runId, sequence, state, options);
|
|
798
574
|
}
|
|
799
575
|
async requestApprovalAndEmit(threadId, runId, input, interruptContent, checkpointRef, sequence) {
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
allowedDecisions: approval.allowedDecisions,
|
|
807
|
-
checkpointRef,
|
|
808
|
-
});
|
|
809
|
-
return { approval, event };
|
|
576
|
+
return requestApprovalAndEmitEvent({
|
|
577
|
+
persistence: this.persistence,
|
|
578
|
+
publishEvent: (event) => this.eventBus.publish(event),
|
|
579
|
+
trackBackgroundTask: (task) => this.trackBackgroundTask(task),
|
|
580
|
+
backgroundEventTypes: AgentHarnessRuntime.BACKGROUND_EVENT_TYPES,
|
|
581
|
+
}, threadId, runId, input, interruptContent, checkpointRef, sequence);
|
|
810
582
|
}
|
|
811
583
|
async emitSyntheticFallback(threadId, runId, selectedAgentId, error, sequence = 3) {
|
|
812
|
-
await
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
584
|
+
await emitSyntheticFallbackEvent({
|
|
585
|
+
persistence: this.persistence,
|
|
586
|
+
publishEvent: (event) => this.eventBus.publish(event),
|
|
587
|
+
trackBackgroundTask: (task) => this.trackBackgroundTask(task),
|
|
588
|
+
backgroundEventTypes: AgentHarnessRuntime.BACKGROUND_EVENT_TYPES,
|
|
589
|
+
}, threadId, runId, selectedAgentId, error, sequence);
|
|
816
590
|
}
|
|
817
591
|
async persistApproval(threadId, runId, checkpointRef, input, interruptContent) {
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
createdAt: approval.requestedAt,
|
|
825
|
-
}, approval);
|
|
826
|
-
await this.emit(threadId, runId, 5, "artifact.created", {
|
|
827
|
-
artifactId: artifact.artifactId,
|
|
828
|
-
kind: artifact.kind,
|
|
829
|
-
path: artifact.path,
|
|
830
|
-
});
|
|
831
|
-
return approval;
|
|
592
|
+
return persistApproval({
|
|
593
|
+
persistence: this.persistence,
|
|
594
|
+
publishEvent: (event) => this.eventBus.publish(event),
|
|
595
|
+
trackBackgroundTask: (task) => this.trackBackgroundTask(task),
|
|
596
|
+
backgroundEventTypes: AgentHarnessRuntime.BACKGROUND_EVENT_TYPES,
|
|
597
|
+
}, threadId, runId, checkpointRef, input, interruptContent);
|
|
832
598
|
}
|
|
833
599
|
async resolveApprovalRecord(options, thread) {
|
|
834
|
-
|
|
835
|
-
const approval = await this.persistence.getApproval(options.approvalId);
|
|
836
|
-
if (!approval) {
|
|
837
|
-
throw new Error(`Unknown approval ${options.approvalId}`);
|
|
838
|
-
}
|
|
839
|
-
return approval;
|
|
840
|
-
}
|
|
841
|
-
const runId = options.runId ?? thread.latestRunId;
|
|
842
|
-
const approvals = await this.persistence.getRunApprovals(options.threadId ?? thread.threadId, runId);
|
|
843
|
-
const approval = approvals
|
|
844
|
-
.filter((candidate) => candidate.status === "pending")
|
|
845
|
-
.sort((left, right) => right.requestedAt.localeCompare(left.requestedAt))[0];
|
|
846
|
-
if (!approval) {
|
|
847
|
-
throw new Error(`No pending approval for run ${runId}`);
|
|
848
|
-
}
|
|
849
|
-
return approval;
|
|
600
|
+
return resolveHarnessApprovalRecord(this.persistence, options, thread);
|
|
850
601
|
}
|
|
851
602
|
isDecisionRun(options) {
|
|
852
603
|
return "decision" in options;
|
|
@@ -926,7 +677,7 @@ export class AgentHarnessRuntime {
|
|
|
926
677
|
released = true;
|
|
927
678
|
await releaseLease();
|
|
928
679
|
this.activeRunSlots = Math.max(0, this.activeRunSlots - 1);
|
|
929
|
-
const next = this.pendingRunSlots
|
|
680
|
+
const next = shiftNextPendingRunSlot(this.pendingRunSlots);
|
|
930
681
|
void next?.activate();
|
|
931
682
|
};
|
|
932
683
|
}
|
|
@@ -1008,81 +759,18 @@ export class AgentHarnessRuntime {
|
|
|
1008
759
|
released = true;
|
|
1009
760
|
await releaseLease();
|
|
1010
761
|
this.activeRunSlots = Math.max(0, this.activeRunSlots - 1);
|
|
1011
|
-
const next = this.pendingRunSlots
|
|
762
|
+
const next = shiftNextPendingRunSlot(this.pendingRunSlots);
|
|
1012
763
|
void next?.activate();
|
|
1013
764
|
};
|
|
1014
765
|
}
|
|
1015
766
|
dropPendingRunSlot(runId) {
|
|
1016
|
-
|
|
1017
|
-
if (index < 0) {
|
|
1018
|
-
return false;
|
|
1019
|
-
}
|
|
1020
|
-
const [entry] = this.pendingRunSlots.splice(index, 1);
|
|
1021
|
-
entry?.abort();
|
|
1022
|
-
return true;
|
|
767
|
+
return dropPendingRunSlot(this.pendingRunSlots, runId);
|
|
1023
768
|
}
|
|
1024
769
|
async dispatchRunListeners(stream, listeners) {
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
if (item.type === "event") {
|
|
1030
|
-
latestEvent = item.event;
|
|
1031
|
-
await this.notifyListener(listeners.onEvent, item.event);
|
|
1032
|
-
continue;
|
|
1033
|
-
}
|
|
1034
|
-
if (item.type === "result") {
|
|
1035
|
-
latestResult = item.result;
|
|
1036
|
-
continue;
|
|
1037
|
-
}
|
|
1038
|
-
if (item.type === "content") {
|
|
1039
|
-
output += item.content;
|
|
1040
|
-
await this.notifyListener(listeners.onChunk, item.content);
|
|
1041
|
-
continue;
|
|
1042
|
-
}
|
|
1043
|
-
if (item.type === "content-blocks") {
|
|
1044
|
-
await this.notifyListener(listeners.onContentBlocks, item.contentBlocks);
|
|
1045
|
-
continue;
|
|
1046
|
-
}
|
|
1047
|
-
if (item.type === "reasoning") {
|
|
1048
|
-
await this.notifyListener(listeners.onReasoning, item.content);
|
|
1049
|
-
continue;
|
|
1050
|
-
}
|
|
1051
|
-
if (item.type === "step") {
|
|
1052
|
-
await this.notifyListener(listeners.onStep, item.content);
|
|
1053
|
-
continue;
|
|
1054
|
-
}
|
|
1055
|
-
if (item.type === "tool-result") {
|
|
1056
|
-
await this.notifyListener(listeners.onToolResult, {
|
|
1057
|
-
toolName: item.toolName,
|
|
1058
|
-
output: item.output,
|
|
1059
|
-
isError: item.isError,
|
|
1060
|
-
});
|
|
1061
|
-
}
|
|
1062
|
-
}
|
|
1063
|
-
if (!latestEvent) {
|
|
1064
|
-
throw new Error("run did not emit any events");
|
|
1065
|
-
}
|
|
1066
|
-
if (latestResult) {
|
|
1067
|
-
return {
|
|
1068
|
-
...latestResult,
|
|
1069
|
-
output: latestResult.output || output,
|
|
1070
|
-
finalMessageText: latestResult.finalMessageText ?? latestResult.output ?? output,
|
|
1071
|
-
};
|
|
1072
|
-
}
|
|
1073
|
-
const thread = await this.getThread(latestEvent.threadId);
|
|
1074
|
-
if (!thread) {
|
|
1075
|
-
throw new Error(`Unknown thread ${latestEvent.threadId}`);
|
|
1076
|
-
}
|
|
1077
|
-
return {
|
|
1078
|
-
threadId: thread.threadId,
|
|
1079
|
-
runId: thread.latestRunId,
|
|
1080
|
-
agentId: thread.runs[0]?.agentId ?? thread.entryAgentId,
|
|
1081
|
-
state: thread.currentState,
|
|
1082
|
-
output,
|
|
1083
|
-
approvalId: thread.pendingDecision?.approvalId,
|
|
1084
|
-
pendingActionId: thread.pendingDecision?.pendingActionId,
|
|
1085
|
-
};
|
|
770
|
+
return dispatchStreamingRunListeners(stream, listeners, {
|
|
771
|
+
notifyListener: (listener, value) => this.notifyListener(listener, value),
|
|
772
|
+
getThread: (threadId) => this.getThread(threadId),
|
|
773
|
+
});
|
|
1086
774
|
}
|
|
1087
775
|
async run(options) {
|
|
1088
776
|
if (this.isDecisionRun(options)) {
|
|
@@ -1095,11 +783,19 @@ export class AgentHarnessRuntime {
|
|
|
1095
783
|
};
|
|
1096
784
|
return this.resume(resumeOptions);
|
|
1097
785
|
}
|
|
1098
|
-
|
|
1099
|
-
|
|
786
|
+
const resolvedListeners = resolveRunListeners(options);
|
|
787
|
+
if (resolvedListeners) {
|
|
788
|
+
return this.dispatchRunListeners(this.streamEvents(options), resolvedListeners);
|
|
1100
789
|
}
|
|
1101
|
-
const invocation =
|
|
1102
|
-
const selectedAgentId = await
|
|
790
|
+
const invocation = normalizeInvocationEnvelope(options);
|
|
791
|
+
const selectedAgentId = await resolveSelectedAgentId({
|
|
792
|
+
workspace: this.workspace,
|
|
793
|
+
input: options.input,
|
|
794
|
+
requestedAgentId: options.agentId,
|
|
795
|
+
threadId: options.threadId,
|
|
796
|
+
preferredHostAgentId: AgentHarnessRuntime.DEFAULT_HOST_AGENT_ID,
|
|
797
|
+
getThreadSummary: (threadId) => this.getSession(threadId),
|
|
798
|
+
});
|
|
1103
799
|
const binding = this.workspace.bindings.get(selectedAgentId);
|
|
1104
800
|
if (!binding) {
|
|
1105
801
|
throw new Error(`Unknown agent ${selectedAgentId}`);
|
|
@@ -1108,8 +804,8 @@ export class AgentHarnessRuntime {
|
|
|
1108
804
|
if (!policyDecision.allowed) {
|
|
1109
805
|
throw new Error(`Policy evaluation blocked agent ${selectedAgentId}: ${policyDecision.reasons.join(", ")}`);
|
|
1110
806
|
}
|
|
1111
|
-
const priority =
|
|
1112
|
-
const runRequest =
|
|
807
|
+
const priority = normalizeRunPriority(options.priority);
|
|
808
|
+
const runRequest = buildPersistedRunRequest(options.input, invocation, priority);
|
|
1113
809
|
const { threadId, runId, isNewThread } = await this.ensureThreadStarted(selectedAgentId, binding, options.input, runRequest, options.threadId);
|
|
1114
810
|
const runCreatedEventPromise = this.emitRunCreated(threadId, runId, {
|
|
1115
811
|
agentId: binding.agent.id,
|
|
@@ -1136,8 +832,15 @@ export class AgentHarnessRuntime {
|
|
|
1136
832
|
}
|
|
1137
833
|
}
|
|
1138
834
|
async *streamEvents(options) {
|
|
1139
|
-
const invocation =
|
|
1140
|
-
const selectedAgentId = await
|
|
835
|
+
const invocation = normalizeInvocationEnvelope(options);
|
|
836
|
+
const selectedAgentId = await resolveSelectedAgentId({
|
|
837
|
+
workspace: this.workspace,
|
|
838
|
+
input: options.input,
|
|
839
|
+
requestedAgentId: options.agentId,
|
|
840
|
+
threadId: options.threadId,
|
|
841
|
+
preferredHostAgentId: AgentHarnessRuntime.DEFAULT_HOST_AGENT_ID,
|
|
842
|
+
getThreadSummary: (threadId) => this.getSession(threadId),
|
|
843
|
+
});
|
|
1141
844
|
const binding = this.workspace.bindings.get(selectedAgentId);
|
|
1142
845
|
if (!binding) {
|
|
1143
846
|
const result = await this.run(options);
|
|
@@ -1154,8 +857,8 @@ export class AgentHarnessRuntime {
|
|
|
1154
857
|
}
|
|
1155
858
|
let emitted = false;
|
|
1156
859
|
let streamActivityObserved = false;
|
|
1157
|
-
const priority =
|
|
1158
|
-
const runRequest =
|
|
860
|
+
const priority = normalizeRunPriority(options.priority);
|
|
861
|
+
const runRequest = buildPersistedRunRequest(options.input, invocation, priority);
|
|
1159
862
|
const { threadId, runId, isNewThread } = await this.ensureThreadStarted(selectedAgentId, binding, options.input, runRequest, options.threadId);
|
|
1160
863
|
const priorHistoryPromise = Promise.resolve(isNewThread ? [] : undefined).then((historyHint) => historyHint ?? this.loadPriorHistory(threadId, runId));
|
|
1161
864
|
const runCreatedEventPromise = this.emitRunCreated(threadId, runId, {
|
|
@@ -1191,6 +894,18 @@ export class AgentHarnessRuntime {
|
|
|
1191
894
|
? { kind: "interrupt", content: chunk.slice(AGENT_INTERRUPT_SENTINEL_PREFIX.length) }
|
|
1192
895
|
: { kind: "content", content: chunk }
|
|
1193
896
|
: chunk;
|
|
897
|
+
if (normalizedChunk.kind === "upstream-event") {
|
|
898
|
+
yield {
|
|
899
|
+
type: "upstream-event",
|
|
900
|
+
threadId,
|
|
901
|
+
runId,
|
|
902
|
+
agentId: selectedAgentId,
|
|
903
|
+
event: normalizedChunk.event.format === "langgraph-v2"
|
|
904
|
+
? normalizedChunk.event
|
|
905
|
+
: normalizeUpstreamRuntimeEvent(normalizedChunk.event.raw ?? normalizedChunk.event),
|
|
906
|
+
};
|
|
907
|
+
continue;
|
|
908
|
+
}
|
|
1194
909
|
if (normalizedChunk.kind === "interrupt") {
|
|
1195
910
|
const checkpointRef = `checkpoints/${threadId}/${runId}/cp-1`;
|
|
1196
911
|
const waitingEvent = await this.setRunStateAndEmit(threadId, runId, 6, "waiting_for_approval", {
|
|
@@ -1490,41 +1205,7 @@ export class AgentHarnessRuntime {
|
|
|
1490
1205
|
}
|
|
1491
1206
|
}
|
|
1492
1207
|
buildResumePayload(binding, approval, options) {
|
|
1493
|
-
|
|
1494
|
-
return options.decision === "edit" && options.editedInput
|
|
1495
|
-
? { decision: "edit", editedInput: options.editedInput }
|
|
1496
|
-
: (options.decision ?? "approve");
|
|
1497
|
-
}
|
|
1498
|
-
const decisionType = options.decision ?? "approve";
|
|
1499
|
-
if (decisionType === "edit" && options.editedInput) {
|
|
1500
|
-
return {
|
|
1501
|
-
decisions: [
|
|
1502
|
-
{
|
|
1503
|
-
type: "edit",
|
|
1504
|
-
editedAction: {
|
|
1505
|
-
name: approval.toolName,
|
|
1506
|
-
args: options.editedInput,
|
|
1507
|
-
},
|
|
1508
|
-
},
|
|
1509
|
-
],
|
|
1510
|
-
};
|
|
1511
|
-
}
|
|
1512
|
-
if (decisionType === "reject") {
|
|
1513
|
-
return {
|
|
1514
|
-
decisions: [
|
|
1515
|
-
{
|
|
1516
|
-
type: "reject",
|
|
1517
|
-
},
|
|
1518
|
-
],
|
|
1519
|
-
};
|
|
1520
|
-
}
|
|
1521
|
-
return {
|
|
1522
|
-
decisions: [
|
|
1523
|
-
{
|
|
1524
|
-
type: "approve",
|
|
1525
|
-
},
|
|
1526
|
-
],
|
|
1527
|
-
};
|
|
1208
|
+
return buildHarnessResumePayload(binding, approval, options);
|
|
1528
1209
|
}
|
|
1529
1210
|
async restartConversation(options) {
|
|
1530
1211
|
const thread = await this.getSession(options.threadId);
|
|
@@ -1567,7 +1248,7 @@ export class AgentHarnessRuntime {
|
|
|
1567
1248
|
if (!run) {
|
|
1568
1249
|
throw new Error(`Unknown run ${options.runId}`);
|
|
1569
1250
|
}
|
|
1570
|
-
if (
|
|
1251
|
+
if (isTerminalRunState(run.state)) {
|
|
1571
1252
|
return {
|
|
1572
1253
|
threadId: run.threadId,
|
|
1573
1254
|
runId: run.runId,
|
|
@@ -1616,7 +1297,7 @@ export class AgentHarnessRuntime {
|
|
|
1616
1297
|
});
|
|
1617
1298
|
continue;
|
|
1618
1299
|
}
|
|
1619
|
-
const releaseRunSlot = await this.acquireRunSlot(thread.threadId, thread.latestRunId, "running",
|
|
1300
|
+
const releaseRunSlot = await this.acquireRunSlot(thread.threadId, thread.latestRunId, "running", normalizeRunPriority(request.priority));
|
|
1620
1301
|
try {
|
|
1621
1302
|
await this.executeQueuedRun(binding, request.input, thread.threadId, thread.latestRunId, runMeta.agentId, {
|
|
1622
1303
|
context: request.invocation?.context,
|
|
@@ -1659,7 +1340,7 @@ export class AgentHarnessRuntime {
|
|
|
1659
1340
|
await this.persistence.releaseRunClaim(thread.latestRunId);
|
|
1660
1341
|
continue;
|
|
1661
1342
|
}
|
|
1662
|
-
const releaseRunSlot = await this.acquireRunSlot(thread.threadId, thread.latestRunId, "running",
|
|
1343
|
+
const releaseRunSlot = await this.acquireRunSlot(thread.threadId, thread.latestRunId, "running", normalizeRunPriority(request.priority));
|
|
1663
1344
|
try {
|
|
1664
1345
|
await this.emit(thread.threadId, thread.latestRunId, 100, "run.resumed", {
|
|
1665
1346
|
resumeKind: "startup-running-recovery",
|