@vincemakes/kiso-code 0.40.3 → 0.40.5
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/auth/adapter-options.d.ts +6 -0
- package/dist/auth/adapter-options.js +24 -0
- package/dist/chat.js +8 -1
- package/dist/config.d.ts +10 -0
- package/dist/config.js +23 -0
- package/dist/dispatch.js +5 -1
- package/dist/stale-version.d.ts +14 -0
- package/dist/stale-version.js +52 -0
- package/package.json +15 -15
|
@@ -18,5 +18,11 @@ export interface AdapterOptions {
|
|
|
18
18
|
readonly accountId: string;
|
|
19
19
|
}>;
|
|
20
20
|
readonly promptCacheKey?: string;
|
|
21
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
21
22
|
}
|
|
23
|
+
/** The profile's headers with `{session}` replaced by the session id. A
|
|
24
|
+
* header that names `{session}` when there is no session (`kiso sessions`,
|
|
25
|
+
* which streams nothing) is left out, never sent with the placeholder in
|
|
26
|
+
* it. Undefined when nothing is left. */
|
|
27
|
+
export declare function expandProfileHeaders(headers: Readonly<Record<string, string>> | undefined, sessionId: string | undefined): Readonly<Record<string, string>> | undefined;
|
|
22
28
|
export declare function adapterOptionsFor(profile: ModelProfile, auth: AdapterAuth, sessionId?: string): AdapterOptions;
|
|
@@ -33,6 +33,25 @@
|
|
|
33
33
|
*/
|
|
34
34
|
import { effectiveBaseUrl } from "./credentials.js";
|
|
35
35
|
import { oauthTokenThunk } from "./token.js";
|
|
36
|
+
/** The profile's headers with `{session}` replaced by the session id. A
|
|
37
|
+
* header that names `{session}` when there is no session (`kiso sessions`,
|
|
38
|
+
* which streams nothing) is left out, never sent with the placeholder in
|
|
39
|
+
* it. Undefined when nothing is left. */
|
|
40
|
+
export function expandProfileHeaders(headers, sessionId) {
|
|
41
|
+
if (headers === undefined)
|
|
42
|
+
return undefined;
|
|
43
|
+
const out = {};
|
|
44
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
45
|
+
if (value.includes("{session}")) {
|
|
46
|
+
if (sessionId === undefined)
|
|
47
|
+
continue;
|
|
48
|
+
out[name] = value.split("{session}").join(sessionId);
|
|
49
|
+
}
|
|
50
|
+
else
|
|
51
|
+
out[name] = value;
|
|
52
|
+
}
|
|
53
|
+
return Object.keys(out).length === 0 ? undefined : out;
|
|
54
|
+
}
|
|
36
55
|
export function adapterOptionsFor(profile, auth, sessionId) {
|
|
37
56
|
// OR-1: exactly one sign-in shape reaches the adapter. An OAuth profile
|
|
38
57
|
// has no key to pass — it passes the thunk the adapter re-resolves per
|
|
@@ -43,6 +62,7 @@ export function adapterOptionsFor(profile, auth, sessionId) {
|
|
|
43
62
|
// own environment variable, and a profile with no baseUrl then sent the
|
|
44
63
|
// stored vendor key wherever that variable pointed.
|
|
45
64
|
const url = effectiveBaseUrl(profile.kind, profile.baseUrl);
|
|
65
|
+
const headers = expandProfileHeaders(profile.headers, sessionId);
|
|
46
66
|
return {
|
|
47
67
|
...credential,
|
|
48
68
|
...(url !== undefined ? { baseUrl: url } : {}),
|
|
@@ -53,5 +73,9 @@ export function adapterOptionsFor(profile, auth, sessionId) {
|
|
|
53
73
|
// cache.
|
|
54
74
|
...(sessionId !== undefined ? { promptCacheKey: sessionId } : {}),
|
|
55
75
|
...(profile.promptCaching !== undefined ? { promptCaching: profile.promptCaching } : {}),
|
|
76
|
+
// The endpoint's own headers (a gateway's session header, say), with
|
|
77
|
+
// the session id where the profile wrote `{session}` — the same id
|
|
78
|
+
// as the cache key above, so one conversation is one lane end to end.
|
|
79
|
+
...(headers !== undefined ? { headers } : {}),
|
|
56
80
|
};
|
|
57
81
|
}
|
package/dist/chat.js
CHANGED
|
@@ -14,8 +14,9 @@ import { canonicalizeUsage } from "@vincemakes/kiso-runtime";
|
|
|
14
14
|
import { canonicalizeUsageForModel, requestBudget } from "@vincemakes/kiso-runtime/internal";
|
|
15
15
|
import { dispatch, abortBangCommand } from "./dispatch.js";
|
|
16
16
|
import { paintWindowTitle } from "./window-title.js";
|
|
17
|
-
import { agentBaseUrl, agentModel, body, bodyLog, configuredWindow, dock, retryOnRow, retryShown, setRetryShown, floorOn, protectedFiles, upstreamOf } from "./state.js";
|
|
17
|
+
import { agentBaseUrl, agentModel, body, bodyLog, configuredWindow, dock, retryOnRow, retryShown, setRetryShown, floorOn, protectedFiles, upstreamOf, VERSION } from "./state.js";
|
|
18
18
|
import { attachImages } from "./attachments.js";
|
|
19
|
+
import { installedVersion, staleVersionNotice } from "./stale-version.js";
|
|
19
20
|
import { learnedWindowFor } from "./learned-windows.js";
|
|
20
21
|
import { lookupContextWindow, lookupModelMetadata } from "@vincemakes/kiso-runtime/internal";
|
|
21
22
|
import { addDontAskAgainRule, askPanel, fixHintFor, pendingAsk, resolveUncertains } from "./trust-ui.js";
|
|
@@ -1365,6 +1366,12 @@ export async function chat(session, faux, input, autoCompact, nav, seed) {
|
|
|
1365
1366
|
stopSpinner();
|
|
1366
1367
|
paintIdle();
|
|
1367
1368
|
currentRun = null;
|
|
1369
|
+
// 0.40.5: the kiso on disk may no longer be the one this
|
|
1370
|
+
// session runs (an upgrade since it started) — said once per
|
|
1371
|
+
// installed version (stale-version.ts).
|
|
1372
|
+
const stale = staleVersionNotice(installedVersion(), VERSION, session.id);
|
|
1373
|
+
if (stale !== null)
|
|
1374
|
+
body.notice(stale);
|
|
1368
1375
|
// round 8: a faux script that ran out of declared turns exits
|
|
1369
1376
|
// loudly with a non-zero status — never a silent status 0.
|
|
1370
1377
|
// round 4 (adversarial): the exhaustion is a CONTROLLED rejection of
|
package/dist/config.d.ts
CHANGED
|
@@ -75,6 +75,16 @@ export interface ModelProfile {
|
|
|
75
75
|
* the registry looks for this model's window when `baseUrl` has no row.
|
|
76
76
|
*/
|
|
77
77
|
readonly upstream?: string;
|
|
78
|
+
/**
|
|
79
|
+
* Headers the endpoint needs on every request — a gateway that routes a
|
|
80
|
+
* conversation by a session header, say. `{session}` in a value becomes
|
|
81
|
+
* the kiso session's id, so one conversation keeps one id across /model
|
|
82
|
+
* and /resume, and two conversations never share one. Names are
|
|
83
|
+
* lower-cased. A credential header is refused by name: a key never lives
|
|
84
|
+
* in this file (`apiKeyEnv` and `kiso login` are the doors), and the
|
|
85
|
+
* framing headers belong to the adapter.
|
|
86
|
+
*/
|
|
87
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
78
88
|
}
|
|
79
89
|
export interface AutoCompactConfig {
|
|
80
90
|
readonly thresholdRatio: number;
|
package/dist/config.js
CHANGED
|
@@ -34,6 +34,27 @@ import { join } from "node:path";
|
|
|
34
34
|
import { kisoHome } from "./state.js";
|
|
35
35
|
import { AuthError, getCredential, providerIdOf } from "./auth/credentials.js";
|
|
36
36
|
import { BUILTIN_MANIFESTS } from "@vincemakes/kiso-runtime/internal";
|
|
37
|
+
/** Header names a profile may not set: credentials (a key never lives in the
|
|
38
|
+
* config file) and the framing the adapter owns. */
|
|
39
|
+
const REFUSED_HEADERS = new Set(["authorization", "proxy-authorization", "x-api-key", "api-key", "cookie", "host", "content-length", "content-type", "transfer-encoding", "connection"]);
|
|
40
|
+
function parseHeaders(field, raw, fail) {
|
|
41
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw))
|
|
42
|
+
fail(field, "expected an object of header names to string values");
|
|
43
|
+
const out = {};
|
|
44
|
+
for (const [name, value] of Object.entries(raw)) {
|
|
45
|
+
if (!/^[A-Za-z0-9-]+$/.test(name))
|
|
46
|
+
fail(`${field}.${name}`, "expected a header name of letters, digits and dashes");
|
|
47
|
+
const lower = name.toLowerCase();
|
|
48
|
+
if (REFUSED_HEADERS.has(lower))
|
|
49
|
+
fail(`${field}.${name}`, "a credential or framing header cannot be set here — the key comes from apiKeyEnv or kiso login");
|
|
50
|
+
if (lower in out)
|
|
51
|
+
fail(`${field}.${name}`, "named twice (header names are case-insensitive)");
|
|
52
|
+
if (typeof value !== "string" || /[\r\n\0]/.test(value))
|
|
53
|
+
fail(`${field}.${name}`, "expected a one-line string value");
|
|
54
|
+
out[lower] = value;
|
|
55
|
+
}
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
37
58
|
const KINDS = ["openai-compat", "anthropic", "openai-responses"];
|
|
38
59
|
const MODES_LIST = ["manual", "default", "accept-edits", "plan", "bypass", "dontAsk"];
|
|
39
60
|
export class ConfigError extends Error {
|
|
@@ -149,6 +170,7 @@ export function parseConfig(text, source) {
|
|
|
149
170
|
fail(`models.${name}.contextWindow`, "expected a positive token count");
|
|
150
171
|
if (p.upstream !== undefined && (typeof p.upstream !== "string" || p.upstream.trim() === ""))
|
|
151
172
|
fail(`models.${name}.upstream`, "expected the URL or name of what this endpoint forwards to");
|
|
173
|
+
const headers = p.headers === undefined ? undefined : parseHeaders(`models.${name}.headers`, p.headers, fail);
|
|
152
174
|
models[name] = {
|
|
153
175
|
kind: p.kind,
|
|
154
176
|
model: p.model,
|
|
@@ -158,6 +180,7 @@ export function parseConfig(text, source) {
|
|
|
158
180
|
...(typeof p.streamIdleMs === "number" ? { streamIdleMs: p.streamIdleMs } : {}),
|
|
159
181
|
...(typeof p.contextWindow === "number" ? { contextWindow: p.contextWindow } : {}),
|
|
160
182
|
...(typeof p.upstream === "string" ? { upstream: p.upstream.trim() } : {}),
|
|
183
|
+
...(headers !== undefined ? { headers } : {}),
|
|
161
184
|
};
|
|
162
185
|
}
|
|
163
186
|
out.models = models;
|
package/dist/dispatch.js
CHANGED
|
@@ -9,9 +9,10 @@ import { buildAdapter, lookupModelMetadata, resolveContinuationScope, resolveRea
|
|
|
9
9
|
import { MODES, MODE_NOTE, OFFERED_MODES, getMode, setMode } from "./mode.js";
|
|
10
10
|
import { clipboardWrite, lastAnswer } from "./clipboard.js";
|
|
11
11
|
import { protectedBangReason, protectedShellVerdict } from "./protected-shell.js";
|
|
12
|
-
import { agentBaseUrl, currentProfileName, setCurrentProfileName, currentModelName, agentModel, body, bodyLog, codingToolOptions, protectedFiles, kisoHome, configModels, dock, lastBinding, loadedSkillsCatalog, mergedConfig, readContextLedger, retryOnRow, sessionsDir, setAgentModel, setConfiguredWindow, setCurrentModelName, setModelChoice, setRetryShown, upstreamOf, setLastBinding } from "./state.js";
|
|
12
|
+
import { agentBaseUrl, currentProfileName, setCurrentProfileName, currentModelName, agentModel, body, bodyLog, codingToolOptions, protectedFiles, kisoHome, configModels, dock, lastBinding, loadedSkillsCatalog, mergedConfig, readContextLedger, retryOnRow, sessionsDir, setAgentModel, setConfiguredWindow, setCurrentModelName, setModelChoice, setRetryShown, upstreamOf, VERSION, setLastBinding } from "./state.js";
|
|
13
13
|
import { adapterOptionsFor } from "./auth/adapter-options.js";
|
|
14
14
|
import { profileProviderLabel, providerLabel } from "./provider-label.js";
|
|
15
|
+
import { installedVersion, versionStatusLine } from "./stale-version.js";
|
|
15
16
|
import { queuedSwitchLines } from "./state.js";
|
|
16
17
|
import { contextWindowTokens, microcompactThresholdFor, startStatusSpinner, statedContextWindow, windowSourceNote } from "./chat.js";
|
|
17
18
|
import { authForProfile, directWriteProfile, profileAvailable, resolveContextWindow, unavailableReason } from "./config.js";
|
|
@@ -514,6 +515,9 @@ export function dispatch(line, ctx) {
|
|
|
514
515
|
// variable; until then, a label that cannot lie.)
|
|
515
516
|
const profileOf = currentProfileName === null ? "" : ` · profile ${currentProfileName}`;
|
|
516
517
|
bodyLog(`model ${agentModel}${providerLabel(agentBaseUrl, upstreamOf(agentBaseUrl))}${profileOf}`);
|
|
518
|
+
// 0.40.5: the version this session RUNS, and the installed one when
|
|
519
|
+
// an upgrade (or a rollback) since start-up made them differ.
|
|
520
|
+
bodyLog(versionStatusLine(installedVersion(), VERSION));
|
|
517
521
|
ctx.input.prompt();
|
|
518
522
|
});
|
|
519
523
|
return;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** The version of the kiso installed where this one was loaded from, read
|
|
2
|
+
* now — null on any failure, never a guess. KISO_INSTALLED_PACKAGE_JSON
|
|
3
|
+
* names another file: the test rigs' knob (like KISO_FAUX_SCRIPT), so an
|
|
4
|
+
* end-to-end run can "upgrade" underneath a live session without touching
|
|
5
|
+
* the checkout's own package.json. */
|
|
6
|
+
export declare function installedVersion(pkgPath?: string): string | null;
|
|
7
|
+
/** The transcript notice, once per installed version that differs from the
|
|
8
|
+
* running one (a newer install, or a rollback); null otherwise. */
|
|
9
|
+
export declare function staleVersionNotice(installed: string | null, running: string, sessionId: string): string | null;
|
|
10
|
+
/** /status's version line: the running version, and the installed one when
|
|
11
|
+
* they differ. */
|
|
12
|
+
export declare function versionStatusLine(installed: string | null, running: string): string;
|
|
13
|
+
/** Tests: forget which version was noticed. */
|
|
14
|
+
export declare function resetStaleVersionNotice(): void;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 0.40.5 — a session says when the kiso on disk is not the kiso it runs.
|
|
3
|
+
*
|
|
4
|
+
* The owner, 2026-09-23: "I am on 0.40.3 — why does edit_file still fail?"
|
|
5
|
+
* The session's process had started at 13:03 on 0.40.2; 0.40.3 was
|
|
6
|
+
* installed at ~14:05. The process kept the code it loaded, so its
|
|
7
|
+
* edit_file still refused overlapping hunks, while `kiso --version` in
|
|
8
|
+
* another shell printed the version ON DISK. Nothing in the session said
|
|
9
|
+
* otherwise. A process that loads a module lazily after an upgrade (a
|
|
10
|
+
* provider on its first /model switch) would also mix the new version with
|
|
11
|
+
* the old — the notice is the cue to restart before that.
|
|
12
|
+
*
|
|
13
|
+
* `VERSION` (state.ts) is read once at start-up from the package.json next
|
|
14
|
+
* to the build; a global install replaces that file, so reading it AGAIN
|
|
15
|
+
* sees what a new start would run. One small read per turn and per
|
|
16
|
+
* /status; no timer, no watcher, no network.
|
|
17
|
+
*/
|
|
18
|
+
import { readFileSync } from "node:fs";
|
|
19
|
+
import { dirname, join } from "node:path";
|
|
20
|
+
import { fileURLToPath } from "node:url";
|
|
21
|
+
/** The version of the kiso installed where this one was loaded from, read
|
|
22
|
+
* now — null on any failure, never a guess. KISO_INSTALLED_PACKAGE_JSON
|
|
23
|
+
* names another file: the test rigs' knob (like KISO_FAUX_SCRIPT), so an
|
|
24
|
+
* end-to-end run can "upgrade" underneath a live session without touching
|
|
25
|
+
* the checkout's own package.json. */
|
|
26
|
+
export function installedVersion(pkgPath = process.env.KISO_INSTALLED_PACKAGE_JSON ?? join(dirname(fileURLToPath(import.meta.url)), "..", "package.json")) {
|
|
27
|
+
try {
|
|
28
|
+
const v = JSON.parse(readFileSync(pkgPath, "utf8")).version;
|
|
29
|
+
return typeof v === "string" && v !== "" ? v : null;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
let lastNoticed = null;
|
|
36
|
+
/** The transcript notice, once per installed version that differs from the
|
|
37
|
+
* running one (a newer install, or a rollback); null otherwise. */
|
|
38
|
+
export function staleVersionNotice(installed, running, sessionId) {
|
|
39
|
+
if (installed === null || installed === running || running === "?" || installed === lastNoticed)
|
|
40
|
+
return null;
|
|
41
|
+
lastNoticed = installed;
|
|
42
|
+
return `✦ kiso ${installed} is installed — this session runs ${running}; exit and resume it (kiso resume ${sessionId}) to use it`;
|
|
43
|
+
}
|
|
44
|
+
/** /status's version line: the running version, and the installed one when
|
|
45
|
+
* they differ. */
|
|
46
|
+
export function versionStatusLine(installed, running) {
|
|
47
|
+
return installed === null || installed === running ? `version ${running}` : `version ${running} (running) · ${installed} installed — restart to use it`;
|
|
48
|
+
}
|
|
49
|
+
/** Tests: forget which version was noticed. */
|
|
50
|
+
export function resetStaleVersionNotice() {
|
|
51
|
+
lastNoticed = null;
|
|
52
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincemakes/kiso-code",
|
|
3
|
-
"version": "0.40.
|
|
3
|
+
"version": "0.40.5",
|
|
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,20 +18,20 @@
|
|
|
18
18
|
"test": "vitest run"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@vincemakes/kiso-ask-ext": "0.40.
|
|
22
|
-
"@vincemakes/kiso-core": "0.40.
|
|
23
|
-
"@vincemakes/kiso-evals": "0.40.
|
|
24
|
-
"@vincemakes/kiso-mcp-ext": "0.40.
|
|
25
|
-
"@vincemakes/kiso-provider-anthropic": "0.40.
|
|
26
|
-
"@vincemakes/kiso-provider-openai": "0.40.
|
|
27
|
-
"@vincemakes/kiso-provider-openai-responses": "0.40.
|
|
28
|
-
"@vincemakes/kiso-runtime": "0.40.
|
|
29
|
-
"@vincemakes/kiso-skills-ext": "0.40.
|
|
30
|
-
"@vincemakes/kiso-subagent-ext": "0.40.
|
|
31
|
-
"@vincemakes/kiso-task-ext": "0.40.
|
|
32
|
-
"@vincemakes/kiso-tools-node": "0.40.
|
|
33
|
-
"@vincemakes/kiso-tui": "0.40.
|
|
34
|
-
"@vincemakes/kiso-tui-cells": "0.40.
|
|
21
|
+
"@vincemakes/kiso-ask-ext": "0.40.5",
|
|
22
|
+
"@vincemakes/kiso-core": "0.40.5",
|
|
23
|
+
"@vincemakes/kiso-evals": "0.40.5",
|
|
24
|
+
"@vincemakes/kiso-mcp-ext": "0.40.5",
|
|
25
|
+
"@vincemakes/kiso-provider-anthropic": "0.40.5",
|
|
26
|
+
"@vincemakes/kiso-provider-openai": "0.40.5",
|
|
27
|
+
"@vincemakes/kiso-provider-openai-responses": "0.40.5",
|
|
28
|
+
"@vincemakes/kiso-runtime": "0.40.5",
|
|
29
|
+
"@vincemakes/kiso-skills-ext": "0.40.5",
|
|
30
|
+
"@vincemakes/kiso-subagent-ext": "0.40.5",
|
|
31
|
+
"@vincemakes/kiso-task-ext": "0.40.5",
|
|
32
|
+
"@vincemakes/kiso-tools-node": "0.40.5",
|
|
33
|
+
"@vincemakes/kiso-tui": "0.40.5",
|
|
34
|
+
"@vincemakes/kiso-tui-cells": "0.40.5"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@types/node": "^26.1.2",
|