@vincemakes/kiso-runtime 0.39.0 → 0.39.2
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/session.d.ts +2 -2
- package/dist/session.js +34 -7
- package/dist/summarize.d.ts +63 -3
- package/dist/summarize.js +123 -3
- package/package.json +6 -6
package/dist/session.d.ts
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
import { EventLog, type AbortSignalLike, type Adapter, type Event, type KisoExtension, type Message, type PermissionDecision, type Tool } from "@vincemakes/kiso-core";
|
|
31
31
|
import { type TaskAssessment } from "./task-assessment.js";
|
|
32
32
|
import { type ContinuationScope } from "@vincemakes/kiso-core";
|
|
33
|
-
import type
|
|
33
|
+
import { type ReasoningSetting } from "./provider/metadata.js";
|
|
34
34
|
import { type SessionStore } from "./store.js";
|
|
35
35
|
import { Run } from "./run.js";
|
|
36
36
|
/** TUI2-R3v2 ③ — one off-trajectory model request (session.sideQuery).
|
|
@@ -89,7 +89,6 @@ export interface CompactInfo {
|
|
|
89
89
|
/** The covered content's estimated tokens (the chars/4 proxy). */
|
|
90
90
|
readonly tokens: number;
|
|
91
91
|
}
|
|
92
|
-
/** @deprecated the canonical name is `Session` (root export, 1.1.0); this alias is removed in the next major. */
|
|
93
92
|
export declare class AgentSession {
|
|
94
93
|
#private;
|
|
95
94
|
readonly id: string;
|
|
@@ -265,6 +264,7 @@ export declare class AgentSession {
|
|
|
265
264
|
onStart?: (info: CompactInfo) => void;
|
|
266
265
|
drop?: boolean;
|
|
267
266
|
focus?: string;
|
|
267
|
+
manualBudget?: boolean;
|
|
268
268
|
}): Promise<SummarizeResult | null>;
|
|
269
269
|
/**
|
|
270
270
|
* E6 — the run-start context policy (candidate A + the crux drop arm).
|
package/dist/session.js
CHANGED
|
@@ -36,7 +36,8 @@ import { assessTasks } from "./task-assessment.js";
|
|
|
36
36
|
const DEFAULT_EVIDENCE_TOOLS = new Set(["shell"]);
|
|
37
37
|
import { denialResult } from "@vincemakes/kiso-core";
|
|
38
38
|
import { buildProfile, readProfile, writeProfile } from "./profile.js";
|
|
39
|
-
import {
|
|
39
|
+
import { resolveReasoning } from "./provider/metadata.js";
|
|
40
|
+
import { DROP_PLACEHOLDER, estimateSummarySavings, KEEP_RECENT_ROUNDS, KEEP_TOKENS_DEFAULT, lastSummaryPoint, MAX_SUMMARY_FAILURES, policyTriggerFromWindow, serializeCovered, MANUAL_SUMMARY_BUDGET, SUMMARY_MAX_OUTPUT, summarizeConversation, summaryBoundarySeq, } from "./summarize.js";
|
|
40
41
|
import { canonicalizeUsageForModel } from "./usage/canonical.js";
|
|
41
42
|
import { appendFileSync, mkdirSync } from "node:fs";
|
|
42
43
|
import { join } from "node:path";
|
|
@@ -69,6 +70,24 @@ export class ResumeBlockedError extends Error {
|
|
|
69
70
|
}
|
|
70
71
|
}
|
|
71
72
|
/** @deprecated the canonical name is `Session` (root export, 1.1.0); this alias is removed in the next major. */
|
|
73
|
+
/**
|
|
74
|
+
* 0.39.2 — thinking OFF for a manual summary, where it can be turned off.
|
|
75
|
+
*
|
|
76
|
+
* The summary call sent no reasoning at all, so it ran at the provider's
|
|
77
|
+
* default, and for a model whose thinking defaults ON the reasoning tokens
|
|
78
|
+
* came out of the same output budget as the checkpoint. Resolved through
|
|
79
|
+
* `resolveReasoning` — the one authority the `/model` path uses — so it
|
|
80
|
+
* only ever sends a NATIVE value for a model the registry knows. For a
|
|
81
|
+
* model it does not know (66 of the 73 profiles on the machine this was
|
|
82
|
+
* found on, the failing one among them) it sends nothing, exactly as
|
|
83
|
+
* before: a raw field to an unknown model can be a 400. That is why this
|
|
84
|
+
* is an optimisation and the scaled budget is the fix — the budget
|
|
85
|
+
* reaches every model, this reaches the ones we can vouch for.
|
|
86
|
+
*/
|
|
87
|
+
function summaryReasoning(model, baseUrl) {
|
|
88
|
+
const r = resolveReasoning(model, { thinking: "disabled", effort: "default" }, baseUrl);
|
|
89
|
+
return r.ok && r.wire.thinking !== undefined ? { reasoning: r.wire } : {};
|
|
90
|
+
}
|
|
72
91
|
export class AgentSession {
|
|
73
92
|
id;
|
|
74
93
|
log;
|
|
@@ -428,6 +447,11 @@ export class AgentSession {
|
|
|
428
447
|
// R3a: `focus` — an optional steer for the summary call ("keep the
|
|
429
448
|
// auth details"). Rides the serialized input as ONE instruction
|
|
430
449
|
// line; absent = byte-identical to the pre-round call.
|
|
450
|
+
// 0.39.2: `manualBudget` — the MANUAL `/compact` gesture's summary
|
|
451
|
+
// call: the measured output budget, and thinking off where the
|
|
452
|
+
// registry says the model can turn it off. Absent — the auto
|
|
453
|
+
// policy — the call is byte-identical to before; see
|
|
454
|
+
// `MANUAL_SUMMARY_BUDGET` for the measurement and for why.
|
|
431
455
|
options = {}) {
|
|
432
456
|
this.ensureHealthy();
|
|
433
457
|
const keepRounds = options.keepRounds ?? KEEP_RECENT_ROUNDS;
|
|
@@ -456,10 +480,11 @@ export class AgentSession {
|
|
|
456
480
|
// call with no fraction (kiso never invents a percentage here).
|
|
457
481
|
if (options.signal !== undefined && options.signal.aborted)
|
|
458
482
|
throw cancelled();
|
|
483
|
+
const coveredTokens = estimateTokens(covered);
|
|
459
484
|
options.onStart?.({
|
|
460
485
|
coversToSeq: boundary,
|
|
461
486
|
rounds: events.filter((e) => e.type === "user_input" && e.seq > prevPoint && e.seq <= boundary).length,
|
|
462
|
-
tokens:
|
|
487
|
+
tokens: coveredTokens,
|
|
463
488
|
});
|
|
464
489
|
let summary;
|
|
465
490
|
let usage = null;
|
|
@@ -483,11 +508,13 @@ export class AgentSession {
|
|
|
483
508
|
// E6 (a): ONE serialized user message — the DSML bug's
|
|
484
509
|
// raw-message array is structurally dead on this path.
|
|
485
510
|
messages: [{ role: "user", content: serializedInput }],
|
|
486
|
-
// E6 (g): the summary call ALWAYS carries
|
|
487
|
-
//
|
|
488
|
-
//
|
|
489
|
-
//
|
|
490
|
-
|
|
511
|
+
// E6 (g): the summary call ALWAYS carries an explicit output
|
|
512
|
+
// budget (a wire-level truncation is caught by the (b)
|
|
513
|
+
// required-section validation, never silently passed).
|
|
514
|
+
// 0.39.2: measured for the manual gesture, fixed for the policy.
|
|
515
|
+
...(options.manualBudget === true
|
|
516
|
+
? { maxOutputTokens: MANUAL_SUMMARY_BUDGET, ...summaryReasoning(binding.model, binding.baseUrl) }
|
|
517
|
+
: { maxOutputTokens: SUMMARY_MAX_OUTPUT }),
|
|
491
518
|
...(options.signal !== undefined ? { signal: options.signal } : {}),
|
|
492
519
|
});
|
|
493
520
|
summary = call.text;
|
package/dist/summarize.d.ts
CHANGED
|
@@ -44,7 +44,48 @@ export declare const SUMMARY_RESULT_MAX_CHARS = 2000;
|
|
|
44
44
|
export declare const SUMMARY_MAX_OUTPUT = 4000;
|
|
45
45
|
export declare const KEEP_TOKENS_DEFAULT = 20000;
|
|
46
46
|
export declare const IN_FLIGHT_HEADROOM = 8000;
|
|
47
|
+
/** ONE NUMBER, TWO CONSUMERS. `SUMMARY_MAX_OUTPUT` is both the summary
|
|
48
|
+
* call's output budget AND a term of this reserve — the reserve buys
|
|
49
|
+
* back room for exactly that much summary. Change one and you have
|
|
50
|
+
* changed the other; see `MANUAL_SUMMARY_BUDGET` for why the manual
|
|
51
|
+
* gesture's larger budget does NOT reach the auto policy that reads this. */
|
|
47
52
|
export declare const POLICY_RESERVE: number;
|
|
53
|
+
/**
|
|
54
|
+
* 0.39.2 — the output budget of a MANUAL `/compact`, and it is MEASURED.
|
|
55
|
+
*
|
|
56
|
+
* The fixed 4,000 failed live sessions: `the summary turn ended with
|
|
57
|
+
* max_tokens`. On the failing profile (an unregistered DeepSeek model
|
|
58
|
+
* behind a gateway), a covered range the size of the reported one —
|
|
59
|
+
* ~100k tokens of real source — was run three ways:
|
|
60
|
+
*
|
|
61
|
+
* budget 4,000 → max_tokens reasoning 3,093 checkpoint 828 3 of 7 sections
|
|
62
|
+
* budget 8,391 → max_tokens reasoning 1,613 checkpoint 6,544 4 of 7
|
|
63
|
+
* budget 32,000 → end_turn reasoning 3,557 checkpoint 15,261 7 of 7
|
|
64
|
+
*
|
|
65
|
+
* A complete checkpoint took 18,837 output tokens. At 4,000 the reasoning
|
|
66
|
+
* LOOKED like the cause (77% of the budget) only because the budget was
|
|
67
|
+
* too small for the checkpoint to get going; with room, reasoning is a
|
|
68
|
+
* fifth and the checkpoint itself is the size. A rule scaled from the
|
|
69
|
+
* covered estimate (a twelfth: 8,391, doubling to 16,782 on retry) was
|
|
70
|
+
* built first and failed BOTH attempts on this data — it was a guess, and
|
|
71
|
+
* the measurement is what falsified it.
|
|
72
|
+
*
|
|
73
|
+
* So the budget is not scaled; it is a generous flat CAP, because a cap
|
|
74
|
+
* is not a charge — the model is billed for what it writes, and a higher
|
|
75
|
+
* limit costs nothing unless the output would have run away anyway. The
|
|
76
|
+
* one thing a lower first budget buys is a failed call before the one
|
|
77
|
+
* that works. 32,000 holds the measured 18,837 with room, and bounds what
|
|
78
|
+
* a genuinely runaway summary can cost: a checkpoint larger than this has
|
|
79
|
+
* stopped being a summary.
|
|
80
|
+
*
|
|
81
|
+
* MANUAL ONLY, and that is the patch boundary. The auto policy's
|
|
82
|
+
* `POLICY_RESERVE` assumes `SUMMARY_MAX_OUTPUT`; giving the policy a larger
|
|
83
|
+
* budget without moving its reserve would let a fire leave less room than
|
|
84
|
+
* the reserve promised, and moving the reserve moves every session's
|
|
85
|
+
* compaction trigger — BM-1 §3's compaction tier, where the paired bench
|
|
86
|
+
* blocks. That belongs to A1b, and the measurement above is its input.
|
|
87
|
+
*/
|
|
88
|
+
export declare const MANUAL_SUMMARY_BUDGET = 32000;
|
|
48
89
|
/** The reference context-window scale (the flash-family window); the
|
|
49
90
|
* env overrides. The default arming point is 120,000 − 32,000 =
|
|
50
91
|
* 88,000 — a post-fire projection (≥ 24k) can never re-cross it, so
|
|
@@ -114,6 +155,13 @@ export interface SummarizeConversationOptions {
|
|
|
114
155
|
readonly signal?: AbortSignalLike;
|
|
115
156
|
/** E6 (g): the summary call's explicit output budget (adapter maxTokens). */
|
|
116
157
|
readonly maxOutputTokens?: number;
|
|
158
|
+
/** 0.39.2: the RESOLVED reasoning for the summary call — native wire
|
|
159
|
+
* values from `resolveReasoning`, never a raw field. Absent sends
|
|
160
|
+
* nothing, and the provider's default applies. */
|
|
161
|
+
readonly reasoning?: {
|
|
162
|
+
readonly thinking?: "adaptive" | "enabled" | "disabled";
|
|
163
|
+
readonly effort?: string;
|
|
164
|
+
};
|
|
117
165
|
}
|
|
118
166
|
/** The summary call's result — the text PLUS the provider-reported usage
|
|
119
167
|
* (E6: the honest accounting — the summary call's cost rides the trace
|
|
@@ -124,9 +172,21 @@ export interface SummarizeConversationResult {
|
|
|
124
172
|
readonly usage: RawUsage | null;
|
|
125
173
|
}
|
|
126
174
|
/**
|
|
127
|
-
* The
|
|
128
|
-
*
|
|
129
|
-
*
|
|
175
|
+
* The summary call, with ONE retry.
|
|
176
|
+
*
|
|
177
|
+
* 0.39.1: `/compact` had no retry at all. The kernel owns retries
|
|
178
|
+
* (ADR-0005) and this path does not go through the kernel — it calls the
|
|
179
|
+
* adapter directly — so a gateway that drops a 95k-token summary stream
|
|
180
|
+
* failed `/compact` every single time, with an honest message and no way
|
|
181
|
+
* forward. The adapter classifies that as a retryable `network` failure
|
|
182
|
+
* (the transport-failure-after-headers class); here is the only place
|
|
183
|
+
* that can act on it.
|
|
184
|
+
*
|
|
185
|
+
* ONE retry, not a loop, and not the kernel's budget: a summary re-pays
|
|
186
|
+
* its whole input, which on the sessions that need compacting is the
|
|
187
|
+
* most expensive request the session makes. A permanent error still
|
|
188
|
+
* throws on the first attempt — the retry is keyed on the classification
|
|
189
|
+
* the adapter already made, never on the fact that something failed.
|
|
130
190
|
*/
|
|
131
191
|
export declare function summarizeConversation(options: SummarizeConversationOptions): Promise<SummarizeConversationResult>;
|
|
132
192
|
/** E6 — the crux-experiment drop arm: the covered turns are replaced by
|
package/dist/summarize.js
CHANGED
|
@@ -41,7 +41,61 @@ export const SUMMARY_RESULT_MAX_CHARS = 2000;
|
|
|
41
41
|
export const SUMMARY_MAX_OUTPUT = 4000;
|
|
42
42
|
export const KEEP_TOKENS_DEFAULT = 20000;
|
|
43
43
|
export const IN_FLIGHT_HEADROOM = 8000;
|
|
44
|
+
/** ONE NUMBER, TWO CONSUMERS. `SUMMARY_MAX_OUTPUT` is both the summary
|
|
45
|
+
* call's output budget AND a term of this reserve — the reserve buys
|
|
46
|
+
* back room for exactly that much summary. Change one and you have
|
|
47
|
+
* changed the other; see `MANUAL_SUMMARY_BUDGET` for why the manual
|
|
48
|
+
* gesture's larger budget does NOT reach the auto policy that reads this. */
|
|
44
49
|
export const POLICY_RESERVE = SUMMARY_MAX_OUTPUT + KEEP_TOKENS_DEFAULT + IN_FLIGHT_HEADROOM;
|
|
50
|
+
/**
|
|
51
|
+
* 0.39.2 — the output budget of a MANUAL `/compact`, and it is MEASURED.
|
|
52
|
+
*
|
|
53
|
+
* The fixed 4,000 failed live sessions: `the summary turn ended with
|
|
54
|
+
* max_tokens`. On the failing profile (an unregistered DeepSeek model
|
|
55
|
+
* behind a gateway), a covered range the size of the reported one —
|
|
56
|
+
* ~100k tokens of real source — was run three ways:
|
|
57
|
+
*
|
|
58
|
+
* budget 4,000 → max_tokens reasoning 3,093 checkpoint 828 3 of 7 sections
|
|
59
|
+
* budget 8,391 → max_tokens reasoning 1,613 checkpoint 6,544 4 of 7
|
|
60
|
+
* budget 32,000 → end_turn reasoning 3,557 checkpoint 15,261 7 of 7
|
|
61
|
+
*
|
|
62
|
+
* A complete checkpoint took 18,837 output tokens. At 4,000 the reasoning
|
|
63
|
+
* LOOKED like the cause (77% of the budget) only because the budget was
|
|
64
|
+
* too small for the checkpoint to get going; with room, reasoning is a
|
|
65
|
+
* fifth and the checkpoint itself is the size. A rule scaled from the
|
|
66
|
+
* covered estimate (a twelfth: 8,391, doubling to 16,782 on retry) was
|
|
67
|
+
* built first and failed BOTH attempts on this data — it was a guess, and
|
|
68
|
+
* the measurement is what falsified it.
|
|
69
|
+
*
|
|
70
|
+
* So the budget is not scaled; it is a generous flat CAP, because a cap
|
|
71
|
+
* is not a charge — the model is billed for what it writes, and a higher
|
|
72
|
+
* limit costs nothing unless the output would have run away anyway. The
|
|
73
|
+
* one thing a lower first budget buys is a failed call before the one
|
|
74
|
+
* that works. 32,000 holds the measured 18,837 with room, and bounds what
|
|
75
|
+
* a genuinely runaway summary can cost: a checkpoint larger than this has
|
|
76
|
+
* stopped being a summary.
|
|
77
|
+
*
|
|
78
|
+
* MANUAL ONLY, and that is the patch boundary. The auto policy's
|
|
79
|
+
* `POLICY_RESERVE` assumes `SUMMARY_MAX_OUTPUT`; giving the policy a larger
|
|
80
|
+
* budget without moving its reserve would let a fire leave less room than
|
|
81
|
+
* the reserve promised, and moving the reserve moves every session's
|
|
82
|
+
* compaction trigger — BM-1 §3's compaction tier, where the paired bench
|
|
83
|
+
* blocks. That belongs to A1b, and the measurement above is its input.
|
|
84
|
+
*/
|
|
85
|
+
export const MANUAL_SUMMARY_BUDGET = 32_000;
|
|
86
|
+
/** Thrown by an attempt that stopped on `max_tokens`, and it NAMES the
|
|
87
|
+
* budget: "not a complete turn" alone told the person nothing about what
|
|
88
|
+
* ran out. Still an `Error`, and still carries the `max_tokens … not a
|
|
89
|
+
* complete turn` wording the CX-1 F3 gate matches. */
|
|
90
|
+
class SummaryBudgetExhausted extends Error {
|
|
91
|
+
budget;
|
|
92
|
+
constructor(budget) {
|
|
93
|
+
super(budget === undefined
|
|
94
|
+
? "the summary turn ended with max_tokens — not a complete turn"
|
|
95
|
+
: `the summary turn ended with max_tokens — it needed more than its ${budget}-token output budget, not a complete turn`);
|
|
96
|
+
this.budget = budget;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
45
99
|
/** The reference context-window scale (the flash-family window); the
|
|
46
100
|
* env overrides. The default arming point is 120,000 − 32,000 =
|
|
47
101
|
* 88,000 — a post-fire projection (≥ 24k) can never re-cross it, so
|
|
@@ -188,12 +242,74 @@ export function validateSummary(text) {
|
|
|
188
242
|
}
|
|
189
243
|
return null;
|
|
190
244
|
}
|
|
245
|
+
/** A thrown value the adapter CLASSIFIED — `{ code, retryable, message }`
|
|
246
|
+
* (ADR-0005 rule 1). The core's own guard is private, and this asks a
|
|
247
|
+
* narrower question than that one: is this a failure someone already
|
|
248
|
+
* decided is worth trying again. A validation rejection below is a plain
|
|
249
|
+
* `Error` and can never match, which is the separation E6 (b) wants —
|
|
250
|
+
* "the model wrote a bad summary" is not retried, ever. */
|
|
251
|
+
function retryableStructured(err) {
|
|
252
|
+
if (err === null || typeof err !== "object")
|
|
253
|
+
return false;
|
|
254
|
+
const e = err;
|
|
255
|
+
return typeof e.code === "string" && typeof e.message === "string" && e.retryable === true;
|
|
256
|
+
}
|
|
257
|
+
/** How long to wait before the one retry. The provider's own ask when it
|
|
258
|
+
* made one and it is short enough to be worth honouring; otherwise a
|
|
259
|
+
* token pause — the failure this exists for is a dropped stream, not a
|
|
260
|
+
* rate limit, and an immediate second attempt is the right response to
|
|
261
|
+
* a socket that died. */
|
|
262
|
+
function retryWaitMs(err) {
|
|
263
|
+
const asked = err.retryAfterMs;
|
|
264
|
+
return typeof asked === "number" && Number.isFinite(asked) && asked >= 0 && asked <= 60_000 ? asked : 250;
|
|
265
|
+
}
|
|
191
266
|
/**
|
|
192
|
-
* The
|
|
193
|
-
*
|
|
194
|
-
*
|
|
267
|
+
* The summary call, with ONE retry.
|
|
268
|
+
*
|
|
269
|
+
* 0.39.1: `/compact` had no retry at all. The kernel owns retries
|
|
270
|
+
* (ADR-0005) and this path does not go through the kernel — it calls the
|
|
271
|
+
* adapter directly — so a gateway that drops a 95k-token summary stream
|
|
272
|
+
* failed `/compact` every single time, with an honest message and no way
|
|
273
|
+
* forward. The adapter classifies that as a retryable `network` failure
|
|
274
|
+
* (the transport-failure-after-headers class); here is the only place
|
|
275
|
+
* that can act on it.
|
|
276
|
+
*
|
|
277
|
+
* ONE retry, not a loop, and not the kernel's budget: a summary re-pays
|
|
278
|
+
* its whole input, which on the sessions that need compacting is the
|
|
279
|
+
* most expensive request the session makes. A permanent error still
|
|
280
|
+
* throws on the first attempt — the retry is keyed on the classification
|
|
281
|
+
* the adapter already made, never on the fact that something failed.
|
|
195
282
|
*/
|
|
196
283
|
export async function summarizeConversation(options) {
|
|
284
|
+
// Asked as a CALL, twice, because `aborted` is a readonly property and
|
|
285
|
+
// the narrowing from the first read would otherwise be carried across
|
|
286
|
+
// the await — where the whole point is that it can have changed.
|
|
287
|
+
const aborted = () => options.signal?.aborted === true;
|
|
288
|
+
// A `max_tokens` stop is NOT retried here. A retry at the same budget
|
|
289
|
+
// buys the same truncation, and a retry at a larger one is only worth
|
|
290
|
+
// having if the first budget was chosen small — which is why the manual
|
|
291
|
+
// gesture now asks for the whole measured budget up front instead
|
|
292
|
+
// (see `MANUAL_SUMMARY_BUDGET`).
|
|
293
|
+
try {
|
|
294
|
+
return await summaryAttempt(options);
|
|
295
|
+
}
|
|
296
|
+
catch (err) {
|
|
297
|
+
// The caller's cancel is the caller's: an aborted `/compact` must
|
|
298
|
+
// not spend a second call on its way out.
|
|
299
|
+
if (!retryableStructured(err) || aborted())
|
|
300
|
+
throw err;
|
|
301
|
+
await new Promise((r) => setTimeout(r, retryWaitMs(err)));
|
|
302
|
+
if (aborted())
|
|
303
|
+
throw err;
|
|
304
|
+
return await summaryAttempt(options);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* ONE attempt. Collects the adapter's text deltas into the summary;
|
|
309
|
+
* usage/stop pass through untouched. Throws when the model produced no
|
|
310
|
+
* text — the caller reports it and nothing is persisted.
|
|
311
|
+
*/
|
|
312
|
+
async function summaryAttempt(options) {
|
|
197
313
|
const { adapter, model, messages } = options;
|
|
198
314
|
let text = "";
|
|
199
315
|
let usage = null;
|
|
@@ -213,6 +329,7 @@ export async function summarizeConversation(options) {
|
|
|
213
329
|
systemPrompt: SUMMARY_PROMPT,
|
|
214
330
|
...(options.signal !== undefined ? { signal: options.signal } : {}),
|
|
215
331
|
...(options.maxOutputTokens !== undefined ? { maxTokens: options.maxOutputTokens } : {}),
|
|
332
|
+
...(options.reasoning !== undefined ? { reasoning: options.reasoning } : {}),
|
|
216
333
|
})) {
|
|
217
334
|
if (stops > 0 && ev.type !== "usage" && ev.type !== "stop" && afterStop === undefined)
|
|
218
335
|
afterStop = ev.type;
|
|
@@ -247,6 +364,9 @@ export async function summarizeConversation(options) {
|
|
|
247
364
|
throw new Error(`the summary turn stopped ${stops} times — not a complete turn`);
|
|
248
365
|
if (toolCalls > 0)
|
|
249
366
|
throw new Error("the summary turn called a tool — a summary is text, never a tool call");
|
|
367
|
+
// The one stop a larger budget can cure, told apart from the rest.
|
|
368
|
+
if (stopReason === "max_tokens")
|
|
369
|
+
throw new SummaryBudgetExhausted(options.maxOutputTokens);
|
|
250
370
|
if (stopReason !== "end_turn")
|
|
251
371
|
throw new Error(`the summary turn ended with ${String(stopReason)} — not a complete turn`);
|
|
252
372
|
if (afterStop !== undefined)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincemakes/kiso-runtime",
|
|
3
|
-
"version": "0.39.
|
|
3
|
+
"version": "0.39.2",
|
|
4
4
|
"description": "kiso runtime \u2014 durable multi-turn agent sessions: AgentDefinition, AgentRuntime, AgentSession, Run, append-only JSONL store.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -25,12 +25,12 @@
|
|
|
25
25
|
"test": "vitest run"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@vincemakes/kiso-core": "0.39.
|
|
28
|
+
"@vincemakes/kiso-core": "0.39.2"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|
|
31
|
-
"@vincemakes/kiso-provider-anthropic": "0.39.
|
|
32
|
-
"@vincemakes/kiso-provider-openai": "0.39.
|
|
33
|
-
"@vincemakes/kiso-provider-openai-responses": "0.39.
|
|
31
|
+
"@vincemakes/kiso-provider-anthropic": "0.39.2",
|
|
32
|
+
"@vincemakes/kiso-provider-openai": "0.39.2",
|
|
33
|
+
"@vincemakes/kiso-provider-openai-responses": "0.39.2"
|
|
34
34
|
},
|
|
35
35
|
"peerDependenciesMeta": {
|
|
36
36
|
"@vincemakes/kiso-provider-anthropic": {
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
}
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"@vincemakes/kiso-evals": "0.39.
|
|
47
|
+
"@vincemakes/kiso-evals": "0.39.2",
|
|
48
48
|
"@types/node": "^26.1.2",
|
|
49
49
|
"typescript": "^5.7.2",
|
|
50
50
|
"vitest": "^3.0.0"
|