@agentproto/driver-agent-cli 1.2.0 → 2.0.1
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/{chunk-TJHKDKCU.mjs → chunk-H43KNN32.mjs} +197 -22
- package/dist/chunk-H43KNN32.mjs.map +1 -0
- package/dist/index.d.ts +65 -4
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/manifest/index.d.ts +3 -2
- package/dist/manifest/index.mjs +2 -2
- package/dist/{schema-0Nwo-i_w.d.ts → schema-BqxySb_M.d.ts} +207 -0
- package/package.json +2 -2
- package/dist/chunk-TJHKDKCU.mjs.map +0 -1
|
@@ -6,7 +6,7 @@ import { existsSync, readFileSync, mkdirSync, writeFileSync, rmSync, rmdirSync,
|
|
|
6
6
|
import { createInterface } from 'readline';
|
|
7
7
|
import { join } from 'path';
|
|
8
8
|
import { randomUUID } from 'crypto';
|
|
9
|
-
import { tmpdir } from 'os';
|
|
9
|
+
import { tmpdir, homedir } from 'os';
|
|
10
10
|
import { createDoctype } from '@agentproto/define-doctype';
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -212,6 +212,14 @@ var capabilitiesSchema = z.object({
|
|
|
212
212
|
var modeSchema = z.object({
|
|
213
213
|
id: z.string().regex(MODE_ID_PATTERN),
|
|
214
214
|
description: z.string().optional(),
|
|
215
|
+
// Which orthogonal session-config axis this mode expresses (SPEC-tracked in
|
|
216
|
+
// @agentproto/runtime's session-config.ts). Narrowed to only "context" (SPEC
|
|
217
|
+
// §3.4a): route is derived from the model catalog (@route), not a manifest
|
|
218
|
+
// mode, and posture comes from the harness's own ACP mode registry
|
|
219
|
+
// (SessionModeState.availableModes) — neither is a `modes[]` entry anymore.
|
|
220
|
+
// The legacy "posture"/"route" classification still exists, but only inside
|
|
221
|
+
// the daemon's back-compat `decomposeMode` shim, not this manifest surface.
|
|
222
|
+
kind: z.enum(["context"]).optional(),
|
|
215
223
|
bin_args_prepend: z.array(z.string()).optional(),
|
|
216
224
|
bin_args_append: z.array(z.string()).optional(),
|
|
217
225
|
env: z.record(z.string(), z.string()).optional(),
|
|
@@ -438,6 +446,15 @@ function createAcpProtocolArm(options) {
|
|
|
438
446
|
get sessionId() {
|
|
439
447
|
return session?.sessionId;
|
|
440
448
|
},
|
|
449
|
+
get availableConfigOptions() {
|
|
450
|
+
return session?.availableConfigOptions ?? [];
|
|
451
|
+
},
|
|
452
|
+
get availableModes() {
|
|
453
|
+
return session?.availableModes ?? [];
|
|
454
|
+
},
|
|
455
|
+
get currentModeId() {
|
|
456
|
+
return session?.currentModeId;
|
|
457
|
+
},
|
|
441
458
|
async connect(opts) {
|
|
442
459
|
const permissionHandler = options.onPermissionRequest ?? defaultPermissionHandlerForMode(options.requestedMode);
|
|
443
460
|
client = await createAcpClient({
|
|
@@ -495,6 +512,14 @@ function createAcpProtocolArm(options) {
|
|
|
495
512
|
if (!session) return;
|
|
496
513
|
await session.cancel();
|
|
497
514
|
},
|
|
515
|
+
async setConfigOption(configId, value) {
|
|
516
|
+
if (!session) return { applied: false, reason: "not-connected" };
|
|
517
|
+
return session.setConfigOption(configId, value);
|
|
518
|
+
},
|
|
519
|
+
async setSessionMode(modeId) {
|
|
520
|
+
if (!session) return { applied: false, reason: "not-connected" };
|
|
521
|
+
return session.setSessionMode(modeId);
|
|
522
|
+
},
|
|
498
523
|
respondPermission(requestId, resolution) {
|
|
499
524
|
return client?.respondPermission(requestId, resolution) ?? false;
|
|
500
525
|
},
|
|
@@ -608,6 +633,33 @@ function createPrintSession(opts) {
|
|
|
608
633
|
async cancel() {
|
|
609
634
|
activeChild?.kill("SIGTERM");
|
|
610
635
|
},
|
|
636
|
+
// The print arm spawns a fresh subprocess PER TURN from `baseArgs`,
|
|
637
|
+
// which already has the model baked in (composed once, before this
|
|
638
|
+
// session object was even constructed — see `bin_args_template`
|
|
639
|
+
// handling in define-agent-cli.ts/compose.ts). There is no live
|
|
640
|
+
// connection to apply a mid-session config change to, and rebuilding
|
|
641
|
+
// `baseArgs` would mean a fresh session, not a live switch — so this
|
|
642
|
+
// is honestly `requires-restart`, same as the `arg` model-apply
|
|
643
|
+
// strategy for ACP arms.
|
|
644
|
+
async setModel() {
|
|
645
|
+
return { applied: false, reason: "requires-restart" };
|
|
646
|
+
},
|
|
647
|
+
// No ACP session — no wrapper-advertised capability read-surface and
|
|
648
|
+
// no `session/set_mode` RPC to switch live. Mirrors the "arm has no
|
|
649
|
+
// mid-session config surface" case `define-agent-cli.ts` reports for
|
|
650
|
+
// `setModel` on other arms.
|
|
651
|
+
availableConfigOptions: [],
|
|
652
|
+
availableModes: [],
|
|
653
|
+
currentModeId: void 0,
|
|
654
|
+
async setSessionMode() {
|
|
655
|
+
return { applied: false, reason: "not-supported" };
|
|
656
|
+
},
|
|
657
|
+
// Same as `setSessionMode`: a print arm has no live ACP session to apply
|
|
658
|
+
// `set_config_option(configId:"effort")` against — effort is baked into
|
|
659
|
+
// the spawn argv/env, so a live change is honestly `not-supported`.
|
|
660
|
+
async setEffort() {
|
|
661
|
+
return { applied: false, reason: "not-supported" };
|
|
662
|
+
},
|
|
611
663
|
async close() {
|
|
612
664
|
activeChild?.kill("SIGTERM");
|
|
613
665
|
mcpRestore?.();
|
|
@@ -767,8 +819,12 @@ function createMastraMapperState() {
|
|
|
767
819
|
return { lastTextLength: 0 };
|
|
768
820
|
}
|
|
769
821
|
function extractTextFromBlocks(content) {
|
|
770
|
-
|
|
771
|
-
|
|
822
|
+
let blocks = content;
|
|
823
|
+
if (blocks !== null && typeof blocks === "object" && !Array.isArray(blocks) && Array.isArray(blocks.parts)) {
|
|
824
|
+
blocks = blocks.parts;
|
|
825
|
+
}
|
|
826
|
+
if (!Array.isArray(blocks)) return "";
|
|
827
|
+
return blocks.filter((c) => c.type === "text" && typeof c.text === "string").map((c) => c.text).join("");
|
|
772
828
|
}
|
|
773
829
|
function mapMastraEvent(evt, sessionId, stderrLines, state) {
|
|
774
830
|
switch (evt.type) {
|
|
@@ -982,6 +1038,31 @@ async function createProprietaryProtocolArm(options) {
|
|
|
982
1038
|
return await candidate(options.definition);
|
|
983
1039
|
}
|
|
984
1040
|
|
|
1041
|
+
// src/legacy-modes.ts
|
|
1042
|
+
var LEGACY_GATEWAY_MODE_IDS = /* @__PURE__ */ new Set([
|
|
1043
|
+
"moonshot",
|
|
1044
|
+
"openrouter",
|
|
1045
|
+
"requesty",
|
|
1046
|
+
"deepseek"
|
|
1047
|
+
]);
|
|
1048
|
+
var LEGACY_POSTURE_MODE_IDS = /* @__PURE__ */ new Set([
|
|
1049
|
+
"default",
|
|
1050
|
+
"plan",
|
|
1051
|
+
"accept-edits",
|
|
1052
|
+
"bypass-permissions",
|
|
1053
|
+
"read-only",
|
|
1054
|
+
"full-access",
|
|
1055
|
+
"build"
|
|
1056
|
+
]);
|
|
1057
|
+
function inferLegacyModeKind(modeId) {
|
|
1058
|
+
if (LEGACY_GATEWAY_MODE_IDS.has(modeId)) return "route";
|
|
1059
|
+
if (LEGACY_POSTURE_MODE_IDS.has(modeId)) return "posture";
|
|
1060
|
+
return "context";
|
|
1061
|
+
}
|
|
1062
|
+
function isLegacyExtractedModeId(modeId) {
|
|
1063
|
+
return LEGACY_GATEWAY_MODE_IDS.has(modeId) || LEGACY_POSTURE_MODE_IDS.has(modeId);
|
|
1064
|
+
}
|
|
1065
|
+
|
|
985
1066
|
// src/manifest/compose.ts
|
|
986
1067
|
var RuntimeConfigError = class extends Error {
|
|
987
1068
|
code;
|
|
@@ -993,7 +1074,7 @@ var RuntimeConfigError = class extends Error {
|
|
|
993
1074
|
this.name = "RuntimeConfigError";
|
|
994
1075
|
}
|
|
995
1076
|
};
|
|
996
|
-
function composeSpawn(handle, config) {
|
|
1077
|
+
function composeSpawn(handle, config, opts) {
|
|
997
1078
|
if (!config)
|
|
998
1079
|
return {
|
|
999
1080
|
binArgs: [...handle.bin_args ?? []],
|
|
@@ -1007,14 +1088,15 @@ function composeSpawn(handle, config) {
|
|
|
1007
1088
|
if (config.mode !== void 0) {
|
|
1008
1089
|
const mode = (handle.modes ?? []).find((m) => m.id === config.mode);
|
|
1009
1090
|
if (!mode) {
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1091
|
+
if (!isLegacyExtractedModeId(config.mode)) {
|
|
1092
|
+
const known = (handle.modes ?? []).map((m) => m.id).join(", ") || "(none)";
|
|
1093
|
+
throw new RuntimeConfigError(
|
|
1094
|
+
"unknown_mode",
|
|
1095
|
+
"config.mode",
|
|
1096
|
+
`Mode '${config.mode}' is not declared by manifest '${handle.id}'. Known modes: ${known}`
|
|
1097
|
+
);
|
|
1098
|
+
}
|
|
1099
|
+
} else if ((mode.apply ?? "bin_args") === "bin_args") {
|
|
1018
1100
|
if (mode.bin_args_prepend) prepend.push(...mode.bin_args_prepend);
|
|
1019
1101
|
if (mode.bin_args_append) append.push(...mode.bin_args_append);
|
|
1020
1102
|
if (mode.env) Object.assign(env, mode.env);
|
|
@@ -1058,7 +1140,7 @@ function composeSpawn(handle, config) {
|
|
|
1058
1140
|
);
|
|
1059
1141
|
}
|
|
1060
1142
|
}
|
|
1061
|
-
if (typeof requestedModel === "string" && handle.models?.apply === "arg" && handle.models.bin_args_template) {
|
|
1143
|
+
if (typeof requestedModel === "string" && handle.models?.apply === "arg" && handle.models.bin_args_template && !opts?.skipModelArg) {
|
|
1062
1144
|
append.push(
|
|
1063
1145
|
...handle.models.bin_args_template.map(
|
|
1064
1146
|
(token) => token.replace("{model}", requestedModel)
|
|
@@ -1229,7 +1311,21 @@ function createAgentCliRuntime(definition) {
|
|
|
1229
1311
|
definition,
|
|
1230
1312
|
async start(opts) {
|
|
1231
1313
|
const cwd = opts?.cwd ?? process.cwd();
|
|
1232
|
-
const
|
|
1314
|
+
const cliEnv = {
|
|
1315
|
+
...filterStringEnv(process.env),
|
|
1316
|
+
...opts?.env ?? {}
|
|
1317
|
+
};
|
|
1318
|
+
const codexAuthMode = definition.id === "codex" ? detectCodexAuthMode(cliEnv, opts?.auth) : void 0;
|
|
1319
|
+
const skipModelArg = definition.id === "codex" && codexAuthMode !== "api-key";
|
|
1320
|
+
const composed = composeSpawn(definition, opts?.config, {
|
|
1321
|
+
skipModelArg
|
|
1322
|
+
});
|
|
1323
|
+
const requestedModel = opts?.config?.options?.model;
|
|
1324
|
+
if (skipModelArg && typeof requestedModel === "string") {
|
|
1325
|
+
console.warn(
|
|
1326
|
+
`[agent-cli] codex: skipped model override "${requestedModel}" for ChatGPT-account auth; using Codex's default model.`
|
|
1327
|
+
);
|
|
1328
|
+
}
|
|
1233
1329
|
const env = {
|
|
1234
1330
|
...filterStringEnv(process.env),
|
|
1235
1331
|
...composed.env
|
|
@@ -1237,7 +1333,8 @@ function createAgentCliRuntime(definition) {
|
|
|
1237
1333
|
for (const k of composed.envUnset) delete env[k];
|
|
1238
1334
|
const authSpec = opts?.auth;
|
|
1239
1335
|
const hasGatewayAuthToken = "ANTHROPIC_AUTH_TOKEN" in composed.env;
|
|
1240
|
-
const
|
|
1336
|
+
const hasGatewayBaseUrl = "ANTHROPIC_BASE_URL" in composed.env;
|
|
1337
|
+
const engageAuth = !!authSpec && !hasGatewayAuthToken && !hasGatewayBaseUrl && (authSpec.enforce === "always" || authSpec.explicit === true);
|
|
1241
1338
|
if (authSpec && engageAuth) {
|
|
1242
1339
|
for (const key of authSpec.unsetEnv) {
|
|
1243
1340
|
if (!(key in composed.env)) delete env[key];
|
|
@@ -1341,6 +1438,15 @@ function createAgentCliRuntime(definition) {
|
|
|
1341
1438
|
return {
|
|
1342
1439
|
sessionId,
|
|
1343
1440
|
pid: child?.pid,
|
|
1441
|
+
// Capability read-surface (SPEC §3.9/§3.4a) — snapshotted once
|
|
1442
|
+
// `arm.connect()` above has resolved, so an ACP arm's captured
|
|
1443
|
+
// `newSession`/`loadSession` response is already populated. Arms
|
|
1444
|
+
// that don't model this (print, proprietary) leave the getters
|
|
1445
|
+
// undefined, defaulted here to the same empty/absent shape their
|
|
1446
|
+
// `setModel`-style counterparts use for "not supported".
|
|
1447
|
+
availableConfigOptions: arm.availableConfigOptions ?? [],
|
|
1448
|
+
availableModes: arm.availableModes ?? [],
|
|
1449
|
+
currentModeId: arm.currentModeId,
|
|
1344
1450
|
send(message) {
|
|
1345
1451
|
const turnId = randomUUID();
|
|
1346
1452
|
currentTurnId = turnId;
|
|
@@ -1379,6 +1485,58 @@ function createAgentCliRuntime(definition) {
|
|
|
1379
1485
|
return arm.respondPermission(requestId, resolution);
|
|
1380
1486
|
}
|
|
1381
1487
|
} : {},
|
|
1488
|
+
/**
|
|
1489
|
+
* Mid-session model switch — the runtime counterpart to the
|
|
1490
|
+
* spawn-time `modelApply` handling above. Dispatches on the same
|
|
1491
|
+
* `definition.models.apply` strategy so a live switch behaves
|
|
1492
|
+
* exactly like the spawn-time apply would have, just against an
|
|
1493
|
+
* already-running session. See {@link SetModelResult} for the
|
|
1494
|
+
* reason vocabulary; this never throws and never tears down the
|
|
1495
|
+
* session on a rejected switch.
|
|
1496
|
+
*/
|
|
1497
|
+
async setModel(modelId) {
|
|
1498
|
+
if (modelApply === "arg") {
|
|
1499
|
+
return { applied: false, reason: "requires-restart" };
|
|
1500
|
+
}
|
|
1501
|
+
if (modelApply === "command") {
|
|
1502
|
+
return applyModelCommand(arm, modelId);
|
|
1503
|
+
}
|
|
1504
|
+
if (!arm.setConfigOption) {
|
|
1505
|
+
return { applied: false, reason: "not-supported" };
|
|
1506
|
+
}
|
|
1507
|
+
const result = await arm.setConfigOption("model", modelId);
|
|
1508
|
+
return result.applied ? { applied: true, model: modelId } : { applied: false, ...result.reason ? { reason: result.reason } : {} };
|
|
1509
|
+
},
|
|
1510
|
+
/**
|
|
1511
|
+
* Mid-session posture switch — the native-mode counterpart to
|
|
1512
|
+
* `setModel`, wired directly to the arm's `setSessionMode` (only
|
|
1513
|
+
* the ACP arm implements it). See {@link SetSessionModeResult} for
|
|
1514
|
+
* the reason vocabulary; this never throws and never tears down
|
|
1515
|
+
* the session on a rejected switch.
|
|
1516
|
+
*/
|
|
1517
|
+
async setSessionMode(modeId) {
|
|
1518
|
+
if (!arm.setSessionMode) {
|
|
1519
|
+
return { applied: false, reason: "not-supported" };
|
|
1520
|
+
}
|
|
1521
|
+
const result = await arm.setSessionMode(modeId);
|
|
1522
|
+
return result.applied ? { applied: true, modeId } : { applied: false, ...result.reason ? { reason: result.reason } : {} };
|
|
1523
|
+
},
|
|
1524
|
+
/**
|
|
1525
|
+
* Mid-session effort switch — the effort-axis counterpart to
|
|
1526
|
+
* `setModel`'s `"config"` strategy, wired to the same
|
|
1527
|
+
* `arm.setConfigOption` surface with `configId:"effort"` (only the
|
|
1528
|
+
* ACP arm implements it). Best-effort and non-fatal: an effort label
|
|
1529
|
+
* the current model rejects resolves `{applied:false, reason}` (SPEC
|
|
1530
|
+
* risk R7), never thrown and never tearing down the session. See
|
|
1531
|
+
* {@link SetEffortResult} for the reason vocabulary.
|
|
1532
|
+
*/
|
|
1533
|
+
async setEffort(effort) {
|
|
1534
|
+
if (!arm.setConfigOption) {
|
|
1535
|
+
return { applied: false, reason: "not-supported" };
|
|
1536
|
+
}
|
|
1537
|
+
const result = await arm.setConfigOption("effort", effort);
|
|
1538
|
+
return result.applied ? { applied: true, effort } : { applied: false, ...result.reason ? { reason: result.reason } : {} };
|
|
1539
|
+
},
|
|
1382
1540
|
async close() {
|
|
1383
1541
|
await arm.close();
|
|
1384
1542
|
if (child && !child.killed) child.kill("SIGTERM");
|
|
@@ -1398,17 +1556,19 @@ async function applyModelCommand(arm, modelId) {
|
|
|
1398
1556
|
if (/switch|model\s+set|now using/i.test(JSON.stringify(evt))) acked = true;
|
|
1399
1557
|
}
|
|
1400
1558
|
} catch (err) {
|
|
1559
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
1401
1560
|
console.warn(
|
|
1402
1561
|
`[agent-cli] /model ${modelId} control turn failed (continuing on default):`,
|
|
1403
1562
|
err instanceof Error ? err.message : err
|
|
1404
1563
|
);
|
|
1405
|
-
return;
|
|
1564
|
+
return { applied: false, reason };
|
|
1406
1565
|
}
|
|
1407
1566
|
if (!acked) {
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1567
|
+
const reason = "no switch acknowledgement \u2014 agent may be on its default model";
|
|
1568
|
+
console.warn(`[agent-cli] /model ${modelId}: ${reason}`);
|
|
1569
|
+
return { applied: false, reason };
|
|
1411
1570
|
}
|
|
1571
|
+
return { applied: true, model: modelId };
|
|
1412
1572
|
}
|
|
1413
1573
|
async function* promptTurn(arm, turnId, message) {
|
|
1414
1574
|
await arm.send(turnId, message);
|
|
@@ -1465,7 +1625,22 @@ function filterStringEnv(env) {
|
|
|
1465
1625
|
}
|
|
1466
1626
|
return out;
|
|
1467
1627
|
}
|
|
1628
|
+
function detectCodexAuthMode(env, authSpec) {
|
|
1629
|
+
if (authSpec?.credential && (authSpec.explicit === true || authSpec.enforce === "always")) {
|
|
1630
|
+
return authSpec.mode === "api-key" ? "api-key" : "chatgpt";
|
|
1631
|
+
}
|
|
1632
|
+
if (env.OPENAI_API_KEY || env.CODEX_API_KEY) return "api-key";
|
|
1633
|
+
const authPath = join(homedir(), ".codex", "auth.json");
|
|
1634
|
+
try {
|
|
1635
|
+
const parsed = JSON.parse(readFileSync(authPath, "utf8"));
|
|
1636
|
+
if (parsed.auth_mode === "api-key" || parsed.auth_mode === "chatgpt") {
|
|
1637
|
+
return parsed.auth_mode;
|
|
1638
|
+
}
|
|
1639
|
+
} catch {
|
|
1640
|
+
}
|
|
1641
|
+
return "chatgpt";
|
|
1642
|
+
}
|
|
1468
1643
|
|
|
1469
|
-
export { RuntimeConfigError, agentCliFrontmatterSchema, autoAllowPermissionHandler, composeSpawn, createAcpProtocolArm, createAgentCliRuntime, createMastraMapperState, createPrintSession, createProprietaryProtocolArm, defineAgentCli, mapMastraEvent, planModePermissionHandler, resolveContinuationStrategy, runtimeConfigSchema, toFileBasedMcpServers };
|
|
1470
|
-
//# sourceMappingURL=chunk-
|
|
1471
|
-
//# sourceMappingURL=chunk-
|
|
1644
|
+
export { LEGACY_GATEWAY_MODE_IDS, LEGACY_POSTURE_MODE_IDS, RuntimeConfigError, agentCliFrontmatterSchema, autoAllowPermissionHandler, composeSpawn, createAcpProtocolArm, createAgentCliRuntime, createMastraMapperState, createPrintSession, createProprietaryProtocolArm, defineAgentCli, inferLegacyModeKind, isLegacyExtractedModeId, mapMastraEvent, planModePermissionHandler, resolveContinuationStrategy, runtimeConfigSchema, toFileBasedMcpServers };
|
|
1645
|
+
//# sourceMappingURL=chunk-H43KNN32.mjs.map
|
|
1646
|
+
//# sourceMappingURL=chunk-H43KNN32.mjs.map
|