shennian 0.3.3 → 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 +22 -22
- 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/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/workbuddy.d.ts +1 -1
- package/dist/src/agents/workbuddy.js +2 -2
- package/dist/src/session/handlers/chat.js +2 -2
- package/dist/src/session/queue.js +3 -3
- package/node_modules/@shennian/wire/dist/session.d.ts +8 -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
|
@@ -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",
|
|
@@ -116,18 +116,18 @@
|
|
|
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
131
|
},
|
|
132
132
|
{
|
|
133
133
|
"file": "src/agents/runtime-compatibility.js",
|
|
@@ -136,8 +136,8 @@
|
|
|
136
136
|
},
|
|
137
137
|
{
|
|
138
138
|
"file": "src/agents/workbuddy.js",
|
|
139
|
-
"beforeBytes":
|
|
140
|
-
"afterBytes":
|
|
139
|
+
"beforeBytes": 11092,
|
|
140
|
+
"afterBytes": 6048
|
|
141
141
|
},
|
|
142
142
|
{
|
|
143
143
|
"file": "src/commands/agent.js",
|
|
@@ -561,8 +561,8 @@
|
|
|
561
561
|
},
|
|
562
562
|
{
|
|
563
563
|
"file": "src/session/handlers/chat.js",
|
|
564
|
-
"beforeBytes":
|
|
565
|
-
"afterBytes":
|
|
564
|
+
"beforeBytes": 29785,
|
|
565
|
+
"afterBytes": 13067
|
|
566
566
|
},
|
|
567
567
|
{
|
|
568
568
|
"file": "src/session/handlers/control.js",
|
|
@@ -606,8 +606,8 @@
|
|
|
606
606
|
},
|
|
607
607
|
{
|
|
608
608
|
"file": "src/session/queue.js",
|
|
609
|
-
"beforeBytes":
|
|
610
|
-
"afterBytes":
|
|
609
|
+
"beforeBytes": 14539,
|
|
610
|
+
"afterBytes": 6841
|
|
611
611
|
},
|
|
612
612
|
{
|
|
613
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,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;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{randomUUID as h}from"node:crypto";import{AgentAdapter as E}from"./adapter.js";import{resolveBuiltinCommand as g,spawnResolvedCommand as w}from"./command-spec.js";import{buildAgentProcessEnv as I}from"../agent-env.js";import{buildInlineChannelPreamble as x}from"./platform-instructions.js";function C(
|
|
2
|
-
`)}const e=t.response??t.message??t.text??t.output??t.content??t.result;if(typeof e=="string"&&e.trim())return e}return""}function k(
|
|
1
|
+
import{randomUUID as h}from"node:crypto";import{AgentAdapter as E}from"./adapter.js";import{resolveBuiltinCommand as g,spawnResolvedCommand as w}from"./command-spec.js";import{buildAgentProcessEnv as I}from"../agent-env.js";import{buildInlineChannelPreamble as x}from"./platform-instructions.js";function C(r){if(r==null)return"";if(typeof r=="string")return r;if(typeof r=="object"){const t=r;if(Array.isArray(t.payloads)){const a=[];for(const n of t.payloads)if(n&&typeof n=="object"){const s=n.text;typeof s=="string"&&a.push(s)}if(a.join("").trim())return a.join(`
|
|
2
|
+
`)}const e=t.response??t.message??t.text??t.output??t.content??t.result;if(typeof e=="string"&&e.trim())return e}return""}function k(r){if(r==null||typeof r!="object")return;const t=r,n=t.meta?.agentMeta?.sessionId??t.sessionId??t.session_id;return typeof n=="string"&&n?n:void 0}function v(r){if(r==null||typeof r!="object")return;const t=r,n=t.meta?.agentMeta?.usage??t.usage;if(!n||typeof n!="object")return;const s=n,u=s.input??s.inputTokens??s.input_tokens,o=s.output??s.outputTokens??s.output_tokens;if(!(typeof u!="number"&&typeof o!="number"))return{inputTokens:typeof u=="number"?u:0,outputTokens:typeof o=="number"?o:0}}function y(r){if(r==null||typeof r!="object")return;const t=r,e=t.error??t.err??t.errorMessage;if(typeof e=="string"&&e.trim())return e}class O extends E{type="openclaw";process=null;sessionId=null;agentSessionId=null;currentModelId=null;workDir=null;seq=0;runId="";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,a){this.sessionId=t,this.workDir=e,this.seq=0,a&&(this.agentSessionId=a)}async send(t,e,a,n,s){await this.killProcess(),this.runId=h(),this.seq=0;const u=this.agentSessionId??this.sessionId;if(!u){this.emitEvent({state:"error",message:"openclaw: session not started"});return}if(e&&e!==this.currentModelId){const i=await this.runAgentCommand(["--message",`/model ${e}`,"--session-id",u]);if(!i.ok){this.emitEvent({state:"error",message:i.error??"openclaw model switch failed"});return}this.currentModelId=e}const o=`${x(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,s)}${t}`;this.spawnAgent(["--message",o,"--session-id",u])}async resume(t){await this.killProcess(),this.agentSessionId=t,this.runId=h(),this.seq=0,this.spawnAgent(["--message","\u200B","--session-id",t])}async stop(){await this.killProcess()}spawnAgent(t){const e=g("openclaw");if(!e){this.emit("error",new Error('Command "openclaw" not found. Is OpenClaw CLI installed?'));return}const a=["agent","--local","--json",...t],n=w(e,a,{cwd:this.workDir??void 0,stdio:["ignore","pipe","pipe"],env:I(this.extraEnv)});this.process=n;let s="";n.stdout?.on("data",o=>{s+=o.toString()});let u="";n.stderr?.on("data",o=>{u+=o.toString()}),n.on("close",o=>{if(this.process!==n)return;if(this.process=null,o!==0&&o!==null){const f=u.trim()||`openclaw exited with code ${o}`;this.emitEvent({state:"error",message:f});return}const i=s.trim();if(!i){const f=u.trim()||"openclaw returned empty stdout";this.emitEvent({state:"error",message:f});return}let c;try{c=JSON.parse(i)}catch{this.emitEvent({state:"error",message:`openclaw stdout is not valid JSON: ${i.slice(0,200)}`});return}const l=c;if(l.ok===!1||l.success===!1){this.emitEvent({state:"error",message:y(c)??"openclaw request failed"});return}const p=k(c);p&&(this.agentSessionId=p);const m=C(c);m&&this.emitEvent({state:"delta",text:m});const S=v(c);this.emitEvent({state:"final",agentSessionId:this.agentSessionId??void 0,usage:S})}),n.on("error",o=>{this.process===n&&(this.process=null,o.code==="ENOENT"?this.emit("error",new Error('Command "openclaw" not found. Is OpenClaw CLI installed?')):this.emit("error",o))})}async runAgentCommand(t){return new Promise(e=>{const a=g("openclaw");if(!a){e({ok:!1,error:'Command "openclaw" not found. Is OpenClaw CLI installed?'});return}const n=["agent","--local","--json",...t],s=w(a,n,{cwd:this.workDir??void 0,stdio:["ignore","pipe","pipe"],env:I(this.extraEnv)});let u="",o="";s.stdout?.on("data",i=>{u+=i.toString()}),s.stderr?.on("data",i=>{o+=i.toString()}),s.on("close",i=>{if(i!==0&&i!==null){e({ok:!1,error:o.trim()||`openclaw exited with code ${i}`});return}const c=u.trim();if(!c){e({ok:!0});return}try{const l=JSON.parse(c);if(l.ok===!1||l.success===!1){e({ok:!1,error:y(l)??"openclaw request failed"});return}const d=k(l);d&&(this.agentSessionId=d),e({ok:!0,parsed:l})}catch{e({ok:!1,error:`openclaw stdout is not valid JSON: ${c.slice(0,200)}`})}}),s.on("error",i=>{e({ok:!1,error:i instanceof Error?i.message:String(i)})})})}emitEvent(t){const e={...t,runId:this.runId,seq:this.seq++};this.emit("agentEvent",e)}async killProcess(){const t=this.process;t&&(this.process=null,t.kill("SIGTERM"),await new Promise(e=>{t.on("close",e),setTimeout(()=>{t.kill("SIGKILL"),e()},3e3)}))}}export{O as OpenClawAdapter};
|
|
@@ -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 OpenCodeAdapter extends AgentAdapter {
|
|
4
4
|
readonly type: "opencode";
|
|
5
5
|
private process;
|
|
@@ -17,7 +17,7 @@ export declare class OpenCodeAdapter 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 resetRunState;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createInterface as h}from"node:readline";import{randomUUID as
|
|
1
|
+
import{createInterface as h}from"node:readline";import{randomUUID as a}from"node:crypto";import{AgentAdapter as d,registerAgent as f}from"./adapter.js";import{resolveBuiltinCommand as m,spawnAgentCommand as c}from"./command-spec.js";import{buildAgentProcessEnv as g}from"../agent-env.js";import{buildInlineChannelPreamble as I}from"./platform-instructions.js";function S(s){if(!s)return;const t=s.input,e=s.output;if(!(typeof t!="number"&&typeof e!="number"))return{inputTokens:typeof t=="number"?t:0,outputTokens:typeof e=="number"?e:0}}function l(s){if(s==null)return"";if(typeof s=="string")return s;try{return JSON.stringify(s)}catch{return String(s)}}function u(s){if(!s)return"opencode request failed";if(typeof s=="string")return s;if(typeof s!="object")return String(s);const t=s;return typeof t.message=="string"?t.message:typeof t.name=="string"?t.name:"data"in t?u(t.data):l(s)||"opencode request failed"}class E extends d{type="opencode";process=null;agentSessionId=null;workDir=null;seq=0;runId="";terminalState="closed";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,i){this.workDir=e,i&&(this.agentSessionId=i),this.resetRunState()}async send(t,e,i,p,o){await this.killProcess(),this.runId=a(),this.resetRunState();const n=["run","--format","json","--dangerously-skip-permissions","--dir",this.workDir??process.cwd()];this.agentSessionId&&n.push("--session",this.agentSessionId),e&&n.push("--model",e);const r=`${I(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,o)}${t}`;n.push(r),this.spawnAndParse(n)}async resume(t){await this.killProcess(),this.agentSessionId=t,this.runId=a(),this.resetRunState(),this.emitEvent({state:"start",agentSessionId:t}),this.emitFinalIfOpen({state:"final",agentSessionId:t})}async stop(){await this.killProcess()}resetRunState(){this.seq=0,this.terminalState="open"}spawnAndParse(t){const e=m("opencode");if(!e){this.emit("error",new Error('Command "opencode" not found. Install it with "npm i -g opencode-ai@latest".'));return}const i=c(e,t,{cwd:this.workDir??void 0,stdio:["ignore","pipe","pipe"],env:g({NO_COLOR:"1",...this.extraEnv})});this.process=i,h({input:i.stdout}).on("line",n=>{if(n.trim())try{const r=JSON.parse(n);this.handleStreamEvent(r)}catch{this.emitEvent({state:"delta",text:n})}});let o="";i.stderr?.on("data",n=>{o+=n.toString()}),i.on("close",n=>{if(this.process!==i||(this.process=null,this.terminalState!=="open"))return;const r=o.trim();if(n!==0&&n!==null){this.emitErrorIfOpen({state:"error",message:r||`opencode exited with code ${n}`});return}this.emitFinalIfOpen({state:"final",agentSessionId:this.agentSessionId??void 0})}),i.on("error",n=>{this.process===i&&(this.process=null,n.code==="ENOENT"?this.emit("error",new Error('Command "opencode" not found. Install it with "npm i -g opencode-ai@latest".')):this.emit("error",n))})}handleStreamEvent(t){t.sessionID&&t.sessionID!==this.agentSessionId&&(this.agentSessionId=t.sessionID,this.emitEvent({state:"start",agentSessionId:t.sessionID}));const e=t.part;if(t.type==="text"&&e?.text){this.emitEvent({state:"delta",text:e.text});return}if(t.type==="reasoning"&&e?.text){this.emitEvent({state:"delta",text:e.text,thinking:!0});return}if(t.type==="tool_use"&&e?.type==="tool"){e.state?.status==="completed"||e.state?.status==="error"?this.emitEvent({state:"tool-result",name:e.tool??"tool",result:e.state.status==="error"?e.state.error??"tool failed":l(e.state?.output)}):this.emitEvent({state:"tool-call",name:e.tool??"tool",args:e.state?.input??{}});return}if(t.type==="error"){this.emitErrorIfOpen({state:"error",message:u(t.error)});return}t.type==="step_finish"&&this.emitFinalIfOpen({state:"final",agentSessionId:this.agentSessionId??t.sessionID,usage:S(e?.tokens)})}emitEvent(t){const e={...t,runId:this.runId,seq:this.seq++};this.emit("agentEvent",e)}emitFinalIfOpen(t){this.terminalState==="open"&&(this.terminalState="closed",this.emitEvent(t))}emitErrorIfOpen(t){this.terminalState==="open"&&(this.terminalState="closed",this.emitEvent(t))}async killProcess(){const t=this.process;t&&(this.process=null,t.kill("SIGTERM"),await new Promise(e=>{t.on("close",e),setTimeout(()=>{t.kill("SIGKILL"),e()},3e3)}))}}f("opencode",()=>new E);export{E as OpenCodeAdapter};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ExternalChannelSessionStatus } from '@shennian/wire';
|
|
2
2
|
export declare const PLATFORM_OUTPUT_INSTRUCTIONS = "## Shennian Output Instructions\n\nWhen you mention a local file that the user may want to open in Shennian, format it as a Markdown link using the exact local path:\n\n- Use [filename.ext](</absolute/path/to/filename.ext>) for absolute Unix, macOS, or Windows paths.\n- Use [filename.ext](<relative/path/to/filename.ext>) for paths relative to the current working directory.\n- Do not use file:// URLs for local files.\n- Do not put user-openable file paths only inside code blocks.\n- Keep normal http:// and https:// links unchanged.";
|
|
3
|
-
export declare function buildPlatformInstructions(workDir: string, externalChannel?: ExternalChannelSessionStatus | null, sessionId?: string): string;
|
|
4
|
-
export declare function buildInlineChannelPreamble(workDir: string, externalChannel?: ExternalChannelSessionStatus | null, sessionId?: string): string;
|
|
5
|
-
export declare function ensurePlatformInstructionsFile(workDir: string, externalChannel?: ExternalChannelSessionStatus | null, sessionId?: string): string;
|
|
3
|
+
export declare function buildPlatformInstructions(workDir: string, externalChannel?: ExternalChannelSessionStatus | null, sessionId?: string, agentSystemPrompt?: string | null): string;
|
|
4
|
+
export declare function buildInlineChannelPreamble(workDir: string, externalChannel?: ExternalChannelSessionStatus | null, sessionId?: string, agentSystemPrompt?: string | null): string;
|
|
5
|
+
export declare function ensurePlatformInstructionsFile(workDir: string, externalChannel?: ExternalChannelSessionStatus | null, sessionId?: string, agentSystemPrompt?: string | null): string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import a from"node:fs";import s from"node:path";import{createHash as u}from"node:crypto";import{resolveShennianPath as f}from"../config/index.js";import{buildExternalChannelInstructions as l}from"./external-channel-instructions.js";const h=`## Shennian Output Instructions
|
|
2
2
|
|
|
3
3
|
When you mention a local file that the user may want to open in Shennian, format it as a Markdown link using the exact local path:
|
|
4
4
|
|
|
@@ -6,17 +6,25 @@ When you mention a local file that the user may want to open in Shennian, format
|
|
|
6
6
|
- Use [filename.ext](<relative/path/to/filename.ext>) for paths relative to the current working directory.
|
|
7
7
|
- Do not use file:// URLs for local files.
|
|
8
8
|
- Do not put user-openable file paths only inside code blocks.
|
|
9
|
-
- Keep normal http:// and https:// links unchanged.`;function
|
|
9
|
+
- Keep normal http:// and https:// links unchanged.`;function m(t){const e=s.join(t,"AGENTS.md");try{return a.readFileSync(e,"utf8").trim()}catch{return""}}function p(t,e,i,o){const r=m(t),n=l(e,s.resolve(t),i);return`${["# Shennian Agent Instructions",r?`## Project Instructions
|
|
10
10
|
|
|
11
|
-
${
|
|
11
|
+
${r}`:"",h,o?.trim()?`## Agent Instructions
|
|
12
12
|
|
|
13
|
-
${
|
|
13
|
+
${o.trim()}`:"",n?`## External Message Channel Instructions
|
|
14
|
+
|
|
15
|
+
${n}`:""].filter(Boolean).join(`
|
|
14
16
|
|
|
15
17
|
`)}
|
|
16
|
-
`}function
|
|
18
|
+
`}function g(t,e,i,o){const r=l(e,s.resolve(t),i),n=[o?.trim()?`## \u667A\u80FD\u4F53\u63D0\u793A\u8BCD
|
|
19
|
+
|
|
20
|
+
${o.trim()}`:"",r?`## \u5916\u90E8\u6D88\u606F\u901A\u9053\u8BF4\u660E
|
|
21
|
+
|
|
22
|
+
${r}`:""].filter(Boolean);return n.length?`# \u795E\u5FF5\u8FD0\u884C\u6307\u4EE4\uFF08\u7CFB\u7EDF\u6307\u4EE4\uFF0C\u975E\u7528\u6237\u8F93\u5165\uFF0C\u8BF7\u9075\u5FAA\u540E\u518D\u56DE\u5E94\u4E0B\u65B9\u7528\u6237\u6D88\u606F\uFF09
|
|
17
23
|
|
|
18
|
-
${
|
|
24
|
+
${n.join(`
|
|
25
|
+
|
|
26
|
+
`)}
|
|
19
27
|
|
|
20
28
|
---
|
|
21
29
|
|
|
22
|
-
`:""}function
|
|
30
|
+
`:""}function y(t,e,i,o){const r=u("sha256").update(`${s.resolve(t)}:${i??""}:${JSON.stringify(e??null)}:${o??""}`).digest("hex").slice(0,16),n=f("runtime","agent-instructions",`${r}.md`),c=p(t,e,i,o);a.mkdirSync(s.dirname(n),{recursive:!0});try{if(a.readFileSync(n,"utf8")===c)return n}catch{}return a.writeFileSync(n,c),n}export{h as PLATFORM_OUTPUT_INSTRUCTIONS,g as buildInlineChannelPreamble,p as buildPlatformInstructions,y as ensurePlatformInstructionsFile};
|
|
@@ -21,7 +21,7 @@ export declare class WorkBuddyAdapter extends AgentAdapter {
|
|
|
21
21
|
env?: NodeJS.ProcessEnv;
|
|
22
22
|
}): void;
|
|
23
23
|
start(_sessionId: string, workDir: string, agentSessionId?: string | null): Promise<void>;
|
|
24
|
-
send(text: string, modelId?: string, reasoningEffort?: string, _attachments?: ChatAttachmentMeta[]): Promise<void>;
|
|
24
|
+
send(text: string, modelId?: string, reasoningEffort?: string, _attachments?: ChatAttachmentMeta[], agentSystemPrompt?: string | null): Promise<void>;
|
|
25
25
|
resume(agentSessionId: string): Promise<void>;
|
|
26
26
|
stop(): Promise<void>;
|
|
27
27
|
getStatus(): Promise<{
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{createInterface as
|
|
1
|
+
import{createInterface as d}from"node:readline";import{randomUUID as m}from"node:crypto";import{AgentAdapter as p,registerAgent as f}from"./adapter.js";import{resolveBuiltinCommand as c,spawnAgentCommand as g}from"./command-spec.js";import{buildAgentProcessEnv as y}from"../agent-env.js";import{buildPlatformInstructions as I}from"./platform-instructions.js";import{ensureWorkBuddyRoomPluginBundle as S}from"../integrations/workbuddy-plugin-bundle.js";const k=new Set(["minimal","low","medium","high","xhigh","max"]);function x(i){return i?.trim()||"auto"}function E(i){const t=i?.trim();if(t){if(k.has(t))return t;throw new Error(`Unsupported WorkBuddy reasoning effort "${t}". Supported values: minimal, low, medium, high, xhigh, max.`)}}class _ extends p{type="workbuddy";process=null;agentSessionId=null;workDir=null;seq=0;runId="";terminalState="open";hasEmittedText=!1;runPhase=null;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.agentSessionId=e)}async send(t,s,e,r,o){await this.killProcess(),this.runId=m(),this.resetRunState();const n=["-p",t,"--output-format","stream-json","--verbose","--permission-mode","auto","--setting-sources","user,project,local","--model",x(s)];n.push("--plugin-dir",S().pluginRoot);const a=I(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,o);a&&n.push("--append-system-prompt",a);const l=E(e);l&&n.push("--effort",l),this.agentSessionId&&n.push("--resume",this.agentSessionId),this.spawnAndParse(n)}async resume(t){await this.killProcess(),this.agentSessionId=t,this.resetRunState()}async stop(){await this.killProcess()}async getStatus(){return{active:this.process!=null&&this.terminalState==="open",runId:this.runId||null,runPhase:this.runPhase,canStop:this.process!=null&&this.terminalState==="open"}}spawnAndParse(t){const s=c("workbuddy");if(!s){this.emit("error",new Error("WorkBuddy was not found. Install WorkBuddy Desktop or the CodeBuddy CLI, then retry."));return}const e=g(s,t,{cwd:this.workDir??void 0,stdio:["ignore","pipe","pipe"],env:y(this.extraEnv)});this.process=e,d({input:e.stdout}).on("line",n=>{if(n.trim())try{this.handleStreamEvent(JSON.parse(n))}catch{}});let o="";e.stderr?.on("data",n=>{o=`${o}${n.toString()}`.slice(-8e3)}),e.on("close",n=>{this.process===e&&(this.process=null,this.runPhase=null,this.handleProcessClose(n,o))}),e.on("error",n=>{if(this.process!==e)return;this.process=null,this.runPhase=null;const a=n.code==="ENOENT";this.emitErrorIfOpen({state:"error",message:a?"WorkBuddy was not found. Install WorkBuddy Desktop or the CodeBuddy CLI, then retry.":u(n.message)})})}handleStreamEvent(t){if(t.type==="system"&&t.subtype==="init"&&t.session_id){this.agentSessionId=t.session_id,this.runPhase="thinking",this.emitEvent({state:"start",agentSessionId:t.session_id});return}if(t.type==="control_request"&&t.request?.subtype==="can_use_tool"){this.runPhase="waiting_approval",this.emitEvent({state:"approval-pending",name:t.request.tool_name,args:t.request.input,approval:{title:`WorkBuddy \u8BF7\u6C42\u4F7F\u7528 ${t.request.tool_name||"\u5DE5\u5177"}`,source:"workbuddy",actionHint:"\u8BF7\u5728 WorkBuddy \u6216\u795E\u5FF5\u4E2D\u786E\u8BA4\u540E\u7EE7\u7EED\u3002"}});return}if(t.type==="assistant"){const e=t.message?.content;if(e?.length)for(const r of e)this.handleContentBlock(r);else t.text&&this.emitText(t.text,!!t.thinking);return}if(t.type!=="result")return;if(t.subtype==="tool_result"){this.runPhase="tool_running",this.emitEvent({state:"tool-result",name:t.name,result:h(t.content)});return}if(t.subtype==="error"||t.error){this.emitErrorIfOpen({state:"error",message:u(t.error||t.result||"WorkBuddy failed.")});return}!this.hasEmittedText&&t.result&&this.emitText(t.result,!1),t.session_id&&(this.agentSessionId=t.session_id);const s=t.usage??t.message?.usage;this.emitFinalIfOpen({state:"final",agentSessionId:this.agentSessionId??void 0,usage:s?{inputTokens:s.input_tokens??0,outputTokens:s.output_tokens??0}:void 0})}handleContentBlock(t){t.type==="text"&&t.text?this.emitText(t.text,!1):t.type==="thinking"&&t.thinking?this.emitText(t.thinking,!0):t.type==="tool_use"?(this.runPhase="tool_running",this.emitEvent({state:"tool-call",name:t.name,args:t.input})):t.type==="tool_result"&&this.emitEvent({state:"tool-result",name:t.name,result:h(t.content)})}emitText(t,s){this.runPhase=s?"thinking":"streaming_text";const e=!s&&this.hasEmittedText?`
|
|
2
2
|
|
|
3
|
-
`:"";this.emitEvent({state:"delta",text:e+t,thinking:s||void 0}),s||(this.hasEmittedText=!0)}handleProcessClose(t,s){if(t!==0&&t!==null){this.emitErrorIfOpen({state:"error",message:u(s)||`WorkBuddy exited with code ${t}.`});return}this.emitFinalIfOpen({state:"final",agentSessionId:this.agentSessionId??void 0})}emitFinalIfOpen(t){this.terminalState==="open"&&(this.terminalState="final",this.runPhase=null,this.emitEvent(t))}emitErrorIfOpen(t){this.terminalState==="open"&&(this.terminalState="error",this.runPhase=null,this.emitEvent(t))}emitEvent(t){this.emit("agentEvent",{...t,runId:this.runId,seq:this.seq++})}resetRunState(){this.seq=0,this.terminalState="open",this.hasEmittedText=!1,this.runPhase=null}async killProcess(){const t=this.process;t&&(this.process=null,this.runPhase=null,t.kill("SIGTERM"),await new Promise(s=>{let e=!1;const
|
|
3
|
+
`:"";this.emitEvent({state:"delta",text:e+t,thinking:s||void 0}),s||(this.hasEmittedText=!0)}handleProcessClose(t,s){if(t!==0&&t!==null){this.emitErrorIfOpen({state:"error",message:u(s)||`WorkBuddy exited with code ${t}.`});return}this.emitFinalIfOpen({state:"final",agentSessionId:this.agentSessionId??void 0})}emitFinalIfOpen(t){this.terminalState==="open"&&(this.terminalState="final",this.runPhase=null,this.emitEvent(t))}emitErrorIfOpen(t){this.terminalState==="open"&&(this.terminalState="error",this.runPhase=null,this.emitEvent(t))}emitEvent(t){this.emit("agentEvent",{...t,runId:this.runId,seq:this.seq++})}resetRunState(){this.seq=0,this.terminalState="open",this.hasEmittedText=!1,this.runPhase=null}async killProcess(){const t=this.process;t&&(this.process=null,this.runPhase=null,t.kill("SIGTERM"),await new Promise(s=>{let e=!1;const r=()=>{e||(e=!0,s())};t.once("close",r),setTimeout(()=>{t.kill("SIGKILL"),r()},3e3).unref?.()}))}}function h(i){if(typeof i=="string")return i;try{return JSON.stringify(i)}catch{return"[unserializable WorkBuddy tool result]"}}function u(i){return i.replace(/(Authorization\s*:\s*)Bearer\s+[A-Za-z0-9._~+\/-]+/gi,"$1Bearer [redacted]").replace(/(api[-_ ]?key|access[-_ ]?token|refresh[-_ ]?token|connector[-_ ]?token)(\s*[:=]\s*)[^\s,;]+/gi,"$1$2[redacted]").trim().slice(0,2e3)}f("workbuddy",()=>new _);export{_ as WorkBuddyAdapter,x as normalizeWorkBuddyModelId,E as normalizeWorkBuddyReasoningEffort,u as sanitizeWorkBuddyError};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
`),a=e>0?Math.min(e,80):Math.min(t.length,80);return t.slice(0,a)}function Y(t,e,a={}){if(t.state==="tool-call"||t.state==="tool-result"){const s={runId:t.runId,sourceSeq:t.seq};return{state:t.state,runId:t.runId,seq:t.seq,sessionId:e,detailRef:s,...t.name?{name:t.name}:{},...t.source?{source:t.source}:{},...t.agentSessionId?{agentSessionId:t.agentSessionId}:{},...a}}return{...t,sessionId:e,...a}}const X=3e4;function Z(t){return t.state==="heartbeat"?t.runPhase??null:t.state==="tool-call"||t.state==="tool-result"?"tool_running":t.state==="approval-pending"?"waiting_approval":t.state==="delta"?t.thinking?"thinking":"streaming_text":t.state==="init"||t.state==="start"?"thinking":null}function ee(t,e){return`Agent send failed: ${e instanceof Error?e.message:String(e)}`}function _(t,e){return t!=="manager"?t:e==="claude"?"claude":"codex"}function L(t,e,a){t.client.sendEvent({type:"event",event:"session.message",payload:{sessionId:e.sessionId,message:e,session:{id:e.sessionId,agentType:a.agentType,agentSessionId:a.agentSessionId??null,modelId:a.modelId??null,workDir:a.workDir,status:"active",externalChannel:null}}})}function te(t,e){B({sessionId:e.sessionId,agentType:e.agentType,workDir:e.workDir,agentSessionId:e.agentSessionId??null,modelId:e.modelId??null}),t.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:e.sessionId,agentType:e.agentType,agentSessionId:e.agentSessionId??null,modelId:e.modelId??null,workDir:e.workDir,status:"active",externalChannel:null}}})}function Ie(t){if(!t||typeof t!="object")return null;const e=t;return{configured:e.configured===void 0?void 0:!!e.configured,connected:!!e.connected,type:typeof e.type=="string"?e.type:null,channelId:typeof e.channelId=="string"?e.channelId:null,name:typeof e.name=="string"?e.name:null,canReply:e.canReply===void 0||e.canReply===null?null:!!e.canReply,systemPrompt:typeof e.systemPrompt=="string"?e.systemPrompt:null,wechatRpaSource:typeof e.wechatRpaSource=="string"?e.wechatRpaSource:null,wechatRpaGroups:Array.isArray(e.wechatRpaGroups)?e.wechatRpaGroups.map(a=>({name:String(a?.name||"").trim()})).filter(a=>a.name):null,pollIntervalMs:Number.isFinite(e.pollIntervalMs)?Number(e.pollIntervalMs):null,recentLimit:Number.isFinite(e.recentLimit)?Number(e.recentLimit):null,idleSeconds:Number.isFinite(e.idleSeconds)?Number(e.idleSeconds):null,forceForeground:e.forceForeground===void 0||e.forceForeground===null?null:!!e.forceForeground,noRestore:e.noRestore===void 0||e.noRestore===null?null:!!e.noRestore,downloadAttachments:e.downloadAttachments===void 0||e.downloadAttachments===null?null:!!e.downloadAttachments,downloadAttachmentsDir:typeof e.downloadAttachmentsDir=="string"?e.downloadAttachmentsDir:null}}function we(t){return!!(t?.configured??t?.connected)}function W(t){return J(t)}function v(t,e,a){return{}}function ne(t,e,a,s,i){t.configure?.({sessionId:e,externalChannel:s??null,env:{...W(a),...v(e,s,i)}})}function Se(t,e,a){return null}function ae(t,e,a){if(t!=="claude"||!a)return e;const s=e.trim();return!!s&&s.startsWith("-")&&!s.includes("/")?U(a)??e:e}function re(t,e,a,s){let i=null;function f(n,r={}){t.client.sendAgentEvent({type:"event",event:"agent",payload:Y(n,e,r),seq:n.seq,id:`agent-evt-${n.runId}-${n.seq}`})}function l(n){n?.heartbeatTimer&&(clearInterval(n.heartbeatTimer),n.heartbeatTimer=null)}function d(n){if(!n.currentRunId||!n.currentRunPhase)return;const r=n.heartbeatSeq++;t.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"heartbeat",sessionId:e,runId:n.currentRunId,seq:r,runPhase:n.currentRunPhase},seq:r,id:`agent-heartbeat-${n.currentRunId}-${r}-${Date.now()}`})}function I(n){!n||n.heartbeatTimer||(n.heartbeatTimer=setInterval(()=>{d(n)},X),n.heartbeatTimer.unref?.())}function w(n){const r=n?.pendingTextEvent;!n||!r||!r.text||(f({state:"delta",runId:r.runId,seq:r.seq,text:r.text,thinking:r.thinking||void 0}),n.pendingTextEvent=null)}s.on("agentEvent",n=>{const r=t.sessions.get(e),R=Z(n),T=n.state==="final"||n.state==="error"||n.state==="aborted";r&&(r.nextEventSeq=n.seq+1,T||(r.currentRunId=n.runId),!T&&R&&(r.currentRunPhase=R,I(r)),n.agentSessionId&&(r.agentSessionId=n.agentSessionId)),t.managerRuntime?.noteAgentEvent(e,n),n.state!=="delta"&&E({level:"info",sessionId:e,wsEvent:`agent.${n.state}`,wsDirection:"out",metadata:{runId:n.runId,seq:n.seq,agentType:a}}),n.state==="delta"&&n.text&&!n.thinking?A(e,{id:`agent-${n.runId}-${n.seq}`,sessionId:e,role:"agent",ts:Date.now(),payload:n.text}):n.state==="tool-call"||n.state==="tool-result"?A(e,{id:`agent-${n.runId}-${n.seq}`,sessionId:e,role:"agent",ts:Date.now(),payload:JSON.stringify({v:1,type:n.state==="tool-call"?"tool_use":"tool_result",name:n.name,status:n.state==="tool-call"?"running":"completed",detailRef:{runId:n.runId,sourceSeq:n.seq},args:n.args,result:n.result})}):n.state==="approval-pending"?A(e,{id:`agent-${n.runId||"run"}-${n.seq}`,sessionId:e,role:"agent",ts:Date.now(),payload:j(n.approval)}):(n.state==="error"||n.state==="aborted")&&n.message&&A(e,{id:`agent-${n.runId||"run"}-${n.seq}`,sessionId:e,role:"agent",ts:Date.now(),payload:n.message});const m=`${e}:${n.runId}`;if(n.state==="delta"&&!n.thinking&&n.text&&t.runTextAcc.set(m,(t.runTextAcc.get(m)??"")+n.text),n.agentSessionId&&n.agentSessionId!==i&&(i=n.agentSessionId,t.nativeFusion?.noteManagedSourceSession(e,_(a,n.source),n.agentSessionId),r&&B({sessionId:e,agentType:a,workDir:r.workDir,agentSessionId:n.agentSessionId}),t.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:e,agentType:a,agentSessionId:n.agentSessionId}}})),n.state==="delta"){const h=n.text??"";if(!h)return;const b=!!n.thinking;r?.pendingTextEvent&&(r.pendingTextEvent.runId!==n.runId||r.pendingTextEvent.thinking!==b)&&w(r),r&&!r.pendingTextEvent&&(r.pendingTextEvent={runId:n.runId,seq:n.seq,text:"",thinking:b}),r?.pendingTextEvent&&(r.pendingTextEvent.text+=h,r.pendingTextEvent.seq=n.seq);return}let p={};if(n.state==="final"){w(r);const h=t.runTextAcc.get(m)??"";h&&(p={messageSummary:V(h)}),t.runTextAcc.delete(m)}else n.state==="error"||n.state==="aborted"?(w(r),t.runTextAcc.delete(m)):(n.state==="tool-call"||n.state==="tool-result"||n.state==="approval-pending")&&w(r);T&&r?.currentRunId===n.runId&&(r.currentRunId=null,r.currentRunPhase=null,r.nextEventSeq=0,l(r),t.chatQueue?.noteTerminal(e)),f(n,p)}),s.on("error",n=>{console.error(`[chat.send] adapter error sessionId=${e} agentType=${a}: ${n.message}`),t.sessions.delete(e),t.chatQueue?.noteTerminal(e),t.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:e,message:n.message,runId:"",seq:0}})})}function se(t,e){if(t.processedReqIds.add(e),t.processedReqIds.size>1e3){const a=t.processedReqIds.values().next().value;t.processedReqIds.delete(a)}}async function q(t){t.heartbeatTimer&&(clearInterval(t.heartbeatTimer),t.heartbeatTimer=null),t.adapter.removeAllListeners(),await t.adapter.stop().catch(()=>{})}async function oe(t,e,a,s,i,f,l){t.evictIdleSessions();const d=O(a);if(!d)throw new Error(`Unsupported agent: ${a}`);ne(d,e,a,f,l),await d.start(e,s,i);const I={adapter:d,workDir:s,agentType:a,agentSessionId:i??null,lastActiveAt:Date.now(),currentRunId:null,currentRunPhase:null,nextEventSeq:0,heartbeatSeq:0,heartbeatTimer:null,pendingTextEvent:null,externalChannel:f??null,externalReplyTarget:l??null,externalChannelEnv:{...W(a),...v(e,f,l)}};return t.sessions.set(e,I),re(t,e,a,d),I}function le(t,e){const a=t.sessions.get(e),s=a?.currentRunId;if(!a||!s)return;const i=a.nextEventSeq;t.runTextAcc.delete(`${e}:${s}`),a.pendingTextEvent=null,a.currentRunId=null,a.currentRunPhase=null,a.nextEventSeq=0,a.heartbeatTimer&&(clearInterval(a.heartbeatTimer),a.heartbeatTimer=null),t.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"aborted",sessionId:e,runId:s,seq:i},seq:i,id:`agent-evt-${s}-${i}`}),t.chatQueue?.noteTerminal(e)}async function xe(t,e){if(t.processedReqIds.has(e.id)){t.client.sendRes({type:"res",id:e.id,ok:!0});return}se(t,e.id);const{sessionId:a,text:s,agentType:i,workDir:f,agentSessionId:l,modelId:d,managerDefaultWorkerAgentType:I,managerDefaultWorkerModelId:w,reasoningEffort:n,clientMessageId:r,sessionListProjection:R,waitForDispatch:T,responseId:m}=e.params,p=m||e.id;G(R);const h=null,b="";if(!a||!s){t.processedReqIds.delete(e.id),t.client.sendRes({type:"res",id:p,ok:!1,error:"sessionId and text are required"});return}const u=i;u==="manager"&&t.managerRuntime?.setManagerWorkerDefaults(a,I??null,w??null);const y=(u==="claude"||u==="codex"||u==="workbuddy")&&typeof n=="string"&&n.trim()?n.trim():void 0,S=t.resolvePath(ae(u,f||z.homedir(),l)||z.homedir()),$=S,D=K(e.params.attachments),g=D?.length?await Q({text:s,attachments:D,workDir:S}):{text:s,attachments:D,localized:!1};let o=t.sessions.get(a);if(o){if(o.lastActiveAt=Date.now(),o.agentType!==u||o.workDir!==S||JSON.stringify(o.externalChannel??null)!==JSON.stringify(h??null)){t.sessions.delete(a);try{await q(o)}catch{t.processedReqIds.delete(e.id)}o=void 0}else if(l&&o.agentSessionId!==l)try{await o.adapter.resume(l),o.agentSessionId=l}catch{t.sessions.delete(a);try{await q(o)}catch{t.processedReqIds.delete(e.id)}o=void 0}}if(!o)try{o=await oe(t,a,u,S,l,h,b)}catch(c){const x=c instanceof Error&&c.message.startsWith("Unsupported agent:")?c.message:`Failed to start ${i}: ${c instanceof Error?c.message:String(c)}`;console.error(`[chat.send] start failed reqId=${e.id} sessionId=${a} agentType=${i} workDir=${S} agentSessionId=${l??""}: ${x}`),t.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:a,message:x,runId:"",seq:0}}),t.processedReqIds.delete(e.id),t.client.sendRes({type:"res",id:p,ok:!1,error:x});return}const P={id:r??`user-${e.id}`,sessionId:a,role:"user",ts:Date.now(),payload:H(g.text,g.attachments)};E({level:"info",sessionId:a,wsEvent:"chat.send.start",metadata:{reqId:e.id,agentType:u,modelId:d,reasoningEffort:y}});const C=()=>{te(t,{sessionId:a,agentType:u,workDir:$,agentSessionId:o.agentSessionId??l??null,modelId:d}),o.currentRunId||(o.nextEventSeq=0),t.nativeFusion?.registerManagedSend({sessionId:a,agentType:u,sourceAgentType:_(u,d),canonicalMessageId:r??null,sourceSessionKey:o.agentSessionId??l??null,text:g.text}),A(a,P),L(t,P,{agentType:u,workDir:$,agentSessionId:o.agentSessionId??l??null,modelId:d})},M=async(c,x)=>{const k=ee(u,c);console.error(`[chat.send] send failed reqId=${e.id} sessionId=${a} agentType=${i} workDir=${S} agentSessionId=${o.agentSessionId??l??""}: ${k}`),t.sessions.delete(a);try{await q(o)}catch{}if(t.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:a,message:k,runId:"",seq:0}}),!x){const N={id:`agent-error-${e.id}-${Date.now()}`,sessionId:a,role:"agent",ts:Date.now(),payload:k};A(a,N),L(t,N,{agentType:u,workDir:$,agentSessionId:o.agentSessionId??l??null,modelId:d})}x&&(t.processedReqIds.delete(e.id),t.client.sendRes({type:"res",id:p,ok:!1,error:k}))};if(T){try{const c=g.attachments;c?.length?await o.adapter.send(g.text,d,y,c):y?await o.adapter.send(g.text,d,y):await o.adapter.send(g.text,d),E({level:"info",sessionId:a,wsEvent:"chat.send.done",metadata:{reqId:e.id}})}catch(c){await M(c,!0);return}C(),t.client.sendRes({type:"res",id:p,ok:!0,...g.localized?{payload:{localizedAttachments:!0}}:{}}),E({level:"info",sessionId:a,wsEvent:"chat.send.res",metadata:{reqId:e.id,ok:!0}});return}C(),t.client.sendRes({type:"res",id:p,ok:!0,...g.localized?{payload:{localizedAttachments:!0}}:{}}),E({level:"info",sessionId:a,wsEvent:"chat.send.res",metadata:{reqId:e.id,ok:!0}});const F=g.attachments;(F?.length?o.adapter.send(g.text,d,y,F):y?o.adapter.send(g.text,d,y):o.adapter.send(g.text,d)).then(()=>{E({level:"info",sessionId:a,wsEvent:"chat.send.done",metadata:{reqId:e.id}})}).catch(c=>{M(c,!1)})}async function Ee(t,e){const{sessionId:a}=e.params,s=t.sessions.get(a);if(s){try{await s.adapter.stop()}catch{}le(t,a),t.activityPublisher?.publish(a,null)}t.client.sendRes({type:"res",id:e.id,ok:!0})}export{Ee as handleChatAbort,xe as handleChatSend};
|
|
1
|
+
import N from"node:os";import{createAgent as H}from"../../agents/adapter.js";import{buildApprovalPendingPayload as U,buildUserMessagePayload as G}from"@shennian/wire";import{reportLog as w}from"../../log-reporter.js";import{lookupClaudeTranscriptCwd as J}from"../../native-fusion/parsers.js";import{appendMessage as A,recordSession as z}from"../store.js";import{mergeProjectedSessions as Q}from"../projection.js";import{buildManagedAgentEnv as K}from"../../agents/config-status.js";import{materializeRemoteChatAttachments as V}from"../remote-attachments.js";function Y(t){if(!Array.isArray(t))return;const e=t.map(a=>{if(!a||typeof a!="object")return null;const s=a,o=typeof s.path=="string"?s.path:"",u=typeof s.name=="string"?s.name:"",i=typeof s.mimeType=="string"?s.mimeType:"";if(!o||!u||!i)return null;const d=typeof s.previewData=="string"&&s.previewData.trim()?s.previewData.trim():void 0;return{path:o,name:u,mimeType:i,kind:i.startsWith("image/")?"image":"file",...d?{previewData:d}:{}}}).filter(a=>a!=null);return e.length?e:void 0}function X(t){const e=t.indexOf(`
|
|
2
|
+
`),a=e>0?Math.min(e,80):Math.min(t.length,80);return t.slice(0,a)}function Z(t,e,a={}){if(t.state==="tool-call"||t.state==="tool-result"){const s={runId:t.runId,sourceSeq:t.seq};return{state:t.state,runId:t.runId,seq:t.seq,sessionId:e,detailRef:s,...t.name?{name:t.name}:{},...t.source?{source:t.source}:{},...t.agentSessionId?{agentSessionId:t.agentSessionId}:{},...a}}return{...t,sessionId:e,...a}}const ee=3e4;function te(t){return t.state==="heartbeat"?t.runPhase??null:t.state==="tool-call"||t.state==="tool-result"?"tool_running":t.state==="approval-pending"?"waiting_approval":t.state==="delta"?t.thinking?"thinking":"streaming_text":t.state==="init"||t.state==="start"?"thinking":null}function ne(t,e){return`Agent send failed: ${e instanceof Error?e.message:String(e)}`}function B(t,e){return t!=="manager"?t:e==="claude"?"claude":"codex"}function _(t,e,a){t.client.sendEvent({type:"event",event:"session.message",payload:{sessionId:e.sessionId,message:e,session:{id:e.sessionId,agentType:a.agentType,agentSessionId:a.agentSessionId??null,modelId:a.modelId??null,workDir:a.workDir,status:"active",externalChannel:null}}})}function ae(t,e){z({sessionId:e.sessionId,agentType:e.agentType,workDir:e.workDir,agentSessionId:e.agentSessionId??null,modelId:e.modelId??null}),t.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:e.sessionId,agentType:e.agentType,agentSessionId:e.agentSessionId??null,modelId:e.modelId??null,workDir:e.workDir,status:"active",externalChannel:null}}})}function we(t){if(!t||typeof t!="object")return null;const e=t;return{configured:e.configured===void 0?void 0:!!e.configured,connected:!!e.connected,type:typeof e.type=="string"?e.type:null,channelId:typeof e.channelId=="string"?e.channelId:null,name:typeof e.name=="string"?e.name:null,canReply:e.canReply===void 0||e.canReply===null?null:!!e.canReply,systemPrompt:typeof e.systemPrompt=="string"?e.systemPrompt:null,wechatRpaSource:typeof e.wechatRpaSource=="string"?e.wechatRpaSource:null,wechatRpaGroups:Array.isArray(e.wechatRpaGroups)?e.wechatRpaGroups.map(a=>({name:String(a?.name||"").trim()})).filter(a=>a.name):null,pollIntervalMs:Number.isFinite(e.pollIntervalMs)?Number(e.pollIntervalMs):null,recentLimit:Number.isFinite(e.recentLimit)?Number(e.recentLimit):null,idleSeconds:Number.isFinite(e.idleSeconds)?Number(e.idleSeconds):null,forceForeground:e.forceForeground===void 0||e.forceForeground===null?null:!!e.forceForeground,noRestore:e.noRestore===void 0||e.noRestore===null?null:!!e.noRestore,downloadAttachments:e.downloadAttachments===void 0||e.downloadAttachments===null?null:!!e.downloadAttachments,downloadAttachmentsDir:typeof e.downloadAttachmentsDir=="string"?e.downloadAttachmentsDir:null}}function Ae(t){return!!(t?.configured??t?.connected)}function L(t){return K(t)}function W(t,e,a){return{}}function re(t,e,a,s,o){t.configure?.({sessionId:e,externalChannel:s??null,env:{...L(a),...W(e,s,o)}})}function Te(t,e,a){return null}function se(t,e,a){if(t!=="claude"||!a)return e;const s=e.trim();return!!s&&s.startsWith("-")&&!s.includes("/")?J(a)??e:e}function oe(t,e,a,s){let o=null;function u(n,r={}){t.client.sendAgentEvent({type:"event",event:"agent",payload:Z(n,e,r),seq:n.seq,id:`agent-evt-${n.runId}-${n.seq}`})}function i(n){n?.heartbeatTimer&&(clearInterval(n.heartbeatTimer),n.heartbeatTimer=null)}function d(n){if(!n.currentRunId||!n.currentRunPhase)return;const r=n.heartbeatSeq++;t.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"heartbeat",sessionId:e,runId:n.currentRunId,seq:r,runPhase:n.currentRunPhase},seq:r,id:`agent-heartbeat-${n.currentRunId}-${r}-${Date.now()}`})}function h(n){!n||n.heartbeatTimer||(n.heartbeatTimer=setInterval(()=>{d(n)},ee),n.heartbeatTimer.unref?.())}function y(n){const r=n?.pendingTextEvent;!n||!r||!r.text||(u({state:"delta",runId:r.runId,seq:r.seq,text:r.text,thinking:r.thinking||void 0}),n.pendingTextEvent=null)}s.on("agentEvent",n=>{const r=t.sessions.get(e),T=te(n),E=n.state==="final"||n.state==="error"||n.state==="aborted";r&&(r.nextEventSeq=n.seq+1,E||(r.currentRunId=n.runId),!E&&T&&(r.currentRunPhase=T,h(r)),n.agentSessionId&&(r.agentSessionId=n.agentSessionId)),t.managerRuntime?.noteAgentEvent(e,n),n.state!=="delta"&&w({level:"info",sessionId:e,wsEvent:`agent.${n.state}`,wsDirection:"out",metadata:{runId:n.runId,seq:n.seq,agentType:a}}),n.state==="delta"&&n.text&&!n.thinking?A(e,{id:`agent-${n.runId}-${n.seq}`,sessionId:e,role:"agent",ts:Date.now(),payload:n.text}):n.state==="tool-call"||n.state==="tool-result"?A(e,{id:`agent-${n.runId}-${n.seq}`,sessionId:e,role:"agent",ts:Date.now(),payload:JSON.stringify({v:1,type:n.state==="tool-call"?"tool_use":"tool_result",name:n.name,status:n.state==="tool-call"?"running":"completed",detailRef:{runId:n.runId,sourceSeq:n.seq},args:n.args,result:n.result})}):n.state==="approval-pending"?A(e,{id:`agent-${n.runId||"run"}-${n.seq}`,sessionId:e,role:"agent",ts:Date.now(),payload:U(n.approval)}):(n.state==="error"||n.state==="aborted")&&n.message&&A(e,{id:`agent-${n.runId||"run"}-${n.seq}`,sessionId:e,role:"agent",ts:Date.now(),payload:n.message});const m=`${e}:${n.runId}`;if(n.state==="delta"&&!n.thinking&&n.text&&t.runTextAcc.set(m,(t.runTextAcc.get(m)??"")+n.text),n.agentSessionId&&n.agentSessionId!==o&&(o=n.agentSessionId,t.nativeFusion?.noteManagedSourceSession(e,B(a,n.source),n.agentSessionId),r&&z({sessionId:e,agentType:a,workDir:r.workDir,agentSessionId:n.agentSessionId}),t.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:e,agentType:a,agentSessionId:n.agentSessionId}}})),n.state==="delta"){const f=n.text??"";if(!f)return;const R=!!n.thinking;r?.pendingTextEvent&&(r.pendingTextEvent.runId!==n.runId||r.pendingTextEvent.thinking!==R)&&y(r),r&&!r.pendingTextEvent&&(r.pendingTextEvent={runId:n.runId,seq:n.seq,text:"",thinking:R}),r?.pendingTextEvent&&(r.pendingTextEvent.text+=f,r.pendingTextEvent.seq=n.seq);return}let x={};if(n.state==="final"){y(r);const f=t.runTextAcc.get(m)??"";f&&(x={messageSummary:X(f)}),t.runTextAcc.delete(m)}else n.state==="error"||n.state==="aborted"?(y(r),t.runTextAcc.delete(m)):(n.state==="tool-call"||n.state==="tool-result"||n.state==="approval-pending")&&y(r);E&&r?.currentRunId===n.runId&&(r.currentRunId=null,r.currentRunPhase=null,r.nextEventSeq=0,i(r),t.chatQueue?.noteTerminal(e)),u(n,x)}),s.on("error",n=>{console.error(`[chat.send] adapter error sessionId=${e} agentType=${a}: ${n.message}`),t.sessions.delete(e),t.chatQueue?.noteTerminal(e),t.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:e,message:n.message,runId:"",seq:0}})})}function le(t,e){if(t.processedReqIds.add(e),t.processedReqIds.size>1e3){const a=t.processedReqIds.values().next().value;t.processedReqIds.delete(a)}}async function q(t){t.heartbeatTimer&&(clearInterval(t.heartbeatTimer),t.heartbeatTimer=null),t.adapter.removeAllListeners(),await t.adapter.stop().catch(()=>{})}function v(t,e,a,s,o,u){return u?.trim()?t.send(e,a,s,o,u):o?.length?t.send(e,a,s,o):s?t.send(e,a,s):t.send(e,a)}async function ie(t,e,a,s,o,u,i){t.evictIdleSessions();const d=H(a);if(!d)throw new Error(`Unsupported agent: ${a}`);re(d,e,a,u,i),await d.start(e,s,o);const h={adapter:d,workDir:s,agentType:a,agentSessionId:o??null,lastActiveAt:Date.now(),currentRunId:null,currentRunPhase:null,nextEventSeq:0,heartbeatSeq:0,heartbeatTimer:null,pendingTextEvent:null,externalChannel:u??null,externalReplyTarget:i??null,externalChannelEnv:{...L(a),...W(e,u,i)}};return t.sessions.set(e,h),oe(t,e,a,d),h}function de(t,e){const a=t.sessions.get(e),s=a?.currentRunId;if(!a||!s)return;const o=a.nextEventSeq;t.runTextAcc.delete(`${e}:${s}`),a.pendingTextEvent=null,a.currentRunId=null,a.currentRunPhase=null,a.nextEventSeq=0,a.heartbeatTimer&&(clearInterval(a.heartbeatTimer),a.heartbeatTimer=null),t.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"aborted",sessionId:e,runId:s,seq:o},seq:o,id:`agent-evt-${s}-${o}`}),t.chatQueue?.noteTerminal(e)}async function Ee(t,e){if(t.processedReqIds.has(e.id)){t.client.sendRes({type:"res",id:e.id,ok:!0});return}le(t,e.id);const{sessionId:a,text:s,agentType:o,workDir:u,agentSessionId:i,modelId:d,systemPrompt:h,managerDefaultWorkerAgentType:y,managerDefaultWorkerModelId:n,reasoningEffort:r,clientMessageId:T,sessionListProjection:E,waitForDispatch:m,responseId:x}=e.params,f=x||e.id;Q(E);const R=null,O="";if(!a||!s){t.processedReqIds.delete(e.id),t.client.sendRes({type:"res",id:f,ok:!1,error:"sessionId and text are required"});return}const g=o;g==="manager"&&t.managerRuntime?.setManagerWorkerDefaults(a,y??null,n??null);const k=(g==="claude"||g==="codex"||g==="workbuddy")&&typeof r=="string"&&r.trim()?r.trim():void 0,I=t.resolvePath(se(g,u||N.homedir(),i)||N.homedir()),$=I,D=Y(e.params.attachments),p=D?.length?await V({text:s,attachments:D,workDir:I}):{text:s,attachments:D,localized:!1};let l=t.sessions.get(a);if(l){if(l.lastActiveAt=Date.now(),l.agentType!==g||l.workDir!==I||JSON.stringify(l.externalChannel??null)!==JSON.stringify(R??null)){t.sessions.delete(a);try{await q(l)}catch{t.processedReqIds.delete(e.id)}l=void 0}else if(i&&l.agentSessionId!==i)try{await l.adapter.resume(i),l.agentSessionId=i}catch{t.sessions.delete(a);try{await q(l)}catch{t.processedReqIds.delete(e.id)}l=void 0}}if(!l)try{l=await ie(t,a,g,I,i,R,O)}catch(c){const S=c instanceof Error&&c.message.startsWith("Unsupported agent:")?c.message:`Failed to start ${o}: ${c instanceof Error?c.message:String(c)}`;console.error(`[chat.send] start failed reqId=${e.id} sessionId=${a} agentType=${o} workDir=${I} agentSessionId=${i??""}: ${S}`),t.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:a,message:S,runId:"",seq:0}}),t.processedReqIds.delete(e.id),t.client.sendRes({type:"res",id:f,ok:!1,error:S});return}const P={id:T??`user-${e.id}`,sessionId:a,role:"user",ts:Date.now(),payload:G(p.text,p.attachments)};w({level:"info",sessionId:a,wsEvent:"chat.send.start",metadata:{reqId:e.id,agentType:g,modelId:d,reasoningEffort:k}});const C=()=>{ae(t,{sessionId:a,agentType:g,workDir:$,agentSessionId:l.agentSessionId??i??null,modelId:d}),l.currentRunId||(l.nextEventSeq=0),t.nativeFusion?.registerManagedSend({sessionId:a,agentType:g,sourceAgentType:B(g,d),canonicalMessageId:T??null,sourceSessionKey:l.agentSessionId??i??null,text:p.text}),A(a,P),_(t,P,{agentType:g,workDir:$,agentSessionId:l.agentSessionId??i??null,modelId:d})},M=async(c,S)=>{const b=ne(g,c);console.error(`[chat.send] send failed reqId=${e.id} sessionId=${a} agentType=${o} workDir=${I} agentSessionId=${l.agentSessionId??i??""}: ${b}`),t.sessions.delete(a);try{await q(l)}catch{}if(t.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:a,message:b,runId:"",seq:0}}),!S){const F={id:`agent-error-${e.id}-${Date.now()}`,sessionId:a,role:"agent",ts:Date.now(),payload:b};A(a,F),_(t,F,{agentType:g,workDir:$,agentSessionId:l.agentSessionId??i??null,modelId:d})}S&&(t.processedReqIds.delete(e.id),t.client.sendRes({type:"res",id:f,ok:!1,error:b}))};if(m){try{const c=p.attachments;await v(l.adapter,p.text,d,k,c,h),w({level:"info",sessionId:a,wsEvent:"chat.send.done",metadata:{reqId:e.id}})}catch(c){await M(c,!0);return}C(),t.client.sendRes({type:"res",id:f,ok:!0,...p.localized?{payload:{localizedAttachments:!0}}:{}}),w({level:"info",sessionId:a,wsEvent:"chat.send.res",metadata:{reqId:e.id,ok:!0}});return}C(),t.client.sendRes({type:"res",id:f,ok:!0,...p.localized?{payload:{localizedAttachments:!0}}:{}}),w({level:"info",sessionId:a,wsEvent:"chat.send.res",metadata:{reqId:e.id,ok:!0}});const j=p.attachments;v(l.adapter,p.text,d,k,j,h).then(()=>{w({level:"info",sessionId:a,wsEvent:"chat.send.done",metadata:{reqId:e.id}})}).catch(c=>{M(c,!1)})}async function Re(t,e){const{sessionId:a}=e.params,s=t.sessions.get(a);if(s){try{await s.adapter.stop()}catch{}de(t,a),t.activityPublisher?.publish(a,null)}t.client.sendRes({type:"res",id:e.id,ok:!0})}export{Re as handleChatAbort,Ee as handleChatSend};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import h from"node:fs";import{randomUUID as y}from"node:crypto";import{resolveShennianPath as I}from"../config/index.js";import{mergeProjectedSessions as w}from"./projection.js";import{materializeRemoteChatAttachments as S}from"./remote-attachments.js";const x=I("chat-queue.json");function M(){return{sessions:{}}}function p(){return new Date().toISOString()}function R(n){return`enqueue-send-${n}-${y()}`}function u(){try{const n=JSON.parse(h.readFileSync(x,"utf-8"));return{sessions:n.sessions&&typeof n.sessions=="object"?n.sessions:{}}}catch{return M()}}function d(n){h.mkdirSync(I(""),{recursive:!0}),h.writeFileSync(x,JSON.stringify(n,null,2))}function f(n){if(!Array.isArray(n))return;const e=n.map(s=>{if(!s||typeof s!="object")return null;const t=s,i={path:typeof t.path=="string"?t.path:"",name:typeof t.name=="string"?t.name:"",mimeType:typeof t.mimeType=="string"?t.mimeType:"",...typeof t.previewData=="string"&&t.previewData.trim()?{previewData:t.previewData.trim()}:{}};return i.path&&i.name&&i.mimeType?i:null}).filter(s=>s!=null);return e.length?e:void 0}function q(n){const e=p();return{id:n.queueMessageId||n.clientMessageId||`queue-${y()}`,sessionId:n.sessionId,text:n.text,agentType:n.agentType,workDir:n.workDir,agentSessionId:n.agentSessionId??null,modelId:n.modelId??null,reasoningEffort:n.reasoningEffort??null,clientMessageId:n.clientMessageId??null,attachments:f(n.attachments),externalChannel:n.externalChannel??null,replyTarget:n.replyTarget??null,origin:n.origin,createdAt:e,updatedAt:e}}class
|
|
1
|
+
import h from"node:fs";import{randomUUID as y}from"node:crypto";import{resolveShennianPath as I}from"../config/index.js";import{mergeProjectedSessions as w}from"./projection.js";import{materializeRemoteChatAttachments as S}from"./remote-attachments.js";const x=I("chat-queue.json");function M(){return{sessions:{}}}function p(){return new Date().toISOString()}function R(n){return`enqueue-send-${n}-${y()}`}function u(){try{const n=JSON.parse(h.readFileSync(x,"utf-8"));return{sessions:n.sessions&&typeof n.sessions=="object"?n.sessions:{}}}catch{return M()}}function d(n){h.mkdirSync(I(""),{recursive:!0}),h.writeFileSync(x,JSON.stringify(n,null,2))}function f(n){if(!Array.isArray(n))return;const e=n.map(s=>{if(!s||typeof s!="object")return null;const t=s,i={path:typeof t.path=="string"?t.path:"",name:typeof t.name=="string"?t.name:"",mimeType:typeof t.mimeType=="string"?t.mimeType:"",...typeof t.previewData=="string"&&t.previewData.trim()?{previewData:t.previewData.trim()}:{}};return i.path&&i.name&&i.mimeType?i:null}).filter(s=>s!=null);return e.length?e:void 0}function q(n){const e=p();return{id:n.queueMessageId||n.clientMessageId||`queue-${y()}`,sessionId:n.sessionId,text:n.text,agentType:n.agentType,workDir:n.workDir,agentSessionId:n.agentSessionId??null,modelId:n.modelId??null,systemPrompt:n.systemPrompt??null,reasoningEffort:n.reasoningEffort??null,clientMessageId:n.clientMessageId??null,attachments:f(n.attachments),externalChannel:n.externalChannel??null,replyTarget:n.replyTarget??null,origin:n.origin,createdAt:e,updatedAt:e}}class z{opts;draining=new Set;constructor(e){this.opts=e,setTimeout(()=>this.drainIdleQueues(),0).unref?.()}getSnapshot(e){return{sessionId:e,busy:!!this.opts.getRuntime().sessions.get(e)?.currentRunId,pending:u().sessions[e]??[]}}async handleEnqueue(e){const s=this.opts.getRuntime(),t=e.params;if(w(t.sessionListProjection),!t.sessionId||!t.text||!t.agentType||!t.workDir){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"sessionId, text, agentType and workDir are required"});return}const i=f(t.attachments),r=i?.length?await S({text:t.text,attachments:i,workDir:t.workDir}):{text:t.text,attachments:i,localized:!1},a=await this.isSessionBusy(t.sessionId),o=u(),c=o.sessions[t.sessionId]??[];if(!a&&!c.length){await this.opts.dispatchReq({...e,id:R(e.id),method:"chat.send",params:{...t,text:r.text,responseId:e.id,clientMessageId:t.clientMessageId??t.queueMessageId,waitForDispatch:!0,attachments:r.attachments}});return}const l=q({...t,text:r.text,attachments:r.attachments}),m=t.origin==="external"?D(c,l):null;m||(o.sessions[t.sessionId]=[...c,l],d(o)),this.broadcast(t.sessionId),s.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queued:!0,queueMessageId:m?.id??l.id,queue:this.getSnapshot(t.sessionId),...r.localized?{localizedAttachments:!0}:{}}}),a||this.drainNext(t.sessionId)}async handleGet(e){const s=this.opts.getRuntime(),t=e.params;if(!t.sessionId){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"sessionId is required"});return}s.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queue:this.getSnapshot(t.sessionId)}}),this.getSnapshot(t.sessionId).busy||this.drainNext(t.sessionId)}async handleEdit(e){const s=this.opts.getRuntime(),t=e.params;if(!t.sessionId||!t.queueMessageId||!t.text){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"sessionId, queueMessageId and text are required"});return}const i=u(),r=i.sessions[t.sessionId]??[],a=r.findIndex(o=>o.id===t.queueMessageId);if(a<0){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"Queued message not found"});return}r[a]={...r[a],text:t.text,attachments:f(t.attachments),updatedAt:p()},i.sessions[t.sessionId]=r,d(i),this.broadcast(t.sessionId),s.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queue:this.getSnapshot(t.sessionId)}})}async handleDelete(e){const s=this.opts.getRuntime(),t=e.params;if(!t.sessionId||!t.queueMessageId){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"sessionId and queueMessageId are required"});return}const i=u(),r=i.sessions[t.sessionId]??[],a=r.filter(o=>o.id!==t.queueMessageId);if(a.length===r.length){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"Queued message not found"});return}a.length?i.sessions[t.sessionId]=a:delete i.sessions[t.sessionId],d(i),this.broadcast(t.sessionId),s.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queue:this.getSnapshot(t.sessionId)}})}noteTerminal(e){this.drainNext(e)}drainIdleQueues(){const e=u();for(const s of Object.keys(e.sessions))this.drainNext(s)}async drainNext(e){if(this.draining.has(e))return;const s=this.opts.getRuntime();if(await this.isSessionBusy(e))return;const t=u(),i=t.sessions[e]??[],r=i.shift();if(!r){this.broadcast(e);return}const a=r.origin==="external"?this.mergeExternalMessages(r,i):r;i.length?t.sessions[e]=i:delete t.sessions[e],d(t),this.broadcast(e),this.draining.add(e);try{await this.dispatchQueuedMessage(a)}finally{this.draining.delete(e)}}mergeExternalMessages(e,s){const t=[e];for(;s[0]?.origin==="external";)t.push(s.shift());const i=k(t);return i.length===1?i[0]:{...e,id:`external-batch-${e.id}`,text:i.map(r=>r.text).filter(Boolean).join(`
|
|
2
2
|
|
|
3
|
-
`),attachments:b(i.flatMap(r=>r.attachments??[])),updatedAt:p()}}async dispatchQueuedMessage(e){await this.opts.dispatchReq({type:"req",id:`queue-send-${e.id}-${Date.now()}`,method:"chat.send",params:{sessionId:e.sessionId,text:e.text,agentType:e.agentType,workDir:e.workDir,agentSessionId:e.agentSessionId??null,modelId:e.modelId??void 0,reasoningEffort:e.reasoningEffort??void 0,clientMessageId:e.clientMessageId??e.id,attachments:e.attachments,externalChannel:e.externalChannel,replyTarget:e.replyTarget,waitForDispatch:!0}})}async isSessionBusy(e){const s=this.opts.getRuntime().sessions.get(e);if(!s)return!1;if(s.currentRunId)return!0;if(!s.adapter.getStatus)return!1;const t=await s.adapter.getStatus().catch(()=>null);return t?.active?(t.runId&&(s.currentRunId=t.runId,s.currentRunPhase=t.runPhase??s.currentRunPhase),!0):!1}broadcast(e){this.opts.getRuntime().client.sendEvent({type:"event",event:"session.queue.update",payload:{queue:this.getSnapshot(e)}})}}function k(n){const e=new Set,s=[];for(const t of n){const i=g(t);e.has(i)||(e.add(i),s.push(t))}return s}function D(n,e){const s=g(e);return n.find(t=>g(t)===s)??null}function g(n){const e=T(n);return e?`id:${e}`:["body",E(n.text),...(n.attachments??[]).map(s=>s.path||`${s.name}:${s.mimeType}`)].join(`
|
|
4
|
-
`)}function T(n){const e=typeof n.clientMessageId=="string"?n.clientMessageId.trim():"";if(e)return e;const s=typeof n.id=="string"?n.id.trim():"";return s&&!s.startsWith("queue-")?s:""}function b(n){const e=new Set,s=[];for(const t of n){const i=t.path||`${t.name}:${t.mimeType}`;e.has(i)||(e.add(i),s.push(t))}return s.length?s:void 0}function E(n){return String(n||"").replace(/\s+/g," ").trim()}export{
|
|
3
|
+
`),attachments:b(i.flatMap(r=>r.attachments??[])),updatedAt:p()}}async dispatchQueuedMessage(e){await this.opts.dispatchReq({type:"req",id:`queue-send-${e.id}-${Date.now()}`,method:"chat.send",params:{sessionId:e.sessionId,text:e.text,agentType:e.agentType,workDir:e.workDir,agentSessionId:e.agentSessionId??null,modelId:e.modelId??void 0,systemPrompt:e.systemPrompt??null,reasoningEffort:e.reasoningEffort??void 0,clientMessageId:e.clientMessageId??e.id,attachments:e.attachments,externalChannel:e.externalChannel,replyTarget:e.replyTarget,waitForDispatch:!0}})}async isSessionBusy(e){const s=this.opts.getRuntime().sessions.get(e);if(!s)return!1;if(s.currentRunId)return!0;if(!s.adapter.getStatus)return!1;const t=await s.adapter.getStatus().catch(()=>null);return t?.active?(t.runId&&(s.currentRunId=t.runId,s.currentRunPhase=t.runPhase??s.currentRunPhase),!0):!1}broadcast(e){this.opts.getRuntime().client.sendEvent({type:"event",event:"session.queue.update",payload:{queue:this.getSnapshot(e)}})}}function k(n){const e=new Set,s=[];for(const t of n){const i=g(t);e.has(i)||(e.add(i),s.push(t))}return s}function D(n,e){const s=g(e);return n.find(t=>g(t)===s)??null}function g(n){const e=T(n);return e?`id:${e}`:["body",E(n.text),...(n.attachments??[]).map(s=>s.path||`${s.name}:${s.mimeType}`)].join(`
|
|
4
|
+
`)}function T(n){const e=typeof n.clientMessageId=="string"?n.clientMessageId.trim():"";if(e)return e;const s=typeof n.id=="string"?n.id.trim():"";return s&&!s.startsWith("queue-")?s:""}function b(n){const e=new Set,s=[];for(const t of n){const i=t.path||`${t.name}:${t.mimeType}`;e.has(i)||(e.add(i),s.push(t))}return s.length?s:void 0}function E(n){return String(n||"").replace(/\s+/g," ").trim()}export{z as ChatQueueManager};
|
|
@@ -153,6 +153,12 @@ export type NianSession = {
|
|
|
153
153
|
agentSessionId: string | null;
|
|
154
154
|
sourceMode?: NativeSessionSourceMode | null;
|
|
155
155
|
modelId?: string | null;
|
|
156
|
+
/** Agent-owned conversations follow the Agent model until explicitly overridden. */
|
|
157
|
+
modelSource?: 'agent' | 'session';
|
|
158
|
+
/** Owner-only live Agent policy used when modelSource is agent. */
|
|
159
|
+
agentDefaultModelId?: string | null;
|
|
160
|
+
/** Owner-only live Agent prompt applied at the start of the next run. */
|
|
161
|
+
agentSystemPrompt?: string | null;
|
|
156
162
|
managerDefaultWorkerAgentType?: AgentType | null;
|
|
157
163
|
managerDefaultWorkerModelId?: string | null;
|
|
158
164
|
title: string;
|
|
@@ -181,6 +187,7 @@ export type ChatSendParams = {
|
|
|
181
187
|
workDir: string;
|
|
182
188
|
agentSessionId?: string | null;
|
|
183
189
|
modelId?: string;
|
|
190
|
+
systemPrompt?: string | null;
|
|
184
191
|
managerDefaultWorkerAgentType?: AgentType | null;
|
|
185
192
|
managerDefaultWorkerModelId?: string | null;
|
|
186
193
|
reasoningEffort?: string | null;
|
|
@@ -203,6 +210,7 @@ export type QueuedChatMessage = {
|
|
|
203
210
|
workDir: string;
|
|
204
211
|
agentSessionId?: string | null;
|
|
205
212
|
modelId?: string | null;
|
|
213
|
+
systemPrompt?: string | null;
|
|
206
214
|
reasoningEffort?: string | null;
|
|
207
215
|
clientMessageId?: string | null;
|
|
208
216
|
attachments?: Array<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAA;AAElE,MAAM,MAAM,gBAAgB,
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,16 @@
|
|
|
1
|
-
export const DISABLED_BUILTIN_AGENT_TYPES = [
|
|
2
|
-
|
|
1
|
+
export const DISABLED_BUILTIN_AGENT_TYPES = [
|
|
2
|
+
'openclaw',
|
|
3
|
+
];
|
|
4
|
+
export const AVAILABLE_BUILTIN_AGENT_TYPES = [
|
|
5
|
+
'claude',
|
|
6
|
+
'codex',
|
|
7
|
+
'workbuddy',
|
|
8
|
+
'gemini',
|
|
9
|
+
'cursor',
|
|
10
|
+
'opencode',
|
|
11
|
+
'pi',
|
|
12
|
+
'manager',
|
|
13
|
+
];
|
|
3
14
|
const AVAILABLE_BUILTIN_AGENT_TYPE_SET = new Set(AVAILABLE_BUILTIN_AGENT_TYPES);
|
|
4
15
|
export function isAvailableBuiltinAgentType(value) {
|
|
5
16
|
return AVAILABLE_BUILTIN_AGENT_TYPE_SET.has(value);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAeA,MAAM,CAAC,MAAM,4BAA4B,GAAG;IAC1C,UAAU;CACoC,CAAA;AAChD,MAAM,CAAC,MAAM,6BAA6B,GAAG;IAC3C,QAAQ;IACR,OAAO;IACP,WAAW;IACX,QAAQ;IACR,QAAQ;IACR,UAAU;IACV,IAAI;IACJ,SAAS;CACqC,CAAA;AAEhD,MAAM,gCAAgC,GAAG,IAAI,GAAG,CAAmB,6BAA6B,CAAC,CAAA;AAqDjG,MAAM,UAAU,2BAA2B,CAAC,KAAa;IACvD,OAAO,gCAAgC,CAAC,GAAG,CAAC,KAAyB,CAAC,CAAA;AACxE,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,KAAa;IAChD,OAAO,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,2BAA2B,CAAC,KAAK,CAAC,CAAA;AAC1E,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,MAAyB;IACjE,MAAM,QAAQ,GAAgB,EAAE,CAAA;IAChC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAa,CAAA;IAEjC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,CAAC,oBAAoB,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;YAAE,SAAQ;QAC7D,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QACf,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACtB,CAAC;IAED,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,MAA6B;IACrE,IAAI,CAAC,MAAM,EAAE,MAAM;QAAE,OAAO,EAAE,CAAA;IAE9B,MAAM,QAAQ,GAAgB,EAAE,CAAA;IAChC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAa,CAAA;IAEjC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,CAAC,oBAAoB,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,SAAQ;QACvE,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACpB,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACtB,CAAC;IAED,OAAO,QAAQ,CAAA;AACjB,CAAC"}
|