@yielded/agent 0.1.0-beta.174 → 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-BHmp2V9p.d.mts → Admin-Qa3I1oA5.d.mts} +38 -7
- 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-CPlw5_7e.mjs} +161 -85
- package/dist/DurableAgentRuntime-CPlw5_7e.mjs.map +1 -0
- package/dist/{EventSource-C9aaJaXT.d.mts → EventSource-BTu68yDW.d.mts} +2 -2
- package/dist/InMemory.d.mts +2 -2
- package/dist/{MessageDelivery-BGDm-c46.d.mts → MessageDelivery-DjAZJ4Fd.d.mts} +4 -4
- 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-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-CTJ1jGrO.d.mts → RunContinuation-3jB5pULC.d.mts} +10 -4
- package/dist/{RunContinuation-4ZATcVLB.mjs → RunContinuation-BiyKJK32.mjs} +74 -40
- package/dist/RunContinuation-BiyKJK32.mjs.map +1 -0
- package/dist/{RunJournal-CNZqA3Ge.mjs → RunJournal-CPMKcfd0.mjs} +84 -79
- package/dist/RunJournal-CPMKcfd0.mjs.map +1 -0
- package/dist/{RunStorage-BHjuuERI.mjs → RunStorage-CzutHJBE.mjs} +3 -2
- package/dist/RunStorage-CzutHJBE.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-DmIHlOJK.d.mts} +2 -2
- package/dist/{SubscriptionInput-BUoXv-_K.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-CodYoJoa.mjs → ThreadImport-CjlG57vH.mjs} +8 -8
- package/dist/{ThreadImport-CodYoJoa.mjs.map → ThreadImport-CjlG57vH.mjs.map} +1 -1
- package/dist/{ThreadImport-CMgzttvr.d.mts → ThreadImport-DP-vOk2F.d.mts} +4 -4
- package/dist/{ThreadStore-59uDGXul.mjs → ThreadStore-EuUilthA.mjs} +5 -7
- package/dist/ThreadStore-EuUilthA.mjs.map +1 -0
- package/dist/{ThreadTransfer-3jigUl3g.mjs → ThreadTransfer-DB_zsrtJ.mjs} +4 -4
- package/dist/{ThreadTransfer-3jigUl3g.mjs.map → ThreadTransfer-DB_zsrtJ.mjs.map} +1 -1
- package/dist/{WorkerAdmission-DDYJdOsU.mjs → WorkerAdmission-eBeXt_mu.mjs} +5 -5
- package/dist/{WorkerAdmission-DDYJdOsU.mjs.map → WorkerAdmission-eBeXt_mu.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 +1 -1
- 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-DVhJZ1Qe.d.mts} +2 -2
- package/package.json +1 -1
- package/src/core/Thread.ts +143 -146
- package/src/durable/DurableAgentRuntime.ts +381 -206
- package/src/durable/RunContinuation.ts +113 -62
- package/src/durable/RunJournal.ts +99 -108
- package/src/durable/RunStorage.ts +7 -0
- package/src/durable/SqlMemoryStore.ts +8 -6
- package/src/durable/SubmissionLedger.ts +7 -0
- package/src/durable/ThreadStore.ts +9 -7
- package/src/durable/ThreadWork.ts +10 -0
- package/src/durable/WakeScheduler.ts +34 -66
- 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
|
@@ -5,7 +5,7 @@ import { AgentPersistenceCapacityError } from "../core/AgentError.ts";
|
|
|
5
5
|
import type { RunId, SubmissionId, ThreadId } from "../core/Identifiers.ts";
|
|
6
6
|
import { ToolCallId } from "../core/Identifiers.ts";
|
|
7
7
|
import { utf8ByteLength } from "../core/internal/utf8.ts";
|
|
8
|
-
import {
|
|
8
|
+
import { resolveEvidence } from "./internal/evidence.ts";
|
|
9
9
|
import { continuationUsage } from "./internal/usage-totals.ts";
|
|
10
10
|
export { reference, resolveEvidence } from "./internal/evidence.ts";
|
|
11
11
|
import {
|
|
@@ -157,17 +157,14 @@ const isFrozenJsonData = (input: Schema.Json): boolean => {
|
|
|
157
157
|
return true;
|
|
158
158
|
};
|
|
159
159
|
|
|
160
|
-
const
|
|
160
|
+
const validateBatchShape = Schema.decodeUnknownSync(
|
|
161
161
|
Schema.Struct({
|
|
162
162
|
batchId: CanonicalBatch.fields.batchId,
|
|
163
163
|
producerId: CanonicalBatch.fields.producerId,
|
|
164
|
+
records: Schema.NonEmptyArray(Schema.Unknown).check(Schema.isMaxLength(256)),
|
|
164
165
|
}),
|
|
165
166
|
);
|
|
166
167
|
|
|
167
|
-
const validateBatchCount = Schema.decodeUnknownSync(
|
|
168
|
-
Schema.NonEmptyArray(Schema.Unknown).check(Schema.isMaxLength(256)),
|
|
169
|
-
);
|
|
170
|
-
|
|
171
168
|
const ContinuationBytes = Schema.Struct({
|
|
172
169
|
turnBytes: RunContinuation.fields.turnBytes,
|
|
173
170
|
terminalBytes: RunContinuation.fields.terminalBytes,
|
|
@@ -185,15 +182,20 @@ const captureFacts = (batch: CommitBatch) =>
|
|
|
185
182
|
Effect.try({
|
|
186
183
|
try: () =>
|
|
187
184
|
Result.gen(function* () {
|
|
188
|
-
const
|
|
185
|
+
const inputs = batch.records;
|
|
189
186
|
|
|
190
|
-
|
|
191
|
-
|
|
187
|
+
const { batchId, producerId } = validateBatchShape({
|
|
188
|
+
batchId: batch.batchId,
|
|
189
|
+
producerId: batch.producerId,
|
|
190
|
+
records: inputs,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
const encodings = yield* Result.all(inputs.map(captureRecord));
|
|
192
194
|
const records = encodings.map((record) => record.canonical);
|
|
193
195
|
|
|
194
196
|
return Object.freeze(
|
|
195
197
|
CanonicalBatch.make(
|
|
196
|
-
{
|
|
198
|
+
{ batchId, producerId, records: [records[0]!, ...records.slice(1)] },
|
|
197
199
|
{ disableChecks: true },
|
|
198
200
|
),
|
|
199
201
|
);
|
|
@@ -236,14 +238,6 @@ export const prepareProgressAppend = (
|
|
|
236
238
|
return Object.freeze(encodings.success.map((record) => record.progress));
|
|
237
239
|
};
|
|
238
240
|
|
|
239
|
-
const factUsageCharge = (facts: ReadonlyArray<RecordEnvelope>) =>
|
|
240
|
-
Effect.fromResult(Result.all(facts.map(recordEncoding))).pipe(
|
|
241
|
-
Effect.map((encodings) =>
|
|
242
|
-
encodings.reduce((bytes, record) => bytes + record.progress.terminalUsageBytes, 0),
|
|
243
|
-
),
|
|
244
|
-
Effect.mapError((cause) => failure("Cannot account canonical progress facts", cause)),
|
|
245
|
-
);
|
|
246
|
-
|
|
247
241
|
/** These values belong to the active Run, not its permanent conversation history. */
|
|
248
242
|
export const isOperationalRecord = ({ payload }: RecordEnvelope): boolean =>
|
|
249
243
|
payload._tag === "RunStarted" ||
|
|
@@ -717,9 +711,27 @@ const advanceFacts = Effect.fnUntraced(function* (
|
|
|
717
711
|
let results = new Map(previous?.results);
|
|
718
712
|
let childResults = new Map(previous?.childResults);
|
|
719
713
|
let completionBytes = previous?.completionBytes;
|
|
714
|
+
let factBytes = 0;
|
|
715
|
+
let turn = previous?.continuation.turn ?? 1;
|
|
716
|
+
let usageCharge = 0;
|
|
717
|
+
let closingBytes = 0;
|
|
718
|
+
let closingCount = 0;
|
|
720
719
|
|
|
721
720
|
for (const fact of facts) {
|
|
722
721
|
const payload = fact.payload;
|
|
722
|
+
const captured = recordEncoding(fact);
|
|
723
|
+
|
|
724
|
+
if (Result.isFailure(captured))
|
|
725
|
+
return yield* failure("Cannot account canonical progress facts", captured.failure);
|
|
726
|
+
const encoded = captured.success;
|
|
727
|
+
|
|
728
|
+
factBytes += encoded.bytes;
|
|
729
|
+
if ("turn" in payload) turn = Math.max(turn, payload.turn);
|
|
730
|
+
usageCharge += encoded.progress.terminalUsageBytes;
|
|
731
|
+
if (encoded.progress.terminal) {
|
|
732
|
+
closingBytes += encoded.bytes;
|
|
733
|
+
closingCount++;
|
|
734
|
+
}
|
|
723
735
|
|
|
724
736
|
switch (payload._tag) {
|
|
725
737
|
case "RunStarted":
|
|
@@ -728,7 +740,7 @@ const advanceFacts = Effect.fnUntraced(function* (
|
|
|
728
740
|
case "RunContextRecorded":
|
|
729
741
|
if (savedContext !== undefined)
|
|
730
742
|
return yield* failure("A Run's original context cannot be replaced");
|
|
731
|
-
savedContext =
|
|
743
|
+
savedContext = EvidenceReference.make({ recordId: fact.recordId });
|
|
732
744
|
position = "awaiting-model";
|
|
733
745
|
break;
|
|
734
746
|
case "ModelResponseRecorded": {
|
|
@@ -782,7 +794,7 @@ const advanceFacts = Effect.fnUntraced(function* (
|
|
|
782
794
|
accounting.lastInputTokens = summary?.inputTokens ?? payload.inputTokens ?? 0;
|
|
783
795
|
accounting.lastOutputTokens = summary?.outputTokens ?? payload.outputTokens ?? 0;
|
|
784
796
|
accounting.unobservedModelCalls += payload.unobservedModelCalls ?? 0;
|
|
785
|
-
latestResponse =
|
|
797
|
+
latestResponse = EvidenceReference.make({ recordId: fact.recordId });
|
|
786
798
|
response = payload;
|
|
787
799
|
results = new Map();
|
|
788
800
|
childResults = new Map();
|
|
@@ -866,12 +878,12 @@ const advanceFacts = Effect.fnUntraced(function* (
|
|
|
866
878
|
? 0
|
|
867
879
|
: utf8ByteLength(JSON.stringify(payload.runDisposition)))
|
|
868
880
|
: undefined;
|
|
869
|
-
terminal =
|
|
881
|
+
terminal = EvidenceReference.make({ recordId: fact.recordId });
|
|
870
882
|
position = "settling";
|
|
871
883
|
break;
|
|
872
884
|
case "SubmissionSettled":
|
|
873
885
|
if (payload.submissionId !== submissionId) break;
|
|
874
|
-
terminal =
|
|
886
|
+
terminal = EvidenceReference.make({ recordId: fact.recordId });
|
|
875
887
|
position = "settled";
|
|
876
888
|
if (payload.usageSummary !== undefined) {
|
|
877
889
|
accounting.modelCalls = payload.usageSummary.modelCalls;
|
|
@@ -929,22 +941,13 @@ const advanceFacts = Effect.fnUntraced(function* (
|
|
|
929
941
|
if (previous?.continuation.position === "settled") position = "settled";
|
|
930
942
|
else if (previous?.continuation.position === "settling" && position !== "settled")
|
|
931
943
|
position = "settling";
|
|
932
|
-
const factBytes = facts.reduce((bytes, fact) => bytes + canonicalRecordBytes(fact), 0);
|
|
933
|
-
|
|
934
|
-
const turn = facts.reduce(
|
|
935
|
-
(current, fact) => ("turn" in fact.payload ? Math.max(current, fact.payload.turn) : current),
|
|
936
|
-
previous?.continuation.turn ?? 1,
|
|
937
|
-
);
|
|
938
944
|
|
|
939
945
|
const turnBase =
|
|
940
946
|
(previous?.continuation.turn === turn ? previous.continuation.turnBytes : initialBytes) +
|
|
941
947
|
factBytes;
|
|
942
948
|
|
|
943
|
-
const usageCharge = yield* factUsageCharge(facts);
|
|
944
949
|
const terminalUsageBytes = (previous?.continuation.terminalUsageBytes ?? 0) + usageCharge;
|
|
945
950
|
|
|
946
|
-
const closing = facts.filter(isTerminalBudgetFact);
|
|
947
|
-
|
|
948
951
|
return {
|
|
949
952
|
accounting,
|
|
950
953
|
savedContext,
|
|
@@ -961,11 +964,9 @@ const advanceFacts = Effect.fnUntraced(function* (
|
|
|
961
964
|
turnBase,
|
|
962
965
|
usageCharge,
|
|
963
966
|
terminalUsageBytes,
|
|
964
|
-
terminalBytes:
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
terminalRecords: (previous?.continuation.terminalRecords ?? 0) + closing.length,
|
|
968
|
-
closing: closing.length > 0,
|
|
967
|
+
terminalBytes: (previous?.continuation.terminalBytes ?? 0) + closingBytes,
|
|
968
|
+
terminalRecords: (previous?.continuation.terminalRecords ?? 0) + closingCount,
|
|
969
|
+
closing: closingCount > 0,
|
|
969
970
|
};
|
|
970
971
|
});
|
|
971
972
|
|
|
@@ -1046,6 +1047,14 @@ export const makeProgressWriter = Effect.fnUntraced(function* (
|
|
|
1046
1047
|
const gate = yield* Semaphore.make(1);
|
|
1047
1048
|
const cached = new Map<RunId, ProgressState>();
|
|
1048
1049
|
|
|
1050
|
+
let verifiedEmpty:
|
|
1051
|
+
| {
|
|
1052
|
+
readonly runId: RunId;
|
|
1053
|
+
readonly through: CanonicalSequence;
|
|
1054
|
+
readonly writer: CurrentRunWriter["Service"];
|
|
1055
|
+
}
|
|
1056
|
+
| undefined;
|
|
1057
|
+
|
|
1049
1058
|
const reservations = new Map<
|
|
1050
1059
|
RecordId,
|
|
1051
1060
|
{
|
|
@@ -1180,13 +1189,6 @@ export const makeProgressWriter = Effect.fnUntraced(function* (
|
|
|
1180
1189
|
};
|
|
1181
1190
|
});
|
|
1182
1191
|
|
|
1183
|
-
const loadState = (runId: RunId, after: CanonicalSequence) =>
|
|
1184
|
-
Effect.suspend(() => {
|
|
1185
|
-
const retained = cached.get(runId);
|
|
1186
|
-
|
|
1187
|
-
return retained === undefined ? loadUncachedState(runId, after) : Effect.succeed(retained);
|
|
1188
|
-
});
|
|
1189
|
-
|
|
1190
1192
|
const checkFutureShapes = (
|
|
1191
1193
|
state: ProgressState,
|
|
1192
1194
|
cursorBytes?: number,
|
|
@@ -1316,12 +1318,9 @@ export const makeProgressWriter = Effect.fnUntraced(function* (
|
|
|
1316
1318
|
if (batch.records.some((record) => record.payload._tag === "RunContinuation"))
|
|
1317
1319
|
return yield* failure("A caller cannot supply interpreter progress to the progress writer");
|
|
1318
1320
|
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
Effect.map((encodings) => encodings.map((record) => record.canonical)),
|
|
1323
|
-
Effect.mapError((cause) => failure("Cannot capture canonical progress facts", cause)),
|
|
1324
|
-
);
|
|
1321
|
+
// Every private caller passes captureFacts' owned snapshot. Keep a mutable
|
|
1322
|
+
// list for settlement accounting without capturing that snapshot a second time.
|
|
1323
|
+
const ownedRecords = [...batch.records];
|
|
1325
1324
|
|
|
1326
1325
|
const groups = new Map<RunId, Array<RecordEnvelope>>();
|
|
1327
1326
|
|
|
@@ -1338,7 +1337,16 @@ export const makeProgressWriter = Effect.fnUntraced(function* (
|
|
|
1338
1337
|
let executionCount = 0;
|
|
1339
1338
|
|
|
1340
1339
|
for (const [runId, facts] of groups) {
|
|
1341
|
-
const
|
|
1340
|
+
const empty =
|
|
1341
|
+
verifiedEmpty?.runId === runId &&
|
|
1342
|
+
verifiedEmpty.through === after &&
|
|
1343
|
+
// Settlement preparation need not have a Run writer; absence disables reuse.
|
|
1344
|
+
verifiedEmpty.writer ===
|
|
1345
|
+
Option.getOrUndefined(yield* Effect.serviceOption(CurrentRunWriter));
|
|
1346
|
+
|
|
1347
|
+
const previous = empty
|
|
1348
|
+
? undefined
|
|
1349
|
+
: (cached.get(runId) ?? (yield* loadUncachedState(runId, after)));
|
|
1342
1350
|
|
|
1343
1351
|
let original = facts.find(
|
|
1344
1352
|
(record) =>
|
|
@@ -1379,7 +1387,7 @@ export const makeProgressWriter = Effect.fnUntraced(function* (
|
|
|
1379
1387
|
if (previous === undefined && original === undefined)
|
|
1380
1388
|
return yield* failure("Run has no accepted original input");
|
|
1381
1389
|
|
|
1382
|
-
if (previous === undefined) {
|
|
1390
|
+
if (previous === undefined && !empty) {
|
|
1383
1391
|
const settled = yield* provide(
|
|
1384
1392
|
getRecord({
|
|
1385
1393
|
threadId,
|
|
@@ -1460,7 +1468,7 @@ export const makeProgressWriter = Effect.fnUntraced(function* (
|
|
|
1460
1468
|
? previous.continuation.originalInput
|
|
1461
1469
|
: original === undefined
|
|
1462
1470
|
? yield* failure("Run progress has no original input")
|
|
1463
|
-
:
|
|
1471
|
+
: EvidenceReference.make({ recordId: original.recordId });
|
|
1464
1472
|
|
|
1465
1473
|
const next = yield* advanceFacts(previous, facts, submissionId, initialBytes);
|
|
1466
1474
|
|
|
@@ -1498,7 +1506,7 @@ export const makeProgressWriter = Effect.fnUntraced(function* (
|
|
|
1498
1506
|
...(savedContext === undefined ? {} : { savedContext }),
|
|
1499
1507
|
...(latestResponse === undefined ? {} : { latestResponse }),
|
|
1500
1508
|
...(terminal === undefined ? {} : { terminal }),
|
|
1501
|
-
lastFact:
|
|
1509
|
+
lastFact: EvidenceReference.make({ recordId: last.recordId }),
|
|
1502
1510
|
position,
|
|
1503
1511
|
accounting,
|
|
1504
1512
|
}).pipe(
|
|
@@ -1824,7 +1832,7 @@ export const makeProgressWriter = Effect.fnUntraced(function* (
|
|
|
1824
1832
|
|
|
1825
1833
|
yield* prepare(yield* captureFacts(probe), after);
|
|
1826
1834
|
const recordId = probe.records[0].recordId;
|
|
1827
|
-
const state = yield*
|
|
1835
|
+
const state = cached.get(runId) ?? (yield* loadUncachedState(runId, after));
|
|
1828
1836
|
|
|
1829
1837
|
if (state === undefined) return yield* failure("Dispatch has no canonical Run progress");
|
|
1830
1838
|
if (reservations.has(recordId))
|
|
@@ -1859,7 +1867,10 @@ export const makeProgressWriter = Effect.fnUntraced(function* (
|
|
|
1859
1867
|
|
|
1860
1868
|
if (response === undefined || response.payload._tag !== "ModelResponseRecorded")
|
|
1861
1869
|
return yield* failure("Deferred dispatch has no response");
|
|
1862
|
-
|
|
1870
|
+
|
|
1871
|
+
const progress =
|
|
1872
|
+
cached.get(response.payload.runId) ??
|
|
1873
|
+
(yield* loadUncachedState(response.payload.runId, after));
|
|
1863
1874
|
|
|
1864
1875
|
if (progress === undefined) return yield* failure("Deferred dispatch has no Run progress");
|
|
1865
1876
|
|
|
@@ -1893,16 +1904,33 @@ export const makeProgressWriter = Effect.fnUntraced(function* (
|
|
|
1893
1904
|
}),
|
|
1894
1905
|
);
|
|
1895
1906
|
|
|
1907
|
+
const checkState = (state: ProgressState | undefined, recovered: boolean) => {
|
|
1908
|
+
if (state === undefined) return Effect.fail(failure("Execution has no canonical Run progress"));
|
|
1909
|
+
|
|
1910
|
+
const capacity = () =>
|
|
1911
|
+
state.continuation.position === "settling" || state.continuation.position === "settled"
|
|
1912
|
+
? Effect.void
|
|
1913
|
+
: checkCapacity(state);
|
|
1914
|
+
|
|
1915
|
+
// Accepted states were shape-checked, but usage and reservations remain live inputs.
|
|
1916
|
+
return recovered ? Effect.andThen(checkFutureShapes(state), capacity) : capacity();
|
|
1917
|
+
};
|
|
1918
|
+
|
|
1896
1919
|
const check = (runId: RunId) =>
|
|
1897
1920
|
gate.withPermits(1)(
|
|
1898
|
-
Effect.
|
|
1899
|
-
|
|
1921
|
+
Effect.flatMap(CurrentRunWriter, (writer) => {
|
|
1922
|
+
if (writer.threadId !== threadId)
|
|
1923
|
+
return Effect.fail(failure("Progress writer belongs to another Thread"));
|
|
1924
|
+
|
|
1925
|
+
const retained = cached.get(runId);
|
|
1900
1926
|
|
|
1901
|
-
if (
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1927
|
+
if (retained !== undefined) return checkState(retained, false);
|
|
1928
|
+
|
|
1929
|
+
return Effect.flatMap(writer.tail, (position) =>
|
|
1930
|
+
Effect.flatMap(loadUncachedState(runId, position.sequence), (state) =>
|
|
1931
|
+
checkState(state, true),
|
|
1932
|
+
),
|
|
1933
|
+
);
|
|
1906
1934
|
}),
|
|
1907
1935
|
);
|
|
1908
1936
|
|
|
@@ -1912,6 +1940,29 @@ export const makeProgressWriter = Effect.fnUntraced(function* (
|
|
|
1912
1940
|
reserve,
|
|
1913
1941
|
defer,
|
|
1914
1942
|
check,
|
|
1943
|
+
/** Internal read view immediately after this writer's acknowledged commit, while
|
|
1944
|
+
* holding its initialization gates. Never authority across ownership or writes. */
|
|
1945
|
+
acceptedCheckpoint: (runId: RunId) => cached.get(runId)?.checkpoint,
|
|
1946
|
+
/** Scope a verified empty execution/evidence view to one owned initialization body.
|
|
1947
|
+
* The caller holds progress+mutation gates; a changed writer or tail never reuses it. */
|
|
1948
|
+
withVerifiedEmptyRun: <A, E, R>(
|
|
1949
|
+
runId: RunId,
|
|
1950
|
+
through: CanonicalSequence,
|
|
1951
|
+
body: Effect.Effect<A, E, R>,
|
|
1952
|
+
): Effect.Effect<A, E, R | CurrentRunWriter> =>
|
|
1953
|
+
Effect.flatMap(CurrentRunWriter, (writer) => {
|
|
1954
|
+
const view = { runId, through, writer };
|
|
1955
|
+
|
|
1956
|
+
verifiedEmpty = view;
|
|
1957
|
+
|
|
1958
|
+
return body.pipe(
|
|
1959
|
+
Effect.ensuring(
|
|
1960
|
+
Effect.sync(() => {
|
|
1961
|
+
if (verifiedEmpty === view) verifiedEmpty = undefined;
|
|
1962
|
+
}),
|
|
1963
|
+
),
|
|
1964
|
+
);
|
|
1965
|
+
}),
|
|
1915
1966
|
stageUsage: (runId: RunId, bytes: number) => {
|
|
1916
1967
|
if (bytes === 0) stagedUsage.delete(runId);
|
|
1917
1968
|
else stagedUsage.set(runId, bytes);
|
|
@@ -13,7 +13,7 @@ import { type ExhaustedLimit } from "../core/RunEvent.ts";
|
|
|
13
13
|
import { RunPolicyUsage } from "../core/RunPolicyUsage.ts";
|
|
14
14
|
import { type Selection, type Snapshot } from "../core/ToolExposure.ts";
|
|
15
15
|
import type { ToolParameterRejection } from "../core/ToolResult.ts";
|
|
16
|
-
import { ModelCallUsage, summarizeModelUsage, type RunUsageSummary } from "../core/Usage.ts";
|
|
16
|
+
import { type ModelCallUsage, summarizeModelUsage, type RunUsageSummary } from "../core/Usage.ts";
|
|
17
17
|
import type { WorkerRef } from "../core/Worker.ts";
|
|
18
18
|
import {
|
|
19
19
|
CLEARED_TOOL_RESULT,
|
|
@@ -436,6 +436,36 @@ export interface RunJournalProjection {
|
|
|
436
436
|
readonly pendingContextToolCallId?: string | undefined;
|
|
437
437
|
}
|
|
438
438
|
|
|
439
|
+
const initialPolicyUsage = () => ({
|
|
440
|
+
committedTurns: 0,
|
|
441
|
+
toolCalls: 0,
|
|
442
|
+
programmaticToolCalls: 0,
|
|
443
|
+
consecutiveToolFailures: 0,
|
|
444
|
+
finalizationUsed: false,
|
|
445
|
+
modelRestarts: 0,
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
const initialUsage = (modelUsage: Array<ModelCallUsage>) => ({
|
|
449
|
+
modelCalls: 0,
|
|
450
|
+
inputTokens: 0,
|
|
451
|
+
outputTokens: 0,
|
|
452
|
+
lastInputTokens: 0,
|
|
453
|
+
lastOutputTokens: 0,
|
|
454
|
+
costMicrousd: 0,
|
|
455
|
+
modelUsage,
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
/** Internal first-Run projection after exact input/checkpoint-absence verification. The
|
|
459
|
+
* new UserInputRecorded contributes no model message; the engine evaluates it later. */
|
|
460
|
+
export const initialRunJournal = (history: Prompt.Prompt): RunJournalProjection => ({
|
|
461
|
+
policyUsage: RunPolicyUsage.make(initialPolicyUsage()),
|
|
462
|
+
usage: initialUsage([]),
|
|
463
|
+
prompt: history,
|
|
464
|
+
historyBefore: history,
|
|
465
|
+
historyFrom: CanonicalSequence.make(1),
|
|
466
|
+
committedTurns: 0,
|
|
467
|
+
});
|
|
468
|
+
|
|
439
469
|
interface ProjectedResponseUsage {
|
|
440
470
|
readonly modelCalls: number;
|
|
441
471
|
readonly inputTokens: number;
|
|
@@ -1050,15 +1080,7 @@ export const projectRunJournalStream = Effect.fnUntraced(function* <
|
|
|
1050
1080
|
const modelUsage: Array<ModelCallUsage> = [];
|
|
1051
1081
|
let unobservedModelCalls = 0;
|
|
1052
1082
|
|
|
1053
|
-
const usage =
|
|
1054
|
-
modelCalls: 0,
|
|
1055
|
-
inputTokens: 0,
|
|
1056
|
-
outputTokens: 0,
|
|
1057
|
-
lastInputTokens: 0,
|
|
1058
|
-
lastOutputTokens: 0,
|
|
1059
|
-
costMicrousd: 0,
|
|
1060
|
-
modelUsage,
|
|
1061
|
-
};
|
|
1083
|
+
const usage = initialUsage(modelUsage);
|
|
1062
1084
|
|
|
1063
1085
|
let toolSelection: Selection | undefined;
|
|
1064
1086
|
let usageTurn = 0;
|
|
@@ -1080,14 +1102,7 @@ export const projectRunJournalStream = Effect.fnUntraced(function* <
|
|
|
1080
1102
|
let pendingContextToolCallId: string | undefined;
|
|
1081
1103
|
let ownerTerminated = false;
|
|
1082
1104
|
|
|
1083
|
-
const policyUsage =
|
|
1084
|
-
committedTurns: 0,
|
|
1085
|
-
toolCalls: 0,
|
|
1086
|
-
programmaticToolCalls: 0,
|
|
1087
|
-
consecutiveToolFailures: 0,
|
|
1088
|
-
finalizationUsed: false,
|
|
1089
|
-
modelRestarts: 0,
|
|
1090
|
-
};
|
|
1105
|
+
const policyUsage = initialPolicyUsage();
|
|
1091
1106
|
|
|
1092
1107
|
const accountResponse = Effect.fnUntraced(function* (
|
|
1093
1108
|
envelope: JournalRecordEnvelope,
|
|
@@ -1639,18 +1654,6 @@ export const promptFromCanonicalRecords = (
|
|
|
1639
1654
|
);
|
|
1640
1655
|
|
|
1641
1656
|
/** Everything one committed Turn contributes to its canonical batch. */
|
|
1642
|
-
/**
|
|
1643
|
-
* Staged usage is validated, never repaired: clamping negatives or truncating
|
|
1644
|
-
* fractions would under-record canonical usage, and NaN/Infinity must fail
|
|
1645
|
-
* typed instead of escaping as a record-construction defect (RUN-023).
|
|
1646
|
-
*/
|
|
1647
|
-
const validStagedUsage = (label: string, value: number): Effect.Effect<number, RunJournalError> =>
|
|
1648
|
-
Number.isSafeInteger(value) && value >= 0
|
|
1649
|
-
? Effect.succeed(value)
|
|
1650
|
-
: Effect.fail(
|
|
1651
|
-
journalError(`Staged ${label} must be a non-negative safe integer, got ${String(value)}`),
|
|
1652
|
-
);
|
|
1653
|
-
|
|
1654
1657
|
export interface TurnCommitInput {
|
|
1655
1658
|
readonly toolResultMaxBytes?: number | undefined;
|
|
1656
1659
|
readonly toolSelectionMaxBytes?: number | undefined;
|
|
@@ -1695,8 +1698,9 @@ export interface TurnCommitInput {
|
|
|
1695
1698
|
}
|
|
1696
1699
|
|
|
1697
1700
|
const decodePersistedJson = Schema.decodeUnknownEffect(PersistedJson);
|
|
1701
|
+
const decodeModelResponse = Schema.decodeUnknownEffect(ModelResponseRecorded);
|
|
1702
|
+
const decodeToolSettled = Schema.decodeUnknownEffect(ToolCallSettled);
|
|
1698
1703
|
const encodePrompt = Schema.encodeEffect(Prompt.Prompt);
|
|
1699
|
-
const decodeModelUsage = Schema.decodeUnknownEffect(Schema.Array(ModelCallUsage));
|
|
1700
1704
|
|
|
1701
1705
|
const requireCanonicalTurn = (turn: number): Effect.Effect<void, RunJournalError> =>
|
|
1702
1706
|
!Number.isInteger(turn) || turn <= 0
|
|
@@ -1742,30 +1746,60 @@ const modelResponseRecord = Effect.fnUntraced(function* (
|
|
|
1742
1746
|
),
|
|
1743
1747
|
);
|
|
1744
1748
|
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
? undefined
|
|
1748
|
-
: yield* decodeModelUsage(input.usage.modelUsage).pipe(
|
|
1749
|
-
Effect.mapError((cause) => journalError("Turn model usage failed to decode", cause)),
|
|
1750
|
-
);
|
|
1749
|
+
// Validate the detached messages and usage together; no mutable caller data is trusted.
|
|
1750
|
+
const modelUsage = input.usage?.modelUsage;
|
|
1751
1751
|
|
|
1752
|
-
|
|
1753
|
-
|
|
1752
|
+
const payload = yield* decodeModelResponse({
|
|
1753
|
+
_tag: "ModelResponseRecorded",
|
|
1754
|
+
toolResultMaxBytes: input.toolResultMaxBytes ?? MAX_PERSISTED_JSON_BYTES,
|
|
1755
|
+
toolSelectionMaxBytes: input.toolSelectionMaxBytes ?? 0,
|
|
1756
|
+
toolOperations: input.toolOperations ?? [],
|
|
1757
|
+
...(input.toolParameterRejections === undefined || input.toolParameterRejections.length === 0
|
|
1758
|
+
? {}
|
|
1759
|
+
: { toolParameterRejections: input.toolParameterRejections }),
|
|
1760
|
+
...(input.toolExposure === undefined ? {} : { toolExposure: input.toolExposure }),
|
|
1761
|
+
runId: input.runId,
|
|
1762
|
+
turnId: input.turnId,
|
|
1763
|
+
turn: input.turn,
|
|
1764
|
+
messages,
|
|
1765
|
+
...(runScopedPrefixLength === undefined ? {} : { runScopedPrefixLength }),
|
|
1766
|
+
...(modelUsage === undefined ? {} : { modelUsage }),
|
|
1767
|
+
...(input.unobservedModelCalls === undefined || input.unobservedModelCalls === 0
|
|
1768
|
+
? {}
|
|
1769
|
+
: {
|
|
1770
|
+
unobservedModelCalls: input.unobservedModelCalls,
|
|
1771
|
+
}),
|
|
1772
|
+
...(input.usage === undefined
|
|
1773
|
+
? {}
|
|
1774
|
+
: {
|
|
1775
|
+
inputTokens: input.usage.inputTokens,
|
|
1776
|
+
outputTokens: input.usage.outputTokens,
|
|
1777
|
+
// Written only when non-zero: absent re-seeds as zero, so the
|
|
1778
|
+
// no-estimator case stays byte-identical to pre-cost histories.
|
|
1779
|
+
...(input.usage.costMicrousd === undefined || input.usage.costMicrousd === 0
|
|
1780
|
+
? {}
|
|
1781
|
+
: {
|
|
1782
|
+
costMicrousd: input.usage.costMicrousd,
|
|
1783
|
+
}),
|
|
1784
|
+
}),
|
|
1785
|
+
}).pipe(
|
|
1786
|
+
Effect.mapError((cause) => journalError("Invalid model response operation evidence", cause)),
|
|
1787
|
+
);
|
|
1788
|
+
|
|
1789
|
+
if (payload.modelUsage !== undefined) {
|
|
1790
|
+
if (payload.modelUsage.length === 0)
|
|
1754
1791
|
return yield* journalError("Turn model usage must contain at least one completed call");
|
|
1755
|
-
}
|
|
1756
1792
|
|
|
1757
|
-
const summary = yield* continuationUsage(modelUsage).pipe(
|
|
1793
|
+
const summary = yield* continuationUsage(payload.modelUsage).pipe(
|
|
1758
1794
|
Effect.mapError((cause) => journalError("Turn model usage exceeds accounting bounds", cause)),
|
|
1759
1795
|
);
|
|
1760
1796
|
|
|
1761
1797
|
if (
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
) {
|
|
1798
|
+
payload.inputTokens !== summary.inputTokens ||
|
|
1799
|
+
payload.outputTokens !== summary.outputTokens ||
|
|
1800
|
+
(payload.costMicrousd ?? 0) !== summary.costMicrousd
|
|
1801
|
+
)
|
|
1767
1802
|
return yield* journalError("Turn detailed and aggregate model usage disagree");
|
|
1768
|
-
}
|
|
1769
1803
|
}
|
|
1770
1804
|
|
|
1771
1805
|
return RecordEnvelope.make({
|
|
@@ -1774,44 +1808,7 @@ const modelResponseRecord = Effect.fnUntraced(function* (
|
|
|
1774
1808
|
schemaVersion: 1,
|
|
1775
1809
|
createdAt: input.createdAt,
|
|
1776
1810
|
deploymentId: input.deploymentId,
|
|
1777
|
-
payload
|
|
1778
|
-
toolResultMaxBytes: input.toolResultMaxBytes ?? MAX_PERSISTED_JSON_BYTES,
|
|
1779
|
-
toolSelectionMaxBytes: input.toolSelectionMaxBytes ?? 0,
|
|
1780
|
-
toolOperations: input.toolOperations ?? [],
|
|
1781
|
-
...(input.toolParameterRejections === undefined || input.toolParameterRejections.length === 0
|
|
1782
|
-
? {}
|
|
1783
|
-
: { toolParameterRejections: input.toolParameterRejections }),
|
|
1784
|
-
...(input.toolExposure === undefined ? {} : { toolExposure: input.toolExposure }),
|
|
1785
|
-
runId: input.runId,
|
|
1786
|
-
turnId: input.turnId,
|
|
1787
|
-
turn: input.turn,
|
|
1788
|
-
messages,
|
|
1789
|
-
...(runScopedPrefixLength === undefined ? {} : { runScopedPrefixLength }),
|
|
1790
|
-
...(modelUsage === undefined ? {} : { modelUsage }),
|
|
1791
|
-
...(input.unobservedModelCalls === undefined || input.unobservedModelCalls === 0
|
|
1792
|
-
? {}
|
|
1793
|
-
: {
|
|
1794
|
-
unobservedModelCalls: yield* validStagedUsage(
|
|
1795
|
-
"unobservedModelCalls",
|
|
1796
|
-
input.unobservedModelCalls,
|
|
1797
|
-
),
|
|
1798
|
-
}),
|
|
1799
|
-
...(input.usage === undefined
|
|
1800
|
-
? {}
|
|
1801
|
-
: {
|
|
1802
|
-
inputTokens: yield* validStagedUsage("inputTokens", input.usage.inputTokens),
|
|
1803
|
-
outputTokens: yield* validStagedUsage("outputTokens", input.usage.outputTokens),
|
|
1804
|
-
// Written only when non-zero: absent re-seeds as zero, so the
|
|
1805
|
-
// no-estimator case stays byte-identical to pre-cost histories.
|
|
1806
|
-
...(input.usage.costMicrousd === undefined || input.usage.costMicrousd === 0
|
|
1807
|
-
? {}
|
|
1808
|
-
: {
|
|
1809
|
-
costMicrousd: yield* validStagedUsage("costMicrousd", input.usage.costMicrousd),
|
|
1810
|
-
}),
|
|
1811
|
-
}),
|
|
1812
|
-
}).pipe(
|
|
1813
|
-
Effect.mapError((cause) => journalError("Invalid model response operation evidence", cause)),
|
|
1814
|
-
),
|
|
1811
|
+
payload,
|
|
1815
1812
|
});
|
|
1816
1813
|
});
|
|
1817
1814
|
|
|
@@ -1821,33 +1818,27 @@ const toolSettledRecords = Effect.fnUntraced(function* (
|
|
|
1821
1818
|
const toolRecords: Array<RecordEnvelope> = [];
|
|
1822
1819
|
|
|
1823
1820
|
for (const part of input.toolResults) {
|
|
1824
|
-
const
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1821
|
+
const payload = yield* decodeToolSettled({
|
|
1822
|
+
_tag: "ToolCallSettled",
|
|
1823
|
+
...(part.toolSelection === undefined ? {} : { toolSelection: part.toolSelection }),
|
|
1824
|
+
runId: input.runId,
|
|
1825
|
+
toolCallId: part.toolCallId,
|
|
1826
|
+
toolName: part.toolName,
|
|
1827
|
+
result: part.result,
|
|
1828
|
+
isFailure: part.isFailure,
|
|
1829
|
+
...(part.budgetRejected === true ? { budgetRejected: true } : {}),
|
|
1830
|
+
}).pipe(
|
|
1831
|
+
Effect.mapError((cause) => journalError(`Invalid Tool result ${part.toolCallId}`, cause)),
|
|
1828
1832
|
);
|
|
1829
1833
|
|
|
1830
|
-
const toolCallId = yield* Effect.try({
|
|
1831
|
-
try: () => decodeToolCallId(part.toolCallId),
|
|
1832
|
-
catch: (cause) => journalError(`Invalid Tool Call ID ${part.toolCallId}`, cause),
|
|
1833
|
-
});
|
|
1834
|
-
|
|
1835
1834
|
toolRecords.push(
|
|
1836
1835
|
RecordEnvelope.make({
|
|
1837
|
-
recordId: toolCallSettledRecordId(input.runId, input.turn, toolCallId),
|
|
1836
|
+
recordId: toolCallSettledRecordId(input.runId, input.turn, payload.toolCallId),
|
|
1838
1837
|
family: "thread",
|
|
1839
1838
|
schemaVersion: 1,
|
|
1840
1839
|
createdAt: input.createdAt,
|
|
1841
1840
|
deploymentId: input.deploymentId,
|
|
1842
|
-
payload
|
|
1843
|
-
...(part.toolSelection === undefined ? {} : { toolSelection: part.toolSelection }),
|
|
1844
|
-
runId: input.runId,
|
|
1845
|
-
toolCallId,
|
|
1846
|
-
toolName: part.toolName,
|
|
1847
|
-
result,
|
|
1848
|
-
isFailure: part.isFailure,
|
|
1849
|
-
...(part.budgetRejected === true ? { budgetRejected: true } : {}),
|
|
1850
|
-
}),
|
|
1841
|
+
payload,
|
|
1851
1842
|
}),
|
|
1852
1843
|
);
|
|
1853
1844
|
}
|
|
@@ -1855,7 +1846,7 @@ const toolSettledRecords = Effect.fnUntraced(function* (
|
|
|
1855
1846
|
return toolRecords;
|
|
1856
1847
|
});
|
|
1857
1848
|
|
|
1858
|
-
const runCompletionRecord =
|
|
1849
|
+
const runCompletionRecord = (input: TurnCommitInput) => {
|
|
1859
1850
|
if (input.runCompletion === undefined) return undefined;
|
|
1860
1851
|
const completion = { runId: input.runId, ...input.runCompletion };
|
|
1861
1852
|
|
|
@@ -1869,7 +1860,7 @@ const runCompletionRecord = Effect.fnUntraced(function* (input: TurnCommitInput)
|
|
|
1869
1860
|
...completion,
|
|
1870
1861
|
}),
|
|
1871
1862
|
});
|
|
1872
|
-
}
|
|
1863
|
+
};
|
|
1873
1864
|
|
|
1874
1865
|
/**
|
|
1875
1866
|
* Build a canonical batch from interpreter-validated Turn facts: one
|
|
@@ -1887,7 +1878,7 @@ export const turnCanonicalBatch = Effect.fnUntraced(function* (
|
|
|
1887
1878
|
yield* requireCanonicalTurn(input.turn);
|
|
1888
1879
|
const modelResponse = yield* modelResponseRecord(input);
|
|
1889
1880
|
const toolRecords = yield* toolSettledRecords(input);
|
|
1890
|
-
const completionRecord =
|
|
1881
|
+
const completionRecord = runCompletionRecord(input);
|
|
1891
1882
|
|
|
1892
1883
|
return CanonicalBatch.make({
|
|
1893
1884
|
batchId: turnBatchId(input.runId, input.turn),
|
|
@@ -1931,7 +1922,7 @@ export const turnResultsBatch = Effect.fnUntraced(function* (
|
|
|
1931
1922
|
yield* requireCanonicalTurn(input.turn);
|
|
1932
1923
|
const toolRecords = yield* toolSettledRecords(input);
|
|
1933
1924
|
const first = toolRecords[0];
|
|
1934
|
-
const completionRecord =
|
|
1925
|
+
const completionRecord = runCompletionRecord(input);
|
|
1935
1926
|
|
|
1936
1927
|
if (first === undefined) {
|
|
1937
1928
|
if (completionRecord === undefined) {
|
|
@@ -113,6 +113,11 @@ export interface RunWriter {
|
|
|
113
113
|
|
|
114
114
|
export interface RunStorageSession extends RunWriter, RunOwnership {
|
|
115
115
|
readonly claim: Claim;
|
|
116
|
+
/** Library-only initialization, before application/model IO. Hold progress before mutation
|
|
117
|
+
* so the captured controls and this owner's acknowledged input remain one read view. */
|
|
118
|
+
readonly withInitialization?: <A, E, R>(
|
|
119
|
+
effect: Effect.Effect<A, E, R>,
|
|
120
|
+
) => Effect.Effect<A, E | OwnershipLost, R>;
|
|
116
121
|
readonly refresh: Effect.Effect<void, ThreadStoreFailure>;
|
|
117
122
|
readonly publishSettlement: (
|
|
118
123
|
batch: CanonicalBatch,
|
|
@@ -316,6 +321,8 @@ export const make = Effect.gen(function* () {
|
|
|
316
321
|
const session: RunStorageSession = {
|
|
317
322
|
...writer,
|
|
318
323
|
claim: claimed,
|
|
324
|
+
withInitialization: (effect) =>
|
|
325
|
+
owner.withProgress(request.threadId, generation.use(effect)),
|
|
319
326
|
release: generation.release,
|
|
320
327
|
refresh: writer.refresh,
|
|
321
328
|
markInputApplied: (marker) =>
|