shennian 0.3.52 → 0.3.53
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,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
`,{encoding:"utf8",mode:384,flag:"wx"});const i=
|
|
1
|
+
import l from"node:fs";import{randomUUID as y}from"node:crypto";import{buildUserMessagePayload as A}from"@shennian/wire";import{mergeProjectedSessions as E}from"./projection.js";import{parsePersonalAttachmentReferences as I}from"./attachment-reference.js";import{assertFinishedAttachmentReferences as D,markAttachmentReferences as w}from"./attachment-transfer-store.js";import{resolvePersonalSyncV1Path as R}from"../personal-sync/paths.js";import{appendMessage as $,getMessageDeliveryStatus as T,recordSession as Q,tombstoneMessage as W,upsertMessage as b}from"./store.js";import{requestSessionIndexPublish as M}from"./index-publisher.js";function C(){return{sessions:{}}}function x(){return new Date().toISOString()}function N(n){return`enqueue-send-${n}-${y()}`}function f(){try{const n=JSON.parse(l.readFileSync(v(),"utf-8"));return{sessions:n.sessions&&typeof n.sessions=="object"?n.sessions:{}}}catch(n){if(n.code==="ENOENT"||n instanceof Error&&n.message.startsWith("ENOENT:"))return C();throw n}}function p(n){const e=R();l.mkdirSync(e,{recursive:!0,mode:448});const s=v(),t=`${s}.tmp-${process.pid}-${y()}`;try{l.writeFileSync(t,`${JSON.stringify(n,null,2)}
|
|
2
|
+
`,{encoding:"utf8",mode:384,flag:"wx"});const i=l.openSync(t,"r");if(typeof i=="number")try{l.fsyncSync(i)}finally{l.closeSync(i)}l.renameSync(t,s)}finally{try{l.unlinkSync(t)}catch{}}}function v(){return R("outbound-queue.json")}function B(n){const e=x();return{id:n.queueMessageId||n.clientMessageId||`queue-${y()}`,sessionId:n.sessionId,text:n.text,agentType:n.agentType,sessionMode:n.sessionMode,managerConfig:n.managerConfig,workDir:n.workDir,agentSessionId:n.agentSessionId??null,modelId:n.modelId??null,systemPrompt:n.systemPrompt??null,managerDefaultWorkerAgentType:n.managerDefaultWorkerAgentType??null,managerDefaultWorkerModelId:n.managerDefaultWorkerModelId??null,reasoningEffort:n.reasoningEffort??null,clientMessageId:n.clientMessageId??null,attachments:I(n.attachments),externalChannel:n.externalChannel??null,replyTarget:n.replyTarget??null,origin:n.origin,createdAt:e,updatedAt:e}}function S(n){return{id:n.clientMessageId??n.id,sessionId:n.sessionId,role:"user",ts:Date.parse(n.createdAt),payload:A(n.text,n.attachments)}}class Y{opts;draining=new Set;constructor(e){this.opts=e,setTimeout(()=>this.drainIdleQueues(),0).unref?.()}getSnapshot(e){return{sessionId:e,busy:!!this.opts.getRuntime().sessions.get(e)?.currentRunId,pending:f().sessions[e]??[]}}async handleEnqueue(e){const s=this.opts.getRuntime(),t=e.params;if(E(t.sessionListProjection),!t.sessionId||!t.text||!t.agentType||!t.workDir){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"sessionId, text, agentType and workDir are required"});return}const i=s.resolvePath(t.workDir),o=I(t.attachments);o?.length&&D(i,o);const r={text:t.text,attachments:o,localized:!1},a=await this.isSessionBusy(t.sessionId),d=f(),h=d.sessions[t.sessionId]??[];if(!a&&!h.length){await this.opts.dispatchReq({...e,id:N(e.id),method:"chat.send",params:{...t,text:r.text,responseId:e.id,clientMessageId:t.clientMessageId??t.queueMessageId,waitForDispatch:!0,attachments:r.attachments}});return}const c=B({...t,text:r.text,attachments:r.attachments}),P=c.clientMessageId??c.id,m=T(t.sessionId,P);if(m.state!=="not_found"){s.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queued:m.state==="queued",queueMessageId:c.id,...m,queue:this.getSnapshot(t.sessionId)}});return}const g=z(h,c);g||(d.sessions[t.sessionId]=[...h,c],p(d));const u=g??c;Q({sessionId:u.sessionId,agentType:u.agentType,sessionMode:u.sessionMode,managerConfig:u.managerConfig,workDir:u.workDir,agentSessionId:u.agentSessionId,modelId:u.modelId}),$(u.sessionId,S(u),"queued"),w(s.resolvePath(u.workDir),u.attachments??[]),M(s.client),this.broadcast(t.sessionId),s.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queued:!0,queueMessageId:g?.id??c.id,...T(t.sessionId,g?.clientMessageId??g?.id??c.clientMessageId??c.id),queue:this.getSnapshot(t.sessionId),...r.localized?{localizedAttachments:!0}:{}}}),a||this.drainNext(t.sessionId)}async handleGet(e){const s=this.opts.getRuntime(),t=e.params;if(!t.sessionId){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"sessionId is required"});return}s.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queue:this.getSnapshot(t.sessionId)}}),this.getSnapshot(t.sessionId).busy||this.drainNext(t.sessionId)}async handleEdit(e){const s=this.opts.getRuntime(),t=e.params;if(!t.sessionId||!t.queueMessageId||!t.text){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"sessionId, queueMessageId and text are required"});return}const i=f(),o=i.sessions[t.sessionId]??[],r=o.findIndex(h=>h.id===t.queueMessageId);if(r<0){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"Queued message not found"});return}const a=I(t.attachments),d=s.resolvePath(o[r].workDir);a?.length&&D(d,a),o[r]={...o[r],text:t.text,attachments:a,updatedAt:x()},i.sessions[t.sessionId]=o,p(i),b(t.sessionId,S(o[r]),"queued"),o[r].attachments?.length&&w(d,o[r].attachments??[]),M(s.client),this.broadcast(t.sessionId),s.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queue:this.getSnapshot(t.sessionId)}})}async handleDelete(e){const s=this.opts.getRuntime(),t=e.params;if(!t.sessionId||!t.queueMessageId){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"sessionId and queueMessageId are required"});return}const i=f(),o=i.sessions[t.sessionId]??[],r=o.find(d=>d.id===t.queueMessageId),a=o.filter(d=>d.id!==t.queueMessageId);if(a.length===o.length){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"Queued message not found"});return}a.length?i.sessions[t.sessionId]=a:delete i.sessions[t.sessionId],p(i),W(t.sessionId,r?.clientMessageId??r?.id??t.queueMessageId),M(s.client),this.broadcast(t.sessionId),s.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queue:this.getSnapshot(t.sessionId)}})}noteTerminal(e){this.drainNext(e)}purgeSession(e){const s=f();s.sessions[e]&&(delete s.sessions[e],p(s),this.draining.delete(e))}drainIdleQueues(){const e=f();for(const s of Object.keys(e.sessions))this.drainNext(s)}async drainNext(e){if(this.draining.has(e)||await this.isSessionBusy(e))return;const i=(f().sessions[e]??[])[0];if(!i){this.broadcast(e);return}const o=i;this.draining.add(e);try{b(e,S(o),"queued"),await this.dispatchQueuedMessage(o);const r=f(),a=(r.sessions[e]??[]).filter(d=>d.id!==i.id);a.length?r.sessions[e]=a:delete r.sessions[e],p(r),this.broadcast(e)}finally{this.draining.delete(e)}}mergeExternalMessages(e,s){const t=[e];for(;s[0]?.origin==="external";)t.push(s.shift());const i=j(t);return i.length===1?i[0]:{...e,id:`external-batch-${e.id}`,text:i.map(o=>o.text).filter(Boolean).join(`
|
|
3
3
|
|
|
4
|
-
`),attachments:
|
|
5
|
-
`)}function
|
|
4
|
+
`),attachments:F(i.flatMap(o=>o.attachments??[])),updatedAt:x()}}async dispatchQueuedMessage(e){await this.opts.dispatchReq({type:"req",id:`queue-send-${e.id}-${Date.now()}`,method:"chat.send",params:{sessionId:e.sessionId,text:e.text,agentType:e.agentType,sessionMode:e.sessionMode,managerConfig:e.managerConfig,workDir:e.workDir,agentSessionId:e.agentSessionId??null,modelId:e.modelId??void 0,systemPrompt:e.systemPrompt??null,managerDefaultWorkerAgentType:e.managerDefaultWorkerAgentType,managerDefaultWorkerModelId:e.managerDefaultWorkerModelId,reasoningEffort:e.reasoningEffort??void 0,clientMessageId:e.clientMessageId??e.id,attachments:e.attachments,externalChannel:e.externalChannel,replyTarget:e.replyTarget,waitForDispatch:!0}})}async isSessionBusy(e){const s=this.opts.getRuntime().sessions.get(e);if(!s)return!1;if(s.currentRunId)return!0;if(!s.adapter.getStatus)return!1;const t=await s.adapter.getStatus().catch(()=>null);return t?.active?(t.runId&&(s.currentRunId=t.runId,s.currentRunPhase=t.runPhase??s.currentRunPhase),!0):!1}broadcast(e){this.opts.getRuntime().client.sendEvent({type:"event",event:"session.queue.update",payload:{queue:this.getSnapshot(e)}})}}function j(n){const e=new Set,s=[];for(const t of n){const i=k(t);e.has(i)||(e.add(i),s.push(t))}return s}function z(n,e){const s=q(e);if(s)return n.find(i=>q(i)===s)??null;if(e.origin!=="external")return null;const t=k(e);return n.find(i=>k(i)===t)??null}function k(n){const e=q(n);return e?`id:${e}`:["body",O(n.text),...(n.attachments??[]).map(s=>s.path||`${s.name}:${s.mimeType}`)].join(`
|
|
5
|
+
`)}function q(n){const e=typeof n.clientMessageId=="string"?n.clientMessageId.trim():"";if(e)return e;const s=typeof n.id=="string"?n.id.trim():"";return s&&!s.startsWith("queue-")?s:""}function F(n){const e=new Set,s=[];for(const t of n){const i=t.path||`${t.name}:${t.mimeType}`;e.has(i)||(e.add(i),s.push(t))}return s.length?s:void 0}function O(n){return String(n||"").replace(/\s+/g," ").trim()}export{Y as ChatQueueManager};
|