@orkestrel/agent 0.0.38 → 0.0.40

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.
@@ -8909,7 +8909,7 @@ var DETERMINISTIC_JUDGE_ERROR = /invalid or duplicate top logprob token/;
8909
8909
  * carrying the machine-readable `code`.
8910
8910
  *
8911
8911
  * @remarks
8912
- * A threshold, share, capacity, limit, topic, lookup, question, or gauge outside its bounds is a
8912
+ * A threshold, share, capacity, limit, topic, lookup, write, question, or gauge outside its bounds is a
8913
8913
  * programmer error and throws this with the matching {@link LedgerErrorCode}. A calibration call that reports
8914
8914
  * no prompt usage throws this with `'GAUGE'`. A snapshot option that `isLedgerSnapshot` refuses
8915
8915
  * throws this with `'SNAPSHOT'`, its `context` holding the `faults`. Narrow a caught value with {@link isLedgerError} and
@@ -8953,7 +8953,7 @@ function isLedgerError(value) {
8953
8953
  return (0, _orkestrel_contract.holds)(() => {
8954
8954
  if (!(value instanceof Error && _orkestrel_contract.INTRINSICS.prototype(value) !== Error.prototype && _orkestrel_contract.INTRINSICS.describe(value, Symbol.for("@orkestrel/agent.LedgerError"))?.value === value)) return false;
8955
8955
  const code = _orkestrel_contract.INTRINSICS.reflect.read(value, "code");
8956
- if (!(code === "REQUEST" || code === "THRESHOLD" || code === "SHARE" || code === "CAPACITY" || code === "LIMIT" || code === "TOPIC" || code === "LOOKUP" || code === "GAUGE" || code === "REFERENCE" || code === "SNAPSHOT" || code === "QUESTION")) return false;
8956
+ if (!(code === "REQUEST" || code === "THRESHOLD" || code === "SHARE" || code === "CAPACITY" || code === "LIMIT" || code === "TOPIC" || code === "LOOKUP" || code === "GAUGE" || code === "REFERENCE" || code === "SNAPSHOT" || code === "QUESTION" || code === "WRITE")) return false;
8957
8957
  const context = _orkestrel_contract.INTRINSICS.reflect.read(value, "context");
8958
8958
  return context === void 0 || (0, _orkestrel_contract.isObject)(context) || (0, _orkestrel_contract.isFunction)(context);
8959
8959
  });
@@ -8983,7 +8983,43 @@ function digestLedgerWindow(exchanges, messages) {
8983
8983
  return values.some((value) => value === void 0) ? void 0 : (0, _orkestrel_contract.canonicalStringify)([values, exchanges.map((entry) => [entry.copy ?? null, entry.lines])]);
8984
8984
  });
8985
8985
  if (!encoded.success || encoded.value === void 0) return void 0;
8986
- const hash = [...encoded.value].reduce((prior, character) => {
8986
+ return computeLedgerChecksum(encoded.value);
8987
+ }
8988
+ /**
8989
+ * Digests tool definitions as the JSON a provider request carries them, in order.
8990
+ *
8991
+ * @remarks
8992
+ * A ledger stores this digest with its gauge, so a hydrate reuses the gauge only for the same
8993
+ * definitions: an added, removed, reordered, or edited definition changes the digest. The digest is
8994
+ * a {@link computeLedgerChecksum} checksum and makes no security claim.
8995
+ *
8996
+ * @param definitions - The tool definitions, as a tool manager's `definitions` method returns them
8997
+ * @returns The 16-digit hexadecimal digest, or undefined when JSON cannot render the definitions
8998
+ * @example
8999
+ * ```ts
9000
+ * digestLedgerTools([{ name: 'lookup_order', description: 'Read an order by its id.' }]) // '1eff754a69b7128c'
9001
+ * ```
9002
+ */
9003
+ function digestLedgerTools(definitions) {
9004
+ const text = renderJSON(definitions);
9005
+ return text === void 0 ? void 0 : computeLedgerChecksum(text);
9006
+ }
9007
+ /**
9008
+ * Computes a checksum of text: two 32-bit FNV-1a lanes over its code points, as 16 hexadecimal digits.
9009
+ *
9010
+ * @remarks
9011
+ * The checksum detects an edit, can collide, and makes no security claim. Over ASCII text, the first
9012
+ * lane is the standard 32-bit FNV-1a hash.
9013
+ *
9014
+ * @param text - The text to checksum
9015
+ * @returns The 16-digit lowercase hexadecimal checksum
9016
+ * @example
9017
+ * ```ts
9018
+ * computeLedgerChecksum('a') // 'e40c292ce457465e'
9019
+ * ```
9020
+ */
9021
+ function computeLedgerChecksum(text) {
9022
+ const hash = [...text].reduce((prior, character) => {
8987
9023
  const code = character.codePointAt(0) ?? 0;
8988
9024
  return {
8989
9025
  first: Math.imul(prior.first ^ code, 16777619) >>> 0,
@@ -8998,19 +9034,21 @@ function digestLedgerWindow(exchanges, messages) {
8998
9034
  /**
8999
9035
  * Collects stored messages eligible to open the recall offer.
9000
9036
  * @remarks
9001
- * Notes and findings without a result do not open the offer. User statements, including quiet
9002
- * statements available through recall's word route, can open it; this helper does not filter results.
9037
+ * Notes, findings without a result, and findings {@link collectRetiredFindings} names do not open
9038
+ * the offer. User statements, including quiet statements available through recall's word route,
9039
+ * can open it; this helper does not filter results.
9003
9040
  * @param input - The messages, findings, and classification
9004
9041
  * @param requests - The marked request ids
9005
9042
  * @param notes - The annotation ids to exclude
9006
- * @returns User statements, lookup findings with results, marked requests, and nonblank call-free replies
9043
+ * @returns User statements, lookup findings with results that no write superseded and no later finding replaced, marked requests, and nonblank call-free replies
9007
9044
  * @example
9008
9045
  * ```ts
9009
9046
  * collectRecallMessages(input, new Set(), new Set()) // eligible stored messages
9010
9047
  * ```
9011
9048
  */
9012
9049
  function collectRecallMessages(input, requests, notes) {
9013
- const findings = new Set(input.findings.filter((finding) => finding.result !== void 0).map((finding) => finding.id));
9050
+ const retired = collectRetiredFindings(input.messages, input.findings);
9051
+ const findings = new Set(input.findings.filter((finding) => finding.result !== void 0 && !retired.has(finding.id)).map((finding) => finding.id));
9014
9052
  return input.messages.filter((message) => !notes.has(message.id) && (requests.has(message.id) || message.role === "assistant" && !hasCalls(message) && message.content.trim() !== "" || message.role === "user" && !hasCalls(message) || message.role === "tool" && findings.has(message.id)));
9015
9053
  }
9016
9054
  /**
@@ -9908,6 +9946,7 @@ function matchesCutLine(line) {
9908
9946
  * @param name - The lookup tool name
9909
9947
  * @param args - The arguments the call carried; arguments JSON cannot carry leave the call as its bare tool name, per {@link renderLookupCall}
9910
9948
  * @param state - What became of the result: `failed`, `empty`, `shown` in the records, or `hidden` from them
9949
+ * @param write - If `true`, the call is a write's, whose `empty` state reads `changed nothing`; if `false`, a lookup's, whose `empty` state reads `no record`. Default: `false`
9911
9950
  * @returns The stub text, which carries the call and its state
9912
9951
  *
9913
9952
  * @example
@@ -9916,10 +9955,10 @@ function matchesCutLine(line) {
9916
9955
  * // 'lookup_order {"id":"BW-5512"}: result not shown; call recall with BW-5512'
9917
9956
  * ```
9918
9957
  */
9919
- function renderStub(name, args, state) {
9958
+ function renderStub(name, args, state, write = false) {
9920
9959
  const head = renderLookupCall(name, args);
9921
9960
  if (state === "failed") return `${head}: failed`;
9922
- if (state === "empty") return `${head}: no record`;
9961
+ if (state === "empty") return write ? `${head}: changed nothing` : `${head}: no record`;
9923
9962
  if (state === "shown") return `${head}: result shown under Records below`;
9924
9963
  return `${head}: result not shown; call recall with ${(Object.values(args).find(_orkestrel_contract.isString) ?? "").trim() || "its id"}`;
9925
9964
  }
@@ -9966,7 +10005,8 @@ function fitSlope(groups) {
9966
10005
  * or superseded. When the whole run is superseded, its first finding reaches that final filter.
9967
10006
  * Different text or an undefined result replaces the earlier run, so an empty lookup leaves the
9968
10007
  * earlier result out of every record. A thrown lookup leaves the earlier result live. A finding
9969
- * with no canonical identity participates in no replacement.
10008
+ * with no canonical identity participates in no replacement. A finding a write retired is
10009
+ * superseded once {@link mergeSupersessions} merges the write's edges into the classification.
9970
10010
  *
9971
10011
  * @param input - The messages, findings, and classification to read
9972
10012
  * @returns The live message ids
@@ -9993,6 +10033,100 @@ function collectLive(input) {
9993
10033
  return [...new Map(input.messages.map((message) => [message.id, message])).values()].filter((message) => message.role === "user" || message.role === "tool" && current.has(message.id)).map((message) => message.id).filter((id) => !excluded.has(id) && !classification.quiet.has(id) && (classification.supersessions.get(id) ?? []).length === 0);
9994
10034
  }
9995
10035
  /**
10036
+ * Collects each finding a write made stale, mapped to the writes that supersede it.
10037
+ *
10038
+ * @remarks
10039
+ * A write is a finding with `targets`. It supersedes another finding whose names meet its targets
10040
+ * when that finding comes before it in conversation order, or sits in its own tool group and
10041
+ * carries no targets, because one batch dispatches its calls at once. So the later of two writes in
10042
+ * one group supersedes the earlier, and never the reverse. A finding's names are its result's `ids`
10043
+ * and owner ids, or, for an empty finding, the ids its string arguments name, as `extractLiterals`
10044
+ * reads them. Names and targets compare exactly. A write never supersedes itself, a finding with
10045
+ * empty `targets` supersedes nothing, and a finding the messages don't hold takes no part.
10046
+ *
10047
+ * @param messages - The conversation's messages, which fix each finding's position and tool group
10048
+ * @param findings - The lookup and write findings of those messages
10049
+ * @returns Each superseded finding's id, in conversation order, mapped to the ids of the writes that supersede it, in conversation order
10050
+ *
10051
+ * @example
10052
+ * ```ts
10053
+ * collectWriteSupersessions(messages, findings) // Map { 'tool-1' => ['tool-2'] } when tool-2 wrote what tool-1 read
10054
+ * ```
10055
+ */
10056
+ function collectWriteSupersessions(messages, findings) {
10057
+ if (!findings.some((finding) => (finding.targets ?? []).length > 0)) return /* @__PURE__ */ new Map();
10058
+ const positions = new Map(messages.map((message, at) => [message.id, at]));
10059
+ const groups = new Map(collectToolGroups(messages).flatMap((group, at) => group.map((message) => [message.id, at])));
10060
+ const held = findings.filter((finding) => positions.has(finding.id)).toSorted((left, right) => (positions.get(left.id) ?? 0) - (positions.get(right.id) ?? 0));
10061
+ const writes = held.filter((finding) => (finding.targets ?? []).length > 0);
10062
+ return new Map(held.flatMap((finding) => {
10063
+ const names = new Set(finding.result === void 0 ? Object.values(finding.arguments).filter(_orkestrel_contract.isString).flatMap((value) => [...extractLiterals(value).ids]) : [...finding.result.ids, ...finding.result.owners.map((owner) => owner.id)]);
10064
+ const at = positions.get(finding.id) ?? 0;
10065
+ const group = groups.get(finding.id);
10066
+ const targeted = (finding.targets ?? []).length > 0;
10067
+ const superseders = writes.filter((write) => write.id !== finding.id && (write.targets ?? []).some((target) => names.has(target)) && ((positions.get(write.id) ?? 0) > at || !targeted && group !== void 0 && groups.get(write.id) === group));
10068
+ return superseders.length === 0 ? [] : [[finding.id, superseders.map((write) => write.id)]];
10069
+ }));
10070
+ }
10071
+ /**
10072
+ * Collects the findings a write superseded or a later finding of the same lookup replaced.
10073
+ *
10074
+ * @remarks
10075
+ * A write supersedes the findings {@link collectWriteSupersessions} maps. A later finding of the
10076
+ * same canonical lookup identity, as {@link identifyLookup} writes it, replaces an earlier one when
10077
+ * its text differs or it holds no result, and a later finding with the same text replaces nothing.
10078
+ * A finding with no canonical identity is never replaced, and a finding the messages don't hold
10079
+ * takes no part. A supersession the judge files is not read here.
10080
+ *
10081
+ * @param messages - The conversation's messages, which fix each finding's position
10082
+ * @param findings - The lookup and write findings of those messages
10083
+ * @returns The ids of the superseded and replaced findings
10084
+ *
10085
+ * @example
10086
+ * ```ts
10087
+ * collectRetiredFindings(messages, findings) // Set { 'tool-1' } when tool-2 wrote what tool-1 read
10088
+ * ```
10089
+ */
10090
+ function collectRetiredFindings(messages, findings) {
10091
+ const positions = new Map(messages.map((message, at) => [message.id, at]));
10092
+ const held = findings.filter((finding) => positions.has(finding.id));
10093
+ const replaced = [...Map.groupBy(held, (finding) => identifyLookup(finding.name, finding.arguments) ?? finding).values()].flatMap((group) => {
10094
+ const ordered = group.toSorted((left, right) => (positions.get(left.id) ?? 0) - (positions.get(right.id) ?? 0));
10095
+ const last = ordered.at(-1);
10096
+ const boundary = last === void 0 ? -1 : ordered.findLastIndex((finding) => finding.result === void 0 || finding.text !== last.text);
10097
+ return ordered.slice(0, Math.min(boundary + 1, ordered.length - 1)).map((finding) => finding.id);
10098
+ });
10099
+ return /* @__PURE__ */ new Set([...collectWriteSupersessions(messages, findings).keys(), ...replaced]);
10100
+ }
10101
+ /**
10102
+ * Merges supersession edges into a classification, adding each edge to both its supersessions and its amendments.
10103
+ *
10104
+ * @remarks
10105
+ * Each earlier message's later ids stay distinct and in conversation order, so every supersession
10106
+ * is still an amendment, as the classifier files one. An empty edge map returns the classification
10107
+ * itself.
10108
+ *
10109
+ * @param classification - The judged classification
10110
+ * @param edges - The later ids that supersede each earlier id, such as {@link collectWriteSupersessions} returns
10111
+ * @param messages - The conversation's messages, which order the later ids
10112
+ * @returns The classification with the edges merged
10113
+ *
10114
+ * @example
10115
+ * ```ts
10116
+ * mergeSupersessions(classification, new Map([['tool-1', ['tool-2']]]), messages).supersessions.get('tool-1') // ['tool-2']
10117
+ * ```
10118
+ */
10119
+ function mergeSupersessions(classification, edges, messages) {
10120
+ if (edges.size === 0) return classification;
10121
+ const positions = new Map(messages.map((message, at) => [message.id, at]));
10122
+ const [amendments = classification.amendments, supersessions = classification.supersessions] = [classification.amendments, classification.supersessions].map((laters) => new Map([.../* @__PURE__ */ new Set([...laters.keys(), ...edges.keys()])].map((earlier) => [earlier, [.../* @__PURE__ */ new Set([...laters.get(earlier) ?? [], ...edges.get(earlier) ?? []])].toSorted((left, right) => (positions.get(left) ?? 0) - (positions.get(right) ?? 0))])));
10123
+ return {
10124
+ ...classification,
10125
+ amendments,
10126
+ supersessions
10127
+ };
10128
+ }
10129
+ /**
9996
10130
  * Places a message on the record keys it joins.
9997
10131
  *
9998
10132
  * @remarks
@@ -10652,7 +10786,8 @@ var Gauge = class {
10652
10786
  // src/core/ledgers/LedgerPass.ts
10653
10787
  /**
10654
10788
  * Holds what one pass of a ledger request keeps: the selection its run adopted last, the
10655
- * conversation boundary its calls count additions from, its summed usage, and its gauge calls.
10789
+ * conversation boundary its calls count additions from, its summed usage, its gauge calls, and the
10790
+ * abort that ends its run.
10656
10791
  *
10657
10792
  * @remarks
10658
10793
  * A `LedgerRequest` opens one pass per agent run and exposes only projections of it, so no public
@@ -10666,6 +10801,7 @@ var LedgerPass = class {
10666
10801
  #selection;
10667
10802
  #boundary;
10668
10803
  #usage;
10804
+ #abort = (0, _orkestrel_abort.createAbort)();
10669
10805
  /**
10670
10806
  * Opens the pass at a conversation boundary.
10671
10807
  *
@@ -10699,6 +10835,22 @@ var LedgerPass = class {
10699
10835
  return this.#usage;
10700
10836
  }
10701
10837
  /**
10838
+ * Returns the signal `abort` aborts.
10839
+ *
10840
+ * @returns The pass's abort signal
10841
+ */
10842
+ get signal() {
10843
+ return this.#abort.signal;
10844
+ }
10845
+ /**
10846
+ * Reports whether `abort` ended the pass.
10847
+ *
10848
+ * @returns True if the pass was aborted; false otherwise
10849
+ */
10850
+ get aborted() {
10851
+ return this.#abort.signal.aborted;
10852
+ }
10853
+ /**
10702
10854
  * Returns the call in flight.
10703
10855
  *
10704
10856
  * @returns The latest call the pass observed, or undefined before one
@@ -10792,6 +10944,10 @@ var LedgerPass = class {
10792
10944
  think(thinking) {
10793
10945
  this.#log = [...this.#log, { thinking }];
10794
10946
  }
10947
+ /** Aborts the pass's run through `signal`, with the reason `'stray'`; a later call changes nothing. */
10948
+ abort() {
10949
+ this.#abort.abort("stray");
10950
+ }
10795
10951
  };
10796
10952
  // src/core/ledgers/LedgerRequest.ts
10797
10953
  /**
@@ -10825,6 +10981,7 @@ var LedgerRequest = class {
10825
10981
  #passes = [];
10826
10982
  #attempts = [];
10827
10983
  #admitted = /* @__PURE__ */ new Set();
10984
+ #denials = /* @__PURE__ */ new Set();
10828
10985
  #listed = [];
10829
10986
  #recalls = 0;
10830
10987
  #closed = false;
@@ -10906,6 +11063,22 @@ var LedgerRequest = class {
10906
11063
  get attempts() {
10907
11064
  return this.#attempts;
10908
11065
  }
11066
+ /**
11067
+ * Returns the signal `abort` aborts for the current pass's run.
11068
+ *
11069
+ * @returns The current pass's abort signal, or undefined before a pass
11070
+ */
11071
+ get signal() {
11072
+ return this.#passes.at(-1)?.signal;
11073
+ }
11074
+ /**
11075
+ * Reports whether `abort` ended the current pass.
11076
+ *
11077
+ * @returns True if the current pass was aborted; false otherwise, and before a pass
11078
+ */
11079
+ get aborted() {
11080
+ return this.#passes.at(-1)?.aborted ?? false;
11081
+ }
10909
11082
  enter(conversation) {
10910
11083
  if (this.#message !== void 0) return this.#message;
10911
11084
  this.#message = conversation.add({
@@ -10920,6 +11093,9 @@ var LedgerRequest = class {
10920
11093
  adopt(selection, boundary) {
10921
11094
  this.#passes.at(-1)?.adopt(selection, boundary);
10922
11095
  }
11096
+ abort() {
11097
+ this.#passes.at(-1)?.abort();
11098
+ }
10923
11099
  observe(call, position) {
10924
11100
  const draft = this.#draft;
10925
11101
  this.#sent = draft !== void 0 && this.selection?.messages.some((message) => message.id === draft.copy.id && message.content === draft.copy.content) ? draft : void 0;
@@ -10954,6 +11130,18 @@ var LedgerRequest = class {
10954
11130
  if (this.#admitted.has(key)) throw new Error(LEDGER_NOTES.repeat);
10955
11131
  this.#admitted = /* @__PURE__ */ new Set([...this.#admitted, key]);
10956
11132
  }
11133
+ release(name, args) {
11134
+ const key = (0, _orkestrel_contract.canonicalStringify)([name, args]);
11135
+ this.#admitted = new Set([...this.#admitted].filter((admitted) => admitted !== key));
11136
+ }
11137
+ deny(name, args) {
11138
+ const key = (0, _orkestrel_contract.canonicalStringify)([name, args]);
11139
+ if (key !== void 0) this.#denials = /* @__PURE__ */ new Set([...this.#denials, key]);
11140
+ }
11141
+ denied(name, args) {
11142
+ const key = (0, _orkestrel_contract.canonicalStringify)([name, args]);
11143
+ return key !== void 0 && this.#denials.has(key);
11144
+ }
10957
11145
  recall() {
10958
11146
  if (this.#recalls >= this.#limit) this.#closed = true;
10959
11147
  if (this.#closed) throw new Error(LEDGER_NOTES.closure);
@@ -11129,7 +11317,8 @@ var ledgerSnapshotShape = (0, _orkestrel_contract.objectShape)({
11129
11317
  failures: (0, _orkestrel_contract.arrayShape)((0, _orkestrel_contract.stringShape)()),
11130
11318
  gauge: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.objectShape)({
11131
11319
  scale: (0, _orkestrel_contract.numberShape)(),
11132
- overhead: (0, _orkestrel_contract.numberShape)()
11320
+ overhead: (0, _orkestrel_contract.numberShape)(),
11321
+ digest: (0, _orkestrel_contract.stringShape)()
11133
11322
  })),
11134
11323
  window: (0, _orkestrel_contract.optionalShape)(ledgerWindowShape)
11135
11324
  });
@@ -11204,8 +11393,8 @@ function isLedgerQuestion(value) {
11204
11393
  * `conversation` must pass `isConversationSnapshot`, and `requests`, `notes`, and `failures` must be
11205
11394
  * dense arrays of strings. Each request and note id must name a `user` message of
11206
11395
  * `conversation.messages` and each failure id a `tool` message, so an id only a section original
11207
- * holds is refused. A `gauge`, when present, must hold a finite `scale` greater than 0 and a finite
11208
- * `overhead` of at least 0. The guard is exact: an unknown member and an own `undefined` `gauge` return
11396
+ * holds is refused. A `gauge`, when present, must hold a finite `scale` greater than 0, a finite
11397
+ * `overhead` of at least 0, and a string `digest`. The guard is exact: an unknown member and an own `undefined` `gauge` return
11209
11398
  * false, at the snapshot and in its `gauge`. Unreadable members and untrusted inputs return false. The
11210
11399
  * guard is structural: it admits a conversation holding a stored `system` role
11211
11400
  * or a repeated id, which `requireConversationSnapshot` and the `Conversation` constructor then
@@ -11231,9 +11420,9 @@ function isLedgerSnapshot(value) {
11231
11420
  const isIds = (0, _orkestrel_contract.arrayOf)(_orkestrel_contract.isString);
11232
11421
  if (!isIds(requests) || !isIds(notes) || !isIds(failures)) return false;
11233
11422
  if (gauge !== void 0) {
11234
- if (!(0, _orkestrel_contract.isRecord)(gauge) || Object.keys(gauge).length !== 2) return false;
11235
- const { scale, overhead } = gauge;
11236
- if (!(0, _orkestrel_contract.isFiniteNumber)(scale) || scale <= 0 || !(0, _orkestrel_contract.isFiniteNumber)(overhead) || overhead < 0) return false;
11423
+ if (!(0, _orkestrel_contract.isRecord)(gauge) || Object.keys(gauge).length !== 3) return false;
11424
+ const { scale, overhead, digest } = gauge;
11425
+ if (!(0, _orkestrel_contract.isFiniteNumber)(scale) || scale <= 0 || !(0, _orkestrel_contract.isFiniteNumber)(overhead) || overhead < 0 || !(0, _orkestrel_contract.isString)(digest)) return false;
11237
11426
  }
11238
11427
  const roles = new Map(conversation.messages.map((message) => [message.id, message.role]));
11239
11428
  return requests.every((id) => roles.get(id) === "user") && notes.every((id) => roles.get(id) === "user") && failures.every((id) => roles.get(id) === "tool") && (window === void 0 || isLedgerWindowSnapshot(window));
@@ -11266,6 +11455,7 @@ var Ledger = class {
11266
11455
  #scans = /* @__PURE__ */ new Set();
11267
11456
  #calibrations = /* @__PURE__ */ new Set();
11268
11457
  #gauge;
11458
+ #digest;
11269
11459
  #window = [];
11270
11460
  #evidence = collectLedgerEvidence([], /* @__PURE__ */ new Set(), []);
11271
11461
  /**
@@ -11273,6 +11463,7 @@ var Ledger = class {
11273
11463
  * @param provider - The provider that serves the conversation
11274
11464
  * @param options - The filing policy, capacity, and request bounds
11275
11465
  * @throws {LedgerError} Thrown when a threshold, share, capacity, limit, topic, lookup, or gauge is invalid
11466
+ * @throws {LedgerError} Thrown when a write lacks the `consequential` annotation, writes come without `agent.authority`, or a write is named `recall` or shares a lookup's or another write's name (code `'WRITE'`)
11276
11467
  * @throws {LedgerError} Thrown when `predict` is not a nonnegative safe integer less than `capacity` (code `'CAPACITY'`)
11277
11468
  * @throws {LedgerError} Thrown when `questions` fails `isLedgerQuestion` (code `'QUESTION'`)
11278
11469
  * @throws {LedgerError} Thrown when `snapshot` is malformed or marks an id its conversation does not hold (code `'SNAPSHOT'`, its faults under `context.faults`)
@@ -11298,6 +11489,12 @@ var Ledger = class {
11298
11489
  if (topics.some((name) => name.trim() === "") || new Set(topics).size !== topics.length) throw new LedgerError("TOPIC", "topic names must be nonempty and unique");
11299
11490
  const lookups = ["recall", ...Array.from(options.lookups ?? [], (lookup) => lookup.tool.name)];
11300
11491
  if (new Set(lookups).size !== lookups.length) throw new LedgerError("LOOKUP", "lookup names must be unique and cannot be recall");
11492
+ const writes = Array.from(options.writes ?? [], (write) => write.tool);
11493
+ const names = [...lookups, ...writes.map((tool) => tool.name)];
11494
+ if (new Set(names).size !== names.length) throw new LedgerError("WRITE", "write names must be unique and cannot be recall or the name of a lookup");
11495
+ if (writes.some((tool) => tool.annotations?.consequential !== true)) throw new LedgerError("WRITE", "a write tool must carry annotations.consequential: true, so the host approves each call");
11496
+ const host = options.agent?.authority;
11497
+ if (writes.length > 0 && host === void 0) throw new LedgerError("WRITE", "writes need an agent.authority that gates each call");
11301
11498
  if (!isLedgerQuestion(options.questions)) throw new LedgerError("QUESTION", "questions must hold a choice category question whose criteria describe every category, a non-empty topic string, and noul amends and supersedes questions; pass the LEDGER_QUESTIONS constant for the measured wording");
11302
11499
  const snapshot = options.snapshot;
11303
11500
  if (snapshot !== void 0 && !isLedgerSnapshot(snapshot)) {
@@ -11312,13 +11509,6 @@ var Ledger = class {
11312
11509
  ...DEFAULT_LEDGER_SHARE,
11313
11510
  ...options.share
11314
11511
  };
11315
- const gauge = options.gauge ?? snapshot?.gauge;
11316
- if (gauge !== void 0) this.#gauge = new Gauge({
11317
- ...gauge,
11318
- capacity: options.capacity,
11319
- predict: this.#predict,
11320
- replay: this.#replay
11321
- });
11322
11512
  const conversations = createConversationManager();
11323
11513
  this.#conversation = snapshot === void 0 ? conversations.add() : conversations.add({ snapshot: snapshot.conversation });
11324
11514
  conversations.switch(this.#conversation.id);
@@ -11339,14 +11529,14 @@ var Ledger = class {
11339
11529
  ...options.agent?.strict === void 0 ? {} : { strict: options.agent.strict }
11340
11530
  });
11341
11531
  const tools = (0, _orkestrel_tool.createToolManager)();
11342
- for (const lookup of options.lookups ?? []) tools.add((0, _orkestrel_tool.createTool)({
11343
- name: lookup.tool.name,
11344
- ...lookup.tool.parameters === void 0 ? {} : { parameters: lookup.tool.parameters },
11345
- ...lookup.tool.description === void 0 ? {} : { description: lookup.tool.description },
11346
- ...lookup.tool.summary === void 0 ? {} : { summary: lookup.tool.summary },
11347
- ...lookup.tool.title === void 0 ? {} : { title: lookup.tool.title },
11348
- ...lookup.tool.annotations === void 0 ? {} : { annotations: lookup.tool.annotations },
11349
- execute: (args, context) => this.#lookup(lookup.tool.name, args, context)
11532
+ for (const { tool } of [...options.lookups ?? [], ...options.writes ?? []]) tools.add((0, _orkestrel_tool.createTool)({
11533
+ name: tool.name,
11534
+ ...tool.parameters === void 0 ? {} : { parameters: tool.parameters },
11535
+ ...tool.description === void 0 ? {} : { description: tool.description },
11536
+ ...tool.summary === void 0 ? {} : { summary: tool.summary },
11537
+ ...tool.title === void 0 ? {} : { title: tool.title },
11538
+ ...tool.annotations === void 0 ? {} : { annotations: tool.annotations },
11539
+ execute: (args, context) => this.#lookup(tool.name, args, context)
11350
11540
  }));
11351
11541
  tools.add((0, _orkestrel_tool.createTool)({
11352
11542
  name: "recall",
@@ -11357,33 +11547,60 @@ var Ledger = class {
11357
11547
  }) }),
11358
11548
  execute: (args) => this.#recall(args)
11359
11549
  }));
11550
+ const advertised = new Authority({
11551
+ rules: [{
11552
+ match: (context) => names.includes(context.call.name),
11553
+ zone: "ledger",
11554
+ verdict: "allow"
11555
+ }],
11556
+ fallback: {
11557
+ zone: "ledger",
11558
+ verdict: "deny",
11559
+ reason: "the ledger advertises no such tool"
11560
+ }
11561
+ });
11360
11562
  this.#agent = createAgent(provider, {
11361
11563
  ...options.agent,
11362
11564
  conversations,
11363
11565
  system: options.system,
11364
11566
  tools,
11365
- authority: createAuthority({
11366
- rules: [{
11367
- match: (context) => lookups.includes(context.call.name),
11368
- zone: "ledger",
11369
- verdict: "allow"
11370
- }],
11371
- fallback: {
11567
+ authority: {
11568
+ evaluate: (context) => this.#current()?.denied(context.call.name, context.call.arguments) === true ? {
11372
11569
  zone: "ledger",
11373
11570
  verdict: "deny",
11374
- reason: "the ledger advertises no such tool"
11375
- }
11376
- }),
11571
+ reason: LEDGER_NOTES.repeat
11572
+ } : host === void 0 || context.call.name === "recall" || !names.includes(context.call.name) ? advertised.evaluate(context) : host.evaluate(context),
11573
+ ask: (context, decision, signal) => this.#current()?.denied(context.call.name, context.call.arguments) === true ? Promise.resolve(false) : host?.ask === void 0 ? advertised.ask(context, decision, signal) : host.ask(context, decision, signal)
11574
+ },
11377
11575
  limit: options.agent?.limit ?? 8,
11378
11576
  select: (conversation, request, signal) => this.#select(conversation, request, signal)
11379
11577
  });
11380
- this.#agent.emitter.on("tool", (_call, result) => {
11578
+ const digest = digestLedgerTools(this.#agent.context.tools.definitions());
11579
+ const gauge = options.gauge ?? (snapshot?.gauge?.digest === digest ? snapshot?.gauge : void 0);
11580
+ if (gauge !== void 0) {
11581
+ this.#gauge = new Gauge({
11582
+ scale: gauge.scale,
11583
+ overhead: gauge.overhead,
11584
+ capacity: options.capacity,
11585
+ predict: this.#predict,
11586
+ replay: this.#replay
11587
+ });
11588
+ this.#digest = digest;
11589
+ }
11590
+ this.#agent.emitter.on("deny", (call, _reason, decision) => {
11591
+ if (decision !== void 0 && call.name !== "recall" && names.includes(call.name)) this.#current()?.deny(call.name, call.arguments);
11592
+ });
11593
+ this.#agent.emitter.on("tool", (call, result) => {
11381
11594
  this.#flush();
11382
11595
  this.#pending.set(this.#conversation.messages().length, result);
11383
- if (!result.success && result.error === LEDGER_NOTES.repeat) {
11596
+ const stopped = denyCall(call, LEDGER_NOTES.repeat);
11597
+ if (!result.success && (result.error === LEDGER_NOTES.repeat || !stopped.success && result.error === stopped.error)) {
11384
11598
  this.#current()?.close();
11385
11599
  this.#agent.abort("repeat");
11386
11600
  }
11601
+ const request = this.#current();
11602
+ if (request?.calls.at(-1)?.tools === 0) request.abort();
11603
+ this.#release(call, result);
11387
11604
  });
11388
11605
  this.#agent.emitter.on("select", (selection) => {
11389
11606
  if (isLedgerError(selection.fault) && selection.fault.code === "REQUEST") return;
@@ -11444,6 +11661,7 @@ var Ledger = class {
11444
11661
  const conversation = this.#conversation.snapshot();
11445
11662
  const ids = conversation.messages.map((message) => message.id);
11446
11663
  const gauge = this.gauge;
11664
+ const priced = this.#digest;
11447
11665
  const window = {
11448
11666
  exchanges: this.#window.map((entry) => ({
11449
11667
  request: entry.request.id,
@@ -11464,7 +11682,10 @@ var Ledger = class {
11464
11682
  requests: ids.filter((id) => this.#requests.has(id)),
11465
11683
  notes: ids.filter((id) => this.#annotations.has(id)),
11466
11684
  failures: ids.filter((id) => this.#results.get(id)?.success === false),
11467
- ...gauge === void 0 ? {} : { gauge },
11685
+ ...gauge === void 0 || priced === void 0 ? {} : { gauge: {
11686
+ ...gauge,
11687
+ digest: priced
11688
+ } },
11468
11689
  ...window.exchanges.length === 0 || digest === void 0 ? {} : { window: {
11469
11690
  ...window,
11470
11691
  digest
@@ -11473,6 +11694,7 @@ var Ledger = class {
11473
11694
  }
11474
11695
  /**
11475
11696
  * Appends a request and serves it, recovering an unfinished or rejected first pass with one answer pass.
11697
+ * In either pass, a call the model makes in a turn that advertises no tools runs nothing and ends the pass after that generation, whatever the agent's `limit`, and when every call of that turn failed, the ledger stores the reply without its calls: a reply with text ends the pass complete, and one without text ends it partial with empty content.
11476
11698
  * A calibration call that reports no prompt usage, or a prompt usage of 0 or less, rejects with `LedgerError` code `'GAUGE'`; a provider error during calibration rejects with that error.
11477
11699
  * When the answer pass rejects, `respond` rejects with that error, and under the default `strict` a judge failure or another selection failure rejects it too. A rejection belongs to its own call: the ledger stays free, and the next call asks the judge again about whatever is still unanswered.
11478
11700
  * @param content - The request text
@@ -11492,14 +11714,14 @@ var Ledger = class {
11492
11714
  if (this.#gauge === void 0) await this.#measureGauge(caller);
11493
11715
  const entered = request.enter(this.#conversation);
11494
11716
  this.#requests.add(entered.id);
11495
- const first = await this.#generatePass(request, caller, this.#options.think).catch((error) => {
11717
+ const first = this.#dropStrayCalls(request, await this.#generatePass(request, caller, this.#options.think).catch((error) => {
11496
11718
  if (request.faulted(error)) throw error;
11497
11719
  return {
11498
11720
  content: "",
11499
11721
  partial: true,
11500
11722
  ...request.usage === void 0 ? {} : { usage: request.usage }
11501
11723
  };
11502
- });
11724
+ }));
11503
11725
  const passes = [first];
11504
11726
  if (!caller.aborted && (first.partial || first.content.trim() === "")) {
11505
11727
  const recovery = this.#buildDigest(request, entered);
@@ -11527,7 +11749,7 @@ var Ledger = class {
11527
11749
  });
11528
11750
  this.#agent.context.apply(answer);
11529
11751
  try {
11530
- passes.push(await this.#generatePass(request, caller, false));
11752
+ passes.push(this.#dropStrayCalls(request, await this.#generatePass(request, caller, false)));
11531
11753
  } finally {
11532
11754
  if (this.#agent.context.scope === answer) this.#agent.context.apply(previous);
11533
11755
  }
@@ -11564,7 +11786,8 @@ var Ledger = class {
11564
11786
  }],
11565
11787
  judgments: []
11566
11788
  }), this.#replay).slice(0, -1);
11567
- const priced = await this.#provider.generate(messages, signal, this.#agent.context.tools.definitions(), { think: false });
11789
+ const definitions = this.#agent.context.tools.definitions();
11790
+ const priced = await this.#provider.generate(messages, signal, definitions, { think: false });
11568
11791
  const bare = await this.#provider.generate(messages, signal, void 0, { think: false });
11569
11792
  if (!(0, _orkestrel_contract.isFiniteNumber)(priced.usage?.prompt) || priced.usage.prompt <= 0 || !(0, _orkestrel_contract.isFiniteNumber)(bare.usage?.prompt) || bare.usage.prompt <= 0) throw new LedgerError("GAUGE", "calibration requires prompt usage from both calls");
11570
11793
  this.#gauge = new Gauge({
@@ -11574,6 +11797,7 @@ var Ledger = class {
11574
11797
  scale: bare.usage.prompt / estimateMessages(messages),
11575
11798
  overhead: Math.max(0, priced.usage.prompt - bare.usage.prompt)
11576
11799
  });
11800
+ this.#digest = digestLedgerTools(definitions);
11577
11801
  return {
11578
11802
  scale: this.#gauge.scale,
11579
11803
  overhead: this.#gauge.overhead
@@ -11585,12 +11809,35 @@ var Ledger = class {
11585
11809
  }
11586
11810
  async #generatePass(request, signal, think) {
11587
11811
  request.open(this.#conversation.messages().length);
11812
+ const stop = request.signal;
11588
11813
  return await this.#agent.generate({
11589
- signal,
11814
+ signal: stop === void 0 ? signal : AbortSignal.any([signal, stop]),
11590
11815
  conversation: this.#conversation,
11591
11816
  ...think === void 0 ? {} : { think }
11592
11817
  });
11593
11818
  }
11819
+ #dropStrayCalls(request, pass) {
11820
+ const boundary = request.boundary;
11821
+ if (!request.aborted || boundary === void 0) return pass;
11822
+ this.#flush();
11823
+ const messages = this.#conversation.messages().slice(boundary);
11824
+ const at = messages.findLastIndex((message) => message.role === "assistant");
11825
+ const reply = messages[at];
11826
+ const replies = messages.slice(at + 1);
11827
+ if (reply === void 0 || !hasCalls(reply) || !replies.every((message) => message.role === "tool" && this.#results.get(message.id)?.success === false)) return pass;
11828
+ this.#conversation.remove([reply.id, ...replies.map((message) => message.id)]);
11829
+ for (const message of replies) this.#results.delete(message.id);
11830
+ this.#conversation.add({
11831
+ role: "assistant",
11832
+ content: reply.content,
11833
+ ...reply.thinking === void 0 ? {} : { thinking: reply.thinking }
11834
+ });
11835
+ return {
11836
+ ...pass,
11837
+ content: reply.content,
11838
+ partial: reply.content.trim() === ""
11839
+ };
11840
+ }
11594
11841
  #current() {
11595
11842
  const [request] = this.#live;
11596
11843
  return request?.message === void 0 ? void 0 : request;
@@ -11680,27 +11927,36 @@ var Ledger = class {
11680
11927
  return collectToolGroups(messages).flatMap((group) => group.slice(1).flatMap((message) => {
11681
11928
  const call = findLedgerCall(group, message);
11682
11929
  const lookup = this.#options.lookups?.find((one) => one.tool.name === call?.name);
11683
- if (call === void 0 || lookup === void 0 || this.#results.get(message.id)?.success === false) return [];
11684
- const read = (0, _orkestrel_contract.attempt)(() => lookup.read(call.arguments, message.content));
11685
- if (!read.success) {
11930
+ const write = this.#options.writes?.find((one) => one.tool.name === call?.name);
11931
+ if (call === void 0 || lookup === void 0 && write === void 0 || this.#results.get(message.id)?.success === false) return [];
11932
+ const read = (0, _orkestrel_contract.attempt)(() => lookup?.read(call.arguments, message.content));
11933
+ const written = (0, _orkestrel_contract.attempt)(() => write?.read(call.arguments, message.content));
11934
+ if (!read.success || !written.success) {
11935
+ const error = read.success ? written.success ? void 0 : written.error : read.error;
11686
11936
  this.#results.set(message.id, {
11687
11937
  success: false,
11688
11938
  id: call.id,
11689
11939
  name: call.name,
11690
- error: (0, _orkestrel_contract.isError)(read.error) ? read.error.message : String(read.error)
11940
+ error: (0, _orkestrel_contract.isError)(error) ? error.message : String(error)
11691
11941
  });
11692
11942
  return [];
11693
11943
  }
11944
+ const literals = Object.values(call.arguments).filter(_orkestrel_contract.isString).flatMap((value) => [...extractLiterals(value).ids]);
11694
11945
  const result = read.value;
11946
+ const change = written.value;
11695
11947
  return [{
11696
11948
  id: message.id,
11697
11949
  name: call.name,
11698
11950
  arguments: call.arguments,
11699
11951
  text: message.content,
11700
- result: result === void 0 ? void 0 : {
11952
+ result: result !== void 0 ? {
11701
11953
  ...result,
11702
- ids: [.../* @__PURE__ */ new Set([...result.ids, ...Object.values(call.arguments).filter(_orkestrel_contract.isString).flatMap((value) => [...extractLiterals(value).ids])])]
11703
- }
11954
+ ids: [.../* @__PURE__ */ new Set([...result.ids, ...literals])]
11955
+ } : change !== void 0 ? {
11956
+ ids: [.../* @__PURE__ */ new Set([...change.ids, ...literals])],
11957
+ owners: change.owners
11958
+ } : void 0,
11959
+ ...change === void 0 ? {} : { targets: [...change.targets] }
11704
11960
  }];
11705
11961
  }));
11706
11962
  }
@@ -11712,7 +11968,7 @@ var Ledger = class {
11712
11968
  messages: scan.messages,
11713
11969
  findings: scan.findings,
11714
11970
  entities: new Map(scan.messages.map((message) => [message.id, [...matchEntities(scan.index, message.content, true)]])),
11715
- classification: this.#classifier.classification()
11971
+ classification: mergeSupersessions(this.#classifier.classification(), collectWriteSupersessions(scan.messages, scan.findings), scan.messages)
11716
11972
  };
11717
11973
  return {
11718
11974
  input,
@@ -12063,7 +12319,7 @@ var Ledger = class {
12063
12319
  kept: (leader.calls ?? []).flatMap((call) => {
12064
12320
  const message = group.slice(1).find((result) => findLedgerCall(group, result) === call);
12065
12321
  const result = message === void 0 ? void 0 : this.#results.get(message.id);
12066
- return message === void 0 || !this.#options.lookups?.some((lookup) => lookup.tool.name === call.name) || result?.success === false && result.error === LEDGER_NOTES.repeat ? [] : [{
12322
+ return message === void 0 || ![...this.#options.lookups ?? [], ...this.#options.writes ?? []].some((entry) => entry.tool.name === call.name) || result?.success === false && result.error === LEDGER_NOTES.repeat ? [] : [{
12067
12323
  call,
12068
12324
  message
12069
12325
  }];
@@ -12109,19 +12365,48 @@ var Ledger = class {
12109
12365
  #renderTailStub(message, scan, shown) {
12110
12366
  const group = scan.group(message.id);
12111
12367
  const call = group === void 0 ? void 0 : findLedgerCall(group, message);
12368
+ const write = this.#options.writes?.some((one) => one.tool.name === call?.name) === true;
12112
12369
  const finding = scan.finding(message.id);
12113
12370
  const hidden = renderStub(call?.name ?? "tool", call?.arguments ?? {}, "hidden");
12114
12371
  const visible = renderStub(call?.name ?? "tool", call?.arguments ?? {}, "shown");
12115
12372
  return {
12116
12373
  ...message,
12117
- content: renderStub(call?.name ?? "tool", call?.arguments ?? {}, this.#results.get(message.id)?.success === false ? "failed" : finding?.result === void 0 ? "empty" : shown === void 0 ? hidden.length > visible.length ? "hidden" : "shown" : scan.findings.some((other) => shown.has(other.id) && matchesLookup(finding, other)) ? "shown" : "hidden")
12374
+ content: renderStub(call?.name ?? "tool", call?.arguments ?? {}, this.#results.get(message.id)?.success === false ? "failed" : finding?.result === void 0 ? "empty" : shown === void 0 ? hidden.length > visible.length ? "hidden" : "shown" : scan.findings.some((other) => shown.has(other.id) && matchesLookup(finding, other)) ? "shown" : "hidden", write)
12118
12375
  };
12119
12376
  }
12377
+ #release(call, result) {
12378
+ const request = this.#current();
12379
+ const write = this.#options.writes?.find((one) => one.tool.name === call.name);
12380
+ if (request === void 0 || write === void 0 || !result.success) return;
12381
+ const text = settleToolResult(result).content;
12382
+ const read = (0, _orkestrel_contract.attempt)(() => {
12383
+ const change = write.read(call.arguments, text);
12384
+ return change === void 0 ? [] : [...change.targets];
12385
+ });
12386
+ if (!read.success || read.value.length === 0) return;
12387
+ const messages = this.#conversation.messages();
12388
+ const findings = this.#readLookups(messages);
12389
+ const id = crypto.randomUUID();
12390
+ const edges = collectWriteSupersessions([...messages, {
12391
+ id,
12392
+ role: "tool",
12393
+ content: text,
12394
+ call: call.id
12395
+ }], [...findings, {
12396
+ id,
12397
+ name: call.name,
12398
+ arguments: call.arguments,
12399
+ text,
12400
+ result: void 0,
12401
+ targets: read.value
12402
+ }]);
12403
+ for (const finding of findings) if ((edges.get(finding.id) ?? []).includes(id) && this.#options.lookups?.some((lookup) => lookup.tool.name === finding.name) === true) request.release(finding.name, finding.arguments);
12404
+ }
12120
12405
  #observeTurn() {
12121
12406
  this.#flush();
12122
12407
  const request = this.#current();
12123
12408
  const boundary = request?.boundary;
12124
- if (request === void 0 || boundary === void 0) return;
12409
+ if (request === void 0 || boundary === void 0 || request.aborted) return;
12125
12410
  const additions = this.#conversation.messages().slice(boundary);
12126
12411
  const messages = this.#agent.context.build(request.selection);
12127
12412
  const names = this.#agent.context.scope?.tools;
@@ -12142,10 +12427,17 @@ var Ledger = class {
12142
12427
  return this.#conversation.messages().filter((message) => message.role === "assistant").reduce((longest, message) => message.content.length > longest.length ? message.content : longest, "");
12143
12428
  }
12144
12429
  #lookup(name, args, context) {
12145
- this.#current()?.admit(name, args);
12146
- const lookup = this.#options.lookups?.find((one) => one.tool.name === name);
12147
- if (lookup === void 0) throw new Error(`unknown lookup ${name}`);
12148
- return lookup.tool.execute(args, context);
12430
+ const request = this.#current();
12431
+ request?.admit(name, args);
12432
+ const entry = this.#options.lookups?.find((one) => one.tool.name === name) ?? this.#options.writes?.find((one) => one.tool.name === name);
12433
+ if (entry === void 0) throw new Error(`unknown lookup or write ${name}`);
12434
+ const ran = (0, _orkestrel_contract.attempt)(() => entry.tool.execute(args, context));
12435
+ if (!ran.success) return this.#reject(request, name, args, ran.error);
12436
+ return (0, _orkestrel_contract.isPromiseLike)(ran.value) ? Promise.resolve(ran.value).catch((error) => this.#reject(request, name, args, error)) : ran.value;
12437
+ }
12438
+ #reject(request, name, args, error) {
12439
+ if ((0, _orkestrel_tool.isToolError)(error) && error.code === "ARGUMENTS") request?.release(name, args);
12440
+ throw error;
12149
12441
  }
12150
12442
  #recall(args) {
12151
12443
  const request = this.#current();
@@ -12183,7 +12475,8 @@ var Ledger = class {
12183
12475
  };
12184
12476
  });
12185
12477
  const start = request?.message === void 0 ? -1 : scan.position(request.message.id) ?? -1;
12186
- const listable = new Map(input.messages.filter((message, at) => !this.#requests.has(message.id) && (at < start || message.role === "tool")).map((message) => [message.id, message]));
12478
+ const retired = collectRetiredFindings(scan.messages, scan.findings);
12479
+ const listable = new Map(input.messages.filter((message, at) => !this.#requests.has(message.id) && !retired.has(message.id) && (at < start || message.role === "tool")).map((message) => [message.id, message]));
12187
12480
  const matched = new Set(searches.flatMap((search) => [...search.matched]));
12188
12481
  const unmatched = searches.filter((search) => search.matched.size === 0 && search.words.length > 0);
12189
12482
  const gathered = [...listable.values()].reverse().reduce((state, message) => {
@@ -12428,7 +12721,10 @@ exports.collectNames = collectNames;
12428
12721
  exports.collectProjectionIds = collectProjectionIds;
12429
12722
  exports.collectRecallMessages = collectRecallMessages;
12430
12723
  exports.collectRegistry = collectRegistry;
12724
+ exports.collectRetiredFindings = collectRetiredFindings;
12431
12725
  exports.collectToolGroups = collectToolGroups;
12726
+ exports.collectWriteSupersessions = collectWriteSupersessions;
12727
+ exports.computeLedgerChecksum = computeLedgerChecksum;
12432
12728
  exports.computeThinking = computeThinking;
12433
12729
  exports.conversationSnapshotContract = conversationSnapshotContract;
12434
12730
  exports.conversationSnapshotShape = conversationSnapshotShape;
@@ -12463,6 +12759,7 @@ exports.denyCall = denyCall;
12463
12759
  exports.describeQuestionRefusal = describeQuestionRefusal;
12464
12760
  exports.describeRelayRefusal = describeRelayRefusal;
12465
12761
  exports.describeSnapshotRefusal = describeSnapshotRefusal;
12762
+ exports.digestLedgerTools = digestLedgerTools;
12466
12763
  exports.digestLedgerWindow = digestLedgerWindow;
12467
12764
  exports.estimateMessages = estimateMessages;
12468
12765
  exports.estimateRequest = estimateRequest;
@@ -12540,6 +12837,7 @@ exports.memoContract = memoContract;
12540
12837
  exports.memoShape = memoShape;
12541
12838
  exports.memoSnapshotContract = memoSnapshotContract;
12542
12839
  exports.memoSnapshotShape = memoSnapshotShape;
12840
+ exports.mergeSupersessions = mergeSupersessions;
12543
12841
  exports.messageContract = messageContract;
12544
12842
  exports.messageInputContract = messageInputContract;
12545
12843
  exports.messageInputShape = messageInputShape;