@yielded/agent 0.1.0-beta.173 → 0.1.0-beta.175
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/{Admin-BX9ns28E.d.mts → Admin-Qa3I1oA5.d.mts} +61 -21
- package/dist/{Agent-9aBoIi74.d.mts → Agent-B39jRnFv.d.mts} +2 -2
- package/dist/{Agent-0WvBWWbM.mjs → Agent-BiRbr73L.mjs} +7 -6
- package/dist/Agent-BiRbr73L.mjs.map +1 -0
- package/dist/{AgentRuntime-BfP14534.d.mts → AgentRuntime-CHDyRbSf.d.mts} +12 -12
- package/dist/{AgentRuntime-CQ-qcETl.mjs → AgentRuntime-DaDKMasp.mjs} +290 -273
- package/dist/AgentRuntime-DaDKMasp.mjs.map +1 -0
- package/dist/{Digest-DCuPlhNk.mjs → Digest-C3EODOee.mjs} +42 -15
- package/dist/Digest-C3EODOee.mjs.map +1 -0
- package/dist/{DurableAgentRuntime-BAmSkWYr.mjs → DurableAgentRuntime-CPlw5_7e.mjs} +1557 -1458
- package/dist/DurableAgentRuntime-CPlw5_7e.mjs.map +1 -0
- package/dist/{EventSource-BwliwQz9.d.mts → EventSource-BTu68yDW.d.mts} +2 -2
- package/dist/InMemory.d.mts +2 -2
- package/dist/{MessageDelivery-B943ebI_.d.mts → MessageDelivery-DjAZJ4Fd.d.mts} +42 -42
- package/dist/{Messaging-C_6OOg_s.d.mts → Messaging-SVu6rWV8.d.mts} +12 -6
- package/dist/{MessagingHost-B8oKM7AC.d.mts → MessagingHost-C6SOAcoG.d.mts} +2 -2
- package/dist/{MessagingHost-CRUK4JBi.mjs → MessagingHost-CZCyrnvJ.mjs} +27 -26
- package/dist/MessagingHost-CZCyrnvJ.mjs.map +1 -0
- package/dist/{Output-Dsx6k52t.d.mts → Output-CRamN1Fy.d.mts} +2 -2
- package/dist/{PreparedInputAdmission-CxSJSiTl.d.mts → PreparedInputAdmission-wgY4JMZY.d.mts} +3 -3
- package/dist/{Records-BiuJDWNe.mjs → Records-DzL4Kbtw.mjs} +2 -2
- package/dist/{Records-BiuJDWNe.mjs.map → Records-DzL4Kbtw.mjs.map} +1 -1
- package/dist/{RunContinuation-FHM7XPjq.d.mts → RunContinuation-3jB5pULC.d.mts} +13 -7
- package/dist/{RunContinuation-DHYNAQFi.mjs → RunContinuation-BiyKJK32.mjs} +173 -82
- package/dist/RunContinuation-BiyKJK32.mjs.map +1 -0
- package/dist/{RunJournal-kfKVxJj7.mjs → RunJournal-CPMKcfd0.mjs} +106 -73
- package/dist/RunJournal-CPMKcfd0.mjs.map +1 -0
- package/dist/{RunOptions-D8zxFIrZ.d.mts → RunOptions-Be77lKVZ.d.mts} +2 -2
- package/dist/{RunStorage-uqPxps09.mjs → RunStorage-CzutHJBE.mjs} +10 -6
- package/dist/RunStorage-CzutHJBE.mjs.map +1 -0
- package/dist/{Scheduling-CVyfXlBR.mjs → Scheduling-07_dsGED.mjs} +12 -12
- package/dist/Scheduling-07_dsGED.mjs.map +1 -0
- package/dist/{Subagent-vpffemql.mjs → Subagent-CexndZSp.mjs} +53 -40
- package/dist/Subagent-CexndZSp.mjs.map +1 -0
- package/dist/{Subagent-E6tvd7-k.d.mts → Subagent-xhN_aD1r.d.mts} +20 -9
- package/dist/{SubagentHost-B6w2m-SI.d.mts → SubagentHost-D1xBgn9g.d.mts} +2 -2
- package/dist/{Subscription-DONig54Q.d.mts → Subscription-DmIHlOJK.d.mts} +2 -2
- package/dist/{SubscriptionInput-mJIRxWJM.d.mts → SubscriptionInput-DgcQhvbe.d.mts} +2 -2
- package/dist/{Thread-dk-QiNml.d.mts → Thread-DzdJAY4J.d.mts} +4 -3
- package/dist/{ThreadHistory-ByxS8HU1.d.mts → ThreadHistory-KPPBJLJb.d.mts} +12 -2
- package/dist/{ThreadImport-DckUMEqJ.mjs → ThreadImport-CjlG57vH.mjs} +9 -9
- package/dist/ThreadImport-CjlG57vH.mjs.map +1 -0
- package/dist/{ThreadImport-DpHxjBrA.d.mts → ThreadImport-DP-vOk2F.d.mts} +5 -5
- package/dist/{ThreadStore-CEekRa80.mjs → ThreadStore-EuUilthA.mjs} +162 -85
- package/dist/ThreadStore-EuUilthA.mjs.map +1 -0
- package/dist/{ThreadTransfer-B4gTQLIl.mjs → ThreadTransfer-DB_zsrtJ.mjs} +4 -4
- package/dist/{ThreadTransfer-B4gTQLIl.mjs.map → ThreadTransfer-DB_zsrtJ.mjs.map} +1 -1
- package/dist/{WorkerAdmission-DFVbbVh2.mjs → WorkerAdmission-eBeXt_mu.mjs} +5 -5
- package/dist/{WorkerAdmission-DFVbbVh2.mjs.map → WorkerAdmission-eBeXt_mu.mjs.map} +1 -1
- package/dist/{agent-registration-ByMZ_cK5.mjs → agent-registration-a6QYaG3h.mjs} +70 -57
- package/dist/agent-registration-a6QYaG3h.mjs.map +1 -0
- package/dist/capabilities/Approval.mjs +2 -2
- package/dist/capabilities/Approval.mjs.map +1 -1
- package/dist/capabilities/BrowserUse.d.mts +102 -1867
- package/dist/capabilities/BrowserUse.mjs +74 -798
- package/dist/capabilities/BrowserUse.mjs.map +1 -1
- package/dist/capabilities/Budget.mjs +3 -1
- package/dist/capabilities/Budget.mjs.map +1 -1
- package/dist/capabilities/CodeMode.d.mts +1 -1
- package/dist/capabilities/CodeMode.mjs +16 -9
- package/dist/capabilities/CodeMode.mjs.map +1 -1
- package/dist/capabilities/Commands.d.mts +1 -1
- package/dist/capabilities/McpClient.mjs +1 -1
- package/dist/capabilities/McpClient.mjs.map +1 -1
- package/dist/capabilities/Messaging.d.mts +1 -1
- package/dist/capabilities/Messaging.mjs +5 -5
- package/dist/capabilities/Messaging.mjs.map +1 -1
- package/dist/capabilities/ModelContext.d.mts +1 -1
- package/dist/capabilities/ModelContext.mjs +7 -5
- package/dist/capabilities/ModelContext.mjs.map +1 -1
- package/dist/capabilities/Redaction.mjs +49 -19
- package/dist/capabilities/Redaction.mjs.map +1 -1
- package/dist/capabilities/RunHooks.d.mts +2 -2
- package/dist/capabilities/RunHooks.mjs +1 -1
- package/dist/capabilities/RunHooks.mjs.map +1 -1
- package/dist/capabilities/Subagent.d.mts +1 -1
- package/dist/capabilities/Subagent.mjs +1 -1
- package/dist/capabilities/SubagentReservations.mjs +3 -1
- package/dist/capabilities/SubagentReservations.mjs.map +1 -1
- package/dist/capabilities/WebCapture.mjs.map +1 -1
- package/dist/capabilities/WebSearch.mjs +7 -7
- package/dist/capabilities/WebSearch.mjs.map +1 -1
- package/dist/core/Agent.d.mts +1 -1
- package/dist/core/Agent.mjs +1 -1
- package/dist/core/AgentUpdates.mjs +8 -8
- package/dist/core/AgentUpdates.mjs.map +1 -1
- package/dist/core/Thread.d.mts +2 -2
- package/dist/core/Thread.mjs +6 -4
- package/dist/core/Thread.mjs.map +1 -1
- package/dist/core/Usage.mjs +2 -2
- package/dist/core/Usage.mjs.map +1 -1
- package/dist/durable/ActivityStore.mjs +1 -1
- package/dist/durable/Admin.d.mts +1 -1
- package/dist/durable/Admin.mjs +1 -1
- package/dist/durable/AgentRegistration.d.mts +1 -1
- package/dist/durable/AgentRegistration.mjs +1 -1
- package/dist/durable/Certification.d.mts +1 -1
- package/dist/durable/CommittedActivity.d.mts +1 -1
- package/dist/durable/CommittedActivity.mjs +3 -3
- package/dist/durable/Digest.mjs +1 -1
- package/dist/durable/DurableAgentRuntime.d.mts +1 -1
- package/dist/durable/DurableAgentRuntime.mjs +2 -2
- package/dist/durable/EventSource.d.mts +1 -1
- package/dist/durable/EventSource.mjs +7 -7
- package/dist/durable/EventSource.mjs.map +1 -1
- package/dist/durable/GitHubWorkflowSource.d.mts +3 -3
- package/dist/durable/LifecyclePublication.d.mts +1 -1
- package/dist/durable/LifecyclePublication.mjs +2 -2
- package/dist/durable/MessageDelivery.d.mts +1 -1
- package/dist/durable/MessageDelivery.mjs +2 -2
- package/dist/durable/MessageDeliveryStoreConformance.d.mts +40 -40
- package/dist/durable/MessageDeliveryStoreConformance.mjs +2 -2
- package/dist/durable/PersistentHistory.d.mts +2 -2
- package/dist/durable/PersistentHistory.mjs +4 -4
- package/dist/durable/PreparedInputAdmission.d.mts +1 -1
- package/dist/durable/RecordFormat.mjs +3 -3
- package/dist/durable/RecordFormat.mjs.map +1 -1
- package/dist/durable/Records.mjs +1 -1
- package/dist/durable/Recovery.d.mts +1 -1
- package/dist/durable/Recovery.mjs +1 -1
- package/dist/durable/RunContinuation.d.mts +2 -2
- package/dist/durable/RunContinuation.mjs +3 -3
- package/dist/durable/RunJournal.d.mts +2 -2
- package/dist/durable/RunJournal.mjs +2 -2
- package/dist/durable/RunStorage.d.mts +1 -1
- package/dist/durable/RunStorage.mjs +1 -1
- package/dist/durable/Schedule.mjs +1 -1
- package/dist/durable/ScheduleStoreConformance.mjs +1 -1
- package/dist/durable/ScheduleTransition.mjs +1 -1
- package/dist/durable/Scheduling.d.mts +1 -1
- package/dist/durable/Scheduling.mjs +1 -1
- package/dist/durable/SettlementPublisher.d.mts +1 -1
- package/dist/durable/SettlementPublisher.mjs +3 -3
- package/dist/durable/SqlMemoryStore.mjs +5 -3
- package/dist/durable/SqlMemoryStore.mjs.map +1 -1
- package/dist/durable/SubmissionLedger.d.mts +1 -1
- package/dist/durable/SubmissionLedger.mjs +11 -3
- package/dist/durable/SubmissionLedger.mjs.map +1 -1
- package/dist/durable/SubmissionLedgerConformance.d.mts +1 -1
- package/dist/durable/SubmissionLedgerConformance.mjs +6 -6
- package/dist/durable/SubmissionStatus.d.mts +1 -1
- package/dist/durable/Subscription.d.mts +1 -1
- package/dist/durable/Subscription.mjs +2 -2
- package/dist/durable/SubscriptionInput.d.mts +1 -1
- package/dist/durable/SubscriptionInput.mjs +4 -4
- package/dist/durable/SubscriptionInput.mjs.map +1 -1
- package/dist/durable/SubscriptionStoreConformance.d.mts +1 -1
- package/dist/durable/SubscriptionStoreConformance.mjs +3 -3
- package/dist/durable/SubscriptionStoreConformance.mjs.map +1 -1
- package/dist/durable/SubscriptionTools.d.mts +2 -2
- package/dist/durable/SubscriptionTransition.d.mts +1 -1
- package/dist/durable/SubscriptionTransition.mjs +1 -1
- package/dist/durable/Subscriptions.d.mts +5 -5
- package/dist/durable/Subscriptions.mjs +3 -3
- package/dist/durable/Subscriptions.mjs.map +1 -1
- package/dist/durable/ThreadArchiveRange.d.mts +1 -1
- package/dist/durable/ThreadArchiveRange.mjs +1 -1
- package/dist/durable/ThreadContextHistory.d.mts +1 -1
- package/dist/durable/ThreadContextHistory.mjs +2 -2
- package/dist/durable/ThreadContextHistoryProjection.mjs +1 -1
- package/dist/durable/ThreadImport.d.mts +1 -1
- package/dist/durable/ThreadImport.mjs +1 -1
- package/dist/durable/ThreadInvariants.d.mts +3 -3
- package/dist/durable/ThreadInvariants.mjs +5 -5
- package/dist/durable/ThreadInvariants.mjs.map +1 -1
- package/dist/durable/ThreadProjection.mjs +1 -1
- package/dist/durable/ThreadProjectionMaintenance.d.mts +1 -1
- package/dist/durable/ThreadReader.d.mts +1 -1
- package/dist/durable/ThreadReader.mjs +1 -1
- package/dist/durable/ThreadStore.d.mts +1 -1
- package/dist/durable/ThreadStore.mjs +2 -2
- package/dist/durable/ThreadStoreConformance.d.mts +1 -1
- package/dist/durable/ThreadStoreConformance.mjs +4 -4
- package/dist/durable/ThreadTransfer.d.mts +1 -1
- package/dist/durable/ThreadTransfer.mjs +1 -1
- package/dist/durable/ThreadWork.d.mts +2 -2
- package/dist/durable/ThreadWork.mjs +12 -6
- package/dist/durable/ThreadWork.mjs.map +1 -1
- package/dist/durable/ToolReconciler.mjs +1 -1
- package/dist/durable/WakeScheduler.mjs +23 -39
- package/dist/durable/WakeScheduler.mjs.map +1 -1
- package/dist/durable/WorkerAdmission.d.mts +1 -1
- package/dist/durable/WorkerAdmission.mjs +1 -1
- package/dist/durable/WorkerHost.d.mts +2 -2
- package/dist/engine/AgentRuntime.d.mts +1 -1
- package/dist/engine/AgentRuntime.mjs +1 -1
- package/dist/engine/MessagingHost.d.mts +1 -1
- package/dist/engine/MessagingHost.mjs +1 -1
- package/dist/engine/Output.d.mts +1 -1
- package/dist/engine/Output.mjs +1 -1
- package/dist/engine/RunOptions.d.mts +1 -1
- package/dist/engine/SubagentHost.d.mts +1 -1
- package/dist/engine/ThreadHistory.d.mts +1 -1
- package/dist/engine/ThreadHistory.mjs +3 -2
- package/dist/engine/ThreadHistory.mjs.map +1 -1
- package/dist/index.d.mts +21 -21
- package/dist/index.mjs +16 -16
- package/dist/{output-contract-CMIhu4Cw.mjs → output-contract-DCnLYCdp.mjs} +12 -15
- package/dist/{output-contract-CMIhu4Cw.mjs.map → output-contract-DCnLYCdp.mjs.map} +1 -1
- package/dist/{run-context-reader-OcsZr4bk.d.mts → run-context-reader-DVhJZ1Qe.d.mts} +2 -2
- package/package.json +1 -1
- package/src/capabilities/Approval.ts +58 -60
- package/src/capabilities/BrowserUse.ts +89 -944
- package/src/capabilities/Budget.ts +8 -1
- package/src/capabilities/CodeMode.ts +57 -33
- package/src/capabilities/McpClient.ts +2 -2
- package/src/capabilities/Messaging.ts +51 -55
- package/src/capabilities/ModelContext.ts +5 -2
- package/src/capabilities/Redaction.ts +64 -34
- package/src/capabilities/RunHooks.ts +52 -55
- package/src/capabilities/Subagent.ts +33 -33
- package/src/capabilities/SubagentReservations.ts +9 -1
- package/src/capabilities/WebCapture.ts +6 -0
- package/src/capabilities/WebSearch.ts +10 -7
- package/src/capabilities/internal/subagent-background.ts +202 -158
- package/src/core/Agent.ts +11 -6
- package/src/core/AgentUpdates.ts +8 -8
- package/src/core/Thread.ts +142 -146
- package/src/core/Usage.ts +7 -8
- package/src/core/internal/agent-updates.ts +1 -0
- package/src/durable/DurableAgentRuntime.ts +1024 -829
- package/src/durable/EventSource.ts +15 -9
- package/src/durable/RecordFormat.ts +5 -3
- package/src/durable/RunContinuation.ts +316 -113
- package/src/durable/RunJournal.ts +106 -114
- package/src/durable/RunStorage.ts +129 -124
- package/src/durable/Scheduling.ts +639 -651
- package/src/durable/SqlMemoryStore.ts +8 -6
- package/src/durable/SubmissionLedger.ts +11 -0
- package/src/durable/SubscriptionInput.ts +5 -3
- package/src/durable/SubscriptionStoreConformance.ts +23 -23
- package/src/durable/Subscriptions.ts +18 -19
- package/src/durable/ThreadImport.ts +18 -19
- package/src/durable/ThreadInvariants.ts +2 -1
- package/src/durable/ThreadStore.ts +217 -111
- package/src/durable/ThreadWork.ts +11 -2
- package/src/durable/WakeScheduler.ts +34 -66
- package/src/durable/internal/StorageOwner.ts +10 -4
- package/src/durable/internal/agent-registration.ts +96 -89
- package/src/durable/internal/canonical-json.ts +61 -20
- package/src/durable/internal/prompt-history-cache.ts +13 -4
- package/src/durable/internal/record-encoding.ts +120 -64
- package/src/durable/internal/schedule-time.ts +6 -6
- package/src/durable/internal/usage-totals.ts +35 -0
- package/src/durable/internal/worker-host.ts +69 -74
- package/src/engine/MessagingHost.ts +4 -2
- package/src/engine/ThreadHistory.ts +47 -48
- package/src/engine/internal/agent-runtime.ts +1298 -1217
- package/src/engine/internal/output-contract.ts +15 -15
- package/src/engine/internal/primitive-delta.ts +2 -3
- package/src/engine/internal/provisional-text.ts +12 -10
- package/src/engine/internal/tool-exposure.ts +22 -18
- package/src/engine/internal/tool-telemetry.ts +15 -12
- package/dist/Agent-0WvBWWbM.mjs.map +0 -1
- package/dist/AgentRuntime-CQ-qcETl.mjs.map +0 -1
- package/dist/Digest-DCuPlhNk.mjs.map +0 -1
- package/dist/DurableAgentRuntime-BAmSkWYr.mjs.map +0 -1
- package/dist/MessagingHost-CRUK4JBi.mjs.map +0 -1
- package/dist/RunContinuation-DHYNAQFi.mjs.map +0 -1
- package/dist/RunJournal-kfKVxJj7.mjs.map +0 -1
- package/dist/RunStorage-uqPxps09.mjs.map +0 -1
- package/dist/Scheduling-CVyfXlBR.mjs.map +0 -1
- package/dist/Subagent-vpffemql.mjs.map +0 -1
- package/dist/ThreadImport-DckUMEqJ.mjs.map +0 -1
- package/dist/ThreadStore-CEekRa80.mjs.map +0 -1
- package/dist/agent-registration-ByMZ_cK5.mjs.map +0 -1
|
@@ -12,37 +12,38 @@ import { DelegationDepth, SubagentBudgetReservation, SubagentDelegationCaps, Sub
|
|
|
12
12
|
import { o as Selection, s as Snapshot } from "./ToolExposure-hTJT2ekj.mjs";
|
|
13
13
|
import { ChildRunUsage, InputTokenUsage, ModelCallUsage, ModelResponseIdentity, ModelUsageGroup, OutputTokenUsage, RunUsageReport, RunUsageSummary, emptyRunTotals, runTotalsFromSummary, sumRunTotals, summarizeModelUsage, unknownRunTotals } from "./core/Usage.mjs";
|
|
14
14
|
import { C as MessageStatus, S as MessageRef, _ as WorkerStop, b as WorkerUpdate, c as WorkerError, f as WorkerRef, l as WorkerHistoryEntry, o as WorkerCompletion, r as FrameworkMessage } from "./Worker-DZjdMjZn.mjs";
|
|
15
|
-
import { a as PeerMessageCapacity, d as MessageAdmission, f as MessagingError, i as PeerDeliveryLifetime, o as PeerRoutes, p as PeerName, r as PeerAuthorizer, t as MessagingHost } from "./MessagingHost-
|
|
15
|
+
import { a as PeerMessageCapacity, d as MessageAdmission, f as MessagingError, i as PeerDeliveryLifetime, o as PeerRoutes, p as PeerName, r as PeerAuthorizer, t as MessagingHost } from "./MessagingHost-CZCyrnvJ.mjs";
|
|
16
16
|
import { SubagentHost } from "./engine/SubagentHost.mjs";
|
|
17
|
+
import { Store, makeMemoryStore } from "./core/Thread.mjs";
|
|
17
18
|
import { ThreadHistory } from "./engine/ThreadHistory.mjs";
|
|
18
19
|
import { n as RunToolVisibility } from "./ToolExposure-DBATXxmL.mjs";
|
|
19
|
-
import { C as boundedValueFootprint, n as AgentChildPending, p as renderInputPrompt, u as executeWithUsageAccountingUnknown } from "./AgentRuntime-
|
|
20
|
+
import { C as boundedValueFootprint, n as AgentChildPending, p as renderInputPrompt, u as executeWithUsageAccountingUnknown } from "./AgentRuntime-DaDKMasp.mjs";
|
|
20
21
|
import { ContextRolloverTool } from "./engine/ContextWindow.mjs";
|
|
21
22
|
import { getToolExecutionClass } from "./engine/DurableStep.mjs";
|
|
22
23
|
import { CompactionError, ContextCompactor } from "./engine/ContextCompactor.mjs";
|
|
23
24
|
import { AgentUpdateAcceptance, CurrentToolFailureObserver, ModelUsageAccounting, RunContextPreparation, RunContextPreparationPassthrough, RunToolAuthorization, RunToolScheduling } from "./engine/RunOptions.mjs";
|
|
24
|
-
import { A as MAX_RUN_EVIDENCE_RECORDS, At as WorkHandoffCompleted, Bt as WorkerReportingIntent, Ct as ToolCallResolved, Dt as ToolStepSettled, Et as ToolOperation, Ft as WorkerInputRequested, G as PromptRecord, H as PeerMessagePrepared, I as ModelCallAborted, It as WorkerOrigin, Mt as WorkerContinuation, Nt as WorkerInputCompleted, O as MAX_RUN_CONTINUATION_BYTES, Ot as ToolUnavailable, P as MAX_RUN_TOOL_CALL_IDENTITIES, Pt as WorkerInputRefused, R as ModelResponseInterrupted, Rt as WorkerReportPrepared, Tt as ToolCallUnknown, U as PersistedJson, V as PROMPT_EVIDENCE_TAGS, Vt as WorkerStopRequested, X as RecordEnvelope, Z as RecordId, _t as SubmissionSettledRecord, at as RunDurationExhausted, bt as ToolApprovalDecided, c as CanonicalBatch, et as RepairAnnotated, f as CanonicalSequence, ft as SubagentJoined, g as DeclaredToolCall, gt as SubmissionSettled, ht as SubagentStarted, i as BatchId, jt as WorkerAdmission, kt as UserInputRecorded, lt as RunStartedRecord, mt as SubagentRequested, n as AgentUpdateEmitted, o as CURRENT_RECORD_FORMAT, p as CompactionCreated, pt as SubagentLineageRecorded, rt as RunContextRecorded, st as RunPolicyUsageReserved, t as AbortRequested, ut as SettlementFailureDiagnostic, v as DefinitionDigests, vt as SubtreeBudgetReserved, w as MAX_PERSISTED_JSON_BYTES, wt as ToolCallSettled, xt as ToolApprovalRequested, zt as WorkerReportRefused } from "./Records-
|
|
25
|
-
import { i as digestCanonicalJson, r as canonicalJson, s as digestJson } from "./Digest-
|
|
25
|
+
import { A as MAX_RUN_EVIDENCE_RECORDS, At as WorkHandoffCompleted, Bt as WorkerReportingIntent, Ct as ToolCallResolved, Dt as ToolStepSettled, Et as ToolOperation, Ft as WorkerInputRequested, G as PromptRecord, H as PeerMessagePrepared, I as ModelCallAborted, It as WorkerOrigin, Mt as WorkerContinuation, Nt as WorkerInputCompleted, O as MAX_RUN_CONTINUATION_BYTES, Ot as ToolUnavailable, P as MAX_RUN_TOOL_CALL_IDENTITIES, Pt as WorkerInputRefused, R as ModelResponseInterrupted, Rt as WorkerReportPrepared, Tt as ToolCallUnknown, U as PersistedJson, V as PROMPT_EVIDENCE_TAGS, Vt as WorkerStopRequested, X as RecordEnvelope, Z as RecordId, _t as SubmissionSettledRecord, at as RunDurationExhausted, bt as ToolApprovalDecided, c as CanonicalBatch, et as RepairAnnotated, f as CanonicalSequence, ft as SubagentJoined, g as DeclaredToolCall, gt as SubmissionSettled, ht as SubagentStarted, i as BatchId, jt as WorkerAdmission, kt as UserInputRecorded, lt as RunStartedRecord, mt as SubagentRequested, n as AgentUpdateEmitted, o as CURRENT_RECORD_FORMAT, p as CompactionCreated, pt as SubagentLineageRecorded, rt as RunContextRecorded, st as RunPolicyUsageReserved, t as AbortRequested, ut as SettlementFailureDiagnostic, v as DefinitionDigests, vt as SubtreeBudgetReserved, w as MAX_PERSISTED_JSON_BYTES, wt as ToolCallSettled, xt as ToolApprovalRequested, zt as WorkerReportRefused } from "./Records-DzL4Kbtw.mjs";
|
|
26
|
+
import { i as digestCanonicalJson, r as canonicalJson, s as digestJson } from "./Digest-C3EODOee.mjs";
|
|
26
27
|
import { AbortCommand, AbortIntentRequest, AdmissionPolicyError, AdmissionRequest, ApprovalDecisionCommand, ApprovalPendingSuspension, BeginChildBudgetReleaseRequest, ChildReservationId, ChildSettledNotification, ClaimHandoff, ClaimRequest, FundingOwnerRequest, LedgerError, MarkReadyRequest, MarkUnknownRequest, ParentLinkage, RecoverySnapshotRequest, ReleaseChildBudgetRequest, RevertJoiningRequest, Settlement, SettlementFinalization, SubmissionLedger, SubmissionLookupById, SubmissionLookupByKey, SubmissionScheduling, UnknownResolutionCommand, WaitingChild, WaitingForChildSuspension, WorkerLedgerState, submissionAbortBatchId, submissionAbortRecordId, submissionInputBatchId, submissionInputRecordId, submissionSettlementBatchId, submissionSettlementId, submissionSettlementRecordId, unknownResolutionKind } from "./durable/SubmissionLedger.mjs";
|
|
27
28
|
import { DeclaredPendingBatchEvidence, OpenDelegationCallEvidence, OpenToolCallEvidence, PendingApprovalEvidence, RecoveryDecision, RecoveryEvidence, classifyRecovery, pendingApprovalForRecovery } from "./durable/Recovery.mjs";
|
|
28
29
|
import { ExplainedEvidence, ExplainedSubmission, ExplainedUnknownCall, ObligationEntry, ObligationReport, RecoveryExplanation, RetryRefused, obligationSeverityOf, predictRecoveryDisposition, recoveryDecisionMeaning } from "./durable/Admin.mjs";
|
|
29
|
-
import { a as compileRegistrations, c as resolveDefinitionBinding, l as resolveWorkerBinding, n as CurrentBindingSelection, o as definitionDigestsEqual, s as makeLegacyWorkerBinding, t as BindingUnavailable, u as toolReplayContracts } from "./agent-registration-
|
|
30
|
-
import { A as
|
|
31
|
-
import { $ as ThreadTailRequest, B as ThreadPromptRead, F as ThreadIdentityRequest, I as ThreadMaterialization, J as ThreadStore, R as ThreadObservation, U as ThreadReader, V as ThreadRead, X as ThreadStoreError, Y as ThreadStoreDiagnostic, _t as isPreContinuationFact, bt as terminalUsageCharge, gt as executionRunIds, ht as canonicalRunIds, lt as readWorkerState, n as AppendRequest, ot as getRecord, p as MAX_THREAD_EXPORT_PAGE_BYTES, pt as captureRecord, st as getRunInput } from "./ThreadStore-
|
|
30
|
+
import { a as compileRegistrations, c as resolveDefinitionBinding, l as resolveWorkerBinding, n as CurrentBindingSelection, o as definitionDigestsEqual, s as makeLegacyWorkerBinding, t as BindingUnavailable, u as toolReplayContracts } from "./agent-registration-a6QYaG3h.mjs";
|
|
31
|
+
import { $ as makeJournalMetadata, A as subagentRequestedRecordId, B as toolStepSettledRecordId, C as runStartedBatchId, D as subagentLineageBatchId, E as subagentJoinedRecordId, F as toolCallResolutionBatchId, G as turnResponseBatch, I as toolCallResolvedRecordId, K as turnResponseBatchId, L as toolCallResultBatchId, M as subagentStartedRecordId, N as toolApprovalDecisionRecordId, O as subagentLineageRecordId, P as toolApprovalRequestRecordId, R as toolCallUnknownRecordId, S as runIdForSubmission, T as subagentJoinBatchId, U as turnCanonicalBatch, V as turnApprovalsBatchId, W as turnIdForRun, X as workerOriginRecordId, Y as workerInputRecordId, Z as workerReportRecordId, _ as projectRunJournalStream, a as childIdempotencyKeyFor, b as runDurationBatchId, c as compactionRecordId, d as markUnknownBatchId, et as toolCallSettledRecordId, f as modelResponseInterruptedBatchId, h as peerMessageRecordId, i as approvalDecisionBatchId, j as subagentStartedBatchId, k as subagentRequestedBatchId, l as firstWorkerInputRecordId, m as modelResponseRecordId, o as childThreadIdFor, p as modelResponseInterruptedRecordId, q as turnResultsBatch, r as agentUpdateRecordId, s as compactionBatchId, t as RunJournalError, u as initialRunJournal, w as runStartedRecordId, x as runDurationRecordId, y as runCompletedRecordId, z as toolStepSettledBatchId } from "./RunJournal-CPMKcfd0.mjs";
|
|
32
|
+
import { $ as ThreadTailRequest, B as ThreadPromptRead, F as ThreadIdentityRequest, I as ThreadMaterialization, J as ThreadStore, R as ThreadObservation, U as ThreadReader, V as ThreadRead, X as ThreadStoreError, Y as ThreadStoreDiagnostic, _t as isPreContinuationFact, bt as terminalUsageCharge, gt as executionRunIds, ht as canonicalRunIds, lt as readWorkerState, n as AppendRequest, ot as getRecord, p as MAX_THREAD_EXPORT_PAGE_BYTES, pt as captureRecord, st as getRunInput } from "./ThreadStore-EuUilthA.mjs";
|
|
32
33
|
import { ScheduledInputRefused, ScheduledInputRetryable } from "./durable/Schedule.mjs";
|
|
33
34
|
import { PreparedInputAdmission } from "./durable/PreparedInputAdmission.mjs";
|
|
34
35
|
import { PreparedInput } from "./durable/Subscription.mjs";
|
|
35
36
|
import { MessageDeliveryDriver, MessageDeliveryFailpoint, MessageDeliveryRecord, MessageDeliveryStore, prepareMessageDelivery } from "./durable/MessageDelivery.mjs";
|
|
36
37
|
import { DurableRuntimeFailpoint } from "./durable/DurableFailpoint.mjs";
|
|
37
|
-
import { _ as readRunContext, a as canonicalRecordBytes, b as reference, f as runEvidence, g as digestRunHistory, l as readContinuation, m as validateSuffix, n as CurrentRunWriter, s as makeProgressWriter, t as CurrentRunSettlement, u as readRunEvidenceSnapshot, x as resolveEvidence, y as RunContextReader } from "./RunContinuation-
|
|
38
|
+
import { _ as readRunContext, a as canonicalRecordBytes, b as reference, f as runEvidence, g as digestRunHistory, l as readContinuation, m as validateSuffix, n as CurrentRunWriter, s as makeProgressWriter, t as CurrentRunSettlement, u as readRunEvidenceSnapshot, x as resolveEvidence, y as RunContextReader } from "./RunContinuation-BiyKJK32.mjs";
|
|
38
39
|
import { MAX_WORK_CURSOR_CHARS, ThreadWorkDiscovery, ThreadWorkEntry, ThreadWorkRequest, WorkDiscoveryUnavailable, decodeWorkCursor, deliveryPredecessor, encodeWorkCursor, operationEvidence, resolveWorkEvidence, validateWorkPage, workId } from "./durable/ThreadWork.mjs";
|
|
39
40
|
import { WakeScheduler } from "./durable/WakeScheduler.mjs";
|
|
40
41
|
import { n as safeUnknownString, t as inspectForeignDiagnostic } from "./foreign-diagnostic-DBQ1XHKh.mjs";
|
|
41
|
-
import { c as threadCreatedBatchId, l as threadCreatedRecordId, n as WorkerAdmissionPort, o as ensureThreadCreated, r as WorkerAdmissionRequest, s as ensureWorkerOrigin } from "./WorkerAdmission-
|
|
42
|
+
import { c as threadCreatedBatchId, l as threadCreatedRecordId, n as WorkerAdmissionPort, o as ensureThreadCreated, r as WorkerAdmissionRequest, s as ensureWorkerOrigin } from "./WorkerAdmission-eBeXt_mu.mjs";
|
|
42
43
|
import { i as unresolvedToolOperations, n as isUnresolvedToolOperation, r as toolOperationStates, t as initialDispatchBlockedTurns } from "./tool-operations-BXBmagY1.mjs";
|
|
43
44
|
import { WorkerBudgetAuthorizer, WorkerConcurrencyLimit, WorkerConcurrencyResolver, WorkerHostAuthorizer, WorkerHostConfig, WorkerPolicyResolver } from "./durable/WorkerHost.mjs";
|
|
44
45
|
import { OperationAuthorizationRequest, OperationAuthorizer, OperationDenied } from "./durable/OperationAuthorizer.mjs";
|
|
45
|
-
import { o as makeRunWriter, r as RunStorage, s as StorageOwner } from "./RunStorage-
|
|
46
|
+
import { o as makeRunWriter, r as RunStorage, s as StorageOwner } from "./RunStorage-CzutHJBE.mjs";
|
|
46
47
|
import { SettlementPublication } from "./durable/SettlementPublisher.mjs";
|
|
47
48
|
import { PendingSubmission, SettledSubmission } from "./durable/SubmissionStatus.mjs";
|
|
48
49
|
import { DeclaredToolCallEvidence, ToolReconciler } from "./durable/ToolReconciler.mjs";
|
|
@@ -736,7 +737,7 @@ function hydratePart(part) {
|
|
|
736
737
|
case "tool-approval-request": return Prompt.toolApprovalRequestPart(part);
|
|
737
738
|
case "tool-approval-response": return Prompt.toolApprovalResponsePart(part);
|
|
738
739
|
}
|
|
739
|
-
|
|
740
|
+
return part;
|
|
740
741
|
}
|
|
741
742
|
const hydrateMessage = (message) => {
|
|
742
743
|
switch (message.role) {
|
|
@@ -754,7 +755,7 @@ const hydrateMessage = (message) => {
|
|
|
754
755
|
content: message.content.map((p) => hydratePart(p))
|
|
755
756
|
});
|
|
756
757
|
}
|
|
757
|
-
|
|
758
|
+
return message;
|
|
758
759
|
};
|
|
759
760
|
/** Internal canonical projection; ownership comes from the ThreadStore read contract. */
|
|
760
761
|
const preparePromptHistory = (prompt) => prompt.content.length > MAX_ENTRIES ? void 0 : {
|
|
@@ -851,7 +852,12 @@ const makeCommittedPromptSuffix = (original) => {
|
|
|
851
852
|
}
|
|
852
853
|
try {
|
|
853
854
|
for (const fact of facts) {
|
|
854
|
-
const
|
|
855
|
+
const captured = captureRecord(fact);
|
|
856
|
+
if (Result.isFailure(captured)) {
|
|
857
|
+
discard();
|
|
858
|
+
return;
|
|
859
|
+
}
|
|
860
|
+
const owned = captured.success;
|
|
855
861
|
const payload = owned.canonical.payload;
|
|
856
862
|
if (payload._tag !== "UserInputRecorded" && payload._tag !== "ModelResponseRecorded" && payload._tag !== "ToolCallSettled" && payload._tag !== "SubmissionSettled") {
|
|
857
863
|
discard();
|
|
@@ -2384,7 +2390,7 @@ const makeWorkerRuntime = Effect.fnUntraced(function* (options) {
|
|
|
2384
2390
|
ownerThreadId: context.source.threadId,
|
|
2385
2391
|
messageId
|
|
2386
2392
|
}).pipe(Effect.mapError(storageFailure("start")));
|
|
2387
|
-
const replay =
|
|
2393
|
+
const replay = Effect.fnUntraced(function* (saved) {
|
|
2388
2394
|
const currentPrevious = command.continuationOf === void 0 ? void 0 : yield* completedContinuation(context.source, command.continuationOf, command.target.id, command.delegationId, previous?.evidence);
|
|
2389
2395
|
const replayPrincipal = yield* authorize("start", "send", void 0, currentPrevious?.evidence);
|
|
2390
2396
|
yield* binding(command.target, "start");
|
|
@@ -2476,7 +2482,7 @@ const makeWorkerRuntime = Effect.fnUntraced(function* (options) {
|
|
|
2476
2482
|
ownerThreadId: context.source.threadId,
|
|
2477
2483
|
messageId
|
|
2478
2484
|
}).pipe(Effect.mapError(storageFailure("followUp")));
|
|
2479
|
-
const replay =
|
|
2485
|
+
const replay = Effect.fnUntraced(function* (saved) {
|
|
2480
2486
|
const replayPrincipal = yield* authorize("followUp", "send", command.worker);
|
|
2481
2487
|
yield* currentPolicy;
|
|
2482
2488
|
return yield* send(origin, messageId, saved.envelope.input, command.encodedParameters, replayPrincipal, "followUp");
|
|
@@ -3147,6 +3153,7 @@ const make = Effect.fnUntraced(function* (bindings) {
|
|
|
3147
3153
|
const store = yield* ThreadStore;
|
|
3148
3154
|
const reader = ThreadReader.fromStore(store);
|
|
3149
3155
|
const promptHistory = yield* makePromptHistoryCache();
|
|
3156
|
+
const unclaimedAdmissions = /* @__PURE__ */ new Map();
|
|
3150
3157
|
const workDiscovery = yield* ThreadWorkDiscovery.pipe(Effect.provide(ThreadWorkDiscovery.layer), Effect.provideService(ThreadStore, store));
|
|
3151
3158
|
const runStorage = yield* RunStorage;
|
|
3152
3159
|
const storageOwner = yield* StorageOwner;
|
|
@@ -3170,8 +3177,10 @@ const make = Effect.fnUntraced(function* (bindings) {
|
|
|
3170
3177
|
})));
|
|
3171
3178
|
const operationAuthorizer = yield* OperationAuthorizer;
|
|
3172
3179
|
const toolFailureObserver = yield* CurrentToolFailureObserver;
|
|
3180
|
+
const runServices = Context.make(CurrentToolFailureObserver, toolFailureObserver).pipe(Context.add(RunToolVisibility, runToolVisibility), Context.add(RunToolScheduling, runToolScheduling), Context.add(ContextCompactor, compactor), Context.add(RunContextPreparation, runContextPreparation));
|
|
3181
|
+
const journalServices = Context.make(ThreadReader, reader).pipe(Context.add(Crypto.Crypto, crypto));
|
|
3173
3182
|
const withCrypto = (effect) => Effect.provideService(effect, Crypto.Crypto, crypto);
|
|
3174
|
-
const readInitialJournal = (original, suffix) => initialContext(original).pipe(Effect.
|
|
3183
|
+
const readInitialJournal = (original, suffix) => initialContext(original).pipe(Effect.provideContext(journalServices), Effect.map((history) => history.concat(suffix)));
|
|
3175
3184
|
const resolutionIntentsFor = (snapshot) => {
|
|
3176
3185
|
const intents = /* @__PURE__ */ new Map();
|
|
3177
3186
|
for (const intent of snapshot.unknownResolutions) if (!intents.has(intent.toolCallId) || unknownResolutionKind(intent.resolution) === "factual") intents.set(intent.toolCallId, intent);
|
|
@@ -3257,6 +3266,7 @@ const make = Effect.fnUntraced(function* (bindings) {
|
|
|
3257
3266
|
let context;
|
|
3258
3267
|
let progress;
|
|
3259
3268
|
let progressThrough;
|
|
3269
|
+
let operational = [];
|
|
3260
3270
|
const invalid = (message) => ThreadStoreError.make({
|
|
3261
3271
|
operation: "read Run continuation",
|
|
3262
3272
|
message
|
|
@@ -3280,7 +3290,7 @@ const make = Effect.fnUntraced(function* (bindings) {
|
|
|
3280
3290
|
const resolve = Effect.fnUntraced(function* (ref) {
|
|
3281
3291
|
const found = byId.get(ref.recordId);
|
|
3282
3292
|
if (found === void 0) {
|
|
3283
|
-
yield* resolveEvidence(threadId, ref).pipe(Effect.
|
|
3293
|
+
yield* resolveEvidence(threadId, ref).pipe(Effect.provideContext(journalServices));
|
|
3284
3294
|
return yield* invalid("Required Run evidence is absent from its locator; rebuild the index explicitly");
|
|
3285
3295
|
}
|
|
3286
3296
|
if (!canonicalRunIds(found.record).includes(runId)) return yield* invalid("Run continuation references another owner");
|
|
@@ -3304,7 +3314,7 @@ const make = Effect.fnUntraced(function* (bindings) {
|
|
|
3304
3314
|
const cachedContext = resolvedContext;
|
|
3305
3315
|
if (cachedContext?.threadId === threadId && cachedContext.recordId === cursor.savedContext.recordId) saved = cachedContext.value;
|
|
3306
3316
|
else {
|
|
3307
|
-
saved = yield* readRunContext(initial, input, cursor.savedContext.recordId).pipe(Effect.provide(RunContextReader.layer(threadId)), Effect.
|
|
3317
|
+
saved = yield* readRunContext(initial, input, cursor.savedContext.recordId).pipe(Effect.provide(RunContextReader.layer(threadId)), Effect.provideContext(journalServices), Effect.mapError(() => invalid("Saved original context cannot be resolved from its evidence")));
|
|
3308
3318
|
resolvedContext = {
|
|
3309
3319
|
threadId,
|
|
3310
3320
|
recordId: cursor.savedContext.recordId,
|
|
@@ -3325,20 +3335,20 @@ const make = Effect.fnUntraced(function* (bindings) {
|
|
|
3325
3335
|
context = saved;
|
|
3326
3336
|
progress = cursor;
|
|
3327
3337
|
progressThrough = envelope.throughSequence;
|
|
3338
|
+
operational = envelope.operational;
|
|
3328
3339
|
}
|
|
3329
3340
|
}
|
|
3330
|
-
const records = [...new Map([...identity.records.filter((entry) => entry.sequence <= throughSequence), ...selected].map((entry) => [entry.sequence, entry])).values()].sort((left, right) => left.sequence - right.sequence);
|
|
3331
3341
|
return {
|
|
3332
|
-
|
|
3342
|
+
records: [...new Map([...identity.records.filter((entry) => entry.sequence <= throughSequence), ...selected].map((entry) => [entry.sequence, entry])).values()].sort((left, right) => left.sequence - right.sequence),
|
|
3333
3343
|
context,
|
|
3334
3344
|
progress,
|
|
3335
|
-
progressThrough
|
|
3345
|
+
progressThrough,
|
|
3346
|
+
operational
|
|
3336
3347
|
};
|
|
3337
3348
|
});
|
|
3338
3349
|
const readControl = Effect.fnUntraced(function* (threadId, submissionIds) {
|
|
3339
3350
|
const tail = yield* store.inspectTail(ThreadTailRequest.make({ threadId }));
|
|
3340
|
-
|
|
3341
|
-
return yield* Stream.runCollect(view.canonical.pipe(Stream.filter(controlRecords(submissionIds))));
|
|
3351
|
+
return (yield* recoveryView(threadId, tail.tailSequence, submissionIds)).records.filter(controlRecords(submissionIds));
|
|
3342
3352
|
});
|
|
3343
3353
|
const readAllTolerant = (threadId, submissionIds) => Effect.suspend(() => readControl(threadId, submissionIds).pipe(Effect.map((records) => ({
|
|
3344
3354
|
records,
|
|
@@ -3360,7 +3370,7 @@ const make = Effect.fnUntraced(function* (bindings) {
|
|
|
3360
3370
|
submissionIds
|
|
3361
3371
|
};
|
|
3362
3372
|
return {
|
|
3363
|
-
records: yield* recoveryView(threadId, tail.value.tailSequence, submissionIds).pipe(Effect.
|
|
3373
|
+
records: yield* recoveryView(threadId, tail.value.tailSequence, submissionIds).pipe(Effect.map((view) => view.records.filter(controlRecords(submissionIds))), Effect.catchTag("ThreadNotMaterialized", (error) => ThreadStoreError.make({
|
|
3364
3374
|
operation: "read recovery history",
|
|
3365
3375
|
message: `Thread ${threadId} disappeared after its recovery tail was captured`,
|
|
3366
3376
|
cause: error
|
|
@@ -3719,7 +3729,7 @@ const make = Effect.fnUntraced(function* (bindings) {
|
|
|
3719
3729
|
const progressWriters = /* @__PURE__ */ new WeakMap();
|
|
3720
3730
|
const activeProgress = /* @__PURE__ */ new Map();
|
|
3721
3731
|
const withProgress = Effect.fnUntraced(function* (writer) {
|
|
3722
|
-
const progress = activeProgress.get(writer.threadId)?.writer ?? (yield* makeProgressWriter(writer.threadId, config.deploymentId).pipe(Effect.
|
|
3732
|
+
const progress = activeProgress.get(writer.threadId)?.writer ?? (yield* makeProgressWriter(writer.threadId, config.deploymentId).pipe(Effect.provideContext(journalServices)));
|
|
3723
3733
|
const owned = {
|
|
3724
3734
|
...writer,
|
|
3725
3735
|
append: (batch) => progress.commit(batch).pipe(Effect.provideService(CurrentRunWriter, writer), Effect.tapError(() => writer.checkActive))
|
|
@@ -3747,8 +3757,8 @@ const make = Effect.fnUntraced(function* (bindings) {
|
|
|
3747
3757
|
});
|
|
3748
3758
|
const progressStore = ThreadStore.of({
|
|
3749
3759
|
...store,
|
|
3750
|
-
append:
|
|
3751
|
-
const progress = activeProgress.get(request.threadId)?.writer ?? (yield* makeProgressWriter(request.threadId, config.deploymentId).pipe(Effect.
|
|
3760
|
+
append: Effect.fnUntraced(function* (request) {
|
|
3761
|
+
const progress = activeProgress.get(request.threadId)?.writer ?? (yield* makeProgressWriter(request.threadId, config.deploymentId).pipe(Effect.provideContext(journalServices)));
|
|
3752
3762
|
let tail = { sequence: request.expectedTailSequence };
|
|
3753
3763
|
return yield* progress.commit(request.batch).pipe(Effect.provideService(CurrentRunWriter, {
|
|
3754
3764
|
threadId: request.threadId,
|
|
@@ -3776,7 +3786,7 @@ const make = Effect.fnUntraced(function* (bindings) {
|
|
|
3776
3786
|
threadId: ctx.threadId,
|
|
3777
3787
|
tail: ctx.tail,
|
|
3778
3788
|
withProgress: ctx.withProgress,
|
|
3779
|
-
publishSettlement:
|
|
3789
|
+
publishSettlement: Effect.fnUntraced(function* (prepared, executions) {
|
|
3780
3790
|
let tail = yield* ctx.tail;
|
|
3781
3791
|
for (let retries = 0;; retries++) {
|
|
3782
3792
|
const result = yield* runStorage.publishSettlement(SettlementPublication.make({
|
|
@@ -4079,23 +4089,26 @@ const make = Effect.fnUntraced(function* (bindings) {
|
|
|
4079
4089
|
sequence: result.firstSequence
|
|
4080
4090
|
});
|
|
4081
4091
|
});
|
|
4082
|
-
const readRunStart = Effect.fnUntraced(function* (threadId, runId) {
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4092
|
+
const readRunStart = Effect.fnUntraced(function* (threadId, runId, operational) {
|
|
4093
|
+
if (operational === void 0) {
|
|
4094
|
+
const loaded = yield* reader.readExecution({
|
|
4095
|
+
threadId,
|
|
4096
|
+
runId
|
|
4097
|
+
}).pipe(Effect.catchTag("ThreadNotMaterialized", () => Effect.succeed(Option.none())));
|
|
4098
|
+
if (Option.isNone(loaded)) return void 0;
|
|
4099
|
+
operational = loaded.value.operational;
|
|
4100
|
+
}
|
|
4088
4101
|
const recordId = runStartedRecordId(runId);
|
|
4089
|
-
const starts =
|
|
4090
|
-
const existing =
|
|
4102
|
+
const starts = operational.filter(({ payload }) => payload._tag === "RunStarted");
|
|
4103
|
+
const existing = operational.find((record) => record.recordId === recordId);
|
|
4091
4104
|
if (starts.length > 1 || starts.length === 1 && starts[0]?.recordId !== recordId || existing !== void 0 && (existing.payload._tag !== "RunStarted" || existing.payload.runId !== runId)) return yield* RunJournalError.make({ message: `Run ${runId} has conflicting active start state` });
|
|
4092
4105
|
return existing;
|
|
4093
4106
|
});
|
|
4094
|
-
const makeRunStart = Effect.fnUntraced(function* (submission, maxDurationMillis, records) {
|
|
4107
|
+
const makeRunStart = Effect.fnUntraced(function* (submission, maxDurationMillis, records, operational) {
|
|
4095
4108
|
const writer = yield* CurrentRunWriter;
|
|
4096
4109
|
const runId = runIdForSubmission(submission.submissionId);
|
|
4097
4110
|
const recordId = runStartedRecordId(runId);
|
|
4098
|
-
const existing = yield* readRunStart(submission.threadId, runId);
|
|
4111
|
+
const existing = yield* readRunStart(submission.threadId, runId, operational);
|
|
4099
4112
|
let start;
|
|
4100
4113
|
let allowance = maxDurationMillis;
|
|
4101
4114
|
let committed = existing !== void 0;
|
|
@@ -4942,1474 +4955,1484 @@ const make = Effect.fnUntraced(function* (bindings) {
|
|
|
4942
4955
|
})).pipe(Effect.catchTag("AppendConflict", () => Effect.void), Effect.asVoid);
|
|
4943
4956
|
knownIds.add(recordId);
|
|
4944
4957
|
});
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
|
|
4949
|
-
|
|
4950
|
-
|
|
4951
|
-
|
|
4952
|
-
|
|
4953
|
-
|
|
4954
|
-
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
|
|
4964
|
-
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
let journal = cached !== void 0 && cached.threadId === ctx.threadId && cached.through === projectionThrough && cached.runId === runId && cached.contextRecordId === priorContext?.recordId ? (boundaries.push(...cached.boundaries), cached.contextEvidence.forEach(retainHistory), cached.journal) : yield* projectRunJournalStream(canonical, runId, (boundary) => boundaries.push(boundary), priorContext, journalMetadata, priorContext === void 0 ? retainHistory : void 0);
|
|
4970
|
-
if (initialJournal?.prefix !== void 0) {
|
|
4971
|
-
const prompt = initialJournal.prefix.prompt;
|
|
4972
|
-
journal = {
|
|
4973
|
-
...journal,
|
|
4974
|
-
prompt,
|
|
4975
|
-
historyBefore: prompt
|
|
4958
|
+
const runModel = Effect.fnUntraced(
|
|
4959
|
+
/**
|
|
4960
|
+
* Drive the shared interpreter Effect with history rebuilt by the run journal, commit
|
|
4961
|
+
* each Turn under the local owner, and watch for durable abort intent. Engine Run failures settle `failed`; coordinator failures abort the
|
|
4962
|
+
* Attempt cleanly with the obligation still owed.
|
|
4963
|
+
*
|
|
4964
|
+
* The interpreter supplies validated response, closed Tool-result, and completion facts.
|
|
4965
|
+
* Responses precede approval and effectful dispatch; readonly responses may join their closed
|
|
4966
|
+
* results. Tool results precede input drains and the next Turn. A no-tool response and Run
|
|
4967
|
+
* completion share one batch. A completion Tool's result
|
|
4968
|
+
* precedes its terminal-only completion batch, so recovery can repeat a pure output projection
|
|
4969
|
+
* without replaying the handler. Pending batches resume from their canonical declarations.
|
|
4970
|
+
*/
|
|
4971
|
+
function* (agent, ctx, submission, session, records, canonical, initialJournal, canonicalThrough, progressThrough, continuation, priorContext, journalMetadata, lineage, approvalDecisions, currentContracts, runTiming, yieldAfter) {
|
|
4972
|
+
const submissionId = submission.submissionId;
|
|
4973
|
+
const runId = runIdForSubmission(submissionId);
|
|
4974
|
+
const boundaries = [];
|
|
4975
|
+
const cached = projectedJournal;
|
|
4976
|
+
const projectionThrough = Math.max(progressThrough ?? 0, records.at(-1)?.sequence ?? 0);
|
|
4977
|
+
const originalInput = records.find(({ record: { payload } }) => payload._tag === "UserInputRecorded" && payload.kind === "user" && payload.submissionId === submissionId);
|
|
4978
|
+
if (originalInput === void 0) return yield* RunJournalError.make({ message: "Run has no original context boundary" });
|
|
4979
|
+
const historyEvidence = /* @__PURE__ */ new Map();
|
|
4980
|
+
const retainHistory = (entry) => {
|
|
4981
|
+
if (priorContext === void 0 && entry.sequence < originalInput.sequence) historyEvidence.set(entry.record.recordId, entry);
|
|
4976
4982
|
};
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
|
|
4981
|
-
|
|
4982
|
-
|
|
4983
|
-
|
|
4984
|
-
|
|
4985
|
-
|
|
4986
|
-
contextRecordId: priorContext?.recordId,
|
|
4987
|
-
contextEvidence: [...historyEvidence.values()],
|
|
4988
|
-
journal,
|
|
4989
|
-
boundaries
|
|
4990
|
-
};
|
|
4991
|
-
if (continuation !== void 0) {
|
|
4992
|
-
const accounting = continuation.accounting;
|
|
4993
|
-
if ([
|
|
4994
|
-
"committedTurns",
|
|
4995
|
-
"toolCalls",
|
|
4996
|
-
"programmaticToolCalls",
|
|
4997
|
-
"consecutiveToolFailures",
|
|
4998
|
-
"finalizationUsed",
|
|
4999
|
-
"modelRestarts"
|
|
5000
|
-
].some((field) => (journal.policyUsage[field] ?? 0) !== accounting[field]) || [
|
|
5001
|
-
"modelCalls",
|
|
5002
|
-
"inputTokens",
|
|
5003
|
-
"outputTokens",
|
|
5004
|
-
"lastInputTokens",
|
|
5005
|
-
"lastOutputTokens",
|
|
5006
|
-
"costMicrousd"
|
|
5007
|
-
].some((field) => journal.usage[field] !== accounting[field]) || (journal.usage.unobservedModelCalls ?? 0) !== accounting.unobservedModelCalls) return yield* RunJournalError.make({ message: "Canonical continuation accounting differs from its exact execution evidence" });
|
|
5008
|
-
}
|
|
5009
|
-
const childLineage = records.find(({ record }) => record.recordId === subagentLineageRecordId(submission.threadId))?.record.payload;
|
|
5010
|
-
const inheritedGrant = submission.workerAdmission?.origin.grant ?? (childLineage?._tag === "SubagentLineageRecorded" ? childLineage.grant : void 0);
|
|
5011
|
-
const delegationDepth = submission.workerAdmission?.origin.depth ?? (childLineage?._tag === "SubagentLineageRecorded" ? childLineage.parentLink.depth : 0);
|
|
5012
|
-
const inheritedBudget = submission.workerAdmission?.origin.budget ?? (childLineage?._tag === "SubagentLineageRecorded" ? childLineage.budget : void 0);
|
|
5013
|
-
if (submission.parentLinkage !== void 0 && (childLineage?._tag !== "SubagentLineageRecorded" || childLineage.parentSubmissionId !== submission.parentLinkage.parentSubmissionId || childLineage.parentLink.parentToolCallId !== submission.parentLinkage.parentToolCallId || !definitionDigestsEqual(childLineage.childDefinitionDigests, submission.agentDigests) || childLineage.childInputDigest !== submission.inputDigest)) return yield* RunJournalError.make({ message: "The child Run has no matching canonical lineage and execution bounds" });
|
|
5014
|
-
const completionTools = [...agent.definition.completion === void 0 ? [] : [agent.definition.completion.tool], ...agent.definition.completionFromTools?.map((declaration) => declaration.tool) ?? []];
|
|
5015
|
-
const pending = yield* pendingToolBatchFor(records, runId, completionTools);
|
|
5016
|
-
const resumeProjection = pending === void 0 ? journal : yield* projectRunJournalStream(withoutPendingBatch(canonical, pending, runId), runId, void 0, priorContext);
|
|
5017
|
-
if (initialJournal !== void 0 && (journal.committedTurns !== 0 || journal.historyFrom !== 1 || journal.contextWindowId !== void 0 || historyEvidence.size !== 0 || pending !== void 0 || boundaries.some((boundary) => boundary.incomplete))) initialJournal.cacheable = false;
|
|
5018
|
-
if (initialJournal?.cacheable) initialJournal.history = initialJournal.prefix ?? preparePromptHistory(journal.historyBefore);
|
|
5019
|
-
if (initialJournal !== void 0) initialJournal.records = void 0;
|
|
5020
|
-
const rolloverOperation = journal.pendingContextToolCallId === void 0 ? void 0 : operationsFor(records, runId).get(journal.pendingContextToolCallId);
|
|
5021
|
-
const rolloverTool = rolloverOperation === void 0 ? void 0 : agent.definition.toolkit.tools[rolloverOperation.toolName];
|
|
5022
|
-
const pendingContextToolCallId = rolloverOperation !== void 0 && rolloverTool !== void 0 && Context.get(rolloverTool.annotations, ContextRolloverTool) && currentContracts[rolloverOperation.toolName] === rolloverOperation.replay ? journal.pendingContextToolCallId : void 0;
|
|
5023
|
-
const applicationCalls = pending?.calls.filter((call) => !call.providerExecuted);
|
|
5024
|
-
const completionCandidate = applicationCalls?.length === 1 && completionTools.some((tool) => tool === applicationCalls[0]?.name) && pending?.settled.some((result) => result.id === applicationCalls[0]?.id && !result.isFailure) ? applicationCalls[0] : void 0;
|
|
5025
|
-
const settledCompletion = pending !== void 0 && completionCandidate !== void 0 && supportsOperation(OpenToolCallEvidence.make({
|
|
5026
|
-
toolCallId: Schema.decodeSync(ToolCallId)(completionCandidate.id),
|
|
5027
|
-
toolName: completionCandidate.name,
|
|
5028
|
-
turn: pending.turn
|
|
5029
|
-
}), pending.toolOperations.find((operation) => operation.toolCallId === completionCandidate.id), {
|
|
5030
|
-
definition: agent.definition,
|
|
5031
|
-
contracts: currentContracts
|
|
5032
|
-
}) ? Schema.decodeSync(ToolCallId)(completionCandidate.id) : void 0;
|
|
5033
|
-
const knownIds = knownRecordIdsOf(records);
|
|
5034
|
-
const stepOutputs = /* @__PURE__ */ new Map();
|
|
5035
|
-
for (const envelope of records) {
|
|
5036
|
-
const payload = envelope.record.payload;
|
|
5037
|
-
if (payload._tag === "ToolStepSettled" && payload.runId === runId) stepOutputs.set(toolStepSettledRecordId(runId, payload.toolCallId, payload.stepName), payload.output);
|
|
5038
|
-
}
|
|
5039
|
-
const canonicalApprovalDecisions = /* @__PURE__ */ new Map();
|
|
5040
|
-
const approvalRequestedTurns = /* @__PURE__ */ new Set();
|
|
5041
|
-
for (const envelope of records) {
|
|
5042
|
-
const payload = envelope.record.payload;
|
|
5043
|
-
if (payload._tag === "ToolApprovalDecided" && payload.runId === runId) canonicalApprovalDecisions.set(payload.toolCallId, payload.decision);
|
|
5044
|
-
else if (payload._tag === "ToolApprovalRequested" && payload.runId === runId) approvalRequestedTurns.add(payload.turn);
|
|
5045
|
-
}
|
|
5046
|
-
const approvalIntents = /* @__PURE__ */ new Map();
|
|
5047
|
-
for (const intent of approvalDecisions) approvalIntents.set(intent.toolCallId, intent);
|
|
5048
|
-
const joinedInputEnvelopes = /* @__PURE__ */ new Map();
|
|
5049
|
-
let lastHostResponseSequence;
|
|
5050
|
-
for (const envelope of records) {
|
|
5051
|
-
const payload = envelope.record.payload;
|
|
5052
|
-
if (payload._tag === "UserInputRecorded" && payload.runId === runId && payload.submissionId !== void 0 && payload.submissionId !== submissionId) joinedInputEnvelopes.set(payload.submissionId, envelope);
|
|
5053
|
-
else if (payload._tag === "ModelResponseRecorded" && payload.runId === runId) {
|
|
5054
|
-
if (lastHostResponseSequence === void 0 || envelope.sequence > lastHostResponseSequence) lastHostResponseSequence = envelope.sequence;
|
|
4983
|
+
const freshPrefix = priorContext === void 0 && initialJournal?.prefix !== void 0 && initialJournal.records?.length === 1 && initialJournal.records[0] === originalInput ? initialJournal.prefix.prompt : void 0;
|
|
4984
|
+
let journal = freshPrefix !== void 0 ? initialRunJournal(freshPrefix) : cached !== void 0 && cached.threadId === ctx.threadId && cached.through === projectionThrough && cached.runId === runId && cached.contextRecordId === priorContext?.recordId ? (boundaries.push(...cached.boundaries), cached.contextEvidence.forEach(retainHistory), cached.journal) : yield* projectRunJournalStream(canonical, runId, (boundary) => boundaries.push(boundary), priorContext, journalMetadata, priorContext === void 0 ? retainHistory : void 0);
|
|
4985
|
+
if (initialJournal?.prefix !== void 0) {
|
|
4986
|
+
const prompt = initialJournal.prefix.prompt;
|
|
4987
|
+
journal = {
|
|
4988
|
+
...journal,
|
|
4989
|
+
prompt,
|
|
4990
|
+
historyBefore: prompt
|
|
4991
|
+
};
|
|
5055
4992
|
}
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
outputTokens: modelUsage.reduce((sum, call) => sum + call.outputTokens.total, 0),
|
|
5069
|
-
costMicrousd: modelUsage.reduce((sum, call) => sum + call.costMicrousd, 0)
|
|
4993
|
+
journalMetadata = void 0;
|
|
4994
|
+
historyEvidence.forEach((entry, id) => {
|
|
4995
|
+
if (entry.sequence >= journal.historyFrom) historyEvidence.delete(id);
|
|
4996
|
+
});
|
|
4997
|
+
projectedJournal = {
|
|
4998
|
+
threadId: ctx.threadId,
|
|
4999
|
+
through: CanonicalSequence.make(projectionThrough),
|
|
5000
|
+
runId,
|
|
5001
|
+
contextRecordId: priorContext?.recordId,
|
|
5002
|
+
contextEvidence: [...historyEvidence.values()],
|
|
5003
|
+
journal,
|
|
5004
|
+
boundaries
|
|
5070
5005
|
};
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
})));
|
|
5089
|
-
const addUsageTotal = (field, left, right) => checkedUsageTotal(field, left + right);
|
|
5090
|
-
const subtractUsageTotal = (field, left, right) => checkedUsageTotal(field, left - right);
|
|
5091
|
-
const currentUsageSummary = () => Effect.gen(function* () {
|
|
5092
|
-
const stagedCalls = [...stagedUsage.values()].flatMap((usage) => usage.modelUsage);
|
|
5093
|
-
let unobservedModelCalls = journal.usage.unobservedModelCalls ?? 0;
|
|
5094
|
-
for (const count of stagedUnobservedCalls.values()) unobservedModelCalls = yield* addUsageTotal("unobservedModelCalls", unobservedModelCalls, count);
|
|
5095
|
-
const detailedCalls = [...journal.usage.modelUsage, ...stagedCalls];
|
|
5096
|
-
const detailed = yield* summarizeModelUsage(detailedCalls, journal.usage.summarizedModelUsage).pipe(Effect.mapError((cause) => RunJournalError.make({
|
|
5097
|
-
message: "Run detailed usage exceeds safe-integer accounting bounds",
|
|
5098
|
-
cause
|
|
5099
|
-
})));
|
|
5100
|
-
let inputTokens = journal.usage.inputTokens;
|
|
5101
|
-
let outputTokens = journal.usage.outputTokens;
|
|
5102
|
-
let costMicrousd = journal.usage.costMicrousd;
|
|
5103
|
-
for (const usage of stagedUsage.values()) {
|
|
5104
|
-
inputTokens = yield* addUsageTotal("inputTokens", inputTokens, usage.inputTokens);
|
|
5105
|
-
outputTokens = yield* addUsageTotal("outputTokens", outputTokens, usage.outputTokens);
|
|
5106
|
-
costMicrousd = yield* addUsageTotal("costMicrousd", costMicrousd, usage.costMicrousd);
|
|
5107
|
-
}
|
|
5108
|
-
const modelCalls = yield* addUsageTotal("modelCalls", journal.usage.modelCalls, stagedCalls.length);
|
|
5109
|
-
const legacyCalls = yield* subtractUsageTotal("legacy.modelCalls", modelCalls, detailed.modelCalls);
|
|
5110
|
-
const legacyInput = yield* subtractUsageTotal("legacy.inputTokens", inputTokens, detailed.inputTokens.total);
|
|
5111
|
-
const legacyOutput = yield* subtractUsageTotal("legacy.outputTokens", outputTokens, detailed.outputTokens.total);
|
|
5112
|
-
const legacyCost = yield* subtractUsageTotal("legacy.costMicrousd", costMicrousd, detailed.costMicrousd);
|
|
5113
|
-
if (legacyCalls === 0 && (legacyInput !== 0 || legacyOutput !== 0 || legacyCost !== 0)) return yield* RunJournalError.make({ message: "Run aggregate usage has legacy totals without a legacy model call" });
|
|
5114
|
-
const byModel = [...detailed.byModel];
|
|
5115
|
-
if (legacyCalls > 0) {
|
|
5116
|
-
const existingIndex = byModel.findIndex((group) => group.provider === "unknown" && group.model === "legacy-record" && group.responseModel === void 0 && group.serviceTier === void 0 && group.pricingVersion === void 0);
|
|
5117
|
-
const existing = existingIndex < 0 ? void 0 : byModel[existingIndex];
|
|
5118
|
-
const legacyGroup = ModelUsageGroup.make({
|
|
5119
|
-
provider: "unknown",
|
|
5120
|
-
model: "legacy-record",
|
|
5121
|
-
modelCalls: yield* addUsageTotal("byModel.modelCalls", existing?.modelCalls ?? 0, legacyCalls),
|
|
5122
|
-
inputTokens: InputTokenUsage.make({
|
|
5123
|
-
total: yield* addUsageTotal("byModel.inputTokens.total", existing?.inputTokens.total ?? 0, legacyInput),
|
|
5124
|
-
uncached: yield* addUsageTotal("byModel.inputTokens.uncached", existing?.inputTokens.uncached ?? 0, legacyInput),
|
|
5125
|
-
cacheRead: existing?.inputTokens.cacheRead ?? 0,
|
|
5126
|
-
cacheWrite: existing?.inputTokens.cacheWrite ?? 0
|
|
5127
|
-
}),
|
|
5128
|
-
outputTokens: OutputTokenUsage.make({
|
|
5129
|
-
total: yield* addUsageTotal("byModel.outputTokens.total", existing?.outputTokens.total ?? 0, legacyOutput),
|
|
5130
|
-
text: yield* addUsageTotal("byModel.outputTokens.text", existing?.outputTokens.text ?? 0, legacyOutput),
|
|
5131
|
-
reasoning: existing?.outputTokens.reasoning ?? 0
|
|
5132
|
-
}),
|
|
5133
|
-
costMicrousd: yield* addUsageTotal("byModel.costMicrousd", existing?.costMicrousd ?? 0, legacyCost)
|
|
5134
|
-
});
|
|
5135
|
-
if (existingIndex < 0) byModel.push(legacyGroup);
|
|
5136
|
-
else byModel[existingIndex] = legacyGroup;
|
|
5006
|
+
if (continuation !== void 0) {
|
|
5007
|
+
const accounting = continuation.accounting;
|
|
5008
|
+
if ([
|
|
5009
|
+
"committedTurns",
|
|
5010
|
+
"toolCalls",
|
|
5011
|
+
"programmaticToolCalls",
|
|
5012
|
+
"consecutiveToolFailures",
|
|
5013
|
+
"finalizationUsed",
|
|
5014
|
+
"modelRestarts"
|
|
5015
|
+
].some((field) => (journal.policyUsage[field] ?? 0) !== accounting[field]) || [
|
|
5016
|
+
"modelCalls",
|
|
5017
|
+
"inputTokens",
|
|
5018
|
+
"outputTokens",
|
|
5019
|
+
"lastInputTokens",
|
|
5020
|
+
"lastOutputTokens",
|
|
5021
|
+
"costMicrousd"
|
|
5022
|
+
].some((field) => journal.usage[field] !== accounting[field]) || (journal.usage.unobservedModelCalls ?? 0) !== accounting.unobservedModelCalls) return yield* RunJournalError.make({ message: "Canonical continuation accounting differs from its exact execution evidence" });
|
|
5137
5023
|
}
|
|
5138
|
-
const
|
|
5139
|
-
const
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
|
|
5150
|
-
|
|
5151
|
-
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
5167
|
-
if (recordedCompletion._tag !== "RunCompleted" || recordedCompletion.runId !== runId) return yield* RunJournalError.make({ message: `Run ${runId} has an invalid terminal completion marker` });
|
|
5168
|
-
const response = [...records].reverse().find((envelope) => envelope.record.payload._tag === "ModelResponseRecorded" && envelope.record.payload.runId === runId)?.record.payload;
|
|
5169
|
-
if (response?._tag !== "ModelResponseRecorded") return yield* RunJournalError.make({ message: `Run ${runId} has a terminal completion marker without a response` });
|
|
5170
|
-
const calls = (yield* declaredToolCalls(response.messages)).application;
|
|
5171
|
-
if (calls.length > 0) {
|
|
5172
|
-
const call = calls[0];
|
|
5173
|
-
const settled = call === void 0 ? void 0 : records.find(({ record }) => record.payload._tag === "ToolCallSettled" && record.payload.runId === runId && record.payload.toolCallId === call.id)?.record.payload;
|
|
5174
|
-
if (calls.length !== 1 || call === void 0 || settled?._tag !== "ToolCallSettled" || settled.toolName !== call.name || settled.isFailure) return yield* RunJournalError.make({ message: `Run ${runId} has a terminal completion marker without one successful declared Tool result` });
|
|
5024
|
+
const childLineage = records.find(({ record }) => record.recordId === subagentLineageRecordId(submission.threadId))?.record.payload;
|
|
5025
|
+
const inheritedGrant = submission.workerAdmission?.origin.grant ?? (childLineage?._tag === "SubagentLineageRecorded" ? childLineage.grant : void 0);
|
|
5026
|
+
const delegationDepth = submission.workerAdmission?.origin.depth ?? (childLineage?._tag === "SubagentLineageRecorded" ? childLineage.parentLink.depth : 0);
|
|
5027
|
+
const inheritedBudget = submission.workerAdmission?.origin.budget ?? (childLineage?._tag === "SubagentLineageRecorded" ? childLineage.budget : void 0);
|
|
5028
|
+
if (submission.parentLinkage !== void 0 && (childLineage?._tag !== "SubagentLineageRecorded" || childLineage.parentSubmissionId !== submission.parentLinkage.parentSubmissionId || childLineage.parentLink.parentToolCallId !== submission.parentLinkage.parentToolCallId || !definitionDigestsEqual(childLineage.childDefinitionDigests, submission.agentDigests) || childLineage.childInputDigest !== submission.inputDigest)) return yield* RunJournalError.make({ message: "The child Run has no matching canonical lineage and execution bounds" });
|
|
5029
|
+
const completionTools = [...agent.definition.completion === void 0 ? [] : [agent.definition.completion.tool], ...agent.definition.completionFromTools?.map((declaration) => declaration.tool) ?? []];
|
|
5030
|
+
const pending = yield* pendingToolBatchFor(records, runId, completionTools);
|
|
5031
|
+
const resumeProjection = pending === void 0 ? journal : yield* projectRunJournalStream(withoutPendingBatch(canonical, pending, runId), runId, void 0, priorContext);
|
|
5032
|
+
if (initialJournal !== void 0 && (journal.committedTurns !== 0 || journal.historyFrom !== 1 || journal.contextWindowId !== void 0 || historyEvidence.size !== 0 || pending !== void 0 || boundaries.some((boundary) => boundary.incomplete))) initialJournal.cacheable = false;
|
|
5033
|
+
if (initialJournal?.cacheable) initialJournal.history = initialJournal.prefix ?? preparePromptHistory(journal.historyBefore);
|
|
5034
|
+
if (initialJournal !== void 0) initialJournal.records = void 0;
|
|
5035
|
+
const rolloverOperation = journal.pendingContextToolCallId === void 0 ? void 0 : operationsFor(records, runId).get(journal.pendingContextToolCallId);
|
|
5036
|
+
const rolloverTool = rolloverOperation === void 0 ? void 0 : agent.definition.toolkit.tools[rolloverOperation.toolName];
|
|
5037
|
+
const pendingContextToolCallId = rolloverOperation !== void 0 && rolloverTool !== void 0 && Context.get(rolloverTool.annotations, ContextRolloverTool) && currentContracts[rolloverOperation.toolName] === rolloverOperation.replay ? journal.pendingContextToolCallId : void 0;
|
|
5038
|
+
const applicationCalls = pending?.calls.filter((call) => !call.providerExecuted);
|
|
5039
|
+
const completionCandidate = applicationCalls?.length === 1 && completionTools.some((tool) => tool === applicationCalls[0]?.name) && pending?.settled.some((result) => result.id === applicationCalls[0]?.id && !result.isFailure) ? applicationCalls[0] : void 0;
|
|
5040
|
+
const settledCompletion = pending !== void 0 && completionCandidate !== void 0 && supportsOperation(OpenToolCallEvidence.make({
|
|
5041
|
+
toolCallId: Schema.decodeSync(ToolCallId)(completionCandidate.id),
|
|
5042
|
+
toolName: completionCandidate.name,
|
|
5043
|
+
turn: pending.turn
|
|
5044
|
+
}), pending.toolOperations.find((operation) => operation.toolCallId === completionCandidate.id), {
|
|
5045
|
+
definition: agent.definition,
|
|
5046
|
+
contracts: currentContracts
|
|
5047
|
+
}) ? Schema.decodeSync(ToolCallId)(completionCandidate.id) : void 0;
|
|
5048
|
+
const knownIds = knownRecordIdsOf(records);
|
|
5049
|
+
const stepOutputs = /* @__PURE__ */ new Map();
|
|
5050
|
+
for (const envelope of records) {
|
|
5051
|
+
const payload = envelope.record.payload;
|
|
5052
|
+
if (payload._tag === "ToolStepSettled" && payload.runId === runId) stepOutputs.set(toolStepSettledRecordId(runId, payload.toolCallId, payload.stepName), payload.output);
|
|
5175
5053
|
}
|
|
5176
|
-
|
|
5177
|
-
|
|
5178
|
-
|
|
5179
|
-
|
|
5180
|
-
|
|
5181
|
-
|
|
5182
|
-
usageSummary: yield* currentUsageSummary()
|
|
5183
|
-
};
|
|
5184
|
-
}
|
|
5185
|
-
let ownerFirstSequence;
|
|
5186
|
-
for (const envelope of records) {
|
|
5187
|
-
const payload = envelope.record.payload;
|
|
5188
|
-
if ("runId" in payload && payload.runId === runId) {
|
|
5189
|
-
ownerFirstSequence = envelope.sequence;
|
|
5190
|
-
break;
|
|
5054
|
+
const canonicalApprovalDecisions = /* @__PURE__ */ new Map();
|
|
5055
|
+
const approvalRequestedTurns = /* @__PURE__ */ new Set();
|
|
5056
|
+
for (const envelope of records) {
|
|
5057
|
+
const payload = envelope.record.payload;
|
|
5058
|
+
if (payload._tag === "ToolApprovalDecided" && payload.runId === runId) canonicalApprovalDecisions.set(payload.toolCallId, payload.decision);
|
|
5059
|
+
else if (payload._tag === "ToolApprovalRequested" && payload.runId === runId) approvalRequestedTurns.add(payload.turn);
|
|
5191
5060
|
}
|
|
5192
|
-
|
|
5193
|
-
|
|
5194
|
-
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
if (declaredToolIds.size > 4096) return yield* RunJournalError.make({ message: `Run exceeds the ${MAX_RUN_TOOL_CALL_IDENTITIES} Tool Call identity limit` });
|
|
5202
|
-
for (const [callId, name] of subagentState.declaredNames) declaredNamesByCallId.set(callId, name);
|
|
5203
|
-
if (pending !== void 0) for (const call of pending.calls) {
|
|
5204
|
-
encodedParamsByCallId.set(call.id, call.params);
|
|
5205
|
-
declaredNamesByCallId.set(call.id, call.name);
|
|
5206
|
-
}
|
|
5207
|
-
let resumeLeadingMessages;
|
|
5208
|
-
let resumeResponseMessages;
|
|
5209
|
-
if (pending !== void 0) {
|
|
5210
|
-
const pendingMessages = yield* decodePrompt(pending.messages).pipe(Effect.mapError((cause) => RunJournalError.make({
|
|
5211
|
-
message: "Pending ModelResponseRecorded messages are not Schema-encoded Prompt messages",
|
|
5212
|
-
cause
|
|
5213
|
-
})));
|
|
5214
|
-
const firstAssistant = pendingMessages.content.findIndex((message) => message.role === "assistant");
|
|
5215
|
-
if (firstAssistant > 0) resumeLeadingMessages = Prompt.fromMessages(pendingMessages.content.slice(0, firstAssistant).filter((message) => message.role !== "system"));
|
|
5216
|
-
if (firstAssistant >= 0) resumeResponseMessages = Prompt.fromMessages(pendingMessages.content.slice(firstAssistant));
|
|
5217
|
-
}
|
|
5218
|
-
const initialDispatchProofTurns = new Set(initialDispatchBlockedTurns(records, runId));
|
|
5219
|
-
let currentToolTurn = pending === void 0 ? void 0 : {
|
|
5220
|
-
turn: pending.turn,
|
|
5221
|
-
turnId: pending.turnId
|
|
5222
|
-
};
|
|
5223
|
-
const haltRef = yield* Ref.make(void 0);
|
|
5224
|
-
const yieldSignal = yield* Deferred.make();
|
|
5225
|
-
const recordHalt = (effect) => effect.pipe(Effect.tapError((failure) => failure instanceof ThreadStoreError && failure.cause instanceof AgentPersistenceCapacityError ? Effect.void : Ref.set(haltRef, failure)), Effect.catchCause((cause) => Effect.failCause(Cause.map(cause, (failure) => failure instanceof ThreadStoreError && failure.cause instanceof AgentPersistenceCapacityError ? failure.cause : new CoordinatorHalt(failure)))));
|
|
5226
|
-
const checkpoint = recordHalt(Effect.gen(function* () {
|
|
5227
|
-
const failure = yield* Ref.get(haltRef);
|
|
5228
|
-
if (failure !== void 0) return yield* failure;
|
|
5229
|
-
const progress = progressWriters.get(ctx);
|
|
5230
|
-
if (progress !== void 0) yield* progress.check(runId).pipe(Effect.provideService(CurrentRunWriter, ctx));
|
|
5231
|
-
}));
|
|
5232
|
-
const responseGate = yield* Semaphore.make(1);
|
|
5233
|
-
let deferredResponse;
|
|
5234
|
-
const acceptResponseDeclarations = (batch) => {
|
|
5235
|
-
for (const record of batch.records) {
|
|
5236
|
-
if (record.payload._tag !== "ModelResponseRecorded") continue;
|
|
5237
|
-
for (const call of record.payload.toolOperations) {
|
|
5238
|
-
declaredToolIds.add(call.toolCallId);
|
|
5239
|
-
declaredNamesByCallId.set(call.toolCallId, call.toolName);
|
|
5061
|
+
const approvalIntents = /* @__PURE__ */ new Map();
|
|
5062
|
+
for (const intent of approvalDecisions) approvalIntents.set(intent.toolCallId, intent);
|
|
5063
|
+
const joinedInputEnvelopes = /* @__PURE__ */ new Map();
|
|
5064
|
+
let lastHostResponseSequence;
|
|
5065
|
+
for (const envelope of records) {
|
|
5066
|
+
const payload = envelope.record.payload;
|
|
5067
|
+
if (payload._tag === "UserInputRecorded" && payload.runId === runId && payload.submissionId !== void 0 && payload.submissionId !== submissionId) joinedInputEnvelopes.set(payload.submissionId, envelope);
|
|
5068
|
+
else if (payload._tag === "ModelResponseRecorded" && payload.runId === runId) {
|
|
5069
|
+
if (lastHostResponseSequence === void 0 || envelope.sequence > lastHostResponseSequence) lastHostResponseSequence = envelope.sequence;
|
|
5240
5070
|
}
|
|
5241
5071
|
}
|
|
5242
|
-
|
|
5243
|
-
|
|
5244
|
-
const
|
|
5245
|
-
|
|
5246
|
-
|
|
5247
|
-
|
|
5248
|
-
|
|
5249
|
-
|
|
5250
|
-
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
5254
|
-
|
|
5255
|
-
|
|
5256
|
-
acceptResponseDeclarations(batch);
|
|
5257
|
-
for (const call of calls.application) encodedParamsByCallId.set(call.id, call.params);
|
|
5258
|
-
recordCommittedUsage(batch);
|
|
5259
|
-
for (const entry of batch.records) knownIds.add(entry.recordId);
|
|
5260
|
-
deferredResponse = void 0;
|
|
5261
|
-
yield* hit("turn:after-response-append");
|
|
5262
|
-
});
|
|
5263
|
-
const flushDeferredResponse = promoteResponse.pipe(Effect.tapError((failure) => failure instanceof ThreadStoreError && failure.cause instanceof AgentPersistenceCapacityError ? Effect.void : Ref.set(haltRef, failure)), responseGate.withPermits(1));
|
|
5264
|
-
let initialHistoryLength = 0;
|
|
5265
|
-
let initialInstructions = [];
|
|
5266
|
-
const completionState = {};
|
|
5267
|
-
const turnCounter = yield* Ref.make(journal.committedTurns + (journal.policyUsage.modelRestarts ?? 0));
|
|
5268
|
-
const idGenerator = {
|
|
5269
|
-
nextThreadId: Effect.succeed(submission.threadId),
|
|
5270
|
-
nextRunId: Effect.succeed(runId),
|
|
5271
|
-
nextTurnId: Ref.modify(turnCounter, (turn) => [turnIdForRun(runId, turn + 1), turn + 1])
|
|
5272
|
-
};
|
|
5273
|
-
const instructionView = (messages, instructions, insertWhenAbsent, priorRunPrefixLength) => {
|
|
5274
|
-
const projected = [];
|
|
5275
|
-
const lengths = [0];
|
|
5276
|
-
let inserted = false;
|
|
5277
|
-
for (const [index, message] of messages.entries()) {
|
|
5278
|
-
if (index >= priorRunPrefixLength && message.role === "system") {
|
|
5279
|
-
if (!inserted) projected.push(...instructions);
|
|
5280
|
-
inserted = true;
|
|
5281
|
-
} else projected.push(message);
|
|
5282
|
-
lengths.push(projected.length);
|
|
5283
|
-
}
|
|
5284
|
-
if (!inserted && insertWhenAbsent) projected.push(...instructions);
|
|
5285
|
-
return {
|
|
5286
|
-
messages: projected,
|
|
5287
|
-
prefixLength: (length) => lengths[length] ?? projected.length
|
|
5072
|
+
const stagedUsage = /* @__PURE__ */ new Map();
|
|
5073
|
+
const committedUsageLengths = /* @__PURE__ */ new Map();
|
|
5074
|
+
const committedUnobservedCalls = /* @__PURE__ */ new Map();
|
|
5075
|
+
const usageForCommit = (turn) => {
|
|
5076
|
+
const staged = stagedUsage.get(turn);
|
|
5077
|
+
if (staged === void 0) return void 0;
|
|
5078
|
+
const modelUsage = staged.modelUsage.slice(committedUsageLengths.get(turn) ?? 0);
|
|
5079
|
+
if (modelUsage.length === 0) return void 0;
|
|
5080
|
+
return {
|
|
5081
|
+
modelUsage,
|
|
5082
|
+
inputTokens: modelUsage.reduce((sum, call) => sum + call.inputTokens.total, 0),
|
|
5083
|
+
outputTokens: modelUsage.reduce((sum, call) => sum + call.outputTokens.total, 0),
|
|
5084
|
+
costMicrousd: modelUsage.reduce((sum, call) => sum + call.costMicrousd, 0)
|
|
5085
|
+
};
|
|
5288
5086
|
};
|
|
5289
|
-
|
|
5290
|
-
|
|
5291
|
-
|
|
5292
|
-
|
|
5293
|
-
|
|
5294
|
-
|
|
5295
|
-
|
|
5296
|
-
|
|
5087
|
+
const unobservedForCommit = (turn) => (stagedUnobservedCalls.get(turn) ?? 0) - (committedUnobservedCalls.get(turn) ?? 0);
|
|
5088
|
+
const recordCommittedUsage = (batch) => {
|
|
5089
|
+
for (const record of batch.records) {
|
|
5090
|
+
if (record.payload._tag !== "ModelResponseRecorded" && record.payload._tag !== "ModelCallAborted") continue;
|
|
5091
|
+
const payload = record.payload;
|
|
5092
|
+
committedUsageLengths.set(payload.turn, (committedUsageLengths.get(payload.turn) ?? 0) + (payload.modelUsage?.length ?? 0));
|
|
5093
|
+
committedUnobservedCalls.set(payload.turn, (committedUnobservedCalls.get(payload.turn) ?? 0) + (payload.unobservedModelCalls ?? 0));
|
|
5094
|
+
}
|
|
5095
|
+
progressWriters.get(ctx)?.stageUsage(runId, terminalUsageCharge(uncommittedModelUsage()));
|
|
5297
5096
|
};
|
|
5298
|
-
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
|
|
5302
|
-
|
|
5303
|
-
|
|
5304
|
-
|
|
5305
|
-
|
|
5306
|
-
|
|
5307
|
-
|
|
5308
|
-
|
|
5309
|
-
|
|
5310
|
-
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
const durability = {
|
|
5314
|
-
toolResultMaxBytes: MAX_PERSISTED_JSON_BYTES,
|
|
5315
|
-
checkpoint,
|
|
5316
|
-
initialize: ({ initialHistory, priorHistoryLength }) => recordHalt(Effect.gen(function* () {
|
|
5317
|
-
initialHistoryLength = initialHistory.content.length;
|
|
5318
|
-
initialInstructions = initialHistory.content.slice(priorHistoryLength).filter((message) => message.role === "system");
|
|
5319
|
-
if (priorContext !== void 0) return;
|
|
5320
|
-
const recordId = decodeRecordIdSync(JSON.stringify(["run-context@1", runId]));
|
|
5321
|
-
const prompt = yield* Schema.encodeEffect(Prompt.Prompt)(Prompt.fromMessages(initialHistory.content.slice(priorHistoryLength))).pipe(Effect.flatMap(decodePersisted), Effect.mapError((cause) => RunJournalError.make({
|
|
5322
|
-
message: "Original Run context exceeds persistence bounds",
|
|
5097
|
+
const uncommittedModelUsage = () => [...stagedUsage.entries()].flatMap(([turn, usage]) => usage.modelUsage.slice(committedUsageLengths.get(turn) ?? 0));
|
|
5098
|
+
const stagedUnobservedCalls = /* @__PURE__ */ new Map();
|
|
5099
|
+
let interruptedUsage = records.some(({ record }) => record.payload._tag === "ModelResponseInterrupted" && record.payload.runId === runId);
|
|
5100
|
+
const checkedUsageTotal = (field, value) => decodeUsageTotal(value).pipe(Effect.mapError((cause) => RunJournalError.make({
|
|
5101
|
+
message: `Run usage summary exceeds safe-integer bounds at ${field}`,
|
|
5102
|
+
cause
|
|
5103
|
+
})));
|
|
5104
|
+
const subtractUsageTotal = (field, left, right) => checkedUsageTotal(field, left - right);
|
|
5105
|
+
const currentUsageSummary = () => Effect.gen(function* () {
|
|
5106
|
+
const stagedCalls = [...stagedUsage.values()].flatMap((usage) => usage.modelUsage);
|
|
5107
|
+
let unobservedModelCalls = journal.usage.unobservedModelCalls ?? 0;
|
|
5108
|
+
for (const count of stagedUnobservedCalls.values()) unobservedModelCalls += count;
|
|
5109
|
+
const detailedCalls = [...journal.usage.modelUsage, ...stagedCalls];
|
|
5110
|
+
const detailed = yield* summarizeModelUsage(detailedCalls, journal.usage.summarizedModelUsage).pipe(Effect.mapError((cause) => RunJournalError.make({
|
|
5111
|
+
message: "Run detailed usage exceeds safe-integer accounting bounds",
|
|
5323
5112
|
cause
|
|
5324
5113
|
})));
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
|
|
5332
|
-
|
|
5333
|
-
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
5114
|
+
let inputTokens = journal.usage.inputTokens;
|
|
5115
|
+
let outputTokens = journal.usage.outputTokens;
|
|
5116
|
+
let costMicrousd = journal.usage.costMicrousd;
|
|
5117
|
+
for (const usage of stagedUsage.values()) {
|
|
5118
|
+
inputTokens += usage.inputTokens;
|
|
5119
|
+
outputTokens += usage.outputTokens;
|
|
5120
|
+
costMicrousd += usage.costMicrousd;
|
|
5121
|
+
}
|
|
5122
|
+
const modelCalls = journal.usage.modelCalls + stagedCalls.length;
|
|
5123
|
+
const legacyCalls = yield* subtractUsageTotal("legacy.modelCalls", modelCalls, detailed.modelCalls);
|
|
5124
|
+
const legacyInput = yield* subtractUsageTotal("legacy.inputTokens", inputTokens, detailed.inputTokens.total);
|
|
5125
|
+
const legacyOutput = yield* subtractUsageTotal("legacy.outputTokens", outputTokens, detailed.outputTokens.total);
|
|
5126
|
+
const legacyCost = yield* subtractUsageTotal("legacy.costMicrousd", costMicrousd, detailed.costMicrousd);
|
|
5127
|
+
if (legacyCalls === 0 && (legacyInput !== 0 || legacyOutput !== 0 || legacyCost !== 0)) return yield* RunJournalError.make({ message: "Run aggregate usage has legacy totals without a legacy model call" });
|
|
5128
|
+
const byModel = [...detailed.byModel];
|
|
5129
|
+
if (legacyCalls > 0) {
|
|
5130
|
+
const existingIndex = byModel.findIndex((group) => group.provider === "unknown" && group.model === "legacy-record" && group.responseModel === void 0 && group.serviceTier === void 0 && group.pricingVersion === void 0);
|
|
5131
|
+
const existing = existingIndex < 0 ? void 0 : byModel[existingIndex];
|
|
5132
|
+
const legacyGroup = yield* ModelUsageGroup.makeEffect({
|
|
5133
|
+
provider: "unknown",
|
|
5134
|
+
model: "legacy-record",
|
|
5135
|
+
modelCalls: (existing?.modelCalls ?? 0) + legacyCalls,
|
|
5136
|
+
inputTokens: {
|
|
5137
|
+
total: (existing?.inputTokens.total ?? 0) + legacyInput,
|
|
5138
|
+
uncached: (existing?.inputTokens.uncached ?? 0) + legacyInput,
|
|
5139
|
+
cacheRead: existing?.inputTokens.cacheRead ?? 0,
|
|
5140
|
+
cacheWrite: existing?.inputTokens.cacheWrite ?? 0
|
|
5141
|
+
},
|
|
5142
|
+
outputTokens: {
|
|
5143
|
+
total: (existing?.outputTokens.total ?? 0) + legacyOutput,
|
|
5144
|
+
text: (existing?.outputTokens.text ?? 0) + legacyOutput,
|
|
5145
|
+
reasoning: existing?.outputTokens.reasoning ?? 0
|
|
5146
|
+
},
|
|
5147
|
+
costMicrousd: (existing?.costMicrousd ?? 0) + legacyCost
|
|
5148
|
+
}).pipe(Effect.mapError((cause) => RunJournalError.make({
|
|
5149
|
+
message: "Run legacy usage exceeds safe-integer accounting bounds",
|
|
5150
|
+
cause
|
|
5151
|
+
})));
|
|
5152
|
+
if (existingIndex < 0) byModel.push(legacyGroup);
|
|
5153
|
+
else byModel[existingIndex] = legacyGroup;
|
|
5154
|
+
}
|
|
5155
|
+
return yield* RunUsageSummary.makeEffect({
|
|
5156
|
+
...legacyCalls === 0 && detailed.webSearchCalls !== void 0 ? { webSearchCalls: detailed.webSearchCalls } : {},
|
|
5157
|
+
modelCalls,
|
|
5158
|
+
inputTokens: {
|
|
5159
|
+
total: inputTokens,
|
|
5160
|
+
uncached: detailed.inputTokens.uncached + legacyInput,
|
|
5161
|
+
cacheRead: detailed.inputTokens.cacheRead,
|
|
5162
|
+
cacheWrite: detailed.inputTokens.cacheWrite
|
|
5163
|
+
},
|
|
5164
|
+
outputTokens: {
|
|
5165
|
+
total: outputTokens,
|
|
5166
|
+
text: detailed.outputTokens.text + legacyOutput,
|
|
5167
|
+
reasoning: detailed.outputTokens.reasoning
|
|
5168
|
+
},
|
|
5169
|
+
costMicrousd,
|
|
5170
|
+
byModel,
|
|
5171
|
+
unobservedModelCalls,
|
|
5172
|
+
usageStatus: legacyCalls > 0 || unobservedModelCalls > 0 || interruptedUsage ? detailed.usageStatus === "unknown" ? "unknown" : "partial" : detailed.usageStatus,
|
|
5173
|
+
pricingStatus: legacyCalls > 0 || unobservedModelCalls > 0 || interruptedUsage ? detailed.pricingStatus === "unknown" ? "unknown" : "partial" : detailed.pricingStatus
|
|
5348
5174
|
}).pipe(Effect.mapError((cause) => RunJournalError.make({
|
|
5349
|
-
message: "
|
|
5175
|
+
message: "Run usage summary exceeds safe-integer accounting bounds",
|
|
5350
5176
|
cause
|
|
5351
5177
|
})));
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
if (
|
|
5360
|
-
const
|
|
5361
|
-
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
}
|
|
5178
|
+
});
|
|
5179
|
+
const activeExecution = yield* reader.readExecution({
|
|
5180
|
+
threadId: ctx.threadId,
|
|
5181
|
+
runId
|
|
5182
|
+
});
|
|
5183
|
+
const recordedCompletion = Option.isSome(activeExecution) ? activeExecution.value.operational.find((record) => record.recordId === runCompletedRecordId(runId))?.payload : void 0;
|
|
5184
|
+
if (recordedCompletion !== void 0) {
|
|
5185
|
+
if (recordedCompletion._tag !== "RunCompleted" || recordedCompletion.runId !== runId) return yield* RunJournalError.make({ message: `Run ${runId} has an invalid terminal completion marker` });
|
|
5186
|
+
const response = [...records].reverse().find((envelope) => envelope.record.payload._tag === "ModelResponseRecorded" && envelope.record.payload.runId === runId)?.record.payload;
|
|
5187
|
+
if (response?._tag !== "ModelResponseRecorded") return yield* RunJournalError.make({ message: `Run ${runId} has a terminal completion marker without a response` });
|
|
5188
|
+
const calls = (yield* declaredToolCalls(response.messages)).application;
|
|
5189
|
+
if (calls.length > 0) {
|
|
5190
|
+
const call = calls[0];
|
|
5191
|
+
const settled = call === void 0 ? void 0 : records.find(({ record }) => record.payload._tag === "ToolCallSettled" && record.payload.runId === runId && record.payload.toolCallId === call.id)?.record.payload;
|
|
5192
|
+
if (calls.length !== 1 || call === void 0 || settled?._tag !== "ToolCallSettled" || settled.toolName !== call.name || settled.isFailure) return yield* RunJournalError.make({ message: `Run ${runId} has a terminal completion marker without one successful declared Tool result` });
|
|
5193
|
+
}
|
|
5194
|
+
return {
|
|
5195
|
+
_tag: "completed",
|
|
5196
|
+
result: recordedCompletion.output,
|
|
5197
|
+
...recordedCompletion.runDisposition === void 0 ? {} : { runDisposition: recordedCompletion.runDisposition },
|
|
5198
|
+
...recordedCompletion.finishReason === void 0 ? {} : { finishReason: recordedCompletion.finishReason },
|
|
5199
|
+
...recordedCompletion.exhausted === void 0 ? {} : { exhausted: recordedCompletion.exhausted },
|
|
5200
|
+
usageSummary: yield* currentUsageSummary()
|
|
5201
|
+
};
|
|
5202
|
+
}
|
|
5203
|
+
let ownerFirstSequence;
|
|
5204
|
+
for (const envelope of records) {
|
|
5205
|
+
const payload = envelope.record.payload;
|
|
5206
|
+
if ("runId" in payload && payload.runId === runId) {
|
|
5207
|
+
ownerFirstSequence = envelope.sequence;
|
|
5208
|
+
break;
|
|
5209
|
+
}
|
|
5210
|
+
}
|
|
5211
|
+
/** Only canonical joined inputs can require restoration from an earlier Attempt. */
|
|
5212
|
+
let joinBacklog = joinedInputEnvelopes.size === 0 ? [] : void 0;
|
|
5213
|
+
/** Joined inputs already handed to the engine during THIS Attempt (never re-deliver). */
|
|
5214
|
+
const deliveredJoinInputs = /* @__PURE__ */ new Set();
|
|
5215
|
+
const encodedParamsByCallId = /* @__PURE__ */ new Map();
|
|
5216
|
+
const declaredNamesByCallId = /* @__PURE__ */ new Map();
|
|
5217
|
+
const subagentState = subagentRecordsOf(records, runId);
|
|
5218
|
+
const declaredToolIds = new Set(subagentState.declaredNames.keys());
|
|
5219
|
+
if (declaredToolIds.size > 4096) return yield* RunJournalError.make({ message: `Run exceeds the ${MAX_RUN_TOOL_CALL_IDENTITIES} Tool Call identity limit` });
|
|
5220
|
+
for (const [callId, name] of subagentState.declaredNames) declaredNamesByCallId.set(callId, name);
|
|
5221
|
+
if (pending !== void 0) for (const call of pending.calls) {
|
|
5222
|
+
encodedParamsByCallId.set(call.id, call.params);
|
|
5223
|
+
declaredNamesByCallId.set(call.id, call.name);
|
|
5224
|
+
}
|
|
5225
|
+
let resumeLeadingMessages;
|
|
5226
|
+
let resumeResponseMessages;
|
|
5227
|
+
if (pending !== void 0) {
|
|
5228
|
+
const pendingMessages = yield* decodePrompt(pending.messages).pipe(Effect.mapError((cause) => RunJournalError.make({
|
|
5229
|
+
message: "Pending ModelResponseRecorded messages are not Schema-encoded Prompt messages",
|
|
5230
|
+
cause
|
|
5231
|
+
})));
|
|
5232
|
+
const firstAssistant = pendingMessages.content.findIndex((message) => message.role === "assistant");
|
|
5233
|
+
if (firstAssistant > 0) resumeLeadingMessages = Prompt.fromMessages(pendingMessages.content.slice(0, firstAssistant).filter((message) => message.role !== "system"));
|
|
5234
|
+
if (firstAssistant >= 0) resumeResponseMessages = Prompt.fromMessages(pendingMessages.content.slice(firstAssistant));
|
|
5235
|
+
}
|
|
5236
|
+
const initialDispatchProofTurns = new Set(initialDispatchBlockedTurns(records, runId));
|
|
5237
|
+
let currentToolTurn = pending === void 0 ? void 0 : {
|
|
5238
|
+
turn: pending.turn,
|
|
5239
|
+
turnId: pending.turnId
|
|
5240
|
+
};
|
|
5241
|
+
const haltRef = yield* Ref.make(void 0);
|
|
5242
|
+
const yieldSignal = yield* Deferred.make();
|
|
5243
|
+
const recordHalt = (effect) => Effect.catchCause(effect, (cause) => {
|
|
5244
|
+
const first = Cause.findErrorOption(cause);
|
|
5245
|
+
const failure = Effect.failCause(Cause.map(cause, (error) => error instanceof ThreadStoreError && error.cause instanceof AgentPersistenceCapacityError ? error.cause : new CoordinatorHalt(error)));
|
|
5246
|
+
return Option.isNone(first) || first.value instanceof ThreadStoreError && first.value.cause instanceof AgentPersistenceCapacityError ? failure : Effect.andThen(Ref.set(haltRef, first.value), failure);
|
|
5247
|
+
});
|
|
5248
|
+
const progress = progressWriters.get(ctx);
|
|
5249
|
+
const checkProgress = progress === void 0 ? Effect.void : progress.check(runId).pipe(Effect.provideService(CurrentRunWriter, ctx));
|
|
5250
|
+
const checkpoint = recordHalt(Effect.flatMap(Ref.get(haltRef), (failure) => failure === void 0 ? checkProgress : Effect.fail(failure)));
|
|
5251
|
+
const responseGate = yield* Semaphore.make(1);
|
|
5252
|
+
let deferredResponse;
|
|
5253
|
+
const acceptResponseDeclarations = (batch) => {
|
|
5254
|
+
for (const record of batch.records) {
|
|
5255
|
+
if (record.payload._tag !== "ModelResponseRecorded") continue;
|
|
5256
|
+
for (const call of record.payload.toolOperations) {
|
|
5257
|
+
declaredToolIds.add(call.toolCallId);
|
|
5258
|
+
declaredNamesByCallId.set(call.toolCallId, call.toolName);
|
|
5259
|
+
}
|
|
5260
|
+
}
|
|
5261
|
+
};
|
|
5262
|
+
const promoteResponse = Effect.gen(function* () {
|
|
5263
|
+
const halted = yield* Ref.get(haltRef);
|
|
5264
|
+
if (halted !== void 0) return yield* halted;
|
|
5265
|
+
const deferred = deferredResponse;
|
|
5266
|
+
if (deferred === void 0) return;
|
|
5267
|
+
const record = deferred.batch.records[0];
|
|
5268
|
+
if (record?.payload._tag !== "ModelResponseRecorded") return yield* RunJournalError.make({ message: "Deferred Turn has no owned response" });
|
|
5269
|
+
const calls = yield* declaredToolCalls(record.payload.messages);
|
|
5368
5270
|
const batch = CanonicalBatch.make({
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
records: [record]
|
|
5271
|
+
...deferred.batch,
|
|
5272
|
+
batchId: turnResponseBatchId(runId, deferred.turn)
|
|
5372
5273
|
});
|
|
5373
5274
|
yield* appendBatch(ctx, batch);
|
|
5275
|
+
acceptResponseDeclarations(batch);
|
|
5276
|
+
for (const call of calls.application) encodedParamsByCallId.set(call.id, call.params);
|
|
5374
5277
|
recordCommittedUsage(batch);
|
|
5375
|
-
knownIds.add(recordId);
|
|
5376
|
-
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
|
|
5381
|
-
|
|
5382
|
-
|
|
5383
|
-
|
|
5384
|
-
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
const deferred = deferredResponse;
|
|
5400
|
-
if (commit._tag === "Response" && deferred !== void 0) return yield* RunJournalError.make({ message: "Turn response was already deferred" });
|
|
5401
|
-
const responseId = modelResponseRecordId(runId, commit.turn);
|
|
5402
|
-
const suppliedResponse = commit._tag === "Partial" ? void 0 : commit.response;
|
|
5403
|
-
const response = knownIds.has(responseId) || deferred !== void 0 ? void 0 : suppliedResponse;
|
|
5404
|
-
if (suppliedResponse !== void 0) currentToolTurn = {
|
|
5405
|
-
turn: commit.turn,
|
|
5406
|
-
turnId: commit.turnId
|
|
5407
|
-
};
|
|
5408
|
-
if (commit._tag === "Response" && response === void 0) return "committed";
|
|
5409
|
-
const toolOperations = [];
|
|
5410
|
-
const responseToolIds = /* @__PURE__ */ new Set();
|
|
5411
|
-
for (const call of response?.calls ?? []) {
|
|
5412
|
-
if (declaredToolIds.has(call.toolCallId) || responseToolIds.has(call.toolCallId)) return yield* RunJournalError.make({ message: "Tool Call identity is reused within a Run" });
|
|
5413
|
-
if (declaredToolIds.size + responseToolIds.size + 1 > 4096) return yield* RunJournalError.make({ message: `Run exceeds the ${MAX_RUN_TOOL_CALL_IDENTITIES} Tool Call identity limit` });
|
|
5414
|
-
const replay = currentContracts[call.toolName];
|
|
5415
|
-
if (replay === void 0) return yield* RunJournalError.make({ message: "Canonical Tool declaration has no original operation contract" });
|
|
5416
|
-
toolOperations.push(ToolOperation.make({
|
|
5417
|
-
toolCallId: call.toolCallId,
|
|
5418
|
-
toolName: call.toolName,
|
|
5419
|
-
executionClass: call.executionClass,
|
|
5420
|
-
executionKind: call.executionKind,
|
|
5421
|
-
replay
|
|
5422
|
-
}));
|
|
5423
|
-
responseToolIds.add(call.toolCallId);
|
|
5278
|
+
for (const entry of batch.records) knownIds.add(entry.recordId);
|
|
5279
|
+
deferredResponse = void 0;
|
|
5280
|
+
yield* hit("turn:after-response-append");
|
|
5281
|
+
});
|
|
5282
|
+
const flushDeferredResponse = promoteResponse.pipe(Effect.tapError((failure) => failure instanceof ThreadStoreError && failure.cause instanceof AgentPersistenceCapacityError ? Effect.void : Ref.set(haltRef, failure)), responseGate.withPermits(1));
|
|
5283
|
+
let initialHistoryLength = 0;
|
|
5284
|
+
let initialInstructions = [];
|
|
5285
|
+
const completionState = {};
|
|
5286
|
+
const turnCounter = yield* Ref.make(journal.committedTurns + (journal.policyUsage.modelRestarts ?? 0));
|
|
5287
|
+
const idGenerator = {
|
|
5288
|
+
nextThreadId: Effect.succeed(submission.threadId),
|
|
5289
|
+
nextRunId: Effect.succeed(runId),
|
|
5290
|
+
nextTurnId: Ref.modify(turnCounter, (turn) => [turnIdForRun(runId, turn + 1), turn + 1])
|
|
5291
|
+
};
|
|
5292
|
+
const instructionView = (messages, instructions, insertWhenAbsent, priorRunPrefixLength) => {
|
|
5293
|
+
const projected = [];
|
|
5294
|
+
const lengths = [0];
|
|
5295
|
+
let inserted = false;
|
|
5296
|
+
for (const [index, message] of messages.entries()) {
|
|
5297
|
+
if (index >= priorRunPrefixLength && message.role === "system") {
|
|
5298
|
+
if (!inserted) projected.push(...instructions);
|
|
5299
|
+
inserted = true;
|
|
5300
|
+
} else projected.push(message);
|
|
5301
|
+
lengths.push(projected.length);
|
|
5424
5302
|
}
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5303
|
+
if (!inserted && insertWhenAbsent) projected.push(...instructions);
|
|
5304
|
+
return {
|
|
5305
|
+
messages: projected,
|
|
5306
|
+
prefixLength: (length) => lengths[length] ?? projected.length
|
|
5307
|
+
};
|
|
5308
|
+
};
|
|
5309
|
+
const resumeContext = { prepare: ({ source }) => Effect.sync(() => {
|
|
5310
|
+
const prefix = journal.committedTurns === 0 && priorContext !== void 0 ? priorContext.prompt.content.slice(priorContext.priorHistoryLength) : [];
|
|
5311
|
+
const priorRunPrefixLength = journal.committedTurns === 0 ? resumeProjection.prompt.content.length : resumeProjection.historyBefore.content.length;
|
|
5312
|
+
const view = instructionView(prefix.length === 0 ? resumeProjection.prompt.content : [...resumeProjection.prompt.content, ...prefix], initialInstructions, true, priorRunPrefixLength);
|
|
5313
|
+
return {
|
|
5314
|
+
prompt: Prompt.fromMessages([...view.messages, ...source.content.slice(initialHistoryLength)]),
|
|
5315
|
+
priorRunPrefixLength: view.prefixLength(priorRunPrefixLength)
|
|
5316
|
+
};
|
|
5317
|
+
}) };
|
|
5318
|
+
const externalContext = runContextPreparation.hook;
|
|
5319
|
+
const needsContextReplay = priorContext !== void 0 || journal.committedTurns > 0;
|
|
5320
|
+
const preparedContext = externalContext === void 0 ? needsContextReplay ? resumeContext : void 0 : { prepare: (request) => (needsContextReplay ? resumeContext.prepare(request) : Effect.succeed({
|
|
5321
|
+
prompt: request.source,
|
|
5322
|
+
priorRunPrefixLength: journal.historyBefore.content.length
|
|
5323
|
+
})).pipe(Effect.flatMap(({ prompt, priorRunPrefixLength }) => externalContext.prepare({
|
|
5324
|
+
...request,
|
|
5325
|
+
source: prompt,
|
|
5326
|
+
priorRunPrefixLength
|
|
5327
|
+
})), Effect.map((prepared) => {
|
|
5328
|
+
if (prepared.rollover === void 0 || !knownIds.has(compactionRecordId(runId, request.turn, "rollover"))) return prepared;
|
|
5329
|
+
const { rollover: _, ...retained } = prepared;
|
|
5330
|
+
return retained;
|
|
5331
|
+
})) };
|
|
5332
|
+
const durability = {
|
|
5333
|
+
toolResultMaxBytes: MAX_PERSISTED_JSON_BYTES,
|
|
5334
|
+
checkpoint,
|
|
5335
|
+
initialize: ({ initialHistory, priorHistoryLength }) => recordHalt(Effect.gen(function* () {
|
|
5336
|
+
initialHistoryLength = initialHistory.content.length;
|
|
5337
|
+
initialInstructions = initialHistory.content.slice(priorHistoryLength).filter((message) => message.role === "system");
|
|
5338
|
+
if (priorContext !== void 0) return;
|
|
5339
|
+
const recordId = decodeRecordIdSync(JSON.stringify(["run-context@1", runId]));
|
|
5340
|
+
const prompt = yield* Schema.encodeEffect(Prompt.Prompt)(Prompt.fromMessages(initialHistory.content.slice(priorHistoryLength))).pipe(Effect.flatMap(decodePersisted), Effect.mapError((cause) => RunJournalError.make({
|
|
5341
|
+
message: "Original Run context exceeds persistence bounds",
|
|
5432
5342
|
cause
|
|
5433
5343
|
})));
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
|
|
5344
|
+
const history = Prompt.fromMessages(initialHistory.content.slice(0, priorHistoryLength));
|
|
5345
|
+
const historyDigest = yield* withCrypto(digestPromptHistory(history, initialJournal?.history));
|
|
5346
|
+
const retained = yield* Effect.forEach([...historyEvidence.values()].filter((entry) => entry.sequence < journal.historyFrom).sort((left, right) => left.sequence - right.sequence), (entry) => Effect.gen(function* () {
|
|
5347
|
+
const full = yield* getRecord({
|
|
5348
|
+
threadId: ctx.threadId,
|
|
5349
|
+
recordId: entry.record.recordId
|
|
5350
|
+
});
|
|
5351
|
+
if (Option.isNone(full) || full.value.sequence !== entry.sequence) return yield* RunJournalError.make({ message: "Retained history has no exact canonical fact" });
|
|
5352
|
+
return {
|
|
5353
|
+
...yield* withCrypto(reference(full.value.record)),
|
|
5354
|
+
sequence: entry.sequence
|
|
5355
|
+
};
|
|
5356
|
+
}).pipe(Effect.provideService(ThreadReader, reader)));
|
|
5357
|
+
const payload = yield* RunContextRecorded.makeEffect({
|
|
5358
|
+
version: 1,
|
|
5359
|
+
runId,
|
|
5360
|
+
runScopedInput: prompt,
|
|
5361
|
+
historyFrom: journal.historyFrom,
|
|
5362
|
+
historyThrough: CanonicalSequence.make(originalInput.sequence - 1),
|
|
5363
|
+
retained,
|
|
5364
|
+
historyDigest,
|
|
5365
|
+
priorHistoryLength,
|
|
5366
|
+
...journal.contextWindowId === void 0 ? {} : { contextWindowId: journal.contextWindowId }
|
|
5367
|
+
}).pipe(Effect.mapError((cause) => RunJournalError.make({
|
|
5368
|
+
message: "Original Run context mapping exceeds its bounds",
|
|
5441
5369
|
cause
|
|
5442
5370
|
})));
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
...completion.exhausted === void 0 ? {} : { exhausted: completion.exhausted }
|
|
5449
|
-
} : {}
|
|
5450
|
-
};
|
|
5451
|
-
}
|
|
5452
|
-
if (response === void 0 && deferred === void 0 && toolResults.length === 0 && runCompletion === void 0) return "committed";
|
|
5453
|
-
if (response === void 0 && deferred === void 0 && !knownIds.has(responseId)) return yield* RunJournalError.make({ message: "Tool results or completion preceded the canonical response" });
|
|
5454
|
-
const input = {
|
|
5455
|
-
toolResultMaxBytes: Math.min(agent.definition.policy.toolResultBounds.maxBytes, MAX_PERSISTED_JSON_BYTES),
|
|
5456
|
-
toolSelectionMaxBytes: utf8ByteLength(JSON.stringify({ toolSelection: { toolNames: Object.keys(currentContracts) } })),
|
|
5457
|
-
runId,
|
|
5458
|
-
turn: commit.turn,
|
|
5459
|
-
turnId: commit.turnId,
|
|
5460
|
-
responseMessages: response?.messages ?? [],
|
|
5461
|
-
toolResults,
|
|
5462
|
-
toolOperations,
|
|
5463
|
-
toolExposure: response?.toolExposure,
|
|
5464
|
-
toolParameterRejections: response?.toolParameterRejections,
|
|
5465
|
-
runScopedPrefixLength: response?.runScopedPrefixLength,
|
|
5466
|
-
producerId: config.producerId,
|
|
5467
|
-
deploymentId: config.deploymentId,
|
|
5468
|
-
createdAt: yield* nowUtc,
|
|
5469
|
-
runCompletion,
|
|
5470
|
-
usage: usageForCommit(commit.turn),
|
|
5471
|
-
unobservedModelCalls: unobservedForCommit(commit.turn)
|
|
5472
|
-
};
|
|
5473
|
-
if (commit._tag === "Partial") {
|
|
5474
|
-
for (const result of toolResults) {
|
|
5475
|
-
const batch = yield* withCrypto(turnResultsBatch({
|
|
5476
|
-
...input,
|
|
5477
|
-
toolResults: [result]
|
|
5478
|
-
}));
|
|
5479
|
-
yield* appendBatch(ctx, CanonicalBatch.make({
|
|
5480
|
-
...batch,
|
|
5481
|
-
batchId: toolCallResultBatchId(runId, commit.turn, result.toolCallId)
|
|
5482
|
-
}));
|
|
5483
|
-
for (const record of batch.records) knownIds.add(record.recordId);
|
|
5484
|
-
yield* hit("subagent:after-sibling-settle");
|
|
5485
|
-
}
|
|
5486
|
-
return "committed";
|
|
5487
|
-
}
|
|
5488
|
-
if (commit._tag === "Response" && commit.defer === true) {
|
|
5489
|
-
if (toolOperations.length === 0 || toolOperations.some((call) => call.executionClass !== "readonly" || call.executionKind !== "ordinary")) return yield* RunJournalError.make({ message: "Only ordinary readonly Tool responses may be deferred" });
|
|
5490
|
-
const candidate = {
|
|
5491
|
-
turn: commit.turn,
|
|
5492
|
-
turnId: commit.turnId,
|
|
5493
|
-
batch: yield* withCrypto(turnCanonicalBatch({
|
|
5494
|
-
...input,
|
|
5495
|
-
toolParameterRejections: input.toolParameterRejections?.map((rejection) => ({
|
|
5496
|
-
...rejection,
|
|
5497
|
-
parameters: copyJson(rejection.parameters),
|
|
5498
|
-
error: {
|
|
5499
|
-
...rejection.error,
|
|
5500
|
-
reason: { ...rejection.error.reason }
|
|
5501
|
-
}
|
|
5502
|
-
})),
|
|
5503
|
-
toolExposure: input.toolExposure === void 0 ? void 0 : Snapshot.make({
|
|
5504
|
-
exposedToolNames: [...input.toolExposure.exposedToolNames],
|
|
5505
|
-
...input.toolExposure.selection === void 0 ? {} : { selection: Selection.make({ toolNames: [...input.toolExposure.selection.toolNames] }) }
|
|
5506
|
-
}),
|
|
5507
|
-
usage: input.usage === void 0 ? void 0 : {
|
|
5508
|
-
...input.usage,
|
|
5509
|
-
modelUsage: input.usage.modelUsage?.map((usage) => ModelCallUsage.make({
|
|
5510
|
-
...usage,
|
|
5511
|
-
...usage.response === void 0 ? {} : { response: ModelResponseIdentity.make({ ...usage.response }) },
|
|
5512
|
-
inputTokens: InputTokenUsage.make({ ...usage.inputTokens }),
|
|
5513
|
-
outputTokens: OutputTokenUsage.make({ ...usage.outputTokens })
|
|
5514
|
-
}))
|
|
5515
|
-
}
|
|
5516
|
-
}))
|
|
5517
|
-
};
|
|
5518
|
-
const progress = progressWriters.get(ctx);
|
|
5519
|
-
if (progress === void 0) return yield* ThreadStoreError.make({
|
|
5520
|
-
operation: "reserve readonly dispatch",
|
|
5521
|
-
message: "Dispatch has no scoped progress writer"
|
|
5522
|
-
});
|
|
5523
|
-
const batch = yield* progress.defer(candidate.batch).pipe(Effect.provideService(CurrentRunWriter, ctx));
|
|
5524
|
-
deferredResponse = {
|
|
5525
|
-
...candidate,
|
|
5526
|
-
batch
|
|
5527
|
-
};
|
|
5528
|
-
return "deferred";
|
|
5529
|
-
}
|
|
5530
|
-
let batch;
|
|
5531
|
-
if (deferred === void 0) batch = yield* withCrypto(commit._tag === "Response" ? turnResponseBatch(input) : response === void 0 ? turnResultsBatch(input) : turnCanonicalBatch(input));
|
|
5532
|
-
else if (toolResults.length === 0 && runCompletion === void 0) batch = deferred.batch;
|
|
5533
|
-
else {
|
|
5534
|
-
const results = yield* withCrypto(turnResultsBatch(input));
|
|
5535
|
-
batch = CanonicalBatch.make({
|
|
5536
|
-
...deferred.batch,
|
|
5537
|
-
records: [...deferred.batch.records, ...results.records]
|
|
5538
|
-
});
|
|
5539
|
-
}
|
|
5540
|
-
yield* appendBatch(ctx, batch);
|
|
5541
|
-
for (const call of response?.calls ?? []) {
|
|
5542
|
-
declaredToolIds.add(call.toolCallId);
|
|
5543
|
-
encodedParamsByCallId.set(call.toolCallId, call.parameters);
|
|
5544
|
-
declaredNamesByCallId.set(call.toolCallId, call.toolName);
|
|
5545
|
-
}
|
|
5546
|
-
if (deferred !== void 0) {
|
|
5547
|
-
acceptResponseDeclarations(batch);
|
|
5548
|
-
deferredResponse = void 0;
|
|
5549
|
-
}
|
|
5550
|
-
if (commit._tag === "Response") initialDispatchProofTurns.add(commit.turn);
|
|
5551
|
-
recordCommittedUsage(batch);
|
|
5552
|
-
for (const record of batch.records) knownIds.add(record.recordId);
|
|
5553
|
-
if (runCompletion !== void 0) completionState.committed = runCompletion;
|
|
5554
|
-
yield* hit(commit._tag === "Response" ? "turn:after-response-append" : response === void 0 && deferred === void 0 ? "turn:after-results-append" : "turn:after-canonical-append");
|
|
5555
|
-
return "committed";
|
|
5556
|
-
}).pipe(responseGate.withPermits(1))),
|
|
5557
|
-
checkToolDispatch: recordHalt(Effect.gen(function* () {
|
|
5558
|
-
if (currentToolTurn === void 0) return yield* RunJournalError.make({ message: "Tool dispatch preceded its canonical response" });
|
|
5559
|
-
yield* hit("tools:before-dispatch-fence");
|
|
5560
|
-
yield* ctx.checkActive;
|
|
5561
|
-
initialDispatchProofTurns.delete(currentToolTurn.turn);
|
|
5562
|
-
yield* hit("tools:after-dispatch-fence");
|
|
5563
|
-
})),
|
|
5564
|
-
step: {
|
|
5565
|
-
lookup: (key) => recordHalt(Effect.gen(function* () {
|
|
5566
|
-
yield* flushDeferredResponse;
|
|
5567
|
-
const output = stepOutputs.get(toolStepSettledRecordId(runId, key.toolCallId, key.stepName));
|
|
5568
|
-
return output === void 0 ? Option.none() : Option.some({ encodedOutput: output });
|
|
5371
|
+
yield* (yield* CurrentRunStart).commit(yield* makeEnvelope(recordId, payload));
|
|
5372
|
+
knownIds.add(runStartedRecordId(runId));
|
|
5373
|
+
knownIds.add(recordId);
|
|
5374
|
+
historyEvidence.clear();
|
|
5375
|
+
projectedJournal = void 0;
|
|
5569
5376
|
})),
|
|
5570
|
-
|
|
5571
|
-
yield*
|
|
5572
|
-
const recordId =
|
|
5573
|
-
const
|
|
5377
|
+
commitModelRestart: (restart) => recordHalt(Effect.gen(function* () {
|
|
5378
|
+
if (knownIds.has(modelResponseRecordId(runId, restart.turn))) return yield* RunJournalError.make({ message: "Cannot restart a canonical model response" });
|
|
5379
|
+
const recordId = decodeRecordIdSync(`model-aborted:${runId}:${restart.restart}`);
|
|
5380
|
+
const record = yield* makeEnvelope(recordId, ModelCallAborted.make({
|
|
5574
5381
|
runId,
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
|
|
5578
|
-
|
|
5579
|
-
})
|
|
5580
|
-
|
|
5581
|
-
message: "Durable Step identity exceeds canonical persistence bounds",
|
|
5582
|
-
cause: AgentPersistenceCapacityError.make({ message: "Durable Step identity exceeds canonical persistence bounds" })
|
|
5583
|
-
}))));
|
|
5584
|
-
const progress = progressWriters.get(ctx);
|
|
5585
|
-
if (progress === void 0) return yield* ThreadStoreError.make({
|
|
5586
|
-
operation: "reserve Step dispatch",
|
|
5587
|
-
message: "Dispatch has no scoped progress writer"
|
|
5588
|
-
});
|
|
5589
|
-
return yield* progress.reserve(runId, CanonicalBatch.make({
|
|
5382
|
+
...restart,
|
|
5383
|
+
reason: "joined-input",
|
|
5384
|
+
modelUsage: usageForCommit(restart.turn)?.modelUsage ?? [],
|
|
5385
|
+
unobservedModelCalls: unobservedForCommit(restart.turn)
|
|
5386
|
+
}));
|
|
5387
|
+
const batch = CanonicalBatch.make({
|
|
5590
5388
|
batchId: decodeBatchIdSync(recordId),
|
|
5591
5389
|
producerId: config.producerId,
|
|
5592
|
-
records: [
|
|
5593
|
-
})
|
|
5390
|
+
records: [record]
|
|
5391
|
+
});
|
|
5392
|
+
yield* appendBatch(ctx, batch);
|
|
5393
|
+
recordCommittedUsage(batch);
|
|
5394
|
+
knownIds.add(recordId);
|
|
5594
5395
|
})),
|
|
5595
|
-
|
|
5396
|
+
reservePolicyUsage: (usage) => recordHalt(Effect.gen(function* () {
|
|
5596
5397
|
yield* flushDeferredResponse;
|
|
5597
|
-
const recordId =
|
|
5398
|
+
const recordId = decodeRecordIdSync(`policy:${runId}:${usage.programmaticToolCalls}:${usage.finalizationUsed}`);
|
|
5598
5399
|
if (knownIds.has(recordId)) return;
|
|
5599
|
-
const
|
|
5600
|
-
operation: "commit Step result",
|
|
5601
|
-
message: "Durable Step output exceeds canonical persistence bounds",
|
|
5602
|
-
cause: AgentPersistenceCapacityError.make({ message: "Durable Step output exceeds canonical persistence bounds" })
|
|
5603
|
-
})));
|
|
5604
|
-
const outputDigest = yield* withCrypto(digestJson(output));
|
|
5605
|
-
const envelope = yield* makeEnvelope(recordId, ToolStepSettled.make({
|
|
5400
|
+
const record = yield* makeEnvelope(recordId, RunPolicyUsageReserved.make({
|
|
5606
5401
|
runId,
|
|
5607
|
-
|
|
5608
|
-
stepName: key.stepName,
|
|
5609
|
-
output,
|
|
5610
|
-
outputDigest
|
|
5402
|
+
...usage
|
|
5611
5403
|
}));
|
|
5404
|
+
yield* hit("policy:before-reservation-append");
|
|
5612
5405
|
yield* appendBatch(ctx, CanonicalBatch.make({
|
|
5613
|
-
batchId:
|
|
5406
|
+
batchId: decodeBatchIdSync(recordId),
|
|
5614
5407
|
producerId: config.producerId,
|
|
5615
|
-
records: [
|
|
5408
|
+
records: [record]
|
|
5616
5409
|
}));
|
|
5617
5410
|
knownIds.add(recordId);
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
|
|
5662
|
-
|
|
5411
|
+
yield* hit("policy:after-reservation-append");
|
|
5412
|
+
})),
|
|
5413
|
+
commitTurn: (commit) => recordHalt(Effect.gen(function* () {
|
|
5414
|
+
const halted = yield* Ref.get(haltRef);
|
|
5415
|
+
if (halted !== void 0) return yield* halted;
|
|
5416
|
+
if (deferredResponse !== void 0 && (deferredResponse.turn !== commit.turn || deferredResponse.turnId !== commit.turnId)) return yield* RunJournalError.make({ message: "A new Turn preceded settlement of its deferred response" });
|
|
5417
|
+
if (commit._tag === "Partial") yield* promoteResponse;
|
|
5418
|
+
const deferred = deferredResponse;
|
|
5419
|
+
if (commit._tag === "Response" && deferred !== void 0) return yield* RunJournalError.make({ message: "Turn response was already deferred" });
|
|
5420
|
+
const responseId = modelResponseRecordId(runId, commit.turn);
|
|
5421
|
+
const suppliedResponse = commit._tag === "Partial" ? void 0 : commit.response;
|
|
5422
|
+
const response = knownIds.has(responseId) || deferred !== void 0 ? void 0 : suppliedResponse;
|
|
5423
|
+
if (suppliedResponse !== void 0) currentToolTurn = {
|
|
5424
|
+
turn: commit.turn,
|
|
5425
|
+
turnId: commit.turnId
|
|
5426
|
+
};
|
|
5427
|
+
if (commit._tag === "Response" && response === void 0) return "committed";
|
|
5428
|
+
const toolOperations = [];
|
|
5429
|
+
const responseToolIds = /* @__PURE__ */ new Set();
|
|
5430
|
+
for (const call of response?.calls ?? []) {
|
|
5431
|
+
if (declaredToolIds.has(call.toolCallId) || responseToolIds.has(call.toolCallId)) return yield* RunJournalError.make({ message: "Tool Call identity is reused within a Run" });
|
|
5432
|
+
if (declaredToolIds.size + responseToolIds.size + 1 > 4096) return yield* RunJournalError.make({ message: `Run exceeds the ${MAX_RUN_TOOL_CALL_IDENTITIES} Tool Call identity limit` });
|
|
5433
|
+
const replay = currentContracts[call.toolName];
|
|
5434
|
+
if (replay === void 0) return yield* RunJournalError.make({ message: "Canonical Tool declaration has no original operation contract" });
|
|
5435
|
+
toolOperations.push(ToolOperation.make({
|
|
5436
|
+
toolCallId: call.toolCallId,
|
|
5437
|
+
toolName: call.toolName,
|
|
5438
|
+
executionClass: call.executionClass,
|
|
5439
|
+
executionKind: call.executionKind,
|
|
5440
|
+
replay
|
|
5441
|
+
}));
|
|
5442
|
+
responseToolIds.add(call.toolCallId);
|
|
5443
|
+
}
|
|
5444
|
+
const toolResults = commit._tag === "Response" ? [] : commit.results.filter((result) => !knownIds.has(toolCallSettledRecordId(runId, commit.turn, result.toolCallId)));
|
|
5445
|
+
let runCompletion;
|
|
5446
|
+
if (commit._tag === "Settled" && commit.completion !== void 0) {
|
|
5447
|
+
const completion = commit.completion;
|
|
5448
|
+
const output = yield* decodePersisted(completion.output).pipe(Effect.mapError((cause) => LedgerError.make({
|
|
5449
|
+
operation: "recordCompleted",
|
|
5450
|
+
message: "Run output exceeds canonical persistence bounds",
|
|
5451
|
+
cause
|
|
5452
|
+
})));
|
|
5453
|
+
if (completion.finishReason === "budget-exhausted" && completion.runDisposition !== void 0) return yield* LedgerError.make({
|
|
5454
|
+
operation: "recordCompleted",
|
|
5455
|
+
message: "A budget-exhausted Run cannot declare an application run disposition"
|
|
5456
|
+
});
|
|
5457
|
+
const runDisposition = completion.runDisposition === void 0 ? void 0 : yield* decodePersisted(completion.runDisposition).pipe(Effect.mapError((cause) => LedgerError.make({
|
|
5458
|
+
operation: "recordCompleted",
|
|
5459
|
+
message: "Run disposition exceeds canonical persistence bounds",
|
|
5460
|
+
cause
|
|
5461
|
+
})));
|
|
5462
|
+
runCompletion = {
|
|
5463
|
+
output,
|
|
5464
|
+
...runDisposition === void 0 ? {} : { runDisposition },
|
|
5465
|
+
...completion.finishReason === "budget-exhausted" ? {
|
|
5466
|
+
finishReason: completion.finishReason,
|
|
5467
|
+
...completion.exhausted === void 0 ? {} : { exhausted: completion.exhausted }
|
|
5468
|
+
} : {}
|
|
5469
|
+
};
|
|
5470
|
+
}
|
|
5471
|
+
if (response === void 0 && deferred === void 0 && toolResults.length === 0 && runCompletion === void 0) return "committed";
|
|
5472
|
+
if (response === void 0 && deferred === void 0 && !knownIds.has(responseId)) return yield* RunJournalError.make({ message: "Tool results or completion preceded the canonical response" });
|
|
5473
|
+
const input = {
|
|
5474
|
+
toolResultMaxBytes: Math.min(agent.definition.policy.toolResultBounds.maxBytes, MAX_PERSISTED_JSON_BYTES),
|
|
5475
|
+
toolSelectionMaxBytes: utf8ByteLength(JSON.stringify({ toolSelection: { toolNames: Object.keys(currentContracts) } })),
|
|
5476
|
+
runId,
|
|
5477
|
+
turn: commit.turn,
|
|
5478
|
+
turnId: commit.turnId,
|
|
5479
|
+
responseMessages: response?.messages ?? [],
|
|
5480
|
+
toolResults,
|
|
5481
|
+
toolOperations,
|
|
5482
|
+
toolExposure: response?.toolExposure,
|
|
5483
|
+
toolParameterRejections: response?.toolParameterRejections,
|
|
5484
|
+
runScopedPrefixLength: response?.runScopedPrefixLength,
|
|
5485
|
+
producerId: config.producerId,
|
|
5486
|
+
deploymentId: config.deploymentId,
|
|
5487
|
+
createdAt: yield* nowUtc,
|
|
5488
|
+
runCompletion,
|
|
5489
|
+
usage: usageForCommit(commit.turn),
|
|
5490
|
+
unobservedModelCalls: unobservedForCommit(commit.turn)
|
|
5491
|
+
};
|
|
5492
|
+
if (commit._tag === "Partial") {
|
|
5493
|
+
for (const result of toolResults) {
|
|
5494
|
+
const batch = yield* turnResultsBatch({
|
|
5495
|
+
...input,
|
|
5496
|
+
toolResults: [result]
|
|
5497
|
+
});
|
|
5498
|
+
yield* appendBatch(ctx, CanonicalBatch.make({
|
|
5499
|
+
...batch,
|
|
5500
|
+
batchId: toolCallResultBatchId(runId, commit.turn, result.toolCallId)
|
|
5501
|
+
}));
|
|
5502
|
+
for (const record of batch.records) knownIds.add(record.recordId);
|
|
5503
|
+
yield* hit("subagent:after-sibling-settle");
|
|
5504
|
+
}
|
|
5505
|
+
return "committed";
|
|
5506
|
+
}
|
|
5507
|
+
if (commit._tag === "Response" && commit.defer === true) {
|
|
5508
|
+
if (toolOperations.length === 0 || toolOperations.some((call) => call.executionClass !== "readonly" || call.executionKind !== "ordinary")) return yield* RunJournalError.make({ message: "Only ordinary readonly Tool responses may be deferred" });
|
|
5509
|
+
const candidate = {
|
|
5510
|
+
turn: commit.turn,
|
|
5511
|
+
turnId: commit.turnId,
|
|
5512
|
+
batch: yield* turnCanonicalBatch({
|
|
5513
|
+
...input,
|
|
5514
|
+
toolParameterRejections: input.toolParameterRejections?.map((rejection) => ({
|
|
5515
|
+
...rejection,
|
|
5516
|
+
parameters: copyJson(rejection.parameters),
|
|
5517
|
+
error: {
|
|
5518
|
+
...rejection.error,
|
|
5519
|
+
reason: { ...rejection.error.reason }
|
|
5520
|
+
}
|
|
5521
|
+
})),
|
|
5522
|
+
toolExposure: input.toolExposure === void 0 ? void 0 : Snapshot.make({
|
|
5523
|
+
exposedToolNames: [...input.toolExposure.exposedToolNames],
|
|
5524
|
+
...input.toolExposure.selection === void 0 ? {} : { selection: Selection.make({ toolNames: [...input.toolExposure.selection.toolNames] }) }
|
|
5525
|
+
}),
|
|
5526
|
+
usage: input.usage === void 0 ? void 0 : {
|
|
5527
|
+
...input.usage,
|
|
5528
|
+
modelUsage: input.usage.modelUsage?.map((usage) => ModelCallUsage.make({
|
|
5529
|
+
...usage,
|
|
5530
|
+
...usage.response === void 0 ? {} : { response: ModelResponseIdentity.make({ ...usage.response }) },
|
|
5531
|
+
inputTokens: InputTokenUsage.make({ ...usage.inputTokens }),
|
|
5532
|
+
outputTokens: OutputTokenUsage.make({ ...usage.outputTokens })
|
|
5533
|
+
}))
|
|
5534
|
+
}
|
|
5535
|
+
})
|
|
5536
|
+
};
|
|
5537
|
+
const progress = progressWriters.get(ctx);
|
|
5538
|
+
if (progress === void 0) return yield* ThreadStoreError.make({
|
|
5539
|
+
operation: "reserve readonly dispatch",
|
|
5540
|
+
message: "Dispatch has no scoped progress writer"
|
|
5541
|
+
});
|
|
5542
|
+
const batch = yield* progress.defer(candidate.batch).pipe(Effect.provideService(CurrentRunWriter, ctx));
|
|
5543
|
+
deferredResponse = {
|
|
5544
|
+
...candidate,
|
|
5545
|
+
batch
|
|
5546
|
+
};
|
|
5547
|
+
return "deferred";
|
|
5548
|
+
}
|
|
5549
|
+
let batch;
|
|
5550
|
+
if (deferred === void 0) batch = yield* commit._tag === "Response" ? turnResponseBatch(input) : response === void 0 ? turnResultsBatch(input) : turnCanonicalBatch(input);
|
|
5551
|
+
else if (toolResults.length === 0 && runCompletion === void 0) batch = deferred.batch;
|
|
5552
|
+
else {
|
|
5553
|
+
const results = yield* turnResultsBatch(input);
|
|
5554
|
+
batch = CanonicalBatch.make({
|
|
5555
|
+
...deferred.batch,
|
|
5556
|
+
records: [...deferred.batch.records, ...results.records]
|
|
5557
|
+
});
|
|
5558
|
+
}
|
|
5559
|
+
yield* appendBatch(ctx, batch);
|
|
5560
|
+
for (const call of response?.calls ?? []) {
|
|
5561
|
+
declaredToolIds.add(call.toolCallId);
|
|
5562
|
+
encodedParamsByCallId.set(call.toolCallId, call.parameters);
|
|
5563
|
+
declaredNamesByCallId.set(call.toolCallId, call.toolName);
|
|
5564
|
+
}
|
|
5565
|
+
if (deferred !== void 0) {
|
|
5566
|
+
acceptResponseDeclarations(batch);
|
|
5567
|
+
deferredResponse = void 0;
|
|
5568
|
+
}
|
|
5569
|
+
if (commit._tag === "Response") initialDispatchProofTurns.add(commit.turn);
|
|
5570
|
+
recordCommittedUsage(batch);
|
|
5571
|
+
for (const record of batch.records) knownIds.add(record.recordId);
|
|
5572
|
+
if (runCompletion !== void 0) completionState.committed = runCompletion;
|
|
5573
|
+
yield* hit(commit._tag === "Response" ? "turn:after-response-append" : response === void 0 && deferred === void 0 ? "turn:after-results-append" : "turn:after-canonical-append");
|
|
5574
|
+
return "committed";
|
|
5575
|
+
}).pipe(responseGate.withPermits(1))),
|
|
5576
|
+
checkToolDispatch: recordHalt(Effect.gen(function* () {
|
|
5577
|
+
if (currentToolTurn === void 0) return yield* RunJournalError.make({ message: "Tool dispatch preceded its canonical response" });
|
|
5578
|
+
yield* hit("tools:before-dispatch-fence");
|
|
5579
|
+
yield* ctx.checkActive;
|
|
5580
|
+
initialDispatchProofTurns.delete(currentToolTurn.turn);
|
|
5581
|
+
yield* hit("tools:after-dispatch-fence");
|
|
5582
|
+
})),
|
|
5583
|
+
step: {
|
|
5584
|
+
lookup: (key) => recordHalt(Effect.gen(function* () {
|
|
5585
|
+
yield* flushDeferredResponse;
|
|
5586
|
+
const output = stepOutputs.get(toolStepSettledRecordId(runId, key.toolCallId, key.stepName));
|
|
5587
|
+
return output === void 0 ? Option.none() : Option.some({ encodedOutput: output });
|
|
5588
|
+
})),
|
|
5589
|
+
reserve: (key) => recordHalt(Effect.gen(function* () {
|
|
5590
|
+
yield* flushDeferredResponse;
|
|
5591
|
+
const recordId = toolStepSettledRecordId(runId, key.toolCallId, key.stepName);
|
|
5592
|
+
const template = yield* makeEnvelope(recordId, yield* ToolStepSettled.makeEffect({
|
|
5593
|
+
runId,
|
|
5594
|
+
toolCallId: key.toolCallId,
|
|
5595
|
+
stepName: key.stepName,
|
|
5596
|
+
output: null,
|
|
5597
|
+
outputDigest: yield* withCrypto(digestJson(null))
|
|
5598
|
+
}).pipe(Effect.mapError(() => ThreadStoreError.make({
|
|
5599
|
+
operation: "reserve Step dispatch",
|
|
5600
|
+
message: "Durable Step identity exceeds canonical persistence bounds",
|
|
5601
|
+
cause: AgentPersistenceCapacityError.make({ message: "Durable Step identity exceeds canonical persistence bounds" })
|
|
5602
|
+
}))));
|
|
5603
|
+
const progress = progressWriters.get(ctx);
|
|
5604
|
+
if (progress === void 0) return yield* ThreadStoreError.make({
|
|
5605
|
+
operation: "reserve Step dispatch",
|
|
5606
|
+
message: "Dispatch has no scoped progress writer"
|
|
5607
|
+
});
|
|
5608
|
+
return yield* progress.reserve(runId, CanonicalBatch.make({
|
|
5609
|
+
batchId: decodeBatchIdSync(recordId),
|
|
5610
|
+
producerId: config.producerId,
|
|
5611
|
+
records: [template]
|
|
5612
|
+
}), canonicalRecordBytes(template) + MAX_PERSISTED_JSON_BYTES + MAX_RUN_CONTINUATION_BYTES).pipe(Effect.provideService(CurrentRunWriter, ctx));
|
|
5613
|
+
})),
|
|
5614
|
+
commit: (key, encodedOutput) => recordHalt(Effect.gen(function* () {
|
|
5615
|
+
yield* flushDeferredResponse;
|
|
5616
|
+
const recordId = toolStepSettledRecordId(runId, key.toolCallId, key.stepName);
|
|
5617
|
+
if (knownIds.has(recordId)) return;
|
|
5618
|
+
const output = yield* decodePersisted(encodedOutput).pipe(Effect.mapError(() => ThreadStoreError.make({
|
|
5619
|
+
operation: "commit Step result",
|
|
5620
|
+
message: "Durable Step output exceeds canonical persistence bounds",
|
|
5621
|
+
cause: AgentPersistenceCapacityError.make({ message: "Durable Step output exceeds canonical persistence bounds" })
|
|
5622
|
+
})));
|
|
5623
|
+
const outputDigest = yield* withCrypto(digestJson(output));
|
|
5624
|
+
const envelope = yield* makeEnvelope(recordId, ToolStepSettled.make({
|
|
5625
|
+
runId,
|
|
5626
|
+
toolCallId: key.toolCallId,
|
|
5627
|
+
stepName: key.stepName,
|
|
5628
|
+
output,
|
|
5629
|
+
outputDigest
|
|
5630
|
+
}));
|
|
5631
|
+
yield* appendBatch(ctx, CanonicalBatch.make({
|
|
5632
|
+
batchId: toolStepSettledBatchId(runId, key.toolCallId, key.stepName),
|
|
5633
|
+
producerId: config.producerId,
|
|
5634
|
+
records: [envelope]
|
|
5635
|
+
}));
|
|
5636
|
+
knownIds.add(recordId);
|
|
5637
|
+
stepOutputs.set(recordId, output);
|
|
5638
|
+
yield* hit("step:after-step-append");
|
|
5639
|
+
}))
|
|
5640
|
+
},
|
|
5641
|
+
noteTurnUsage: (usage) => Effect.sync(() => {
|
|
5642
|
+
const key = usage.turn;
|
|
5643
|
+
const prior = stagedUsage.get(key);
|
|
5644
|
+
stagedUsage.set(key, {
|
|
5645
|
+
inputTokens: (prior?.inputTokens ?? 0) + usage.usage.inputTokens.total,
|
|
5646
|
+
outputTokens: (prior?.outputTokens ?? 0) + usage.usage.outputTokens.total,
|
|
5647
|
+
costMicrousd: (prior?.costMicrousd ?? 0) + usage.usage.costMicrousd,
|
|
5648
|
+
modelUsage: [...prior?.modelUsage ?? [], usage.usage]
|
|
5649
|
+
});
|
|
5650
|
+
progressWriters.get(ctx)?.stageUsage(runId, terminalUsageCharge(uncommittedModelUsage()));
|
|
5651
|
+
}),
|
|
5652
|
+
commitCompaction: Effect.fnUntraced(function* (commit) {
|
|
5653
|
+
const canonicalTurn = commit.turn;
|
|
5654
|
+
const recordId = compactionRecordId(runId, canonicalTurn, commit.kind);
|
|
5655
|
+
if (knownIds.has(recordId)) return yield* CompactionError.make({ message: "Compaction is already committed for this Turn and kind" });
|
|
5656
|
+
let sourceJournal = journal;
|
|
5657
|
+
let sourceBoundaries = boundaries;
|
|
5658
|
+
if (initialJournal !== void 0) {
|
|
5659
|
+
initialJournal.cacheable = false;
|
|
5660
|
+
initialJournal.history = void 0;
|
|
5661
|
+
}
|
|
5662
|
+
if (commit.kind !== "summarize" || initialJournal?.prefix !== void 0) {
|
|
5663
|
+
const tail = yield* ctx.tail;
|
|
5664
|
+
const source = initialJournal === void 0 ? canonical : Stream.fromIterable(yield* recordHalt(readInitialJournal(initialJournal.original, initialJournal.suffix)));
|
|
5665
|
+
sourceBoundaries = [];
|
|
5666
|
+
sourceJournal = yield* recordHalt(projectRunJournalStream(Stream.concat(source, Stream.fromIterable(yield* recordHalt(selectedRange(ctx.threadId, [submissionId], tail.sequence, canonicalThrough)))).pipe(Stream.filter((envelope) => envelope.record.payload._tag !== "CompactionCreated" || envelope.sequence <= canonicalThrough)), runId, (boundary) => sourceBoundaries.push(boundary), priorContext));
|
|
5667
|
+
}
|
|
5668
|
+
const coverable = sourceBoundaries.filter((boundary) => commit.kind !== "summarize" || ownerFirstSequence === void 0 || boundary.sequence < ownerFirstSequence);
|
|
5669
|
+
if (coverable.length === 0) return yield* CompactionError.make({ message: commit.kind === "rollover" ? "Durable rollover requires complete canonical records" : "Durable compaction requires eligible canonical records" });
|
|
5670
|
+
const comparisonView = instructionView(sourceJournal.prompt.content, initialInstructions, false, sourceJournal.historyBefore.content.length);
|
|
5671
|
+
let matchingPrefix = 0;
|
|
5672
|
+
let requiredThrough = 0;
|
|
5673
|
+
const comparisonLimit = Math.min(comparisonView.messages.length, commit.through);
|
|
5674
|
+
for (let index = 0; index < commit.through; index += 1) {
|
|
5675
|
+
const message = commit.source.content[index];
|
|
5676
|
+
if (message !== void 0 && (commit.kind === "clear-tool-results" ? message.role === "tool" : message.role !== "system")) requiredThrough = index + 1;
|
|
5677
|
+
if (index >= comparisonLimit || index !== matchingPrefix || message === void 0) continue;
|
|
5678
|
+
const canonicalMessage = comparisonView.messages[index];
|
|
5679
|
+
if (canonicalMessage === void 0) continue;
|
|
5680
|
+
const encode = (entry) => encodeCompactionMessageJson(entry).pipe(Effect.flatMap(decodeCompactionMessageJson), Effect.map(canonicalJson), Effect.mapError((cause) => CompactionError.make({
|
|
5681
|
+
message: "Could not encode the canonical compaction prefix",
|
|
5682
|
+
cause
|
|
5683
|
+
})));
|
|
5684
|
+
if ((yield* encode(canonicalMessage)) === (yield* encode(message))) matchingPrefix += 1;
|
|
5685
|
+
}
|
|
5686
|
+
let lastCovered;
|
|
5687
|
+
for (let index = 0; index < coverable.length; index += 1) {
|
|
5688
|
+
const candidate = coverable[index];
|
|
5689
|
+
if (candidate === void 0) continue;
|
|
5690
|
+
if (coverable[index + 1]?.tag === "ToolCallSettled") continue;
|
|
5691
|
+
const length = comparisonView.prefixLength(candidate.promptLength);
|
|
5692
|
+
if (length === 0 || length > commit.through) continue;
|
|
5693
|
+
if (length < requiredThrough || length > matchingPrefix) continue;
|
|
5694
|
+
lastCovered = candidate;
|
|
5695
|
+
}
|
|
5696
|
+
if (lastCovered === void 0) return yield* CompactionError.make({ message: commit.kind === "rollover" ? "Rollover coverage cannot be mapped to complete canonical records" : "Compaction coverage cannot be mapped to complete canonical records" });
|
|
5697
|
+
const coveredSequence = lastCovered.sequence;
|
|
5698
|
+
if (commit.kind !== "summarize" && sourceBoundaries.some((boundary) => boundary.incomplete === true && boundary.terminalPriorRun !== true && boundary.sequence <= coveredSequence)) return yield* CompactionError.make({ message: "Compaction cannot cover an incomplete Tool batch" });
|
|
5699
|
+
if (commit.kind === "summarize" && (commit.summary ?? "").trim().length === 0) return yield* CompactionError.make({ message: "A summarize compaction commit carried no summary" });
|
|
5700
|
+
const payload = yield* Schema.decodeEffect(CompactionCreated)({
|
|
5701
|
+
_tag: "CompactionCreated",
|
|
5702
|
+
runId,
|
|
5703
|
+
turn: canonicalTurn,
|
|
5704
|
+
kind: commit.kind,
|
|
5705
|
+
coversThrough: lastCovered.sequence,
|
|
5706
|
+
...commit.kind === "summarize" ? { summary: commit.summary } : {},
|
|
5707
|
+
...commit.kind === "rollover" && commit.handoff !== void 0 ? { handoff: commit.handoff } : {}
|
|
5708
|
+
}).pipe(Effect.mapError((cause) => CompactionError.make({
|
|
5709
|
+
message: "Compaction decision exceeds canonical persistence bounds",
|
|
5663
5710
|
cause
|
|
5664
5711
|
})));
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
const payload = yield* Schema.decodeEffect(CompactionCreated)({
|
|
5682
|
-
_tag: "CompactionCreated",
|
|
5683
|
-
runId,
|
|
5684
|
-
turn: canonicalTurn,
|
|
5685
|
-
kind: commit.kind,
|
|
5686
|
-
coversThrough: lastCovered.sequence,
|
|
5687
|
-
...commit.kind === "summarize" ? { summary: commit.summary } : {},
|
|
5688
|
-
...commit.kind === "rollover" && commit.handoff !== void 0 ? { handoff: commit.handoff } : {}
|
|
5689
|
-
}).pipe(Effect.mapError((cause) => CompactionError.make({
|
|
5690
|
-
message: "Compaction decision exceeds canonical persistence bounds",
|
|
5712
|
+
const envelope = yield* recordHalt(makeEnvelope(recordId, payload));
|
|
5713
|
+
yield* recordHalt(hit("compaction:before-canonical-append"));
|
|
5714
|
+
yield* recordHalt(appendBatch(ctx, CanonicalBatch.make({
|
|
5715
|
+
batchId: compactionBatchId(runId, canonicalTurn, commit.kind),
|
|
5716
|
+
producerId: config.producerId,
|
|
5717
|
+
records: [envelope]
|
|
5718
|
+
})));
|
|
5719
|
+
knownIds.add(recordId);
|
|
5720
|
+
yield* recordHalt(hit("compaction:after-canonical-append"));
|
|
5721
|
+
})
|
|
5722
|
+
};
|
|
5723
|
+
/** Digest of one declared call's canonical encoded parameters (the original normalized wire). */
|
|
5724
|
+
const approvalParametersDigest = (toolCallId) => Effect.gen(function* () {
|
|
5725
|
+
if (!encodedParamsByCallId.has(toolCallId)) return yield* RunJournalError.make({ message: `Tool Call ${toolCallId} requested approval before its response commit` });
|
|
5726
|
+
const parameters = yield* decodePersisted(encodedParamsByCallId.get(toolCallId)).pipe(Effect.mapError((cause) => RunJournalError.make({
|
|
5727
|
+
message: `Tool Call ${toolCallId} parameters exceed canonical persistence bounds`,
|
|
5691
5728
|
cause
|
|
5692
5729
|
})));
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
|
|
5697
|
-
|
|
5698
|
-
|
|
5699
|
-
|
|
5700
|
-
|
|
5701
|
-
|
|
5702
|
-
}
|
|
5703
|
-
|
|
5704
|
-
|
|
5705
|
-
|
|
5706
|
-
|
|
5707
|
-
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
|
|
5711
|
-
|
|
5712
|
-
|
|
5713
|
-
|
|
5714
|
-
|
|
5715
|
-
|
|
5716
|
-
|
|
5717
|
-
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
const appendApprovalRecords = (turnInfo, toolCallId, toolName, decided) => Effect.gen(function* () {
|
|
5725
|
-
const requestRecordId = toolApprovalRequestRecordId(runId, turnInfo.turn, toolCallId);
|
|
5726
|
-
const decisionRecordId = toolApprovalDecisionRecordId(runId, turnInfo.turn, toolCallId);
|
|
5727
|
-
const envelopes = [];
|
|
5728
|
-
const appendRequest = !knownIds.has(requestRecordId);
|
|
5729
|
-
if (appendRequest) {
|
|
5730
|
-
const parametersDigest = yield* approvalParametersDigest(toolCallId);
|
|
5731
|
-
envelopes.push(yield* makeEnvelope(requestRecordId, ToolApprovalRequested.make({
|
|
5732
|
-
blocksInitialDispatch: initialDispatchProofTurns.has(turnInfo.turn),
|
|
5730
|
+
return yield* withCrypto(digestJson(parameters));
|
|
5731
|
+
});
|
|
5732
|
+
/**
|
|
5733
|
+
* Append the canonical approval records for one declared call: the `ToolApprovalRequested`
|
|
5734
|
+
* record — plus the immediate `ToolApprovalDecided` for a policy-auto or intent-backed
|
|
5735
|
+
* decision, one atomic batch — or the decision alone when the request is already canonical.
|
|
5736
|
+
* Batch identity: the Turn's FIRST canonical approval append owns
|
|
5737
|
+
* `turn-approvals:{runId}:{turn}`; later appends of the same Turn (across suspension
|
|
5738
|
+
* cycles) use deterministic per-call batches so committed batch content is never
|
|
5739
|
+
* contradicted; decision-only appends use `approval-decision:{sid}:{toolCallId}`. Record
|
|
5740
|
+
* identity dedupes every replay; an identity conflict means another pass already committed
|
|
5741
|
+
* the same records.
|
|
5742
|
+
*/
|
|
5743
|
+
const appendApprovalRecords = (turnInfo, toolCallId, toolName, decided) => Effect.gen(function* () {
|
|
5744
|
+
const requestRecordId = toolApprovalRequestRecordId(runId, turnInfo.turn, toolCallId);
|
|
5745
|
+
const decisionRecordId = toolApprovalDecisionRecordId(runId, turnInfo.turn, toolCallId);
|
|
5746
|
+
const envelopes = [];
|
|
5747
|
+
const appendRequest = !knownIds.has(requestRecordId);
|
|
5748
|
+
if (appendRequest) {
|
|
5749
|
+
const parametersDigest = yield* approvalParametersDigest(toolCallId);
|
|
5750
|
+
envelopes.push(yield* makeEnvelope(requestRecordId, ToolApprovalRequested.make({
|
|
5751
|
+
blocksInitialDispatch: initialDispatchProofTurns.has(turnInfo.turn),
|
|
5752
|
+
runId,
|
|
5753
|
+
turnId: turnInfo.turnId,
|
|
5754
|
+
turn: turnInfo.turn,
|
|
5755
|
+
toolCallId,
|
|
5756
|
+
toolName,
|
|
5757
|
+
parametersDigest
|
|
5758
|
+
})));
|
|
5759
|
+
}
|
|
5760
|
+
if (decided !== void 0 && !knownIds.has(decisionRecordId)) envelopes.push(yield* makeEnvelope(decisionRecordId, ToolApprovalDecided.make({
|
|
5733
5761
|
runId,
|
|
5734
|
-
turnId: turnInfo.turnId,
|
|
5735
5762
|
turn: turnInfo.turn,
|
|
5736
5763
|
toolCallId,
|
|
5737
|
-
|
|
5738
|
-
|
|
5764
|
+
decision: decided.decision,
|
|
5765
|
+
resolver: decided.resolver,
|
|
5766
|
+
reason: decided.reason
|
|
5739
5767
|
})));
|
|
5740
|
-
|
|
5741
|
-
|
|
5742
|
-
|
|
5743
|
-
|
|
5744
|
-
|
|
5745
|
-
|
|
5746
|
-
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
const head = envelopes[0];
|
|
5750
|
-
if (head !== void 0) {
|
|
5751
|
-
const batchId = appendRequest ? approvalRequestedTurns.has(turnInfo.turn) ? decodeBatchId(`approval-request:${runId}:${turnInfo.turn}:${toolCallId}`) : turnApprovalsBatchId(runId, turnInfo.turn) : approvalDecisionBatchId(submissionId, toolCallId);
|
|
5752
|
-
yield* appendBatch(ctx, CanonicalBatch.make({
|
|
5753
|
-
batchId,
|
|
5754
|
-
producerId: config.producerId,
|
|
5755
|
-
records: [head, ...envelopes.slice(1)]
|
|
5756
|
-
})).pipe(Effect.catchTag("AppendConflict", () => Effect.void), Effect.asVoid);
|
|
5757
|
-
for (const record of envelopes) knownIds.add(record.recordId);
|
|
5758
|
-
}
|
|
5759
|
-
if (appendRequest) {
|
|
5760
|
-
approvalRequestedTurns.add(turnInfo.turn);
|
|
5761
|
-
yield* hit("approval:after-request-append");
|
|
5762
|
-
}
|
|
5763
|
-
if (decided !== void 0) canonicalApprovalDecisions.set(toolCallId, decided.decision);
|
|
5764
|
-
});
|
|
5765
|
-
/**
|
|
5766
|
-
* Retain every required request before any decision can remove initial-dispatch proof.
|
|
5767
|
-
* Policy preparation shares the engine deadline; canonical acceptance is a separate,
|
|
5768
|
-
* fenced commit. Canonical decisions and accepted resolver intents keep their audit.
|
|
5769
|
-
*/
|
|
5770
|
-
const approval = {
|
|
5771
|
-
prepareBatch: (requests) => recordHalt(Effect.gen(function* () {
|
|
5772
|
-
if (requests.length === 0) return;
|
|
5773
|
-
yield* flushDeferredResponse;
|
|
5774
|
-
const turnInfo = currentToolTurn;
|
|
5775
|
-
if (turnInfo === void 0) return yield* RunJournalError.make({ message: "Approval preparation preceded its canonical response" });
|
|
5776
|
-
for (const request of requests) {
|
|
5777
|
-
if (request.threadId !== submission.threadId || request.runId !== runId || request.turnId !== turnInfo.turnId || declaredNamesByCallId.get(request.toolCallId) !== request.toolName) return yield* RunJournalError.make({ message: "Approval preparation does not match its original declaration" });
|
|
5778
|
-
yield* appendApprovalRecords(turnInfo, request.toolCallId, request.toolName, void 0);
|
|
5779
|
-
}
|
|
5780
|
-
})),
|
|
5781
|
-
request: (request) => recordHalt(Effect.gen(function* () {
|
|
5782
|
-
const canonical = canonicalApprovalDecisions.get(request.toolCallId);
|
|
5783
|
-
if (canonical !== void 0) return canonical === "approved" ? { _tag: "approved" } : { _tag: "denied" };
|
|
5784
|
-
const intent = approvalIntents.get(request.toolCallId);
|
|
5785
|
-
if (intent !== void 0) return intent.decision === "approved" ? {
|
|
5786
|
-
_tag: "approved",
|
|
5787
|
-
reason: intent.reason
|
|
5788
|
-
} : {
|
|
5789
|
-
_tag: "denied",
|
|
5790
|
-
reason: intent.reason
|
|
5791
|
-
};
|
|
5792
|
-
return approvalResolver === void 0 ? { _tag: "unresolved" } : yield* approvalResolver.request(request);
|
|
5793
|
-
})),
|
|
5794
|
-
commit: (request, decision) => recordHalt(Effect.gen(function* () {
|
|
5795
|
-
const turnInfo = currentToolTurn;
|
|
5796
|
-
if (turnInfo === void 0 || request.threadId !== submission.threadId || request.runId !== runId || request.turnId !== turnInfo.turnId || declaredNamesByCallId.get(request.toolCallId) !== request.toolName) return yield* RunJournalError.make({ message: "Approval acceptance does not match its original declaration" });
|
|
5797
|
-
const canonical = canonicalApprovalDecisions.get(request.toolCallId);
|
|
5798
|
-
if (canonical !== void 0) {
|
|
5799
|
-
if (decision._tag !== canonical) return yield* RunJournalError.make({ message: "Approval preparation disagrees with its canonical decision" });
|
|
5800
|
-
return;
|
|
5768
|
+
const head = envelopes[0];
|
|
5769
|
+
if (head !== void 0) {
|
|
5770
|
+
const batchId = appendRequest ? approvalRequestedTurns.has(turnInfo.turn) ? decodeBatchId(`approval-request:${runId}:${turnInfo.turn}:${toolCallId}`) : turnApprovalsBatchId(runId, turnInfo.turn) : approvalDecisionBatchId(submissionId, toolCallId);
|
|
5771
|
+
yield* appendBatch(ctx, CanonicalBatch.make({
|
|
5772
|
+
batchId,
|
|
5773
|
+
producerId: config.producerId,
|
|
5774
|
+
records: [head, ...envelopes.slice(1)]
|
|
5775
|
+
})).pipe(Effect.catchTag("AppendConflict", () => Effect.void), Effect.asVoid);
|
|
5776
|
+
for (const record of envelopes) knownIds.add(record.recordId);
|
|
5801
5777
|
}
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
5805
|
-
decision: intent.decision,
|
|
5806
|
-
resolver: intent.resolver,
|
|
5807
|
-
reason: intent.reason
|
|
5808
|
-
} : decision._tag === "unresolved" ? void 0 : {
|
|
5809
|
-
decision: decision._tag,
|
|
5810
|
-
resolver: APPROVAL_POLICY_RESOLVER,
|
|
5811
|
-
reason: boundedApprovalReason(decision.reason, "The configured approval policy decided immediately")
|
|
5812
|
-
});
|
|
5813
|
-
}))
|
|
5814
|
-
};
|
|
5815
|
-
/**
|
|
5816
|
-
* Joining/Joined queued input hook (plan §2.5, DUR-016). At every engine drain seam:
|
|
5817
|
-
*
|
|
5818
|
-
* 1. Reattach first — pre-existing joins whose canonical `input:{sid}` record is not yet
|
|
5819
|
-
* prompt-covered re-deliver WITHOUT re-appending (record identity is the dedupe);
|
|
5820
|
-
* covered inputs are already inside the journal prompt. A `joining` row whose input is
|
|
5821
|
-
* canonical only lost its marker: it is repaired from history under the host's live
|
|
5822
|
-
* ownership (DUR-015). A `joining` row WITHOUT canonical input was never consumed and
|
|
5823
|
-
* is recovery's to revert — the hook never guesses at it (fail-closed).
|
|
5824
|
-
* 2. Claim fresh — `claimJoining` atomically transitions the contiguous ready prefix of
|
|
5825
|
-
* strictly-later queue sequences to `joining` under the host's local generation (an
|
|
5826
|
-
* admitted-not-ready row breaks the prefix). Per fresh claim: honor a
|
|
5827
|
-
* pre-consumption abort intent by reverting (revert-then-abort), else append the
|
|
5828
|
-
* deterministic `UserInputRecorded` (batch `submission-input:{sid}`, record
|
|
5829
|
-
* `input:{sid}`, `runId` = host Run, kind `steering`) → `join:after-canonical-append`
|
|
5830
|
-
* → `markJoined` → hand the engine the `RunInputCommand`.
|
|
5831
|
-
*
|
|
5832
|
-
* Delivered input is `steering`: the engine appends it to official history at the seam,
|
|
5833
|
-
* so the next Turn's response commit makes it model-visible canonically — exactly the
|
|
5834
|
-
* prompt-coverage rule recovery relies on.
|
|
5835
|
-
*/
|
|
5836
|
-
const renderJoinedInput = ({ input: encodedInput, messageAdmission }) => Effect.gen(function* () {
|
|
5837
|
-
if (Schema.is(FrameworkMessage)(messageAdmission)) return yield* Schema.encodeEffect(Schema.fromJsonString(FrameworkMessage))(messageAdmission).pipe(Effect.mapError(() => AgentInputError.make({ message: "Invalid worker completion message" })));
|
|
5838
|
-
const inputPrompt = agent.definition.inputPrompt;
|
|
5839
|
-
if (inputPrompt === void 0) return yield* renderInputPrompt(void 0, encodedInput, encodedInput);
|
|
5840
|
-
const decodedInput = yield* Schema.decodeEffect(agent.definition.input)(encodedInput).pipe(Effect.mapError((cause) => AgentInputDecodeError.make({ message: cause.message })));
|
|
5841
|
-
return yield* renderInputPrompt(inputPrompt, decodedInput, encodedInput);
|
|
5842
|
-
});
|
|
5843
|
-
const pendingJoinClaims = [];
|
|
5844
|
-
const claimInputs = Effect.fnUntraced(function* (maxCount) {
|
|
5845
|
-
const claims = yield* session.claimJoining(maxCount);
|
|
5846
|
-
pendingJoinClaims.push(...claims.map((claim) => ({ claim })));
|
|
5847
|
-
return claims.length;
|
|
5848
|
-
}, Effect.uninterruptible);
|
|
5849
|
-
const revertClaims = Effect.fnUntraced(function* (claims) {
|
|
5850
|
-
for (const pending of claims) {
|
|
5851
|
-
yield* session.revertJoining(pending.claim.submissionId);
|
|
5852
|
-
pendingJoinClaims.splice(pendingJoinClaims.indexOf(pending), 1);
|
|
5853
|
-
}
|
|
5854
|
-
}, Effect.uninterruptible);
|
|
5855
|
-
const prepareInputs = Effect.fnUntraced(function* (limit, firstReady = false) {
|
|
5856
|
-
if (pendingJoinClaims.length < limit && (yield* claimInputs(limit - pendingJoinClaims.length)) > 0) yield* hit("join:after-claim");
|
|
5857
|
-
const prepared = [];
|
|
5858
|
-
for (const pending of pendingJoinClaims.slice(0, limit)) {
|
|
5859
|
-
const claim = pending.claim;
|
|
5860
|
-
const snapshot = yield* ledger.loadRecoverySnapshot(RecoverySnapshotRequest.make({ submissionId: claim.submissionId }));
|
|
5861
|
-
if (snapshot.abortIntent !== void 0) {
|
|
5862
|
-
yield* revertClaims([pending]);
|
|
5863
|
-
continue;
|
|
5778
|
+
if (appendRequest) {
|
|
5779
|
+
approvalRequestedTurns.add(turnInfo.turn);
|
|
5780
|
+
yield* hit("approval:after-request-append");
|
|
5864
5781
|
}
|
|
5865
|
-
if (
|
|
5866
|
-
|
|
5867
|
-
|
|
5868
|
-
|
|
5869
|
-
|
|
5870
|
-
|
|
5871
|
-
|
|
5872
|
-
|
|
5873
|
-
|
|
5782
|
+
if (decided !== void 0) canonicalApprovalDecisions.set(toolCallId, decided.decision);
|
|
5783
|
+
});
|
|
5784
|
+
/**
|
|
5785
|
+
* Retain every required request before any decision can remove initial-dispatch proof.
|
|
5786
|
+
* Policy preparation shares the engine deadline; canonical acceptance is a separate,
|
|
5787
|
+
* fenced commit. Canonical decisions and accepted resolver intents keep their audit.
|
|
5788
|
+
*/
|
|
5789
|
+
const approval = {
|
|
5790
|
+
prepareBatch: (requests) => recordHalt(Effect.gen(function* () {
|
|
5791
|
+
if (requests.length === 0) return;
|
|
5792
|
+
yield* flushDeferredResponse;
|
|
5793
|
+
const turnInfo = currentToolTurn;
|
|
5794
|
+
if (turnInfo === void 0) return yield* RunJournalError.make({ message: "Approval preparation preceded its canonical response" });
|
|
5795
|
+
for (const request of requests) {
|
|
5796
|
+
if (request.threadId !== submission.threadId || request.runId !== runId || request.turnId !== turnInfo.turnId || declaredNamesByCallId.get(request.toolCallId) !== request.toolName) return yield* RunJournalError.make({ message: "Approval preparation does not match its original declaration" });
|
|
5797
|
+
yield* appendApprovalRecords(turnInfo, request.toolCallId, request.toolName, void 0);
|
|
5874
5798
|
}
|
|
5875
|
-
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
|
|
5799
|
+
})),
|
|
5800
|
+
request: (request) => recordHalt(Effect.gen(function* () {
|
|
5801
|
+
const canonical = canonicalApprovalDecisions.get(request.toolCallId);
|
|
5802
|
+
if (canonical !== void 0) return canonical === "approved" ? { _tag: "approved" } : { _tag: "denied" };
|
|
5803
|
+
const intent = approvalIntents.get(request.toolCallId);
|
|
5804
|
+
if (intent !== void 0) return intent.decision === "approved" ? {
|
|
5805
|
+
_tag: "approved",
|
|
5806
|
+
reason: intent.reason
|
|
5807
|
+
} : {
|
|
5808
|
+
_tag: "denied",
|
|
5809
|
+
reason: intent.reason
|
|
5879
5810
|
};
|
|
5811
|
+
return approvalResolver === void 0 ? { _tag: "unresolved" } : yield* approvalResolver.request(request);
|
|
5812
|
+
})),
|
|
5813
|
+
commit: (request, decision) => recordHalt(Effect.gen(function* () {
|
|
5814
|
+
const turnInfo = currentToolTurn;
|
|
5815
|
+
if (turnInfo === void 0 || request.threadId !== submission.threadId || request.runId !== runId || request.turnId !== turnInfo.turnId || declaredNamesByCallId.get(request.toolCallId) !== request.toolName) return yield* RunJournalError.make({ message: "Approval acceptance does not match its original declaration" });
|
|
5816
|
+
const canonical = canonicalApprovalDecisions.get(request.toolCallId);
|
|
5817
|
+
if (canonical !== void 0) {
|
|
5818
|
+
if (decision._tag !== canonical) return yield* RunJournalError.make({ message: "Approval preparation disagrees with its canonical decision" });
|
|
5819
|
+
return;
|
|
5820
|
+
}
|
|
5821
|
+
const intent = approvalIntents.get(request.toolCallId);
|
|
5822
|
+
if (intent !== void 0 && decision._tag !== intent.decision) return yield* RunJournalError.make({ message: "Approval preparation disagrees with its accepted intent" });
|
|
5823
|
+
yield* appendApprovalRecords(turnInfo, request.toolCallId, request.toolName, intent !== void 0 ? {
|
|
5824
|
+
decision: intent.decision,
|
|
5825
|
+
resolver: intent.resolver,
|
|
5826
|
+
reason: intent.reason
|
|
5827
|
+
} : decision._tag === "unresolved" ? void 0 : {
|
|
5828
|
+
decision: decision._tag,
|
|
5829
|
+
resolver: APPROVAL_POLICY_RESOLVER,
|
|
5830
|
+
reason: boundedApprovalReason(decision.reason, "The configured approval policy decided immediately")
|
|
5831
|
+
});
|
|
5832
|
+
}))
|
|
5833
|
+
};
|
|
5834
|
+
/**
|
|
5835
|
+
* Joining/Joined queued input hook (plan §2.5, DUR-016). At every engine drain seam:
|
|
5836
|
+
*
|
|
5837
|
+
* 1. Reattach first — pre-existing joins whose canonical `input:{sid}` record is not yet
|
|
5838
|
+
* prompt-covered re-deliver WITHOUT re-appending (record identity is the dedupe);
|
|
5839
|
+
* covered inputs are already inside the journal prompt. A `joining` row whose input is
|
|
5840
|
+
* canonical only lost its marker: it is repaired from history under the host's live
|
|
5841
|
+
* ownership (DUR-015). A `joining` row WITHOUT canonical input was never consumed and
|
|
5842
|
+
* is recovery's to revert — the hook never guesses at it (fail-closed).
|
|
5843
|
+
* 2. Claim fresh — `claimJoining` atomically transitions the contiguous ready prefix of
|
|
5844
|
+
* strictly-later queue sequences to `joining` under the host's local generation (an
|
|
5845
|
+
* admitted-not-ready row breaks the prefix). Per fresh claim: honor a
|
|
5846
|
+
* pre-consumption abort intent by reverting (revert-then-abort), else append the
|
|
5847
|
+
* deterministic `UserInputRecorded` (batch `submission-input:{sid}`, record
|
|
5848
|
+
* `input:{sid}`, `runId` = host Run, kind `steering`) → `join:after-canonical-append`
|
|
5849
|
+
* → `markJoined` → hand the engine the `RunInputCommand`.
|
|
5850
|
+
*
|
|
5851
|
+
* Delivered input is `steering`: the engine appends it to official history at the seam,
|
|
5852
|
+
* so the next Turn's response commit makes it model-visible canonically — exactly the
|
|
5853
|
+
* prompt-coverage rule recovery relies on.
|
|
5854
|
+
*/
|
|
5855
|
+
const renderJoinedInput = Effect.fnUntraced(function* (encodedInput, messageAdmission) {
|
|
5856
|
+
if (Schema.is(FrameworkMessage)(messageAdmission)) return yield* Schema.encodeEffect(Schema.fromJsonString(FrameworkMessage))(messageAdmission).pipe(Effect.mapError(() => AgentInputError.make({ message: "Invalid worker completion message" })));
|
|
5857
|
+
const inputPrompt = agent.definition.inputPrompt;
|
|
5858
|
+
if (inputPrompt === void 0) return yield* renderInputPrompt(void 0, encodedInput, encodedInput);
|
|
5859
|
+
const decodedInput = yield* Schema.decodeEffect(agent.definition.input)(encodedInput).pipe(Effect.mapError((cause) => AgentInputDecodeError.make({ message: cause.message })));
|
|
5860
|
+
return yield* renderInputPrompt(inputPrompt, decodedInput, encodedInput);
|
|
5861
|
+
});
|
|
5862
|
+
const pendingJoinClaims = [];
|
|
5863
|
+
const claimInputs = Effect.fnUntraced(function* (maxCount) {
|
|
5864
|
+
const claims = yield* session.claimJoining(maxCount);
|
|
5865
|
+
pendingJoinClaims.push(...claims.map((claim) => ({ claim })));
|
|
5866
|
+
return claims.length;
|
|
5867
|
+
}, Effect.uninterruptible);
|
|
5868
|
+
const revertClaims = Effect.fnUntraced(function* (claims) {
|
|
5869
|
+
for (const pending of claims) {
|
|
5870
|
+
yield* session.revertJoining(pending.claim.submissionId);
|
|
5871
|
+
pendingJoinClaims.splice(pendingJoinClaims.indexOf(pending), 1);
|
|
5880
5872
|
}
|
|
5881
|
-
|
|
5882
|
-
|
|
5883
|
-
|
|
5884
|
-
|
|
5885
|
-
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
|
|
5889
|
-
|
|
5890
|
-
|
|
5891
|
-
yield* notified;
|
|
5892
|
-
return false;
|
|
5893
|
-
}))) return;
|
|
5894
|
-
})),
|
|
5895
|
-
drain: (policy) => Effect.gen(function* () {
|
|
5896
|
-
const joinedInputs = yield* recordHalt(Effect.gen(function* () {
|
|
5897
|
-
const limit = policy === "one" ? 1 : MAX_JOIN_DRAIN;
|
|
5898
|
-
const joinedInputs = [];
|
|
5899
|
-
if (joinBacklog === void 0) joinBacklog = (yield* ledger.loadRecoverySnapshot(RecoverySnapshotRequest.make({ submissionId }))).joins;
|
|
5900
|
-
for (const join of joinBacklog) {
|
|
5901
|
-
const joinId = join.submissionId;
|
|
5902
|
-
if (deliveredJoinInputs.has(joinId)) continue;
|
|
5903
|
-
if (join.state !== "joining" && join.state !== "joined") continue;
|
|
5904
|
-
const existing = joinedInputEnvelopes.get(joinId);
|
|
5905
|
-
if (existing === void 0) continue;
|
|
5906
|
-
if (join.state === "joining") yield* session.markJoined(joinId, {
|
|
5907
|
-
recordId: existing.record.recordId,
|
|
5908
|
-
sequence: existing.sequence
|
|
5909
|
-
});
|
|
5910
|
-
deliveredJoinInputs.add(joinId);
|
|
5911
|
-
if (lastHostResponseSequence !== void 0 && lastHostResponseSequence > existing.sequence) continue;
|
|
5912
|
-
const payload = existing.record.payload;
|
|
5913
|
-
if (payload._tag !== "UserInputRecorded") continue;
|
|
5914
|
-
joinedInputs.push(payload);
|
|
5873
|
+
}, Effect.uninterruptible);
|
|
5874
|
+
const prepareInputs = Effect.fnUntraced(function* (limit, firstReady = false) {
|
|
5875
|
+
if (pendingJoinClaims.length < limit && (yield* claimInputs(limit - pendingJoinClaims.length)) > 0) yield* hit("join:after-claim");
|
|
5876
|
+
const prepared = [];
|
|
5877
|
+
for (const pending of pendingJoinClaims.slice(0, limit)) {
|
|
5878
|
+
const claim = pending.claim;
|
|
5879
|
+
const snapshot = yield* ledger.loadRecoverySnapshot(RecoverySnapshotRequest.make({ submissionId: claim.submissionId }));
|
|
5880
|
+
if (snapshot.abortIntent !== void 0) {
|
|
5881
|
+
yield* revertClaims([pending]);
|
|
5882
|
+
continue;
|
|
5915
5883
|
}
|
|
5916
|
-
|
|
5917
|
-
|
|
5918
|
-
|
|
5919
|
-
|
|
5920
|
-
|
|
5921
|
-
const
|
|
5922
|
-
if (
|
|
5923
|
-
|
|
5924
|
-
|
|
5925
|
-
submissionId: claim.submissionId,
|
|
5926
|
-
kind: "steering",
|
|
5927
|
-
runId,
|
|
5928
|
-
input: claim.inputPayload,
|
|
5929
|
-
...payload.messageAdmission === void 0 ? {} : { messageAdmission: payload.messageAdmission }
|
|
5930
|
-
}));
|
|
5931
|
-
sequence = (yield* appendBatch(ctx, CanonicalBatch.make({
|
|
5932
|
-
batchId: submissionInputBatchId(claim.submissionId),
|
|
5933
|
-
producerId: config.producerId,
|
|
5934
|
-
records: [envelope]
|
|
5935
|
-
}))).firstSequence;
|
|
5936
|
-
knownIds.add(recordId);
|
|
5937
|
-
yield* hit("join:after-canonical-append");
|
|
5884
|
+
if (pending.prepared === void 0) {
|
|
5885
|
+
const input = {
|
|
5886
|
+
input: claim.inputPayload,
|
|
5887
|
+
...snapshot.submission.messageAdmission === void 0 ? {} : { messageAdmission: snapshot.submission.messageAdmission }
|
|
5888
|
+
};
|
|
5889
|
+
const rendered = yield* Effect.result(renderJoinedInput(input.input, input.messageAdmission));
|
|
5890
|
+
if (Result.isFailure(rendered)) {
|
|
5891
|
+
yield* revertClaims(pendingJoinClaims.slice(pendingJoinClaims.indexOf(pending)));
|
|
5892
|
+
break;
|
|
5938
5893
|
}
|
|
5939
|
-
|
|
5940
|
-
|
|
5941
|
-
|
|
5942
|
-
|
|
5943
|
-
|
|
5944
|
-
joinedInputs.push({
|
|
5945
|
-
...payload,
|
|
5946
|
-
rendered
|
|
5947
|
-
});
|
|
5894
|
+
pending.prepared = {
|
|
5895
|
+
claim,
|
|
5896
|
+
input,
|
|
5897
|
+
rendered: rendered.success
|
|
5898
|
+
};
|
|
5948
5899
|
}
|
|
5949
|
-
|
|
5950
|
-
|
|
5951
|
-
return yield* Effect.forEach(joinedInputs, (joinedInput) => (joinedInput.rendered === void 0 ? renderJoinedInput(joinedInput) : Effect.succeed(joinedInput.rendered)).pipe(Effect.map((input) => ({
|
|
5952
|
-
kind: "steering",
|
|
5953
|
-
input
|
|
5954
|
-
}))));
|
|
5955
|
-
})
|
|
5956
|
-
};
|
|
5957
|
-
/**
|
|
5958
|
-
* Durable child establishment: `establish` performs or replays
|
|
5959
|
-
* the idempotent get-or-create establishment protocol under the
|
|
5960
|
-
* parent's ownership fence and reports where the one child stands; `join` appends the
|
|
5961
|
-
* atomic `[SubagentJoined, ToolCallSettled]` settlement batch (SUB-019) and applies the
|
|
5962
|
-
* reservation release. Both use the halt side channel exactly like the durability/step
|
|
5963
|
-
* hooks: the engine wraps a `CoordinatorHalt` into `SubagentDurabilityError` in the
|
|
5964
|
-
* handler channel while the Attempt aborts with the original infrastructure failure.
|
|
5965
|
-
*/
|
|
5966
|
-
const establishmentGate = yield* Semaphore.make(1);
|
|
5967
|
-
const establishSubagent = (request) => recordHalt(Effect.gen(function* () {
|
|
5968
|
-
const toolCallId = request.toolCallId;
|
|
5969
|
-
const turnInfo = currentToolTurn;
|
|
5970
|
-
if (turnInfo === void 0) return yield* RunJournalError.make({ message: `Delegation Tool Call ${toolCallId} established before any canonical response commit` });
|
|
5971
|
-
const denied = (errorTag, message) => ({
|
|
5972
|
-
_tag: "denied",
|
|
5973
|
-
errorTag,
|
|
5974
|
-
message: boundedText(message)
|
|
5975
|
-
});
|
|
5976
|
-
let requestedPayload = subagentState.requested.get(toolCallId);
|
|
5977
|
-
if (requestedPayload === void 0) {
|
|
5978
|
-
if (request.depth !== delegationDepth + 1) return denied("SubagentDepthUnsupported", `The child depth must be exactly one greater than its source depth ${delegationDepth}`);
|
|
5979
|
-
let targetDigests = request.targetDigests;
|
|
5980
|
-
if (request.target !== void 0) {
|
|
5981
|
-
if (request.target.id !== request.targetAgentId) return denied("SubagentBindingUnavailable", "The child target identity differs from its Definition");
|
|
5982
|
-
const binding = yield* resolveDefinitionBinding(registeredBindings, request.target).pipe(Effect.result);
|
|
5983
|
-
if (binding._tag === "Failure") return denied("SubagentBindingUnavailable", binding.failure.message);
|
|
5984
|
-
if (targetDigests !== void 0 && (targetDigests.agent !== binding.success.digests.agent || targetDigests.model !== binding.success.digests.model || targetDigests.tools !== binding.success.digests.tools)) return denied("SubagentDigestsInvalid", "The explicit child digests differ from its exact registration");
|
|
5985
|
-
targetDigests = binding.success.digests;
|
|
5900
|
+
prepared.push(pending.prepared);
|
|
5901
|
+
if (firstReady) break;
|
|
5986
5902
|
}
|
|
5987
|
-
|
|
5988
|
-
|
|
5989
|
-
|
|
5990
|
-
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
|
|
5994
|
-
|
|
5995
|
-
|
|
5996
|
-
|
|
5997
|
-
|
|
5998
|
-
|
|
5999
|
-
|
|
6000
|
-
|
|
6001
|
-
|
|
6002
|
-
|
|
6003
|
-
|
|
6004
|
-
|
|
6005
|
-
|
|
6006
|
-
|
|
6007
|
-
|
|
6008
|
-
|
|
6009
|
-
|
|
6010
|
-
|
|
6011
|
-
|
|
6012
|
-
|
|
6013
|
-
|
|
6014
|
-
|
|
6015
|
-
|
|
6016
|
-
|
|
6017
|
-
|
|
6018
|
-
|
|
6019
|
-
|
|
6020
|
-
|
|
6021
|
-
|
|
6022
|
-
|
|
6023
|
-
|
|
6024
|
-
const
|
|
6025
|
-
|
|
6026
|
-
|
|
5903
|
+
return prepared;
|
|
5904
|
+
});
|
|
5905
|
+
const input = {
|
|
5906
|
+
awaitJoin: recordHalt(Effect.gen(function* () {
|
|
5907
|
+
while (true) if (yield* Effect.scoped(Effect.gen(function* () {
|
|
5908
|
+
const notified = yield* wake.subscribe(submission.threadId);
|
|
5909
|
+
if ((yield* prepareInputs(MAX_JOIN_DRAIN, true)).length > 0) return true;
|
|
5910
|
+
yield* notified;
|
|
5911
|
+
return false;
|
|
5912
|
+
}))) return;
|
|
5913
|
+
})),
|
|
5914
|
+
drain: Effect.fnUntraced(function* (policy) {
|
|
5915
|
+
const joinedInputs = yield* recordHalt(Effect.gen(function* () {
|
|
5916
|
+
const limit = policy === "one" ? 1 : MAX_JOIN_DRAIN;
|
|
5917
|
+
const joinedInputs = [];
|
|
5918
|
+
if (joinBacklog === void 0) joinBacklog = (yield* ledger.loadRecoverySnapshot(RecoverySnapshotRequest.make({ submissionId }))).joins;
|
|
5919
|
+
for (const join of joinBacklog) {
|
|
5920
|
+
const joinId = join.submissionId;
|
|
5921
|
+
if (deliveredJoinInputs.has(joinId)) continue;
|
|
5922
|
+
if (join.state !== "joining" && join.state !== "joined") continue;
|
|
5923
|
+
const existing = joinedInputEnvelopes.get(joinId);
|
|
5924
|
+
if (existing === void 0) continue;
|
|
5925
|
+
if (join.state === "joining") yield* session.markJoined(joinId, {
|
|
5926
|
+
recordId: existing.record.recordId,
|
|
5927
|
+
sequence: existing.sequence
|
|
5928
|
+
});
|
|
5929
|
+
deliveredJoinInputs.add(joinId);
|
|
5930
|
+
if (lastHostResponseSequence !== void 0 && lastHostResponseSequence > existing.sequence) continue;
|
|
5931
|
+
const payload = existing.record.payload;
|
|
5932
|
+
if (payload._tag !== "UserInputRecorded") continue;
|
|
5933
|
+
joinedInputs.push(payload);
|
|
5934
|
+
}
|
|
5935
|
+
const claims = yield* prepareInputs(limit);
|
|
5936
|
+
pendingJoinClaims.splice(0, claims.length);
|
|
5937
|
+
for (const { claim, input: payload, rendered } of claims) {
|
|
5938
|
+
const recordId = submissionInputRecordId(claim.submissionId);
|
|
5939
|
+
let sequence;
|
|
5940
|
+
const existing = joinedInputEnvelopes.get(claim.submissionId);
|
|
5941
|
+
if (existing !== void 0) sequence = existing.sequence;
|
|
5942
|
+
else {
|
|
5943
|
+
const envelope = yield* makeEnvelope(recordId, UserInputRecorded.make({
|
|
5944
|
+
submissionId: claim.submissionId,
|
|
5945
|
+
kind: "steering",
|
|
5946
|
+
runId,
|
|
5947
|
+
input: claim.inputPayload,
|
|
5948
|
+
...payload.messageAdmission === void 0 ? {} : { messageAdmission: payload.messageAdmission }
|
|
5949
|
+
}));
|
|
5950
|
+
sequence = (yield* appendBatch(ctx, CanonicalBatch.make({
|
|
5951
|
+
batchId: submissionInputBatchId(claim.submissionId),
|
|
5952
|
+
producerId: config.producerId,
|
|
5953
|
+
records: [envelope]
|
|
5954
|
+
}))).firstSequence;
|
|
5955
|
+
knownIds.add(recordId);
|
|
5956
|
+
yield* hit("join:after-canonical-append");
|
|
5957
|
+
}
|
|
5958
|
+
yield* session.markJoined(claim.submissionId, {
|
|
5959
|
+
recordId,
|
|
5960
|
+
sequence
|
|
5961
|
+
});
|
|
5962
|
+
deliveredJoinInputs.add(claim.submissionId);
|
|
5963
|
+
joinedInputs.push({
|
|
5964
|
+
...payload,
|
|
5965
|
+
rendered
|
|
5966
|
+
});
|
|
6027
5967
|
}
|
|
6028
|
-
|
|
5968
|
+
return joinedInputs;
|
|
5969
|
+
}));
|
|
5970
|
+
return yield* Effect.forEach(joinedInputs, (joinedInput) => (joinedInput.rendered === void 0 ? renderJoinedInput(joinedInput.input, joinedInput.messageAdmission) : Effect.succeed(joinedInput.rendered)).pipe(Effect.map((input) => ({
|
|
5971
|
+
kind: "steering",
|
|
5972
|
+
input
|
|
5973
|
+
}))));
|
|
5974
|
+
})
|
|
5975
|
+
};
|
|
5976
|
+
/**
|
|
5977
|
+
* Durable child establishment: `establish` performs or replays
|
|
5978
|
+
* the idempotent get-or-create establishment protocol under the
|
|
5979
|
+
* parent's ownership fence and reports where the one child stands; `join` appends the
|
|
5980
|
+
* atomic `[SubagentJoined, ToolCallSettled]` settlement batch (SUB-019) and applies the
|
|
5981
|
+
* reservation release. Both use the halt side channel exactly like the durability/step
|
|
5982
|
+
* hooks: the engine wraps a `CoordinatorHalt` into `SubagentDurabilityError` in the
|
|
5983
|
+
* handler channel while the Attempt aborts with the original infrastructure failure.
|
|
5984
|
+
*/
|
|
5985
|
+
const establishmentGate = yield* Semaphore.make(1);
|
|
5986
|
+
const establishSubagent = (request) => recordHalt(Effect.gen(function* () {
|
|
5987
|
+
const toolCallId = request.toolCallId;
|
|
5988
|
+
const turnInfo = currentToolTurn;
|
|
5989
|
+
if (turnInfo === void 0) return yield* RunJournalError.make({ message: `Delegation Tool Call ${toolCallId} established before any canonical response commit` });
|
|
5990
|
+
const denied = (errorTag, message) => ({
|
|
5991
|
+
_tag: "denied",
|
|
5992
|
+
errorTag,
|
|
5993
|
+
message: boundedText(message)
|
|
5994
|
+
});
|
|
5995
|
+
let requestedPayload = subagentState.requested.get(toolCallId);
|
|
5996
|
+
if (requestedPayload === void 0) {
|
|
5997
|
+
if (request.depth !== delegationDepth + 1) return denied("SubagentDepthUnsupported", `The child depth must be exactly one greater than its source depth ${delegationDepth}`);
|
|
5998
|
+
let targetDigests = request.targetDigests;
|
|
5999
|
+
if (request.target !== void 0) {
|
|
6000
|
+
if (request.target.id !== request.targetAgentId) return denied("SubagentBindingUnavailable", "The child target identity differs from its Definition");
|
|
6001
|
+
const binding = yield* resolveDefinitionBinding(registeredBindings, request.target).pipe(Effect.result);
|
|
6002
|
+
if (binding._tag === "Failure") return denied("SubagentBindingUnavailable", binding.failure.message);
|
|
6003
|
+
if (targetDigests !== void 0 && (targetDigests.agent !== binding.success.digests.agent || targetDigests.model !== binding.success.digests.model || targetDigests.tools !== binding.success.digests.tools)) return denied("SubagentDigestsInvalid", "The explicit child digests differ from its exact registration");
|
|
6004
|
+
targetDigests = binding.success.digests;
|
|
6029
6005
|
}
|
|
6030
|
-
|
|
6031
|
-
|
|
6032
|
-
|
|
6033
|
-
|
|
6034
|
-
|
|
6035
|
-
|
|
6036
|
-
|
|
6037
|
-
|
|
6038
|
-
|
|
6039
|
-
|
|
6040
|
-
|
|
6041
|
-
|
|
6042
|
-
|
|
6043
|
-
|
|
6044
|
-
|
|
6045
|
-
|
|
6046
|
-
|
|
6047
|
-
|
|
6048
|
-
|
|
6049
|
-
|
|
6006
|
+
const decodedDigests = yield* decodeDefinitionDigests(targetDigests).pipe(Effect.option);
|
|
6007
|
+
if (Option.isNone(decodedDigests)) return denied("SubagentDigestsInvalid", "The declared child Binding digests are not valid stored digests");
|
|
6008
|
+
const childInput = yield* decodePersisted(request.encodedChildInput).pipe(Effect.option);
|
|
6009
|
+
if (Option.isNone(childInput)) return denied("SubagentInputUnpersistable", "The prepared child input does not satisfy the canonical persistence bounds");
|
|
6010
|
+
const grant = yield* decodePersisted(request.encodedGrant).pipe(Effect.option);
|
|
6011
|
+
const allocation = yield* decodePersisted(request.encodedAllocation).pipe(Effect.option);
|
|
6012
|
+
if (Option.isNone(grant) || Option.isNone(allocation)) return denied("SubagentDeclarationUnpersistable", "The delegation grant or allocation does not satisfy the canonical persistence bounds");
|
|
6013
|
+
const decodedGrant = Schema.decodeUnknownOption(SubagentGrant)(grant.value);
|
|
6014
|
+
if (Option.isNone(decodedGrant)) return denied("SubagentGrantInvalid", "The child authority grant is invalid");
|
|
6015
|
+
if (request.policy === void 0 || request.budget === void 0) return denied("SubagentBudgetInvalid", "New durable children require their full execution policy and subtree allocation");
|
|
6016
|
+
if (request.toolCallAllowance !== void 0 && !Schema.is(SubagentRequested.fields.toolCallAllowance)(request.toolCallAllowance)) return denied("SubagentAllowanceInvalid", "The child Tool Call allowance must be a positive integer");
|
|
6017
|
+
if (request.policy !== void 0 && !Schema.is(AgentPolicy)(request.policy)) return denied("SubagentPolicyInvalid", "The resolved child policy is invalid");
|
|
6018
|
+
if (request.budget !== void 0) {
|
|
6019
|
+
if (!Schema.is(SubagentBudgetReservation)(request.budget)) return denied("SubagentBudgetInvalid", "The shared delegation budget is invalid");
|
|
6020
|
+
const decodedAllocation = Schema.decodeUnknownOption(SubagentReservationAmounts)(allocation.value);
|
|
6021
|
+
if (Option.isNone(decodedAllocation) || !Equal.equals(decodedAllocation.value, request.budget.allocation)) return denied("SubagentBudgetInvalid", "The reserved allocation differs from its budget declaration");
|
|
6022
|
+
const { caps, allocation: requested } = request.budget;
|
|
6023
|
+
const prior = [...subagentState.requested.values()];
|
|
6024
|
+
if (prior.some((entry) => entry.budget === void 0 || !Equal.equals(entry.budget.caps, caps))) return denied("SubagentParentBudgetConflict", "Delegations in one parent Run must share the same caps");
|
|
6025
|
+
if (caps.maxTotalChildInvocations !== void 0 && prior.reduce((sum, entry) => sum + 1 + (entry.budget?.descendantInvocations ?? 0), 1 + (request.budget.descendantInvocations ?? 0)) > caps.maxTotalChildInvocations) return denied("SubagentBudgetExhausted", "The parent Run exhausted its child invocation budget");
|
|
6026
|
+
const active = prior.filter((entry) => !subagentState.joined.has(entry.toolCallId));
|
|
6027
|
+
if (caps.maxConcurrentChildren !== void 0 && active.length >= caps.maxConcurrentChildren) return denied("SubagentBudgetExhausted", "The parent Run exhausted its concurrent child budget");
|
|
6028
|
+
const dimensions = [
|
|
6029
|
+
["turns", "maxTurns"],
|
|
6030
|
+
["toolCalls", "maxToolCalls"],
|
|
6031
|
+
["durationMillis", "maxDurationMillis"],
|
|
6032
|
+
["inputTokens", "maxInputTokens"],
|
|
6033
|
+
["outputTokens", "maxOutputTokens"],
|
|
6034
|
+
["costMicrousd", "maxCostMicrousd"],
|
|
6035
|
+
["resultBytes", "maxResultBytes"]
|
|
6036
|
+
];
|
|
6037
|
+
const accounting = Schema.Struct({ consumed: SubagentReservationAmounts });
|
|
6038
|
+
for (const [amount, cap] of dimensions) {
|
|
6039
|
+
const limit = caps[cap];
|
|
6040
|
+
if (limit === void 0) continue;
|
|
6041
|
+
let consumed = requested[amount];
|
|
6042
|
+
for (const entry of prior) {
|
|
6043
|
+
const joined = subagentState.joined.get(entry.toolCallId);
|
|
6044
|
+
const observed = joined === void 0 ? Option.none() : Schema.decodeUnknownOption(accounting)(joined.finalAccounting);
|
|
6045
|
+
consumed += Option.isSome(observed) ? observed.value.consumed[amount] : entry.budget?.allocation[amount] ?? limit;
|
|
6046
|
+
}
|
|
6047
|
+
if (consumed > limit) return denied("SubagentBudgetExhausted", `The parent Run exhausted its shared ${amount} budget`);
|
|
6048
|
+
}
|
|
6049
|
+
}
|
|
6050
|
+
const childInputDigest = yield* withCrypto(digestJson(childInput.value));
|
|
6051
|
+
const grantDigest = yield* withCrypto(digestJson(grant.value));
|
|
6052
|
+
const allocationDigest = yield* withCrypto(digestJson(allocation.value));
|
|
6053
|
+
const reservationId = childReservationIdFor(runId, toolCallId);
|
|
6054
|
+
const subtree = delegationDepth === 0 ? void 0 : yield* workerRuntime.reserveSubtree(submission.threadId, SubtreeBudgetReserved.make({
|
|
6055
|
+
reservationId,
|
|
6056
|
+
executionRunId: runId,
|
|
6057
|
+
sourceSubmissionId: submissionId,
|
|
6058
|
+
childThreadId: childThreadIdFor(submissionId, toolCallId),
|
|
6059
|
+
lifetime: "attached",
|
|
6060
|
+
depth: request.depth,
|
|
6061
|
+
policy: request.policy,
|
|
6062
|
+
grant: decodedGrant.value,
|
|
6063
|
+
budget: request.budget
|
|
6064
|
+
})).pipe(Effect.result);
|
|
6065
|
+
if (subtree?._tag === "Failure") {
|
|
6066
|
+
if (subtree.failure.reason === "storage") return yield* LedgerError.make({
|
|
6067
|
+
operation: "reserve-subtree",
|
|
6068
|
+
message: "Subtree reservation is unavailable"
|
|
6069
|
+
});
|
|
6070
|
+
return denied("SubagentBudgetExhausted", `The subtree reservation was refused: ${subtree.failure.reason}`);
|
|
6071
|
+
}
|
|
6072
|
+
yield* session.reserveChildBudget({
|
|
6073
|
+
reservationId,
|
|
6074
|
+
parentToolCallId: toolCallId,
|
|
6075
|
+
allocation: allocation.value,
|
|
6076
|
+
allocationDigest
|
|
6077
|
+
}).pipe(Effect.catchTag("ChildReservationConflict", conflictToLedgerError("reserveChildBudget")));
|
|
6078
|
+
yield* hit("subagent:after-reserve");
|
|
6079
|
+
requestedPayload = SubagentRequested.make({
|
|
6080
|
+
runId,
|
|
6081
|
+
turnId: turnInfo.turnId,
|
|
6082
|
+
turn: turnInfo.turn,
|
|
6083
|
+
toolCallId,
|
|
6084
|
+
delegationId: request.delegationId,
|
|
6085
|
+
targetAgentId: request.targetAgentId,
|
|
6086
|
+
targetDigests: decodedDigests.value,
|
|
6087
|
+
childInput: childInput.value,
|
|
6088
|
+
childInputDigest,
|
|
6089
|
+
grantDigest,
|
|
6090
|
+
grant: decodedGrant.value,
|
|
6091
|
+
depth: request.depth,
|
|
6092
|
+
reservationId,
|
|
6093
|
+
reservationDigest: allocationDigest,
|
|
6094
|
+
childThreadId: childThreadIdFor(submissionId, toolCallId),
|
|
6095
|
+
childPrincipal: submission.principal,
|
|
6096
|
+
childIdempotencyKey: childIdempotencyKeyFor(runId, toolCallId),
|
|
6097
|
+
...request.toolCallAllowance === void 0 ? {} : { toolCallAllowance: request.toolCallAllowance },
|
|
6098
|
+
...request.policy === void 0 ? {} : { policy: request.policy },
|
|
6099
|
+
...request.budget === void 0 ? {} : { budget: request.budget }
|
|
6050
6100
|
});
|
|
6051
|
-
|
|
6101
|
+
const requestRecordId = subagentRequestedRecordId(runId, toolCallId);
|
|
6102
|
+
if (!knownIds.has(requestRecordId)) {
|
|
6103
|
+
const envelope = yield* makeEnvelope(requestRecordId, requestedPayload);
|
|
6104
|
+
yield* appendBatch(ctx, CanonicalBatch.make({
|
|
6105
|
+
batchId: subagentRequestedBatchId(runId, toolCallId),
|
|
6106
|
+
producerId: config.producerId,
|
|
6107
|
+
records: [envelope]
|
|
6108
|
+
})).pipe(Effect.catchTag("AppendConflict", () => Effect.void), Effect.asVoid);
|
|
6109
|
+
knownIds.add(requestRecordId);
|
|
6110
|
+
}
|
|
6111
|
+
subagentState.requested.set(toolCallId, requestedPayload);
|
|
6112
|
+
yield* hit("subagent:after-request-append");
|
|
6052
6113
|
}
|
|
6053
|
-
yield*
|
|
6054
|
-
|
|
6055
|
-
|
|
6056
|
-
|
|
6057
|
-
allocationDigest
|
|
6058
|
-
}).pipe(Effect.catchTag("ChildReservationConflict", conflictToLedgerError("reserveChildBudget")));
|
|
6059
|
-
yield* hit("subagent:after-reserve");
|
|
6060
|
-
requestedPayload = SubagentRequested.make({
|
|
6061
|
-
runId,
|
|
6062
|
-
turnId: turnInfo.turnId,
|
|
6063
|
-
turn: turnInfo.turn,
|
|
6064
|
-
toolCallId,
|
|
6065
|
-
delegationId: request.delegationId,
|
|
6066
|
-
targetAgentId: request.targetAgentId,
|
|
6067
|
-
targetDigests: decodedDigests.value,
|
|
6068
|
-
childInput: childInput.value,
|
|
6069
|
-
childInputDigest,
|
|
6070
|
-
grantDigest,
|
|
6071
|
-
grant: decodedGrant.value,
|
|
6072
|
-
depth: request.depth,
|
|
6073
|
-
reservationId,
|
|
6074
|
-
reservationDigest: allocationDigest,
|
|
6075
|
-
childThreadId: childThreadIdFor(submissionId, toolCallId),
|
|
6076
|
-
childPrincipal: submission.principal,
|
|
6077
|
-
childIdempotencyKey: childIdempotencyKeyFor(runId, toolCallId),
|
|
6078
|
-
...request.toolCallAllowance === void 0 ? {} : { toolCallAllowance: request.toolCallAllowance },
|
|
6079
|
-
...request.policy === void 0 ? {} : { policy: request.policy },
|
|
6080
|
-
...request.budget === void 0 ? {} : { budget: request.budget }
|
|
6114
|
+
const admission = yield* establishChildFromRequest(submission, requestedPayload);
|
|
6115
|
+
if (admission._tag === "indeterminate") return yield* LedgerError.make({
|
|
6116
|
+
operation: "establishSubagent",
|
|
6117
|
+
message: `Child admission for Tool Call ${toolCallId} is indeterminate (${admission.reason}); retrying without a second admission (SUB-031)`
|
|
6081
6118
|
});
|
|
6082
|
-
const
|
|
6083
|
-
|
|
6084
|
-
|
|
6085
|
-
|
|
6086
|
-
|
|
6087
|
-
|
|
6088
|
-
|
|
6089
|
-
|
|
6090
|
-
|
|
6091
|
-
|
|
6092
|
-
|
|
6093
|
-
|
|
6094
|
-
|
|
6095
|
-
|
|
6096
|
-
|
|
6097
|
-
|
|
6098
|
-
|
|
6099
|
-
|
|
6100
|
-
|
|
6101
|
-
|
|
6102
|
-
|
|
6103
|
-
|
|
6104
|
-
|
|
6105
|
-
|
|
6106
|
-
|
|
6107
|
-
|
|
6108
|
-
childReceiptId: admission.receiptId,
|
|
6109
|
-
childRunId
|
|
6119
|
+
const childRunId = runIdForSubmission(admission.childSubmissionId);
|
|
6120
|
+
let startedPayload = subagentState.started.get(toolCallId);
|
|
6121
|
+
if (startedPayload === void 0) {
|
|
6122
|
+
startedPayload = SubagentStarted.make({
|
|
6123
|
+
runId,
|
|
6124
|
+
toolCallId,
|
|
6125
|
+
childThreadId: requestedPayload.childThreadId,
|
|
6126
|
+
childSubmissionId: admission.childSubmissionId,
|
|
6127
|
+
childReceiptId: admission.receiptId,
|
|
6128
|
+
childRunId
|
|
6129
|
+
});
|
|
6130
|
+
const startRecordId = subagentStartedRecordId(runId, toolCallId);
|
|
6131
|
+
if (!knownIds.has(startRecordId)) {
|
|
6132
|
+
const envelope = yield* makeEnvelope(startRecordId, startedPayload);
|
|
6133
|
+
yield* appendBatch(ctx, CanonicalBatch.make({
|
|
6134
|
+
batchId: subagentStartedBatchId(runId, toolCallId),
|
|
6135
|
+
producerId: config.producerId,
|
|
6136
|
+
records: [envelope]
|
|
6137
|
+
})).pipe(Effect.catchTag("AppendConflict", () => Effect.void), Effect.asVoid);
|
|
6138
|
+
knownIds.add(startRecordId);
|
|
6139
|
+
}
|
|
6140
|
+
subagentState.started.set(toolCallId, startedPayload);
|
|
6141
|
+
yield* hit("subagent:after-start-append");
|
|
6142
|
+
} else if (startedPayload.childSubmissionId !== admission.childSubmissionId) return yield* LedgerError.make({
|
|
6143
|
+
operation: "establishSubagent",
|
|
6144
|
+
message: `The canonical SubagentStarted record names child ${startedPayload.childSubmissionId} but admission resolved ${admission.childSubmissionId}; establishment fails closed (SUB-016)`
|
|
6110
6145
|
});
|
|
6111
|
-
|
|
6112
|
-
|
|
6113
|
-
|
|
6146
|
+
yield* session.attachChildToReservation({
|
|
6147
|
+
reservationId: decodeChildReservationIdSync(requestedPayload.reservationId),
|
|
6148
|
+
childSubmissionId: startedPayload.childSubmissionId
|
|
6149
|
+
}).pipe(Effect.catchTag("ChildReservationConflict", conflictToLedgerError("attachChildToReservation")));
|
|
6150
|
+
const identity = {
|
|
6151
|
+
childThreadId: startedPayload.childThreadId,
|
|
6152
|
+
childSubmissionId: startedPayload.childSubmissionId,
|
|
6153
|
+
childRunId: startedPayload.childRunId,
|
|
6154
|
+
receiptId: startedPayload.childReceiptId
|
|
6155
|
+
};
|
|
6156
|
+
const child = yield* ledger.lookup(SubmissionLookupById.make({ submissionId: startedPayload.childSubmissionId }));
|
|
6157
|
+
if (Option.isNone(child)) return yield* LedgerError.make({
|
|
6158
|
+
operation: "establishSubagent",
|
|
6159
|
+
message: `Established child ${startedPayload.childSubmissionId} is unknown to the ledger`
|
|
6160
|
+
});
|
|
6161
|
+
if (child.value.state !== "settled") return {
|
|
6162
|
+
_tag: "waiting",
|
|
6163
|
+
...identity
|
|
6164
|
+
};
|
|
6165
|
+
const verification = yield* verifySettledChild(submission, requestedPayload, startedPayload.childSubmissionId);
|
|
6166
|
+
if (verification._tag === "mismatch") return denied("SubagentVerificationFailed", verification.message);
|
|
6167
|
+
return {
|
|
6168
|
+
_tag: "settled",
|
|
6169
|
+
...identity,
|
|
6170
|
+
outcome: verification.value.outcome,
|
|
6171
|
+
encodedResult: verification.value.encodedResult,
|
|
6172
|
+
...yield* verifiedChildUsage(verification.value, startedPayload.childRunId),
|
|
6173
|
+
...verification.value.settlement.finishReason === void 0 ? {} : { finishReason: verification.value.settlement.finishReason }
|
|
6174
|
+
};
|
|
6175
|
+
}).pipe(establishmentGate.withPermits(1)));
|
|
6176
|
+
const joinSubagent = (request) => recordHalt(Effect.gen(function* () {
|
|
6177
|
+
const toolCallId = request.toolCallId;
|
|
6178
|
+
const turnInfo = currentToolTurn;
|
|
6179
|
+
if (turnInfo === void 0) return yield* RunJournalError.make({ message: `Delegation Tool Call ${toolCallId} joined before any canonical response commit` });
|
|
6180
|
+
const requestedPayload = subagentState.requested.get(toolCallId);
|
|
6181
|
+
const startedPayload = subagentState.started.get(toolCallId);
|
|
6182
|
+
if (requestedPayload === void 0 || startedPayload === void 0) return yield* RunJournalError.make({ message: `Delegation Tool Call ${toolCallId} joined without canonical establishment records` });
|
|
6183
|
+
const reservationId = decodeChildReservationIdSync(requestedPayload.reservationId);
|
|
6184
|
+
const joinedRecordId = subagentJoinedRecordId(runId, toolCallId);
|
|
6185
|
+
let finalAccounting;
|
|
6186
|
+
const existingJoined = subagentState.joined.get(toolCallId);
|
|
6187
|
+
if (existingJoined !== void 0) finalAccounting = existingJoined.finalAccounting;
|
|
6188
|
+
else {
|
|
6189
|
+
const encodedResult = yield* decodePersisted(request.encodedResult).pipe(Effect.mapError((cause) => RunJournalError.make({
|
|
6190
|
+
message: `The projected result of Tool Call ${toolCallId} exceeds canonical persistence bounds`,
|
|
6191
|
+
cause
|
|
6192
|
+
})));
|
|
6193
|
+
const accounting = yield* decodePersisted(request.encodedAccounting).pipe(Effect.mapError((cause) => RunJournalError.make({
|
|
6194
|
+
message: `The join accounting of Tool Call ${toolCallId} exceeds canonical persistence bounds`,
|
|
6195
|
+
cause
|
|
6196
|
+
})));
|
|
6197
|
+
const verification = yield* verifySettledChild(submission, requestedPayload, startedPayload.childSubmissionId);
|
|
6198
|
+
if (verification._tag === "mismatch") return yield* LedgerError.make({
|
|
6199
|
+
operation: "joinSubagent",
|
|
6200
|
+
message: `Child Settlement verification failed for Tool Call ${toolCallId}: ${verification.message}`
|
|
6201
|
+
});
|
|
6202
|
+
const verified = verification.value;
|
|
6203
|
+
const toolName = declaredNamesByCallId.get(toolCallId);
|
|
6204
|
+
if (toolName === void 0) return yield* RunJournalError.make({ message: `Delegation Tool Call ${toolCallId} joined without a declared Tool name` });
|
|
6205
|
+
yield* hit("subagent:before-join-append");
|
|
6206
|
+
const joinedPayload = SubagentJoined.make({
|
|
6207
|
+
runId,
|
|
6208
|
+
toolCallId,
|
|
6209
|
+
childSubmissionId: startedPayload.childSubmissionId,
|
|
6210
|
+
childSettlementId: verified.settlement.settlementId,
|
|
6211
|
+
childOutcome: verified.outcome,
|
|
6212
|
+
usageSummary: yield* childUsageSummaryOf(verified.childRecords, startedPayload.childRunId),
|
|
6213
|
+
...yield* verifiedChildUsage(verified, startedPayload.childRunId),
|
|
6214
|
+
reservationId: requestedPayload.reservationId,
|
|
6215
|
+
finalAccounting: accounting
|
|
6216
|
+
});
|
|
6217
|
+
const settledRecordId = toolCallSettledRecordId(runId, turnInfo.turn, toolCallId);
|
|
6218
|
+
const joinedEnvelope = yield* makeEnvelope(joinedRecordId, joinedPayload);
|
|
6219
|
+
const settledEnvelope = yield* makeEnvelope(settledRecordId, ToolCallSettled.make({
|
|
6220
|
+
runId,
|
|
6221
|
+
toolCallId,
|
|
6222
|
+
toolName,
|
|
6223
|
+
result: encodedResult,
|
|
6224
|
+
isFailure: request.isFailure
|
|
6225
|
+
}));
|
|
6114
6226
|
yield* appendBatch(ctx, CanonicalBatch.make({
|
|
6115
|
-
batchId:
|
|
6227
|
+
batchId: subagentJoinBatchId(runId, toolCallId),
|
|
6116
6228
|
producerId: config.producerId,
|
|
6117
|
-
records: [
|
|
6229
|
+
records: [joinedEnvelope, settledEnvelope]
|
|
6118
6230
|
})).pipe(Effect.catchTag("AppendConflict", () => Effect.void), Effect.asVoid);
|
|
6119
|
-
knownIds.add(
|
|
6231
|
+
knownIds.add(joinedRecordId);
|
|
6232
|
+
knownIds.add(settledRecordId);
|
|
6233
|
+
subagentState.joined.set(toolCallId, joinedPayload);
|
|
6234
|
+
finalAccounting = accounting;
|
|
6235
|
+
yield* hit("subagent:after-join-append");
|
|
6120
6236
|
}
|
|
6121
|
-
|
|
6122
|
-
|
|
6123
|
-
} else if (startedPayload.childSubmissionId !== admission.childSubmissionId) return yield* LedgerError.make({
|
|
6124
|
-
operation: "establishSubagent",
|
|
6125
|
-
message: `The canonical SubagentStarted record names child ${startedPayload.childSubmissionId} but admission resolved ${admission.childSubmissionId}; establishment fails closed (SUB-016)`
|
|
6126
|
-
});
|
|
6127
|
-
yield* session.attachChildToReservation({
|
|
6128
|
-
reservationId: decodeChildReservationIdSync(requestedPayload.reservationId),
|
|
6129
|
-
childSubmissionId: startedPayload.childSubmissionId
|
|
6130
|
-
}).pipe(Effect.catchTag("ChildReservationConflict", conflictToLedgerError("attachChildToReservation")));
|
|
6131
|
-
const identity = {
|
|
6132
|
-
childThreadId: startedPayload.childThreadId,
|
|
6133
|
-
childSubmissionId: startedPayload.childSubmissionId,
|
|
6134
|
-
childRunId: startedPayload.childRunId,
|
|
6135
|
-
receiptId: startedPayload.childReceiptId
|
|
6136
|
-
};
|
|
6137
|
-
const child = yield* ledger.lookup(SubmissionLookupById.make({ submissionId: startedPayload.childSubmissionId }));
|
|
6138
|
-
if (Option.isNone(child)) return yield* LedgerError.make({
|
|
6139
|
-
operation: "establishSubagent",
|
|
6140
|
-
message: `Established child ${startedPayload.childSubmissionId} is unknown to the ledger`
|
|
6141
|
-
});
|
|
6142
|
-
if (child.value.state !== "settled") return {
|
|
6143
|
-
_tag: "waiting",
|
|
6144
|
-
...identity
|
|
6145
|
-
};
|
|
6146
|
-
const verification = yield* verifySettledChild(submission, requestedPayload, startedPayload.childSubmissionId);
|
|
6147
|
-
if (verification._tag === "mismatch") return denied("SubagentVerificationFailed", verification.message);
|
|
6148
|
-
return {
|
|
6149
|
-
_tag: "settled",
|
|
6150
|
-
...identity,
|
|
6151
|
-
outcome: verification.value.outcome,
|
|
6152
|
-
encodedResult: verification.value.encodedResult,
|
|
6153
|
-
...yield* verifiedChildUsage(verification.value, startedPayload.childRunId),
|
|
6154
|
-
...verification.value.settlement.finishReason === void 0 ? {} : { finishReason: verification.value.settlement.finishReason }
|
|
6155
|
-
};
|
|
6156
|
-
}).pipe(establishmentGate.withPermits(1)));
|
|
6157
|
-
const joinSubagent = (request) => recordHalt(Effect.gen(function* () {
|
|
6158
|
-
const toolCallId = request.toolCallId;
|
|
6159
|
-
const turnInfo = currentToolTurn;
|
|
6160
|
-
if (turnInfo === void 0) return yield* RunJournalError.make({ message: `Delegation Tool Call ${toolCallId} joined before any canonical response commit` });
|
|
6161
|
-
const requestedPayload = subagentState.requested.get(toolCallId);
|
|
6162
|
-
const startedPayload = subagentState.started.get(toolCallId);
|
|
6163
|
-
if (requestedPayload === void 0 || startedPayload === void 0) return yield* RunJournalError.make({ message: `Delegation Tool Call ${toolCallId} joined without canonical establishment records` });
|
|
6164
|
-
const reservationId = decodeChildReservationIdSync(requestedPayload.reservationId);
|
|
6165
|
-
const joinedRecordId = subagentJoinedRecordId(runId, toolCallId);
|
|
6166
|
-
let finalAccounting;
|
|
6167
|
-
const existingJoined = subagentState.joined.get(toolCallId);
|
|
6168
|
-
if (existingJoined !== void 0) finalAccounting = existingJoined.finalAccounting;
|
|
6169
|
-
else {
|
|
6170
|
-
const encodedResult = yield* decodePersisted(request.encodedResult).pipe(Effect.mapError((cause) => RunJournalError.make({
|
|
6171
|
-
message: `The projected result of Tool Call ${toolCallId} exceeds canonical persistence bounds`,
|
|
6172
|
-
cause
|
|
6173
|
-
})));
|
|
6174
|
-
const accounting = yield* decodePersisted(request.encodedAccounting).pipe(Effect.mapError((cause) => RunJournalError.make({
|
|
6175
|
-
message: `The join accounting of Tool Call ${toolCallId} exceeds canonical persistence bounds`,
|
|
6176
|
-
cause
|
|
6177
|
-
})));
|
|
6178
|
-
const verification = yield* verifySettledChild(submission, requestedPayload, startedPayload.childSubmissionId);
|
|
6179
|
-
if (verification._tag === "mismatch") return yield* LedgerError.make({
|
|
6180
|
-
operation: "joinSubagent",
|
|
6181
|
-
message: `Child Settlement verification failed for Tool Call ${toolCallId}: ${verification.message}`
|
|
6182
|
-
});
|
|
6183
|
-
const verified = verification.value;
|
|
6184
|
-
const toolName = declaredNamesByCallId.get(toolCallId);
|
|
6185
|
-
if (toolName === void 0) return yield* RunJournalError.make({ message: `Delegation Tool Call ${toolCallId} joined without a declared Tool name` });
|
|
6186
|
-
yield* hit("subagent:before-join-append");
|
|
6187
|
-
const joinedPayload = SubagentJoined.make({
|
|
6237
|
+
yield* applyReservationRelease(reservationId, finalAccounting, {
|
|
6238
|
+
threadId: submission.threadId,
|
|
6188
6239
|
runId,
|
|
6189
|
-
toolCallId
|
|
6190
|
-
childSubmissionId: startedPayload.childSubmissionId,
|
|
6191
|
-
childSettlementId: verified.settlement.settlementId,
|
|
6192
|
-
childOutcome: verified.outcome,
|
|
6193
|
-
usageSummary: yield* childUsageSummaryOf(verified.childRecords, startedPayload.childRunId),
|
|
6194
|
-
...yield* verifiedChildUsage(verified, startedPayload.childRunId),
|
|
6195
|
-
reservationId: requestedPayload.reservationId,
|
|
6196
|
-
finalAccounting: accounting
|
|
6240
|
+
toolCallId
|
|
6197
6241
|
});
|
|
6198
|
-
|
|
6199
|
-
|
|
6200
|
-
|
|
6201
|
-
|
|
6202
|
-
|
|
6203
|
-
|
|
6204
|
-
|
|
6205
|
-
|
|
6206
|
-
|
|
6207
|
-
|
|
6208
|
-
|
|
6209
|
-
|
|
6210
|
-
|
|
6211
|
-
|
|
6212
|
-
knownIds.add(joinedRecordId);
|
|
6213
|
-
knownIds.add(settledRecordId);
|
|
6214
|
-
subagentState.joined.set(toolCallId, joinedPayload);
|
|
6215
|
-
finalAccounting = accounting;
|
|
6216
|
-
yield* hit("subagent:after-join-append");
|
|
6217
|
-
}
|
|
6218
|
-
yield* applyReservationRelease(reservationId, finalAccounting, {
|
|
6242
|
+
}));
|
|
6243
|
+
const subagent = {
|
|
6244
|
+
establish: establishSubagent,
|
|
6245
|
+
join: joinSubagent
|
|
6246
|
+
};
|
|
6247
|
+
const toolAuthorization = inheritedGrant === void 0 && runToolAuthorization === RunToolAuthorization.allowAllPolicy ? runToolAuthorization : { authorize: (request) => inheritedGrant !== void 0 && !inheritedGrant.allowedToolNames.includes(request.call.toolName) ? Effect.succeed({
|
|
6248
|
+
_tag: "denied",
|
|
6249
|
+
reason: "Tool exceeds the worker's immutable grant"
|
|
6250
|
+
}) : runToolAuthorization.authorize({
|
|
6251
|
+
...request,
|
|
6252
|
+
input: submission.inputPayload,
|
|
6253
|
+
...Schema.is(FrameworkMessage)(submission.messageAdmission) ? { frameworkMessage: submission.messageAdmission } : {}
|
|
6254
|
+
}) };
|
|
6255
|
+
const options = {
|
|
6219
6256
|
threadId: submission.threadId,
|
|
6220
6257
|
runId,
|
|
6221
|
-
|
|
6222
|
-
|
|
6223
|
-
|
|
6224
|
-
|
|
6225
|
-
|
|
6226
|
-
|
|
6227
|
-
|
|
6228
|
-
|
|
6229
|
-
|
|
6230
|
-
|
|
6231
|
-
|
|
6232
|
-
|
|
6233
|
-
|
|
6234
|
-
|
|
6235
|
-
|
|
6236
|
-
|
|
6237
|
-
|
|
6238
|
-
|
|
6239
|
-
|
|
6240
|
-
|
|
6241
|
-
|
|
6242
|
-
|
|
6243
|
-
|
|
6244
|
-
|
|
6245
|
-
|
|
6246
|
-
|
|
6247
|
-
|
|
6248
|
-
|
|
6249
|
-
|
|
6250
|
-
|
|
6251
|
-
|
|
6252
|
-
|
|
6253
|
-
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
|
|
6259
|
-
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
|
|
6263
|
-
|
|
6264
|
-
|
|
6265
|
-
|
|
6266
|
-
|
|
6267
|
-
|
|
6268
|
-
|
|
6269
|
-
} },
|
|
6270
|
-
...preparedContext === void 0 ? {} : { context: preparedContext },
|
|
6271
|
-
beforeTurn: () => Effect.gen(function* () {
|
|
6272
|
-
if (yieldAfter !== void 0 && (yield* Clock.currentTimeMillis) >= DateTime.toEpochMillis(yieldAfter)) {
|
|
6273
|
-
yield* Deferred.succeed(yieldSignal, void 0);
|
|
6274
|
-
return yield* Effect.never;
|
|
6275
|
-
}
|
|
6276
|
-
if (submissionScheduling.yieldTo !== void 0 && (yield* Ref.get(turnCounter)) > 0) {
|
|
6277
|
-
const candidate = yield* recordHalt(eligibleThreadHead(submission.threadId, submission.queueSequence));
|
|
6278
|
-
if (Option.isSome(candidate) && (candidate.value.state === "ready" || candidate.value.state === "input-applied")) {
|
|
6279
|
-
const next = yield* recordHalt(ledger.lookup(SubmissionLookupById.make({ submissionId: candidate.value.submissionId })));
|
|
6280
|
-
if (Option.isSome(next) && next.value.agentId === submission.agentId && (next.value.state === "ready" || next.value.state === "input-applied") && (yield* recordHalt(submissionScheduling.yieldTo({
|
|
6281
|
-
active: submission,
|
|
6282
|
-
next: next.value
|
|
6283
|
-
})))) {
|
|
6284
|
-
yield* Deferred.succeed(yieldSignal, next.value.submissionId);
|
|
6285
|
-
return yield* Effect.never;
|
|
6258
|
+
history: pending === void 0 ? journal.historyBefore : resumeProjection.historyBefore,
|
|
6259
|
+
input,
|
|
6260
|
+
commandDrainPolicy: "all",
|
|
6261
|
+
...priorContext !== void 0 || journal.committedTurns > 0 || Schema.is(FrameworkMessage)(submission.messageAdmission) ? { retainedInput: submission.inputPayload } : {},
|
|
6262
|
+
...priorContext === void 0 ? {} : { retainedContext: Prompt.fromMessages(priorContext.prompt.content.slice(priorContext.priorHistoryLength)) },
|
|
6263
|
+
...Schema.is(FrameworkMessage)(submission.messageAdmission) ? { frameworkMessage: submission.messageAdmission } : {},
|
|
6264
|
+
approval,
|
|
6265
|
+
toolAuthorization,
|
|
6266
|
+
...journal.toolSelection === void 0 ? {} : { toolSelection: { toolNames: journal.toolSelection.toolNames.filter((name) => Object.hasOwn(agent.definition.toolkit.tools, name)) } },
|
|
6267
|
+
durability,
|
|
6268
|
+
subagent,
|
|
6269
|
+
delegationDepth,
|
|
6270
|
+
...inheritedGrant === void 0 ? {} : { subagentGrant: inheritedGrant },
|
|
6271
|
+
...inheritedBudget === void 0 ? {} : { subagentBudget: inheritedBudget },
|
|
6272
|
+
...submission.workerAdmission?.origin.budgetScope === void 0 ? {} : { subagentBudgetScope: submission.workerAdmission.origin.budgetScope },
|
|
6273
|
+
runStartedAt: runTiming.startedAt,
|
|
6274
|
+
durationDeadline: runTiming.deadline,
|
|
6275
|
+
...submission.workerAdmission === void 0 ? {} : { toolCallAllowance: submission.workerAdmission.origin.toolCallAllowance },
|
|
6276
|
+
...submission.parentLinkage !== void 0 && childLineage?._tag === "SubagentLineageRecorded" ? { toolCallAllowance: childLineage.toolCallAllowance } : {},
|
|
6277
|
+
...pending === void 0 ? {} : { resume: {
|
|
6278
|
+
...settledCompletion === void 0 ? {} : { settledCompletion },
|
|
6279
|
+
turn: pending.turn,
|
|
6280
|
+
toolResultMaxBytes: pending.toolResultMaxBytes,
|
|
6281
|
+
turnId: pending.turnId,
|
|
6282
|
+
calls: pending.calls,
|
|
6283
|
+
toolParameterRejections: pending.toolParameterRejections,
|
|
6284
|
+
settled: pending.settled,
|
|
6285
|
+
toolExposure: pending.toolExposure ?? Snapshot.make({ exposedToolNames: [...new Set(pending.calls.map((call) => call.name))] }),
|
|
6286
|
+
...resumeLeadingMessages === void 0 ? {} : { leadingMessages: resumeLeadingMessages },
|
|
6287
|
+
...resumeResponseMessages === void 0 ? {} : { responseMessages: resumeResponseMessages }
|
|
6288
|
+
} },
|
|
6289
|
+
...preparedContext === void 0 ? {} : { context: preparedContext },
|
|
6290
|
+
beforeTurn: Effect.fnUntraced(function* () {
|
|
6291
|
+
if (yieldAfter !== void 0 && (yield* Clock.currentTimeMillis) >= DateTime.toEpochMillis(yieldAfter)) {
|
|
6292
|
+
yield* Deferred.succeed(yieldSignal, void 0);
|
|
6293
|
+
return yield* Effect.never;
|
|
6294
|
+
}
|
|
6295
|
+
if (submissionScheduling.yieldTo !== void 0 && (yield* Ref.get(turnCounter)) > 0) {
|
|
6296
|
+
const candidate = yield* recordHalt(eligibleThreadHead(submission.threadId, submission.queueSequence));
|
|
6297
|
+
if (Option.isSome(candidate) && (candidate.value.state === "ready" || candidate.value.state === "input-applied")) {
|
|
6298
|
+
const next = yield* recordHalt(ledger.lookup(SubmissionLookupById.make({ submissionId: candidate.value.submissionId })));
|
|
6299
|
+
if (Option.isSome(next) && next.value.agentId === submission.agentId && (next.value.state === "ready" || next.value.state === "input-applied") && (yield* recordHalt(submissionScheduling.yieldTo({
|
|
6300
|
+
active: submission,
|
|
6301
|
+
next: next.value
|
|
6302
|
+
})))) {
|
|
6303
|
+
yield* Deferred.succeed(yieldSignal, next.value.submissionId);
|
|
6304
|
+
return yield* Effect.never;
|
|
6305
|
+
}
|
|
6286
6306
|
}
|
|
6287
6307
|
}
|
|
6288
|
-
}
|
|
6289
|
-
|
|
6290
|
-
|
|
6291
|
-
|
|
6292
|
-
|
|
6293
|
-
|
|
6294
|
-
|
|
6295
|
-
|
|
6296
|
-
|
|
6297
|
-
|
|
6298
|
-
|
|
6299
|
-
|
|
6300
|
-
|
|
6301
|
-
|
|
6302
|
-
|
|
6303
|
-
|
|
6304
|
-
interruptedUsage = true;
|
|
6305
|
-
}
|
|
6306
|
-
const consume = executeWithUsageAccountingUnknown(agent, submission.inputPayload, options).pipe(Effect.provideService(AgentUpdateAcceptance, { accept: (update) => flushDeferredResponse.pipe(Effect.catch((failure) => Ref.set(haltRef, failure).pipe(Effect.andThen(Effect.fail(UpdateError.make({ reason: "storage" }))))), Effect.andThen(() => updateRuntime.emit({
|
|
6307
|
-
updateId: update.updateId,
|
|
6308
|
-
value: update.value,
|
|
6309
|
-
submission,
|
|
6310
|
-
runId,
|
|
6311
|
-
definitions: submission.agentDigests
|
|
6312
|
-
}).pipe(Effect.provideService(CurrentRunWriter, ctx))), Effect.catchTag(["LedgerError", "DurableRuntimeFailpointError"], (failure) => Ref.set(haltRef, failure).pipe(Effect.andThen(Effect.fail(UpdateError.make({ reason: "storage" })))))) }), Effect.provideService(ModelUsageAccounting, { noteIncompleteUsage: (turn) => Effect.sync(() => {
|
|
6313
|
-
stagedUnobservedCalls.set(turn, (stagedUnobservedCalls.get(turn) ?? 0) + 1);
|
|
6314
|
-
}) }), Effect.provide(ThreadHistory.layer), Effect.provideService(SubagentHost.forTool, (source) => source.threadId !== submission.threadId || source.agentId !== submission.agentId || source.runId !== runId ? SubagentHost.unavailable : workerRuntime.facet({
|
|
6315
|
-
source,
|
|
6316
|
-
policy: agent.definition.policy,
|
|
6317
|
-
depth: delegationDepth,
|
|
6318
|
-
...inheritedGrant === void 0 ? {} : { grant: inheritedGrant }
|
|
6319
|
-
}, submission.principal, submission.submissionId)), Effect.provideService(MessagingHost.forTool, (source) => source.threadId !== submission.threadId || source.agentId !== submission.agentId || source.runId !== runId ? MessagingHost.unavailable : messagingRuntime.forTool(source, submission.principal)), Effect.provideService(CurrentToolFailureObserver, toolFailureObserver), Effect.provideService(RunToolVisibility, runToolVisibility), Effect.provideService(RunToolScheduling, runToolScheduling), Effect.provideService(ContextCompactor, compactor), Effect.provideService(RunContextPreparation, runContextPreparation), Effect.andThen(checkpoint), Effect.catchCause((cause) => Ref.get(haltRef).pipe(Effect.flatMap((failure) => failure === void 0 ? Effect.failCause(cause) : Effect.failCause(Cause.map(cause, (error) => error instanceof CoordinatorHalt ? error : new CoordinatorHalt(failure)))))), Effect.tapCause((cause) => Option.isSome(agentApprovalPendingOption(cause)) && cause.reasons.every(Cause.isFailReason) ? Effect.flatMap(DurableApprovalSuspension, (retain) => retain === void 0 ? Effect.void : halt(retain)) : Effect.void), Effect.as({ _tag: "run" }));
|
|
6320
|
-
const abortWatcher = halt(Effect.gen(function* () {
|
|
6321
|
-
while (true) {
|
|
6322
|
-
yield* Effect.sleep(config.abortPollInterval);
|
|
6323
|
-
const intent = yield* ledger.readAbortIntent(AbortIntentRequest.make({ submissionId }));
|
|
6324
|
-
if (intent === void 0) continue;
|
|
6325
|
-
yield* appendAbortRecord(ctx, intent);
|
|
6326
|
-
return { _tag: "aborted" };
|
|
6327
|
-
}
|
|
6328
|
-
}));
|
|
6329
|
-
const execution = Effect.raceFirst(consume, abortWatcher);
|
|
6330
|
-
const result = yield* (yieldAfter === void 0 && submissionScheduling.yieldTo === void 0 ? execution : Effect.raceFirst(execution, Deferred.await(yieldSignal).pipe(Effect.map((nextSubmissionId) => ({
|
|
6331
|
-
_tag: "yielded",
|
|
6332
|
-
...nextSubmissionId === void 0 ? {} : { nextSubmissionId }
|
|
6333
|
-
}))))).pipe(Effect.provideService(IdGenerator$1, idGenerator)).pipe(Effect.catchCauseFilter(Cause.findError, (error, cause) => {
|
|
6334
|
-
if (isCoordinatorHaltCause(cause)) return Effect.failCause(Cause.map(cause, (halt) => halt.failure));
|
|
6335
|
-
if (cause.reasons.some((reason) => reason._tag === "Fail" && reason.error instanceof AgentInputDecodeError)) return Effect.failCause(Cause.map(cause, () => BindingUnavailable.make({
|
|
6336
|
-
agentId: agent.definition.id,
|
|
6337
|
-
message: "The current Binding cannot decode accepted input"
|
|
6338
|
-
})));
|
|
6339
|
-
const approvalPending = agentApprovalPendingOption(cause);
|
|
6340
|
-
if (Option.isSome(approvalPending)) {
|
|
6341
|
-
const residual = Cause.fromReasons(cause.reasons.filter((reason) => reason._tag !== "Fail"));
|
|
6342
|
-
if (residual.reasons.length > 0) return Effect.failCause(residual);
|
|
6343
|
-
return decodeToolCallIdUnknown(approvalPending.value.toolCallId).pipe(Effect.orDie, Effect.map((toolCallId) => ({
|
|
6344
|
-
_tag: "suspendedRun",
|
|
6345
|
-
toolCallId
|
|
6346
|
-
})));
|
|
6308
|
+
}),
|
|
6309
|
+
...runContextPreparation.transientContext === void 0 ? {} : { transientContext: runContextPreparation.transientContext },
|
|
6310
|
+
...config.estimateCostMicrousd === void 0 ? {} : { estimateCostMicrousd: config.estimateCostMicrousd },
|
|
6311
|
+
resumeUsage: {
|
|
6312
|
+
...journal.usage,
|
|
6313
|
+
...journal.policyUsage,
|
|
6314
|
+
...journal.usage.modelCalls === 0 && (journal.usage.unobservedModelCalls ?? 0) === 0 && !records.some(({ record }) => record.payload._tag === "ModelResponseInterrupted" && record.payload.runId === runId) ? emptyRunTotals() : runTotalsFromSummary(yield* currentUsageSummary()),
|
|
6315
|
+
children: childUsageReportsOf(subagentState)
|
|
6316
|
+
},
|
|
6317
|
+
...journal.contextWindowId === void 0 ? {} : { initialContextWindowId: journal.contextWindowId },
|
|
6318
|
+
...journal.protectedContext === void 0 ? {} : { protectedContext: journal.protectedContext },
|
|
6319
|
+
...pendingContextToolCallId === void 0 ? {} : { pendingContextToolCallId }
|
|
6320
|
+
};
|
|
6321
|
+
if (pending === void 0 && lineage.inputWasRecorded) {
|
|
6322
|
+
yield* appendInterruptedAudit(ctx, runId, knownIds);
|
|
6323
|
+
interruptedUsage = true;
|
|
6347
6324
|
}
|
|
6348
|
-
const
|
|
6349
|
-
|
|
6350
|
-
|
|
6351
|
-
|
|
6352
|
-
|
|
6353
|
-
|
|
6354
|
-
|
|
6355
|
-
|
|
6356
|
-
|
|
6357
|
-
|
|
6325
|
+
const consume = executeWithUsageAccountingUnknown(agent, submission.inputPayload, options).pipe(Effect.provideService(AgentUpdateAcceptance, { accept: (update) => flushDeferredResponse.pipe(Effect.catch((failure) => Ref.set(haltRef, failure).pipe(Effect.andThen(Effect.fail(UpdateError.make({ reason: "storage" }))))), Effect.andThen(() => updateRuntime.emit({
|
|
6326
|
+
updateId: update.updateId,
|
|
6327
|
+
value: update.value,
|
|
6328
|
+
submission,
|
|
6329
|
+
runId,
|
|
6330
|
+
definitions: submission.agentDigests
|
|
6331
|
+
}).pipe(Effect.provideService(CurrentRunWriter, ctx))), Effect.catchTag(["LedgerError", "DurableRuntimeFailpointError"], (failure) => Ref.set(haltRef, failure).pipe(Effect.andThen(Effect.fail(UpdateError.make({ reason: "storage" })))))) }), Effect.provideService(ModelUsageAccounting, { noteIncompleteUsage: (turn) => Effect.sync(() => {
|
|
6332
|
+
stagedUnobservedCalls.set(turn, (stagedUnobservedCalls.get(turn) ?? 0) + 1);
|
|
6333
|
+
}) }), (body) => body.pipe(Effect.provideServiceEffect(ThreadHistory, ThreadHistory.makeFromStore), Effect.provideServiceEffect(Store, makeMemoryStore), Effect.scoped), Effect.provideContext(runServices.pipe(Context.add(SubagentHost.forTool, (source) => source.threadId !== submission.threadId || source.agentId !== submission.agentId || source.runId !== runId ? SubagentHost.unavailable : workerRuntime.facet({
|
|
6334
|
+
source,
|
|
6335
|
+
policy: agent.definition.policy,
|
|
6336
|
+
depth: delegationDepth,
|
|
6337
|
+
...inheritedGrant === void 0 ? {} : { grant: inheritedGrant }
|
|
6338
|
+
}, submission.principal, submission.submissionId)), Context.add(MessagingHost.forTool, (source) => source.threadId !== submission.threadId || source.agentId !== submission.agentId || source.runId !== runId ? MessagingHost.unavailable : messagingRuntime.forTool(source, submission.principal)))), Effect.andThen(checkpoint), Effect.catchCause((cause) => Ref.get(haltRef).pipe(Effect.flatMap((failure) => failure === void 0 ? Effect.failCause(cause) : Effect.failCause(Cause.map(cause, (error) => error instanceof CoordinatorHalt ? error : new CoordinatorHalt(failure)))))), Effect.tapCause((cause) => Option.isSome(agentApprovalPendingOption(cause)) && cause.reasons.every(Cause.isFailReason) ? Effect.flatMap(DurableApprovalSuspension, (retain) => retain === void 0 ? Effect.void : halt(retain)) : Effect.void), Effect.as({ _tag: "run" }));
|
|
6339
|
+
const abortWatcher = halt(Effect.gen(function* () {
|
|
6340
|
+
while (true) {
|
|
6341
|
+
yield* Effect.sleep(config.abortPollInterval);
|
|
6358
6342
|
const intent = yield* ledger.readAbortIntent(AbortIntentRequest.make({ submissionId }));
|
|
6359
|
-
if (intent
|
|
6360
|
-
|
|
6361
|
-
|
|
6362
|
-
}
|
|
6343
|
+
if (intent === void 0) continue;
|
|
6344
|
+
yield* appendAbortRecord(ctx, intent);
|
|
6345
|
+
return { _tag: "aborted" };
|
|
6363
6346
|
}
|
|
6364
|
-
|
|
6347
|
+
}));
|
|
6348
|
+
const result = yield* Effect.raceAllFirst([
|
|
6349
|
+
consume,
|
|
6350
|
+
abortWatcher,
|
|
6351
|
+
...yieldAfter === void 0 && submissionScheduling.yieldTo === void 0 ? [] : [Deferred.await(yieldSignal).pipe(Effect.map((nextSubmissionId) => ({
|
|
6352
|
+
_tag: "yielded",
|
|
6353
|
+
...nextSubmissionId === void 0 ? {} : { nextSubmissionId }
|
|
6354
|
+
})))]
|
|
6355
|
+
]).pipe(Effect.provideService(IdGenerator$1, idGenerator)).pipe(Effect.catchCauseFilter(Cause.findError, (error, cause) => {
|
|
6356
|
+
if (isCoordinatorHaltCause(cause)) return Effect.failCause(Cause.map(cause, (halt) => halt.failure));
|
|
6357
|
+
if (cause.reasons.some((reason) => reason._tag === "Fail" && reason.error instanceof AgentInputDecodeError)) return Effect.failCause(Cause.map(cause, () => BindingUnavailable.make({
|
|
6365
6358
|
agentId: agent.definition.id,
|
|
6366
|
-
|
|
6367
|
-
|
|
6368
|
-
|
|
6369
|
-
|
|
6370
|
-
|
|
6371
|
-
|
|
6372
|
-
|
|
6373
|
-
|
|
6359
|
+
message: "The current Binding cannot decode accepted input"
|
|
6360
|
+
})));
|
|
6361
|
+
const approvalPending = agentApprovalPendingOption(cause);
|
|
6362
|
+
if (Option.isSome(approvalPending)) {
|
|
6363
|
+
const residual = Cause.fromReasons(cause.reasons.filter((reason) => reason._tag !== "Fail"));
|
|
6364
|
+
if (residual.reasons.length > 0) return Effect.failCause(residual);
|
|
6365
|
+
return decodeToolCallIdUnknown(approvalPending.value.toolCallId).pipe(Effect.orDie, Effect.map((toolCallId) => ({
|
|
6366
|
+
_tag: "suspendedRun",
|
|
6367
|
+
toolCallId
|
|
6368
|
+
})));
|
|
6369
|
+
}
|
|
6370
|
+
const childPending = agentChildPendingOption(error);
|
|
6371
|
+
if (Option.isSome(childPending)) return Effect.succeed({
|
|
6372
|
+
_tag: "suspendedChildRun",
|
|
6373
|
+
children: childPending.value.children
|
|
6374
|
+
});
|
|
6375
|
+
return Effect.gen(function* () {
|
|
6376
|
+
const halted = yield* Ref.get(haltRef);
|
|
6377
|
+
if (halted !== void 0) return yield* halted;
|
|
6378
|
+
yield* flushDeferredResponse;
|
|
6379
|
+
if (error instanceof AgentToolAuthorizationDenied) {
|
|
6380
|
+
const intent = yield* ledger.readAbortIntent(AbortIntentRequest.make({ submissionId }));
|
|
6381
|
+
if (intent !== void 0) {
|
|
6382
|
+
yield* appendAbortRecord(ctx, intent);
|
|
6383
|
+
return { _tag: "aborted" };
|
|
6384
|
+
}
|
|
6385
|
+
}
|
|
6386
|
+
if (cause.reasons.some((reason) => reason._tag === "Die" || reason._tag === "Fail" && !(reason.error instanceof AgentApprovalDenied) && !(reason.error instanceof AgentToolAuthorizationDenied))) yield* Effect.logError("Agent run failed", cause).pipe(Effect.annotateLogs({
|
|
6374
6387
|
agentId: agent.definition.id,
|
|
6375
6388
|
runId,
|
|
6376
6389
|
threadId: ctx.threadId,
|
|
6377
6390
|
submissionId,
|
|
6378
6391
|
attemptId: lineage.attemptId
|
|
6379
|
-
})
|
|
6392
|
+
}));
|
|
6393
|
+
return {
|
|
6394
|
+
_tag: "failedRun",
|
|
6395
|
+
outcome: yield* failureOutcome(error, cause, {
|
|
6396
|
+
agentId: agent.definition.id,
|
|
6397
|
+
runId,
|
|
6398
|
+
threadId: ctx.threadId,
|
|
6399
|
+
submissionId,
|
|
6400
|
+
attemptId: lineage.attemptId
|
|
6401
|
+
})
|
|
6402
|
+
};
|
|
6403
|
+
});
|
|
6404
|
+
}));
|
|
6405
|
+
if (result._tag === "yielded") return result;
|
|
6406
|
+
if (result._tag === "suspendedRun") return approvalSuspension(result.toolCallId);
|
|
6407
|
+
if (result._tag === "suspendedChildRun") return childSuspension(result.children);
|
|
6408
|
+
if (result._tag === "aborted") {
|
|
6409
|
+
yield* flushDeferredResponse;
|
|
6410
|
+
return {
|
|
6411
|
+
...abortedRunPhase(yield* currentUsageSummary()),
|
|
6412
|
+
uncommittedModelUsage: uncommittedModelUsage()
|
|
6380
6413
|
};
|
|
6414
|
+
}
|
|
6415
|
+
if (result._tag === "failedRun") return {
|
|
6416
|
+
...result.outcome,
|
|
6417
|
+
usageSummary: yield* currentUsageSummary(),
|
|
6418
|
+
uncommittedModelUsage: uncommittedModelUsage()
|
|
6419
|
+
};
|
|
6420
|
+
const committedCompletion = completionState.committed;
|
|
6421
|
+
if (committedCompletion === void 0) return yield* LedgerError.make({
|
|
6422
|
+
operation: "runModel",
|
|
6423
|
+
message: "Agent Run ended without a committed completion"
|
|
6381
6424
|
});
|
|
6382
|
-
}));
|
|
6383
|
-
if (result._tag === "yielded") return result;
|
|
6384
|
-
if (result._tag === "suspendedRun") return approvalSuspension(result.toolCallId);
|
|
6385
|
-
if (result._tag === "suspendedChildRun") return childSuspension(result.children);
|
|
6386
|
-
if (result._tag === "aborted") {
|
|
6387
|
-
yield* flushDeferredResponse;
|
|
6388
6425
|
return {
|
|
6389
|
-
|
|
6426
|
+
_tag: "completed",
|
|
6427
|
+
result: committedCompletion.output,
|
|
6428
|
+
...committedCompletion.runDisposition === void 0 ? {} : { runDisposition: committedCompletion.runDisposition },
|
|
6429
|
+
...committedCompletion.finishReason === void 0 ? {} : { finishReason: committedCompletion.finishReason },
|
|
6430
|
+
...committedCompletion.exhausted === void 0 ? {} : { exhausted: committedCompletion.exhausted },
|
|
6431
|
+
usageSummary: yield* currentUsageSummary(),
|
|
6390
6432
|
uncommittedModelUsage: uncommittedModelUsage()
|
|
6391
6433
|
};
|
|
6392
6434
|
}
|
|
6393
|
-
|
|
6394
|
-
...result.outcome,
|
|
6395
|
-
usageSummary: yield* currentUsageSummary(),
|
|
6396
|
-
uncommittedModelUsage: uncommittedModelUsage()
|
|
6397
|
-
};
|
|
6398
|
-
const committedCompletion = completionState.committed;
|
|
6399
|
-
if (committedCompletion === void 0) return yield* LedgerError.make({
|
|
6400
|
-
operation: "runModel",
|
|
6401
|
-
message: "Agent Run ended without a committed completion"
|
|
6402
|
-
});
|
|
6403
|
-
return {
|
|
6404
|
-
_tag: "completed",
|
|
6405
|
-
result: committedCompletion.output,
|
|
6406
|
-
...committedCompletion.runDisposition === void 0 ? {} : { runDisposition: committedCompletion.runDisposition },
|
|
6407
|
-
...committedCompletion.finishReason === void 0 ? {} : { finishReason: committedCompletion.finishReason },
|
|
6408
|
-
...committedCompletion.exhausted === void 0 ? {} : { exhausted: committedCompletion.exhausted },
|
|
6409
|
-
usageSummary: yield* currentUsageSummary(),
|
|
6410
|
-
uncommittedModelUsage: uncommittedModelUsage()
|
|
6411
|
-
};
|
|
6412
|
-
});
|
|
6435
|
+
);
|
|
6413
6436
|
/**
|
|
6414
6437
|
* One ownership period over the claimed lane head. The step order mirrors the pure recovery
|
|
6415
6438
|
* classifier's decision table, so a fresh Attempt and a recovering Attempt take the same path
|
|
@@ -6417,16 +6440,16 @@ const make = Effect.fnUntraced(function* (bindings) {
|
|
|
6417
6440
|
* (Unknown Outcomes, or a durable approval suspension) — no settlement occurs and the
|
|
6418
6441
|
* obligation stays owed.
|
|
6419
6442
|
*/
|
|
6420
|
-
const runAttempt = (registeredAgent, session, resumeAfterRetention, onHandoff, yieldAfter
|
|
6443
|
+
const runAttempt = Effect.fnUntraced(function* (registeredAgent, session, resumeAfterRetention, onHandoff, yieldAfter, freshlyAdmitted = false) {
|
|
6421
6444
|
yield* session.checkActive;
|
|
6422
|
-
const checkpointPrompt = yield* promptHistory.take({ threadId: session.threadId }).pipe(Effect.provideService(ThreadStore, store), Effect.
|
|
6445
|
+
const checkpointPrompt = yield* promptHistory.take({ threadId: session.threadId }).pipe(Effect.provideService(ThreadStore, store), Effect.provideContext(journalServices));
|
|
6423
6446
|
let committedPromptSuffix;
|
|
6424
6447
|
const storageSession = session;
|
|
6425
6448
|
yield* Effect.addFinalizer(() => Effect.sync(() => {
|
|
6426
6449
|
committedPromptSuffix?.discard();
|
|
6427
6450
|
committedPromptSuffix = void 0;
|
|
6428
6451
|
}));
|
|
6429
|
-
|
|
6452
|
+
const promptSession = {
|
|
6430
6453
|
...storageSession,
|
|
6431
6454
|
append: (batch, executions) => {
|
|
6432
6455
|
const suffix = committedPromptSuffix;
|
|
@@ -6445,12 +6468,45 @@ const make = Effect.fnUntraced(function* (bindings) {
|
|
|
6445
6468
|
replayed: result.replayed
|
|
6446
6469
|
}))), Effect.tapCause(() => Effect.sync(() => suffix.discard())));
|
|
6447
6470
|
}
|
|
6448
|
-
}
|
|
6471
|
+
};
|
|
6472
|
+
session = yield* withProgressSession(promptSession);
|
|
6449
6473
|
const { claim, threadId } = session;
|
|
6450
6474
|
const submissionId = claim.submissionId;
|
|
6451
|
-
|
|
6475
|
+
let prepared = freshlyAdmitted && session.withInitialization !== void 0 ? yield* session.withInitialization(Effect.gen(function* () {
|
|
6476
|
+
const snapshot = yield* ledger.loadRecoverySnapshot(RecoverySnapshotRequest.make({ submissionId }));
|
|
6477
|
+
const submission = snapshot.submission;
|
|
6478
|
+
if (submission.state !== "ready" || submission.workerAdmission !== void 0 || submission.messageAdmission !== void 0 || submission.parentLinkage !== void 0 || snapshot.inputApplied !== void 0 || snapshot.abortIntent !== void 0 || snapshot.approvalDecisions.length !== 0) return void 0;
|
|
6479
|
+
yield* ensureThreadCreated$1(threadId, submission.agentId, submission.agentDigests);
|
|
6480
|
+
yield* session.refresh;
|
|
6481
|
+
const before = (yield* session.tail).sequence;
|
|
6482
|
+
const view = yield* recoveryView(threadId, before, [submissionId], runIdForSubmission(submissionId));
|
|
6483
|
+
if (view.progress !== void 0 || view.context !== void 0 || view.operational.length !== 0 || view.records.some(({ record }) => record.payload._tag !== "ThreadCreated")) return void 0;
|
|
6484
|
+
const progress = progressWriters.get(session);
|
|
6485
|
+
const applyInput = applyCanonicalInput(session, submission, session, view.records, void 0);
|
|
6486
|
+
yield* progress === void 0 ? applyInput : progress.withVerifiedEmptyRun(runIdForSubmission(submissionId), before, applyInput).pipe(Effect.provideService(CurrentRunWriter, promptSession));
|
|
6487
|
+
const through = (yield* session.tail).sequence;
|
|
6488
|
+
const added = yield* selectedRange(threadId, [submissionId], through, before);
|
|
6489
|
+
const records = [...view.records, ...added];
|
|
6490
|
+
const accepted = progressWriters.get(session)?.acceptedCheckpoint(runIdForSubmission(submissionId));
|
|
6491
|
+
if (accepted === void 0 || accepted.throughSequence !== through || accepted.progress.runId !== runIdForSubmission(submissionId) || accepted.progress.submissionId !== submissionId) return void 0;
|
|
6492
|
+
const start = yield* makeRunStart(submission, Duration.toMillis(registeredAgent.definition.policy.maxDuration), records, view.operational).pipe(Effect.provideService(CurrentRunWriter, session));
|
|
6493
|
+
return {
|
|
6494
|
+
snapshot,
|
|
6495
|
+
through,
|
|
6496
|
+
view: {
|
|
6497
|
+
...view,
|
|
6498
|
+
records,
|
|
6499
|
+
progress: accepted.progress,
|
|
6500
|
+
progressThrough: accepted.throughSequence,
|
|
6501
|
+
operational: accepted.operational
|
|
6502
|
+
},
|
|
6503
|
+
start
|
|
6504
|
+
};
|
|
6505
|
+
})) : void 0;
|
|
6506
|
+
const preparedInput = prepared !== void 0;
|
|
6507
|
+
const snapshot = prepared?.snapshot ?? (yield* ledger.loadRecoverySnapshot(RecoverySnapshotRequest.make({ submissionId })));
|
|
6452
6508
|
const submission = snapshot.submission;
|
|
6453
|
-
yield* ensureThreadCreated$1(threadId, submission.agentId, submission.agentDigests);
|
|
6509
|
+
if (prepared === void 0) yield* ensureThreadCreated$1(threadId, submission.agentId, submission.agentDigests);
|
|
6454
6510
|
if (submission.workerAdmission?.origin.reporting?.mode === "standard") yield* updateRuntime.repairRun(threadId, submissionId);
|
|
6455
6511
|
if (submission.workerAdmission !== void 0) yield* workerRuntime.ensureOrigin(submission.workerAdmission.origin).pipe(Effect.mapError((cause) => LedgerError.make({
|
|
6456
6512
|
operation: "worker-origin",
|
|
@@ -6458,10 +6514,11 @@ const make = Effect.fnUntraced(function* (bindings) {
|
|
|
6458
6514
|
cause
|
|
6459
6515
|
})));
|
|
6460
6516
|
if (submission.state === "admitted") yield* ledger.markReady(MarkReadyRequest.make({ submissionId }));
|
|
6461
|
-
yield* session.refresh;
|
|
6517
|
+
if (prepared === void 0) yield* session.refresh;
|
|
6462
6518
|
const ctx = session;
|
|
6463
|
-
let controlThrough = (yield* session.tail).sequence;
|
|
6464
|
-
const
|
|
6519
|
+
let controlThrough = prepared?.through ?? (yield* session.tail).sequence;
|
|
6520
|
+
const initialThrough = controlThrough;
|
|
6521
|
+
const initialView = prepared?.view ?? (yield* recoveryView(threadId, initialThrough, [submissionId], runIdForSubmission(submissionId)));
|
|
6465
6522
|
let journalMetadata;
|
|
6466
6523
|
const retainControl = controlRecords([submissionId]);
|
|
6467
6524
|
const collectControl = (record) => {
|
|
@@ -6473,7 +6530,7 @@ const make = Effect.fnUntraced(function* (bindings) {
|
|
|
6473
6530
|
journalMetadata = void 0;
|
|
6474
6531
|
return metadata;
|
|
6475
6532
|
};
|
|
6476
|
-
let records =
|
|
6533
|
+
let records = initialView.records.filter(collectControl);
|
|
6477
6534
|
const refreshControl = Effect.fnUntraced(function* (throughSequence) {
|
|
6478
6535
|
const through = throughSequence ?? (yield* store.inspectTail(ThreadTailRequest.make({ threadId }))).tailSequence;
|
|
6479
6536
|
if (through > controlThrough) {
|
|
@@ -6512,8 +6569,8 @@ const make = Effect.fnUntraced(function* (bindings) {
|
|
|
6512
6569
|
}
|
|
6513
6570
|
return Option.some(yield* settleAborted(ctx, submission, session.publishSettlement, snapshot.abortIntent, evidence, knownIds));
|
|
6514
6571
|
}
|
|
6515
|
-
yield* applyCanonicalInput(ctx, submission, session, records, snapshot.inputApplied);
|
|
6516
|
-
const start = yield* makeRunStart(submission, Duration.toMillis(agent.definition.policy.maxDuration), yield* refreshControl()).pipe(Effect.provideService(CurrentRunWriter, ctx));
|
|
6572
|
+
if (prepared === void 0) yield* applyCanonicalInput(ctx, submission, session, records, snapshot.inputApplied);
|
|
6573
|
+
const start = prepared?.start ?? (yield* makeRunStart(submission, Duration.toMillis(agent.definition.policy.maxDuration), yield* refreshControl(), initialView.operational).pipe(Effect.provideService(CurrentRunWriter, ctx)));
|
|
6517
6574
|
const savedRunTiming = start.timing;
|
|
6518
6575
|
const commitStart = Effect.flatMap(CurrentRunStart, (publication) => publication.commit()).pipe(Effect.provideService(CurrentRunStart, start.publication));
|
|
6519
6576
|
const runTiming = workerOrigin === void 0 ? savedRunTiming : {
|
|
@@ -6521,13 +6578,17 @@ const make = Effect.fnUntraced(function* (bindings) {
|
|
|
6521
6578
|
deadline: DateTime.makeUnsafe(Math.min(DateTime.toEpochMillis(savedRunTiming.deadline), workerOrigin.expiresAtMillis))
|
|
6522
6579
|
};
|
|
6523
6580
|
let expiredChildObligation = false;
|
|
6581
|
+
let preparedControl = prepared !== void 0;
|
|
6524
6582
|
if ((yield* Clock.currentTimeMillis) >= DateTime.toEpochMillis(runTiming.deadline)) {
|
|
6583
|
+
prepared = void 0;
|
|
6584
|
+
preparedControl = false;
|
|
6525
6585
|
yield* commitStart;
|
|
6526
6586
|
yield* reconcileRetainedChildren(ctx, submission, session);
|
|
6527
6587
|
expiredChildObligation = yield* completeJoinedReleases(submission);
|
|
6528
6588
|
}
|
|
6529
6589
|
const ordinaryCallsResolved = Effect.gen(function* () {
|
|
6530
|
-
const reconciliationRecords = yield* refreshControl();
|
|
6590
|
+
const reconciliationRecords = preparedControl ? records : yield* refreshControl();
|
|
6591
|
+
preparedControl = false;
|
|
6531
6592
|
const reconciliationEvidence = yield* evidenceFor(reconciliationRecords, submissionId, true, snapshot.hostSubmissionId);
|
|
6532
6593
|
if (reconciliationEvidence.openToolCalls.length === 0) return true;
|
|
6533
6594
|
const reconciliationSnapshot = yield* ledger.loadRecoverySnapshot(RecoverySnapshotRequest.make({ submissionId }));
|
|
@@ -6544,7 +6605,7 @@ const make = Effect.fnUntraced(function* (bindings) {
|
|
|
6544
6605
|
return true;
|
|
6545
6606
|
});
|
|
6546
6607
|
if (!expiredChildObligation && !(yield* ordinaryCallsResolved)) return Option.none();
|
|
6547
|
-
const continuationRecords = yield* refreshControl();
|
|
6608
|
+
const continuationRecords = prepared === void 0 ? yield* refreshControl() : records;
|
|
6548
6609
|
const continuation = yield* pendingToolBatchFor(continuationRecords, runIdForSubmission(submissionId));
|
|
6549
6610
|
if (continuation !== void 0) {
|
|
6550
6611
|
const current = {
|
|
@@ -6615,15 +6676,17 @@ const make = Effect.fnUntraced(function* (bindings) {
|
|
|
6615
6676
|
}
|
|
6616
6677
|
const lineage = {
|
|
6617
6678
|
attemptId: claim.attemptId,
|
|
6618
|
-
inputWasRecorded: evidence.inputRecorded
|
|
6679
|
+
inputWasRecorded: !preparedInput && evidence.inputRecorded
|
|
6619
6680
|
};
|
|
6620
6681
|
let approvalDecisionIntents = snapshot.approvalDecisions;
|
|
6621
6682
|
while (true) {
|
|
6622
|
-
|
|
6683
|
+
const initialization = prepared;
|
|
6684
|
+
prepared = void 0;
|
|
6685
|
+
if (initialization === void 0) yield* session.refresh;
|
|
6623
6686
|
const tail = yield* session.tail;
|
|
6624
|
-
const currentRecords = yield* refreshControl(tail.sequence);
|
|
6625
|
-
const view = yield* recoveryView(threadId, tail.sequence, [submissionId], runIdForSubmission(submissionId), currentRecords);
|
|
6626
|
-
let canonical = view.
|
|
6687
|
+
const currentRecords = initialization === void 0 ? yield* refreshControl(tail.sequence) : records;
|
|
6688
|
+
const view = initialization?.view ?? (yield* recoveryView(threadId, tail.sequence, [submissionId], runIdForSubmission(submissionId), currentRecords));
|
|
6689
|
+
let canonical = Stream.fromIterable(view.records);
|
|
6627
6690
|
let initialJournal;
|
|
6628
6691
|
if (view.context === void 0) {
|
|
6629
6692
|
const original = currentRecords.find(({ record }) => record.payload._tag === "UserInputRecorded" && record.payload.kind === "user" && record.payload.submissionId === submissionId);
|
|
@@ -6733,7 +6796,7 @@ const make = Effect.fnUntraced(function* (bindings) {
|
|
|
6733
6796
|
if (outcome._tag === "completed" && initialJournal?.cacheable && initialJournal.history !== void 0) yield* promptHistory.complete({ threadId: session.threadId }, initialJournal.original, initialJournal.history, committedPromptSuffix).pipe(Effect.provideService(CurrentRunWriter, session), Effect.provideService(ThreadStore, store), Effect.provideService(ThreadReader, reader));
|
|
6734
6797
|
return Option.some(settlement);
|
|
6735
6798
|
}
|
|
6736
|
-
}).pipe(Effect.scoped);
|
|
6799
|
+
}, (effect) => effect.pipe(Effect.scoped));
|
|
6737
6800
|
const acquireAdministrativeClaim = (threadId, handoff) => runStorage.claim(ClaimRequest.make({
|
|
6738
6801
|
threadId,
|
|
6739
6802
|
...handoff === void 0 ? {} : { handoff }
|
|
@@ -6751,6 +6814,8 @@ const make = Effect.fnUntraced(function* (bindings) {
|
|
|
6751
6814
|
if (Option.isNone(claimed)) return Option.none();
|
|
6752
6815
|
const session = claimed.value;
|
|
6753
6816
|
const { claim } = session;
|
|
6817
|
+
const freshlyAdmitted = unclaimedAdmissions.get(claim.submissionId) === threadId;
|
|
6818
|
+
unclaimedAdmissions.delete(claim.submissionId);
|
|
6754
6819
|
firstClaimedSubmissionId ??= claim.submissionId;
|
|
6755
6820
|
const attributes = {
|
|
6756
6821
|
threadId,
|
|
@@ -6789,7 +6854,7 @@ const make = Effect.fnUntraced(function* (bindings) {
|
|
|
6789
6854
|
deferredSubmissionIds: [...handoff?.deferredSubmissionIds ?? [], claim.submissionId],
|
|
6790
6855
|
submissionId: nextSubmissionId
|
|
6791
6856
|
});
|
|
6792
|
-
}, options?.yieldAfter), threadId, claim);
|
|
6857
|
+
}, options?.yieldAfter, freshlyAdmitted), threadId, claim);
|
|
6793
6858
|
}));
|
|
6794
6859
|
while (true) {
|
|
6795
6860
|
resumeAfterRetention = false;
|
|
@@ -6819,7 +6884,7 @@ const make = Effect.fnUntraced(function* (bindings) {
|
|
|
6819
6884
|
settlements.push(settlement.value);
|
|
6820
6885
|
}
|
|
6821
6886
|
}).pipe((body) => withProcessing(threadId, body));
|
|
6822
|
-
const processThreadImpl =
|
|
6887
|
+
const processThreadImpl = Effect.fnUntraced(function* (agent, threadId) {
|
|
6823
6888
|
const binding = yield* makeLegacyWorkerBinding(agent);
|
|
6824
6889
|
return yield* drainThread((submission) => submission.agentId === binding.agentId ? Effect.succeed(binding) : Effect.fail(BindingUnavailable.make({
|
|
6825
6890
|
agentId: submission.agentId,
|
|
@@ -7221,8 +7286,7 @@ const make = Effect.fnUntraced(function* (bindings) {
|
|
|
7221
7286
|
const snapshot = yield* ledger.loadRecoverySnapshot(RecoverySnapshotRequest.make({ submissionId: submission.submissionId }));
|
|
7222
7287
|
if (snapshot.hostSubmissionId !== void 0 && !history.submissionIds.includes(snapshot.hostSubmissionId)) {
|
|
7223
7288
|
const hostId = snapshot.hostSubmissionId;
|
|
7224
|
-
const
|
|
7225
|
-
const hostRecords = yield* Stream.runCollect(hostView.canonical.pipe(Stream.filter(controlRecords([hostId]))));
|
|
7289
|
+
const hostRecords = (yield* recoveryView(submission.threadId, history.throughSequence, [hostId])).records.filter(controlRecords([hostId]));
|
|
7226
7290
|
const merged = new Map(history.records.map((entry) => [entry.sequence, entry]));
|
|
7227
7291
|
for (const entry of hostRecords) merged.set(entry.sequence, entry);
|
|
7228
7292
|
history = {
|
|
@@ -7383,7 +7447,7 @@ const make = Effect.fnUntraced(function* (bindings) {
|
|
|
7383
7447
|
cause
|
|
7384
7448
|
})));
|
|
7385
7449
|
});
|
|
7386
|
-
const recoverOwnedWork = Effect.fnUntraced(function* (request, recoveredAdmissions = /* @__PURE__ */ new Map()) {
|
|
7450
|
+
const recoverOwnedWork = Effect.fnUntraced(function* (request, recoveredAdmissions = /* @__PURE__ */ new Map(), deferUnclaimedAdmissions = false) {
|
|
7387
7451
|
const { threadId, work: entry } = yield* Schema.decodeEffect(WorkRecoveryRequest)(request).pipe(Effect.mapError((cause) => ThreadStoreError.make({
|
|
7388
7452
|
operation: "recover work",
|
|
7389
7453
|
message: "Invalid selected work",
|
|
@@ -7410,7 +7474,10 @@ const make = Effect.fnUntraced(function* (bindings) {
|
|
|
7410
7474
|
});
|
|
7411
7475
|
if (owner._tag === "Admission") {
|
|
7412
7476
|
if (entry.id !== workId("admission", owner.submissionId) || entry.stateReference._tag !== "Submission" || entry.stateReference.submissionId !== owner.submissionId) return yield* invalid();
|
|
7413
|
-
|
|
7477
|
+
const original = yield* lookupKnownSubmission("recover work", owner.submissionId);
|
|
7478
|
+
if (original.threadId !== threadId) return yield* invalid();
|
|
7479
|
+
if (deferUnclaimedAdmissions && unclaimedAdmissions.get(owner.submissionId) === threadId && original.state === "ready" && !storageOwner.hasOwner(threadId) && (yield* ledger.readAbortIntent(AbortIntentRequest.make({ submissionId: owner.submissionId }))) === void 0) return report("deferred");
|
|
7480
|
+
unclaimedAdmissions.delete(owner.submissionId);
|
|
7414
7481
|
const submission = yield* recoverAdmission(owner.submissionId);
|
|
7415
7482
|
return report(submission.disposition, submission);
|
|
7416
7483
|
}
|
|
@@ -7616,6 +7683,16 @@ const make = Effect.fnUntraced(function* (bindings) {
|
|
|
7616
7683
|
let complete = false;
|
|
7617
7684
|
let phase = "history";
|
|
7618
7685
|
const outcome = yield* isolateRecovery(Effect.gen(function* () {
|
|
7686
|
+
if (workCursor === void 0 && options?.deferUnclaimedAdmissions === true && workDiscovery.isOnlyFreshAdmission !== void 0 && !storageOwner.hasOwner(threadId)) {
|
|
7687
|
+
const fresh = [...unclaimedAdmissions].find(([, owner]) => owner === threadId);
|
|
7688
|
+
if (fresh !== void 0 && (yield* workDiscovery.isOnlyFreshAdmission({
|
|
7689
|
+
threadId,
|
|
7690
|
+
submissionId: fresh[0]
|
|
7691
|
+
}))) {
|
|
7692
|
+
complete = true;
|
|
7693
|
+
return;
|
|
7694
|
+
}
|
|
7695
|
+
}
|
|
7619
7696
|
for (let pages = 0; pages < 8 && workReports.length < 32; pages++) {
|
|
7620
7697
|
phase = "history";
|
|
7621
7698
|
const workPage = yield* discoverWork({
|
|
@@ -7628,7 +7705,7 @@ const make = Effect.fnUntraced(function* (bindings) {
|
|
|
7628
7705
|
const repaired = yield* recoverOwnedWork({
|
|
7629
7706
|
threadId,
|
|
7630
7707
|
work
|
|
7631
|
-
}, recoveredAdmissions);
|
|
7708
|
+
}, recoveredAdmissions, options?.deferUnclaimedAdmissions === true);
|
|
7632
7709
|
workReports.push(repaired);
|
|
7633
7710
|
if (repaired.submission !== void 0 && !reportedAdmissions.has(repaired.submission.submissionId)) {
|
|
7634
7711
|
reportedAdmissions.add(repaired.submission.submissionId);
|
|
@@ -7735,7 +7812,7 @@ const make = Effect.fnUntraced(function* (bindings) {
|
|
|
7735
7812
|
queueSequence: admitted.queueSequence
|
|
7736
7813
|
});
|
|
7737
7814
|
}
|
|
7738
|
-
const admitted = yield* ledger.admit(request);
|
|
7815
|
+
const admitted = yield* ledger.admit(request, { readyIfInitialized: true });
|
|
7739
7816
|
yield* hit("submit:after-admit");
|
|
7740
7817
|
const receipt = Receipt.make({
|
|
7741
7818
|
receiptId: admitted.receiptId,
|
|
@@ -7744,10 +7821,19 @@ const make = Effect.fnUntraced(function* (bindings) {
|
|
|
7744
7821
|
queueSequence: admitted.queueSequence
|
|
7745
7822
|
});
|
|
7746
7823
|
if (admitted.replayed && admitted.state !== "admitted") return receipt;
|
|
7747
|
-
|
|
7748
|
-
|
|
7749
|
-
|
|
7750
|
-
|
|
7824
|
+
if (admitted.state === "admitted") {
|
|
7825
|
+
yield* materializeThread(options.threadId);
|
|
7826
|
+
yield* ensureThreadCreated$1(options.threadId, agent.definition.id, options.definitions);
|
|
7827
|
+
yield* hit("submit:after-materialize");
|
|
7828
|
+
yield* ledger.markReady(MarkReadyRequest.make({ submissionId: admitted.submissionId }));
|
|
7829
|
+
}
|
|
7830
|
+
if (!admitted.replayed && messageAdmission === void 0 && options.workerAdmission === void 0) {
|
|
7831
|
+
unclaimedAdmissions.set(admitted.submissionId, options.threadId);
|
|
7832
|
+
if (unclaimedAdmissions.size > 128) {
|
|
7833
|
+
const oldest = unclaimedAdmissions.keys().next().value;
|
|
7834
|
+
if (oldest !== void 0) unclaimedAdmissions.delete(oldest);
|
|
7835
|
+
}
|
|
7836
|
+
}
|
|
7751
7837
|
yield* wake.notify(options.threadId);
|
|
7752
7838
|
return receipt;
|
|
7753
7839
|
});
|
|
@@ -7776,10 +7862,6 @@ const make = Effect.fnUntraced(function* (bindings) {
|
|
|
7776
7862
|
submissionId: receipt.submissionId
|
|
7777
7863
|
});
|
|
7778
7864
|
if (snapshot.value.state !== "settled") return Option.none();
|
|
7779
|
-
const settlement = yield* ledger.finalizeSettlement(SettlementFinalization.make({
|
|
7780
|
-
submissionId: receipt.submissionId,
|
|
7781
|
-
settlementId: submissionSettlementId(receipt.submissionId)
|
|
7782
|
-
}));
|
|
7783
7865
|
const canonical = yield* getRecord({
|
|
7784
7866
|
threadId: receipt.threadId,
|
|
7785
7867
|
recordId: submissionSettlementRecordId(receipt.submissionId)
|
|
@@ -7793,6 +7875,23 @@ const make = Effect.fnUntraced(function* (bindings) {
|
|
|
7793
7875
|
message: "Finalized Submission has no canonical Settlement"
|
|
7794
7876
|
});
|
|
7795
7877
|
const record = yield* settlementPayloadFromRecord(canonical.value.record, receipt.submissionId);
|
|
7878
|
+
const finalized = snapshot.value;
|
|
7879
|
+
const retainedFinalization = finalized.settledAt !== void 0 && finalized.settledRecordId !== void 0 && finalized.settledOutcome !== void 0;
|
|
7880
|
+
if (retainedFinalization && (finalized.settledRecordId !== canonical.value.record.recordId || finalized.settledOutcome !== record.outcome || canonical.value.batchId !== submissionSettlementBatchId(receipt.submissionId))) return yield* LedgerError.make({
|
|
7881
|
+
operation: "awaitSettlement",
|
|
7882
|
+
message: "Settled projection disagrees with its canonical Settlement"
|
|
7883
|
+
});
|
|
7884
|
+
const settlement = retainedFinalization ? Settlement.make({
|
|
7885
|
+
submissionId: receipt.submissionId,
|
|
7886
|
+
settlementId: record.settlementId,
|
|
7887
|
+
receiptId: record.receiptId,
|
|
7888
|
+
outcome: record.outcome,
|
|
7889
|
+
...record.outcome === "failed" ? { failure: record.result } : {},
|
|
7890
|
+
settledAt: finalized.settledAt
|
|
7891
|
+
}) : yield* ledger.finalizeSettlement(SettlementFinalization.make({
|
|
7892
|
+
submissionId: receipt.submissionId,
|
|
7893
|
+
settlementId: submissionSettlementId(receipt.submissionId)
|
|
7894
|
+
}));
|
|
7796
7895
|
if (record.receiptId !== receipt.receiptId || record.settlementId !== settlement.settlementId || record.outcome !== settlement.outcome) return yield* LedgerError.make({
|
|
7797
7896
|
operation: "awaitSettlement",
|
|
7798
7897
|
message: "Canonical Settlement disagrees with the receipt or finalized outcome"
|
|
@@ -8348,4 +8447,4 @@ var DurableAgentRuntime = class DurableAgentRuntime extends Context.Service()("@
|
|
|
8348
8447
|
//#endregion
|
|
8349
8448
|
export { DurableApprovalSuspension as a, RecoveryFailure as c, WorkRecoveryReport as d, WorkRecoveryRequest as f, recoveryRepairRecordId as g, recoveryRepairBatchId as h, DurableApprovalResolver as i, RecoveryReport as l, isolateRecovery as m, DurableAgentRuntime as n, DurableRuntimeConfig as o, childReservationIdFor as p, DurableAgentRuntime_exports as r, RecoveryBlocked as s, ApprovalSuspensionError as t, RecoverySweepResult as u };
|
|
8350
8449
|
|
|
8351
|
-
//# sourceMappingURL=DurableAgentRuntime-
|
|
8450
|
+
//# sourceMappingURL=DurableAgentRuntime-CPlw5_7e.mjs.map
|