@orkestrel/agent 0.0.36 → 0.0.37
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 +578 -84
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +324 -32
- package/dist/src/core/index.d.ts +324 -32
- package/dist/src/core/index.js +567 -85
- package/dist/src/core/index.js.map +1 -1
- package/package.json +7 -7
package/dist/src/core/index.cjs
CHANGED
|
@@ -8806,6 +8806,11 @@ var PLACED_CATEGORIES = Object.freeze(["rule", "correction"]);
|
|
|
8806
8806
|
var LEDGER_RULES_KEY = "rules";
|
|
8807
8807
|
/** Prefixes the key of an owner's record, which the owner's id follows. */
|
|
8808
8808
|
var LEDGER_OWNER_PREFIX = "owner:";
|
|
8809
|
+
/** Labels recalled conversation text by its origin. */
|
|
8810
|
+
var LEDGER_RECALL_LABELS = Object.freeze({
|
|
8811
|
+
request: "Earlier request:",
|
|
8812
|
+
reply: "Earlier reply:"
|
|
8813
|
+
});
|
|
8809
8814
|
/**
|
|
8810
8815
|
* Supplies the wording of every question the ledger asks its judge.
|
|
8811
8816
|
*
|
|
@@ -8953,6 +8958,108 @@ function isLedgerError(value) {
|
|
|
8953
8958
|
}
|
|
8954
8959
|
// src/core/ledgers/helpers.ts
|
|
8955
8960
|
/**
|
|
8961
|
+
* Digests held messages, lookup call context, stored copies, and sentence receipts using canonical text.
|
|
8962
|
+
* This non-cryptographic checksum detects host edits and makes no security claim.
|
|
8963
|
+
* @param exchanges - The stored exchange entries
|
|
8964
|
+
* @param messages - The conversation holding their messages
|
|
8965
|
+
* @returns The hexadecimal checksum, or undefined when a required message is absent or canonical encoding fails
|
|
8966
|
+
* @example
|
|
8967
|
+
* ```ts
|
|
8968
|
+
* digestLedgerWindow([], []) // a deterministic hexadecimal checksum
|
|
8969
|
+
* ```
|
|
8970
|
+
*/
|
|
8971
|
+
function digestLedgerWindow(exchanges, messages) {
|
|
8972
|
+
const byId = new Map(messages.map((message) => [message.id, message]));
|
|
8973
|
+
const held = [...new Set(exchanges.flatMap((entry) => [
|
|
8974
|
+
entry.request,
|
|
8975
|
+
entry.reply,
|
|
8976
|
+
...entry.lines.map((line) => line.source)
|
|
8977
|
+
]))].map((id) => byId.get(id));
|
|
8978
|
+
const callers = messages.filter((message) => message.role === "tool" || message.calls !== void 0);
|
|
8979
|
+
const encoded = (0, _orkestrel_contract.attempt)(() => {
|
|
8980
|
+
const values = [...held, ...callers].map((message) => (0, _orkestrel_contract.canonicalStringify)(message));
|
|
8981
|
+
return values.some((value) => value === void 0) ? void 0 : (0, _orkestrel_contract.canonicalStringify)([values, exchanges.map((entry) => [entry.copy ?? null, entry.lines])]);
|
|
8982
|
+
});
|
|
8983
|
+
if (!encoded.success || encoded.value === void 0) return void 0;
|
|
8984
|
+
const hash = [...encoded.value].reduce((prior, character) => {
|
|
8985
|
+
const code = character.codePointAt(0) ?? 0;
|
|
8986
|
+
return {
|
|
8987
|
+
first: Math.imul(prior.first ^ code, 16777619) >>> 0,
|
|
8988
|
+
second: Math.imul(prior.second ^ code, 16777619) >>> 0
|
|
8989
|
+
};
|
|
8990
|
+
}, {
|
|
8991
|
+
first: 2166136261,
|
|
8992
|
+
second: 3335557771
|
|
8993
|
+
});
|
|
8994
|
+
return hash.first.toString(16).padStart(8, "0") + hash.second.toString(16).padStart(8, "0");
|
|
8995
|
+
}
|
|
8996
|
+
/**
|
|
8997
|
+
* Collects stored messages eligible to open the recall offer.
|
|
8998
|
+
* @remarks
|
|
8999
|
+
* Notes and findings without a result do not open the offer. User statements, including quiet
|
|
9000
|
+
* statements available through recall's word route, can open it; this helper does not filter results.
|
|
9001
|
+
* @param input - The messages, findings, and classification
|
|
9002
|
+
* @param requests - The marked request ids
|
|
9003
|
+
* @param notes - The annotation ids to exclude
|
|
9004
|
+
* @returns User statements, lookup findings with results, marked requests, and nonblank call-free replies
|
|
9005
|
+
* @example
|
|
9006
|
+
* ```ts
|
|
9007
|
+
* collectRecallMessages(input, new Set(), new Set()) // eligible stored messages
|
|
9008
|
+
* ```
|
|
9009
|
+
*/
|
|
9010
|
+
function collectRecallMessages(input, requests, notes) {
|
|
9011
|
+
const findings = new Set(input.findings.filter((finding) => finding.result !== void 0).map((finding) => finding.id));
|
|
9012
|
+
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)));
|
|
9013
|
+
}
|
|
9014
|
+
/**
|
|
9015
|
+
* Checks whether an eligible earlier message is absent from the prompt or incompletely covered.
|
|
9016
|
+
* A successful finding is held when a finding with the same canonical identity and text is fully received.
|
|
9017
|
+
* @param input - The messages, findings, and classification
|
|
9018
|
+
* @param request - The current request id; only messages before it count
|
|
9019
|
+
* @param requests - The marked request ids
|
|
9020
|
+
* @param notes - The annotation ids to exclude
|
|
9021
|
+
* @param messages - The seed tail and held exchange messages; lookup stubs retain their rendered text
|
|
9022
|
+
* @param lines - The receipts held by the window and the request copy together
|
|
9023
|
+
* @returns True if an eligible earlier message is absent or only partly covered; false otherwise
|
|
9024
|
+
* @example
|
|
9025
|
+
* ```ts
|
|
9026
|
+
* hasHiddenRecall(input, request.id, requests, notes, tail, lines) // whether to offer recall
|
|
9027
|
+
* ```
|
|
9028
|
+
*/
|
|
9029
|
+
function hasHiddenRecall(input, request, requests, notes, messages, lines) {
|
|
9030
|
+
const start = input.messages.findIndex((message) => message.id === request);
|
|
9031
|
+
const before = new Set(input.messages.slice(0, Math.max(0, start)).map((message) => message.id));
|
|
9032
|
+
const present = new Map(messages.map((message) => [message.id, message]));
|
|
9033
|
+
const receipts = Map.groupBy(lines, (line) => line.source);
|
|
9034
|
+
return collectRecallMessages(input, requests, notes).some((message) => {
|
|
9035
|
+
if (!before.has(message.id)) return false;
|
|
9036
|
+
if (requests.has(message.id) || message.role === "assistant") return !present.has(message.id);
|
|
9037
|
+
if (present.get(message.id)?.content === message.content) return false;
|
|
9038
|
+
const finding = input.findings.find((one) => one.id === message.id);
|
|
9039
|
+
return !(finding === void 0 ? [message.id] : input.findings.filter((one) => before.has(one.id) && matchesLookup(finding, one)).map((one) => one.id)).some((id) => {
|
|
9040
|
+
if (present.get(id)?.content === message.content) return true;
|
|
9041
|
+
const held = new Set((receipts.get(id) ?? []).map((line) => line.sentence));
|
|
9042
|
+
return splitSentences(message.content).every((_, at) => held.has(at));
|
|
9043
|
+
});
|
|
9044
|
+
});
|
|
9045
|
+
}
|
|
9046
|
+
/**
|
|
9047
|
+
* Checks whether two successful findings carry the same text for the same canonical lookup.
|
|
9048
|
+
* @param left - The finding to compare
|
|
9049
|
+
* @param right - The candidate copy
|
|
9050
|
+
* @returns True for the same finding or equal canonical identities and text; unkeyable findings match only themselves
|
|
9051
|
+
* @example
|
|
9052
|
+
* ```ts
|
|
9053
|
+
* matchesLookup(finding, finding) // true when it has a result
|
|
9054
|
+
* ```
|
|
9055
|
+
*/
|
|
9056
|
+
function matchesLookup(left, right) {
|
|
9057
|
+
if (left.result === void 0 || right.result === void 0 || left.text !== right.text) return false;
|
|
9058
|
+
if (left.id === right.id) return true;
|
|
9059
|
+
const identity = identifyLookup(left.name, left.arguments);
|
|
9060
|
+
return identity !== void 0 && identity === identifyLookup(right.name, right.arguments);
|
|
9061
|
+
}
|
|
9062
|
+
/**
|
|
8956
9063
|
* Collects the live message ids placed in records or left without a record.
|
|
8957
9064
|
* @param projection - The projected records and unplaced ids
|
|
8958
9065
|
* @returns The distinct live message ids
|
|
@@ -9508,17 +9615,17 @@ function matchEntities(index, text, partial) {
|
|
|
9508
9615
|
* Projects the owner records and the rules record from a conversation's messages.
|
|
9509
9616
|
*
|
|
9510
9617
|
* @remarks
|
|
9511
|
-
* Each line is a sentence of a live message, verbatim except that a sentence that opens with a
|
|
9512
|
-
*
|
|
9513
|
-
*
|
|
9514
|
-
*
|
|
9618
|
+
* Each line is a sentence of a live message, verbatim except that a sentence that opens with a
|
|
9619
|
+
* pronoun opens with its party and a colon. {@link collectLive} retains user messages and the
|
|
9620
|
+
* earliest finding in each call identity's last run of identical text, subject to exclusions,
|
|
9621
|
+
* quiet classification, and supersessions. An undefined result still replaces the earlier finding.
|
|
9515
9622
|
*
|
|
9516
9623
|
* A live message joins the owner records its entities name, directly or through a linked lookup
|
|
9517
9624
|
* argument. A message that names no owner joins where its earlier side of an amendment pair joins,
|
|
9518
9625
|
* or on the rules record when it is filed as a rule or a correction, and is an orphan otherwise.
|
|
9519
9626
|
*
|
|
9520
|
-
* Every live sentence is retained. Accepted
|
|
9521
|
-
*
|
|
9627
|
+
* Every live sentence is retained. Accepted edges are listed in `amendments`. An amender that is
|
|
9628
|
+
* superseded points to its newest live successor, or retains its endpoint when none exists.
|
|
9522
9629
|
*
|
|
9523
9630
|
* A sentence that opens with a pronoun takes the party named in the sentence before it. The reading
|
|
9524
9631
|
* trusts capitals, so a capitalized word that is no person, such as a carrier named mid-sentence,
|
|
@@ -9728,10 +9835,12 @@ function splitTopic(topic) {
|
|
|
9728
9835
|
* @remarks
|
|
9729
9836
|
* The cut keeps at least one entry. When it leaves entries out, its last line reads
|
|
9730
9837
|
* `N older items not shown; name a narrower topic to narrow the recall`, which
|
|
9731
|
-
* {@link matchesCutLine} recognizes.
|
|
9838
|
+
* {@link matchesCutLine} recognizes. Pass `more` when the entries aren't in age order, so the line
|
|
9839
|
+
* doesn't claim an omitted entry is older than a kept one.
|
|
9732
9840
|
*
|
|
9733
9841
|
* @param entries - The entries in the order they are kept
|
|
9734
9842
|
* @param room - The estimate units the joined entries can take
|
|
9843
|
+
* @param kind - What the cut line calls an omitted entry. Default: `older`
|
|
9735
9844
|
* @returns The kept entries followed by the cut line when any were left out, joined by newlines
|
|
9736
9845
|
*
|
|
9737
9846
|
* @example
|
|
@@ -9739,7 +9848,7 @@ function splitTopic(topic) {
|
|
|
9739
9848
|
* cutListing(['first entry', 'second entry'], 1) // 'first entry\n1 older item not shown; name a narrower topic to narrow the recall'
|
|
9740
9849
|
* ```
|
|
9741
9850
|
*/
|
|
9742
|
-
function cutListing(entries, room) {
|
|
9851
|
+
function cutListing(entries, room, kind = "older") {
|
|
9743
9852
|
const stop = [...entries.keys()].findIndex((at) => at > 0 && estimateMessages([{
|
|
9744
9853
|
id: "recall",
|
|
9745
9854
|
role: "tool",
|
|
@@ -9747,7 +9856,7 @@ function cutListing(entries, room) {
|
|
|
9747
9856
|
}]) > room);
|
|
9748
9857
|
const kept = entries.slice(0, stop === -1 ? void 0 : stop);
|
|
9749
9858
|
const left = entries.length - kept.length;
|
|
9750
|
-
return [...kept, ...left > 0 ? [`${left}
|
|
9859
|
+
return [...kept, ...left > 0 ? [`${left} ${kind} item${left === 1 ? "" : "s"} not shown; name a narrower topic to narrow the recall`] : []].join("\n");
|
|
9751
9860
|
}
|
|
9752
9861
|
/**
|
|
9753
9862
|
* Checks whether a line is the cut line {@link cutListing} writes.
|
|
@@ -9761,7 +9870,7 @@ function cutListing(entries, room) {
|
|
|
9761
9870
|
* ```
|
|
9762
9871
|
*/
|
|
9763
9872
|
function matchesCutLine(line) {
|
|
9764
|
-
return /^\d+ older items? not shown; /.test(line);
|
|
9873
|
+
return /^\d+ (?:older|more) items? not shown; /.test(line);
|
|
9765
9874
|
}
|
|
9766
9875
|
/**
|
|
9767
9876
|
* Renders the tail stub of a lookup result from an earlier request.
|
|
@@ -9822,11 +9931,12 @@ function fitSlope(groups) {
|
|
|
9822
9931
|
* Collects the ids of the live messages in conversation order.
|
|
9823
9932
|
*
|
|
9824
9933
|
* @remarks
|
|
9825
|
-
* A message is live when it is a user message
|
|
9826
|
-
* call, and the input neither excludes it nor files it quiet
|
|
9827
|
-
*
|
|
9828
|
-
*
|
|
9829
|
-
*
|
|
9934
|
+
* A message is live when it is a user message or the first unsuperseded finding in its canonical
|
|
9935
|
+
* call identity's last run of identical text, and the input neither excludes it nor files it quiet
|
|
9936
|
+
* or superseded. When the whole run is superseded, its first finding reaches that final filter.
|
|
9937
|
+
* Different text or an undefined result replaces the earlier run, so an empty lookup leaves the
|
|
9938
|
+
* earlier result out of every record. A thrown lookup leaves the earlier result live. A finding
|
|
9939
|
+
* with no canonical identity participates in no replacement.
|
|
9830
9940
|
*
|
|
9831
9941
|
* @param input - The messages, findings, and classification to read
|
|
9832
9942
|
* @returns The live message ids
|
|
@@ -9842,7 +9952,14 @@ function collectLive(input) {
|
|
|
9842
9952
|
const position = new Map(input.messages.map((message, at) => [message.id, at]));
|
|
9843
9953
|
const findings = input.findings.filter((finding) => position.has(finding.id));
|
|
9844
9954
|
const identities = new Map(findings.map((finding) => [finding.id, identifyLookup(finding.name, finding.arguments)]));
|
|
9845
|
-
const current = new Set(
|
|
9955
|
+
const current = new Set([...Map.groupBy(findings, (finding) => identities.get(finding.id) ?? finding).values()].flatMap((group) => {
|
|
9956
|
+
const ordered = group.toSorted((left, right) => (position.get(left.id) ?? -1) - (position.get(right.id) ?? -1));
|
|
9957
|
+
const last = ordered.at(-1);
|
|
9958
|
+
if (last?.result === void 0) return [];
|
|
9959
|
+
const boundary = ordered.findLastIndex((finding) => finding.result === void 0 || finding.text !== last.text);
|
|
9960
|
+
const first = ordered.slice(boundary + 1).find((finding) => (classification.supersessions.get(finding.id) ?? []).length === 0) ?? ordered[boundary + 1];
|
|
9961
|
+
return first === void 0 ? [] : [first.id];
|
|
9962
|
+
}));
|
|
9846
9963
|
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);
|
|
9847
9964
|
}
|
|
9848
9965
|
/**
|
|
@@ -9897,17 +10014,18 @@ function placeMember(input, links, amended, id, seen, settled) {
|
|
|
9897
10014
|
return keys;
|
|
9898
10015
|
}
|
|
9899
10016
|
/**
|
|
9900
|
-
* Collects accepted
|
|
10017
|
+
* Collects accepted amendments of live messages, following superseded amenders to live successors.
|
|
9901
10018
|
*
|
|
9902
10019
|
* @remarks
|
|
9903
10020
|
* An accepted edge relates an earlier live message to an amender without claiming which sentences
|
|
9904
|
-
* changed.
|
|
9905
|
-
*
|
|
10021
|
+
* changed. A superseded amender points to its newest reachable live successor in conversation order,
|
|
10022
|
+
* with cycles guarded and duplicate endpoints removed. With no live successor, its endpoint stays.
|
|
10023
|
+
* This never restores superseded text. An excluded or quiet user or tool message has no effect.
|
|
9906
10024
|
*
|
|
9907
10025
|
* @param input - The exclusions and classification to read
|
|
9908
10026
|
* @param byId - The messages by id
|
|
9909
10027
|
* @param live - The live message ids from {@link collectLive}
|
|
9910
|
-
* @returns The distinct accepted
|
|
10028
|
+
* @returns The distinct accepted edges in conversation order
|
|
9911
10029
|
*
|
|
9912
10030
|
* @example
|
|
9913
10031
|
* ```ts
|
|
@@ -9921,7 +10039,10 @@ function collectAmendments(input, byId, live) {
|
|
|
9921
10039
|
const ordered = [...new Set(input.messages.map((message) => message.id))];
|
|
9922
10040
|
const positions = new Map(ordered.map((id, index) => [id, index]));
|
|
9923
10041
|
const effective = /* @__PURE__ */ new Set([...live, ...[...byId.values()].filter((message) => message.role !== "assistant" && !excluded.has(message.id) && !classification.quiet.has(message.id) && (classification.supersessions.get(message.id) ?? []).length > 0).map((message) => message.id)]);
|
|
9924
|
-
return ordered.filter((id) => living.has(id)).flatMap((earlier) => [...new Set(classification.amendments.get(earlier) ?? [])
|
|
10042
|
+
return ordered.filter((id) => living.has(id)).flatMap((earlier) => [...new Set((classification.amendments.get(earlier) ?? []).filter((later) => effective.has(later) && positions.has(later)).map((later) => {
|
|
10043
|
+
const successors = new Set(scanAmendments(classification.supersessions, later, () => true));
|
|
10044
|
+
return ordered.findLast((id) => living.has(id) && successors.has(id)) ?? later;
|
|
10045
|
+
}))].sort((a, b) => (positions.get(a) ?? 0) - (positions.get(b) ?? 0)).map((later) => ({
|
|
9925
10046
|
earlier,
|
|
9926
10047
|
later
|
|
9927
10048
|
})));
|
|
@@ -9967,6 +10088,83 @@ function buildLines(input, byId, id, holders, system) {
|
|
|
9967
10088
|
}];
|
|
9968
10089
|
});
|
|
9969
10090
|
}
|
|
10091
|
+
/**
|
|
10092
|
+
* Encodes a sentence's record placement without comparing rendered text.
|
|
10093
|
+
* @param line - The record key, title, source, and zero-based sentence index
|
|
10094
|
+
* @returns The serialized placement identity
|
|
10095
|
+
* @example
|
|
10096
|
+
* ```ts
|
|
10097
|
+
* buildLedgerLineKey({ key: 'rules', title: 'Rules', source: 'one', sentence: 0 })
|
|
10098
|
+
* ```
|
|
10099
|
+
*/
|
|
10100
|
+
function buildLedgerLineKey(line) {
|
|
10101
|
+
return JSON.stringify([
|
|
10102
|
+
line.key,
|
|
10103
|
+
line.title,
|
|
10104
|
+
line.source,
|
|
10105
|
+
line.sentence
|
|
10106
|
+
]);
|
|
10107
|
+
}
|
|
10108
|
+
/**
|
|
10109
|
+
* Collects the record's sentence receipts not already held by a window.
|
|
10110
|
+
* @param record - The selected record with its original sentence identities
|
|
10111
|
+
* @param held - Placement identities already rendered in the window
|
|
10112
|
+
* @returns The remaining sentences with their record placement
|
|
10113
|
+
* @example
|
|
10114
|
+
* ```ts
|
|
10115
|
+
* collectLedgerLines({ key: 'rules', title: 'Rules', members: [], lines: [] }, new Set()) // []
|
|
10116
|
+
* ```
|
|
10117
|
+
*/
|
|
10118
|
+
function collectLedgerLines(record, held) {
|
|
10119
|
+
return record.lines.map((line) => ({
|
|
10120
|
+
...line,
|
|
10121
|
+
key: record.key,
|
|
10122
|
+
title: record.title
|
|
10123
|
+
})).filter((line) => !held.has(buildLedgerLineKey(line)));
|
|
10124
|
+
}
|
|
10125
|
+
/**
|
|
10126
|
+
* Selects each marked request's unambiguous final call-free reply.
|
|
10127
|
+
* @param messages - Stored conversation messages in order
|
|
10128
|
+
* @param requests - Marked request ids delimiting reply intervals
|
|
10129
|
+
* @param notes - Ledger notes that separate answer passes
|
|
10130
|
+
* @returns Eligible final replies keyed by request id
|
|
10131
|
+
* @example
|
|
10132
|
+
* ```ts
|
|
10133
|
+
* collectLedgerReplies([], new Set(), new Set()).size // 0
|
|
10134
|
+
* ```
|
|
10135
|
+
*/
|
|
10136
|
+
function collectLedgerReplies(messages, requests, notes) {
|
|
10137
|
+
const positions = messages.flatMap((message, at) => requests.has(message.id) ? [at] : []);
|
|
10138
|
+
return new Map(positions.flatMap((position, index) => {
|
|
10139
|
+
const request = messages[position];
|
|
10140
|
+
const turns = messages.slice(position + 1, positions[index + 1]);
|
|
10141
|
+
const reply = turns.findLast((message) => message.role === "assistant" && !hasCalls(message));
|
|
10142
|
+
const answers = turns.flatMap((message, at) => message.role === "assistant" && !hasCalls(message) && message.content.trim() !== "" ? [at] : []);
|
|
10143
|
+
const certain = answers.every((at, offset) => offset === 0 || turns.slice((answers[offset - 1] ?? -1) + 1, at).some((message) => notes.has(message.id)));
|
|
10144
|
+
return request !== void 0 && certain && reply !== void 0 && reply.content.trim() !== "" ? [[request.id, reply]] : [];
|
|
10145
|
+
}));
|
|
10146
|
+
}
|
|
10147
|
+
/**
|
|
10148
|
+
* Captures source bytes and direct amendment edges for a held window.
|
|
10149
|
+
* @param messages - Current stored messages
|
|
10150
|
+
* @param sources - Requests, replies, and record sources the window holds
|
|
10151
|
+
* @param amendments - Accepted direct amendment edges from the current projection
|
|
10152
|
+
* @returns Source and edge identities for stale detection
|
|
10153
|
+
* @example
|
|
10154
|
+
* ```ts
|
|
10155
|
+
* collectLedgerEvidence([], new Set(), []).messages.size // 0
|
|
10156
|
+
* ```
|
|
10157
|
+
*/
|
|
10158
|
+
function collectLedgerEvidence(messages, sources, amendments) {
|
|
10159
|
+
return {
|
|
10160
|
+
messages: new Set(messages.filter((message) => sources.has(message.id)).map((message) => JSON.stringify(["message", message]))),
|
|
10161
|
+
amendments: new Map(amendments.filter((edge) => sources.has(edge.earlier) || sources.has(edge.later)).map((edge) => [JSON.stringify([
|
|
10162
|
+
"edge",
|
|
10163
|
+
edge.earlier,
|
|
10164
|
+
edge.later
|
|
10165
|
+
]), { ...edge }]))
|
|
10166
|
+
};
|
|
10167
|
+
}
|
|
9970
10168
|
// src/core/ledgers/Classifier.ts
|
|
9971
10169
|
/**
|
|
9972
10170
|
* Files messages through the conversation's judgment manager and reads their categories and corrections.
|
|
@@ -10011,7 +10209,7 @@ var Classifier = class {
|
|
|
10011
10209
|
/**
|
|
10012
10210
|
* Reads the category a message is filed under.
|
|
10013
10211
|
* @param id - The message id
|
|
10014
|
-
* @returns The assigned category, the recorded category at the cutoff, or `undefined
|
|
10212
|
+
* @returns The assigned category, the recorded category at the cutoff, or `undefined`; a quiet winner suppressed by the user literal floor remains undecided
|
|
10015
10213
|
*/
|
|
10016
10214
|
category(id) {
|
|
10017
10215
|
const message = this.#options.conversation.message(id);
|
|
@@ -10020,25 +10218,29 @@ var Classifier = class {
|
|
|
10020
10218
|
if (assigned !== void 0) return assigned;
|
|
10021
10219
|
const answer = this.#readCategories(id);
|
|
10022
10220
|
const cutoff = this.#options.thresholds.category;
|
|
10023
|
-
|
|
10221
|
+
const winner = LEDGER_CATEGORIES.flatMap((category) => {
|
|
10024
10222
|
const probability = answer?.probabilities[category];
|
|
10025
10223
|
return probability !== void 0 && probability >= cutoff ? [{
|
|
10026
10224
|
category,
|
|
10027
10225
|
probability
|
|
10028
10226
|
}] : [];
|
|
10029
10227
|
}).reduce((best, candidate) => best === void 0 || candidate.probability > best.probability ? candidate : best, void 0)?.category;
|
|
10228
|
+
return winner !== void 0 && QUIET_CATEGORIES.includes(winner) && !this.quiet(id) ? void 0 : winner;
|
|
10030
10229
|
}
|
|
10031
10230
|
/**
|
|
10032
10231
|
* Reports whether a message files under a quiet category.
|
|
10033
10232
|
* @param id - The message id
|
|
10034
|
-
* @returns True if the assigned or recorded
|
|
10233
|
+
* @returns True if the assigned category is quiet or the recorded quiet weight reaches the cutoff, except for a user message carrying an id or number; false otherwise
|
|
10035
10234
|
*/
|
|
10036
10235
|
quiet(id) {
|
|
10037
10236
|
const message = this.#options.conversation.message(id);
|
|
10038
10237
|
if (message === void 0) return false;
|
|
10039
10238
|
const assigned = this.#options.assign(message);
|
|
10040
10239
|
if (assigned !== void 0) return QUIET_CATEGORIES.includes(assigned);
|
|
10041
|
-
|
|
10240
|
+
if (this.#weigh(id, QUIET_CATEGORIES) < this.#options.thresholds.category) return false;
|
|
10241
|
+
if (message.role !== "user") return true;
|
|
10242
|
+
const literals = extractLiterals(message.content);
|
|
10243
|
+
return literals.ids.size + literals.numbers.size === 0;
|
|
10042
10244
|
}
|
|
10043
10245
|
/**
|
|
10044
10246
|
* Reports whether a message files under a decisive category.
|
|
@@ -10077,7 +10279,7 @@ var Classifier = class {
|
|
|
10077
10279
|
if (head !== "amends" && head !== "supersedes" || !(0, _orkestrel_contract.isString)(earlier) || !(0, _orkestrel_contract.isString)(later)) return [];
|
|
10078
10280
|
const before = this.#options.conversation.message(earlier);
|
|
10079
10281
|
const after = this.#options.conversation.message(later);
|
|
10080
|
-
if (before === void 0 || after === void 0 || (this.#readNoul(this.#buildPair(head, earlier, later)) ?? 0) < this.#options.thresholds[head]) return [];
|
|
10282
|
+
if (before === void 0 || after === void 0 || (this.#readNoul(this.#buildPair(head, earlier, later)) ?? 0) < this.#options.thresholds[head] || this.quiet(later)) return [];
|
|
10081
10283
|
return head === "amends" && !this.#sharesLiteral(extractLiterals(before.content), extractLiterals(after.content)) ? [] : [{
|
|
10082
10284
|
head,
|
|
10083
10285
|
earlier,
|
|
@@ -10329,8 +10531,9 @@ var Classifier = class {
|
|
|
10329
10531
|
* has left.
|
|
10330
10532
|
*
|
|
10331
10533
|
* @remarks
|
|
10332
|
-
* `observe` rescales from the first call
|
|
10333
|
-
*
|
|
10534
|
+
* `observe` rescales from the first call only when `spared` is absent, zero, or at least `overhead`,
|
|
10535
|
+
* with `max(0, overhead - spared)` taken out. A partially spared call keeps the existing scale.
|
|
10536
|
+
* It keeps that request's calls for the marginal rate and the longest final completion for the reply
|
|
10334
10537
|
* reserve after subtracting its thinking. `overhead` never changes after construction.
|
|
10335
10538
|
* {@link GaugeOptions} defines the measured use, reply reserve, and recall-room formulas.
|
|
10336
10539
|
* {@link LedgerOptions} defines the ledger's plan budget and recall close rule.
|
|
@@ -10388,7 +10591,7 @@ var Gauge = class {
|
|
|
10388
10591
|
}
|
|
10389
10592
|
remainder(calls) {
|
|
10390
10593
|
const call = calls.at(-1);
|
|
10391
|
-
const used = (0, _orkestrel_contract.isFiniteNumber)(call?.prompt) ? call.prompt + (call.completion ?? 0) - (this.#replay === "none" ? call.thinking ?? 0 : 0) : this.#overhead + this.#scale * (call?.estimate ?? 0);
|
|
10594
|
+
const used = (0, _orkestrel_contract.isFiniteNumber)(call?.prompt) ? call.prompt + (call.completion ?? 0) - (this.#replay === "none" ? call.thinking ?? 0 : 0) : Math.max(0, this.#overhead - (call?.spared ?? 0)) + this.#scale * (call?.estimate ?? 0);
|
|
10392
10595
|
return Math.max(0, this.#capacity - used);
|
|
10393
10596
|
}
|
|
10394
10597
|
reserve(calls, longest) {
|
|
@@ -10408,8 +10611,8 @@ var Gauge = class {
|
|
|
10408
10611
|
}
|
|
10409
10612
|
observe(calls, reply) {
|
|
10410
10613
|
const first = calls[0];
|
|
10411
|
-
if (first !== void 0 && (0, _orkestrel_contract.isFiniteNumber)(first.prompt) && first.estimate > 0) {
|
|
10412
|
-
const priced = first.prompt - this.#overhead;
|
|
10614
|
+
if (first !== void 0 && (0, _orkestrel_contract.isFiniteNumber)(first.prompt) && first.estimate > 0 && ((first.spared ?? 0) === 0 || (first.spared ?? 0) >= this.#overhead)) {
|
|
10615
|
+
const priced = first.prompt - Math.max(0, this.#overhead - (first.spared ?? 0));
|
|
10413
10616
|
if (priced > 0) this.#scale = priced / first.estimate;
|
|
10414
10617
|
}
|
|
10415
10618
|
this.#history = [...this.#history, [...calls]];
|
|
@@ -10586,6 +10789,9 @@ var LedgerRequest = class {
|
|
|
10586
10789
|
#faults = /* @__PURE__ */ new Set();
|
|
10587
10790
|
#message;
|
|
10588
10791
|
#plan;
|
|
10792
|
+
#scope;
|
|
10793
|
+
#draft;
|
|
10794
|
+
#sent;
|
|
10589
10795
|
#passes = [];
|
|
10590
10796
|
#attempts = [];
|
|
10591
10797
|
#admitted = /* @__PURE__ */ new Set();
|
|
@@ -10620,6 +10826,16 @@ var LedgerRequest = class {
|
|
|
10620
10826
|
get plan() {
|
|
10621
10827
|
return this.#plan;
|
|
10622
10828
|
}
|
|
10829
|
+
get scope() {
|
|
10830
|
+
return this.#scope;
|
|
10831
|
+
}
|
|
10832
|
+
apply(scope) {
|
|
10833
|
+
this.#scope = scope;
|
|
10834
|
+
}
|
|
10835
|
+
/** Returns the copy and receipts adopted by the last provider turn. */
|
|
10836
|
+
get sent() {
|
|
10837
|
+
return this.#sent;
|
|
10838
|
+
}
|
|
10623
10839
|
/**
|
|
10624
10840
|
* Returns the selection the current pass's run adopted last.
|
|
10625
10841
|
*
|
|
@@ -10675,6 +10891,8 @@ var LedgerRequest = class {
|
|
|
10675
10891
|
this.#passes.at(-1)?.adopt(selection, boundary);
|
|
10676
10892
|
}
|
|
10677
10893
|
observe(call, position) {
|
|
10894
|
+
const draft = this.#draft;
|
|
10895
|
+
this.#sent = draft !== void 0 && this.selection?.messages.some((message) => message.id === draft.copy.id && message.content === draft.copy.content) ? draft : void 0;
|
|
10678
10896
|
this.#passes.at(-1)?.observe(call, position);
|
|
10679
10897
|
}
|
|
10680
10898
|
spend(usage) {
|
|
@@ -10695,8 +10913,9 @@ var LedgerRequest = class {
|
|
|
10695
10913
|
faulted(error) {
|
|
10696
10914
|
return this.#faults.has(error);
|
|
10697
10915
|
}
|
|
10698
|
-
file(attempts, plan) {
|
|
10916
|
+
file(attempts, plan, draft) {
|
|
10699
10917
|
this.#attempts = [...this.#attempts, ...attempts];
|
|
10918
|
+
this.#draft = draft;
|
|
10700
10919
|
if (plan !== void 0) this.#plan = plan;
|
|
10701
10920
|
}
|
|
10702
10921
|
admit(name, args) {
|
|
@@ -10828,6 +11047,29 @@ var LedgerScan = class {
|
|
|
10828
11047
|
}
|
|
10829
11048
|
};
|
|
10830
11049
|
// src/core/ledgers/shapers.ts
|
|
11050
|
+
/** Describes the minimal serialized evidence of a nonempty exchange window. */
|
|
11051
|
+
var ledgerWindowShape = (0, _orkestrel_contract.objectShape)({
|
|
11052
|
+
digest: (0, _orkestrel_contract.stringShape)(),
|
|
11053
|
+
exchanges: (0, _orkestrel_contract.arrayShape)((0, _orkestrel_contract.objectShape)({
|
|
11054
|
+
request: (0, _orkestrel_contract.stringShape)(),
|
|
11055
|
+
copy: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.stringShape)()),
|
|
11056
|
+
reply: (0, _orkestrel_contract.stringShape)(),
|
|
11057
|
+
lines: (0, _orkestrel_contract.arrayShape)((0, _orkestrel_contract.objectShape)({
|
|
11058
|
+
key: (0, _orkestrel_contract.stringShape)(),
|
|
11059
|
+
title: (0, _orkestrel_contract.stringShape)(),
|
|
11060
|
+
source: (0, _orkestrel_contract.stringShape)(),
|
|
11061
|
+
sentence: (0, _orkestrel_contract.numberShape)({
|
|
11062
|
+
integer: true,
|
|
11063
|
+
min: 0,
|
|
11064
|
+
max: Number.MAX_SAFE_INTEGER
|
|
11065
|
+
})
|
|
11066
|
+
}))
|
|
11067
|
+
}), { min: 1 }),
|
|
11068
|
+
amendments: (0, _orkestrel_contract.arrayShape)((0, _orkestrel_contract.objectShape)({
|
|
11069
|
+
earlier: (0, _orkestrel_contract.stringShape)(),
|
|
11070
|
+
later: (0, _orkestrel_contract.stringShape)()
|
|
11071
|
+
}))
|
|
11072
|
+
});
|
|
10831
11073
|
/**
|
|
10832
11074
|
* Describes a ledger snapshot exactly: an unknown key refuses, so a key a later version adds never reads
|
|
10833
11075
|
* as absent.
|
|
@@ -10845,13 +11087,36 @@ var ledgerSnapshotShape = (0, _orkestrel_contract.objectShape)({
|
|
|
10845
11087
|
gauge: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.objectShape)({
|
|
10846
11088
|
scale: (0, _orkestrel_contract.numberShape)(),
|
|
10847
11089
|
overhead: (0, _orkestrel_contract.numberShape)()
|
|
10848
|
-
}))
|
|
11090
|
+
})),
|
|
11091
|
+
window: (0, _orkestrel_contract.optionalShape)(ledgerWindowShape)
|
|
10849
11092
|
});
|
|
10850
11093
|
// src/core/ledgers/contracts.ts
|
|
10851
|
-
/** Reads
|
|
11094
|
+
/** Reads structural faults of a serialized exchange window. */
|
|
11095
|
+
var ledgerWindowContract = (0, _orkestrel_contract.createContract)(ledgerWindowShape);
|
|
11096
|
+
/** Reads structural faults of a ledger snapshot, including its optional held exchange window. */
|
|
10852
11097
|
var ledgerSnapshotContract = (0, _orkestrel_contract.createContract)(ledgerSnapshotShape);
|
|
10853
11098
|
// src/core/ledgers/validators.ts
|
|
10854
11099
|
/**
|
|
11100
|
+
* Checks whether a value has the exact shape of a nonempty exchange window.
|
|
11101
|
+
* @param value - The untrusted window
|
|
11102
|
+
* @returns True if the window and its members are well shaped; false otherwise
|
|
11103
|
+
* @example
|
|
11104
|
+
* ```ts
|
|
11105
|
+
* isLedgerWindowSnapshot({ digest: 'checksum', exchanges: [{ request: 'request', reply: 'reply', lines: [] }], amendments: [] }) // true
|
|
11106
|
+
* ```
|
|
11107
|
+
*/
|
|
11108
|
+
function isLedgerWindowSnapshot(value) {
|
|
11109
|
+
return (0, _orkestrel_contract.holds)(() => {
|
|
11110
|
+
if (!(0, _orkestrel_contract.isRecord)(value) || Object.keys(value).length !== 3 || !(0, _orkestrel_contract.isString)(value.digest)) return false;
|
|
11111
|
+
const { exchanges, amendments } = value;
|
|
11112
|
+
if (!(0, _orkestrel_contract.arrayOf)(_orkestrel_contract.isRecord)(exchanges) || exchanges.length === 0 || !(0, _orkestrel_contract.arrayOf)(_orkestrel_contract.isRecord)(amendments)) return false;
|
|
11113
|
+
return exchanges.every((entry) => {
|
|
11114
|
+
const { request, reply, copy, lines } = entry;
|
|
11115
|
+
return Object.keys(entry).length === 3 + Number(copy !== void 0) && (0, _orkestrel_contract.isString)(request) && (0, _orkestrel_contract.isString)(reply) && (copy === void 0 || (0, _orkestrel_contract.isString)(copy)) && (0, _orkestrel_contract.arrayOf)(_orkestrel_contract.isRecord)(lines) && lines.every((line) => Object.keys(line).length === 4 && (0, _orkestrel_contract.isString)(line.key) && (0, _orkestrel_contract.isString)(line.title) && (0, _orkestrel_contract.isString)(line.source) && isNonNegativeSafeInteger(line.sentence));
|
|
11116
|
+
}) && amendments.every((edge) => Object.keys(edge).length === 2 && (0, _orkestrel_contract.isString)(edge.earlier) && (0, _orkestrel_contract.isString)(edge.later));
|
|
11117
|
+
});
|
|
11118
|
+
}
|
|
11119
|
+
/**
|
|
10855
11120
|
* Checks whether a value is finite and lies in the interval (0, 1].
|
|
10856
11121
|
* @param value - The value to inspect
|
|
10857
11122
|
* @returns True if the value is a valid ledger fraction; false otherwise
|
|
@@ -10902,6 +11167,8 @@ function isLedgerQuestion(value) {
|
|
|
10902
11167
|
* guard is structural: it admits a conversation holding a stored `system` role
|
|
10903
11168
|
* or a repeated id, which `requireConversationSnapshot` and the `Conversation` constructor then
|
|
10904
11169
|
* refuse as the stored-data check a ledger's hydrate runs.
|
|
11170
|
+
* A present `window` must be nonempty and exactly shaped. This guard does not audit its references
|
|
11171
|
+
* or sentence ranges. Hydration discards the window when its digest disagrees or cannot be computed.
|
|
10905
11172
|
*
|
|
10906
11173
|
* @param value - The value to inspect, such as a parsed checkpoint
|
|
10907
11174
|
* @returns True if the value has the shape of a ledger snapshot whose marked ids name messages of its own conversation; false otherwise
|
|
@@ -10915,8 +11182,8 @@ function isLedgerQuestion(value) {
|
|
|
10915
11182
|
function isLedgerSnapshot(value) {
|
|
10916
11183
|
return (0, _orkestrel_contract.holds)(() => {
|
|
10917
11184
|
if (!(0, _orkestrel_contract.isRecord)(value)) return false;
|
|
10918
|
-
const { conversation, requests, notes, failures, gauge } = value;
|
|
10919
|
-
if (Object.keys(value).length !== (gauge
|
|
11185
|
+
const { conversation, requests, notes, failures, gauge, window } = value;
|
|
11186
|
+
if (Object.keys(value).length !== 4 + Number(gauge !== void 0) + Number(window !== void 0)) return false;
|
|
10920
11187
|
if (!isConversationSnapshot(conversation)) return false;
|
|
10921
11188
|
const isIds = (0, _orkestrel_contract.arrayOf)(_orkestrel_contract.isString);
|
|
10922
11189
|
if (!isIds(requests) || !isIds(notes) || !isIds(failures)) return false;
|
|
@@ -10926,7 +11193,7 @@ function isLedgerSnapshot(value) {
|
|
|
10926
11193
|
if (!(0, _orkestrel_contract.isFiniteNumber)(scale) || scale <= 0 || !(0, _orkestrel_contract.isFiniteNumber)(overhead) || overhead < 0) return false;
|
|
10927
11194
|
}
|
|
10928
11195
|
const roles = new Map(conversation.messages.map((message) => [message.id, message.role]));
|
|
10929
|
-
return requests.every((id) => roles.get(id) === "user") && notes.every((id) => roles.get(id) === "user") && failures.every((id) => roles.get(id) === "tool");
|
|
11196
|
+
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));
|
|
10930
11197
|
});
|
|
10931
11198
|
}
|
|
10932
11199
|
// src/core/ledgers/Ledger.ts
|
|
@@ -10956,6 +11223,8 @@ var Ledger = class {
|
|
|
10956
11223
|
#scans = /* @__PURE__ */ new Set();
|
|
10957
11224
|
#calibrations = /* @__PURE__ */ new Set();
|
|
10958
11225
|
#gauge;
|
|
11226
|
+
#window = [];
|
|
11227
|
+
#evidence = collectLedgerEvidence([], /* @__PURE__ */ new Set(), []);
|
|
10959
11228
|
/**
|
|
10960
11229
|
* Composes the conversation, classifier, tools, and agent.
|
|
10961
11230
|
* @param provider - The provider that serves the conversation
|
|
@@ -10989,7 +11258,8 @@ var Ledger = class {
|
|
|
10989
11258
|
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");
|
|
10990
11259
|
const snapshot = options.snapshot;
|
|
10991
11260
|
if (snapshot !== void 0 && !isLedgerSnapshot(snapshot)) {
|
|
10992
|
-
const
|
|
11261
|
+
const candidate = options.snapshot;
|
|
11262
|
+
const faults = ledgerSnapshotContract.audit(candidate);
|
|
10993
11263
|
throw new LedgerError("SNAPSHOT", `snapshot must be well formed and mark only messages of its conversation; pass what snapshot() returned${faults.length === 0 ? "" : `\n${(0, _orkestrel_contract.describeFaults)(faults, ledgerSnapshotContract.schema)}`}`, { context: { faults } });
|
|
10994
11264
|
}
|
|
10995
11265
|
this.#provider = provider;
|
|
@@ -11037,7 +11307,7 @@ var Ledger = class {
|
|
|
11037
11307
|
}));
|
|
11038
11308
|
tools.add((0, _orkestrel_tool.createTool)({
|
|
11039
11309
|
name: "recall",
|
|
11040
|
-
description: `
|
|
11310
|
+
description: `Find something said earlier that isn't in the messages you can see, by an owner name, an id, or one of the topics ${renderTopicNames(options.topics)}. Returns statements and lookup findings first, then earlier requests and replies labeled by origin; newest first within each group.`,
|
|
11041
11311
|
contract: (0, _orkestrel_contract.objectShape)({ topic: (0, _orkestrel_contract.stringShape)({
|
|
11042
11312
|
min: 1,
|
|
11043
11313
|
description: "An owner name, an id, or a topic"
|
|
@@ -11121,8 +11391,8 @@ var Ledger = class {
|
|
|
11121
11391
|
}
|
|
11122
11392
|
}
|
|
11123
11393
|
/**
|
|
11124
|
-
* Serializes the conversation,
|
|
11125
|
-
* @returns The snapshot, each id list in conversation order
|
|
11394
|
+
* Serializes the conversation, marked ids, gauge, and completed exchange window for a later ledger.
|
|
11395
|
+
* @returns The snapshot, each id list in conversation order, with a gauge and window only when held
|
|
11126
11396
|
* @throws {AgentError} Thrown when a request or calibration is active (code `'CONCURRENCY'`)
|
|
11127
11397
|
*/
|
|
11128
11398
|
snapshot() {
|
|
@@ -11131,12 +11401,31 @@ var Ledger = class {
|
|
|
11131
11401
|
const conversation = this.#conversation.snapshot();
|
|
11132
11402
|
const ids = conversation.messages.map((message) => message.id);
|
|
11133
11403
|
const gauge = this.gauge;
|
|
11404
|
+
const window = {
|
|
11405
|
+
exchanges: this.#window.map((entry) => ({
|
|
11406
|
+
request: entry.request.id,
|
|
11407
|
+
...entry.request.content === this.#conversation.message(entry.request.id)?.content ? {} : { copy: entry.request.content },
|
|
11408
|
+
reply: entry.reply.id,
|
|
11409
|
+
lines: entry.lines.map(({ key, title, source, sentence }) => ({
|
|
11410
|
+
key,
|
|
11411
|
+
title,
|
|
11412
|
+
source,
|
|
11413
|
+
sentence
|
|
11414
|
+
}))
|
|
11415
|
+
})),
|
|
11416
|
+
amendments: [...this.#evidence.amendments.values()].map((edge) => ({ ...edge }))
|
|
11417
|
+
};
|
|
11418
|
+
const digest = window.exchanges.length === 0 ? void 0 : digestLedgerWindow(window.exchanges, conversation.messages);
|
|
11134
11419
|
return {
|
|
11135
11420
|
conversation,
|
|
11136
11421
|
requests: ids.filter((id) => this.#requests.has(id)),
|
|
11137
11422
|
notes: ids.filter((id) => this.#annotations.has(id)),
|
|
11138
11423
|
failures: ids.filter((id) => this.#results.get(id)?.success === false),
|
|
11139
|
-
...gauge === void 0 ? {} : { gauge }
|
|
11424
|
+
...gauge === void 0 ? {} : { gauge },
|
|
11425
|
+
...window.exchanges.length === 0 || digest === void 0 ? {} : { window: {
|
|
11426
|
+
...window,
|
|
11427
|
+
digest
|
|
11428
|
+
} }
|
|
11140
11429
|
};
|
|
11141
11430
|
}
|
|
11142
11431
|
/**
|
|
@@ -11154,6 +11443,7 @@ var Ledger = class {
|
|
|
11154
11443
|
if (this.#busy()) throw new AgentError("CONCURRENCY", "a ledger request is already active");
|
|
11155
11444
|
const caller = (0, _orkestrel_abort.createAbort)({ ...signal === void 0 ? {} : { signal } }).signal;
|
|
11156
11445
|
const request = new LedgerRequest(content, this.#options.recall?.limit);
|
|
11446
|
+
const scope = this.#agent.context.scope;
|
|
11157
11447
|
this.#live.add(request);
|
|
11158
11448
|
try {
|
|
11159
11449
|
if (this.#gauge === void 0) await this.#measureGauge(caller);
|
|
@@ -11179,7 +11469,8 @@ var Ledger = class {
|
|
|
11179
11469
|
content: LEDGER_NOTES.cue
|
|
11180
11470
|
}).id);
|
|
11181
11471
|
const previous = this.#agent.context.scope;
|
|
11182
|
-
|
|
11472
|
+
const answer = createScope({
|
|
11473
|
+
...previous,
|
|
11183
11474
|
name: "answer",
|
|
11184
11475
|
tools: [],
|
|
11185
11476
|
select: async (conversation, message, runSignal) => {
|
|
@@ -11190,11 +11481,12 @@ var Ledger = class {
|
|
|
11190
11481
|
messages: selection.messages.filter((one) => one.role !== "tool" && !hasCalls(one))
|
|
11191
11482
|
};
|
|
11192
11483
|
}
|
|
11193
|
-
})
|
|
11484
|
+
});
|
|
11485
|
+
this.#agent.context.apply(answer);
|
|
11194
11486
|
try {
|
|
11195
11487
|
passes.push(await this.#generatePass(request, caller, false));
|
|
11196
11488
|
} finally {
|
|
11197
|
-
this.#agent.context.apply(previous);
|
|
11489
|
+
if (this.#agent.context.scope === answer) this.#agent.context.apply(previous);
|
|
11198
11490
|
}
|
|
11199
11491
|
}
|
|
11200
11492
|
const last = passes.at(-1) ?? first;
|
|
@@ -11213,7 +11505,9 @@ var Ledger = class {
|
|
|
11213
11505
|
...last.stop === void 0 ? {} : { stop: last.stop }
|
|
11214
11506
|
};
|
|
11215
11507
|
} finally {
|
|
11508
|
+
if (request.scope !== void 0 && this.#agent.context.scope === request.scope) this.#agent.context.apply(scope);
|
|
11216
11509
|
this.#flush();
|
|
11510
|
+
this.#commitExchange(request);
|
|
11217
11511
|
this.#live.delete(request);
|
|
11218
11512
|
}
|
|
11219
11513
|
}
|
|
@@ -11276,6 +11570,37 @@ var Ledger = class {
|
|
|
11276
11570
|
for (const id of snapshot.requests) this.#requests.add(id);
|
|
11277
11571
|
for (const id of snapshot.notes) this.#annotations.add(id);
|
|
11278
11572
|
const messages = this.#conversation.messages();
|
|
11573
|
+
if (snapshot.window !== void 0 && digestLedgerWindow(snapshot.window.exchanges, messages) === snapshot.window.digest) {
|
|
11574
|
+
const window = snapshot.window.exchanges.map((entry) => {
|
|
11575
|
+
const request = this.#conversation.message(entry.request);
|
|
11576
|
+
const reply = this.#conversation.message(entry.reply);
|
|
11577
|
+
if (request === void 0 || reply === void 0) throw new LedgerError("SNAPSHOT", "window pair must belong to its conversation");
|
|
11578
|
+
const lines = entry.lines.map((line) => {
|
|
11579
|
+
const source = this.#conversation.message(line.source);
|
|
11580
|
+
if (source === void 0) throw new LedgerError("SNAPSHOT", "window source must belong to its conversation");
|
|
11581
|
+
return {
|
|
11582
|
+
...line,
|
|
11583
|
+
text: splitSentences(source.content)[line.sentence] ?? "",
|
|
11584
|
+
topics: [],
|
|
11585
|
+
role: source.role
|
|
11586
|
+
};
|
|
11587
|
+
});
|
|
11588
|
+
return {
|
|
11589
|
+
request: {
|
|
11590
|
+
...request,
|
|
11591
|
+
content: entry.copy ?? request.content
|
|
11592
|
+
},
|
|
11593
|
+
reply,
|
|
11594
|
+
lines
|
|
11595
|
+
};
|
|
11596
|
+
});
|
|
11597
|
+
this.#window = window;
|
|
11598
|
+
this.#evidence = collectLedgerEvidence(messages, new Set(this.#window.flatMap((entry) => [
|
|
11599
|
+
entry.request.id,
|
|
11600
|
+
entry.reply.id,
|
|
11601
|
+
...entry.lines.map((line) => line.source)
|
|
11602
|
+
])), snapshot.window.amendments);
|
|
11603
|
+
}
|
|
11279
11604
|
const groups = collectToolGroups(messages);
|
|
11280
11605
|
for (const message of messages) {
|
|
11281
11606
|
if (!snapshot.failures.includes(message.id)) continue;
|
|
@@ -11406,20 +11731,26 @@ var Ledger = class {
|
|
|
11406
11731
|
const { attempts, failure, ...filed } = classified;
|
|
11407
11732
|
const planned = (0, _orkestrel_contract.attempt)(() => {
|
|
11408
11733
|
if (filed.fault !== void 0) throw filed.fault;
|
|
11734
|
+
const { draft, ...plan } = this.#plan(selected, this.#rescan());
|
|
11409
11735
|
return {
|
|
11410
|
-
|
|
11411
|
-
|
|
11412
|
-
|
|
11736
|
+
draft,
|
|
11737
|
+
selection: {
|
|
11738
|
+
...plan,
|
|
11739
|
+
...filed,
|
|
11740
|
+
...failure === void 0 ? {} : { fault: failure }
|
|
11741
|
+
}
|
|
11413
11742
|
};
|
|
11414
11743
|
});
|
|
11415
|
-
request.file(attempts, planned.success ? planned.value : void 0);
|
|
11744
|
+
request.file(attempts, planned.success ? planned.value.selection : void 0, planned.success ? planned.value.draft : void 0);
|
|
11416
11745
|
if (!planned.success) return this.#refuse(planned.error, filed, this.#conversation);
|
|
11746
|
+
const selection = planned.value.selection;
|
|
11417
11747
|
return this.#annotations.has(message.id) ? {
|
|
11418
|
-
...
|
|
11419
|
-
messages: [...
|
|
11420
|
-
} :
|
|
11748
|
+
...selection,
|
|
11749
|
+
messages: [...selection.messages, ...this.#collectAfter(selected)]
|
|
11750
|
+
} : selection;
|
|
11421
11751
|
}
|
|
11422
11752
|
#refuse(error, filed, conversation) {
|
|
11753
|
+
if (conversation === this.#conversation && !(isLedgerError(error) && error.code === "REQUEST")) this.#current()?.file([]);
|
|
11423
11754
|
return {
|
|
11424
11755
|
...filed,
|
|
11425
11756
|
messages: conversation.view(),
|
|
@@ -11446,7 +11777,11 @@ var Ledger = class {
|
|
|
11446
11777
|
topics: [...near]
|
|
11447
11778
|
});
|
|
11448
11779
|
const total = Math.max(0, (this.#options.capacity - this.#predict) * this.#share.prompt - (this.#gauge?.overhead ?? 0)) / (1 + LEDGER_SCALE_DRIFT);
|
|
11449
|
-
const
|
|
11780
|
+
const built = this.#agent.context.build({
|
|
11781
|
+
messages: [request],
|
|
11782
|
+
judgments: []
|
|
11783
|
+
});
|
|
11784
|
+
const tail = this.#selectTail(request, total, input, scan);
|
|
11450
11785
|
const tailIds = new Set(tail.map((message) => message.id));
|
|
11451
11786
|
const scoped = records.some((record) => record.key !== LEDGER_RULES_KEY);
|
|
11452
11787
|
const held = /* @__PURE__ */ new Set([...projection.records.filter((record) => scoped || record.key === "rules").flatMap((record) => record.members), ...records.length > 0 ? projection.records.flatMap((record) => record.members.filter((id) => this.#conversation.message(id)?.role === "user" && this.#classifier.category(id) === "rule" && this.#classifier.decisive(id))) : []]);
|
|
@@ -11494,25 +11829,121 @@ var Ledger = class {
|
|
|
11494
11829
|
source: unit.source,
|
|
11495
11830
|
record: this.#buildUnitRecord(unit.source, unit.category, input, projection, held)
|
|
11496
11831
|
}));
|
|
11497
|
-
const trimmed = this.#trim(steps, records, mapped, new Set(ordered.map((unit) => unit.source)),
|
|
11498
|
-
const
|
|
11499
|
-
|
|
11500
|
-
|
|
11501
|
-
|
|
11502
|
-
|
|
11503
|
-
|
|
11504
|
-
|
|
11505
|
-
|
|
11506
|
-
const
|
|
11507
|
-
|
|
11508
|
-
|
|
11832
|
+
const trimmed = this.#trim(steps, records, mapped, new Set(ordered.map((unit) => unit.source)), built, tail, total, projection.amendments, scan);
|
|
11833
|
+
const replies = collectLedgerReplies(scan.messages, this.#requests, this.#annotations);
|
|
11834
|
+
const sources = new Set(this.#window.flatMap((entry) => [
|
|
11835
|
+
entry.request.id,
|
|
11836
|
+
entry.reply.id,
|
|
11837
|
+
...entry.lines.map((line) => line.source)
|
|
11838
|
+
]));
|
|
11839
|
+
const evidence = collectLedgerEvidence(scan.messages, sources, projection.amendments);
|
|
11840
|
+
const prefix = this.#window.flatMap((entry) => entry.lines);
|
|
11841
|
+
const prior = buildLedgerRenderContext(scan.messages, prefix, projection.amendments);
|
|
11842
|
+
const combined = buildLedgerRenderContext(scan.messages, [...prefix, ...trimmed.rendered.lines], projection.amendments);
|
|
11843
|
+
const stale = evidence.messages.size !== this.#evidence.messages.size || [...evidence.messages].some((receipt) => !this.#evidence.messages.has(receipt)) || evidence.amendments.size !== this.#evidence.amendments.size || [...evidence.amendments.keys()].some((receipt) => !this.#evidence.amendments.has(receipt)) || this.#window.some((entry) => replies.get(entry.request.id)?.id !== entry.reply.id || entry.lines.some((line) => !live.has(line.source))) || projection.amendments.some((edge) => prior.first.has(edge.earlier) && prior.complete.has(edge.later) !== combined.complete.has(edge.later) || prior.first.has(edge.later) && combined.complete.has(edge.later) && !prior.first.has(edge.earlier) && combined.first.has(edge.earlier));
|
|
11844
|
+
const last = stale ? this.#window.at(-1) : void 0;
|
|
11845
|
+
const retained = last === void 0 || replies.get(last.request.id)?.id !== last.reply.id ? void 0 : this.#conversation.message(last.request.id);
|
|
11846
|
+
if (stale) this.#window = [];
|
|
11847
|
+
const [previous, reply] = this.#window.length === 0 ? this.#selectExchange(request, input) : [];
|
|
11848
|
+
const window = this.#window.length > 0 ? this.#window : previous !== void 0 && reply !== void 0 ? [{
|
|
11849
|
+
request: previous,
|
|
11850
|
+
reply,
|
|
11851
|
+
lines: []
|
|
11852
|
+
}] : retained !== void 0 && last !== void 0 ? [{
|
|
11853
|
+
request: retained,
|
|
11854
|
+
reply: last.reply,
|
|
11855
|
+
lines: []
|
|
11856
|
+
}] : [];
|
|
11857
|
+
if (this.#window.length === 0) {
|
|
11858
|
+
const derived = collectLedgerEvidence(scan.messages, new Set(window.flatMap((entry) => [entry.request.id, entry.reply.id])), projection.amendments);
|
|
11859
|
+
this.#window = window;
|
|
11860
|
+
this.#evidence = derived;
|
|
11861
|
+
}
|
|
11862
|
+
const carried = window.flatMap((entry) => entry.lines);
|
|
11863
|
+
const delta = this.#render(trimmed.records, mapped, trimmed.included, projection.amendments, scan, new Set(carried.map(buildLedgerLineKey)), carried);
|
|
11864
|
+
const newest = window.at(-1);
|
|
11865
|
+
const plain = newest === void 0 ? void 0 : this.#conversation.message(newest.request.id);
|
|
11866
|
+
const fallback = newest === void 0 || plain === void 0 ? [] : [{
|
|
11867
|
+
request: plain,
|
|
11868
|
+
reply: newest.reply,
|
|
11869
|
+
lines: []
|
|
11870
|
+
}];
|
|
11871
|
+
const empty = {
|
|
11872
|
+
window: [],
|
|
11873
|
+
rendered: trimmed.rendered
|
|
11874
|
+
};
|
|
11875
|
+
const rungs = [
|
|
11876
|
+
{
|
|
11877
|
+
window,
|
|
11878
|
+
rendered: delta
|
|
11879
|
+
},
|
|
11880
|
+
{
|
|
11881
|
+
window: fallback,
|
|
11882
|
+
rendered: trimmed.rendered
|
|
11883
|
+
},
|
|
11884
|
+
empty
|
|
11885
|
+
];
|
|
11886
|
+
const probes = rungs.map((rung) => [...built.slice(0, -1), ...stripThinking([
|
|
11887
|
+
...tail.slice(0, -1),
|
|
11888
|
+
...rung.window.flatMap((entry) => [entry.request, entry.reply]),
|
|
11889
|
+
buildRequestMessage(built.at(-1) ?? request, rung.rendered.text)
|
|
11890
|
+
], this.#replay)]);
|
|
11891
|
+
const names = this.#agent.context.scope?.tools;
|
|
11892
|
+
const definitions = this.#agent.context.tools.definitions();
|
|
11893
|
+
const offered = rungs.map((rung) => hasHiddenRecall(input, request.id, this.#requests, this.#annotations, [...tail.slice(0, -1), ...rung.window.flatMap((entry) => [entry.request, entry.reply])], [...rung.window.flatMap((entry) => entry.lines), ...rung.rendered.lines]));
|
|
11894
|
+
const longest = this.#findLongest();
|
|
11895
|
+
const closed = probes.map((messages, at) => {
|
|
11896
|
+
const tools = definitions.filter((tool) => (names === void 0 || names.includes(tool.name)) && (tool.name !== "recall" || offered[at]));
|
|
11897
|
+
const calls = [{
|
|
11898
|
+
estimate: estimateMessages(messages),
|
|
11899
|
+
tools: tools.length,
|
|
11900
|
+
spared: this.#spared(tools)
|
|
11901
|
+
}];
|
|
11902
|
+
return offered[at] === true && this.#gauge !== void 0 && this.#gauge.remainder(calls) - this.#predict < 2 * this.#gauge.reserve(calls, longest);
|
|
11509
11903
|
});
|
|
11904
|
+
const prices = probes.map((messages) => this.#price(messages));
|
|
11905
|
+
const admitted = rungs.find((_rung, at) => (prices[at] ?? Infinity) <= total && (closed[2] === true || closed[at] === false)) ?? empty;
|
|
11906
|
+
if (offered[rungs.indexOf(admitted)] === false && (names === void 0 || names.includes("recall"))) {
|
|
11907
|
+
const tools = definitions.filter((tool) => tool.name !== "recall").map((tool) => tool.name);
|
|
11908
|
+
const narrowed = this.#agent.context.scope?.narrow({ tools }) ?? createScope({
|
|
11909
|
+
name: "ledger",
|
|
11910
|
+
tools
|
|
11911
|
+
});
|
|
11912
|
+
this.#current()?.apply(narrowed);
|
|
11913
|
+
this.#agent.context.apply(narrowed);
|
|
11914
|
+
}
|
|
11915
|
+
const copy = buildRequestMessage(request, admitted.rendered.text);
|
|
11916
|
+
const kept = admitted.window.flatMap((entry) => entry.lines);
|
|
11917
|
+
const origins = /* @__PURE__ */ new Set([
|
|
11918
|
+
request.id,
|
|
11919
|
+
...admitted.window.flatMap((entry) => [entry.request.id, entry.reply.id]),
|
|
11920
|
+
...kept.map((line) => line.source),
|
|
11921
|
+
...admitted.rendered.lines.map((line) => line.source)
|
|
11922
|
+
]);
|
|
11923
|
+
const draft = {
|
|
11924
|
+
copy,
|
|
11925
|
+
lines: admitted.rendered.lines,
|
|
11926
|
+
evidence: collectLedgerEvidence(scan.messages, origins, projection.amendments),
|
|
11927
|
+
window: admitted.window
|
|
11928
|
+
};
|
|
11929
|
+
const shown = buildLedgerRenderContext(scan.messages, [...kept, ...admitted.rendered.lines], []).complete;
|
|
11930
|
+
return {
|
|
11931
|
+
draft,
|
|
11932
|
+
messages: [
|
|
11933
|
+
...tail.slice(0, -1).map((message) => message.role === "tool" ? this.#renderTailStub(message, scan, shown) : message),
|
|
11934
|
+
...admitted.window.flatMap((entry) => [entry.request, entry.reply]),
|
|
11935
|
+
copy
|
|
11936
|
+
]
|
|
11937
|
+
};
|
|
11938
|
+
}
|
|
11939
|
+
#trim(steps, records, mapped, included, built, tail, total, amendments, scan) {
|
|
11510
11940
|
const head = built.slice(0, -1);
|
|
11511
|
-
const priced = built.at(-1)
|
|
11941
|
+
const priced = built.at(-1);
|
|
11942
|
+
if (priced === void 0) throw new Error("a built plan holds its request");
|
|
11512
11943
|
const found = findLedgerCut(0, steps.length, (count) => {
|
|
11513
11944
|
const cut = buildLedgerCut(steps.slice(0, count), records, included);
|
|
11514
11945
|
const rendered = this.#render(cut.records, mapped, cut.included, amendments, scan);
|
|
11515
|
-
const copy = buildRequestMessage(priced, rendered);
|
|
11946
|
+
const copy = buildRequestMessage(priced, rendered.text);
|
|
11516
11947
|
return this.#price([...head, ...stripThinking([...tail.slice(0, -1), copy], this.#replay)]) <= total ? {
|
|
11517
11948
|
...cut,
|
|
11518
11949
|
rendered
|
|
@@ -11537,36 +11968,48 @@ var Ledger = class {
|
|
|
11537
11968
|
const live = collectProjectionIds(projection);
|
|
11538
11969
|
return scanAmendments(input.classification.amendments, source, (id) => id === source || !held.has(id) && live.has(id)).flatMap((id) => this.#projectLines(input, id));
|
|
11539
11970
|
}
|
|
11540
|
-
#render(records, mapped, included, amendments, scan) {
|
|
11541
|
-
const
|
|
11971
|
+
#render(records, mapped, included, amendments, scan, held = /* @__PURE__ */ new Set(), prefix = []) {
|
|
11972
|
+
const population = records.map((record) => ({
|
|
11973
|
+
...record,
|
|
11974
|
+
lines: collectLedgerLines(record, held)
|
|
11975
|
+
}));
|
|
11976
|
+
const entries = mapped.filter((unit) => included.has(unit.source)).flatMap(({ record: unit }) => [...Map.groupBy(collectLedgerLines(unit, /* @__PURE__ */ new Set()), (line) => line.source)].map(([source, lines]) => ({
|
|
11542
11977
|
unit,
|
|
11543
11978
|
source,
|
|
11544
11979
|
lines
|
|
11545
11980
|
})));
|
|
11546
11981
|
const first = new Map(entries.toReversed().map((entry) => [entry.source, entry]));
|
|
11547
|
-
const unique = entries.filter((entry) => first.get(entry.source) === entry)
|
|
11548
|
-
|
|
11549
|
-
|
|
11550
|
-
|
|
11982
|
+
const unique = entries.filter((entry) => first.get(entry.source) === entry).map((entry) => ({
|
|
11983
|
+
...entry,
|
|
11984
|
+
lines: entry.lines.filter((line) => !prefix.some((prior) => prior.source === line.source && prior.sentence === line.sentence))
|
|
11985
|
+
})).filter((entry) => entry.lines.length > 0);
|
|
11986
|
+
const record = population.find((candidate) => candidate.key === "rules" && candidate.lines.length > 0);
|
|
11987
|
+
const ownerRecords = population.filter((candidate) => candidate.key !== "rules" && candidate.lines.length > 0);
|
|
11988
|
+
const lines = [
|
|
11551
11989
|
...ownerRecords.flatMap((candidate) => candidate.lines),
|
|
11552
11990
|
...unique.filter((entry) => entry.unit.key !== LEDGER_RULES_KEY).flatMap((entry) => entry.lines),
|
|
11553
11991
|
...record?.lines ?? [],
|
|
11554
11992
|
...unique.filter((entry) => entry.unit.key === LEDGER_RULES_KEY).flatMap((entry) => entry.lines)
|
|
11555
|
-
]
|
|
11993
|
+
];
|
|
11994
|
+
const context = buildLedgerRenderContext(scan.messages, [...prefix, ...lines], amendments);
|
|
11556
11995
|
const owners = ownerRecords.map((owner) => renderLedgerPinned(owner, context)).join("\n\n");
|
|
11557
|
-
const rendered = unique.map(({ unit, source, lines }) => {
|
|
11996
|
+
const rendered = unique.map(({ unit, source, lines: retained }) => {
|
|
11558
11997
|
const sentences = splitSentences(this.#conversation.message(source)?.content ?? "");
|
|
11559
11998
|
return {
|
|
11560
11999
|
rules: unit.key === LEDGER_RULES_KEY,
|
|
11561
|
-
texts: unit.key === "rules" && source === unit.members[0] ?
|
|
12000
|
+
texts: unit.key === "rules" && source === unit.members[0] ? retained.map((line) => this.#renderSource(source, sentences, [line], context, scan)) : [this.#renderSource(source, sentences, retained, context, scan)]
|
|
11562
12001
|
};
|
|
11563
12002
|
});
|
|
11564
12003
|
const pinned = rendered.filter((one) => !one.rules).flatMap((one) => one.texts);
|
|
11565
12004
|
const rules = rendered.filter((one) => one.rules).flatMap((one) => one.texts);
|
|
11566
12005
|
const body = [owners, pinned.join("\n")].filter((text) => text !== "").join("\n\n");
|
|
11567
|
-
return
|
|
12006
|
+
return {
|
|
12007
|
+
text: [body === "" ? "" : `## Records\n${body}`, record === void 0 ? rules.length === 0 ? "" : ["## Rules", ...rules].join("\n") : [renderLedgerRecord(record, context), ...rules].join("\n")].filter((part) => part !== "").join("\n\n"),
|
|
12008
|
+
lines
|
|
12009
|
+
};
|
|
11568
12010
|
}
|
|
11569
|
-
#selectTail(request,
|
|
12011
|
+
#selectTail(request, total, input, scan) {
|
|
12012
|
+
const cap = total * this.#share.tail;
|
|
11570
12013
|
const first = input.messages.findIndex((message) => this.#requests.has(message.id));
|
|
11571
12014
|
const seed = input.messages.slice(0, first < 0 ? input.messages.findIndex((message) => message.id === request.id) : first);
|
|
11572
12015
|
const groups = collectToolGroups(seed).flatMap((group) => {
|
|
@@ -11597,6 +12040,29 @@ var Ledger = class {
|
|
|
11597
12040
|
const stop = exchanges.findIndex((_exchange, index) => this.#price(stripThinking([...exchanges.slice(0, index + 1).toReversed().flat(), request], this.#replay)) > cap);
|
|
11598
12041
|
return [...exchanges.slice(0, stop === -1 ? exchanges.length : stop).toReversed().flat(), request];
|
|
11599
12042
|
}
|
|
12043
|
+
#selectExchange(request, input) {
|
|
12044
|
+
const before = input.messages.slice(0, input.messages.findIndex((message) => message.id === request.id));
|
|
12045
|
+
const previous = before.findLast((message) => this.#requests.has(message.id));
|
|
12046
|
+
const reply = previous === void 0 ? void 0 : collectLedgerReplies(before, this.#requests, this.#annotations).get(previous.id);
|
|
12047
|
+
return previous !== void 0 && reply !== void 0 ? [previous, reply] : [];
|
|
12048
|
+
}
|
|
12049
|
+
#commitExchange(request) {
|
|
12050
|
+
const draft = request.sent;
|
|
12051
|
+
const message = request.message;
|
|
12052
|
+
if (message === void 0) return;
|
|
12053
|
+
const reply = collectLedgerReplies(this.#conversation.messages(), this.#requests, this.#annotations).get(message.id);
|
|
12054
|
+
if (reply === void 0) return;
|
|
12055
|
+
this.#window = [...draft?.window ?? this.#window, {
|
|
12056
|
+
request: draft?.copy ?? message,
|
|
12057
|
+
reply,
|
|
12058
|
+
lines: draft?.lines ?? []
|
|
12059
|
+
}];
|
|
12060
|
+
const evidence = draft?.evidence ?? this.#evidence;
|
|
12061
|
+
this.#evidence = {
|
|
12062
|
+
messages: /* @__PURE__ */ new Set([...evidence.messages, ...collectLedgerEvidence([message, reply], /* @__PURE__ */ new Set([message.id, reply.id]), []).messages]),
|
|
12063
|
+
amendments: evidence.amendments
|
|
12064
|
+
};
|
|
12065
|
+
}
|
|
11600
12066
|
#renderTailStub(message, scan, shown) {
|
|
11601
12067
|
const group = scan.group(message.id);
|
|
11602
12068
|
const call = group === void 0 ? void 0 : findLedgerCall(group, message);
|
|
@@ -11605,7 +12071,7 @@ var Ledger = class {
|
|
|
11605
12071
|
const visible = renderStub(call?.name ?? "tool", call?.arguments ?? {}, "shown");
|
|
11606
12072
|
return {
|
|
11607
12073
|
...message,
|
|
11608
|
-
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" : shown.has(
|
|
12074
|
+
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")
|
|
11609
12075
|
};
|
|
11610
12076
|
}
|
|
11611
12077
|
#observeTurn() {
|
|
@@ -11616,11 +12082,19 @@ var Ledger = class {
|
|
|
11616
12082
|
const additions = this.#conversation.messages().slice(boundary);
|
|
11617
12083
|
const messages = this.#agent.context.build(request.selection);
|
|
11618
12084
|
const names = this.#agent.context.scope?.tools;
|
|
12085
|
+
const tools = this.#agent.context.tools.definitions().filter((tool) => names === void 0 || names.includes(tool.name));
|
|
11619
12086
|
request.observe({
|
|
11620
12087
|
estimate: estimateMessages(stripThinking([...messages, ...additions], this.#replay)),
|
|
11621
|
-
tools:
|
|
12088
|
+
tools: tools.length,
|
|
12089
|
+
spared: this.#spared(tools)
|
|
11622
12090
|
}, this.#conversation.messages().length);
|
|
11623
12091
|
}
|
|
12092
|
+
#spared(tools) {
|
|
12093
|
+
const overhead = this.#gauge?.overhead ?? 0;
|
|
12094
|
+
if (tools.length === 0) return overhead;
|
|
12095
|
+
const missing = this.#agent.context.tools.definitions().filter((tool) => !tools.some((one) => one.name === tool.name));
|
|
12096
|
+
return missing.length === 0 ? 0 : Math.min(overhead, estimateTokens(JSON.stringify(missing)) * (this.#gauge?.scale ?? 1));
|
|
12097
|
+
}
|
|
11624
12098
|
#findLongest() {
|
|
11625
12099
|
return this.#conversation.messages().filter((message) => message.role === "assistant").reduce((longest, message) => message.content.length > longest.length ? message.content : longest, "");
|
|
11626
12100
|
}
|
|
@@ -11673,11 +12147,12 @@ var Ledger = class {
|
|
|
11673
12147
|
const source = listable.get(id);
|
|
11674
12148
|
if (source === void 0) return [];
|
|
11675
12149
|
const lookup = scan.finding(id);
|
|
11676
|
-
const
|
|
12150
|
+
const content = source.content.replace(/(^|[\n\v\f\r\u0085\u2028\u2029])(?=Earlier (?:request|reply):)/g, "$1 ");
|
|
12151
|
+
const text = lookup === void 0 ? content : `${renderLookupCall(lookup.name, lookup.arguments)}: ${content}`;
|
|
11677
12152
|
return [{
|
|
11678
12153
|
id,
|
|
11679
12154
|
text,
|
|
11680
|
-
stored: lookup === void 0 ? [] : [[splitResultLines(text)[0] ?? "", splitResultLines(
|
|
12155
|
+
stored: lookup === void 0 ? [] : [[splitResultLines(text)[0] ?? "", splitResultLines(content)[0] ?? ""]]
|
|
11681
12156
|
}];
|
|
11682
12157
|
});
|
|
11683
12158
|
return {
|
|
@@ -11690,7 +12165,14 @@ var Ledger = class {
|
|
|
11690
12165
|
listed: [],
|
|
11691
12166
|
recalled: /* @__PURE__ */ new Map()
|
|
11692
12167
|
});
|
|
11693
|
-
const
|
|
12168
|
+
const earlier = input.messages.slice(0, Math.max(0, start)).reverse().flatMap((message) => {
|
|
12169
|
+
if (gathered.done.has(message.id) || this.#annotations.has(message.id)) return [];
|
|
12170
|
+
const label = this.#requests.has(message.id) ? LEDGER_RECALL_LABELS.request : message.role === "assistant" && !hasCalls(message) && message.content.trim() !== "" ? LEDGER_RECALL_LABELS.reply : void 0;
|
|
12171
|
+
if (label === void 0 || !searches.some((search) => search.words.length > 0 && search.words.every((word) => message.content.toLowerCase().includes(word)))) return [];
|
|
12172
|
+
return [`${label} ${message.content.replace(/[\n\v\f\r\u0085\u2028\u2029]+/g, "\n ")}`];
|
|
12173
|
+
});
|
|
12174
|
+
const listed = [...gathered.listed, ...earlier];
|
|
12175
|
+
const result = listed.length === 0 ? `nothing earlier on "${topic}"; answer from the messages you can see` : cutListing(listed, room, earlier.length > 0 ? "more" : "older");
|
|
11694
12176
|
request?.list(result, gathered.recalled);
|
|
11695
12177
|
return result;
|
|
11696
12178
|
} finally {
|
|
@@ -11703,7 +12185,7 @@ var Ledger = class {
|
|
|
11703
12185
|
const result = this.#results.get(message.id);
|
|
11704
12186
|
if (message.role !== "tool" || result?.success !== true) return [];
|
|
11705
12187
|
const recalled = result.name === "recall";
|
|
11706
|
-
if (recalled && /^nothing on /.test(message.content)) return [];
|
|
12188
|
+
if (recalled && /^nothing earlier on /.test(message.content)) return [];
|
|
11707
12189
|
const stored = recalled ? request.lines(message.content) : void 0;
|
|
11708
12190
|
return splitResultLines(message.content).filter((line) => !recalled || !matchesCutLine(line)).map((line) => stored?.get(line) ?? line);
|
|
11709
12191
|
}))];
|
|
@@ -11768,6 +12250,7 @@ exports.LEDGER_CATEGORIES = LEDGER_CATEGORIES;
|
|
|
11768
12250
|
exports.LEDGER_NOTES = LEDGER_NOTES;
|
|
11769
12251
|
exports.LEDGER_OWNER_PREFIX = LEDGER_OWNER_PREFIX;
|
|
11770
12252
|
exports.LEDGER_QUESTIONS = LEDGER_QUESTIONS;
|
|
12253
|
+
exports.LEDGER_RECALL_LABELS = LEDGER_RECALL_LABELS;
|
|
11771
12254
|
exports.LEDGER_RULES_KEY = LEDGER_RULES_KEY;
|
|
11772
12255
|
exports.LEDGER_SCALE_DRIFT = LEDGER_SCALE_DRIFT;
|
|
11773
12256
|
exports.LEDGER_SLICE = LEDGER_SLICE;
|
|
@@ -11826,6 +12309,7 @@ exports.buildJudgeResult = buildJudgeResult;
|
|
|
11826
12309
|
exports.buildJudgments = buildJudgments;
|
|
11827
12310
|
exports.buildLedgerCut = buildLedgerCut;
|
|
11828
12311
|
exports.buildLedgerIndex = buildLedgerIndex;
|
|
12312
|
+
exports.buildLedgerLineKey = buildLedgerLineKey;
|
|
11829
12313
|
exports.buildLedgerRenderContext = buildLedgerRenderContext;
|
|
11830
12314
|
exports.buildLines = buildLines;
|
|
11831
12315
|
exports.buildProviderHeaders = buildProviderHeaders;
|
|
@@ -11840,9 +12324,13 @@ exports.chargeUsage = chargeUsage;
|
|
|
11840
12324
|
exports.collectAmendments = collectAmendments;
|
|
11841
12325
|
exports.collectExchanges = collectExchanges;
|
|
11842
12326
|
exports.collectImageData = collectImageData;
|
|
12327
|
+
exports.collectLedgerEvidence = collectLedgerEvidence;
|
|
12328
|
+
exports.collectLedgerLines = collectLedgerLines;
|
|
12329
|
+
exports.collectLedgerReplies = collectLedgerReplies;
|
|
11843
12330
|
exports.collectLive = collectLive;
|
|
11844
12331
|
exports.collectNames = collectNames;
|
|
11845
12332
|
exports.collectProjectionIds = collectProjectionIds;
|
|
12333
|
+
exports.collectRecallMessages = collectRecallMessages;
|
|
11846
12334
|
exports.collectRegistry = collectRegistry;
|
|
11847
12335
|
exports.collectToolGroups = collectToolGroups;
|
|
11848
12336
|
exports.computeThinking = computeThinking;
|
|
@@ -11879,6 +12367,7 @@ exports.denyCall = denyCall;
|
|
|
11879
12367
|
exports.describeQuestionRefusal = describeQuestionRefusal;
|
|
11880
12368
|
exports.describeRelayRefusal = describeRelayRefusal;
|
|
11881
12369
|
exports.describeSnapshotRefusal = describeSnapshotRefusal;
|
|
12370
|
+
exports.digestLedgerWindow = digestLedgerWindow;
|
|
11882
12371
|
exports.estimateMessages = estimateMessages;
|
|
11883
12372
|
exports.estimateRequest = estimateRequest;
|
|
11884
12373
|
exports.estimateTokens = estimateTokens;
|
|
@@ -11894,6 +12383,7 @@ exports.fitSlope = fitSlope;
|
|
|
11894
12383
|
exports.freezeJSON = freezeJSON;
|
|
11895
12384
|
exports.handleAgentQueueJob = handleAgentQueueJob;
|
|
11896
12385
|
exports.hasCalls = hasCalls;
|
|
12386
|
+
exports.hasHiddenRecall = hasHiddenRecall;
|
|
11897
12387
|
exports.identifyLookup = identifyLookup;
|
|
11898
12388
|
exports.inferStop = inferStop;
|
|
11899
12389
|
exports.intersectKeys = intersectKeys;
|
|
@@ -11915,6 +12405,7 @@ exports.isJudgment = isJudgment;
|
|
|
11915
12405
|
exports.isLedgerError = isLedgerError;
|
|
11916
12406
|
exports.isLedgerQuestion = isLedgerQuestion;
|
|
11917
12407
|
exports.isLedgerSnapshot = isLedgerSnapshot;
|
|
12408
|
+
exports.isLedgerWindowSnapshot = isLedgerWindowSnapshot;
|
|
11918
12409
|
exports.isMemo = isMemo;
|
|
11919
12410
|
exports.isMemoOrigin = isMemoOrigin;
|
|
11920
12411
|
exports.isMemoSnapshot = isMemoSnapshot;
|
|
@@ -11938,11 +12429,14 @@ exports.judgmentContract = judgmentContract;
|
|
|
11938
12429
|
exports.judgmentShape = judgmentShape;
|
|
11939
12430
|
exports.ledgerSnapshotContract = ledgerSnapshotContract;
|
|
11940
12431
|
exports.ledgerSnapshotShape = ledgerSnapshotShape;
|
|
12432
|
+
exports.ledgerWindowContract = ledgerWindowContract;
|
|
12433
|
+
exports.ledgerWindowShape = ledgerWindowShape;
|
|
11941
12434
|
exports.linkOwners = linkOwners;
|
|
11942
12435
|
exports.matchEntities = matchEntities;
|
|
11943
12436
|
exports.matchesCutLine = matchesCutLine;
|
|
11944
12437
|
exports.matchesJSON = matchesJSON;
|
|
11945
12438
|
exports.matchesJudgment = matchesJudgment;
|
|
12439
|
+
exports.matchesLookup = matchesLookup;
|
|
11946
12440
|
exports.measureAnswer = measureAnswer;
|
|
11947
12441
|
exports.measureMessage = measureMessage;
|
|
11948
12442
|
exports.measureRequest = measureRequest;
|