@botbotgo/agent-harness 0.0.102 → 0.0.103
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/runtime/adapter/middleware-assembly.d.ts +75 -0
- package/dist/runtime/adapter/middleware-assembly.js +175 -0
- package/dist/runtime/adapter/runtime-shell.d.ts +27 -0
- package/dist/runtime/adapter/runtime-shell.js +168 -0
- package/dist/runtime/adapter/tool-resolution.d.ts +14 -0
- package/dist/runtime/adapter/tool-resolution.js +57 -0
- package/dist/runtime/agent-runtime-adapter.d.ts +1 -6
- package/dist/runtime/agent-runtime-adapter.js +76 -356
- package/dist/runtime/harness/run/startup-runtime.d.ts +37 -0
- package/dist/runtime/harness/run/startup-runtime.js +68 -0
- package/dist/runtime/harness/run/thread-records.d.ts +21 -0
- package/dist/runtime/harness/run/thread-records.js +59 -0
- package/dist/runtime/harness.js +42 -111
- package/package.json +1 -1
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { isTerminalRunState, toPublicApprovalRecord } from "./helpers.js";
|
|
2
|
+
export async function getThreadRecord(input, threadId) {
|
|
3
|
+
const [threadSummary, meta, messages, runs] = await Promise.all([
|
|
4
|
+
input.getSession(threadId),
|
|
5
|
+
input.persistence.getThreadMeta(threadId),
|
|
6
|
+
input.persistence.listThreadMessages(threadId, 200),
|
|
7
|
+
input.persistence.listThreadRuns(threadId),
|
|
8
|
+
]);
|
|
9
|
+
if (!threadSummary || !meta) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
const latestRunId = threadSummary.latestRunId;
|
|
13
|
+
const latestApprovals = await input.persistence.getRunApprovals(threadId, latestRunId);
|
|
14
|
+
const pendingApproval = latestApprovals
|
|
15
|
+
.filter((approval) => approval.status === "pending")
|
|
16
|
+
.sort((left, right) => right.requestedAt.localeCompare(left.requestedAt))[0];
|
|
17
|
+
return {
|
|
18
|
+
threadId,
|
|
19
|
+
entryAgentId: meta.entryAgentId,
|
|
20
|
+
currentState: threadSummary.status,
|
|
21
|
+
latestRunId,
|
|
22
|
+
createdAt: meta.createdAt,
|
|
23
|
+
updatedAt: threadSummary.updatedAt,
|
|
24
|
+
messages,
|
|
25
|
+
runs,
|
|
26
|
+
pendingDecision: pendingApproval
|
|
27
|
+
? {
|
|
28
|
+
approvalId: pendingApproval.approvalId,
|
|
29
|
+
pendingActionId: pendingApproval.pendingActionId,
|
|
30
|
+
toolName: pendingApproval.toolName,
|
|
31
|
+
allowedDecisions: pendingApproval.allowedDecisions,
|
|
32
|
+
requestedAt: pendingApproval.requestedAt,
|
|
33
|
+
}
|
|
34
|
+
: undefined,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export async function listPublicApprovals(input, filter) {
|
|
38
|
+
const approvals = await input.persistence.listApprovals(filter);
|
|
39
|
+
return approvals.map((approval) => toPublicApprovalRecord(approval));
|
|
40
|
+
}
|
|
41
|
+
export async function getPublicApproval(input, approvalId) {
|
|
42
|
+
const approval = await input.persistence.getApproval(approvalId);
|
|
43
|
+
return approval ? toPublicApprovalRecord(approval) : null;
|
|
44
|
+
}
|
|
45
|
+
export async function deleteThreadRecord(input, threadId) {
|
|
46
|
+
const thread = await input.getThread(threadId);
|
|
47
|
+
if (!thread) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
const activeRun = thread.runs.find((run) => !isTerminalRunState(run.state));
|
|
51
|
+
if (activeRun) {
|
|
52
|
+
throw new Error(`Cannot delete thread ${threadId} while run ${activeRun.runId} is ${activeRun.state}`);
|
|
53
|
+
}
|
|
54
|
+
const deleted = await input.deleteThread(threadId);
|
|
55
|
+
if (deleted) {
|
|
56
|
+
await input.deleteThreadCheckpoints(threadId);
|
|
57
|
+
}
|
|
58
|
+
return deleted;
|
|
59
|
+
}
|
package/dist/runtime/harness.js
CHANGED
|
@@ -14,7 +14,7 @@ import { RuntimeRecordMaintenanceLoop, discoverRuntimeRecordMaintenanceTargets,
|
|
|
14
14
|
import { HealthMonitor } from "./harness/system/health-monitor.js";
|
|
15
15
|
import { readHealthMonitorConfig } from "./harness/system/health-monitor.js";
|
|
16
16
|
import { extractMessageText, normalizeMessageContent } from "../utils/message-content.js";
|
|
17
|
-
import { buildPersistedRunRequest,
|
|
17
|
+
import { buildPersistedRunRequest, normalizeInvocationEnvelope, normalizeRunPriority, resolveRunListeners, } from "./harness/run/helpers.js";
|
|
18
18
|
import { emitHarnessEvent, emitRunCreatedEvent, emitSyntheticFallbackEvent, requestApprovalAndEmitEvent, setRunStateAndEmitEvent, } from "./harness/events/events.js";
|
|
19
19
|
import { appendAssistantMessage as appendLifecycleAssistantMessage, finalizeCancelledRun as finalizeLifecycleCancelledRun, finalizeContinuedRun as finalizeLifecycleContinuedRun, } from "./harness/run/run-lifecycle.js";
|
|
20
20
|
import { dispatchRunListeners as dispatchStreamingRunListeners, } from "./harness/events/streaming.js";
|
|
@@ -29,8 +29,9 @@ import { getBindingAdapterKind, getBindingPrimaryTools, getBindingStoreConfig }
|
|
|
29
29
|
import { isRuntimeEntryBinding } from "./support/runtime-entry.js";
|
|
30
30
|
import { describeWorkspaceInventory, listAgentSkills as listWorkspaceAgentSkills, } from "./harness/system/inventory.js";
|
|
31
31
|
import { createDefaultHealthSnapshot, isInventoryEnabled, isThreadMemorySyncEnabled, } from "./harness/runtime-defaults.js";
|
|
32
|
-
import {
|
|
32
|
+
import { initializeHarnessRuntime, isStaleRunningRun as isHarnessStaleRunningRun, reclaimExpiredClaimedRuns as reclaimHarnessExpiredClaimedRuns, recoverStartupRuns as recoverHarnessStartupRuns, } from "./harness/run/startup-runtime.js";
|
|
33
33
|
import { streamHarnessRun } from "./harness/run/stream-run.js";
|
|
34
|
+
import { deleteThreadRecord, getPublicApproval, getThreadRecord, listPublicApprovals, } from "./harness/run/thread-records.js";
|
|
34
35
|
export class AgentHarnessRuntime {
|
|
35
36
|
workspace;
|
|
36
37
|
runtimeAdapterOptions;
|
|
@@ -159,11 +160,13 @@ export class AgentHarnessRuntime {
|
|
|
159
160
|
this.healthMonitor?.recordLlmFailure(Date.now() - startedAt);
|
|
160
161
|
}
|
|
161
162
|
async initialize() {
|
|
162
|
-
await
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
163
|
+
await initializeHarnessRuntime({
|
|
164
|
+
persistence: this.persistence,
|
|
165
|
+
checkpointMaintenance: this.checkpointMaintenance,
|
|
166
|
+
runtimeRecordMaintenance: this.runtimeRecordMaintenance,
|
|
167
|
+
healthMonitor: this.healthMonitor,
|
|
168
|
+
recoverStartupRuns: () => this.recoverStartupRuns(),
|
|
169
|
+
});
|
|
167
170
|
}
|
|
168
171
|
subscribe(listener) {
|
|
169
172
|
return this.eventBus.subscribe(listener);
|
|
@@ -204,47 +207,20 @@ export class AgentHarnessRuntime {
|
|
|
204
207
|
return this.persistence.getSession(threadId);
|
|
205
208
|
}
|
|
206
209
|
async getThread(threadId) {
|
|
207
|
-
|
|
208
|
-
this.
|
|
209
|
-
this.
|
|
210
|
-
|
|
211
|
-
this.persistence.listThreadRuns(threadId),
|
|
212
|
-
]);
|
|
213
|
-
if (!threadSummary || !meta) {
|
|
214
|
-
return null;
|
|
215
|
-
}
|
|
216
|
-
const latestRunId = threadSummary.latestRunId;
|
|
217
|
-
const latestApprovals = await this.persistence.getRunApprovals(threadId, latestRunId);
|
|
218
|
-
const pendingApproval = latestApprovals
|
|
219
|
-
.filter((approval) => approval.status === "pending")
|
|
220
|
-
.sort((left, right) => right.requestedAt.localeCompare(left.requestedAt))[0];
|
|
221
|
-
return {
|
|
222
|
-
threadId,
|
|
223
|
-
entryAgentId: meta.entryAgentId,
|
|
224
|
-
currentState: threadSummary.status,
|
|
225
|
-
latestRunId,
|
|
226
|
-
createdAt: meta.createdAt,
|
|
227
|
-
updatedAt: threadSummary.updatedAt,
|
|
228
|
-
messages,
|
|
229
|
-
runs,
|
|
230
|
-
pendingDecision: pendingApproval
|
|
231
|
-
? {
|
|
232
|
-
approvalId: pendingApproval.approvalId,
|
|
233
|
-
pendingActionId: pendingApproval.pendingActionId,
|
|
234
|
-
toolName: pendingApproval.toolName,
|
|
235
|
-
allowedDecisions: pendingApproval.allowedDecisions,
|
|
236
|
-
requestedAt: pendingApproval.requestedAt,
|
|
237
|
-
}
|
|
238
|
-
: undefined,
|
|
239
|
-
};
|
|
210
|
+
return getThreadRecord({
|
|
211
|
+
persistence: this.persistence,
|
|
212
|
+
getSession: (currentThreadId) => this.getSession(currentThreadId),
|
|
213
|
+
}, threadId);
|
|
240
214
|
}
|
|
241
215
|
async listApprovals(filter) {
|
|
242
|
-
|
|
243
|
-
|
|
216
|
+
return listPublicApprovals({
|
|
217
|
+
persistence: this.persistence,
|
|
218
|
+
}, filter);
|
|
244
219
|
}
|
|
245
220
|
async getApproval(approvalId) {
|
|
246
|
-
|
|
247
|
-
|
|
221
|
+
return getPublicApproval({
|
|
222
|
+
persistence: this.persistence,
|
|
223
|
+
}, approvalId);
|
|
248
224
|
}
|
|
249
225
|
listAgentSkills(agentId, options = {}) {
|
|
250
226
|
return listWorkspaceAgentSkills(this.workspace, agentId, {
|
|
@@ -277,19 +253,11 @@ export class AgentHarnessRuntime {
|
|
|
277
253
|
}
|
|
278
254
|
}
|
|
279
255
|
async deleteThread(threadId) {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
if (activeRun) {
|
|
286
|
-
throw new Error(`Cannot delete thread ${threadId} while run ${activeRun.runId} is ${activeRun.state}`);
|
|
287
|
-
}
|
|
288
|
-
const deleted = await this.persistence.deleteThread(threadId);
|
|
289
|
-
if (deleted) {
|
|
290
|
-
await this.deleteThreadCheckpoints(threadId);
|
|
291
|
-
}
|
|
292
|
-
return deleted;
|
|
256
|
+
return deleteThreadRecord({
|
|
257
|
+
getThread: (currentThreadId) => this.getThread(currentThreadId),
|
|
258
|
+
deleteThread: (currentThreadId) => this.persistence.deleteThread(currentThreadId),
|
|
259
|
+
deleteThreadCheckpoints: (currentThreadId) => this.deleteThreadCheckpoints(currentThreadId),
|
|
260
|
+
}, threadId);
|
|
293
261
|
}
|
|
294
262
|
async createToolMcpServer(options) {
|
|
295
263
|
const tools = this.resolveAgentTools(options.agentId).map(({ compiledTool, resolvedTool }) => ({
|
|
@@ -771,63 +739,26 @@ export class AgentHarnessRuntime {
|
|
|
771
739
|
}, options);
|
|
772
740
|
}
|
|
773
741
|
async recoverStartupRuns() {
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
for (const thread of threads) {
|
|
781
|
-
const handled = await recoverQueuedStartupRun(recoveryContext, thread) ||
|
|
782
|
-
await recoverRunningStartupRun(recoveryContext, thread) ||
|
|
783
|
-
await recoverResumingStartupRun(recoveryContext, thread);
|
|
784
|
-
if (handled) {
|
|
785
|
-
continue;
|
|
786
|
-
}
|
|
787
|
-
}
|
|
742
|
+
await recoverHarnessStartupRuns({
|
|
743
|
+
recoveryConfig: this.recoveryConfig,
|
|
744
|
+
persistence: this.persistence,
|
|
745
|
+
createStartupRecoveryContext: () => this.createStartupRecoveryContext(),
|
|
746
|
+
reclaimExpiredClaimedRuns: (nowIso) => this.reclaimExpiredClaimedRuns(nowIso),
|
|
747
|
+
});
|
|
788
748
|
}
|
|
789
749
|
async reclaimExpiredClaimedRuns(nowIso = new Date().toISOString()) {
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
const lifecycle = await this.persistence.getRunLifecycle(claim.threadId, claim.runId);
|
|
798
|
-
if (lifecycle.state === "claimed") {
|
|
799
|
-
await this.persistence.enqueueRun({
|
|
800
|
-
threadId: claim.threadId,
|
|
801
|
-
runId: claim.runId,
|
|
802
|
-
priority: claim.priority,
|
|
803
|
-
queueKey: claim.queueKey,
|
|
804
|
-
availableAt: nowIso,
|
|
805
|
-
});
|
|
806
|
-
await this.setRunStateAndEmit(claim.threadId, claim.runId, 99, "queued", {
|
|
807
|
-
previousState: "claimed",
|
|
808
|
-
});
|
|
809
|
-
await this.emit(claim.threadId, claim.runId, 100, "run.queued", {
|
|
810
|
-
queuePosition: 0,
|
|
811
|
-
activeRunCount: this.activeRunSlots,
|
|
812
|
-
maxConcurrentRuns: this.concurrencyConfig.maxConcurrentRuns,
|
|
813
|
-
recoveredOnStartup: true,
|
|
814
|
-
reclaimReason: "expired-lease",
|
|
815
|
-
});
|
|
816
|
-
continue;
|
|
817
|
-
}
|
|
818
|
-
await this.persistence.releaseRunClaim(claim.runId);
|
|
819
|
-
}
|
|
750
|
+
await reclaimHarnessExpiredClaimedRuns({
|
|
751
|
+
persistence: this.persistence,
|
|
752
|
+
setRunStateAndEmit: (threadId, runId, sequence, state, options) => this.setRunStateAndEmit(threadId, runId, sequence, state, options),
|
|
753
|
+
emit: (threadId, runId, sequence, eventType, payload) => this.emit(threadId, runId, sequence, eventType, payload),
|
|
754
|
+
concurrencyConfig: this.concurrencyConfig,
|
|
755
|
+
getActiveRunSlots: () => this.activeRunSlots,
|
|
756
|
+
}, nowIso);
|
|
820
757
|
}
|
|
821
758
|
async isStaleRunningRun(thread, nowMs = Date.now()) {
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
}
|
|
827
|
-
const heartbeatAtMs = Date.parse(heartbeatAt);
|
|
828
|
-
if (!Number.isFinite(heartbeatAtMs)) {
|
|
829
|
-
return true;
|
|
830
|
-
}
|
|
831
|
-
return nowMs - heartbeatAtMs >= this.concurrencyConfig.heartbeatTimeoutMs;
|
|
759
|
+
return isHarnessStaleRunningRun({
|
|
760
|
+
persistence: this.persistence,
|
|
761
|
+
concurrencyConfig: this.concurrencyConfig,
|
|
762
|
+
}, thread, nowMs);
|
|
832
763
|
}
|
|
833
764
|
}
|