shennian 0.3.29 → 0.3.30
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.
|
@@ -2,6 +2,7 @@ import type { ChatAttachmentMeta, ExternalChannelSessionStatus, SessionRunPhase
|
|
|
2
2
|
import { AgentAdapter, type AgentSendContext } from './adapter.js';
|
|
3
3
|
export declare function normalizeWorkBuddyModelId(modelId?: string | null): string | undefined;
|
|
4
4
|
export declare function normalizeWorkBuddyReasoningEffort(value?: string | null): string | undefined;
|
|
5
|
+
export declare function workBuddySystemPromptArgs(systemPrompt: string | null, platform: NodeJS.Platform, promptFile?: string): string[];
|
|
5
6
|
export declare class WorkBuddyAdapter extends AgentAdapter {
|
|
6
7
|
readonly type: "workbuddy";
|
|
7
8
|
private process;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{createInterface as
|
|
1
|
+
import{createInterface as y}from"node:readline";import{randomUUID as I}from"node:crypto";import{AgentAdapter as k,registerAgent as w}from"./adapter.js";import{resolveBuiltinCommand as S,spawnAgentCommand as x}from"./command-spec.js";import{buildAgentProcessEnv as _}from"../agent-env.js";import{buildPlatformInstructions as E,ensurePlatformInstructionsFile as B}from"./platform-instructions.js";import{ensureWorkBuddyRoomPluginBundle as P}from"../integrations/workbuddy-plugin-bundle.js";import{roomMcpHostToolName as T}from"../integrations/room-plugin-shared.js";const W=new Set(["minimal","low","medium","high","xhigh","max"]);function C(n){const t=n?.trim();return t&&t!=="auto"?t:void 0}function A(n){const t=n?.trim();if(t){if(W.has(t))return t;throw new Error(`Unsupported WorkBuddy reasoning effort "${t}". Supported values: minimal, low, medium, high, xhigh, max.`)}}function D(n,t,e){if(!n)return[];if(t==="win32"){if(!e)throw new Error("WorkBuddy system prompt file is required on Windows.");return["--system-prompt-file",e]}return["--append-system-prompt",n]}class O extends k{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,e,s){this.workDir=e,this.seq=0,s&&(this.agentSessionId=s)}async send(t,e,s,o,a,i){await this.killProcess(),this.runId=I(),this.resetRunState();const u=i?.source==="room_activation",r=["-p",t,"--output-format","stream-json","--verbose","--permission-mode",u?"dontAsk":"auto","--setting-sources","user,project,local"],h=C(e);h&&r.push("--model",h);const m=P(),l=T("workbuddy");u?r.push("--allowedTools",l,"--tools",`NoDefer(${l})`,"--mcp-config",m.mcpFile,"--strict-mcp-config","--disallowedTools","mcp__shennian_room__shennian_agent","--max-turns","2"):r.push("--allowedTools",l,"--tools",`*,NoDefer(${l})`),r.push("--plugin-dir",m.pluginRoot);const p=this.shennianSessionId?.startsWith("room-managed-")&&!this.agentSessionId&&!u?null:E(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,a);if(p){const g=process.platform==="win32"?B(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,a):void 0;r.push(...D(p,process.platform,g))}const f=A(s);f&&r.push("--effort",f),this.agentSessionId&&r.push("--resume",this.agentSessionId),this.spawnAndParse(r)}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 e=S("workbuddy");if(!e){this.emit("error",new Error("WorkBuddy was not found. Install WorkBuddy Desktop or the CodeBuddy CLI, then retry."));return}const s=x(e,t,{cwd:this.workDir??void 0,stdio:["ignore","pipe","pipe"],env:_(this.extraEnv)});this.process=s,y({input:s.stdout}).on("line",i=>{if(i.trim())try{this.handleStreamEvent(JSON.parse(i))}catch{}});let a="";s.stderr?.on("data",i=>{a=`${a}${i.toString()}`.slice(-8e3)}),s.on("close",i=>{this.process===s&&(this.process=null,this.runPhase=null,this.handleProcessClose(i,a))}),s.on("error",i=>{if(this.process!==s)return;this.process=null,this.runPhase=null;const u=i.code==="ENOENT";this.emitErrorIfOpen({state:"error",message:u?"WorkBuddy was not found. Install WorkBuddy Desktop or the CodeBuddy CLI, then retry.":d(i.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 s=t.message?.content;if(s?.length)for(const o of s)this.handleContentBlock(o);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:c(t.content)});return}if(t.subtype==="error"||t.error){this.emitErrorIfOpen({state:"error",message:d(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 e=t.usage??t.message?.usage;this.emitFinalIfOpen({state:"final",agentSessionId:this.agentSessionId??void 0,usage:e?{inputTokens:e.input_tokens??0,outputTokens:e.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:c(t.content)})}emitText(t,e){this.runPhase=e?"thinking":"streaming_text";const s=!e&&this.hasEmittedText?`
|
|
2
2
|
|
|
3
|
-
`:"";this.emitEvent({state:"delta",text:
|
|
3
|
+
`:"";this.emitEvent({state:"delta",text:s+t,thinking:e||void 0}),e||(this.hasEmittedText=!0)}handleProcessClose(t,e){if(t!==0&&t!==null){this.emitErrorIfOpen({state:"error",message:d(e)||`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(e=>{let s=!1;const o=()=>{s||(s=!0,e())};t.once("close",o),setTimeout(()=>{t.kill("SIGKILL"),o()},3e3).unref?.()}))}}function c(n){if(typeof n=="string")return n;try{return JSON.stringify(n)}catch{return"[unserializable WorkBuddy tool result]"}}function d(n){return n.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)}w("workbuddy",()=>new O);export{O as WorkBuddyAdapter,C as normalizeWorkBuddyModelId,A as normalizeWorkBuddyReasoningEffort,d as sanitizeWorkBuddyError,D as workBuddySystemPromptArgs};
|