@vincemakes/kiso-runtime 0.47.3 → 0.48.0
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/provider/metadata.js +9 -0
- package/dist/run.js +6 -2
- package/dist/session.d.ts +1 -1
- package/dist/tasks/delivery.d.ts +8 -3
- package/dist/tasks/delivery.js +40 -26
- package/dist/trace/guard.js +1 -0
- package/dist/trace/rent.d.ts +16 -6
- package/dist/trace/rent.js +14 -5
- package/package.json +6 -6
|
@@ -167,6 +167,14 @@ const chatgptRow = (model, opts = {}) => ({
|
|
|
167
167
|
const OPENAI_MODELS_ASOF_2 = "2026-09-09";
|
|
168
168
|
const CHATGPT_PRESETS_SOURCE_2 = "https://github.com/openai/codex/blob/634ebc1865c6ac840ed3ba118f040d527bf4b55d/codex-rs/models-manager/models.json";
|
|
169
169
|
const ULTRA_LADDER = ["low", "medium", "high", "xhigh", "max", "ultra"];
|
|
170
|
+
/** 0.48.0 (finding 0473-F2): the presets at a later commit, read 2026-10-09.
|
|
171
|
+
* The owner's `sol` profile moved to `gpt-6.1-sol` on 2026-10-08, and with
|
|
172
|
+
* no row kiso sent it no effort: the remembered `high` never reached the
|
|
173
|
+
* wire and no reasoning summary came back. The id answered on the
|
|
174
|
+
* subscription backend that night (the 0.47.3 live sessions). No
|
|
175
|
+
* first-party row: no model page was read for it. */
|
|
176
|
+
const OPENAI_MODELS_ASOF_3 = "2026-10-09";
|
|
177
|
+
const CHATGPT_PRESETS_SOURCE_3 = "https://github.com/openai/codex/blob/d63a9b8344cfe58bc78bbe319b560378fc8756ef/codex-rs/models-manager/models.json";
|
|
170
178
|
/** The v1 table. Nulls outnumber numbers ON PURPOSE: only values with a
|
|
171
179
|
* named source enter; everything else waits for one. */
|
|
172
180
|
const ENTRIES = [
|
|
@@ -409,6 +417,7 @@ const ENTRIES = [
|
|
|
409
417
|
openaiRow("gpt-5.6-sol", "medium", { inputPerM: 4, outputPerM: 20, cacheReadPerM: 0.4 }, "https://developers.openai.com/api/docs/models/gpt-5.6-sol", { levels: ["none", "low", "medium", "high", "xhigh", "max"], asOf: OPENAI_MODELS_ASOF_2 }),
|
|
410
418
|
chatgptRow("gpt-6-astra", { levels: ULTRA_LADDER, default: "low", source: CHATGPT_PRESETS_SOURCE_2, asOf: OPENAI_MODELS_ASOF_2 }),
|
|
411
419
|
chatgptRow("gpt-5.6-sol", { levels: ULTRA_LADDER, default: "low", source: CHATGPT_PRESETS_SOURCE_2, asOf: OPENAI_MODELS_ASOF_2 }),
|
|
420
|
+
chatgptRow("gpt-6.1-sol", { levels: ULTRA_LADDER, default: "low", source: CHATGPT_PRESETS_SOURCE_3, asOf: OPENAI_MODELS_ASOF_3 }),
|
|
412
421
|
// The compat table's SECOND row (roadmap R3.2 §1a step 1): GLM 5.3 Flash
|
|
413
422
|
// through OpenRouter, read from OpenRouter's models API on 2026-09-09. The
|
|
414
423
|
// id is OpenRouter's, so the row is keyed to that origin; the
|
package/dist/run.js
CHANGED
|
@@ -7,7 +7,7 @@ import { denialResult, loop, validateArgs } from "@vincemakes/kiso-core";
|
|
|
7
7
|
import { ABORTED, MergedSignal, abortable, openRunId } from "./recovery.js";
|
|
8
8
|
import { resolveReasoning } from "./provider/metadata.js";
|
|
9
9
|
import { deriveRecoveryPlan, invocationSeqOf } from "./recovery-plan.js";
|
|
10
|
-
import { appendOf, composeApprovalChain, joinPrompt, promptPerAttempt, runBasePrompt } from "./compose.js";
|
|
10
|
+
import { appendOf, composeApprovalChain, composeToolTable, joinPrompt, promptPerAttempt, runBasePrompt } from "./compose.js";
|
|
11
11
|
import { truncationGuard } from "./truncation-guard.js";
|
|
12
12
|
import { overflowBelt } from "./overflow-belt.js";
|
|
13
13
|
import { DEFAULT_STREAM_IDLE_MS, idleGuard } from "./idle-guard.js";
|
|
@@ -212,7 +212,11 @@ export class Run {
|
|
|
212
212
|
// that layer, records the bytes the model was sent. The in-band
|
|
213
213
|
// summary reads the last attempt's snapshot (the prefix the run
|
|
214
214
|
// last sent) or takes one if no attempt has happened yet.
|
|
215
|
-
|
|
215
|
+
// RG-F2: the generated table is a ledger line of its own — the
|
|
216
|
+
// same text runBasePrompt placed between the base and the appends
|
|
217
|
+
// (one registry read at the same instant, so it cannot differ).
|
|
218
|
+
const table = (this.#config.toolTable ?? "on") === "on" ? composeToolTable(this.#config.registry, this.#config.toolRules ?? []) : "";
|
|
219
|
+
const rentParts = { ...(this.#config.systemPrompt !== undefined ? { base: this.#config.systemPrompt } : {}), ...(table !== "" ? { table } : {}), appends: [] };
|
|
216
220
|
let lastPrompt;
|
|
217
221
|
let taken = false;
|
|
218
222
|
const snapshot = () => {
|
package/dist/session.d.ts
CHANGED
|
@@ -130,7 +130,7 @@ export declare class AgentSession {
|
|
|
130
130
|
/** Deliver this session's task transitions to the model: into a live
|
|
131
131
|
* run at its next safe point, or — idle — held for the next run, or one
|
|
132
132
|
* continuation run through `onWake` (off with `wake: false`). */
|
|
133
|
-
useTasks(manager: TaskManager, options?: Pick<TaskDeliveryOptions, "wake" | "onWake" | "windowMs" | "onLost"> & {
|
|
133
|
+
useTasks(manager: TaskManager, options?: Pick<TaskDeliveryOptions, "wake" | "onWake" | "windowMs" | "maxWakes" | "onLost"> & {
|
|
134
134
|
readonly autoDetachMinAgeMs?: number;
|
|
135
135
|
}): () => void;
|
|
136
136
|
/** ADR-0057 §5 (3e D1) — a person's steer arrived: the foreground
|
package/dist/tasks/delivery.d.ts
CHANGED
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
* Exactly once, from the log: a transition counts as delivered when a
|
|
16
16
|
* `user_input` whose `via.items` names it is in the session's log (ADR-0051
|
|
17
17
|
* Amendment 8). The set is a cache rebuilt from the log, never a second
|
|
18
|
-
* truth.
|
|
19
|
-
*
|
|
18
|
+
* truth. The chain budget from the log too (ADR-0058 Amendment 9): the wake
|
|
19
|
+
* runs since the last run a person started are counted, never kept.
|
|
20
20
|
*
|
|
21
21
|
* The summary snapshot is what the MODEL was told, never the live journal:
|
|
22
22
|
* a compaction must not reveal a transition that has not been delivered.
|
|
@@ -43,12 +43,16 @@ import { type Run } from "../run.js";
|
|
|
43
43
|
import { type TaskInfo, type TaskManager } from "./manager.js";
|
|
44
44
|
export interface TaskDeliveryOptions {
|
|
45
45
|
readonly manager: TaskManager;
|
|
46
|
-
/** The session's durable events: receipts and
|
|
46
|
+
/** The session's durable events: receipts and the chain are read here. */
|
|
47
47
|
readonly events: () => readonly Event[];
|
|
48
48
|
/** The session's live run, when one is running. */
|
|
49
49
|
readonly liveRun: () => Run | undefined;
|
|
50
50
|
/** False turns every wake into a notify (the switch, ADR-0058 §8.4). */
|
|
51
51
|
readonly wake?: boolean;
|
|
52
|
+
/** ADR-0058 Amendment 9 — the chain budget: how many autonomous wakes may follow
|
|
53
|
+
* one person's input before a terminal delivers as a notify instead.
|
|
54
|
+
* Replaces ADR-0058 §8 guard 3 (lineage depth 1). Default 20. */
|
|
55
|
+
readonly maxWakes?: number;
|
|
52
56
|
/** Start ONE continuation run whose first input is this notice. */
|
|
53
57
|
readonly onWake?: (input: {
|
|
54
58
|
readonly content: string;
|
|
@@ -65,6 +69,7 @@ export interface TaskDeliveryOptions {
|
|
|
65
69
|
/** Read a task's output tail (injectable for tests). */
|
|
66
70
|
readonly readTail?: (task: TaskInfo, bytes: number) => string;
|
|
67
71
|
}
|
|
72
|
+
export declare const DEFAULT_MAX_WAKES = 20;
|
|
68
73
|
export declare class TaskDelivery {
|
|
69
74
|
#private;
|
|
70
75
|
constructor(options: TaskDeliveryOptions);
|
package/dist/tasks/delivery.js
CHANGED
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
* Exactly once, from the log: a transition counts as delivered when a
|
|
16
16
|
* `user_input` whose `via.items` names it is in the session's log (ADR-0051
|
|
17
17
|
* Amendment 8). The set is a cache rebuilt from the log, never a second
|
|
18
|
-
* truth.
|
|
19
|
-
*
|
|
18
|
+
* truth. The chain budget from the log too (ADR-0058 Amendment 9): the wake
|
|
19
|
+
* runs since the last run a person started are counted, never kept.
|
|
20
20
|
*
|
|
21
21
|
* The summary snapshot is what the MODEL was told, never the live journal:
|
|
22
22
|
* a compaction must not reveal a transition that has not been delivered.
|
|
@@ -44,6 +44,7 @@ import { isRuntimeInput } from "@vincemakes/kiso-core";
|
|
|
44
44
|
import { NOTICE_FOOTER as FOOTER } from "../run.js";
|
|
45
45
|
import { endTransitionOf } from "./manager.js";
|
|
46
46
|
const key = (i) => `${i.taskId}:${i.transition}`;
|
|
47
|
+
export const DEFAULT_MAX_WAKES = 20;
|
|
47
48
|
/** ADR-0058 3d (D3): a child's excerpt, and a group's excerpts together. */
|
|
48
49
|
const CHILD_EXCERPT_BYTES = 4_096;
|
|
49
50
|
const GROUP_EXCERPT_BYTES = 16_384;
|
|
@@ -166,7 +167,8 @@ export class TaskDelivery {
|
|
|
166
167
|
const mode = this.#modeOf(task, item);
|
|
167
168
|
if (mode === "silent")
|
|
168
169
|
return;
|
|
169
|
-
|
|
170
|
+
const spent = mode === "notify" && this.#eligible(task, item) && !this.#underBudget();
|
|
171
|
+
this.#buffer.push({ item, line: spent ? `${this.#line(task, item)}\nchain budget spent: ${this.#wakesSinceLastPerson()} autonomous wakes since the person's last message — continue when they speak` : this.#line(task, item), mode });
|
|
170
172
|
if (this.#timer === null)
|
|
171
173
|
this.#timer = setTimeout(() => this.#flush(), this.#o.windowMs ?? 1_000);
|
|
172
174
|
}
|
|
@@ -221,7 +223,7 @@ export class TaskDelivery {
|
|
|
221
223
|
}
|
|
222
224
|
this.#scanned = events.length;
|
|
223
225
|
}
|
|
224
|
-
/** ADR-0058 §8 defaults, then the guards: the switch, and
|
|
226
|
+
/** ADR-0058 §8 defaults, then the guards: the switch, and the chain budget. */
|
|
225
227
|
#modeOf(task, item) {
|
|
226
228
|
if (item.transition === "ready" || item.transition === "stopped" || item.transition === "unknown")
|
|
227
229
|
return "notify";
|
|
@@ -232,17 +234,45 @@ export class TaskDelivery {
|
|
|
232
234
|
return this.#wakes(item) ? "wake" : "notify";
|
|
233
235
|
}
|
|
234
236
|
#wakes(item) {
|
|
235
|
-
if (this.#o.wake === false)
|
|
236
|
-
return false;
|
|
237
|
-
if (item.transition !== "exited" && item.transition !== "failed")
|
|
238
|
-
return false;
|
|
239
237
|
const task = this.#o.manager.get(item.taskId);
|
|
240
|
-
if (task === undefined || task
|
|
238
|
+
if (task === undefined || !this.#eligible(task, item))
|
|
241
239
|
return false;
|
|
242
240
|
// a child wakes only with its whole group (D2): never on its own
|
|
243
241
|
if (task.agent !== undefined && !this.#complete(this.#groupOf(task)))
|
|
244
242
|
return false;
|
|
245
|
-
return
|
|
243
|
+
return this.#underBudget();
|
|
244
|
+
}
|
|
245
|
+
/** The transition could wake, budget aside: the switch, a terminal, an
|
|
246
|
+
* execution's task, not a service. */
|
|
247
|
+
#eligible(task, item) {
|
|
248
|
+
if (this.#o.wake === false)
|
|
249
|
+
return false;
|
|
250
|
+
if (item.transition !== "exited" && item.transition !== "failed")
|
|
251
|
+
return false;
|
|
252
|
+
if (task.executionId === undefined || task.profile === "service")
|
|
253
|
+
return false;
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
/** ADR-0058 Amendment 9: the chain budget, derived from the log — never a
|
|
257
|
+
* counter. The count is the wake runs (first input a runtime notice)
|
|
258
|
+
* since the last run a person started. */
|
|
259
|
+
#underBudget() {
|
|
260
|
+
return this.#wakesSinceLastPerson() < (this.#o.maxWakes ?? DEFAULT_MAX_WAKES);
|
|
261
|
+
}
|
|
262
|
+
#wakesSinceLastPerson() {
|
|
263
|
+
let wakes = 0;
|
|
264
|
+
let firstOfRun = true;
|
|
265
|
+
for (const e of this.#o.events()) {
|
|
266
|
+
if (e.type === "terminal") {
|
|
267
|
+
firstOfRun = true;
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
if (e.type !== "user_input" || !firstOfRun)
|
|
271
|
+
continue;
|
|
272
|
+
firstOfRun = false;
|
|
273
|
+
wakes = isRuntimeInput(e) ? wakes + 1 : 0;
|
|
274
|
+
}
|
|
275
|
+
return wakes;
|
|
246
276
|
}
|
|
247
277
|
/** ADR-0058 3d: an agent task has ended — a failure goes into a live run
|
|
248
278
|
* at once; every end waits for its group. */
|
|
@@ -383,22 +413,6 @@ export class TaskDelivery {
|
|
|
383
413
|
attrs.push(existsSync(result) ? `result="${result}"` : `output="${task.outputPath}"`);
|
|
384
414
|
return `<kiso-task ${attrs.join(" ")}/>`;
|
|
385
415
|
}
|
|
386
|
-
/** Lineage depth 1: the run that started the task began with a notice. */
|
|
387
|
-
#startedInWakeRun(executionId) {
|
|
388
|
-
const events = this.#o.events();
|
|
389
|
-
const at = events.findIndex((e) => e.type === "tool_execution_started" && e.executionId === executionId);
|
|
390
|
-
if (at < 0)
|
|
391
|
-
return false;
|
|
392
|
-
let start = 0;
|
|
393
|
-
for (let n = at - 1; n >= 0; n--) {
|
|
394
|
-
if (events[n].type === "terminal") {
|
|
395
|
-
start = n + 1;
|
|
396
|
-
break;
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
const first = events.slice(start, at).find((e) => e.type === "user_input");
|
|
400
|
-
return isRuntimeInput(first);
|
|
401
|
-
}
|
|
402
416
|
#line(task, item) {
|
|
403
417
|
const attrs = [`id="${task.id}"`, `status="${item.transition}"`];
|
|
404
418
|
if (task.state.kind === "ended" && task.state.exitCode !== null)
|
package/dist/trace/guard.js
CHANGED
|
@@ -176,6 +176,7 @@ export class RequestTracer {
|
|
|
176
176
|
const rent = buildRentLedger({
|
|
177
177
|
model: options.model,
|
|
178
178
|
...(rentParts?.base !== undefined ? { base: rentParts.base } : {}),
|
|
179
|
+
...(rentParts?.table !== undefined ? { table: rentParts.table } : {}),
|
|
179
180
|
...(rentParts?.appends !== undefined ? { appends: rentParts.appends } : {}),
|
|
180
181
|
...(tools !== undefined ? { tools } : {}),
|
|
181
182
|
});
|
package/dist/trace/rent.d.ts
CHANGED
|
@@ -11,10 +11,17 @@
|
|
|
11
11
|
*
|
|
12
12
|
* - system:base the session's own prompt as the CLI handed it
|
|
13
13
|
* (built-in constant + project instructions — the
|
|
14
|
-
* runtime cannot split those, R3).
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
14
|
+
* runtime cannot split those, R3).
|
|
15
|
+
* - system:tools the runtime's generated tool table (compose.ts,
|
|
16
|
+
* composeToolTable): the routing rows, the fixed
|
|
17
|
+
* directives, each tool's snippet and guidelines,
|
|
18
|
+
* between the base and the appends. OVERTURNS the
|
|
19
|
+
* E3 note that it "stays out of the ledger (counts
|
|
20
|
+
* live in tool:<name> lines)": the table is prose
|
|
21
|
+
* the tool specs do not contain (1,686 chars at
|
|
22
|
+
* f42a0edc), so the ledger was short by that much
|
|
23
|
+
* on every request (finding RG-F2, kiso-doc
|
|
24
|
+
* plan-rent-gate rev 2).
|
|
18
25
|
* - system:ext:<name> one line per extension with a non-empty
|
|
19
26
|
* systemPrompt.append, measured on the append
|
|
20
27
|
* string, in load order.
|
|
@@ -44,7 +51,7 @@
|
|
|
44
51
|
*/
|
|
45
52
|
import type { ToolSpec } from "@vincemakes/kiso-core";
|
|
46
53
|
export interface RentLine {
|
|
47
|
-
/** "system:base" | "system:ext:<name>" | "tool:<name>" | "envelope" */
|
|
54
|
+
/** "system:base" | "system:tools" | "system:ext:<name>" | "tool:<name>" | "envelope" */
|
|
48
55
|
surface: string;
|
|
49
56
|
/** length of the serialized surface, measured, never a copy */
|
|
50
57
|
chars: number;
|
|
@@ -59,6 +66,9 @@ export declare const RENT_LINE_FIELDS: readonly ["surface", "chars", "estTokens"
|
|
|
59
66
|
* systemPrompt is the result — the parts are the ledger's inputs). */
|
|
60
67
|
export interface RentParts {
|
|
61
68
|
base?: string;
|
|
69
|
+
/** RG-F2: the generated tool table's text, as composed for the run
|
|
70
|
+
* (absent when the table is off or the registry is empty). */
|
|
71
|
+
table?: string;
|
|
62
72
|
appends?: readonly {
|
|
63
73
|
name: string;
|
|
64
74
|
text: string;
|
|
@@ -68,7 +78,7 @@ export interface RentInput extends RentParts {
|
|
|
68
78
|
model: string;
|
|
69
79
|
tools?: readonly ToolSpec[];
|
|
70
80
|
}
|
|
71
|
-
/** The one ledger: system:base, then system:ext:* (load order), then
|
|
81
|
+
/** The one ledger: system:base, then system:tools, then system:ext:* (load order), then
|
|
72
82
|
* tool:* (the array's order — the registry's toSpecs() order), then the
|
|
73
83
|
* envelope. Absent surfaces contribute no lines (R9). */
|
|
74
84
|
export declare function buildRentLedger(input: RentInput): RentLine[];
|
package/dist/trace/rent.js
CHANGED
|
@@ -11,10 +11,17 @@
|
|
|
11
11
|
*
|
|
12
12
|
* - system:base the session's own prompt as the CLI handed it
|
|
13
13
|
* (built-in constant + project instructions — the
|
|
14
|
-
* runtime cannot split those, R3).
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
14
|
+
* runtime cannot split those, R3).
|
|
15
|
+
* - system:tools the runtime's generated tool table (compose.ts,
|
|
16
|
+
* composeToolTable): the routing rows, the fixed
|
|
17
|
+
* directives, each tool's snippet and guidelines,
|
|
18
|
+
* between the base and the appends. OVERTURNS the
|
|
19
|
+
* E3 note that it "stays out of the ledger (counts
|
|
20
|
+
* live in tool:<name> lines)": the table is prose
|
|
21
|
+
* the tool specs do not contain (1,686 chars at
|
|
22
|
+
* f42a0edc), so the ledger was short by that much
|
|
23
|
+
* on every request (finding RG-F2, kiso-doc
|
|
24
|
+
* plan-rent-gate rev 2).
|
|
18
25
|
* - system:ext:<name> one line per extension with a non-empty
|
|
19
26
|
* systemPrompt.append, measured on the append
|
|
20
27
|
* string, in load order.
|
|
@@ -49,13 +56,15 @@ const line = (surface, text) => ({
|
|
|
49
56
|
chars: text.length,
|
|
50
57
|
estTokens: Math.ceil(text.length / 4),
|
|
51
58
|
});
|
|
52
|
-
/** The one ledger: system:base, then system:ext:* (load order), then
|
|
59
|
+
/** The one ledger: system:base, then system:tools, then system:ext:* (load order), then
|
|
53
60
|
* tool:* (the array's order — the registry's toSpecs() order), then the
|
|
54
61
|
* envelope. Absent surfaces contribute no lines (R9). */
|
|
55
62
|
export function buildRentLedger(input) {
|
|
56
63
|
const lines = [];
|
|
57
64
|
if (input.base !== undefined)
|
|
58
65
|
lines.push(line("system:base", input.base));
|
|
66
|
+
if (input.table !== undefined && input.table !== "")
|
|
67
|
+
lines.push(line("system:tools", input.table));
|
|
59
68
|
for (const append of input.appends ?? [])
|
|
60
69
|
lines.push(line(`system:ext:${append.name}`, append.text));
|
|
61
70
|
for (const tool of input.tools ?? []) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincemakes/kiso-runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.48.0",
|
|
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.
|
|
28
|
+
"@vincemakes/kiso-core": "0.48.0"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|
|
31
|
-
"@vincemakes/kiso-provider-anthropic": "0.
|
|
32
|
-
"@vincemakes/kiso-provider-openai": "0.
|
|
33
|
-
"@vincemakes/kiso-provider-openai-responses": "0.
|
|
31
|
+
"@vincemakes/kiso-provider-anthropic": "0.48.0",
|
|
32
|
+
"@vincemakes/kiso-provider-openai": "0.48.0",
|
|
33
|
+
"@vincemakes/kiso-provider-openai-responses": "0.48.0"
|
|
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.
|
|
47
|
+
"@vincemakes/kiso-evals": "0.48.0",
|
|
48
48
|
"@types/node": "^26.1.2",
|
|
49
49
|
"typescript": "^5.7.2",
|
|
50
50
|
"vitest": "^3.0.0"
|