@byok-sdk/client 0.1.1 → 0.3.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 +46 -6
- package/dist/adapters/claude/claude-adapter.d.ts +3 -0
- package/dist/adapters/claude/resolve-bin.d.ts +2 -2
- package/dist/adapters/codex/codex-adapter.d.ts +5 -3
- package/dist/adapters/index.d.ts +1 -1
- package/dist/adapters/index.js +293 -100
- package/dist/adapters/index.js.map +1 -1
- package/dist/adapters/pi/events.d.ts +10 -37
- package/dist/adapters/pi/permission-mapping.d.ts +4 -20
- package/dist/adapters/pi/pi-adapter.d.ts +22 -0
- package/dist/adapters/pi/resolve-bin.d.ts +18 -14
- package/dist/adapters/pi/rpc-client.d.ts +1 -4
- package/dist/adapters/provider-credential-environment.d.ts +18 -0
- package/dist/bin/byok-agent.js +1839 -838
- package/dist/bin/byok-agent.js.map +1 -1
- package/dist/bin/byok-approval-mcp.js +2 -2
- package/dist/bin/byok-approval-mcp.js.map +1 -1
- package/dist/daemon/assertion-client.d.ts +68 -0
- package/dist/daemon/capabilities-client.d.ts +48 -0
- package/dist/daemon/control-protocol.d.ts +81 -4
- package/dist/daemon/create-daemon.d.ts +169 -1
- package/dist/daemon/daemon-owner.d.ts +35 -0
- package/dist/daemon/device-assertion-signer.d.ts +41 -0
- package/dist/daemon/device-keys.d.ts +15 -13
- package/dist/daemon/observer.d.ts +68 -3
- package/dist/daemon/presence-publisher.d.ts +69 -0
- package/dist/daemon/skill-pack-installer.d.ts +116 -0
- package/dist/daemon/task-runner.d.ts +129 -3
- package/dist/index.d.ts +22 -3
- package/dist/index.js +1872 -284
- package/dist/index.js.map +1 -1
- package/dist/lifecycle/create-service-lifecycle.d.ts +2 -2
- package/dist/types.d.ts +29 -0
- package/package.json +6 -5
package/dist/adapters/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { execFile, spawn, spawnSync } from 'child_process';
|
|
2
2
|
import { promisify } from 'util';
|
|
3
|
-
import { promises, realpathSync } from 'fs';
|
|
4
|
-
import
|
|
5
|
-
import path2 from 'path';
|
|
3
|
+
import { promises, existsSync, readFileSync, realpathSync } from 'fs';
|
|
4
|
+
import path3 from 'path';
|
|
6
5
|
import { fileURLToPath } from 'url';
|
|
6
|
+
import os from 'os';
|
|
7
7
|
import 'readline';
|
|
8
8
|
|
|
9
9
|
// src/adapters/pi/pi-adapter.ts
|
|
@@ -24,20 +24,50 @@ var SteerUnsupportedError = class extends Error {
|
|
|
24
24
|
this.runtimeId = runtimeId;
|
|
25
25
|
}
|
|
26
26
|
};
|
|
27
|
-
|
|
28
|
-
// src/adapters/pi/resolve-bin.ts
|
|
29
27
|
var PI_PACKAGE_NAME = "@earendil-works/pi-coding-agent";
|
|
28
|
+
function readPackageJson(dir) {
|
|
29
|
+
const candidate = path3.join(dir, "package.json");
|
|
30
|
+
if (!existsSync(candidate)) return void 0;
|
|
31
|
+
try {
|
|
32
|
+
return JSON.parse(readFileSync(candidate, "utf8"));
|
|
33
|
+
} catch {
|
|
34
|
+
return void 0;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
30
37
|
function resolvePiBin() {
|
|
31
38
|
const override = process.env.BYOK_PI_BIN;
|
|
32
39
|
if (override) {
|
|
33
|
-
return { command: override, source: "
|
|
40
|
+
return { command: override, source: "env" };
|
|
34
41
|
}
|
|
35
|
-
|
|
42
|
+
try {
|
|
43
|
+
const mainEntryUrl = import.meta.resolve(PI_PACKAGE_NAME);
|
|
44
|
+
let dir = path3.dirname(fileURLToPath(mainEntryUrl));
|
|
45
|
+
for (let depth = 0; depth < 6; depth++) {
|
|
46
|
+
const pkg = readPackageJson(dir);
|
|
47
|
+
if (pkg?.name === PI_PACKAGE_NAME) {
|
|
48
|
+
const binRel = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.pi;
|
|
49
|
+
if (binRel) {
|
|
50
|
+
return { command: path3.join(dir, binRel), source: "package" };
|
|
51
|
+
}
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
const parent = path3.dirname(dir);
|
|
55
|
+
if (parent === dir) break;
|
|
56
|
+
dir = parent;
|
|
57
|
+
}
|
|
58
|
+
} catch (cause) {
|
|
59
|
+
throw new Error(
|
|
60
|
+
`Required ${PI_PACKAGE_NAME} could not be resolved; install @byok-sdk/client dependencies or set BYOK_PI_BIN to a Node 22.19+ pi sidecar`,
|
|
61
|
+
{ cause }
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
throw new Error(
|
|
65
|
+
`Required ${PI_PACKAGE_NAME} does not expose the pi CLI; reinstall the pinned dependency or set BYOK_PI_BIN to a Node 22.19+ pi sidecar`
|
|
66
|
+
);
|
|
36
67
|
}
|
|
37
68
|
|
|
38
69
|
// src/adapters/pi/permission-mapping.ts
|
|
39
70
|
var READONLY_TOOLS = ["read", "grep", "find", "ls"];
|
|
40
|
-
var DEFAULT_ACTIVE_TOOLS = ["read", "bash", "edit", "write"];
|
|
41
71
|
function mapPermissionPolicyToPiArgs(policy) {
|
|
42
72
|
if (policy.network === false) {
|
|
43
73
|
return {
|
|
@@ -56,22 +86,18 @@ function mapPermissionPolicyToPiArgs(policy) {
|
|
|
56
86
|
const denyTools = policy.denyTools ?? [];
|
|
57
87
|
if (policy.mode === "readonly") {
|
|
58
88
|
const base = policy.allowTools ? policy.allowTools.filter((tool) => READONLY_TOOLS.includes(tool)) : [...READONLY_TOOLS];
|
|
59
|
-
|
|
60
|
-
return {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const effective = subtractDenied(base, denyTools);
|
|
65
|
-
return { ok: true, args: effective.length === 0 ? ["--no-tools"] : ["--tools", effective.join(",")] };
|
|
89
|
+
if (base.length === 0) return { ok: true, args: ["--no-tools"] };
|
|
90
|
+
return {
|
|
91
|
+
ok: true,
|
|
92
|
+
args: ["--tools", base.join(","), ...denyTools.length > 0 ? ["--exclude-tools", denyTools.join(",")] : []]
|
|
93
|
+
};
|
|
66
94
|
}
|
|
95
|
+
const args = [];
|
|
67
96
|
if (policy.allowTools && policy.allowTools.length > 0) {
|
|
68
|
-
|
|
97
|
+
args.push("--tools", policy.allowTools.join(","));
|
|
69
98
|
}
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
function subtractDenied(tools, denyTools) {
|
|
73
|
-
const denied = new Set(denyTools);
|
|
74
|
-
return tools.filter((tool) => !denied.has(tool));
|
|
99
|
+
if (denyTools.length > 0) args.push("--exclude-tools", denyTools.join(","));
|
|
100
|
+
return { ok: true, args };
|
|
75
101
|
}
|
|
76
102
|
|
|
77
103
|
// src/adapters/pi/events.ts
|
|
@@ -96,7 +122,7 @@ function mapPiMessageToAgentEvent(msg) {
|
|
|
96
122
|
output: { result: msg.result, isError: msg.isError === true }
|
|
97
123
|
};
|
|
98
124
|
}
|
|
99
|
-
case "
|
|
125
|
+
case "agent_settled":
|
|
100
126
|
return { type: "turn_end" };
|
|
101
127
|
/**
|
|
102
128
|
* `artifact` is NOT a real pi RPC message — pi's own `write` tool only
|
|
@@ -132,16 +158,22 @@ function mapPiMessageToAgentEvent(msg) {
|
|
|
132
158
|
// `recordUnmappedFrame`) can tell "known, expected, silently ignored"
|
|
133
159
|
// apart from "genuinely never seen before" (falls to `default` below).
|
|
134
160
|
case "agent_start":
|
|
161
|
+
case "agent_end":
|
|
162
|
+
// one low-level run; `agent_settled` is BYOK completion
|
|
135
163
|
case "turn_start":
|
|
136
164
|
case "turn_end":
|
|
137
|
-
// pi's own per-LLM-turn boundary, not ours
|
|
165
|
+
// pi's own per-LLM-turn boundary, not ours
|
|
138
166
|
case "message_start":
|
|
139
167
|
case "message_end":
|
|
168
|
+
case "bash_execution_update":
|
|
140
169
|
case "tool_execution_update":
|
|
141
170
|
case "queue_update":
|
|
142
171
|
case "compaction_start":
|
|
143
172
|
case "compaction_end":
|
|
144
173
|
case "auto_retry_start":
|
|
174
|
+
case "summarization_retry_scheduled":
|
|
175
|
+
case "summarization_retry_attempt_start":
|
|
176
|
+
case "summarization_retry_finished":
|
|
145
177
|
case "session_info_changed":
|
|
146
178
|
case "thinking_level_changed":
|
|
147
179
|
return void 0;
|
|
@@ -151,15 +183,20 @@ function mapPiMessageToAgentEvent(msg) {
|
|
|
151
183
|
}
|
|
152
184
|
var ROUTINE_PI_EVENT_TYPES = /* @__PURE__ */ new Set([
|
|
153
185
|
"agent_start",
|
|
186
|
+
"agent_end",
|
|
154
187
|
"turn_start",
|
|
155
188
|
"turn_end",
|
|
156
189
|
"message_start",
|
|
157
190
|
"message_end",
|
|
191
|
+
"bash_execution_update",
|
|
158
192
|
"tool_execution_update",
|
|
159
193
|
"queue_update",
|
|
160
194
|
"compaction_start",
|
|
161
195
|
"compaction_end",
|
|
162
196
|
"auto_retry_start",
|
|
197
|
+
"summarization_retry_scheduled",
|
|
198
|
+
"summarization_retry_attempt_start",
|
|
199
|
+
"summarization_retry_finished",
|
|
163
200
|
"session_info_changed",
|
|
164
201
|
"thinking_level_changed"
|
|
165
202
|
]);
|
|
@@ -293,10 +330,7 @@ var PiRpcClient = class {
|
|
|
293
330
|
* traffic. Logs once per distinct type (not per occurrence, so a
|
|
294
331
|
* repeating unmapped type can't spam stdout); the running tally is also
|
|
295
332
|
* folded into this client's exit-time error message (`buildExitError`) so
|
|
296
|
-
* a post-mortem on a failed/hung task has it without
|
|
297
|
-
* scraping. This is the exact mechanism that would have turned this
|
|
298
|
-
* task's root-cause hang (`agent_end` arriving with no mapping) into a
|
|
299
|
-
* one-line, immediate warning instead of a silent stall.
|
|
333
|
+
* a post-mortem on a failed/hung task has it without separate log scraping.
|
|
300
334
|
*/
|
|
301
335
|
recordUnmappedFrame(type) {
|
|
302
336
|
const next = (this.unmappedFrameCounts.get(type) ?? 0) + 1;
|
|
@@ -407,13 +441,8 @@ var PiRpcClient = class {
|
|
|
407
441
|
}
|
|
408
442
|
};
|
|
409
443
|
|
|
410
|
-
// src/adapters/
|
|
411
|
-
var
|
|
412
|
-
var DETECT_TIMEOUT_MS = 5e3;
|
|
413
|
-
function errorMessage(err) {
|
|
414
|
-
return err instanceof Error ? err.message : String(err);
|
|
415
|
-
}
|
|
416
|
-
var KNOWN_PROVIDER_ENV_VARS = [
|
|
444
|
+
// src/adapters/provider-credential-environment.ts
|
|
445
|
+
var PROVIDER_CREDENTIAL_ENV_NAMES = [
|
|
417
446
|
"ANTHROPIC_API_KEY",
|
|
418
447
|
"ANTHROPIC_OAUTH_TOKEN",
|
|
419
448
|
"OPENAI_API_KEY",
|
|
@@ -424,24 +453,66 @@ var KNOWN_PROVIDER_ENV_VARS = [
|
|
|
424
453
|
"MISTRAL_API_KEY",
|
|
425
454
|
"OPENROUTER_API_KEY",
|
|
426
455
|
"XAI_API_KEY",
|
|
427
|
-
// Confirmed against the installed pi's own docs/providers.md ("ZAI |
|
|
428
|
-
// `ZAI_API_KEY` | `zai`") and exercised live against real GLM traffic
|
|
429
|
-
// during this task's acceptance run — omitting it made `authPresent`
|
|
430
|
-
// silently false for a perfectly valid, working z.ai/GLM setup.
|
|
431
456
|
"ZAI_API_KEY"
|
|
432
457
|
];
|
|
458
|
+
var PROVIDER_CREDENTIAL_ENV_DENY_NAMES = [
|
|
459
|
+
...PROVIDER_CREDENTIAL_ENV_NAMES,
|
|
460
|
+
"ANT_LING_API_KEY",
|
|
461
|
+
"NVIDIA_API_KEY",
|
|
462
|
+
"CEREBRAS_API_KEY",
|
|
463
|
+
"CLOUDFLARE_API_KEY",
|
|
464
|
+
"AI_GATEWAY_API_KEY",
|
|
465
|
+
"ZAI_CODING_CN_API_KEY",
|
|
466
|
+
"OPENCODE_API_KEY",
|
|
467
|
+
"RADIUS_API_KEY",
|
|
468
|
+
"FIREWORKS_API_KEY",
|
|
469
|
+
"TOGETHER_API_KEY",
|
|
470
|
+
"BASETEN_API_KEY",
|
|
471
|
+
"KIMI_API_KEY",
|
|
472
|
+
"MINIMAX_API_KEY",
|
|
473
|
+
"MINIMAX_CN_API_KEY",
|
|
474
|
+
"QWEN_TOKEN_PLAN_API_KEY",
|
|
475
|
+
"QWEN_TOKEN_PLAN_CN_API_KEY",
|
|
476
|
+
"XIAOMI_API_KEY",
|
|
477
|
+
"XIAOMI_TOKEN_PLAN_CN_API_KEY",
|
|
478
|
+
"XIAOMI_TOKEN_PLAN_AMS_API_KEY",
|
|
479
|
+
"XIAOMI_TOKEN_PLAN_SGP_API_KEY",
|
|
480
|
+
"AWS_ACCESS_KEY_ID",
|
|
481
|
+
"AWS_SECRET_ACCESS_KEY",
|
|
482
|
+
"AWS_SESSION_TOKEN",
|
|
483
|
+
"GOOGLE_APPLICATION_CREDENTIALS",
|
|
484
|
+
// Reserved by the keys-owned Pi projection. It must never be inherited
|
|
485
|
+
// from the daemon; the launcher deletes any ambient copy and injects only
|
|
486
|
+
// the exact credential it just resolved from OS custody.
|
|
487
|
+
"PI_PROVIDER_API_KEY"
|
|
488
|
+
];
|
|
489
|
+
function withoutProviderCredentials(env) {
|
|
490
|
+
const sanitized = { ...env };
|
|
491
|
+
for (const name of PROVIDER_CREDENTIAL_ENV_DENY_NAMES) {
|
|
492
|
+
delete sanitized[name];
|
|
493
|
+
}
|
|
494
|
+
return sanitized;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// src/adapters/pi/pi-adapter.ts
|
|
498
|
+
var execFileAsync = promisify(execFile);
|
|
499
|
+
var DETECT_TIMEOUT_MS = 5e3;
|
|
500
|
+
function errorMessage(err) {
|
|
501
|
+
return err instanceof Error ? err.message : String(err);
|
|
502
|
+
}
|
|
433
503
|
var PiAdapter = class {
|
|
434
504
|
constructor(options = {}) {
|
|
435
505
|
this.options = options;
|
|
436
506
|
}
|
|
437
507
|
options;
|
|
438
508
|
id = "pi";
|
|
509
|
+
supportsDispatchSelection = true;
|
|
439
510
|
async detect() {
|
|
440
|
-
const bin = this.resolveBin();
|
|
441
511
|
try {
|
|
512
|
+
const bin = this.resolveBin();
|
|
442
513
|
const { stdout, stderr } = await execFileAsync(bin.command, ["--version"], { timeout: DETECT_TIMEOUT_MS });
|
|
443
514
|
const version = stdout.trim() || stderr.trim();
|
|
444
|
-
const authPresent =
|
|
515
|
+
const authPresent = PROVIDER_CREDENTIAL_ENV_NAMES.some((name) => process.env[name] !== void 0);
|
|
445
516
|
return { present: true, version, authPresent };
|
|
446
517
|
} catch {
|
|
447
518
|
return { present: false };
|
|
@@ -460,7 +531,7 @@ var PiAdapter = class {
|
|
|
460
531
|
* variable beyond the platform baseline (`daemon/environment.ts`).
|
|
461
532
|
*/
|
|
462
533
|
environmentRequirements() {
|
|
463
|
-
return { credentialNames:
|
|
534
|
+
return { credentialNames: PROVIDER_CREDENTIAL_ENV_NAMES };
|
|
464
535
|
}
|
|
465
536
|
async start(task, ctx) {
|
|
466
537
|
if (typeof task.instruction !== "string") {
|
|
@@ -472,12 +543,45 @@ var PiAdapter = class {
|
|
|
472
543
|
}
|
|
473
544
|
const bin = this.resolveBin();
|
|
474
545
|
const resumeSessionId = task.sessionRef;
|
|
475
|
-
const
|
|
546
|
+
const piArgs = ["--mode", "rpc", ...resumeSessionId ? ["--session", resumeSessionId] : [], ...mapping.args];
|
|
547
|
+
const selection = task.dispatchSelection;
|
|
548
|
+
let command = bin.command;
|
|
549
|
+
let args = piArgs;
|
|
550
|
+
if (selection !== void 0) {
|
|
551
|
+
if (selection.lane !== "byok" || selection.runtimeId !== "pi") {
|
|
552
|
+
throw new PolicyUnsupportedError(
|
|
553
|
+
`pi adapter cannot execute ${selection.lane} selection for runtime ${selection.runtimeId}`
|
|
554
|
+
);
|
|
555
|
+
}
|
|
556
|
+
const launcher = this.options.byokLauncher;
|
|
557
|
+
if (launcher === void 0) {
|
|
558
|
+
throw new PolicyUnsupportedError(
|
|
559
|
+
"pi BYOK selection requires a configured credential-custody launcher"
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
command = launcher.command;
|
|
563
|
+
args = [
|
|
564
|
+
...launcher.args ?? [],
|
|
565
|
+
"--pi-bin",
|
|
566
|
+
bin.command,
|
|
567
|
+
"--profile-db",
|
|
568
|
+
launcher.profileDbPath,
|
|
569
|
+
"--session-dir",
|
|
570
|
+
launcher.sessionDir,
|
|
571
|
+
...launcher.secretServicePrefix ? ["--secret-service-prefix", launcher.secretServicePrefix] : [],
|
|
572
|
+
"--provider",
|
|
573
|
+
selection.providerId,
|
|
574
|
+
"--model",
|
|
575
|
+
selection.modelId,
|
|
576
|
+
"--",
|
|
577
|
+
...piArgs
|
|
578
|
+
];
|
|
579
|
+
}
|
|
476
580
|
const rpc = new PiRpcClient({
|
|
477
|
-
command
|
|
581
|
+
command,
|
|
478
582
|
args,
|
|
479
583
|
cwd: ctx.workspaceDir,
|
|
480
|
-
env: ctx.env,
|
|
584
|
+
env: selection === void 0 ? ctx.env : withoutProviderCredentials(ctx.env),
|
|
481
585
|
spawnFn: this.options.spawnFn
|
|
482
586
|
});
|
|
483
587
|
const response = await rpc.send({ type: "prompt", message: task.instruction });
|
|
@@ -496,7 +600,7 @@ var PiAdapter = class {
|
|
|
496
600
|
throw err;
|
|
497
601
|
}
|
|
498
602
|
}
|
|
499
|
-
return new PiSession(sessionRef, rpc);
|
|
603
|
+
return new PiSession(sessionRef, rpc, selection);
|
|
500
604
|
}
|
|
501
605
|
resolveBin() {
|
|
502
606
|
return (this.options.resolveBin ?? resolvePiBin)();
|
|
@@ -524,12 +628,14 @@ async function resolveFreshSessionId(rpc) {
|
|
|
524
628
|
);
|
|
525
629
|
}
|
|
526
630
|
var PiSession = class {
|
|
527
|
-
constructor(sessionRef, rpc) {
|
|
631
|
+
constructor(sessionRef, rpc, selection) {
|
|
528
632
|
this.sessionRef = sessionRef;
|
|
529
633
|
this.rpc = rpc;
|
|
634
|
+
this.selection = selection;
|
|
530
635
|
}
|
|
531
636
|
sessionRef;
|
|
532
637
|
rpc;
|
|
638
|
+
selection;
|
|
533
639
|
get events() {
|
|
534
640
|
const rpc = this.rpc;
|
|
535
641
|
return {
|
|
@@ -558,6 +664,12 @@ var PiSession = class {
|
|
|
558
664
|
if (typeof task.instruction !== "string") {
|
|
559
665
|
throw new PolicyUnsupportedError("pi adapter only supports string instructions in M0 (no blob-ref fetch yet)");
|
|
560
666
|
}
|
|
667
|
+
const requestedSelection = task.dispatchSelection;
|
|
668
|
+
if (requestedSelection !== void 0 && (this.selection?.lane !== "byok" || requestedSelection.lane !== "byok" || requestedSelection.runtimeId !== "pi" || requestedSelection.providerId !== this.selection.providerId || requestedSelection.modelId !== this.selection.modelId)) {
|
|
669
|
+
throw new PolicyUnsupportedError(
|
|
670
|
+
"pi persistent session cannot change its authoritative BYOK provider/model selection"
|
|
671
|
+
);
|
|
672
|
+
}
|
|
561
673
|
await this.rpc.send({ type: "prompt", message: task.instruction, streamingBehavior: "followUp" });
|
|
562
674
|
}
|
|
563
675
|
async interrupt() {
|
|
@@ -584,7 +696,7 @@ function resolveApprovalMcpBin() {
|
|
|
584
696
|
if (override) {
|
|
585
697
|
return { command: override, args: [], source: "env" };
|
|
586
698
|
}
|
|
587
|
-
const distBin =
|
|
699
|
+
const distBin = path3.join(path3.dirname(fileURLToPath(import.meta.url)), "bin", "byok-approval-mcp.js");
|
|
588
700
|
return { command: process.execPath, args: [distBin], source: "dist" };
|
|
589
701
|
}
|
|
590
702
|
|
|
@@ -615,7 +727,7 @@ function mapPermissionPolicyToClaudeArgs(policy) {
|
|
|
615
727
|
}
|
|
616
728
|
if (policy.mode === "readonly") {
|
|
617
729
|
const base = policy.allowTools ? policy.allowTools.filter((tool) => READONLY_TOOLS2.includes(tool)) : [...READONLY_TOOLS2];
|
|
618
|
-
const effective =
|
|
730
|
+
const effective = subtractDenied(base, denyTools);
|
|
619
731
|
return { ok: true, args: ["--permission-mode", "default", "--tools", effective.join(",")] };
|
|
620
732
|
}
|
|
621
733
|
if (denyTools.length > 0) {
|
|
@@ -632,7 +744,7 @@ function mapPermissionPolicyToClaudeArgs(policy) {
|
|
|
632
744
|
}
|
|
633
745
|
return { ok: true, args };
|
|
634
746
|
}
|
|
635
|
-
function
|
|
747
|
+
function subtractDenied(tools, denyTools) {
|
|
636
748
|
const denied = new Set(denyTools);
|
|
637
749
|
return tools.filter((tool) => !denied.has(tool));
|
|
638
750
|
}
|
|
@@ -664,7 +776,7 @@ var EXTENSION_CONTENT_TYPES = {
|
|
|
664
776
|
".yml": "application/yaml"
|
|
665
777
|
};
|
|
666
778
|
function guessContentType(filePath) {
|
|
667
|
-
const ext =
|
|
779
|
+
const ext = path3.extname(filePath).toLowerCase();
|
|
668
780
|
return EXTENSION_CONTENT_TYPES[ext] ?? "application/octet-stream";
|
|
669
781
|
}
|
|
670
782
|
function mapAssistant(msg, correlation) {
|
|
@@ -736,11 +848,11 @@ function tryBuildArtifactEvent(msg, workspaceDir) {
|
|
|
736
848
|
const filePath = toolUseResult && typeof toolUseResult.filePath === "string" ? toolUseResult.filePath : void 0;
|
|
737
849
|
if (!filePath) return void 0;
|
|
738
850
|
const realWorkspaceDir = tryRealpath(workspaceDir) ?? workspaceDir;
|
|
739
|
-
const fileDir =
|
|
851
|
+
const fileDir = path3.dirname(filePath);
|
|
740
852
|
const realFileDir = tryRealpath(fileDir) ?? fileDir;
|
|
741
|
-
const realFilePath =
|
|
742
|
-
const relative =
|
|
743
|
-
if (relative === "" || relative.startsWith("..") ||
|
|
853
|
+
const realFilePath = path3.join(realFileDir, path3.basename(filePath));
|
|
854
|
+
const relative = path3.relative(realWorkspaceDir, realFilePath);
|
|
855
|
+
if (relative === "" || relative.startsWith("..") || path3.isAbsolute(relative)) {
|
|
744
856
|
return void 0;
|
|
745
857
|
}
|
|
746
858
|
return { type: "artifact", name: relative, contentType: guessContentType(filePath) };
|
|
@@ -982,7 +1094,7 @@ var APPROVAL_TOOL_NAME = "approval_prompt";
|
|
|
982
1094
|
var APPROVAL_MCP_SERVER_NAME = "byokapproval";
|
|
983
1095
|
var execFileAsync2 = promisify(execFile);
|
|
984
1096
|
var DETECT_TIMEOUT_MS2 = 5e3;
|
|
985
|
-
async function
|
|
1097
|
+
async function cleanupMcpConfigDir(dir) {
|
|
986
1098
|
if (!dir) return;
|
|
987
1099
|
await promises.rm(dir, { recursive: true, force: true }).catch(() => {
|
|
988
1100
|
});
|
|
@@ -992,6 +1104,7 @@ var ClaudeAdapter = class {
|
|
|
992
1104
|
this.options = options;
|
|
993
1105
|
}
|
|
994
1106
|
options;
|
|
1107
|
+
supportsDispatchSelection = true;
|
|
995
1108
|
id = "claude";
|
|
996
1109
|
async detect() {
|
|
997
1110
|
const bin = this.resolveBin();
|
|
@@ -1005,7 +1118,13 @@ var ClaudeAdapter = class {
|
|
|
1005
1118
|
}
|
|
1006
1119
|
}
|
|
1007
1120
|
capabilities() {
|
|
1008
|
-
return {
|
|
1121
|
+
return {
|
|
1122
|
+
steer: false,
|
|
1123
|
+
resume: true,
|
|
1124
|
+
approvalInteractive: true,
|
|
1125
|
+
mcpToolsets: true,
|
|
1126
|
+
permissionModes: ["auto", "readonly", "plan", "confirm"]
|
|
1127
|
+
};
|
|
1009
1128
|
}
|
|
1010
1129
|
/**
|
|
1011
1130
|
* M5: deliberate product-boundary decision, not an oversight — byok's
|
|
@@ -1031,42 +1150,51 @@ var ClaudeAdapter = class {
|
|
|
1031
1150
|
if (!mapping.ok) {
|
|
1032
1151
|
throw new PolicyUnsupportedError(mapping.reason ?? "policy rejected by claude adapter");
|
|
1033
1152
|
}
|
|
1034
|
-
|
|
1153
|
+
const modelId = subscriptionModel(task, "claude");
|
|
1154
|
+
let mcpConfigDir;
|
|
1155
|
+
const taskMcpServers = ctx.mcpServers ?? {};
|
|
1156
|
+
const needsMcpConfig = mapping.needsApprovalMcp || Object.keys(taskMcpServers).length > 0;
|
|
1035
1157
|
if (mapping.needsApprovalMcp) {
|
|
1036
1158
|
if (!ctx.approvalChannel) {
|
|
1037
1159
|
throw new PolicyUnsupportedError(
|
|
1038
1160
|
'claude adapter requires policy.mode "confirm" to be started with an approval channel (TaskContext.approvalChannel) \u2014 none was provided'
|
|
1039
1161
|
);
|
|
1040
1162
|
}
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1163
|
+
if (Object.prototype.hasOwnProperty.call(taskMcpServers, APPROVAL_MCP_SERVER_NAME)) {
|
|
1164
|
+
throw new PolicyUnsupportedError(
|
|
1165
|
+
`MCP server name "${APPROVAL_MCP_SERVER_NAME}" is reserved by the claude approval channel`
|
|
1166
|
+
);
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
if (needsMcpConfig) {
|
|
1170
|
+
mcpConfigDir = await promises.mkdtemp(path3.join(os.tmpdir(), "byok-mcp-"));
|
|
1171
|
+
await promises.chmod(mcpConfigDir, 448).catch(() => {
|
|
1044
1172
|
});
|
|
1045
|
-
const mcpConfigPath =
|
|
1046
|
-
const
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1173
|
+
const mcpConfigPath = path3.join(mcpConfigDir, "mcp-config.json");
|
|
1174
|
+
const mcpServers = { ...taskMcpServers };
|
|
1175
|
+
if (mapping.needsApprovalMcp) {
|
|
1176
|
+
const approvalChannel = ctx.approvalChannel;
|
|
1177
|
+
if (!approvalChannel) throw new Error("unreachable: approval channel checked above");
|
|
1178
|
+
const approvalMcpBin = (this.options.resolveApprovalMcpBin ?? resolveApprovalMcpBin)();
|
|
1179
|
+
mcpServers[APPROVAL_MCP_SERVER_NAME] = {
|
|
1180
|
+
command: approvalMcpBin.command,
|
|
1181
|
+
args: approvalMcpBin.args,
|
|
1182
|
+
env: {
|
|
1183
|
+
BYOK_STORE_DIR: approvalChannel.storeDir,
|
|
1184
|
+
BYOK_PRODUCT_ID: approvalChannel.productId,
|
|
1185
|
+
BYOK_TASK_ID: approvalChannel.taskId,
|
|
1186
|
+
BYOK_APPROVAL_TIMEOUT_MS: String(approvalChannel.timeoutMs)
|
|
1057
1187
|
}
|
|
1058
|
-
}
|
|
1059
|
-
}
|
|
1060
|
-
await promises.writeFile(mcpConfigPath, JSON.stringify(
|
|
1188
|
+
};
|
|
1189
|
+
}
|
|
1190
|
+
await promises.writeFile(mcpConfigPath, JSON.stringify({ mcpServers }), { mode: 384 });
|
|
1061
1191
|
mapping.args = [
|
|
1062
1192
|
...mapping.args,
|
|
1063
|
-
"--permission-prompt-tool",
|
|
1064
|
-
`mcp__${APPROVAL_MCP_SERVER_NAME}__${APPROVAL_TOOL_NAME}`,
|
|
1193
|
+
...mapping.needsApprovalMcp ? ["--permission-prompt-tool", `mcp__${APPROVAL_MCP_SERVER_NAME}__${APPROVAL_TOOL_NAME}`] : [],
|
|
1065
1194
|
"--mcp-config",
|
|
1066
1195
|
mcpConfigPath,
|
|
1067
|
-
//
|
|
1068
|
-
//
|
|
1069
|
-
// the only MCP server this invocation should ever see.
|
|
1196
|
+
// The generated file is the complete task-scoped MCP authority.
|
|
1197
|
+
// Never merge ambient user/project MCP configuration into it.
|
|
1070
1198
|
"--strict-mcp-config"
|
|
1071
1199
|
];
|
|
1072
1200
|
}
|
|
@@ -1083,6 +1211,7 @@ var ClaudeAdapter = class {
|
|
|
1083
1211
|
// "Error: When using --print, --output-format=stream-json requires
|
|
1084
1212
|
// --verbose", before spawning any model call.
|
|
1085
1213
|
"--verbose",
|
|
1214
|
+
...modelId ? ["--model", modelId] : [],
|
|
1086
1215
|
...resumeSessionId ? ["--resume", resumeSessionId] : [],
|
|
1087
1216
|
...mapping.args
|
|
1088
1217
|
];
|
|
@@ -1090,7 +1219,7 @@ var ClaudeAdapter = class {
|
|
|
1090
1219
|
command: bin.command,
|
|
1091
1220
|
args,
|
|
1092
1221
|
cwd: ctx.workspaceDir,
|
|
1093
|
-
env: ctx.env,
|
|
1222
|
+
env: withoutProviderCredentials(ctx.env),
|
|
1094
1223
|
spawnFn: this.options.spawnFn
|
|
1095
1224
|
});
|
|
1096
1225
|
client.writeUserMessage(task.instruction);
|
|
@@ -1099,17 +1228,24 @@ var ClaudeAdapter = class {
|
|
|
1099
1228
|
sessionRef = await client.waitForInit();
|
|
1100
1229
|
} catch (err) {
|
|
1101
1230
|
client.kill();
|
|
1102
|
-
await
|
|
1231
|
+
await cleanupMcpConfigDir(mcpConfigDir);
|
|
1103
1232
|
throw err;
|
|
1104
1233
|
}
|
|
1105
1234
|
if (resumeSessionId !== void 0 && sessionRef !== resumeSessionId) {
|
|
1106
1235
|
client.kill();
|
|
1107
|
-
await
|
|
1236
|
+
await cleanupMcpConfigDir(mcpConfigDir);
|
|
1108
1237
|
throw new Error(
|
|
1109
1238
|
`claude --resume echoed a different session id than requested (requested ${resumeSessionId}, got ${sessionRef}) \u2014 refusing to continue in a possibly-wrong session (fail-closed)`
|
|
1110
1239
|
);
|
|
1111
1240
|
}
|
|
1112
|
-
return new ClaudeSession(
|
|
1241
|
+
return new ClaudeSession(
|
|
1242
|
+
sessionRef,
|
|
1243
|
+
client,
|
|
1244
|
+
ctx.workspaceDir,
|
|
1245
|
+
ctx.approvalChannel,
|
|
1246
|
+
mcpConfigDir,
|
|
1247
|
+
modelId
|
|
1248
|
+
);
|
|
1113
1249
|
}
|
|
1114
1250
|
/**
|
|
1115
1251
|
* `claude auth status --json` is claude's OWN non-secret login-state
|
|
@@ -1143,19 +1279,31 @@ var ClaudeAdapter = class {
|
|
|
1143
1279
|
return (this.options.resolveBin ?? resolveClaudeBin)();
|
|
1144
1280
|
}
|
|
1145
1281
|
};
|
|
1282
|
+
function subscriptionModel(task, runtimeId) {
|
|
1283
|
+
const selection = task.dispatchSelection;
|
|
1284
|
+
if (selection === void 0) return void 0;
|
|
1285
|
+
if (selection.lane !== "subscription" || selection.runtimeId !== runtimeId) {
|
|
1286
|
+
throw new PolicyUnsupportedError(
|
|
1287
|
+
`claude adapter cannot execute ${selection.lane} selection for runtime ${selection.runtimeId}`
|
|
1288
|
+
);
|
|
1289
|
+
}
|
|
1290
|
+
return selection.modelId;
|
|
1291
|
+
}
|
|
1146
1292
|
var ClaudeSession = class {
|
|
1147
|
-
constructor(sessionRef, client, workspaceDir, approvalChannel,
|
|
1293
|
+
constructor(sessionRef, client, workspaceDir, approvalChannel, mcpConfigDir, modelId) {
|
|
1148
1294
|
this.sessionRef = sessionRef;
|
|
1149
1295
|
this.client = client;
|
|
1150
1296
|
this.workspaceDir = workspaceDir;
|
|
1151
1297
|
this.approvalChannel = approvalChannel;
|
|
1152
|
-
this.
|
|
1298
|
+
this.mcpConfigDir = mcpConfigDir;
|
|
1299
|
+
this.modelId = modelId;
|
|
1153
1300
|
}
|
|
1154
1301
|
sessionRef;
|
|
1155
1302
|
client;
|
|
1156
1303
|
workspaceDir;
|
|
1157
1304
|
approvalChannel;
|
|
1158
|
-
|
|
1305
|
+
mcpConfigDir;
|
|
1306
|
+
modelId;
|
|
1159
1307
|
correlation = createToolUseCorrelation();
|
|
1160
1308
|
get events() {
|
|
1161
1309
|
const client = this.client;
|
|
@@ -1206,6 +1354,12 @@ var ClaudeSession = class {
|
|
|
1206
1354
|
if (typeof task.instruction !== "string") {
|
|
1207
1355
|
throw new PolicyUnsupportedError("claude adapter only supports string instructions in M2 (no blob-ref fetch yet)");
|
|
1208
1356
|
}
|
|
1357
|
+
const requestedModel = subscriptionModel(task, "claude");
|
|
1358
|
+
if (requestedModel !== void 0 && requestedModel !== this.modelId) {
|
|
1359
|
+
throw new PolicyUnsupportedError(
|
|
1360
|
+
`claude persistent session cannot change model from ${this.modelId ?? "(legacy default)"} to ${requestedModel}`
|
|
1361
|
+
);
|
|
1362
|
+
}
|
|
1209
1363
|
this.client.writeUserMessage(task.instruction);
|
|
1210
1364
|
}
|
|
1211
1365
|
/**
|
|
@@ -1225,7 +1379,7 @@ var ClaudeSession = class {
|
|
|
1225
1379
|
}
|
|
1226
1380
|
async close() {
|
|
1227
1381
|
this.client.kill();
|
|
1228
|
-
await
|
|
1382
|
+
await cleanupMcpConfigDir(this.mcpConfigDir);
|
|
1229
1383
|
}
|
|
1230
1384
|
/**
|
|
1231
1385
|
* M4 Phase 3: routes into the out-of-band approval channel `start()`
|
|
@@ -1389,8 +1543,8 @@ function extractArtifactEvents(changes, workspaceDir) {
|
|
|
1389
1543
|
const absolutePath = typeof change.path === "string" ? change.path : void 0;
|
|
1390
1544
|
const kind = typeof change.kind === "string" ? change.kind : void 0;
|
|
1391
1545
|
if (!absolutePath || kind === "delete") continue;
|
|
1392
|
-
const relative =
|
|
1393
|
-
if (relative.length === 0 || relative.startsWith("..") ||
|
|
1546
|
+
const relative = path3.relative(workspaceDir, absolutePath);
|
|
1547
|
+
if (relative.length === 0 || relative.startsWith("..") || path3.isAbsolute(relative)) continue;
|
|
1394
1548
|
events.push({ type: "artifact", name: relative, contentType: guessContentType2(relative) });
|
|
1395
1549
|
}
|
|
1396
1550
|
return events;
|
|
@@ -1411,7 +1565,7 @@ var CONTENT_TYPE_BY_EXTENSION = {
|
|
|
1411
1565
|
".csv": "text/csv"
|
|
1412
1566
|
};
|
|
1413
1567
|
function guessContentType2(relativePath) {
|
|
1414
|
-
return CONTENT_TYPE_BY_EXTENSION[
|
|
1568
|
+
return CONTENT_TYPE_BY_EXTENSION[path3.extname(relativePath).toLowerCase()] ?? "application/octet-stream";
|
|
1415
1569
|
}
|
|
1416
1570
|
function extractErrorMessage(rawError) {
|
|
1417
1571
|
if (typeof rawError === "string") return rawError;
|
|
@@ -1549,6 +1703,7 @@ var CodexAdapter = class {
|
|
|
1549
1703
|
this.options = options;
|
|
1550
1704
|
}
|
|
1551
1705
|
options;
|
|
1706
|
+
supportsDispatchSelection = true;
|
|
1552
1707
|
id = "codex";
|
|
1553
1708
|
async detect() {
|
|
1554
1709
|
const bin = this.resolveBin();
|
|
@@ -1572,9 +1727,10 @@ var CodexAdapter = class {
|
|
|
1572
1727
|
* Two independently-verified channel gotchas apply here, the "pi lesson"
|
|
1573
1728
|
* yet again:
|
|
1574
1729
|
* - `codex login status`'s human-readable "Logged in using ChatGPT"
|
|
1575
|
-
* message prints on STDERR, not stdout
|
|
1576
|
-
*
|
|
1577
|
-
*
|
|
1730
|
+
* message prints on STDERR, not stdout — both streams are checked
|
|
1731
|
+
* here for exactly that reason. pi's `--version` is the same class of
|
|
1732
|
+
* hazard from the other direction: its channel has moved between pi
|
|
1733
|
+
* releases (see ../pi/pi-adapter.ts), so neither stream is assumed.
|
|
1578
1734
|
* - The NOT-logged-in message/exit-code shape was deliberately never
|
|
1579
1735
|
* empirically tested: this machine has a real, live ChatGPT login, and
|
|
1580
1736
|
* running `codex logout` to observe the negative case would have
|
|
@@ -1620,17 +1776,20 @@ ${withStreams.stderr ?? ""}`);
|
|
|
1620
1776
|
if (!mapping.ok) {
|
|
1621
1777
|
throw new PolicyUnsupportedError(mapping.reason ?? "policy rejected by codex adapter");
|
|
1622
1778
|
}
|
|
1779
|
+
const modelId = subscriptionModel2(task);
|
|
1623
1780
|
const bin = this.resolveBin();
|
|
1624
1781
|
const queue = new AsyncQueue();
|
|
1625
1782
|
const recordUnmapped = makeUnmappedFrameRecorder(/* @__PURE__ */ new Map());
|
|
1626
1783
|
const workspaceDir = await resolveRealWorkspaceDir(ctx.workspaceDir);
|
|
1784
|
+
const runtimeEnv = withoutProviderCredentials(ctx.env);
|
|
1627
1785
|
const { sessionRef, runner } = await runCodexTurn({
|
|
1628
1786
|
command: bin.command,
|
|
1629
1787
|
resumeRef: task.sessionRef,
|
|
1630
1788
|
instruction: task.instruction,
|
|
1789
|
+
modelId,
|
|
1631
1790
|
policyArgs: mapping.args,
|
|
1632
1791
|
cwd: ctx.workspaceDir,
|
|
1633
|
-
env:
|
|
1792
|
+
env: runtimeEnv,
|
|
1634
1793
|
spawnFn: this.options.spawnFn,
|
|
1635
1794
|
workspaceDir,
|
|
1636
1795
|
queue,
|
|
@@ -1647,7 +1806,8 @@ ${withStreams.stderr ?? ""}`);
|
|
|
1647
1806
|
queue,
|
|
1648
1807
|
recordUnmapped,
|
|
1649
1808
|
initialRunner: runner,
|
|
1650
|
-
preparedGit: ctx.gitWorkspace !== void 0
|
|
1809
|
+
preparedGit: ctx.gitWorkspace !== void 0,
|
|
1810
|
+
modelId
|
|
1651
1811
|
});
|
|
1652
1812
|
}
|
|
1653
1813
|
resolveBin() {
|
|
@@ -1668,12 +1828,25 @@ function makeUnmappedFrameRecorder(counts) {
|
|
|
1668
1828
|
}
|
|
1669
1829
|
};
|
|
1670
1830
|
}
|
|
1671
|
-
function buildArgv(resumeRef, policyArgs, instruction, preparedGit = false) {
|
|
1831
|
+
function buildArgv(resumeRef, policyArgs, instruction, modelId, preparedGit = false) {
|
|
1672
1832
|
const base = resumeRef !== void 0 ? ["exec", "resume", resumeRef] : ["exec"];
|
|
1673
|
-
return [
|
|
1833
|
+
return [
|
|
1834
|
+
...base,
|
|
1835
|
+
"--json",
|
|
1836
|
+
...modelId ? ["--model", modelId] : [],
|
|
1837
|
+
...preparedGit ? [] : ["--skip-git-repo-check"],
|
|
1838
|
+
...policyArgs,
|
|
1839
|
+
instruction
|
|
1840
|
+
];
|
|
1674
1841
|
}
|
|
1675
1842
|
async function runCodexTurn(params) {
|
|
1676
|
-
const argv = buildArgv(
|
|
1843
|
+
const argv = buildArgv(
|
|
1844
|
+
params.resumeRef,
|
|
1845
|
+
params.policyArgs,
|
|
1846
|
+
params.instruction,
|
|
1847
|
+
params.modelId,
|
|
1848
|
+
params.preparedGit
|
|
1849
|
+
);
|
|
1677
1850
|
let firstLineSettled = false;
|
|
1678
1851
|
let resolveFirstLine;
|
|
1679
1852
|
let rejectFirstLine;
|
|
@@ -1774,6 +1947,7 @@ var CodexSession = class {
|
|
|
1774
1947
|
queue;
|
|
1775
1948
|
recordUnmapped;
|
|
1776
1949
|
preparedGit;
|
|
1950
|
+
modelId;
|
|
1777
1951
|
currentRunner;
|
|
1778
1952
|
closed = false;
|
|
1779
1953
|
constructor(options) {
|
|
@@ -1785,6 +1959,7 @@ var CodexSession = class {
|
|
|
1785
1959
|
this.queue = options.queue;
|
|
1786
1960
|
this.recordUnmapped = options.recordUnmapped;
|
|
1787
1961
|
this.preparedGit = options.preparedGit;
|
|
1962
|
+
this.modelId = options.modelId;
|
|
1788
1963
|
this.currentRunner = options.initialRunner;
|
|
1789
1964
|
void this.forgetRunnerOnceClosed(options.initialRunner);
|
|
1790
1965
|
}
|
|
@@ -1845,6 +2020,13 @@ var CodexSession = class {
|
|
|
1845
2020
|
if (!mapping.ok) {
|
|
1846
2021
|
throw new PolicyUnsupportedError(mapping.reason ?? "policy rejected by codex adapter");
|
|
1847
2022
|
}
|
|
2023
|
+
const requestedModel = subscriptionModel2(task);
|
|
2024
|
+
if (requestedModel !== void 0 && requestedModel !== this.modelId) {
|
|
2025
|
+
throw new PolicyUnsupportedError(
|
|
2026
|
+
`codex persistent session cannot change model from ${this.modelId ?? "(legacy default)"} to ${requestedModel}`
|
|
2027
|
+
);
|
|
2028
|
+
}
|
|
2029
|
+
const modelId = this.modelId;
|
|
1848
2030
|
const resumeRef = this.sessionRef;
|
|
1849
2031
|
let sessionRef;
|
|
1850
2032
|
let runner;
|
|
@@ -1853,9 +2035,10 @@ var CodexSession = class {
|
|
|
1853
2035
|
command: this.command,
|
|
1854
2036
|
resumeRef,
|
|
1855
2037
|
instruction: task.instruction,
|
|
2038
|
+
modelId,
|
|
1856
2039
|
policyArgs: mapping.args,
|
|
1857
2040
|
cwd: this.workspaceDir,
|
|
1858
|
-
env: this.env,
|
|
2041
|
+
env: withoutProviderCredentials(this.env),
|
|
1859
2042
|
spawnFn: this.spawnFn,
|
|
1860
2043
|
workspaceDir: this.workspaceDir,
|
|
1861
2044
|
queue: this.queue,
|
|
@@ -1915,6 +2098,16 @@ var CodexSession = class {
|
|
|
1915
2098
|
);
|
|
1916
2099
|
}
|
|
1917
2100
|
};
|
|
2101
|
+
function subscriptionModel2(task) {
|
|
2102
|
+
const selection = task.dispatchSelection;
|
|
2103
|
+
if (selection === void 0) return void 0;
|
|
2104
|
+
if (selection.lane !== "subscription" || selection.runtimeId !== "codex") {
|
|
2105
|
+
throw new PolicyUnsupportedError(
|
|
2106
|
+
`codex adapter cannot execute ${selection.lane} selection for runtime ${selection.runtimeId}`
|
|
2107
|
+
);
|
|
2108
|
+
}
|
|
2109
|
+
return selection.modelId;
|
|
2110
|
+
}
|
|
1918
2111
|
|
|
1919
2112
|
export { ClaudeAdapter, CodexAdapter, PI_PACKAGE_NAME, PiAdapter };
|
|
1920
2113
|
//# sourceMappingURL=index.js.map
|