@byok-sdk/keys 0.4.3 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -0
- package/dist/bin/pi-provider-launcher.js +121 -26
- package/dist/bin/pi-provider-launcher.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +71 -7
- package/dist/index.js.map +1 -1
- package/dist/pi-model-config.d.ts +51 -0
- package/dist/pi-provider-launcher-core.d.ts +2 -0
- package/dist/provider-profile.d.ts +47 -0
- package/dist/registry.d.ts +4 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
# @byok-sdk/keys
|
|
2
2
|
|
|
3
|
+
Pi launcher configuration in the unpublished 0.5.0 candidate is explicit.
|
|
4
|
+
Set `pi_model` on `ProviderRegistry.configure` for profiles used by Pi:
|
|
5
|
+
|
|
6
|
+
```ts
|
|
7
|
+
const pi_model = {
|
|
8
|
+
contextWindow: 1_000_000,
|
|
9
|
+
maxTokens: 131_072,
|
|
10
|
+
reasoning: true,
|
|
11
|
+
thinkingLevel: 'low',
|
|
12
|
+
thinkingLevelMap: {
|
|
13
|
+
off: null, minimal: null, low: 'low', medium: null,
|
|
14
|
+
high: 'high', xhigh: null, max: 'max',
|
|
15
|
+
},
|
|
16
|
+
compat: {
|
|
17
|
+
supportsStore: false, supportsDeveloperRole: false,
|
|
18
|
+
supportsReasoningEffort: true, supportsUsageInStreaming: true,
|
|
19
|
+
maxTokensField: 'max_tokens', thinkingFormat: 'zai', zaiToolStream: true,
|
|
20
|
+
},
|
|
21
|
+
} satisfies PiModelConfig;
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
These illustrate declared GLM-5.3-Flash/Pi model settings, not Host input budgets
|
|
25
|
+
or automatic defaults. Import `PiModelConfig` from this package. The bounded
|
|
26
|
+
`PiModelConfigSchema` rejects unknown fields, incomplete level maps and
|
|
27
|
+
unsupported selected levels; it accepts no identity, URL, header or secret.
|
|
28
|
+
Use the exact provider's authoritative configuration. Missing `pi_model`
|
|
29
|
+
permits direct provider transports but rejects Pi admission and launch.
|
|
30
|
+
Configuration changes alter the profile hash and registry revision, fencing
|
|
31
|
+
stale tasks before credential access. The launcher projects the selected
|
|
32
|
+
thinking level through its own argv, not delegated overrides.
|
|
33
|
+
|
|
34
|
+
The SQLite profile schema changes in this candidate. Existing stores are
|
|
35
|
+
rejected and preserved: explicitly provision a separate current-schema store
|
|
36
|
+
after reviewing the old configuration. Do not delete an old store or infer its
|
|
37
|
+
missing model settings. No live-store conversion is performed by the SDK.
|
|
38
|
+
|
|
3
39
|
Key-based BYOK: a validated provider profile, credential-backed auth headers, and
|
|
4
40
|
direct transports to OpenAI-compatible and Anthropic providers.
|
|
5
41
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { spawn } from 'child_process';
|
|
3
3
|
import { promises, mkdirSync, existsSync, chmodSync } from 'fs';
|
|
4
4
|
import os from 'os';
|
|
5
|
-
import path2, { dirname } from 'path';
|
|
5
|
+
import path2, { isAbsolute, dirname } from 'path';
|
|
6
6
|
import { z } from 'zod';
|
|
7
7
|
import { createHash } from 'crypto';
|
|
8
8
|
import { createRequire } from 'module';
|
|
@@ -193,6 +193,54 @@ function isPrivateNetworkLiteral(hostname) {
|
|
|
193
193
|
}
|
|
194
194
|
return parts[0] === 10 || parts[0] === 127 || parts[0] === 169 && parts[1] === 254 || parts[0] === 172 && (parts[1] ?? 0) >= 16 && (parts[1] ?? 0) <= 31 || parts[0] === 192 && parts[1] === 168;
|
|
195
195
|
}
|
|
196
|
+
var PI_THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
|
|
197
|
+
var effort = z.string().min(1).max(64).regex(/^[a-zA-Z0-9_-]+$/u).nullable();
|
|
198
|
+
var PiModelConfigSchema = z.object({
|
|
199
|
+
contextWindow: z.number().int().positive().max(Number.MAX_SAFE_INTEGER),
|
|
200
|
+
maxTokens: z.number().int().positive().max(Number.MAX_SAFE_INTEGER),
|
|
201
|
+
reasoning: z.boolean(),
|
|
202
|
+
thinkingLevel: z.enum(PI_THINKING_LEVELS),
|
|
203
|
+
thinkingLevelMap: z.object({
|
|
204
|
+
off: effort,
|
|
205
|
+
minimal: effort,
|
|
206
|
+
low: effort,
|
|
207
|
+
medium: effort,
|
|
208
|
+
high: effort,
|
|
209
|
+
xhigh: effort,
|
|
210
|
+
max: effort
|
|
211
|
+
}).strict(),
|
|
212
|
+
compat: z.object({
|
|
213
|
+
supportsStore: z.boolean().optional(),
|
|
214
|
+
supportsDeveloperRole: z.boolean().optional(),
|
|
215
|
+
supportsReasoningEffort: z.boolean().optional(),
|
|
216
|
+
supportsUsageInStreaming: z.boolean().optional(),
|
|
217
|
+
maxTokensField: z.enum(["max_completion_tokens", "max_tokens"]).optional(),
|
|
218
|
+
thinkingFormat: z.enum([
|
|
219
|
+
"openai",
|
|
220
|
+
"openrouter",
|
|
221
|
+
"deepseek",
|
|
222
|
+
"together",
|
|
223
|
+
"baseten",
|
|
224
|
+
"zai",
|
|
225
|
+
"qwen",
|
|
226
|
+
"chat-template",
|
|
227
|
+
"qwen-chat-template",
|
|
228
|
+
"string-thinking",
|
|
229
|
+
"ant-ling"
|
|
230
|
+
]).optional(),
|
|
231
|
+
zaiToolStream: z.boolean().optional()
|
|
232
|
+
}).strict()
|
|
233
|
+
}).strict().superRefine((config, ctx) => {
|
|
234
|
+
if (config.maxTokens > config.contextWindow) {
|
|
235
|
+
ctx.addIssue({ code: "custom", path: ["maxTokens"], message: "Pi maximum output cannot exceed its context window" });
|
|
236
|
+
}
|
|
237
|
+
if (config.reasoning && config.thinkingLevelMap[config.thinkingLevel] === null) {
|
|
238
|
+
ctx.addIssue({ code: "custom", path: ["thinkingLevel"], message: "Pi thinking level is not supported by the declared model" });
|
|
239
|
+
}
|
|
240
|
+
if (!config.reasoning && config.thinkingLevel !== "off") {
|
|
241
|
+
ctx.addIssue({ code: "custom", path: ["thinkingLevel"], message: "Non-reasoning Pi models require thinking off" });
|
|
242
|
+
}
|
|
243
|
+
});
|
|
196
244
|
|
|
197
245
|
// src/provider-profile.ts
|
|
198
246
|
var PROVIDER_PROFILE_REF_PATTERN = /^[a-z0-9]+(?:[-_][a-z0-9]+)*$/u;
|
|
@@ -251,6 +299,8 @@ var ModelProviderProfileSchema = z.object({
|
|
|
251
299
|
enabled: z.boolean(),
|
|
252
300
|
kind: z.literal("model"),
|
|
253
301
|
model: boundedString("model", 160),
|
|
302
|
+
// Direct transports do not use Pi; Pi admission requires this explicit configuration.
|
|
303
|
+
pi_model: PiModelConfigSchema.optional(),
|
|
254
304
|
profile_ref: ProviderProfileRefSchema,
|
|
255
305
|
provider_kind: z.enum(MODEL_PROVIDER_KINDS),
|
|
256
306
|
updated_at: isoTimestamp("updated_at")
|
|
@@ -309,6 +359,7 @@ function exactProviderProfileBinding(profileInput, requiredCapabilities = profil
|
|
|
309
359
|
capabilities: normalizedCapabilities,
|
|
310
360
|
kind: profile.kind,
|
|
311
361
|
model: profile.model,
|
|
362
|
+
...profile.pi_model === void 0 ? {} : { pi_model: profile.pi_model },
|
|
312
363
|
profile_ref: profile.profile_ref,
|
|
313
364
|
provider_kind: profile.provider_kind
|
|
314
365
|
});
|
|
@@ -539,13 +590,12 @@ function assertKeychainPath(keychainPath) {
|
|
|
539
590
|
}
|
|
540
591
|
return keychainPath;
|
|
541
592
|
}
|
|
542
|
-
|
|
543
|
-
// src/pi-provider-projection.ts
|
|
544
593
|
var PI_PROJECTED_KEY_ENV = "PI_PROVIDER_API_KEY";
|
|
545
594
|
function piProjectionProviderId(profileRef) {
|
|
546
595
|
return `byok-sdk-${profileRef}`;
|
|
547
596
|
}
|
|
548
597
|
function buildPiProviderProjection(profile) {
|
|
598
|
+
const { thinkingLevel: _, ...modelSettings } = requirePiModelConfig(profile);
|
|
549
599
|
const projectedProviderId = piProjectionProviderId(profile.profile_ref);
|
|
550
600
|
return {
|
|
551
601
|
providers: {
|
|
@@ -556,6 +606,7 @@ function buildPiProviderProjection(profile) {
|
|
|
556
606
|
...profile.auth_mode === "bearer" ? { authHeader: true } : {},
|
|
557
607
|
models: [
|
|
558
608
|
{
|
|
609
|
+
...modelSettings,
|
|
559
610
|
id: profile.model,
|
|
560
611
|
name: profile.display_name,
|
|
561
612
|
input: [
|
|
@@ -569,10 +620,27 @@ function buildPiProviderProjection(profile) {
|
|
|
569
620
|
};
|
|
570
621
|
}
|
|
571
622
|
function buildPiProviderArgs(profile, delegatedArgs) {
|
|
623
|
+
const config = requirePiModelConfig(profile);
|
|
624
|
+
if (delegatedArgs.length > 128) throw new Error("Pi launcher delegated argument limit exceeded");
|
|
572
625
|
let modeCount = 0;
|
|
626
|
+
let extensionCount = 0;
|
|
627
|
+
const singleFlags = /* @__PURE__ */ new Set();
|
|
573
628
|
for (let index = 0; index < delegatedArgs.length; index += 1) {
|
|
574
629
|
const flag = delegatedArgs[index];
|
|
630
|
+
if (typeof flag !== "string" || /[\u0000\r\n]/u.test(flag)) throw new Error("Pi launcher argument must be single-line");
|
|
631
|
+
if (flag !== "--extension") {
|
|
632
|
+
if (singleFlags.has(flag)) throw new Error(`Pi launcher duplicate argument ${flag}`);
|
|
633
|
+
singleFlags.add(flag);
|
|
634
|
+
}
|
|
575
635
|
if (flag === "--no-tools") continue;
|
|
636
|
+
if (flag === "--extension") {
|
|
637
|
+
const value = delegatedArgs[++index];
|
|
638
|
+
if (typeof value !== "string" || !isAbsolute(value) || /[\u0000\r\n]/u.test(value)) {
|
|
639
|
+
throw new Error("Pi launcher --extension requires an absolute single-line path");
|
|
640
|
+
}
|
|
641
|
+
if (++extensionCount > 16) throw new Error("Pi launcher extension limit exceeded");
|
|
642
|
+
continue;
|
|
643
|
+
}
|
|
576
644
|
if (flag === "--mode") {
|
|
577
645
|
modeCount += 1;
|
|
578
646
|
const value = delegatedArgs[index + 1];
|
|
@@ -582,7 +650,7 @@ function buildPiProviderArgs(profile, delegatedArgs) {
|
|
|
582
650
|
}
|
|
583
651
|
if (flag === "--session" || flag === "--tools" || flag === "--exclude-tools") {
|
|
584
652
|
const value = delegatedArgs[index + 1];
|
|
585
|
-
if (!value || value.startsWith("--")) {
|
|
653
|
+
if (!value || value.startsWith("--") || /[\u0000\r\n]/u.test(value)) {
|
|
586
654
|
throw new Error(`${flag} requires a value`);
|
|
587
655
|
}
|
|
588
656
|
index += 1;
|
|
@@ -591,14 +659,23 @@ function buildPiProviderArgs(profile, delegatedArgs) {
|
|
|
591
659
|
throw new Error(`Pi launcher does not allow delegated argument ${flag ?? "<missing>"}`);
|
|
592
660
|
}
|
|
593
661
|
if (modeCount !== 1) throw new Error("Pi launcher requires exactly one --mode rpc");
|
|
662
|
+
if (singleFlags.has("--no-tools") && singleFlags.has("--tools")) {
|
|
663
|
+
throw new Error("Pi launcher cannot combine --no-tools and --tools");
|
|
664
|
+
}
|
|
594
665
|
return [
|
|
595
666
|
...delegatedArgs,
|
|
596
667
|
"--provider",
|
|
597
668
|
piProjectionProviderId(profile.profile_ref),
|
|
598
669
|
"--model",
|
|
599
|
-
profile.model
|
|
670
|
+
profile.model,
|
|
671
|
+
"--thinking",
|
|
672
|
+
config.thinkingLevel
|
|
600
673
|
];
|
|
601
674
|
}
|
|
675
|
+
function requirePiModelConfig(profile) {
|
|
676
|
+
if (profile.pi_model === void 0) throw new Error("Pi execution requires explicit pi_model configuration");
|
|
677
|
+
return PiModelConfigSchema.parse(profile.pi_model);
|
|
678
|
+
}
|
|
602
679
|
|
|
603
680
|
// src/pi-provider-launcher-core.ts
|
|
604
681
|
var PI_CHILD_BASE_ENV_NAMES = [
|
|
@@ -637,6 +714,7 @@ function parsePiProviderLauncherOptions(args) {
|
|
|
637
714
|
const piArgs = separator < 0 ? [] : args.slice(separator + 1);
|
|
638
715
|
const allowedFlags = /* @__PURE__ */ new Set([
|
|
639
716
|
"--pi-bin",
|
|
717
|
+
"--pi-entry",
|
|
640
718
|
"--profile-db",
|
|
641
719
|
"--provider",
|
|
642
720
|
"--model",
|
|
@@ -725,7 +803,12 @@ function parsePiProviderLauncherOptions(args) {
|
|
|
725
803
|
requiredCapabilities: parsedCapabilities.data
|
|
726
804
|
};
|
|
727
805
|
}
|
|
806
|
+
const piEntry = values.get("--pi-entry");
|
|
807
|
+
if (piEntry !== void 0 && (!path2.isAbsolute(piEntry) || /[\u0000\r\n]/u.test(piEntry))) {
|
|
808
|
+
throw new Error("--pi-entry requires an absolute single-line path");
|
|
809
|
+
}
|
|
728
810
|
return {
|
|
811
|
+
...piEntry === void 0 ? {} : { piEntry },
|
|
729
812
|
piBin: required("--pi-bin"),
|
|
730
813
|
profileDbPath,
|
|
731
814
|
profileRef: profileRef.data,
|
|
@@ -770,11 +853,18 @@ function buildPiProviderChildEnvironment(options) {
|
|
|
770
853
|
const isPrefixed = platform === "win32" ? platformName.startsWith("LC_") || platformName.startsWith("XDG_") : name.startsWith("LC_") || name.startsWith("XDG_");
|
|
771
854
|
if (isExact || isPrefixed) result[name] = value;
|
|
772
855
|
}
|
|
856
|
+
const mcpPath = options.ambient.BYOK_PI_MCP_CONFIG_PATH;
|
|
857
|
+
if (mcpPath !== void 0) {
|
|
858
|
+
if (!path2.isAbsolute(mcpPath) || /[\u0000\r\n]/u.test(mcpPath)) throw new Error("BYOK_PI_MCP_CONFIG_PATH must be an absolute single-line path");
|
|
859
|
+
result.BYOK_PI_MCP_CONFIG_PATH = mcpPath;
|
|
860
|
+
}
|
|
861
|
+
const permissionMode = options.ambient.BYOK_PI_PERMISSION_MODE;
|
|
862
|
+
if (permissionMode !== void 0) {
|
|
863
|
+
if (permissionMode !== "auto" && permissionMode !== "readonly") throw new Error("BYOK_PI_PERMISSION_MODE must be auto or readonly");
|
|
864
|
+
result.BYOK_PI_PERMISSION_MODE = permissionMode;
|
|
865
|
+
}
|
|
773
866
|
result.PI_CODING_AGENT_DIR = options.projectionDir;
|
|
774
867
|
result.PI_CODING_AGENT_SESSION_DIR = options.sessionDir;
|
|
775
|
-
if (options.secret !== void 0) {
|
|
776
|
-
result[PI_PROJECTED_KEY_ENV] = options.secret;
|
|
777
|
-
}
|
|
778
868
|
return result;
|
|
779
869
|
}
|
|
780
870
|
async function ensurePiSessionDirectory(sessionDir) {
|
|
@@ -878,6 +968,7 @@ CREATE TABLE IF NOT EXISTS provider_profile (
|
|
|
878
968
|
base_url TEXT NOT NULL,
|
|
879
969
|
auth_mode TEXT NOT NULL CHECK (auth_mode IN (${sqlList(PROVIDER_AUTH_MODES)})),
|
|
880
970
|
model TEXT NOT NULL,
|
|
971
|
+
pi_model TEXT,
|
|
881
972
|
capabilities TEXT NOT NULL,
|
|
882
973
|
enabled INTEGER NOT NULL CHECK (enabled IN (0, 1)),
|
|
883
974
|
created_at TEXT NOT NULL,
|
|
@@ -896,7 +987,7 @@ function assertProviderProfileSchemaIsCurrent(database, path4) {
|
|
|
896
987
|
if (normalizeTableDdl(stored) === normalizeTableDdl(SCHEMA)) return;
|
|
897
988
|
throw new ByokKeysError(
|
|
898
989
|
"PROVIDER_STORE_SCHEMA_STALE",
|
|
899
|
-
`Provider profile store at ${path4} was created by a different @byok-sdk/keys schema;
|
|
990
|
+
`Provider profile store at ${path4} was created by a different @byok-sdk/keys schema; preserve this store and explicitly provision a separate current-schema store before continuing`
|
|
900
991
|
);
|
|
901
992
|
}
|
|
902
993
|
var ENABLED_INDEX = `
|
|
@@ -978,8 +1069,8 @@ var SqliteProviderProfileStore = class {
|
|
|
978
1069
|
this.#database.prepare(
|
|
979
1070
|
`INSERT INTO provider_profile (
|
|
980
1071
|
profile_ref, provider_kind, kind, adapter, display_name, base_url,
|
|
981
|
-
auth_mode, model, capabilities, enabled, created_at, updated_at
|
|
982
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
1072
|
+
auth_mode, model, pi_model, capabilities, enabled, created_at, updated_at
|
|
1073
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
983
1074
|
ON CONFLICT(profile_ref) DO UPDATE SET
|
|
984
1075
|
provider_kind = excluded.provider_kind,
|
|
985
1076
|
adapter = excluded.adapter,
|
|
@@ -987,6 +1078,7 @@ var SqliteProviderProfileStore = class {
|
|
|
987
1078
|
base_url = excluded.base_url,
|
|
988
1079
|
auth_mode = excluded.auth_mode,
|
|
989
1080
|
model = excluded.model,
|
|
1081
|
+
pi_model = excluded.pi_model,
|
|
990
1082
|
capabilities = excluded.capabilities,
|
|
991
1083
|
enabled = excluded.enabled,
|
|
992
1084
|
updated_at = excluded.updated_at`
|
|
@@ -999,6 +1091,7 @@ var SqliteProviderProfileStore = class {
|
|
|
999
1091
|
validated.base_url,
|
|
1000
1092
|
validated.auth_mode,
|
|
1001
1093
|
validated.model,
|
|
1094
|
+
validated.pi_model === void 0 ? null : JSON.stringify(validated.pi_model),
|
|
1002
1095
|
JSON.stringify(validated.capabilities),
|
|
1003
1096
|
validated.enabled ? 1 : 0,
|
|
1004
1097
|
validated.created_at,
|
|
@@ -1037,6 +1130,7 @@ function parseRow(row) {
|
|
|
1037
1130
|
}
|
|
1038
1131
|
return parseModelProviderProfile({
|
|
1039
1132
|
...row,
|
|
1133
|
+
pi_model: row.pi_model === null ? void 0 : JSON.parse(row.pi_model),
|
|
1040
1134
|
capabilities,
|
|
1041
1135
|
enabled: row.enabled === 1
|
|
1042
1136
|
});
|
|
@@ -1357,31 +1451,32 @@ async function run(options) {
|
|
|
1357
1451
|
if (options.expectedBinding !== void 0) {
|
|
1358
1452
|
assertExactProviderProfileBinding(profile, options.expectedBinding);
|
|
1359
1453
|
}
|
|
1454
|
+
const projection = buildPiProviderProjection(profile);
|
|
1360
1455
|
if (options.validateOnly) return 0;
|
|
1361
|
-
const
|
|
1362
|
-
profile,
|
|
1363
|
-
() => createSecretStore(
|
|
1364
|
-
options.secretServicePrefix,
|
|
1365
|
-
options.macosKeychainPath
|
|
1366
|
-
)
|
|
1367
|
-
);
|
|
1456
|
+
const childArgs = buildPiProviderArgs(profile, options.piArgs);
|
|
1368
1457
|
projectionDir = await promises.mkdtemp(path2.join(os.tmpdir(), "byok-pi-provider-"));
|
|
1369
1458
|
await promises.chmod(projectionDir, 448).catch(() => {
|
|
1370
1459
|
});
|
|
1371
1460
|
await ensurePiSessionDirectory(options.sessionDir);
|
|
1461
|
+
const childEnv = buildPiProviderChildEnvironment({
|
|
1462
|
+
ambient: process.env,
|
|
1463
|
+
projectionDir,
|
|
1464
|
+
sessionDir: options.sessionDir,
|
|
1465
|
+
secret: void 0
|
|
1466
|
+
});
|
|
1467
|
+
const secret = await resolvePiProviderSecret(
|
|
1468
|
+
profile,
|
|
1469
|
+
() => createSecretStore(options.secretServicePrefix, options.macosKeychainPath)
|
|
1470
|
+
);
|
|
1471
|
+
if (secret !== void 0) childEnv[PI_PROJECTED_KEY_ENV] = secret;
|
|
1372
1472
|
await promises.writeFile(
|
|
1373
1473
|
path2.join(projectionDir, "models.json"),
|
|
1374
|
-
`${JSON.stringify(
|
|
1474
|
+
`${JSON.stringify(projection)}
|
|
1375
1475
|
`,
|
|
1376
1476
|
{ mode: 384 }
|
|
1377
1477
|
);
|
|
1378
|
-
const child = spawn(options.piBin,
|
|
1379
|
-
env:
|
|
1380
|
-
ambient: process.env,
|
|
1381
|
-
projectionDir,
|
|
1382
|
-
sessionDir: options.sessionDir,
|
|
1383
|
-
secret
|
|
1384
|
-
}),
|
|
1478
|
+
const child = spawn(options.piBin, [...options.piEntry === void 0 ? [] : [options.piEntry], ...childArgs], {
|
|
1479
|
+
env: childEnv,
|
|
1385
1480
|
stdio: "inherit"
|
|
1386
1481
|
});
|
|
1387
1482
|
const forward = (signal) => {
|