@vincemakes/kiso-runtime 0.53.0 → 0.54.1

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.
@@ -0,0 +1,34 @@
1
+ /**
2
+ * A Work's added folders (ADR-0058 Amendment 19): one small file per session, `<id>.environment.json`.
3
+ *
4
+ * It is apart from `<id>.meta.json` on purpose: the sidecar's writers replace the whole file with no lock, and a rename in one
5
+ * process could write back a list read a moment earlier. This file has one writer, under its own short lock.
6
+ *
7
+ * The file tools read it on every call, so nothing holds a stale copy. It decides what the file tools may reach and nothing else:
8
+ * what the model has been told is the conversation's business, and authorisation never reads the conversation.
9
+ *
10
+ * A damaged file, or one of a version this kiso does not know, honours no added folder: the workspace keeps working.
11
+ */
12
+ export declare const ENVIRONMENT_NOTE_HEAD = "Environment update from kiso (a fact about this session, not a request from the person)";
13
+ /** The line a host puts before a person's next message after a change, kept out of the bubble and the title. Best effort. */
14
+ export declare const isEnvironmentNote: (text: string) => boolean;
15
+ /** A folder that cannot be added or removed, in words for the person. */
16
+ export declare class EnvironmentRefusedError extends Error {
17
+ constructor(message: string);
18
+ }
19
+ export declare const environmentFile: (id: string) => string;
20
+ export interface EnvironmentState {
21
+ readonly added: readonly string[];
22
+ /** the file is there and cannot be honoured; `added` is empty */
23
+ readonly damaged: boolean;
24
+ }
25
+ export declare function readEnvironment(root: string, id: string): EnvironmentState;
26
+ /** Add `folder` to the Work. `primary` is where it started; `stops` are folders the new reach never enters. */
27
+ export declare function addFolder(root: string, id: string, options: {
28
+ readonly primary: string;
29
+ readonly folder: string;
30
+ readonly stops: readonly string[];
31
+ }): Promise<readonly string[]>;
32
+ export declare function removeFolder(root: string, id: string, folder: string): Promise<readonly string[]>;
33
+ /** A fork takes the parent's current list. */
34
+ export declare function copyEnvironment(root: string, from: string, to: string): void;
@@ -0,0 +1,159 @@
1
+ /**
2
+ * A Work's added folders (ADR-0058 Amendment 19): one small file per session, `<id>.environment.json`.
3
+ *
4
+ * It is apart from `<id>.meta.json` on purpose: the sidecar's writers replace the whole file with no lock, and a rename in one
5
+ * process could write back a list read a moment earlier. This file has one writer, under its own short lock.
6
+ *
7
+ * The file tools read it on every call, so nothing holds a stale copy. It decides what the file tools may reach and nothing else:
8
+ * what the model has been told is the conversation's business, and authorisation never reads the conversation.
9
+ *
10
+ * A damaged file, or one of a version this kiso does not know, honours no added folder: the workspace keeps working.
11
+ */
12
+ import { closeSync, copyFileSync, existsSync, fsyncSync, openSync, readFileSync, realpathSync, renameSync, statSync, writeSync } from "node:fs";
13
+ import { dirname, isAbsolute, join, relative } from "node:path";
14
+ import { LockedError, nativeLockAdapter } from "./lock-adapter.js";
15
+ const VERSION = 1;
16
+ const LOCK_WAIT_MS = 2_000;
17
+ export const ENVIRONMENT_NOTE_HEAD = "Environment update from kiso (a fact about this session, not a request from the person)";
18
+ /** The line a host puts before a person's next message after a change, kept out of the bubble and the title. Best effort. */
19
+ export const isEnvironmentNote = (text) => text.startsWith(ENVIRONMENT_NOTE_HEAD);
20
+ /** A folder that cannot be added or removed, in words for the person. */
21
+ export class EnvironmentRefusedError extends Error {
22
+ constructor(message) {
23
+ super(message);
24
+ this.name = "EnvironmentRefusedError";
25
+ }
26
+ }
27
+ export const environmentFile = (id) => `${id}.environment.json`;
28
+ export function readEnvironment(root, id) {
29
+ let raw;
30
+ try {
31
+ raw = readFileSync(join(root, environmentFile(id)), "utf8");
32
+ }
33
+ catch (err) {
34
+ return { added: [], damaged: err.code !== "ENOENT" };
35
+ }
36
+ try {
37
+ const parsed = JSON.parse(raw);
38
+ if (parsed.version !== VERSION || !Array.isArray(parsed.added) || !parsed.added.every((p) => typeof p === "string" && isAbsolute(p)))
39
+ return { added: [], damaged: true };
40
+ return { added: parsed.added, damaged: false };
41
+ }
42
+ catch {
43
+ return { added: [], damaged: true };
44
+ }
45
+ }
46
+ const within = (root, target) => {
47
+ const rel = relative(root, target);
48
+ return rel === "" || (!rel.startsWith("..") && !isAbsolute(rel));
49
+ };
50
+ /**
51
+ * The list's own lock: the session store's identity-confirmed link lock (ADR-0050), never taken from a live holder and released
52
+ * only by its owner. A dead holder is taken over by the adapter's rules; a live one is waited for briefly, then refused in words.
53
+ */
54
+ async function withLock(path, id, work) {
55
+ const deadline = Date.now() + LOCK_WAIT_MS;
56
+ let handle;
57
+ for (;;) {
58
+ try {
59
+ handle = await nativeLockAdapter.acquire(`${path}.lock`, id, () => undefined);
60
+ break;
61
+ }
62
+ catch (err) {
63
+ if (!(err instanceof LockedError) || Date.now() > deadline) {
64
+ throw err instanceof LockedError ? new EnvironmentRefusedError("this Work's folders are being changed elsewhere: try again") : err;
65
+ }
66
+ await new Promise((r) => setTimeout(r, 20));
67
+ }
68
+ }
69
+ try {
70
+ if (!handle.verify())
71
+ throw new EnvironmentRefusedError("this Work's folders are being changed elsewhere: try again");
72
+ return work();
73
+ }
74
+ finally {
75
+ handle.release();
76
+ }
77
+ }
78
+ function replace(path, added) {
79
+ const tmp = `${path}.${process.pid}.tmp`;
80
+ const fd = openSync(tmp, "w", 0o600);
81
+ try {
82
+ writeSync(fd, `${JSON.stringify({ version: VERSION, added })}\n`);
83
+ fsyncSync(fd);
84
+ }
85
+ finally {
86
+ closeSync(fd);
87
+ }
88
+ renameSync(tmp, path);
89
+ // the rename is the commit: from here a failure must not be reported as one. A platform whose directories cannot be opened or
90
+ // flushed (Windows) keeps the rename.
91
+ try {
92
+ const dir = openSync(dirname(path), "r");
93
+ try {
94
+ fsyncSync(dir);
95
+ }
96
+ finally {
97
+ closeSync(dir);
98
+ }
99
+ }
100
+ catch {
101
+ // the change stands
102
+ }
103
+ }
104
+ function update(root, id, change) {
105
+ const path = join(root, environmentFile(id));
106
+ return withLock(path, id, () => {
107
+ const now = readEnvironment(root, id);
108
+ if (now.damaged)
109
+ throw new EnvironmentRefusedError(`this Work's folder list cannot be read: remove ${path} to start it again`);
110
+ const next = change(now.added);
111
+ replace(path, next);
112
+ return next;
113
+ });
114
+ }
115
+ /** Add `folder` to the Work. `primary` is where it started; `stops` are folders the new reach never enters. */
116
+ export async function addFolder(root, id, options) {
117
+ let real;
118
+ try {
119
+ real = realpathSync(options.folder);
120
+ if (!statSync(real).isDirectory())
121
+ throw new Error("not a directory");
122
+ }
123
+ catch {
124
+ throw new EnvironmentRefusedError(`${options.folder} is not a folder on this computer`);
125
+ }
126
+ const realOrSelf = (p) => {
127
+ try {
128
+ return realpathSync(p);
129
+ }
130
+ catch {
131
+ return p;
132
+ }
133
+ };
134
+ if (options.stops.map(realOrSelf).some((stop) => within(stop, real)))
135
+ throw new EnvironmentRefusedError(`${real} can't be added: the file tools do not reach this folder`);
136
+ const primary = realOrSelf(options.primary);
137
+ if (real === primary)
138
+ throw new EnvironmentRefusedError("this is already the Work's primary folder");
139
+ return update(root, id, (added) => {
140
+ if (added.includes(real))
141
+ throw new EnvironmentRefusedError("this folder is already in the Work");
142
+ if ([primary, ...added.map(realOrSelf)].some((r) => within(r, real) || within(real, r)))
143
+ throw new EnvironmentRefusedError("a folder inside, or containing, another of the Work's folders can't be added");
144
+ return [...added, real];
145
+ });
146
+ }
147
+ export async function removeFolder(root, id, folder) {
148
+ return update(root, id, (added) => {
149
+ if (!added.includes(folder))
150
+ throw new EnvironmentRefusedError("this folder is not in the Work");
151
+ return added.filter((p) => p !== folder);
152
+ });
153
+ }
154
+ /** A fork takes the parent's current list. */
155
+ export function copyEnvironment(root, from, to) {
156
+ const source = join(root, environmentFile(from));
157
+ if (existsSync(source))
158
+ copyFileSync(source, join(root, environmentFile(to)));
159
+ }
package/dist/fork.js CHANGED
@@ -7,6 +7,7 @@
7
7
  * describe runs after the cut. The parent is only read; lines it appends meanwhile are after the cut. The sidecar is
8
8
  * written first: the runtime reads a session's profile before its first event.
9
9
  */
10
+ import { copyEnvironment } from "./environment.js";
10
11
  import { closeSync, fsyncSync, openSync, readFileSync, renameSync, writeSync } from "node:fs";
11
12
  import { join } from "node:path";
12
13
  import { readSessionName, tenantsOf, writeForkSidecar } from "./profile.js";
@@ -68,6 +69,7 @@ export function forkSession(root, parent, afterSeq) {
68
69
  const id = newId();
69
70
  const origin = { session: parent, afterSeq: cut.seq, at: Date.now(), title };
70
71
  writeForkSidecar(root, id, { profile: tenantsOf(root, parent)["profile"], name: `${(title || "Session").slice(0, 110)} (fork)`, forkedFrom: origin });
72
+ copyEnvironment(root, parent, id); // before the log: a fork that is listed has its folders
71
73
  durable(join(root, `${id}.jsonl`), log.subarray(0, cut.end));
72
74
  return { id, origin };
73
75
  }
package/dist/index.d.ts CHANGED
@@ -29,6 +29,8 @@ export type { CheckpointSection } from "./summarize.js";
29
29
  export { Run, RunClosedError } from "./run.js";
30
30
  export { SessionStore, StaleWriterError, StoreCorruptionError } from "./store.js";
31
31
  export { ForkRefusedError } from "./fork.js";
32
+ export { addFolder, EnvironmentRefusedError, isEnvironmentNote, readEnvironment, removeFolder } from "./environment.js";
33
+ export type { EnvironmentState } from "./environment.js";
32
34
  export type { ForkOrigin } from "./profile.js";
33
35
  export type { Event, SessionMeta, StoreRecord } from "./store.js";
34
36
  export { disposeExtensions, loadExtensions, loadProjectExtensions } from "./extensions.js";
@@ -43,3 +45,5 @@ export type { ProjectArtifact, ProjectArtifacts, TrustDecision, TrustRecord } fr
43
45
  export { runsACheck } from "./compaction-policy.js";
44
46
  export { canonicalizeUsage } from "./usage/canonical.js";
45
47
  export { estimateTokens } from "./estimate-tokens.js";
48
+ export { lookupContextWindow } from "./provider/metadata.js";
49
+ export type { ContextWindowSource, ResolvedContextWindow } from "./provider/metadata.js";
package/dist/index.js CHANGED
@@ -30,6 +30,7 @@ export { Run, RunClosedError } from "./run.js";
30
30
  // store
31
31
  export { SessionStore, StaleWriterError, StoreCorruptionError } from "./store.js";
32
32
  export { ForkRefusedError } from "./fork.js";
33
+ export { addFolder, EnvironmentRefusedError, isEnvironmentNote, readEnvironment, removeFolder } from "./environment.js";
33
34
  // extensions
34
35
  export { disposeExtensions, loadExtensions, loadProjectExtensions } from "./extensions.js";
35
36
  // tasks (ADR-0058): a host that wires background tasks needs the manager
@@ -55,3 +56,7 @@ export { canonicalizeUsage } from "./usage/canonical.js";
55
56
  // policy, not a kernel primitive — it moved here unchanged from the core
56
57
  // package, which never called it.
57
58
  export { estimateTokens } from "./estimate-tokens.js";
59
+ // The context window a host needs for a model and route (a child session's window, a display): the same
60
+ // resolution the runtime uses — the route's row, the upstream's, every row of the model, then the release snapshot.
61
+ // Promoted from ./internal on the three products' request (2026-11-14): hosts import from the root only.
62
+ export { lookupContextWindow } from "./provider/metadata.js";
@@ -185,6 +185,11 @@ export interface ResolvedContextWindow {
185
185
  * facts about a route and stay on lookupModelMetadata.
186
186
  */
187
187
  export declare function lookupContextWindow(model: string, endpoint?: string, upstream?: string): ResolvedContextWindow | null;
188
+ /**
189
+ * What a model takes in (owner, 2026-11-11): the table's row for this route when it says, else the release snapshot for the
190
+ * model's weights (whether a model reads pictures belongs to the weights), else null, unknown. A host decides what unknown means.
191
+ */
192
+ export declare function lookupInputModalities(model: string, endpoint?: string): readonly string[] | null;
188
193
  /**
189
194
  * XP-1 §4.2 — native-only resolution. The rules, in order:
190
195
  * default/default → NO wire fields (the byte-identity anchor — a
@@ -19,6 +19,7 @@
19
19
  * does not move; core is untouched.
20
20
  */
21
21
  import { OPENROUTER_ROWS } from "./openrouter-rows.js";
22
+ import { MODEL_SNAPSHOT, MODEL_SNAPSHOT_AS_OF } from "./model-snapshot.js";
22
23
  /**
23
24
  * REG-1 — the OFF-PEAK rates, read from the vendor's pricing table on
24
25
  * 2026-09-17. The table carries TWO sets: off-peak and peak, the peak
@@ -581,6 +582,10 @@ const MODEL_ALIASES = {
581
582
  // The pricing table: `deepseek-flash` IS DeepSeek-V4.1-Flash. Gateways
582
583
  // serve it by the version name (`deepseek-v4.1-flash`).
583
584
  "deepseek-v4.1-flash": { is: "deepseek-flash", asOf: "2026-09-17", source: "https://api-docs.deepseek.com/quick_start/pricing/" },
585
+ // OpenRouter's dated snapshot: "the October 17, 2026 snapshot of DeepSeek V4.1 Flash, served by DeepSeek under the
586
+ // `deepseek-flash` API model name" (its model entry, read 2026-11-14). The window is then DeepSeek's own 1,000,000, not
587
+ // the gateway's 1,048,576 the release snapshot carried; without the alias the three products' writer on it read that.
588
+ "deepseek-v4.1-flash-1017": { is: "deepseek-flash", asOf: "2026-11-14", source: "https://openrouter.ai/deepseek/deepseek-v4.1-flash-1017" },
584
589
  // OpenRouter spells the 5.5 line with a dot; the vendor's ids carry dashes
585
590
  // (the models overview, read 2026-10-17). Same weights.
586
591
  "claude-opus-5.5": { is: "claude-opus-5-5", asOf: "2026-10-17", source: "https://platform.claude.com/docs/en/models/overview" },
@@ -632,14 +637,47 @@ export function lookupContextWindow(model, endpoint, upstream) {
632
637
  }
633
638
  const identity = modelIdentity(model);
634
639
  let found = null;
640
+ let rowed = route !== null;
635
641
  for (const entry of ENTRIES) {
636
642
  const tokens = entry.capabilities.contextWindow;
637
- if (tokens === null || modelIdentity(entry.model) !== identity)
643
+ if (modelIdentity(entry.model) !== identity)
644
+ continue;
645
+ rowed = true;
646
+ if (tokens === null)
638
647
  continue;
639
648
  if (found === null || tokens < found.tokens)
640
649
  found = { tokens, source: "model", from: entry.model };
641
650
  }
642
- return found;
651
+ if (found !== null || rowed)
652
+ return found; // a row that states no window lends none (CW-1): the snapshot does not overrule it
653
+ // last, for a model the table has no row for at all: the release's snapshot (kiso.work), by the same identity
654
+ const snap = snapshotOf(model);
655
+ return snap?.window != null ? { tokens: snap.window, source: "model", from: `${snap.key} (kiso.work, ${MODEL_SNAPSHOT_AS_OF})` } : null;
656
+ }
657
+ let dashed = null;
658
+ /** The release snapshot's row for a model: by its folded name, by the weights it names (an alias), by a name that names the
659
+ * same weights, and with dots and dashes read alike (`claude-fable-5.2` is the vendor's `claude-fable-5-2`). */
660
+ function snapshotOf(model) {
661
+ const folded = model.slice(model.lastIndexOf("/") + 1).toLowerCase();
662
+ const identity = modelIdentity(model);
663
+ const names = [folded, identity, ...Object.entries(MODEL_ALIASES).filter(([, a]) => a.is === identity).map(([n]) => n)];
664
+ for (const n of names)
665
+ if (MODEL_SNAPSHOT[n] !== undefined)
666
+ return { key: n, ...MODEL_SNAPSHOT[n] };
667
+ dashed ??= new Map(Object.keys(MODEL_SNAPSHOT).map((k) => [k.replace(/\./g, "-"), k]));
668
+ for (const n of names) {
669
+ const k = dashed.get(n.replace(/\./g, "-"));
670
+ if (k !== undefined)
671
+ return { key: k, ...MODEL_SNAPSHOT[k] };
672
+ }
673
+ return null;
674
+ }
675
+ /**
676
+ * What a model takes in (owner, 2026-11-11): the table's row for this route when it says, else the release snapshot for the
677
+ * model's weights (whether a model reads pictures belongs to the weights), else null, unknown. A host decides what unknown means.
678
+ */
679
+ export function lookupInputModalities(model, endpoint) {
680
+ return lookupModelMetadata(model, endpoint)?.capabilities.inputModalities ?? snapshotOf(model)?.input ?? null;
643
681
  }
644
682
  function originOf(endpoint) {
645
683
  try {
@@ -0,0 +1,11 @@
1
+ /**
2
+ * GENERATED by scripts/model-snapshot.mjs from https://kiso.work/models/all.json (as of 2026-11-11).
3
+ * Do not edit by hand: a release runs the script and commits the diff.
4
+ */
5
+ export declare const MODEL_SNAPSHOT_AS_OF = "2026-11-11";
6
+ export declare const MODEL_SNAPSHOT_SOURCE = "https://kiso.work/models/all.json";
7
+ /** Keyed by the model's name with its vendor prefix off, in lower case. */
8
+ export declare const MODEL_SNAPSHOT: Readonly<Record<string, {
9
+ readonly input: readonly string[] | null;
10
+ readonly window: number | null;
11
+ }>>;
@@ -0,0 +1,361 @@
1
+ /**
2
+ * GENERATED by scripts/model-snapshot.mjs from https://kiso.work/models/all.json (as of 2026-11-11).
3
+ * Do not edit by hand: a release runs the script and commits the diff.
4
+ */
5
+ export const MODEL_SNAPSHOT_AS_OF = "2026-11-11";
6
+ export const MODEL_SNAPSHOT_SOURCE = "https://kiso.work/models/all.json";
7
+ /** Keyed by the model's name with its vendor prefix off, in lower case. */
8
+ export const MODEL_SNAPSHOT = {
9
+ "aion-2.0": { "input": ["text"], "window": 131072 },
10
+ "aion-3.0": { "input": ["text"], "window": 131072 },
11
+ "aion-3.0-mini": { "input": ["text"], "window": 131072 },
12
+ "aion-3.5": { "input": ["text"], "window": 262144 },
13
+ "aion-3.5-mini": { "input": ["text"], "window": 262144 },
14
+ "aion-rp-llama-3.1-8b": { "input": ["text"], "window": 32768 },
15
+ "auto": { "input": ["text", "image", "audio", "file", "video"], "window": 2000000 },
16
+ "auto-beta": { "input": ["text", "image", "audio", "file", "video"], "window": 2000000 },
17
+ "auto-code": { "input": ["text", "image", "audio", "file", "video"], "window": 2000000 },
18
+ "beam-1.0-501b-a23b": { "input": ["text"], "window": 1048576 },
19
+ "bodybuilder": { "input": ["text"], "window": 128000 },
20
+ "claude-fable-5": { "input": ["text", "image", "file"], "window": 1000000 },
21
+ "claude-fable-5.1": { "input": ["text", "image", "file"], "window": 1000000 },
22
+ "claude-fable-5.2": { "input": ["text", "image", "file"], "window": 1000000 },
23
+ "claude-haiku-4.5": { "input": ["text", "image", "file"], "window": 200000 },
24
+ "claude-haiku-5.5": { "input": ["text", "image", "file"], "window": 1000000 },
25
+ "claude-opus-4.1": { "input": ["image", "text", "file"], "window": 200000 },
26
+ "claude-opus-4.5": { "input": ["file", "image", "text"], "window": 200000 },
27
+ "claude-opus-4.6": { "input": ["text", "image", "file"], "window": 1000000 },
28
+ "claude-opus-4.7": { "input": ["text", "image", "file"], "window": 1000000 },
29
+ "claude-opus-4.8": { "input": ["text", "image", "file"], "window": 1000000 },
30
+ "claude-opus-5": { "input": ["text", "image", "file"], "window": 1000000 },
31
+ "claude-opus-5.5": { "input": ["text", "image", "file"], "window": 1000000 },
32
+ "claude-sonnet-4.5": { "input": ["text", "image", "file"], "window": 1000000 },
33
+ "claude-sonnet-4.6": { "input": ["text", "image", "file"], "window": 1000000 },
34
+ "claude-sonnet-5": { "input": ["text", "image", "file"], "window": 1000000 },
35
+ "claude-sonnet-5.5": { "input": ["text", "image", "file"], "window": 1000000 },
36
+ "codestral-2508": { "input": ["text", "file"], "window": 256000 },
37
+ "command-a": { "input": ["text"], "window": 256000 },
38
+ "command-a-plus": { "input": ["text", "image"], "window": 192000 },
39
+ "command-r-08-2024": { "input": ["text"], "window": 128000 },
40
+ "command-r-plus-08-2024": { "input": ["text"], "window": 128000 },
41
+ "command-r7b-12-2024": { "input": ["text"], "window": 128000 },
42
+ "cydonia-24b-v4.1": { "input": ["text"], "window": 131072 },
43
+ "deepseek-chat": { "input": ["text"], "window": 163840 },
44
+ "deepseek-chat-v3-0324": { "input": ["text"], "window": 163840 },
45
+ "deepseek-chat-v3.1": { "input": ["text"], "window": 163840 },
46
+ "deepseek-r1-0528": { "input": ["text"], "window": 163840 },
47
+ "deepseek-v3.1-terminus": { "input": ["text"], "window": 163840 },
48
+ "deepseek-v3.2": { "input": ["text"], "window": 163840 },
49
+ "deepseek-v3.2-exp": { "input": ["text"], "window": 163840 },
50
+ "deepseek-v4-flash": { "input": ["text"], "window": 1048576 },
51
+ "deepseek-v4-flash-0731": { "input": ["text"], "window": 1048576 },
52
+ "deepseek-v4-flash-vision-exp": { "input": ["text", "image"], "window": 1048576 },
53
+ "deepseek-v4-pro": { "input": ["text"], "window": 1048576 },
54
+ "deepseek-v4-pro-0813": { "input": ["text"], "window": 1048576 },
55
+ "deepseek-v4.1-flash": { "input": ["text", "image"], "window": 1048576 },
56
+ "deepseek-v4.1-flash-1017": { "input": ["text", "image"], "window": 1048576 },
57
+ "devstral-2512": { "input": ["text", "file"], "window": 262144 },
58
+ "dolphin-mistral-24b-venice-edition": { "input": ["text"], "window": 128000 },
59
+ "ember-1": { "input": ["text", "image"], "window": 1048576 },
60
+ "ernie-light-dt-1.0-intl": { "input": ["text"], "window": 1024000 },
61
+ "extract": { "input": ["text", "image", "file"], "window": 1000000 },
62
+ "free": { "input": ["text", "image"], "window": 200000 },
63
+ "fugu-max": { "input": ["text", "image", "file"], "window": 1000000 },
64
+ "fugu-ultra": { "input": ["text", "image"], "window": 1000000 },
65
+ "fugu-ultra-v2": { "input": ["text", "image", "file"], "window": 1000000 },
66
+ "fusion": { "input": ["text"], "window": 1000000 },
67
+ "gemini-2.5-flash": { "input": ["file", "image", "text", "audio", "video"], "window": 1048576 },
68
+ "gemini-2.5-flash-image": { "input": ["image", "text"], "window": 32768 },
69
+ "gemini-2.5-flash-lite": { "input": ["text", "image", "file", "audio", "video"], "window": 1048576 },
70
+ "gemini-2.5-pro": { "input": ["text", "image", "file", "audio", "video"], "window": 1048576 },
71
+ "gemini-2.5-pro-preview": { "input": ["file", "image", "text", "audio"], "window": 1048576 },
72
+ "gemini-3-flash-preview": { "input": ["text", "image", "file", "audio", "video"], "window": 1048576 },
73
+ "gemini-3-pro-image": { "input": ["image", "text"], "window": 131072 },
74
+ "gemini-3-pro-image-preview": { "input": ["image", "text"], "window": 65536 },
75
+ "gemini-3.1-flash-image": { "input": ["image", "text"], "window": 131072 },
76
+ "gemini-3.1-flash-image-preview": { "input": ["image", "text"], "window": 65536 },
77
+ "gemini-3.1-flash-lite": { "input": ["text", "image", "video", "file", "audio"], "window": 1048576 },
78
+ "gemini-3.1-flash-lite-image": { "input": ["image", "text"], "window": 65536 },
79
+ "gemini-3.1-flash-lite-preview": { "input": ["text", "image", "video", "file", "audio"], "window": 1048576 },
80
+ "gemini-3.1-pro-preview": { "input": ["audio", "file", "image", "text", "video"], "window": 1048576 },
81
+ "gemini-3.1-pro-preview-customtools": { "input": ["text", "audio", "image", "video", "file"], "window": 1048576 },
82
+ "gemini-3.5-flash": { "input": ["text", "image", "video", "file", "audio"], "window": 1048576 },
83
+ "gemini-3.5-flash-lite": { "input": ["text", "image", "video", "file", "audio"], "window": 1048576 },
84
+ "gemini-3.6-flash": { "input": ["text", "image", "video", "file", "audio"], "window": 1048576 },
85
+ "gemini-3.7-flash": { "input": ["text", "image", "video", "file", "audio"], "window": 1048576 },
86
+ "gemini-3.8-flash": { "input": ["text", "image", "video", "file", "audio"], "window": 1048576 },
87
+ "gemini-4-argon": { "input": ["audio", "file", "image", "text", "video"], "window": 1048576 },
88
+ "gemini-4-carbon": { "input": ["audio", "file", "image", "text", "video"], "window": 1048576 },
89
+ "gemini-nano-banana-2.1": { "input": ["image", "text"], "window": 65536 },
90
+ "gemini-omni-1.1-flash": { "input": ["text", "image", "video"], "window": 131072 },
91
+ "gemini-omni-1.2-flash": { "input": ["text", "image", "video"], "window": 131072 },
92
+ "gemma-2-27b-it": { "input": ["text"], "window": 8192 },
93
+ "gemma-3-12b-it": { "input": ["text", "image"], "window": 131072 },
94
+ "gemma-3-27b-it": { "input": ["text", "image"], "window": 131072 },
95
+ "gemma-3-4b-it": { "input": ["text", "image"], "window": 131072 },
96
+ "gemma-4-26b-a4b-it": { "input": ["image", "text", "video"], "window": 262144 },
97
+ "gemma-4-31b-it": { "input": ["image", "text", "video"], "window": 262144 },
98
+ "glimpse": { "input": ["text", "image", "video"], "window": 262144 },
99
+ "glm-4.5": { "input": ["text"], "window": 131072 },
100
+ "glm-4.5-air": { "input": ["text"], "window": 131072 },
101
+ "glm-4.5v": { "input": ["text", "image"], "window": 65536 },
102
+ "glm-4.6": { "input": ["text"], "window": 204800 },
103
+ "glm-4.6v": { "input": ["image", "text", "video"], "window": 131072 },
104
+ "glm-4.7": { "input": ["text"], "window": 204800 },
105
+ "glm-4.7-flash": { "input": ["text"], "window": 200000 },
106
+ "glm-5": { "input": ["text"], "window": 204800 },
107
+ "glm-5-turbo": { "input": ["text"], "window": 202752 },
108
+ "glm-5.1": { "input": ["text"], "window": 204800 },
109
+ "glm-5.2": { "input": ["text"], "window": 1048576 },
110
+ "glm-5.3": { "input": ["text"], "window": 1048576 },
111
+ "glm-5.3-flash": { "input": ["text", "image", "video"], "window": 1048576 },
112
+ "glm-5.3-flashx": { "input": ["text", "image", "video"], "window": 1048576 },
113
+ "glm-5.3-flashx-legal": { "input": ["text", "image", "video"], "window": 1048576 },
114
+ "glm-5.3-prime": { "input": ["text"], "window": 1000000 },
115
+ "glm-5v-turbo": { "input": ["image", "text", "video"], "window": 202752 },
116
+ "gpt-3.5-turbo-0613": { "input": ["text"], "window": 4095 },
117
+ "gpt-3.5-turbo-16k": { "input": ["text"], "window": 16385 },
118
+ "gpt-4": { "input": ["text"], "window": 8191 },
119
+ "gpt-4.1": { "input": ["image", "text", "file"], "window": 1047576 },
120
+ "gpt-4.1-mini": { "input": ["image", "text", "file"], "window": 1047576 },
121
+ "gpt-4.1-nano": { "input": ["image", "text", "file"], "window": 1047576 },
122
+ "gpt-4o": { "input": ["text", "image", "file"], "window": 128000 },
123
+ "gpt-4o-2024-05-13": { "input": ["text", "image", "file"], "window": 128000 },
124
+ "gpt-4o-2024-08-06": { "input": ["text", "image", "file"], "window": 128000 },
125
+ "gpt-4o-2024-11-20": { "input": ["text", "image", "file"], "window": 128000 },
126
+ "gpt-4o-mini": { "input": ["text", "image", "file"], "window": 128000 },
127
+ "gpt-4o-mini-2024-07-18": { "input": ["text", "image", "file"], "window": 128000 },
128
+ "gpt-5": { "input": ["text", "image", "file"], "window": 400000 },
129
+ "gpt-5-image": { "input": ["image", "text", "file"], "window": 400000 },
130
+ "gpt-5-image-mini": { "input": ["file", "image", "text"], "window": 400000 },
131
+ "gpt-5-mini": { "input": ["text", "image", "file"], "window": 400000 },
132
+ "gpt-5-nano": { "input": ["text", "image", "file"], "window": 400000 },
133
+ "gpt-5-pro": { "input": ["image", "text", "file"], "window": 400000 },
134
+ "gpt-5.1": { "input": ["image", "text", "file"], "window": 400000 },
135
+ "gpt-5.1-codex": { "input": ["text", "image"], "window": 400000 },
136
+ "gpt-5.1-codex-max": { "input": ["text", "image"], "window": 400000 },
137
+ "gpt-5.1-codex-mini": { "input": ["image", "text"], "window": 400000 },
138
+ "gpt-5.2": { "input": ["file", "image", "text"], "window": 400000 },
139
+ "gpt-5.2-chat": { "input": ["file", "image", "text"], "window": 128000 },
140
+ "gpt-5.2-codex": { "input": ["text", "image"], "window": 400000 },
141
+ "gpt-5.2-pro": { "input": ["image", "text", "file"], "window": 400000 },
142
+ "gpt-5.3-codex": { "input": ["text", "image", "file"], "window": 400000 },
143
+ "gpt-5.4": { "input": ["text", "image", "file"], "window": 1050000 },
144
+ "gpt-5.4-image-2": { "input": ["image", "text", "file"], "window": 272000 },
145
+ "gpt-5.4-mini": { "input": ["file", "image", "text"], "window": 400000 },
146
+ "gpt-5.4-nano": { "input": ["file", "image", "text"], "window": 400000 },
147
+ "gpt-5.4-pro": { "input": ["text", "image", "file"], "window": 1050000 },
148
+ "gpt-5.5": { "input": ["file", "image", "text"], "window": 1050000 },
149
+ "gpt-5.5-pro": { "input": ["file", "image", "text"], "window": 1050000 },
150
+ "gpt-5.6-luna": { "input": ["file", "image", "text"], "window": 1050000 },
151
+ "gpt-5.6-luna-pro": { "input": ["file", "image", "text"], "window": 1050000 },
152
+ "gpt-5.6-sol": { "input": ["file", "image", "text"], "window": 1050000 },
153
+ "gpt-5.6-sol-pro": { "input": ["file", "image", "text"], "window": 1050000 },
154
+ "gpt-5.6-terra": { "input": ["file", "image", "text"], "window": 1050000 },
155
+ "gpt-5.6-terra-pro": { "input": ["file", "image", "text"], "window": 1050000 },
156
+ "gpt-6-astra": { "input": ["file", "image", "text"], "window": 1050000 },
157
+ "gpt-6-astra-pro": { "input": ["file", "image", "text"], "window": 1050000 },
158
+ "gpt-6-luna": { "input": ["file", "image", "text"], "window": 1050000 },
159
+ "gpt-6-luna-pro": { "input": ["file", "image", "text"], "window": 1050000 },
160
+ "gpt-6-sol": { "input": ["file", "image", "text"], "window": 1050000 },
161
+ "gpt-6-sol-pro": { "input": ["file", "image", "text"], "window": 1050000 },
162
+ "gpt-6.1-sol": { "input": ["file", "image", "text"], "window": 1050000 },
163
+ "gpt-6.1-sol-pro": { "input": ["file", "image", "text"], "window": 1050000 },
164
+ "gpt-6.1-terra": { "input": ["file", "image", "text"], "window": 1050000 },
165
+ "gpt-6.1-terra-pro": { "input": ["file", "image", "text"], "window": 1050000 },
166
+ "gpt-audio": { "input": ["text", "audio"], "window": 128000 },
167
+ "gpt-audio-mini": { "input": ["text", "audio"], "window": 128000 },
168
+ "gpt-chat-latest": { "input": ["text", "image", "file"], "window": 400000 },
169
+ "gpt-oss-120b": { "input": ["text"], "window": 131072 },
170
+ "gpt-oss-20b": { "input": ["text"], "window": 131072 },
171
+ "gpt-oss-safeguard-20b": { "input": ["text"], "window": 131072 },
172
+ "granite-4.2-8b": { "input": ["text"], "window": 131072 },
173
+ "grok-4.20": { "input": ["text", "image", "file"], "window": 2000000 },
174
+ "grok-4.20-multi-agent": { "input": ["text", "image", "file"], "window": 2000000 },
175
+ "grok-4.3": { "input": ["text", "image", "file"], "window": 1000000 },
176
+ "grok-4.5": { "input": ["text", "image", "file"], "window": 500000 },
177
+ "grok-4.6": { "input": ["text", "image", "file"], "window": 500000 },
178
+ "grok-4.7": { "input": ["text", "image", "file"], "window": 500000 },
179
+ "grok-build-0.1": { "input": ["text", "image", "file"], "window": 256000 },
180
+ "hermes-4-405b": { "input": ["text"], "window": 131072 },
181
+ "hunyuan-a13b-instruct": { "input": ["text"], "window": 131072 },
182
+ "hy-mt2-1.8b": { "input": ["text"], "window": 8192 },
183
+ "hy-mt2-30b-a3b": { "input": ["text"], "window": 8192 },
184
+ "hy-mt2-7b": { "input": ["text"], "window": 8192 },
185
+ "hy3": { "input": ["text"], "window": 262144 },
186
+ "hy3-preview": { "input": ["text"], "window": 262144 },
187
+ "hy4": { "input": ["text", "image"], "window": 1048576 },
188
+ "hy4-preview": { "input": ["text"], "window": 1048576 },
189
+ "inkling": { "input": ["text", "image", "audio"], "window": 524288 },
190
+ "inkling-small": { "input": ["text", "image", "audio"], "window": 524288 },
191
+ "jev-router": { "input": ["audio", "file", "image", "text", "video"], "window": 1000000 },
192
+ "kimi-k2": { "input": ["text"], "window": 131072 },
193
+ "kimi-k2-0905": { "input": ["text"], "window": 262144 },
194
+ "kimi-k2-thinking": { "input": ["text"], "window": 262144 },
195
+ "kimi-k2.5": { "input": ["text", "image"], "window": 262144 },
196
+ "kimi-k2.6": { "input": ["text", "image"], "window": 262144 },
197
+ "kimi-k2.7-code": { "input": ["text", "image"], "window": 262144 },
198
+ "kimi-k3": { "input": ["text", "image", "video"], "window": 1048576 },
199
+ "kimi-k3.1-pro": { "input": ["text", "image", "video"], "window": 1048576 },
200
+ "l3-lunaris-8b": { "input": ["text"], "window": 8192 },
201
+ "l3.1-euryale-70b": { "input": ["text"], "window": 131072 },
202
+ "lfm-2.5-2.6b": { "input": ["text"], "window": 128000 },
203
+ "lfm-2.5-24b-a2b": { "input": ["text"], "window": 128000 },
204
+ "lfm-3-1.7b": { "input": ["text"], "window": 262144 },
205
+ "ling-3.0-flash": { "input": ["text"], "window": 262144 },
206
+ "ling-3.0-flash-vl": { "input": ["text", "image", "video"], "window": 131072 },
207
+ "ling-3.0-tiny": { "input": ["text"], "window": 262144 },
208
+ "ling-3.1-flash": { "input": ["text"], "window": 1000000 },
209
+ "llama-3.1-70b-instruct": { "input": ["text"], "window": 131072 },
210
+ "llama-3.1-8b-instruct": { "input": ["text"], "window": 131072 },
211
+ "llama-3.2-1b-instruct": { "input": ["text"], "window": 60000 },
212
+ "llama-3.2-3b-instruct": { "input": ["text"], "window": 131072 },
213
+ "llama-3.3-70b-instruct": { "input": ["text"], "window": 131072 },
214
+ "llama-4-maverick": { "input": ["text", "image"], "window": 524288 },
215
+ "llama-4-scout": { "input": ["text", "image"], "window": 1310720 },
216
+ "llama-guard-4-12b": { "input": ["image", "text"], "window": 163840 },
217
+ "longcat-2.0": { "input": ["text"], "window": 1048756 },
218
+ "lyria-3-clip-preview": { "input": ["text", "image"], "window": 1048576 },
219
+ "lyria-3-pro-preview": { "input": ["text", "image"], "window": 1048576 },
220
+ "magnum-v4-72b": { "input": ["text"], "window": 32768 },
221
+ "midm-k-3.0-pro": { "input": ["text"], "window": 261795 },
222
+ "mimo-v2.5": { "input": ["text", "audio", "image", "video"], "window": 1000000 },
223
+ "mimo-v2.5-pro": { "input": ["text"], "window": 1024000 },
224
+ "mimo-v2.6-flash": { "input": ["text", "image", "video", "audio"], "window": 1050000 },
225
+ "mimo-v2.6-pro": { "input": ["text", "image", "video", "audio"], "window": 1050000 },
226
+ "mimo-v2.6-pro-ultraspeed": { "input": ["text", "image", "video", "audio"], "window": 1048576 },
227
+ "minimax-m2.5": { "input": ["text"], "window": 200000 },
228
+ "minimax-m2.7": { "input": ["text"], "window": 196608 },
229
+ "minimax-m3": { "input": ["text", "image", "video"], "window": 1048576 },
230
+ "minimax-m3.1-flash": { "input": ["text", "image", "video"], "window": 1048576 },
231
+ "ministral-14b-2512": { "input": ["text", "image"], "window": 262144 },
232
+ "ministral-3b-2512": { "input": ["text", "image"], "window": 131072 },
233
+ "ministral-8b-2512": { "input": ["text", "image"], "window": 262144 },
234
+ "mistral-large": { "input": ["text", "file"], "window": 128000 },
235
+ "mistral-large-2407": { "input": ["text", "file"], "window": 131072 },
236
+ "mistral-large-2512": { "input": ["text", "image", "file"], "window": 262144 },
237
+ "mistral-large-4-0": { "input": ["text", "image"], "window": 1048576 },
238
+ "mistral-medium-3": { "input": ["text", "image", "file"], "window": 131072 },
239
+ "mistral-medium-3-5": { "input": ["text", "image", "file"], "window": 262144 },
240
+ "mistral-medium-3.1": { "input": ["text", "image", "file"], "window": 131072 },
241
+ "mistral-nemo": { "input": ["text"], "window": 131072 },
242
+ "mistral-saba": { "input": ["text", "file"], "window": 32768 },
243
+ "mistral-small-24b-instruct-2501": { "input": ["text"], "window": 32768 },
244
+ "mistral-small-2603": { "input": ["text", "image"], "window": 262144 },
245
+ "mistral-small-3.1-24b-instruct": { "input": ["text", "image"], "window": 128000 },
246
+ "mistral-small-3.2-24b-instruct": { "input": ["image", "text"], "window": 256000 },
247
+ "mixtral-8x22b-instruct": { "input": ["text", "file"], "window": 65536 },
248
+ "moondream3-preview": { "input": ["text", "image"], "window": 32000 },
249
+ "moondream3.1-9b-a2b": { "input": ["text", "image"], "window": 32000 },
250
+ "morph-v3-fast": { "input": ["text"], "window": 262144 },
251
+ "morph-v3-large": { "input": ["text"], "window": 262144 },
252
+ "motif-3": { "input": ["text"], "window": 262144 },
253
+ "muse-ember": { "input": ["text", "image", "video", "file", "audio"], "window": 1048576 },
254
+ "muse-glimmer-30b": { "input": ["text", "image"], "window": 131072 },
255
+ "muse-spark-1.1": { "input": ["text", "image", "video", "file"], "window": 1048576 },
256
+ "muse-spark-1.2": { "input": ["text", "image", "video", "file"], "window": 1048576 },
257
+ "muse-spark-1.2-contributor": { "input": ["text", "image", "video", "file"], "window": 1048576 },
258
+ "muse-spark-1.3": { "input": ["text", "image", "video", "file"], "window": 1048576 },
259
+ "muse-spark-1.3-contributor": { "input": ["text", "image", "video", "file"], "window": 1048576 },
260
+ "muse-spark-open": { "input": ["text", "image", "video", "file", "audio"], "window": 1048576 },
261
+ "muse-wonder": { "input": ["text", "image", "video", "file", "audio"], "window": 1048576 },
262
+ "mythomax-l2-13b": { "input": ["text"], "window": 8192 },
263
+ "nemotron-3-nano-30b-a3b": { "input": ["text"], "window": 262144 },
264
+ "nemotron-3-super-120b-a12b": { "input": ["text"], "window": 262144 },
265
+ "nemotron-3-ultra-550b-a55b": { "input": ["text"], "window": 262144 },
266
+ "nemotron-3.5-content-safety": { "input": ["text", "image"], "window": 131072 },
267
+ "nemotron-3.5-lightning": { "input": ["text"], "window": 262144 },
268
+ "nemotron-3.5-super-vl": { "input": ["text", "image", "video"], "window": 1048576 },
269
+ "nex-n2.5-mini": { "input": ["text", "image"], "window": 262144 },
270
+ "nex-n2.5-pro": { "input": ["text", "image"], "window": 262144 },
271
+ "nex-n2.6": { "input": ["text", "image"], "window": 262144 },
272
+ "nova-2-lite-v1": { "input": ["text", "image", "video", "file"], "window": 1000000 },
273
+ "nova-lite-v1": { "input": ["text", "image"], "window": 300000 },
274
+ "nova-micro-v1": { "input": ["text"], "window": 128000 },
275
+ "nova-premier-v1": { "input": ["text", "image"], "window": 1000000 },
276
+ "nova-pro-v1": { "input": ["text", "image"], "window": 300000 },
277
+ "o3": { "input": ["image", "text", "file"], "window": 200000 },
278
+ "o3-pro": { "input": ["text", "file", "image"], "window": 200000 },
279
+ "palmyra-x5": { "input": ["text"], "window": 1040000 },
280
+ "pareto-26.10": { "input": ["text", "image"], "window": 1048576 },
281
+ "pareto-26.9": { "input": ["text", "image"], "window": 262144 },
282
+ "pareto-code": { "input": ["text"], "window": 2000000 },
283
+ "particle-1": { "input": ["text", "image"], "window": 1048576 },
284
+ "perceptron-mk1": { "input": ["text", "image", "video"], "window": 32768 },
285
+ "perceptron-mk1.5": { "input": ["text", "image", "video", "audio"], "window": 36864 },
286
+ "phi-4": { "input": ["text"], "window": 16384 },
287
+ "qwen-2.5-72b-instruct": { "input": ["text"], "window": 32768 },
288
+ "qwen-2.5-coder-32b-instruct": { "input": ["text"], "window": 32768 },
289
+ "qwen-plus": { "input": ["text"], "window": 1000000 },
290
+ "qwen2.5-vl-72b-instruct": { "input": ["text", "image"], "window": 128000 },
291
+ "qwen3-14b": { "input": ["text"], "window": 40960 },
292
+ "qwen3-235b-a22b-2507": { "input": ["text"], "window": 262144 },
293
+ "qwen3-235b-a22b-thinking-2507": { "input": ["text"], "window": 128000 },
294
+ "qwen3-30b-a3b": { "input": ["text"], "window": 40960 },
295
+ "qwen3-30b-a3b-instruct-2507": { "input": ["text"], "window": 262144 },
296
+ "qwen3-32b": { "input": ["text"], "window": 131072 },
297
+ "qwen3-coder": { "input": ["text"], "window": 262144 },
298
+ "qwen3-coder-30b-a3b-instruct": { "input": ["text"], "window": 262144 },
299
+ "qwen3-coder-flash": { "input": ["text"], "window": 1000000 },
300
+ "qwen3-coder-next": { "input": ["text"], "window": 262144 },
301
+ "qwen3-next-80b-a3b-instruct": { "input": ["text"], "window": 262144 },
302
+ "qwen3-vl-235b-a22b-instruct": { "input": ["text", "image"], "window": 262144 },
303
+ "qwen3-vl-30b-a3b-instruct": { "input": ["text", "image"], "window": 262144 },
304
+ "qwen3-vl-30b-a3b-thinking": { "input": ["text", "image"], "window": 262144 },
305
+ "qwen3-vl-8b-instruct": { "input": ["image", "text"], "window": 262144 },
306
+ "qwen3.5-122b-a10b": { "input": ["text", "image", "video"], "window": 262144 },
307
+ "qwen3.5-27b": { "input": ["text", "image", "video"], "window": 262144 },
308
+ "qwen3.5-35b-a3b": { "input": ["text", "image", "video"], "window": 262144 },
309
+ "qwen3.5-397b-a17b": { "input": ["text", "image", "video"], "window": 262144 },
310
+ "qwen3.5-9b": { "input": ["text", "image", "video"], "window": 262144 },
311
+ "qwen3.5-flash-02-23": { "input": ["text", "image", "video"], "window": 1000000 },
312
+ "qwen3.5-plus-02-15": { "input": ["text", "image", "video"], "window": 1000000 },
313
+ "qwen3.5-plus-20260420": { "input": ["text", "image", "video"], "window": 1000000 },
314
+ "qwen3.6-27b": { "input": ["text", "image", "video"], "window": 262144 },
315
+ "qwen3.6-35b-a3b": { "input": ["text", "image", "video"], "window": 262144 },
316
+ "qwen3.6-flash": { "input": ["text", "image", "video"], "window": 1000000 },
317
+ "qwen3.6-plus": { "input": ["text", "image", "video"], "window": 1000000 },
318
+ "qwen3.7-flash": { "input": ["text", "image", "video"], "window": 1000000 },
319
+ "qwen3.7-max": { "input": ["text"], "window": 1000000 },
320
+ "qwen3.7-plus": { "input": ["text", "image"], "window": 1000000 },
321
+ "qwen3.8-2.4t-a95b": { "input": ["text"], "window": 1048576 },
322
+ "qwen3.8-27b": { "input": ["text", "image", "video"], "window": 1048575 },
323
+ "qwen3.8-flash": { "input": ["text", "image", "video"], "window": 1000000 },
324
+ "qwen3.8-max-0902": { "input": ["text", "image", "video"], "window": 1000000 },
325
+ "qwen3.8-max-prime": { "input": ["text", "image", "video"], "window": 1000000 },
326
+ "qwen3.8-omni-flash": { "input": ["text", "image", "audio", "video"], "window": 1000000 },
327
+ "reka-edge": { "input": ["image", "text", "video"], "window": 16384 },
328
+ "reka-flash-3": { "input": ["text"], "window": 65536 },
329
+ "relace-apply-3": { "input": ["text"], "window": 256000 },
330
+ "relace-search": { "input": ["text"], "window": 256000 },
331
+ "remm-slerp-l2-13b": { "input": ["text"], "window": 6144 },
332
+ "ripple-65b-preview": { "input": ["text"], "window": 1048576 },
333
+ "sakana-namazu": { "input": ["text", "image", "file"], "window": 262144 },
334
+ "schematron-v2-small": { "input": ["text"], "window": 128000 },
335
+ "schematron-v2-turbo": { "input": ["text"], "window": 128000 },
336
+ "seed-1.6": { "input": ["image", "text", "video"], "window": 262144 },
337
+ "seed-1.6-flash": { "input": ["image", "text", "video"], "window": 262144 },
338
+ "seed-2-1-turbo": { "input": ["text", "image", "video"], "window": 262144 },
339
+ "seed-2.0-code": { "input": ["text", "image", "video"], "window": 262144 },
340
+ "seed-2.0-lite": { "input": ["text", "image", "video"], "window": 262144 },
341
+ "seed-2.0-mini": { "input": ["text", "image", "video"], "window": 262144 },
342
+ "skyfall-36b-v2": { "input": ["text"], "window": 32768 },
343
+ "solar-mini4": { "input": ["text"], "window": 524288 },
344
+ "solar-pro4": { "input": ["text"], "window": 524288 },
345
+ "sonar": { "input": ["text", "image"], "window": 127072 },
346
+ "sonar-deep-research": { "input": ["text"], "window": 128000 },
347
+ "sonar-pro": { "input": ["text", "image"], "window": 200000 },
348
+ "sonar-pro-search": { "input": ["text", "image"], "window": 200000 },
349
+ "sonar-reasoning-pro": { "input": ["text", "image"], "window": 128000 },
350
+ "step-3.5-flash": { "input": ["text"], "window": 262144 },
351
+ "step-3.7-flash": { "input": ["text", "image", "video"], "window": 262144 },
352
+ "step-5-preview": { "input": ["text", "image", "video"], "window": 1000000 },
353
+ "summarize": { "input": ["text", "image", "file"], "window": 1000000 },
354
+ "switchyard": { "input": ["text"], "window": 1000000 },
355
+ "ternary-bonsai-2-27b": { "input": ["text", "image"], "window": 262144 },
356
+ "ternary-bonsai-2-9b": { "input": ["text", "image"], "window": 262144 },
357
+ "ui-tars-1.5-7b": { "input": ["image", "text"], "window": 128000 },
358
+ "unslopnemo-12b": { "input": ["text"], "window": 1024000 },
359
+ "voxtral-small-24b-2507": { "input": ["text", "audio", "file"], "window": 32768 },
360
+ "weaver": { "input": ["text"], "window": 8000 },
361
+ };
package/dist/session.d.ts CHANGED
@@ -101,12 +101,14 @@ export interface CompactInfo {
101
101
  }
102
102
  /** The follow-up's built-in ask (Session.followUp with no `ask`): the line the person may send next. No language is
103
103
  * named: without the clause, Chinese conversations still gave Chinese lines (measured, owner 2026-11-03). */
104
- export declare const FOLLOW_UP_ASK = "Write the one message the person is most likely to send you next, as they would type it, and nothing else. If the work is done and nothing naturally follows, answer with nothing.";
105
- /** The built-in follow-up's answer as a line: its first non-empty line, without quotes around it, at most 200
106
- * characters; "" for none. */
104
+ export declare const FOLLOW_UP_ASK = "Write the one message the person is most likely to send you next, as they would type it, and nothing else. Write it in their voice, as their reply to you: in it, \"I\" is the person and \"you\" is you. If the work is done and nothing naturally follows, answer with nothing.";
105
+ /** The built-in follow-up's answer as a line: its first non-empty line, without quotes around it; "" for none, and ""
106
+ * for a line over 200 characters (a cut message is not one the person would send, so it is dropped, not shortened). */
107
107
  export declare function followUpLine(text: string): string;
108
- /** The session title's ask (Session.title): no language named, the model follows the message's own. */
109
- export declare const TITLE_PROMPT = "Write a short title (2 to 8 words) for a conversation that opens with the user's message. Only the title: no quotes, no punctuation at the end.";
108
+ /** The session title's ask (Session.title). The language is named, unlike the follow-up's: the title sees one message
109
+ * and no history, and a short greeting under an English ask came back English (ds, a three-character Chinese
110
+ * greeting: 5 of 10 English titles without the clause, 0 of 10 with it; owner 2026-11-04). */
111
+ export declare const TITLE_PROMPT = "Write a short title (2 to 8 words) for a conversation that opens with the user's message, in the language of that message. Only the title: no quotes, no punctuation at the end.";
110
112
  /** A model's title as a name: its first non-empty line, without quotes around it or punctuation at its end, its spaces
111
113
  * collapsed, at most 60 characters; "" when no letter or digit is left. */
112
114
  export declare function cleanTitle(text: string): string;
package/dist/session.js CHANGED
@@ -94,16 +94,20 @@ function summaryReasoning(model, baseUrl) {
94
94
  }
95
95
  /** The follow-up's built-in ask (Session.followUp with no `ask`): the line the person may send next. No language is
96
96
  * named: without the clause, Chinese conversations still gave Chinese lines (measured, owner 2026-11-03). */
97
- export const FOLLOW_UP_ASK = "Write the one message the person is most likely to send you next, as they would type it, and nothing else. If the work is done and nothing naturally follows, answer with nothing.";
98
- /** The built-in follow-up's answer as a line: its first non-empty line, without quotes around it, at most 200
99
- * characters; "" for none. */
97
+ export const FOLLOW_UP_ASK = "Write the one message the person is most likely to send you next, as they would type it, and nothing else. Write it in their voice, as their reply to you: in it, \"I\" is the person and \"you\" is you. If the work is done and nothing naturally follows, answer with nothing.";
98
+ /** The built-in follow-up's answer as a line: its first non-empty line, without quotes around it; "" for none, and ""
99
+ * for a line over 200 characters (a cut message is not one the person would send, so it is dropped, not shortened). */
100
100
  export function followUpLine(text) {
101
101
  const first = text.split("\n").map((l) => l.trim()).find((l) => l !== "") ?? "";
102
102
  const bare = first.replace(/^["'`\u201c\u2018\u300c]+|["'`\u201d\u2019\u300d]+$/g, "").trim();
103
- return [...bare].length > 200 ? `${[...bare].slice(0, 199).join("")}\u2026` : bare;
103
+ return [...bare].length > 200 ? "" : bare;
104
104
  }
105
- /** The session title's ask (Session.title): no language named, the model follows the message's own. */
106
- export const TITLE_PROMPT = "Write a short title (2 to 8 words) for a conversation that opens with the user's message. Only the title: no quotes, no punctuation at the end.";
105
+ /** The built-in follow-up's room when its thinking cannot be turned off: a one-line answer after the model's own thinking. */
106
+ const FOLLOW_UP_THINKING_ROOM = 600;
107
+ /** The session title's ask (Session.title). The language is named, unlike the follow-up's: the title sees one message
108
+ * and no history, and a short greeting under an English ask came back English (ds, a three-character Chinese
109
+ * greeting: 5 of 10 English titles without the clause, 0 of 10 with it; owner 2026-11-04). */
110
+ export const TITLE_PROMPT = "Write a short title (2 to 8 words) for a conversation that opens with the user's message, in the language of that message. Only the title: no quotes, no punctuation at the end.";
107
111
  /** No thinking for a side answer, where the model table says how: thinking disabled, else effort `none`; null when the
108
112
  * table knows neither (then nothing is sent: a raw field to an unknown model can be a 400). */
109
113
  function quietReasoning(model, baseUrl) {
@@ -971,12 +975,19 @@ export class AgentSession {
971
975
  });
972
976
  tracer.init();
973
977
  const guarded = traceGuard(tracer, idleGuard(this.#adapter, this.#config.streamIdleMs ?? DEFAULT_STREAM_IDLE_MS));
978
+ // The built-in line asks for no thinking where the model table says how, as the title does: half of the measured
979
+ // follow-ups spent 80-200 output tokens thinking about one line, and some were cut off by the budget. Not on the
980
+ // anthropic route, where changing the thinking setting drops the cached prefix this request exists to reuse. A model
981
+ // that cannot be quieted keeps its own setting and gets room for its thinking. A host's own `ask` is sent as before.
982
+ const quiet = options.ask === undefined && this.#provider !== "anthropic" ? quietReasoning(this.#model, this.#baseUrl) : null;
983
+ const maxTokens = options.ask === undefined && quiet === null && options.maxTokens !== undefined ? Math.max(options.maxTokens, FOLLOW_UP_THINKING_ROOM) : options.maxTokens;
974
984
  let text = "";
975
985
  try {
976
986
  for await (const ev of guarded.stream({
977
987
  ...last,
988
+ ...(quiet !== null ? { reasoning: quiet } : {}),
978
989
  messages: [...last.messages, ...this.#after(last.messages), { role: "user", content: options.ask ?? FOLLOW_UP_ASK }],
979
- ...(options.maxTokens !== undefined ? { maxTokens: options.maxTokens } : {}),
990
+ ...(maxTokens !== undefined ? { maxTokens } : {}),
980
991
  ...(options.signal !== undefined ? { signal: options.signal } : {}),
981
992
  })) {
982
993
  if (ev.type === "text_delta")
package/dist/store.js CHANGED
@@ -48,6 +48,7 @@ import { isKisoEvent } from "@vincemakes/kiso-core";
48
48
  import { readForkOrigin, readSessionName } from "./profile.js";
49
49
  import { forkSession } from "./fork.js";
50
50
  import { LockedError, nativeLockAdapter, } from "./lock-adapter.js";
51
+ import { isEnvironmentNote } from "./environment.js";
51
52
  /** History that does not parse as a contiguous kiso trajectory. */
52
53
  export class StoreCorruptionError extends Error {
53
54
  constructor(message) {
@@ -127,8 +128,10 @@ function contentText(content) {
127
128
  if (block === null || typeof block !== "object")
128
129
  continue;
129
130
  const b = block;
130
- if (b.type === "text" && typeof b.text === "string")
131
- parts.push(b.text);
131
+ if (b.type === "text" && typeof b.text === "string") {
132
+ if (!isEnvironmentNote(b.text))
133
+ parts.push(b.text); // the host's line about a folder, never the person's words
134
+ }
132
135
  else if (b.type === "image")
133
136
  parts.push("(image)");
134
137
  }
@@ -160,6 +163,8 @@ export class SessionStore {
160
163
  #fds = new Map();
161
164
  /** sessionId → the lock handle THIS instance holds (ADR-0050). */
162
165
  #lockHandles = new Map();
166
+ /** sessionId → what the last load read: the file it was (device, inode, size, mtime), the byte after its last committed line, and the records (load's tail read). */
167
+ #loaded = new Map();
163
168
  #lockAdapter;
164
169
  /** round 4 (adversarial): serialize concurrent acquireLock calls ON this instance —
165
170
  * two racing appends must not issue two acquisitions and fight each other. */
@@ -367,9 +372,92 @@ export class SessionStore {
367
372
  */
368
373
  load(sessionId) {
369
374
  const path = this.pathFor(sessionId);
370
- if (!existsSync(path))
375
+ if (!existsSync(path)) {
376
+ this.#loaded.delete(sessionId);
371
377
  return [];
372
- const raw = readFileSync(path, "utf8");
378
+ }
379
+ const fresh = this.#loadTail(sessionId, path);
380
+ if (fresh !== null)
381
+ return fresh;
382
+ const st = statSync(path);
383
+ const raw = readFileSync(path);
384
+ const records = this.#loadWhole(raw.toString("utf8"));
385
+ const end = raw.lastIndexOf(0x0a);
386
+ let lines = 0;
387
+ for (let i = 0; i <= end; i++)
388
+ if (raw[i] === 0x0a)
389
+ lines += 1;
390
+ this.#loaded.set(sessionId, { dev: st.dev, ino: st.ino, size: st.size, mtimeMs: st.mtimeMs, committed: end + 1, lines, records });
391
+ return records.slice();
392
+ }
393
+ /**
394
+ * The log read again only from where the last load stopped, when the file is the same file (device and inode) and has
395
+ * only grown past that point, which is how this store writes it: append-only, a torn tail truncated. Anything else (a
396
+ * shorter file, another inode, the same size with a new mtime, a last committed byte that is not a newline) is read whole
397
+ * by the strict path below, so a cached read never stands in for one that would have refused. Each caller gets its own
398
+ * array; the records themselves are shared and never mutated.
399
+ */
400
+ #loadTail(sessionId, path) {
401
+ const held = this.#loaded.get(sessionId);
402
+ if (held === undefined)
403
+ return null;
404
+ let st;
405
+ try {
406
+ st = statSync(path);
407
+ }
408
+ catch {
409
+ return null;
410
+ }
411
+ if (st.dev !== held.dev || st.ino !== held.ino || st.size < held.committed)
412
+ return null;
413
+ if (st.size === held.size && st.mtimeMs === held.mtimeMs)
414
+ return held.records.slice();
415
+ if (st.size === held.size)
416
+ return null;
417
+ const fd = openSync(path, "r");
418
+ let chunk;
419
+ try {
420
+ const from = held.committed - 1;
421
+ chunk = Buffer.alloc(st.size - from);
422
+ let got = 0;
423
+ while (got < chunk.length) {
424
+ const n = readSync(fd, chunk, got, chunk.length - got, from + got);
425
+ if (n === 0)
426
+ break;
427
+ got += n;
428
+ }
429
+ chunk = chunk.subarray(0, got);
430
+ }
431
+ finally {
432
+ closeSync(fd);
433
+ }
434
+ if (held.committed > 0 && chunk[0] !== 0x0a)
435
+ return null; // the byte before the new part must end a committed line
436
+ const body = held.committed > 0 ? chunk.subarray(1) : chunk;
437
+ const end = body.lastIndexOf(0x0a);
438
+ const records = held.records.slice();
439
+ let line = held.lines;
440
+ if (end >= 0) {
441
+ for (const text of body.subarray(0, end).toString("utf8").split("\n")) {
442
+ line += 1;
443
+ if (text === "")
444
+ continue;
445
+ let parsed;
446
+ try {
447
+ parsed = JSON.parse(text);
448
+ }
449
+ catch {
450
+ return null; // the strict path names it
451
+ }
452
+ if (!isRecord(parsed) || parsed.event.seq !== records.length)
453
+ return null;
454
+ records.push(parsed);
455
+ }
456
+ }
457
+ this.#loaded.set(sessionId, { dev: st.dev, ino: st.ino, size: st.size, mtimeMs: st.mtimeMs, committed: held.committed + (end >= 0 ? end + 1 : 0), lines: line, records });
458
+ return records.slice();
459
+ }
460
+ #loadWhole(raw) {
373
461
  const lines = raw.split("\n");
374
462
  const nonEmpty = [];
375
463
  for (let i = 0; i < lines.length; i++) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vincemakes/kiso-runtime",
3
- "version": "0.53.0",
3
+ "version": "0.54.1",
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.53.0"
28
+ "@vincemakes/kiso-core": "0.54.1"
29
29
  },
30
30
  "peerDependencies": {
31
- "@vincemakes/kiso-provider-anthropic": "0.53.0",
32
- "@vincemakes/kiso-provider-openai": "0.53.0",
33
- "@vincemakes/kiso-provider-openai-responses": "0.53.0"
31
+ "@vincemakes/kiso-provider-anthropic": "0.54.1",
32
+ "@vincemakes/kiso-provider-openai": "0.54.1",
33
+ "@vincemakes/kiso-provider-openai-responses": "0.54.1"
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.53.0",
47
+ "@vincemakes/kiso-evals": "0.54.1",
48
48
  "@types/node": "^26.1.2",
49
49
  "typescript": "^5.7.2",
50
50
  "vitest": "^3.0.0"