shennian 0.4.50 → 0.4.51
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
import w from"node:path";import{createHash as S,randomUUID as f}from"node:crypto";import{AVAILABLE_BUILTIN_AGENT_TYPES as h,extractPayloadText as M,isAgentHiddenPayload as q,isToolPayload as W}from"@shennian/wire";import{loadConfig as
|
|
1
|
+
import w from"node:path";import{createHash as S,randomUUID as f}from"node:crypto";import{AVAILABLE_BUILTIN_AGENT_TYPES as h,extractPayloadText as M,isAgentHiddenPayload as q,isToolPayload as W}from"@shennian/wire";import{loadConfig as _}from"../config/index.js";import{readMessages as E,recordSession as T}from"../session/store.js";import{deriveWorkerTitle as c,formatWorkerMarkdown as k,normalizeWorkerTitle as v}from"./worker-markdown.js";function y(e){return w.resolve(e||process.cwd())}function x(e){return e==="manager"||e==="pi"?!1:e.startsWith("custom:")?!0:h.includes(e)}function b(e){return e==="worker.final"?"completed":e==="worker.error"?"failed":e==="worker.aborted"?"stopped":"progress"}function D(e,a){const s=[];for(const g of e)if(!q(g.payload))if(W(g.payload)){let i="tool",l="completed";try{const u=JSON.parse(g.payload);i=u.name||i,l=u.status||l}catch{}s.push({...g,payload:`[\u5DE5\u5177] ${i} \xB7 ${l}`})}else s.push({...g,payload:M(g.payload)});return s.slice(-Math.max(1,Math.min(a,500)))}async function N(e,a,s,g){if(a==="/skill/context"){const r=_(),n=String(s.host||""),o=String(s.hostSessionId||""),d=y(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(!o)throw new Error("native_agent_session_unavailable");if(!d||!w.isAbsolute(d))throw new Error("workDir is required");const m=`skill_manager_${S("sha256").update(r.machineId).update("\0").update(n).update("\0").update(o).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 i=String(s.managerSessionId||g||"");if(!i)throw new Error("managerSessionId is required");const l=e.registry.getManager(i);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(i,{runningSessionIds:r});return{status:200,body:{ok:!0,sessions:l.controllerKind==="native_skill"?n.filter(d=>d.role==="managed_worker"&&d.managedBy===i):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(!x(r))throw new Error(`Unsupported manager worker agent: ${r}`);const n=y(String(s.workDir||l.workDir));if(n!==l.workDir)throw new Error("Manager can only start workers in the same workDir");const o=String(s.message||"");if(!o)throw new Error("message is required");const d=s.title?v(String(s.title)):c(o),m=e.registry.addWorker({managerSessionId:i,agentType:r,workDir:n,title:d,summary:o.slice(0,120)}),p=String(s.modelId||(r===l.defaultWorkerAgentType?l.defaultWorkerModelId??"":""));T({sessionId:m.sessionId,agentType:r,workDir:n,agentSessionId:null,modelId:p||null,title:d,titleSource:"shennian_generated"}),await e.dispatchChatEnqueue(m.sessionId,r,n,o,null,p,i);const I=k({kind:"created",sessionId:m.sessionId,title:d,body:o});return e.appendManagerVisibleMarkdown(i,I,`worker-created:${m.sessionId}`),{status:200,body:{ok:!0,session:m,markdown:I}}}const u=String(s.sessionId||""),t=e.registry.getWorkerForManager(i,u);if(!t||l.controllerKind==="native_skill"&&(t.role!=="managed_worker"||t.managedBy!==i))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,o=String(s.modelId||(t.agentType===l.defaultWorkerAgentType?l.defaultWorkerModelId??"":""));await e.dispatchChatEnqueue(t.sessionId,t.agentType,t.workDir,r,t.agentSessionId??null,o,i);const d=k({kind:"message",sessionId:u,title:t.title||c(t.userGoal||t.summary||r),body:r});return e.appendManagerVisibleMarkdown(i,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:{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:{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=E(u,{limit:Math.max(r*20,r)});return{status:200,body:{ok:!0,messages:D(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 o;for(;Date.now()<n&&(o=e.registry.listInboxEvents(i).find(m=>m.workerSessionId===u),!o);)await new Promise(m=>setTimeout(m,1e3));if(!o)return{status:200,body:{ok:!0,timedOut:!0,status:e.registry.getWorkerForManager(i,u)?.status}};const d=k({kind:b(o.kind),sessionId:u,title:t.title||c(t.userGoal||t.summary||o.summary),body:o.summary});return e.registry.removeInboxEvents(i,[o.id]),{status:200,body:{ok:!0,timedOut:!1,markdown:d,event:o}}}return null}export{N as handleWorkerIpcRoute};
|