@byok-sdk/keys 0.3.8 → 0.3.10
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 +13 -1
- package/dist/bin/pi-provider-launcher.js +312 -181
- package/dist/bin/pi-provider-launcher.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +188 -91
- package/dist/index.js.map +1 -1
- package/dist/pi-provider-launcher-core.d.ts +5 -2
- package/dist/pi-provider-projection.d.ts +11 -2
- package/dist/profile-store.d.ts +12 -12
- package/dist/provider-profile.d.ts +58 -5
- package/dist/registry.d.ts +22 -9
- package/dist/secret-store.d.ts +17 -14
- package/dist/sqlite-profile-store.d.ts +6 -6
- package/dist/truth-profile-store.d.ts +14 -4
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { createHash } from 'crypto';
|
|
2
3
|
import { spawn } from 'child_process';
|
|
3
4
|
import path, { dirname } from 'path';
|
|
4
|
-
import { createHash } from 'crypto';
|
|
5
5
|
import { mkdirSync, existsSync, chmodSync } from 'fs';
|
|
6
6
|
import { createRequire } from 'module';
|
|
7
7
|
import { isCoreConflictError, contentHash } from '@byok-sdk/core';
|
|
@@ -99,12 +99,19 @@ function isPrivateNetworkLiteral(hostname) {
|
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
// src/provider-profile.ts
|
|
102
|
-
var
|
|
102
|
+
var PROVIDER_PROFILE_REF_PATTERN = /^[a-z0-9]+(?:[-_][a-z0-9]+)*$/u;
|
|
103
|
+
var ProviderProfileRefSchema = z.string().min(1).max(64).regex(
|
|
104
|
+
PROVIDER_PROFILE_REF_PATTERN,
|
|
105
|
+
"provider profile refs must be lowercase portable identifiers"
|
|
106
|
+
);
|
|
107
|
+
var MODEL_PROVIDER_KINDS = [
|
|
103
108
|
"openai",
|
|
104
109
|
"deepseek",
|
|
105
110
|
"anthropic",
|
|
106
111
|
"custom"
|
|
107
112
|
];
|
|
113
|
+
var PROVIDER_MODEL_CAPABILITIES = ["image-input"];
|
|
114
|
+
var ProviderModelCapabilitySchema = z.enum(PROVIDER_MODEL_CAPABILITIES);
|
|
108
115
|
var PROVIDER_AUTH_MODES = ["bearer", "x_api_key", "none"];
|
|
109
116
|
var MODEL_PROVIDER_ADAPTERS = ["openai_compatible", "anthropic"];
|
|
110
117
|
function boundedString(field, maximumLength) {
|
|
@@ -144,14 +151,23 @@ var ModelProviderProfileSchema = z.object({
|
|
|
144
151
|
adapter: z.enum(MODEL_PROVIDER_ADAPTERS),
|
|
145
152
|
auth_mode: z.enum(PROVIDER_AUTH_MODES),
|
|
146
153
|
base_url: providerBaseUrl,
|
|
154
|
+
capabilities: z.array(ProviderModelCapabilitySchema).max(8),
|
|
147
155
|
created_at: isoTimestamp("created_at"),
|
|
148
156
|
display_name: boundedString("display_name", 100),
|
|
149
157
|
enabled: z.boolean(),
|
|
150
158
|
kind: z.literal("model"),
|
|
151
159
|
model: boundedString("model", 160),
|
|
152
|
-
|
|
160
|
+
profile_ref: ProviderProfileRefSchema,
|
|
161
|
+
provider_kind: z.enum(MODEL_PROVIDER_KINDS),
|
|
153
162
|
updated_at: isoTimestamp("updated_at")
|
|
154
163
|
}).superRefine((profile, ctx) => {
|
|
164
|
+
if (new Set(profile.capabilities).size !== profile.capabilities.length) {
|
|
165
|
+
ctx.addIssue({
|
|
166
|
+
code: "custom",
|
|
167
|
+
message: "Provider capabilities cannot repeat",
|
|
168
|
+
path: ["capabilities"]
|
|
169
|
+
});
|
|
170
|
+
}
|
|
155
171
|
if (profile.adapter === "anthropic" && profile.auth_mode !== "x_api_key") {
|
|
156
172
|
ctx.addIssue({
|
|
157
173
|
code: "custom",
|
|
@@ -174,6 +190,47 @@ var ModelProviderProfileSchema = z.object({
|
|
|
174
190
|
});
|
|
175
191
|
}
|
|
176
192
|
});
|
|
193
|
+
function exactProviderProfileBinding(profileInput, requiredCapabilities = profileInput.capabilities) {
|
|
194
|
+
const profile = parseModelProviderProfile(profileInput);
|
|
195
|
+
const revision = Date.parse(profile.updated_at);
|
|
196
|
+
if (!Number.isSafeInteger(revision) || revision < 0) {
|
|
197
|
+
throw new ByokKeysError(
|
|
198
|
+
"PROVIDER_PROFILE_INVALID",
|
|
199
|
+
"Provider updated_at cannot be represented as a canonical revision"
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
const normalizedCapabilities = [...profile.capabilities].sort();
|
|
203
|
+
const canonical = JSON.stringify({
|
|
204
|
+
adapter: profile.adapter,
|
|
205
|
+
auth_mode: profile.auth_mode,
|
|
206
|
+
base_url: profile.base_url,
|
|
207
|
+
capabilities: normalizedCapabilities,
|
|
208
|
+
kind: profile.kind,
|
|
209
|
+
model: profile.model,
|
|
210
|
+
profile_ref: profile.profile_ref,
|
|
211
|
+
provider_kind: profile.provider_kind
|
|
212
|
+
});
|
|
213
|
+
return {
|
|
214
|
+
profileRef: profile.profile_ref,
|
|
215
|
+
profileRevision: String(revision),
|
|
216
|
+
profileHash: `sha256:${createHash("sha256").update(canonical).digest("hex")}`,
|
|
217
|
+
modelId: profile.model,
|
|
218
|
+
requiredCapabilities: [...requiredCapabilities]
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
function assertExactProviderProfileBinding(profile, expected) {
|
|
222
|
+
if (new Set(expected.requiredCapabilities).size !== expected.requiredCapabilities.length) {
|
|
223
|
+
throw new Error("provider profile required capabilities must be unique");
|
|
224
|
+
}
|
|
225
|
+
const actual = exactProviderProfileBinding(profile, expected.requiredCapabilities);
|
|
226
|
+
if (actual.profileRef !== expected.profileRef) throw new Error("provider profile ref mismatch");
|
|
227
|
+
if (actual.profileRevision !== expected.profileRevision) throw new Error("provider profile revision mismatch");
|
|
228
|
+
if (actual.profileHash !== expected.profileHash) throw new Error("provider profile hash mismatch");
|
|
229
|
+
if (actual.modelId !== expected.modelId) throw new Error("provider profile model mismatch");
|
|
230
|
+
const supported = new Set(profile.capabilities);
|
|
231
|
+
const unsupported = expected.requiredCapabilities.find((capability) => !supported.has(capability));
|
|
232
|
+
if (unsupported !== void 0) throw new Error(`provider profile does not support required capability ${unsupported}`);
|
|
233
|
+
}
|
|
177
234
|
function parseModelProviderProfile(value) {
|
|
178
235
|
const result = ModelProviderProfileSchema.safeParse(value);
|
|
179
236
|
if (result.success) return result.data;
|
|
@@ -527,14 +584,16 @@ function assertSecretNamespace(value) {
|
|
|
527
584
|
|
|
528
585
|
// src/secret-store.ts
|
|
529
586
|
var DEFAULT_SECRET_SERVICE_PREFIX = "com.byok.keys";
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
587
|
+
function modelProviderSecretName(profileRef) {
|
|
588
|
+
const parsed = ProviderProfileRefSchema.safeParse(profileRef);
|
|
589
|
+
if (!parsed.success) {
|
|
590
|
+
throw new ByokKeysError(
|
|
591
|
+
"PROVIDER_PROFILE_INVALID",
|
|
592
|
+
"Provider profile ref must be a lowercase portable identifier",
|
|
593
|
+
{ cause: parsed.error }
|
|
594
|
+
);
|
|
595
|
+
}
|
|
596
|
+
return assertSecretName(`model-${parsed.data}-api-key`);
|
|
538
597
|
}
|
|
539
598
|
function assertSharedSecretValue(secret) {
|
|
540
599
|
if (secret.length === 0 || /[\u0000\r\n]/u.test(secret)) {
|
|
@@ -1143,10 +1202,10 @@ function normalizeSecretScope(scope) {
|
|
|
1143
1202
|
}
|
|
1144
1203
|
|
|
1145
1204
|
// src/profile-store.ts
|
|
1146
|
-
function providerNotConfigured(
|
|
1205
|
+
function providerNotConfigured(profileRef) {
|
|
1147
1206
|
return new ByokKeysError(
|
|
1148
1207
|
"PROVIDER_NOT_CONFIGURED",
|
|
1149
|
-
`${
|
|
1208
|
+
`${profileRef} model provider is not configured`
|
|
1150
1209
|
);
|
|
1151
1210
|
}
|
|
1152
1211
|
var InMemoryProviderProfileStore = class {
|
|
@@ -1154,38 +1213,38 @@ var InMemoryProviderProfileStore = class {
|
|
|
1154
1213
|
async close() {
|
|
1155
1214
|
this.#profiles.clear();
|
|
1156
1215
|
}
|
|
1157
|
-
async delete(
|
|
1158
|
-
return this.#profiles.delete(
|
|
1216
|
+
async delete(profileRef) {
|
|
1217
|
+
return this.#profiles.delete(profileRef);
|
|
1159
1218
|
}
|
|
1160
|
-
async get(
|
|
1161
|
-
return this.#profiles.get(
|
|
1219
|
+
async get(profileRef) {
|
|
1220
|
+
return this.#profiles.get(profileRef);
|
|
1162
1221
|
}
|
|
1163
1222
|
async getEnabled() {
|
|
1164
1223
|
return [...this.#profiles.values()].find((profile) => profile.enabled);
|
|
1165
1224
|
}
|
|
1166
1225
|
async list() {
|
|
1167
1226
|
return [...this.#profiles.values()].sort(
|
|
1168
|
-
(left, right) => left.
|
|
1227
|
+
(left, right) => left.profile_ref.localeCompare(right.profile_ref)
|
|
1169
1228
|
);
|
|
1170
1229
|
}
|
|
1171
1230
|
async save(profile) {
|
|
1172
1231
|
const validated = parseModelProviderProfile({
|
|
1173
1232
|
...profile,
|
|
1174
|
-
created_at: this.#profiles.get(profile.
|
|
1233
|
+
created_at: this.#profiles.get(profile.profile_ref)?.created_at ?? profile.created_at
|
|
1175
1234
|
});
|
|
1176
1235
|
if (validated.enabled) {
|
|
1177
|
-
for (const [
|
|
1178
|
-
if (
|
|
1179
|
-
this.#profiles.set(
|
|
1236
|
+
for (const [profileRef, existing] of this.#profiles) {
|
|
1237
|
+
if (profileRef !== validated.profile_ref && existing.enabled) {
|
|
1238
|
+
this.#profiles.set(profileRef, { ...existing, enabled: false });
|
|
1180
1239
|
}
|
|
1181
1240
|
}
|
|
1182
1241
|
}
|
|
1183
|
-
this.#profiles.set(validated.
|
|
1242
|
+
this.#profiles.set(validated.profile_ref, validated);
|
|
1184
1243
|
return validated;
|
|
1185
1244
|
}
|
|
1186
|
-
async setEnabled(
|
|
1187
|
-
const existing = this.#profiles.get(
|
|
1188
|
-
if (existing === void 0) throw providerNotConfigured(
|
|
1245
|
+
async setEnabled(profileRef) {
|
|
1246
|
+
const existing = this.#profiles.get(profileRef);
|
|
1247
|
+
if (existing === void 0) throw providerNotConfigured(profileRef);
|
|
1189
1248
|
return this.save({ ...existing, enabled: true });
|
|
1190
1249
|
}
|
|
1191
1250
|
};
|
|
@@ -1263,16 +1322,18 @@ function secureSqliteFilePermissions(databasePath) {
|
|
|
1263
1322
|
// src/sqlite-profile-store.ts
|
|
1264
1323
|
var SCHEMA = `
|
|
1265
1324
|
CREATE TABLE IF NOT EXISTS provider_profile (
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1325
|
+
profile_ref TEXT PRIMARY KEY,
|
|
1326
|
+
provider_kind TEXT NOT NULL CHECK (provider_kind IN ('openai', 'deepseek', 'anthropic', 'custom')),
|
|
1327
|
+
kind TEXT NOT NULL CHECK (kind = 'model'),
|
|
1328
|
+
adapter TEXT NOT NULL CHECK (adapter IN ('openai_compatible', 'anthropic')),
|
|
1329
|
+
display_name TEXT NOT NULL,
|
|
1330
|
+
base_url TEXT NOT NULL,
|
|
1331
|
+
auth_mode TEXT NOT NULL CHECK (auth_mode IN ('bearer', 'x_api_key', 'none')),
|
|
1332
|
+
model TEXT NOT NULL,
|
|
1333
|
+
capabilities TEXT NOT NULL,
|
|
1334
|
+
enabled INTEGER NOT NULL CHECK (enabled IN (0, 1)),
|
|
1335
|
+
created_at TEXT NOT NULL,
|
|
1336
|
+
updated_at TEXT NOT NULL
|
|
1276
1337
|
);
|
|
1277
1338
|
`;
|
|
1278
1339
|
var ENABLED_INDEX = `
|
|
@@ -1312,12 +1373,12 @@ var SqliteProviderProfileStore = class {
|
|
|
1312
1373
|
this.#closed = true;
|
|
1313
1374
|
this.#database.close();
|
|
1314
1375
|
}
|
|
1315
|
-
async delete(
|
|
1316
|
-
const result = this.#database.prepare("DELETE FROM provider_profile WHERE
|
|
1376
|
+
async delete(profileRef) {
|
|
1377
|
+
const result = this.#database.prepare("DELETE FROM provider_profile WHERE profile_ref = ?").run(profileRef);
|
|
1317
1378
|
return Number(result.changes) === 1;
|
|
1318
1379
|
}
|
|
1319
|
-
async get(
|
|
1320
|
-
const row = this.#database.prepare("SELECT * FROM provider_profile WHERE
|
|
1380
|
+
async get(profileRef) {
|
|
1381
|
+
const row = this.#database.prepare("SELECT * FROM provider_profile WHERE profile_ref = ?").get(profileRef);
|
|
1321
1382
|
return row === void 0 ? void 0 : parseRow(row);
|
|
1322
1383
|
}
|
|
1323
1384
|
async getEnabled() {
|
|
@@ -1325,11 +1386,11 @@ var SqliteProviderProfileStore = class {
|
|
|
1325
1386
|
return row === void 0 ? void 0 : parseRow(row);
|
|
1326
1387
|
}
|
|
1327
1388
|
async list() {
|
|
1328
|
-
const rows = this.#database.prepare("SELECT * FROM provider_profile ORDER BY
|
|
1389
|
+
const rows = this.#database.prepare("SELECT * FROM provider_profile ORDER BY profile_ref ASC").all();
|
|
1329
1390
|
return rows.map(parseRow);
|
|
1330
1391
|
}
|
|
1331
1392
|
async save(profile) {
|
|
1332
|
-
const existing = await this.get(profile.
|
|
1393
|
+
const existing = await this.get(profile.profile_ref);
|
|
1333
1394
|
const validated = parseModelProviderProfile({
|
|
1334
1395
|
...profile,
|
|
1335
1396
|
created_at: existing?.created_at ?? profile.created_at
|
|
@@ -1337,40 +1398,44 @@ var SqliteProviderProfileStore = class {
|
|
|
1337
1398
|
this.#transaction(() => {
|
|
1338
1399
|
if (validated.enabled) {
|
|
1339
1400
|
this.#database.prepare(
|
|
1340
|
-
"UPDATE provider_profile SET enabled = 0 WHERE
|
|
1341
|
-
).run(validated.
|
|
1401
|
+
"UPDATE provider_profile SET enabled = 0 WHERE profile_ref <> ?"
|
|
1402
|
+
).run(validated.profile_ref);
|
|
1342
1403
|
}
|
|
1343
1404
|
this.#database.prepare(
|
|
1344
1405
|
`INSERT INTO provider_profile (
|
|
1345
|
-
|
|
1346
|
-
auth_mode, model, enabled, created_at, updated_at
|
|
1347
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
1348
|
-
ON CONFLICT(
|
|
1406
|
+
profile_ref, provider_kind, kind, adapter, display_name, base_url,
|
|
1407
|
+
auth_mode, model, capabilities, enabled, created_at, updated_at
|
|
1408
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
1409
|
+
ON CONFLICT(profile_ref) DO UPDATE SET
|
|
1410
|
+
provider_kind = excluded.provider_kind,
|
|
1349
1411
|
adapter = excluded.adapter,
|
|
1350
1412
|
display_name = excluded.display_name,
|
|
1351
1413
|
base_url = excluded.base_url,
|
|
1352
1414
|
auth_mode = excluded.auth_mode,
|
|
1353
1415
|
model = excluded.model,
|
|
1416
|
+
capabilities = excluded.capabilities,
|
|
1354
1417
|
enabled = excluded.enabled,
|
|
1355
1418
|
updated_at = excluded.updated_at`
|
|
1356
1419
|
).run(
|
|
1357
|
-
validated.
|
|
1420
|
+
validated.profile_ref,
|
|
1421
|
+
validated.provider_kind,
|
|
1358
1422
|
validated.kind,
|
|
1359
1423
|
validated.adapter,
|
|
1360
1424
|
validated.display_name,
|
|
1361
1425
|
validated.base_url,
|
|
1362
1426
|
validated.auth_mode,
|
|
1363
1427
|
validated.model,
|
|
1428
|
+
JSON.stringify(validated.capabilities),
|
|
1364
1429
|
validated.enabled ? 1 : 0,
|
|
1365
1430
|
validated.created_at,
|
|
1366
1431
|
validated.updated_at
|
|
1367
1432
|
);
|
|
1368
1433
|
});
|
|
1369
|
-
return await this.get(validated.
|
|
1434
|
+
return await this.get(validated.profile_ref);
|
|
1370
1435
|
}
|
|
1371
|
-
async setEnabled(
|
|
1372
|
-
const existing = await this.get(
|
|
1373
|
-
if (existing === void 0) throw providerNotConfigured(
|
|
1436
|
+
async setEnabled(profileRef) {
|
|
1437
|
+
const existing = await this.get(profileRef);
|
|
1438
|
+
if (existing === void 0) throw providerNotConfigured(profileRef);
|
|
1374
1439
|
return this.save({ ...existing, enabled: true });
|
|
1375
1440
|
}
|
|
1376
1441
|
/** `BEGIN IMMEDIATE` / `COMMIT` / `ROLLBACK`, per `providers.ts:1252-1263`. */
|
|
@@ -1386,8 +1451,19 @@ var SqliteProviderProfileStore = class {
|
|
|
1386
1451
|
}
|
|
1387
1452
|
};
|
|
1388
1453
|
function parseRow(row) {
|
|
1454
|
+
let capabilities;
|
|
1455
|
+
try {
|
|
1456
|
+
capabilities = JSON.parse(row.capabilities);
|
|
1457
|
+
} catch (cause) {
|
|
1458
|
+
throw new ByokKeysError(
|
|
1459
|
+
"PROVIDER_PROFILE_INVALID",
|
|
1460
|
+
"Provider profile capabilities column is not valid JSON",
|
|
1461
|
+
{ cause }
|
|
1462
|
+
);
|
|
1463
|
+
}
|
|
1389
1464
|
return parseModelProviderProfile({
|
|
1390
1465
|
...row,
|
|
1466
|
+
capabilities,
|
|
1391
1467
|
enabled: row.enabled === 1
|
|
1392
1468
|
});
|
|
1393
1469
|
}
|
|
@@ -1396,14 +1472,17 @@ var PROFILE_KEYS = [
|
|
|
1396
1472
|
"adapter",
|
|
1397
1473
|
"auth_mode",
|
|
1398
1474
|
"base_url",
|
|
1475
|
+
"capabilities",
|
|
1399
1476
|
"created_at",
|
|
1400
1477
|
"display_name",
|
|
1401
1478
|
"enabled",
|
|
1402
1479
|
"kind",
|
|
1403
1480
|
"model",
|
|
1404
|
-
"
|
|
1481
|
+
"profile_ref",
|
|
1482
|
+
"provider_kind",
|
|
1405
1483
|
"updated_at"
|
|
1406
1484
|
];
|
|
1485
|
+
var MAX_PROVIDER_PROFILES = 32;
|
|
1407
1486
|
var TruthStoreProviderProfileStore = class {
|
|
1408
1487
|
#tenant;
|
|
1409
1488
|
#truth;
|
|
@@ -1413,20 +1492,20 @@ var TruthStoreProviderProfileStore = class {
|
|
|
1413
1492
|
}
|
|
1414
1493
|
async close() {
|
|
1415
1494
|
}
|
|
1416
|
-
async delete(
|
|
1495
|
+
async delete(profileRef) {
|
|
1417
1496
|
const current = await this.#load();
|
|
1418
|
-
if (!current.profiles.some((profile) => profile.
|
|
1497
|
+
if (!current.profiles.some((profile) => profile.profile_ref === profileRef)) {
|
|
1419
1498
|
return false;
|
|
1420
1499
|
}
|
|
1421
1500
|
await this.#write(
|
|
1422
|
-
current.profiles.filter((profile) => profile.
|
|
1501
|
+
current.profiles.filter((profile) => profile.profile_ref !== profileRef),
|
|
1423
1502
|
current.rev
|
|
1424
1503
|
);
|
|
1425
1504
|
return true;
|
|
1426
1505
|
}
|
|
1427
|
-
async get(
|
|
1506
|
+
async get(profileRef) {
|
|
1428
1507
|
return (await this.#load()).profiles.find(
|
|
1429
|
-
(profile) => profile.
|
|
1508
|
+
(profile) => profile.profile_ref === profileRef
|
|
1430
1509
|
);
|
|
1431
1510
|
}
|
|
1432
1511
|
async getEnabled() {
|
|
@@ -1438,28 +1517,28 @@ var TruthStoreProviderProfileStore = class {
|
|
|
1438
1517
|
async save(profile) {
|
|
1439
1518
|
const current = await this.#load();
|
|
1440
1519
|
const existing = current.profiles.find(
|
|
1441
|
-
(candidate) => candidate.
|
|
1520
|
+
(candidate) => candidate.profile_ref === profile.profile_ref
|
|
1442
1521
|
);
|
|
1443
1522
|
const validated = parseModelProviderProfile({
|
|
1444
1523
|
...profile,
|
|
1445
1524
|
created_at: existing?.created_at ?? profile.created_at
|
|
1446
1525
|
});
|
|
1447
|
-
const next = current.profiles.filter((candidate) => candidate.
|
|
1526
|
+
const next = current.profiles.filter((candidate) => candidate.profile_ref !== validated.profile_ref).map(
|
|
1448
1527
|
(candidate) => validated.enabled && candidate.enabled ? { ...candidate, enabled: false } : candidate
|
|
1449
1528
|
);
|
|
1450
1529
|
next.push(validated);
|
|
1451
1530
|
await this.#write(next, current.rev);
|
|
1452
1531
|
return validated;
|
|
1453
1532
|
}
|
|
1454
|
-
async setEnabled(
|
|
1533
|
+
async setEnabled(profileRef) {
|
|
1455
1534
|
const current = await this.#load();
|
|
1456
1535
|
const selected = current.profiles.find(
|
|
1457
|
-
(profile) => profile.
|
|
1536
|
+
(profile) => profile.profile_ref === profileRef
|
|
1458
1537
|
);
|
|
1459
|
-
if (selected === void 0) throw providerNotConfigured(
|
|
1538
|
+
if (selected === void 0) throw providerNotConfigured(profileRef);
|
|
1460
1539
|
const next = current.profiles.map((profile) => ({
|
|
1461
1540
|
...profile,
|
|
1462
|
-
enabled: profile.
|
|
1541
|
+
enabled: profile.profile_ref === profileRef
|
|
1463
1542
|
}));
|
|
1464
1543
|
await this.#write(next, current.rev);
|
|
1465
1544
|
return { ...selected, enabled: true };
|
|
@@ -1505,7 +1584,7 @@ var TruthStoreProviderProfileStore = class {
|
|
|
1505
1584
|
}
|
|
1506
1585
|
};
|
|
1507
1586
|
function encodeRegistry(profiles) {
|
|
1508
|
-
const normalized = profiles.map((profile) => parseModelProviderProfile(profile)).sort((left, right) => left.
|
|
1587
|
+
const normalized = profiles.map((profile) => parseModelProviderProfile(profile)).sort((left, right) => left.profile_ref.localeCompare(right.profile_ref));
|
|
1509
1588
|
assertRegistryInvariants(normalized);
|
|
1510
1589
|
const snapshot = {
|
|
1511
1590
|
schema_version: 1,
|
|
@@ -1513,12 +1592,14 @@ function encodeRegistry(profiles) {
|
|
|
1513
1592
|
adapter: profile.adapter,
|
|
1514
1593
|
auth_mode: profile.auth_mode,
|
|
1515
1594
|
base_url: profile.base_url,
|
|
1595
|
+
capabilities: profile.capabilities,
|
|
1516
1596
|
created_at: profile.created_at,
|
|
1517
1597
|
display_name: profile.display_name,
|
|
1518
1598
|
enabled: profile.enabled,
|
|
1519
1599
|
kind: profile.kind,
|
|
1520
1600
|
model: profile.model,
|
|
1521
|
-
|
|
1601
|
+
profile_ref: profile.profile_ref,
|
|
1602
|
+
provider_kind: profile.provider_kind,
|
|
1522
1603
|
updated_at: profile.updated_at
|
|
1523
1604
|
}))
|
|
1524
1605
|
};
|
|
@@ -1550,7 +1631,7 @@ function decodeRegistryRecord(record, tenant) {
|
|
|
1550
1631
|
if (raw.schema_version !== 1 || !Array.isArray(raw.profiles)) {
|
|
1551
1632
|
throw invalidTruth("Provider profile TruthStore body has an unsupported schema");
|
|
1552
1633
|
}
|
|
1553
|
-
if (raw.profiles.length >
|
|
1634
|
+
if (raw.profiles.length > MAX_PROVIDER_PROFILES) {
|
|
1554
1635
|
throw invalidTruth("Provider profile TruthStore body exceeds the provider registry bound");
|
|
1555
1636
|
}
|
|
1556
1637
|
let profiles;
|
|
@@ -1577,10 +1658,10 @@ function assertRegistryInvariants(profiles) {
|
|
|
1577
1658
|
const seen = /* @__PURE__ */ new Set();
|
|
1578
1659
|
let enabled = 0;
|
|
1579
1660
|
for (const profile of profiles) {
|
|
1580
|
-
if (seen.has(profile.
|
|
1581
|
-
throw invalidTruth(`Provider profile ${profile.
|
|
1661
|
+
if (seen.has(profile.profile_ref)) {
|
|
1662
|
+
throw invalidTruth(`Provider profile ${profile.profile_ref} appears more than once`);
|
|
1582
1663
|
}
|
|
1583
|
-
seen.add(profile.
|
|
1664
|
+
seen.add(profile.profile_ref);
|
|
1584
1665
|
if (profile.enabled) enabled += 1;
|
|
1585
1666
|
}
|
|
1586
1667
|
if (enabled > 1) {
|
|
@@ -1630,16 +1711,23 @@ var ProviderRegistry = class {
|
|
|
1630
1711
|
* authentication it cannot perform.
|
|
1631
1712
|
*/
|
|
1632
1713
|
async configure(configuration, secret) {
|
|
1633
|
-
const
|
|
1634
|
-
const
|
|
1714
|
+
const previous = await this.#profiles.get(configuration.profile_ref);
|
|
1715
|
+
const observedNow = this.#now().getTime();
|
|
1716
|
+
const previousRevision = previous === void 0 ? void 0 : Date.parse(previous.updated_at);
|
|
1717
|
+
const revision = previousRevision === void 0 ? observedNow : Math.max(observedNow, previousRevision + 1);
|
|
1718
|
+
if (!Number.isSafeInteger(revision) || revision < 0) {
|
|
1719
|
+
throw new ByokKeysError("PROVIDER_PROFILE_INVALID", "Provider clock cannot produce a monotonic profile revision");
|
|
1720
|
+
}
|
|
1721
|
+
const timestamp = new Date(revision).toISOString();
|
|
1635
1722
|
const profile = parseModelProviderProfile({
|
|
1636
1723
|
...configuration,
|
|
1724
|
+
capabilities: [...configuration.capabilities],
|
|
1637
1725
|
created_at: previous?.created_at ?? timestamp,
|
|
1638
1726
|
enabled: configuration.enabled ?? true,
|
|
1639
1727
|
kind: "model",
|
|
1640
1728
|
updated_at: timestamp
|
|
1641
1729
|
});
|
|
1642
|
-
const secretName = modelProviderSecretName(configuration.
|
|
1730
|
+
const secretName = modelProviderSecretName(configuration.profile_ref);
|
|
1643
1731
|
let previousSecret;
|
|
1644
1732
|
let secretWritten = false;
|
|
1645
1733
|
if (configuration.auth_mode === "none" && secret !== void 0) {
|
|
@@ -1691,14 +1779,14 @@ var ProviderRegistry = class {
|
|
|
1691
1779
|
}
|
|
1692
1780
|
return this.#status(saved);
|
|
1693
1781
|
}
|
|
1694
|
-
/** Remove a
|
|
1695
|
-
async delete(
|
|
1696
|
-
const removed = await this.#profiles.delete(
|
|
1697
|
-
await this.#secrets.delete(modelProviderSecretName(
|
|
1782
|
+
/** Remove a profile and its secret together. */
|
|
1783
|
+
async delete(profileRef) {
|
|
1784
|
+
const removed = await this.#profiles.delete(profileRef);
|
|
1785
|
+
await this.#secrets.delete(modelProviderSecretName(profileRef));
|
|
1698
1786
|
return removed;
|
|
1699
1787
|
}
|
|
1700
|
-
async get(
|
|
1701
|
-
const profile = await this.#profiles.get(
|
|
1788
|
+
async get(profileRef) {
|
|
1789
|
+
const profile = await this.#profiles.get(profileRef);
|
|
1702
1790
|
return profile === void 0 ? void 0 : this.#status(profile);
|
|
1703
1791
|
}
|
|
1704
1792
|
async list() {
|
|
@@ -1717,27 +1805,32 @@ var ProviderRegistry = class {
|
|
|
1717
1805
|
const profile = await this.#profiles.getEnabled();
|
|
1718
1806
|
if (profile === void 0) return void 0;
|
|
1719
1807
|
const secret = await this.#secrets.get(
|
|
1720
|
-
modelProviderSecretName(profile.
|
|
1808
|
+
modelProviderSecretName(profile.profile_ref)
|
|
1721
1809
|
);
|
|
1722
1810
|
const options = { fetchImpl: this.#fetch, profile, secret };
|
|
1723
1811
|
return profile.adapter === "anthropic" ? new AnthropicMessagesClient(options) : new OpenAiCompatibleChatClient(options);
|
|
1724
1812
|
}
|
|
1725
|
-
/** Switch which configured
|
|
1726
|
-
async setDefaultModelProvider(
|
|
1727
|
-
return this.#status(await this.#profiles.setEnabled(
|
|
1813
|
+
/** Switch which configured profile is the default. */
|
|
1814
|
+
async setDefaultModelProvider(profileRef) {
|
|
1815
|
+
return this.#status(await this.#profiles.setEnabled(profileRef));
|
|
1728
1816
|
}
|
|
1729
1817
|
async #status(profile) {
|
|
1818
|
+
const binding = exactProviderProfileBinding(profile, []);
|
|
1730
1819
|
return {
|
|
1731
1820
|
adapter: profile.adapter,
|
|
1732
1821
|
auth_mode: profile.auth_mode,
|
|
1733
1822
|
base_url: profile.base_url,
|
|
1823
|
+
capabilities: profile.capabilities,
|
|
1734
1824
|
created_at: profile.created_at,
|
|
1735
1825
|
display_name: profile.display_name,
|
|
1736
1826
|
enabled: profile.enabled,
|
|
1737
1827
|
model: profile.model,
|
|
1738
|
-
|
|
1828
|
+
profile_ref: profile.profile_ref,
|
|
1829
|
+
profile_revision: binding.profileRevision,
|
|
1830
|
+
profile_hash: binding.profileHash,
|
|
1831
|
+
provider_kind: profile.provider_kind,
|
|
1739
1832
|
secret_configured: await this.#secrets.has(
|
|
1740
|
-
modelProviderSecretName(profile.
|
|
1833
|
+
modelProviderSecretName(profile.profile_ref)
|
|
1741
1834
|
),
|
|
1742
1835
|
updated_at: profile.updated_at
|
|
1743
1836
|
};
|
|
@@ -1746,11 +1839,11 @@ var ProviderRegistry = class {
|
|
|
1746
1839
|
|
|
1747
1840
|
// src/pi-provider-projection.ts
|
|
1748
1841
|
var PI_PROJECTED_KEY_ENV = "PI_PROVIDER_API_KEY";
|
|
1749
|
-
function piProjectionProviderId(
|
|
1750
|
-
return `byok-sdk-${
|
|
1842
|
+
function piProjectionProviderId(profileRef) {
|
|
1843
|
+
return `byok-sdk-${profileRef}`;
|
|
1751
1844
|
}
|
|
1752
1845
|
function buildPiProviderProjection(profile) {
|
|
1753
|
-
const projectedProviderId = piProjectionProviderId(profile.
|
|
1846
|
+
const projectedProviderId = piProjectionProviderId(profile.profile_ref);
|
|
1754
1847
|
return {
|
|
1755
1848
|
providers: {
|
|
1756
1849
|
[projectedProviderId]: {
|
|
@@ -1761,7 +1854,11 @@ function buildPiProviderProjection(profile) {
|
|
|
1761
1854
|
models: [
|
|
1762
1855
|
{
|
|
1763
1856
|
id: profile.model,
|
|
1764
|
-
name: profile.display_name
|
|
1857
|
+
name: profile.display_name,
|
|
1858
|
+
input: [
|
|
1859
|
+
"text",
|
|
1860
|
+
...profile.capabilities.includes("image-input") ? ["image"] : []
|
|
1861
|
+
]
|
|
1765
1862
|
}
|
|
1766
1863
|
]
|
|
1767
1864
|
}
|
|
@@ -1769,6 +1866,6 @@ function buildPiProviderProjection(profile) {
|
|
|
1769
1866
|
};
|
|
1770
1867
|
}
|
|
1771
1868
|
|
|
1772
|
-
export { AnthropicMessagesClient, BYOK_KEYS_ERROR_CODES, ByokKeysError, DEFAULT_KEYCHAIN_SECRET_STORAGE_PREFIX, DEFAULT_SECRET_ENVELOPE_PREFIX, DEFAULT_SECRET_SERVICE_PREFIX, EnvelopeScopedSecretStore, InMemoryProviderProfileStore, InMemorySecretStore, MODEL_PROVIDER_ADAPTERS,
|
|
1869
|
+
export { AnthropicMessagesClient, BYOK_KEYS_ERROR_CODES, ByokKeysError, DEFAULT_KEYCHAIN_SECRET_STORAGE_PREFIX, DEFAULT_SECRET_ENVELOPE_PREFIX, DEFAULT_SECRET_SERVICE_PREFIX, EnvelopeScopedSecretStore, InMemoryProviderProfileStore, InMemorySecretStore, MODEL_PROVIDER_ADAPTERS, MODEL_PROVIDER_KINDS, MacOsKeychainSecretStore, ModelProviderProfileSchema, OpenAiCompatibleChatClient, PI_PROJECTED_KEY_ENV, PROVIDER_AUTH_MODES, PROVIDER_MODEL_CAPABILITIES, PROVIDER_PROFILE_TRUTH_RECORD_KEY, PROVIDER_RESPONSE_MAX_BYTES, PROVIDER_TIMEOUT_MS, ProviderModelCapabilitySchema, ProviderProfileRefSchema, ProviderRegistry, SECRET_NAMESPACE_PATTERN, SECRET_NAME_PATTERN, SqliteProviderProfileStore, TruthStoreProviderProfileStore, WindowsCredentialManagerSecretStore, anthropicMessageText, assertExactProviderProfileBinding, assertLiveModelResponse, assertSecretName, assertSecretNamespace, assertSharedSecretValue, buildPiProviderProjection, chatCompletionText, classifyModelProviderHttpError, decodeStrictBase64Utf8, exactProviderProfileBinding, fetchWithProviderGuards, isLoopbackHost, isLoopbackProviderUrl, isPrivateNetworkLiteral, isSqliteAvailable, loadSqliteModule, modelApiUrl, modelMessageText, modelProviderSecretName, normalizeProviderUrl, objectValue, openSqliteDatabase, parseBoundedJsonResponse, parseModelProviderProfile, providerHeaders, readModelProviderResponse, requiredProviderSecret, runCommand, scopeSecretStore, secretScopeId, secureSqliteFilePermissions };
|
|
1773
1870
|
//# sourceMappingURL=index.js.map
|
|
1774
1871
|
//# sourceMappingURL=index.js.map
|