@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.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ContractError, INTRINSICS, arrayOf, arrayShape, attempt, booleanShape, boundsOf, canonicalStringify, cloneJSONValue, createContract, describeFaults, errorToMessage, failure, holds, isArray, isBoolean, isError, isFiniteNumber, isFunction, isJSONValue, isNumber, isObject, isRecord, isString, jsonShape, literalShape, nullableOf, nullableShape, numberShape, objectOf, objectShape, optionalOf, optionalShape, parseJSON, parseJSONAs, parseJSONValue, preview, rawShape, recordOf, recordShape, schemaToShape, stringShape, success, unionOf, unionShape } from "@orkestrel/contract";
|
|
1
|
+
import { ContractError, INTRINSICS, arrayOf, arrayShape, attempt, booleanShape, boundsOf, canonicalStringify, cloneJSONValue, createContract, describeFaults, errorToMessage, failure, holds, isArray, isBoolean, isError, isFiniteNumber, isFunction, isJSONValue, isNumber, isObject, isPromiseLike, isRecord, isString, jsonShape, literalShape, nullableOf, nullableShape, numberShape, objectOf, objectShape, optionalOf, optionalShape, parseJSON, parseJSONAs, parseJSONValue, preview, rawShape, recordOf, recordShape, schemaToShape, stringShape, success, unionOf, unionShape } from "@orkestrel/contract";
|
|
2
2
|
import { createTokenBudget, createTokenMeter, isBudget, isBudgetAmount, isBudgetError, isTokenUsage } from "@orkestrel/budget";
|
|
3
|
-
import { ToolManager, createTool, createToolManager, isToolCall } from "@orkestrel/tool";
|
|
3
|
+
import { ToolManager, createTool, createToolManager, isToolCall, isToolError } from "@orkestrel/tool";
|
|
4
4
|
import { createNDJSONParser } from "@orkestrel/ndjson";
|
|
5
5
|
import { Timeout, createTimeout } from "@orkestrel/timeout";
|
|
6
6
|
import { createDatabase, createMemoryDriver } from "@orkestrel/database";
|
|
@@ -8908,7 +8908,7 @@ var DETERMINISTIC_JUDGE_ERROR = /invalid or duplicate top logprob token/;
|
|
|
8908
8908
|
* carrying the machine-readable `code`.
|
|
8909
8909
|
*
|
|
8910
8910
|
* @remarks
|
|
8911
|
-
* A threshold, share, capacity, limit, topic, lookup, question, or gauge outside its bounds is a
|
|
8911
|
+
* A threshold, share, capacity, limit, topic, lookup, write, question, or gauge outside its bounds is a
|
|
8912
8912
|
* programmer error and throws this with the matching {@link LedgerErrorCode}. A calibration call that reports
|
|
8913
8913
|
* no prompt usage throws this with `'GAUGE'`. A snapshot option that `isLedgerSnapshot` refuses
|
|
8914
8914
|
* throws this with `'SNAPSHOT'`, its `context` holding the `faults`. Narrow a caught value with {@link isLedgerError} and
|
|
@@ -8952,7 +8952,7 @@ function isLedgerError(value) {
|
|
|
8952
8952
|
return holds(() => {
|
|
8953
8953
|
if (!(value instanceof Error && INTRINSICS.prototype(value) !== Error.prototype && INTRINSICS.describe(value, Symbol.for("@orkestrel/agent.LedgerError"))?.value === value)) return false;
|
|
8954
8954
|
const code = INTRINSICS.reflect.read(value, "code");
|
|
8955
|
-
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;
|
|
8955
|
+
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;
|
|
8956
8956
|
const context = INTRINSICS.reflect.read(value, "context");
|
|
8957
8957
|
return context === void 0 || isObject(context) || isFunction(context);
|
|
8958
8958
|
});
|
|
@@ -8982,7 +8982,43 @@ function digestLedgerWindow(exchanges, messages) {
|
|
|
8982
8982
|
return values.some((value) => value === void 0) ? void 0 : canonicalStringify([values, exchanges.map((entry) => [entry.copy ?? null, entry.lines])]);
|
|
8983
8983
|
});
|
|
8984
8984
|
if (!encoded.success || encoded.value === void 0) return void 0;
|
|
8985
|
-
|
|
8985
|
+
return computeLedgerChecksum(encoded.value);
|
|
8986
|
+
}
|
|
8987
|
+
/**
|
|
8988
|
+
* Digests tool definitions as the JSON a provider request carries them, in order.
|
|
8989
|
+
*
|
|
8990
|
+
* @remarks
|
|
8991
|
+
* A ledger stores this digest with its gauge, so a hydrate reuses the gauge only for the same
|
|
8992
|
+
* definitions: an added, removed, reordered, or edited definition changes the digest. The digest is
|
|
8993
|
+
* a {@link computeLedgerChecksum} checksum and makes no security claim.
|
|
8994
|
+
*
|
|
8995
|
+
* @param definitions - The tool definitions, as a tool manager's `definitions` method returns them
|
|
8996
|
+
* @returns The 16-digit hexadecimal digest, or undefined when JSON cannot render the definitions
|
|
8997
|
+
* @example
|
|
8998
|
+
* ```ts
|
|
8999
|
+
* digestLedgerTools([{ name: 'lookup_order', description: 'Read an order by its id.' }]) // '1eff754a69b7128c'
|
|
9000
|
+
* ```
|
|
9001
|
+
*/
|
|
9002
|
+
function digestLedgerTools(definitions) {
|
|
9003
|
+
const text = renderJSON(definitions);
|
|
9004
|
+
return text === void 0 ? void 0 : computeLedgerChecksum(text);
|
|
9005
|
+
}
|
|
9006
|
+
/**
|
|
9007
|
+
* Computes a checksum of text: two 32-bit FNV-1a lanes over its code points, as 16 hexadecimal digits.
|
|
9008
|
+
*
|
|
9009
|
+
* @remarks
|
|
9010
|
+
* The checksum detects an edit, can collide, and makes no security claim. Over ASCII text, the first
|
|
9011
|
+
* lane is the standard 32-bit FNV-1a hash.
|
|
9012
|
+
*
|
|
9013
|
+
* @param text - The text to checksum
|
|
9014
|
+
* @returns The 16-digit lowercase hexadecimal checksum
|
|
9015
|
+
* @example
|
|
9016
|
+
* ```ts
|
|
9017
|
+
* computeLedgerChecksum('a') // 'e40c292ce457465e'
|
|
9018
|
+
* ```
|
|
9019
|
+
*/
|
|
9020
|
+
function computeLedgerChecksum(text) {
|
|
9021
|
+
const hash = [...text].reduce((prior, character) => {
|
|
8986
9022
|
const code = character.codePointAt(0) ?? 0;
|
|
8987
9023
|
return {
|
|
8988
9024
|
first: Math.imul(prior.first ^ code, 16777619) >>> 0,
|
|
@@ -8997,19 +9033,21 @@ function digestLedgerWindow(exchanges, messages) {
|
|
|
8997
9033
|
/**
|
|
8998
9034
|
* Collects stored messages eligible to open the recall offer.
|
|
8999
9035
|
* @remarks
|
|
9000
|
-
* Notes
|
|
9001
|
-
* statements available through recall's word route,
|
|
9036
|
+
* Notes, findings without a result, and findings {@link collectRetiredFindings} names do not open
|
|
9037
|
+
* the offer. User statements, including quiet statements available through recall's word route,
|
|
9038
|
+
* can open it; this helper does not filter results.
|
|
9002
9039
|
* @param input - The messages, findings, and classification
|
|
9003
9040
|
* @param requests - The marked request ids
|
|
9004
9041
|
* @param notes - The annotation ids to exclude
|
|
9005
|
-
* @returns User statements, lookup findings with results, marked requests, and nonblank call-free replies
|
|
9042
|
+
* @returns User statements, lookup findings with results that no write superseded and no later finding replaced, marked requests, and nonblank call-free replies
|
|
9006
9043
|
* @example
|
|
9007
9044
|
* ```ts
|
|
9008
9045
|
* collectRecallMessages(input, new Set(), new Set()) // eligible stored messages
|
|
9009
9046
|
* ```
|
|
9010
9047
|
*/
|
|
9011
9048
|
function collectRecallMessages(input, requests, notes) {
|
|
9012
|
-
const
|
|
9049
|
+
const retired = collectRetiredFindings(input.messages, input.findings);
|
|
9050
|
+
const findings = new Set(input.findings.filter((finding) => finding.result !== void 0 && !retired.has(finding.id)).map((finding) => finding.id));
|
|
9013
9051
|
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)));
|
|
9014
9052
|
}
|
|
9015
9053
|
/**
|
|
@@ -9907,6 +9945,7 @@ function matchesCutLine(line) {
|
|
|
9907
9945
|
* @param name - The lookup tool name
|
|
9908
9946
|
* @param args - The arguments the call carried; arguments JSON cannot carry leave the call as its bare tool name, per {@link renderLookupCall}
|
|
9909
9947
|
* @param state - What became of the result: `failed`, `empty`, `shown` in the records, or `hidden` from them
|
|
9948
|
+
* @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`
|
|
9910
9949
|
* @returns The stub text, which carries the call and its state
|
|
9911
9950
|
*
|
|
9912
9951
|
* @example
|
|
@@ -9915,10 +9954,10 @@ function matchesCutLine(line) {
|
|
|
9915
9954
|
* // 'lookup_order {"id":"BW-5512"}: result not shown; call recall with BW-5512'
|
|
9916
9955
|
* ```
|
|
9917
9956
|
*/
|
|
9918
|
-
function renderStub(name, args, state) {
|
|
9957
|
+
function renderStub(name, args, state, write = false) {
|
|
9919
9958
|
const head = renderLookupCall(name, args);
|
|
9920
9959
|
if (state === "failed") return `${head}: failed`;
|
|
9921
|
-
if (state === "empty") return `${head}: no record`;
|
|
9960
|
+
if (state === "empty") return write ? `${head}: changed nothing` : `${head}: no record`;
|
|
9922
9961
|
if (state === "shown") return `${head}: result shown under Records below`;
|
|
9923
9962
|
return `${head}: result not shown; call recall with ${(Object.values(args).find(isString) ?? "").trim() || "its id"}`;
|
|
9924
9963
|
}
|
|
@@ -9965,7 +10004,8 @@ function fitSlope(groups) {
|
|
|
9965
10004
|
* or superseded. When the whole run is superseded, its first finding reaches that final filter.
|
|
9966
10005
|
* Different text or an undefined result replaces the earlier run, so an empty lookup leaves the
|
|
9967
10006
|
* earlier result out of every record. A thrown lookup leaves the earlier result live. A finding
|
|
9968
|
-
* with no canonical identity participates in no replacement.
|
|
10007
|
+
* with no canonical identity participates in no replacement. A finding a write retired is
|
|
10008
|
+
* superseded once {@link mergeSupersessions} merges the write's edges into the classification.
|
|
9969
10009
|
*
|
|
9970
10010
|
* @param input - The messages, findings, and classification to read
|
|
9971
10011
|
* @returns The live message ids
|
|
@@ -9992,6 +10032,100 @@ function collectLive(input) {
|
|
|
9992
10032
|
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);
|
|
9993
10033
|
}
|
|
9994
10034
|
/**
|
|
10035
|
+
* Collects each finding a write made stale, mapped to the writes that supersede it.
|
|
10036
|
+
*
|
|
10037
|
+
* @remarks
|
|
10038
|
+
* A write is a finding with `targets`. It supersedes another finding whose names meet its targets
|
|
10039
|
+
* when that finding comes before it in conversation order, or sits in its own tool group and
|
|
10040
|
+
* carries no targets, because one batch dispatches its calls at once. So the later of two writes in
|
|
10041
|
+
* one group supersedes the earlier, and never the reverse. A finding's names are its result's `ids`
|
|
10042
|
+
* and owner ids, or, for an empty finding, the ids its string arguments name, as `extractLiterals`
|
|
10043
|
+
* reads them. Names and targets compare exactly. A write never supersedes itself, a finding with
|
|
10044
|
+
* empty `targets` supersedes nothing, and a finding the messages don't hold takes no part.
|
|
10045
|
+
*
|
|
10046
|
+
* @param messages - The conversation's messages, which fix each finding's position and tool group
|
|
10047
|
+
* @param findings - The lookup and write findings of those messages
|
|
10048
|
+
* @returns Each superseded finding's id, in conversation order, mapped to the ids of the writes that supersede it, in conversation order
|
|
10049
|
+
*
|
|
10050
|
+
* @example
|
|
10051
|
+
* ```ts
|
|
10052
|
+
* collectWriteSupersessions(messages, findings) // Map { 'tool-1' => ['tool-2'] } when tool-2 wrote what tool-1 read
|
|
10053
|
+
* ```
|
|
10054
|
+
*/
|
|
10055
|
+
function collectWriteSupersessions(messages, findings) {
|
|
10056
|
+
if (!findings.some((finding) => (finding.targets ?? []).length > 0)) return /* @__PURE__ */ new Map();
|
|
10057
|
+
const positions = new Map(messages.map((message, at) => [message.id, at]));
|
|
10058
|
+
const groups = new Map(collectToolGroups(messages).flatMap((group, at) => group.map((message) => [message.id, at])));
|
|
10059
|
+
const held = findings.filter((finding) => positions.has(finding.id)).toSorted((left, right) => (positions.get(left.id) ?? 0) - (positions.get(right.id) ?? 0));
|
|
10060
|
+
const writes = held.filter((finding) => (finding.targets ?? []).length > 0);
|
|
10061
|
+
return new Map(held.flatMap((finding) => {
|
|
10062
|
+
const names = new Set(finding.result === void 0 ? Object.values(finding.arguments).filter(isString).flatMap((value) => [...extractLiterals(value).ids]) : [...finding.result.ids, ...finding.result.owners.map((owner) => owner.id)]);
|
|
10063
|
+
const at = positions.get(finding.id) ?? 0;
|
|
10064
|
+
const group = groups.get(finding.id);
|
|
10065
|
+
const targeted = (finding.targets ?? []).length > 0;
|
|
10066
|
+
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));
|
|
10067
|
+
return superseders.length === 0 ? [] : [[finding.id, superseders.map((write) => write.id)]];
|
|
10068
|
+
}));
|
|
10069
|
+
}
|
|
10070
|
+
/**
|
|
10071
|
+
* Collects the findings a write superseded or a later finding of the same lookup replaced.
|
|
10072
|
+
*
|
|
10073
|
+
* @remarks
|
|
10074
|
+
* A write supersedes the findings {@link collectWriteSupersessions} maps. A later finding of the
|
|
10075
|
+
* same canonical lookup identity, as {@link identifyLookup} writes it, replaces an earlier one when
|
|
10076
|
+
* its text differs or it holds no result, and a later finding with the same text replaces nothing.
|
|
10077
|
+
* A finding with no canonical identity is never replaced, and a finding the messages don't hold
|
|
10078
|
+
* takes no part. A supersession the judge files is not read here.
|
|
10079
|
+
*
|
|
10080
|
+
* @param messages - The conversation's messages, which fix each finding's position
|
|
10081
|
+
* @param findings - The lookup and write findings of those messages
|
|
10082
|
+
* @returns The ids of the superseded and replaced findings
|
|
10083
|
+
*
|
|
10084
|
+
* @example
|
|
10085
|
+
* ```ts
|
|
10086
|
+
* collectRetiredFindings(messages, findings) // Set { 'tool-1' } when tool-2 wrote what tool-1 read
|
|
10087
|
+
* ```
|
|
10088
|
+
*/
|
|
10089
|
+
function collectRetiredFindings(messages, findings) {
|
|
10090
|
+
const positions = new Map(messages.map((message, at) => [message.id, at]));
|
|
10091
|
+
const held = findings.filter((finding) => positions.has(finding.id));
|
|
10092
|
+
const replaced = [...Map.groupBy(held, (finding) => identifyLookup(finding.name, finding.arguments) ?? finding).values()].flatMap((group) => {
|
|
10093
|
+
const ordered = group.toSorted((left, right) => (positions.get(left.id) ?? 0) - (positions.get(right.id) ?? 0));
|
|
10094
|
+
const last = ordered.at(-1);
|
|
10095
|
+
const boundary = last === void 0 ? -1 : ordered.findLastIndex((finding) => finding.result === void 0 || finding.text !== last.text);
|
|
10096
|
+
return ordered.slice(0, Math.min(boundary + 1, ordered.length - 1)).map((finding) => finding.id);
|
|
10097
|
+
});
|
|
10098
|
+
return /* @__PURE__ */ new Set([...collectWriteSupersessions(messages, findings).keys(), ...replaced]);
|
|
10099
|
+
}
|
|
10100
|
+
/**
|
|
10101
|
+
* Merges supersession edges into a classification, adding each edge to both its supersessions and its amendments.
|
|
10102
|
+
*
|
|
10103
|
+
* @remarks
|
|
10104
|
+
* Each earlier message's later ids stay distinct and in conversation order, so every supersession
|
|
10105
|
+
* is still an amendment, as the classifier files one. An empty edge map returns the classification
|
|
10106
|
+
* itself.
|
|
10107
|
+
*
|
|
10108
|
+
* @param classification - The judged classification
|
|
10109
|
+
* @param edges - The later ids that supersede each earlier id, such as {@link collectWriteSupersessions} returns
|
|
10110
|
+
* @param messages - The conversation's messages, which order the later ids
|
|
10111
|
+
* @returns The classification with the edges merged
|
|
10112
|
+
*
|
|
10113
|
+
* @example
|
|
10114
|
+
* ```ts
|
|
10115
|
+
* mergeSupersessions(classification, new Map([['tool-1', ['tool-2']]]), messages).supersessions.get('tool-1') // ['tool-2']
|
|
10116
|
+
* ```
|
|
10117
|
+
*/
|
|
10118
|
+
function mergeSupersessions(classification, edges, messages) {
|
|
10119
|
+
if (edges.size === 0) return classification;
|
|
10120
|
+
const positions = new Map(messages.map((message, at) => [message.id, at]));
|
|
10121
|
+
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))])));
|
|
10122
|
+
return {
|
|
10123
|
+
...classification,
|
|
10124
|
+
amendments,
|
|
10125
|
+
supersessions
|
|
10126
|
+
};
|
|
10127
|
+
}
|
|
10128
|
+
/**
|
|
9995
10129
|
* Places a message on the record keys it joins.
|
|
9996
10130
|
*
|
|
9997
10131
|
* @remarks
|
|
@@ -10651,7 +10785,8 @@ var Gauge = class {
|
|
|
10651
10785
|
// src/core/ledgers/LedgerPass.ts
|
|
10652
10786
|
/**
|
|
10653
10787
|
* Holds what one pass of a ledger request keeps: the selection its run adopted last, the
|
|
10654
|
-
* conversation boundary its calls count additions from, its summed usage,
|
|
10788
|
+
* conversation boundary its calls count additions from, its summed usage, its gauge calls, and the
|
|
10789
|
+
* abort that ends its run.
|
|
10655
10790
|
*
|
|
10656
10791
|
* @remarks
|
|
10657
10792
|
* A `LedgerRequest` opens one pass per agent run and exposes only projections of it, so no public
|
|
@@ -10665,6 +10800,7 @@ var LedgerPass = class {
|
|
|
10665
10800
|
#selection;
|
|
10666
10801
|
#boundary;
|
|
10667
10802
|
#usage;
|
|
10803
|
+
#abort = createAbort();
|
|
10668
10804
|
/**
|
|
10669
10805
|
* Opens the pass at a conversation boundary.
|
|
10670
10806
|
*
|
|
@@ -10698,6 +10834,22 @@ var LedgerPass = class {
|
|
|
10698
10834
|
return this.#usage;
|
|
10699
10835
|
}
|
|
10700
10836
|
/**
|
|
10837
|
+
* Returns the signal `abort` aborts.
|
|
10838
|
+
*
|
|
10839
|
+
* @returns The pass's abort signal
|
|
10840
|
+
*/
|
|
10841
|
+
get signal() {
|
|
10842
|
+
return this.#abort.signal;
|
|
10843
|
+
}
|
|
10844
|
+
/**
|
|
10845
|
+
* Reports whether `abort` ended the pass.
|
|
10846
|
+
*
|
|
10847
|
+
* @returns True if the pass was aborted; false otherwise
|
|
10848
|
+
*/
|
|
10849
|
+
get aborted() {
|
|
10850
|
+
return this.#abort.signal.aborted;
|
|
10851
|
+
}
|
|
10852
|
+
/**
|
|
10701
10853
|
* Returns the call in flight.
|
|
10702
10854
|
*
|
|
10703
10855
|
* @returns The latest call the pass observed, or undefined before one
|
|
@@ -10791,6 +10943,10 @@ var LedgerPass = class {
|
|
|
10791
10943
|
think(thinking) {
|
|
10792
10944
|
this.#log = [...this.#log, { thinking }];
|
|
10793
10945
|
}
|
|
10946
|
+
/** Aborts the pass's run through `signal`, with the reason `'stray'`; a later call changes nothing. */
|
|
10947
|
+
abort() {
|
|
10948
|
+
this.#abort.abort("stray");
|
|
10949
|
+
}
|
|
10794
10950
|
};
|
|
10795
10951
|
// src/core/ledgers/LedgerRequest.ts
|
|
10796
10952
|
/**
|
|
@@ -10824,6 +10980,7 @@ var LedgerRequest = class {
|
|
|
10824
10980
|
#passes = [];
|
|
10825
10981
|
#attempts = [];
|
|
10826
10982
|
#admitted = /* @__PURE__ */ new Set();
|
|
10983
|
+
#denials = /* @__PURE__ */ new Set();
|
|
10827
10984
|
#listed = [];
|
|
10828
10985
|
#recalls = 0;
|
|
10829
10986
|
#closed = false;
|
|
@@ -10905,6 +11062,22 @@ var LedgerRequest = class {
|
|
|
10905
11062
|
get attempts() {
|
|
10906
11063
|
return this.#attempts;
|
|
10907
11064
|
}
|
|
11065
|
+
/**
|
|
11066
|
+
* Returns the signal `abort` aborts for the current pass's run.
|
|
11067
|
+
*
|
|
11068
|
+
* @returns The current pass's abort signal, or undefined before a pass
|
|
11069
|
+
*/
|
|
11070
|
+
get signal() {
|
|
11071
|
+
return this.#passes.at(-1)?.signal;
|
|
11072
|
+
}
|
|
11073
|
+
/**
|
|
11074
|
+
* Reports whether `abort` ended the current pass.
|
|
11075
|
+
*
|
|
11076
|
+
* @returns True if the current pass was aborted; false otherwise, and before a pass
|
|
11077
|
+
*/
|
|
11078
|
+
get aborted() {
|
|
11079
|
+
return this.#passes.at(-1)?.aborted ?? false;
|
|
11080
|
+
}
|
|
10908
11081
|
enter(conversation) {
|
|
10909
11082
|
if (this.#message !== void 0) return this.#message;
|
|
10910
11083
|
this.#message = conversation.add({
|
|
@@ -10919,6 +11092,9 @@ var LedgerRequest = class {
|
|
|
10919
11092
|
adopt(selection, boundary) {
|
|
10920
11093
|
this.#passes.at(-1)?.adopt(selection, boundary);
|
|
10921
11094
|
}
|
|
11095
|
+
abort() {
|
|
11096
|
+
this.#passes.at(-1)?.abort();
|
|
11097
|
+
}
|
|
10922
11098
|
observe(call, position) {
|
|
10923
11099
|
const draft = this.#draft;
|
|
10924
11100
|
this.#sent = draft !== void 0 && this.selection?.messages.some((message) => message.id === draft.copy.id && message.content === draft.copy.content) ? draft : void 0;
|
|
@@ -10953,6 +11129,18 @@ var LedgerRequest = class {
|
|
|
10953
11129
|
if (this.#admitted.has(key)) throw new Error(LEDGER_NOTES.repeat);
|
|
10954
11130
|
this.#admitted = /* @__PURE__ */ new Set([...this.#admitted, key]);
|
|
10955
11131
|
}
|
|
11132
|
+
release(name, args) {
|
|
11133
|
+
const key = canonicalStringify([name, args]);
|
|
11134
|
+
this.#admitted = new Set([...this.#admitted].filter((admitted) => admitted !== key));
|
|
11135
|
+
}
|
|
11136
|
+
deny(name, args) {
|
|
11137
|
+
const key = canonicalStringify([name, args]);
|
|
11138
|
+
if (key !== void 0) this.#denials = /* @__PURE__ */ new Set([...this.#denials, key]);
|
|
11139
|
+
}
|
|
11140
|
+
denied(name, args) {
|
|
11141
|
+
const key = canonicalStringify([name, args]);
|
|
11142
|
+
return key !== void 0 && this.#denials.has(key);
|
|
11143
|
+
}
|
|
10956
11144
|
recall() {
|
|
10957
11145
|
if (this.#recalls >= this.#limit) this.#closed = true;
|
|
10958
11146
|
if (this.#closed) throw new Error(LEDGER_NOTES.closure);
|
|
@@ -11128,7 +11316,8 @@ var ledgerSnapshotShape = objectShape({
|
|
|
11128
11316
|
failures: arrayShape(stringShape()),
|
|
11129
11317
|
gauge: optionalShape(objectShape({
|
|
11130
11318
|
scale: numberShape(),
|
|
11131
|
-
overhead: numberShape()
|
|
11319
|
+
overhead: numberShape(),
|
|
11320
|
+
digest: stringShape()
|
|
11132
11321
|
})),
|
|
11133
11322
|
window: optionalShape(ledgerWindowShape)
|
|
11134
11323
|
});
|
|
@@ -11203,8 +11392,8 @@ function isLedgerQuestion(value) {
|
|
|
11203
11392
|
* `conversation` must pass `isConversationSnapshot`, and `requests`, `notes`, and `failures` must be
|
|
11204
11393
|
* dense arrays of strings. Each request and note id must name a `user` message of
|
|
11205
11394
|
* `conversation.messages` and each failure id a `tool` message, so an id only a section original
|
|
11206
|
-
* holds is refused. A `gauge`, when present, must hold a finite `scale` greater than 0
|
|
11207
|
-
* `overhead` of at least 0
|
|
11395
|
+
* holds is refused. A `gauge`, when present, must hold a finite `scale` greater than 0, a finite
|
|
11396
|
+
* `overhead` of at least 0, and a string `digest`. The guard is exact: an unknown member and an own `undefined` `gauge` return
|
|
11208
11397
|
* false, at the snapshot and in its `gauge`. Unreadable members and untrusted inputs return false. The
|
|
11209
11398
|
* guard is structural: it admits a conversation holding a stored `system` role
|
|
11210
11399
|
* or a repeated id, which `requireConversationSnapshot` and the `Conversation` constructor then
|
|
@@ -11230,9 +11419,9 @@ function isLedgerSnapshot(value) {
|
|
|
11230
11419
|
const isIds = arrayOf(isString);
|
|
11231
11420
|
if (!isIds(requests) || !isIds(notes) || !isIds(failures)) return false;
|
|
11232
11421
|
if (gauge !== void 0) {
|
|
11233
|
-
if (!isRecord(gauge) || Object.keys(gauge).length !==
|
|
11234
|
-
const { scale, overhead } = gauge;
|
|
11235
|
-
if (!isFiniteNumber(scale) || scale <= 0 || !isFiniteNumber(overhead) || overhead < 0) return false;
|
|
11422
|
+
if (!isRecord(gauge) || Object.keys(gauge).length !== 3) return false;
|
|
11423
|
+
const { scale, overhead, digest } = gauge;
|
|
11424
|
+
if (!isFiniteNumber(scale) || scale <= 0 || !isFiniteNumber(overhead) || overhead < 0 || !isString(digest)) return false;
|
|
11236
11425
|
}
|
|
11237
11426
|
const roles = new Map(conversation.messages.map((message) => [message.id, message.role]));
|
|
11238
11427
|
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));
|
|
@@ -11265,6 +11454,7 @@ var Ledger = class {
|
|
|
11265
11454
|
#scans = /* @__PURE__ */ new Set();
|
|
11266
11455
|
#calibrations = /* @__PURE__ */ new Set();
|
|
11267
11456
|
#gauge;
|
|
11457
|
+
#digest;
|
|
11268
11458
|
#window = [];
|
|
11269
11459
|
#evidence = collectLedgerEvidence([], /* @__PURE__ */ new Set(), []);
|
|
11270
11460
|
/**
|
|
@@ -11272,6 +11462,7 @@ var Ledger = class {
|
|
|
11272
11462
|
* @param provider - The provider that serves the conversation
|
|
11273
11463
|
* @param options - The filing policy, capacity, and request bounds
|
|
11274
11464
|
* @throws {LedgerError} Thrown when a threshold, share, capacity, limit, topic, lookup, or gauge is invalid
|
|
11465
|
+
* @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'`)
|
|
11275
11466
|
* @throws {LedgerError} Thrown when `predict` is not a nonnegative safe integer less than `capacity` (code `'CAPACITY'`)
|
|
11276
11467
|
* @throws {LedgerError} Thrown when `questions` fails `isLedgerQuestion` (code `'QUESTION'`)
|
|
11277
11468
|
* @throws {LedgerError} Thrown when `snapshot` is malformed or marks an id its conversation does not hold (code `'SNAPSHOT'`, its faults under `context.faults`)
|
|
@@ -11297,6 +11488,12 @@ var Ledger = class {
|
|
|
11297
11488
|
if (topics.some((name) => name.trim() === "") || new Set(topics).size !== topics.length) throw new LedgerError("TOPIC", "topic names must be nonempty and unique");
|
|
11298
11489
|
const lookups = ["recall", ...Array.from(options.lookups ?? [], (lookup) => lookup.tool.name)];
|
|
11299
11490
|
if (new Set(lookups).size !== lookups.length) throw new LedgerError("LOOKUP", "lookup names must be unique and cannot be recall");
|
|
11491
|
+
const writes = Array.from(options.writes ?? [], (write) => write.tool);
|
|
11492
|
+
const names = [...lookups, ...writes.map((tool) => tool.name)];
|
|
11493
|
+
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");
|
|
11494
|
+
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");
|
|
11495
|
+
const host = options.agent?.authority;
|
|
11496
|
+
if (writes.length > 0 && host === void 0) throw new LedgerError("WRITE", "writes need an agent.authority that gates each call");
|
|
11300
11497
|
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");
|
|
11301
11498
|
const snapshot = options.snapshot;
|
|
11302
11499
|
if (snapshot !== void 0 && !isLedgerSnapshot(snapshot)) {
|
|
@@ -11311,13 +11508,6 @@ var Ledger = class {
|
|
|
11311
11508
|
...DEFAULT_LEDGER_SHARE,
|
|
11312
11509
|
...options.share
|
|
11313
11510
|
};
|
|
11314
|
-
const gauge = options.gauge ?? snapshot?.gauge;
|
|
11315
|
-
if (gauge !== void 0) this.#gauge = new Gauge({
|
|
11316
|
-
...gauge,
|
|
11317
|
-
capacity: options.capacity,
|
|
11318
|
-
predict: this.#predict,
|
|
11319
|
-
replay: this.#replay
|
|
11320
|
-
});
|
|
11321
11511
|
const conversations = createConversationManager();
|
|
11322
11512
|
this.#conversation = snapshot === void 0 ? conversations.add() : conversations.add({ snapshot: snapshot.conversation });
|
|
11323
11513
|
conversations.switch(this.#conversation.id);
|
|
@@ -11338,14 +11528,14 @@ var Ledger = class {
|
|
|
11338
11528
|
...options.agent?.strict === void 0 ? {} : { strict: options.agent.strict }
|
|
11339
11529
|
});
|
|
11340
11530
|
const tools = createToolManager();
|
|
11341
|
-
for (const
|
|
11342
|
-
name:
|
|
11343
|
-
...
|
|
11344
|
-
...
|
|
11345
|
-
...
|
|
11346
|
-
...
|
|
11347
|
-
...
|
|
11348
|
-
execute: (args, context) => this.#lookup(
|
|
11531
|
+
for (const { tool } of [...options.lookups ?? [], ...options.writes ?? []]) tools.add(createTool({
|
|
11532
|
+
name: tool.name,
|
|
11533
|
+
...tool.parameters === void 0 ? {} : { parameters: tool.parameters },
|
|
11534
|
+
...tool.description === void 0 ? {} : { description: tool.description },
|
|
11535
|
+
...tool.summary === void 0 ? {} : { summary: tool.summary },
|
|
11536
|
+
...tool.title === void 0 ? {} : { title: tool.title },
|
|
11537
|
+
...tool.annotations === void 0 ? {} : { annotations: tool.annotations },
|
|
11538
|
+
execute: (args, context) => this.#lookup(tool.name, args, context)
|
|
11349
11539
|
}));
|
|
11350
11540
|
tools.add(createTool({
|
|
11351
11541
|
name: "recall",
|
|
@@ -11356,33 +11546,60 @@ var Ledger = class {
|
|
|
11356
11546
|
}) }),
|
|
11357
11547
|
execute: (args) => this.#recall(args)
|
|
11358
11548
|
}));
|
|
11549
|
+
const advertised = new Authority({
|
|
11550
|
+
rules: [{
|
|
11551
|
+
match: (context) => names.includes(context.call.name),
|
|
11552
|
+
zone: "ledger",
|
|
11553
|
+
verdict: "allow"
|
|
11554
|
+
}],
|
|
11555
|
+
fallback: {
|
|
11556
|
+
zone: "ledger",
|
|
11557
|
+
verdict: "deny",
|
|
11558
|
+
reason: "the ledger advertises no such tool"
|
|
11559
|
+
}
|
|
11560
|
+
});
|
|
11359
11561
|
this.#agent = createAgent(provider, {
|
|
11360
11562
|
...options.agent,
|
|
11361
11563
|
conversations,
|
|
11362
11564
|
system: options.system,
|
|
11363
11565
|
tools,
|
|
11364
|
-
authority:
|
|
11365
|
-
|
|
11366
|
-
match: (context) => lookups.includes(context.call.name),
|
|
11367
|
-
zone: "ledger",
|
|
11368
|
-
verdict: "allow"
|
|
11369
|
-
}],
|
|
11370
|
-
fallback: {
|
|
11566
|
+
authority: {
|
|
11567
|
+
evaluate: (context) => this.#current()?.denied(context.call.name, context.call.arguments) === true ? {
|
|
11371
11568
|
zone: "ledger",
|
|
11372
11569
|
verdict: "deny",
|
|
11373
|
-
reason:
|
|
11374
|
-
}
|
|
11375
|
-
|
|
11570
|
+
reason: LEDGER_NOTES.repeat
|
|
11571
|
+
} : host === void 0 || context.call.name === "recall" || !names.includes(context.call.name) ? advertised.evaluate(context) : host.evaluate(context),
|
|
11572
|
+
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)
|
|
11573
|
+
},
|
|
11376
11574
|
limit: options.agent?.limit ?? 8,
|
|
11377
11575
|
select: (conversation, request, signal) => this.#select(conversation, request, signal)
|
|
11378
11576
|
});
|
|
11379
|
-
this.#agent.
|
|
11577
|
+
const digest = digestLedgerTools(this.#agent.context.tools.definitions());
|
|
11578
|
+
const gauge = options.gauge ?? (snapshot?.gauge?.digest === digest ? snapshot?.gauge : void 0);
|
|
11579
|
+
if (gauge !== void 0) {
|
|
11580
|
+
this.#gauge = new Gauge({
|
|
11581
|
+
scale: gauge.scale,
|
|
11582
|
+
overhead: gauge.overhead,
|
|
11583
|
+
capacity: options.capacity,
|
|
11584
|
+
predict: this.#predict,
|
|
11585
|
+
replay: this.#replay
|
|
11586
|
+
});
|
|
11587
|
+
this.#digest = digest;
|
|
11588
|
+
}
|
|
11589
|
+
this.#agent.emitter.on("deny", (call, _reason, decision) => {
|
|
11590
|
+
if (decision !== void 0 && call.name !== "recall" && names.includes(call.name)) this.#current()?.deny(call.name, call.arguments);
|
|
11591
|
+
});
|
|
11592
|
+
this.#agent.emitter.on("tool", (call, result) => {
|
|
11380
11593
|
this.#flush();
|
|
11381
11594
|
this.#pending.set(this.#conversation.messages().length, result);
|
|
11382
|
-
|
|
11595
|
+
const stopped = denyCall(call, LEDGER_NOTES.repeat);
|
|
11596
|
+
if (!result.success && (result.error === LEDGER_NOTES.repeat || !stopped.success && result.error === stopped.error)) {
|
|
11383
11597
|
this.#current()?.close();
|
|
11384
11598
|
this.#agent.abort("repeat");
|
|
11385
11599
|
}
|
|
11600
|
+
const request = this.#current();
|
|
11601
|
+
if (request?.calls.at(-1)?.tools === 0) request.abort();
|
|
11602
|
+
this.#release(call, result);
|
|
11386
11603
|
});
|
|
11387
11604
|
this.#agent.emitter.on("select", (selection) => {
|
|
11388
11605
|
if (isLedgerError(selection.fault) && selection.fault.code === "REQUEST") return;
|
|
@@ -11443,6 +11660,7 @@ var Ledger = class {
|
|
|
11443
11660
|
const conversation = this.#conversation.snapshot();
|
|
11444
11661
|
const ids = conversation.messages.map((message) => message.id);
|
|
11445
11662
|
const gauge = this.gauge;
|
|
11663
|
+
const priced = this.#digest;
|
|
11446
11664
|
const window = {
|
|
11447
11665
|
exchanges: this.#window.map((entry) => ({
|
|
11448
11666
|
request: entry.request.id,
|
|
@@ -11463,7 +11681,10 @@ var Ledger = class {
|
|
|
11463
11681
|
requests: ids.filter((id) => this.#requests.has(id)),
|
|
11464
11682
|
notes: ids.filter((id) => this.#annotations.has(id)),
|
|
11465
11683
|
failures: ids.filter((id) => this.#results.get(id)?.success === false),
|
|
11466
|
-
...gauge === void 0 ? {} : { gauge
|
|
11684
|
+
...gauge === void 0 || priced === void 0 ? {} : { gauge: {
|
|
11685
|
+
...gauge,
|
|
11686
|
+
digest: priced
|
|
11687
|
+
} },
|
|
11467
11688
|
...window.exchanges.length === 0 || digest === void 0 ? {} : { window: {
|
|
11468
11689
|
...window,
|
|
11469
11690
|
digest
|
|
@@ -11472,6 +11693,7 @@ var Ledger = class {
|
|
|
11472
11693
|
}
|
|
11473
11694
|
/**
|
|
11474
11695
|
* Appends a request and serves it, recovering an unfinished or rejected first pass with one answer pass.
|
|
11696
|
+
* 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.
|
|
11475
11697
|
* 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.
|
|
11476
11698
|
* 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.
|
|
11477
11699
|
* @param content - The request text
|
|
@@ -11491,14 +11713,14 @@ var Ledger = class {
|
|
|
11491
11713
|
if (this.#gauge === void 0) await this.#measureGauge(caller);
|
|
11492
11714
|
const entered = request.enter(this.#conversation);
|
|
11493
11715
|
this.#requests.add(entered.id);
|
|
11494
|
-
const first = await this.#generatePass(request, caller, this.#options.think).catch((error) => {
|
|
11716
|
+
const first = this.#dropStrayCalls(request, await this.#generatePass(request, caller, this.#options.think).catch((error) => {
|
|
11495
11717
|
if (request.faulted(error)) throw error;
|
|
11496
11718
|
return {
|
|
11497
11719
|
content: "",
|
|
11498
11720
|
partial: true,
|
|
11499
11721
|
...request.usage === void 0 ? {} : { usage: request.usage }
|
|
11500
11722
|
};
|
|
11501
|
-
});
|
|
11723
|
+
}));
|
|
11502
11724
|
const passes = [first];
|
|
11503
11725
|
if (!caller.aborted && (first.partial || first.content.trim() === "")) {
|
|
11504
11726
|
const recovery = this.#buildDigest(request, entered);
|
|
@@ -11526,7 +11748,7 @@ var Ledger = class {
|
|
|
11526
11748
|
});
|
|
11527
11749
|
this.#agent.context.apply(answer);
|
|
11528
11750
|
try {
|
|
11529
|
-
passes.push(await this.#generatePass(request, caller, false));
|
|
11751
|
+
passes.push(this.#dropStrayCalls(request, await this.#generatePass(request, caller, false)));
|
|
11530
11752
|
} finally {
|
|
11531
11753
|
if (this.#agent.context.scope === answer) this.#agent.context.apply(previous);
|
|
11532
11754
|
}
|
|
@@ -11563,7 +11785,8 @@ var Ledger = class {
|
|
|
11563
11785
|
}],
|
|
11564
11786
|
judgments: []
|
|
11565
11787
|
}), this.#replay).slice(0, -1);
|
|
11566
|
-
const
|
|
11788
|
+
const definitions = this.#agent.context.tools.definitions();
|
|
11789
|
+
const priced = await this.#provider.generate(messages, signal, definitions, { think: false });
|
|
11567
11790
|
const bare = await this.#provider.generate(messages, signal, void 0, { think: false });
|
|
11568
11791
|
if (!isFiniteNumber(priced.usage?.prompt) || priced.usage.prompt <= 0 || !isFiniteNumber(bare.usage?.prompt) || bare.usage.prompt <= 0) throw new LedgerError("GAUGE", "calibration requires prompt usage from both calls");
|
|
11569
11792
|
this.#gauge = new Gauge({
|
|
@@ -11573,6 +11796,7 @@ var Ledger = class {
|
|
|
11573
11796
|
scale: bare.usage.prompt / estimateMessages(messages),
|
|
11574
11797
|
overhead: Math.max(0, priced.usage.prompt - bare.usage.prompt)
|
|
11575
11798
|
});
|
|
11799
|
+
this.#digest = digestLedgerTools(definitions);
|
|
11576
11800
|
return {
|
|
11577
11801
|
scale: this.#gauge.scale,
|
|
11578
11802
|
overhead: this.#gauge.overhead
|
|
@@ -11584,12 +11808,35 @@ var Ledger = class {
|
|
|
11584
11808
|
}
|
|
11585
11809
|
async #generatePass(request, signal, think) {
|
|
11586
11810
|
request.open(this.#conversation.messages().length);
|
|
11811
|
+
const stop = request.signal;
|
|
11587
11812
|
return await this.#agent.generate({
|
|
11588
|
-
signal,
|
|
11813
|
+
signal: stop === void 0 ? signal : AbortSignal.any([signal, stop]),
|
|
11589
11814
|
conversation: this.#conversation,
|
|
11590
11815
|
...think === void 0 ? {} : { think }
|
|
11591
11816
|
});
|
|
11592
11817
|
}
|
|
11818
|
+
#dropStrayCalls(request, pass) {
|
|
11819
|
+
const boundary = request.boundary;
|
|
11820
|
+
if (!request.aborted || boundary === void 0) return pass;
|
|
11821
|
+
this.#flush();
|
|
11822
|
+
const messages = this.#conversation.messages().slice(boundary);
|
|
11823
|
+
const at = messages.findLastIndex((message) => message.role === "assistant");
|
|
11824
|
+
const reply = messages[at];
|
|
11825
|
+
const replies = messages.slice(at + 1);
|
|
11826
|
+
if (reply === void 0 || !hasCalls(reply) || !replies.every((message) => message.role === "tool" && this.#results.get(message.id)?.success === false)) return pass;
|
|
11827
|
+
this.#conversation.remove([reply.id, ...replies.map((message) => message.id)]);
|
|
11828
|
+
for (const message of replies) this.#results.delete(message.id);
|
|
11829
|
+
this.#conversation.add({
|
|
11830
|
+
role: "assistant",
|
|
11831
|
+
content: reply.content,
|
|
11832
|
+
...reply.thinking === void 0 ? {} : { thinking: reply.thinking }
|
|
11833
|
+
});
|
|
11834
|
+
return {
|
|
11835
|
+
...pass,
|
|
11836
|
+
content: reply.content,
|
|
11837
|
+
partial: reply.content.trim() === ""
|
|
11838
|
+
};
|
|
11839
|
+
}
|
|
11593
11840
|
#current() {
|
|
11594
11841
|
const [request] = this.#live;
|
|
11595
11842
|
return request?.message === void 0 ? void 0 : request;
|
|
@@ -11679,27 +11926,36 @@ var Ledger = class {
|
|
|
11679
11926
|
return collectToolGroups(messages).flatMap((group) => group.slice(1).flatMap((message) => {
|
|
11680
11927
|
const call = findLedgerCall(group, message);
|
|
11681
11928
|
const lookup = this.#options.lookups?.find((one) => one.tool.name === call?.name);
|
|
11682
|
-
|
|
11683
|
-
|
|
11684
|
-
|
|
11929
|
+
const write = this.#options.writes?.find((one) => one.tool.name === call?.name);
|
|
11930
|
+
if (call === void 0 || lookup === void 0 && write === void 0 || this.#results.get(message.id)?.success === false) return [];
|
|
11931
|
+
const read = attempt(() => lookup?.read(call.arguments, message.content));
|
|
11932
|
+
const written = attempt(() => write?.read(call.arguments, message.content));
|
|
11933
|
+
if (!read.success || !written.success) {
|
|
11934
|
+
const error = read.success ? written.success ? void 0 : written.error : read.error;
|
|
11685
11935
|
this.#results.set(message.id, {
|
|
11686
11936
|
success: false,
|
|
11687
11937
|
id: call.id,
|
|
11688
11938
|
name: call.name,
|
|
11689
|
-
error: isError(
|
|
11939
|
+
error: isError(error) ? error.message : String(error)
|
|
11690
11940
|
});
|
|
11691
11941
|
return [];
|
|
11692
11942
|
}
|
|
11943
|
+
const literals = Object.values(call.arguments).filter(isString).flatMap((value) => [...extractLiterals(value).ids]);
|
|
11693
11944
|
const result = read.value;
|
|
11945
|
+
const change = written.value;
|
|
11694
11946
|
return [{
|
|
11695
11947
|
id: message.id,
|
|
11696
11948
|
name: call.name,
|
|
11697
11949
|
arguments: call.arguments,
|
|
11698
11950
|
text: message.content,
|
|
11699
|
-
result: result
|
|
11951
|
+
result: result !== void 0 ? {
|
|
11700
11952
|
...result,
|
|
11701
|
-
ids: [.../* @__PURE__ */ new Set([...result.ids, ...
|
|
11702
|
-
}
|
|
11953
|
+
ids: [.../* @__PURE__ */ new Set([...result.ids, ...literals])]
|
|
11954
|
+
} : change !== void 0 ? {
|
|
11955
|
+
ids: [.../* @__PURE__ */ new Set([...change.ids, ...literals])],
|
|
11956
|
+
owners: change.owners
|
|
11957
|
+
} : void 0,
|
|
11958
|
+
...change === void 0 ? {} : { targets: [...change.targets] }
|
|
11703
11959
|
}];
|
|
11704
11960
|
}));
|
|
11705
11961
|
}
|
|
@@ -11711,7 +11967,7 @@ var Ledger = class {
|
|
|
11711
11967
|
messages: scan.messages,
|
|
11712
11968
|
findings: scan.findings,
|
|
11713
11969
|
entities: new Map(scan.messages.map((message) => [message.id, [...matchEntities(scan.index, message.content, true)]])),
|
|
11714
|
-
classification: this.#classifier.classification()
|
|
11970
|
+
classification: mergeSupersessions(this.#classifier.classification(), collectWriteSupersessions(scan.messages, scan.findings), scan.messages)
|
|
11715
11971
|
};
|
|
11716
11972
|
return {
|
|
11717
11973
|
input,
|
|
@@ -12062,7 +12318,7 @@ var Ledger = class {
|
|
|
12062
12318
|
kept: (leader.calls ?? []).flatMap((call) => {
|
|
12063
12319
|
const message = group.slice(1).find((result) => findLedgerCall(group, result) === call);
|
|
12064
12320
|
const result = message === void 0 ? void 0 : this.#results.get(message.id);
|
|
12065
|
-
return message === void 0 || !this.#options.lookups
|
|
12321
|
+
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 ? [] : [{
|
|
12066
12322
|
call,
|
|
12067
12323
|
message
|
|
12068
12324
|
}];
|
|
@@ -12108,19 +12364,48 @@ var Ledger = class {
|
|
|
12108
12364
|
#renderTailStub(message, scan, shown) {
|
|
12109
12365
|
const group = scan.group(message.id);
|
|
12110
12366
|
const call = group === void 0 ? void 0 : findLedgerCall(group, message);
|
|
12367
|
+
const write = this.#options.writes?.some((one) => one.tool.name === call?.name) === true;
|
|
12111
12368
|
const finding = scan.finding(message.id);
|
|
12112
12369
|
const hidden = renderStub(call?.name ?? "tool", call?.arguments ?? {}, "hidden");
|
|
12113
12370
|
const visible = renderStub(call?.name ?? "tool", call?.arguments ?? {}, "shown");
|
|
12114
12371
|
return {
|
|
12115
12372
|
...message,
|
|
12116
|
-
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")
|
|
12373
|
+
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)
|
|
12117
12374
|
};
|
|
12118
12375
|
}
|
|
12376
|
+
#release(call, result) {
|
|
12377
|
+
const request = this.#current();
|
|
12378
|
+
const write = this.#options.writes?.find((one) => one.tool.name === call.name);
|
|
12379
|
+
if (request === void 0 || write === void 0 || !result.success) return;
|
|
12380
|
+
const text = settleToolResult(result).content;
|
|
12381
|
+
const read = attempt(() => {
|
|
12382
|
+
const change = write.read(call.arguments, text);
|
|
12383
|
+
return change === void 0 ? [] : [...change.targets];
|
|
12384
|
+
});
|
|
12385
|
+
if (!read.success || read.value.length === 0) return;
|
|
12386
|
+
const messages = this.#conversation.messages();
|
|
12387
|
+
const findings = this.#readLookups(messages);
|
|
12388
|
+
const id = crypto.randomUUID();
|
|
12389
|
+
const edges = collectWriteSupersessions([...messages, {
|
|
12390
|
+
id,
|
|
12391
|
+
role: "tool",
|
|
12392
|
+
content: text,
|
|
12393
|
+
call: call.id
|
|
12394
|
+
}], [...findings, {
|
|
12395
|
+
id,
|
|
12396
|
+
name: call.name,
|
|
12397
|
+
arguments: call.arguments,
|
|
12398
|
+
text,
|
|
12399
|
+
result: void 0,
|
|
12400
|
+
targets: read.value
|
|
12401
|
+
}]);
|
|
12402
|
+
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);
|
|
12403
|
+
}
|
|
12119
12404
|
#observeTurn() {
|
|
12120
12405
|
this.#flush();
|
|
12121
12406
|
const request = this.#current();
|
|
12122
12407
|
const boundary = request?.boundary;
|
|
12123
|
-
if (request === void 0 || boundary === void 0) return;
|
|
12408
|
+
if (request === void 0 || boundary === void 0 || request.aborted) return;
|
|
12124
12409
|
const additions = this.#conversation.messages().slice(boundary);
|
|
12125
12410
|
const messages = this.#agent.context.build(request.selection);
|
|
12126
12411
|
const names = this.#agent.context.scope?.tools;
|
|
@@ -12141,10 +12426,17 @@ var Ledger = class {
|
|
|
12141
12426
|
return this.#conversation.messages().filter((message) => message.role === "assistant").reduce((longest, message) => message.content.length > longest.length ? message.content : longest, "");
|
|
12142
12427
|
}
|
|
12143
12428
|
#lookup(name, args, context) {
|
|
12144
|
-
this.#current()
|
|
12145
|
-
|
|
12146
|
-
|
|
12147
|
-
|
|
12429
|
+
const request = this.#current();
|
|
12430
|
+
request?.admit(name, args);
|
|
12431
|
+
const entry = this.#options.lookups?.find((one) => one.tool.name === name) ?? this.#options.writes?.find((one) => one.tool.name === name);
|
|
12432
|
+
if (entry === void 0) throw new Error(`unknown lookup or write ${name}`);
|
|
12433
|
+
const ran = attempt(() => entry.tool.execute(args, context));
|
|
12434
|
+
if (!ran.success) return this.#reject(request, name, args, ran.error);
|
|
12435
|
+
return isPromiseLike(ran.value) ? Promise.resolve(ran.value).catch((error) => this.#reject(request, name, args, error)) : ran.value;
|
|
12436
|
+
}
|
|
12437
|
+
#reject(request, name, args, error) {
|
|
12438
|
+
if (isToolError(error) && error.code === "ARGUMENTS") request?.release(name, args);
|
|
12439
|
+
throw error;
|
|
12148
12440
|
}
|
|
12149
12441
|
#recall(args) {
|
|
12150
12442
|
const request = this.#current();
|
|
@@ -12182,7 +12474,8 @@ var Ledger = class {
|
|
|
12182
12474
|
};
|
|
12183
12475
|
});
|
|
12184
12476
|
const start = request?.message === void 0 ? -1 : scan.position(request.message.id) ?? -1;
|
|
12185
|
-
const
|
|
12477
|
+
const retired = collectRetiredFindings(scan.messages, scan.findings);
|
|
12478
|
+
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]));
|
|
12186
12479
|
const matched = new Set(searches.flatMap((search) => [...search.matched]));
|
|
12187
12480
|
const unmatched = searches.filter((search) => search.matched.size === 0 && search.words.length > 0);
|
|
12188
12481
|
const gathered = [...listable.values()].reverse().reduce((state, message) => {
|
|
@@ -12303,6 +12596,6 @@ var Ledger = class {
|
|
|
12303
12596
|
function createLedger(provider, options) {
|
|
12304
12597
|
return new Ledger(provider, options);
|
|
12305
12598
|
}
|
|
12306
|
-
export { AUTHORITY_NOTES, Agent, AgentContext, AgentError, AgentFanout, AgentJobError, AgentJudge, AgentProvider, AgentRegistry, Approver, Authority, CONVERSATION_RECAP_PREFIX, CONVERSATION_ROLES, Channel, Classifier, ContextError, Conversation, ConversationError, ConversationManager, DECISIVE_CATEGORIES, DEFAULT_AGENT_LIMIT, DEFAULT_CONVERSATION_KEEP, DEFAULT_LEDGER_LIMIT, DEFAULT_LEDGER_SHARE, DEFAULT_PROVIDER_TIMEOUT, DEFAULT_RECALL_LIMIT, DEFAULT_RELAY_LIMIT, DETERMINISTIC_JUDGE_ERROR, DatabaseConversationStore, DatabaseMemoStore, Gauge, IMAGE_TOKEN_ESTIMATE, INVALID_RELAY_STATUS, Instruction, InstructionManager, JudgeAbortError, JudgeError, JudgmentManager, LEDGER_CATEGORIES, LEDGER_NOTES, LEDGER_OWNER_PREFIX, LEDGER_QUESTIONS, LEDGER_RECALL_LABELS, LEDGER_RULES_KEY, LEDGER_SCALE_DRIFT, LEDGER_SLICE, LEDGER_WORD, Ledger, LedgerError, LedgerRequest, MAX_ERROR_BODY_LENGTH, MEMO_SECTION_HEADER, MESSAGE_ROLES, MESSAGE_TOKEN_OVERHEAD, MemoManager, MemoryConversationStore, MemoryMemoStore, OVERSIZED_RELAY_STATUS, PLACED_CATEGORIES, ProviderAbortError, ProviderError, QUIET_CATEGORIES, REFUSED_RELAY_CONTENT_TYPE, REFUSED_RELAY_STATUS, RELAY_CONTENT_TYPE, RELAY_PROVIDER_MESSAGE, RelayProvider, RelayStream, SCOPE_NOTE, SKILL_SECTION_HEADER, SYSTEM_ONE_PATH, Scope, ScopeManager, SkillManager, SystemOneJudge, THINK_CLOSE, THINK_OPEN, ThinkSplitter, UNAUTHORIZED_RELAY_STATUS, UPSTREAM_RELAY_STATUS, WORKSPACE_SECTION_HEADER, agentAnswerContract, agentAnswerShape, agentChunkToFrame, agentFrameContract, agentFrameShape, agentJobContract, agentJobShape, agentPromptContract, agentPromptShape, agentResultToFrame, agentResultToJSON, agentStreamToFrames, armReaderAbort, assembleResult, attachImages, attachUserImages, buildJudgeResult, buildJudgments, buildLedgerCut, buildLedgerIndex, buildLedgerLineKey, buildLedgerRenderContext, buildLines, buildProviderHeaders, buildProviderResult, buildRecallMessage, buildRecapMessage, buildRecords, buildRelayRequest, buildRequestMessage, buildSummaryMessage, chargeUsage, collectAmendments, collectExchanges, collectImageData, collectLedgerEvidence, collectLedgerLines, collectLedgerReplies, collectLive, collectNames, collectProjectionIds, collectRecallMessages, collectRegistry, collectToolGroups, computeThinking, conversationSnapshotContract, conversationSnapshotShape, copyJSON, createAgent, createAgentContext, createAgentQueue, createAgentRegistry, createAgentRunner, createApprover, createAuthority, createChannel, createConversation, createConversationManager, createDatabaseConversationStore, createDatabaseMemoStore, createInstruction, createInstructionManager, createLedger, createMemoManager, createMemoryConversationStore, createMemoryMemoStore, createRelay, createRelayProvider, createScope, createScopeManager, createSkillManager, createSystemOneJudge, createThinkSplitter, cutListing, denyCall, describeQuestionRefusal, describeRelayRefusal, describeSnapshotRefusal, digestLedgerWindow, estimateMessages, estimateRequest, estimateTokens, extractLiterals, extractQueueOptions, extractSystemOneAnswer, extractSystemOneUsage, extractWords, filterAllowList, findLedgerCall, findLedgerCut, fitSlope, freezeJSON, handleAgentQueueJob, hasCalls, hasHiddenRecall, identifyLookup, inferStop, intersectKeys, isAgentError, isAgentJobError, isAuthorityDecision, isAuthorityVerdict, isContextError, isConversation, isConversationError, isConversationSnapshot, isFraction, isJudgeAbortError, isJudgeAnswer, isJudgeEntry, isJudgeError, isJudgeQuestion, isJudgment, isLedgerError, isLedgerQuestion, isLedgerSnapshot, isLedgerWindowSnapshot, isMemo, isMemoOrigin, isMemoSnapshot, isMessage, isMessageInput, isNonNegativeSafeInteger, isPositiveSafeInteger, isProviderAbortError, isProviderError, isProviderResult, isSection, isSystemOneAnswer, isSystemOneResponse, joinThinking, judgeAnswerContract, judgeAnswerShape, judgeEntryShape, judgeQuestionContract, judgeQuestionShape, judgmentContract, judgmentShape, ledgerSnapshotContract, ledgerSnapshotShape, ledgerWindowContract, ledgerWindowShape, linkOwners, matchEntities, matchesCutLine, matchesJSON, matchesJudgment, matchesLookup, measureAnswer, measureMessage, measureRequest, memoContract, memoShape, memoSnapshotContract, memoSnapshotShape, messageContract, messageInputContract, messageInputShape, messageShape, normalizeArgument, normalizeWord, placeMember, providerRequestContract, providerRequestShape, providerResultContract, providerResultShape, questionToSystemOne, raceSignal, rankLedgerCut, readBodyText, readChunks, readFailure, readJudgeOutcome, readProviderDelta, relayFrameContract, relayFrameShape, releaseReader, removeEntries, renderArguments, renderCauseChain, renderFencedFile, renderIndexEntry, renderJSON, renderLedgerAnnotation, renderLedgerPinned, renderLedgerRecord, renderLookupCall, renderSection, renderStub, renderToolValue, renderTopicNames, requestToRelay, requireAnswer, requireBudget, requireConversation, requireConversationSnapshot, requireCumulative, requireEntry, requireFallback, requireJudgeResult, requireJudgment, requireKeep, requireLimit, requireMessageInput, requireProviderResult, requireRole, requireRules, requireSectionsCap, requireSummary, resolveDecision, resolvePredict, sanitizeToken, sanitizeUsage, scanAmendments, scanJudgmentTies, scanProbability, sectionContract, sectionShape, selectRecords, settleAgentJob, settleToolResult, splitResultLines, splitSentences, splitTopic, splitWords, stripThinking, sumUsage, tokenUsageShape, tokenUsageToJSON, toolCallShape };
|
|
12599
|
+
export { AUTHORITY_NOTES, Agent, AgentContext, AgentError, AgentFanout, AgentJobError, AgentJudge, AgentProvider, AgentRegistry, Approver, Authority, CONVERSATION_RECAP_PREFIX, CONVERSATION_ROLES, Channel, Classifier, ContextError, Conversation, ConversationError, ConversationManager, DECISIVE_CATEGORIES, DEFAULT_AGENT_LIMIT, DEFAULT_CONVERSATION_KEEP, DEFAULT_LEDGER_LIMIT, DEFAULT_LEDGER_SHARE, DEFAULT_PROVIDER_TIMEOUT, DEFAULT_RECALL_LIMIT, DEFAULT_RELAY_LIMIT, DETERMINISTIC_JUDGE_ERROR, DatabaseConversationStore, DatabaseMemoStore, Gauge, IMAGE_TOKEN_ESTIMATE, INVALID_RELAY_STATUS, Instruction, InstructionManager, JudgeAbortError, JudgeError, JudgmentManager, LEDGER_CATEGORIES, LEDGER_NOTES, LEDGER_OWNER_PREFIX, LEDGER_QUESTIONS, LEDGER_RECALL_LABELS, LEDGER_RULES_KEY, LEDGER_SCALE_DRIFT, LEDGER_SLICE, LEDGER_WORD, Ledger, LedgerError, LedgerRequest, MAX_ERROR_BODY_LENGTH, MEMO_SECTION_HEADER, MESSAGE_ROLES, MESSAGE_TOKEN_OVERHEAD, MemoManager, MemoryConversationStore, MemoryMemoStore, OVERSIZED_RELAY_STATUS, PLACED_CATEGORIES, ProviderAbortError, ProviderError, QUIET_CATEGORIES, REFUSED_RELAY_CONTENT_TYPE, REFUSED_RELAY_STATUS, RELAY_CONTENT_TYPE, RELAY_PROVIDER_MESSAGE, RelayProvider, RelayStream, SCOPE_NOTE, SKILL_SECTION_HEADER, SYSTEM_ONE_PATH, Scope, ScopeManager, SkillManager, SystemOneJudge, THINK_CLOSE, THINK_OPEN, ThinkSplitter, UNAUTHORIZED_RELAY_STATUS, UPSTREAM_RELAY_STATUS, WORKSPACE_SECTION_HEADER, agentAnswerContract, agentAnswerShape, agentChunkToFrame, agentFrameContract, agentFrameShape, agentJobContract, agentJobShape, agentPromptContract, agentPromptShape, agentResultToFrame, agentResultToJSON, agentStreamToFrames, armReaderAbort, assembleResult, attachImages, attachUserImages, buildJudgeResult, buildJudgments, buildLedgerCut, buildLedgerIndex, buildLedgerLineKey, buildLedgerRenderContext, buildLines, buildProviderHeaders, buildProviderResult, buildRecallMessage, buildRecapMessage, buildRecords, buildRelayRequest, buildRequestMessage, buildSummaryMessage, chargeUsage, collectAmendments, collectExchanges, collectImageData, collectLedgerEvidence, collectLedgerLines, collectLedgerReplies, collectLive, collectNames, collectProjectionIds, collectRecallMessages, collectRegistry, collectRetiredFindings, collectToolGroups, collectWriteSupersessions, computeLedgerChecksum, computeThinking, conversationSnapshotContract, conversationSnapshotShape, copyJSON, createAgent, createAgentContext, createAgentQueue, createAgentRegistry, createAgentRunner, createApprover, createAuthority, createChannel, createConversation, createConversationManager, createDatabaseConversationStore, createDatabaseMemoStore, createInstruction, createInstructionManager, createLedger, createMemoManager, createMemoryConversationStore, createMemoryMemoStore, createRelay, createRelayProvider, createScope, createScopeManager, createSkillManager, createSystemOneJudge, createThinkSplitter, cutListing, denyCall, describeQuestionRefusal, describeRelayRefusal, describeSnapshotRefusal, digestLedgerTools, digestLedgerWindow, estimateMessages, estimateRequest, estimateTokens, extractLiterals, extractQueueOptions, extractSystemOneAnswer, extractSystemOneUsage, extractWords, filterAllowList, findLedgerCall, findLedgerCut, fitSlope, freezeJSON, handleAgentQueueJob, hasCalls, hasHiddenRecall, identifyLookup, inferStop, intersectKeys, isAgentError, isAgentJobError, isAuthorityDecision, isAuthorityVerdict, isContextError, isConversation, isConversationError, isConversationSnapshot, isFraction, isJudgeAbortError, isJudgeAnswer, isJudgeEntry, isJudgeError, isJudgeQuestion, isJudgment, isLedgerError, isLedgerQuestion, isLedgerSnapshot, isLedgerWindowSnapshot, isMemo, isMemoOrigin, isMemoSnapshot, isMessage, isMessageInput, isNonNegativeSafeInteger, isPositiveSafeInteger, isProviderAbortError, isProviderError, isProviderResult, isSection, isSystemOneAnswer, isSystemOneResponse, joinThinking, judgeAnswerContract, judgeAnswerShape, judgeEntryShape, judgeQuestionContract, judgeQuestionShape, judgmentContract, judgmentShape, ledgerSnapshotContract, ledgerSnapshotShape, ledgerWindowContract, ledgerWindowShape, linkOwners, matchEntities, matchesCutLine, matchesJSON, matchesJudgment, matchesLookup, measureAnswer, measureMessage, measureRequest, memoContract, memoShape, memoSnapshotContract, memoSnapshotShape, mergeSupersessions, messageContract, messageInputContract, messageInputShape, messageShape, normalizeArgument, normalizeWord, placeMember, providerRequestContract, providerRequestShape, providerResultContract, providerResultShape, questionToSystemOne, raceSignal, rankLedgerCut, readBodyText, readChunks, readFailure, readJudgeOutcome, readProviderDelta, relayFrameContract, relayFrameShape, releaseReader, removeEntries, renderArguments, renderCauseChain, renderFencedFile, renderIndexEntry, renderJSON, renderLedgerAnnotation, renderLedgerPinned, renderLedgerRecord, renderLookupCall, renderSection, renderStub, renderToolValue, renderTopicNames, requestToRelay, requireAnswer, requireBudget, requireConversation, requireConversationSnapshot, requireCumulative, requireEntry, requireFallback, requireJudgeResult, requireJudgment, requireKeep, requireLimit, requireMessageInput, requireProviderResult, requireRole, requireRules, requireSectionsCap, requireSummary, resolveDecision, resolvePredict, sanitizeToken, sanitizeUsage, scanAmendments, scanJudgmentTies, scanProbability, sectionContract, sectionShape, selectRecords, settleAgentJob, settleToolResult, splitResultLines, splitSentences, splitTopic, splitWords, stripThinking, sumUsage, tokenUsageShape, tokenUsageToJSON, toolCallShape };
|
|
12307
12600
|
|
|
12308
12601
|
//# sourceMappingURL=index.js.map
|