shennian 0.2.137 → 0.3.1

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.
@@ -131,8 +131,8 @@
131
131
  },
132
132
  {
133
133
  "file": "src/agents/pi.js",
134
- "beforeBytes": 31836,
135
- "afterBytes": 15039
134
+ "beforeBytes": 32860,
135
+ "afterBytes": 15955
136
136
  },
137
137
  {
138
138
  "file": "src/agents/platform-instructions.js",
@@ -601,8 +601,8 @@
601
601
  },
602
602
  {
603
603
  "file": "src/session/handlers/chat.js",
604
- "beforeBytes": 31287,
605
- "afterBytes": 14096
604
+ "beforeBytes": 31078,
605
+ "afterBytes": 13839
606
606
  },
607
607
  {
608
608
  "file": "src/session/handlers/control.js",
@@ -1,6 +1,7 @@
1
1
  import { AgentAdapter } from './adapter.js';
2
2
  import type { ExternalChannelSessionStatus } from '@shennian/wire';
3
3
  export { buildShellCommandSpec } from './pi-context.js';
4
+ export declare function formatNianHostedModelError(message: string): string;
4
5
  export declare class PiAdapter extends AgentAdapter {
5
6
  readonly type: "pi";
6
7
  private agent;
@@ -1,17 +1,17 @@
1
- import{randomUUID as b}from"node:crypto";import l from"node:fs";import g from"node:path";import{execFile as _}from"node:child_process";import{promisify as A}from"node:util";import{Agent as I,streamProxy as T}from"@mariozechner/pi-agent-core";import{streamOpenAICompletions as j}from"@mariozechner/pi-ai/openai-completions";import{Type as p}from"@sinclair/typebox";import{AgentAdapter as D,registerAgent as $}from"./adapter.js";import{buildExternalChannelInstructions as F}from"./external-channel-instructions.js";import{loadConfig as L}from"../config/index.js";import{getManagedAgentProviderConfig as O}from"./config-status.js";import{SERVERS as N}from"../region.js";import{buildAgentProcessEnv as q}from"../agent-env.js";import{buildRollingSummary as E,buildShellCommandSpec as P,cloneMessages as S,CONTEXT_TOKEN_THRESHOLD as v,createPiModel as M,estimateTokens as w,getSessionDir as z,KEEP_RECENT_MESSAGES as k,LEGACY_SUMMARY_FILENAME as R,loadAgentsMdInstructions as U,longestCommonPrefixLength as B,MESSAGES_FILENAME as K,messagesToText as G,PI_DEFAULT_MODEL_ID as J,requestProxySummary as H,SNAPSHOT_FILENAME as Y,SYSTEM_PROMPT as W,SUMMARY_FILENAME as V}from"./pi-context.js";import{buildShellCommandSpec as Mt}from"./pi-context.js";const X=A(_),Q="https://dashscope.aliyuncs.com/compatible-mode/v1";function y(o,t){return g.resolve(o,t)}async function Z(o,t,e,s){const n=P(t),{stdout:i,stderr:a}=await X(n.file,n.args,{cwd:o,env:q(e),timeout:3e4,signal:s,maxBuffer:1024*1024,windowsHide:!0});return{stdout:i,stderr:a,shell:n.shell}}function C(o){return typeof o=="string"?o:Buffer.isBuffer(o)?o.toString("utf8"):""}function tt(o){if(!o||typeof o!="object")return String(o);const t=o,e=[t.message||String(o)],s=C(t.stdout).trim(),n=C(t.stderr).trim();return s&&e.push(`---stdout---
1
+ import{randomUUID as _}from"node:crypto";import l from"node:fs";import g from"node:path";import{execFile as A}from"node:child_process";import{promisify as T}from"node:util";import{Agent as I,streamProxy as j}from"@mariozechner/pi-agent-core";import{streamOpenAICompletions as D}from"@mariozechner/pi-ai/openai-completions";import{Type as p}from"@sinclair/typebox";import{AgentAdapter as $,registerAgent as F}from"./adapter.js";import{buildExternalChannelInstructions as L}from"./external-channel-instructions.js";import{loadConfig as N}from"../config/index.js";import{getManagedAgentProviderConfig as O}from"./config-status.js";import{SERVERS as z}from"../region.js";import{buildAgentProcessEnv as R}from"../agent-env.js";import{buildRollingSummary as E,buildShellCommandSpec as P,cloneMessages as f,CONTEXT_TOKEN_THRESHOLD as v,createPiModel as M,estimateTokens as w,getSessionDir as q,KEEP_RECENT_MESSAGES as k,LEGACY_SUMMARY_FILENAME as U,loadAgentsMdInstructions as B,longestCommonPrefixLength as K,MESSAGES_FILENAME as G,messagesToText as J,PI_DEFAULT_MODEL_ID as H,requestProxySummary as Y,SNAPSHOT_FILENAME as W,SYSTEM_PROMPT as V,SUMMARY_FILENAME as X}from"./pi-context.js";import{buildShellCommandSpec as Et}from"./pi-context.js";const Q=T(A),Z="https://dashscope.aliyuncs.com/compatible-mode/v1";function C(r){return r.includes("entitlement_required")?"\u5F53\u524D\u8D26\u53F7\u5C1A\u672A\u5F00\u901A Nian \u6258\u7BA1\u6A21\u578B\u3002\u8BF7\u524D\u5F80\u795E\u5FF5\u300C\u5957\u9910\u4E0E\u652F\u4ED8\u300D\u5F00\u901A Pro \u6216 Team\uFF0C\u83B7\u5F97\u79EF\u5206\u540E\u91CD\u8BD5\u3002":r.includes("insufficient_credits")?"\u79EF\u5206\u4E0D\u8DB3\uFF0CNian \u6682\u65F6\u65E0\u6CD5\u56DE\u590D\u3002\u8BF7\u524D\u5F80\u795E\u5FF5\u300C\u5957\u9910\u4E0E\u652F\u4ED8\u300D\u8D2D\u4E70\u79EF\u5206\u5305\u540E\u91CD\u8BD5\u3002":r.includes("429")||r.includes("daily_quota_exceeded")||r.includes("nian_quota_exceeded")?r.includes("too quickly")||r.includes("per minute")?"Nian \u8BF7\u6C42\u8FC7\u4E8E\u9891\u7E41\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5\u3002":"Nian \u4ECA\u65E5\u989D\u5EA6\u5DF2\u7528\u5B8C\uFF0C\u6B21\u65E5\u81EA\u52A8\u6062\u590D\u3002":r}function y(r,t){return g.resolve(r,t)}async function tt(r,t,e,s){const n=P(t),{stdout:i,stderr:o}=await Q(n.file,n.args,{cwd:r,env:R(e),timeout:3e4,signal:s,maxBuffer:1024*1024,windowsHide:!0});return{stdout:i,stderr:o,shell:n.shell}}function b(r){return typeof r=="string"?r:Buffer.isBuffer(r)?r.toString("utf8"):""}function et(r){if(!r||typeof r!="object")return String(r);const t=r,e=[t.message||String(r)],s=b(t.stdout).trim(),n=b(t.stderr).trim();return s&&e.push(`---stdout---
2
2
  ${s}`),n&&e.push(`---stderr---
3
3
  ${n}`),t.code!==void 0&&e.push(`exitCode: ${String(t.code)}`),t.signal&&e.push(`signal: ${t.signal}`),e.join(`
4
- `)}function et(o,t={}){return[{name:"read_file",label:"\u8BFB\u53D6\u6587\u4EF6",description:"Read the full content of a file at the given path.",parameters:p.Object({path:p.String({description:"Absolute or relative file path"})}),async execute(e,{path:s}){let n="";try{return n=y(o,s),{content:[{type:"text",text:l.readFileSync(n,"utf-8")}],details:{path:n}}}catch(i){return{content:[{type:"text",text:`Error: ${i instanceof Error?i.message:String(i)}`}],details:{path:n}}}}},{name:"write_file",label:"\u5199\u5165\u6587\u4EF6",description:"Write content to a file, creating it or overwriting if it exists.",parameters:p.Object({path:p.String({description:"Absolute or relative file path"}),content:p.String({description:"File content to write"})}),async execute(e,{path:s,content:n}){let i="";try{return i=y(o,s),l.mkdirSync(g.dirname(i),{recursive:!0}),l.writeFileSync(i,n,"utf-8"),{content:[{type:"text",text:`Written ${n.length} bytes to ${i}`}],details:{path:i}}}catch(a){return{content:[{type:"text",text:`Error: ${a instanceof Error?a.message:String(a)}`}],details:{path:i}}}}},{name:"list_directory",label:"\u5217\u51FA\u76EE\u5F55",description:"List files and directories at the given path.",parameters:p.Object({path:p.String({description:"Directory path to list",default:"."})}),async execute(e,{path:s}){let n="";try{return n=y(o,s),{content:[{type:"text",text:l.readdirSync(n,{withFileTypes:!0}).map(h=>`${h.isDirectory()?"d":"f"} ${h.name}`).join(`
5
- `)||"(empty)"}],details:{path:n}}}catch(i){return{content:[{type:"text",text:`Error: ${i instanceof Error?i.message:String(i)}`}],details:{path:n}}}}},{name:"bash",label:"\u6267\u884C\u547D\u4EE4",description:"Execute a shell command in the working directory. Uses PowerShell on Windows and bash on macOS/Linux. Timeout: 30s.",parameters:p.Object({command:p.String({description:"Shell command to execute"})}),async execute(e,{command:s},n){try{const{stdout:i,stderr:a,shell:h}=await Z(o,s,t,n);return{content:[{type:"text",text:[i,a].filter(Boolean).join(`
4
+ `)}function st(r,t={}){return[{name:"read_file",label:"\u8BFB\u53D6\u6587\u4EF6",description:"Read the full content of a file at the given path.",parameters:p.Object({path:p.String({description:"Absolute or relative file path"})}),async execute(e,{path:s}){let n="";try{return n=y(r,s),{content:[{type:"text",text:l.readFileSync(n,"utf-8")}],details:{path:n}}}catch(i){return{content:[{type:"text",text:`Error: ${i instanceof Error?i.message:String(i)}`}],details:{path:n}}}}},{name:"write_file",label:"\u5199\u5165\u6587\u4EF6",description:"Write content to a file, creating it or overwriting if it exists.",parameters:p.Object({path:p.String({description:"Absolute or relative file path"}),content:p.String({description:"File content to write"})}),async execute(e,{path:s,content:n}){let i="";try{return i=y(r,s),l.mkdirSync(g.dirname(i),{recursive:!0}),l.writeFileSync(i,n,"utf-8"),{content:[{type:"text",text:`Written ${n.length} bytes to ${i}`}],details:{path:i}}}catch(o){return{content:[{type:"text",text:`Error: ${o instanceof Error?o.message:String(o)}`}],details:{path:i}}}}},{name:"list_directory",label:"\u5217\u51FA\u76EE\u5F55",description:"List files and directories at the given path.",parameters:p.Object({path:p.String({description:"Directory path to list",default:"."})}),async execute(e,{path:s}){let n="";try{return n=y(r,s),{content:[{type:"text",text:l.readdirSync(n,{withFileTypes:!0}).map(h=>`${h.isDirectory()?"d":"f"} ${h.name}`).join(`
5
+ `)||"(empty)"}],details:{path:n}}}catch(i){return{content:[{type:"text",text:`Error: ${i instanceof Error?i.message:String(i)}`}],details:{path:n}}}}},{name:"bash",label:"\u6267\u884C\u547D\u4EE4",description:"Execute a shell command in the working directory. Uses PowerShell on Windows and bash on macOS/Linux. Timeout: 30s.",parameters:p.Object({command:p.String({description:"Shell command to execute"})}),async execute(e,{command:s},n){try{const{stdout:i,stderr:o,shell:h}=await tt(r,s,t,n);return{content:[{type:"text",text:[i,o].filter(Boolean).join(`
6
6
  ---stderr---
7
- `)||"(no output)"}],details:{command:s,shell:h}}}catch(i){return{content:[{type:"text",text:`Error: ${tt(i)}`}],details:{command:s,shell:P(s).shell}}}}},{name:"read_image",label:"\u8BFB\u53D6\u56FE\u7247",description:"Read an image file and return its content for visual analysis. Supports png, jpg, jpeg, gif, webp. Max 10 MB.",parameters:p.Object({path:p.String({description:"Absolute or relative path to the image file"})}),async execute(e,{path:s}){let n;try{n=y(o,s)}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:String(r)}`}],details:{path:s}}}const i=g.extname(n).toLowerCase().slice(1),h={png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",webp:"image/webp"}[i];if(!h)return{content:[{type:"text",text:`Error: unsupported image type ".${i}". Supported: png, jpg, jpeg, gif, webp`}],details:{path:n}};try{const r=l.statSync(n);return r.size>10*1024*1024?{content:[{type:"text",text:`Error: image too large (${(r.size/1024/1024).toFixed(1)} MB, max 10 MB)`}],details:{path:n}}:{content:[{type:"image",data:l.readFileSync(n).toString("base64"),mimeType:h}],details:{path:n,mimeType:h,size:r.size}}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:String(r)}`}],details:{path:n}}}}}]}class st extends D{type="pi";agent=null;sessionId=null;workDir=null;seq=0;runId="";emittedLengths=new Map;terminalState="open";authToken=null;proxyUrl=null;providerConfig;sessionDir=null;messagesPath=null;snapshotPath=null;summaryPath=null;cachedSummary=null;restoredMessages=[];compressing=!1;lastSummaryMsgCount=0;pendingBaseMessages=[];finalizePromise=Promise.resolve();sendGeneration=0;externalChannel=null;shennianSessionId=null;extraEnv={};pendingSendStart=null;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,this.sessionDir=z(t),this.messagesPath=g.join(this.sessionDir,K),this.snapshotPath=g.join(this.sessionDir,Y),this.summaryPath=g.join(this.sessionDir,V),this.loadSnapshot(),this.loadSummary()}async send(t,e){const s=++this.sendGeneration,n=this.agent&&this.terminalState==="open"?S(this.pendingBaseMessages):null;n&&(this.agent?.abort(),this.agent=null,this.restoredMessages=n,this.finalizePromise=Promise.resolve());const i=L(),a=i.machineToken??i.accessToken;if(!a){this.emit("agentEvent",{state:"error",runId:this.runId,seq:++this.seq,message:"\u672A\u914D\u5BF9\uFF0C\u8BF7\u5148\u8FD0\u884C shennian \u5B8C\u6210\u673A\u5668\u914D\u5BF9"});return}this.authToken=a,this.proxyUrl=(i.serverUrl??N.cn.url).replace(/\/$/,"");const h=O("pi"),r=i.apiKeys?.dashscope?.trim();this.providerConfig=h??(r?{agent:"pi",token:r,updatedAt:""}:void 0),this.runId=b(),this.seq=0,this.emittedLengths.clear(),this.terminalState="open",this.agent||this.initAgent(),await this.finalizePromise.catch(()=>{}),this.agent?.setModel(M(e??J)),this.pendingBaseMessages=S(this.agent?.state.messages??[]);const d=this.runId,m=new Promise((c,u)=>{this.pendingSendStart={runId:d,resolve:c,reject:u}});this.emit("agentEvent",{state:"init",runId:d,seq:++this.seq}),this.agent.prompt(t).then(async()=>{s===this.sendGeneration&&(this.resolvePendingSendStart(d),await this.finalizePromise.catch(()=>{}))}).catch(c=>{if(s!==this.sendGeneration||(this.rejectPendingSendStart(d,c),this.terminalState!=="open"))return;this.terminalState="error";const u=c instanceof Error?c.message:String(c);u.includes("429")||u.includes("daily_quota_exceeded")||u.includes("nian_quota_exceeded")?this.emit("agentEvent",{state:"error",runId:d,seq:++this.seq,message:"Nian \u4ECA\u65E5\u989D\u5EA6\u5DF2\u7528\u5B8C\uFF0C\u6B21\u65E5\u81EA\u52A8\u6062\u590D\u3002"}):this.emit("agentEvent",{state:"error",runId:d,seq:++this.seq,message:u})}),await m}async getStatus(){const t=!!(this.runId&&this.terminalState==="open");return{active:t,runId:this.runId||null,runPhase:null,canStop:t}}initAgent(){const t=this.workDir??process.cwd(),e=et(t,this.extraEnv),s=U(t),n=new I({initialState:{systemPrompt:[W,s,`\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\uFF1A${t}`,F(this.externalChannel,t,this.shennianSessionId??void 0)].filter(Boolean).join(`
7
+ `)||"(no output)"}],details:{command:s,shell:h}}}catch(i){return{content:[{type:"text",text:`Error: ${et(i)}`}],details:{command:s,shell:P(s).shell}}}}},{name:"read_image",label:"\u8BFB\u53D6\u56FE\u7247",description:"Read an image file and return its content for visual analysis. Supports png, jpg, jpeg, gif, webp. Max 10 MB.",parameters:p.Object({path:p.String({description:"Absolute or relative path to the image file"})}),async execute(e,{path:s}){let n;try{n=y(r,s)}catch(a){return{content:[{type:"text",text:`Error: ${a instanceof Error?a.message:String(a)}`}],details:{path:s}}}const i=g.extname(n).toLowerCase().slice(1),h={png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",webp:"image/webp"}[i];if(!h)return{content:[{type:"text",text:`Error: unsupported image type ".${i}". Supported: png, jpg, jpeg, gif, webp`}],details:{path:n}};try{const a=l.statSync(n);return a.size>10*1024*1024?{content:[{type:"text",text:`Error: image too large (${(a.size/1024/1024).toFixed(1)} MB, max 10 MB)`}],details:{path:n}}:{content:[{type:"image",data:l.readFileSync(n).toString("base64"),mimeType:h}],details:{path:n,mimeType:h,size:a.size}}}catch(a){return{content:[{type:"text",text:`Error: ${a instanceof Error?a.message:String(a)}`}],details:{path:n}}}}}]}class nt extends ${type="pi";agent=null;sessionId=null;workDir=null;seq=0;runId="";emittedLengths=new Map;terminalState="open";authToken=null;proxyUrl=null;providerConfig;sessionDir=null;messagesPath=null;snapshotPath=null;summaryPath=null;cachedSummary=null;restoredMessages=[];compressing=!1;lastSummaryMsgCount=0;pendingBaseMessages=[];finalizePromise=Promise.resolve();sendGeneration=0;externalChannel=null;shennianSessionId=null;extraEnv={};pendingSendStart=null;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,this.sessionDir=q(t),this.messagesPath=g.join(this.sessionDir,G),this.snapshotPath=g.join(this.sessionDir,W),this.summaryPath=g.join(this.sessionDir,X),this.loadSnapshot(),this.loadSummary()}async send(t,e){const s=++this.sendGeneration,n=this.agent&&this.terminalState==="open"?f(this.pendingBaseMessages):null;n&&(this.agent?.abort(),this.agent=null,this.restoredMessages=n,this.finalizePromise=Promise.resolve());const i=N(),o=i.machineToken??i.accessToken;if(!o){this.emit("agentEvent",{state:"error",runId:this.runId,seq:++this.seq,message:"\u672A\u914D\u5BF9\uFF0C\u8BF7\u5148\u8FD0\u884C shennian \u5B8C\u6210\u673A\u5668\u914D\u5BF9"});return}this.authToken=o,this.proxyUrl=(i.serverUrl??z.cn.url).replace(/\/$/,"");const h=O("pi"),a=i.apiKeys?.dashscope?.trim();this.providerConfig=h??(a?{agent:"pi",token:a,updatedAt:""}:void 0),this.runId=_(),this.seq=0,this.emittedLengths.clear(),this.terminalState="open",this.agent||this.initAgent(),await this.finalizePromise.catch(()=>{}),this.agent?.setModel(M(e??H)),this.pendingBaseMessages=f(this.agent?.state.messages??[]);const u=this.runId,m=new Promise((c,d)=>{this.pendingSendStart={runId:u,resolve:c,reject:d}});this.emit("agentEvent",{state:"init",runId:u,seq:++this.seq}),this.agent.prompt(t).then(async()=>{s===this.sendGeneration&&(this.resolvePendingSendStart(u),await this.finalizePromise.catch(()=>{}))}).catch(c=>{if(s!==this.sendGeneration||(this.rejectPendingSendStart(u,c),this.terminalState!=="open"))return;this.terminalState="error";const d=c instanceof Error?c.message:String(c);this.emit("agentEvent",{state:"error",runId:u,seq:++this.seq,message:C(d)})}),await m}async getStatus(){const t=!!(this.runId&&this.terminalState==="open");return{active:t,runId:this.runId||null,runPhase:null,canStop:t}}initAgent(){const t=this.workDir??process.cwd(),e=st(t,this.extraEnv),s=B(t),n=new I({initialState:{systemPrompt:[V,s,`\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\uFF1A${t}`,L(this.externalChannel,t,this.shennianSessionId??void 0)].filter(Boolean).join(`
8
8
 
9
- `),model:M(),tools:e},streamFn:(i,a,h)=>{const r=this.providerConfig;return r?.token?j(M(i.id,{provider:"dashscope",baseUrl:r.baseUrl||Q,compat:{supportsDeveloperRole:!1,supportsStore:!1,supportsReasoningEffort:!1,maxTokensField:"max_tokens",thinkingFormat:"qwen"}}),a,{...h,apiKey:r.token}):T(i,a,{...h,authToken:this.authToken,proxyUrl:this.proxyUrl})},transformContext:i=>this.compressContext(i)});this.agent=n,this.restoredMessages.length>0?n.replaceMessages(S(this.restoredMessages)):this.cachedSummary&&(n.appendMessage({role:"user",content:[{type:"text",text:`[\u4E4B\u524D\u7684\u5BF9\u8BDD\u6458\u8981]
10
- ${this.cachedSummary}`}],timestamp:Date.now()}),n.appendMessage({role:"assistant",content:[{type:"text",text:"\u597D\u7684\uFF0C\u6211\u5DF2\u4E86\u89E3\u4E4B\u524D\u7684\u5BF9\u8BDD\u4E0A\u4E0B\u6587\uFF0C\u8BF7\u7EE7\u7EED\u3002"}],timestamp:Date.now()})),n.subscribe(i=>{if(this.agent!==n||this.terminalState!=="open")return;const a=++this.seq,h=this.runId;switch(i.type){case"agent_start":this.resolvePendingSendStart(h),this.emit("agentEvent",{state:"start",runId:h,seq:a});break;case"message_update":{const r=i.message;if(r.role!=="assistant")break;const d=r.content??[];for(let m=0;m<d.length;m++){const c=d[m];if(c.type==="text"&&c.text){const u=`text:${m}`,f=this.emittedLengths.get(u)??0;if(c.text.length>f){const x=c.text.slice(f);this.emittedLengths.set(u,c.text.length),this.emit("agentEvent",{state:"delta",runId:h,seq:a,text:x})}}else if(c.type==="thinking"&&c.thinking){const u=`thinking:${m}`,f=this.emittedLengths.get(u)??0;if(c.thinking.length>f){const x=c.thinking.slice(f);this.emittedLengths.set(u,c.thinking.length),this.emit("agentEvent",{state:"delta",runId:h,seq:a,text:x,thinking:!0})}}}break}case"tool_execution_start":this.emit("agentEvent",{state:"tool-call",runId:h,seq:a,name:i.toolName,args:i.args});break;case"tool_execution_end":this.emit("agentEvent",{state:"tool-result",runId:h,seq:a,name:i.toolName,result:typeof i.result=="string"?i.result:JSON.stringify(i.result)});break;case"agent_end":{this.terminalState="final";const r=i.messages,m=[...r].reverse().find(c=>c.role==="assistant")?.usage;this.emit("agentEvent",{state:"final",runId:h,seq:a,usage:m?{inputTokens:m.input??0,outputTokens:m.output??0}:void 0}),this.finalizePromise=this.finalizeTurn(r);break}}})}async compressAndReplace(){if(!this.agent||this.compressing)return;const t=this.agent.state.messages;if(w(t)<v)return;const s=this.splitMessages(t);if(!s)return;const n=await this.generateSummary(s.toCompress);if(!n)return;this.cachedSummary=n,this.lastSummaryMsgCount+=s.toCompress.length;const i=[{role:"user",content:[{type:"text",text:`[\u5386\u53F2\u5BF9\u8BDD\u6458\u8981]
9
+ `),model:M(),tools:e},streamFn:(i,o,h)=>{const a=this.providerConfig;return a?.token?D(M(i.id,{provider:"dashscope",baseUrl:a.baseUrl||Z,compat:{supportsDeveloperRole:!1,supportsStore:!1,supportsReasoningEffort:!1,maxTokensField:"max_tokens",thinkingFormat:"qwen"}}),o,{...h,apiKey:a.token}):j(i,o,{...h,authToken:this.authToken,proxyUrl:this.proxyUrl})},transformContext:i=>this.compressContext(i)});this.agent=n,this.restoredMessages.length>0?n.replaceMessages(f(this.restoredMessages)):this.cachedSummary&&(n.appendMessage({role:"user",content:[{type:"text",text:`[\u4E4B\u524D\u7684\u5BF9\u8BDD\u6458\u8981]
10
+ ${this.cachedSummary}`}],timestamp:Date.now()}),n.appendMessage({role:"assistant",content:[{type:"text",text:"\u597D\u7684\uFF0C\u6211\u5DF2\u4E86\u89E3\u4E4B\u524D\u7684\u5BF9\u8BDD\u4E0A\u4E0B\u6587\uFF0C\u8BF7\u7EE7\u7EED\u3002"}],timestamp:Date.now()})),n.subscribe(i=>{if(this.agent!==n||this.terminalState!=="open")return;const o=++this.seq,h=this.runId;switch(i.type){case"agent_start":this.resolvePendingSendStart(h),this.emit("agentEvent",{state:"start",runId:h,seq:o});break;case"message_update":{const a=i.message;if(a.role!=="assistant")break;const u=a.content??[];for(let m=0;m<u.length;m++){const c=u[m];if(c.type==="text"&&c.text){const d=`text:${m}`,S=this.emittedLengths.get(d)??0;if(c.text.length>S){const x=c.text.slice(S);this.emittedLengths.set(d,c.text.length),this.emit("agentEvent",{state:"delta",runId:h,seq:o,text:x})}}else if(c.type==="thinking"&&c.thinking){const d=`thinking:${m}`,S=this.emittedLengths.get(d)??0;if(c.thinking.length>S){const x=c.thinking.slice(S);this.emittedLengths.set(d,c.thinking.length),this.emit("agentEvent",{state:"delta",runId:h,seq:o,text:x,thinking:!0})}}}break}case"tool_execution_start":this.emit("agentEvent",{state:"tool-call",runId:h,seq:o,name:i.toolName,args:i.args});break;case"tool_execution_end":this.emit("agentEvent",{state:"tool-result",runId:h,seq:o,name:i.toolName,result:typeof i.result=="string"?i.result:JSON.stringify(i.result)});break;case"agent_end":{const a=i.messages,u=[...a].reverse().find(d=>d.role==="assistant"),m=u;if(m?.stopReason==="error"){this.terminalState="error",this.emit("agentEvent",{state:"error",runId:h,seq:o,message:C(m.errorMessage||"Nian \u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002")}),this.finalizePromise=this.finalizeTurn(a);break}this.terminalState="final";const c=u?.usage;this.emit("agentEvent",{state:"final",runId:h,seq:o,usage:c?{inputTokens:c.input??0,outputTokens:c.output??0}:void 0}),this.finalizePromise=this.finalizeTurn(a);break}}})}async compressAndReplace(){if(!this.agent||this.compressing)return;const t=this.agent.state.messages;if(w(t)<v)return;const s=this.splitMessages(t);if(!s)return;const n=await this.generateSummary(s.toCompress);if(!n)return;this.cachedSummary=n,this.lastSummaryMsgCount+=s.toCompress.length;const i=[{role:"user",content:[{type:"text",text:`[\u5386\u53F2\u5BF9\u8BDD\u6458\u8981]
11
11
  ${n}`}],timestamp:Date.now()},{role:"assistant",content:[{type:"text",text:"\u597D\u7684\uFF0C\u6211\u5DF2\u4E86\u89E3\u4E0A\u4E0B\u6587\u3002"}],timestamp:Date.now()},...s.toKeep];this.agent.replaceMessages(i)}async compressContext(t){if(w(t)<v||!this.cachedSummary)return t;const s=this.splitMessages(t);return s?[{role:"user",content:[{type:"text",text:`[\u5386\u53F2\u5BF9\u8BDD\u6458\u8981]
12
- ${this.cachedSummary}`}],timestamp:Date.now()},...s.toKeep]:t}splitMessages(t){const e=t.filter(n=>n.role!=="system");if(e.length<=k)return null;let s=e.length-k;for(;s>0&&e[s].role==="toolResult";)s--;return s<=0?null:{toCompress:e.slice(0,s),toKeep:e.slice(s)}}async generateSummary(t){if(!this.authToken||!this.proxyUrl||this.compressing)return this.cachedSummary;this.compressing=!0;try{const e=G(t);if(e.length<100)return null;const s=e.length>1e4?e.slice(0,1e4)+`
13
- ...(\u5DF2\u622A\u65AD)`:e;return await H(this.proxyUrl,this.authToken,`\u8BF7\u5C06\u4EE5\u4E0B\u5BF9\u8BDD\u5386\u53F2\u538B\u7F29\u4E3A\u7B80\u6D01\u6458\u8981\uFF0C\u4FDD\u7559\u5173\u952E\u4FE1\u606F\uFF1A\u8BA8\u8BBA\u7684\u6587\u4EF6\u548C\u76EE\u5F55\u3001\u505A\u51FA\u7684\u6280\u672F\u51B3\u5B9A\u3001\u5F53\u524D\u4EFB\u52A1\u8FDB\u5EA6\u3001\u672A\u5B8C\u6210\u7684\u5DE5\u4F5C\u3002\u6458\u8981\u63A7\u5236\u5728 300 \u5B57\u4EE5\u5185\u3002
12
+ ${this.cachedSummary}`}],timestamp:Date.now()},...s.toKeep]:t}splitMessages(t){const e=t.filter(n=>n.role!=="system");if(e.length<=k)return null;let s=e.length-k;for(;s>0&&e[s].role==="toolResult";)s--;return s<=0?null:{toCompress:e.slice(0,s),toKeep:e.slice(s)}}async generateSummary(t){if(!this.authToken||!this.proxyUrl||this.compressing)return this.cachedSummary;this.compressing=!0;try{const e=J(t);if(e.length<100)return null;const s=e.length>1e4?e.slice(0,1e4)+`
13
+ ...(\u5DF2\u622A\u65AD)`:e;return await Y(this.proxyUrl,this.authToken,`\u8BF7\u5C06\u4EE5\u4E0B\u5BF9\u8BDD\u5386\u53F2\u538B\u7F29\u4E3A\u7B80\u6D01\u6458\u8981\uFF0C\u4FDD\u7559\u5173\u952E\u4FE1\u606F\uFF1A\u8BA8\u8BBA\u7684\u6587\u4EF6\u548C\u76EE\u5F55\u3001\u505A\u51FA\u7684\u6280\u672F\u51B3\u5B9A\u3001\u5F53\u524D\u4EFB\u52A1\u8FDB\u5EA6\u3001\u672A\u5B8C\u6210\u7684\u5DE5\u4F5C\u3002\u6458\u8981\u63A7\u5236\u5728 300 \u5B57\u4EE5\u5185\u3002
14
14
 
15
- ${s}`)}catch{return this.cachedSummary}finally{this.compressing=!1}}loadSnapshot(){if(this.snapshotPath)try{const t=l.readFileSync(this.snapshotPath,"utf-8"),e=JSON.parse(t);this.restoredMessages=Array.isArray(e.messages)?e.messages:[],this.cachedSummary=e.summary??this.cachedSummary,this.lastSummaryMsgCount=e.summarizedCount??this.lastSummaryMsgCount}catch{this.restoredMessages=[]}}loadSummary(){if(this.summaryPath)try{const t=l.readFileSync(this.summaryPath,"utf-8"),e=JSON.parse(t);this.cachedSummary=e.summary??null,this.lastSummaryMsgCount=e.summarizedCount??0}catch{if(!this.sessionDir)return;try{const t=g.join(this.sessionDir,R),e=l.readFileSync(t,"utf-8"),s=JSON.parse(e);this.cachedSummary=s.summary??null,this.lastSummaryMsgCount=s.summarizedCount??0}catch{}}}saveSummary(t){if(this.summaryPath)try{l.mkdirSync(g.dirname(this.summaryPath),{recursive:!0});const e=E(this.cachedSummary,t);this.cachedSummary=e,l.writeFileSync(this.summaryPath,JSON.stringify({version:1,summary:e,summarizedCount:this.lastSummaryMsgCount,updatedAt:Date.now()},null,2))}catch{}}saveSnapshot(t){if(!(!this.snapshotPath||!this.sessionId||!this.workDir))try{l.mkdirSync(g.dirname(this.snapshotPath),{recursive:!0}),l.writeFileSync(this.snapshotPath,JSON.stringify({version:1,sessionId:this.sessionId,workDir:this.workDir,summary:this.cachedSummary,summarizedCount:this.lastSummaryMsgCount,messages:t,updatedAt:Date.now()},null,2)),this.restoredMessages=S(t)}catch{}}appendMessagesLog(t){if(!(!this.messagesPath||t.length===0))try{l.mkdirSync(g.dirname(this.messagesPath),{recursive:!0});const e=t.map(s=>JSON.stringify(s)).join(`
15
+ ${s}`)}catch{return this.cachedSummary}finally{this.compressing=!1}}loadSnapshot(){if(this.snapshotPath)try{const t=l.readFileSync(this.snapshotPath,"utf-8"),e=JSON.parse(t);this.restoredMessages=Array.isArray(e.messages)?e.messages:[],this.cachedSummary=e.summary??this.cachedSummary,this.lastSummaryMsgCount=e.summarizedCount??this.lastSummaryMsgCount}catch{this.restoredMessages=[]}}loadSummary(){if(this.summaryPath)try{const t=l.readFileSync(this.summaryPath,"utf-8"),e=JSON.parse(t);this.cachedSummary=e.summary??null,this.lastSummaryMsgCount=e.summarizedCount??0}catch{if(!this.sessionDir)return;try{const t=g.join(this.sessionDir,U),e=l.readFileSync(t,"utf-8"),s=JSON.parse(e);this.cachedSummary=s.summary??null,this.lastSummaryMsgCount=s.summarizedCount??0}catch{}}}saveSummary(t){if(this.summaryPath)try{l.mkdirSync(g.dirname(this.summaryPath),{recursive:!0});const e=E(this.cachedSummary,t);this.cachedSummary=e,l.writeFileSync(this.summaryPath,JSON.stringify({version:1,summary:e,summarizedCount:this.lastSummaryMsgCount,updatedAt:Date.now()},null,2))}catch{}}saveSnapshot(t){if(!(!this.snapshotPath||!this.sessionId||!this.workDir))try{l.mkdirSync(g.dirname(this.snapshotPath),{recursive:!0}),l.writeFileSync(this.snapshotPath,JSON.stringify({version:1,sessionId:this.sessionId,workDir:this.workDir,summary:this.cachedSummary,summarizedCount:this.lastSummaryMsgCount,messages:t,updatedAt:Date.now()},null,2)),this.restoredMessages=f(t)}catch{}}appendMessagesLog(t){if(!(!this.messagesPath||t.length===0))try{l.mkdirSync(g.dirname(this.messagesPath),{recursive:!0});const e=t.map(s=>JSON.stringify(s)).join(`
16
16
  `)+`
17
- `;l.appendFileSync(this.messagesPath,e,"utf-8")}catch{}}getTurnMessages(t){const e=B(this.pendingBaseMessages,t);return S(t.slice(e))}async finalizeTurn(t){const e=S(t),s=this.getTurnMessages(e);this.appendMessagesLog(s),await this.compressAndReplace();const n=this.agent?S(this.agent.state.messages):e;this.cachedSummary||(this.cachedSummary=E(null,e)),this.saveSummary(n),this.saveSnapshot(n)}async resume(t){this.loadSnapshot(),this.loadSummary(),this.agent&&this.restoredMessages.length>0&&this.agent.replaceMessages(S(this.restoredMessages))}async stop(){if(this.rejectPendingSendStart(this.runId,new Error("Pi run stopped before dispatch completed")),await this.finalizePromise.catch(()=>{}),this.agent){const t=S(this.agent.state.messages??[]);this.saveSummary(t),this.saveSnapshot(t)}this.agent?.abort(),this.agent=null}resolvePendingSendStart(t){if(!this.pendingSendStart||this.pendingSendStart.runId!==t)return;const{resolve:e}=this.pendingSendStart;this.pendingSendStart=null,e()}rejectPendingSendStart(t,e){if(!this.pendingSendStart||this.pendingSendStart.runId!==t)return;const{reject:s}=this.pendingSendStart;this.pendingSendStart=null,s(e)}}$("pi",()=>new st);export{st as PiAdapter,Mt as buildShellCommandSpec};
17
+ `;l.appendFileSync(this.messagesPath,e,"utf-8")}catch{}}getTurnMessages(t){const e=K(this.pendingBaseMessages,t);return f(t.slice(e))}async finalizeTurn(t){const e=f(t),s=this.getTurnMessages(e);this.appendMessagesLog(s),await this.compressAndReplace();const n=this.agent?f(this.agent.state.messages):e;this.cachedSummary||(this.cachedSummary=E(null,e)),this.saveSummary(n),this.saveSnapshot(n)}async resume(t){this.loadSnapshot(),this.loadSummary(),this.agent&&this.restoredMessages.length>0&&this.agent.replaceMessages(f(this.restoredMessages))}async stop(){if(this.rejectPendingSendStart(this.runId,new Error("Pi run stopped before dispatch completed")),await this.finalizePromise.catch(()=>{}),this.agent){const t=f(this.agent.state.messages??[]);this.saveSummary(t),this.saveSnapshot(t)}this.agent?.abort(),this.agent=null}resolvePendingSendStart(t){if(!this.pendingSendStart||this.pendingSendStart.runId!==t)return;const{resolve:e}=this.pendingSendStart;this.pendingSendStart=null,e()}rejectPendingSendStart(t,e){if(!this.pendingSendStart||this.pendingSendStart.runId!==t)return;const{reject:s}=this.pendingSendStart;this.pendingSendStart=null,s(e)}}F("pi",()=>new nt);export{nt as PiAdapter,Et as buildShellCommandSpec,C as formatNianHostedModelError};
@@ -1,2 +1,2 @@
1
- import F from"node:os";import{createAgent as H}from"../../agents/adapter.js";import{buildApprovalPendingPayload as O,buildUserMessagePayload as G}from"@shennian/wire";import{reportLog as x}from"../../log-reporter.js";import{lookupClaudeTranscriptCwd as U}from"../../native-fusion/parsers.js";import{appendMessage as A,recordSession as v}from"../store.js";import{mergeProjectedSessions as J}from"../projection.js";import{getManagerRuntimeService as Q}from"../../manager/runtime.js";import{buildManagedAgentEnv as K}from"../../agents/config-status.js";import{materializeRemoteChatAttachments as V}from"../remote-attachments.js";function X(t){if(!Array.isArray(t))return;const e=t.map(a=>{if(!a||typeof a!="object")return null;const s=a,d=typeof s.path=="string"?s.path:"",f=typeof s.name=="string"?s.name:"",l=typeof s.mimeType=="string"?s.mimeType:"";if(!d||!f||!l)return null;const i=typeof s.previewData=="string"&&s.previewData.trim()?s.previewData.trim():void 0;return{path:d,name:f,mimeType:l,kind:l.startsWith("image/")?"image":"file",...i?{previewData:i}:{}}}).filter(a=>a!=null);return e.length?e:void 0}function Y(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){const a=e instanceof Error?e.message:String(e);return t==="pi"&&(a.includes("429")||a.includes("daily_quota_exceeded")||a.includes("nian_quota_exceeded"))?a.includes("too quickly")||a.includes("per minute")?"Nian \u8BF7\u6C42\u8FC7\u4E8E\u9891\u7E41\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5\u3002":"Nian \u4ECA\u65E5\u989D\u5EA6\u5DF2\u7528\u5B8C\uFF0C\u6B21\u65E5\u81EA\u52A8\u6062\u590D\u3002":`Agent send failed: ${a}`}function B(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:j(t,e.sessionId,a.agentType)}}})}function ae(t,e){v({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:j(t,e.sessionId,e.agentType)}}})}function re(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 se(t){return!!(t?.configured??t?.connected)}function z(t){return K(t)}function W(t,e,a){return se(e)?{...Q()?.getInjectedEnv(t,null,process.cwd(),"external")??{},SHENNIAN_EXTERNAL_SESSION_ID:t,SHENNIAN_MANAGER_SESSION_ID:t,...a?.trim()?{SHENNIAN_EXTERNAL_REPLY_TARGET:a.trim()}:{}}:{}}function oe(t,e,a,s,d){t.configure?.({sessionId:e,externalChannel:s??null,env:{...z(a),...W(e,s,d)}})}function j(t,e,a){const s=t.sessions.get(e);return s?.externalChannel?s.externalChannel:a==="manager"?t.managerRuntime?.getExternalChannelStatus(e)??null:null}function le(t,e,a){if(t!=="claude"||!a)return e;const s=e.trim();return!!s&&s.startsWith("-")&&!s.includes("/")?U(a)??e:e}function ie(t,e,a,s){let d=null;function f(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 l(n){n?.heartbeatTimer&&(clearInterval(n.heartbeatTimer),n.heartbeatTimer=null)}function i(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 S(n){!n||n.heartbeatTimer||(n.heartbeatTimer=setInterval(()=>{i(n)},ee),n.heartbeatTimer.unref?.())}function E(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),T=te(n),R=n.state==="final"||n.state==="error"||n.state==="aborted";r&&(r.nextEventSeq=n.seq+1,R||(r.currentRunId=n.runId),!R&&T&&(r.currentRunPhase=T,S(r)),n.agentSessionId&&(r.agentSessionId=n.agentSessionId)),t.managerRuntime?.noteAgentEvent(e,n),n.state!=="delta"&&x({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:O(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 h=`${e}:${n.runId}`;if(n.state==="delta"&&!n.thinking&&n.text&&t.runTextAcc.set(h,(t.runTextAcc.get(h)??"")+n.text),n.agentSessionId&&n.agentSessionId!==d&&(d=n.agentSessionId,t.nativeFusion?.noteManagedSourceSession(e,B(a,n.source),n.agentSessionId),r&&v({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 p=n.text??"";if(!p)return;const k=!!n.thinking;r?.pendingTextEvent&&(r.pendingTextEvent.runId!==n.runId||r.pendingTextEvent.thinking!==k)&&E(r),r&&!r.pendingTextEvent&&(r.pendingTextEvent={runId:n.runId,seq:n.seq,text:"",thinking:k}),r?.pendingTextEvent&&(r.pendingTextEvent.text+=p,r.pendingTextEvent.seq=n.seq);return}let m={};if(n.state==="final"){E(r);const p=t.runTextAcc.get(h)??"";p&&(m={messageSummary:Y(p)}),t.runTextAcc.delete(h)}else n.state==="error"||n.state==="aborted"?(E(r),t.runTextAcc.delete(h)):(n.state==="tool-call"||n.state==="tool-result"||n.state==="approval-pending")&&E(r);R&&r?.currentRunId===n.runId&&(r.currentRunId=null,r.currentRunPhase=null,r.nextEventSeq=0,l(r),t.chatQueue?.noteTerminal(e)),f(n,m)}),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 de(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 ce(t,e,a,s,d,f,l){t.evictIdleSessions();const i=H(a);if(!i)throw new Error(`Unsupported agent: ${a}`);oe(i,e,a,f,l),await i.start(e,s,d);const S={adapter:i,workDir:s,agentType:a,agentSessionId:d??null,lastActiveAt:Date.now(),currentRunId:null,currentRunPhase:null,nextEventSeq:0,heartbeatSeq:0,heartbeatTimer:null,pendingTextEvent:null,externalChannel:f??null,externalReplyTarget:l??null,externalChannelEnv:{...z(a),...W(e,f,l)}};return t.sessions.set(e,S),ie(t,e,a,i),S}function ue(t,e){const a=t.sessions.get(e),s=a?.currentRunId;if(!a||!s)return;const d=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:d},seq:d,id:`agent-evt-${s}-${d}`}),t.chatQueue?.noteTerminal(e)}async function Ae(t,e){if(t.processedReqIds.has(e.id)){t.client.sendRes({type:"res",id:e.id,ok:!0});return}de(t,e.id);const{sessionId:a,text:s,agentType:d,workDir:f,agentSessionId:l,modelId:i,managerDefaultWorkerAgentType:S,managerDefaultWorkerModelId:E,reasoningEffort:n,clientMessageId:r,sessionListProjection:T,waitForDispatch:R,responseId:h}=e.params,m=h||e.id;J(T);const p=re(e.params.externalChannel),k=typeof e.params.replyTarget=="string"?e.params.replyTarget.trim():"";if(!a||!s){t.processedReqIds.delete(e.id),t.client.sendRes({type:"res",id:m,ok:!1,error:"sessionId and text are required"});return}const u=d;u==="manager"&&t.managerRuntime?.setManagerWorkerDefaults(a,S??null,E??null);const y=(u==="claude"||u==="codex")&&typeof n=="string"&&n.trim()?n.trim():void 0,I=t.resolvePath(le(u,f||F.homedir(),l)||F.homedir()),D=I,$=X(e.params.attachments),g=$?.length?await V({text:s,attachments:$,workDir:I}):{text:s,attachments:$,localized:!1};let o=t.sessions.get(a);if(o){if(o.lastActiveAt=Date.now(),o.agentType!==u||o.workDir!==I||JSON.stringify(o.externalChannel??null)!==JSON.stringify(p??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 ce(t,a,u,I,l,p,k)}catch(c){const w=c instanceof Error&&c.message.startsWith("Unsupported agent:")?c.message:`Failed to start ${d}: ${c instanceof Error?c.message:String(c)}`;console.error(`[chat.send] start failed reqId=${e.id} sessionId=${a} agentType=${d} workDir=${I} agentSessionId=${l??""}: ${w}`),t.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:a,message:w,runId:"",seq:0}}),t.processedReqIds.delete(e.id),t.client.sendRes({type:"res",id:m,ok:!1,error:w});return}t.managerRuntime?.notifyWeChatRpaSessionBinding({sessionId:a,workDir:I,agentType:u,agentSessionId:o.agentSessionId??l??null,modelId:i??null,externalChannel:p});const N={id:r??`user-${e.id}`,sessionId:a,role:"user",ts:Date.now(),payload:G(g.text,g.attachments)};x({level:"info",sessionId:a,wsEvent:"chat.send.start",metadata:{reqId:e.id,agentType:u,modelId:i,reasoningEffort:y}});const P=()=>{ae(t,{sessionId:a,agentType:u,workDir:D,agentSessionId:o.agentSessionId??l??null,modelId:i}),o.currentRunId||(o.nextEventSeq=0),t.nativeFusion?.registerManagedSend({sessionId:a,agentType:u,sourceAgentType:B(u,i),canonicalMessageId:r??null,sourceSessionKey:o.agentSessionId??l??null,text:g.text}),A(a,N),L(t,N,{agentType:u,workDir:D,agentSessionId:o.agentSessionId??l??null,modelId:i})},C=async(c,w)=>{const b=ne(u,c);console.error(`[chat.send] send failed reqId=${e.id} sessionId=${a} agentType=${d} workDir=${I} agentSessionId=${o.agentSessionId??l??""}: ${b}`),t.sessions.delete(a);try{await q(o)}catch{}if(t.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:a,message:b,runId:"",seq:0}}),!w){const M={id:`agent-error-${e.id}-${Date.now()}`,sessionId:a,role:"agent",ts:Date.now(),payload:b};A(a,M),L(t,M,{agentType:u,workDir:D,agentSessionId:o.agentSessionId??l??null,modelId:i})}w&&(t.processedReqIds.delete(e.id),t.client.sendRes({type:"res",id:m,ok:!1,error:b}))};if(R){try{const c=g.attachments;c?.length?await o.adapter.send(g.text,i,y,c):y?await o.adapter.send(g.text,i,y):await o.adapter.send(g.text,i),x({level:"info",sessionId:a,wsEvent:"chat.send.done",metadata:{reqId:e.id}})}catch(c){await C(c,!0);return}P(),t.client.sendRes({type:"res",id:m,ok:!0,...g.localized?{payload:{localizedAttachments:!0}}:{}}),x({level:"info",sessionId:a,wsEvent:"chat.send.res",metadata:{reqId:e.id,ok:!0}});return}P(),t.client.sendRes({type:"res",id:m,ok:!0,...g.localized?{payload:{localizedAttachments:!0}}:{}}),x({level:"info",sessionId:a,wsEvent:"chat.send.res",metadata:{reqId:e.id,ok:!0}});const _=g.attachments;(_?.length?o.adapter.send(g.text,i,y,_):y?o.adapter.send(g.text,i,y):o.adapter.send(g.text,i)).then(()=>{x({level:"info",sessionId:a,wsEvent:"chat.send.done",metadata:{reqId:e.id}})}).catch(c=>{C(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{}ue(t,a),t.activityPublisher?.publish(a,null)}t.client.sendRes({type:"res",id:e.id,ok:!0})}export{Re as handleChatAbort,Ae as handleChatSend};
1
+ import F from"node:os";import{createAgent as j}from"../../agents/adapter.js";import{buildApprovalPendingPayload as O,buildUserMessagePayload as G}from"@shennian/wire";import{reportLog as x}from"../../log-reporter.js";import{lookupClaudeTranscriptCwd as U}from"../../native-fusion/parsers.js";import{appendMessage as A,recordSession as v}from"../store.js";import{mergeProjectedSessions as J}from"../projection.js";import{getManagerRuntimeService as Q}from"../../manager/runtime.js";import{buildManagedAgentEnv as K}from"../../agents/config-status.js";import{materializeRemoteChatAttachments as V}from"../remote-attachments.js";import{formatNianHostedModelError as X}from"../../agents/pi.js";function Y(t){if(!Array.isArray(t))return;const e=t.map(a=>{if(!a||typeof a!="object")return null;const s=a,d=typeof s.path=="string"?s.path:"",f=typeof s.name=="string"?s.name:"",l=typeof s.mimeType=="string"?s.mimeType:"";if(!d||!f||!l)return null;const i=typeof s.previewData=="string"&&s.previewData.trim()?s.previewData.trim():void 0;return{path:d,name:f,mimeType:l,kind:l.startsWith("image/")?"image":"file",...i?{previewData:i}:{}}}).filter(a=>a!=null);return e.length?e:void 0}function Z(t){const e=t.indexOf(`
2
+ `),a=e>0?Math.min(e,80):Math.min(t.length,80);return t.slice(0,a)}function ee(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 te=3e4;function ne(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 ae(t,e){const a=e instanceof Error?e.message:String(e);return t==="pi"?X(a):`Agent send failed: ${a}`}function B(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:H(t,e.sessionId,a.agentType)}}})}function re(t,e){v({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:H(t,e.sessionId,e.agentType)}}})}function se(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 oe(t){return!!(t?.configured??t?.connected)}function z(t){return K(t)}function W(t,e,a){return oe(e)?{...Q()?.getInjectedEnv(t,null,process.cwd(),"external")??{},SHENNIAN_EXTERNAL_SESSION_ID:t,SHENNIAN_MANAGER_SESSION_ID:t,...a?.trim()?{SHENNIAN_EXTERNAL_REPLY_TARGET:a.trim()}:{}}:{}}function le(t,e,a,s,d){t.configure?.({sessionId:e,externalChannel:s??null,env:{...z(a),...W(e,s,d)}})}function H(t,e,a){const s=t.sessions.get(e);return s?.externalChannel?s.externalChannel:a==="manager"?t.managerRuntime?.getExternalChannelStatus(e)??null:null}function ie(t,e,a){if(t!=="claude"||!a)return e;const s=e.trim();return!!s&&s.startsWith("-")&&!s.includes("/")?U(a)??e:e}function de(t,e,a,s){let d=null;function f(n,r={}){t.client.sendAgentEvent({type:"event",event:"agent",payload:ee(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 i(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 S(n){!n||n.heartbeatTimer||(n.heartbeatTimer=setInterval(()=>{i(n)},te),n.heartbeatTimer.unref?.())}function E(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),T=ne(n),R=n.state==="final"||n.state==="error"||n.state==="aborted";r&&(r.nextEventSeq=n.seq+1,R||(r.currentRunId=n.runId),!R&&T&&(r.currentRunPhase=T,S(r)),n.agentSessionId&&(r.agentSessionId=n.agentSessionId)),t.managerRuntime?.noteAgentEvent(e,n),n.state!=="delta"&&x({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:O(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 h=`${e}:${n.runId}`;if(n.state==="delta"&&!n.thinking&&n.text&&t.runTextAcc.set(h,(t.runTextAcc.get(h)??"")+n.text),n.agentSessionId&&n.agentSessionId!==d&&(d=n.agentSessionId,t.nativeFusion?.noteManagedSourceSession(e,B(a,n.source),n.agentSessionId),r&&v({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 p=n.text??"";if(!p)return;const b=!!n.thinking;r?.pendingTextEvent&&(r.pendingTextEvent.runId!==n.runId||r.pendingTextEvent.thinking!==b)&&E(r),r&&!r.pendingTextEvent&&(r.pendingTextEvent={runId:n.runId,seq:n.seq,text:"",thinking:b}),r?.pendingTextEvent&&(r.pendingTextEvent.text+=p,r.pendingTextEvent.seq=n.seq);return}let m={};if(n.state==="final"){E(r);const p=t.runTextAcc.get(h)??"";p&&(m={messageSummary:Z(p)}),t.runTextAcc.delete(h)}else n.state==="error"||n.state==="aborted"?(E(r),t.runTextAcc.delete(h)):(n.state==="tool-call"||n.state==="tool-result"||n.state==="approval-pending")&&E(r);R&&r?.currentRunId===n.runId&&(r.currentRunId=null,r.currentRunPhase=null,r.nextEventSeq=0,l(r),t.chatQueue?.noteTerminal(e)),f(n,m)}),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 ce(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 ue(t,e,a,s,d,f,l){t.evictIdleSessions();const i=j(a);if(!i)throw new Error(`Unsupported agent: ${a}`);le(i,e,a,f,l),await i.start(e,s,d);const S={adapter:i,workDir:s,agentType:a,agentSessionId:d??null,lastActiveAt:Date.now(),currentRunId:null,currentRunPhase:null,nextEventSeq:0,heartbeatSeq:0,heartbeatTimer:null,pendingTextEvent:null,externalChannel:f??null,externalReplyTarget:l??null,externalChannelEnv:{...z(a),...W(e,f,l)}};return t.sessions.set(e,S),de(t,e,a,i),S}function ge(t,e){const a=t.sessions.get(e),s=a?.currentRunId;if(!a||!s)return;const d=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:d},seq:d,id:`agent-evt-${s}-${d}`}),t.chatQueue?.noteTerminal(e)}async function Te(t,e){if(t.processedReqIds.has(e.id)){t.client.sendRes({type:"res",id:e.id,ok:!0});return}ce(t,e.id);const{sessionId:a,text:s,agentType:d,workDir:f,agentSessionId:l,modelId:i,managerDefaultWorkerAgentType:S,managerDefaultWorkerModelId:E,reasoningEffort:n,clientMessageId:r,sessionListProjection:T,waitForDispatch:R,responseId:h}=e.params,m=h||e.id;J(T);const p=se(e.params.externalChannel),b=typeof e.params.replyTarget=="string"?e.params.replyTarget.trim():"";if(!a||!s){t.processedReqIds.delete(e.id),t.client.sendRes({type:"res",id:m,ok:!1,error:"sessionId and text are required"});return}const u=d;u==="manager"&&t.managerRuntime?.setManagerWorkerDefaults(a,S??null,E??null);const y=(u==="claude"||u==="codex")&&typeof n=="string"&&n.trim()?n.trim():void 0,I=t.resolvePath(ie(u,f||F.homedir(),l)||F.homedir()),D=I,$=Y(e.params.attachments),g=$?.length?await V({text:s,attachments:$,workDir:I}):{text:s,attachments:$,localized:!1};let o=t.sessions.get(a);if(o){if(o.lastActiveAt=Date.now(),o.agentType!==u||o.workDir!==I||JSON.stringify(o.externalChannel??null)!==JSON.stringify(p??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 ue(t,a,u,I,l,p,b)}catch(c){const w=c instanceof Error&&c.message.startsWith("Unsupported agent:")?c.message:`Failed to start ${d}: ${c instanceof Error?c.message:String(c)}`;console.error(`[chat.send] start failed reqId=${e.id} sessionId=${a} agentType=${d} workDir=${I} agentSessionId=${l??""}: ${w}`),t.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:a,message:w,runId:"",seq:0}}),t.processedReqIds.delete(e.id),t.client.sendRes({type:"res",id:m,ok:!1,error:w});return}t.managerRuntime?.notifyWeChatRpaSessionBinding({sessionId:a,workDir:I,agentType:u,agentSessionId:o.agentSessionId??l??null,modelId:i??null,externalChannel:p});const N={id:r??`user-${e.id}`,sessionId:a,role:"user",ts:Date.now(),payload:G(g.text,g.attachments)};x({level:"info",sessionId:a,wsEvent:"chat.send.start",metadata:{reqId:e.id,agentType:u,modelId:i,reasoningEffort:y}});const P=()=>{re(t,{sessionId:a,agentType:u,workDir:D,agentSessionId:o.agentSessionId??l??null,modelId:i}),o.currentRunId||(o.nextEventSeq=0),t.nativeFusion?.registerManagedSend({sessionId:a,agentType:u,sourceAgentType:B(u,i),canonicalMessageId:r??null,sourceSessionKey:o.agentSessionId??l??null,text:g.text}),A(a,N),L(t,N,{agentType:u,workDir:D,agentSessionId:o.agentSessionId??l??null,modelId:i})},C=async(c,w)=>{const k=ae(u,c);console.error(`[chat.send] send failed reqId=${e.id} sessionId=${a} agentType=${d} workDir=${I} 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}}),!w){const _={id:`agent-error-${e.id}-${Date.now()}`,sessionId:a,role:"agent",ts:Date.now(),payload:k};A(a,_),L(t,_,{agentType:u,workDir:D,agentSessionId:o.agentSessionId??l??null,modelId:i})}w&&(t.processedReqIds.delete(e.id),t.client.sendRes({type:"res",id:m,ok:!1,error:k}))};if(R){try{const c=g.attachments;c?.length?await o.adapter.send(g.text,i,y,c):y?await o.adapter.send(g.text,i,y):await o.adapter.send(g.text,i),x({level:"info",sessionId:a,wsEvent:"chat.send.done",metadata:{reqId:e.id}})}catch(c){await C(c,!0);return}P(),t.client.sendRes({type:"res",id:m,ok:!0,...g.localized?{payload:{localizedAttachments:!0}}:{}}),x({level:"info",sessionId:a,wsEvent:"chat.send.res",metadata:{reqId:e.id,ok:!0}});return}P(),t.client.sendRes({type:"res",id:m,ok:!0,...g.localized?{payload:{localizedAttachments:!0}}:{}}),x({level:"info",sessionId:a,wsEvent:"chat.send.res",metadata:{reqId:e.id,ok:!0}});const M=g.attachments;(M?.length?o.adapter.send(g.text,i,y,M):y?o.adapter.send(g.text,i,y):o.adapter.send(g.text,i)).then(()=>{x({level:"info",sessionId:a,wsEvent:"chat.send.done",metadata:{reqId:e.id}})}).catch(c=>{C(c,!1)})}async function be(t,e){const{sessionId:a}=e.params,s=t.sessions.get(a);if(s){try{await s.adapter.stop()}catch{}ge(t,a),t.activityPublisher?.publish(a,null)}t.client.sendRes({type:"res",id:e.id,ok:!0})}export{be as handleChatAbort,Te as handleChatSend};
@@ -10,4 +10,6 @@ export * from './external-message-format.ts';
10
10
  export * from './native-session.ts';
11
11
  export * from './skills.ts';
12
12
  export * from './tool-detail.ts';
13
+ export * from './voice-chief.ts';
14
+ export * from './project.ts';
13
15
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAA;AAC7B,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA;AAC3B,cAAc,SAAS,CAAA;AACvB,cAAc,cAAc,CAAA;AAC5B,cAAc,sBAAsB,CAAA;AACpC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,qBAAqB,CAAA;AACnC,cAAc,aAAa,CAAA;AAC3B,cAAc,kBAAkB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAA;AAC7B,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA;AAC3B,cAAc,SAAS,CAAA;AACvB,cAAc,cAAc,CAAA;AAC5B,cAAc,sBAAsB,CAAA;AACpC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,qBAAqB,CAAA;AACnC,cAAc,aAAa,CAAA;AAC3B,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,cAAc,CAAA"}
@@ -10,4 +10,6 @@ export * from "./external-message-format.js";
10
10
  export * from "./native-session.js";
11
11
  export * from "./skills.js";
12
12
  export * from "./tool-detail.js";
13
+ export * from "./voice-chief.js";
14
+ export * from "./project.js";
13
15
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAA;AAC7B,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA;AAC3B,cAAc,SAAS,CAAA;AACvB,cAAc,cAAc,CAAA;AAC5B,cAAc,sBAAsB,CAAA;AACpC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,qBAAqB,CAAA;AACnC,cAAc,aAAa,CAAA;AAC3B,cAAc,kBAAkB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAA;AAC7B,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA;AAC3B,cAAc,SAAS,CAAA;AACvB,cAAc,cAAc,CAAA;AAC5B,cAAc,sBAAsB,CAAA;AACpC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,qBAAqB,CAAA;AACnC,cAAc,aAAa,CAAA;AAC3B,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,cAAc,CAAA"}
@@ -0,0 +1,12 @@
1
+ export type NianProject = {
2
+ id: string;
3
+ machineId: string;
4
+ machineName: string;
5
+ machineOnline: boolean;
6
+ workDir: string;
7
+ displayName: string;
8
+ lastActivityAt: string;
9
+ createdAt: string;
10
+ updatedAt: string;
11
+ };
12
+ //# sourceMappingURL=project.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../src/project.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,aAAa,EAAE,OAAO,CAAA;IACtB,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;IACnB,cAAc,EAAE,MAAM,CAAA;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=project.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project.js","sourceRoot":"","sources":["../src/project.ts"],"names":[],"mappings":""}
@@ -0,0 +1,116 @@
1
+ import type { AgentType, SessionRunPhase } from './session.ts';
2
+ export type VoiceChiefConversationBrief = {
3
+ conversationId: string;
4
+ title: string;
5
+ agentType: AgentType;
6
+ modelId?: string | null;
7
+ status: 'active' | 'completed' | 'failed';
8
+ runPhase?: SessionRunPhase | null;
9
+ canStop?: boolean;
10
+ lastActivityAt: string;
11
+ lastMessagePreview?: string | null;
12
+ };
13
+ export type VoiceChiefProjectBrief = {
14
+ projectId: string;
15
+ displayName: string;
16
+ summary: string;
17
+ machineId: string;
18
+ machineName: string;
19
+ machineStatus: 'online' | 'offline' | 'unknown';
20
+ recentProgress: string[];
21
+ conversations: VoiceChiefConversationBrief[];
22
+ };
23
+ export type VoiceChiefReadableMessage = {
24
+ id: string;
25
+ role: 'user' | 'agent';
26
+ ts: number;
27
+ text: string;
28
+ };
29
+ export type VoiceChiefOperationStatus = {
30
+ status: 'ok' | 'created' | 'delivered' | 'stopped' | 'scheduled' | 'cancelled' | 'ended' | 'unavailable' | 'failed';
31
+ message: string;
32
+ projectId?: string;
33
+ projectName?: string;
34
+ conversationId?: string;
35
+ conversationTitle?: string;
36
+ };
37
+ export type VoiceChiefToolCallDebug = {
38
+ callId: string;
39
+ name: string;
40
+ argumentsJson: string;
41
+ createdAt: string;
42
+ };
43
+ export type VoiceChiefTaskCompletionNotifyMode = 'message' | 'call';
44
+ export type VoiceChiefVoiceId = 'longanqian' | 'longanlingxin' | 'longanlingxi' | 'longanxiaoxin' | 'longanlufeng';
45
+ export type VoiceChiefVoiceOption = {
46
+ id: VoiceChiefVoiceId;
47
+ labelKey: string;
48
+ default?: boolean;
49
+ };
50
+ export type VoiceChiefPreferences = {
51
+ voice: VoiceChiefVoiceId;
52
+ options: VoiceChiefVoiceOption[];
53
+ };
54
+ export type VoiceChiefClientFrame = {
55
+ type: 'start';
56
+ projectHint?: string;
57
+ voice?: string;
58
+ debugTools?: boolean;
59
+ incomingCallId?: string;
60
+ initialPrompt?: string;
61
+ reason?: string;
62
+ reconnectAttempt?: number;
63
+ } | {
64
+ type: 'playback_complete';
65
+ responseId: string;
66
+ } | {
67
+ type: 'ping';
68
+ } | {
69
+ type: 'end';
70
+ };
71
+ export type VoiceChiefServerFrame = {
72
+ type: 'ready';
73
+ conversationId: string;
74
+ inputSampleRate: 16_000;
75
+ outputSampleRate: 24_000;
76
+ projects: VoiceChiefProjectBrief[];
77
+ } | {
78
+ type: 'status';
79
+ state: 'connecting' | 'listening' | 'thinking' | 'speaking' | 'ended';
80
+ } | {
81
+ type: 'input_transcript';
82
+ text: string;
83
+ final: boolean;
84
+ } | {
85
+ type: 'output_transcript';
86
+ text: string;
87
+ final: boolean;
88
+ responseId?: string;
89
+ } | {
90
+ type: 'audio_start';
91
+ responseId: string;
92
+ sampleRate: 24_000;
93
+ } | {
94
+ type: 'audio_done';
95
+ responseId: string;
96
+ } | {
97
+ type: 'audio_cancel';
98
+ responseId: string;
99
+ } | ({
100
+ type: 'operation_status';
101
+ } & VoiceChiefOperationStatus) | {
102
+ type: 'tool_call';
103
+ call: VoiceChiefToolCallDebug;
104
+ } | {
105
+ type: 'hang_up';
106
+ reason?: string;
107
+ delayMs?: number;
108
+ } | {
109
+ type: 'pong';
110
+ } | {
111
+ type: 'error';
112
+ code: string;
113
+ message: string;
114
+ recoverable: boolean;
115
+ };
116
+ //# sourceMappingURL=voice-chief.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voice-chief.d.ts","sourceRoot":"","sources":["../src/voice-chief.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ // @arch docs/features/voice-shennian.md
2
+ // @test packages/server/src/__tests__/voice-chief-realtime.test.ts
3
+ export {};
4
+ //# sourceMappingURL=voice-chief.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voice-chief.js","sourceRoot":"","sources":["../src/voice-chief.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,mEAAmE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shennian",
3
- "version": "0.2.137",
3
+ "version": "0.3.1",
4
4
  "description": "Shennian — AI Agent Control Plane CLI",
5
5
  "type": "module",
6
6
  "bin": {