shennian 0.3.2 → 0.3.4
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/publish-build-manifest.json +65 -45
- package/dist/src/agents/adapter.d.ts +1 -1
- package/dist/src/agents/claude.d.ts +2 -2
- package/dist/src/agents/claude.js +4 -4
- package/dist/src/agents/codex.d.ts +2 -1
- package/dist/src/agents/codex.js +6 -6
- package/dist/src/agents/cursor.d.ts +2 -2
- package/dist/src/agents/cursor.js +1 -1
- package/dist/src/agents/custom.d.ts +2 -2
- package/dist/src/agents/custom.js +4 -4
- package/dist/src/agents/gemini.d.ts +2 -2
- package/dist/src/agents/gemini.js +1 -1
- package/dist/src/agents/model-registry/service.js +1 -1
- package/dist/src/agents/openclaw.d.ts +2 -2
- package/dist/src/agents/openclaw.js +2 -2
- package/dist/src/agents/opencode.d.ts +2 -2
- package/dist/src/agents/opencode.js +1 -1
- package/dist/src/agents/platform-instructions.d.ts +3 -3
- package/dist/src/agents/platform-instructions.js +15 -7
- package/dist/src/agents/runtime-compatibility.d.ts +11 -0
- package/dist/src/agents/runtime-compatibility.js +1 -0
- package/dist/src/agents/workbuddy.d.ts +1 -1
- package/dist/src/agents/workbuddy.js +2 -2
- package/dist/src/index.js +2 -2
- package/dist/src/integrations/room-plugin-bundles.js +1 -1
- package/dist/src/integrations/room-plugin-shared.d.ts +1 -0
- package/dist/src/integrations/room-plugin-shared.js +2 -2
- package/dist/src/room/agent-tool.d.ts +62 -0
- package/dist/src/room/agent-tool.js +1 -0
- package/dist/src/room/managed-room-binding.d.ts +42 -0
- package/dist/src/room/managed-room-binding.js +1 -0
- package/dist/src/room/room-action-client.d.ts +2 -0
- package/dist/src/room/room-action-client.js +1 -1
- package/dist/src/room/room-action-ipc.js +1 -1
- package/dist/src/room/room-action-schema.js +1 -1
- package/dist/src/room/room-authorized-action-executor.js +1 -1
- package/dist/src/room/tool-schema.d.ts +4 -0
- package/dist/src/room/tool-schema.js +1 -1
- package/dist/src/room/tool-server.js +3 -3
- package/dist/src/session/handlers/chat.js +2 -2
- package/dist/src/session/handlers/room-managed.d.ts +4 -0
- package/dist/src/session/handlers/room-managed.js +1 -0
- package/dist/src/session/manager.d.ts +3 -1
- package/dist/src/session/manager.js +1 -1
- package/dist/src/session/queue.js +3 -3
- package/node_modules/@shennian/wire/dist/agent-workspace.d.ts +41 -0
- package/node_modules/@shennian/wire/dist/agent-workspace.d.ts.map +1 -0
- package/node_modules/@shennian/wire/dist/agent-workspace.js +3 -0
- package/node_modules/@shennian/wire/dist/agent-workspace.js.map +1 -0
- package/node_modules/@shennian/wire/dist/index.d.ts +1 -0
- package/node_modules/@shennian/wire/dist/index.d.ts.map +1 -1
- package/node_modules/@shennian/wire/dist/index.js +1 -0
- package/node_modules/@shennian/wire/dist/index.js.map +1 -1
- package/node_modules/@shennian/wire/dist/methods.d.ts +1 -1
- package/node_modules/@shennian/wire/dist/methods.d.ts.map +1 -1
- package/node_modules/@shennian/wire/dist/session.d.ts +21 -0
- package/node_modules/@shennian/wire/dist/session.d.ts.map +1 -1
- package/node_modules/@shennian/wire/dist/session.js +13 -2
- package/node_modules/@shennian/wire/dist/session.js.map +1 -1
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"jsMinified": true,
|
|
4
4
|
"minifier": "esbuild",
|
|
5
|
-
"fileCount":
|
|
5
|
+
"fileCount": 128,
|
|
6
6
|
"files": [
|
|
7
7
|
{
|
|
8
8
|
"file": "bin/shennian.js",
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
23
|
"file": "src/agents/claude.js",
|
|
24
|
-
"beforeBytes":
|
|
25
|
-
"afterBytes":
|
|
24
|
+
"beforeBytes": 11715,
|
|
25
|
+
"afterBytes": 6026
|
|
26
26
|
},
|
|
27
27
|
{
|
|
28
28
|
"file": "src/agents/codex-utils.js",
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
33
|
"file": "src/agents/codex.js",
|
|
34
|
-
"beforeBytes":
|
|
35
|
-
"afterBytes":
|
|
34
|
+
"beforeBytes": 39045,
|
|
35
|
+
"afterBytes": 19734
|
|
36
36
|
},
|
|
37
37
|
{
|
|
38
38
|
"file": "src/agents/command-spec.js",
|
|
@@ -46,13 +46,13 @@
|
|
|
46
46
|
},
|
|
47
47
|
{
|
|
48
48
|
"file": "src/agents/cursor.js",
|
|
49
|
-
"beforeBytes":
|
|
50
|
-
"afterBytes":
|
|
49
|
+
"beforeBytes": 9236,
|
|
50
|
+
"afterBytes": 4191
|
|
51
51
|
},
|
|
52
52
|
{
|
|
53
53
|
"file": "src/agents/custom.js",
|
|
54
|
-
"beforeBytes":
|
|
55
|
-
"afterBytes":
|
|
54
|
+
"beforeBytes": 10938,
|
|
55
|
+
"afterBytes": 5449
|
|
56
56
|
},
|
|
57
57
|
{
|
|
58
58
|
"file": "src/agents/detect.js",
|
|
@@ -66,8 +66,8 @@
|
|
|
66
66
|
},
|
|
67
67
|
{
|
|
68
68
|
"file": "src/agents/gemini.js",
|
|
69
|
-
"beforeBytes":
|
|
70
|
-
"afterBytes":
|
|
69
|
+
"beforeBytes": 6212,
|
|
70
|
+
"afterBytes": 3210
|
|
71
71
|
},
|
|
72
72
|
{
|
|
73
73
|
"file": "src/agents/manager.js",
|
|
@@ -96,8 +96,8 @@
|
|
|
96
96
|
},
|
|
97
97
|
{
|
|
98
98
|
"file": "src/agents/model-registry/service.js",
|
|
99
|
-
"beforeBytes":
|
|
100
|
-
"afterBytes":
|
|
99
|
+
"beforeBytes": 2880,
|
|
100
|
+
"afterBytes": 1209
|
|
101
101
|
},
|
|
102
102
|
{
|
|
103
103
|
"file": "src/agents/model-registry/types.js",
|
|
@@ -116,23 +116,28 @@
|
|
|
116
116
|
},
|
|
117
117
|
{
|
|
118
118
|
"file": "src/agents/openclaw.js",
|
|
119
|
-
"beforeBytes":
|
|
120
|
-
"afterBytes":
|
|
119
|
+
"beforeBytes": 11104,
|
|
120
|
+
"afterBytes": 4973
|
|
121
121
|
},
|
|
122
122
|
{
|
|
123
123
|
"file": "src/agents/opencode.js",
|
|
124
|
-
"beforeBytes":
|
|
125
|
-
"afterBytes":
|
|
124
|
+
"beforeBytes": 8314,
|
|
125
|
+
"afterBytes": 4377
|
|
126
126
|
},
|
|
127
127
|
{
|
|
128
128
|
"file": "src/agents/platform-instructions.js",
|
|
129
|
-
"beforeBytes":
|
|
130
|
-
"afterBytes":
|
|
129
|
+
"beforeBytes": 3550,
|
|
130
|
+
"afterBytes": 2047
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"file": "src/agents/runtime-compatibility.js",
|
|
134
|
+
"beforeBytes": 1705,
|
|
135
|
+
"afterBytes": 810
|
|
131
136
|
},
|
|
132
137
|
{
|
|
133
138
|
"file": "src/agents/workbuddy.js",
|
|
134
|
-
"beforeBytes":
|
|
135
|
-
"afterBytes":
|
|
139
|
+
"beforeBytes": 11092,
|
|
140
|
+
"afterBytes": 6048
|
|
136
141
|
},
|
|
137
142
|
{
|
|
138
143
|
"file": "src/commands/agent.js",
|
|
@@ -261,8 +266,8 @@
|
|
|
261
266
|
},
|
|
262
267
|
{
|
|
263
268
|
"file": "src/index.js",
|
|
264
|
-
"beforeBytes":
|
|
265
|
-
"afterBytes":
|
|
269
|
+
"beforeBytes": 25091,
|
|
270
|
+
"afterBytes": 13039
|
|
266
271
|
},
|
|
267
272
|
{
|
|
268
273
|
"file": "src/integrations/claude-room-plugin-lifecycle.js",
|
|
@@ -276,8 +281,8 @@
|
|
|
276
281
|
},
|
|
277
282
|
{
|
|
278
283
|
"file": "src/integrations/room-plugin-bundles.js",
|
|
279
|
-
"beforeBytes":
|
|
280
|
-
"afterBytes":
|
|
284
|
+
"beforeBytes": 5035,
|
|
285
|
+
"afterBytes": 2787
|
|
281
286
|
},
|
|
282
287
|
{
|
|
283
288
|
"file": "src/integrations/room-plugin-lifecycle-common.js",
|
|
@@ -286,8 +291,8 @@
|
|
|
286
291
|
},
|
|
287
292
|
{
|
|
288
293
|
"file": "src/integrations/room-plugin-shared.js",
|
|
289
|
-
"beforeBytes":
|
|
290
|
-
"afterBytes":
|
|
294
|
+
"beforeBytes": 8353,
|
|
295
|
+
"afterBytes": 5533
|
|
291
296
|
},
|
|
292
297
|
{
|
|
293
298
|
"file": "src/integrations/room-session-hook.js",
|
|
@@ -399,6 +404,11 @@
|
|
|
399
404
|
"beforeBytes": 6932,
|
|
400
405
|
"afterBytes": 3325
|
|
401
406
|
},
|
|
407
|
+
{
|
|
408
|
+
"file": "src/room/agent-tool.js",
|
|
409
|
+
"beforeBytes": 4977,
|
|
410
|
+
"afterBytes": 2981
|
|
411
|
+
},
|
|
402
412
|
{
|
|
403
413
|
"file": "src/room/attachment-cache.js",
|
|
404
414
|
"beforeBytes": 12422,
|
|
@@ -454,6 +464,11 @@
|
|
|
454
464
|
"beforeBytes": 17535,
|
|
455
465
|
"afterBytes": 9157
|
|
456
466
|
},
|
|
467
|
+
{
|
|
468
|
+
"file": "src/room/managed-room-binding.js",
|
|
469
|
+
"beforeBytes": 2323,
|
|
470
|
+
"afterBytes": 1329
|
|
471
|
+
},
|
|
457
472
|
{
|
|
458
473
|
"file": "src/room/managed-room-session.js",
|
|
459
474
|
"beforeBytes": 17103,
|
|
@@ -476,23 +491,23 @@
|
|
|
476
491
|
},
|
|
477
492
|
{
|
|
478
493
|
"file": "src/room/room-action-client.js",
|
|
479
|
-
"beforeBytes":
|
|
480
|
-
"afterBytes":
|
|
494
|
+
"beforeBytes": 20923,
|
|
495
|
+
"afterBytes": 10541
|
|
481
496
|
},
|
|
482
497
|
{
|
|
483
498
|
"file": "src/room/room-action-ipc.js",
|
|
484
|
-
"beforeBytes":
|
|
485
|
-
"afterBytes":
|
|
499
|
+
"beforeBytes": 15434,
|
|
500
|
+
"afterBytes": 6907
|
|
486
501
|
},
|
|
487
502
|
{
|
|
488
503
|
"file": "src/room/room-action-schema.js",
|
|
489
|
-
"beforeBytes":
|
|
490
|
-
"afterBytes":
|
|
504
|
+
"beforeBytes": 6307,
|
|
505
|
+
"afterBytes": 3087
|
|
491
506
|
},
|
|
492
507
|
{
|
|
493
508
|
"file": "src/room/room-authorized-action-executor.js",
|
|
494
|
-
"beforeBytes":
|
|
495
|
-
"afterBytes":
|
|
509
|
+
"beforeBytes": 6641,
|
|
510
|
+
"afterBytes": 3594
|
|
496
511
|
},
|
|
497
512
|
{
|
|
498
513
|
"file": "src/room/room-binding-client.js",
|
|
@@ -516,13 +531,13 @@
|
|
|
516
531
|
},
|
|
517
532
|
{
|
|
518
533
|
"file": "src/room/tool-schema.js",
|
|
519
|
-
"beforeBytes":
|
|
520
|
-
"afterBytes":
|
|
534
|
+
"beforeBytes": 4903,
|
|
535
|
+
"afterBytes": 2973
|
|
521
536
|
},
|
|
522
537
|
{
|
|
523
538
|
"file": "src/room/tool-server.js",
|
|
524
|
-
"beforeBytes":
|
|
525
|
-
"afterBytes":
|
|
539
|
+
"beforeBytes": 4995,
|
|
540
|
+
"afterBytes": 2782
|
|
526
541
|
},
|
|
527
542
|
{
|
|
528
543
|
"file": "src/session/archive-zip.js",
|
|
@@ -546,8 +561,8 @@
|
|
|
546
561
|
},
|
|
547
562
|
{
|
|
548
563
|
"file": "src/session/handlers/chat.js",
|
|
549
|
-
"beforeBytes":
|
|
550
|
-
"afterBytes":
|
|
564
|
+
"beforeBytes": 29785,
|
|
565
|
+
"afterBytes": 13067
|
|
551
566
|
},
|
|
552
567
|
{
|
|
553
568
|
"file": "src/session/handlers/control.js",
|
|
@@ -559,6 +574,11 @@
|
|
|
559
574
|
"beforeBytes": 29785,
|
|
560
575
|
"afterBytes": 13579
|
|
561
576
|
},
|
|
577
|
+
{
|
|
578
|
+
"file": "src/session/handlers/room-managed.js",
|
|
579
|
+
"beforeBytes": 1595,
|
|
580
|
+
"afterBytes": 965
|
|
581
|
+
},
|
|
562
582
|
{
|
|
563
583
|
"file": "src/session/handlers/session-refresh.js",
|
|
564
584
|
"beforeBytes": 963,
|
|
@@ -576,8 +596,8 @@
|
|
|
576
596
|
},
|
|
577
597
|
{
|
|
578
598
|
"file": "src/session/manager.js",
|
|
579
|
-
"beforeBytes":
|
|
580
|
-
"afterBytes":
|
|
599
|
+
"beforeBytes": 15890,
|
|
600
|
+
"afterBytes": 8153
|
|
581
601
|
},
|
|
582
602
|
{
|
|
583
603
|
"file": "src/session/projection.js",
|
|
@@ -586,8 +606,8 @@
|
|
|
586
606
|
},
|
|
587
607
|
{
|
|
588
608
|
"file": "src/session/queue.js",
|
|
589
|
-
"beforeBytes":
|
|
590
|
-
"afterBytes":
|
|
609
|
+
"beforeBytes": 14539,
|
|
610
|
+
"afterBytes": 6841
|
|
591
611
|
},
|
|
592
612
|
{
|
|
593
613
|
"file": "src/session/remote-attachments.js",
|
|
@@ -44,7 +44,7 @@ export declare abstract class AgentAdapter extends EventEmitter<AgentAdapterEven
|
|
|
44
44
|
}>;
|
|
45
45
|
setTitle?(agentSessionId: string, title: string, workDir?: string): Promise<void>;
|
|
46
46
|
abstract start(sessionId: string, workDir: string, agentSessionId?: string | null): Promise<void>;
|
|
47
|
-
abstract send(text: string, modelId?: string, reasoningEffort?: string, attachments?: ChatAttachmentMeta[]): Promise<void>;
|
|
47
|
+
abstract send(text: string, modelId?: string, reasoningEffort?: string, attachments?: ChatAttachmentMeta[], systemPrompt?: string | null): Promise<void>;
|
|
48
48
|
abstract resume(agentSessionId: string): Promise<void>;
|
|
49
49
|
abstract stop(): Promise<void>;
|
|
50
50
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AgentAdapter } from './adapter.js';
|
|
2
|
-
import type { ExternalChannelSessionStatus } from '@shennian/wire';
|
|
2
|
+
import type { ChatAttachmentMeta, ExternalChannelSessionStatus } from '@shennian/wire';
|
|
3
3
|
export declare function normalizeClaudeModelId(modelId?: string | null): string;
|
|
4
4
|
export declare function normalizeClaudeReasoningEffort(reasoningEffort?: string | null): string | undefined;
|
|
5
5
|
export declare function resetClaudeCapabilityCacheForTests(): void;
|
|
@@ -28,7 +28,7 @@ export declare class ClaudeAdapter extends AgentAdapter {
|
|
|
28
28
|
env?: NodeJS.ProcessEnv;
|
|
29
29
|
}): void;
|
|
30
30
|
start(sessionId: string, workDir: string, agentSessionId?: string | null): Promise<void>;
|
|
31
|
-
send(text: string, modelId?: string, reasoningEffort?: string): Promise<void>;
|
|
31
|
+
send(text: string, modelId?: string, reasoningEffort?: string, _attachments?: ChatAttachmentMeta[], agentSystemPrompt?: string | null): Promise<void>;
|
|
32
32
|
resume(agentSessionId: string): Promise<void>;
|
|
33
33
|
stop(): Promise<void>;
|
|
34
34
|
private spawnAndParse;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{createInterface as f}from"node:readline";import{randomUUID as
|
|
2
|
-
${e.stderr??""}`,
|
|
3
|
-
`)){const l
|
|
4
|
-
`})}}),s.on("close",n=>{this.process===s&&(this.process=null,this.handleProcessClose(n,
|
|
1
|
+
import{createInterface as f}from"node:readline";import{randomUUID as d}from"node:crypto";import{AgentAdapter as g,registerAgent as I}from"./adapter.js";import{resolveBuiltinCommand as p,spawnAgentCommand as S,spawnResolvedCommandSync as E}from"./command-spec.js";import{buildAgentProcessEnv as m}from"../agent-env.js";import{buildPlatformInstructions as c}from"./platform-instructions.js";function y(i){return i?.trim()||"default"}const x=new Set(["low","medium","high","xhigh","max"]),a=new Map;function w(i){const t=i?.trim();if(t){if(x.has(t))return t;throw new Error(`Unsupported Claude reasoning effort "${t}". Supported values: low, medium, high, xhigh, max.`)}}function R(){a.clear()}function C(){const i=p("claude");if(!i)return!1;const t=`${i.kind}:${i.path}:${i.command}:${i.args.join("\0")}`;if(a.has(t))return a.get(t)??!1;try{const e=E(i,["--help"],{encoding:"utf-8",stdio:["ignore","pipe","pipe"],timeout:3e3,env:m()}),s=`${e.stdout??""}
|
|
2
|
+
${e.stderr??""}`,o=/(?:^|\s)--effort(?:\s|,|<)/.test(s);return a.set(t,o),o}catch{return a.set(t,!1),!1}}class k extends g{options;type="claude";process=null;agentSessionId=null;sessionId=null;workDir=null;seq=0;runId="";hasEmittedText=!1;terminalState="open";constructor(t={}){super(),this.options=t}externalChannel=null;shennianSessionId=null;extraEnv={};configure(t){this.shennianSessionId=t.sessionId??null,this.externalChannel=t.externalChannel??null,this.extraEnv=t.env??{}}async start(t,e,s){this.sessionId=t,this.workDir=e,this.seq=0,s&&(this.agentSessionId=s)}async send(t,e,s,o,u){await this.killProcess(),this.runId=d(),this.resetRunState();const n=["-p",t,"--output-format","stream-json","--verbose"],r=this.options.systemPrompt??c(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,u);r&&n.push("--append-system-prompt",r),this.options.hidden&&n.push("--name","Shennian Manager Substrate"),process.getuid?.()!==0&&n.push("--dangerously-skip-permissions"),n.push("--model",y(e));const l=w(s);l&&C()&&n.push("--effort",l),this.agentSessionId&&n.push("--resume",this.agentSessionId),this.spawnAndParse(n)}async resume(t){await this.killProcess(),this.agentSessionId=t,this.runId=d(),this.resetRunState();const e=["--resume",t,"--output-format","stream-json","--verbose"],s=this.options.systemPrompt??c(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0);s&&e.push("--append-system-prompt",s),this.options.hidden&&e.push("--name","Shennian Manager Substrate"),process.getuid?.()!==0&&e.push("--dangerously-skip-permissions"),this.spawnAndParse(e)}async stop(){await this.killProcess()}spawnAndParse(t){const e=p("claude");if(!e){this.emit("error",new Error('Command "claude" not found. Is Claude Code CLI installed?'));return}const s=S(e,t,{cwd:this.workDir??void 0,stdio:["ignore","pipe","pipe"],env:m(this.extraEnv)});this.process=s,f({input:s.stdout}).on("line",n=>{if(n.trim())try{const r=JSON.parse(n);this.handleStreamEvent(r)}catch{}});let u="";s.stderr?.on("data",n=>{const r=n.toString();if(u+=r,this.terminalState==="open")for(const l of r.split(`
|
|
3
|
+
`)){const h=l.trim();h&&this.emitEvent({state:"delta",text:h+`
|
|
4
|
+
`})}}),s.on("close",n=>{this.process===s&&(this.process=null,this.handleProcessClose(n,u))}),s.on("error",n=>{this.process===s&&(this.process=null,n.code==="ENOENT"?this.emit("error",new Error('Command "claude" not found. Is Claude Code CLI installed?')):this.emit("error",n))})}handleStreamEvent(t){if(t.type==="system"&&t.subtype==="init"&&t.session_id){this.agentSessionId=t.session_id,this.emitEvent({state:"start",agentSessionId:this.agentSessionId});return}if(t.type==="system"&&t.subtype==="api_retry"&&t.error==="authentication_failed"){this.emitErrorIfOpen({state:"error",message:'Claude authentication failed. Run "claude auth login" and retry.'});return}if(t.type==="assistant"){if(t.message?.content){for(const e of t.message.content)if(e.type==="text"&&e.text){const s=this.hasEmittedText?`
|
|
5
5
|
|
|
6
6
|
`:"";this.emitEvent({state:"delta",text:s+e.text}),this.hasEmittedText=!0}else e.type==="thinking"&&e.thinking?this.emitEvent({state:"delta",text:e.thinking,thinking:!0}):e.type==="tool_use"&&this.emitEvent({state:"tool-call",name:e.name,args:e.input});return}if(t.subtype==="text"&&t.text){const e=this.hasEmittedText?`
|
|
7
7
|
|
|
@@ -24,6 +24,7 @@ export declare class CodexAdapter extends AgentAdapter {
|
|
|
24
24
|
private namedThread;
|
|
25
25
|
private deltaItemIds;
|
|
26
26
|
private lastTransientStatus;
|
|
27
|
+
private agentSystemPrompt;
|
|
27
28
|
constructor(options?: {
|
|
28
29
|
modelInstructionsFile?: string;
|
|
29
30
|
hidden?: boolean;
|
|
@@ -37,7 +38,7 @@ export declare class CodexAdapter extends AgentAdapter {
|
|
|
37
38
|
env?: NodeJS.ProcessEnv;
|
|
38
39
|
}): void;
|
|
39
40
|
start(_sessionId: string, workDir: string, agentSessionId?: string | null): Promise<void>;
|
|
40
|
-
send(text: string, modelId?: string, reasoningEffort?: string, attachments?: ChatAttachmentMeta[]): Promise<void>;
|
|
41
|
+
send(text: string, modelId?: string, reasoningEffort?: string, attachments?: ChatAttachmentMeta[], agentSystemPrompt?: string | null): Promise<void>;
|
|
41
42
|
resume(agentSessionId: string): Promise<void>;
|
|
42
43
|
setTitle(agentSessionId: string, title: string, workDir?: string): Promise<void>;
|
|
43
44
|
stop(): Promise<void>;
|
package/dist/src/agents/codex.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import{spawnSync as x}from"node:child_process";import{createInterface as u}from"node:readline";import{randomUUID as I}from"node:crypto";import
|
|
2
|
-
`)}function G(a){return a.replace(/[[\]\\]/g,"\\$&")}class J extends
|
|
3
|
-
`,
|
|
4
|
-
(exit ${t.exitCode})`:""].join("").trim()});break}case"mcpToolCall":case"dynamicToolCall":{const s=typeof t.tool=="string"?t.tool:t.type;if(
|
|
1
|
+
import{spawnSync as x}from"node:child_process";import{createInterface as u}from"node:readline";import{randomUUID as I}from"node:crypto";import S from"node:path";import{AgentAdapter as T,registerAgent as k}from"./adapter.js";import{resolveBuiltinCommand as h,spawnAgentCommand as m}from"./command-spec.js";import{buildAgentProcessEnv as f}from"../agent-env.js";import{ensurePlatformInstructionsFile as w}from"./platform-instructions.js";import{CODEX_APP_SERVER_CLIENT_INFO as E,extractAppServerErrorMessage as C,formatCodexErrorMessage as A,formatTransientCodexStatus as _,isCodexCollabAgentItem as R,isCodexCollabAgentToolName as d,isCodexLegacyCollabAgentItem as P,isCodexUnsupportedEffortError as q,isMissingCodexRolloutError as O,isTransientCodexErrorMessage as $,looksLikeCodexInteractiveAuthPrompt as b,looksLikeFatalCodexStderr as F,makeThreadTitle as L,normalizeCodexModelId as g,normalizeCodexReasoningEffort as U,normalizeCodexStderr as v,normalizeTerminalText as M,safeStringify as y,stripGitDirectiveArtifacts as N}from"./codex-utils.js";import{isCodexUnsupportedEffortError as re,isMissingCodexRolloutError as ne,normalizeCodexModelId as ie,normalizeCodexReasoningEffort as ae}from"./codex-utils.js";function D(a,e){const t=e?.flatMap(r=>z(r)).filter(r=>!/^https?:\/\//i.test(r.path)).filter(r=>r.path);return{type:"text",text:W(a,e),text_elements:[],...t?.length?{local_images:t}:{}}}function z(a){if(a.kind==="image")return a.previewData?[{path:a.path,data:a.previewData,mimeType:a.mimeType}]:[{path:a.path}];if(a.mimeType.startsWith("video/")){const e=B(a.path);return e?[{path:e}]:[]}return[]}function B(a){if(!a||/^https?:\/\//i.test(a))return null;const e=S.extname(a),s=`${e?a.slice(0,-e.length):a}.preview.png`;return x("ffmpeg",["-y","-ss","0","-i",a,"-frames:v","1","-vf","scale=320:-1",s],{stdio:"ignore",timeout:15e3}).status===0?s:null}function W(a,e){const t=e?.filter(i=>i.kind!=="image").filter(i=>i.path&&!/^https?:\/\//i.test(i.path));if(!t?.length||t.every(i=>a.includes(i.path)))return a;const r=t.map((i,n)=>{const o=i.name||`attachment-${n+1}`,l=i.mimeType?` (${i.mimeType})`:"";return`[${G(o)}${l}](<${i.path}>)`});return[a,"",...r].join(`
|
|
2
|
+
`)}function G(a){return a.replace(/[[\]\\]/g,"\\$&")}class J extends T{options;type="codex";process=null;workDir=null;seq=0;runId="";pendingUsage;agentSessionId=null;hasEmittedText=!1;textTail="";terminalState="open";forceCloseTimer=null;stderrBuf="";rpcSeq=1;pendingRequests=new Map;appServerReady=null;appServerStartupError=null;activeTurnId=null;namedThread=!1;deltaItemIds=new Set;lastTransientStatus="";agentSystemPrompt="";constructor(e={}){super(),this.options=e}externalChannel=null;shennianSessionId=null;extraEnv={};configure(e){this.shennianSessionId=e.sessionId??null,this.externalChannel=e.externalChannel??null,this.extraEnv=e.env??{}}async start(e,t,s){this.workDir=t,this.seq=0,s&&(this.agentSessionId=s)}async send(e,t,s,r,i){this.activeTurnId&&(await this.interruptActiveTurn().catch(()=>{}),await this.killProcess());const n=g(t),o=U(s),l=i?.trim()??"";l!==this.agentSystemPrompt&&(this.agentSystemPrompt=l,this.process&&await this.killProcess()),this.runId=I(),this.seq=0,this.resetRunState(),await this.ensureAppServer(n);const p=this.agentSessionId;if(!p)throw new Error("codex app-server did not create a thread");this.emitEvent({state:"start",agentSessionId:p}),this.namedThread||(await this.sendRpc("thread/name/set",{threadId:p,name:L(e)}).catch(()=>{}),this.namedThread=!0);const c=await this.startTurnWithRecovery(p,e,n,o,r);this.activeTurnId=c.turn?.id??null}async resume(e){await this.killProcess(),this.agentSessionId=e,this.namedThread=!0,this.resetTextState()}async setTitle(e,t,s){const r=e.trim(),i=t.replace(/\s+/g," ").trim();!r||!i||(this.agentSessionId=r,s?.trim()&&(this.workDir=s),await this.ensureAppServer(),await this.sendRpc("thread/name/set",{threadId:r,name:i}),this.namedThread=!0)}async stop(){await this.interruptActiveTurn().catch(()=>{}),await this.killProcess()}async getStatus(){const e=this.agentSessionId,t=this.activeTurnId;if(!e||!this.process)return{active:!1,runId:t,runPhase:null,canStop:!1};let s=null;try{s=(await this.sendRpc("thread/read",{threadId:e,includeTurns:!1},5e3)).thread?.status??null}catch{}const r=s?.type==="active"||!!t;return{active:r,runId:t,runPhase:r?this.mapThreadStatusToRunPhase(s):null,canStop:!!(r&&t&&this.process)}}spawnCodex(e){const t=h("codex");if(!t){this.emit("error",new Error('Command "codex" not found. Is OpenAI Codex CLI installed?'));return}const s=m(t,e,{cwd:this.workDir??void 0,stdio:["ignore","pipe","pipe"],env:f(this.extraEnv)});this.process=s,u({input:s.stdout}).on("line",n=>{if(n.trim())try{const o=JSON.parse(n);this.handleStreamEvent(o)}catch{this.emitEvent({state:"delta",text:n})}});let i="";s.stderr?.on("data",n=>{i+=n.toString()}),s.on("close",n=>{this.process===s&&(this.process=null,this.clearForceCloseTimer(),this.handleProcessClose(n,i))}),s.on("error",n=>{this.process===s&&(this.process=null,n.code==="ENOENT"?this.emit("error",new Error('Command "codex" not found. Is OpenAI Codex CLI installed?')):this.emit("error",n))})}spawnAppServer(){const e=h("codex");if(!e){this.emit("error",new Error('Command "codex" not found. Is OpenAI Codex CLI installed?'));return}const t=["app-server","--listen","stdio://"],s=this.options.modelInstructionsFile??w(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,this.agentSystemPrompt);s&&t.push("-c",`model_instructions_file=${JSON.stringify(s)}`);const r=m(e,t,{cwd:this.workDir??void 0,stdio:["pipe","pipe","pipe"],env:f({NO_COLOR:"1",...this.extraEnv})});this.process=r,this.stderrBuf="",this.appServerStartupError=null,u({input:r.stdout}).on("line",n=>{if(!n.trim())return;let o;try{o=JSON.parse(n)}catch{this.handleAppServerNonJsonStdout(n);return}this.handleAppServerMessage(o)}),r.stderr?.on("data",n=>{this.stderrBuf+=n.toString()}),r.on("close",n=>{if(this.process!==r)return;const o=this.activeTurnId!=null;this.process=null,this.appServerReady=null,this.activeTurnId=null,this.rejectAllPending(new Error(v(this.stderrBuf)||`codex app-server exited with code ${n}`)),this.terminalState==="open"&&o&&this.handleProcessClose(n,this.stderrBuf)}),r.on("error",n=>{this.process===r&&(this.process=null,this.rejectAllPending(n),n.code==="ENOENT"?this.emit("error",new Error('Command "codex" not found. Is OpenAI Codex CLI installed?')):this.emit("error",n))})}async ensureAppServer(e){return this.appServerReady?this.appServerReady:(this.spawnAppServer(),this.appServerReady=this.initializeAppServer(e).catch(async t=>{throw this.appServerReady=null,await this.killProcess(),t}),this.appServerReady)}async initializeAppServer(e){const t=g(e);if(await this.sendRpc("initialize",{clientInfo:E,capabilities:{experimentalApi:!0}}),this.agentSessionId){const i=await this.sendRpc("thread/resume",{threadId:this.agentSessionId,cwd:this.workDir,approvalPolicy:"never",sandbox:"danger-full-access",persistExtendedHistory:!0,...this.options.hidden?{threadSource:"subagent"}:{},...t?{model:t}:{}});this.agentSessionId=i.thread?.id??this.agentSessionId,this.namedThread=!!i.thread?.name;return}const s=await this.sendRpc("thread/start",{cwd:this.workDir,approvalPolicy:"never",sandbox:"danger-full-access",serviceName:"Shennian",threadSource:this.options.hidden?"subagent":"user",experimentalRawEvents:!1,persistExtendedHistory:!0,...t?{model:t}:{}}),r=s.thread?.id;if(!r)throw new Error("codex app-server thread/start returned no thread id");this.agentSessionId=r,this.namedThread=!!s.thread?.name}async startTurnWithRecovery(e,t,s,r,i){try{return await this.startTurn(e,t,s,r,i)}catch(n){if(!O(n))throw n;return await this.killProcess(),await this.ensureAppServer(s),await this.startTurn(e,t,s,r,i)}}async startTurn(e,t,s,r,i){try{return await this.sendRpc("turn/start",{threadId:e,input:[D(t,i)],approvalPolicy:"never",sandboxPolicy:{type:"dangerFullAccess"},...s?{model:s}:{},...r?{effort:r}:{}})}catch(n){throw r&&q(n)?new Error(`Codex app-server does not accept reasoning effort "${r}" for this turn. Refresh models or upgrade Codex CLI, then retry.`,{cause:n}):n}}async interruptActiveTurn(){const e=this.agentSessionId,t=this.activeTurnId;!e||!t||!this.process||(await this.sendRpc("turn/interrupt",{threadId:e,turnId:t},5e3),this.activeTurnId=null)}sendRpc(e,t,s=6e4){if(this.appServerStartupError)return Promise.reject(this.appServerStartupError);const r=this.process;if(!r?.stdin)return Promise.reject(new Error("codex app-server is not running"));const i=this.rpcSeq++,n=JSON.stringify({id:i,method:e,params:t});return new Promise((o,l)=>{const p=setTimeout(()=>{this.pendingRequests.delete(i),l(new Error(`codex app-server request timed out: ${e}`))},s);this.pendingRequests.set(i,{resolve:o,reject:l,timer:p}),r.stdin.write(`${n}
|
|
3
|
+
`,c=>{c&&(clearTimeout(p),this.pendingRequests.delete(i),l(c))})})}handleAppServerMessage(e){if(e.id!=null){const s=this.pendingRequests.get(e.id);s&&(clearTimeout(s.timer),this.pendingRequests.delete(e.id),e.error?s.reject(new Error(e.error.message||`codex app-server error ${e.error.code??""}`.trim())):s.resolve(e.result))}if(!e.method)return;const t=e.params??{};switch(e.method){case"turn/started":{const s=typeof t.turn=="object"&&t.turn!==null?t.turn:null,r=typeof s?.id=="string"?s.id:null;r&&(this.activeTurnId=r);break}case"thread/status/changed":{const s=typeof t.threadId=="string"?t.threadId:"";if(s&&this.agentSessionId&&s!==this.agentSessionId)break;const r=typeof t.status=="object"&&t.status!==null?t.status:null;r?.type==="active"&&this.emitEvent({state:"heartbeat",runPhase:this.mapThreadStatusToRunPhase(r)});break}case"item/agentMessage/delta":{const s=typeof t.itemId=="string"?t.itemId:"";s&&this.deltaItemIds.add(s),typeof t.delta=="string"&&this.emitText(t.delta);break}case"item/completed":this.handleAppServerCompletedItem(t);break;case"thread/tokenUsage/updated":this.handleAppServerUsage(t);break;case"turn/completed":{const s=typeof t.turn=="object"&&t.turn!==null?t.turn:null,r=typeof s?.id=="string"?s.id:null;(!this.activeTurnId||r===this.activeTurnId)&&(this.activeTurnId=null,this.emitFinalIfOpen());break}case"error":{const s=C(t);if($(s)){this.emitTransientStatus(s);return}this.emitErrorIfOpen(s);break}}}mapThreadStatusToRunPhase(e){const t=e?.type==="active"&&Array.isArray(e.activeFlags)?e.activeFlags:[];return t.includes("waitingOnApproval")?"waiting_approval":t.includes("waitingOnUserInput")?"waiting_user_input":"thinking"}handleAppServerNonJsonStdout(e){const t=M(e);b(t)&&this.failAppServerStartup(new Error("Codex \u672A\u767B\u5F55\u3002\u8BF7\u5148\u5728\u8FD9\u53F0\u7535\u8111\u7684\u7EC8\u7AEF\u8FD0\u884C `codex`\uFF0C\u6309\u63D0\u793A\u5B8C\u6210 ChatGPT \u767B\u5F55\u6216\u914D\u7F6E API key\uFF0C\u7136\u540E\u518D\u56DE\u5230\u795E\u5FF5\u53D1\u9001\u6D88\u606F\u3002"))}failAppServerStartup(e){this.appServerStartupError||(this.appServerStartupError=e,this.rejectAllPending(e),this.process?.kill("SIGTERM"))}handleAppServerCompletedItem(e){const t=typeof e.item=="object"&&e.item!==null?e.item:null;if(!(!t||typeof t.type!="string")&&!R(t))switch(t.type){case"agentMessage":{const s=typeof t.id=="string"?t.id:"";if(s&&this.deltaItemIds.has(s))return;typeof t.text=="string"&&this.emitText(t.text,"block");break}case"commandExecution":{const s=typeof t.command=="string"?t.command:"",r=typeof t.aggregatedOutput=="string"?t.aggregatedOutput:"";s&&this.emitEvent({state:"tool-call",name:"command_execution",args:{command:s}}),this.emitEvent({state:"tool-result",name:"command_execution",result:[r,t.exitCode!=null?`
|
|
4
|
+
(exit ${t.exitCode})`:""].join("").trim()});break}case"mcpToolCall":case"dynamicToolCall":{const s=typeof t.tool=="string"?t.tool:t.type;if(d(s))return;const r=typeof t.arguments=="object"&&t.arguments!==null?t.arguments:{};this.emitEvent({state:"tool-call",name:s,args:r}),this.emitEvent({state:"tool-result",name:s,result:y(t.error??t.result??t.contentItems??"")});break}case"fileChange":{const r=(Array.isArray(t.changes)?t.changes:[]).map(i=>{if(typeof i!="object"||i===null)return"";const n=i,o=typeof n.path=="string"?n.path:typeof n.file=="string"?n.file:"",l=typeof n.kind=="string"?n.kind:typeof n.type=="string"?n.type:"change";return o?`${l}: ${o}`:""}).filter(Boolean).join(`
|
|
5
5
|
`);r&&this.emitText(r,"block");break}case"approvalRequest":case"approval_request":case"permissionRequest":case"permission_request":case"userInputRequired":case"user_input_required":{this.emitApprovalPending(t);break}}}handleAppServerUsage(e){const t=typeof e.tokenUsage=="object"&&e.tokenUsage!==null?e.tokenUsage:null,s=typeof t?.last=="object"&&t.last!==null?t.last:null,r=typeof t?.total=="object"&&t.total!==null?t.total:null,i=s??r;if(!i)return;const n=typeof i.inputTokens=="number"?i.inputTokens:void 0,o=typeof i.outputTokens=="number"?i.outputTokens:void 0;(n!=null||o!=null)&&(this.pendingUsage={inputTokens:n??0,outputTokens:o??0})}handleCodexItemLine(e){const t=e.item;if(t?.type&&!P(t))switch(t.type){case"agent_message":case"reasoning":{e.type==="item.completed"&&t.text&&this.emitText(t.text,"block");break}case"command_execution":{if(e.type==="item.started"&&t.command&&this.emitEvent({state:"tool-call",name:"command_execution",args:{command:t.command}}),e.type==="item.completed"){const s=[t.aggregated_output??"",t.exit_code!=null?`
|
|
6
|
-
(exit ${t.exit_code})`:""];this.emitEvent({state:"tool-result",name:"command_execution",result:s.join("").trim()||String(t.status??"")})}break}case"mcp_tool_call":{if(t.tool&&
|
|
6
|
+
(exit ${t.exit_code})`:""];this.emitEvent({state:"tool-result",name:"command_execution",result:s.join("").trim()||String(t.status??"")})}break}case"mcp_tool_call":{if(t.tool&&d(t.tool))return;if(e.type==="item.started"&&this.emitEvent({state:"tool-call",name:t.tool??"mcp_tool",args:{server:t.server,...t.arguments&&typeof t.arguments=="object"?t.arguments:{}}}),e.type==="item.completed"){const s=t.error&&typeof t.error=="object"?t.error.message:void 0;this.emitEvent({state:"tool-result",name:t.tool??"mcp_tool",result:s??y(t.result)})}break}case"file_change":{if(e.type==="item.completed"&&t.changes?.length){const s=t.changes.map(r=>`${r.kind}: ${r.path}`).join(`
|
|
7
7
|
`);this.emitText(s,"block")}break}case"web_search":{e.type==="item.completed"&&t.query&&this.emitText(`[web_search] ${t.query}`,"block");break}case"todo_list":{if(e.type==="item.completed"&&t.items?.length){const s=t.items.map(r=>`- [${r.completed?"x":" "}] ${r.text}`).join(`
|
|
8
|
-
`);this.emitText(s,"block")}break}case"approval_request":case"approvalRequest":case"permission_request":case"permissionRequest":case"user_input_required":case"userInputRequired":{(e.type==="item.started"||e.type==="item.completed")&&this.emitApprovalPending(t);break}case"error":{e.type==="item.completed"&&t.message&&this.emitEvent({state:"error",message:t.message});break}default:break}}handleStreamEvent(e){const t=e.type??e.event;switch(t?.startsWith("item.")&&this.handleCodexItemLine(e),t){case"turn.completed":{const r=e.usage;if(r){const i=r.input_tokens??r.prompt_tokens,n=r.output_tokens??r.completion_tokens;(i!=null||n!=null)&&(this.pendingUsage={inputTokens:i??0,outputTokens:n??0})}this.emitFinalIfOpen();return}case"turn.failed":{const r=typeof e.error=="object"&&e.error?.message?e.error.message:typeof e.error=="string"?e.error:"turn failed";this.emitErrorIfOpen(r);return}case"error":{const r=typeof e.message=="string"?e.message:"";if(r.includes("Reconnecting"))return;this.emitErrorIfOpen(r||(typeof e.error=="string"?e.error:"stream error"));return}case"thread.started":{const r=e.thread_id??e.session_id??e.id;typeof r=="string"&&r&&(this.agentSessionId=r,this.emitEvent({state:"start",agentSessionId:this.agentSessionId}));return}case"turn.started":return}if(t?.startsWith("item."))return;switch(e.type??e.event){case"message":case"text":case"content":{const r=e.content??e.text;r&&this.emitText(r);break}case"function_call":case"tool_call":{if(this.isApprovalLikeName(e.name)){this.emitApprovalPending(e);break}if(e.name&&
|
|
8
|
+
`);this.emitText(s,"block")}break}case"approval_request":case"approvalRequest":case"permission_request":case"permissionRequest":case"user_input_required":case"userInputRequired":{(e.type==="item.started"||e.type==="item.completed")&&this.emitApprovalPending(t);break}case"error":{e.type==="item.completed"&&t.message&&this.emitEvent({state:"error",message:t.message});break}default:break}}handleStreamEvent(e){const t=e.type??e.event;switch(t?.startsWith("item.")&&this.handleCodexItemLine(e),t){case"turn.completed":{const r=e.usage;if(r){const i=r.input_tokens??r.prompt_tokens,n=r.output_tokens??r.completion_tokens;(i!=null||n!=null)&&(this.pendingUsage={inputTokens:i??0,outputTokens:n??0})}this.emitFinalIfOpen();return}case"turn.failed":{const r=typeof e.error=="object"&&e.error?.message?e.error.message:typeof e.error=="string"?e.error:"turn failed";this.emitErrorIfOpen(r);return}case"error":{const r=typeof e.message=="string"?e.message:"";if(r.includes("Reconnecting"))return;this.emitErrorIfOpen(r||(typeof e.error=="string"?e.error:"stream error"));return}case"thread.started":{const r=e.thread_id??e.session_id??e.id;typeof r=="string"&&r&&(this.agentSessionId=r,this.emitEvent({state:"start",agentSessionId:this.agentSessionId}));return}case"turn.started":return}if(t?.startsWith("item."))return;switch(e.type??e.event){case"message":case"text":case"content":{const r=e.content??e.text;r&&this.emitText(r);break}case"function_call":case"tool_call":{if(this.isApprovalLikeName(e.name)){this.emitApprovalPending(e);break}if(e.name&&d(e.name))return;this.emitEvent({state:"tool-call",name:e.name,args:e.arguments??e.input});break}case"function_call_output":case"tool_result":{if(e.name&&d(e.name))return;this.emitEvent({state:"tool-result",name:e.name,result:e.output??e.result});break}case"approval_request":case"approvalRequest":case"permission_request":case"permissionRequest":case"user_input_required":case"userInputRequired":{this.emitApprovalPending(e);break}case"error":break;case"done":case"completed":{e.usage&&(this.pendingUsage={inputTokens:e.usage.prompt_tokens??e.usage.input_tokens??0,outputTokens:e.usage.completion_tokens??e.usage.output_tokens??0}),this.emitFinalIfOpen();break}}}emitEvent(e){if(this.terminalState!=="open"&&e.state!=="final"&&e.state!=="error"&&e.state!=="aborted")return;const t={...e,runId:this.runId,seq:this.seq++};this.emit("agentEvent",t)}isApprovalLikeName(e){return typeof e!="string"?!1:/approval|permission|confirm|user[_-]?input|request[_-]?user/i.test(e)}emitApprovalPending(e){const t=typeof e.command=="string"?e.command:"",s=typeof e.title=="string"&&e.title.trim()?e.title:"\u9700\u8981\u7528\u6237\u786E\u8BA4",r=typeof e.prompt=="string"?e.prompt:typeof e.reason=="string"?e.reason:typeof e.message=="string"?e.message:t?`Codex \u8BF7\u6C42\u6267\u884C\u547D\u4EE4\uFF1A${t}`:"Codex \u6B63\u5728\u7B49\u5F85\u7528\u6237\u786E\u8BA4\u540E\u7EE7\u7EED\u3002";this.emitEvent({state:"approval-pending",approval:{title:s,content:r,source:"codex",actionHint:"\u5F53\u524D\u795E\u5FF5\u6682\u4E0D\u652F\u6301\u8FDC\u7A0B\u786E\u8BA4\uFF0C\u8BF7\u56DE\u5230\u8FD0\u884C Codex \u7684\u7535\u8111/\u7EC8\u7AEF\u5B8C\u6210\u786E\u8BA4\u3002"}})}async killProcess(){const e=this.process;if(this.appServerReady=null,this.activeTurnId=null,!e){this.rejectAllPending(new Error("codex app-server stopped"));return}this.process=null,this.clearForceCloseTimer(),e.kill("SIGTERM"),await new Promise(t=>{e.on("close",t),setTimeout(()=>{e.kill("SIGKILL"),t()},3e3)}),this.rejectAllPending(new Error("codex app-server stopped"))}rejectAllPending(e){for(const[t,s]of this.pendingRequests.entries())clearTimeout(s.timer),s.reject(e),this.pendingRequests.delete(t)}handleProcessClose(e,t){const s=v(t);if(e!==0&&e!==null){const r=s||`codex exited with code ${e}`;this.emitErrorIfOpen(r)}else F(s)?this.emitErrorIfOpen(s):this.emitFinalIfOpen();this.pendingUsage=void 0}emitFinalIfOpen(){this.terminalState==="open"&&(this.terminalState="final",this.emitEvent({state:"final",usage:this.pendingUsage,agentSessionId:this.agentSessionId??void 0}))}emitErrorIfOpen(e){this.terminalState==="open"&&(this.terminalState="error",this.emitEvent({state:"error",message:A(e)}),this.scheduleProcessClose())}resetRunState(){this.pendingUsage=void 0,this.terminalState="open",this.deltaItemIds.clear(),this.lastTransientStatus="",this.clearForceCloseTimer(),this.resetTextState()}emitTransientStatus(e){const t=_(e);!t||t===this.lastTransientStatus||this.terminalState!=="open"||(this.lastTransientStatus=t,this.emitEvent({state:"delta",text:`${t}
|
|
9
9
|
`,thinking:!0}))}resetTextState(){this.hasEmittedText=!1,this.textTail=""}emitText(e,t="delta"){if(!e)return;let s=N(e);s&&(t==="block"&&this.hasEmittedText&&!s.startsWith(`
|
|
10
10
|
`)&&(this.textTail.endsWith(`
|
|
11
11
|
`)?s=`
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AgentAdapter } from './adapter.js';
|
|
2
|
-
import type { ExternalChannelSessionStatus } from '@shennian/wire';
|
|
2
|
+
import type { ChatAttachmentMeta, ExternalChannelSessionStatus } from '@shennian/wire';
|
|
3
3
|
export declare class CursorAdapter extends AgentAdapter {
|
|
4
4
|
readonly type: "cursor";
|
|
5
5
|
private process;
|
|
@@ -17,7 +17,7 @@ export declare class CursorAdapter extends AgentAdapter {
|
|
|
17
17
|
env?: NodeJS.ProcessEnv;
|
|
18
18
|
}): void;
|
|
19
19
|
start(_sessionId: string, workDir: string, agentSessionId?: string | null): Promise<void>;
|
|
20
|
-
send(text: string, modelId?: string): Promise<void>;
|
|
20
|
+
send(text: string, modelId?: string, _reasoningEffort?: string, _attachments?: ChatAttachmentMeta[], agentSystemPrompt?: string | null): Promise<void>;
|
|
21
21
|
resume(agentSessionId: string): Promise<void>;
|
|
22
22
|
stop(): Promise<void>;
|
|
23
23
|
private spawnAndParse;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createInterface as l}from"node:readline";import{randomUUID as
|
|
1
|
+
import{createInterface as l}from"node:readline";import{randomUUID as a}from"node:crypto";import{AgentAdapter as h,registerAgent as u}from"./adapter.js";import{resolveBuiltinCommand as d,spawnResolvedCommand as c}from"./command-spec.js";import{buildAgentProcessEnv as m}from"../agent-env.js";import{buildInlineChannelPreamble as p}from"./platform-instructions.js";class f extends h{type="cursor";process=null;chatId=null;workDir=null;seq=0;runId="";emittedText="";externalChannel=null;shennianSessionId=null;extraEnv={};configure(t){this.shennianSessionId=t.sessionId??null,this.externalChannel=t.externalChannel??null,this.extraEnv=t.env??{}}async start(t,s,e){this.workDir=s,this.seq=0,e&&(this.chatId=e)}async send(t,s,e,o,r){await this.killProcess(),this.runId=a(),this.resetRunState();const n=["-p",`${p(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,r)}${t}`,"--output-format","stream-json","--stream-partial-output","--trust"];s&&n.push("--model",s),this.chatId&&n.push("--continue"),this.spawnAndParse(n)}async resume(t){await this.killProcess(),this.chatId=t,this.runId=a(),this.resetRunState(),this.spawnAndParse(["--resume",t,"--output-format","stream-json","--stream-partial-output","--trust"])}async stop(){await this.killProcess()}spawnAndParse(t){const s=d("cursor");if(!s){this.emit("error",new Error('Cursor Agent CLI not found. Expected "agent" or "cursor agent".'));return}const e=c(s,t,{cwd:this.workDir??void 0,stdio:["ignore","pipe","pipe"],env:m(this.extraEnv)});this.process=e,l({input:e.stdout}).on("line",i=>{if(i.trim())try{const n=JSON.parse(i);this.handleStreamEvent(n)}catch{this.emitEvent({state:"delta",text:i})}});let r="";e.stderr?.on("data",i=>{r+=i.toString()}),e.on("close",i=>{if(this.process===e&&(this.process=null,i!==0&&i!==null)){const n=r.trim()||`cursor agent exited with code ${i}`;this.emitEvent({state:"error",message:n})}}),e.on("error",i=>{this.process===e&&(this.process=null,i.code==="ENOENT"?this.emit("error",new Error('Command "cursor" not found. Is Cursor CLI installed?')):this.emit("error",i))})}handleStreamEvent(t){switch(t.session_id&&!this.chatId&&(this.chatId=t.session_id),t.chat_id&&!this.chatId&&(this.chatId=t.chat_id),t.type??t.event){case"system":break;case"assistant":{if(t.message?.content){if(!this.isLiveAssistantDelta(t))break;for(const e of t.message.content)e.type==="text"&&e.text?this.emitTextDelta(e.text):e.type==="thinking"&&e.thinking?this.emitEvent({state:"delta",text:e.thinking,thinking:!0}):e.type==="tool_use"&&this.emitEvent({state:"tool-call",name:e.name,args:e.input});break}(t.delta??t.text)&&this.emitEvent({state:"delta",text:t.delta??t.text});break}case"user":break;case"result":{if(t.subtype==="success"||!t.is_error){this.emitFinalResultDelta(t.result);const e=t.usage;this.emitEvent({state:"final",agentSessionId:this.chatId??void 0,usage:e?{inputTokens:e.inputTokens??e.input_tokens??0,outputTokens:e.outputTokens??e.output_tokens??0}:void 0})}else this.emitEvent({state:"error",message:t.result??t.error??"unknown error"});break}case"error":{this.emitEvent({state:"error",message:t.error??"unknown error"});break}case"text":case"delta":case"content":{const e=t.delta??t.text;e&&this.emitEvent({state:"delta",text:e});break}case"done":{this.emitEvent({state:"final",agentSessionId:this.chatId??void 0});break}default:t.done?this.emitEvent({state:"final",agentSessionId:this.chatId??void 0}):(t.delta??t.text)&&this.emitEvent({state:"delta",text:t.delta??t.text})}}emitEvent(t){const s={...t,runId:this.runId,seq:this.seq++};this.emit("agentEvent",s)}async killProcess(){const t=this.process;t&&(this.process=null,t.kill("SIGTERM"),await new Promise(s=>{t.on("close",s),setTimeout(()=>{t.kill("SIGKILL"),s()},3e3)}))}resetRunState(){this.seq=0,this.emittedText=""}isLiveAssistantDelta(t){return t.timestamp_ms!=null&&!t.model_call_id}emitTextDelta(t){t&&(this.emittedText+=t,this.emitEvent({state:"delta",text:t}))}emitFinalResultDelta(t){if(!t)return;if(!this.emittedText){this.emitTextDelta(t);return}if(!t.startsWith(this.emittedText))return;const s=t.slice(this.emittedText.length);s&&this.emitTextDelta(s)}}u("cursor",()=>new f);export{f as CursorAdapter};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AgentAdapter } from './adapter.js';
|
|
2
|
-
import type { CustomAgentType, ExternalChannelSessionStatus } from '@shennian/wire';
|
|
2
|
+
import type { ChatAttachmentMeta, CustomAgentType, ExternalChannelSessionStatus } from '@shennian/wire';
|
|
3
3
|
import type { CustomAgentEntry } from '../config/index.js';
|
|
4
4
|
export declare class CustomAgentAdapter extends AgentAdapter {
|
|
5
5
|
readonly type: CustomAgentType;
|
|
@@ -25,7 +25,7 @@ export declare class CustomAgentAdapter extends AgentAdapter {
|
|
|
25
25
|
externalChannel?: ExternalChannelSessionStatus | null;
|
|
26
26
|
env?: NodeJS.ProcessEnv;
|
|
27
27
|
}): void;
|
|
28
|
-
send(text: string, modelId?: string): Promise<void>;
|
|
28
|
+
send(text: string, modelId?: string, _reasoningEffort?: string, _attachments?: ChatAttachmentMeta[], agentSystemPrompt?: string | null): Promise<void>;
|
|
29
29
|
resume(agentSessionId: string): Promise<void>;
|
|
30
30
|
stop(): Promise<void>;
|
|
31
31
|
private runSpawn;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{createInterface as d}from"node:readline";import{randomUUID as o}from"node:crypto";import{AgentAdapter as l,registerAgent as p}from"./adapter.js";import{spawnCommandString as c}from"./command-spec.js";import{buildAgentProcessEnv as h}from"../agent-env.js";import{buildInlineChannelPreamble as m}from"./platform-instructions.js";const u=3e3;class w extends l{type;command;mode;proactive;sessionId=null;agentSessionId=null;workDir=null;runId="";seq=0;externalChannel=null;shennianSessionId=null;extraEnv={};stdioProcess=null;spawnProcess=null;dispatchGuard=null;dispatchObservedEvent=!1;constructor(s,t){super(),this.type=`custom:${s}`,this.command=t.command,this.mode=t.caps.mode,this.proactive=t.caps.proactive??!1}async start(s,t,
|
|
2
|
-
`)}}async stop(){this.mode==="stdio"?await this.stopStdioProcess():await this.killSpawnProcess()}async runSpawn(s,t){await this.killSpawnProcess();const
|
|
3
|
-
`),await
|
|
4
|
-
`),await new Promise(
|
|
1
|
+
import{createInterface as d}from"node:readline";import{randomUUID as o}from"node:crypto";import{AgentAdapter as l,registerAgent as p}from"./adapter.js";import{spawnCommandString as c}from"./command-spec.js";import{buildAgentProcessEnv as h}from"../agent-env.js";import{buildInlineChannelPreamble as m}from"./platform-instructions.js";const u=3e3;class w extends l{type;command;mode;proactive;sessionId=null;agentSessionId=null;workDir=null;runId="";seq=0;externalChannel=null;shennianSessionId=null;extraEnv={};stdioProcess=null;spawnProcess=null;dispatchGuard=null;dispatchObservedEvent=!1;constructor(s,t){super(),this.type=`custom:${s}`,this.command=t.command,this.mode=t.caps.mode,this.proactive=t.caps.proactive??!1}async start(s,t,r){this.sessionId=s,this.workDir=t,this.seq=0,r&&(this.agentSessionId=r),this.mode==="stdio"&&await this.startStdioProcess()}configure(s){this.shennianSessionId=s.sessionId??null,this.externalChannel=s.externalChannel??null,this.extraEnv=s.env??{}}async send(s,t,r,i,e){this.runId=o(),this.seq=0;const n=`${m(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,e)}${s}`;this.mode==="stdio"?await this.sendStdio(n,t):await this.runSpawn(n,t)}async resume(s){if(this.mode==="stdio"){const t=JSON.stringify({method:"resume",id:o(),params:{sessionId:this.sessionId,agentSessionId:s}});this.stdioProcess?.stdin?.write(t+`
|
|
2
|
+
`)}}async stop(){this.mode==="stdio"?await this.stopStdioProcess():await this.killSpawnProcess()}async runSpawn(s,t){await this.killSpawnProcess();const r=this.startDispatchGuard();this.dispatchObservedEvent=!1;const i=["/run","--workdir",this.workDir??process.cwd()];this.sessionId&&i.push("--session",this.sessionId),this.agentSessionId&&i.push("--resume",this.agentSessionId),t&&i.push("--model",t);const e=c(this.command,i,{cwd:this.workDir??void 0,stdio:["pipe","pipe","pipe"],env:h(this.extraEnv)});this.spawnProcess=e,this.attachOutputHandlers(e,()=>{this.spawnProcess===e&&(this.spawnProcess=null)}),e.stdin?.once("error",n=>this.rejectDispatch(n)),e.stdin?.write(s),e.stdin?.end(),await r.promise}async killSpawnProcess(){const s=this.spawnProcess;s&&(this.spawnProcess=null,s.kill("SIGTERM"),await new Promise(t=>{s.on("close",t),setTimeout(()=>{s.kill("SIGKILL"),t()},3e3)}))}async startStdioProcess(){const s=c(this.command,["/start","--workdir",this.workDir??process.cwd()],{cwd:this.workDir??void 0,stdio:["pipe","pipe","pipe"],env:h(this.extraEnv)});this.stdioProcess=s,this.attachOutputHandlers(s,()=>{this.stdioProcess===s&&(this.stdioProcess=null,this.emit("error",new Error("Custom agent process exited unexpectedly")))})}async sendStdio(s,t){this.stdioProcess||await this.startStdioProcess();const r=this.startDispatchGuard();this.dispatchObservedEvent=!1;const i=JSON.stringify({method:"send",id:o(),params:{sessionId:this.sessionId,text:s,modelId:t}});this.stdioProcess?.stdin?.once("error",e=>this.rejectDispatch(e)),this.stdioProcess?.stdin?.write(i+`
|
|
3
|
+
`),await r.promise}async stopStdioProcess(){const s=this.stdioProcess;if(!s)return;const t=JSON.stringify({method:"stop",id:o()});s.stdin?.write(t+`
|
|
4
|
+
`),await new Promise(r=>{const i=setTimeout(()=>{s.kill("SIGTERM"),setTimeout(()=>{s.kill("SIGKILL"),r()},3e3)},5e3);s.on("close",()=>{clearTimeout(i),r()})}),this.stdioProcess=null}attachOutputHandlers(s,t){d({input:s.stdout}).on("line",e=>{if(e.trim())try{const n=JSON.parse(e);this.handleProtocolEvent(n)}catch{}});let i="";s.stderr?.on("data",e=>{i+=e.toString()}),s.on("close",e=>{if(t(),e!==0&&e!==null){const n=i.trim()||`Agent exited with code ${e}`;this.rejectDispatch(new Error(n)),this.emitEvent({state:"error",message:n})}else this.dispatchObservedEvent?this.acceptDispatch():this.rejectDispatch(new Error("Custom agent exited without protocol events"))}),s.on("error",e=>{t(),this.rejectDispatch(e),this.emit("error",e)})}handleProtocolEvent(s){const{state:t}=s;if(t)switch(this.dispatchObservedEvent=!0,t){case"delta":this.acceptDispatch(),this.emitEvent({state:"delta",text:s.text??"",thinking:s.thinking});break;case"final":this.acceptDispatch(),s.agentSessionId&&(this.agentSessionId=s.agentSessionId),this.emitEvent({state:"final",usage:s.usage,agentSessionId:this.agentSessionId??void 0});break;case"error":this.rejectDispatch(new Error(s.message??"unknown error")),this.emitEvent({state:"error",message:s.message??"unknown error"});break;case"tool-call":this.acceptDispatch(),this.emitEvent({state:"tool-call",name:s.name??"",args:s.args});break;case"tool-result":this.acceptDispatch(),this.emitEvent({state:"tool-result",name:s.name??"",result:s.result??""});break;case"notify":this.acceptDispatch(),this.emitEvent({state:"notify",text:s.text??"",title:s.title,source:s.source});break}}startDispatchGuard(){this.acceptDispatch();let s;const t=new Promise((r,i)=>{s={settled:!1,timer:setTimeout(()=>this.acceptDispatch(s),u),resolve:r,reject:i,promise:Promise.resolve()}});return s.promise=t,this.dispatchGuard=s,s}acceptDispatch(s=this.dispatchGuard){!s||s.settled||(s.settled=!0,clearTimeout(s.timer),this.dispatchGuard===s&&(this.dispatchGuard=null),s.resolve())}rejectDispatch(s,t=this.dispatchGuard){!t||t.settled||(t.settled=!0,clearTimeout(t.timer),this.dispatchGuard===t&&(this.dispatchGuard=null),t.reject(s))}emitEvent(s){const t={...s,runId:this.runId,seq:this.seq++};this.emit("agentEvent",t)}}function E(a,s){const t=`custom:${a}`;p(t,()=>new w(a,s))}export{w as CustomAgentAdapter,E as registerCustomAgent};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AgentAdapter } from './adapter.js';
|
|
2
|
-
import type { ExternalChannelSessionStatus } from '@shennian/wire';
|
|
2
|
+
import type { ChatAttachmentMeta, ExternalChannelSessionStatus } from '@shennian/wire';
|
|
3
3
|
export declare class GeminiAdapter extends AgentAdapter {
|
|
4
4
|
readonly type: "gemini";
|
|
5
5
|
private process;
|
|
@@ -16,7 +16,7 @@ export declare class GeminiAdapter extends AgentAdapter {
|
|
|
16
16
|
env?: NodeJS.ProcessEnv;
|
|
17
17
|
}): void;
|
|
18
18
|
start(_sessionId: string, workDir: string, agentSessionId?: string | null): Promise<void>;
|
|
19
|
-
send(text: string, modelId?: string): Promise<void>;
|
|
19
|
+
send(text: string, modelId?: string, _reasoningEffort?: string, _attachments?: ChatAttachmentMeta[], agentSystemPrompt?: string | null): Promise<void>;
|
|
20
20
|
resume(agentSessionId: string): Promise<void>;
|
|
21
21
|
stop(): Promise<void>;
|
|
22
22
|
private spawnAndParse;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createInterface as
|
|
1
|
+
import{createInterface as l}from"node:readline";import{randomUUID as u}from"node:crypto";import{AgentAdapter as d,registerAgent as h}from"./adapter.js";import{resolveBuiltinCommand as c,spawnResolvedCommand as p}from"./command-spec.js";import{buildAgentProcessEnv as f}from"../agent-env.js";import{buildInlineChannelPreamble as g}from"./platform-instructions.js";function r(t){return typeof t=="number"&&Number.isFinite(t)?t:void 0}function k(t){if(!t)return;const e=r(t.input_tokens)??r(t.prompt_tokens)??r(t.inputTokens)??r(t.promptTokenCount),n=r(t.output_tokens)??r(t.completion_tokens)??r(t.outputTokens)??r(t.candidatesTokenCount)??r(t.responseTokenCount);if(!(e===void 0&&n===void 0))return{inputTokens:e??0,outputTokens:n??0}}class I extends d{type="gemini";process=null;agentSessionId=null;workDir=null;seq=0;runId="";externalChannel=null;shennianSessionId=null;extraEnv={};configure(e){this.shennianSessionId=e.sessionId??null,this.externalChannel=e.externalChannel??null,this.extraEnv=e.env??{}}async start(e,n,i){this.workDir=n,this.seq=0,i&&(this.agentSessionId=i)}async send(e,n,i,m,a){await this.killProcess(),this.runId=u(),this.seq=0;const o=["-p",`${g(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,a)}${e}`,"--output-format","stream-json"];n&&o.push("-m",n),this.agentSessionId&&o.push("--resume",this.agentSessionId),this.spawnAndParse(o)}async resume(e){await this.killProcess(),this.agentSessionId=e,this.runId=u(),this.seq=0,this.spawnAndParse(["--resume",e,"--output-format","stream-json"])}async stop(){await this.killProcess()}spawnAndParse(e){const n=c("gemini");if(!n){this.emit("error",new Error('Command "gemini" not found. Is Gemini CLI installed?'));return}const i=p(n,e,{cwd:this.workDir??void 0,stdio:["ignore","pipe","pipe"],env:f(this.extraEnv)});this.process=i,l({input:i.stdout}).on("line",s=>{if(s.trim())try{const o=JSON.parse(s);this.handleStreamEvent(o)}catch{this.emitEvent({state:"delta",text:s})}});let a="";i.stderr?.on("data",s=>{a+=s.toString()}),i.on("close",s=>{if(this.process===i&&(this.process=null,s!==0&&s!==null)){const o=a.trim()||`gemini exited with code ${s}`;this.emitEvent({state:"error",message:o})}}),i.on("error",s=>{this.process===i&&(this.process=null,s.code==="ENOENT"?this.emit("error",new Error('Command "gemini" not found. Is Gemini CLI installed?')):this.emit("error",s))})}handleStreamEvent(e){switch(e.type){case"init":{e.session_id&&(this.agentSessionId=e.session_id);break}case"message":{e.role==="assistant"&&e.content&&this.emitEvent({state:"delta",text:e.content});break}case"result":{if(e.status==="success")this.emitEvent({state:"final",agentSessionId:this.agentSessionId??void 0,usage:k(e.stats)});else if(e.status==="error"){const n=typeof e.error=="string"&&e.error||typeof e.message=="string"&&e.message||"gemini result error";this.emitEvent({state:"error",message:n})}break}default:break}}emitEvent(e){const n={...e,runId:this.runId,seq:this.seq++};this.emit("agentEvent",n)}async killProcess(){const e=this.process;e&&(this.process=null,e.kill("SIGTERM"),await new Promise(n=>{e.on("close",n),setTimeout(()=>{e.kill("SIGKILL"),n()},3e3)}))}}h("gemini",()=>new I);export{I as GeminiAdapter};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getAgentConfigSummary as
|
|
1
|
+
import{getAgentConfigSummary as u}from"../config-status.js";import{isCacheFresh as h,readCache as m,writeCache as p}from"./cache.js";import{discoverModelsForAgent as y}from"./discovery.js";import{getAgentRuntimeSummary as g}from"../runtime-compatibility.js";function v(o){const s=new Set,e=[];for(const t of o)!t.id||s.has(t.id)||(s.add(t.id),e.push(t));return e}function I(o){const s=m();return o.map(e=>{const t=u(e.type),r=g(e);return{type:e.type,models:s.agents[e.type]?.models??e.models??[],...t?{config:t}:{},...r?{runtime:r}:{}}})}async function q(o,s){const e=m();for(const t of o)delete e.agents[t.type];return p(e),A(o,s)}async function A(o,s){const e=m();let t=!1;const r=[];for(const n of o){const c=e.agents[n.type];let i;if(h(c,n.version))i=c.models;else{let f=null;try{f=v(await y(n,s)),i=f.length>0?f:c?.models??n.models??[]}catch{i=c?.models??n.models??[]}if(f&&f.length>0){const l={version:n.version,refreshedAt:Date.now(),models:i};JSON.stringify(c)!==JSON.stringify(l)&&(e.agents[n.type]=l,t=!0)}}const a=u(n.type),d=g(n);r.push({type:n.type,models:i,...a?{config:a}:{},...d?{runtime:d}:{}})}return t&&p(e),r}export{I as getCachedAgentInfos,q as refreshAgentInfos,A as resolveAgentInfos};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AgentAdapter } from './adapter.js';
|
|
2
|
-
import type { ExternalChannelSessionStatus } from '@shennian/wire';
|
|
2
|
+
import type { ChatAttachmentMeta, ExternalChannelSessionStatus } from '@shennian/wire';
|
|
3
3
|
export declare class OpenClawAdapter extends AgentAdapter {
|
|
4
4
|
readonly type: "openclaw";
|
|
5
5
|
private process;
|
|
@@ -19,7 +19,7 @@ export declare class OpenClawAdapter extends AgentAdapter {
|
|
|
19
19
|
env?: NodeJS.ProcessEnv;
|
|
20
20
|
}): void;
|
|
21
21
|
start(sessionId: string, workDir: string, agentSessionId?: string | null): Promise<void>;
|
|
22
|
-
send(text: string, modelId?: string): Promise<void>;
|
|
22
|
+
send(text: string, modelId?: string, _reasoningEffort?: string, _attachments?: ChatAttachmentMeta[], agentSystemPrompt?: string | null): Promise<void>;
|
|
23
23
|
resume(agentSessionId: string): Promise<void>;
|
|
24
24
|
stop(): Promise<void>;
|
|
25
25
|
private spawnAgent;
|