effect-agent 0.1.0-beta.160 → 0.1.0-beta.161

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.
@@ -90,15 +90,16 @@ var RecoveryCheckpointContents = class extends Schema.Class("@effect-agent/threa
90
90
  state: RecoveryCheckpointState,
91
91
  digest: Digest
92
92
  }) {};
93
- const RECOVERY_ENGINE_VERSION = "effect-agent/recovery@3";
93
+ const RECOVERY_ENGINE_VERSION = "effect-agent/recovery@4";
94
94
  /**
95
95
  * Prove that indexed original-input absence also means absent prefix Run/control evidence.
96
- * Only cache consumers with colon-free Submission IDs use this certificate. For those IDs,
97
- * every possible control marker is exactly :run:<submission-id>:. Parsing here can only decline
98
- * caching; it never supplies an execution identity. Separator-bearing identities use full replay.
96
+ * A certificate covers only Run IDs with the given length. Every possible control marker for
97
+ * those IDs is exactly :<run-id>:, including markers nested inside opaque IDs. Cache consumers
98
+ * must have the checkpoint owner's ID length; shorter/longer aliases require full replay.
99
+ * Parsing here can only decline caching; it never supplies an execution identity.
99
100
  * The temporary anchor set is discarded after certification, not persisted with the context.
100
101
  */
101
- const makeThreadContextCertificate = () => {
102
+ const makeThreadContextCertificate = (runIdLength) => {
102
103
  const anchored = /* @__PURE__ */ new Set();
103
104
  let valid = true;
104
105
  return {
@@ -114,8 +115,8 @@ const makeThreadContextCertificate = () => {
114
115
  if (originalInput) anchored.add(payload.runId);
115
116
  }
116
117
  for (let start = record.recordId.indexOf(":run:"); start !== -1; start = record.recordId.indexOf(":run:", start + 1)) {
117
- const end = record.recordId.indexOf(":", start + 5);
118
- if (end !== -1 && !anchored.has(record.recordId.slice(start + 1, end))) {
118
+ const end = start + 1 + runIdLength;
119
+ if (record.recordId[end] === ":" && !anchored.has(record.recordId.slice(start + 1, end))) {
119
120
  valid = false;
120
121
  return;
121
122
  }
@@ -2547,7 +2548,7 @@ const make = Effect.fn("DurableAgentRuntime.make")(function* (bindings) {
2547
2548
  })).pipe(Effect.catchTag("CheckpointRejected", () => Effect.succeed(Option.none())));
2548
2549
  if (Option.isNone(loaded)) return Option.none();
2549
2550
  const checkpoint = loaded.value;
2550
- if (checkpoint.engineVersion !== "effect-agent/recovery@3" || checkpoint.threadId !== threadId || checkpoint.throughSequence > throughSequence) return Option.none();
2551
+ if (checkpoint.engineVersion !== "effect-agent/recovery@4" || checkpoint.threadId !== threadId || checkpoint.throughSequence > throughSequence) return Option.none();
2551
2552
  const decoded = yield* Schema.decodeUnknownEffect(RecoveryCheckpointContents)(checkpoint.state).pipe(Effect.option);
2552
2553
  if (Option.isNone(decoded)) return Option.none();
2553
2554
  const { state, digest } = decoded.value;
@@ -2581,7 +2582,7 @@ const make = Effect.fn("DurableAgentRuntime.make")(function* (bindings) {
2581
2582
  /** Late/foreign evidence and new compactions require the original canonical proof. */
2582
2583
  const contextSuffixCompatible = (records, submissionId) => {
2583
2584
  const runId = runIdForSubmission(submissionId);
2584
- const certificate = makeThreadContextCertificate();
2585
+ const certificate = makeThreadContextCertificate(runId.length);
2585
2586
  for (const entry of records) {
2586
2587
  const { payload, recordId } = entry.record;
2587
2588
  if (payload._tag === "CompactionCreated" || retainThreadIdentity(entry)) return false;
@@ -2604,7 +2605,7 @@ const make = Effect.fn("DurableAgentRuntime.make")(function* (bindings) {
2604
2605
  const { checkpoint, state } = loaded.value;
2605
2606
  if (throughSequence - checkpoint.throughSequence > 4096) return full;
2606
2607
  const submissionId = submissionIds.length === 1 ? submissionIds[0] : void 0;
2607
- if (state.context !== void 0 && submissionId !== void 0 && !submissionId.includes(":") && (journalOwner === void 0 || journalOwner === runIdForSubmission(submissionId))) {
2608
+ if (state.context !== void 0 && submissionId !== void 0 && submissionId.length === state.submissionId.length && (journalOwner === void 0 || journalOwner === runIdForSubmission(submissionId))) {
2608
2609
  const runId = runIdForSubmission(submissionId);
2609
2610
  if ([yield* getRunInput({
2610
2611
  threadId,
@@ -2636,16 +2637,17 @@ const make = Effect.fn("DurableAgentRuntime.make")(function* (bindings) {
2636
2637
  seed: state.seed
2637
2638
  };
2638
2639
  });
2639
- const persistRecoveryCheckpoint = Effect.fn("DurableAgentRuntime.persistRecoveryCheckpoint")(function* (ctx, submission, state, tail, createdAt) {
2640
- if (store.recoveryCheckpoints === void 0) return;
2640
+ const encodeRecoveryCheckpoint = Effect.fnUntraced(function* (state) {
2641
2641
  const encoded = yield* Schema.encodeEffect(RecoveryCheckpointState)(state).pipe(Effect.option);
2642
- if (Option.isNone(encoded)) return;
2642
+ if (Option.isNone(encoded)) return Option.none();
2643
2643
  const digest = yield* withCrypto(digestJson(encoded.value));
2644
- const contents = yield* Schema.encodeEffect(Schema.fromJsonString(RecoveryCheckpointContents))(RecoveryCheckpointContents.make({
2644
+ return yield* Schema.encodeEffect(Schema.fromJsonString(RecoveryCheckpointContents))(RecoveryCheckpointContents.make({
2645
2645
  state,
2646
2646
  digest
2647
2647
  })).pipe(Effect.flatMap(Schema.decodeUnknownEffect(Schema.fromJsonString(PersistedJson))), Effect.option);
2648
- if (Option.isNone(contents)) return;
2648
+ });
2649
+ const persistRecoveryCheckpoint = Effect.fn("DurableAgentRuntime.persistRecoveryCheckpoint")(function* (ctx, submission, contents, tail, createdAt) {
2650
+ if (store.recoveryCheckpoints === void 0) return;
2649
2651
  const checkpoint = ThreadCheckpoint.make({
2650
2652
  schemaVersion: 1,
2651
2653
  threadId: ctx.threadId,
@@ -2655,7 +2657,7 @@ const make = Effect.fn("DurableAgentRuntime.make")(function* (bindings) {
2655
2657
  agentDefinitionDigest: submission.agentDigests.agent,
2656
2658
  modelDigest: submission.agentDigests.model,
2657
2659
  toolDigest: submission.agentDigests.tools,
2658
- state: contents.value,
2660
+ state: contents,
2659
2661
  createdAt
2660
2662
  });
2661
2663
  yield* hit("checkpoint:before-save");
@@ -2680,7 +2682,7 @@ const make = Effect.fn("DurableAgentRuntime.make")(function* (bindings) {
2680
2682
  }
2681
2683
  if (projection === void 0) {
2682
2684
  const source = canonicalRange(ctx.threadId, tail.sequence);
2683
- const certificate = makeThreadContextCertificate();
2685
+ const certificate = makeThreadContextCertificate(runIdForSubmission(submission.submissionId).length);
2684
2686
  const metadata = makeJournalMetadata(void 0);
2685
2687
  const retained = [];
2686
2688
  yield* Stream.runForEach(source, (entry) => Effect.sync(() => {
@@ -2695,30 +2697,32 @@ const make = Effect.fn("DurableAgentRuntime.make")(function* (bindings) {
2695
2697
  if (projection === void 0) return;
2696
2698
  const prompt = yield* Schema.encodeEffect(Prompt.Prompt)(projection.prompt).pipe(Effect.flatMap(decodePersisted), Effect.option);
2697
2699
  if (Option.isNone(prompt)) return;
2698
- let seed;
2699
- let records = identities;
2700
- let submissionIds = [submission.submissionId];
2701
- if (previous.state.submissionId === submission.submissionId && previous.state.seed !== void 0 && tail.sequence - previous.checkpoint.throughSequence + previous.state.records.length <= 4096) {
2702
- const suffix = yield* Stream.runCollect(canonicalRange(ctx.threadId, tail.sequence, previous.checkpoint.throughSequence));
2703
- if (checkpointSuffixCompatible(previous.state.seed, suffix, previous.state.records)) {
2704
- seed = previous.state.seed;
2705
- records = [...previous.state.records, ...suffix];
2706
- submissionIds = previous.state.submissionIds;
2707
- }
2708
- }
2709
- yield* persistRecoveryCheckpoint(ctx, submission, RecoveryCheckpointState.make({
2700
+ const contextState = RecoveryCheckpointState.make({
2710
2701
  schemaVersion: 2,
2711
2702
  policyAccountingVersion: 1,
2712
2703
  submissionId: submission.submissionId,
2713
- submissionIds,
2714
- ...seed === void 0 ? {} : { seed },
2704
+ submissionIds: [submission.submissionId],
2715
2705
  context: ThreadContextCheckpoint.make({
2716
2706
  throughSequence: tail.sequence,
2717
2707
  prompt: prompt.value,
2718
2708
  ...projection.contextWindowId === void 0 ? {} : { contextWindowId: projection.contextWindowId }
2719
2709
  }),
2720
- records
2721
- }), tail, yield* DateTime.now);
2710
+ records: identities
2711
+ });
2712
+ let state = contextState;
2713
+ if (previous.state.submissionId === submission.submissionId && previous.state.seed !== void 0 && tail.sequence - previous.checkpoint.throughSequence + previous.state.records.length <= 4096) {
2714
+ const suffix = yield* Stream.runCollect(canonicalRange(ctx.threadId, tail.sequence, previous.checkpoint.throughSequence));
2715
+ if (checkpointSuffixCompatible(previous.state.seed, suffix, previous.state.records)) state = RecoveryCheckpointState.make({
2716
+ ...contextState,
2717
+ seed: previous.state.seed,
2718
+ records: [...previous.state.records, ...suffix],
2719
+ submissionIds: previous.state.submissionIds
2720
+ });
2721
+ }
2722
+ let contents = yield* encodeRecoveryCheckpoint(state);
2723
+ if (Option.isNone(contents) && state.seed !== void 0) contents = yield* encodeRecoveryCheckpoint(contextState);
2724
+ if (Option.isNone(contents)) return;
2725
+ yield* persistRecoveryCheckpoint(ctx, submission, contents.value, tail, yield* DateTime.now);
2722
2726
  });
2723
2727
  const readAllTolerant = Effect.fn("DurableAgentRuntime.readAllTolerant")((threadId, submissionIds) => readControl(threadId, submissionIds).pipe(Effect.map((records) => ({
2724
2728
  records,
@@ -4451,7 +4455,9 @@ const make = Effect.fn("DurableAgentRuntime.make")(function* (bindings) {
4451
4455
  ].some((field) => current.usage[field] !== candidate.usage[field]) || (current.usage.unobservedModelCalls ?? 0) !== (candidate.usage.unobservedModelCalls ?? 0)) return;
4452
4456
  const summaries = yield* Effect.forEach([current, candidate], (projection) => summarizeModelUsage(projection.usage.modelUsage, projection.usage.summarizedModelUsage)).pipe(Effect.option);
4453
4457
  if (Option.isNone(summaries) || summaries.value[0] === void 0 || summaries.value[1] === void 0 || !Schema.toEquivalence(RunUsageSummary)(summaries.value[0], summaries.value[1])) return;
4454
- yield* persistRecoveryCheckpoint(ctx, submission, validated.value, tail, replacement.record.createdAt);
4458
+ const contents = yield* encodeRecoveryCheckpoint(validated.value);
4459
+ if (Option.isNone(contents)) return;
4460
+ yield* persistRecoveryCheckpoint(ctx, submission, contents.value, tail, replacement.record.createdAt);
4455
4461
  });
4456
4462
  const childLineage = records.find(({ record }) => record.recordId === subagentLineageRecordId(submission.threadId))?.record.payload;
4457
4463
  const inheritedGrant = submission.workerAdmission?.origin.grant ?? (childLineage?._tag === "SubagentLineageRecorded" ? childLineage.grant : void 0);
@@ -7504,4 +7510,4 @@ var DurableAgentRuntime = class DurableAgentRuntime extends Context.Service()("@
7504
7510
  //#endregion
7505
7511
  export { DurableApprovalSuspension as a, RecoveryFailure as c, childReservationIdFor as d, isolateRecovery as f, DurableApprovalResolver as i, RecoveryReport as l, recoveryRepairRecordId as m, DurableAgentRuntime as n, DurableRuntimeConfig as o, recoveryRepairBatchId as p, DurableAgentRuntime_exports as r, RecoveryBlocked as s, ApprovalSuspensionError as t, RecoverySweepResult as u };
7506
7512
 
7507
- //# sourceMappingURL=DurableAgentRuntime-pr7cCaZw.mjs.map
7513
+ //# sourceMappingURL=DurableAgentRuntime-BpB5rBcu.mjs.map