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": 31005,
565
- "afterBytes": 13491
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": 16155,
600
- "afterBytes": 8279
599
+ "beforeBytes": 16188,
600
+ "afterBytes": 8308
601
601
  },
602
602
  {
603
603
  "file": "src/session/projection.js",
@@ -1,2 +1,2 @@
1
- import v from"node:os";import{createAgent as U}from"../../agents/adapter.js";import{buildApprovalPendingPayload as J,buildUserMessagePayload as K}from"@shennian/wire";import{reportLog as E}from"../../log-reporter.js";import{lookupClaudeTranscriptCwd as Q}from"../../native-fusion/parsers.js";import{appendMessage as A,recordSession as z}from"../store.js";import{mergeProjectedSessions as Y}from"../projection.js";import{buildManagedAgentEnv as V}from"../../agents/config-status.js";import{materializeRemoteChatAttachments as X}from"../remote-attachments.js";function Z(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 ee(t){const e=t.indexOf(`
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 Q,handleFsTransferFinish as z,handleFsTransferStart as D,handleFsExportMarkdownPdf as E,handleFsExportMarkdownPdfSetup as U,handleFsArchiveZip as V}from"./handlers/fs.js";import{handleRegionProbe as _,handleRegionSwitch as O,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,a,i=null,n=null){this.client=e,this.nativeFusion=t,this.cliVersion=a,this.upgradePolicyController=i,this.managedRoomBinder=n,this.managerRuntime=new W({getRuntime:()=>this.getRuntime(),dispatchReq:s=>this.handleReq(s)}),this.chatQueue=new j({getRuntime:()=>this.getRuntime(),dispatchReq:s=>this.handleReq(s)}),o(this.managerRuntime),this.managerRuntime.start(),this.reloadCustomAgents(),this.activityProbeTimer=setInterval(()=>{this.publishManagedActivitySnapshots().catch(s=>{console.error("[session.activity] managed probe failed",s)})},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},a=new Proxy(this.client,{get:(i,n)=>{if(n==="sendRes")return c=>{t.value=c};const s=Reflect.get(i,n,i);return typeof s=="function"?s.bind(i):s}});return await r({...this.getRuntime(),client:a},{type:"req",id:e.clientMessageId,method:"chat.send",params:{...e,waitForDispatch:!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 a=await t.adapter.getStatus().catch(()=>null);if(!a?.active||!a.runPhase)continue;const i=new Date().toISOString();this.publishSessionActivity(e,{sessionId:e,runId:a.runId||t.currentRunId,runPhase:a.runPhase,startedAt:new Date(t.lastActiveAt).toISOString(),updatedAt:i,canStop:a.canStop??!0});const n=t.heartbeatSeq++;this.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"heartbeat",sessionId:e,runId:a.runId||t.currentRunId,seq:n,runPhase:a.runPhase,canStop:a.canStop??!0},seq:n,id:`agent-status-${a.runId||t.currentRunId}-${Date.now()}`})}}reloadCustomAgents(){for(const t of l())t.startsWith("custom:")&&h(t);const e=u();for(const[t,a]of Object.entries(e.customAgents??{}))N(t,a)}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 E(t,e);break;case"fs.export.markdown-pdf.setup":await U(t,e);break;case"fs.archive.zip":await V(t,e);break;case"fs.rename":await C(t,e);break;case"fs.transfer":await M(t,e);break;case"fs.transfer.start":await D(t,e);break;case"fs.transfer.chunk":await Q(t,e);break;case"fs.transfer.finish":await z(t,e);break;case"fs.transfer.abort":await x(t,e);break;case"region.probe":await _(t,e);break;case"region.switch":await O(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(a){this.client.sendRes({type:"res",id:e.id,ok:!1,error:a instanceof Error?a.message:String(a)})}finally{this.activeRequests--}}evictIdleSessions(){if(this.sessions.size<Z)return;let e=null;for(const[t,a]of this.sessions)(!e||a.lastActiveAt<e.session.lastActiveAt)&&(e={key:t,session:a});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};
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};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shennian",
3
- "version": "0.3.8",
3
+ "version": "0.3.9",
4
4
  "description": "Shennian — AI Agent Control Plane CLI",
5
5
  "type": "module",
6
6
  "bin": {