shennian 0.3.8 → 0.3.9
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.
|
@@ -561,8 +561,8 @@
|
|
|
561
561
|
},
|
|
562
562
|
{
|
|
563
563
|
"file": "src/session/handlers/chat.js",
|
|
564
|
-
"beforeBytes":
|
|
565
|
-
"afterBytes":
|
|
564
|
+
"beforeBytes": 31062,
|
|
565
|
+
"afterBytes": 13525
|
|
566
566
|
},
|
|
567
567
|
{
|
|
568
568
|
"file": "src/session/handlers/control.js",
|
|
@@ -596,8 +596,8 @@
|
|
|
596
596
|
},
|
|
597
597
|
{
|
|
598
598
|
"file": "src/session/manager.js",
|
|
599
|
-
"beforeBytes":
|
|
600
|
-
"afterBytes":
|
|
599
|
+
"beforeBytes": 16188,
|
|
600
|
+
"afterBytes": 8308
|
|
601
601
|
},
|
|
602
602
|
{
|
|
603
603
|
"file": "src/session/projection.js",
|
|
@@ -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 te(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 ne=3e4;function ae(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 re(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 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 se(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 Ee(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 W(t){return V(t)}function O(t,e,a){return{}}function H(t,e,a,s,l,u){t.configure?.({sessionId:e,externalChannel:s??null,env:{...W(a),...O(e,s,l),...u?{SHENNIAN_ROOM_REGISTRY_KEY:u}:{}}})}function Re(t,e,a){return null}function oe(t,e,a){if(t!=="claude"||!a)return e;const s=e.trim();return!!s&&s.startsWith("-")&&!s.includes("/")?Q(a)??e:e}function le(t,e,a,s){let l=null;function u(n,r={}){t.client.sendAgentEvent({type:"event",event:"agent",payload:te(n,e,r),seq:n.seq,id:`agent-evt-${n.runId}-${n.seq}`})}function d(n){n?.heartbeatTimer&&(clearInterval(n.heartbeatTimer),n.heartbeatTimer=null)}function c(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 y(n){!n||n.heartbeatTimer||(n.heartbeatTimer=setInterval(()=>{c(n)},ne),n.heartbeatTimer.unref?.())}function S(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),R=ae(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,y(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 I=`${e}:${n.runId}`;if(n.state==="delta"&&!n.thinking&&n.text&&t.runTextAcc.set(I,(t.runTextAcc.get(I)??"")+n.text),n.agentSessionId&&n.agentSessionId!==l&&(l=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 h=n.text??"";if(!h)return;const m=!!n.thinking;r?.pendingTextEvent&&(r.pendingTextEvent.runId!==n.runId||r.pendingTextEvent.thinking!==m)&&S(r),r&&!r.pendingTextEvent&&(r.pendingTextEvent={runId:n.runId,seq:n.seq,text:"",thinking:m}),r?.pendingTextEvent&&(r.pendingTextEvent.text+=h,r.pendingTextEvent.seq=n.seq);return}let x={};if(n.state==="final"){S(r);const h=t.runTextAcc.get(I)??"";h&&(x={messageSummary:ee(h)}),t.runTextAcc.delete(I)}else n.state==="error"||n.state==="aborted"?(S(r),t.runTextAcc.delete(I)):(n.state==="tool-call"||n.state==="tool-result"||n.state==="approval-pending")&&S(r);T&&r?.currentRunId===n.runId&&(r.currentRunId=null,r.currentRunPhase=null,r.nextEventSeq=0,d(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 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 P(t){t.heartbeatTimer&&(clearInterval(t.heartbeatTimer),t.heartbeatTimer=null),t.adapter.removeAllListeners(),await t.adapter.stop().catch(()=>{})}function j(t,e,a,s,l,u){return u?.trim()?t.send(e,a,s,l,u):l?.length?t.send(e,a,s,l):s?t.send(e,a,s):t.send(e,a)}async function ie(t,e,a,s,l,u,d){t.evictIdleSessions();const c=U(a);if(!c)throw new Error(`Unsupported agent: ${a}`);H(c,e,a,u,d),await c.start(e,s,l);const y={adapter:c,workDir:s,agentType:a,agentSessionId:l??null,lastActiveAt:Date.now(),currentRunId:null,currentRunPhase:null,nextEventSeq:0,heartbeatSeq:0,heartbeatTimer:null,pendingTextEvent:null,externalChannel:u??null,externalReplyTarget:d??null,externalChannelEnv:{...W(a),...O(e,u,d)}};return t.sessions.set(e,y),le(t,e,a,c),y}function ce(t,e){const a=t.sessions.get(e),s=a?.currentRunId;if(!a||!s)return;const l=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:l},seq:l,id:`agent-evt-${s}-${l}`}),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}de(t,e.id);const{sessionId:a,text:s,agentType:l,workDir:u,agentSessionId:d,modelId:c,systemPrompt:y,managerDefaultWorkerAgentType:S,managerDefaultWorkerModelId:n,reasoningEffort:r,clientMessageId:R,sessionListProjection:T,waitForDispatch:I,responseId:x,roomContextRegistryKey:h}=e.params,m=x||e.id;Y(T);const k=null,M="";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 g=l;g==="manager"&&t.managerRuntime?.setManagerWorkerDefaults(a,S??null,n??null);const $=(g==="claude"||g==="codex"||g==="workbuddy")&&typeof r=="string"&&r.trim()?r.trim():void 0,w=t.resolvePath(oe(g,u||v.homedir(),d)||v.homedir()),q=w,D=Z(e.params.attachments),f=D?.length?await X({text:s,attachments:D,workDir:w}):{text:s,attachments:D,localized:!1};let o=t.sessions.get(a);if(o){if(o.lastActiveAt=Date.now(),o.agentType!==g||o.workDir!==w||JSON.stringify(o.externalChannel??null)!==JSON.stringify(k??null)){t.sessions.delete(a);try{await P(o)}catch{t.processedReqIds.delete(e.id)}o=void 0}else if(d&&o.agentSessionId!==d)try{await o.adapter.resume(d),o.agentSessionId=d}catch{t.sessions.delete(a);try{await P(o)}catch{t.processedReqIds.delete(e.id)}o=void 0}}if(!o)try{o=await ie(t,a,g,w,d,k,M)}catch(i){const p=i instanceof Error&&i.message.startsWith("Unsupported agent:")?i.message:`Failed to start ${l}: ${i instanceof Error?i.message:String(i)}`;console.error(`[chat.send] start failed reqId=${e.id} sessionId=${a} agentType=${l} workDir=${w} agentSessionId=${d??""}: ${p}`),t.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:a,message:p,runId:"",seq:0}}),t.processedReqIds.delete(e.id),t.client.sendRes({type:"res",id:m,ok:!1,error:p});return}h&&/^[a-f0-9]{64}$/.test(h)&&H(o.adapter,a,g,k,M,h);const _={id:R??`user-${e.id}`,sessionId:a,role:"user",ts:Date.now(),payload:K(f.text,f.attachments)};E({level:"info",sessionId:a,wsEvent:"chat.send.start",metadata:{reqId:e.id,agentType:g,modelId:c,reasoningEffort:$}});const C=i=>{se(t,{sessionId:a,agentType:g,workDir:q,agentSessionId:o.agentSessionId??d??null,modelId:c}),o.currentRunId||(o.nextEventSeq=0),t.nativeFusion?.registerManagedSend({sessionId:a,agentType:g,sourceAgentType:B(g,c),canonicalMessageId:R??null,sourceSessionKey:o.agentSessionId??d??null,text:f.text,managedEchoPolicy:i?.deliveryMode==="external_owner_queue"?"import_following":"suppress_following"}),A(a,_),L(t,_,{agentType:g,workDir:q,agentSessionId:o.agentSessionId??d??null,modelId:c})},F=async(i,p)=>{const b=re(g,i);console.error(`[chat.send] send failed reqId=${e.id} sessionId=${a} agentType=${l} workDir=${w} agentSessionId=${o.agentSessionId??d??""}: ${b}`),t.sessions.delete(a);try{await P(o)}catch{}if(t.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:a,message:b,runId:"",seq:0}}),!p){const N={id:`agent-error-${e.id}-${Date.now()}`,sessionId:a,role:"agent",ts:Date.now(),payload:b};A(a,N),L(t,N,{agentType:g,workDir:q,agentSessionId:o.agentSessionId??d??null,modelId:c})}p&&(t.processedReqIds.delete(e.id),t.client.sendRes({type:"res",id:m,ok:!1,error:b}))};if(I){let i;try{const p=f.attachments;i=await j(o.adapter,f.text,c,$,p,y),E({level:"info",sessionId:a,wsEvent:"chat.send.done",metadata:{reqId:e.id}})}catch(p){await F(p,!0);return}C(i??void 0),t.client.sendRes({type:"res",id:m,ok:!0,...f.localized||i?.deliveryMode==="external_owner_queue"?{payload:{...f.localized?{localizedAttachments:!0}:{},...i?.deliveryMode==="external_owner_queue"?{queued:!0,deliveryMode:i.deliveryMode,queuedSubmissionId:i.queuedSubmissionId}:{}}}:{}}),E({level:"info",sessionId:a,wsEvent:"chat.send.res",metadata:{reqId:e.id,ok:!0}});return}C(),t.client.sendRes({type:"res",id:m,ok:!0,...f.localized?{payload:{localizedAttachments:!0}}:{}}),E({level:"info",sessionId:a,wsEvent:"chat.send.res",metadata:{reqId:e.id,ok:!0}});const G=f.attachments;j(o.adapter,f.text,c,$,G,y).then(()=>{E({level:"info",sessionId:a,wsEvent:"chat.send.done",metadata:{reqId:e.id}})}).catch(i=>{F(i,!1)})}async function xe(t,e){const{sessionId:a}=e.params,s=t.sessions.get(a);if(s){try{await s.adapter.stop()}catch{}ce(t,a),t.activityPublisher?.publish(a,null)}t.client.sendRes({type:"res",id:e.id,ok:!0})}export{xe as handleChatAbort,Te as handleChatSend};
|
|
1
|
+
import z from"node:os";import{createAgent as J}from"../../agents/adapter.js";import{buildApprovalPendingPayload as K,buildUserMessagePayload as Q}from"@shennian/wire";import{reportLog as S}from"../../log-reporter.js";import{lookupClaudeTranscriptCwd as Y}from"../../native-fusion/parsers.js";import{appendMessage as E,recordSession as B}from"../store.js";import{mergeProjectedSessions as V}from"../projection.js";import{buildManagedAgentEnv as X}from"../../agents/config-status.js";import{materializeRemoteChatAttachments as Z}from"../remote-attachments.js";function ee(t){if(!Array.isArray(t))return;const e=t.map(a=>{if(!a||typeof a!="object")return null;const s=a,l=typeof s.path=="string"?s.path:"",u=typeof s.name=="string"?s.name:"",d=typeof s.mimeType=="string"?s.mimeType:"";if(!l||!u||!d)return null;const c=typeof s.previewData=="string"&&s.previewData.trim()?s.previewData.trim():void 0;return{path:l,name:u,mimeType:d,kind:d.startsWith("image/")?"image":"file",...c?{previewData:c}:{}}}).filter(a=>a!=null);return e.length?e:void 0}function te(t){const e=t.indexOf(`
|
|
2
|
+
`),a=e>0?Math.min(e,80):Math.min(t.length,80);return t.slice(0,a)}function ne(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 ae=3e4;function re(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 se(t,e){return`Agent send failed: ${e instanceof Error?e.message:String(e)}`}function L(t,e){return t!=="manager"?t:e==="claude"?"claude":"codex"}function O(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 oe(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 Ae(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 Re(t){return!!(t?.configured??t?.connected)}function W(t){return X(t)}function H(t,e,a){return{}}function j(t,e,a,s,l,u){t.configure?.({sessionId:e,externalChannel:s??null,env:{...W(a),...H(e,s,l),...u?{SHENNIAN_ROOM_REGISTRY_KEY:u}:{}}})}function Te(t,e,a){return null}function le(t,e,a){if(t!=="claude"||!a)return e;const s=e.trim();return!!s&&s.startsWith("-")&&!s.includes("/")?Y(a)??e:e}function de(t,e,a,s){let l=null;function u(n,r={}){t.client.sendAgentEvent({type:"event",event:"agent",payload:ne(n,e,r),seq:n.seq,id:`agent-evt-${n.runId}-${n.seq}`})}function d(n){n?.heartbeatTimer&&(clearInterval(n.heartbeatTimer),n.heartbeatTimer=null)}function c(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 m(n){!n||n.heartbeatTimer||(n.heartbeatTimer=setInterval(()=>{c(n)},ae),n.heartbeatTimer.unref?.())}function I(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),A=re(n),R=n.state==="final"||n.state==="error"||n.state==="aborted";r&&(r.nextEventSeq=n.seq+1,R||(r.currentRunId=n.runId),!R&&A&&(r.currentRunPhase=A,m(r)),n.agentSessionId&&(r.agentSessionId=n.agentSessionId)),t.managerRuntime?.noteAgentEvent(e,n),n.state!=="delta"&&S({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?E(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"?E(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"?E(e,{id:`agent-${n.runId||"run"}-${n.seq}`,sessionId:e,role:"agent",ts:Date.now(),payload:K(n.approval)}):(n.state==="error"||n.state==="aborted")&&n.message&&E(e,{id:`agent-${n.runId||"run"}-${n.seq}`,sessionId:e,role:"agent",ts:Date.now(),payload:n.message});const y=`${e}:${n.runId}`;if(n.state==="delta"&&!n.thinking&&n.text&&t.runTextAcc.set(y,(t.runTextAcc.get(y)??"")+n.text),n.agentSessionId&&n.agentSessionId!==l&&(l=n.agentSessionId,t.nativeFusion?.noteManagedSourceSession(e,L(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)&&I(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 x={};if(n.state==="final"){I(r);const h=t.runTextAcc.get(y)??"";h&&(x={messageSummary:te(h)}),t.runTextAcc.delete(y)}else n.state==="error"||n.state==="aborted"?(I(r),t.runTextAcc.delete(y)):(n.state==="tool-call"||n.state==="tool-result"||n.state==="approval-pending")&&I(r);R&&r?.currentRunId===n.runId&&(r.currentRunId=null,r.currentRunPhase=null,r.nextEventSeq=0,d(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 ie(t,e){if(t.processedReqIds.add(e),t.processedReqIds.size>1e3){const a=t.processedReqIds.values().next().value;t.processedReqIds.delete(a)}}async function M(t){t.heartbeatTimer&&(clearInterval(t.heartbeatTimer),t.heartbeatTimer=null),t.adapter.removeAllListeners(),await t.adapter.stop().catch(()=>{})}function G(t,e,a,s,l,u){return u?.trim()?t.send(e,a,s,l,u):l?.length?t.send(e,a,s,l):s?t.send(e,a,s):t.send(e,a)}async function ce(t,e,a,s,l,u,d){t.evictIdleSessions();const c=J(a);if(!c)throw new Error(`Unsupported agent: ${a}`);j(c,e,a,u,d),await c.start(e,s,l);const m={adapter:c,workDir:s,agentType:a,agentSessionId:l??null,lastActiveAt:Date.now(),currentRunId:null,currentRunPhase:null,nextEventSeq:0,heartbeatSeq:0,heartbeatTimer:null,pendingTextEvent:null,externalChannel:u??null,externalReplyTarget:d??null,externalChannelEnv:{...W(a),...H(e,u,d)}};return t.sessions.set(e,m),de(t,e,a,c),m}function ue(t,e){const a=t.sessions.get(e),s=a?.currentRunId;if(!a||!s)return;const l=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:l},seq:l,id:`agent-evt-${s}-${l}`}),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}ie(t,e.id);const{sessionId:a,text:s,agentType:l,workDir:u,agentSessionId:d,modelId:c,systemPrompt:m,managerDefaultWorkerAgentType:I,managerDefaultWorkerModelId:n,reasoningEffort:r,clientMessageId:A,sessionListProjection:R,waitForDispatch:y,responseId:x,roomContextRegistryKey:h,suppressExternalOwnerEcho:b}=e.params,T=x||e.id;V(R);const $=null,_="";if(!a||!s){t.processedReqIds.delete(e.id),t.client.sendRes({type:"res",id:T,ok:!1,error:"sessionId and text are required"});return}const g=l;g==="manager"&&t.managerRuntime?.setManagerWorkerDefaults(a,I??null,n??null);const q=(g==="claude"||g==="codex"||g==="workbuddy")&&typeof r=="string"&&r.trim()?r.trim():void 0,w=t.resolvePath(le(g,u||z.homedir(),d)||z.homedir()),D=w,P=ee(e.params.attachments),f=P?.length?await Z({text:s,attachments:P,workDir:w}):{text:s,attachments:P,localized:!1};let o=t.sessions.get(a);if(o){if(o.lastActiveAt=Date.now(),o.agentType!==g||o.workDir!==w||JSON.stringify(o.externalChannel??null)!==JSON.stringify($??null)){t.sessions.delete(a);try{await M(o)}catch{t.processedReqIds.delete(e.id)}o=void 0}else if(d&&o.agentSessionId!==d)try{await o.adapter.resume(d),o.agentSessionId=d}catch{t.sessions.delete(a);try{await M(o)}catch{t.processedReqIds.delete(e.id)}o=void 0}}if(!o)try{o=await ce(t,a,g,w,d,$,_)}catch(i){const p=i instanceof Error&&i.message.startsWith("Unsupported agent:")?i.message:`Failed to start ${l}: ${i instanceof Error?i.message:String(i)}`;console.error(`[chat.send] start failed reqId=${e.id} sessionId=${a} agentType=${l} workDir=${w} agentSessionId=${d??""}: ${p}`),t.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:a,message:p,runId:"",seq:0}}),t.processedReqIds.delete(e.id),t.client.sendRes({type:"res",id:T,ok:!1,error:p});return}h&&/^[a-f0-9]{64}$/.test(h)&&j(o.adapter,a,g,$,_,h);const C={id:A??`user-${e.id}`,sessionId:a,role:"user",ts:Date.now(),payload:Q(f.text,f.attachments)};S({level:"info",sessionId:a,wsEvent:"chat.send.start",metadata:{reqId:e.id,agentType:g,modelId:c,reasoningEffort:q}});const F=i=>{oe(t,{sessionId:a,agentType:g,workDir:D,agentSessionId:o.agentSessionId??d??null,modelId:c}),o.currentRunId||(o.nextEventSeq=0),t.nativeFusion?.registerManagedSend({sessionId:a,agentType:g,sourceAgentType:L(g,c),canonicalMessageId:A??null,sourceSessionKey:o.agentSessionId??d??null,text:f.text,managedEchoPolicy:i?.deliveryMode==="external_owner_queue"&&!b?"import_following":"suppress_following"}),E(a,C),O(t,C,{agentType:g,workDir:D,agentSessionId:o.agentSessionId??d??null,modelId:c})},N=async(i,p)=>{const k=se(g,i);console.error(`[chat.send] send failed reqId=${e.id} sessionId=${a} agentType=${l} workDir=${w} agentSessionId=${o.agentSessionId??d??""}: ${k}`),t.sessions.delete(a);try{await M(o)}catch{}if(t.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:a,message:k,runId:"",seq:0}}),!p){const v={id:`agent-error-${e.id}-${Date.now()}`,sessionId:a,role:"agent",ts:Date.now(),payload:k};E(a,v),O(t,v,{agentType:g,workDir:D,agentSessionId:o.agentSessionId??d??null,modelId:c})}p&&(t.processedReqIds.delete(e.id),t.client.sendRes({type:"res",id:T,ok:!1,error:k}))};if(y){let i;try{const p=f.attachments;i=await G(o.adapter,f.text,c,q,p,m),S({level:"info",sessionId:a,wsEvent:"chat.send.done",metadata:{reqId:e.id}})}catch(p){await N(p,!0);return}F(i??void 0),t.client.sendRes({type:"res",id:T,ok:!0,...f.localized||i?.deliveryMode==="external_owner_queue"?{payload:{...f.localized?{localizedAttachments:!0}:{},...i?.deliveryMode==="external_owner_queue"?{queued:!0,deliveryMode:i.deliveryMode,queuedSubmissionId:i.queuedSubmissionId}:{}}}:{}}),S({level:"info",sessionId:a,wsEvent:"chat.send.res",metadata:{reqId:e.id,ok:!0}});return}F(),t.client.sendRes({type:"res",id:T,ok:!0,...f.localized?{payload:{localizedAttachments:!0}}:{}}),S({level:"info",sessionId:a,wsEvent:"chat.send.res",metadata:{reqId:e.id,ok:!0}});const U=f.attachments;G(o.adapter,f.text,c,q,U,m).then(()=>{S({level:"info",sessionId:a,wsEvent:"chat.send.done",metadata:{reqId:e.id}})}).catch(i=>{N(i,!1)})}async function be(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{be as handleChatAbort,xe as handleChatSend};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getRegisteredAgents as l,unregisterAgent as h}from"../agents/adapter.js";import{loadConfig as u}from"../config/index.js";import{handleUpgradeStart as d,handleUpgradeStatus as m}from"../commands/upgrade.js";import{handleAgentsRefresh as p,handleModelsRefresh as f}from"./handlers/agents.js";import{handleAgentCapabilitiesList as g}from"./handlers/agent-capabilities.js";import{handleAgentConfigClear as b,handleAgentConfigGet as w,handleAgentConfigTest as v,handleAgentConfigUpsert as k}from"./handlers/agent-config.js";import{handleChatAbort as R,handleChatSend as r}from"./handlers/chat.js";import{handleSessionRefresh as y}from"./handlers/session-refresh.js";import{handleSessionToolDetail as S}from"./handlers/tool-detail.js";import{handleSessionTitleSet as A}from"./handlers/title.js";import{cleanupPendingTransfers as T,handleFsLs as P,handleFsRead as I,handleFsRename as C,handleFsWrite as F,handleFsTransfer as M,handleFsTransferAbort as x,handleFsTransferChunk as
|
|
1
|
+
import{getRegisteredAgents as l,unregisterAgent as h}from"../agents/adapter.js";import{loadConfig as u}from"../config/index.js";import{handleUpgradeStart as d,handleUpgradeStatus as m}from"../commands/upgrade.js";import{handleAgentsRefresh as p,handleModelsRefresh as f}from"./handlers/agents.js";import{handleAgentCapabilitiesList as g}from"./handlers/agent-capabilities.js";import{handleAgentConfigClear as b,handleAgentConfigGet as w,handleAgentConfigTest as v,handleAgentConfigUpsert as k}from"./handlers/agent-config.js";import{handleChatAbort as R,handleChatSend as r}from"./handlers/chat.js";import{handleSessionRefresh as y}from"./handlers/session-refresh.js";import{handleSessionToolDetail as S}from"./handlers/tool-detail.js";import{handleSessionTitleSet as A}from"./handlers/title.js";import{cleanupPendingTransfers as T,handleFsLs as P,handleFsRead as I,handleFsRename as C,handleFsWrite as F,handleFsTransfer as M,handleFsTransferAbort as x,handleFsTransferChunk as E,handleFsTransferFinish as Q,handleFsTransferStart as z,handleFsExportMarkdownPdf as D,handleFsExportMarkdownPdfSetup as O,handleFsArchiveZip as U}from"./handlers/fs.js";import{handleRegionProbe as V,handleRegionSwitch as _,handleUpgradeSetPolicy as B}from"./handlers/control.js";import{ManagerRuntimeService as W,setManagerRuntimeService as o}from"../manager/runtime.js";import{ChatQueueManager as j}from"./queue.js";import{createAuthorizedFsRoot as L,resolveAuthorizedPath as $,resolveSessionWorkDir as G}from"../fs/boundary.js";import"../agents/claude.js";import"../agents/codex.js";import"../agents/workbuddy.js";import"../agents/gemini.js";import"../agents/cursor.js";import"../agents/opencode.js";import"../agents/manager.js";import{registerCustomAgent as N}from"../agents/custom.js";import{handleManagedRoomBind as X}from"./handlers/room-managed.js";const Z=50;import{resolveSessionWorkDir as Se}from"../fs/boundary.js";class ke{client;nativeFusion;cliVersion;upgradePolicyController;managedRoomBinder;sessions=new Map;processedReqIds=new Set;runTextAcc=new Map;pendingTransfers=new Map;managerRuntime;chatQueue;activityProbeTimer=null;activeRequests=0;constructor(e,t=null,s,i=null,n=null){this.client=e,this.nativeFusion=t,this.cliVersion=s,this.upgradePolicyController=i,this.managedRoomBinder=n,this.managerRuntime=new W({getRuntime:()=>this.getRuntime(),dispatchReq:a=>this.handleReq(a)}),this.chatQueue=new j({getRuntime:()=>this.getRuntime(),dispatchReq:a=>this.handleReq(a)}),o(this.managerRuntime),this.managerRuntime.start(),this.reloadCustomAgents(),this.activityProbeTimer=setInterval(()=>{this.publishManagedActivitySnapshots().catch(a=>{console.error("[session.activity] managed probe failed",a)})},15e3),this.activityProbeTimer.unref?.()}getRuntime(){return{client:this.client,pendingTransfers:this.pendingTransfers,processedReqIds:this.processedReqIds,reloadCustomAgents:()=>this.reloadCustomAgents(),resolvePath:e=>this.resolvePath(e),resolveAuthorizedPath:(e,t)=>this.resolveAuthorizedPath(e,t),runTextAcc:this.runTextAcc,sessions:this.sessions,evictIdleSessions:()=>this.evictIdleSessions(),nativeFusion:this.nativeFusion,managerRuntime:this.managerRuntime,chatQueue:this.chatQueue,activityPublisher:{publish:(e,t)=>this.publishSessionActivity(e,t)},upgradePolicyController:this.upgradePolicyController}}getUpgradeIdleState(){const e=[];return[...this.sessions.values()].some(t=>t.currentRunId!==null)&&e.push("active-agent-turn"),this.pendingTransfers.size>0&&e.push("file-transfer"),this.activeRequests>0&&e.push("active-daemon-request"),{idle:e.length===0,reasons:e}}async activateRoomSession(e){const t={value:null},s=new Proxy(this.client,{get:(i,n)=>{if(n==="sendRes")return c=>{t.value=c};const a=Reflect.get(i,n,i);return typeof a=="function"?a.bind(i):a}});return await r({...this.getRuntime(),client:s},{type:"req",id:e.clientMessageId,method:"chat.send",params:{...e,waitForDispatch:!0,suppressExternalOwnerEcho:!0}}),{externalOwnerQueued:t.value?.ok===!0&&t.value.payload?.deliveryMode==="external_owner_queue"}}publishSessionActivity(e,t){this.client.sendEvent({type:"event",event:"session.activity",payload:{sessionId:e,activity:t}})}async publishManagedActivitySnapshots(){for(const[e,t]of this.sessions.entries()){if(!t.currentRunId||!t.adapter.getStatus)continue;const s=await t.adapter.getStatus().catch(()=>null);if(!s?.active||!s.runPhase)continue;const i=new Date().toISOString();this.publishSessionActivity(e,{sessionId:e,runId:s.runId||t.currentRunId,runPhase:s.runPhase,startedAt:new Date(t.lastActiveAt).toISOString(),updatedAt:i,canStop:s.canStop??!0});const n=t.heartbeatSeq++;this.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"heartbeat",sessionId:e,runId:s.runId||t.currentRunId,seq:n,runPhase:s.runPhase,canStop:s.canStop??!0},seq:n,id:`agent-status-${s.runId||t.currentRunId}-${Date.now()}`})}}reloadCustomAgents(){for(const t of l())t.startsWith("custom:")&&h(t);const e=u();for(const[t,s]of Object.entries(e.customAgents??{}))N(t,s)}async handleReq(e){const t=this.getRuntime();this.activeRequests++;try{switch(e.method){case"chat.send":await r(t,e);break;case"chat.enqueue":await this.chatQueue.handleEnqueue(e);break;case"chat.queue.get":await this.chatQueue.handleGet(e);break;case"chat.queue.edit":await this.chatQueue.handleEdit(e);break;case"chat.queue.delete":await this.chatQueue.handleDelete(e);break;case"chat.abort":await R(t,e);break;case"session.refresh":await y(t,e);break;case"session.tool.detail":await S(t,e);break;case"session.title.set":await A(t,e);break;case"room.agent.bind-managed":await X(t,this.managedRoomBinder,e);break;case"fs.ls":await P(t,e);break;case"fs.read":await I(t,e);break;case"fs.write":await F(t,e);break;case"fs.export.markdown-pdf":await D(t,e);break;case"fs.export.markdown-pdf.setup":await O(t,e);break;case"fs.archive.zip":await U(t,e);break;case"fs.rename":await C(t,e);break;case"fs.transfer":await M(t,e);break;case"fs.transfer.start":await z(t,e);break;case"fs.transfer.chunk":await E(t,e);break;case"fs.transfer.finish":await Q(t,e);break;case"fs.transfer.abort":await x(t,e);break;case"region.probe":await V(t,e);break;case"region.switch":await _(t,e);break;case"upgrade.start":await d(this.client,e.id,e.params.version,{currentVersion:this.cliVersion,confirmedMajor:e.params.confirmedMajor===!0});break;case"upgrade.status":await m(this.client,e.id,{currentVersion:this.cliVersion});break;case"upgrade.set-policy":await B(t,e);break;case"agents.refresh":await p(t,e);break;case"models.refresh":await f(t,e);break;case"agent.config.get":await w(t,e);break;case"agent.config.upsert":await k(t,e);break;case"agent.config.clear":await b(t,e);break;case"agent.config.test":await v(t,e);break;case"agent.capabilities.list":await g(t,e);break;case"skill.list":case"skill.install":case"skill.doctor":case"skill.setup":case"skill.use":this.client.sendRes({type:"res",id:e.id,ok:!1,error:"feature_retired"});break;case"session.wechat-rpa.channel.get":case"session.wechat-rpa.channel.upsert":case"session.wechat-rpa.channel.sync":case"manager.wechat-rpa.channel.get":case"manager.wechat-rpa.channel.upsert":case"manager.wechat-rpa.channel.sync":this.client.sendRes({type:"res",id:e.id,ok:!1,error:"feature_retired"});break;default:this.client.sendRes({type:"res",id:e.id,ok:!1,error:`Unknown method: ${e.method}`})}}catch(s){this.client.sendRes({type:"res",id:e.id,ok:!1,error:s instanceof Error?s.message:String(s)})}finally{this.activeRequests--}}evictIdleSessions(){if(this.sessions.size<Z)return;let e=null;for(const[t,s]of this.sessions)(!e||s.lastActiveAt<e.session.lastActiveAt)&&(e={key:t,session:s});e&&(e.session.heartbeatTimer&&(clearInterval(e.session.heartbeatTimer),e.session.heartbeatTimer=null),e.session.adapter.removeAllListeners(),e.session.adapter.stop().catch(()=>{}),this.sessions.delete(e.key))}resolvePath(e){return G(e)}resolveAuthorizedPath(e,t){return $(e,L(t))}async cleanup(){this.activityProbeTimer&&(clearInterval(this.activityProbeTimer),this.activityProbeTimer=null);for(const[,e]of this.sessions)e.heartbeatTimer&&(clearInterval(e.heartbeatTimer),e.heartbeatTimer=null),await e.adapter.stop().catch(()=>{});this.sessions.clear(),this.runTextAcc.clear(),T(this.getRuntime()),await this.managerRuntime.stop(),o(null)}}export{ke as SessionManager,Se as resolveSessionWorkDir};
|