@vincemakes/kiso-code 0.40.3 → 0.40.4
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/config.d.ts +10 -0
- package/dist/config.js +23 -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/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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincemakes/kiso-code",
|
|
3
|
-
"version": "0.40.
|
|
3
|
+
"version": "0.40.4",
|
|
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.4",
|
|
22
|
+
"@vincemakes/kiso-core": "0.40.4",
|
|
23
|
+
"@vincemakes/kiso-evals": "0.40.4",
|
|
24
|
+
"@vincemakes/kiso-mcp-ext": "0.40.4",
|
|
25
|
+
"@vincemakes/kiso-provider-anthropic": "0.40.4",
|
|
26
|
+
"@vincemakes/kiso-provider-openai": "0.40.4",
|
|
27
|
+
"@vincemakes/kiso-provider-openai-responses": "0.40.4",
|
|
28
|
+
"@vincemakes/kiso-runtime": "0.40.4",
|
|
29
|
+
"@vincemakes/kiso-skills-ext": "0.40.4",
|
|
30
|
+
"@vincemakes/kiso-subagent-ext": "0.40.4",
|
|
31
|
+
"@vincemakes/kiso-task-ext": "0.40.4",
|
|
32
|
+
"@vincemakes/kiso-tools-node": "0.40.4",
|
|
33
|
+
"@vincemakes/kiso-tui": "0.40.4",
|
|
34
|
+
"@vincemakes/kiso-tui-cells": "0.40.4"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@types/node": "^26.1.2",
|