@orkestrel/agent 0.0.37 → 0.0.38

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.
@@ -5349,14 +5349,19 @@ export declare function createThinkSplitter(): ThinkSplitterInterface;
5349
5349
  * Cuts entries to a room and names how many it left out.
5350
5350
  *
5351
5351
  * @remarks
5352
- * The cut keeps at least one entry. When it leaves entries out, its last line reads
5352
+ * By default the cut keeps at least one entry. With `first: false`, it keeps whole entries only
5353
+ * when the joined result, tool framing, and omission line fit, and considers later entries after
5354
+ * an oversized group. When it leaves some entries out, its last line reads
5353
5355
  * `N older items not shown; name a narrower topic to narrow the recall`, which
5354
5356
  * {@link matchesCutLine} recognizes. Pass `more` when the entries aren't in age order, so the line
5355
- * doesn't claim an omitted entry is older than a kept one.
5357
+ * doesn't claim an omitted entry is older than a kept one. A fitted cut also uses `more` when it
5358
+ * skips an entry before a kept one. With no kept entry it reads
5359
+ * `N older items didn't fit in this request; answer from the messages you can see`.
5356
5360
  *
5357
5361
  * @param entries - The entries in the order they are kept
5358
5362
  * @param room - The estimate units the joined entries can take
5359
5363
  * @param kind - What the cut line calls an omitted entry. Default: `older`
5364
+ * @param first - If `true`, keeps the first entry regardless of room; if `false`, fits every entry and the omission line. Default: `true`
5360
5365
  * @returns The kept entries followed by the cut line when any were left out, joined by newlines
5361
5366
  *
5362
5367
  * @example
@@ -5364,7 +5369,7 @@ export declare function createThinkSplitter(): ThinkSplitterInterface;
5364
5369
  * cutListing(['first entry', 'second entry'], 1) // 'first entry\n1 older item not shown; name a narrower topic to narrow the recall'
5365
5370
  * ```
5366
5371
  */
5367
- export declare function cutListing(entries: readonly string[], room: number, kind?: 'older' | 'more'): string;
5372
+ export declare function cutListing(entries: readonly string[], room: number, kind?: 'older' | 'more', first?: boolean): string;
5368
5373
 
5369
5374
  /**
5370
5375
  * Backs a {@link ConversationStoreInterface} with one table of the `databases` layer — a
@@ -6091,8 +6096,12 @@ export declare interface GaugeInterface extends LedgerGauge {
6091
6096
  * `max(0, overhead - (spared ?? 0)) + scale * estimate`.
6092
6097
  * Capacity left is `max(0, capacity - used)`. The reply reserve adds recall uniform at the marginal
6093
6098
  * rate to the largest observed reply's `completion - (thinking ?? 0)` for every policy.
6094
- * Without a positive reply observation, it prices the longest reply text at that rate. Recall room is
6095
- * `max(0, (remainder - predict - reserve) / 2 / rate)`; recall closes at `remainder - predict < 2 * reserve`.
6099
+ * Without a positive reply observation, it prices the longest reply text at that rate. The room formula
6100
+ * `max(0, (remainder - predict - reserve) / 2 / rate)` is the planning forecast. The ledger's runtime
6101
+ * recall instead fits results below `capacity - predict`, anchoring the prefix to reported usage
6102
+ * and pricing additions at the larger of the marginal rate and the request's measured rate, with
6103
+ * `LEDGER_SCALE_DRIFT` headroom. The measured rate subtracts overhead only where `observe` would
6104
+ * rescale; partially spared calls retain the marginal rate. Missing usage uses an estimate.
6096
6105
  */
6097
6106
  export declare interface GaugeOptions extends LedgerGauge {
6098
6107
  readonly capacity: number;
@@ -8035,6 +8044,14 @@ export declare interface LedgerLine {
8035
8044
  readonly role: MessageRole;
8036
8045
  }
8037
8046
 
8047
+ /** Carries a recall result, its accepted whole groups, lookup line translations, and provider-turn position. */
8048
+ export declare interface LedgerListing {
8049
+ readonly result: string;
8050
+ readonly lines: ReadonlyMap<string, string>;
8051
+ readonly groups: readonly string[];
8052
+ readonly turn: number;
8053
+ }
8054
+
8038
8055
  /**
8039
8056
  * Carries one application lookup: the tool the model calls and the handler that reads its results.
8040
8057
  *
@@ -8134,7 +8151,10 @@ export declare interface LedgerOccurrence extends LedgerLine, LedgerReceipt {
8134
8151
  * nonnegative safe integer less than `capacity`; construction throws `LedgerError` with code
8135
8152
  * `'CAPACITY'` otherwise. The plan budgets
8136
8153
  * `max(0, (capacity - predict) * share.prompt - overhead) / (1 + LEDGER_SCALE_DRIFT)`.
8137
- * Recall closes when `remainder - predict < 2 * reserve`. `snapshot` hydrates the conversation and
8154
+ * The plan retains its `remainder - predict < 2 * reserve` admission rule. Runtime recall fits whole
8155
+ * results to measured remaining capacity at the larger of the gauge rate and the request's measured
8156
+ * rate, allowing `LEDGER_SCALE_DRIFT` for new text. Lack of room omits results without closing recall.
8157
+ * `snapshot` hydrates the conversation and
8138
8158
  * the marked ids a ledger's `snapshot()` returned; construction throws `LedgerError` with code
8139
8159
  * `'SNAPSHOT'` when `isLedgerSnapshot` refuses it, and `ConversationError` with code `'ROLE'` or
8140
8160
  * `'SNAPSHOT'` when its conversation holds a `system` message or repeats an id.
@@ -8273,6 +8293,12 @@ export declare interface LedgerRecord {
8273
8293
  readonly lines: readonly LedgerLine[];
8274
8294
  }
8275
8295
 
8296
+ /** Carries the answer note and the partial messages omitted from its prompt. */
8297
+ export declare interface LedgerRecovery {
8298
+ readonly digest: string | undefined;
8299
+ readonly omitted: ReadonlySet<string>;
8300
+ }
8301
+
8276
8302
  /**
8277
8303
  * Carries the ids the ledger's lookups named and the owners among them.
8278
8304
  *
@@ -8397,7 +8423,9 @@ export declare class LedgerRequest implements LedgerRequestInterface {
8397
8423
  admit(name: string, args: Readonly<Record<string, unknown>>): void;
8398
8424
  recall(): void;
8399
8425
  close(): void;
8400
- list(result: string, lines: ReadonlyMap<string, string>): void;
8426
+ list(result: string, lines: ReadonlyMap<string, string>, groups: readonly string[]): void;
8427
+ /** Returns recall results with their accepted whole groups and provider-turn positions. */
8428
+ get listings(): readonly LedgerListing[];
8401
8429
  lines(result: string): ReadonlyMap<string, string> | undefined;
8402
8430
  }
8403
8431
 
@@ -8517,8 +8545,11 @@ export declare interface LedgerRequestInterface {
8517
8545
  *
8518
8546
  * @param result - The recall result text
8519
8547
  * @param lines - Each listed lookup line mapped to the first line of its stored content
8548
+ * @param groups - The complete candidate groups, in listing order; only groups present in the result are retained
8520
8549
  */
8521
- list(result: string, lines: ReadonlyMap<string, string>): void;
8550
+ list(result: string, lines: ReadonlyMap<string, string>, groups: readonly string[]): void;
8551
+ /** Holds each recall result with its accepted groups and provider-turn position. */
8552
+ readonly listings: readonly LedgerListing[];
8522
8553
  /**
8523
8554
  * Returns the stored first lines a recall result listed.
8524
8555
  *
@@ -12496,6 +12527,7 @@ export declare type SystemOneEntry = JudgeEntry | null;
12496
12527
  *
12497
12528
  * @remarks
12498
12529
  * The caller supplies the server origin and model. Every question travels in one request.
12530
+ * Wire keys are zero-based positions in question entry order; answers return under the caller's ids.
12499
12531
  * Server measures are ignored; the response model is preserved.
12500
12532
  * `headers` supplies authentication through the shared judge engine.
12501
12533
  * The example readings are those of the response Ollama 0.40.0 returned for that request on 2026-10-07.
@@ -12546,14 +12578,14 @@ export declare class SystemOneJudge extends AgentJudge {
12546
12578
  /** Identifies the System One protocol. */
12547
12579
  readonly name = "systemone";
12548
12580
  /**
12549
- * Projects the state and questions onto the System One request with the configured model.
12581
+ * Projects the state and questions onto the System One request with the configured model and positional keys.
12550
12582
  *
12551
12583
  * @param request - The state and questions keyed by caller id
12552
12584
  * @returns The System One request body
12553
12585
  */
12554
12586
  encode(request: JudgeRequest): SystemOneRequest;
12555
12587
  /**
12556
- * Decodes requested System One answers and reports the server model and available usage.
12588
+ * Decodes positional System One answers under caller ids and reports the server model and available usage.
12557
12589
  *
12558
12590
  * @param value - The parsed response body
12559
12591
  * @param request - The questions defining the expected answers
@@ -5349,14 +5349,19 @@ export declare function createThinkSplitter(): ThinkSplitterInterface;
5349
5349
  * Cuts entries to a room and names how many it left out.
5350
5350
  *
5351
5351
  * @remarks
5352
- * The cut keeps at least one entry. When it leaves entries out, its last line reads
5352
+ * By default the cut keeps at least one entry. With `first: false`, it keeps whole entries only
5353
+ * when the joined result, tool framing, and omission line fit, and considers later entries after
5354
+ * an oversized group. When it leaves some entries out, its last line reads
5353
5355
  * `N older items not shown; name a narrower topic to narrow the recall`, which
5354
5356
  * {@link matchesCutLine} recognizes. Pass `more` when the entries aren't in age order, so the line
5355
- * doesn't claim an omitted entry is older than a kept one.
5357
+ * doesn't claim an omitted entry is older than a kept one. A fitted cut also uses `more` when it
5358
+ * skips an entry before a kept one. With no kept entry it reads
5359
+ * `N older items didn't fit in this request; answer from the messages you can see`.
5356
5360
  *
5357
5361
  * @param entries - The entries in the order they are kept
5358
5362
  * @param room - The estimate units the joined entries can take
5359
5363
  * @param kind - What the cut line calls an omitted entry. Default: `older`
5364
+ * @param first - If `true`, keeps the first entry regardless of room; if `false`, fits every entry and the omission line. Default: `true`
5360
5365
  * @returns The kept entries followed by the cut line when any were left out, joined by newlines
5361
5366
  *
5362
5367
  * @example
@@ -5364,7 +5369,7 @@ export declare function createThinkSplitter(): ThinkSplitterInterface;
5364
5369
  * cutListing(['first entry', 'second entry'], 1) // 'first entry\n1 older item not shown; name a narrower topic to narrow the recall'
5365
5370
  * ```
5366
5371
  */
5367
- export declare function cutListing(entries: readonly string[], room: number, kind?: 'older' | 'more'): string;
5372
+ export declare function cutListing(entries: readonly string[], room: number, kind?: 'older' | 'more', first?: boolean): string;
5368
5373
 
5369
5374
  /**
5370
5375
  * Backs a {@link ConversationStoreInterface} with one table of the `databases` layer — a
@@ -6091,8 +6096,12 @@ export declare interface GaugeInterface extends LedgerGauge {
6091
6096
  * `max(0, overhead - (spared ?? 0)) + scale * estimate`.
6092
6097
  * Capacity left is `max(0, capacity - used)`. The reply reserve adds recall uniform at the marginal
6093
6098
  * rate to the largest observed reply's `completion - (thinking ?? 0)` for every policy.
6094
- * Without a positive reply observation, it prices the longest reply text at that rate. Recall room is
6095
- * `max(0, (remainder - predict - reserve) / 2 / rate)`; recall closes at `remainder - predict < 2 * reserve`.
6099
+ * Without a positive reply observation, it prices the longest reply text at that rate. The room formula
6100
+ * `max(0, (remainder - predict - reserve) / 2 / rate)` is the planning forecast. The ledger's runtime
6101
+ * recall instead fits results below `capacity - predict`, anchoring the prefix to reported usage
6102
+ * and pricing additions at the larger of the marginal rate and the request's measured rate, with
6103
+ * `LEDGER_SCALE_DRIFT` headroom. The measured rate subtracts overhead only where `observe` would
6104
+ * rescale; partially spared calls retain the marginal rate. Missing usage uses an estimate.
6096
6105
  */
6097
6106
  export declare interface GaugeOptions extends LedgerGauge {
6098
6107
  readonly capacity: number;
@@ -8035,6 +8044,14 @@ export declare interface LedgerLine {
8035
8044
  readonly role: MessageRole;
8036
8045
  }
8037
8046
 
8047
+ /** Carries a recall result, its accepted whole groups, lookup line translations, and provider-turn position. */
8048
+ export declare interface LedgerListing {
8049
+ readonly result: string;
8050
+ readonly lines: ReadonlyMap<string, string>;
8051
+ readonly groups: readonly string[];
8052
+ readonly turn: number;
8053
+ }
8054
+
8038
8055
  /**
8039
8056
  * Carries one application lookup: the tool the model calls and the handler that reads its results.
8040
8057
  *
@@ -8134,7 +8151,10 @@ export declare interface LedgerOccurrence extends LedgerLine, LedgerReceipt {
8134
8151
  * nonnegative safe integer less than `capacity`; construction throws `LedgerError` with code
8135
8152
  * `'CAPACITY'` otherwise. The plan budgets
8136
8153
  * `max(0, (capacity - predict) * share.prompt - overhead) / (1 + LEDGER_SCALE_DRIFT)`.
8137
- * Recall closes when `remainder - predict < 2 * reserve`. `snapshot` hydrates the conversation and
8154
+ * The plan retains its `remainder - predict < 2 * reserve` admission rule. Runtime recall fits whole
8155
+ * results to measured remaining capacity at the larger of the gauge rate and the request's measured
8156
+ * rate, allowing `LEDGER_SCALE_DRIFT` for new text. Lack of room omits results without closing recall.
8157
+ * `snapshot` hydrates the conversation and
8138
8158
  * the marked ids a ledger's `snapshot()` returned; construction throws `LedgerError` with code
8139
8159
  * `'SNAPSHOT'` when `isLedgerSnapshot` refuses it, and `ConversationError` with code `'ROLE'` or
8140
8160
  * `'SNAPSHOT'` when its conversation holds a `system` message or repeats an id.
@@ -8273,6 +8293,12 @@ export declare interface LedgerRecord {
8273
8293
  readonly lines: readonly LedgerLine[];
8274
8294
  }
8275
8295
 
8296
+ /** Carries the answer note and the partial messages omitted from its prompt. */
8297
+ export declare interface LedgerRecovery {
8298
+ readonly digest: string | undefined;
8299
+ readonly omitted: ReadonlySet<string>;
8300
+ }
8301
+
8276
8302
  /**
8277
8303
  * Carries the ids the ledger's lookups named and the owners among them.
8278
8304
  *
@@ -8397,7 +8423,9 @@ export declare class LedgerRequest implements LedgerRequestInterface {
8397
8423
  admit(name: string, args: Readonly<Record<string, unknown>>): void;
8398
8424
  recall(): void;
8399
8425
  close(): void;
8400
- list(result: string, lines: ReadonlyMap<string, string>): void;
8426
+ list(result: string, lines: ReadonlyMap<string, string>, groups: readonly string[]): void;
8427
+ /** Returns recall results with their accepted whole groups and provider-turn positions. */
8428
+ get listings(): readonly LedgerListing[];
8401
8429
  lines(result: string): ReadonlyMap<string, string> | undefined;
8402
8430
  }
8403
8431
 
@@ -8517,8 +8545,11 @@ export declare interface LedgerRequestInterface {
8517
8545
  *
8518
8546
  * @param result - The recall result text
8519
8547
  * @param lines - Each listed lookup line mapped to the first line of its stored content
8548
+ * @param groups - The complete candidate groups, in listing order; only groups present in the result are retained
8520
8549
  */
8521
- list(result: string, lines: ReadonlyMap<string, string>): void;
8550
+ list(result: string, lines: ReadonlyMap<string, string>, groups: readonly string[]): void;
8551
+ /** Holds each recall result with its accepted groups and provider-turn position. */
8552
+ readonly listings: readonly LedgerListing[];
8522
8553
  /**
8523
8554
  * Returns the stored first lines a recall result listed.
8524
8555
  *
@@ -12496,6 +12527,7 @@ export declare type SystemOneEntry = JudgeEntry | null;
12496
12527
  *
12497
12528
  * @remarks
12498
12529
  * The caller supplies the server origin and model. Every question travels in one request.
12530
+ * Wire keys are zero-based positions in question entry order; answers return under the caller's ids.
12499
12531
  * Server measures are ignored; the response model is preserved.
12500
12532
  * `headers` supplies authentication through the shared judge engine.
12501
12533
  * The example readings are those of the response Ollama 0.40.0 returned for that request on 2026-10-07.
@@ -12546,14 +12578,14 @@ export declare class SystemOneJudge extends AgentJudge {
12546
12578
  /** Identifies the System One protocol. */
12547
12579
  readonly name = "systemone";
12548
12580
  /**
12549
- * Projects the state and questions onto the System One request with the configured model.
12581
+ * Projects the state and questions onto the System One request with the configured model and positional keys.
12550
12582
  *
12551
12583
  * @param request - The state and questions keyed by caller id
12552
12584
  * @returns The System One request body
12553
12585
  */
12554
12586
  encode(request: JudgeRequest): SystemOneRequest;
12555
12587
  /**
12556
- * Decodes requested System One answers and reports the server model and available usage.
12588
+ * Decodes positional System One answers under caller ids and reports the server model and available usage.
12557
12589
  *
12558
12590
  * @param value - The parsed response body
12559
12591
  * @param request - The questions defining the expected answers
@@ -2755,6 +2755,7 @@ var AgentJudge = class {
2755
2755
  *
2756
2756
  * @remarks
2757
2757
  * The caller supplies the server origin and model. Every question travels in one request.
2758
+ * Wire keys are zero-based positions in question entry order; answers return under the caller's ids.
2758
2759
  * Server measures are ignored; the response model is preserved.
2759
2760
  * `headers` supplies authentication through the shared judge engine.
2760
2761
  * The example readings are those of the response Ollama 0.40.0 returned for that request on 2026-10-07.
@@ -2811,7 +2812,7 @@ var SystemOneJudge = class extends AgentJudge {
2811
2812
  /** Identifies the System One protocol. */
2812
2813
  name = "systemone";
2813
2814
  /**
2814
- * Projects the state and questions onto the System One request with the configured model.
2815
+ * Projects the state and questions onto the System One request with the configured model and positional keys.
2815
2816
  *
2816
2817
  * @param request - The state and questions keyed by caller id
2817
2818
  * @returns The System One request body
@@ -2820,11 +2821,11 @@ var SystemOneJudge = class extends AgentJudge {
2820
2821
  return {
2821
2822
  state: request.state,
2822
2823
  model: this.model,
2823
- questions: Object.fromEntries(Object.entries(request.questions).map(([id, question]) => [id, questionToSystemOne(question)]))
2824
+ questions: Object.fromEntries(Object.values(request.questions).map((question, index) => [String(index), questionToSystemOne(question)]))
2824
2825
  };
2825
2826
  }
2826
2827
  /**
2827
- * Decodes requested System One answers and reports the server model and available usage.
2828
+ * Decodes positional System One answers under caller ids and reports the server model and available usage.
2828
2829
  *
2829
2830
  * @param value - The parsed response body
2830
2831
  * @param request - The questions defining the expected answers
@@ -2834,9 +2835,10 @@ var SystemOneJudge = class extends AgentJudge {
2834
2835
  */
2835
2836
  read(value, request) {
2836
2837
  if (!isSystemOneResponse(value)) throw new JudgeError("PROTOCOL", `judge error: invalid System One response envelope; received ${preview(value)}`);
2837
- const entries = Object.entries(request.questions).map(([id, question]) => {
2838
- if (!Object.hasOwn(value.answers, id)) throw new JudgeError("PROTOCOL", `judge error: question ${id} has no System One answer`);
2839
- const wire = value.answers[id];
2838
+ const entries = Object.entries(request.questions).map(([id, question], index) => {
2839
+ const position = String(index);
2840
+ if (!Object.hasOwn(value.answers, position)) throw new JudgeError("PROTOCOL", `judge error: question ${id} has no System One answer`);
2841
+ const wire = value.answers[position];
2840
2842
  if (!isSystemOneAnswer(wire)) throw new JudgeError("PROTOCOL", `judge error: question ${id} has an invalid System One answer; received ${preview(wire)}`);
2841
2843
  const answer = extractSystemOneAnswer(wire, question);
2842
2844
  if (answer === void 0) throw new JudgeError("PROTOCOL", `judge error: question ${id} has a mismatched or incomplete System One answer`);
@@ -9832,14 +9834,19 @@ function splitTopic(topic) {
9832
9834
  * Cuts entries to a room and names how many it left out.
9833
9835
  *
9834
9836
  * @remarks
9835
- * The cut keeps at least one entry. When it leaves entries out, its last line reads
9837
+ * By default the cut keeps at least one entry. With `first: false`, it keeps whole entries only
9838
+ * when the joined result, tool framing, and omission line fit, and considers later entries after
9839
+ * an oversized group. When it leaves some entries out, its last line reads
9836
9840
  * `N older items not shown; name a narrower topic to narrow the recall`, which
9837
9841
  * {@link matchesCutLine} recognizes. Pass `more` when the entries aren't in age order, so the line
9838
- * doesn't claim an omitted entry is older than a kept one.
9842
+ * doesn't claim an omitted entry is older than a kept one. A fitted cut also uses `more` when it
9843
+ * skips an entry before a kept one. With no kept entry it reads
9844
+ * `N older items didn't fit in this request; answer from the messages you can see`.
9839
9845
  *
9840
9846
  * @param entries - The entries in the order they are kept
9841
9847
  * @param room - The estimate units the joined entries can take
9842
9848
  * @param kind - What the cut line calls an omitted entry. Default: `older`
9849
+ * @param first - If `true`, keeps the first entry regardless of room; if `false`, fits every entry and the omission line. Default: `true`
9843
9850
  * @returns The kept entries followed by the cut line when any were left out, joined by newlines
9844
9851
  *
9845
9852
  * @example
@@ -9847,7 +9854,30 @@ function splitTopic(topic) {
9847
9854
  * cutListing(['first entry', 'second entry'], 1) // 'first entry\n1 older item not shown; name a narrower topic to narrow the recall'
9848
9855
  * ```
9849
9856
  */
9850
- function cutListing(entries, room, kind = "older") {
9857
+ function cutListing(entries, room, kind = "older", first = true) {
9858
+ if (!first) {
9859
+ if (estimateMessages([{
9860
+ id: "recall",
9861
+ role: "tool",
9862
+ content: entries.join("\n")
9863
+ }]) <= room) return entries.join("\n");
9864
+ const kept = entries.reduce((accepted, entry, at) => {
9865
+ const left = entries.length - accepted.length - 1;
9866
+ const omitted = accepted.length < at ? "more" : kind;
9867
+ return estimateMessages([{
9868
+ id: "recall",
9869
+ role: "tool",
9870
+ content: [
9871
+ ...accepted.map((index) => entries[index]),
9872
+ entry,
9873
+ ...left > 0 ? [`${left} ${omitted} item${left === 1 ? "" : "s"} not shown; name a narrower topic to narrow the recall`] : []
9874
+ ].join("\n")
9875
+ }]) <= room ? [...accepted, at] : accepted;
9876
+ }, []);
9877
+ const left = entries.length - kept.length;
9878
+ const omitted = kept.some((at, index) => at !== index) ? "more" : kind;
9879
+ return [...kept.map((at) => entries[at]), ...left > 0 ? [`${left} ${omitted} item${left === 1 ? "" : "s"} ${kept.length === 0 ? "didn't fit in this request; answer from the messages you can see" : "not shown; name a narrower topic to narrow the recall"}`] : []].join("\n");
9880
+ }
9851
9881
  const stop = [...entries.keys()].findIndex((at) => at > 0 && estimateMessages([{
9852
9882
  id: "recall",
9853
9883
  role: "tool",
@@ -9869,7 +9899,7 @@ function cutListing(entries, room, kind = "older") {
9869
9899
  * ```
9870
9900
  */
9871
9901
  function matchesCutLine(line) {
9872
- return /^\d+ (?:older|more) items? not shown; /.test(line);
9902
+ return /^\d+ (?:older|more) items? (?:not shown; |didn't fit in this request; answer from the messages you can see$)/.test(line);
9873
9903
  }
9874
9904
  /**
9875
9905
  * Renders the tail stub of a lookup result from an earlier request.
@@ -10794,7 +10824,7 @@ var LedgerRequest = class {
10794
10824
  #passes = [];
10795
10825
  #attempts = [];
10796
10826
  #admitted = /* @__PURE__ */ new Set();
10797
- #listed = /* @__PURE__ */ new Map();
10827
+ #listed = [];
10798
10828
  #recalls = 0;
10799
10829
  #closed = false;
10800
10830
  /**
@@ -10931,11 +10961,24 @@ var LedgerRequest = class {
10931
10961
  close() {
10932
10962
  this.#closed = true;
10933
10963
  }
10934
- list(result, lines) {
10935
- this.#listed = new Map([...this.#listed, [result, lines]]);
10964
+ list(result, lines, groups) {
10965
+ const accepted = groups.reduce((kept, group) => {
10966
+ const offset = kept.length === 0 ? 0 : kept.join("\n").length + 1;
10967
+ return result.slice(offset) === group || result.slice(offset).startsWith(`${group}\n`) ? [...kept, group] : kept;
10968
+ }, []);
10969
+ this.#listed = [...this.#listed, {
10970
+ result,
10971
+ lines,
10972
+ groups: accepted,
10973
+ turn: this.calls.length
10974
+ }];
10975
+ }
10976
+ /** Returns recall results with their accepted whole groups and provider-turn positions. */
10977
+ get listings() {
10978
+ return this.#listed;
10936
10979
  }
10937
10980
  lines(result) {
10938
- return this.#listed.get(result);
10981
+ return this.#listed.findLast((listing) => listing.result === result)?.lines;
10939
10982
  }
10940
10983
  };
10941
10984
  // src/core/ledgers/LedgerScan.ts
@@ -11458,10 +11501,10 @@ var Ledger = class {
11458
11501
  });
11459
11502
  const passes = [first];
11460
11503
  if (!caller.aborted && (first.partial || first.content.trim() === "")) {
11461
- const digest = this.#buildDigest(request, entered);
11462
- if (digest !== void 0) this.#annotations.add(this.#conversation.add({
11504
+ const recovery = this.#buildDigest(request, entered);
11505
+ if (recovery.digest !== void 0) this.#annotations.add(this.#conversation.add({
11463
11506
  role: "user",
11464
- content: digest
11507
+ content: recovery.digest
11465
11508
  }).id);
11466
11509
  this.#annotations.add(this.#conversation.add({
11467
11510
  role: "user",
@@ -11477,7 +11520,7 @@ var Ledger = class {
11477
11520
  if (selection.fault !== void 0) return selection;
11478
11521
  return {
11479
11522
  ...selection,
11480
- messages: selection.messages.filter((one) => one.role !== "tool" && !hasCalls(one))
11523
+ messages: selection.messages.filter((one) => one.role !== "tool" && !hasCalls(one) && !recovery.omitted.has(one.id))
11481
11524
  };
11482
11525
  }
11483
11526
  });
@@ -12110,11 +12153,21 @@ var Ledger = class {
12110
12153
  request?.admit("recall", { topic });
12111
12154
  const gauge = this.#gauge;
12112
12155
  const calls = request?.calls ?? [];
12113
- if (gauge !== void 0 && calls.length > 0 && gauge.remainder(calls) - this.#predict < 2 * gauge.reserve(calls, this.#findLongest())) request?.close();
12114
12156
  request?.recall();
12115
12157
  const guidance = `an owner name, an id, or one of ${renderTopicNames(this.#options.topics)}`;
12116
12158
  if (topic === "") throw new Error(`recall needs a topic: ${guidance}`);
12117
- const room = (gauge?.room(calls, this.#findLongest()) ?? 0) - estimateMessages([buildRecallMessage(topic)]);
12159
+ const rate = this.#recallRate(request) * (1 + LEDGER_SCALE_DRIFT);
12160
+ const call = calls.at(-1);
12161
+ const carried = request === void 0 ? 0 : estimateMessages(stripThinking([...this.#agent.context.build(request.selection), ...this.#conversation.messages().slice(request.boundary)], this.#replay));
12162
+ const completion = isFiniteNumber(call?.prompt) ? (call.completion ?? 0) - (this.#replay === "none" ? call.thinking ?? 0 : 0) : 0;
12163
+ const extra = Math.max(0, (carried - (call?.estimate ?? carried)) * rate - completion);
12164
+ const drift = isFiniteNumber(call?.prompt) ? 0 : Math.max(0, (call?.estimate ?? 0) * (rate - (gauge?.scale ?? rate)));
12165
+ const siblings = estimateMessages((request?.listings ?? []).filter((listing) => listing.turn === calls.length).map((listing) => ({
12166
+ id: "result",
12167
+ role: "tool",
12168
+ content: listing.result
12169
+ })));
12170
+ const room = gauge === void 0 ? -estimateMessages([buildRecallMessage(topic)]) : (gauge.remainder(calls) - this.#predict - extra - drift) / rate - siblings;
12118
12171
  const scan = this.#scan(this.#conversation.messages());
12119
12172
  const added = this.#scans.size === 0;
12120
12173
  if (added) this.#hold(scan);
@@ -12171,8 +12224,8 @@ var Ledger = class {
12171
12224
  return [`${label} ${message.content.replace(/[\n\v\f\r\u0085\u2028\u2029]+/g, "\n ")}`];
12172
12225
  });
12173
12226
  const listed = [...gathered.listed, ...earlier];
12174
- const result = listed.length === 0 ? `nothing earlier on "${topic}"; answer from the messages you can see` : cutListing(listed, room, earlier.length > 0 ? "more" : "older");
12175
- request?.list(result, gathered.recalled);
12227
+ const result = listed.length === 0 ? `nothing earlier on "${topic}"; answer from the messages you can see` : cutListing(listed, room, earlier.length > 0 ? "more" : "older", gauge === void 0);
12228
+ request?.list(result, gathered.recalled, listed);
12176
12229
  return result;
12177
12230
  } finally {
12178
12231
  if (added) this.#scans.delete(scan);
@@ -12180,15 +12233,58 @@ var Ledger = class {
12180
12233
  }
12181
12234
  #buildDigest(request, entered) {
12182
12235
  this.#flush();
12183
- const lines = [...new Set(this.#collectAfter(entered).flatMap((message) => {
12236
+ const groups = [...new Set(this.#collectAfter(entered).flatMap((message) => {
12184
12237
  const result = this.#results.get(message.id);
12185
12238
  if (message.role !== "tool" || result?.success !== true) return [];
12186
12239
  const recalled = result.name === "recall";
12187
12240
  if (recalled && /^nothing earlier on /.test(message.content)) return [];
12188
- const stored = recalled ? request.lines(message.content) : void 0;
12189
- return splitResultLines(message.content).filter((line) => !recalled || !matchesCutLine(line)).map((line) => stored?.get(line) ?? line);
12241
+ const listing = recalled ? request.listings.findLast((one) => one.result === message.content) : void 0;
12242
+ return (listing?.groups ?? [message.content]).map((group) => splitResultLines(group).map((line) => listing?.lines.get(line) ?? line).join("\n")).filter((group) => group !== "");
12190
12243
  }))];
12191
- return lines.length === 0 ? void 0 : `${LEDGER_NOTES.results}\n${lines.join("\n")}`;
12244
+ const unique = groups.filter((group, at) => !splitResultLines(group).every((line) => groups.slice(0, at).some((earlier) => splitResultLines(earlier).includes(line))));
12245
+ const digest = unique.length === 0 ? void 0 : `${LEDGER_NOTES.results}\n${unique.join("\n")}`;
12246
+ const omitted = /* @__PURE__ */ new Set();
12247
+ const rate = this.#recallRate(request) * (1 + LEDGER_SCALE_DRIFT);
12248
+ const allowance = (this.#options.capacity - this.#predict) / rate;
12249
+ const after = this.#collectAfter(entered);
12250
+ const messages = [
12251
+ ...request.plan?.messages ?? request.selection?.messages ?? [],
12252
+ ...after,
12253
+ {
12254
+ id: "cue",
12255
+ role: "user",
12256
+ content: LEDGER_NOTES.cue
12257
+ }
12258
+ ].filter((message) => message.role !== "tool" && !hasCalls(message));
12259
+ const note = digest === void 0 ? [] : [{
12260
+ id: "results",
12261
+ role: "user",
12262
+ content: digest
12263
+ }];
12264
+ if (this.#gauge === void 0 || estimateMessages(stripThinking(this.#agent.context.build({
12265
+ messages: [...messages, ...note],
12266
+ judgments: []
12267
+ }), this.#replay)) <= allowance) return {
12268
+ digest,
12269
+ omitted
12270
+ };
12271
+ const partials = new Set(after.filter((message) => message.role === "assistant" && !hasCalls(message)).map((message) => message.id));
12272
+ const fitted = cutListing(unique, allowance - estimateMessages(stripThinking(this.#agent.context.build({
12273
+ messages: messages.filter((message) => !partials.has(message.id)),
12274
+ judgments: []
12275
+ }), this.#replay)) - estimateTokens(`${LEDGER_NOTES.results}\n`), "more", false);
12276
+ return {
12277
+ digest: fitted === "" ? void 0 : `${LEDGER_NOTES.results}\n${fitted}`,
12278
+ omitted: partials
12279
+ };
12280
+ }
12281
+ #recallRate(request) {
12282
+ const gauge = this.#gauge;
12283
+ if (gauge === void 0) return 1;
12284
+ const calls = request?.calls ?? [];
12285
+ const last = calls.findLast((call) => isFiniteNumber(call.prompt));
12286
+ const measured = last !== void 0 && isFiniteNumber(last.prompt) && last.estimate > 0 && ((last.spared ?? 0) === 0 || (last.spared ?? 0) >= gauge.overhead) ? (last.prompt - Math.max(0, gauge.overhead - (last.spared ?? 0))) / last.estimate : 0;
12287
+ return Math.max(gauge.rate(calls), measured);
12192
12288
  }
12193
12289
  };
12194
12290
  // src/core/ledgers/factories.ts