pi-acp 0.0.32 → 0.0.34
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 +6 -2
- package/dist/index.js +141 -78
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -25,6 +25,10 @@ Expect some minor breaking changes.
|
|
|
25
25
|
- Loads file-based slash commands compatible with pi’s conventions
|
|
26
26
|
- Adds a small set of built-in commands for headless/editor usage
|
|
27
27
|
- Supports skill commands (if enabled in pi settings, they appear as `/skill:skill-name` in the ACP client)
|
|
28
|
+
- Context window usage
|
|
29
|
+
- Reports pi's real context occupancy (`get_session_stats` → `contextUsage`) to the client as ACP `usage_update` after each turn, on `session/new` and `session/load`, and after a model switch
|
|
30
|
+
- Requires a pi version whose `get_session_stats` response includes `contextUsage`; otherwise no usage is reported
|
|
31
|
+
- Right after compaction pi may not have a trustworthy token count yet, so the client keeps the previous value until the next model response
|
|
28
32
|
- Skills are loaded by pi directly and are available in ACP sessions
|
|
29
33
|
- (Zed) `pi-acp` emits “startup info” block into the session (pi version, context, skills, prompts, extensions - similar to `pi` in the terminal). You can disable it by setting `quietStartup: true` in pi settings (`~/.pi/agent/settings.json` or `<project>/.pi/settings.json`). When `quietStartup` is enabled, `pi-acp` will still emit a 'New version available' message if the installed pi version is outdated.
|
|
30
34
|
- (Zed) Session history is supported in Zed starting with [`v0.225.0`](https://zed.dev/releases/preview/0.225.0). Session loading / history maps to pi's session files. Sessions can be resumed both in `pi` and in the ACP client.
|
|
@@ -38,7 +42,7 @@ npm install -g @earendil-works/pi-coding-agent
|
|
|
38
42
|
```
|
|
39
43
|
|
|
40
44
|
- Node.js 22+
|
|
41
|
-
- `pi` installed and available on your `PATH` (the adapter runs the `pi` executable)
|
|
45
|
+
- `pi` v0.81.0+ installed and available on your `PATH` (the adapter runs the `pi` executable)
|
|
42
46
|
- Configure `pi` separately for your model providers/API keys
|
|
43
47
|
|
|
44
48
|
## Install
|
|
@@ -155,7 +159,7 @@ Loaded from:
|
|
|
155
159
|
|
|
156
160
|
Other built-in commands:
|
|
157
161
|
|
|
158
|
-
- `/model` -
|
|
162
|
+
- `/model` - not implemented (use the model selector UI in Zed)
|
|
159
163
|
- `/thinking` - maps to 'mode' selector in Zed
|
|
160
164
|
- `/clear` - not implemented (use ACP client 'new' command)
|
|
161
165
|
|
package/dist/index.js
CHANGED
|
@@ -54,6 +54,7 @@ import { isAbsolute, resolve as resolvePath } from "path";
|
|
|
54
54
|
// src/pi-rpc/process.ts
|
|
55
55
|
import { spawn } from "child_process";
|
|
56
56
|
import * as readline from "readline";
|
|
57
|
+
import crossSpawn from "cross-spawn";
|
|
57
58
|
|
|
58
59
|
// src/pi-rpc/command.ts
|
|
59
60
|
import { platform } from "os";
|
|
@@ -89,6 +90,7 @@ var ANSI_ESCAPE_REGEX = new RegExp(
|
|
|
89
90
|
function stripAnsi(s) {
|
|
90
91
|
return s.replace(ANSI_ESCAPE_REGEX, "");
|
|
91
92
|
}
|
|
93
|
+
var SESSION_STATS_TIMEOUT_MS = 1e3;
|
|
92
94
|
var PiRpcProcess = class _PiRpcProcess {
|
|
93
95
|
child;
|
|
94
96
|
pending = /* @__PURE__ */ new Map();
|
|
@@ -109,14 +111,8 @@ var PiRpcProcess = class _PiRpcProcess {
|
|
|
109
111
|
}
|
|
110
112
|
if (msg?.type === "response") {
|
|
111
113
|
const id = typeof msg.id === "string" ? msg.id : void 0;
|
|
112
|
-
if (id)
|
|
113
|
-
|
|
114
|
-
if (pending) {
|
|
115
|
-
this.pending.delete(id);
|
|
116
|
-
pending.resolve(msg);
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
114
|
+
if (id !== void 0) this.pending.get(id)?.resolve(msg);
|
|
115
|
+
return;
|
|
120
116
|
}
|
|
121
117
|
for (const h of this.eventHandlers) h(msg);
|
|
122
118
|
});
|
|
@@ -134,11 +130,11 @@ var PiRpcProcess = class _PiRpcProcess {
|
|
|
134
130
|
const cmd = getPiCommand(params.piCommand);
|
|
135
131
|
const args = ["--mode", "rpc", "--no-themes"];
|
|
136
132
|
if (params.sessionPath) args.push("--session", params.sessionPath);
|
|
137
|
-
const
|
|
133
|
+
const start = shouldUseShellForPiCommand(cmd) ? crossSpawn : spawn;
|
|
134
|
+
const child = start(cmd, args, {
|
|
138
135
|
cwd: params.cwd,
|
|
139
136
|
stdio: "pipe",
|
|
140
|
-
env: process.env
|
|
141
|
-
shell: shouldUseShellForPiCommand(cmd)
|
|
137
|
+
env: process.env
|
|
142
138
|
});
|
|
143
139
|
try {
|
|
144
140
|
await new Promise((resolve4, reject) => {
|
|
@@ -229,6 +225,17 @@ var PiRpcProcess = class _PiRpcProcess {
|
|
|
229
225
|
if (!res.success) throw new Error(`pi set_model failed: ${res.error ?? JSON.stringify(res.data)}`);
|
|
230
226
|
return res.data;
|
|
231
227
|
}
|
|
228
|
+
async getAvailableThinkingLevels() {
|
|
229
|
+
const res = await this.request({ type: "get_available_thinking_levels" });
|
|
230
|
+
if (!res.success)
|
|
231
|
+
throw new Error(`pi get_available_thinking_levels failed: ${res.error ?? JSON.stringify(res.data)}`);
|
|
232
|
+
const data = res.data;
|
|
233
|
+
const levels = data && typeof data === "object" && "levels" in data ? data.levels : void 0;
|
|
234
|
+
if (!Array.isArray(levels) || levels.length === 0 || !levels.every((level) => typeof level === "string" && level.length > 0)) {
|
|
235
|
+
throw new Error("pi get_available_thinking_levels returned invalid levels");
|
|
236
|
+
}
|
|
237
|
+
return levels;
|
|
238
|
+
}
|
|
232
239
|
async setThinkingLevel(level) {
|
|
233
240
|
const res = await this.request({ type: "set_thinking_level", level });
|
|
234
241
|
if (!res.success) throw new Error(`pi set_thinking_level failed: ${res.error ?? JSON.stringify(res.data)}`);
|
|
@@ -250,10 +257,10 @@ var PiRpcProcess = class _PiRpcProcess {
|
|
|
250
257
|
const res = await this.request({ type: "set_auto_compaction", enabled });
|
|
251
258
|
if (!res.success) throw new Error(`pi set_auto_compaction failed: ${res.error ?? JSON.stringify(res.data)}`);
|
|
252
259
|
}
|
|
253
|
-
async getSessionStats() {
|
|
254
|
-
const res = await this.request({ type: "get_session_stats" });
|
|
260
|
+
async getSessionStats(timeoutMs) {
|
|
261
|
+
const res = await this.request({ type: "get_session_stats" }, { timeoutMs });
|
|
255
262
|
if (!res.success) throw new Error(`pi get_session_stats failed: ${res.error ?? JSON.stringify(res.data)}`);
|
|
256
|
-
return res.data;
|
|
263
|
+
return res.data ?? {};
|
|
257
264
|
}
|
|
258
265
|
async setSessionName(name) {
|
|
259
266
|
const res = await this.request({ type: "set_session_name", name });
|
|
@@ -283,15 +290,41 @@ var PiRpcProcess = class _PiRpcProcess {
|
|
|
283
290
|
await this.writeLine(`${JSON.stringify({ type: "extension_ui_response", ...response })}
|
|
284
291
|
`);
|
|
285
292
|
}
|
|
286
|
-
request(cmd) {
|
|
293
|
+
request(cmd, opts) {
|
|
287
294
|
const id = crypto.randomUUID();
|
|
288
295
|
const withId = { ...cmd, id };
|
|
296
|
+
const timeoutMs = opts?.timeoutMs;
|
|
289
297
|
const line = `${JSON.stringify(withId)}
|
|
290
298
|
`;
|
|
291
299
|
return new Promise((resolve4, reject) => {
|
|
292
|
-
|
|
300
|
+
let timer;
|
|
301
|
+
const drop = () => {
|
|
302
|
+
if (timer !== void 0) {
|
|
303
|
+
clearTimeout(timer);
|
|
304
|
+
timer = void 0;
|
|
305
|
+
}
|
|
306
|
+
return this.pending.delete(id);
|
|
307
|
+
};
|
|
308
|
+
this.pending.set(id, {
|
|
309
|
+
resolve: (res) => {
|
|
310
|
+
drop();
|
|
311
|
+
resolve4(res);
|
|
312
|
+
},
|
|
313
|
+
reject: (error) => {
|
|
314
|
+
drop();
|
|
315
|
+
reject(error);
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
if (timeoutMs !== void 0) {
|
|
319
|
+
timer = setTimeout(() => {
|
|
320
|
+
timer = void 0;
|
|
321
|
+
if (!this.pending.delete(id)) return;
|
|
322
|
+
reject(new Error(`pi ${cmd.type} timed out after ${timeoutMs}ms`));
|
|
323
|
+
}, timeoutMs);
|
|
324
|
+
timer.unref?.();
|
|
325
|
+
}
|
|
293
326
|
void this.writeLine(line).catch((error) => {
|
|
294
|
-
|
|
327
|
+
if (!drop()) return;
|
|
295
328
|
reject(error);
|
|
296
329
|
});
|
|
297
330
|
});
|
|
@@ -610,6 +643,13 @@ var CONFIRM_PERMISSION_OPTIONS = [
|
|
|
610
643
|
];
|
|
611
644
|
var EXTENSION_UI_RAW_INPUT_KEYS = ["title", "message", "options", "placeholder", "prefill"];
|
|
612
645
|
var CHOICE_OPTION_PREFIX = "choice-";
|
|
646
|
+
function toUsageUpdate(stats) {
|
|
647
|
+
const used = stats?.contextUsage?.tokens;
|
|
648
|
+
const size = stats?.contextUsage?.contextWindow;
|
|
649
|
+
if (typeof used !== "number" || !Number.isSafeInteger(used) || used < 0) return null;
|
|
650
|
+
if (typeof size !== "number" || !Number.isSafeInteger(size) || size <= 0) return null;
|
|
651
|
+
return { sessionUpdate: "usage_update", used, size };
|
|
652
|
+
}
|
|
613
653
|
function findUniqueLineNumber(text, needle) {
|
|
614
654
|
if (!needle) return void 0;
|
|
615
655
|
const first = text.indexOf(needle);
|
|
@@ -787,8 +827,9 @@ var PiAcpSession = class {
|
|
|
787
827
|
// Some pi events can arrive out of order (e.g. late toolcall_* deltas after execution starts),
|
|
788
828
|
// and clients may hide progress if we ever downgrade back to `pending`.
|
|
789
829
|
currentToolCalls = /* @__PURE__ */ new Map();
|
|
790
|
-
// pi can emit multiple `turn_end` events for a single user prompt
|
|
791
|
-
//
|
|
830
|
+
// pi can emit multiple `turn_end` and `agent_end` events for a single user prompt
|
|
831
|
+
// when retry, compaction, or queued continuations run. The session-level prompt
|
|
832
|
+
// completes only when `agent_settled` is emitted.
|
|
792
833
|
inAgentLoop = false;
|
|
793
834
|
// For ACP diff support: capture file contents before edit/write mutations,
|
|
794
835
|
// then emit ToolCallContent {type:"diff"}. Compatible structured edit/write
|
|
@@ -880,6 +921,41 @@ var PiAcpSession = class {
|
|
|
880
921
|
async flushEmits() {
|
|
881
922
|
await this.lastEmit;
|
|
882
923
|
}
|
|
924
|
+
/**
|
|
925
|
+
* Best-effort: publish the real pi context-window occupancy as ACP `usage_update`.
|
|
926
|
+
* Queued updates are flushed even when the stats query fails or times out, so callers
|
|
927
|
+
* can await this before resolving `session/prompt`.
|
|
928
|
+
*/
|
|
929
|
+
async publishContextUsage() {
|
|
930
|
+
try {
|
|
931
|
+
if (typeof this.proc.getSessionStats === "function") {
|
|
932
|
+
const update = toUsageUpdate(await this.proc.getSessionStats(SESSION_STATS_TIMEOUT_MS));
|
|
933
|
+
if (update) this.emit(update);
|
|
934
|
+
}
|
|
935
|
+
} catch {
|
|
936
|
+
}
|
|
937
|
+
await this.flushEmits();
|
|
938
|
+
}
|
|
939
|
+
async settleTurn() {
|
|
940
|
+
await this.publishContextUsage();
|
|
941
|
+
const reason = this.cancelRequested ? "cancelled" : "end_turn";
|
|
942
|
+
this.pendingTurn?.resolve(reason);
|
|
943
|
+
this.pendingTurn = null;
|
|
944
|
+
this.inAgentLoop = false;
|
|
945
|
+
const next = this.turnQueue.shift();
|
|
946
|
+
if (next) {
|
|
947
|
+
this.emit({
|
|
948
|
+
sessionUpdate: "agent_message_chunk",
|
|
949
|
+
content: { type: "text", text: `Starting queued message. (${this.turnQueue.length} remaining)` }
|
|
950
|
+
});
|
|
951
|
+
this.startTurn(next);
|
|
952
|
+
} else {
|
|
953
|
+
this.emit({
|
|
954
|
+
sessionUpdate: "session_info_update",
|
|
955
|
+
_meta: { piAcp: { queueDepth: 0, running: false } }
|
|
956
|
+
});
|
|
957
|
+
}
|
|
958
|
+
}
|
|
883
959
|
emitBashToolCall(params) {
|
|
884
960
|
this.bashToolCallIds.add(params.toolCallId);
|
|
885
961
|
this.emit({
|
|
@@ -1205,25 +1281,11 @@ var PiAcpSession = class {
|
|
|
1205
1281
|
break;
|
|
1206
1282
|
}
|
|
1207
1283
|
case "agent_end": {
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
const next = this.turnQueue.shift();
|
|
1214
|
-
if (next) {
|
|
1215
|
-
this.emit({
|
|
1216
|
-
sessionUpdate: "agent_message_chunk",
|
|
1217
|
-
content: { type: "text", text: `Starting queued message. (${this.turnQueue.length} remaining)` }
|
|
1218
|
-
});
|
|
1219
|
-
this.startTurn(next);
|
|
1220
|
-
} else {
|
|
1221
|
-
this.emit({
|
|
1222
|
-
sessionUpdate: "session_info_update",
|
|
1223
|
-
_meta: { piAcp: { queueDepth: 0, running: false } }
|
|
1224
|
-
});
|
|
1225
|
-
}
|
|
1226
|
-
});
|
|
1284
|
+
this.inAgentLoop = false;
|
|
1285
|
+
break;
|
|
1286
|
+
}
|
|
1287
|
+
case "agent_settled": {
|
|
1288
|
+
void this.settleTurn();
|
|
1227
1289
|
break;
|
|
1228
1290
|
}
|
|
1229
1291
|
default:
|
|
@@ -1999,10 +2061,15 @@ var PiAcpAgent = class {
|
|
|
1999
2061
|
"Configure an API key or log in with an OAuth provider."
|
|
2000
2062
|
);
|
|
2001
2063
|
}
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2064
|
+
let configuration;
|
|
2065
|
+
try {
|
|
2066
|
+
if (stateErr) throw stateErr;
|
|
2067
|
+
configuration = await getSessionConfiguration(session.proc, { state, availableModels });
|
|
2068
|
+
} catch (err) {
|
|
2069
|
+
this.cleanupFailedNewSession(session.sessionId, state);
|
|
2070
|
+
throw maybeAuthRequiredError(err) ?? RequestError3.internalError({}, String(err?.message ?? err));
|
|
2071
|
+
}
|
|
2072
|
+
const { configOptions, models, modes } = configuration;
|
|
2006
2073
|
const quietStartup = getQuietStartup(params.cwd);
|
|
2007
2074
|
const updateNotice = buildUpdateNotice();
|
|
2008
2075
|
const preludeText = quietStartup ? updateNotice ? updateNotice + "\n" : "" : buildStartupInfo({
|
|
@@ -2027,6 +2094,7 @@ var PiAcpAgent = class {
|
|
|
2027
2094
|
if (preludeText) setTimeout(() => session.sendStartupInfoIfPending(), 0);
|
|
2028
2095
|
setTimeout(() => {
|
|
2029
2096
|
void (async () => {
|
|
2097
|
+
await session.publishContextUsage();
|
|
2030
2098
|
try {
|
|
2031
2099
|
const pi = await session.proc.getCommands();
|
|
2032
2100
|
const { commands } = toAvailableCommandsFromPiGetCommands(pi, {
|
|
@@ -2468,6 +2536,14 @@ ${JSON.stringify(stats, null, 2)}`;
|
|
|
2468
2536
|
mcpServers: params.mcpServers
|
|
2469
2537
|
});
|
|
2470
2538
|
const proc = session.proc;
|
|
2539
|
+
let configuration;
|
|
2540
|
+
try {
|
|
2541
|
+
configuration = await getSessionConfiguration(proc);
|
|
2542
|
+
} catch (err) {
|
|
2543
|
+
this.sessions.close(session.sessionId);
|
|
2544
|
+
throw err;
|
|
2545
|
+
}
|
|
2546
|
+
const { configOptions, models, modes } = configuration;
|
|
2471
2547
|
const fileCommands = loadSlashCommands(params.cwd);
|
|
2472
2548
|
this.sessions.closeAllExcept?.(session.sessionId);
|
|
2473
2549
|
this.store.upsert({
|
|
@@ -2561,7 +2637,6 @@ ${JSON.stringify(stats, null, 2)}`;
|
|
|
2561
2637
|
});
|
|
2562
2638
|
}
|
|
2563
2639
|
}
|
|
2564
|
-
const { configOptions, models, modes } = await getSessionConfiguration(proc);
|
|
2565
2640
|
const response = {
|
|
2566
2641
|
configOptions,
|
|
2567
2642
|
models,
|
|
@@ -2574,6 +2649,7 @@ ${JSON.stringify(stats, null, 2)}`;
|
|
|
2574
2649
|
};
|
|
2575
2650
|
setTimeout(() => {
|
|
2576
2651
|
void (async () => {
|
|
2652
|
+
await session.publishContextUsage();
|
|
2577
2653
|
try {
|
|
2578
2654
|
const pi = await proc.getCommands();
|
|
2579
2655
|
const { commands } = toAvailableCommandsFromPiGetCommands(pi, {
|
|
@@ -2621,66 +2697,48 @@ ${JSON.stringify(stats, null, 2)}`;
|
|
|
2621
2697
|
const session = await this.restoreSession(params.sessionId);
|
|
2622
2698
|
await setSessionModel(session.proc, params.modelId);
|
|
2623
2699
|
await emitConfigOptionsUpdate(this.conn, session.sessionId, session.proc);
|
|
2700
|
+
await session.publishContextUsage();
|
|
2624
2701
|
}
|
|
2625
2702
|
async setSessionMode(params) {
|
|
2626
2703
|
const session = await this.restoreSession(params.sessionId);
|
|
2627
|
-
const mode =
|
|
2628
|
-
if (
|
|
2629
|
-
throw RequestError3.invalidParams(
|
|
2704
|
+
const mode = params.modeId;
|
|
2705
|
+
if (typeof mode !== "string" || mode.length === 0) {
|
|
2706
|
+
throw RequestError3.invalidParams("Expected nonempty string modeId");
|
|
2630
2707
|
}
|
|
2631
2708
|
await session.proc.setThinkingLevel(mode);
|
|
2632
|
-
void this.conn.sessionUpdate({
|
|
2633
|
-
sessionId: session.sessionId,
|
|
2634
|
-
update: {
|
|
2635
|
-
sessionUpdate: "current_mode_update",
|
|
2636
|
-
currentModeId: mode
|
|
2637
|
-
}
|
|
2638
|
-
});
|
|
2639
2709
|
await emitConfigOptionsUpdate(this.conn, session.sessionId, session.proc);
|
|
2640
2710
|
return {};
|
|
2641
2711
|
}
|
|
2642
2712
|
async setSessionConfigOption(params) {
|
|
2643
2713
|
const session = await this.restoreSession(params.sessionId);
|
|
2644
2714
|
const configId = String(params.configId);
|
|
2715
|
+
let modelChanged = false;
|
|
2645
2716
|
if (typeof params.value !== "string") {
|
|
2646
2717
|
throw RequestError3.invalidParams(`Expected string value for config option: ${configId}`);
|
|
2647
2718
|
}
|
|
2648
2719
|
if (configId === MODEL_CONFIG_ID) {
|
|
2649
2720
|
await setSessionModel(session.proc, params.value);
|
|
2721
|
+
modelChanged = true;
|
|
2650
2722
|
} else if (configId === THOUGHT_LEVEL_CONFIG_ID) {
|
|
2651
|
-
if (
|
|
2652
|
-
throw RequestError3.invalidParams(
|
|
2723
|
+
if (params.value.length === 0) {
|
|
2724
|
+
throw RequestError3.invalidParams("Expected nonempty thinking level");
|
|
2653
2725
|
}
|
|
2654
2726
|
await session.proc.setThinkingLevel(params.value);
|
|
2655
|
-
void this.conn.sessionUpdate({
|
|
2656
|
-
sessionId: session.sessionId,
|
|
2657
|
-
update: {
|
|
2658
|
-
sessionUpdate: "current_mode_update",
|
|
2659
|
-
currentModeId: params.value
|
|
2660
|
-
}
|
|
2661
|
-
});
|
|
2662
2727
|
} else {
|
|
2663
2728
|
throw RequestError3.invalidParams(`Unknown config option: ${configId}`);
|
|
2664
2729
|
}
|
|
2665
2730
|
const configOptions = await emitConfigOptionsUpdate(this.conn, session.sessionId, session.proc);
|
|
2731
|
+
if (modelChanged) await session.publishContextUsage();
|
|
2666
2732
|
return { configOptions };
|
|
2667
2733
|
}
|
|
2668
2734
|
};
|
|
2669
|
-
function isThinkingLevel(x) {
|
|
2670
|
-
return x === "off" || x === "minimal" || x === "low" || x === "medium" || x === "high" || x === "xhigh";
|
|
2671
|
-
}
|
|
2672
2735
|
async function getThinkingState(proc, pre) {
|
|
2673
|
-
|
|
2674
|
-
const
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
}
|
|
2680
|
-
})();
|
|
2681
|
-
const tl = typeof state?.thinkingLevel === "string" ? state.thinkingLevel : null;
|
|
2682
|
-
if (tl && isThinkingLevel(tl)) current = tl;
|
|
2683
|
-
const available = ["off", "minimal", "low", "medium", "high", "xhigh"];
|
|
2736
|
+
const state = pre?.state ?? await proc.getState();
|
|
2737
|
+
const available = await proc.getAvailableThinkingLevels();
|
|
2738
|
+
const current = state && typeof state === "object" && "thinkingLevel" in state ? state.thinkingLevel : void 0;
|
|
2739
|
+
if (typeof current !== "string" || current.length === 0 || !available.includes(current)) {
|
|
2740
|
+
throw new Error("pi returned a thinking level absent from available levels");
|
|
2741
|
+
}
|
|
2684
2742
|
return {
|
|
2685
2743
|
currentModeId: current,
|
|
2686
2744
|
availableModes: available.map((id) => ({
|
|
@@ -2691,7 +2749,8 @@ async function getThinkingState(proc, pre) {
|
|
|
2691
2749
|
};
|
|
2692
2750
|
}
|
|
2693
2751
|
async function getSessionConfiguration(proc, pre) {
|
|
2694
|
-
const
|
|
2752
|
+
const state = pre?.state ?? await proc.getState();
|
|
2753
|
+
const [models, modes] = await Promise.all([getModelState(proc, { ...pre, state }), getThinkingState(proc, { state })]);
|
|
2695
2754
|
return {
|
|
2696
2755
|
configOptions: buildConfigOptions({ models, modes }),
|
|
2697
2756
|
models,
|
|
@@ -2774,7 +2833,11 @@ async function getModelState(proc, pre) {
|
|
|
2774
2833
|
};
|
|
2775
2834
|
}
|
|
2776
2835
|
async function emitConfigOptionsUpdate(conn, sessionId, proc) {
|
|
2777
|
-
const { configOptions } = await getSessionConfiguration(proc);
|
|
2836
|
+
const { configOptions, modes } = await getSessionConfiguration(proc);
|
|
2837
|
+
await conn.sessionUpdate({
|
|
2838
|
+
sessionId,
|
|
2839
|
+
update: { sessionUpdate: "current_mode_update", currentModeId: modes.currentModeId }
|
|
2840
|
+
});
|
|
2778
2841
|
await conn.sessionUpdate({
|
|
2779
2842
|
sessionId,
|
|
2780
2843
|
update: {
|