@linkshell/host 0.4.17 → 0.4.18
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 +27 -1
- package/dist/host/src/drivers/acp/connection.d.ts +1 -0
- package/dist/host/src/drivers/acp/connection.js +6 -0
- package/dist/host/src/drivers/acp/connection.js.map +1 -1
- package/dist/host/src/drivers/acp/driver.d.ts +10 -5
- package/dist/host/src/drivers/acp/driver.js +51 -25
- package/dist/host/src/drivers/acp/driver.js.map +1 -1
- package/dist/host/src/drivers/acp/questions.d.ts +14 -0
- package/dist/host/src/drivers/acp/questions.js +114 -0
- package/dist/host/src/drivers/acp/questions.js.map +1 -0
- package/dist/host/src/drivers/claude/tasks.d.ts +2 -2
- package/dist/host/src/drivers/claude/transcript.d.ts +76 -69
- package/dist/host/src/drivers/codex/attention.d.ts +7 -0
- package/dist/host/src/drivers/codex/attention.js +82 -0
- package/dist/host/src/drivers/codex/attention.js.map +1 -0
- package/dist/host/src/drivers/codex/driver.d.ts +2 -0
- package/dist/host/src/drivers/codex/driver.js +45 -2
- package/dist/host/src/drivers/codex/driver.js.map +1 -1
- package/dist/host/src/drivers/types.d.ts +2 -1
- package/dist/host/src/hub.d.ts +3 -1
- package/dist/host/src/hub.js +33 -3
- package/dist/host/src/hub.js.map +1 -1
- package/dist/host/tsconfig.tsbuildinfo +1 -1
- package/dist/wire/src/async-questions.d.ts +40 -0
- package/dist/wire/src/async-questions.js +66 -0
- package/dist/wire/src/async-questions.js.map +1 -0
- package/dist/wire/src/goal.d.ts +2 -2
- package/dist/wire/src/index.d.ts +1 -0
- package/dist/wire/src/index.js +1 -0
- package/dist/wire/src/index.js.map +1 -1
- package/dist/wire/src/model.d.ts +108 -84
- package/dist/wire/src/model.js +3 -0
- package/dist/wire/src/model.js.map +1 -1
- package/dist/wire/src/rpc.d.ts +2110 -1722
- package/dist/wire/src/updates.d.ts +633 -561
- package/dist/wire/src/updates.js +6 -1
- package/dist/wire/src/updates.js.map +1 -1
- package/dist/wire/src/workflow.d.ts +8 -8
- package/package.json +2 -2
|
@@ -46,7 +46,7 @@ export declare const transcriptTimes: WeakMap<{
|
|
|
46
46
|
type: "resource_link";
|
|
47
47
|
name: string;
|
|
48
48
|
uri: string;
|
|
49
|
-
kind?: "
|
|
49
|
+
kind?: "file" | "skill" | "agent" | undefined;
|
|
50
50
|
};
|
|
51
51
|
sessionUpdate: "user_message_chunk";
|
|
52
52
|
messageId?: string | undefined;
|
|
@@ -63,7 +63,7 @@ export declare const transcriptTimes: WeakMap<{
|
|
|
63
63
|
type: "resource_link";
|
|
64
64
|
name: string;
|
|
65
65
|
uri: string;
|
|
66
|
-
kind?: "
|
|
66
|
+
kind?: "file" | "skill" | "agent" | undefined;
|
|
67
67
|
};
|
|
68
68
|
sessionUpdate: "agent_message_chunk";
|
|
69
69
|
messageId: string;
|
|
@@ -81,7 +81,7 @@ export declare const transcriptTimes: WeakMap<{
|
|
|
81
81
|
type: "resource_link";
|
|
82
82
|
name: string;
|
|
83
83
|
uri: string;
|
|
84
|
-
kind?: "
|
|
84
|
+
kind?: "file" | "skill" | "agent" | undefined;
|
|
85
85
|
};
|
|
86
86
|
sessionUpdate: "agent_thought_chunk";
|
|
87
87
|
messageId: string;
|
|
@@ -90,23 +90,60 @@ export declare const transcriptTimes: WeakMap<{
|
|
|
90
90
|
status: "completed" | "failed" | "pending" | "in_progress";
|
|
91
91
|
toolCallId: string;
|
|
92
92
|
title: string;
|
|
93
|
-
kind: "
|
|
93
|
+
kind: "delete" | "other" | "read" | "edit" | "move" | "search" | "execute" | "think" | "fetch";
|
|
94
94
|
sessionUpdate: "tool_call";
|
|
95
|
+
content?: ({
|
|
96
|
+
type: "content";
|
|
97
|
+
content: {
|
|
98
|
+
type: "text";
|
|
99
|
+
text: string;
|
|
100
|
+
} | {
|
|
101
|
+
type: "image";
|
|
102
|
+
mimeType: string;
|
|
103
|
+
data?: string | undefined;
|
|
104
|
+
uri?: string | undefined;
|
|
105
|
+
} | {
|
|
106
|
+
type: "resource_link";
|
|
107
|
+
name: string;
|
|
108
|
+
uri: string;
|
|
109
|
+
kind?: "file" | "skill" | "agent" | undefined;
|
|
110
|
+
};
|
|
111
|
+
} | {
|
|
112
|
+
path: string;
|
|
113
|
+
type: "diff";
|
|
114
|
+
newText: string;
|
|
115
|
+
oldText?: string | null | undefined;
|
|
116
|
+
} | {
|
|
117
|
+
path: string;
|
|
118
|
+
type: "patch";
|
|
119
|
+
diff: string;
|
|
120
|
+
change: "add" | "delete" | "update";
|
|
121
|
+
movePath?: string | undefined;
|
|
122
|
+
} | {
|
|
123
|
+
type: "terminal";
|
|
124
|
+
terminalId: string;
|
|
125
|
+
})[] | undefined;
|
|
126
|
+
parentToolCallId?: string | undefined;
|
|
127
|
+
rawInput?: unknown;
|
|
128
|
+
locations?: {
|
|
129
|
+
path: string;
|
|
130
|
+
line?: number | undefined;
|
|
131
|
+
}[] | undefined;
|
|
95
132
|
detail?: {
|
|
96
133
|
type: "mcp";
|
|
97
|
-
tool: string;
|
|
98
134
|
server: string;
|
|
135
|
+
tool: string;
|
|
99
136
|
} | {
|
|
100
137
|
type: "subagent";
|
|
101
138
|
action: "message" | "resume" | "spawn" | "wait" | "stop" | "list";
|
|
102
|
-
state?: "
|
|
139
|
+
state?: "unknown" | "paused" | "running" | "completed" | "failed" | "stopped" | "pending" | undefined;
|
|
103
140
|
model?: string | undefined;
|
|
104
141
|
name?: string | undefined;
|
|
105
142
|
task?: string | undefined;
|
|
106
143
|
agentType?: string | undefined;
|
|
107
144
|
workflow?: {
|
|
108
145
|
completed?: number | undefined;
|
|
109
|
-
state?: "
|
|
146
|
+
state?: "paused" | "running" | "completed" | "failed" | "stopped" | undefined;
|
|
110
147
|
tokens?: number | undefined;
|
|
111
148
|
durationMs?: number | undefined;
|
|
112
149
|
startedAt?: number | undefined;
|
|
@@ -122,7 +159,7 @@ export declare const transcriptTimes: WeakMap<{
|
|
|
122
159
|
agents?: {
|
|
123
160
|
id: string;
|
|
124
161
|
title: string;
|
|
125
|
-
state: "
|
|
162
|
+
state: "unknown" | "paused" | "running" | "completed" | "failed" | "stopped" | "pending";
|
|
126
163
|
toolCallId?: string | undefined;
|
|
127
164
|
phaseId?: string | undefined;
|
|
128
165
|
model?: string | undefined;
|
|
@@ -154,7 +191,11 @@ export declare const transcriptTimes: WeakMap<{
|
|
|
154
191
|
text: string;
|
|
155
192
|
more?: number | undefined;
|
|
156
193
|
} | undefined;
|
|
157
|
-
|
|
194
|
+
} | {
|
|
195
|
+
toolCallId: string;
|
|
196
|
+
sessionUpdate: "tool_call_update";
|
|
197
|
+
status?: "completed" | "failed" | "pending" | "in_progress" | undefined;
|
|
198
|
+
title?: string | undefined;
|
|
158
199
|
content?: ({
|
|
159
200
|
type: "content";
|
|
160
201
|
content: {
|
|
@@ -169,7 +210,7 @@ export declare const transcriptTimes: WeakMap<{
|
|
|
169
210
|
type: "resource_link";
|
|
170
211
|
name: string;
|
|
171
212
|
uri: string;
|
|
172
|
-
kind?: "
|
|
213
|
+
kind?: "file" | "skill" | "agent" | undefined;
|
|
173
214
|
};
|
|
174
215
|
} | {
|
|
175
216
|
path: string;
|
|
@@ -180,37 +221,28 @@ export declare const transcriptTimes: WeakMap<{
|
|
|
180
221
|
path: string;
|
|
181
222
|
type: "patch";
|
|
182
223
|
diff: string;
|
|
183
|
-
change: "
|
|
224
|
+
change: "add" | "delete" | "update";
|
|
184
225
|
movePath?: string | undefined;
|
|
185
226
|
} | {
|
|
186
227
|
type: "terminal";
|
|
187
228
|
terminalId: string;
|
|
188
229
|
})[] | undefined;
|
|
189
|
-
|
|
190
|
-
locations?: {
|
|
191
|
-
path: string;
|
|
192
|
-
line?: number | undefined;
|
|
193
|
-
}[] | undefined;
|
|
194
|
-
} | {
|
|
195
|
-
toolCallId: string;
|
|
196
|
-
sessionUpdate: "tool_call_update";
|
|
197
|
-
status?: "completed" | "failed" | "pending" | "in_progress" | undefined;
|
|
198
|
-
title?: string | undefined;
|
|
230
|
+
parentToolCallId?: string | undefined;
|
|
199
231
|
detail?: {
|
|
200
232
|
type: "mcp";
|
|
201
|
-
tool: string;
|
|
202
233
|
server: string;
|
|
234
|
+
tool: string;
|
|
203
235
|
} | {
|
|
204
236
|
type: "subagent";
|
|
205
237
|
action: "message" | "resume" | "spawn" | "wait" | "stop" | "list";
|
|
206
|
-
state?: "
|
|
238
|
+
state?: "unknown" | "paused" | "running" | "completed" | "failed" | "stopped" | "pending" | undefined;
|
|
207
239
|
model?: string | undefined;
|
|
208
240
|
name?: string | undefined;
|
|
209
241
|
task?: string | undefined;
|
|
210
242
|
agentType?: string | undefined;
|
|
211
243
|
workflow?: {
|
|
212
244
|
completed?: number | undefined;
|
|
213
|
-
state?: "
|
|
245
|
+
state?: "paused" | "running" | "completed" | "failed" | "stopped" | undefined;
|
|
214
246
|
tokens?: number | undefined;
|
|
215
247
|
durationMs?: number | undefined;
|
|
216
248
|
startedAt?: number | undefined;
|
|
@@ -226,7 +258,7 @@ export declare const transcriptTimes: WeakMap<{
|
|
|
226
258
|
agents?: {
|
|
227
259
|
id: string;
|
|
228
260
|
title: string;
|
|
229
|
-
state: "
|
|
261
|
+
state: "unknown" | "paused" | "running" | "completed" | "failed" | "stopped" | "pending";
|
|
230
262
|
toolCallId?: string | undefined;
|
|
231
263
|
phaseId?: string | undefined;
|
|
232
264
|
model?: string | undefined;
|
|
@@ -258,38 +290,6 @@ export declare const transcriptTimes: WeakMap<{
|
|
|
258
290
|
text: string;
|
|
259
291
|
more?: number | undefined;
|
|
260
292
|
} | undefined;
|
|
261
|
-
parentToolCallId?: string | undefined;
|
|
262
|
-
content?: ({
|
|
263
|
-
type: "content";
|
|
264
|
-
content: {
|
|
265
|
-
type: "text";
|
|
266
|
-
text: string;
|
|
267
|
-
} | {
|
|
268
|
-
type: "image";
|
|
269
|
-
mimeType: string;
|
|
270
|
-
data?: string | undefined;
|
|
271
|
-
uri?: string | undefined;
|
|
272
|
-
} | {
|
|
273
|
-
type: "resource_link";
|
|
274
|
-
name: string;
|
|
275
|
-
uri: string;
|
|
276
|
-
kind?: "agent" | "file" | "skill" | undefined;
|
|
277
|
-
};
|
|
278
|
-
} | {
|
|
279
|
-
path: string;
|
|
280
|
-
type: "diff";
|
|
281
|
-
newText: string;
|
|
282
|
-
oldText?: string | null | undefined;
|
|
283
|
-
} | {
|
|
284
|
-
path: string;
|
|
285
|
-
type: "patch";
|
|
286
|
-
diff: string;
|
|
287
|
-
change: "delete" | "add" | "update";
|
|
288
|
-
movePath?: string | undefined;
|
|
289
|
-
} | {
|
|
290
|
-
type: "terminal";
|
|
291
|
-
terminalId: string;
|
|
292
|
-
})[] | undefined;
|
|
293
293
|
appendOutput?: string | undefined;
|
|
294
294
|
rawOutput?: unknown;
|
|
295
295
|
} | {
|
|
@@ -302,8 +302,8 @@ export declare const transcriptTimes: WeakMap<{
|
|
|
302
302
|
} | {
|
|
303
303
|
sessionUpdate: "ls_goal";
|
|
304
304
|
goal: {
|
|
305
|
-
status: "paused" | "active" | "blocked" | "usageLimited" | "budgetLimited" | "complete";
|
|
306
305
|
objective: string;
|
|
306
|
+
status: "active" | "paused" | "blocked" | "usageLimited" | "budgetLimited" | "complete";
|
|
307
307
|
tokenBudget?: number | null | undefined;
|
|
308
308
|
tokensUsed?: number | undefined;
|
|
309
309
|
timeUsedSeconds?: number | undefined;
|
|
@@ -328,16 +328,23 @@ export declare const transcriptTimes: WeakMap<{
|
|
|
328
328
|
sessionUpdate: "usage_update";
|
|
329
329
|
usedTokens?: number | undefined;
|
|
330
330
|
contextWindow?: number | undefined;
|
|
331
|
+
} | {
|
|
332
|
+
sessionUpdate: "ls_async_questions";
|
|
333
|
+
questions: {
|
|
334
|
+
options: string[];
|
|
335
|
+
id: string;
|
|
336
|
+
title: string;
|
|
337
|
+
}[];
|
|
331
338
|
} | {
|
|
332
339
|
sessionUpdate: "ls_message_done";
|
|
333
340
|
messageId: string;
|
|
334
341
|
role: "agent" | "thought" | "user";
|
|
342
|
+
parentToolCallId?: string | undefined;
|
|
335
343
|
questions?: {
|
|
336
344
|
options: string[];
|
|
337
345
|
id: string;
|
|
338
346
|
title: string;
|
|
339
347
|
}[] | undefined;
|
|
340
|
-
parentToolCallId?: string | undefined;
|
|
341
348
|
} | {
|
|
342
349
|
options: {
|
|
343
350
|
values: {
|
|
@@ -347,7 +354,7 @@ export declare const transcriptTimes: WeakMap<{
|
|
|
347
354
|
}[];
|
|
348
355
|
id: string;
|
|
349
356
|
name: string;
|
|
350
|
-
category: "model" | "
|
|
357
|
+
category: "model" | "mode" | "effort" | "other";
|
|
351
358
|
current: string;
|
|
352
359
|
}[];
|
|
353
360
|
sessionUpdate: "ls_config";
|
|
@@ -361,22 +368,22 @@ export declare const transcriptTimes: WeakMap<{
|
|
|
361
368
|
sessionUpdate: "ls_turn";
|
|
362
369
|
parentToolCallId?: string | undefined;
|
|
363
370
|
turnId?: string | undefined;
|
|
364
|
-
stopReason?: "
|
|
371
|
+
stopReason?: "end_turn" | "cancelled" | "error" | "max_tokens" | "refusal" | undefined;
|
|
365
372
|
} | {
|
|
366
373
|
options: {
|
|
367
374
|
name: string;
|
|
368
|
-
optionId: string;
|
|
369
375
|
kind: "allow_once" | "allow_always" | "reject_once" | "reject_always";
|
|
376
|
+
optionId: string;
|
|
370
377
|
}[];
|
|
371
378
|
title: string;
|
|
372
|
-
requestId: string;
|
|
373
379
|
sessionUpdate: "ls_permission";
|
|
380
|
+
requestId: string;
|
|
374
381
|
toolCallId?: string | undefined;
|
|
375
382
|
detail?: string | undefined;
|
|
376
383
|
questions?: {
|
|
377
384
|
id: string;
|
|
378
|
-
kind: "text" | "choice" | "choices";
|
|
379
385
|
text: string;
|
|
386
|
+
kind: "text" | "choice" | "choices";
|
|
380
387
|
options?: {
|
|
381
388
|
value: string;
|
|
382
389
|
label: string;
|
|
@@ -388,8 +395,8 @@ export declare const transcriptTimes: WeakMap<{
|
|
|
388
395
|
required?: boolean | undefined;
|
|
389
396
|
}[] | undefined;
|
|
390
397
|
} | {
|
|
391
|
-
requestId: string;
|
|
392
398
|
sessionUpdate: "ls_permission_resolved";
|
|
399
|
+
requestId: string;
|
|
393
400
|
optionId?: string | undefined;
|
|
394
401
|
answers?: {
|
|
395
402
|
values: string[];
|
|
@@ -397,27 +404,27 @@ export declare const transcriptTimes: WeakMap<{
|
|
|
397
404
|
other?: string | undefined;
|
|
398
405
|
}[] | undefined;
|
|
399
406
|
} | {
|
|
400
|
-
driver: "remote" | "desktop" | "none";
|
|
401
407
|
sessionUpdate: "ls_driver";
|
|
408
|
+
driver: "desktop" | "remote" | "none";
|
|
402
409
|
deviceId?: string | undefined;
|
|
403
410
|
} | {
|
|
404
|
-
state: "running" | "
|
|
411
|
+
state: "running" | "error" | "idle" | "waiting" | "offline";
|
|
405
412
|
sessionUpdate: "ls_status";
|
|
406
413
|
} | {
|
|
407
414
|
task: {
|
|
408
415
|
id: string;
|
|
409
416
|
title: string;
|
|
410
|
-
state: "
|
|
417
|
+
state: "unknown" | "running" | "completed" | "failed" | "stopped";
|
|
411
418
|
startedAt: number;
|
|
412
419
|
kind: "shell" | "monitor";
|
|
413
420
|
toolCallId?: string | undefined;
|
|
414
421
|
endedAt?: number | undefined;
|
|
415
|
-
lastSeq?: number | undefined;
|
|
416
422
|
command?: string | undefined;
|
|
417
423
|
summary?: string | undefined;
|
|
418
424
|
exitCode?: number | undefined;
|
|
419
425
|
output?: boolean | undefined;
|
|
420
426
|
canStop?: boolean | undefined;
|
|
427
|
+
lastSeq?: number | undefined;
|
|
421
428
|
};
|
|
422
429
|
sessionUpdate: "ls_task";
|
|
423
430
|
} | {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type AsyncQuestion } from "@linkshell/wire";
|
|
2
|
+
export interface CodexAttention {
|
|
3
|
+
running: boolean;
|
|
4
|
+
questions: AsyncQuestion[];
|
|
5
|
+
}
|
|
6
|
+
/** Read only the current turn, so list badges work without taking ownership of the thread. */
|
|
7
|
+
export declare function rolloutAttention(path: string, chunk?: number, limit?: number): CodexAttention | undefined;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { closeSync, fstatSync, openSync, readSync } from "node:fs";
|
|
2
|
+
import { answeredQuestions } from "@linkshell/wire";
|
|
3
|
+
import { asyncQuestions } from "./mapper.js";
|
|
4
|
+
/** Read only the current turn, so list badges work without taking ownership of the thread. */
|
|
5
|
+
export function rolloutAttention(path, chunk = 256 * 1024, limit = 16 * 1024 * 1024) {
|
|
6
|
+
let fd;
|
|
7
|
+
try {
|
|
8
|
+
fd = openSync(path, "r");
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
const size = fstatSync(fd).size;
|
|
15
|
+
let end = size;
|
|
16
|
+
let prefix = Buffer.alloc(0);
|
|
17
|
+
const questions = [];
|
|
18
|
+
const answered = new Set();
|
|
19
|
+
while (end > 0 && size - end < limit) {
|
|
20
|
+
const start = Math.max(0, end - Math.min(chunk, limit - (size - end)));
|
|
21
|
+
const bytes = Buffer.alloc(end - start);
|
|
22
|
+
readSync(fd, bytes, 0, bytes.length, start);
|
|
23
|
+
let data = Buffer.concat([bytes, prefix]);
|
|
24
|
+
// A writer may still be appending the last record.
|
|
25
|
+
if (end === size)
|
|
26
|
+
data = data.subarray(0, data.lastIndexOf(10) + 1);
|
|
27
|
+
end = start;
|
|
28
|
+
const first = start === 0 ? 0 : data.indexOf(10) + 1;
|
|
29
|
+
if (first === 0 && start > 0) {
|
|
30
|
+
prefix = data;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
const lines = data.subarray(first).toString("utf8").split("\n");
|
|
34
|
+
prefix = data.subarray(0, first);
|
|
35
|
+
for (let index = lines.length - 1; index >= 0; index--) {
|
|
36
|
+
const line = lines[index];
|
|
37
|
+
if (!line.includes('"task_') && !line.includes("request_user_input_async") && !line.includes("send_user_message_question_reply"))
|
|
38
|
+
continue;
|
|
39
|
+
let entry;
|
|
40
|
+
try {
|
|
41
|
+
entry = JSON.parse(line);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const payload = entry.payload;
|
|
47
|
+
if (!payload || typeof payload !== "object")
|
|
48
|
+
continue;
|
|
49
|
+
if (entry.type === "event_msg" && payload.type === "task_complete")
|
|
50
|
+
return { running: false, questions: [] };
|
|
51
|
+
if (entry.type === "event_msg" && payload.type === "task_started") {
|
|
52
|
+
return { running: true, questions: questions.filter((question) => !answered.has(question.id)) };
|
|
53
|
+
}
|
|
54
|
+
if (entry.type !== "response_item")
|
|
55
|
+
continue;
|
|
56
|
+
if (payload.type === "function_call" && typeof payload.name === "string" && /(?:^|\.)request_user_input_async$/.test(payload.name)) {
|
|
57
|
+
try {
|
|
58
|
+
const args = JSON.parse(payload.arguments);
|
|
59
|
+
questions.unshift(...(asyncQuestions({ id: payload.call_id, delivery: "async", questions: args.questions }) ?? []));
|
|
60
|
+
}
|
|
61
|
+
catch { /* Incomplete arguments cannot make an actionable question. */ }
|
|
62
|
+
}
|
|
63
|
+
if (payload.type === "message" && payload.role === "user" && Array.isArray(payload.content)) {
|
|
64
|
+
for (const block of payload.content) {
|
|
65
|
+
if (typeof block?.text === "string")
|
|
66
|
+
for (const [id] of answeredQuestions(block.text))
|
|
67
|
+
answered.add(id);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Unknown is not idle: do not clear a known pending question on a bounded read.
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
finally {
|
|
79
|
+
closeSync(fd);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=attention.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attention.js","sourceRoot":"","sources":["../../../../../src/drivers/codex/attention.ts"],"names":[],"mappings":"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"}
|
|
@@ -116,6 +116,7 @@ export declare class CodexDriver implements AgentDriver {
|
|
|
116
116
|
start(host: DriverHost): Promise<DriverStatus>;
|
|
117
117
|
authStatus(): Promise<AgentAuth>;
|
|
118
118
|
stop(): Promise<void>;
|
|
119
|
+
private readonly attention;
|
|
119
120
|
listSessions(limit: number): Promise<DiscoveredSession[]>;
|
|
120
121
|
private stateElsewhere;
|
|
121
122
|
/** Codex's own fork: a new thread with this one's turns, all or through `lastTurnId`, in `cwd`. */
|
|
@@ -139,6 +140,7 @@ export declare class CodexDriver implements AgentDriver {
|
|
|
139
140
|
private observe;
|
|
140
141
|
/** Reports what the other process has finished since the last look. An item still being written isn't on disk. */
|
|
141
142
|
private refresh;
|
|
143
|
+
private announceQuestions;
|
|
142
144
|
/**
|
|
143
145
|
* The model, effort and permissions the other process runs the thread with,
|
|
144
146
|
* from its rollout file: a thread that can only be read has no
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { rolloutAttention } from "./attention.js";
|
|
1
2
|
import { closeSync, fstatSync, openSync, readSync, statSync } from "node:fs";
|
|
2
3
|
import { codexPreview } from "./computer-preview.js";
|
|
3
|
-
import { ABANDON, RpcError, sessionGoalSchema } from "@linkshell/wire";
|
|
4
|
+
import { ABANDON, RpcError, questionReplies, updateAsyncQuestions, sessionGoalSchema } from "@linkshell/wire";
|
|
4
5
|
import { parseCodexLoginStatus, runStatusCommand } from "../auth.js";
|
|
5
6
|
import { CodexAppServer, CodexSharedServer, detectCodex, sharedServerSocket } from "./app-server.js";
|
|
6
7
|
import { APPROVAL_METHODS, QUESTION_METHODS, mapApprovalRequest, mapQuestionRequest, mapNotification, threadStateOf, threadToDiscovered, spawnedThreads, subagentHistory, threadToHistory, toCodexInput, toolStart, turnUnderWay, } from "./mapper.js";
|
|
@@ -215,12 +216,23 @@ export class CodexDriver {
|
|
|
215
216
|
await this.server?.stop();
|
|
216
217
|
this.server = undefined;
|
|
217
218
|
}
|
|
219
|
+
attention = new Map();
|
|
218
220
|
async listSessions(limit) {
|
|
219
221
|
const result = await this.rpc("thread/list", { limit, archived: false });
|
|
220
222
|
return result.data.map((thread) => {
|
|
221
223
|
const discovered = threadToDiscovered(thread);
|
|
222
224
|
// This host's app-server only knows the state of the threads loaded in it.
|
|
223
225
|
const state = this.stateElsewhere(thread.id);
|
|
226
|
+
const stamp = thread.path ? fileStamp(thread.path) : undefined;
|
|
227
|
+
let attention = this.attention.get(thread.id);
|
|
228
|
+
if (thread.path && stamp && attention?.stamp !== stamp) {
|
|
229
|
+
attention = { stamp, value: rolloutAttention(thread.path) };
|
|
230
|
+
this.attention.set(thread.id, attention);
|
|
231
|
+
}
|
|
232
|
+
// Live notifications win over the file, which can lag while the agent writes.
|
|
233
|
+
if (!this.attached.has(thread.id) && !this.observed.has(thread.id) && attention?.value) {
|
|
234
|
+
return { ...discovered, state: attention.value.running ? "running" : "idle", asyncQuestions: attention.value.questions };
|
|
235
|
+
}
|
|
224
236
|
return state ? { ...discovered, state } : discovered;
|
|
225
237
|
});
|
|
226
238
|
}
|
|
@@ -391,6 +403,7 @@ export class CodexDriver {
|
|
|
391
403
|
if (active)
|
|
392
404
|
this.host?.update(this.id, threadId, { sessionUpdate: "ls_turn", state: "started", turnId: active.id });
|
|
393
405
|
this.host?.update(this.id, threadId, { sessionUpdate: "ls_status", state: threadStateOf(thread.status) });
|
|
406
|
+
this.announceQuestions(threadId, thread, true);
|
|
394
407
|
const read = new Set((thread.turns ?? []).flatMap((turn) => turn.items.map((item) => item.id)));
|
|
395
408
|
for (const item of underWay) {
|
|
396
409
|
// A command still running: its card. (Its output so far was missed, so the whole of it comes when it finishes.)
|
|
@@ -435,6 +448,7 @@ export class CodexDriver {
|
|
|
435
448
|
this.cwds.set(threadId, thread.cwd);
|
|
436
449
|
this.host?.update(this.id, threadId, { sessionUpdate: "ls_status", state: running ? "running" : "idle" });
|
|
437
450
|
this.reportHeld(threadId, true);
|
|
451
|
+
this.announceQuestions(threadId, thread, true);
|
|
438
452
|
this.readHeldSettings(threadId, thread.path ?? undefined);
|
|
439
453
|
void this.announceCommands(threadId);
|
|
440
454
|
void this.announceGoal(threadId);
|
|
@@ -478,6 +492,7 @@ export class CodexDriver {
|
|
|
478
492
|
watch.seen.add(item.itemId);
|
|
479
493
|
this.report(threadId, item);
|
|
480
494
|
}
|
|
495
|
+
this.announceQuestions(threadId, thread);
|
|
481
496
|
const last = thread.turns?.at(-1);
|
|
482
497
|
const running = turnUnderWay(last);
|
|
483
498
|
watch.turnId = running ? last?.id : undefined;
|
|
@@ -498,6 +513,20 @@ export class CodexDriver {
|
|
|
498
513
|
watch.reading = false;
|
|
499
514
|
}
|
|
500
515
|
}
|
|
516
|
+
announceQuestions(threadId, thread, force = false) {
|
|
517
|
+
const turn = thread.turns?.at(-1);
|
|
518
|
+
let questions = [];
|
|
519
|
+
if (turnUnderWay(turn)) {
|
|
520
|
+
for (const item of threadToHistory({ ...thread, turns: turn ? [turn] : [] })) {
|
|
521
|
+
for (const update of item.updates)
|
|
522
|
+
questions = updateAsyncQuestions(questions, update);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
// Always restore on attach, even if this host already imported the history.
|
|
526
|
+
const changed = this.isNews(`questions:${threadId}`, questions);
|
|
527
|
+
if (force || changed)
|
|
528
|
+
this.host?.update(this.id, threadId, { sessionUpdate: "ls_async_questions", questions });
|
|
529
|
+
}
|
|
501
530
|
/**
|
|
502
531
|
* The model, effort and permissions the other process runs the thread with,
|
|
503
532
|
* from its rollout file: a thread that can only be read has no
|
|
@@ -1046,7 +1075,21 @@ export class CodexDriver {
|
|
|
1046
1075
|
async send(nativeId, input, clientMessageId) {
|
|
1047
1076
|
if (input.length === 0)
|
|
1048
1077
|
throw RpcError.app("invalid_params", "nothing to send");
|
|
1049
|
-
|
|
1078
|
+
const watch = this.observed.get(nativeId);
|
|
1079
|
+
if (watch?.running && questionReplies(textOf(input))) {
|
|
1080
|
+
try {
|
|
1081
|
+
if (!this.desktopBusPath)
|
|
1082
|
+
throw new Error("desktop bus unavailable");
|
|
1083
|
+
await steerThroughDesktop(this.desktopBusPath, nativeId, this.desktopMessage(nativeId, input, clientMessageId));
|
|
1084
|
+
}
|
|
1085
|
+
catch (error) {
|
|
1086
|
+
this.host?.log(`[codex] couldn't deliver a question answer to ${nativeId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
1087
|
+
throw this.refused(nativeId, "回答未确认送达 · 请重试或在电脑上回答", "回答未确认送达,问题仍保留");
|
|
1088
|
+
}
|
|
1089
|
+
void this.refresh(nativeId);
|
|
1090
|
+
return "steered";
|
|
1091
|
+
}
|
|
1092
|
+
if (watch)
|
|
1050
1093
|
return this.enqueue(nativeId, input, clientMessageId);
|
|
1051
1094
|
const activeTurnId = this.stateOf(nativeId).activeTurnId;
|
|
1052
1095
|
if (activeTurnId) {
|