@orkestrel/agent 0.0.37 → 0.0.39
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 +122 -26
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +42 -10
- package/dist/src/core/index.d.ts +42 -10
- package/dist/src/core/index.js +122 -26
- package/dist/src/core/index.js.map +1 -1
- package/package.json +11 -11
package/dist/src/core/index.cjs
CHANGED
|
@@ -2756,6 +2756,7 @@ var AgentJudge = class {
|
|
|
2756
2756
|
*
|
|
2757
2757
|
* @remarks
|
|
2758
2758
|
* The caller supplies the server origin and model. Every question travels in one request.
|
|
2759
|
+
* Wire keys are zero-based positions in question entry order; answers return under the caller's ids.
|
|
2759
2760
|
* Server measures are ignored; the response model is preserved.
|
|
2760
2761
|
* `headers` supplies authentication through the shared judge engine.
|
|
2761
2762
|
* The example readings are those of the response Ollama 0.40.0 returned for that request on 2026-10-07.
|
|
@@ -2812,7 +2813,7 @@ var SystemOneJudge = class extends AgentJudge {
|
|
|
2812
2813
|
/** Identifies the System One protocol. */
|
|
2813
2814
|
name = "systemone";
|
|
2814
2815
|
/**
|
|
2815
|
-
* Projects the state and questions onto the System One request with the configured model.
|
|
2816
|
+
* Projects the state and questions onto the System One request with the configured model and positional keys.
|
|
2816
2817
|
*
|
|
2817
2818
|
* @param request - The state and questions keyed by caller id
|
|
2818
2819
|
* @returns The System One request body
|
|
@@ -2821,11 +2822,11 @@ var SystemOneJudge = class extends AgentJudge {
|
|
|
2821
2822
|
return {
|
|
2822
2823
|
state: request.state,
|
|
2823
2824
|
model: this.model,
|
|
2824
|
-
questions: Object.fromEntries(Object.
|
|
2825
|
+
questions: Object.fromEntries(Object.values(request.questions).map((question, index) => [String(index), questionToSystemOne(question)]))
|
|
2825
2826
|
};
|
|
2826
2827
|
}
|
|
2827
2828
|
/**
|
|
2828
|
-
* Decodes
|
|
2829
|
+
* Decodes positional System One answers under caller ids and reports the server model and available usage.
|
|
2829
2830
|
*
|
|
2830
2831
|
* @param value - The parsed response body
|
|
2831
2832
|
* @param request - The questions defining the expected answers
|
|
@@ -2835,9 +2836,10 @@ var SystemOneJudge = class extends AgentJudge {
|
|
|
2835
2836
|
*/
|
|
2836
2837
|
read(value, request) {
|
|
2837
2838
|
if (!isSystemOneResponse(value)) throw new JudgeError("PROTOCOL", `judge error: invalid System One response envelope; received ${(0, _orkestrel_contract.preview)(value)}`);
|
|
2838
|
-
const entries = Object.entries(request.questions).map(([id, question]) => {
|
|
2839
|
-
|
|
2840
|
-
|
|
2839
|
+
const entries = Object.entries(request.questions).map(([id, question], index) => {
|
|
2840
|
+
const position = String(index);
|
|
2841
|
+
if (!Object.hasOwn(value.answers, position)) throw new JudgeError("PROTOCOL", `judge error: question ${id} has no System One answer`);
|
|
2842
|
+
const wire = value.answers[position];
|
|
2841
2843
|
if (!isSystemOneAnswer(wire)) throw new JudgeError("PROTOCOL", `judge error: question ${id} has an invalid System One answer; received ${(0, _orkestrel_contract.preview)(wire)}`);
|
|
2842
2844
|
const answer = extractSystemOneAnswer(wire, question);
|
|
2843
2845
|
if (answer === void 0) throw new JudgeError("PROTOCOL", `judge error: question ${id} has a mismatched or incomplete System One answer`);
|
|
@@ -9833,14 +9835,19 @@ function splitTopic(topic) {
|
|
|
9833
9835
|
* Cuts entries to a room and names how many it left out.
|
|
9834
9836
|
*
|
|
9835
9837
|
* @remarks
|
|
9836
|
-
*
|
|
9838
|
+
* By default the cut keeps at least one entry. With `first: false`, it keeps whole entries only
|
|
9839
|
+
* when the joined result, tool framing, and omission line fit, and considers later entries after
|
|
9840
|
+
* an oversized group. When it leaves some entries out, its last line reads
|
|
9837
9841
|
* `N older items not shown; name a narrower topic to narrow the recall`, which
|
|
9838
9842
|
* {@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.
|
|
9843
|
+
* doesn't claim an omitted entry is older than a kept one. A fitted cut also uses `more` when it
|
|
9844
|
+
* skips an entry before a kept one. With no kept entry it reads
|
|
9845
|
+
* `N older items didn't fit in this request; answer from the messages you can see`.
|
|
9840
9846
|
*
|
|
9841
9847
|
* @param entries - The entries in the order they are kept
|
|
9842
9848
|
* @param room - The estimate units the joined entries can take
|
|
9843
9849
|
* @param kind - What the cut line calls an omitted entry. Default: `older`
|
|
9850
|
+
* @param first - If `true`, keeps the first entry regardless of room; if `false`, fits every entry and the omission line. Default: `true`
|
|
9844
9851
|
* @returns The kept entries followed by the cut line when any were left out, joined by newlines
|
|
9845
9852
|
*
|
|
9846
9853
|
* @example
|
|
@@ -9848,7 +9855,30 @@ function splitTopic(topic) {
|
|
|
9848
9855
|
* cutListing(['first entry', 'second entry'], 1) // 'first entry\n1 older item not shown; name a narrower topic to narrow the recall'
|
|
9849
9856
|
* ```
|
|
9850
9857
|
*/
|
|
9851
|
-
function cutListing(entries, room, kind = "older") {
|
|
9858
|
+
function cutListing(entries, room, kind = "older", first = true) {
|
|
9859
|
+
if (!first) {
|
|
9860
|
+
if (estimateMessages([{
|
|
9861
|
+
id: "recall",
|
|
9862
|
+
role: "tool",
|
|
9863
|
+
content: entries.join("\n")
|
|
9864
|
+
}]) <= room) return entries.join("\n");
|
|
9865
|
+
const kept = entries.reduce((accepted, entry, at) => {
|
|
9866
|
+
const left = entries.length - accepted.length - 1;
|
|
9867
|
+
const omitted = accepted.length < at ? "more" : kind;
|
|
9868
|
+
return estimateMessages([{
|
|
9869
|
+
id: "recall",
|
|
9870
|
+
role: "tool",
|
|
9871
|
+
content: [
|
|
9872
|
+
...accepted.map((index) => entries[index]),
|
|
9873
|
+
entry,
|
|
9874
|
+
...left > 0 ? [`${left} ${omitted} item${left === 1 ? "" : "s"} not shown; name a narrower topic to narrow the recall`] : []
|
|
9875
|
+
].join("\n")
|
|
9876
|
+
}]) <= room ? [...accepted, at] : accepted;
|
|
9877
|
+
}, []);
|
|
9878
|
+
const left = entries.length - kept.length;
|
|
9879
|
+
const omitted = kept.some((at, index) => at !== index) ? "more" : kind;
|
|
9880
|
+
return [...kept.map((at) => entries[at]), ...left > 0 ? [`${left} ${omitted} item${left === 1 ? "" : "s"} ${kept.length === 0 ? "didn't fit in this request; answer from the messages you can see" : "not shown; name a narrower topic to narrow the recall"}`] : []].join("\n");
|
|
9881
|
+
}
|
|
9852
9882
|
const stop = [...entries.keys()].findIndex((at) => at > 0 && estimateMessages([{
|
|
9853
9883
|
id: "recall",
|
|
9854
9884
|
role: "tool",
|
|
@@ -9870,7 +9900,7 @@ function cutListing(entries, room, kind = "older") {
|
|
|
9870
9900
|
* ```
|
|
9871
9901
|
*/
|
|
9872
9902
|
function matchesCutLine(line) {
|
|
9873
|
-
return /^\d+ (?:older|more) items? not shown; /.test(line);
|
|
9903
|
+
return /^\d+ (?:older|more) items? (?:not shown; |didn't fit in this request; answer from the messages you can see$)/.test(line);
|
|
9874
9904
|
}
|
|
9875
9905
|
/**
|
|
9876
9906
|
* Renders the tail stub of a lookup result from an earlier request.
|
|
@@ -10795,7 +10825,7 @@ var LedgerRequest = class {
|
|
|
10795
10825
|
#passes = [];
|
|
10796
10826
|
#attempts = [];
|
|
10797
10827
|
#admitted = /* @__PURE__ */ new Set();
|
|
10798
|
-
#listed =
|
|
10828
|
+
#listed = [];
|
|
10799
10829
|
#recalls = 0;
|
|
10800
10830
|
#closed = false;
|
|
10801
10831
|
/**
|
|
@@ -10932,11 +10962,24 @@ var LedgerRequest = class {
|
|
|
10932
10962
|
close() {
|
|
10933
10963
|
this.#closed = true;
|
|
10934
10964
|
}
|
|
10935
|
-
list(result, lines) {
|
|
10936
|
-
|
|
10965
|
+
list(result, lines, groups) {
|
|
10966
|
+
const accepted = groups.reduce((kept, group) => {
|
|
10967
|
+
const offset = kept.length === 0 ? 0 : kept.join("\n").length + 1;
|
|
10968
|
+
return result.slice(offset) === group || result.slice(offset).startsWith(`${group}\n`) ? [...kept, group] : kept;
|
|
10969
|
+
}, []);
|
|
10970
|
+
this.#listed = [...this.#listed, {
|
|
10971
|
+
result,
|
|
10972
|
+
lines,
|
|
10973
|
+
groups: accepted,
|
|
10974
|
+
turn: this.calls.length
|
|
10975
|
+
}];
|
|
10976
|
+
}
|
|
10977
|
+
/** Returns recall results with their accepted whole groups and provider-turn positions. */
|
|
10978
|
+
get listings() {
|
|
10979
|
+
return this.#listed;
|
|
10937
10980
|
}
|
|
10938
10981
|
lines(result) {
|
|
10939
|
-
return this.#listed.
|
|
10982
|
+
return this.#listed.findLast((listing) => listing.result === result)?.lines;
|
|
10940
10983
|
}
|
|
10941
10984
|
};
|
|
10942
10985
|
// src/core/ledgers/LedgerScan.ts
|
|
@@ -11459,10 +11502,10 @@ var Ledger = class {
|
|
|
11459
11502
|
});
|
|
11460
11503
|
const passes = [first];
|
|
11461
11504
|
if (!caller.aborted && (first.partial || first.content.trim() === "")) {
|
|
11462
|
-
const
|
|
11463
|
-
if (digest !== void 0) this.#annotations.add(this.#conversation.add({
|
|
11505
|
+
const recovery = this.#buildDigest(request, entered);
|
|
11506
|
+
if (recovery.digest !== void 0) this.#annotations.add(this.#conversation.add({
|
|
11464
11507
|
role: "user",
|
|
11465
|
-
content: digest
|
|
11508
|
+
content: recovery.digest
|
|
11466
11509
|
}).id);
|
|
11467
11510
|
this.#annotations.add(this.#conversation.add({
|
|
11468
11511
|
role: "user",
|
|
@@ -11478,7 +11521,7 @@ var Ledger = class {
|
|
|
11478
11521
|
if (selection.fault !== void 0) return selection;
|
|
11479
11522
|
return {
|
|
11480
11523
|
...selection,
|
|
11481
|
-
messages: selection.messages.filter((one) => one.role !== "tool" && !hasCalls(one))
|
|
11524
|
+
messages: selection.messages.filter((one) => one.role !== "tool" && !hasCalls(one) && !recovery.omitted.has(one.id))
|
|
11482
11525
|
};
|
|
11483
11526
|
}
|
|
11484
11527
|
});
|
|
@@ -12111,11 +12154,21 @@ var Ledger = class {
|
|
|
12111
12154
|
request?.admit("recall", { topic });
|
|
12112
12155
|
const gauge = this.#gauge;
|
|
12113
12156
|
const calls = request?.calls ?? [];
|
|
12114
|
-
if (gauge !== void 0 && calls.length > 0 && gauge.remainder(calls) - this.#predict < 2 * gauge.reserve(calls, this.#findLongest())) request?.close();
|
|
12115
12157
|
request?.recall();
|
|
12116
12158
|
const guidance = `an owner name, an id, or one of ${renderTopicNames(this.#options.topics)}`;
|
|
12117
12159
|
if (topic === "") throw new Error(`recall needs a topic: ${guidance}`);
|
|
12118
|
-
const
|
|
12160
|
+
const rate = this.#recallRate(request) * (1 + LEDGER_SCALE_DRIFT);
|
|
12161
|
+
const call = calls.at(-1);
|
|
12162
|
+
const carried = request === void 0 ? 0 : estimateMessages(stripThinking([...this.#agent.context.build(request.selection), ...this.#conversation.messages().slice(request.boundary)], this.#replay));
|
|
12163
|
+
const completion = (0, _orkestrel_contract.isFiniteNumber)(call?.prompt) ? (call.completion ?? 0) - (this.#replay === "none" ? call.thinking ?? 0 : 0) : 0;
|
|
12164
|
+
const extra = Math.max(0, (carried - (call?.estimate ?? carried)) * rate - completion);
|
|
12165
|
+
const drift = (0, _orkestrel_contract.isFiniteNumber)(call?.prompt) ? 0 : Math.max(0, (call?.estimate ?? 0) * (rate - (gauge?.scale ?? rate)));
|
|
12166
|
+
const siblings = estimateMessages((request?.listings ?? []).filter((listing) => listing.turn === calls.length).map((listing) => ({
|
|
12167
|
+
id: "result",
|
|
12168
|
+
role: "tool",
|
|
12169
|
+
content: listing.result
|
|
12170
|
+
})));
|
|
12171
|
+
const room = gauge === void 0 ? -estimateMessages([buildRecallMessage(topic)]) : (gauge.remainder(calls) - this.#predict - extra - drift) / rate - siblings;
|
|
12119
12172
|
const scan = this.#scan(this.#conversation.messages());
|
|
12120
12173
|
const added = this.#scans.size === 0;
|
|
12121
12174
|
if (added) this.#hold(scan);
|
|
@@ -12172,8 +12225,8 @@ var Ledger = class {
|
|
|
12172
12225
|
return [`${label} ${message.content.replace(/[\n\v\f\r\u0085\u2028\u2029]+/g, "\n ")}`];
|
|
12173
12226
|
});
|
|
12174
12227
|
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");
|
|
12176
|
-
request?.list(result, gathered.recalled);
|
|
12228
|
+
const result = listed.length === 0 ? `nothing earlier on "${topic}"; answer from the messages you can see` : cutListing(listed, room, earlier.length > 0 ? "more" : "older", gauge === void 0);
|
|
12229
|
+
request?.list(result, gathered.recalled, listed);
|
|
12177
12230
|
return result;
|
|
12178
12231
|
} finally {
|
|
12179
12232
|
if (added) this.#scans.delete(scan);
|
|
@@ -12181,15 +12234,58 @@ var Ledger = class {
|
|
|
12181
12234
|
}
|
|
12182
12235
|
#buildDigest(request, entered) {
|
|
12183
12236
|
this.#flush();
|
|
12184
|
-
const
|
|
12237
|
+
const groups = [...new Set(this.#collectAfter(entered).flatMap((message) => {
|
|
12185
12238
|
const result = this.#results.get(message.id);
|
|
12186
12239
|
if (message.role !== "tool" || result?.success !== true) return [];
|
|
12187
12240
|
const recalled = result.name === "recall";
|
|
12188
12241
|
if (recalled && /^nothing earlier on /.test(message.content)) return [];
|
|
12189
|
-
const
|
|
12190
|
-
return
|
|
12242
|
+
const listing = recalled ? request.listings.findLast((one) => one.result === message.content) : void 0;
|
|
12243
|
+
return (listing?.groups ?? [message.content]).map((group) => splitResultLines(group).map((line) => listing?.lines.get(line) ?? line).join("\n")).filter((group) => group !== "");
|
|
12191
12244
|
}))];
|
|
12192
|
-
|
|
12245
|
+
const unique = groups.filter((group, at) => !splitResultLines(group).every((line) => groups.slice(0, at).some((earlier) => splitResultLines(earlier).includes(line))));
|
|
12246
|
+
const digest = unique.length === 0 ? void 0 : `${LEDGER_NOTES.results}\n${unique.join("\n")}`;
|
|
12247
|
+
const omitted = /* @__PURE__ */ new Set();
|
|
12248
|
+
const rate = this.#recallRate(request) * (1 + LEDGER_SCALE_DRIFT);
|
|
12249
|
+
const allowance = (this.#options.capacity - this.#predict) / rate;
|
|
12250
|
+
const after = this.#collectAfter(entered);
|
|
12251
|
+
const messages = [
|
|
12252
|
+
...request.plan?.messages ?? request.selection?.messages ?? [],
|
|
12253
|
+
...after,
|
|
12254
|
+
{
|
|
12255
|
+
id: "cue",
|
|
12256
|
+
role: "user",
|
|
12257
|
+
content: LEDGER_NOTES.cue
|
|
12258
|
+
}
|
|
12259
|
+
].filter((message) => message.role !== "tool" && !hasCalls(message));
|
|
12260
|
+
const note = digest === void 0 ? [] : [{
|
|
12261
|
+
id: "results",
|
|
12262
|
+
role: "user",
|
|
12263
|
+
content: digest
|
|
12264
|
+
}];
|
|
12265
|
+
if (this.#gauge === void 0 || estimateMessages(stripThinking(this.#agent.context.build({
|
|
12266
|
+
messages: [...messages, ...note],
|
|
12267
|
+
judgments: []
|
|
12268
|
+
}), this.#replay)) <= allowance) return {
|
|
12269
|
+
digest,
|
|
12270
|
+
omitted
|
|
12271
|
+
};
|
|
12272
|
+
const partials = new Set(after.filter((message) => message.role === "assistant" && !hasCalls(message)).map((message) => message.id));
|
|
12273
|
+
const fitted = cutListing(unique, allowance - estimateMessages(stripThinking(this.#agent.context.build({
|
|
12274
|
+
messages: messages.filter((message) => !partials.has(message.id)),
|
|
12275
|
+
judgments: []
|
|
12276
|
+
}), this.#replay)) - estimateTokens(`${LEDGER_NOTES.results}\n`), "more", false);
|
|
12277
|
+
return {
|
|
12278
|
+
digest: fitted === "" ? void 0 : `${LEDGER_NOTES.results}\n${fitted}`,
|
|
12279
|
+
omitted: partials
|
|
12280
|
+
};
|
|
12281
|
+
}
|
|
12282
|
+
#recallRate(request) {
|
|
12283
|
+
const gauge = this.#gauge;
|
|
12284
|
+
if (gauge === void 0) return 1;
|
|
12285
|
+
const calls = request?.calls ?? [];
|
|
12286
|
+
const last = calls.findLast((call) => (0, _orkestrel_contract.isFiniteNumber)(call.prompt));
|
|
12287
|
+
const measured = last !== void 0 && (0, _orkestrel_contract.isFiniteNumber)(last.prompt) && last.estimate > 0 && ((last.spared ?? 0) === 0 || (last.spared ?? 0) >= gauge.overhead) ? (last.prompt - Math.max(0, gauge.overhead - (last.spared ?? 0))) / last.estimate : 0;
|
|
12288
|
+
return Math.max(gauge.rate(calls), measured);
|
|
12193
12289
|
}
|
|
12194
12290
|
};
|
|
12195
12291
|
// src/core/ledgers/factories.ts
|