pi-acp 0.0.27 → 0.0.29
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/index.js +327 -113
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -48,36 +48,6 @@ function terminalAuthLaunchSpec() {
|
|
|
48
48
|
|
|
49
49
|
// src/acp/session.ts
|
|
50
50
|
import { RequestError as RequestError2 } from "@agentclientprotocol/sdk";
|
|
51
|
-
|
|
52
|
-
// src/acp/auth-required.ts
|
|
53
|
-
import { RequestError } from "@agentclientprotocol/sdk";
|
|
54
|
-
function maybeAuthRequiredError(err) {
|
|
55
|
-
const msg = String(err?.message ?? err ?? "");
|
|
56
|
-
const s = msg.toLowerCase();
|
|
57
|
-
const patterns = [
|
|
58
|
-
"api key",
|
|
59
|
-
"apikey",
|
|
60
|
-
"missing key",
|
|
61
|
-
"no key",
|
|
62
|
-
"not configured",
|
|
63
|
-
"unauthorized",
|
|
64
|
-
"authentication",
|
|
65
|
-
"permission denied",
|
|
66
|
-
"forbidden",
|
|
67
|
-
"401",
|
|
68
|
-
"403"
|
|
69
|
-
];
|
|
70
|
-
const hit = patterns.some((p) => s.includes(p));
|
|
71
|
-
if (!hit) return null;
|
|
72
|
-
return RequestError.authRequired(
|
|
73
|
-
{
|
|
74
|
-
authMethods: getAuthMethods()
|
|
75
|
-
},
|
|
76
|
-
"Configure an API key or log in with an OAuth provider."
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// src/acp/session.ts
|
|
81
51
|
import { readFileSync as readFileSync3 } from "fs";
|
|
82
52
|
import { isAbsolute, resolve as resolvePath } from "path";
|
|
83
53
|
|
|
@@ -309,27 +279,68 @@ var PiRpcProcess = class _PiRpcProcess {
|
|
|
309
279
|
if (!res.success) throw new Error(`pi get_commands failed: ${res.error ?? JSON.stringify(res.data)}`);
|
|
310
280
|
return res.data;
|
|
311
281
|
}
|
|
282
|
+
async sendExtensionUiResponse(response) {
|
|
283
|
+
await this.writeLine(`${JSON.stringify({ type: "extension_ui_response", ...response })}
|
|
284
|
+
`);
|
|
285
|
+
}
|
|
312
286
|
request(cmd) {
|
|
313
287
|
const id = crypto.randomUUID();
|
|
314
288
|
const withId = { ...cmd, id };
|
|
315
|
-
const line = JSON.stringify(withId)
|
|
289
|
+
const line = `${JSON.stringify(withId)}
|
|
290
|
+
`;
|
|
316
291
|
return new Promise((resolve4, reject) => {
|
|
317
292
|
this.pending.set(id, { resolve: resolve4, reject });
|
|
293
|
+
void this.writeLine(line).catch((error) => {
|
|
294
|
+
this.pending.delete(id);
|
|
295
|
+
reject(error);
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
writeLine(line) {
|
|
300
|
+
return new Promise((resolve4, reject) => {
|
|
318
301
|
try {
|
|
319
|
-
this.child.stdin.write(line, (
|
|
320
|
-
if (
|
|
321
|
-
|
|
322
|
-
|
|
302
|
+
this.child.stdin.write(line, (error) => {
|
|
303
|
+
if (error) {
|
|
304
|
+
reject(error);
|
|
305
|
+
return;
|
|
323
306
|
}
|
|
307
|
+
resolve4();
|
|
324
308
|
});
|
|
325
|
-
} catch (
|
|
326
|
-
|
|
327
|
-
reject(e);
|
|
309
|
+
} catch (error) {
|
|
310
|
+
reject(error);
|
|
328
311
|
}
|
|
329
312
|
});
|
|
330
313
|
}
|
|
331
314
|
};
|
|
332
315
|
|
|
316
|
+
// src/acp/auth-required.ts
|
|
317
|
+
import { RequestError } from "@agentclientprotocol/sdk";
|
|
318
|
+
function maybeAuthRequiredError(err) {
|
|
319
|
+
const msg = String(err?.message ?? err ?? "");
|
|
320
|
+
const s = msg.toLowerCase();
|
|
321
|
+
const patterns = [
|
|
322
|
+
"api key",
|
|
323
|
+
"apikey",
|
|
324
|
+
"missing key",
|
|
325
|
+
"no key",
|
|
326
|
+
"not configured",
|
|
327
|
+
"unauthorized",
|
|
328
|
+
"authentication",
|
|
329
|
+
"permission denied",
|
|
330
|
+
"forbidden",
|
|
331
|
+
"401",
|
|
332
|
+
"403"
|
|
333
|
+
];
|
|
334
|
+
const hit = patterns.some((p) => s.includes(p));
|
|
335
|
+
if (!hit) return null;
|
|
336
|
+
return RequestError.authRequired(
|
|
337
|
+
{
|
|
338
|
+
authMethods: getAuthMethods()
|
|
339
|
+
},
|
|
340
|
+
"Configure an API key or log in with an OAuth provider."
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
|
|
333
344
|
// src/acp/session-store.ts
|
|
334
345
|
import { mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
335
346
|
import { dirname } from "path";
|
|
@@ -391,37 +402,6 @@ var SessionStore = class {
|
|
|
391
402
|
}
|
|
392
403
|
};
|
|
393
404
|
|
|
394
|
-
// src/acp/translate/pi-tools.ts
|
|
395
|
-
function toolResultToText(result) {
|
|
396
|
-
if (!result) return "";
|
|
397
|
-
const content = result.content;
|
|
398
|
-
if (Array.isArray(content)) {
|
|
399
|
-
const texts = content.map((c) => c?.type === "text" && typeof c.text === "string" ? c.text : "").filter(Boolean);
|
|
400
|
-
if (texts.length) return texts.join("");
|
|
401
|
-
}
|
|
402
|
-
const details = result?.details;
|
|
403
|
-
const diff = details?.diff;
|
|
404
|
-
if (typeof diff === "string" && diff.trim()) {
|
|
405
|
-
return diff;
|
|
406
|
-
}
|
|
407
|
-
const stdout = (typeof details?.stdout === "string" ? details.stdout : void 0) ?? (typeof result?.stdout === "string" ? result.stdout : void 0) ?? (typeof details?.output === "string" ? details.output : void 0) ?? (typeof result?.output === "string" ? result.output : void 0);
|
|
408
|
-
const stderr = (typeof details?.stderr === "string" ? details.stderr : void 0) ?? (typeof result?.stderr === "string" ? result.stderr : void 0);
|
|
409
|
-
const exitCode = (typeof details?.exitCode === "number" ? details.exitCode : void 0) ?? (typeof result?.exitCode === "number" ? result.exitCode : void 0) ?? (typeof details?.code === "number" ? details.code : void 0) ?? (typeof result?.code === "number" ? result.code : void 0);
|
|
410
|
-
if (typeof stdout === "string" && stdout.trim() || typeof stderr === "string" && stderr.trim()) {
|
|
411
|
-
const parts = [];
|
|
412
|
-
if (typeof stdout === "string" && stdout.trim()) parts.push(stdout);
|
|
413
|
-
if (typeof stderr === "string" && stderr.trim()) parts.push(`stderr:
|
|
414
|
-
${stderr}`);
|
|
415
|
-
if (typeof exitCode === "number") parts.push(`exit code: ${exitCode}`);
|
|
416
|
-
return parts.join("\n\n").trimEnd();
|
|
417
|
-
}
|
|
418
|
-
try {
|
|
419
|
-
return JSON.stringify(result, null, 2);
|
|
420
|
-
} catch {
|
|
421
|
-
return String(result);
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
|
|
425
405
|
// src/acp/slash-commands.ts
|
|
426
406
|
import { existsSync, readdirSync, readFileSync as readFileSync2 } from "fs";
|
|
427
407
|
import { homedir as homedir2 } from "os";
|
|
@@ -546,7 +526,44 @@ function expandSlashCommand(text, fileCommands) {
|
|
|
546
526
|
return substituteArgs(cmd.content, args);
|
|
547
527
|
}
|
|
548
528
|
|
|
529
|
+
// src/acp/translate/pi-tools.ts
|
|
530
|
+
function toolResultToText(result) {
|
|
531
|
+
if (!result) return "";
|
|
532
|
+
const content = result.content;
|
|
533
|
+
if (Array.isArray(content)) {
|
|
534
|
+
const texts = content.map((c) => c?.type === "text" && typeof c.text === "string" ? c.text : "").filter(Boolean);
|
|
535
|
+
if (texts.length) return texts.join("");
|
|
536
|
+
}
|
|
537
|
+
const details = result?.details;
|
|
538
|
+
const diff = details?.diff;
|
|
539
|
+
if (typeof diff === "string" && diff.trim()) {
|
|
540
|
+
return diff;
|
|
541
|
+
}
|
|
542
|
+
const stdout = (typeof details?.stdout === "string" ? details.stdout : void 0) ?? (typeof result?.stdout === "string" ? result.stdout : void 0) ?? (typeof details?.output === "string" ? details.output : void 0) ?? (typeof result?.output === "string" ? result.output : void 0);
|
|
543
|
+
const stderr = (typeof details?.stderr === "string" ? details.stderr : void 0) ?? (typeof result?.stderr === "string" ? result.stderr : void 0);
|
|
544
|
+
const exitCode = (typeof details?.exitCode === "number" ? details.exitCode : void 0) ?? (typeof result?.exitCode === "number" ? result.exitCode : void 0) ?? (typeof details?.code === "number" ? details.code : void 0) ?? (typeof result?.code === "number" ? result.code : void 0);
|
|
545
|
+
if (typeof stdout === "string" && stdout.trim() || typeof stderr === "string" && stderr.trim()) {
|
|
546
|
+
const parts = [];
|
|
547
|
+
if (typeof stdout === "string" && stdout.trim()) parts.push(stdout);
|
|
548
|
+
if (typeof stderr === "string" && stderr.trim()) parts.push(`stderr:
|
|
549
|
+
${stderr}`);
|
|
550
|
+
if (typeof exitCode === "number") parts.push(`exit code: ${exitCode}`);
|
|
551
|
+
return parts.join("\n\n").trimEnd();
|
|
552
|
+
}
|
|
553
|
+
try {
|
|
554
|
+
return JSON.stringify(result, null, 2);
|
|
555
|
+
} catch {
|
|
556
|
+
return String(result);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
549
560
|
// src/acp/session.ts
|
|
561
|
+
var CONFIRM_PERMISSION_OPTIONS = [
|
|
562
|
+
{ optionId: "yes", name: "Yes", kind: "allow_once" },
|
|
563
|
+
{ optionId: "no", name: "No", kind: "reject_once" }
|
|
564
|
+
];
|
|
565
|
+
var EXTENSION_UI_RAW_INPUT_KEYS = ["title", "message", "options", "placeholder", "prefill"];
|
|
566
|
+
var CHOICE_OPTION_PREFIX = "choice-";
|
|
550
567
|
function findUniqueLineNumber(text, needle) {
|
|
551
568
|
if (!needle) return void 0;
|
|
552
569
|
const first = text.indexOf(needle);
|
|
@@ -660,8 +677,7 @@ var PiAcpSession = class {
|
|
|
660
677
|
cwd;
|
|
661
678
|
mcpServers;
|
|
662
679
|
startupInfo = null;
|
|
663
|
-
|
|
664
|
-
startupInfoSentInPrompt = false;
|
|
680
|
+
startupInfoSent = false;
|
|
665
681
|
proc;
|
|
666
682
|
conn;
|
|
667
683
|
fileCommands;
|
|
@@ -696,8 +712,7 @@ var PiAcpSession = class {
|
|
|
696
712
|
}
|
|
697
713
|
setStartupInfo(text) {
|
|
698
714
|
this.startupInfo = text;
|
|
699
|
-
this.
|
|
700
|
-
this.startupInfoSentInPrompt = false;
|
|
715
|
+
this.startupInfoSent = false;
|
|
701
716
|
}
|
|
702
717
|
/**
|
|
703
718
|
* Best-effort attempt to send startup info outside of a prompt turn.
|
|
@@ -705,23 +720,14 @@ var PiAcpSession = class {
|
|
|
705
720
|
* callers can invoke this shortly after session/new returns.
|
|
706
721
|
*/
|
|
707
722
|
sendStartupInfoIfPending() {
|
|
708
|
-
if (this.
|
|
709
|
-
this.
|
|
710
|
-
this.emit({
|
|
711
|
-
sessionUpdate: "agent_message_chunk",
|
|
712
|
-
content: { type: "text", text: this.startupInfo }
|
|
713
|
-
});
|
|
714
|
-
}
|
|
715
|
-
sendStartupInfoOnFirstPromptIfPending() {
|
|
716
|
-
if (this.startupInfoSentInPrompt || !this.startupInfo) return;
|
|
717
|
-
this.startupInfoSentInPrompt = true;
|
|
723
|
+
if (this.startupInfoSent || !this.startupInfo) return;
|
|
724
|
+
this.startupInfoSent = true;
|
|
718
725
|
this.emit({
|
|
719
726
|
sessionUpdate: "agent_message_chunk",
|
|
720
727
|
content: { type: "text", text: this.startupInfo }
|
|
721
728
|
});
|
|
722
729
|
}
|
|
723
730
|
async prompt(message, images = []) {
|
|
724
|
-
this.sendStartupInfoOnFirstPromptIfPending();
|
|
725
731
|
const expandedMessage = expandSlashCommand(message, this.fileCommands);
|
|
726
732
|
const turnPromise = new Promise((resolve4, reject) => {
|
|
727
733
|
const queued = { message: expandedMessage, images, resolve: resolve4, reject };
|
|
@@ -963,6 +969,17 @@ var PiAcpSession = class {
|
|
|
963
969
|
this.editSnapshots.delete(toolCallId);
|
|
964
970
|
break;
|
|
965
971
|
}
|
|
972
|
+
case "extension_ui_request": {
|
|
973
|
+
void this.handleExtensionUiRequest(ev).catch(() => {
|
|
974
|
+
const id = stringProp(ev, "id");
|
|
975
|
+
if (!id) {
|
|
976
|
+
return;
|
|
977
|
+
}
|
|
978
|
+
void this.proc.sendExtensionUiResponse({ id, cancelled: true }).catch(() => {
|
|
979
|
+
});
|
|
980
|
+
});
|
|
981
|
+
break;
|
|
982
|
+
}
|
|
966
983
|
case "auto_retry_start": {
|
|
967
984
|
this.emit({
|
|
968
985
|
sessionUpdate: "agent_message_chunk",
|
|
@@ -1030,7 +1047,116 @@ var PiAcpSession = class {
|
|
|
1030
1047
|
break;
|
|
1031
1048
|
}
|
|
1032
1049
|
}
|
|
1050
|
+
async handleExtensionUiRequest(ev) {
|
|
1051
|
+
const id = stringProp(ev, "id");
|
|
1052
|
+
const method = stringProp(ev, "method");
|
|
1053
|
+
if (!id) {
|
|
1054
|
+
return;
|
|
1055
|
+
}
|
|
1056
|
+
if (method === "select") {
|
|
1057
|
+
await this.handleExtensionSelect(ev, id);
|
|
1058
|
+
return;
|
|
1059
|
+
}
|
|
1060
|
+
if (method === "confirm") {
|
|
1061
|
+
await this.handleExtensionConfirm(ev, id);
|
|
1062
|
+
return;
|
|
1063
|
+
}
|
|
1064
|
+
if (method === "input" || method === "editor") {
|
|
1065
|
+
this.emit({
|
|
1066
|
+
sessionUpdate: "agent_message_chunk",
|
|
1067
|
+
content: {
|
|
1068
|
+
type: "text",
|
|
1069
|
+
text: `Pi ${method} UI request is not supported in ACP yet; cancelling it.`
|
|
1070
|
+
}
|
|
1071
|
+
});
|
|
1072
|
+
await this.proc.sendExtensionUiResponse({ id, cancelled: true });
|
|
1073
|
+
return;
|
|
1074
|
+
}
|
|
1075
|
+
if (method === "notify") {
|
|
1076
|
+
this.emit({
|
|
1077
|
+
sessionUpdate: "agent_message_chunk",
|
|
1078
|
+
content: { type: "text", text: stringProp(ev, "message") ?? "Pi notification" }
|
|
1079
|
+
});
|
|
1080
|
+
await this.proc.sendExtensionUiResponse({ id, cancelled: true });
|
|
1081
|
+
return;
|
|
1082
|
+
}
|
|
1083
|
+
await this.proc.sendExtensionUiResponse({ id, cancelled: true });
|
|
1084
|
+
}
|
|
1085
|
+
async handleExtensionSelect(ev, id) {
|
|
1086
|
+
const rawOptions = ev.options;
|
|
1087
|
+
const options = Array.isArray(rawOptions) ? rawOptions.map((option) => String(option)) : [];
|
|
1088
|
+
if (!options.length) {
|
|
1089
|
+
await this.proc.sendExtensionUiResponse({ id, cancelled: true });
|
|
1090
|
+
return;
|
|
1091
|
+
}
|
|
1092
|
+
const permissionOptions = options.map((name, index2) => ({
|
|
1093
|
+
optionId: `${CHOICE_OPTION_PREFIX}${index2}`,
|
|
1094
|
+
name,
|
|
1095
|
+
kind: "allow_once"
|
|
1096
|
+
}));
|
|
1097
|
+
const selected = await this.requestExtensionPermission(id, ev, permissionOptions);
|
|
1098
|
+
if (selected === null) {
|
|
1099
|
+
return;
|
|
1100
|
+
}
|
|
1101
|
+
const selectedOptionId = selected.outcome.outcome === "selected" ? selected.outcome.optionId : null;
|
|
1102
|
+
const index = selectedOptionId === null ? null : optionIndex(selectedOptionId);
|
|
1103
|
+
const value = index === null ? null : options.at(index) ?? null;
|
|
1104
|
+
await this.proc.sendExtensionUiResponse(value === null ? { id, cancelled: true } : { id, value });
|
|
1105
|
+
}
|
|
1106
|
+
async handleExtensionConfirm(ev, id) {
|
|
1107
|
+
const selected = await this.requestExtensionPermission(id, ev, CONFIRM_PERMISSION_OPTIONS);
|
|
1108
|
+
if (selected === null) {
|
|
1109
|
+
return;
|
|
1110
|
+
}
|
|
1111
|
+
if (selected.outcome.outcome === "cancelled") {
|
|
1112
|
+
await this.proc.sendExtensionUiResponse({ id, cancelled: true });
|
|
1113
|
+
return;
|
|
1114
|
+
}
|
|
1115
|
+
await this.proc.sendExtensionUiResponse({ id, confirmed: selected.outcome.optionId === "yes" });
|
|
1116
|
+
}
|
|
1117
|
+
async requestExtensionPermission(id, ev, options) {
|
|
1118
|
+
try {
|
|
1119
|
+
return await this.conn.requestPermission({
|
|
1120
|
+
sessionId: this.sessionId,
|
|
1121
|
+
toolCall: extensionUiToolCall(id, ev),
|
|
1122
|
+
options
|
|
1123
|
+
});
|
|
1124
|
+
} catch {
|
|
1125
|
+
await this.proc.sendExtensionUiResponse({ id, cancelled: true });
|
|
1126
|
+
return null;
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1033
1129
|
};
|
|
1130
|
+
function extensionUiToolCall(id, ev) {
|
|
1131
|
+
const method = stringProp(ev, "method") ?? "ui";
|
|
1132
|
+
const title = stringProp(ev, "title") ?? `Pi ${method}`;
|
|
1133
|
+
const rawInput = { method };
|
|
1134
|
+
for (const key of EXTENSION_UI_RAW_INPUT_KEYS) {
|
|
1135
|
+
if (Object.hasOwn(ev, key)) rawInput[key] = ev[key];
|
|
1136
|
+
}
|
|
1137
|
+
return {
|
|
1138
|
+
toolCallId: `pi-ui-${id}`,
|
|
1139
|
+
title,
|
|
1140
|
+
kind: "other",
|
|
1141
|
+
status: "pending",
|
|
1142
|
+
rawInput
|
|
1143
|
+
};
|
|
1144
|
+
}
|
|
1145
|
+
function stringProp(source, key) {
|
|
1146
|
+
const value = source[key];
|
|
1147
|
+
return typeof value === "string" ? value : null;
|
|
1148
|
+
}
|
|
1149
|
+
function optionIndex(optionId) {
|
|
1150
|
+
if (!optionId.startsWith(CHOICE_OPTION_PREFIX)) {
|
|
1151
|
+
return null;
|
|
1152
|
+
}
|
|
1153
|
+
const rawIndex = optionId.slice(CHOICE_OPTION_PREFIX.length);
|
|
1154
|
+
if (!rawIndex) {
|
|
1155
|
+
return null;
|
|
1156
|
+
}
|
|
1157
|
+
const index = Number(rawIndex);
|
|
1158
|
+
return Number.isSafeInteger(index) && index >= 0 && String(index) === rawIndex ? index : null;
|
|
1159
|
+
}
|
|
1034
1160
|
function formatAutoRetryMessage(ev) {
|
|
1035
1161
|
const attempt = Number(ev.attempt);
|
|
1036
1162
|
const maxAttempts = Number(ev.maxAttempts);
|
|
@@ -1463,6 +1589,8 @@ import { existsSync as existsSync4, readFileSync as readFileSync6, realpathSync,
|
|
|
1463
1589
|
import { join as join5, dirname as dirname2, basename } from "path";
|
|
1464
1590
|
import { spawnSync } from "child_process";
|
|
1465
1591
|
import { fileURLToPath } from "url";
|
|
1592
|
+
var MODEL_CONFIG_ID = "model";
|
|
1593
|
+
var THOUGHT_LEVEL_CONFIG_ID = "thought_level";
|
|
1466
1594
|
function builtinAvailableCommands() {
|
|
1467
1595
|
return [
|
|
1468
1596
|
{
|
|
@@ -1626,8 +1754,10 @@ var PiAcpAgent = class {
|
|
|
1626
1754
|
"Configure an API key or log in with an OAuth provider."
|
|
1627
1755
|
);
|
|
1628
1756
|
}
|
|
1629
|
-
const models = await
|
|
1630
|
-
|
|
1757
|
+
const { configOptions, models, modes } = await getSessionConfiguration(session.proc, {
|
|
1758
|
+
state,
|
|
1759
|
+
availableModels
|
|
1760
|
+
});
|
|
1631
1761
|
const quietStartup = getQuietStartup(params.cwd);
|
|
1632
1762
|
const updateNotice = buildUpdateNotice();
|
|
1633
1763
|
const preludeText = quietStartup ? updateNotice ? updateNotice + "\n" : "" : buildStartupInfo({
|
|
@@ -1640,8 +1770,9 @@ var PiAcpAgent = class {
|
|
|
1640
1770
|
this.sessions.closeAllExcept?.(session.sessionId);
|
|
1641
1771
|
const response = {
|
|
1642
1772
|
sessionId: session.sessionId,
|
|
1773
|
+
configOptions,
|
|
1643
1774
|
models,
|
|
1644
|
-
modes
|
|
1775
|
+
modes,
|
|
1645
1776
|
_meta: {
|
|
1646
1777
|
piAcp: {
|
|
1647
1778
|
startupInfo: preludeText || null
|
|
@@ -2171,11 +2302,11 @@ ${JSON.stringify(stats, null, 2)}`;
|
|
|
2171
2302
|
});
|
|
2172
2303
|
}
|
|
2173
2304
|
}
|
|
2174
|
-
const models = await
|
|
2175
|
-
const thinking = await getThinkingState(proc);
|
|
2305
|
+
const { configOptions, models, modes } = await getSessionConfiguration(proc);
|
|
2176
2306
|
const response = {
|
|
2307
|
+
configOptions,
|
|
2177
2308
|
models,
|
|
2178
|
-
modes
|
|
2309
|
+
modes,
|
|
2179
2310
|
_meta: {
|
|
2180
2311
|
piAcp: {
|
|
2181
2312
|
startupInfo: null
|
|
@@ -2213,28 +2344,8 @@ ${JSON.stringify(stats, null, 2)}`;
|
|
|
2213
2344
|
}
|
|
2214
2345
|
async unstable_setSessionModel(params) {
|
|
2215
2346
|
const session = this.sessions.get(params.sessionId);
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
if (params.modelId.includes("/")) {
|
|
2219
|
-
const [p, ...rest] = params.modelId.split("/");
|
|
2220
|
-
provider = p;
|
|
2221
|
-
modelId = rest.join("/");
|
|
2222
|
-
} else {
|
|
2223
|
-
modelId = params.modelId;
|
|
2224
|
-
}
|
|
2225
|
-
if (!provider) {
|
|
2226
|
-
const data = await session.proc.getAvailableModels();
|
|
2227
|
-
const models = Array.isArray(data?.models) ? data.models : [];
|
|
2228
|
-
const found = models.find((m) => String(m?.id) === modelId);
|
|
2229
|
-
if (found) {
|
|
2230
|
-
provider = String(found.provider);
|
|
2231
|
-
modelId = String(found.id);
|
|
2232
|
-
}
|
|
2233
|
-
}
|
|
2234
|
-
if (!provider || !modelId) {
|
|
2235
|
-
throw RequestError3.invalidParams(`Unknown modelId: ${params.modelId}`);
|
|
2236
|
-
}
|
|
2237
|
-
await session.proc.setModel(provider, modelId);
|
|
2347
|
+
await setSessionModel(session.proc, params.modelId);
|
|
2348
|
+
await emitConfigOptionsUpdate(this.conn, session.sessionId, session.proc);
|
|
2238
2349
|
}
|
|
2239
2350
|
async setSessionMode(params) {
|
|
2240
2351
|
const session = this.sessions.get(params.sessionId);
|
|
@@ -2250,8 +2361,35 @@ ${JSON.stringify(stats, null, 2)}`;
|
|
|
2250
2361
|
currentModeId: mode
|
|
2251
2362
|
}
|
|
2252
2363
|
});
|
|
2364
|
+
await emitConfigOptionsUpdate(this.conn, session.sessionId, session.proc);
|
|
2253
2365
|
return {};
|
|
2254
2366
|
}
|
|
2367
|
+
async setSessionConfigOption(params) {
|
|
2368
|
+
const session = this.sessions.get(params.sessionId);
|
|
2369
|
+
const configId = String(params.configId);
|
|
2370
|
+
if (typeof params.value !== "string") {
|
|
2371
|
+
throw RequestError3.invalidParams(`Expected string value for config option: ${configId}`);
|
|
2372
|
+
}
|
|
2373
|
+
if (configId === MODEL_CONFIG_ID) {
|
|
2374
|
+
await setSessionModel(session.proc, params.value);
|
|
2375
|
+
} else if (configId === THOUGHT_LEVEL_CONFIG_ID) {
|
|
2376
|
+
if (!isThinkingLevel(params.value)) {
|
|
2377
|
+
throw RequestError3.invalidParams(`Unknown thinking level: ${params.value}`);
|
|
2378
|
+
}
|
|
2379
|
+
await session.proc.setThinkingLevel(params.value);
|
|
2380
|
+
void this.conn.sessionUpdate({
|
|
2381
|
+
sessionId: session.sessionId,
|
|
2382
|
+
update: {
|
|
2383
|
+
sessionUpdate: "current_mode_update",
|
|
2384
|
+
currentModeId: params.value
|
|
2385
|
+
}
|
|
2386
|
+
});
|
|
2387
|
+
} else {
|
|
2388
|
+
throw RequestError3.invalidParams(`Unknown config option: ${configId}`);
|
|
2389
|
+
}
|
|
2390
|
+
const configOptions = await emitConfigOptionsUpdate(this.conn, session.sessionId, session.proc);
|
|
2391
|
+
return { configOptions };
|
|
2392
|
+
}
|
|
2255
2393
|
};
|
|
2256
2394
|
function isThinkingLevel(x) {
|
|
2257
2395
|
return x === "off" || x === "minimal" || x === "low" || x === "medium" || x === "high" || x === "xhigh";
|
|
@@ -2277,6 +2415,47 @@ async function getThinkingState(proc, pre) {
|
|
|
2277
2415
|
}))
|
|
2278
2416
|
};
|
|
2279
2417
|
}
|
|
2418
|
+
async function getSessionConfiguration(proc, pre) {
|
|
2419
|
+
const [models, modes] = await Promise.all([getModelState(proc, pre), getThinkingState(proc, { state: pre?.state })]);
|
|
2420
|
+
return {
|
|
2421
|
+
configOptions: buildConfigOptions({ models, modes }),
|
|
2422
|
+
models,
|
|
2423
|
+
modes
|
|
2424
|
+
};
|
|
2425
|
+
}
|
|
2426
|
+
function buildConfigOptions(state) {
|
|
2427
|
+
const configOptions = [
|
|
2428
|
+
{
|
|
2429
|
+
type: "select",
|
|
2430
|
+
id: THOUGHT_LEVEL_CONFIG_ID,
|
|
2431
|
+
category: "thought_level",
|
|
2432
|
+
name: "Thinking",
|
|
2433
|
+
description: "Set the reasoning effort for this session",
|
|
2434
|
+
currentValue: state.modes.currentModeId,
|
|
2435
|
+
options: state.modes.availableModes.map((mode) => ({
|
|
2436
|
+
value: mode.id,
|
|
2437
|
+
name: mode.name,
|
|
2438
|
+
description: mode.description ?? null
|
|
2439
|
+
}))
|
|
2440
|
+
}
|
|
2441
|
+
];
|
|
2442
|
+
if (state.models?.availableModels.length) {
|
|
2443
|
+
configOptions.unshift({
|
|
2444
|
+
type: "select",
|
|
2445
|
+
id: MODEL_CONFIG_ID,
|
|
2446
|
+
category: "model",
|
|
2447
|
+
name: "Model",
|
|
2448
|
+
description: "Select the model for this session",
|
|
2449
|
+
currentValue: state.models.currentModelId,
|
|
2450
|
+
options: state.models.availableModels.map((model) => ({
|
|
2451
|
+
value: model.modelId,
|
|
2452
|
+
name: model.name,
|
|
2453
|
+
description: model.description ?? null
|
|
2454
|
+
}))
|
|
2455
|
+
});
|
|
2456
|
+
}
|
|
2457
|
+
return configOptions;
|
|
2458
|
+
}
|
|
2280
2459
|
async function getModelState(proc, pre) {
|
|
2281
2460
|
let availableModels = [];
|
|
2282
2461
|
const data = pre?.availableModels ?? await (async () => {
|
|
@@ -2316,9 +2495,44 @@ async function getModelState(proc, pre) {
|
|
|
2316
2495
|
if (!currentModelId) currentModelId = availableModels[0]?.modelId ?? "default";
|
|
2317
2496
|
return {
|
|
2318
2497
|
availableModels,
|
|
2319
|
-
currentModelId
|
|
2498
|
+
currentModelId: currentModelId ?? availableModels[0]?.modelId ?? "default"
|
|
2320
2499
|
};
|
|
2321
2500
|
}
|
|
2501
|
+
async function emitConfigOptionsUpdate(conn, sessionId, proc) {
|
|
2502
|
+
const { configOptions } = await getSessionConfiguration(proc);
|
|
2503
|
+
await conn.sessionUpdate({
|
|
2504
|
+
sessionId,
|
|
2505
|
+
update: {
|
|
2506
|
+
sessionUpdate: "config_option_update",
|
|
2507
|
+
configOptions
|
|
2508
|
+
}
|
|
2509
|
+
});
|
|
2510
|
+
return configOptions;
|
|
2511
|
+
}
|
|
2512
|
+
async function setSessionModel(proc, requestedModelId) {
|
|
2513
|
+
let provider = null;
|
|
2514
|
+
let modelId = null;
|
|
2515
|
+
if (requestedModelId.includes("/")) {
|
|
2516
|
+
const [candidateProvider, ...rest] = requestedModelId.split("/");
|
|
2517
|
+
provider = candidateProvider;
|
|
2518
|
+
modelId = rest.join("/");
|
|
2519
|
+
} else {
|
|
2520
|
+
modelId = requestedModelId;
|
|
2521
|
+
}
|
|
2522
|
+
if (!provider) {
|
|
2523
|
+
const data = await proc.getAvailableModels();
|
|
2524
|
+
const models = Array.isArray(data?.models) ? data.models : [];
|
|
2525
|
+
const found = models.find((m) => String(m?.id) === modelId);
|
|
2526
|
+
if (found) {
|
|
2527
|
+
provider = String(found.provider);
|
|
2528
|
+
modelId = String(found.id);
|
|
2529
|
+
}
|
|
2530
|
+
}
|
|
2531
|
+
if (!provider || !modelId) {
|
|
2532
|
+
throw RequestError3.invalidParams(`Unknown modelId: ${requestedModelId}`);
|
|
2533
|
+
}
|
|
2534
|
+
await proc.setModel(provider, modelId);
|
|
2535
|
+
}
|
|
2322
2536
|
function isSemver(v) {
|
|
2323
2537
|
return /^\d+\.\d+\.\d+(?:[-+].+)?$/.test(v);
|
|
2324
2538
|
}
|