shennian 0.4.55 → 0.4.57

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.
@@ -471,13 +471,13 @@
471
471
  },
472
472
  {
473
473
  "file": "src/manager/runtime.js",
474
- "beforeBytes": 26434,
475
- "afterBytes": 13641
474
+ "beforeBytes": 28472,
475
+ "afterBytes": 14502
476
476
  },
477
477
  {
478
478
  "file": "src/manager/worker-ipc.js",
479
- "beforeBytes": 11490,
480
- "afterBytes": 6256
479
+ "beforeBytes": 11611,
480
+ "afterBytes": 6311
481
481
  },
482
482
  {
483
483
  "file": "src/manager/worker-markdown.js",
@@ -1,13 +1,13 @@
1
- import E from"node:http";import{createHash as R,randomBytes as A,randomUUID as p}from"node:crypto";import h from"node:fs";import M from"node:os";import f from"node:path";import{ManagerRegistry as S}from"./registry.js";import{appendMessage as b}from"../session/store.js";import{requestSessionIndexPublish as _}from"../session/index-publisher.js";import{RetiredChannelRuntime as N}from"./retired-external-channel-compat.js";import{resolveShennianPath as x}from"../config/index.js";import{buildExternalChannelInstructions as T}from"../agents/external-channel-instructions.js";import{getPersonalSyncIdentity as y}from"../personal-sync/epoch.js";import{handleWorkerIpcRoute as k}from"./worker-ipc.js";import{deriveWorkerTitle as D,formatWorkerMarkdown as q}from"./worker-markdown.js";const W=Number(process.env.SHENNIAN_MANAGER_IPC_BODY_MAX_BYTES||2*1024*1024),m=12*6e4;let w=null;function ee(a){w=a}function te(){return w}function g(a){return f.resolve(a||M.homedir())}function c(a,e,t){a.writeHead(e,{"content-type":"application/json; charset=utf-8"}),a.end(JSON.stringify(t))}function I(a){return a.replace(/\r\n/g,`
2
- `).trim()}function P(a){return a==="worker.final"?"completed":a==="worker.error"?"failed":a==="worker.aborted"?"stopped":"progress"}function C(a,e){return`manager-inbox:${R("sha256").update(a).update("\0").update(e.map(r=>r.id).join("\0")).digest("hex").slice(0,32)}`}async function O(a){const e=[];let t=0;for await(const r of a){const n=Buffer.isBuffer(r)?r:Buffer.from(r);if(t+=n.length,t>W)throw new Error("Request body too large");e.push(n)}return e.length===0?{}:JSON.parse(Buffer.concat(e).toString("utf8"))}function H(a,e,t,r){a.client.sendRes({type:"res",id:e,ok:t,...t?{payload:r}:{error:String(r.error||"unknown error")}})}function v(){return B()?f.join(M.tmpdir(),"shennian-vitest-runtime",String(process.pid),"manager-ipc.json"):x("runtime","manager-ipc.json")}function B(){return(process.env.VITEST==="true"||!!process.env.VITEST_WORKER_ID)&&!process.env.SHENNIAN_HOME?.trim()}class re{opts;managedPolicies=new Map;registry=new S;channelRuntime;server=null;ipcUrl=null;ipcToken=A(24).toString("hex");healthTimer=null;startPromise=null;workerTextAcc=new Map;constructor(e){this.opts=e,this.channelRuntime=e.channelRuntime??new N}async start(){return this.startPromise?this.startPromise:(this.startPromise=this.doStart(),this.startPromise)}async doStart(){if(this.server)return;this.server=E.createServer((t,r)=>{this.handleIpc(t,r)}),this.server.requestTimeout=m,this.server.timeout=m,this.server.keepAliveTimeout=m,this.server.headersTimeout=m+5e3,await new Promise((t,r)=>{this.server.once("error",r),this.server.listen(0,"127.0.0.1",()=>t())});const e=this.server.address();typeof e=="object"&&e&&(this.ipcUrl=`http://127.0.0.1:${e.port}`,this.writeIpcRuntimeFile()),this.server.unref(),await this.channelRuntime.start(),this.healthTimer=setInterval(()=>this.scanWorkerHealth(),6e4),this.healthTimer.unref(),this.recoverPersistedInboxDeliveries()}async ready(){await this.start()}async stop(){this.healthTimer&&clearInterval(this.healthTimer),this.healthTimer=null,await this.channelRuntime.stop(),await new Promise(e=>{if(!this.server)return e();this.server.close(()=>e())}),this.server=null,this.ipcUrl=null,this.removeIpcRuntimeFile()}writeIpcRuntimeFile(){if(this.ipcUrl)try{const e=v();h.mkdirSync(f.dirname(e),{recursive:!0}),h.writeFileSync(e,JSON.stringify({url:this.ipcUrl,token:this.ipcToken,pid:process.pid,updatedAt:new Date().toISOString()},null,2),{mode:384}),h.chmodSync(e,384)}catch{}}removeIpcRuntimeFile(){try{const e=v(),t=JSON.parse(h.readFileSync(e,"utf-8"));(t.url===this.ipcUrl||t.token===this.ipcToken)&&h.unlinkSync(e)}catch{}}getInjectedEnv(e,t,r,n){return this.ipcUrl?{SHENNIAN_MANAGER_SESSION_ID:e,SHENNIAN_MANAGER_AGENT_SESSION_ID:t??"",SHENNIAN_MANAGER_WORKDIR:g(r),SHENNIAN_MANAGER_MODEL:n,SHENNIAN_MANAGER_IPC_URL:this.ipcUrl,SHENNIAN_MANAGER_IPC_TOKEN:this.ipcToken}:{}}registerManager(e){this.registry.upsertManager({...e,workDir:g(e.workDir),machineId:process.env.SHENNIAN_MACHINE_ID??null,managedRoomBound:e.managedRoomBound??(this.managedPolicies.has(e.sessionId)||void 0)})}setManagedAgentPolicy(e,t){if(t){this.managedPolicies.set(e,t);const r=this.registry.getManager(e);r&&!r.managedRoomBound&&this.registry.upsertManager({...r,managedRoomBound:!0})}else this.managedPolicies.delete(e)}getManagedAgentPolicyForWorker(e,t){const r=this.registry.getManager(e),n=this.managedPolicies.get(e);return!r||!n||g(t)!==r.workDir?null:n}isNativeSkillManager(e,t){const r=this.registry.getManager(e);return r?.controllerKind==="native_skill"&&g(t)===r.workDir}setManagerWorkerDefaults(e,t,r){const n=this.registry.getManager(e);n&&this.registry.upsertManager({...n,defaultWorkerAgentType:t??null,defaultWorkerModelId:r??null})}getManagerWorkerDefaults(e){const t=this.registry.getManager(e);return{agentType:t?.defaultWorkerAgentType??null,modelId:t?.defaultWorkerModelId??null}}noteManagerAgentSession(e,t,r,n){const s=this.registry.getManager(e);this.registry.upsertManager({sessionId:e,agentSessionId:t,workDir:g(r),machineId:process.env.SHENNIAN_MACHINE_ID??null,modelId:n,agentType:s?.agentType,providerModelId:s?.providerModelId})}noteAgentEvent(e,t){const r=this.findWorker(e);if(!r)return;const n={lastActivityAt:new Date().toISOString(),runId:t.runId};t.agentSessionId&&(n.agentSessionId=t.agentSessionId);const s=`${e}:${t.runId}`;let o=t.message||r.summary||"(\u65E0\u53EF\u89C1\u5185\u5BB9)";if(t.state==="delta"&&t.text&&!t.thinking){const u=(this.workerTextAcc.get(s)??"")+t.text;this.workerTextAcc.set(s,u);const i=I(u);i&&(n.summary=i.length>160?`${i.slice(0,160)}...`:i)}if(t.state==="final"||t.state==="error"||t.state==="aborted"){n.status=t.state;const u=I(this.workerTextAcc.get(s)??"");u&&(n.summary=u.length>240?`${u.slice(0,240)}...`:u,o=t.message||u),this.workerTextAcc.delete(s)}else t.state==="start"&&(n.status="running");const d=this.registry.updateWorker(e,n);d&&(t.state==="final"||t.state==="error"||t.state==="aborted")&&this.enqueueWorkerEvent(d.managedBy,d,t.state,t.runId,o)}findWorker(e){return this.registry.load().workers[e]}async handleAppReq(e){H(this.opts.getRuntime(),e.id,!1,{error:"feature_retired"})}async handleIpc(e,t){if(e.headers.authorization!==`Bearer ${this.ipcToken}`){c(t,401,{ok:!1,error:"Unauthorized"});return}try{const r=new URL(e.url??"/","http://127.0.0.1"),n=await O(e);if(r.pathname.startsWith("/channel/")||r.pathname.startsWith("/external/")||r.pathname.startsWith("/wechat-rpa/")){c(t,410,{ok:!1,error:"feature_retired"});return}const s=await k({registry:this.registry,getRuntime:this.opts.getRuntime,dispatchReq:this.opts.dispatchReq,dispatchChatEnqueue:this.dispatchChatEnqueue.bind(this),appendManagerVisibleMarkdown:this.appendManagerVisibleMarkdown.bind(this)},r.pathname,n,String(e.headers["x-shennian-manager-session-id"]||""));if(s){c(t,s.status,s.body);return}c(t,404,{ok:!1,error:`Unknown manager IPC path: ${r.pathname}`})}catch(r){c(t,400,{ok:!1,error:r instanceof Error?r.message:String(r)})}}async executeScopedWorkerAction(e,t,r){const n={"manager.sessions.list":"/sessions/list","manager.sessions.start":"/sessions/start","manager.sessions.send":"/sessions/send","manager.sessions.queue":"/sessions/queue","manager.sessions.queue.edit":"/sessions/queue/edit","manager.sessions.queue.delete":"/sessions/queue/delete","manager.sessions.stop":"/sessions/stop","manager.sessions.read":"/sessions/read","manager.memory.path":"/memory/path"},s=await k({registry:this.registry,getRuntime:this.opts.getRuntime,dispatchReq:this.opts.dispatchReq,dispatchChatEnqueue:this.dispatchChatEnqueue.bind(this),appendManagerVisibleMarkdown:this.appendManagerVisibleMarkdown.bind(this)},n[t],r,e);if(!s||s.status<200||s.status>=300)throw new Error(String(s?.body.error||"Managed Manager action failed"));return JSON.parse(JSON.stringify(s.body))}async dispatchChatEnqueue(e,t,r,n,s,o,d){if((await this.opts.dispatchReq({type:"req",id:`manager-enqueue-${p()}`,method:"chat.enqueue",params:{...y(),sessionId:e,text:n,agentType:t,workDir:r,agentSessionId:s,modelId:o,managedWorkerParentSessionId:d}}))?.durableQueueHandoff===!1)throw new Error("manager_worker_queue_handoff_unconfirmed")}appendManagerVisibleMarkdown(e,t,r){this.registry.getManager(e)?.controllerKind!=="native_skill"&&(b(e,{id:r,sessionId:e,role:"agent",ts:Date.now(),payload:t},"committed"),_(this.opts.getRuntime().client))}enqueueWorkerEvent(e,t,r,n,s){const o=this.registry.enqueueInboxEvent({managerSessionId:e,workerSessionId:t.sessionId,kind:r==="final"?"worker.final":r==="error"?"worker.error":"worker.aborted",priority:"normal",runId:n??null,summary:s||t.summary||"(\u65E0\u53EF\u89C1\u6458\u8981)"}),d=this.registry.getManager(e);o&&d?.controllerKind!=="native_skill"&&this.drainManagerInbox(e)}scanWorkerHealth(){const e=Date.now(),t=this.registry.load();for(const r of Object.values(t.workers)){if(r.status!=="running")continue;const n=e-Date.parse(r.createdAt);if(n<10*6e4)continue;const s=r.healthNotifiedAt?Date.parse(r.healthNotifiedAt):0;if(s&&e-s<10*6e4)continue;const o=t.managers[r.managedBy];if(!o)continue;const d=Math.max(0,Math.floor((e-Date.parse(r.lastActivityAt))/6e4)),u=I(r.runId?this.workerTextAcc.get(`${r.sessionId}:${r.runId}`)??"":""),i=`\u5DF2\u8FD0\u884C ${Math.floor(n/6e4)} \u5206\u949F\uFF0C\u5C1A\u672A\u7ED3\u675F\u3002
1
+ import _ from"node:http";import{createHash as N,randomBytes as x,randomUUID as f}from"node:crypto";import h from"node:fs";import v from"node:os";import y from"node:path";import{ManagerRegistry as T}from"./registry.js";import{appendMessage as D}from"../session/store.js";import{requestSessionIndexPublish as q}from"../session/index-publisher.js";import{RetiredChannelRuntime as W}from"./retired-external-channel-compat.js";import{resolveShennianPath as P}from"../config/index.js";import{buildExternalChannelInstructions as O}from"../agents/external-channel-instructions.js";import{getPersonalSyncIdentity as I}from"../personal-sync/epoch.js";import{handleWorkerIpcRoute as E}from"./worker-ipc.js";import{deriveWorkerTitle as C,formatWorkerMarkdown as H}from"./worker-markdown.js";const B=Number(process.env.SHENNIAN_MANAGER_IPC_BODY_MAX_BYTES||2*1024*1024),m=12*6e4;let R=null;function ae(o){R=o}function oe(){return R}function c(o){return y.resolve(o||v.homedir())}function g(o,e,t){o.writeHead(e,{"content-type":"application/json; charset=utf-8"}),o.end(JSON.stringify(t))}function M(o){return o.replace(/\r\n/g,`
2
+ `).trim()}function $(o){return o==="worker.final"?"completed":o==="worker.error"?"failed":o==="worker.aborted"?"stopped":"progress"}function U(o,e){return`manager-inbox:${N("sha256").update(o).update("\0").update(e.map(r=>r.id).join("\0")).digest("hex").slice(0,32)}`}async function j(o){const e=[];let t=0;for await(const r of o){const n=Buffer.isBuffer(r)?r:Buffer.from(r);if(t+=n.length,t>B)throw new Error("Request body too large");e.push(n)}return e.length===0?{}:JSON.parse(Buffer.concat(e).toString("utf8"))}function G(o,e,t,r){o.client.sendRes({type:"res",id:e,ok:t,...t?{payload:r}:{error:String(r.error||"unknown error")}})}function A(){return F()?y.join(v.tmpdir(),"shennian-vitest-runtime",String(process.pid),"manager-ipc.json"):P("runtime","manager-ipc.json")}function F(){return(process.env.VITEST==="true"||!!process.env.VITEST_WORKER_ID)&&!process.env.SHENNIAN_HOME?.trim()}class ue{opts;managedPolicies=new Map;registry=new T;channelRuntime;server=null;ipcUrl=null;ipcToken=x(24).toString("hex");healthTimer=null;startPromise=null;workerTextAcc=new Map;constructor(e){this.opts=e,this.channelRuntime=e.channelRuntime??new W}async start(){return this.startPromise?this.startPromise:(this.startPromise=this.doStart(),this.startPromise)}async doStart(){if(this.server)return;this.server=_.createServer((t,r)=>{this.handleIpc(t,r)}),this.server.requestTimeout=m,this.server.timeout=m,this.server.keepAliveTimeout=m,this.server.headersTimeout=m+5e3,await new Promise((t,r)=>{this.server.once("error",r),this.server.listen(0,"127.0.0.1",()=>t())});const e=this.server.address();typeof e=="object"&&e&&(this.ipcUrl=`http://127.0.0.1:${e.port}`,this.writeIpcRuntimeFile()),this.server.unref(),await this.channelRuntime.start(),this.healthTimer=setInterval(()=>this.scanWorkerHealth(),6e4),this.healthTimer.unref(),this.recoverPersistedInboxDeliveries()}async ready(){await this.start()}async stop(){this.healthTimer&&clearInterval(this.healthTimer),this.healthTimer=null,await this.channelRuntime.stop(),await new Promise(e=>{if(!this.server)return e();this.server.close(()=>e())}),this.server=null,this.ipcUrl=null,this.removeIpcRuntimeFile()}writeIpcRuntimeFile(){if(this.ipcUrl)try{const e=A();h.mkdirSync(y.dirname(e),{recursive:!0}),h.writeFileSync(e,JSON.stringify({url:this.ipcUrl,token:this.ipcToken,pid:process.pid,updatedAt:new Date().toISOString()},null,2),{mode:384}),h.chmodSync(e,384)}catch{}}removeIpcRuntimeFile(){try{const e=A(),t=JSON.parse(h.readFileSync(e,"utf-8"));(t.url===this.ipcUrl||t.token===this.ipcToken)&&h.unlinkSync(e)}catch{}}getInjectedEnv(e,t,r,n){return this.ipcUrl?{SHENNIAN_MANAGER_SESSION_ID:e,SHENNIAN_MANAGER_AGENT_SESSION_ID:t??"",SHENNIAN_MANAGER_WORKDIR:c(r),SHENNIAN_MANAGER_MODEL:n,SHENNIAN_MANAGER_IPC_URL:this.ipcUrl,SHENNIAN_MANAGER_IPC_TOKEN:this.ipcToken}:{}}registerManager(e){this.registry.upsertManager({...e,workDir:c(e.workDir),machineId:process.env.SHENNIAN_MACHINE_ID??null,managedRoomBound:e.managedRoomBound??(this.managedPolicies.has(e.sessionId)||void 0)})}setManagedAgentPolicy(e,t){if(t){this.managedPolicies.set(e,t);const r=this.registry.getManager(e);r&&!r.managedRoomBound&&this.registry.upsertManager({...r,managedRoomBound:!0})}else this.managedPolicies.delete(e)}getManagedAgentPolicyForWorker(e,t){const r=this.registry.getManager(e),n=this.managedPolicies.get(e);return!r||!n||c(t)!==r.workDir?null:n}isNativeSkillManager(e,t){const r=this.registry.getManager(e);return r?.controllerKind==="native_skill"&&c(t)===r.workDir}setManagerWorkerDefaults(e,t,r){const n=this.registry.getManager(e);n&&this.registry.upsertManager({...n,defaultWorkerAgentType:t??null,defaultWorkerModelId:r??null})}getManagerWorkerDefaults(e){const t=this.registry.getManager(e);return{agentType:t?.defaultWorkerAgentType??null,modelId:t?.defaultWorkerModelId??null}}noteManagerAgentSession(e,t,r,n){const s=this.registry.getManager(e);this.registry.upsertManager({sessionId:e,agentSessionId:t,workDir:c(r),machineId:process.env.SHENNIAN_MACHINE_ID??null,modelId:n,agentType:s?.agentType,providerModelId:s?.providerModelId})}noteAgentEvent(e,t){const r=this.findWorker(e);if(!r)return;const n={lastActivityAt:new Date().toISOString(),runId:t.runId};t.agentSessionId&&(n.agentSessionId=t.agentSessionId);const s=`${e}:${t.runId}`;let i=t.message||r.summary||"(\u65E0\u53EF\u89C1\u5185\u5BB9)";if(t.state==="delta"&&t.text&&!t.thinking){const u=(this.workerTextAcc.get(s)??"")+t.text;this.workerTextAcc.set(s,u);const a=M(u);a&&(n.summary=a.length>160?`${a.slice(0,160)}...`:a)}if(t.state==="final"||t.state==="error"||t.state==="aborted"){n.status=t.state;const u=M(this.workerTextAcc.get(s)??"");u&&(n.summary=u.length>240?`${u.slice(0,240)}...`:u,i=t.message||u),this.workerTextAcc.delete(s)}else t.state==="start"&&(n.status="running");const d=this.registry.updateWorker(e,n);d&&(t.state==="final"||t.state==="error"||t.state==="aborted")&&this.enqueueWorkerEvent(d.managedBy,d,t.state,t.runId,i)}findWorker(e){return this.registry.load().workers[e]}async handleAppReq(e){G(this.opts.getRuntime(),e.id,!1,{error:"feature_retired"})}async handleIpc(e,t){if(e.headers.authorization!==`Bearer ${this.ipcToken}`){g(t,401,{ok:!1,error:"Unauthorized"});return}try{const r=new URL(e.url??"/","http://127.0.0.1"),n=await j(e);if(r.pathname.startsWith("/channel/")||r.pathname.startsWith("/external/")||r.pathname.startsWith("/wechat-rpa/")){g(t,410,{ok:!1,error:"feature_retired"});return}const s=await E({registry:this.registry,getRuntime:this.opts.getRuntime,dispatchReq:this.opts.dispatchReq,dispatchChatEnqueue:this.dispatchChatEnqueue.bind(this),appendManagerVisibleMarkdown:this.appendManagerVisibleMarkdown.bind(this)},r.pathname,n,String(e.headers["x-shennian-manager-session-id"]||""));if(s){g(t,s.status,s.body);return}g(t,404,{ok:!1,error:`Unknown manager IPC path: ${r.pathname}`})}catch(r){g(t,400,{ok:!1,error:r instanceof Error?r.message:String(r)})}}async executeScopedWorkerAction(e,t,r){const n={"manager.sessions.list":"/sessions/list","manager.sessions.start":"/sessions/start","manager.sessions.send":"/sessions/send","manager.sessions.queue":"/sessions/queue","manager.sessions.queue.edit":"/sessions/queue/edit","manager.sessions.queue.delete":"/sessions/queue/delete","manager.sessions.stop":"/sessions/stop","manager.sessions.read":"/sessions/read","manager.memory.path":"/memory/path"},s=await E({registry:this.registry,getRuntime:this.opts.getRuntime,dispatchReq:this.opts.dispatchReq,dispatchChatEnqueue:this.dispatchChatEnqueue.bind(this),appendManagerVisibleMarkdown:this.appendManagerVisibleMarkdown.bind(this)},n[t],r,e);if(!s||s.status<200||s.status>=300)throw new Error(String(s?.body.error||"Managed Manager action failed"));return JSON.parse(JSON.stringify(s.body))}async dispatchChatEnqueue(e,t,r,n,s,i,d){if((await this.opts.dispatchReq({type:"req",id:`manager-enqueue-${f()}`,method:"chat.enqueue",params:{...I(),sessionId:e,text:n,agentType:t,workDir:r,agentSessionId:s,modelId:i,managedWorkerParentSessionId:d}}))?.durableQueueHandoff===!1)throw new Error("manager_worker_queue_handoff_unconfirmed")}appendManagerVisibleMarkdown(e,t,r){this.registry.getManager(e)?.controllerKind!=="native_skill"&&(D(e,{id:r,sessionId:e,role:"agent",ts:Date.now(),payload:t},"committed"),q(this.opts.getRuntime().client))}enqueueWorkerEvent(e,t,r,n,s){const i=this.registry.enqueueInboxEvent({managerSessionId:e,workerSessionId:t.sessionId,kind:r==="final"?"worker.final":r==="error"?"worker.error":"worker.aborted",priority:"normal",runId:n??null,summary:s||t.summary||"(\u65E0\u53EF\u89C1\u6458\u8981)"}),d=this.registry.getManager(e);i&&d?.controllerKind!=="native_skill"&&this.drainManagerInbox(e)}scanWorkerHealth(){const e=Date.now(),t=this.registry.load(),r=this.opts.getRuntime();for(const n of Object.values(t.workers)){if(n.status!=="running")continue;const s=e-Date.parse(n.createdAt);if(s<10*6e4)continue;const i=e-Date.parse(n.lastActivityAt),d=r.sessions.get(n.sessionId)?.currentRunId,u=!!r.chatQueue?.getSnapshot(n.sessionId).pending.length;if(!d){if(!u&&i>=10*6e4){const w="\u672A\u627E\u5230\u6D3B\u52A8\u4E2D\u7684 Provider Run \u6216\u5F85\u5904\u7406\u6D88\u606F\uFF1B\u5DF2\u5C06\u9057\u7559\u7684\u8FD0\u884C\u72B6\u6001\u6536\u655B\u4E3A\u5931\u8D25\u3002\u539F Worker \u4F1A\u8BDD\u4ECD\u4FDD\u7559\uFF0C\u53EF\u7EE7\u7EED\u53D1\u9001\u65B0\u6D88\u606F\u3002",p=this.registry.updateWorker(n.sessionId,{status:"error",lastActivityAt:new Date(e).toISOString(),summary:w});p&&this.enqueueWorkerEvent(p.managedBy,p,"error",n.runId??void 0,w)}continue}const a=n.healthNotifiedAt?Date.parse(n.healthNotifiedAt):0;if(a&&e-a<10*6e4)continue;const l=t.managers[n.managedBy];if(!l)continue;const S=Math.max(0,Math.floor(i/6e4)),b=M(n.runId?this.workerTextAcc.get(`${n.sessionId}:${n.runId}`)??"":""),k=`\u5DF2\u8FD0\u884C ${Math.floor(s/6e4)} \u5206\u949F\uFF0C\u5C1A\u672A\u7ED3\u675F\u3002
3
3
 
4
4
  \u5F53\u524D\u53EF\u89C1\u8FDB\u5C55\uFF1A
5
- - \u6700\u8FD1\u6587\u672C\uFF1A${u||r.summary||"(\u65E0\u53EF\u89C1\u5185\u5BB9)"}
6
- - \u6700\u8FD1\u6D3B\u52A8\u65F6\u95F4\uFF1A${r.lastActivityAt}
7
- - \u6700\u8FD1 ${d} \u5206\u949F\u6CA1\u6709\u65B0\u6D3B\u52A8\u3002`;this.registry.updateWorker(r.sessionId,{healthNotifiedAt:new Date(e).toISOString(),lastHealthSummary:i}),this.registry.enqueueInboxEvent({managerSessionId:o.sessionId,workerSessionId:r.sessionId,kind:"worker.health",priority:"normal",runId:r.runId??null,summary:i})&&o.controllerKind!=="native_skill"&&this.drainManagerInbox(o.sessionId)}}async interruptAndResumeManager(e,t,r){this.opts.getRuntime().sessions.get(e.sessionId)?.currentRunId&&await this.opts.dispatchReq({type:"req",id:`manager-interrupt-${p()}`,method:"chat.abort",params:{...y(),sessionId:e.sessionId}}),await this.dispatchManagerContinuation(e,t,!1,r)}bindManagerAdapterEvents(e,t){t.on("agentEvent",r=>{if(r.state==="start"&&r.agentSessionId){const n=this.registry.getManager(e);n&&this.noteManagerAgentSession(e,r.agentSessionId,n.workDir,n.modelId)}r.state==="start"&&(this.acknowledgeManagerInboxDelivery(e),this.updateManagerStatus(e,"running")),(r.state==="final"||r.state==="error"||r.state==="aborted")&&(this.updateManagerStatus(e,"idle"),queueMicrotask(()=>{this.drainManagerInbox(e)}))})}updateManagerStatus(e,t){const r=this.registry.getManager(e);r&&this.registry.upsertManager({...r,status:t})}async drainManagerInbox(e){const t=this.registry.getManager(e);if(!t||t.deliveringInboxEventIds?.length)return;const r=this.registry.listInboxEvents(e);if(!r.length)return;const n=r.find(i=>i.priority==="high"),s=this.opts.getRuntime().sessions.get(e);if(t.status!=="idle"&&!n||s?.currentRunId&&!n)return;const o=n?[n]:r.slice(0,20),d=o.map(i=>{const l=this.registry.getWorkerForManager(e,i.workerSessionId);return q({kind:P(i.kind),sessionId:i.workerSessionId,title:l?.title||D(l?.userGoal||l?.summary||i.summary),body:i.summary})}).join(`
5
+ - \u6700\u8FD1\u6587\u672C\uFF1A${b||n.summary||"(\u65E0\u53EF\u89C1\u5185\u5BB9)"}
6
+ - \u6700\u8FD1\u6D3B\u52A8\u65F6\u95F4\uFF1A${n.lastActivityAt}
7
+ - \u6700\u8FD1 ${S} \u5206\u949F\u6CA1\u6709\u65B0\u6D3B\u52A8\u3002`;this.registry.updateWorker(n.sessionId,{healthNotifiedAt:new Date(e).toISOString(),lastHealthSummary:k}),this.registry.enqueueInboxEvent({managerSessionId:l.sessionId,workerSessionId:n.sessionId,kind:"worker.health",priority:"normal",runId:n.runId??null,summary:k})&&l.controllerKind!=="native_skill"&&this.drainManagerInbox(l.sessionId)}}async interruptAndResumeManager(e,t,r){this.opts.getRuntime().sessions.get(e.sessionId)?.currentRunId&&await this.opts.dispatchReq({type:"req",id:`manager-interrupt-${f()}`,method:"chat.abort",params:{...I(),sessionId:e.sessionId}}),await this.dispatchManagerContinuation(e,t,!1,r)}bindManagerAdapterEvents(e,t){t.on("agentEvent",r=>{if(r.state==="start"&&r.agentSessionId){const n=this.registry.getManager(e);n&&this.noteManagerAgentSession(e,r.agentSessionId,n.workDir,n.modelId)}r.state==="start"&&(this.acknowledgeManagerInboxDelivery(e),this.updateManagerStatus(e,"running")),(r.state==="final"||r.state==="error"||r.state==="aborted")&&(this.updateManagerStatus(e,"idle"),queueMicrotask(()=>{this.drainManagerInbox(e)}))})}updateManagerStatus(e,t){const r=this.registry.getManager(e);r&&this.registry.upsertManager({...r,status:t})}async drainManagerInbox(e){const t=this.registry.getManager(e);if(!t||t.deliveringInboxEventIds?.length)return;const r=this.registry.listInboxEvents(e);if(!r.length)return;const n=r.find(a=>a.priority==="high"),s=this.opts.getRuntime().sessions.get(e);if(t.status!=="idle"&&!n||s?.currentRunId&&!n)return;const i=n?[n]:r.slice(0,20),d=i.map(a=>{const l=this.registry.getWorkerForManager(e,a.workerSessionId);return H({kind:$(a.kind),sessionId:a.workerSessionId,title:l?.title||C(l?.userGoal||l?.summary||a.summary),body:a.summary})}).join(`
8
8
 
9
9
  ---
10
10
 
11
- `),u=C(e,o);try{n&&s?.currentRunId?(this.registry.upsertManager({...t,status:"interrupting",deliveringInboxEventIds:o.map(l=>l.id)}),await this.interruptAndResumeManager(t,d,u)):(this.registry.upsertManager({...t,status:"running",deliveringInboxEventIds:o.map(l=>l.id)}),await this.dispatchManagerContinuation(t,d,!0,u)),this.registry.removeInboxEvents(e,o.map(l=>l.id));const i=this.registry.getManager(e);i&&this.registry.upsertManager({...i,deliveringInboxEventIds:[]})}catch(i){this.registry.upsertManager({...t,status:"idle",deliveringInboxEventIds:[]}),console.error(`[manager-inbox] delivery failed sessionId=${e}: ${i instanceof Error?i.message:String(i)}`)}}acknowledgeManagerInboxDelivery(e){const t=this.registry.getManager(e),r=t?.deliveringInboxEventIds??[];!t||r.length===0||(this.registry.removeInboxEvents(e,r),this.registry.upsertManager({...t,deliveringInboxEventIds:[]}))}recoverPersistedInboxDeliveries(){const e=this.registry.load();for(const t of Object.values(e.managers))this.opts.getRuntime().sessions.get(t.sessionId)?.currentRunId||((t.status!=="idle"||t.deliveringInboxEventIds?.length)&&this.registry.upsertManager({...t,status:"idle",deliveringInboxEventIds:[]}),this.registry.listInboxEvents(t.sessionId).length>0&&queueMicrotask(()=>{this.drainManagerInbox(t.sessionId)}))}async dispatchManagerContinuation(e,t,r=!1,n){const s=e.agentType??"manager",o=s==="manager"?e.modelId:e.providerModelId??void 0,d={...y(),sessionId:e.sessionId,text:t,agentType:s,sessionMode:"manager",workDir:e.workDir,agentSessionId:e.agentSessionId,modelId:o,managerDefaultWorkerAgentType:e.defaultWorkerAgentType??null,managerDefaultWorkerModelId:e.defaultWorkerModelId??null,...e.managedRoomBound?{managedAgentDirect:!0}:{},clientMessageId:n,managerEventId:n};if((await this.opts.dispatchReq({type:"req",id:`manager-${r?"enqueue":"send"}-${p()}`,method:"chat.enqueue",params:d}))?.durableQueueHandoff===!1)throw new Error("manager_event_queue_handoff_unconfirmed")}getExternalChannelStatus(e){return this.channelRuntime.getManagerChannelStatus(e)}getManagerExternalChannelSystemPrompt(e){return this.channelRuntime.listManagerExternalChannels(e).map(t=>T(t,void 0,e,"manager")).join(`
11
+ `),u=U(e,i);try{n&&s?.currentRunId?(this.registry.upsertManager({...t,status:"interrupting",deliveringInboxEventIds:i.map(l=>l.id)}),await this.interruptAndResumeManager(t,d,u)):(this.registry.upsertManager({...t,status:"running",deliveringInboxEventIds:i.map(l=>l.id)}),await this.dispatchManagerContinuation(t,d,!0,u)),this.registry.removeInboxEvents(e,i.map(l=>l.id));const a=this.registry.getManager(e);a&&this.registry.upsertManager({...a,deliveringInboxEventIds:[]})}catch(a){this.registry.upsertManager({...t,status:"idle",deliveringInboxEventIds:[]}),console.error(`[manager-inbox] delivery failed sessionId=${e}: ${a instanceof Error?a.message:String(a)}`)}}acknowledgeManagerInboxDelivery(e){const t=this.registry.getManager(e),r=t?.deliveringInboxEventIds??[];!t||r.length===0||(this.registry.removeInboxEvents(e,r),this.registry.upsertManager({...t,deliveringInboxEventIds:[]}))}recoverPersistedInboxDeliveries(){const e=this.registry.load(),t=this.opts.getRuntime();for(const r of Object.values(e.managers)){if(t.sessions.get(r.sessionId)?.currentRunId)continue;(r.status!=="idle"||r.deliveringInboxEventIds?.length)&&this.registry.upsertManager({...r,status:"idle",deliveringInboxEventIds:[]});const s=this.registry.listInboxEvents(r.sessionId).filter(i=>i.kind==="worker.health"&&!t.sessions.get(i.workerSessionId)?.currentRunId).map(i=>i.id);this.registry.removeInboxEvents(r.sessionId,s),this.registry.listInboxEvents(r.sessionId).length>0&&queueMicrotask(()=>{this.drainManagerInbox(r.sessionId)})}}async dispatchManagerContinuation(e,t,r=!1,n){const s=e.agentType??"manager",i=s==="manager"?e.modelId:e.providerModelId??void 0,d={...I(),sessionId:e.sessionId,text:t,agentType:s,sessionMode:"manager",workDir:e.workDir,agentSessionId:e.agentSessionId,modelId:i,managerDefaultWorkerAgentType:e.defaultWorkerAgentType??null,managerDefaultWorkerModelId:e.defaultWorkerModelId??null,...e.managedRoomBound?{managedAgentDirect:!0}:{},clientMessageId:n,managerEventId:n};if((await this.opts.dispatchReq({type:"req",id:`manager-${r?"enqueue":"send"}-${f()}`,method:"chat.enqueue",params:d}))?.durableQueueHandoff===!1)throw new Error("manager_event_queue_handoff_unconfirmed")}getExternalChannelStatus(e){return this.channelRuntime.getManagerChannelStatus(e)}getManagerExternalChannelSystemPrompt(e){return this.channelRuntime.listManagerExternalChannels(e).map(t=>O(t,void 0,e,"manager")).join(`
12
12
 
13
- `).trim()}}export{re as ManagerRuntimeService,te as getManagerRuntimeService,ee as setManagerRuntimeService};
13
+ `).trim()}}export{ue as ManagerRuntimeService,oe as getManagerRuntimeService,ae as setManagerRuntimeService};
@@ -1 +1 @@
1
- import w from"node:path";import{createHash as h,randomUUID as f}from"node:crypto";import{AVAILABLE_BUILTIN_AGENT_TYPES as M,extractPayloadText as q,isAgentHiddenPayload as W,isToolPayload as _}from"@shennian/wire";import{loadConfig as E}from"../config/index.js";import{getPersonalSyncIdentity as y}from"../personal-sync/epoch.js";import{readMessages as T,recordSession as v}from"../session/store.js";import{deriveWorkerTitle as c,formatWorkerMarkdown as k,normalizeWorkerTitle as x}from"./worker-markdown.js";function S(e){return w.resolve(e||process.cwd())}function b(e){return e==="manager"||e==="pi"?!1:e.startsWith("custom:")?!0:M.includes(e)}function D(e){return e==="worker.final"?"completed":e==="worker.error"?"failed":e==="worker.aborted"?"stopped":"progress"}function A(e,a){const s=[];for(const g of e)if(!W(g.payload))if(_(g.payload)){let o="tool",l="completed";try{const u=JSON.parse(g.payload);o=u.name||o,l=u.status||l}catch{}s.push({...g,payload:`[\u5DE5\u5177] ${o} \xB7 ${l}`})}else s.push({...g,payload:q(g.payload)});return s.slice(-Math.max(1,Math.min(a,500)))}async function K(e,a,s,g){if(a==="/skill/context"){const r=E(),n=String(s.host||""),i=String(s.hostSessionId||""),d=S(String(s.workDir||""));if(!r.machineId||!r.machineToken&&!r.accessToken)throw new Error("Shennian CLI must be paired and logged in");if(n!=="codex"&&n!=="claude")throw new Error("unsupported_native_agent_host");if(!i)throw new Error("native_agent_session_unavailable");if(!d||!w.isAbsolute(d))throw new Error("workDir is required");const m=`skill_manager_${h("sha256").update(r.machineId).update("\0").update(n).update("\0").update(i).update("\0").update(d).digest("hex").slice(0,32)}`;return e.registry.upsertManager({sessionId:m,agentSessionId:null,workDir:d,machineId:r.machineId,modelId:n,agentType:n,controllerKind:"native_skill",status:"idle"}),{status:200,body:{ok:!0,managerSessionId:m}}}if(!a.startsWith("/sessions/")&&a!=="/memory/path")return null;const o=String(s.managerSessionId||g||"");if(!o)throw new Error("managerSessionId is required");const l=e.registry.getManager(o);if(!l)throw new Error("Manager runtime is not registered");if(a==="/sessions/list"){const r=new Set(e.getRuntime().sessions.keys()),n=e.registry.listWorkers(o,{runningSessionIds:r});return{status:200,body:{ok:!0,sessions:l.controllerKind==="native_skill"?n.filter(d=>d.role==="managed_worker"&&d.managedBy===o):n}}}if(a==="/memory/path")return{status:200,body:{ok:!0,path:w.join(l.workDir,".shennian")}};if(a==="/sessions/start"){const r=String(s.agentType||s.agent||l.defaultWorkerAgentType||"codex");if(!b(r))throw new Error(`Unsupported manager worker agent: ${r}`);const n=S(String(s.workDir||l.workDir));if(n!==l.workDir)throw new Error("Manager can only start workers in the same workDir");const i=String(s.message||"");if(!i)throw new Error("message is required");const d=s.title?x(String(s.title)):c(i),m=e.registry.addWorker({managerSessionId:o,agentType:r,workDir:n,title:d,summary:i.slice(0,120)}),p=String(s.modelId||(r===l.defaultWorkerAgentType?l.defaultWorkerModelId??"":""));v({sessionId:m.sessionId,agentType:r,workDir:n,agentSessionId:null,modelId:p||null,title:d,titleSource:"shennian_generated"}),await e.dispatchChatEnqueue(m.sessionId,r,n,i,null,p||void 0,o);const I=k({kind:"created",sessionId:m.sessionId,title:d,body:i});return e.appendManagerVisibleMarkdown(o,I,`worker-created:${m.sessionId}`),{status:200,body:{ok:!0,session:m,markdown:I}}}const u=String(s.sessionId||""),t=e.registry.getWorkerForManager(o,u);if(!t||l.controllerKind==="native_skill"&&(t.role!=="managed_worker"||t.managedBy!==o))throw new Error("Worker not found in this manager scope");if(a==="/sessions/send"){const r=String(s.message||"");if(!r.trim())throw new Error("message is required");const n=s.enqueue===void 0?!0:!!s.enqueue,i=String(s.modelId||(t.agentType===l.defaultWorkerAgentType?l.defaultWorkerModelId??"":""));await e.dispatchChatEnqueue(t.sessionId,t.agentType,t.workDir,r,t.agentSessionId??null,i||void 0,o);const d=k({kind:"message",sessionId:u,title:t.title||c(t.userGoal||t.summary||r),body:r});return e.appendManagerVisibleMarkdown(o,d,`worker-message:${f()}`),{status:200,body:{ok:!0,markdown:d,queued:!0,directRequested:!n}}}if(a==="/sessions/queue")return{status:200,body:{ok:!0,queue:e.getRuntime().chatQueue?.getSnapshot(u)}};if(a==="/sessions/queue/edit"||a==="/sessions/queue/delete"){const r=a.endsWith("/edit");return await e.dispatchReq({type:"req",id:`manager-queue-${r?"edit":"delete"}-${f()}`,method:r?"chat.queue.edit":"chat.queue.delete",params:{...y(),sessionId:u,queueMessageId:String(s.queueMessageId||s.messageId||""),...r?{text:String(s.message||s.text||"")}:{}}}),{status:200,body:{ok:!0,queue:e.getRuntime().chatQueue?.getSnapshot(u)}}}if(a==="/sessions/stop"||a==="/sessions/terminate"){if(t.status==="final"||t.status==="error"||t.status==="aborted"){const r=t.status==="final"?"completed":t.status==="error"?"failed":"stopped";return{status:200,body:{ok:!0,alreadyTerminal:!0,status:t.status,markdown:k({kind:r,sessionId:u,title:t.title||c(t.userGoal||t.summary||""),body:t.summary||"\u672C\u6B21\u6267\u884C\u5DF2\u7ECF\u7ED3\u675F\u3002"})}}}return await e.dispatchReq({type:"req",id:`manager-abort-${f()}`,method:"chat.abort",params:{...y(),sessionId:u}}),e.registry.updateWorker(u,{status:"aborted"}),{status:200,body:{ok:!0,markdown:k({kind:"stopped",sessionId:u,title:t.title||c(t.userGoal||t.summary||""),body:"\u5DF2\u505C\u6B62\u672C\u6B21\u6267\u884C\u3002"})}}}if(a==="/sessions/read"){const r=Number(s.limit||200),n=T(u,{limit:Math.max(r*20,r)});return{status:200,body:{ok:!0,messages:A(n,r),rawMessageCount:n.length}}}if(a==="/sessions/wait"){const r=Math.max(1e3,Math.min(Number(s.timeoutMs||6e5),6e5)),n=Date.now()+r;let i;for(;Date.now()<n&&(i=e.registry.listInboxEvents(o).find(m=>m.workerSessionId===u),!i);)await new Promise(m=>setTimeout(m,1e3));if(!i)return{status:200,body:{ok:!0,timedOut:!0,status:e.registry.getWorkerForManager(o,u)?.status}};const d=k({kind:D(i.kind),sessionId:u,title:t.title||c(t.userGoal||t.summary||i.summary),body:i.summary});return e.registry.removeInboxEvents(o,[i.id]),{status:200,body:{ok:!0,timedOut:!1,markdown:d,event:i}}}return null}export{K as handleWorkerIpcRoute};
1
+ import f from"node:path";import{createHash as h,randomUUID as w}from"node:crypto";import{AVAILABLE_BUILTIN_AGENT_TYPES as M,extractPayloadText as q,isAgentHiddenPayload as W,isToolPayload as _}from"@shennian/wire";import{loadConfig as E}from"../config/index.js";import{getPersonalSyncIdentity as y}from"../personal-sync/epoch.js";import{readMessages as T,recordSession as v}from"../session/store.js";import{deriveWorkerTitle as c,formatWorkerMarkdown as k,normalizeWorkerTitle as x}from"./worker-markdown.js";function S(e){return f.resolve(e||process.cwd())}function b(e){return e==="manager"||e==="pi"?!1:e.startsWith("custom:")?!0:M.includes(e)}function D(e){return e==="worker.final"?"completed":e==="worker.error"?"failed":e==="worker.aborted"?"stopped":"progress"}function A(e,u){const s=[];for(const g of e)if(!W(g.payload))if(_(g.payload)){let a="tool",l="completed";try{const d=JSON.parse(g.payload);a=d.name||a,l=d.status||l}catch{}s.push({...g,payload:`[\u5DE5\u5177] ${a} \xB7 ${l}`})}else s.push({...g,payload:q(g.payload)});return s.slice(-Math.max(1,Math.min(u,500)))}async function K(e,u,s,g){if(u==="/skill/context"){const r=E(),n=String(s.host||""),i=String(s.hostSessionId||""),o=S(String(s.workDir||""));if(!r.machineId||!r.machineToken&&!r.accessToken)throw new Error("Shennian CLI must be paired and logged in");if(n!=="codex"&&n!=="claude")throw new Error("unsupported_native_agent_host");if(!i)throw new Error("native_agent_session_unavailable");if(!o||!f.isAbsolute(o))throw new Error("workDir is required");const m=`skill_manager_${h("sha256").update(r.machineId).update("\0").update(n).update("\0").update(i).update("\0").update(o).digest("hex").slice(0,32)}`;return e.registry.upsertManager({sessionId:m,agentSessionId:null,workDir:o,machineId:r.machineId,modelId:n,agentType:n,controllerKind:"native_skill",status:"idle"}),{status:200,body:{ok:!0,managerSessionId:m}}}if(!u.startsWith("/sessions/")&&u!=="/memory/path")return null;const a=String(s.managerSessionId||g||"");if(!a)throw new Error("managerSessionId is required");const l=e.registry.getManager(a);if(!l)throw new Error("Manager runtime is not registered");if(u==="/sessions/list"){const r=new Set([...e.getRuntime().sessions.entries()].filter(([,o])=>!!o.currentRunId).map(([o])=>o)),n=e.registry.listWorkers(a,{runningSessionIds:r});return{status:200,body:{ok:!0,sessions:l.controllerKind==="native_skill"?n.filter(o=>o.role==="managed_worker"&&o.managedBy===a):n}}}if(u==="/memory/path")return{status:200,body:{ok:!0,path:f.join(l.workDir,".shennian")}};if(u==="/sessions/start"){const r=String(s.agentType||s.agent||l.defaultWorkerAgentType||"codex");if(!b(r))throw new Error(`Unsupported manager worker agent: ${r}`);const n=S(String(s.workDir||l.workDir));if(n!==l.workDir)throw new Error("Manager can only start workers in the same workDir");const i=String(s.message||"");if(!i)throw new Error("message is required");const o=s.title?x(String(s.title)):c(i),m=e.registry.addWorker({managerSessionId:a,agentType:r,workDir:n,title:o,summary:i.slice(0,120)}),p=String(s.modelId||(r===l.defaultWorkerAgentType?l.defaultWorkerModelId??"":""));v({sessionId:m.sessionId,agentType:r,workDir:n,agentSessionId:null,modelId:p||null,title:o,titleSource:"shennian_generated"}),await e.dispatchChatEnqueue(m.sessionId,r,n,i,null,p||void 0,a);const I=k({kind:"created",sessionId:m.sessionId,title:o,body:i});return e.appendManagerVisibleMarkdown(a,I,`worker-created:${m.sessionId}`),{status:200,body:{ok:!0,session:m,markdown:I}}}const d=String(s.sessionId||""),t=e.registry.getWorkerForManager(a,d);if(!t||l.controllerKind==="native_skill"&&(t.role!=="managed_worker"||t.managedBy!==a))throw new Error("Worker not found in this manager scope");if(u==="/sessions/send"){const r=String(s.message||"");if(!r.trim())throw new Error("message is required");const n=s.enqueue===void 0?!0:!!s.enqueue,i=String(s.modelId||(t.agentType===l.defaultWorkerAgentType?l.defaultWorkerModelId??"":""));await e.dispatchChatEnqueue(t.sessionId,t.agentType,t.workDir,r,t.agentSessionId??null,i||void 0,a);const o=k({kind:"message",sessionId:d,title:t.title||c(t.userGoal||t.summary||r),body:r});return e.appendManagerVisibleMarkdown(a,o,`worker-message:${w()}`),{status:200,body:{ok:!0,markdown:o,queued:!0,directRequested:!n}}}if(u==="/sessions/queue")return{status:200,body:{ok:!0,queue:e.getRuntime().chatQueue?.getSnapshot(d)}};if(u==="/sessions/queue/edit"||u==="/sessions/queue/delete"){const r=u.endsWith("/edit");return await e.dispatchReq({type:"req",id:`manager-queue-${r?"edit":"delete"}-${w()}`,method:r?"chat.queue.edit":"chat.queue.delete",params:{...y(),sessionId:d,queueMessageId:String(s.queueMessageId||s.messageId||""),...r?{text:String(s.message||s.text||"")}:{}}}),{status:200,body:{ok:!0,queue:e.getRuntime().chatQueue?.getSnapshot(d)}}}if(u==="/sessions/stop"||u==="/sessions/terminate"){if(t.status==="final"||t.status==="error"||t.status==="aborted"){const r=t.status==="final"?"completed":t.status==="error"?"failed":"stopped";return{status:200,body:{ok:!0,alreadyTerminal:!0,status:t.status,markdown:k({kind:r,sessionId:d,title:t.title||c(t.userGoal||t.summary||""),body:t.summary||"\u672C\u6B21\u6267\u884C\u5DF2\u7ECF\u7ED3\u675F\u3002"})}}}return await e.dispatchReq({type:"req",id:`manager-abort-${w()}`,method:"chat.abort",params:{...y(),sessionId:d}}),e.registry.updateWorker(d,{status:"aborted"}),{status:200,body:{ok:!0,markdown:k({kind:"stopped",sessionId:d,title:t.title||c(t.userGoal||t.summary||""),body:"\u5DF2\u505C\u6B62\u672C\u6B21\u6267\u884C\u3002"})}}}if(u==="/sessions/read"){const r=Number(s.limit||200),n=T(d,{limit:Math.max(r*20,r)});return{status:200,body:{ok:!0,messages:A(n,r),rawMessageCount:n.length}}}if(u==="/sessions/wait"){const r=Math.max(1e3,Math.min(Number(s.timeoutMs||6e5),6e5)),n=Date.now()+r;let i;for(;Date.now()<n&&(i=e.registry.listInboxEvents(a).find(m=>m.workerSessionId===d),!i);)await new Promise(m=>setTimeout(m,1e3));if(!i)return{status:200,body:{ok:!0,timedOut:!0,status:e.registry.getWorkerForManager(a,d)?.status}};const o=k({kind:D(i.kind),sessionId:d,title:t.title||c(t.userGoal||t.summary||i.summary),body:i.summary});return e.registry.removeInboxEvents(a,[i.id]),{status:200,body:{ok:!0,timedOut:!1,markdown:o,event:i}}}return null}export{K as handleWorkerIpcRoute};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shennian",
3
- "version": "0.4.55",
3
+ "version": "0.4.57",
4
4
  "description": "Shennian — AI Agent Control Plane CLI",
5
5
  "type": "module",
6
6
  "bin": {