@vincemakes/kiso-code 0.50.1 → 0.51.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.
package/dist/chat.js CHANGED
@@ -1645,7 +1645,7 @@ export async function chat(session, faux, input, autoCompact, nav, seed) {
1645
1645
  dock.setLive(liveRow(compactingStatus(runGlyph, summary.rounds, summary.tokens, Math.round((Date.now() - summary.since) / 1000), W - 20, retryOnRow(), summary.progress, "auto"), ["esc stops"], W));
1646
1646
  return;
1647
1647
  }
1648
- dock.setLive(workingRow(runGlyph, runStart, runUsage.out, lastTokPerSec, rowWidth(), retryOnRow(), detachableNow()));
1648
+ dock.setLive(workingRow(runGlyph, runStart, runUsage.out, rowWidth(), retryOnRow(), detachableNow()));
1649
1649
  dock.setBar(barFor(session, { tokPerSec: lastTokPerSec, tasks: taskCountsNow() }));
1650
1650
  };
1651
1651
  // W19: under plan the idle row makes the posture unmistakable — the W4
package/dist/config.d.ts CHANGED
@@ -31,6 +31,20 @@
31
31
  * with an invalid value is likewise loud; unknown top-level keys are
32
32
  * ignored (forward compatibility).
33
33
  */
34
+ /** The reasoning-effort levels a profile may declare: the registry's own
35
+ * vocabulary (without `default`, which is "send nothing"). */
36
+ declare const EFFORT_LEVELS: readonly ["none", "minimal", "low", "medium", "high", "xhigh", "max", "ultra"];
37
+ type EffortLevel = (typeof EFFORT_LEVELS)[number];
38
+ /** A profile's own claim about its route's effort levels (the same kind of
39
+ * claim as `contextWindow`: yours, not ours). */
40
+ export interface ProfileEffort {
41
+ readonly levels: readonly EffortLevel[];
42
+ /** the level the route uses when none is sent; omit or null = unknown */
43
+ readonly default?: EffortLevel | null;
44
+ /** the route's spelling where it differs from the level's name, e.g.
45
+ * `{ "none": "off" }`; each key must be one of `levels` */
46
+ readonly values?: Readonly<Partial<Record<EffortLevel, string>>>;
47
+ }
34
48
  /** OR-1: `openai-responses` is a DIALECT, not a vendor — the same kind
35
49
  * drives the first-party Responses API and the ChatGPT subscription
36
50
  * backend, and which one it is follows the profile's baseUrl (and so
@@ -67,6 +81,15 @@ export interface ModelProfile {
67
81
  * registry, where every figure has to carry a source.
68
82
  */
69
83
  readonly contextWindow?: number;
84
+ /**
85
+ * The reasoning-effort levels this profile's route accepts, for a route
86
+ * the registry has no row for (a gateway, a new model). It enables the
87
+ * effort picker and the `/model <profile> <level>` form; the levels are
88
+ * YOUR claim. A route that refuses a level answers 400, and nothing here
89
+ * hides it. `kiso`'s own table wins nowhere over this: your declaration
90
+ * replaces the registry's levels for this model at this endpoint.
91
+ */
92
+ readonly effort?: ProfileEffort;
70
93
  /**
71
94
  * What this endpoint FORWARDS to, when `baseUrl` is a local proxy — a URL
72
95
  * (`https://gateway.example/v1`) or a name (`my gateway`). It never
@@ -88,6 +111,10 @@ export interface ModelProfile {
88
111
  */
89
112
  readonly headers?: Readonly<Record<string, string>>;
90
113
  }
114
+ /** Hand every profile's declared effort levels to the registry's lookup
115
+ * (called once, right after the config is merged). A profile without a
116
+ * declaration is not touched, and one that declares nothing changes nothing. */
117
+ export declare function applyEffortDeclarations(cfg: KisoConfig): void;
91
118
  export interface AutoCompactConfig {
92
119
  readonly thresholdRatio: number;
93
120
  }
@@ -228,3 +255,4 @@ export declare function resolveAutoCompact(merged: KisoConfig): AutoCompactConfi
228
255
  * gate, and it could not anyway, since an untrusted project's config is
229
256
  * never read. */
230
257
  export declare function resolveProjectTrustPolicy(merged: KisoConfig): "ask" | "never";
258
+ export {};
package/dist/config.js CHANGED
@@ -37,7 +37,10 @@ import { join, win32 } from "node:path";
37
37
  import { kisoHome } from "./state.js";
38
38
  import { MODE_VALUES, parseMode } from "./mode.js";
39
39
  import { AuthError, effectiveBaseUrl, endpointCredentialId, getCredential, providerIdOf } from "./auth/credentials.js";
40
- import { BUILTIN_MANIFESTS } from "@vincemakes/kiso-runtime/internal";
40
+ import { BUILTIN_MANIFESTS, declareEffort } from "@vincemakes/kiso-runtime/internal";
41
+ /** The reasoning-effort levels a profile may declare: the registry's own
42
+ * vocabulary (without `default`, which is "send nothing"). */
43
+ const EFFORT_LEVELS = ["none", "minimal", "low", "medium", "high", "xhigh", "max", "ultra"];
41
44
  /** Header names a profile may not set: credentials (a key never lives in the
42
45
  * config file) and the framing the adapter owns. */
43
46
  const REFUSED_HEADERS = new Set(["authorization", "proxy-authorization", "x-api-key", "api-key", "cookie", "host", "content-length", "content-type", "transfer-encoding", "connection"]);
@@ -59,6 +62,61 @@ function parseHeaders(field, raw, fail) {
59
62
  }
60
63
  return out;
61
64
  }
65
+ function parseEffort(field, raw, fail) {
66
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw))
67
+ fail(field, "expected an object: { levels: [...], default?: ..., values?: { ... } }");
68
+ const o = raw;
69
+ for (const k of Object.keys(o))
70
+ if (k !== "levels" && k !== "default" && k !== "values")
71
+ fail(`${field}.${k}`, "unknown key (levels, default and values are the only ones)");
72
+ const known = (v) => typeof v === "string" && EFFORT_LEVELS.includes(v);
73
+ if (!Array.isArray(o.levels) || o.levels.length === 0 || o.levels.length > EFFORT_LEVELS.length)
74
+ fail(`${field}.levels`, `expected 1 to ${EFFORT_LEVELS.length} levels`);
75
+ const levels = [];
76
+ for (const l of o.levels) {
77
+ if (!known(l))
78
+ fail(`${field}.levels`, `${JSON.stringify(l)} is not a level (${EFFORT_LEVELS.join(", ")})`);
79
+ if (levels.includes(l))
80
+ fail(`${field}.levels`, `${l} is listed twice`);
81
+ levels.push(l);
82
+ }
83
+ let def;
84
+ if (o.default !== undefined && o.default !== null) {
85
+ if (!known(o.default) || !levels.includes(o.default))
86
+ fail(`${field}.default`, "expected null or one of the listed levels");
87
+ def = o.default;
88
+ }
89
+ else if (o.default === null)
90
+ def = null;
91
+ let values;
92
+ if (o.values !== undefined) {
93
+ if (o.values === null || typeof o.values !== "object" || Array.isArray(o.values))
94
+ fail(`${field}.values`, "expected an object of level names to the route's spelling");
95
+ values = {};
96
+ for (const [k, v] of Object.entries(o.values)) {
97
+ if (!known(k) || !levels.includes(k))
98
+ fail(`${field}.values.${k}`, "expected one of the listed levels");
99
+ if (typeof v !== "string" || !/^[A-Za-z0-9_.-]{1,24}$/.test(v))
100
+ fail(`${field}.values.${k}`, "expected a short word (letters, digits, . _ -)");
101
+ values[k] = v;
102
+ }
103
+ }
104
+ return { levels, ...(def !== undefined ? { default: def } : {}), ...(values !== undefined ? { values } : {}) };
105
+ }
106
+ /** Hand every profile's declared effort levels to the registry's lookup
107
+ * (called once, right after the config is merged). A profile without a
108
+ * declaration is not touched, and one that declares nothing changes nothing. */
109
+ export function applyEffortDeclarations(cfg) {
110
+ for (const profile of Object.values(cfg.models ?? {})) {
111
+ if (profile.effort === undefined)
112
+ continue;
113
+ declareEffort(profile.model, profile.baseUrl, {
114
+ levels: profile.effort.levels,
115
+ default: profile.effort.default ?? null,
116
+ ...(profile.effort.values !== undefined ? { values: profile.effort.values } : {}),
117
+ });
118
+ }
119
+ }
62
120
  const KINDS = ["openai-compat", "anthropic", "openai-responses"];
63
121
  export class ConfigError extends Error {
64
122
  }
@@ -192,6 +250,7 @@ export function parseConfig(text, source) {
192
250
  if (p.upstream !== undefined && (typeof p.upstream !== "string" || p.upstream.trim() === ""))
193
251
  fail(`models.${name}.upstream`, "expected the URL or name of what this endpoint forwards to");
194
252
  const headers = p.headers === undefined ? undefined : parseHeaders(`models.${name}.headers`, p.headers, fail);
253
+ const effort = p.effort === undefined ? undefined : parseEffort(`models.${name}.effort`, p.effort, fail);
195
254
  models[name] = {
196
255
  kind: p.kind,
197
256
  model: p.model,
@@ -202,6 +261,7 @@ export function parseConfig(text, source) {
202
261
  ...(typeof p.contextWindow === "number" ? { contextWindow: p.contextWindow } : {}),
203
262
  ...(typeof p.upstream === "string" ? { upstream: p.upstream.trim() } : {}),
204
263
  ...(headers !== undefined ? { headers } : {}),
264
+ ...(effort !== undefined ? { effort } : {}),
205
265
  };
206
266
  }
207
267
  out.models = models;
@@ -14,7 +14,7 @@ import { migrationNotice, pendingLegacyIds, planMigration, runMigration } from "
14
14
  import { askUi, resolveProjectTrust } from "./trust-ui.js";
15
15
  import { isFirstRun, scaffoldFirstRun } from "./first-run.js";
16
16
  import { fauxSkip, readFauxScript } from "./faux-glue.js";
17
- import { loadProjectConfig, loadUserConfig, mergeConfigs, resolveContextWindow, resolveModel } from "./config.js";
17
+ import { applyEffortDeclarations, loadProjectConfig, loadUserConfig, mergeConfigs, resolveContextWindow, resolveModel } from "./config.js";
18
18
  import { builtInLayer } from "./builtin.js";
19
19
  import { recordLearnedWindow, useLearnedWindows } from "./learned-windows.js";
20
20
  import { compactionDiscardedNotice, contextWindowTokens, knownContextWindow, unknownWindowNotice, windowLearnedNotice } from "./chat.js";
@@ -163,6 +163,9 @@ export async function createCodingAgent(sessionId, input, modelFlag) {
163
163
  const userCfg = loadUserConfig();
164
164
  const projectCfg = loadProjectConfig(process.cwd(), project !== null);
165
165
  const merged = mergeConfigs(userCfg, projectCfg);
166
+ // a profile's own effort levels reach the registry's lookup before the
167
+ // picker, `/model <profile> <level>` or a resumed session reads them
168
+ applyEffortDeclarations(merged);
166
169
  // 0.40.6: /settings names each value's layer from these
167
170
  settingsLayers.user = userCfg;
168
171
  settingsLayers.project = projectCfg;
package/dist/dispatch.js CHANGED
@@ -100,7 +100,9 @@ function effortAxis(p) {
100
100
  // cursor could NOT land where the previous selection asked.
101
101
  ...(carried !== undefined && carried !== "default" && carriedIdx < 0 && defaultIdx >= 0
102
102
  ? { levelNote: `effort ${carried} \u2192 ${levels[defaultIdx]}: this model's default (it has no ${carried})` }
103
- : {}),
103
+ : effort.declared === true
104
+ ? { levelNote: "levels declared in your profile" }
105
+ : {}),
104
106
  };
105
107
  }
106
108
  /** What signs a profile in, for the listing: `stored key` when a key in
package/dist/index.js CHANGED
File without changes
package/dist/resume.js CHANGED
@@ -32,7 +32,7 @@ export async function resume(session, prompt, faux, input) {
32
32
  runUsage = u;
33
33
  if (!dock.active)
34
34
  return;
35
- dock.setLive(workingRow(runGlyph, runStart, u.out, null, width(), retryOnRow()));
35
+ dock.setLive(workingRow(runGlyph, runStart, u.out, width(), retryOnRow()));
36
36
  dock.setBar(barFor(session, { tokPerSec: null }));
37
37
  };
38
38
  const paintIdle = () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vincemakes/kiso-code",
3
- "version": "0.50.1",
3
+ "version": "0.51.1",
4
4
  "description": "kiso-code \u2014 the coding agent on kiso, the durable runtime for AI agents: kiso chat / kiso resume / kiso sessions.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -18,19 +18,19 @@
18
18
  "test": "vitest run"
19
19
  },
20
20
  "dependencies": {
21
- "@vincemakes/kiso-ask-ext": "0.50.1",
22
- "@vincemakes/kiso-core": "0.50.1",
23
- "@vincemakes/kiso-evals": "0.50.1",
24
- "@vincemakes/kiso-mcp-ext": "0.50.1",
25
- "@vincemakes/kiso-provider-anthropic": "0.50.1",
26
- "@vincemakes/kiso-provider-openai": "0.50.1",
27
- "@vincemakes/kiso-provider-openai-responses": "0.50.1",
28
- "@vincemakes/kiso-runtime": "0.50.1",
29
- "@vincemakes/kiso-skills-ext": "0.50.1",
30
- "@vincemakes/kiso-subagent-ext": "0.50.1",
31
- "@vincemakes/kiso-tools-node": "0.50.1",
32
- "@vincemakes/kiso-tui": "0.50.1",
33
- "@vincemakes/kiso-tui-cells": "0.50.1"
21
+ "@vincemakes/kiso-ask-ext": "0.51.1",
22
+ "@vincemakes/kiso-core": "0.51.1",
23
+ "@vincemakes/kiso-evals": "0.51.1",
24
+ "@vincemakes/kiso-mcp-ext": "0.51.1",
25
+ "@vincemakes/kiso-provider-anthropic": "0.51.1",
26
+ "@vincemakes/kiso-provider-openai": "0.51.1",
27
+ "@vincemakes/kiso-provider-openai-responses": "0.51.1",
28
+ "@vincemakes/kiso-runtime": "0.51.1",
29
+ "@vincemakes/kiso-skills-ext": "0.51.1",
30
+ "@vincemakes/kiso-subagent-ext": "0.51.1",
31
+ "@vincemakes/kiso-tools-node": "0.51.1",
32
+ "@vincemakes/kiso-tui": "0.51.1",
33
+ "@vincemakes/kiso-tui-cells": "0.51.1"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@types/node": "^26.1.2",