shennian 0.4.56 → 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,8 +471,8 @@
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",
@@ -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};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shennian",
3
- "version": "0.4.56",
3
+ "version": "0.4.57",
4
4
  "description": "Shennian — AI Agent Control Plane CLI",
5
5
  "type": "module",
6
6
  "bin": {