@yielded/agent 0.1.0-beta.174 → 0.1.0-beta.176
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-BHmp2V9p.d.mts → Admin-DTDihBra.d.mts} +50 -13
- package/dist/{AgentRuntime-BD3ZHAMq.d.mts → AgentRuntime-CHDyRbSf.d.mts} +3 -3
- package/dist/{AgentRuntime-B6qZlD3f.mjs → AgentRuntime-DaDKMasp.mjs} +123 -114
- package/dist/AgentRuntime-DaDKMasp.mjs.map +1 -0
- package/dist/{Digest-EpeqWEdv.mjs → Digest-C3EODOee.mjs} +2 -2
- package/dist/{Digest-EpeqWEdv.mjs.map → Digest-C3EODOee.mjs.map} +1 -1
- package/dist/{DurableAgentRuntime-CBBjRNJN.mjs → DurableAgentRuntime-BJbuIqQq.mjs} +237 -114
- package/dist/DurableAgentRuntime-BJbuIqQq.mjs.map +1 -0
- package/dist/{EventSource-C9aaJaXT.d.mts → EventSource-Cc58uEso.d.mts} +2 -2
- package/dist/InMemory.d.mts +2 -2
- package/dist/{MessageDelivery-BGDm-c46.d.mts → MessageDelivery-ClHg7c0O.d.mts} +42 -42
- package/dist/{MessagingHost-CRUK4JBi.mjs → MessagingHost-CZCyrnvJ.mjs} +27 -26
- package/dist/MessagingHost-CZCyrnvJ.mjs.map +1 -0
- package/dist/{PreparedInputAdmission-BvDqlgiP.d.mts → PreparedInputAdmission-CjcX1OP0.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-4ZATcVLB.mjs → RunContinuation-CWHuciup.mjs} +74 -40
- package/dist/RunContinuation-CWHuciup.mjs.map +1 -0
- package/dist/{RunContinuation-CTJ1jGrO.d.mts → RunContinuation-DSnUTSSb.d.mts} +11 -5
- package/dist/{RunJournal-CNZqA3Ge.mjs → RunJournal-DGblbFas.mjs} +86 -81
- package/dist/RunJournal-DGblbFas.mjs.map +1 -0
- package/dist/{RunStorage-BHjuuERI.mjs → RunStorage-BF2YgWkg.mjs} +44 -33
- package/dist/RunStorage-BF2YgWkg.mjs.map +1 -0
- package/dist/{Scheduling-NG8slKdI.mjs → Scheduling-07_dsGED.mjs} +3 -3
- package/dist/{Scheduling-NG8slKdI.mjs.map → Scheduling-07_dsGED.mjs.map} +1 -1
- package/dist/{Subagent-CTIpnzlB.mjs → Subagent-CexndZSp.mjs} +2 -2
- package/dist/{Subagent-CTIpnzlB.mjs.map → Subagent-CexndZSp.mjs.map} +1 -1
- package/dist/{Subagent-DKhZA72u.d.mts → Subagent-xhN_aD1r.d.mts} +3 -3
- package/dist/{Subscription-BNg9VCRl.d.mts → Subscription-DuC_PcGx.d.mts} +2 -2
- package/dist/{SubscriptionInput-BUoXv-_K.d.mts → SubscriptionInput-B1IeAEDi.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-CMgzttvr.d.mts → ThreadImport-D_Biid6w.d.mts} +42 -42
- package/dist/{ThreadImport-CodYoJoa.mjs → ThreadImport-ZgWxf7bB.mjs} +8 -8
- package/dist/{ThreadImport-CodYoJoa.mjs.map → ThreadImport-ZgWxf7bB.mjs.map} +1 -1
- package/dist/{ThreadStore-59uDGXul.mjs → ThreadStore-BC4V-mY-.mjs} +42 -23
- package/dist/ThreadStore-BC4V-mY-.mjs.map +1 -0
- package/dist/{ThreadTransfer-3jigUl3g.mjs → ThreadTransfer-S7FnTRHt.mjs} +4 -4
- package/dist/{ThreadTransfer-3jigUl3g.mjs.map → ThreadTransfer-S7FnTRHt.mjs.map} +1 -1
- package/dist/{WorkerAdmission-DDYJdOsU.mjs → WorkerAdmission-C47Vy_cK.mjs} +5 -5
- package/dist/{WorkerAdmission-DDYJdOsU.mjs.map → WorkerAdmission-C47Vy_cK.mjs.map} +1 -1
- package/dist/{agent-registration-DRbyhAu-.mjs → agent-registration-a6QYaG3h.mjs} +4 -4
- package/dist/{agent-registration-DRbyhAu-.mjs.map → agent-registration-a6QYaG3h.mjs.map} +1 -1
- package/dist/capabilities/Messaging.mjs +1 -1
- package/dist/capabilities/ModelContext.d.mts +1 -1
- package/dist/capabilities/RunHooks.d.mts +1 -1
- package/dist/capabilities/Subagent.d.mts +1 -1
- package/dist/capabilities/Subagent.mjs +1 -1
- package/dist/core/Thread.d.mts +2 -2
- package/dist/core/Thread.mjs +5 -3
- package/dist/core/Thread.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 +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 +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 +7 -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 +2 -2
- package/dist/durable/SubscriptionStoreConformance.d.mts +1 -1
- package/dist/durable/SubscriptionStoreConformance.mjs +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 +2 -2
- 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 +4 -4
- 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 +68 -68
- package/dist/durable/WorkerAdmission.mjs +1 -1
- package/dist/durable/WorkerHost.d.mts +1 -1
- package/dist/engine/AgentRuntime.d.mts +1 -1
- package/dist/engine/AgentRuntime.mjs +1 -1
- package/dist/engine/MessagingHost.mjs +1 -1
- package/dist/engine/Output.mjs +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 +12 -12
- package/dist/index.mjs +13 -13
- 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-CC7ZD95F.d.mts → run-context-reader-DvTEq2RC.d.mts} +2 -2
- package/package.json +1 -1
- package/src/core/Thread.ts +143 -146
- package/src/durable/DurableAgentRuntime.ts +549 -260
- package/src/durable/RunContinuation.ts +115 -64
- package/src/durable/RunJournal.ts +107 -112
- package/src/durable/RunStorage.ts +90 -61
- package/src/durable/SqlMemoryStore.ts +8 -6
- package/src/durable/SubmissionLedger.ts +15 -0
- package/src/durable/ThreadStore.ts +48 -26
- package/src/durable/ThreadWork.ts +10 -0
- package/src/durable/WakeScheduler.ts +34 -66
- package/src/durable/internal/initial-context.ts +17 -2
- package/src/durable/internal/prompt-history-cache.ts +13 -8
- package/src/durable/internal/usage-totals.ts +28 -31
- package/src/engine/MessagingHost.ts +4 -2
- package/src/engine/ThreadHistory.ts +47 -48
- package/src/engine/internal/agent-runtime.ts +234 -202
- package/src/engine/internal/output-contract.ts +15 -15
- package/src/engine/internal/primitive-delta.ts +2 -3
- package/src/engine/internal/tool-telemetry.ts +3 -5
- package/dist/AgentRuntime-B6qZlD3f.mjs.map +0 -1
- package/dist/DurableAgentRuntime-CBBjRNJN.mjs.map +0 -1
- package/dist/MessagingHost-CRUK4JBi.mjs.map +0 -1
- package/dist/RunContinuation-4ZATcVLB.mjs.map +0 -1
- package/dist/RunJournal-CNZqA3Ge.mjs.map +0 -1
- package/dist/RunStorage-BHjuuERI.mjs.map +0 -1
- package/dist/ThreadStore-59uDGXul.mjs.map +0 -1
|
@@ -63,6 +63,7 @@ import {
|
|
|
63
63
|
getToolExecutionKind,
|
|
64
64
|
SubagentParentLink,
|
|
65
65
|
} from "../core/SubagentContract.ts";
|
|
66
|
+
import { Store as ConversationStore, makeMemoryStore } from "../core/Thread.ts";
|
|
66
67
|
import { Selection, Snapshot } from "../core/ToolExposure.ts";
|
|
67
68
|
import type { ToolParameterRejection } from "../core/ToolResult.ts";
|
|
68
69
|
import {
|
|
@@ -157,7 +158,7 @@ import {
|
|
|
157
158
|
} from "./internal/agent-registration.ts";
|
|
158
159
|
import { makeAgentUpdateRuntime } from "./internal/agent-updates.ts";
|
|
159
160
|
import { inspectForeignDiagnostic, safeUnknownString } from "./internal/foreign-diagnostic.ts";
|
|
160
|
-
import { initialContext } from "./internal/initial-context.ts";
|
|
161
|
+
import { initialContext, type InitialContextInput } from "./internal/initial-context.ts";
|
|
161
162
|
import {
|
|
162
163
|
makeJournalMetadata,
|
|
163
164
|
type JournalMetadata,
|
|
@@ -280,6 +281,7 @@ import {
|
|
|
280
281
|
modelResponseInterruptedRecordId,
|
|
281
282
|
modelResponseRecordId,
|
|
282
283
|
projectRunJournalStream,
|
|
284
|
+
initialRunJournal,
|
|
283
285
|
type JournalBoundary,
|
|
284
286
|
type RunJournalProjection,
|
|
285
287
|
type RunJournalContext,
|
|
@@ -401,6 +403,9 @@ import {
|
|
|
401
403
|
getRunInput,
|
|
402
404
|
ThreadReader,
|
|
403
405
|
MAX_THREAD_EXPORT_PAGE_BYTES,
|
|
406
|
+
PreparedAppend,
|
|
407
|
+
type CommitBatch,
|
|
408
|
+
type ExecutionUpdate,
|
|
404
409
|
} from "./ThreadStore.ts";
|
|
405
410
|
import {
|
|
406
411
|
type WorkIndexRebuildRequest,
|
|
@@ -592,6 +597,11 @@ export { threadCreatedBatchId, threadCreatedRecordId } from "./internal/thread-i
|
|
|
592
597
|
export const recoveryRepairBatchId = (submissionId: SubmissionId, decisionTag: string): BatchId =>
|
|
593
598
|
decodeBatchId(`repair:${submissionId}:${decisionTag}`);
|
|
594
599
|
|
|
600
|
+
const isOriginalInputRecord = (
|
|
601
|
+
record: RecordEnvelope,
|
|
602
|
+
): record is RecordEnvelope & { readonly payload: UserInputRecorded } =>
|
|
603
|
+
record.payload._tag === "UserInputRecorded";
|
|
604
|
+
|
|
595
605
|
/** Deterministic record identity of one executed recovery decision's `RepairAnnotated` record. */
|
|
596
606
|
export const recoveryRepairRecordId = (submissionId: SubmissionId, decisionTag: string): RecordId =>
|
|
597
607
|
decodeRecordId(`repair:${submissionId}:${decisionTag}`);
|
|
@@ -846,6 +856,11 @@ export class RecoverySweepResult extends Schema.Class<RecoverySweepResult>("Reco
|
|
|
846
856
|
/** Recover one bounded page of native work, optionally confined to one Thread. */
|
|
847
857
|
export interface RecoverySweepOptions {
|
|
848
858
|
readonly threadId?: ThreadId;
|
|
859
|
+
/** Leave this incarnation's untouched root admissions to their first actual claim.
|
|
860
|
+
* A verified sole admission needs no recovery inventory; other owners retain bounded
|
|
861
|
+
* discovery and deferred reports. Neither case supplies ownership or a recovery decision:
|
|
862
|
+
* the Attempt still verifies current controls, journal, fencing and historyDigest. */
|
|
863
|
+
readonly deferUnclaimedAdmissions?: boolean;
|
|
849
864
|
/** Continue the previous pass with the same Thread selection until its result has no cursor. */
|
|
850
865
|
readonly cursor?: string;
|
|
851
866
|
}
|
|
@@ -1357,7 +1372,7 @@ interface OpenCallReview {
|
|
|
1357
1372
|
|
|
1358
1373
|
interface InitialJournalSource {
|
|
1359
1374
|
records: ReadonlyArray<JournalRecordEnvelope> | undefined;
|
|
1360
|
-
readonly original:
|
|
1375
|
+
readonly original: InitialContextInput;
|
|
1361
1376
|
readonly suffix: ReadonlyArray<CanonicalRecordEnvelope>;
|
|
1362
1377
|
cacheable: boolean;
|
|
1363
1378
|
readonly prefix?: CachedPromptHistory;
|
|
@@ -1374,6 +1389,11 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
1374
1389
|
const reader = ThreadReader.fromStore(store);
|
|
1375
1390
|
const promptHistory = yield* makePromptHistoryCache();
|
|
1376
1391
|
|
|
1392
|
+
// One incarnation remembers only newly accepted root input, never a recovery decision.
|
|
1393
|
+
// A claim consumes the hint before binding/application code can run. Cold owners,
|
|
1394
|
+
// replays, linked inputs, and any changed ledger state retain the recovery path.
|
|
1395
|
+
const unclaimedAdmissions = new Map<SubmissionId, ThreadId>();
|
|
1396
|
+
|
|
1377
1397
|
const workDiscovery = yield* ThreadWorkDiscovery.pipe(
|
|
1378
1398
|
Effect.provide(ThreadWorkDiscovery.layer),
|
|
1379
1399
|
Effect.provideService(ThreadStore, store),
|
|
@@ -1444,17 +1464,27 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
1444
1464
|
// observer must never replace this host choice on a fresh or replacement Attempt.
|
|
1445
1465
|
const toolFailureObserver = yield* CurrentToolFailureObserver;
|
|
1446
1466
|
|
|
1467
|
+
const runServices = Context.make(CurrentToolFailureObserver, toolFailureObserver).pipe(
|
|
1468
|
+
Context.add(RunToolVisibility, runToolVisibility),
|
|
1469
|
+
Context.add(RunToolScheduling, runToolScheduling),
|
|
1470
|
+
Context.add(ContextCompactor, compactor),
|
|
1471
|
+
Context.add(RunContextPreparation, runContextPreparation),
|
|
1472
|
+
);
|
|
1473
|
+
|
|
1474
|
+
const journalServices = Context.make(ThreadReader, reader).pipe(
|
|
1475
|
+
Context.add(Crypto.Crypto, crypto),
|
|
1476
|
+
);
|
|
1477
|
+
|
|
1447
1478
|
const withCrypto = <A, E>(effect: Effect.Effect<A, E, Crypto.Crypto>): Effect.Effect<A, E> =>
|
|
1448
1479
|
Effect.provideService(effect, Crypto.Crypto, crypto);
|
|
1449
1480
|
|
|
1450
1481
|
// Rebuild the pinned admission and captured suffix using this runtime's host dependencies.
|
|
1451
1482
|
const readInitialJournal = (
|
|
1452
|
-
original:
|
|
1483
|
+
original: InitialContextInput,
|
|
1453
1484
|
suffix: ReadonlyArray<CanonicalRecordEnvelope>,
|
|
1454
1485
|
) =>
|
|
1455
1486
|
initialContext(original).pipe(
|
|
1456
|
-
Effect.
|
|
1457
|
-
Effect.provideService(Crypto.Crypto, crypto),
|
|
1487
|
+
Effect.provideContext(journalServices),
|
|
1458
1488
|
Effect.map((history) => history.concat(suffix)),
|
|
1459
1489
|
);
|
|
1460
1490
|
|
|
@@ -1708,10 +1738,7 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
1708
1738
|
|
|
1709
1739
|
if (found === undefined) {
|
|
1710
1740
|
// An exact lookup distinguishes missing evidence from an incomplete native index.
|
|
1711
|
-
yield* resolveEvidence(threadId, ref).pipe(
|
|
1712
|
-
Effect.provideService(ThreadReader, reader),
|
|
1713
|
-
Effect.provideService(Crypto.Crypto, crypto),
|
|
1714
|
-
);
|
|
1741
|
+
yield* resolveEvidence(threadId, ref).pipe(Effect.provideContext(journalServices));
|
|
1715
1742
|
|
|
1716
1743
|
return yield* invalid(
|
|
1717
1744
|
"Required Run evidence is absent from its locator; rebuild the index explicitly",
|
|
@@ -1778,8 +1805,7 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
1778
1805
|
} else {
|
|
1779
1806
|
saved = yield* readRunContext(initial, input, cursor.savedContext.recordId).pipe(
|
|
1780
1807
|
Effect.provide(RunContextReader.layer(threadId)),
|
|
1781
|
-
Effect.
|
|
1782
|
-
Effect.provideService(Crypto.Crypto, crypto),
|
|
1808
|
+
Effect.provideContext(journalServices),
|
|
1783
1809
|
Effect.mapError(() =>
|
|
1784
1810
|
invalid("Saved original context cannot be resolved from its evidence"),
|
|
1785
1811
|
),
|
|
@@ -2573,8 +2599,7 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
2573
2599
|
const progress =
|
|
2574
2600
|
active?.writer ??
|
|
2575
2601
|
(yield* makeProgressWriter(writer.threadId, config.deploymentId).pipe(
|
|
2576
|
-
Effect.
|
|
2577
|
-
Effect.provideService(Crypto.Crypto, crypto),
|
|
2602
|
+
Effect.provideContext(journalServices),
|
|
2578
2603
|
));
|
|
2579
2604
|
|
|
2580
2605
|
const owned: RunWriter = {
|
|
@@ -2600,7 +2625,10 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
2600
2625
|
Effect.map(({ owned }) => owned),
|
|
2601
2626
|
);
|
|
2602
2627
|
|
|
2603
|
-
const withProgressSession = Effect.fnUntraced(function* (
|
|
2628
|
+
const withProgressSession = Effect.fnUntraced(function* (
|
|
2629
|
+
session: RunStorageSession,
|
|
2630
|
+
originalInput?: () => InitialContextInput | undefined,
|
|
2631
|
+
) {
|
|
2604
2632
|
const { owned, progress } = yield* withProgress(session);
|
|
2605
2633
|
|
|
2606
2634
|
activeProgress.set(session.threadId, { writer: progress });
|
|
@@ -2611,9 +2639,44 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
2611
2639
|
}),
|
|
2612
2640
|
);
|
|
2613
2641
|
|
|
2642
|
+
const inputWriter =
|
|
2643
|
+
session.appendInput === undefined
|
|
2644
|
+
? undefined
|
|
2645
|
+
: {
|
|
2646
|
+
...session,
|
|
2647
|
+
append: session.appendInput,
|
|
2648
|
+
};
|
|
2649
|
+
|
|
2614
2650
|
const wrapped: RunStorageSession = {
|
|
2615
2651
|
...session,
|
|
2616
2652
|
append: owned.append,
|
|
2653
|
+
...(inputWriter === undefined
|
|
2654
|
+
? {}
|
|
2655
|
+
: {
|
|
2656
|
+
appendInput: (batch: CommitBatch) =>
|
|
2657
|
+
storageOwner.withProgress(
|
|
2658
|
+
session.threadId,
|
|
2659
|
+
storageOwner.withMutation(
|
|
2660
|
+
Effect.gen(function* () {
|
|
2661
|
+
yield* session.checkActive;
|
|
2662
|
+
// The captured empty canonical prefix is enforced again by the append tail and
|
|
2663
|
+
// checkpoint revision-zero CAS. It is not a cache entry across preparation IO.
|
|
2664
|
+
const original = originalInput?.();
|
|
2665
|
+
const commit = progress.commit(batch);
|
|
2666
|
+
|
|
2667
|
+
return yield* (
|
|
2668
|
+
original === undefined
|
|
2669
|
+
? commit
|
|
2670
|
+
: progress.withVerifiedEmptyRun(
|
|
2671
|
+
runIdForSubmission(session.claim.submissionId),
|
|
2672
|
+
CanonicalSequence.make(original.sequence - 1),
|
|
2673
|
+
commit,
|
|
2674
|
+
)
|
|
2675
|
+
).pipe(Effect.provideService(CurrentRunWriter, inputWriter));
|
|
2676
|
+
}),
|
|
2677
|
+
),
|
|
2678
|
+
),
|
|
2679
|
+
}),
|
|
2617
2680
|
publishSettlement: (batch) =>
|
|
2618
2681
|
progress.publish(batch).pipe(Effect.provideService(CurrentRunSettlement, session)),
|
|
2619
2682
|
};
|
|
@@ -2633,8 +2696,7 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
2633
2696
|
const progress =
|
|
2634
2697
|
active?.writer ??
|
|
2635
2698
|
(yield* makeProgressWriter(request.threadId, config.deploymentId).pipe(
|
|
2636
|
-
Effect.
|
|
2637
|
-
Effect.provideService(Crypto.Crypto, crypto),
|
|
2699
|
+
Effect.provideContext(journalServices),
|
|
2638
2700
|
));
|
|
2639
2701
|
|
|
2640
2702
|
let tail = {
|
|
@@ -3151,6 +3213,20 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
3151
3213
|
);
|
|
3152
3214
|
});
|
|
3153
3215
|
|
|
3216
|
+
const prepareOriginalInput = (submission: SubmissionSnapshot) =>
|
|
3217
|
+
makeEnvelope(
|
|
3218
|
+
submissionInputRecordId(submission.submissionId),
|
|
3219
|
+
UserInputRecorded.make({
|
|
3220
|
+
submissionId: submission.submissionId,
|
|
3221
|
+
kind: "user",
|
|
3222
|
+
runId: runIdForSubmission(submission.submissionId),
|
|
3223
|
+
input: submission.inputPayload,
|
|
3224
|
+
...(submission.messageAdmission === undefined
|
|
3225
|
+
? {}
|
|
3226
|
+
: { messageAdmission: submission.messageAdmission }),
|
|
3227
|
+
}),
|
|
3228
|
+
);
|
|
3229
|
+
|
|
3154
3230
|
/**
|
|
3155
3231
|
* Plan step 2: append the deterministic `UserInputRecorded` record (batch idempotency makes it
|
|
3156
3232
|
* exactly-once canonical, DUR-007) and mark it applied. When canonical history already carries
|
|
@@ -3176,18 +3252,7 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
3176
3252
|
return;
|
|
3177
3253
|
}
|
|
3178
3254
|
|
|
3179
|
-
const envelope = yield*
|
|
3180
|
-
recordId,
|
|
3181
|
-
UserInputRecorded.make({
|
|
3182
|
-
submissionId,
|
|
3183
|
-
kind: "user",
|
|
3184
|
-
runId: runIdForSubmission(submissionId),
|
|
3185
|
-
input: submission.inputPayload,
|
|
3186
|
-
...(submission.messageAdmission === undefined
|
|
3187
|
-
? {}
|
|
3188
|
-
: { messageAdmission: submission.messageAdmission }),
|
|
3189
|
-
}),
|
|
3190
|
-
);
|
|
3255
|
+
const envelope = yield* prepareOriginalInput(submission);
|
|
3191
3256
|
|
|
3192
3257
|
const result = yield* appendBatch(
|
|
3193
3258
|
ctx,
|
|
@@ -3238,8 +3303,13 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
3238
3303
|
maxDurationMillis: number,
|
|
3239
3304
|
records: ReadonlyArray<CanonicalRecordEnvelope>,
|
|
3240
3305
|
operational: ReadonlyArray<RecordEnvelope>,
|
|
3306
|
+
input?: RecordEnvelope,
|
|
3241
3307
|
) {
|
|
3242
3308
|
const writer = yield* CurrentRunWriter;
|
|
3309
|
+
const append = input === undefined ? writer.append : writer.appendInput;
|
|
3310
|
+
|
|
3311
|
+
if (append === undefined)
|
|
3312
|
+
return yield* RunJournalError.make({ message: "Fresh startup requires an input publisher" });
|
|
3243
3313
|
const runId = runIdForSubmission(submission.submissionId);
|
|
3244
3314
|
const recordId = runStartedRecordId(runId);
|
|
3245
3315
|
const existing = yield* readRunStart(submission.threadId, runId, operational);
|
|
@@ -3288,13 +3358,21 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
3288
3358
|
}
|
|
3289
3359
|
yield* hit("run:before-start-append");
|
|
3290
3360
|
yield* appendBatch(
|
|
3291
|
-
writer,
|
|
3361
|
+
{ threadId: writer.threadId, append },
|
|
3292
3362
|
CanonicalBatch.make({
|
|
3293
|
-
batchId:
|
|
3363
|
+
batchId:
|
|
3364
|
+
input === undefined
|
|
3365
|
+
? runStartedBatchId(runId)
|
|
3366
|
+
: submissionInputBatchId(submission.submissionId),
|
|
3294
3367
|
producerId: config.producerId,
|
|
3295
|
-
records: [
|
|
3368
|
+
records: [
|
|
3369
|
+
input ?? start,
|
|
3370
|
+
...(input === undefined ? [] : [start]),
|
|
3371
|
+
...(context === undefined ? [] : [context]),
|
|
3372
|
+
],
|
|
3296
3373
|
}),
|
|
3297
3374
|
);
|
|
3375
|
+
if (input !== undefined) yield* hit("input:after-canonical-append");
|
|
3298
3376
|
committed = true;
|
|
3299
3377
|
yield* hit("run:after-start-append");
|
|
3300
3378
|
});
|
|
@@ -4840,12 +4918,14 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
4840
4918
|
// Unrelated Thread traffic does not invalidate an already validated owner projection.
|
|
4841
4919
|
const projectionThrough = Math.max(progressThrough ?? 0, records.at(-1)?.sequence ?? 0);
|
|
4842
4920
|
|
|
4843
|
-
const originalInput =
|
|
4844
|
-
|
|
4845
|
-
|
|
4846
|
-
payload
|
|
4847
|
-
|
|
4848
|
-
|
|
4921
|
+
const originalInput =
|
|
4922
|
+
initialJournal?.original ??
|
|
4923
|
+
records.find(
|
|
4924
|
+
({ record: { payload } }) =>
|
|
4925
|
+
payload._tag === "UserInputRecorded" &&
|
|
4926
|
+
payload.kind === "user" &&
|
|
4927
|
+
payload.submissionId === submissionId,
|
|
4928
|
+
);
|
|
4849
4929
|
|
|
4850
4930
|
if (originalInput === undefined)
|
|
4851
4931
|
return yield* RunJournalError.make({ message: "Run has no original context boundary" });
|
|
@@ -4856,23 +4936,35 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
4856
4936
|
historyEvidence.set(entry.record.recordId, entry);
|
|
4857
4937
|
};
|
|
4858
4938
|
|
|
4939
|
+
// An exact cache prefix followed only by this fresh input has no response,
|
|
4940
|
+
// policy reservation or context to replay. Keep recovery on the full projector.
|
|
4941
|
+
const freshPrefix =
|
|
4942
|
+
priorContext === undefined &&
|
|
4943
|
+
initialJournal?.prefix !== undefined &&
|
|
4944
|
+
initialJournal.records?.length === 1 &&
|
|
4945
|
+
initialJournal.records[0] === originalInput
|
|
4946
|
+
? initialJournal.prefix.prompt
|
|
4947
|
+
: undefined;
|
|
4948
|
+
|
|
4859
4949
|
let journal =
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
cached.
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4950
|
+
freshPrefix !== undefined
|
|
4951
|
+
? initialRunJournal(freshPrefix)
|
|
4952
|
+
: cached !== undefined &&
|
|
4953
|
+
cached.threadId === ctx.threadId &&
|
|
4954
|
+
cached.through === projectionThrough &&
|
|
4955
|
+
cached.runId === runId &&
|
|
4956
|
+
cached.contextRecordId === priorContext?.recordId
|
|
4957
|
+
? (boundaries.push(...cached.boundaries),
|
|
4958
|
+
cached.contextEvidence.forEach(retainHistory),
|
|
4959
|
+
cached.journal)
|
|
4960
|
+
: yield* projectRunJournalStream(
|
|
4961
|
+
canonical,
|
|
4962
|
+
runId,
|
|
4963
|
+
(boundary) => boundaries.push(boundary),
|
|
4964
|
+
priorContext,
|
|
4965
|
+
journalMetadata,
|
|
4966
|
+
priorContext === undefined ? retainHistory : undefined,
|
|
4967
|
+
);
|
|
4876
4968
|
|
|
4877
4969
|
if (initialJournal?.prefix !== undefined) {
|
|
4878
4970
|
const prompt = initialJournal.prefix.prompt;
|
|
@@ -5192,9 +5284,6 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
5192
5284
|
),
|
|
5193
5285
|
);
|
|
5194
5286
|
|
|
5195
|
-
const addUsageTotal = (field: string, left: number, right: number) =>
|
|
5196
|
-
checkedUsageTotal(field, left + right);
|
|
5197
|
-
|
|
5198
5287
|
const subtractUsageTotal = (field: string, left: number, right: number) =>
|
|
5199
5288
|
checkedUsageTotal(field, left - right);
|
|
5200
5289
|
|
|
@@ -5204,11 +5293,7 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
5204
5293
|
let unobservedModelCalls = journal.usage.unobservedModelCalls ?? 0;
|
|
5205
5294
|
|
|
5206
5295
|
for (const count of stagedUnobservedCalls.values()) {
|
|
5207
|
-
unobservedModelCalls
|
|
5208
|
-
"unobservedModelCalls",
|
|
5209
|
-
unobservedModelCalls,
|
|
5210
|
-
count,
|
|
5211
|
-
);
|
|
5296
|
+
unobservedModelCalls += count;
|
|
5212
5297
|
}
|
|
5213
5298
|
const detailedCalls = [...journal.usage.modelUsage, ...stagedCalls];
|
|
5214
5299
|
|
|
@@ -5229,17 +5314,15 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
5229
5314
|
let costMicrousd = journal.usage.costMicrousd;
|
|
5230
5315
|
|
|
5231
5316
|
for (const usage of stagedUsage.values()) {
|
|
5232
|
-
inputTokens
|
|
5233
|
-
outputTokens
|
|
5234
|
-
costMicrousd
|
|
5317
|
+
inputTokens += usage.inputTokens;
|
|
5318
|
+
outputTokens += usage.outputTokens;
|
|
5319
|
+
costMicrousd += usage.costMicrousd;
|
|
5235
5320
|
}
|
|
5236
5321
|
|
|
5237
|
-
const modelCalls =
|
|
5238
|
-
"modelCalls",
|
|
5239
|
-
journal.usage.modelCalls,
|
|
5240
|
-
stagedCalls.length,
|
|
5241
|
-
);
|
|
5322
|
+
const modelCalls = journal.usage.modelCalls + stagedCalls.length;
|
|
5242
5323
|
|
|
5324
|
+
// Reconciliation must reject negative legacy deltas independently of
|
|
5325
|
+
// the final summary's complete safe-integer and additive checks.
|
|
5243
5326
|
const legacyCalls = yield* subtractUsageTotal(
|
|
5244
5327
|
"legacy.modelCalls",
|
|
5245
5328
|
modelCalls,
|
|
@@ -5283,81 +5366,52 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
5283
5366
|
|
|
5284
5367
|
const existing = existingIndex < 0 ? undefined : byModel[existingIndex];
|
|
5285
5368
|
|
|
5286
|
-
const legacyGroup = ModelUsageGroup.
|
|
5369
|
+
const legacyGroup = yield* ModelUsageGroup.makeEffect({
|
|
5287
5370
|
provider: "unknown",
|
|
5288
5371
|
model: "legacy-record",
|
|
5289
|
-
modelCalls:
|
|
5290
|
-
|
|
5291
|
-
existing?.
|
|
5292
|
-
|
|
5293
|
-
),
|
|
5294
|
-
inputTokens: InputTokenUsage.make({
|
|
5295
|
-
total: yield* addUsageTotal(
|
|
5296
|
-
"byModel.inputTokens.total",
|
|
5297
|
-
existing?.inputTokens.total ?? 0,
|
|
5298
|
-
legacyInput,
|
|
5299
|
-
),
|
|
5300
|
-
uncached: yield* addUsageTotal(
|
|
5301
|
-
"byModel.inputTokens.uncached",
|
|
5302
|
-
existing?.inputTokens.uncached ?? 0,
|
|
5303
|
-
legacyInput,
|
|
5304
|
-
),
|
|
5372
|
+
modelCalls: (existing?.modelCalls ?? 0) + legacyCalls,
|
|
5373
|
+
inputTokens: {
|
|
5374
|
+
total: (existing?.inputTokens.total ?? 0) + legacyInput,
|
|
5375
|
+
uncached: (existing?.inputTokens.uncached ?? 0) + legacyInput,
|
|
5305
5376
|
cacheRead: existing?.inputTokens.cacheRead ?? 0,
|
|
5306
5377
|
cacheWrite: existing?.inputTokens.cacheWrite ?? 0,
|
|
5307
|
-
}
|
|
5308
|
-
outputTokens:
|
|
5309
|
-
total:
|
|
5310
|
-
|
|
5311
|
-
existing?.outputTokens.total ?? 0,
|
|
5312
|
-
legacyOutput,
|
|
5313
|
-
),
|
|
5314
|
-
text: yield* addUsageTotal(
|
|
5315
|
-
"byModel.outputTokens.text",
|
|
5316
|
-
existing?.outputTokens.text ?? 0,
|
|
5317
|
-
legacyOutput,
|
|
5318
|
-
),
|
|
5378
|
+
},
|
|
5379
|
+
outputTokens: {
|
|
5380
|
+
total: (existing?.outputTokens.total ?? 0) + legacyOutput,
|
|
5381
|
+
text: (existing?.outputTokens.text ?? 0) + legacyOutput,
|
|
5319
5382
|
reasoning: existing?.outputTokens.reasoning ?? 0,
|
|
5320
|
-
}
|
|
5321
|
-
costMicrousd:
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5383
|
+
},
|
|
5384
|
+
costMicrousd: (existing?.costMicrousd ?? 0) + legacyCost,
|
|
5385
|
+
}).pipe(
|
|
5386
|
+
Effect.mapError((cause) =>
|
|
5387
|
+
RunJournalError.make({
|
|
5388
|
+
message: "Run legacy usage exceeds safe-integer accounting bounds",
|
|
5389
|
+
cause,
|
|
5390
|
+
}),
|
|
5325
5391
|
),
|
|
5326
|
-
|
|
5392
|
+
);
|
|
5327
5393
|
|
|
5328
5394
|
if (existingIndex < 0) byModel.push(legacyGroup);
|
|
5329
5395
|
else byModel[existingIndex] = legacyGroup;
|
|
5330
5396
|
}
|
|
5331
5397
|
|
|
5332
|
-
|
|
5333
|
-
"inputTokens.uncached",
|
|
5334
|
-
detailed.inputTokens.uncached,
|
|
5335
|
-
legacyInput,
|
|
5336
|
-
);
|
|
5337
|
-
|
|
5338
|
-
const text = yield* addUsageTotal(
|
|
5339
|
-
"outputTokens.text",
|
|
5340
|
-
detailed.outputTokens.text,
|
|
5341
|
-
legacyOutput,
|
|
5342
|
-
);
|
|
5343
|
-
|
|
5344
|
-
return RunUsageSummary.make({
|
|
5398
|
+
return yield* RunUsageSummary.makeEffect({
|
|
5345
5399
|
...(legacyCalls === 0 && detailed.webSearchCalls !== undefined
|
|
5346
5400
|
? { webSearchCalls: detailed.webSearchCalls }
|
|
5347
5401
|
: {}),
|
|
5348
5402
|
modelCalls,
|
|
5349
|
-
inputTokens:
|
|
5403
|
+
inputTokens: {
|
|
5350
5404
|
total: inputTokens,
|
|
5351
5405
|
// Legacy aggregate inputs are conservatively classified as uncached.
|
|
5352
|
-
uncached,
|
|
5406
|
+
uncached: detailed.inputTokens.uncached + legacyInput,
|
|
5353
5407
|
cacheRead: detailed.inputTokens.cacheRead,
|
|
5354
5408
|
cacheWrite: detailed.inputTokens.cacheWrite,
|
|
5355
|
-
}
|
|
5356
|
-
outputTokens:
|
|
5409
|
+
},
|
|
5410
|
+
outputTokens: {
|
|
5357
5411
|
total: outputTokens,
|
|
5358
|
-
text,
|
|
5412
|
+
text: detailed.outputTokens.text + legacyOutput,
|
|
5359
5413
|
reasoning: detailed.outputTokens.reasoning,
|
|
5360
|
-
}
|
|
5414
|
+
},
|
|
5361
5415
|
costMicrousd,
|
|
5362
5416
|
byModel,
|
|
5363
5417
|
unobservedModelCalls,
|
|
@@ -5373,7 +5427,14 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
5373
5427
|
? "unknown"
|
|
5374
5428
|
: "partial"
|
|
5375
5429
|
: detailed.pricingStatus,
|
|
5376
|
-
})
|
|
5430
|
+
}).pipe(
|
|
5431
|
+
Effect.mapError((cause) =>
|
|
5432
|
+
RunJournalError.make({
|
|
5433
|
+
message: "Run usage summary exceeds safe-integer accounting bounds",
|
|
5434
|
+
cause,
|
|
5435
|
+
}),
|
|
5436
|
+
),
|
|
5437
|
+
);
|
|
5377
5438
|
});
|
|
5378
5439
|
|
|
5379
5440
|
const activeExecution = yield* reader.readExecution({ threadId: ctx.threadId, runId });
|
|
@@ -5450,18 +5511,6 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
5450
5511
|
usageSummary: yield* currentUsageSummary(),
|
|
5451
5512
|
};
|
|
5452
5513
|
}
|
|
5453
|
-
// Summaries cover only prior Runs. Pruning and rollover also map fully settled
|
|
5454
|
-
// current-Run records and preserves the canonical instruction/input block during replay.
|
|
5455
|
-
let ownerFirstSequence: CanonicalSequence | undefined;
|
|
5456
|
-
|
|
5457
|
-
for (const envelope of records) {
|
|
5458
|
-
const payload = envelope.record.payload;
|
|
5459
|
-
|
|
5460
|
-
if ("runId" in payload && payload.runId === runId) {
|
|
5461
|
-
ownerFirstSequence = envelope.sequence;
|
|
5462
|
-
break;
|
|
5463
|
-
}
|
|
5464
|
-
}
|
|
5465
5514
|
|
|
5466
5515
|
/** Only canonical joined inputs can require restoration from an earlier Attempt. */
|
|
5467
5516
|
let joinBacklog: ReadonlyArray<JoinSnapshot> | undefined =
|
|
@@ -5549,37 +5598,38 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
5549
5598
|
const recordHalt = <A, R>(
|
|
5550
5599
|
effect: Effect.Effect<A, DurableWorkerFailure, R>,
|
|
5551
5600
|
): Effect.Effect<A, CoordinatorHalt | AgentPersistenceCapacityError, R> =>
|
|
5552
|
-
|
|
5553
|
-
|
|
5554
|
-
|
|
5555
|
-
|
|
5556
|
-
|
|
5557
|
-
|
|
5558
|
-
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
Cause.map(cause, (failure) =>
|
|
5562
|
-
failure instanceof ThreadStoreError &&
|
|
5563
|
-
failure.cause instanceof AgentPersistenceCapacityError
|
|
5564
|
-
? failure.cause
|
|
5565
|
-
: new CoordinatorHalt(failure),
|
|
5566
|
-
),
|
|
5601
|
+
Effect.catchCause(effect, (cause) => {
|
|
5602
|
+
const first = Cause.findErrorOption(cause);
|
|
5603
|
+
|
|
5604
|
+
const failure = Effect.failCause(
|
|
5605
|
+
Cause.map(cause, (error) =>
|
|
5606
|
+
error instanceof ThreadStoreError &&
|
|
5607
|
+
error.cause instanceof AgentPersistenceCapacityError
|
|
5608
|
+
? error.cause
|
|
5609
|
+
: new CoordinatorHalt(error),
|
|
5567
5610
|
),
|
|
5568
|
-
)
|
|
5569
|
-
|
|
5611
|
+
);
|
|
5612
|
+
|
|
5613
|
+
return Option.isNone(first) ||
|
|
5614
|
+
(first.value instanceof ThreadStoreError &&
|
|
5615
|
+
first.value.cause instanceof AgentPersistenceCapacityError)
|
|
5616
|
+
? failure
|
|
5617
|
+
: Effect.andThen(Ref.set(haltRef, first.value), failure);
|
|
5618
|
+
});
|
|
5570
5619
|
|
|
5571
5620
|
// Infrastructure errors can be wrapped by broker/Tool APIs. The interpreter checks this
|
|
5572
5621
|
// authority before semantic work; progress delivery is not a coordinator checkpoint.
|
|
5573
|
-
const
|
|
5574
|
-
Effect.gen(function* () {
|
|
5575
|
-
const failure = yield* Ref.get(haltRef);
|
|
5622
|
+
const progress = progressWriters.get(ctx);
|
|
5576
5623
|
|
|
5577
|
-
|
|
5578
|
-
|
|
5624
|
+
const checkProgress =
|
|
5625
|
+
progress === undefined
|
|
5626
|
+
? Effect.void
|
|
5627
|
+
: progress.check(runId).pipe(Effect.provideService(CurrentRunWriter, ctx));
|
|
5579
5628
|
|
|
5580
|
-
|
|
5581
|
-
|
|
5582
|
-
|
|
5629
|
+
const checkpoint = recordHalt(
|
|
5630
|
+
Effect.flatMap(Ref.get(haltRef), (failure) =>
|
|
5631
|
+
failure === undefined ? checkProgress : Effect.fail(failure),
|
|
5632
|
+
),
|
|
5583
5633
|
);
|
|
5584
5634
|
|
|
5585
5635
|
// One readonly Turn may own its response without publishing it. Promotion and settlement
|
|
@@ -5841,6 +5891,7 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
5841
5891
|
const start = yield* CurrentRunStart;
|
|
5842
5892
|
|
|
5843
5893
|
yield* start.commit(yield* makeEnvelope(recordId, payload));
|
|
5894
|
+
knownIds.add(originalInput.record.recordId);
|
|
5844
5895
|
knownIds.add(runStartedRecordId(runId));
|
|
5845
5896
|
knownIds.add(recordId);
|
|
5846
5897
|
historyEvidence.clear();
|
|
@@ -6402,13 +6453,10 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
6402
6453
|
);
|
|
6403
6454
|
}
|
|
6404
6455
|
|
|
6405
|
-
//
|
|
6406
|
-
// complete current-Run
|
|
6456
|
+
// The validated original input bounds summaries even when startup deferred its append.
|
|
6457
|
+
// Pruning and rollover also admit complete current-Run canonical boundaries.
|
|
6407
6458
|
const coverable = sourceBoundaries.filter(
|
|
6408
|
-
(boundary) =>
|
|
6409
|
-
commit.kind !== "summarize" ||
|
|
6410
|
-
ownerFirstSequence === undefined ||
|
|
6411
|
-
boundary.sequence < ownerFirstSequence,
|
|
6459
|
+
(boundary) => commit.kind !== "summarize" || boundary.sequence < originalInput.sequence,
|
|
6412
6460
|
);
|
|
6413
6461
|
|
|
6414
6462
|
if (coverable.length === 0) {
|
|
@@ -7834,35 +7882,39 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
7834
7882
|
stagedUnobservedCalls.set(turn, (stagedUnobservedCalls.get(turn) ?? 0) + 1);
|
|
7835
7883
|
}),
|
|
7836
7884
|
}),
|
|
7837
|
-
|
|
7838
|
-
|
|
7839
|
-
|
|
7840
|
-
|
|
7841
|
-
|
|
7842
|
-
|
|
7843
|
-
|
|
7844
|
-
|
|
7845
|
-
|
|
7846
|
-
|
|
7847
|
-
|
|
7848
|
-
|
|
7849
|
-
|
|
7850
|
-
|
|
7851
|
-
|
|
7852
|
-
|
|
7853
|
-
|
|
7854
|
-
|
|
7855
|
-
|
|
7856
|
-
|
|
7857
|
-
|
|
7858
|
-
|
|
7859
|
-
|
|
7885
|
+
(body) =>
|
|
7886
|
+
body.pipe(
|
|
7887
|
+
Effect.provideServiceEffect(ThreadHistory, ThreadHistory.makeFromStore),
|
|
7888
|
+
Effect.provideServiceEffect(ConversationStore, makeMemoryStore),
|
|
7889
|
+
Effect.scoped,
|
|
7890
|
+
),
|
|
7891
|
+
Effect.provideContext(
|
|
7892
|
+
runServices.pipe(
|
|
7893
|
+
Context.add(SubagentHost.forTool, (source) =>
|
|
7894
|
+
source.threadId !== submission.threadId ||
|
|
7895
|
+
source.agentId !== submission.agentId ||
|
|
7896
|
+
source.runId !== runId
|
|
7897
|
+
? SubagentHost.unavailable
|
|
7898
|
+
: workerRuntime.facet(
|
|
7899
|
+
{
|
|
7900
|
+
source,
|
|
7901
|
+
policy: agent.definition.policy,
|
|
7902
|
+
depth: delegationDepth,
|
|
7903
|
+
...(inheritedGrant === undefined ? {} : { grant: inheritedGrant }),
|
|
7904
|
+
},
|
|
7905
|
+
submission.principal,
|
|
7906
|
+
submission.submissionId,
|
|
7907
|
+
),
|
|
7908
|
+
),
|
|
7909
|
+
Context.add(MessagingHost.forTool, (source) =>
|
|
7910
|
+
source.threadId !== submission.threadId ||
|
|
7911
|
+
source.agentId !== submission.agentId ||
|
|
7912
|
+
source.runId !== runId
|
|
7913
|
+
? MessagingHost.unavailable
|
|
7914
|
+
: messagingRuntime.forTool(source, submission.principal),
|
|
7915
|
+
),
|
|
7916
|
+
),
|
|
7860
7917
|
),
|
|
7861
|
-
Effect.provideService(CurrentToolFailureObserver, toolFailureObserver),
|
|
7862
|
-
Effect.provideService(RunToolVisibility, runToolVisibility),
|
|
7863
|
-
Effect.provideService(RunToolScheduling, runToolScheduling),
|
|
7864
|
-
Effect.provideService(ContextCompactor, compactor),
|
|
7865
|
-
Effect.provideService(RunContextPreparation, runContextPreparation),
|
|
7866
7918
|
Effect.andThen(checkpoint),
|
|
7867
7919
|
// A wrapped Tool/approval failure cannot outrank retained infrastructure authority.
|
|
7868
7920
|
// Preserve independent defects, interruptions and already-marked coordinator failures.
|
|
@@ -7909,21 +7961,20 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
7909
7961
|
}),
|
|
7910
7962
|
);
|
|
7911
7963
|
|
|
7912
|
-
const
|
|
7913
|
-
|
|
7914
|
-
|
|
7915
|
-
yieldAfter === undefined && submissionScheduling.yieldTo === undefined
|
|
7916
|
-
?
|
|
7917
|
-
:
|
|
7918
|
-
execution,
|
|
7964
|
+
const raced = Effect.raceAllFirst([
|
|
7965
|
+
consume,
|
|
7966
|
+
abortWatcher,
|
|
7967
|
+
...(yieldAfter === undefined && submissionScheduling.yieldTo === undefined
|
|
7968
|
+
? []
|
|
7969
|
+
: [
|
|
7919
7970
|
Deferred.await(yieldSignal).pipe(
|
|
7920
7971
|
Effect.map((nextSubmissionId) => ({
|
|
7921
7972
|
_tag: "yielded" as const,
|
|
7922
7973
|
...(nextSubmissionId === undefined ? {} : { nextSubmissionId }),
|
|
7923
7974
|
})),
|
|
7924
7975
|
),
|
|
7925
|
-
)
|
|
7926
|
-
).pipe(Effect.provideService(IdGenerator, idGenerator));
|
|
7976
|
+
]),
|
|
7977
|
+
]).pipe(Effect.provideService(IdGenerator, idGenerator));
|
|
7927
7978
|
|
|
7928
7979
|
const result = yield* raced.pipe(
|
|
7929
7980
|
Effect.catchCauseFilter(
|
|
@@ -8149,23 +8200,21 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
8149
8200
|
resumeAfterRetention: () => void,
|
|
8150
8201
|
onHandoff: (nextSubmissionId: SubmissionId) => void,
|
|
8151
8202
|
yieldAfter?: DateTime.Utc,
|
|
8203
|
+
freshlyAdmitted = false,
|
|
8152
8204
|
) {
|
|
8153
8205
|
// Recheck ownership outside the disposable cache's failure recovery.
|
|
8154
8206
|
yield* session.checkActive;
|
|
8155
8207
|
|
|
8156
8208
|
const checkpointPrompt = yield* promptHistory
|
|
8157
8209
|
.take({ threadId: session.threadId })
|
|
8158
|
-
.pipe(
|
|
8159
|
-
Effect.provideService(ThreadStore, store),
|
|
8160
|
-
Effect.provideService(ThreadReader, reader),
|
|
8161
|
-
Effect.provideService(Crypto.Crypto, crypto),
|
|
8162
|
-
);
|
|
8210
|
+
.pipe(Effect.provideService(ThreadStore, store), Effect.provideContext(journalServices));
|
|
8163
8211
|
|
|
8164
8212
|
// withProgressSession exposes only progress.commit/publish. Their prepare step owns and
|
|
8165
8213
|
// freezes each canonical fact before reaching this raw writer. Snapshot the private array
|
|
8166
8214
|
// before suspension; only acknowledged ranges enter this Attempt's disposable suffix.
|
|
8167
8215
|
let committedPromptSuffix: CommittedPromptSuffix | undefined;
|
|
8168
8216
|
const storageSession = session;
|
|
8217
|
+
let pendingOriginal: InitialContextInput | undefined;
|
|
8169
8218
|
|
|
8170
8219
|
yield* Effect.addFinalizer(() =>
|
|
8171
8220
|
Effect.sync(() => {
|
|
@@ -8173,8 +8222,30 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
8173
8222
|
committedPromptSuffix = undefined;
|
|
8174
8223
|
}),
|
|
8175
8224
|
);
|
|
8176
|
-
|
|
8225
|
+
|
|
8226
|
+
const promptSession: RunStorageSession = {
|
|
8177
8227
|
...storageSession,
|
|
8228
|
+
...(storageSession.appendInput === undefined
|
|
8229
|
+
? {}
|
|
8230
|
+
: {
|
|
8231
|
+
appendInput: (batch: CommitBatch, executions?: ReadonlyArray<ExecutionUpdate>) =>
|
|
8232
|
+
storageSession.appendInput!(batch, executions).pipe(
|
|
8233
|
+
Effect.tap((result) =>
|
|
8234
|
+
Effect.sync(() => {
|
|
8235
|
+
if (
|
|
8236
|
+
pendingOriginal !== undefined &&
|
|
8237
|
+
!result.replayed &&
|
|
8238
|
+
result.firstSequence === pendingOriginal.sequence
|
|
8239
|
+
)
|
|
8240
|
+
committedPromptSuffix = makeCommittedPromptSuffix({
|
|
8241
|
+
threadId: storageSession.threadId,
|
|
8242
|
+
sequence: result.firstSequence,
|
|
8243
|
+
record: batch.records[0]!,
|
|
8244
|
+
});
|
|
8245
|
+
}),
|
|
8246
|
+
),
|
|
8247
|
+
),
|
|
8248
|
+
}),
|
|
8178
8249
|
append: (batch, executions) => {
|
|
8179
8250
|
const suffix = committedPromptSuffix;
|
|
8180
8251
|
const append = storageSession.append(batch, executions);
|
|
@@ -8208,17 +8279,153 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
8208
8279
|
Effect.tapCause(() => Effect.sync(() => suffix.discard())),
|
|
8209
8280
|
);
|
|
8210
8281
|
},
|
|
8211
|
-
}
|
|
8282
|
+
};
|
|
8283
|
+
|
|
8284
|
+
session = yield* withProgressSession(promptSession, () => pendingOriginal);
|
|
8212
8285
|
const { claim, threadId } = session;
|
|
8213
8286
|
const submissionId = claim.submissionId;
|
|
8214
8287
|
|
|
8215
|
-
|
|
8216
|
-
|
|
8217
|
-
|
|
8288
|
+
// The hint only selects this preparation. A real claim, current controls, exact
|
|
8289
|
+
// evidence and checkpoint absence are verified under its owner before any reuse.
|
|
8290
|
+
// No binding, instructions, model, Tool or cross-Thread operation runs in the window.
|
|
8291
|
+
let prepared =
|
|
8292
|
+
freshlyAdmitted && session.withInitialization !== undefined
|
|
8293
|
+
? yield* session.withInitialization(
|
|
8294
|
+
Effect.gen(function* () {
|
|
8295
|
+
const snapshot = yield* ledger.loadRecoverySnapshot(
|
|
8296
|
+
RecoverySnapshotRequest.make({ submissionId }),
|
|
8297
|
+
);
|
|
8298
|
+
|
|
8299
|
+
const submission = snapshot.submission;
|
|
8300
|
+
|
|
8301
|
+
if (
|
|
8302
|
+
submission.state !== "ready" ||
|
|
8303
|
+
submission.workerAdmission !== undefined ||
|
|
8304
|
+
submission.messageAdmission !== undefined ||
|
|
8305
|
+
submission.parentLinkage !== undefined ||
|
|
8306
|
+
snapshot.inputApplied !== undefined ||
|
|
8307
|
+
snapshot.abortIntent !== undefined ||
|
|
8308
|
+
snapshot.approvalDecisions.length !== 0
|
|
8309
|
+
)
|
|
8310
|
+
return undefined;
|
|
8311
|
+
yield* ensureThreadCreated(threadId, submission.agentId, submission.agentDigests);
|
|
8312
|
+
yield* session.refresh;
|
|
8313
|
+
const before = (yield* session.tail).sequence;
|
|
8314
|
+
|
|
8315
|
+
const view = yield* recoveryView(
|
|
8316
|
+
threadId,
|
|
8317
|
+
before,
|
|
8318
|
+
[submissionId],
|
|
8319
|
+
runIdForSubmission(submissionId),
|
|
8320
|
+
);
|
|
8321
|
+
|
|
8322
|
+
if (
|
|
8323
|
+
view.progress !== undefined ||
|
|
8324
|
+
view.context !== undefined ||
|
|
8325
|
+
view.operational.length !== 0 ||
|
|
8326
|
+
view.records.some(({ record }) => record.payload._tag !== "ThreadCreated")
|
|
8327
|
+
)
|
|
8328
|
+
return undefined;
|
|
8329
|
+
if (session.appendInput !== undefined) {
|
|
8330
|
+
const captured = yield* PreparedAppend.capture(
|
|
8331
|
+
AppendRequest.make({
|
|
8332
|
+
threadId,
|
|
8333
|
+
expectedTailSequence: before,
|
|
8334
|
+
batch: CanonicalBatch.make({
|
|
8335
|
+
batchId: submissionInputBatchId(submissionId),
|
|
8336
|
+
producerId: config.producerId,
|
|
8337
|
+
records: [yield* prepareOriginalInput(submission)],
|
|
8338
|
+
}),
|
|
8339
|
+
}),
|
|
8340
|
+
);
|
|
8341
|
+
|
|
8342
|
+
const record = captured.records[0]!.canonical;
|
|
8343
|
+
|
|
8344
|
+
if (!isOriginalInputRecord(record))
|
|
8345
|
+
return yield* RunJournalError.make({
|
|
8346
|
+
message: "Captured startup has no original input",
|
|
8347
|
+
});
|
|
8348
|
+
pendingOriginal = {
|
|
8349
|
+
threadId,
|
|
8350
|
+
sequence: CanonicalSequence.make(before + 1),
|
|
8351
|
+
record,
|
|
8352
|
+
};
|
|
8353
|
+
|
|
8354
|
+
const start = yield* makeRunStart(
|
|
8355
|
+
submission,
|
|
8356
|
+
Duration.toMillis(registeredAgent.definition.policy.maxDuration),
|
|
8357
|
+
view.records,
|
|
8358
|
+
view.operational,
|
|
8359
|
+
record,
|
|
8360
|
+
).pipe(Effect.provideService(CurrentRunWriter, session));
|
|
8361
|
+
|
|
8362
|
+
return { snapshot, through: before, view, start, input: pendingOriginal };
|
|
8363
|
+
}
|
|
8364
|
+
const progress = progressWriters.get(session);
|
|
8365
|
+
|
|
8366
|
+
const applyInput = applyCanonicalInput(
|
|
8367
|
+
session,
|
|
8368
|
+
submission,
|
|
8369
|
+
session,
|
|
8370
|
+
view.records,
|
|
8371
|
+
undefined,
|
|
8372
|
+
);
|
|
8373
|
+
|
|
8374
|
+
yield* progress === undefined
|
|
8375
|
+
? applyInput
|
|
8376
|
+
: progress
|
|
8377
|
+
.withVerifiedEmptyRun(runIdForSubmission(submissionId), before, applyInput)
|
|
8378
|
+
.pipe(Effect.provideService(CurrentRunWriter, promptSession));
|
|
8379
|
+
const through = (yield* session.tail).sequence;
|
|
8380
|
+
const added = yield* selectedRange(threadId, [submissionId], through, before);
|
|
8381
|
+
const records = [...view.records, ...added];
|
|
8382
|
+
|
|
8383
|
+
const accepted = progressWriters
|
|
8384
|
+
.get(session)
|
|
8385
|
+
?.acceptedCheckpoint(runIdForSubmission(submissionId));
|
|
8386
|
+
|
|
8387
|
+
if (
|
|
8388
|
+
accepted === undefined ||
|
|
8389
|
+
accepted.throughSequence !== through ||
|
|
8390
|
+
accepted.progress.runId !== runIdForSubmission(submissionId) ||
|
|
8391
|
+
accepted.progress.submissionId !== submissionId
|
|
8392
|
+
)
|
|
8393
|
+
return undefined;
|
|
8394
|
+
|
|
8395
|
+
const start = yield* makeRunStart(
|
|
8396
|
+
submission,
|
|
8397
|
+
Duration.toMillis(registeredAgent.definition.policy.maxDuration),
|
|
8398
|
+
records,
|
|
8399
|
+
view.operational,
|
|
8400
|
+
).pipe(Effect.provideService(CurrentRunWriter, session));
|
|
8401
|
+
|
|
8402
|
+
return {
|
|
8403
|
+
snapshot,
|
|
8404
|
+
through,
|
|
8405
|
+
view: {
|
|
8406
|
+
...view,
|
|
8407
|
+
records,
|
|
8408
|
+
progress: accepted.progress,
|
|
8409
|
+
progressThrough: accepted.throughSequence,
|
|
8410
|
+
operational: accepted.operational,
|
|
8411
|
+
},
|
|
8412
|
+
start,
|
|
8413
|
+
input: undefined,
|
|
8414
|
+
};
|
|
8415
|
+
}),
|
|
8416
|
+
)
|
|
8417
|
+
: undefined;
|
|
8418
|
+
|
|
8419
|
+
const preparedInput = prepared !== undefined;
|
|
8420
|
+
|
|
8421
|
+
const snapshot =
|
|
8422
|
+
prepared?.snapshot ??
|
|
8423
|
+
(yield* ledger.loadRecoverySnapshot(RecoverySnapshotRequest.make({ submissionId })));
|
|
8218
8424
|
|
|
8219
8425
|
const submission = snapshot.submission;
|
|
8220
8426
|
|
|
8221
|
-
|
|
8427
|
+
if (prepared === undefined)
|
|
8428
|
+
yield* ensureThreadCreated(threadId, submission.agentId, submission.agentDigests);
|
|
8222
8429
|
if (submission.workerAdmission?.origin.reporting?.mode === "standard")
|
|
8223
8430
|
yield* updateRuntime.repairRun(threadId, submissionId);
|
|
8224
8431
|
if (submission.workerAdmission !== undefined) {
|
|
@@ -8233,18 +8440,20 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
8233
8440
|
if (submission.state === "admitted") {
|
|
8234
8441
|
yield* ledger.markReady(MarkReadyRequest.make({ submissionId }));
|
|
8235
8442
|
}
|
|
8236
|
-
yield* session.refresh;
|
|
8443
|
+
if (prepared === undefined) yield* session.refresh;
|
|
8237
8444
|
const ctx: AttemptAppendContext = session;
|
|
8238
|
-
let controlThrough = (yield* session.tail).sequence;
|
|
8445
|
+
let controlThrough = prepared?.through ?? (yield* session.tail).sequence;
|
|
8239
8446
|
|
|
8240
8447
|
const initialThrough = controlThrough;
|
|
8241
8448
|
|
|
8242
|
-
const initialView =
|
|
8243
|
-
|
|
8244
|
-
|
|
8245
|
-
|
|
8246
|
-
|
|
8247
|
-
|
|
8449
|
+
const initialView =
|
|
8450
|
+
prepared?.view ??
|
|
8451
|
+
(yield* recoveryView(
|
|
8452
|
+
threadId,
|
|
8453
|
+
initialThrough,
|
|
8454
|
+
[submissionId],
|
|
8455
|
+
runIdForSubmission(submissionId),
|
|
8456
|
+
));
|
|
8248
8457
|
|
|
8249
8458
|
let journalMetadata: ReturnType<typeof makeJournalMetadata> | undefined;
|
|
8250
8459
|
|
|
@@ -8367,15 +8576,17 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
8367
8576
|
),
|
|
8368
8577
|
);
|
|
8369
8578
|
}
|
|
8370
|
-
|
|
8579
|
+
if (prepared === undefined)
|
|
8580
|
+
yield* applyCanonicalInput(ctx, submission, session, records, snapshot.inputApplied);
|
|
8371
8581
|
|
|
8372
|
-
const start =
|
|
8373
|
-
|
|
8374
|
-
|
|
8375
|
-
|
|
8376
|
-
|
|
8377
|
-
|
|
8378
|
-
|
|
8582
|
+
const start =
|
|
8583
|
+
prepared?.start ??
|
|
8584
|
+
(yield* makeRunStart(
|
|
8585
|
+
submission,
|
|
8586
|
+
Duration.toMillis(agent.definition.policy.maxDuration),
|
|
8587
|
+
yield* refreshControl(),
|
|
8588
|
+
initialView.operational,
|
|
8589
|
+
).pipe(Effect.provideService(CurrentRunWriter, ctx)));
|
|
8379
8590
|
|
|
8380
8591
|
const savedRunTiming = start.timing;
|
|
8381
8592
|
|
|
@@ -8397,8 +8608,11 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
8397
8608
|
};
|
|
8398
8609
|
|
|
8399
8610
|
let expiredChildObligation = false;
|
|
8611
|
+
let preparedControl = prepared !== undefined;
|
|
8400
8612
|
|
|
8401
8613
|
if ((yield* Clock.currentTimeMillis) >= DateTime.toEpochMillis(runTiming.deadline)) {
|
|
8614
|
+
prepared = undefined;
|
|
8615
|
+
preparedControl = false;
|
|
8402
8616
|
yield* commitStart;
|
|
8403
8617
|
yield* reconcileRetainedChildren(ctx, submission, session);
|
|
8404
8618
|
expiredChildObligation = yield* completeJoinedReleases(submission);
|
|
@@ -8406,7 +8620,9 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
8406
8620
|
|
|
8407
8621
|
// Recheck after duration interruption too: that Attempt may have declared new ordinary calls.
|
|
8408
8622
|
const ordinaryCallsResolved = Effect.gen(function* () {
|
|
8409
|
-
const reconciliationRecords = yield* refreshControl();
|
|
8623
|
+
const reconciliationRecords = preparedControl ? records : yield* refreshControl();
|
|
8624
|
+
|
|
8625
|
+
preparedControl = false;
|
|
8410
8626
|
|
|
8411
8627
|
const reconciliationEvidence = yield* evidenceFor(
|
|
8412
8628
|
reconciliationRecords,
|
|
@@ -8456,7 +8672,7 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
8456
8672
|
if (!expiredChildObligation && !(yield* ordinaryCallsResolved))
|
|
8457
8673
|
return Option.none<Settlement>();
|
|
8458
8674
|
|
|
8459
|
-
const continuationRecords = yield* refreshControl();
|
|
8675
|
+
const continuationRecords = prepared === undefined ? yield* refreshControl() : records;
|
|
8460
8676
|
|
|
8461
8677
|
const continuation = yield* pendingToolBatchFor(
|
|
8462
8678
|
continuationRecords,
|
|
@@ -8596,24 +8812,30 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
8596
8812
|
|
|
8597
8813
|
const lineage: AttemptLineage = {
|
|
8598
8814
|
attemptId: claim.attemptId,
|
|
8599
|
-
inputWasRecorded: evidence.inputRecorded,
|
|
8815
|
+
inputWasRecorded: !preparedInput && evidence.inputRecorded,
|
|
8600
8816
|
};
|
|
8601
8817
|
|
|
8602
8818
|
let approvalDecisionIntents = snapshot.approvalDecisions;
|
|
8603
8819
|
|
|
8604
8820
|
while (true) {
|
|
8605
|
-
|
|
8821
|
+
const initialization = prepared;
|
|
8822
|
+
|
|
8823
|
+
prepared = undefined;
|
|
8824
|
+
if (initialization === undefined) yield* session.refresh;
|
|
8606
8825
|
const tail = yield* session.tail;
|
|
8607
8826
|
|
|
8608
|
-
const currentRecords =
|
|
8827
|
+
const currentRecords =
|
|
8828
|
+
initialization === undefined ? yield* refreshControl(tail.sequence) : records;
|
|
8609
8829
|
|
|
8610
|
-
const view =
|
|
8611
|
-
|
|
8612
|
-
|
|
8613
|
-
|
|
8614
|
-
|
|
8615
|
-
|
|
8616
|
-
|
|
8830
|
+
const view =
|
|
8831
|
+
initialization?.view ??
|
|
8832
|
+
(yield* recoveryView(
|
|
8833
|
+
threadId,
|
|
8834
|
+
tail.sequence,
|
|
8835
|
+
[submissionId],
|
|
8836
|
+
runIdForSubmission(submissionId),
|
|
8837
|
+
currentRecords,
|
|
8838
|
+
));
|
|
8617
8839
|
|
|
8618
8840
|
let canonical: Stream.Stream<
|
|
8619
8841
|
JournalRecordEnvelope,
|
|
@@ -8623,12 +8845,14 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
8623
8845
|
let initialJournal: InitialJournalSource | undefined;
|
|
8624
8846
|
|
|
8625
8847
|
if (view.context === undefined) {
|
|
8626
|
-
const original =
|
|
8627
|
-
|
|
8628
|
-
|
|
8629
|
-
record
|
|
8630
|
-
|
|
8631
|
-
|
|
8848
|
+
const original =
|
|
8849
|
+
initialization?.input ??
|
|
8850
|
+
currentRecords.find(
|
|
8851
|
+
({ record }) =>
|
|
8852
|
+
record.payload._tag === "UserInputRecorded" &&
|
|
8853
|
+
record.payload.kind === "user" &&
|
|
8854
|
+
record.payload.submissionId === submissionId,
|
|
8855
|
+
);
|
|
8632
8856
|
|
|
8633
8857
|
if (original === undefined)
|
|
8634
8858
|
return yield* RunJournalError.make({
|
|
@@ -8638,7 +8862,10 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
8638
8862
|
const suffix = currentRecords.filter((entry) => entry.sequence > original.sequence);
|
|
8639
8863
|
|
|
8640
8864
|
const fresh =
|
|
8641
|
-
|
|
8865
|
+
initialization?.input !== undefined ||
|
|
8866
|
+
(!lineage.inputWasRecorded &&
|
|
8867
|
+
tail.sequence === original.sequence &&
|
|
8868
|
+
suffix.length === 0);
|
|
8642
8869
|
|
|
8643
8870
|
// Every replay stays bounded at the ORIGINAL admission, never the later Thread tail.
|
|
8644
8871
|
const source: InitialJournalSource = yield* Effect.gen(function* () {
|
|
@@ -8681,9 +8908,10 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
8681
8908
|
}
|
|
8682
8909
|
|
|
8683
8910
|
committedPromptSuffix?.discard();
|
|
8684
|
-
committedPromptSuffix =
|
|
8685
|
-
|
|
8686
|
-
|
|
8911
|
+
committedPromptSuffix =
|
|
8912
|
+
initialJournal?.cacheable && initialization?.input === undefined
|
|
8913
|
+
? makeCommittedPromptSuffix(initialJournal.original)
|
|
8914
|
+
: undefined;
|
|
8687
8915
|
|
|
8688
8916
|
const outcome = yield* runModel(
|
|
8689
8917
|
agent,
|
|
@@ -8693,7 +8921,7 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
8693
8921
|
currentRecords,
|
|
8694
8922
|
canonical,
|
|
8695
8923
|
initialJournal,
|
|
8696
|
-
tail.sequence,
|
|
8924
|
+
initialization?.input?.sequence ?? tail.sequence,
|
|
8697
8925
|
view.progressThrough,
|
|
8698
8926
|
view.progress,
|
|
8699
8927
|
view.context,
|
|
@@ -8933,6 +9161,9 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
8933
9161
|
const session = claimed.value;
|
|
8934
9162
|
const { claim } = session;
|
|
8935
9163
|
|
|
9164
|
+
const freshlyAdmitted = unclaimedAdmissions.get(claim.submissionId) === threadId;
|
|
9165
|
+
|
|
9166
|
+
unclaimedAdmissions.delete(claim.submissionId);
|
|
8936
9167
|
firstClaimedSubmissionId ??= claim.submissionId;
|
|
8937
9168
|
|
|
8938
9169
|
const attributes = {
|
|
@@ -9017,6 +9248,7 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
9017
9248
|
});
|
|
9018
9249
|
},
|
|
9019
9250
|
options?.yieldAfter,
|
|
9251
|
+
freshlyAdmitted,
|
|
9020
9252
|
),
|
|
9021
9253
|
threadId,
|
|
9022
9254
|
claim,
|
|
@@ -10395,6 +10627,7 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
10395
10627
|
const recoverOwnedWork = Effect.fnUntraced(function* (
|
|
10396
10628
|
request: WorkRecoveryRequest,
|
|
10397
10629
|
recoveredAdmissions = new Map<SubmissionId, RecoveryReport>(),
|
|
10630
|
+
deferUnclaimedAdmissions = false,
|
|
10398
10631
|
): Effect.fn.Return<WorkRecoveryReport, DurableWorkerFailure> {
|
|
10399
10632
|
const { threadId, work: entry } = yield* Schema.decodeEffect(WorkRecoveryRequest)(request).pipe(
|
|
10400
10633
|
Effect.mapError((cause) =>
|
|
@@ -10448,6 +10681,21 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
10448
10681
|
const original = yield* lookupKnownSubmission("recover work", owner.submissionId);
|
|
10449
10682
|
|
|
10450
10683
|
if (original.threadId !== threadId) return yield* invalid();
|
|
10684
|
+
if (
|
|
10685
|
+
deferUnclaimedAdmissions &&
|
|
10686
|
+
unclaimedAdmissions.get(owner.submissionId) === threadId &&
|
|
10687
|
+
original.state === "ready" &&
|
|
10688
|
+
!storageOwner.hasOwner(threadId) &&
|
|
10689
|
+
(yield* ledger.readAbortIntent(
|
|
10690
|
+
AbortIntentRequest.make({ submissionId: owner.submissionId }),
|
|
10691
|
+
)) === undefined
|
|
10692
|
+
) {
|
|
10693
|
+
// The worker's first scoped claim performs the authoritative control/journal
|
|
10694
|
+
// read. This hint skips only a redundant pre-claim recovery traversal; it grants
|
|
10695
|
+
// no claim, synthesizes no decision, and supplies no model-visible facts.
|
|
10696
|
+
return report("deferred");
|
|
10697
|
+
}
|
|
10698
|
+
unclaimedAdmissions.delete(owner.submissionId);
|
|
10451
10699
|
const submission = yield* recoverAdmission(owner.submissionId);
|
|
10452
10700
|
|
|
10453
10701
|
return report(submission.disposition, submission);
|
|
@@ -10926,6 +11174,29 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
10926
11174
|
|
|
10927
11175
|
const outcome = yield* isolateRecovery(
|
|
10928
11176
|
Effect.gen(function* () {
|
|
11177
|
+
// This incarnation admitted the sole untouched root. The native snapshot proves
|
|
11178
|
+
// there is no old owner to repair; claim and live controls still run normally.
|
|
11179
|
+
// New source mutations retain their dirty generation for the next maintenance scan.
|
|
11180
|
+
if (
|
|
11181
|
+
workCursor === undefined &&
|
|
11182
|
+
options?.deferUnclaimedAdmissions === true &&
|
|
11183
|
+
workDiscovery.isOnlyFreshAdmission !== undefined &&
|
|
11184
|
+
!storageOwner.hasOwner(threadId)
|
|
11185
|
+
) {
|
|
11186
|
+
const fresh = [...unclaimedAdmissions].find(([, owner]) => owner === threadId);
|
|
11187
|
+
|
|
11188
|
+
if (
|
|
11189
|
+
fresh !== undefined &&
|
|
11190
|
+
(yield* workDiscovery.isOnlyFreshAdmission({
|
|
11191
|
+
threadId,
|
|
11192
|
+
submissionId: fresh[0],
|
|
11193
|
+
}))
|
|
11194
|
+
) {
|
|
11195
|
+
complete = true;
|
|
11196
|
+
|
|
11197
|
+
return;
|
|
11198
|
+
}
|
|
11199
|
+
}
|
|
10929
11200
|
for (
|
|
10930
11201
|
let pages = 0;
|
|
10931
11202
|
pages < MAX_RECOVERY_PAGES && workReports.length < MAX_RECOVERY_WORK_ITEMS;
|
|
@@ -10941,7 +11212,11 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
10941
11212
|
|
|
10942
11213
|
phase = "recovery";
|
|
10943
11214
|
for (const work of workPage.entries) {
|
|
10944
|
-
const repaired = yield* recoverOwnedWork(
|
|
11215
|
+
const repaired = yield* recoverOwnedWork(
|
|
11216
|
+
{ threadId, work },
|
|
11217
|
+
recoveredAdmissions,
|
|
11218
|
+
options?.deferUnclaimedAdmissions === true,
|
|
11219
|
+
);
|
|
10945
11220
|
|
|
10946
11221
|
workReports.push(repaired);
|
|
10947
11222
|
if (
|
|
@@ -11165,7 +11440,7 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
11165
11440
|
queueSequence: admitted.queueSequence,
|
|
11166
11441
|
});
|
|
11167
11442
|
}
|
|
11168
|
-
const admitted = yield* ledger.admit(request);
|
|
11443
|
+
const admitted = yield* ledger.admit(request, { readyIfInitialized: true });
|
|
11169
11444
|
|
|
11170
11445
|
yield* hit("submit:after-admit");
|
|
11171
11446
|
|
|
@@ -11181,10 +11456,24 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
|
|
|
11181
11456
|
if (admitted.replayed && admitted.state !== "admitted") {
|
|
11182
11457
|
return receipt;
|
|
11183
11458
|
}
|
|
11184
|
-
|
|
11185
|
-
|
|
11186
|
-
|
|
11187
|
-
|
|
11459
|
+
if (admitted.state === "admitted") {
|
|
11460
|
+
yield* materializeThread(options.threadId);
|
|
11461
|
+
yield* ensureThreadCreated(options.threadId, agent.definition.id, options.definitions);
|
|
11462
|
+
yield* hit("submit:after-materialize");
|
|
11463
|
+
yield* ledger.markReady(MarkReadyRequest.make({ submissionId: admitted.submissionId }));
|
|
11464
|
+
}
|
|
11465
|
+
if (
|
|
11466
|
+
!admitted.replayed &&
|
|
11467
|
+
messageAdmission === undefined &&
|
|
11468
|
+
options.workerAdmission === undefined
|
|
11469
|
+
) {
|
|
11470
|
+
unclaimedAdmissions.set(admitted.submissionId, options.threadId);
|
|
11471
|
+
if (unclaimedAdmissions.size > 128) {
|
|
11472
|
+
const oldest = unclaimedAdmissions.keys().next().value;
|
|
11473
|
+
|
|
11474
|
+
if (oldest !== undefined) unclaimedAdmissions.delete(oldest);
|
|
11475
|
+
}
|
|
11476
|
+
}
|
|
11188
11477
|
yield* wake.notify(options.threadId);
|
|
11189
11478
|
|
|
11190
11479
|
return receipt;
|