@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.
- package/dist/src/core/index.cjs +364 -66
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +299 -32
- package/dist/src/core/index.d.ts +299 -32
- package/dist/src/core/index.js +362 -69
- package/dist/src/core/index.js.map +1 -1
- package/package.json +11 -11
package/dist/src/core/index.cjs
CHANGED
|
@@ -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
|
-
|
|
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
|
|
9002
|
-
* statements available through recall's word route,
|
|
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
|
|
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,
|
|
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
|
|
11208
|
-
* `overhead` of at least 0
|
|
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 !==
|
|
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
|
|
11343
|
-
name:
|
|
11344
|
-
...
|
|
11345
|
-
...
|
|
11346
|
-
...
|
|
11347
|
-
...
|
|
11348
|
-
...
|
|
11349
|
-
execute: (args, context) => this.#lookup(
|
|
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:
|
|
11366
|
-
|
|
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:
|
|
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.
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
11684
|
-
|
|
11685
|
-
|
|
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)(
|
|
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
|
|
11952
|
+
result: result !== void 0 ? {
|
|
11701
11953
|
...result,
|
|
11702
|
-
ids: [.../* @__PURE__ */ new Set([...result.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
|
|
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()
|
|
12146
|
-
|
|
12147
|
-
|
|
12148
|
-
|
|
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
|
|
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;
|