shennian 0.5.2 → 0.5.3

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 p from"node:fs/promises";import D from"node:path";import{randomUUID as h}from"node:crypto";import{isAvailableAgentType as A}from"@shennian/wire";import{createAgent as I}from"../../agents/adapter.js";import{buildManagedAgentEnv as b}from"../../agents/config-status.js";import{ManagerModeAdapter as N}from"../../agents/manager.js";import{NativeSessionLifecycleRegistry as C}from"../native-session-lifecycle.js";import{validateManagedAgentWorkDir as S}from"../../security/managed-agent-policy.js";const T="\u8BF7\u56DE\u590D hello\uFF0C\u7528\u4E8E\u786E\u8BA4\u4F60\u5DF2\u51C6\u5907\u597D\u3002",O=6e4,M=new C;async function x(e,r={}){try{return await R(e,r)}catch(t){const n=t instanceof Error?t.message:"";return{ok:!1,errorCode:n==="agent_validation_cleanup_failed"?n:_(t,"start")}}}async function R(e,r){if(!A(e.runtimeAdapter)||e.runtimeAdapter==="manager"||e.runtimeAdapter==="pi"||e.runtimeAdapter==="openclaw")return{ok:!1,errorCode:"agent_validation_runtime_unavailable"};if(!D.isAbsolute(e.workDir.trim()))return{ok:!1,errorCode:"agent_validation_workdir_invalid"};let t;try{t=await(r.resolveWorkDir??W)(e.workDir)}catch(i){return{ok:!1,errorCode:L(i)}}if(!(r.validateWorkDir?await r.validateWorkDir(t):(await S(t,async()=>t)).ok))return{ok:!1,errorCode:"agent_validation_workdir_invalid"};const s=(r.createAdapter??I)(e.runtimeAdapter);if(!s)return{ok:!1,errorCode:"agent_validation_runtime_unavailable"};const o=e.sessionMode==="manager"?new N(s,e.runtimeAdapter):s,g=`agent-validation-${h()}`;let l="",u="",f=null,c=null;const y=new Promise(i=>{c=i}),k=i=>{i.agentSessionId&&(l=i.agentSessionId,r.ignoreNativeSession?.(e.runtimeAdapter,l)),i.state==="delta"&&!i.thinking&&i.text&&(u+=i.text),i.state==="final"?(i.text&&(u+=i.text),c?.({kind:"final"})):(i.state==="error"||i.state==="aborted")&&c?.({kind:"error",error:i.message??i.state})},v=i=>c?.({kind:"error",error:i});o.on("agentEvent",k),o.on("error",v);const E=async()=>{o.configure?.({sessionId:g,env:b(e.runtimeAdapter)});try{await o.start(g,t,null,{persistNativeSession:!1})}catch(a){return{ok:!1,errorCode:_(a,"start")}}const i=new Promise(a=>{f=setTimeout(()=>a({kind:"timeout"}),r.timeoutMs??O)}),m=o.send(T,e.modelId??void 0).then(()=>y).catch(a=>({kind:"error",error:a})),d=await Promise.race([m,i]);return d.kind==="timeout"?{ok:!1,errorCode:"agent_validation_response_timeout"}:d.kind==="error"?{ok:!1,errorCode:_(d.error,"response")}:u.toLowerCase().includes("hello")?{ok:!0}:{ok:!1,errorCode:"agent_validation_response_mismatch"}};let w;try{w=await E()}finally{f&&clearTimeout(f),o.removeListener("agentEvent",k),o.removeListener("error",v),await o.stop().catch(()=>{}),l&&(r.cleanupNativeSession??((m,d,a)=>{M.execute(m,d,{workDir:a}).catch(()=>{})}))(e.runtimeAdapter,l,t)}return w}async function J(e,r){const t=U(r.params);if(!t){e.client.sendRes({type:"res",id:r.id,ok:!1,error:"agent_validation_invalid_configuration"});return}const n=await x(t,{ignoreNativeSession:(s,o)=>{e.nativeFusion?.ignoreNativeSource(s,o)}});e.client.sendRes(n.ok?{type:"res",id:r.id,ok:!0,payload:{ready:!0}}:{type:"res",id:r.id,ok:!1,error:n.errorCode})}async function W(e){const r=e.trim();if(!r)throw Object.assign(new Error("workdir_required"),{code:"EINVAL"});const t=await p.realpath(r);if(!(await p.stat(t)).isDirectory())throw Object.assign(new Error("workdir_not_directory"),{code:"ENOTDIR"});return t}function L(e){const r=P(e);return r==="ENOENT"?"agent_validation_workdir_not_found":r==="ENOTDIR"?"agent_validation_workdir_not_directory":r==="EACCES"||r==="EPERM"?"agent_validation_workdir_unavailable":"agent_validation_workdir_invalid"}function _(e,r){const t=e instanceof Error?e.message:String(e);return t==="agent_validation_server_upgrade_required"?t:/model.*(?:not found|unavailable|unsupported|invalid|access denied|permission denied|not (?:allowed|authorized))|(?:access|permission) denied.*model|unknown model/i.test(t)?"agent_validation_model_unavailable":/quota|insufficient.*(?:credit|balance)|billing|rate.?limit|\b429\b/i.test(t)?"agent_validation_quota_exceeded":/not found|enoent|command .* missing|is .* installed/i.test(t)?"agent_validation_runtime_unavailable":/unauth|authentication|not logged|login required|api key|token.*missing|forbidden|401|403/i.test(t)?"agent_validation_runtime_auth_required":/ECONNREFUSED|ECONNRESET|ENOTFOUND|ETIMEDOUT|network|fetch failed|connection.*(?:failed|closed|refused)/i.test(t)?"agent_validation_network_failed":r==="start"?"agent_validation_start_failed":"agent_validation_response_failed"}function P(e){return typeof e=="object"&&e&&"code"in e?String(e.code):""}function U(e){const r=typeof e.runtimeAdapter=="string"?e.runtimeAdapter:"",t=typeof e.workDir=="string"?e.workDir:"",n=e.sessionMode==="manager"?"manager":"standard";return!A(r)||!t.trim()?null:{runtimeAdapter:r,workDir:t,sessionMode:n,modelId:typeof e.modelId=="string"?e.modelId:null}}export{J as handleAgentWorkspaceValidation,x as validateAgentWorkspaceConfiguration};
1
+ import E from"node:fs/promises";import N from"node:path";import{randomUUID as O}from"node:crypto";import{isAvailableAgentType as y}from"@shennian/wire";import{createAgent as b}from"../../agents/adapter.js";import{buildManagedAgentEnv as C}from"../../agents/config-status.js";import{ManagerModeAdapter as S}from"../../agents/manager.js";import{NativeSessionLifecycleRegistry as M}from"../native-session-lifecycle.js";import{validateManagedAgentWorkDir as x}from"../../security/managed-agent-policy.js";const P="\u8BF7\u56DE\u590D hello\uFF0C\u7528\u4E8E\u786E\u8BA4\u4F60\u5DF2\u51C6\u5907\u597D\u3002",D=6e4,I=8e3,Y=D+I,R=new M;async function W(e,r={}){try{return await L(e,r)}catch(t){const o=t instanceof Error?t.message:"";return{ok:!1,errorCode:o==="agent_validation_cleanup_failed"?o:k(t,"start")}}}async function L(e,r){if(!y(e.runtimeAdapter)||e.runtimeAdapter==="manager"||e.runtimeAdapter==="pi"||e.runtimeAdapter==="openclaw")return{ok:!1,errorCode:"agent_validation_runtime_unavailable"};if(!N.isAbsolute(e.workDir.trim()))return{ok:!1,errorCode:"agent_validation_workdir_invalid"};let t;try{t=await(r.resolveWorkDir??V)(e.workDir)}catch(i){return{ok:!1,errorCode:j(i)}}if(!(r.validateWorkDir?await r.validateWorkDir(t):(await x(t,async()=>t)).ok))return{ok:!1,errorCode:"agent_validation_workdir_invalid"};const a=(r.createAdapter??b)(e.runtimeAdapter);if(!a)return{ok:!1,errorCode:"agent_validation_runtime_unavailable"};const n=e.sessionMode==="manager"?new S(a,e.runtimeAdapter):a,v=`agent-validation-${O()}`;let u="",f="",m=null,_=!1,c=null;const T=new Promise(i=>{c=i}),w=i=>{i.agentSessionId&&(u=i.agentSessionId,r.ignoreNativeSession?.(e.runtimeAdapter,u)),i.state==="delta"&&!i.thinking&&i.text&&(f+=i.text),i.state==="final"?(i.text&&(f+=i.text),c?.({kind:"final"})):(i.state==="error"||i.state==="aborted")&&c?.({kind:"error",error:i.message??i.state})},p=i=>c?.({kind:"error",error:i});n.on("agentEvent",w),n.on("error",p);const h=async()=>{n.configure?.({sessionId:v,env:C(e.runtimeAdapter)});const i=new Promise(l=>{m=setTimeout(()=>l({kind:"timeout"}),r.timeoutMs??D)}),s=await Promise.race([Promise.resolve().then(()=>n.start(v,t,null,{persistNativeSession:!1})).then(()=>({kind:"started"}),l=>({kind:"error",error:l})),i]);if(s.kind==="timeout")return _=!0,{ok:!1,errorCode:"agent_validation_start_failed"};if(s.kind==="error")return{ok:!1,errorCode:k(s.error,"start")};const g=n.send(P,e.modelId??void 0).then(()=>T).catch(l=>({kind:"error",error:l})),d=await Promise.race([g,i]);return d.kind==="timeout"?(_=!0,{ok:!1,errorCode:"agent_validation_response_timeout"}):d.kind==="error"?{ok:!1,errorCode:k(d.error,"response")}:f.toLowerCase().includes("hello")?{ok:!0}:{ok:!1,errorCode:"agent_validation_response_mismatch"}};let A;try{A=await h()}finally{m&&clearTimeout(m),n.removeListener("agentEvent",w),n.removeListener("error",p),await U(n,r.stopTimeoutMs??I),u&&!_&&(r.cleanupNativeSession??((s,g,d)=>{R.execute(s,g,{workDir:d}).catch(()=>{})}))(e.runtimeAdapter,u,t)}return A}async function U(e,r){let t=null;await Promise.race([e.stop().catch(()=>{}),new Promise(o=>{t=setTimeout(o,r)})]),t&&clearTimeout(t)}async function Z(e,r){const t=F(r.params);if(!t){e.client.sendRes({type:"res",id:r.id,ok:!1,error:"agent_validation_invalid_configuration"});return}const o=await W(t,{ignoreNativeSession:(a,n)=>{e.nativeFusion?.ignoreNativeSource(a,n)}});e.client.sendRes(o.ok?{type:"res",id:r.id,ok:!0,payload:{ready:!0}}:{type:"res",id:r.id,ok:!1,error:o.errorCode})}async function V(e){const r=e.trim();if(!r)throw Object.assign(new Error("workdir_required"),{code:"EINVAL"});const t=await E.realpath(r);if(!(await E.stat(t)).isDirectory())throw Object.assign(new Error("workdir_not_directory"),{code:"ENOTDIR"});return t}function j(e){const r=q(e);return r==="ENOENT"?"agent_validation_workdir_not_found":r==="ENOTDIR"?"agent_validation_workdir_not_directory":r==="EACCES"||r==="EPERM"?"agent_validation_workdir_unavailable":"agent_validation_workdir_invalid"}function k(e,r){const t=e instanceof Error?e.message:String(e);return t==="agent_validation_server_upgrade_required"?t:/model.*(?:not found|unavailable|unsupported|invalid|access denied|permission denied|not (?:allowed|authorized))|(?:access|permission) denied.*model|unknown model/i.test(t)?"agent_validation_model_unavailable":/quota|insufficient.*(?:credit|balance)|billing|rate.?limit|\b429\b/i.test(t)?"agent_validation_quota_exceeded":/not found|enoent|command .* missing|is .* installed/i.test(t)?"agent_validation_runtime_unavailable":/unauth|authentication|not logged|login required|api key|token.*missing|forbidden|401|403/i.test(t)?"agent_validation_runtime_auth_required":/ECONNREFUSED|ECONNRESET|ENOTFOUND|ETIMEDOUT|network|fetch failed|connection.*(?:failed|closed|refused)/i.test(t)?"agent_validation_network_failed":r==="start"?"agent_validation_start_failed":"agent_validation_response_failed"}function q(e){return typeof e=="object"&&e&&"code"in e?String(e.code):""}function F(e){const r=typeof e.runtimeAdapter=="string"?e.runtimeAdapter:"",t=typeof e.workDir=="string"?e.workDir:"",o=e.sessionMode==="manager"?"manager":"standard";return!y(r)||!t.trim()?null:{runtimeAdapter:r,workDir:t,sessionMode:o,modelId:typeof e.modelId=="string"?e.modelId:null}}export{Y as AGENT_VALIDATION_MAX_DURATION_MS,Z as handleAgentWorkspaceValidation,W as validateAgentWorkspaceConfiguration};
@@ -1 +1 @@
1
- import{createHash as u}from"node:crypto";import{buildManagedAgentPermissionPrompt as g}from"../../room/managed-prompt-composer.js";import{configureAdapterForSession as d,replaceManagedRoomContextToken as p}from"./chat-adapter-config.js";import{createActiveSession as y}from"./chat-session-lifecycle.js";import{validateManagedRoomExecutionContext as c}from"./chat.js";async function h(a,e,m=()=>{}){let o=null,s=null,i=null,r;if(e.source==="managed_room"||e.source==="managed_direct"||e.source==="manager_event"&&e.managedPolicyVersion){const n=await a.prepareManagedRecovery?.(e);if(!n)return{result:"recovery_failed",reason:"permission_context_unavailable",message:"managed recovery requires a fresh permission context"};if(n.agentType!==e.agentType||n.sessionMode!==e.sessionMode||a.resolvePath(n.workDir)!==a.resolvePath(e.workDir)||n.managedRoomPromptSnapshot.managedRoomPolicyVersion!==e.managedPolicyVersion||n.managedRoomPromptSnapshot.runtimePermissionPolicyHash!==e.managedRuntimePolicyHash)return a.revokeManagedRoomContextToken?.(n.managedRoomContextToken),{result:"recovery_failed",reason:"permission_context_unavailable",message:"managed recovery authority no longer matches the interrupted run"};if(o=n.managedAgentPolicy,e.source==="manager_event"||e.source==="managed_direct")s=n.managedRoomContextToken,i=n.systemPrompt,r={source:"managed_private",recovery:"upgrade"};else{const l={source:"room_activation",managedAgentPolicy:n.managedAgentPolicy,managedRoomPromptSnapshot:n.managedRoomPromptSnapshot};c(l,n.systemPrompt,n.managedRoomContextToken),s=n.managedRoomContextToken,i=n.systemPrompt,r={...l,recovery:"upgrade"}}}else if(e.source==="manager_worker"&&!e.managerWorkerNativeFull){const n=e.parentSessionId;if(o=n?a.managerRuntime?.getManagedAgentPolicyForWorker(n,e.workDir)??null:null,!o)return{result:"recovery_failed",reason:"permission_context_unavailable",message:"manager worker recovery requires the current parent policy"};if(u("sha256").update(JSON.stringify({requestedPolicy:o.requestedPolicy,enforcement:o.enforcement})).digest("hex")!==e.managedRuntimePolicyHash)return{result:"recovery_failed",reason:"permission_context_unavailable",message:"manager worker policy changed after interruption"};i=g({requestedPolicy:o.requestedPolicy,enforcement:o.enforcement,resolvedWorkDir:o.adapterPolicy.workDir})}r??={source:"upgrade_recovery",recovery:"upgrade"};let t=a.sessions.get(e.sessionId);return t||(t=await y(a,e.sessionId,e.agentType,e.sessionMode,e.workDir,e.agentSessionId,null,null,o,e.nativeSessionVisibility)),s&&(p(a,t,s),d(t.adapter,e.sessionId,e.agentType,null,null,s,o,a.managedRoomExecutor)),t.journalRunId=e.runId,t.currentRunId=e.providerRunId??`recovery:${e.runId}`,t.currentRunPhase="thinking",t.lastProviderActivityAt=Date.now(),e.agentType==="codex"&&e.deliveryMode==="external_owner_queue"&&e.agentSessionId&&e.externalRunId&&a.nativeFusion?.restoreExternalObservation({sessionId:e.sessionId,sourceSessionKey:e.agentSessionId,runId:e.externalRunId,canonicalMessageId:e.clientMessageId,createdAt:Date.parse(e.createdAt)})?{result:"reattached"}:t.adapter.recoverInterruptedRun({sessionId:e.sessionId,shennianRunId:e.runId,workDir:e.workDir,agentSessionId:e.agentSessionId,modelId:e.modelId,reasoningEffort:e.reasoningEffort,providerRunId:e.providerRunId,lastObservedEventSeq:e.lastObservedEventSeq,continueDispatchState:e.continueDispatchState,systemPrompt:i,sendContext:r,beforeContinueDispatch:m})}export{h as recoverJournaledRun};
1
+ import{createHash as u}from"node:crypto";import{buildManagedAgentPermissionPrompt as g}from"../../room/managed-prompt-composer.js";import{configureAdapterForSession as d,replaceManagedRoomContextToken as p}from"./chat-adapter-config.js";import{createActiveSession as c}from"./chat-session-lifecycle.js";import{validateManagedRoomExecutionContext as y}from"./chat.js";async function R(a,e,m=()=>{}){let o=null,s=null,i=null,r;if(e.source==="managed_room"||e.source==="managed_direct"||e.source==="manager_event"&&e.managedPolicyVersion){const n=await a.prepareManagedRecovery?.(e);if(!n)return{result:"recovery_failed",reason:"permission_context_unavailable",message:"managed recovery requires a fresh permission context"};if(n.agentType!==e.agentType||n.sessionMode!==e.sessionMode||a.resolvePath(n.workDir)!==a.resolvePath(e.workDir)||n.managedRoomPromptSnapshot.managedRoomPolicyVersion!==e.managedPolicyVersion||n.managedRoomPromptSnapshot.runtimePermissionPolicyHash!==e.managedRuntimePolicyHash)return a.revokeManagedRoomContextToken?.(n.managedRoomContextToken),{result:"recovery_failed",reason:"permission_context_unavailable",message:"managed recovery authority no longer matches the interrupted run"};if(o=n.managedAgentPolicy,e.source==="manager_event"||e.source==="managed_direct")s=n.managedRoomContextToken,i=n.systemPrompt,r={source:"managed_private",recovery:"upgrade",modelSelectionSource:"upgrade_recovery_model"};else{const l={source:"room_activation",managedAgentPolicy:n.managedAgentPolicy,managedRoomPromptSnapshot:n.managedRoomPromptSnapshot};y(l,n.systemPrompt,n.managedRoomContextToken),s=n.managedRoomContextToken,i=n.systemPrompt,r={...l,recovery:"upgrade",modelSelectionSource:"upgrade_recovery_model"}}}else if(e.source==="manager_worker"&&!e.managerWorkerNativeFull){const n=e.parentSessionId;if(o=n?a.managerRuntime?.getManagedAgentPolicyForWorker(n,e.workDir)??null:null,!o)return{result:"recovery_failed",reason:"permission_context_unavailable",message:"manager worker recovery requires the current parent policy"};if(u("sha256").update(JSON.stringify({requestedPolicy:o.requestedPolicy,enforcement:o.enforcement})).digest("hex")!==e.managedRuntimePolicyHash)return{result:"recovery_failed",reason:"permission_context_unavailable",message:"manager worker policy changed after interruption"};i=g({requestedPolicy:o.requestedPolicy,enforcement:o.enforcement,resolvedWorkDir:o.adapterPolicy.workDir})}r??={source:"upgrade_recovery",recovery:"upgrade",modelSelectionSource:"upgrade_recovery_model"};let t=a.sessions.get(e.sessionId);return t||(t=await c(a,e.sessionId,e.agentType,e.sessionMode,e.workDir,e.agentSessionId,null,null,o,e.nativeSessionVisibility)),s&&(p(a,t,s),d(t.adapter,e.sessionId,e.agentType,null,null,s,o,a.managedRoomExecutor)),t.journalRunId=e.runId,t.currentRunId=e.providerRunId??`recovery:${e.runId}`,t.currentRunPhase="thinking",t.lastProviderActivityAt=Date.now(),e.agentType==="codex"&&e.deliveryMode==="external_owner_queue"&&e.agentSessionId&&e.externalRunId&&a.nativeFusion?.restoreExternalObservation({sessionId:e.sessionId,sourceSessionKey:e.agentSessionId,runId:e.externalRunId,canonicalMessageId:e.clientMessageId,createdAt:Date.parse(e.createdAt)})?{result:"reattached"}:t.adapter.recoverInterruptedRun({sessionId:e.sessionId,shennianRunId:e.runId,workDir:e.workDir,agentSessionId:e.agentSessionId,modelId:e.modelId,reasoningEffort:e.reasoningEffort,providerRunId:e.providerRunId,lastObservedEventSeq:e.lastObservedEventSeq,continueDispatchState:e.continueDispatchState,systemPrompt:i,sendContext:r,beforeContinueDispatch:m})}export{R as recoverJournaledRun};
@@ -1 +1 @@
1
- import{buildUserMessagePayload as de}from"@shennian/wire";import{createHash as Ae,randomUUID as Me}from"node:crypto";import le from"node:os";import{reportLog as b}from"../../log-reporter.js";import{getPersonalSyncIdentity as Pe}from"../../personal-sync/epoch.js";import{buildManagedAgentPermissionPrompt as Ee}from"../../room/managed-prompt-composer.js";import{parsePersonalAttachmentReferences as De}from"../attachment-reference.js";import{assertFinishedAttachmentReferences as Te,markAttachmentReferences as be}from"../attachment-transfer-store.js";import{requestSessionIndexPublish as R}from"../index-publisher.js";import{isTrustedManagerEvent as $e}from"../manager-event-authority.js";import{mergeProjectedSessions as xe}from"../projection.js";import{appendMessage as ce,getDaemonInstallationId as ue,getMessageDeliveryStatus as Ce,upsertMessage as _}from"../store.js";import{configureAdapterForSession as ge,maybeResolveClaudeImportedWorkDir as We,replaceManagedRoomContextToken as pe,revokeManagedRoomContextToken as me}from"./chat-adapter-config.js";import{resolveNativeSessionVisibility as qe,sendSessionUpdateEvent as je,validateManagedRoomExecutionContext as Fe}from"./chat-context.js";import{getNativeSourceAgentType as Oe}from"./chat-events.js";import{noteRunActivity as Be}from"../run-stall.js";import{createActiveSession as Je,disposeSession as C,prepareAdapterTurn as ze,rememberProcessedReqId as Ue,sendAdapterTurn as fe}from"./chat-session-lifecycle.js";import{sendSessionUpdateEvent as vn,validateManagedRoomExecutionContext as hn}from"./chat-context.js";function ye(e,n){return`Agent send failed: ${n instanceof Error?n.message:String(n)}`}function He(e,n){const t=e.sessions.get(n),s=t?.currentRunId;if(!t||!s)return;const o=t.nextEventSeq;e.runTextAcc.delete(`${n}:${s}`),me(e,t),t.pendingTextEvent=null,Be(n,t,!0),t.currentRunId=null,t.currentRunPhase=null,t.nextEventSeq=0,t.heartbeatTimer&&(clearInterval(t.heartbeatTimer),t.heartbeatTimer=null),e.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"aborted",sessionId:n,runId:s,seq:o},seq:o,id:`agent-evt-${s}-${o}`}),t.journalRunId&&(e.runJournal?.remove(n,t.journalRunId),e.recoveryBarrier?.end(n),t.journalRunId=null),e.chatQueue?.noteTerminal(n)}async function pn(e,n,t){const s=t?n.params.managedRoomContextToken??null:null;let o=!1;try{await Ne(e,n,t,()=>{o=!0})}finally{s&&!o&&e.revokeManagedRoomContextToken?.(s)}}async function Ne(e,n,t,s){if(e.processedReqIds.has(n.id)){e.client.sendRes({type:"res",id:n.id,ok:!0});return}const{sessionId:o,text:p,agentType:I,sessionMode:W,managerConfig:Z,workDir:ve,agentSessionId:m,modelId:S,systemPrompt:G,managerDefaultWorkerAgentType:q,managerDefaultWorkerModelId:j,reasoningEffort:F,clientMessageId:he,sessionListProjection:Ie,waitForDispatch:X,responseId:Re,managedRoomContextToken:w,suppressExternalOwnerEcho:_e,queuedBatchItems:O,managedWorkerParentSessionId:g,managerWorkerRoomOrigin:B,managerWorkerNativeFull:J,managedRecoverySource:E}=n.params,c=Re||n.id,Y=n.params;if((Y.managerEventId||Y.managerEventRoomOrigin||g||B||J||E)&&!$e(n))throw new Error("manager_event_source_untrusted");xe(Ie);const $=null,z="";if(t?.source==="room_activation"&&(Fe(t,G,w),I==="manager"))throw new Error("managed_agent_manager_mode_unsupported");if(t?.source==="manager_event"){if(!t.managedAgentPolicy)throw new Error("managed_agent_policy_missing");if(!w||!/^mrc_[A-Za-z0-9_-]{43}$/.test(w))throw new Error("managed_room_context_unavailable")}if(Ue(e,n.id),!o||!p){e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:c,ok:!1,error:"sessionId and text are required"});return}if(e.recoveryBarrier?.isDispatchFrozen()){e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:c,ok:!1,error:"upgrade_in_progress"});return}e.recoveryBarrier?.isRecovering(o)&&await e.recoveryBarrier.wait(o);const l=I,k=l==="manager"||W==="manager"?"manager":"standard";k==="manager"&&e.managerRuntime?.setManagerWorkerDefaults(o,q??null,j??null);const D=(l==="claude"||l==="codex"||l==="workbuddy"||l==="pi-coding-agent"||l.startsWith("acp:"))&&typeof F=="string"&&F.trim()?F.trim():void 0,v=e.resolvePath(We(l,ve||le.homedir(),m)||le.homedir()),y=t?.managedAgentPolicy??(g?e.managerRuntime?.getManagedAgentPolicyForWorker(g,v)??null:null);if(g&&!J&&!y)throw new Error("managed_worker_permission_context_unavailable");const U=qe(o,l,k,!!(y||g||t)),H=g&&y?Ee({requestedPolicy:y.requestedPolicy,enforcement:y.enforcement,resolvedWorkDir:y.adapterPolicy.workDir}):G??null,Se=v,x=De(n.params.attachments);x?.length&&Te(v,x);const f={text:p,attachments:x,localized:!1};let r=e.sessions.get(o);if(r){if(r.lastActiveAt=Date.now(),r.agentType!==l||(r.sessionMode??(r.agentType==="manager"?"manager":"standard"))!==k||r.workDir!==v||(r.nativeSessionVisibility??"user")!==U||JSON.stringify(r.externalChannel??null)!==JSON.stringify($??null)){e.sessions.delete(o);try{await C(e,r)}catch{e.processedReqIds.delete(n.id)}r=void 0}else if(m&&r.agentSessionId!==m)try{await r.adapter.resume(m),r.agentSessionId=m}catch{e.sessions.delete(o);try{await C(e,r)}catch{e.processedReqIds.delete(n.id)}r=void 0}}if(!r)try{r=await Je(e,o,l,k,v,m,$,z,y,U)}catch(a){const d=a instanceof Error&&a.message.startsWith("Unsupported agent:")?a.message:`Failed to start ${I}: ${a instanceof Error?a.message:String(a)}`;console.error(`[chat.send] start failed reqId=${n.id} sessionId=${o} agentType=${I} workDir=${v} agentSessionId=${m??""}: ${d}`),e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:o,message:d,runId:"",seq:0}}),e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:c,ok:!1,error:d});return}const u={id:he??`user-${n.id}`,sessionId:o,role:"user",ts:Date.now(),payload:de(f.text,f.attachments)},ee=Array.isArray(O)&&O.length>0?O.map(a=>({id:a.clientMessageId??a.id,sessionId:o,role:E==="manager_event"||n.params.scheduledDelivery===!0?"agent":"user",ts:E==="manager_event"||t?.source==="room_activation"?Date.parse(a.createdAt):u.ts,payload:de(a.text,a.attachments)})):null,A=ee??[u],N=Ce(o,u.id),ne=N.state==="queued";if(N.state!=="not_found"&&!ne){e.client.sendRes({type:"res",id:c,ok:!0,payload:N});return}if(X){(t?.source==="room_activation"||t?.source==="manager_event")&&ge(r.adapter,o,l,$,z,w,t.managedAgentPolicy,e.managedRoomExecutor);try{await ze(r.adapter,f.text,S,D,f.attachments,H,t?.source==="room_activation"?{source:"room_activation"}:t?.source==="manager_event"?{source:"managed_private"}:void 0)}catch(a){e.processedReqIds.delete(n.id),e.sessions.delete(o),await C(e,r),e.client.sendRes({type:"res",id:c,ok:!1,error:a instanceof Error?a.message:String(a)});return}}b({level:"info",sessionId:o,wsEvent:"chat.send.start",metadata:{reqId:n.id,agentType:l,sessionMode:k,managerConfig:Z??null,modelId:S,managerDefaultWorkerAgentType:q??null,managerDefaultWorkerModelId:j??null,reasoningEffort:D,...t?.source==="room_activation"?{managedRoomPromptSnapshot:t.managedRoomPromptSnapshot}:{}}});const M=(a,d)=>({...Pe(ue()),sessionId:o,clientMessageId:u.id,messageId:u.id,deliveryState:a,bodyRevision:d,committedAt:new Date(u.ts).toISOString()}),V=a=>{e.nativeFusion?.registerManagedSend({sessionId:o,agentType:l,sourceAgentType:Oe(l,S),canonicalMessageId:u.id,sourceSessionKey:r.agentSessionId??m??null,text:f.text,managedEchoPolicy:a?.deliveryMode==="external_owner_queue"&&!_e?"import_following":"suppress_following",externalRunId:a?.deliveryMode==="external_owner_queue"?`codex-external-${a.queuedSubmissionId??u.id}`:null})},ae=()=>{r.currentRunId||(r.currentRunId=`dispatch:${n.id}`,r.currentRunPhase="thinking",r.nextEventSeq=0,r.lastProviderActivityAt=Date.now())},te=()=>{if(!e.runJournal||r.journalRunId)return;const a=`run:${Me()}`;e.runJournal.begin({daemonInstallationId:ue(),sessionId:o,runId:a,clientMessageId:u.id,agentType:l,sessionMode:k,workDir:v,agentSessionId:r.agentSessionId??m??null,modelId:S??null,reasoningEffort:D??null,nativeSessionVisibility:U,providerRunId:null,source:E==="manager_event"?"manager_event":t?.source==="room_activation"?E==="managed_direct"?"managed_direct":"managed_room":g?"manager_worker":"personal",parentSessionId:g??null,managerWorkerNativeFull:J===!0,roomContextRegistryKey:typeof n.params.roomContextRegistryKey=="string"?n.params.roomContextRegistryKey:null,activationCauseMessageId:typeof n.params.activationCauseMessageId=="string"?n.params.activationCauseMessageId:null,rootCauseMessageId:typeof n.params.rootCauseMessageId=="string"?n.params.rootCauseMessageId:null,activationSequence:typeof n.params.activationSequence=="string"?n.params.activationSequence:null,activationHopCount:typeof n.params.activationHopCount=="number"?n.params.activationHopCount:null,managedPolicyVersion:t?.source==="room_activation"?t.managedRoomPromptSnapshot.managedRoomPolicyVersion:t?.source==="manager_event"?t.managedRoomPolicyVersion:null,managedRuntimePolicyHash:(t?.source==="room_activation"?t.managedRoomPromptSnapshot.runtimePermissionPolicyHash:t?.source==="manager_event"?t.managedRuntimePolicyHash:null)??(y?Ae("sha256").update(JSON.stringify({requestedPolicy:y.requestedPolicy,enforcement:y.enforcement})).digest("hex"):null)}),r.journalRunId=a},oe=()=>{if(V(),ne){let a=0;for(const[d,i]of A.entries()){const h=_(o,i,"queued");d===0&&(a=h)}return M("queued",a)}try{je(e,{sessionId:o,agentType:l,sessionMode:k,managerConfig:Z??null,workDir:Se,agentSessionId:r.agentSessionId??m??null,modelId:S,managerDefaultWorkerAgentType:q??null,managerDefaultWorkerModelId:j??null});let a=0;for(const[d,i]of A.entries()){const h=ee?_(o,i,"committed"):ce(o,i,"committed");d===0&&(a=h)}return be(v,x??[]),R(e.client),M("committed",a)}catch(a){throw e.nativeFusion?.cancelManagedSend?.(u.id),a}},re=a=>{r.journalRunId&&e.runJournal?.update(o,r.journalRunId,{deliveryMode:a?.deliveryMode==="external_owner_queue"?"external_owner_queue":"direct",externalRunId:a?.deliveryMode==="external_owner_queue"?`codex-external-${a.queuedSubmissionId??u.id}`:null})},se=a=>{r.currentRunId||(r.nextEventSeq=0),re(a),V(a);const d=a?.deliveryMode==="external_owner_queue"?"queued":"executing";let i=0;for(const[h,T]of A.entries()){const P=_(o,T,d);h===0&&(i=P)}return R(e.client),M(d,i)},K=async(a,d)=>{e.nativeFusion?.cancelManagedSend?.(u.id);const i=ye(l,a);if(console.error(`[chat.send] send failed reqId=${n.id} sessionId=${o} agentType=${I} workDir=${v} agentSessionId=${r.agentSessionId??m??""}: ${i}`),r.adapter.hasPendingAuthenticationRetry?.()===!0){d&&e.client.sendRes({type:"res",id:c,ok:!0,payload:M("queued",0)});return}e.sessions.delete(o),r.journalRunId&&(e.runJournal?.update(o,r.journalRunId,{phase:"terminal"}),e.runJournal?.remove(o,r.journalRunId),e.recoveryBarrier?.end(o),r.journalRunId=null);try{await C(e,r)}catch{}if(e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:o,message:i,runId:"",seq:0}}),!d){const T={id:`agent-error-${n.id}-${Date.now()}`,sessionId:o,role:"agent",ts:Date.now(),payload:i};ce(o,T),R(e.client)}d&&(e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:c,ok:!1,error:i}))};if(X){try{oe()}catch(i){e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:c,ok:!1,error:`Durable message commit failed: ${i instanceof Error?i.message:String(i)}`});return}te(),ae();let a;try{(t?.source==="room_activation"||t?.source==="manager_event")&&(pe(e,r,w),s());const i=f.attachments;g&&e.managerRuntime?.prepareWorkerTurnOrigin(o,B),a=await fe(r.adapter,f.text,S,D,i,H,t?.source==="room_activation"?{source:"room_activation"}:t?.source==="manager_event"?{source:"managed_private"}:void 0),b({level:"info",sessionId:o,wsEvent:"chat.send.done",metadata:{reqId:n.id}})}catch(i){if(g&&e.managerRuntime?.prepareWorkerTurnOrigin(o),r.adapter.hasPendingAuthenticationRetry?.()){let P=0;for(const[L,Q]of A.entries()){const ke=_(o,Q,"queued");L===0&&(P=ke)}R(e.client),await K(i,!1),e.client.sendRes({type:"res",id:c,ok:!0,payload:M("queued",P)});return}let h=0;for(const[P,L]of A.entries()){const Q=_(o,L,"failed");P===0&&(h=Q)}R(e.client);const T=ye(l,i);await K(i,!1),e.client.sendRes({type:"res",id:c,ok:!0,payload:{...M("failed",h),failureMessage:T}});return}const d=se(a??void 0);e.client.sendRes({type:"res",id:c,ok:!0,payload:{...d,...f.localized?{localizedAttachments:!0}:{},...a?.deliveryMode==="external_owner_queue"?{queued:!0,deliveryMode:a.deliveryMode,queuedSubmissionId:a.queuedSubmissionId}:{}}}),b({level:"info",sessionId:o,wsEvent:"chat.send.res",metadata:{reqId:n.id,ok:!0}});return}let ie;try{ie=oe()}catch(a){e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:c,ok:!1,error:`Durable message commit failed: ${a instanceof Error?a.message:String(a)}`});return}te(),ae(),(t?.source==="room_activation"||t?.source==="manager_event")&&(ge(r.adapter,o,l,$,z,w,t.managedAgentPolicy,e.managedRoomExecutor),pe(e,r,w),s()),se(),e.client.sendRes({type:"res",id:c,ok:!0,payload:{...ie,...f.localized?{localizedAttachments:!0}:{}}}),b({level:"info",sessionId:o,wsEvent:"chat.send.res",metadata:{reqId:n.id,ok:!0}});const we=f.attachments;g&&e.managerRuntime?.prepareWorkerTurnOrigin(o,B),fe(r.adapter,f.text,S,D,we,H,t?.source==="room_activation"?{source:"room_activation"}:t?.source==="manager_event"?{source:"managed_private"}:void 0).then(a=>{if(a?.deliveryMode==="external_owner_queue"){re(a),V(a);for(const d of A)_(o,d,"queued");R(e.client)}b({level:"info",sessionId:o,wsEvent:"chat.send.done",metadata:{reqId:n.id}})}).catch(a=>{g&&e.managerRuntime?.prepareWorkerTurnOrigin(o),_(o,u,r.adapter.hasPendingAuthenticationRetry?.()?"queued":"failed"),R(e.client),K(a,!1)})}const Ve=2e4;async function Ke(e,n){let t;const s=new Promise(o=>{t=setTimeout(()=>o("timed_out"),n)});try{return await Promise.race([e.adapter.stop().then(()=>"stopped"),s])}finally{clearTimeout(t)}}async function mn(e,n,t=Ve){const{sessionId:s,discardPending:o}=n.params,p=e.sessions.get(s);if(p){p.journalRunId&&e.runJournal?.markAborted(s,p.journalRunId),me(e,p);let I;try{I=await Ke(p,t)}catch{e.client.sendRes({type:"res",id:n.id,ok:!1,error:"agent_stop_failed"});return}const W=p.currentRunId;He(e,s),I==="timed_out"&&(e.sessions.delete(s),p.adapter.removeAllListeners(),p.adapter.stop().catch(()=>{}),console.error(`[chat.abort] agent did not stop within ${t}ms; ended the run by force sessionId=${s}`),_(s,{id:`stop-forced-${W??n.id}`,sessionId:s,role:"agent",ts:Date.now(),payload:"AI \u6CA1\u6709\u54CD\u5E94\u201C\u505C\u6B62\u201D\u8BF7\u6C42\uFF0C\u795E\u5FF5\u5DF2\u5F3A\u5236\u7ED3\u675F\u8FD9\u4E00\u8F6E\u3002\u53EF\u4EE5\u76F4\u63A5\u53D1\u9001\u65B0\u6D88\u606F\u7EE7\u7EED\uFF1B\u5982\u679C\u53CD\u590D\u51FA\u73B0\uFF0C\u8BF7\u68C0\u67E5\u8FD9\u53F0\u7535\u8111\u4E0A\u8BE5 AI \u7684\u8FD0\u884C\u72B6\u6001\u3002"}),R(e.client)),e.activityPublisher?.publish(s,null)}o===!0&&e.chatQueue?.purgeSession(s),e.client.sendRes({type:"res",id:n.id,ok:!0})}export{Ve as STOP_TIMEOUT_MS,mn as handleChatAbort,pn as handleChatSend,vn as sendSessionUpdateEvent,hn as validateManagedRoomExecutionContext};
1
+ import{buildUserMessagePayload as ce}from"@shennian/wire";import{createHash as Pe,randomUUID as Ee}from"node:crypto";import ue from"node:os";import{reportLog as b}from"../../log-reporter.js";import{getPersonalSyncIdentity as De}from"../../personal-sync/epoch.js";import{buildManagedAgentPermissionPrompt as Te}from"../../room/managed-prompt-composer.js";import{parsePersonalAttachmentReferences as be}from"../attachment-reference.js";import{assertFinishedAttachmentReferences as xe,markAttachmentReferences as $e}from"../attachment-transfer-store.js";import{requestSessionIndexPublish as _}from"../index-publisher.js";import{isTrustedManagerEvent as Ce}from"../manager-event-authority.js";import{mergeProjectedSessions as We}from"../projection.js";import{appendMessage as ge,getDaemonInstallationId as pe,getMessageDeliveryStatus as qe,upsertMessage as S}from"../store.js";import{configureAdapterForSession as me,maybeResolveClaudeImportedWorkDir as je,replaceManagedRoomContextToken as fe,revokeManagedRoomContextToken as ye}from"./chat-adapter-config.js";import{resolveNativeSessionVisibility as Fe,sendSessionUpdateEvent as Oe,validateManagedRoomExecutionContext as Be}from"./chat-context.js";import{getNativeSourceAgentType as Je}from"./chat-events.js";import{noteRunActivity as ze}from"../run-stall.js";import{createActiveSession as Ue,disposeSession as C,prepareAdapterTurn as He,rememberProcessedReqId as Ne,sendAdapterTurn as ve}from"./chat-session-lifecycle.js";import{sendSessionUpdateEvent as In,validateManagedRoomExecutionContext as Rn}from"./chat-context.js";function he(e,n){return`Agent send failed: ${n instanceof Error?n.message:String(n)}`}function Ve(e,n){const o=e.sessions.get(n),s=o?.currentRunId;if(!o||!s)return;const t=o.nextEventSeq;e.runTextAcc.delete(`${n}:${s}`),ye(e,o),o.pendingTextEvent=null,ze(n,o,!0),o.currentRunId=null,o.currentRunPhase=null,o.nextEventSeq=0,o.heartbeatTimer&&(clearInterval(o.heartbeatTimer),o.heartbeatTimer=null),e.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"aborted",sessionId:n,runId:s,seq:t},seq:t,id:`agent-evt-${s}-${t}`}),o.journalRunId&&(e.runJournal?.remove(n,o.journalRunId),e.recoveryBarrier?.end(n),o.journalRunId=null),e.chatQueue?.noteTerminal(n)}async function fn(e,n,o){const s=o?n.params.managedRoomContextToken??null:null;let t=!1;try{await Ke(e,n,o,()=>{t=!0})}finally{s&&!t&&e.revokeManagedRoomContextToken?.(s)}}async function Ke(e,n,o,s){if(e.processedReqIds.has(n.id)){e.client.sendRes({type:"res",id:n.id,ok:!0});return}const{sessionId:t,text:p,agentType:R,sessionMode:W,managerConfig:X,workDir:Ie,agentSessionId:m,modelId:y,modelSelectionSource:q,systemPrompt:Y,managerDefaultWorkerAgentType:j,managerDefaultWorkerModelId:F,reasoningEffort:O,clientMessageId:Re,sessionListProjection:_e,waitForDispatch:ee,responseId:Se,managedRoomContextToken:w,suppressExternalOwnerEcho:we,queuedBatchItems:B,managedWorkerParentSessionId:g,managerWorkerRoomOrigin:J,managerWorkerNativeFull:z,managedRecoverySource:E}=n.params,c=Se||n.id,ne=n.params;if((ne.managerEventId||ne.managerEventRoomOrigin||g||J||z||E)&&!Ce(n))throw new Error("manager_event_source_untrusted");We(_e);const x=null,U="";if(o?.source==="room_activation"&&(Be(o,Y,w),R==="manager"))throw new Error("managed_agent_manager_mode_unsupported");if(o?.source==="manager_event"){if(!o.managedAgentPolicy)throw new Error("managed_agent_policy_missing");if(!w||!/^mrc_[A-Za-z0-9_-]{43}$/.test(w))throw new Error("managed_room_context_unavailable")}if(Ne(e,n.id),!t||!p){e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:c,ok:!1,error:"sessionId and text are required"});return}if(e.recoveryBarrier?.isDispatchFrozen()){e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:c,ok:!1,error:"upgrade_in_progress"});return}e.recoveryBarrier?.isRecovering(t)&&await e.recoveryBarrier.wait(t);const i=R,k=i==="manager"||W==="manager"?"manager":"standard";k==="manager"&&e.managerRuntime?.setManagerWorkerDefaults(t,j??null,F??null);const D=(i==="claude"||i==="codex"||i==="workbuddy"||i==="pi-coding-agent"||i.startsWith("acp:"))&&typeof O=="string"&&O.trim()?O.trim():void 0,H=o?.source==="room_activation"?{source:"room_activation",...i==="pi-coding-agent"?{modelSelectionSource:q??(y?"request_model":"pi_default_model")}:{}}:o?.source==="manager_event"?{source:"managed_private",...i==="pi-coding-agent"?{modelSelectionSource:q??(y?"request_model":"pi_default_model")}:{}}:i==="pi-coding-agent"?{source:"personal",modelSelectionSource:q??(y?"request_model":"pi_default_model")}:void 0,h=e.resolvePath(je(i,Ie||ue.homedir(),m)||ue.homedir()),v=o?.managedAgentPolicy??(g?e.managerRuntime?.getManagedAgentPolicyForWorker(g,h)??null:null);if(g&&!z&&!v)throw new Error("managed_worker_permission_context_unavailable");const N=Fe(t,i,k,!!(v||g||o)),V=g&&v?Te({requestedPolicy:v.requestedPolicy,enforcement:v.enforcement,resolvedWorkDir:v.adapterPolicy.workDir}):Y??null,ke=h,$=be(n.params.attachments);$?.length&&xe(h,$);const f={text:p,attachments:$,localized:!1};let r=e.sessions.get(t);if(r){if(r.lastActiveAt=Date.now(),r.agentType!==i||(r.sessionMode??(r.agentType==="manager"?"manager":"standard"))!==k||r.workDir!==h||(r.nativeSessionVisibility??"user")!==N||JSON.stringify(r.externalChannel??null)!==JSON.stringify(x??null)){e.sessions.delete(t);try{await C(e,r)}catch{e.processedReqIds.delete(n.id)}r=void 0}else if(m&&r.agentSessionId!==m)try{await r.adapter.resume(m),r.agentSessionId=m}catch{e.sessions.delete(t);try{await C(e,r)}catch{e.processedReqIds.delete(n.id)}r=void 0}}if(!r)try{r=await Ue(e,t,i,k,h,m,x,U,v,N)}catch(a){const l=a instanceof Error&&a.message.startsWith("Unsupported agent:")?a.message:`Failed to start ${R}: ${a instanceof Error?a.message:String(a)}`;console.error(`[chat.send] start failed reqId=${n.id} sessionId=${t} agentType=${R} workDir=${h} agentSessionId=${m??""}: ${l}`),e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:t,message:l,runId:"",seq:0}}),e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:c,ok:!1,error:l});return}const u={id:Re??`user-${n.id}`,sessionId:t,role:"user",ts:Date.now(),payload:ce(f.text,f.attachments)},ae=Array.isArray(B)&&B.length>0?B.map(a=>({id:a.clientMessageId??a.id,sessionId:t,role:E==="manager_event"||n.params.scheduledDelivery===!0?"agent":"user",ts:E==="manager_event"||o?.source==="room_activation"?Date.parse(a.createdAt):u.ts,payload:ce(a.text,a.attachments)})):null,A=ae??[u],K=qe(t,u.id),te=K.state==="queued";if(K.state!=="not_found"&&!te){e.client.sendRes({type:"res",id:c,ok:!0,payload:K});return}if(ee){(o?.source==="room_activation"||o?.source==="manager_event")&&me(r.adapter,t,i,x,U,w,o.managedAgentPolicy,e.managedRoomExecutor);try{await He(r.adapter,f.text,y,D,f.attachments,V,H)}catch(a){e.processedReqIds.delete(n.id),e.sessions.delete(t),await C(e,r),e.client.sendRes({type:"res",id:c,ok:!1,error:a instanceof Error?a.message:String(a)});return}}b({level:"info",sessionId:t,wsEvent:"chat.send.start",metadata:{reqId:n.id,agentType:i,sessionMode:k,managerConfig:X??null,modelId:y,managerDefaultWorkerAgentType:j??null,managerDefaultWorkerModelId:F??null,reasoningEffort:D,...o?.source==="room_activation"?{managedRoomPromptSnapshot:o.managedRoomPromptSnapshot}:{}}});const M=(a,l)=>({...De(pe()),sessionId:t,clientMessageId:u.id,messageId:u.id,deliveryState:a,bodyRevision:l,committedAt:new Date(u.ts).toISOString()}),L=a=>{e.nativeFusion?.registerManagedSend({sessionId:t,agentType:i,sourceAgentType:Je(i,y),canonicalMessageId:u.id,sourceSessionKey:r.agentSessionId??m??null,text:f.text,managedEchoPolicy:a?.deliveryMode==="external_owner_queue"&&!we?"import_following":"suppress_following",externalRunId:a?.deliveryMode==="external_owner_queue"?`codex-external-${a.queuedSubmissionId??u.id}`:null})},oe=()=>{r.currentRunId||(r.currentRunId=`dispatch:${n.id}`,r.currentRunPhase="thinking",r.nextEventSeq=0,r.lastProviderActivityAt=Date.now())},re=()=>{if(!e.runJournal||r.journalRunId)return;const a=`run:${Ee()}`;e.runJournal.begin({daemonInstallationId:pe(),sessionId:t,runId:a,clientMessageId:u.id,agentType:i,sessionMode:k,workDir:h,agentSessionId:r.agentSessionId??m??null,modelId:y??null,reasoningEffort:D??null,nativeSessionVisibility:N,providerRunId:null,source:E==="manager_event"?"manager_event":o?.source==="room_activation"?E==="managed_direct"?"managed_direct":"managed_room":g?"manager_worker":"personal",parentSessionId:g??null,managerWorkerNativeFull:z===!0,roomContextRegistryKey:typeof n.params.roomContextRegistryKey=="string"?n.params.roomContextRegistryKey:null,activationCauseMessageId:typeof n.params.activationCauseMessageId=="string"?n.params.activationCauseMessageId:null,rootCauseMessageId:typeof n.params.rootCauseMessageId=="string"?n.params.rootCauseMessageId:null,activationSequence:typeof n.params.activationSequence=="string"?n.params.activationSequence:null,activationHopCount:typeof n.params.activationHopCount=="number"?n.params.activationHopCount:null,managedPolicyVersion:o?.source==="room_activation"?o.managedRoomPromptSnapshot.managedRoomPolicyVersion:o?.source==="manager_event"?o.managedRoomPolicyVersion:null,managedRuntimePolicyHash:(o?.source==="room_activation"?o.managedRoomPromptSnapshot.runtimePermissionPolicyHash:o?.source==="manager_event"?o.managedRuntimePolicyHash:null)??(v?Pe("sha256").update(JSON.stringify({requestedPolicy:v.requestedPolicy,enforcement:v.enforcement})).digest("hex"):null)}),r.journalRunId=a},se=()=>{if(L(),te){let a=0;for(const[l,d]of A.entries()){const I=S(t,d,"queued");l===0&&(a=I)}return M("queued",a)}try{Oe(e,{sessionId:t,agentType:i,sessionMode:k,managerConfig:X??null,workDir:ke,agentSessionId:r.agentSessionId??m??null,modelId:y,managerDefaultWorkerAgentType:j??null,managerDefaultWorkerModelId:F??null});let a=0;for(const[l,d]of A.entries()){const I=ae?S(t,d,"committed"):ge(t,d,"committed");l===0&&(a=I)}return $e(h,$??[]),_(e.client),M("committed",a)}catch(a){throw e.nativeFusion?.cancelManagedSend?.(u.id),a}},ie=a=>{r.journalRunId&&e.runJournal?.update(t,r.journalRunId,{deliveryMode:a?.deliveryMode==="external_owner_queue"?"external_owner_queue":"direct",externalRunId:a?.deliveryMode==="external_owner_queue"?`codex-external-${a.queuedSubmissionId??u.id}`:null})},de=a=>{r.currentRunId||(r.nextEventSeq=0),ie(a),L(a);const l=a?.deliveryMode==="external_owner_queue"?"queued":"executing";let d=0;for(const[I,T]of A.entries()){const P=S(t,T,l);I===0&&(d=P)}return _(e.client),M(l,d)},Q=async(a,l)=>{e.nativeFusion?.cancelManagedSend?.(u.id);const d=he(i,a);if(console.error(`[chat.send] send failed reqId=${n.id} sessionId=${t} agentType=${R} workDir=${h} agentSessionId=${r.agentSessionId??m??""}: ${d}`),r.adapter.hasPendingAuthenticationRetry?.()===!0){l&&e.client.sendRes({type:"res",id:c,ok:!0,payload:M("queued",0)});return}e.sessions.delete(t),r.journalRunId&&(e.runJournal?.update(t,r.journalRunId,{phase:"terminal"}),e.runJournal?.remove(t,r.journalRunId),e.recoveryBarrier?.end(t),r.journalRunId=null);try{await C(e,r)}catch{}if(e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:t,message:d,runId:"",seq:0}}),!l){const T={id:`agent-error-${n.id}-${Date.now()}`,sessionId:t,role:"agent",ts:Date.now(),payload:d};ge(t,T),_(e.client)}l&&(e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:c,ok:!1,error:d}))};if(ee){try{se()}catch(d){e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:c,ok:!1,error:`Durable message commit failed: ${d instanceof Error?d.message:String(d)}`});return}re(),oe();let a;try{(o?.source==="room_activation"||o?.source==="manager_event")&&(fe(e,r,w),s());const d=f.attachments;g&&e.managerRuntime?.prepareWorkerTurnOrigin(t,J),a=await ve(r.adapter,f.text,y,D,d,V,H),b({level:"info",sessionId:t,wsEvent:"chat.send.done",metadata:{reqId:n.id}})}catch(d){if(g&&e.managerRuntime?.prepareWorkerTurnOrigin(t),r.adapter.hasPendingAuthenticationRetry?.()){let P=0;for(const[Z,G]of A.entries()){const Me=S(t,G,"queued");Z===0&&(P=Me)}_(e.client),await Q(d,!1),e.client.sendRes({type:"res",id:c,ok:!0,payload:M("queued",P)});return}let I=0;for(const[P,Z]of A.entries()){const G=S(t,Z,"failed");P===0&&(I=G)}_(e.client);const T=he(i,d);await Q(d,!1),e.client.sendRes({type:"res",id:c,ok:!0,payload:{...M("failed",I),failureMessage:T}});return}const l=de(a??void 0);e.client.sendRes({type:"res",id:c,ok:!0,payload:{...l,...f.localized?{localizedAttachments:!0}:{},...a?.deliveryMode==="external_owner_queue"?{queued:!0,deliveryMode:a.deliveryMode,queuedSubmissionId:a.queuedSubmissionId}:{}}}),b({level:"info",sessionId:t,wsEvent:"chat.send.res",metadata:{reqId:n.id,ok:!0}});return}let le;try{le=se()}catch(a){e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:c,ok:!1,error:`Durable message commit failed: ${a instanceof Error?a.message:String(a)}`});return}re(),oe(),(o?.source==="room_activation"||o?.source==="manager_event")&&(me(r.adapter,t,i,x,U,w,o.managedAgentPolicy,e.managedRoomExecutor),fe(e,r,w),s()),de(),e.client.sendRes({type:"res",id:c,ok:!0,payload:{...le,...f.localized?{localizedAttachments:!0}:{}}}),b({level:"info",sessionId:t,wsEvent:"chat.send.res",metadata:{reqId:n.id,ok:!0}});const Ae=f.attachments;g&&e.managerRuntime?.prepareWorkerTurnOrigin(t,J),ve(r.adapter,f.text,y,D,Ae,V,H).then(a=>{if(a?.deliveryMode==="external_owner_queue"){ie(a),L(a);for(const l of A)S(t,l,"queued");_(e.client)}b({level:"info",sessionId:t,wsEvent:"chat.send.done",metadata:{reqId:n.id}})}).catch(a=>{g&&e.managerRuntime?.prepareWorkerTurnOrigin(t),S(t,u,r.adapter.hasPendingAuthenticationRetry?.()?"queued":"failed"),_(e.client),Q(a,!1)})}const Le=2e4;async function Qe(e,n){let o;const s=new Promise(t=>{o=setTimeout(()=>t("timed_out"),n)});try{return await Promise.race([e.adapter.stop().then(()=>"stopped"),s])}finally{clearTimeout(o)}}async function yn(e,n,o=Le){const{sessionId:s,discardPending:t}=n.params,p=e.sessions.get(s);if(p){p.journalRunId&&e.runJournal?.markAborted(s,p.journalRunId),ye(e,p);let R;try{R=await Qe(p,o)}catch{e.client.sendRes({type:"res",id:n.id,ok:!1,error:"agent_stop_failed"});return}const W=p.currentRunId;Ve(e,s),R==="timed_out"&&(e.sessions.delete(s),p.adapter.removeAllListeners(),p.adapter.stop().catch(()=>{}),console.error(`[chat.abort] agent did not stop within ${o}ms; ended the run by force sessionId=${s}`),S(s,{id:`stop-forced-${W??n.id}`,sessionId:s,role:"agent",ts:Date.now(),payload:"AI \u6CA1\u6709\u54CD\u5E94\u201C\u505C\u6B62\u201D\u8BF7\u6C42\uFF0C\u795E\u5FF5\u5DF2\u5F3A\u5236\u7ED3\u675F\u8FD9\u4E00\u8F6E\u3002\u53EF\u4EE5\u76F4\u63A5\u53D1\u9001\u65B0\u6D88\u606F\u7EE7\u7EED\uFF1B\u5982\u679C\u53CD\u590D\u51FA\u73B0\uFF0C\u8BF7\u68C0\u67E5\u8FD9\u53F0\u7535\u8111\u4E0A\u8BE5 AI \u7684\u8FD0\u884C\u72B6\u6001\u3002"}),_(e.client)),e.activityPublisher?.publish(s,null)}t===!0&&e.chatQueue?.purgeSession(s),e.client.sendRes({type:"res",id:n.id,ok:!0})}export{Le as STOP_TIMEOUT_MS,yn as handleChatAbort,fn as handleChatSend,In as sendSessionUpdateEvent,Rn as validateManagedRoomExecutionContext};
@@ -1 +1 @@
1
- import b from"node:crypto";import{getRegisteredAgents as S,unregisterAgent as k}from"../agents/adapter.js";import{resetCommandSpecCache as w}from"../agents/command-spec.js";import{loadConfig as A}from"../config/index.js";import{handleUpgradeStart as I,handleUpgradeStatus as T}from"../commands/upgrade.js";import{handleAgentsRefresh as P,handleModelsRefresh as C,refreshMachineAgents as M}from"./handlers/agents.js";import{AcpDiscoveryWatcher as x}from"../agents/acp/watcher.js";import{handleAgentCapabilitiesList as D}from"./handlers/agent-capabilities.js";import{handleAgentConfigClear as F,handleAgentConfigGet as E,handleAgentConfigTest as Q,handleAgentConfigUpsert as j}from"./handlers/agent-config.js";import{handleChatAbort as z,handleChatSend as O}from"./handlers/chat.js";import{recoverJournaledRun as B}from"./handlers/chat-recovery.js";import{handleSessionRefresh as W}from"./handlers/session-refresh.js";import{handleSessionToolDetail as _}from"./handlers/tool-detail.js";import{handleSessionTitleSet as H}from"./handlers/title.js";import{handleSessionMessageStatus as U}from"./handlers/message-status.js";import{handleAgentWorkspaceValidation as J}from"./handlers/agent-workspace-validation.js";import{handleVoiceSessionBodyWindow as $}from"./handlers/voice-window.js";import{handleRemoteAccessPause as V}from"./handlers/remote-access.js";import{cleanupPendingTransfers as L,handleFsLs as N,handleFsRead as G,handleFsRename as K,handleFsWrite as X,handleFsTransferAbort as Z,handleFsTransferChunk as Y,handleFsTransferFinish as q,handleFsTransferStart as ee,handleFsExportMarkdownPdf as se,handleFsExportMarkdownPdfSetup as te,handleFsArchiveZip as ae}from"./handlers/fs.js";import{handleRegionProbe as re,handleRegionSwitch as ne,handleUpgradeSetPolicy as ie}from"./handlers/control.js";import{ManagerRuntimeService as oe,setManagerRuntimeService as u}from"../manager/runtime.js";import{ChatQueueManager as ce}from"./queue.js";import{createAuthorizedFsRoot as le,createAuthorizedFsRootAsync as he,resolveAuthorizedPath as ue,resolveAuthorizedPathAsync as de,resolveSessionWorkDir as me}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/pi-coding-agent.js";import"../agents/manager.js";import{registerCustomAgent as pe}from"../agents/custom.js";import{handleManagedRoomBind as ge,handleManagedRoomRestart as fe,discardPreBindingSession as ve}from"./handlers/room-managed.js";import{getDaemonInstallationId as d,listSessionRecords as h,purgeCanonicalSession as ye,purgeSessionRecord as Re,recordSession as be,upsertMessage as Se}from"./store.js";import{requestSessionIndexPublish as m}from"./index-publisher.js";import{checkRunStalls as ke}from"./run-stall.js";import{reportUpgradeAggregateMetric as we}from"../log-reporter.js";import{PersonalHistorySubscriptions as Ae}from"./history-subscriptions.js";import{sweepAttachmentTransfers as Ie}from"./attachment-transfer-store.js";import{NativeSourceDeletionStore as Te}from"../native-fusion/native-source-deletions.js";import{collectLocalNativeSources as Pe}from"../native-fusion/session-native-sources.js";import{purgeToolDetails as Ce}from"./tool-detail-store.js";import{NativeSessionCleanupOutbox as Me}from"./native-cleanup-outbox.js";import{assertPersonalSyncIdentity as o}from"../personal-sync/epoch.js";import{ActiveRunJournal as xe}from"./run-recovery/journal.js";import{RunRecoveryBarrier as De}from"./run-recovery/barrier.js";import{RunRecoveryCoordinator as Fe}from"./run-recovery/coordinator.js";import{ProjectFsHandleStore as Ee}from"./project-fs-store.js";import{handleProjectFsRequest as Qe}from"./handlers/project-fs.js";import{handleAgentPermissionResponse as je,handleAcpAgentRequest as ze}from"./handlers/agent-control.js";import{SessionDeletionSynchronizer as Oe}from"./deletion-synchronizer.js";import{dispatchManagedChat as Be,dispatchQueuedChat as We,interruptQueuedChat as _e}from"./queued-chat-dispatch.js";const He=50;import{resolveSessionWorkDir as Vs}from"../fs/boundary.js";function Ue(){return"\u795E\u5FF5\u5347\u7EA7\u4E2D\u65AD\u4E86\u672C\u6B21\u8FD0\u884C\u3002\u5DF2\u5B8C\u6210\u7684\u56DE\u590D\u6216\u64CD\u4F5C\u4ECD\u7136\u6709\u6548\uFF0C\u672A\u5B8C\u6210\u90E8\u5206\u53EF\u91CD\u8BD5\u3002\u539F\u4F1A\u8BDD\u5DF2\u4FDD\u7559\u3002"}class Us{client;nativeFusion;cliVersion;upgradePolicyController;managedRoomBinder;remoteAccessPauseController;managedRoomContextRevoker;managedRoomExecutor;trustedProjectFsRequestResolver;getAgentSnapshot;scheduleHandler;getScheduleQueue(){return this.chatQueue}sessions=new Map;processedReqIds=new Set;runTextAcc=new Map;pendingTransfers=new Map;managerRuntime;chatQueue;historySubscriptions;nativeCleanupOutbox;activityProbeTimer=null;attachmentCleanupTimer=null;activeRequests=0;acpDiscoveryWatcher;runJournal;recoveryBarrier=new De;recoveryCoordinator;recoveryPass=null;prepareManagedRecovery;projectFsHandleStore=new Ee;deletionSynchronizer;constructor(e,t=null,s,n=null,r=null,l=null,p=null,g=null,f=null,v=null,y=null){this.client=e,this.nativeFusion=t,this.cliVersion=s,this.upgradePolicyController=n,this.managedRoomBinder=r,this.remoteAccessPauseController=l,this.managedRoomContextRevoker=p,this.managedRoomExecutor=g,this.trustedProjectFsRequestResolver=v,this.getAgentSnapshot=y,this.runJournal=f??new xe(d());for(const a of this.runJournal.loadPendingReconciliation().records)this.recoveryBarrier.begin(a.sessionId);this.recoveryCoordinator=new Fe({journal:this.runJournal,barrier:this.recoveryBarrier,recover:(a,i)=>B(this.getRuntime(),a,i),commitTerminal:(a,i)=>this.commitRecoveryTerminal(a,i),isCanonicalTerminal:a=>{const i=h().find(R=>R.sessionId===a.sessionId),c=`terminal:${b.createHash("sha256").update(`${a.runId}\0`).digest("hex")}`;return i?.lastAttentionId===c},onOutcome:a=>we({kind:"recovery",adapterType:a.adapterType,result:a.result,stage:a.result==="continued"?"continue":a.result==="reattached"?"reattach":a.result==="resumed"?"resume":a.result==="terminal_reconciled"?"inspect":"terminal",durationMs:a.durationMs,retries:Math.max(0,a.attempts-1),...a.reason?{errorCode:a.reason}:{}})}),this.managerRuntime=new oe({getRuntime:()=>this.getRuntime(),getAgentSnapshot:this.getAgentSnapshot??void 0,dispatchReq:a=>this.handleReq(a,{propagateErrors:!0})}),this.chatQueue=new ce({getRuntime:()=>this.getRuntime(),dispatchReq:a=>this.handleReq(a),dispatchManagedReq:(a,i)=>Be(this.getRuntime(),a,i),dispatchQueuedReq:(a,i)=>We(this.getRuntime(),a,i),interruptQueuedSession:a=>_e(this.getRuntime(),a)}),this.deletionSynchronizer=new Oe(e,a=>this.applySessionDeletion(a)),this.historySubscriptions=new Ae(this.client),this.nativeCleanupOutbox=new Me({logger:console.info}),this.acpDiscoveryWatcher=new x(async()=>{w(),await M(this.getRuntime())}),this.nativeFusion?.setExternalTerminalHandler?.(a=>{this.handleExternalTerminal(a)}),this.nativeFusion?.setExternalClaimHandler?.((a,i)=>{this.chatQueue.noteExternalClaim(a,i)}),this.nativeCleanupOutbox.start(),u(this.managerRuntime),this.managerRuntime.start(),this.reloadCustomAgents();try{this.acpDiscoveryWatcher.start()}catch(a){console.warn(`[acp.discovery] watcher unavailable: ${a instanceof Error?a.message:String(a)}`)}this.activityProbeTimer=setInterval(()=>{ke(this.sessions.entries(),()=>m(this.client)),this.publishManagedActivitySnapshots().catch(a=>{console.error("[session.activity] managed probe failed",a)})},15e3),this.activityProbeTimer.unref?.(),this.attachmentCleanupTimer=setInterval(()=>{const a=new Set([...h().map(i=>i.workDir),...Array.from(this.pendingTransfers.values()).map(i=>i.rootPath)]);for(const i of a)try{Ie(this.resolvePath(i))}catch(c){console.error("[attachment.cleanup] failed",c instanceof Error?c.message:String(c))}},6e4),this.attachmentCleanupTimer.unref?.()}executeManagedManagerAction(e){return this.managerRuntime.executeScopedWorkerAction(e.managerSessionId,e.action,e.params,e.roomOrigin)}noteManagedRoomSendOutcome(e){for(const t of this.sessions.values()){if(t.managedRoomContextToken!==e.token)continue;const s=t.roomSendOutcome??(t.roomSendOutcome={successes:0,failureCodes:[]});e.ok?s.successes+=1:s.failureCodes.length<20&&s.failureCodes.push(e.errorCode??"managed_room_action_failed");return}}getRuntime(){return{client:this.client,pendingTransfers:this.pendingTransfers,processedReqIds:this.processedReqIds,reloadCustomAgents:()=>this.reloadCustomAgents(),getAgentSnapshot:this.getAgentSnapshot??void 0,resolvePath:e=>this.resolvePath(e),resolveAuthorizedPath:(e,t)=>this.resolveAuthorizedPath(e,t),resolveAuthorizedPathAsync:(e,t)=>this.resolveAuthorizedPathAsync(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,revokeManagedRoomContextToken:this.managedRoomContextRevoker,managedRoomExecutor:this.managedRoomExecutor,runJournal:this.runJournal,recoveryBarrier:this.recoveryBarrier,prepareManagedRecovery:this.prepareManagedRecovery}}async resumePendingAcpAuthentication(e){const t=[...this.sessions.values()].find(s=>s.agentType===e&&s.adapter.hasPendingAuthenticationRetry?.());return t?.adapter.resumeAfterExternalAuthentication?(await t.adapter.resumeAfterExternalAuthentication(),!0):!1}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}}prepareForUpgrade(e){this.recoveryBarrier.freezeDispatch();const t=this.runJournal.markPlannedUpgrade(e);return this.runJournal.sync(),{activeRunCount:t}}cancelUpgradePreparation(){this.recoveryBarrier.unfreezeDispatch()}async recoverInterruptedRuns(){this.recoveryPass??=this.recoveryCoordinator.recoverAll(),await this.recoveryPass}getPendingRecoveryCount(){return this.runJournal.loadPendingReconciliation().records.length}revokeProjectFsHandles(){this.projectFsHandleStore.revokeAll()}async commitRecoveryTerminal(e,t){const s=this.sessions.get(e.sessionId);s&&(s.currentRunId=null,s.currentRunPhase=null,s.journalRunId=null,s.heartbeatTimer&&(clearInterval(s.heartbeatTimer),s.heartbeatTimer=null)),this.runTextAcc.delete(`${e.sessionId}:${e.providerRunId??e.runId}`),this.publishSessionActivity(e.sessionId,null);const n=Ue();Se(e.sessionId,{id:`upgrade-recovery-terminal-${e.runId}`,sessionId:e.sessionId,role:"agent",ts:Date.now(),payload:JSON.stringify({v:1,type:"error",content:n,error:!0,recoveryState:t.result,recoveryReason:t.reason})}),be({sessionId:e.sessionId,agentType:e.agentType,sessionMode:e.sessionMode,workDir:e.workDir,agentSessionId:e.agentSessionId,modelId:e.modelId,status:"failed",attentionId:`upgrade-recovery:${e.runId}`,lastActivityAt:new Date().toISOString()}),this.managerRuntime.noteAgentEvent(e.sessionId,{state:"error",runId:e.providerRunId??e.runId,seq:e.lastObservedEventSeq+1,message:n}),m(this.client);const r=e.lastObservedEventSeq+1;this.client.sendAgentEvent({type:"event",event:"agent",payload:t.result==="interrupted_by_upgrade"?{state:"interrupted_by_upgrade",sessionId:e.sessionId,runId:e.providerRunId??e.runId,seq:r,reason:t.reason}:{state:"recovery_failed",sessionId:e.sessionId,runId:e.providerRunId??e.runId,seq:r,reason:t.reason,...t.message?{message:t.message}:{}},seq:r,id:`agent-recovery-terminal-${e.runId}`}),this.chatQueue.noteTerminal(e.sessionId)}setManagedRoomTurnPreparer(e){this.chatQueue.setManagedRoomTurnPreparer(e)}setManagedAgentDirectTurnPreparer(e){this.chatQueue.setManagedAgentDirectTurnPreparer(e)}setManagedRecoveryPreparer(e){this.prepareManagedRecovery=e}async enqueueManagedRoomBatch(e){const t=e.map(s=>{const n=h().find(r=>r.sessionId===s.params.sessionId);return{context:s.context,params:{...s.params,modelId:n?.modelId??s.params.modelId,sessionMode:n?.sessionMode??s.params.sessionMode,managerConfig:n?.managerConfig??s.params.managerConfig,managerDefaultWorkerAgentType:n?.managerDefaultWorkerAgentType??s.params.managerDefaultWorkerAgentType,managerDefaultWorkerModelId:n?.managerDefaultWorkerModelId??s.params.managerDefaultWorkerModelId}}});await this.chatQueue.enqueueManagedRoomBatch(t)}async retireManagedRoomSession(e){this.chatQueue.purgeSession(e),await ve(this.getRuntime(),e)}discardPendingManagedRoomMessages(e){return this.chatQueue.discardPendingManagedRoomMessages(e)}async synchronizeSessionDeletions(){await this.deletionSynchronizer.synchronize()}async applySessionDeletion(e){const t=new Te({daemonInstallationId:d()});let s=[];try{s=Pe(e.sessionId,{records:h()})}catch(r){console.warn("[session.deletions] local native source lookup failed",{error:r instanceof Error?r.message:String(r)})}t.recordSession(e);for(const r of[...e.sources,...s]){const l=t.find(r.agentType,r.sourceSessionKey);l&&l.sessionId!==e.sessionId||t.record({...e,...r})}this.runJournal.markSessionAborted(e.sessionId),this.recoveryBarrier.end(e.sessionId);const n=this.sessions.get(e.sessionId);if(n){this.revokeManagedRoomToken(n);try{await n.adapter.stop()}catch{}this.sessions.delete(e.sessionId)}this.historySubscriptions.closeSession(e.sessionId),this.nativeFusion?.handleSessionDeleted(e.sessionId),this.chatQueue.purgeSession(e.sessionId),Ce(e.sessionId),ye(e.sessionId),Re(e.sessionId),this.runTextAcc.delete(e.sessionId),this.publishSessionActivity(e.sessionId,null),this.nativeCleanupOutbox.enqueue(e),this.nativeCleanupOutbox.kick()}publishSessionActivity(e,t){this.client.sendEvent({type:"event",event:"session.activity",payload:{sessionId:e,activity:t}})}async handleExternalTerminal(e){const t=this.sessions.get(e);t&&(t.journalRunId&&(this.recoveryCoordinator.completeFromProvider(e,t.journalRunId),t.journalRunId=null),this.sessions.delete(e),this.revokeManagedRoomToken(t),t.heartbeatTimer&&clearInterval(t.heartbeatTimer),t.adapter.removeAllListeners(),await t.adapter.stop().catch(()=>{})),this.chatQueue.noteTerminal(e)}async publishManagedActivitySnapshots(){for(const[e,t]of this.sessions.entries()){if(t.heartbeatTimer||!t.currentRunId||!t.adapter.getStatus)continue;const s=await t.adapter.getStatus().catch(()=>null);if(!s?.active||!s.runPhase)continue;const n=new Date().toISOString();this.publishSessionActivity(e,{sessionId:e,runId:s.runId||t.currentRunId,runPhase:s.runPhase,startedAt:new Date(t.lastActiveAt).toISOString(),updatedAt:n,canStop:s.canStop??!0});const r=t.heartbeatSeq++;this.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"heartbeat",sessionId:e,runId:s.runId||t.currentRunId,seq:r,runPhase:s.runPhase,canStop:s.canStop??!0},seq:r,id:`agent-status-${s.runId||t.currentRunId}-${Date.now()}`})}}reloadCustomAgents(){for(const t of S())t.startsWith("custom:")&&k(t);const e=A();for(const[t,s]of Object.entries(e.customAgents??{}))pe(t,s)}async handleReq(e,t={}){const s=this.getRuntime();let n;this.activeRequests++;try{switch(e.method){case"schedule.deliver":if(!this.scheduleHandler)throw new Error("schedules_unavailable");await this.scheduleHandler(e);break;case"chat.send":if(e.params.scheduledDelivery)throw new Error("schedule_source_untrusted");o(e.params),this.recoveryBarrier.isDispatchFrozen()||this.recoveryBarrier.isRecovering(String(e.params.sessionId??""))?n={durableQueueHandoff:await this.chatQueue.handleEnqueue({...e,method:"chat.enqueue"})}:await O(s,e);break;case"chat.enqueue":o(e.params),n={durableQueueHandoff:await this.chatQueue.handleEnqueue(e)};break;case"chat.queue.get":o(e.params),await this.chatQueue.handleGet(e);break;case"chat.queue.edit":o(e.params),await this.chatQueue.handleEdit(e);break;case"chat.queue.delete":o(e.params),await this.chatQueue.handleDelete(e);break;case"chat.queue.promote":o(e.params),await this.chatQueue.handlePromote(e);break;case"chat.abort":o(e.params),await z(s,e);break;case"session.refresh":o(e.params),await W(s,e);break;case"session.history.open":this.historySubscriptions.handleOpen(e);break;case"session.history.sync":this.historySubscriptions.handleSync(e);break;case"session.history.page":this.historySubscriptions.handlePage(e);break;case"session.history.close":this.historySubscriptions.handleClose(e);break;case"session.body.replica.subscribe":this.historySubscriptions.handleReplicaSubscribe(e);break;case"session.body.replica.unsubscribe":this.historySubscriptions.handleReplicaUnsubscribe(e);break;case"session.history":this.client.sendRes({type:"res",id:e.id,ok:!1,error:"upgrade_required"});break;case"session.message.status":U(s,e);break;case"session.tool.detail":await _(s,e);break;case"voice.session.body.window":$(s,e);break;case"session.title.set":await H(s,e);break;case"room.agent.bind-managed":await ge(s,this.managedRoomBinder,e);break;case"room.agent.restart-managed":await fe(s,this.managedRoomBinder,e);break;case"fs.ls":await N(s,e);break;case"project.fs.open":case"project.fs.list":case"project.fs.read":case"project.fs.close":await Qe(this.client,this.projectFsHandleStore,e,this.trustedProjectFsRequestResolver);break;case"fs.read":await G(s,e);break;case"fs.write":await X(s,e);break;case"fs.export.markdown-pdf":await se(s,e);break;case"fs.export.markdown-pdf.setup":await te(s,e);break;case"fs.archive.zip":await ae(s,e);break;case"fs.rename":await K(s,e);break;case"fs.transfer.start":await ee(s,e);break;case"fs.transfer.chunk":await Y(s,e);break;case"fs.transfer.finish":await q(s,e);break;case"fs.transfer.abort":await Z(s,e);break;case"region.probe":await re(s,e);break;case"region.switch":await ne(s,e);break;case"upgrade.start":await I(this.client,e.id,e.params.version,{currentVersion:this.cliVersion,confirmedMajor:e.params.confirmedMajor===!0,prepareForUpgrade:r=>this.prepareForUpgrade(r),cancelUpgradePreparation:()=>this.cancelUpgradePreparation(),shutdownAfterHandoff:()=>{setTimeout(()=>process.kill(process.pid,"SIGTERM"),100).unref?.()}});break;case"upgrade.status":await T(this.client,e.id,{currentVersion:this.cliVersion});break;case"upgrade.set-policy":await ie(s,e);break;case"machine.remote-access.pause":await V(this.client,this.remoteAccessPauseController,e);break;case"agents.refresh":await P(s,e);break;case"agent.permission.respond":await je(s,e);break;case"agent.auth.start":case"agent.auth.logout":case"agent.session-options.get":case"agent.external-sessions.list":case"agent.external-sessions.import":case"agent.external-sessions.close":case"agent.external-sessions.delete":await ze(s,e);break;case"models.refresh":await C(s,e);break;case"agent.config.get":await E(s,e);break;case"agent.config.upsert":await j(s,e);break;case"agent.config.clear":await F(s,e);break;case"agent.config.test":await Q(s,e);break;case"agent.workspace.validate":await J(s,e);break;case"agent.capabilities.list":await D(s,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(r){if(t.propagateErrors)throw r;this.client.sendRes({type:"res",id:e.id,ok:!1,error:r instanceof Error?r.message:String(r)})}finally{this.activeRequests--}return n}evictIdleSessions(){if(this.sessions.size<He)return;let e=null;for(const[t,s]of this.sessions)(!e||s.lastActiveAt<e.session.lastActiveAt)&&(e={key:t,session:s});e&&(this.revokeManagedRoomToken(e.session),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 me(e)}resolveAuthorizedPath(e,t){return ue(e,le(t))}async resolveAuthorizedPathAsync(e,t){return de(e,await he(t))}async cleanup(){this.chatQueue.stop(),this.projectFsHandleStore.revokeAll(),this.acpDiscoveryWatcher.stop(),this.nativeFusion?.setExternalTerminalHandler?.(null),this.nativeCleanupOutbox.stop(),this.historySubscriptions.closeAll(),this.activityProbeTimer&&(clearInterval(this.activityProbeTimer),this.activityProbeTimer=null),this.attachmentCleanupTimer&&(clearInterval(this.attachmentCleanupTimer),this.attachmentCleanupTimer=null);for(const[,e]of this.sessions)this.revokeManagedRoomToken(e),e.heartbeatTimer&&(clearInterval(e.heartbeatTimer),e.heartbeatTimer=null),e.adapter.removeAllListeners(),await e.adapter.stop().catch(()=>{});this.sessions.clear(),this.runTextAcc.clear(),L(this.getRuntime()),await this.managerRuntime.stop(),u(null)}revokeManagedRoomToken(e){const t=e.managedRoomContextToken;e.managedRoomContextToken=null,t&&this.managedRoomContextRevoker?.(t)}}export{Us as SessionManager,Vs as resolveSessionWorkDir,Ue as upgradeRecoveryVisibleMessage};
1
+ import b from"node:crypto";import{getRegisteredAgents as S,unregisterAgent as k}from"../agents/adapter.js";import{resetCommandSpecCache as w}from"../agents/command-spec.js";import{loadConfig as I}from"../config/index.js";import{handleUpgradeStart as A,handleUpgradeStatus as T}from"../commands/upgrade.js";import{handleAgentsRefresh as P,handleModelsRefresh as C,refreshMachineAgents as M}from"./handlers/agents.js";import{AcpDiscoveryWatcher as x}from"../agents/acp/watcher.js";import{handleAgentCapabilitiesList as D}from"./handlers/agent-capabilities.js";import{handleAgentConfigClear as F,handleAgentConfigGet as E,handleAgentConfigTest as Q,handleAgentConfigUpsert as j}from"./handlers/agent-config.js";import{handleChatAbort as z,handleChatSend as O}from"./handlers/chat.js";import{recoverJournaledRun as B}from"./handlers/chat-recovery.js";import{handleSessionRefresh as W}from"./handlers/session-refresh.js";import{handleSessionToolDetail as _}from"./handlers/tool-detail.js";import{handleSessionTitleSet as H}from"./handlers/title.js";import{handleSessionMessageStatus as U}from"./handlers/message-status.js";import{handleAgentWorkspaceValidation as J}from"./handlers/agent-workspace-validation.js";import{handleVoiceSessionBodyWindow as $}from"./handlers/voice-window.js";import{handleRemoteAccessPause as V}from"./handlers/remote-access.js";import{cleanupPendingTransfers as L,handleFsLs as N,handleFsRead as G,handleFsRename as K,handleFsWrite as X,handleFsTransferAbort as Z,handleFsTransferChunk as Y,handleFsTransferFinish as q,handleFsTransferStart as ee,handleFsExportMarkdownPdf as se,handleFsExportMarkdownPdfSetup as te,handleFsArchiveZip as ae}from"./handlers/fs.js";import{handleRegionProbe as re,handleRegionSwitch as ne,handleUpgradeSetPolicy as ie}from"./handlers/control.js";import{ManagerRuntimeService as oe,setManagerRuntimeService as h}from"../manager/runtime.js";import{ChatQueueManager as ce}from"./queue.js";import{createAuthorizedFsRoot as le,createAuthorizedFsRootAsync as ue,resolveAuthorizedPath as he,resolveAuthorizedPathAsync as de,resolveSessionWorkDir as me}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/pi-coding-agent.js";import"../agents/manager.js";import{registerCustomAgent as pe}from"../agents/custom.js";import{handleManagedRoomBind as ge,handleManagedRoomRestart as fe,discardPreBindingSession as ve}from"./handlers/room-managed.js";import{getDaemonInstallationId as d,listSessionRecords as u,purgeCanonicalSession as ye,purgeSessionRecord as Re,recordSession as be,upsertMessage as Se}from"./store.js";import{requestSessionIndexPublish as m}from"./index-publisher.js";import{checkRunStalls as ke}from"./run-stall.js";import{reportUpgradeAggregateMetric as we}from"../log-reporter.js";import{PersonalHistorySubscriptions as Ie}from"./history-subscriptions.js";import{sweepAttachmentTransfers as Ae}from"./attachment-transfer-store.js";import{NativeSourceDeletionStore as Te}from"../native-fusion/native-source-deletions.js";import{collectLocalNativeSources as Pe}from"../native-fusion/session-native-sources.js";import{purgeToolDetails as Ce}from"./tool-detail-store.js";import{NativeSessionCleanupOutbox as Me}from"./native-cleanup-outbox.js";import{assertPersonalSyncIdentity as o}from"../personal-sync/epoch.js";import{ActiveRunJournal as xe}from"./run-recovery/journal.js";import{RunRecoveryBarrier as De}from"./run-recovery/barrier.js";import{RunRecoveryCoordinator as Fe}from"./run-recovery/coordinator.js";import{ProjectFsHandleStore as Ee}from"./project-fs-store.js";import{handleProjectFsRequest as Qe}from"./handlers/project-fs.js";import{handleAgentPermissionResponse as je,handleAcpAgentRequest as ze}from"./handlers/agent-control.js";import{SessionDeletionSynchronizer as Oe}from"./deletion-synchronizer.js";import{dispatchManagedChat as Be,dispatchQueuedChat as We,interruptQueuedChat as _e}from"./queued-chat-dispatch.js";const He=50;import{resolveSessionWorkDir as Vs}from"../fs/boundary.js";function Ue(){return"\u795E\u5FF5\u5347\u7EA7\u4E2D\u65AD\u4E86\u672C\u6B21\u8FD0\u884C\u3002\u5DF2\u5B8C\u6210\u7684\u56DE\u590D\u6216\u64CD\u4F5C\u4ECD\u7136\u6709\u6548\uFF0C\u672A\u5B8C\u6210\u90E8\u5206\u53EF\u91CD\u8BD5\u3002\u539F\u4F1A\u8BDD\u5DF2\u4FDD\u7559\u3002"}class Us{client;nativeFusion;cliVersion;upgradePolicyController;managedRoomBinder;remoteAccessPauseController;managedRoomContextRevoker;managedRoomExecutor;trustedProjectFsRequestResolver;getAgentSnapshot;scheduleHandler;getScheduleQueue(){return this.chatQueue}sessions=new Map;processedReqIds=new Set;runTextAcc=new Map;pendingTransfers=new Map;managerRuntime;chatQueue;historySubscriptions;nativeCleanupOutbox;activityProbeTimer=null;attachmentCleanupTimer=null;activeRequests=0;acpDiscoveryWatcher;runJournal;recoveryBarrier=new De;recoveryCoordinator;recoveryPass=null;prepareManagedRecovery;projectFsHandleStore=new Ee;deletionSynchronizer;constructor(e,t=null,s,n=null,r=null,l=null,p=null,g=null,f=null,v=null,y=null){this.client=e,this.nativeFusion=t,this.cliVersion=s,this.upgradePolicyController=n,this.managedRoomBinder=r,this.remoteAccessPauseController=l,this.managedRoomContextRevoker=p,this.managedRoomExecutor=g,this.trustedProjectFsRequestResolver=v,this.getAgentSnapshot=y,this.runJournal=f??new xe(d());for(const a of this.runJournal.loadPendingReconciliation().records)this.recoveryBarrier.begin(a.sessionId);this.recoveryCoordinator=new Fe({journal:this.runJournal,barrier:this.recoveryBarrier,recover:(a,i)=>B(this.getRuntime(),a,i),commitTerminal:(a,i)=>this.commitRecoveryTerminal(a,i),isCanonicalTerminal:a=>{const i=u().find(R=>R.sessionId===a.sessionId),c=`terminal:${b.createHash("sha256").update(`${a.runId}\0`).digest("hex")}`;return i?.lastAttentionId===c},onOutcome:a=>we({kind:"recovery",adapterType:a.adapterType,result:a.result,stage:a.result==="continued"?"continue":a.result==="reattached"?"reattach":a.result==="resumed"?"resume":a.result==="terminal_reconciled"?"inspect":"terminal",durationMs:a.durationMs,retries:Math.max(0,a.attempts-1),...a.reason?{errorCode:a.reason}:{}})}),this.managerRuntime=new oe({getRuntime:()=>this.getRuntime(),getAgentSnapshot:this.getAgentSnapshot??void 0,dispatchReq:a=>this.handleReq(a,{propagateErrors:!0})}),this.chatQueue=new ce({getRuntime:()=>this.getRuntime(),dispatchReq:a=>this.handleReq(a),dispatchManagedReq:(a,i)=>Be(this.getRuntime(),a,i),dispatchQueuedReq:(a,i)=>We(this.getRuntime(),a,i),interruptQueuedSession:a=>_e(this.getRuntime(),a)}),this.deletionSynchronizer=new Oe(e,a=>this.applySessionDeletion(a)),this.historySubscriptions=new Ie(this.client),this.nativeCleanupOutbox=new Me({logger:console.info}),this.acpDiscoveryWatcher=new x(async()=>{w(),await M(this.getRuntime())}),this.nativeFusion?.setExternalTerminalHandler?.(a=>{this.handleExternalTerminal(a)}),this.nativeFusion?.setExternalClaimHandler?.((a,i)=>{this.chatQueue.noteExternalClaim(a,i)}),this.nativeCleanupOutbox.start(),h(this.managerRuntime),this.managerRuntime.start(),this.reloadCustomAgents();try{this.acpDiscoveryWatcher.start()}catch(a){console.warn(`[acp.discovery] watcher unavailable: ${a instanceof Error?a.message:String(a)}`)}this.activityProbeTimer=setInterval(()=>{ke(this.sessions.entries(),()=>m(this.client)),this.publishManagedActivitySnapshots().catch(a=>{console.error("[session.activity] managed probe failed",a)})},15e3),this.activityProbeTimer.unref?.(),this.attachmentCleanupTimer=setInterval(()=>{const a=new Set([...u().map(i=>i.workDir),...Array.from(this.pendingTransfers.values()).map(i=>i.rootPath)]);for(const i of a)try{Ae(this.resolvePath(i))}catch(c){console.error("[attachment.cleanup] failed",c instanceof Error?c.message:String(c))}},6e4),this.attachmentCleanupTimer.unref?.()}executeManagedManagerAction(e){return this.managerRuntime.executeScopedWorkerAction(e.managerSessionId,e.action,e.params,e.roomOrigin)}noteManagedRoomSendOutcome(e){for(const t of this.sessions.values()){if(t.managedRoomContextToken!==e.token)continue;const s=t.roomSendOutcome??(t.roomSendOutcome={successes:0,failureCodes:[]});e.ok?s.successes+=1:s.failureCodes.length<20&&s.failureCodes.push(e.errorCode??"managed_room_action_failed");return}}getManagedRoomActiveRunId(e,t){const s=this.sessions.get(t);if(s?.currentRunId)return s.currentRunId;for(const n of this.sessions.values())if(n.managedRoomContextToken===e)return n.currentRunId??null;return null}getRuntime(){return{client:this.client,pendingTransfers:this.pendingTransfers,processedReqIds:this.processedReqIds,reloadCustomAgents:()=>this.reloadCustomAgents(),getAgentSnapshot:this.getAgentSnapshot??void 0,resolvePath:e=>this.resolvePath(e),resolveAuthorizedPath:(e,t)=>this.resolveAuthorizedPath(e,t),resolveAuthorizedPathAsync:(e,t)=>this.resolveAuthorizedPathAsync(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,revokeManagedRoomContextToken:this.managedRoomContextRevoker,managedRoomExecutor:this.managedRoomExecutor,runJournal:this.runJournal,recoveryBarrier:this.recoveryBarrier,prepareManagedRecovery:this.prepareManagedRecovery}}async resumePendingAcpAuthentication(e){const t=[...this.sessions.values()].find(s=>s.agentType===e&&s.adapter.hasPendingAuthenticationRetry?.());return t?.adapter.resumeAfterExternalAuthentication?(await t.adapter.resumeAfterExternalAuthentication(),!0):!1}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}}prepareForUpgrade(e){this.recoveryBarrier.freezeDispatch();const t=this.runJournal.markPlannedUpgrade(e);return this.runJournal.sync(),{activeRunCount:t}}cancelUpgradePreparation(){this.recoveryBarrier.unfreezeDispatch()}async recoverInterruptedRuns(){this.recoveryPass??=this.recoveryCoordinator.recoverAll(),await this.recoveryPass}getPendingRecoveryCount(){return this.runJournal.loadPendingReconciliation().records.length}revokeProjectFsHandles(){this.projectFsHandleStore.revokeAll()}async commitRecoveryTerminal(e,t){const s=this.sessions.get(e.sessionId);s&&(s.currentRunId=null,s.currentRunPhase=null,s.journalRunId=null,s.heartbeatTimer&&(clearInterval(s.heartbeatTimer),s.heartbeatTimer=null)),this.runTextAcc.delete(`${e.sessionId}:${e.providerRunId??e.runId}`),this.publishSessionActivity(e.sessionId,null);const n=Ue();Se(e.sessionId,{id:`upgrade-recovery-terminal-${e.runId}`,sessionId:e.sessionId,role:"agent",ts:Date.now(),payload:JSON.stringify({v:1,type:"error",content:n,error:!0,recoveryState:t.result,recoveryReason:t.reason})}),be({sessionId:e.sessionId,agentType:e.agentType,sessionMode:e.sessionMode,workDir:e.workDir,agentSessionId:e.agentSessionId,modelId:e.modelId,status:"failed",attentionId:`upgrade-recovery:${e.runId}`,lastActivityAt:new Date().toISOString()}),this.managerRuntime.noteAgentEvent(e.sessionId,{state:"error",runId:e.providerRunId??e.runId,seq:e.lastObservedEventSeq+1,message:n}),m(this.client);const r=e.lastObservedEventSeq+1;this.client.sendAgentEvent({type:"event",event:"agent",payload:t.result==="interrupted_by_upgrade"?{state:"interrupted_by_upgrade",sessionId:e.sessionId,runId:e.providerRunId??e.runId,seq:r,reason:t.reason}:{state:"recovery_failed",sessionId:e.sessionId,runId:e.providerRunId??e.runId,seq:r,reason:t.reason,...t.message?{message:t.message}:{}},seq:r,id:`agent-recovery-terminal-${e.runId}`}),this.chatQueue.noteTerminal(e.sessionId)}setManagedRoomTurnPreparer(e){this.chatQueue.setManagedRoomTurnPreparer(e)}setManagedAgentDirectTurnPreparer(e){this.chatQueue.setManagedAgentDirectTurnPreparer(e)}setManagedRecoveryPreparer(e){this.prepareManagedRecovery=e}async enqueueManagedRoomBatch(e){const t=e.map(s=>{const n=u().find(r=>r.sessionId===s.params.sessionId);return{context:s.context,params:{...s.params,modelId:n?.modelId??s.params.modelId,sessionMode:n?.sessionMode??s.params.sessionMode,managerConfig:n?.managerConfig??s.params.managerConfig,managerDefaultWorkerAgentType:n?.managerDefaultWorkerAgentType??s.params.managerDefaultWorkerAgentType,managerDefaultWorkerModelId:n?.managerDefaultWorkerModelId??s.params.managerDefaultWorkerModelId}}});await this.chatQueue.enqueueManagedRoomBatch(t)}async retireManagedRoomSession(e){this.chatQueue.purgeSession(e),await ve(this.getRuntime(),e)}discardPendingManagedRoomMessages(e){return this.chatQueue.discardPendingManagedRoomMessages(e)}async synchronizeSessionDeletions(){await this.deletionSynchronizer.synchronize()}async applySessionDeletion(e){const t=new Te({daemonInstallationId:d()});let s=[];try{s=Pe(e.sessionId,{records:u()})}catch(r){console.warn("[session.deletions] local native source lookup failed",{error:r instanceof Error?r.message:String(r)})}t.recordSession(e);for(const r of[...e.sources,...s]){const l=t.find(r.agentType,r.sourceSessionKey);l&&l.sessionId!==e.sessionId||t.record({...e,...r})}this.runJournal.markSessionAborted(e.sessionId),this.recoveryBarrier.end(e.sessionId);const n=this.sessions.get(e.sessionId);if(n){this.revokeManagedRoomToken(n);try{await n.adapter.stop()}catch{}this.sessions.delete(e.sessionId)}this.historySubscriptions.closeSession(e.sessionId),this.nativeFusion?.handleSessionDeleted(e.sessionId),this.chatQueue.purgeSession(e.sessionId),Ce(e.sessionId),ye(e.sessionId),Re(e.sessionId),this.runTextAcc.delete(e.sessionId),this.publishSessionActivity(e.sessionId,null),this.nativeCleanupOutbox.enqueue(e),this.nativeCleanupOutbox.kick()}publishSessionActivity(e,t){this.client.sendEvent({type:"event",event:"session.activity",payload:{sessionId:e,activity:t}})}async handleExternalTerminal(e){const t=this.sessions.get(e);t&&(t.journalRunId&&(this.recoveryCoordinator.completeFromProvider(e,t.journalRunId),t.journalRunId=null),this.sessions.delete(e),this.revokeManagedRoomToken(t),t.heartbeatTimer&&clearInterval(t.heartbeatTimer),t.adapter.removeAllListeners(),await t.adapter.stop().catch(()=>{})),this.chatQueue.noteTerminal(e)}async publishManagedActivitySnapshots(){for(const[e,t]of this.sessions.entries()){if(t.heartbeatTimer||!t.currentRunId||!t.adapter.getStatus)continue;const s=await t.adapter.getStatus().catch(()=>null);if(!s?.active||!s.runPhase)continue;const n=new Date().toISOString();this.publishSessionActivity(e,{sessionId:e,runId:s.runId||t.currentRunId,runPhase:s.runPhase,startedAt:new Date(t.lastActiveAt).toISOString(),updatedAt:n,canStop:s.canStop??!0});const r=t.heartbeatSeq++;this.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"heartbeat",sessionId:e,runId:s.runId||t.currentRunId,seq:r,runPhase:s.runPhase,canStop:s.canStop??!0},seq:r,id:`agent-status-${s.runId||t.currentRunId}-${Date.now()}`})}}reloadCustomAgents(){for(const t of S())t.startsWith("custom:")&&k(t);const e=I();for(const[t,s]of Object.entries(e.customAgents??{}))pe(t,s)}async handleReq(e,t={}){const s=this.getRuntime();let n;this.activeRequests++;try{switch(e.method){case"schedule.deliver":if(!this.scheduleHandler)throw new Error("schedules_unavailable");await this.scheduleHandler(e);break;case"chat.send":if(e.params.scheduledDelivery)throw new Error("schedule_source_untrusted");o(e.params),this.recoveryBarrier.isDispatchFrozen()||this.recoveryBarrier.isRecovering(String(e.params.sessionId??""))?n={durableQueueHandoff:await this.chatQueue.handleEnqueue({...e,method:"chat.enqueue"})}:await O(s,e);break;case"chat.enqueue":o(e.params),n={durableQueueHandoff:await this.chatQueue.handleEnqueue(e)};break;case"chat.queue.get":o(e.params),await this.chatQueue.handleGet(e);break;case"chat.queue.edit":o(e.params),await this.chatQueue.handleEdit(e);break;case"chat.queue.delete":o(e.params),await this.chatQueue.handleDelete(e);break;case"chat.queue.promote":o(e.params),await this.chatQueue.handlePromote(e);break;case"chat.abort":o(e.params),await z(s,e);break;case"session.refresh":o(e.params),await W(s,e);break;case"session.history.open":this.historySubscriptions.handleOpen(e);break;case"session.history.sync":this.historySubscriptions.handleSync(e);break;case"session.history.page":this.historySubscriptions.handlePage(e);break;case"session.history.close":this.historySubscriptions.handleClose(e);break;case"session.body.replica.subscribe":this.historySubscriptions.handleReplicaSubscribe(e);break;case"session.body.replica.unsubscribe":this.historySubscriptions.handleReplicaUnsubscribe(e);break;case"session.history":this.client.sendRes({type:"res",id:e.id,ok:!1,error:"upgrade_required"});break;case"session.message.status":U(s,e);break;case"session.tool.detail":await _(s,e);break;case"voice.session.body.window":$(s,e);break;case"session.title.set":await H(s,e);break;case"room.agent.bind-managed":await ge(s,this.managedRoomBinder,e);break;case"room.agent.restart-managed":await fe(s,this.managedRoomBinder,e);break;case"fs.ls":await N(s,e);break;case"project.fs.open":case"project.fs.list":case"project.fs.read":case"project.fs.close":await Qe(this.client,this.projectFsHandleStore,e,this.trustedProjectFsRequestResolver);break;case"fs.read":await G(s,e);break;case"fs.write":await X(s,e);break;case"fs.export.markdown-pdf":await se(s,e);break;case"fs.export.markdown-pdf.setup":await te(s,e);break;case"fs.archive.zip":await ae(s,e);break;case"fs.rename":await K(s,e);break;case"fs.transfer.start":await ee(s,e);break;case"fs.transfer.chunk":await Y(s,e);break;case"fs.transfer.finish":await q(s,e);break;case"fs.transfer.abort":await Z(s,e);break;case"region.probe":await re(s,e);break;case"region.switch":await ne(s,e);break;case"upgrade.start":await A(this.client,e.id,e.params.version,{currentVersion:this.cliVersion,confirmedMajor:e.params.confirmedMajor===!0,prepareForUpgrade:r=>this.prepareForUpgrade(r),cancelUpgradePreparation:()=>this.cancelUpgradePreparation(),shutdownAfterHandoff:()=>{setTimeout(()=>process.kill(process.pid,"SIGTERM"),100).unref?.()}});break;case"upgrade.status":await T(this.client,e.id,{currentVersion:this.cliVersion});break;case"upgrade.set-policy":await ie(s,e);break;case"machine.remote-access.pause":await V(this.client,this.remoteAccessPauseController,e);break;case"agents.refresh":await P(s,e);break;case"agent.permission.respond":await je(s,e);break;case"agent.auth.start":case"agent.auth.logout":case"agent.session-options.get":case"agent.external-sessions.list":case"agent.external-sessions.import":case"agent.external-sessions.close":case"agent.external-sessions.delete":await ze(s,e);break;case"models.refresh":await C(s,e);break;case"agent.config.get":await E(s,e);break;case"agent.config.upsert":await j(s,e);break;case"agent.config.clear":await F(s,e);break;case"agent.config.test":await Q(s,e);break;case"agent.workspace.validate":await J(s,e);break;case"agent.capabilities.list":await D(s,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(r){if(t.propagateErrors)throw r;this.client.sendRes({type:"res",id:e.id,ok:!1,error:r instanceof Error?r.message:String(r)})}finally{this.activeRequests--}return n}evictIdleSessions(){if(this.sessions.size<He)return;let e=null;for(const[t,s]of this.sessions)(!e||s.lastActiveAt<e.session.lastActiveAt)&&(e={key:t,session:s});e&&(this.revokeManagedRoomToken(e.session),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 me(e)}resolveAuthorizedPath(e,t){return he(e,le(t))}async resolveAuthorizedPathAsync(e,t){return de(e,await ue(t))}async cleanup(){this.chatQueue.stop(),this.projectFsHandleStore.revokeAll(),this.acpDiscoveryWatcher.stop(),this.nativeFusion?.setExternalTerminalHandler?.(null),this.nativeCleanupOutbox.stop(),this.historySubscriptions.closeAll(),this.activityProbeTimer&&(clearInterval(this.activityProbeTimer),this.activityProbeTimer=null),this.attachmentCleanupTimer&&(clearInterval(this.attachmentCleanupTimer),this.attachmentCleanupTimer=null);for(const[,e]of this.sessions)this.revokeManagedRoomToken(e),e.heartbeatTimer&&(clearInterval(e.heartbeatTimer),e.heartbeatTimer=null),e.adapter.removeAllListeners(),await e.adapter.stop().catch(()=>{});this.sessions.clear(),this.runTextAcc.clear(),L(this.getRuntime()),await this.managerRuntime.stop(),h(null)}revokeManagedRoomToken(e){const t=e.managedRoomContextToken;e.managedRoomContextToken=null,t&&this.managedRoomContextRevoker?.(t)}}export{Us as SessionManager,Vs as resolveSessionWorkDir,Ue as upgradeRecoveryVisibleMessage};
@@ -1 +1 @@
1
- import{NativeSourceDeletionStore as N}from"../native-fusion/native-source-deletions.js";import{QueueRetryScheduler as z}from"./queue-retry.js";import{findDuplicateQueuedMessage as x,stripLocalQueueFields as $,takeCompatibleBatch as T,formatQueuedBatch as J,dedupeQueuedAttachments as K,classifyQueueError as G,normalizeQueuedModelId as _,resolveManagedRoomNativeSessionId as D,managedDirectTurnOptions as q}from"./queue-helpers.js";import{CODEX_DESKTOP_SEND_UNAVAILABLE as U}from"@shennian/wire";import{isCodexThreadTailInterrupted as H}from"../native-fusion/codex-files.js";import{mergeProjectedSessions as V}from"./projection.js";import{assertFinishedAttachmentReferences as X,markAttachmentReferences as Y}from"./attachment-transfer-store.js";import{appendMessage as A,getMessageDeliveryStatus as R,listSessionRecords as E,recordSession as B,tombstoneMessage as Z,upsertMessage as ee}from"./store.js";import{handleQueueDispatchFailure as te,queueBlockedUntil as Q,resolveQueueRecoveryNotice as P}from"./queue-dispatch-failure.js";import{resetCommandSpecCache as ne}from"../agents/command-spec.js";import{requestSessionIndexPublish as w}from"./index-publisher.js";import{clearPersistedManagerRoomOrigins as se,purgeQueuedSessionData as ie,readQueue as m,writeQueue as M}from"./queue-storage.js";import{parsePersonalAttachmentReferences as re}from"./attachment-reference.js";import{getPersonalSyncIdentity as b}from"../personal-sync/epoch.js";import{getDaemonInstallationId as W}from"../personal-sync/identity.js";import{isTrustedManagerEvent as ae}from"./manager-event-authority.js";import{getQueueSnapshot as oe,handleQueueDelete as de,handleQueueEdit as ue,handleQueueGet as ge,handleQueuePromote as le}from"./queue-control.js";import{TerminalQueuedChatDispatchError as L,nowIso as F,queueEnvelope as C,queueMessageFromParams as O}from"./queue-message.js";import{purgeQueuedSessionData as Qe}from"./queue-storage.js";import{TerminalQueuedChatDispatchError as be}from"./queue-message.js";class Ae{opts;validateScheduledTarget;async enqueueScheduled(e){return this.handleEnqueue(e,!0)}draining=new Set;promoting=new Set;disposed=!1;retries=new z(e=>{this.wakeSession(e)});deletions=new N;inFlightMessageIds=new Map;deferredLogState=new Map;prepareManagedRoomTurn=null;prepareManagedAgentDirectTurn=null;constructor(e){this.opts=e,se(),setTimeout(()=>this.drainIdleQueues(),0).unref?.()}stop(){this.disposed=!0,this.retries.stop()}getSnapshot(e){return oe({getRuntime:this.opts.getRuntime,inFlightMessageIds:this.inFlightMessageIds,broadcast:t=>this.broadcast(t)},e)}isImmediateSendAvailable(e){const t=this.opts.getRuntime(),n=t.sessions.get(e);return n?.currentRunId?n.journalRunId?t.runJournal?.get(e,n.journalRunId)?.deliveryMode==="direct":!1:!0}setManagedRoomTurnPreparer(e){this.prepareManagedRoomTurn=e}setManagedAgentDirectTurnPreparer(e){this.prepareManagedAgentDirectTurn=e}async enqueueManagedRoomBatch(e){if(e.length===0)return;const t=this.opts.getRuntime(),n=m(),i=new Set,o=new Map;let d=!1;for(const a of e){const s=a.params;if(this.deletions.hasSession(s.sessionId)){delete n.sessions[s.sessionId],d=!0;continue}if(!s.sessionId||!s.text||!s.agentType||!s.workDir)throw new Error("sessionId, text, agentType and workDir are required");const u=O({...b(W()),...s});typeof s.roomMessageCreatedAt=="string"&&Number.isFinite(Date.parse(s.roomMessageCreatedAt))&&(u.createdAt=new Date(s.roomMessageCreatedAt).toISOString()),u.origin="room",u.managedRoom=a.context,u.trigger={kind:"room_activation",...a.context};const g=n.sessions[s.sessionId]??[],l=x(g,u),f=u.clientMessageId??u.id,S=R(s.sessionId,f);if(!l&&S.state==="not_found")g.push(u),n.sessions[s.sessionId]=g,o.set(`${u.sessionId}\0${f}`,u),i.add(s.sessionId),d=!0;else if(l&&S.state==="not_found")o.set(`${l.sessionId}\0${f}`,l),i.add(s.sessionId);else if(l&&S.state==="queued")i.add(s.sessionId);else if(l){const y=g.filter(k=>k.id!==l.id);y.length?n.sessions[s.sessionId]=y:delete n.sessions[s.sessionId],d=!0}}d&&M(n);let r;for(const a of i)try{for(const s of o.values())s.sessionId===a&&(A(a,C(s),"queued"),B({sessionId:a,agentType:s.agentType,sessionMode:s.sessionMode,managerConfig:s.managerConfig,workDir:s.workDir,agentSessionId:D(t,s),modelId:s.modelId}));this.logLifecycle("enqueue.persisted",a,{origin:"room",pendingCount:m().sessions[a]?.length??0}),this.broadcast(a),this.wakeSession(a)}catch(s){r=s,this.logLifecycle("enqueue.commit-failed",a,{failureClass:G(s instanceof Error?s.message:"","canonical_commit_failed")},"error"),this.retries.schedule(a,!0)}if(i.size&&w(t.client),r)throw r}async handleEnqueue(e,t=!1){const n=this.opts.getRuntime(),i=e.params;if(i.scheduledTask&&!t)throw new Error("schedule_source_untrusted");if((i.managerEventId||i.managerEventRoomOrigin||i.managedWorkerParentSessionId||i.managerWorkerRoomOrigin||e.params.managerWorkerNativeFull||e.params.managedRecoverySource)&&!ae(e))throw new Error("manager_event_source_untrusted");const o=!!(t&&i.scheduledTask?.bindingId);if(V(i.sessionListProjection),!i.sessionId||!i.text||!i.agentType||!i.workDir)return n.client.sendRes({type:"res",id:e.id,ok:!1,error:"sessionId, text, agentType and workDir are required"}),!1;const d=q(i.managerEventId?{roomOrigin:i.managerEventRoomOrigin}:null,!!i.managedAgentDirect),r=i.managedAgentDirect||o?await this.prepareManagedAgentDirectTurn?.(i.sessionId,d):null;if((i.managedAgentDirect||o)&&!r)throw new Error("managed_agent_context_unavailable");const a=r?E().find(j=>j.sessionId===i.sessionId):null,s=r?{...i,...r,agentType:r.agentType,sessionMode:r.sessionMode,managerConfig:r.managerConfig,workDir:r.workDir,agentSessionId:r.agentSessionId?.startsWith("managed:")?a?.agentSessionId&&!a.agentSessionId.startsWith("managed:")?a.agentSessionId:null:r.agentSessionId,modelId:a?.modelId??void 0,systemPrompt:r.systemPrompt,externalChannel:i.managedAgentDirect?null:i.externalChannel,replyTarget:i.managedAgentDirect?null:i.replyTarget,managerDefaultWorkerAgentType:r.managerDefaultWorkerAgentType,managerDefaultWorkerModelId:r.managerDefaultWorkerModelId}:i,u=n.resolvePath(s.workDir),g=re(s.attachments);g?.length&&X(u,g);const l={text:s.text,attachments:g,localized:!1},f=n.sessions.get(s.sessionId);if(s.agentType==="codex"&&s.agentSessionId&&f?.currentRunId?.startsWith("dispatch:")&&H(s.agentSessionId))return n.client.sendRes({type:"res",id:e.id,ok:!1,error:U}),!1;r?.managedRoomContextToken&&n.revokeManagedRoomContextToken?.(r.managedRoomContextToken);const S=await this.isSessionBusy(s.sessionId),y=m(),k=y.sessions[s.sessionId]??[],h=O({...s,text:l.text,attachments:l.attachments,systemPrompt:r?null:s.systemPrompt});r&&(i.managedAgentDirect&&(h.managedAgentDirect=!0),h.trigger?.kind!=="manager_event"&&h.trigger?.kind!=="scheduled"&&(h.trigger={kind:"managed_direct"}));const v=h.clientMessageId??h.id,c=R(s.sessionId,v);if(c.state!=="not_found")return n.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queued:c.state==="queued",queueMessageId:h.id,...c,queue:this.getSnapshot(s.sessionId)}}),!0;const I=x(k,h);I||(y.sessions[s.sessionId]=[...k,h],M(y));const p=I??h;return B({sessionId:p.sessionId,agentType:p.agentType,sessionMode:p.sessionMode,managerConfig:p.managerConfig,workDir:p.workDir,agentSessionId:p.agentSessionId,modelId:p.modelId}),A(p.sessionId,C(p),"queued"),Y(n.resolvePath(p.workDir),p.attachments??[]),w(n.client),this.logLifecycle("enqueue.persisted",s.sessionId,{origin:s.origin??"app",queueMessageId:p.id,pendingCount:(m().sessions[s.sessionId]??[]).length}),this.broadcast(s.sessionId),n.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queued:!0,queueMessageId:I?.id??h.id,...R(s.sessionId,I?.clientMessageId??I?.id??h.clientMessageId??h.id),queue:this.getSnapshot(s.sessionId),...l.localized?{localizedAttachments:!0}:{}}}),S?this.retries.schedule(s.sessionId):this.wakeSession(s.sessionId),!0}async handleGet(e){await ge(this.queueControlContext(),e)}async handleEdit(e){await ue(this.queueControlContext(),e)}async handleDelete(e){await de(this.queueControlContext(),e)}queueControlContext(){return{getRuntime:this.opts.getRuntime,inFlightMessageIds:this.inFlightMessageIds,broadcast:e=>this.broadcast(e)}}async handlePromote(e){await le({...this.queueControlContext(),promoting:this.promoting,draining:this.draining,isImmediateSendAvailable:t=>this.isImmediateSendAvailable(t),canInjectActiveBatch:(t,n)=>this.canInjectActiveBatch(t,n),interruptQueuedSession:this.opts.interruptQueuedSession,dispatchQueuedMessages:t=>this.dispatchQueuedMessages(t),markExternalQueued:(t,n)=>this.markExternalQueued(t,n),removeBatch:(t,n)=>this.removeBatch(t,n),wakeSession:t=>this.wakeSession(t)},e)}isDispatching(e){return this.inFlightMessageIds.has(e)}noteTerminal(e){const t=m().sessions[e]?.find(n=>!!n.externalQueuedSubmissionId);t&&this.noteExternalClaim(e,t.clientMessageId??t.id),this.wakeSession(e)}purgeSession(e){ie(e),this.retries.cancel(e)}discardPendingManagedRoomMessages(e){if(this.deletions.hasSession(e)){const r=m().sessions[e]?.length??0;return this.purgeSession(e),r}const t=m(),n=t.sessions[e]??[],i=this.inFlightMessageIds.get(e)??new Set,o=n.filter(r=>r.managedRoom&&!i.has(r.id));if(o.length===0)return 0;const d=n.filter(r=>!o.includes(r));d.length?t.sessions[e]=d:delete t.sessions[e],M(t);for(const r of o)Z(e,r.clientMessageId??r.id);return w(this.opts.getRuntime().client),this.logLifecycle("managed-room.discarded-paused",e,{discardedCount:o.length,pendingCount:d.length}),this.broadcast(e),o.length}wakeSession(e){this.drainNext(e).catch(()=>{this.logLifecycle("drain.retry-required",e,{},"error"),this.retries.schedule(e,!0)})}drainIdleQueues(){if(this.disposed)return;const e=m();for(const t of Object.keys(e.sessions))this.wakeSession(t)}async drainNext(e){if(this.disposed||this.draining.has(e)||this.promoting.has(e))return;this.draining.add(e);let t=!1,n=!1,i=[];try{if(this.deletions.hasSession(e)){this.purgeSession(e);return}if(await this.isSessionBusy(e)){const g=m().sessions[e]?.length??0,l=this.deferredLogState.get(e),f=Date.now();(!l||l.pendingCount!==g||f-l.at>=3e4)&&(this.logLifecycle("drain.deferred",e,{pendingCount:g}),this.deferredLogState.set(e,{at:f,pendingCount:g}));return}this.deferredLogState.delete(e);const o=m(),d=o.sessions[e]??[],r=d.filter(g=>{const l=g.clientMessageId??g.id,f=R(e,l).state;return f==="queued"||f==="not_found"});if(r.length!==d.length&&(r.length?o.sessions[e]=r:delete o.sessions[e],M(o),this.logLifecycle("drain.pruned-terminal",e,{prunedCount:d.length-r.length,pendingCount:r.length})),r.some(g=>!!g.externalQueuedSubmissionId)){this.broadcast(e);return}const a=T(r);if(a.length===0){this.broadcast(e);return}if(Q(a))return;a.some(g=>(g.dispatchBlock?.retryAt??0)>0)&&ne(),i=a,this.inFlightMessageIds.set(e,new Set(a.map(g=>g.id))),this.logLifecycle("dispatch.start",e,{batchCount:a.length,queueMessageId:a[0].id,origin:a[0].origin??"app"}),this.broadcast(e);for(const g of a)ee(e,C(g),"queued");const s=await this.dispatchQueuedMessages(a);if(s.deliveryMode==="external_owner_queue"){this.markExternalQueued(a,s.queuedSubmissionId),P(a),a.some(g=>g.dispatchBlock)&&w(this.opts.getRuntime().client),this.logLifecycle("dispatch.external-queued",e,{batchCount:a.length,queueMessageId:a[0].id}),this.broadcast(e);return}const u=this.removeBatch(e,a);P(a),a.some(g=>g.dispatchBlock)&&w(this.opts.getRuntime().client),this.logLifecycle("dispatch.accepted",e,{batchCount:a.length,queueMessageId:a[0].id,pendingCount:u}),this.deferredLogState.delete(e),t=u>0,this.broadcast(e)}catch(o){const d=te({error:o,sessionId:e,batch:i,publish:()=>w(this.opts.getRuntime().client),isManagedWorker:!!this.opts.getRuntime().managerRuntime?.isManagedWorkerSession(e),removeBatch:()=>this.removeBatch(e,i),log:(r,a)=>this.logLifecycle(r,e,a,"error")});t=d.drainAgain,n=d.transientFailure,this.broadcast(e)}finally{this.inFlightMessageIds.delete(e),this.draining.delete(e);const o=m().sessions[e]??[];o.length?(this.broadcast(e),o.some(d=>!!d.externalQueuedSubmissionId)?this.retries.cancel(e):t?queueMicrotask(()=>this.wakeSession(e)):this.retries.schedule(e,n,Q(T(o)))):this.retries.cancel(e)}}noteExternalClaim(e,t){const n=m(),i=n.sessions[e]??[],o=i.filter(d=>(d.clientMessageId??d.id)!==t);o.length!==i.length&&(o.length?n.sessions[e]=o:delete n.sessions[e],M(n),this.broadcast(e))}canInjectActiveBatch(e,t){if(!e.adapter.supportsActiveInput||!e.adapter.injectActiveInput||!e.journalRunId)return!1;const n=this.opts.getRuntime().runJournal?.get(t[0].sessionId,e.journalRunId),i=t[0].trigger?.kind==="managed_direct"||t[0].managedAgentDirect?null:"personal";return!!(i&&t[0].systemPrompt==null&&n&&n.source===i&&n.deliveryMode==="direct"&&n.agentType===t[0].agentType&&n.workDir===e.workDir&&n.agentSessionId===e.agentSessionId&&n.modelId===(t[0].modelId??null)&&n.reasoningEffort===(t[0].reasoningEffort??null))}removeBatch(e,t){if(t.length===0)return m().sessions[e]?.length??0;const n=m(),i=new Set(t.map(d=>d.id)),o=(n.sessions[e]??[]).filter(d=>!i.has(d.id));return o.length?n.sessions[e]=o:delete n.sessions[e],M(n),o.length}logLifecycle(e,t,n,i="info"){const o=`[chat.queue] ${JSON.stringify({at:F(),event:e,sessionId:t,...n})}`;i==="error"?console.error(o):console.info(o)}async dispatchQueuedMessages(e){const t=e[0],n=t.trigger?.kind==="scheduled"?t.trigger:null;if(n&&await this.validateScheduledTarget?.({sessionId:t.sessionId,...n})!=="ready")throw new L("schedule_target_unavailable");const i=e.flatMap(c=>{if(c.trigger?.kind==="room_activation"){const{kind:I,...p}=c.trigger;return[p]}return!c.trigger&&c.managedRoom?[c.managedRoom]:[]}),o=e.find(c=>c.trigger?.kind==="manager_event")?.trigger,d=e.some(c=>c.trigger?.kind==="managed_direct"||!!c.managedAgentDirect),r=d||!!n?.bindingId,a=e.find(c=>c.trigger?.kind==="manager_worker")?.trigger,s=o?.kind==="manager_event"||d,u=i.length>0?await this.prepareManagedRoomTurn?.(i):r||o?.kind==="manager_event"?await this.prepareManagedAgentDirectTurn?.(t.sessionId,q(o?.kind==="manager_event"?o:null,d)):void 0;if(i.length>0&&!u)throw new Error("managed_room_turn_preparer_unavailable");if(r&&!u)throw new Error("managed_agent_context_unavailable");if(o?.kind==="manager_event"&&this.opts.getRuntime().managerRuntime?.isManagedRoomBoundManager(t.sessionId)&&!u)throw new Error("managed_agent_context_unavailable");const g=new Set((m().sessions[t.sessionId]??[]).map(c=>c.id));if(this.disposed||this.deletions.hasSession(t.sessionId)||e.some(c=>!g.has(c.id)))throw u?.managedRoomContextToken&&this.opts.getRuntime().revokeManagedRoomContextToken?.(u.managedRoomContextToken),this.disposed?new Error("queue_stopped"):new L("queued_dispatch_cancelled");const l=u??null,f=l?.sessionMode==="manager"?l.managerConfig:null,S=e.length===1?t.text:J(e),y=K(e.flatMap(c=>c.attachments??[])),k=r||o?.kind==="manager_event"&&!!u,h=k?u.agentSessionId?.startsWith("managed:")?D(this.opts.getRuntime(),t):u.agentSessionId:i.length>0?D(this.opts.getRuntime(),t):t.agentSessionId??null,v=u?E().find(c=>c.sessionId===t.sessionId):null;return await this.opts.dispatchQueuedReq({type:"req",id:`queue-send-${t.id}-${Date.now()}`,method:"chat.send",params:{...b(W()),sessionId:t.sessionId,text:S,agentType:k?u.agentType:t.agentType,sessionMode:l?.sessionMode??t.sessionMode,managerConfig:l?f:t.managerConfig,workDir:k?u.workDir:t.workDir,agentSessionId:h,modelId:_(v?.modelId)??_(t.modelId),systemPrompt:u?.systemPrompt??t.systemPrompt??null,managerDefaultWorkerAgentType:l?l.managerDefaultWorkerAgentType:t.managerDefaultWorkerAgentType,managerDefaultWorkerModelId:l?l.managerDefaultWorkerModelId:t.managerDefaultWorkerModelId,reasoningEffort:t.reasoningEffort??void 0,clientMessageId:t.clientMessageId??t.id,attachments:y,externalChannel:s?void 0:t.externalChannel,replyTarget:s?void 0:t.replyTarget,roomContextRegistryKey:s?void 0:u?.roomContextRegistryKey,activationCauseMessageId:s?void 0:i.at(-1)?.causeMessageId,rootCauseMessageId:s?void 0:i.at(-1)?.rootCauseMessageId,activationSequence:s?void 0:i.at(-1)?.sequence,activationHopCount:s?void 0:i.at(-1)?.hopCount,managedRecoverySource:o?.kind==="manager_event"?"manager_event":r?"managed_direct":i.length>0?"managed_room":void 0,managerEventId:o?.kind==="manager_event"?o.eventId:void 0,managedWorkerParentSessionId:a?.kind==="manager_worker"?a.parentSessionId:void 0,managerWorkerRoomOrigin:a?.kind==="manager_worker"?a.roomOrigin:void 0,managerWorkerNativeFull:a?.kind==="manager_worker"&&this.opts.getRuntime().managerRuntime?.isExternalWorkerController(a.parentSessionId,t.workDir)||void 0,managedRoomContextToken:u?.managedRoomContextToken,scheduledDelivery:!!n,suppressExternalOwnerEcho:i.length>0||!!n||void 0,queuedBatchItems:e.map(c=>{const I=$(c);return s?{...I,systemPrompt:u?.systemPrompt??null,externalChannel:null,replyTarget:null}:I}),waitForDispatch:!0}},u??void 0)??{}}markExternalQueued(e,t){const n=m(),i=new Set(e.map(r=>r.id)),o=n.sessions[e[0].sessionId]??[];let d=!1;for(const r of o)i.has(r.id)&&(r.externalQueuedSubmissionId=t||r.id,r.updatedAt=F(),d=!0);d&&M(n)}async isSessionBusy(e){const t=this.opts.getRuntime().recoveryBarrier;if(t?.isDispatchFrozen()||t?.isRecovering(e))return!0;const n=this.opts.getRuntime().sessions.get(e);if(!n)return!1;if(n.currentRunId){if(!(n.currentRunId.startsWith("dispatch:")&&!!this.opts.getRuntime().runJournal&&!n.journalRunId)||(n.adapter.getStatus?await n.adapter.getStatus().catch(()=>null):null)?.active)return!0;this.logLifecycle("drain.recovered-stale-dispatch",e,{staleRunId:n.currentRunId}),n.currentRunId=null,n.currentRunPhase=null}if(!n.adapter.getStatus)return!1;const i=await n.adapter.getStatus().catch(()=>null);return i?.active?(i.runId&&(n.currentRunId=i.runId,n.currentRunPhase=i.runPhase??n.currentRunPhase),!0):!1}broadcast(e){this.opts.getRuntime().client.sendEvent({type:"event",event:"session.queue.update",payload:{queue:this.getSnapshot(e)}})}}export{Ae as ChatQueueManager,be as TerminalQueuedChatDispatchError,Qe as purgeQueuedSessionData};
1
+ import{NativeSourceDeletionStore as $}from"../native-fusion/native-source-deletions.js";import{QueueRetryScheduler as J}from"./queue-retry.js";import{findDuplicateQueuedMessage as q,stripLocalQueueFields as K,takeCompatibleBatch as A,formatQueuedBatch as G,dedupeQueuedAttachments as U,classifyQueueError as H,normalizeQueuedModelId as w,resolveManagedRoomNativeSessionId as x,managedDirectTurnOptions as E}from"./queue-helpers.js";import{CODEX_DESKTOP_SEND_UNAVAILABLE as V}from"@shennian/wire";import{isCodexThreadTailInterrupted as X}from"../native-fusion/codex-files.js";import{mergeProjectedSessions as Y}from"./projection.js";import{assertFinishedAttachmentReferences as Z,markAttachmentReferences as ee}from"./attachment-transfer-store.js";import{appendMessage as B,getMessageDeliveryStatus as C,listSessionRecords as Q,recordSession as P,tombstoneMessage as te,upsertMessage as ne}from"./store.js";import{handleQueueDispatchFailure as se,queueBlockedUntil as b,resolveQueueRecoveryNotice as W}from"./queue-dispatch-failure.js";import{resetCommandSpecCache as ie}from"../agents/command-spec.js";import{requestSessionIndexPublish as R}from"./index-publisher.js";import{clearPersistedManagerRoomOrigins as re,purgeQueuedSessionData as ae,readQueue as m,writeQueue as y}from"./queue-storage.js";import{parsePersonalAttachmentReferences as oe}from"./attachment-reference.js";import{getPersonalSyncIdentity as L}from"../personal-sync/epoch.js";import{getDaemonInstallationId as F}from"../personal-sync/identity.js";import{isTrustedManagerEvent as de}from"./manager-event-authority.js";import{getQueueSnapshot as ue,handleQueueDelete as le,handleQueueEdit as ge,handleQueueGet as ce,handleQueuePromote as me}from"./queue-control.js";import{TerminalQueuedChatDispatchError as O,nowIso as j,queueEnvelope as T,queueMessageFromParams as N}from"./queue-message.js";import{purgeQueuedSessionData as be}from"./queue-storage.js";import{TerminalQueuedChatDispatchError as Le}from"./queue-message.js";class Be{opts;validateScheduledTarget;async enqueueScheduled(e){return this.handleEnqueue(e,!0)}draining=new Set;promoting=new Set;disposed=!1;retries=new J(e=>{this.wakeSession(e)});deletions=new $;inFlightMessageIds=new Map;deferredLogState=new Map;prepareManagedRoomTurn=null;prepareManagedAgentDirectTurn=null;constructor(e){this.opts=e,re(),setTimeout(()=>this.drainIdleQueues(),0).unref?.()}stop(){this.disposed=!0,this.retries.stop()}getSnapshot(e){return ue({getRuntime:this.opts.getRuntime,inFlightMessageIds:this.inFlightMessageIds,broadcast:t=>this.broadcast(t)},e)}isImmediateSendAvailable(e){const t=this.opts.getRuntime(),n=t.sessions.get(e);return n?.currentRunId?n.journalRunId?t.runJournal?.get(e,n.journalRunId)?.deliveryMode==="direct":!1:!0}setManagedRoomTurnPreparer(e){this.prepareManagedRoomTurn=e}setManagedAgentDirectTurnPreparer(e){this.prepareManagedAgentDirectTurn=e}async enqueueManagedRoomBatch(e){if(e.length===0)return;const t=this.opts.getRuntime(),n=m(),r=new Set,o=new Map;let i=!1;for(const d of e){const s=d.params;if(this.deletions.hasSession(s.sessionId)){delete n.sessions[s.sessionId],i=!0;continue}if(!s.sessionId||!s.text||!s.agentType||!s.workDir)throw new Error("sessionId, text, agentType and workDir are required");const u=N({...L(F()),...s});typeof s.roomMessageCreatedAt=="string"&&Number.isFinite(Date.parse(s.roomMessageCreatedAt))&&(u.createdAt=new Date(s.roomMessageCreatedAt).toISOString()),u.origin="room",u.managedRoom=d.context,u.trigger={kind:"room_activation",...d.context};const a=n.sessions[s.sessionId]??[],c=q(a,u),h=u.clientMessageId??u.id,I=C(s.sessionId,h);if(!c&&I.state==="not_found")a.push(u),n.sessions[s.sessionId]=a,o.set(`${u.sessionId}\0${h}`,u),r.add(s.sessionId),i=!0;else if(c&&I.state==="not_found")o.set(`${c.sessionId}\0${h}`,c),r.add(s.sessionId);else if(c&&I.state==="queued")r.add(s.sessionId);else if(c){const M=a.filter(k=>k.id!==c.id);M.length?n.sessions[s.sessionId]=M:delete n.sessions[s.sessionId],i=!0}}i&&y(n);let l;for(const d of r)try{for(const s of o.values())s.sessionId===d&&(B(d,T(s),"queued"),P({sessionId:d,agentType:s.agentType,sessionMode:s.sessionMode,managerConfig:s.managerConfig,workDir:s.workDir,agentSessionId:x(t,s),modelId:s.modelId}));this.logLifecycle("enqueue.persisted",d,{origin:"room",pendingCount:m().sessions[d]?.length??0}),this.broadcast(d),this.wakeSession(d)}catch(s){l=s,this.logLifecycle("enqueue.commit-failed",d,{failureClass:H(s instanceof Error?s.message:"","canonical_commit_failed")},"error"),this.retries.schedule(d,!0)}if(r.size&&R(t.client),l)throw l}async handleEnqueue(e,t=!1){const n=this.opts.getRuntime(),r=e.params;if(r.scheduledTask&&!t)throw new Error("schedule_source_untrusted");if((r.managerEventId||r.managerEventRoomOrigin||r.managedWorkerParentSessionId||r.managerWorkerRoomOrigin||e.params.managerWorkerNativeFull||e.params.managedRecoverySource)&&!de(e))throw new Error("manager_event_source_untrusted");const o=!t&&!r.managedWorkerParentSessionId?n.managerRuntime?.getWorkerControllerSessionId?.(String(r.sessionId??""),String(r.workDir??"")):null,i=o?{...r,managedWorkerParentSessionId:o}:r,l=!!(t&&i.scheduledTask?.bindingId);if(Y(i.sessionListProjection),!i.sessionId||!i.text||!i.agentType||!i.workDir)return n.client.sendRes({type:"res",id:e.id,ok:!1,error:"sessionId, text, agentType and workDir are required"}),!1;const d=E(i.managerEventId?{roomOrigin:i.managerEventRoomOrigin}:null,!!i.managedAgentDirect),s=i.managedAgentDirect||l?await this.prepareManagedAgentDirectTurn?.(i.sessionId,d):null;if((i.managedAgentDirect||l)&&!s)throw new Error("managed_agent_context_unavailable");const u=s?Q().find(z=>z.sessionId===i.sessionId):null,a=s?{...i,...s,agentType:s.agentType,sessionMode:s.sessionMode,managerConfig:s.managerConfig,workDir:s.workDir,agentSessionId:s.agentSessionId?.startsWith("managed:")?u?.agentSessionId&&!u.agentSessionId.startsWith("managed:")?u.agentSessionId:null:s.agentSessionId,modelId:s.effectiveModelId!==void 0?w(s.effectiveModelId):u?.modelId??void 0,systemPrompt:s.systemPrompt,externalChannel:i.managedAgentDirect?null:i.externalChannel,replyTarget:i.managedAgentDirect?null:i.replyTarget,managerDefaultWorkerAgentType:s.managerDefaultWorkerAgentType,managerDefaultWorkerModelId:s.managerDefaultWorkerModelId}:i,c=n.resolvePath(a.workDir),h=oe(a.attachments);h?.length&&Z(c,h);const I={text:a.text,attachments:h,localized:!1},M=n.sessions.get(a.sessionId);if(a.agentType==="codex"&&a.agentSessionId&&M?.currentRunId?.startsWith("dispatch:")&&X(a.agentSessionId))return n.client.sendRes({type:"res",id:e.id,ok:!1,error:V}),!1;s?.managedRoomContextToken&&n.revokeManagedRoomContextToken?.(s.managedRoomContextToken);const k=await this.isSessionBusy(a.sessionId),v=m(),D=v.sessions[a.sessionId]??[],p=N({...a,text:I.text,attachments:I.attachments,systemPrompt:s?null:a.systemPrompt});s&&(i.managedAgentDirect&&(p.managedAgentDirect=!0),p.trigger?.kind!=="manager_event"&&p.trigger?.kind!=="scheduled"&&(p.trigger={kind:"managed_direct"}));const _=p.clientMessageId??p.id,g=C(a.sessionId,_);if(g.state!=="not_found")return n.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queued:g.state==="queued",queueMessageId:p.id,...g,queue:this.getSnapshot(a.sessionId)}}),!0;const S=q(D,p);S||(v.sessions[a.sessionId]=[...D,p],y(v));const f=S??p;return P({sessionId:f.sessionId,agentType:f.agentType,sessionMode:f.sessionMode,managerConfig:f.managerConfig,workDir:f.workDir,agentSessionId:f.agentSessionId,modelId:f.modelId}),B(f.sessionId,T(f),"queued"),ee(n.resolvePath(f.workDir),f.attachments??[]),R(n.client),this.logLifecycle("enqueue.persisted",a.sessionId,{origin:a.origin??"app",queueMessageId:f.id,pendingCount:(m().sessions[a.sessionId]??[]).length}),this.broadcast(a.sessionId),n.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queued:!0,queueMessageId:S?.id??p.id,...C(a.sessionId,S?.clientMessageId??S?.id??p.clientMessageId??p.id),queue:this.getSnapshot(a.sessionId),...I.localized?{localizedAttachments:!0}:{}}}),k?this.retries.schedule(a.sessionId):this.wakeSession(a.sessionId),!0}async handleGet(e){await ce(this.queueControlContext(),e)}async handleEdit(e){await ge(this.queueControlContext(),e)}async handleDelete(e){await le(this.queueControlContext(),e)}queueControlContext(){return{getRuntime:this.opts.getRuntime,inFlightMessageIds:this.inFlightMessageIds,broadcast:e=>this.broadcast(e)}}async handlePromote(e){await me({...this.queueControlContext(),promoting:this.promoting,draining:this.draining,isImmediateSendAvailable:t=>this.isImmediateSendAvailable(t),canInjectActiveBatch:(t,n)=>this.canInjectActiveBatch(t,n),interruptQueuedSession:this.opts.interruptQueuedSession,dispatchQueuedMessages:t=>this.dispatchQueuedMessages(t),markExternalQueued:(t,n)=>this.markExternalQueued(t,n),removeBatch:(t,n)=>this.removeBatch(t,n),wakeSession:t=>this.wakeSession(t)},e)}isDispatching(e){return this.inFlightMessageIds.has(e)}noteTerminal(e){const t=m().sessions[e]?.find(n=>!!n.externalQueuedSubmissionId);t&&this.noteExternalClaim(e,t.clientMessageId??t.id),this.wakeSession(e)}purgeSession(e){ae(e),this.retries.cancel(e)}discardPendingManagedRoomMessages(e){if(this.deletions.hasSession(e)){const l=m().sessions[e]?.length??0;return this.purgeSession(e),l}const t=m(),n=t.sessions[e]??[],r=this.inFlightMessageIds.get(e)??new Set,o=n.filter(l=>l.managedRoom&&!r.has(l.id));if(o.length===0)return 0;const i=n.filter(l=>!o.includes(l));i.length?t.sessions[e]=i:delete t.sessions[e],y(t);for(const l of o)te(e,l.clientMessageId??l.id);return R(this.opts.getRuntime().client),this.logLifecycle("managed-room.discarded-paused",e,{discardedCount:o.length,pendingCount:i.length}),this.broadcast(e),o.length}wakeSession(e){this.drainNext(e).catch(()=>{this.logLifecycle("drain.retry-required",e,{},"error"),this.retries.schedule(e,!0)})}drainIdleQueues(){if(this.disposed)return;const e=m();for(const t of Object.keys(e.sessions))this.wakeSession(t)}async drainNext(e){if(this.disposed||this.draining.has(e)||this.promoting.has(e))return;this.draining.add(e);let t=!1,n=!1,r=[];try{if(this.deletions.hasSession(e)){this.purgeSession(e);return}if(await this.isSessionBusy(e)){const a=m().sessions[e]?.length??0,c=this.deferredLogState.get(e),h=Date.now();(!c||c.pendingCount!==a||h-c.at>=3e4)&&(this.logLifecycle("drain.deferred",e,{pendingCount:a}),this.deferredLogState.set(e,{at:h,pendingCount:a}));return}this.deferredLogState.delete(e);const o=m(),i=o.sessions[e]??[],l=i.filter(a=>{const c=a.clientMessageId??a.id,h=C(e,c).state;return h==="queued"||h==="not_found"});if(l.length!==i.length&&(l.length?o.sessions[e]=l:delete o.sessions[e],y(o),this.logLifecycle("drain.pruned-terminal",e,{prunedCount:i.length-l.length,pendingCount:l.length})),l.some(a=>!!a.externalQueuedSubmissionId)){this.broadcast(e);return}const d=A(l);if(d.length===0){this.broadcast(e);return}if(b(d))return;d.some(a=>(a.dispatchBlock?.retryAt??0)>0)&&ie(),r=d,this.inFlightMessageIds.set(e,new Set(d.map(a=>a.id))),this.logLifecycle("dispatch.start",e,{batchCount:d.length,queueMessageId:d[0].id,origin:d[0].origin??"app"}),this.broadcast(e);for(const a of d)ne(e,T(a),"queued");const s=await this.dispatchQueuedMessages(d);if(s.deliveryMode==="external_owner_queue"){this.markExternalQueued(d,s.queuedSubmissionId),W(d),d.some(a=>a.dispatchBlock)&&R(this.opts.getRuntime().client),this.logLifecycle("dispatch.external-queued",e,{batchCount:d.length,queueMessageId:d[0].id}),this.broadcast(e);return}const u=this.removeBatch(e,d);W(d),d.some(a=>a.dispatchBlock)&&R(this.opts.getRuntime().client),this.logLifecycle("dispatch.accepted",e,{batchCount:d.length,queueMessageId:d[0].id,pendingCount:u}),this.deferredLogState.delete(e),t=u>0,this.broadcast(e)}catch(o){const i=se({error:o,sessionId:e,batch:r,publish:()=>R(this.opts.getRuntime().client),isManagedWorker:!!this.opts.getRuntime().managerRuntime?.isManagedWorkerSession(e),removeBatch:()=>this.removeBatch(e,r),log:(l,d)=>this.logLifecycle(l,e,d,"error")});t=i.drainAgain,n=i.transientFailure,this.broadcast(e)}finally{this.inFlightMessageIds.delete(e),this.draining.delete(e);const o=m().sessions[e]??[];o.length?(this.broadcast(e),o.some(i=>!!i.externalQueuedSubmissionId)?this.retries.cancel(e):t?queueMicrotask(()=>this.wakeSession(e)):this.retries.schedule(e,n,b(A(o)))):this.retries.cancel(e)}}noteExternalClaim(e,t){const n=m(),r=n.sessions[e]??[],o=r.filter(i=>(i.clientMessageId??i.id)!==t);o.length!==r.length&&(o.length?n.sessions[e]=o:delete n.sessions[e],y(n),this.broadcast(e))}canInjectActiveBatch(e,t){if(!e.adapter.supportsActiveInput||!e.adapter.injectActiveInput||!e.journalRunId)return!1;const n=this.opts.getRuntime().runJournal?.get(t[0].sessionId,e.journalRunId),r=t[0].trigger?.kind==="managed_direct"||t[0].managedAgentDirect?null:"personal";return!!(r&&t[0].systemPrompt==null&&n&&n.source===r&&n.deliveryMode==="direct"&&n.agentType===t[0].agentType&&n.workDir===e.workDir&&n.agentSessionId===e.agentSessionId&&n.modelId===(t[0].modelId??null)&&n.reasoningEffort===(t[0].reasoningEffort??null))}removeBatch(e,t){if(t.length===0)return m().sessions[e]?.length??0;const n=m(),r=new Set(t.map(i=>i.id)),o=(n.sessions[e]??[]).filter(i=>!r.has(i.id));return o.length?n.sessions[e]=o:delete n.sessions[e],y(n),o.length}logLifecycle(e,t,n,r="info"){const o=`[chat.queue] ${JSON.stringify({at:j(),event:e,sessionId:t,...n})}`;r==="error"?console.error(o):console.info(o)}async dispatchQueuedMessages(e){const t=e[0],n=t.trigger?.kind==="scheduled"?t.trigger:null;if(n&&await this.validateScheduledTarget?.({sessionId:t.sessionId,...n})!=="ready")throw new O("schedule_target_unavailable");const r=e.flatMap(g=>{if(g.trigger?.kind==="room_activation"){const{kind:S,...f}=g.trigger;return[f]}return!g.trigger&&g.managedRoom?[g.managedRoom]:[]}),o=e.find(g=>g.trigger?.kind==="manager_event")?.trigger,i=e.some(g=>g.trigger?.kind==="managed_direct"||!!g.managedAgentDirect),l=i||!!n?.bindingId,d=e.find(g=>g.trigger?.kind==="manager_worker")?.trigger,s=o?.kind==="manager_event"||i,u=r.length>0?await this.prepareManagedRoomTurn?.(r):l||o?.kind==="manager_event"?await this.prepareManagedAgentDirectTurn?.(t.sessionId,E(o?.kind==="manager_event"?o:null,i)):void 0;if(r.length>0&&!u)throw new Error("managed_room_turn_preparer_unavailable");if(l&&!u)throw new Error("managed_agent_context_unavailable");if(o?.kind==="manager_event"&&this.opts.getRuntime().managerRuntime?.isManagedRoomBoundManager(t.sessionId)&&!u)throw new Error("managed_agent_context_unavailable");const a=new Set((m().sessions[t.sessionId]??[]).map(g=>g.id));if(this.disposed||this.deletions.hasSession(t.sessionId)||e.some(g=>!a.has(g.id)))throw u?.managedRoomContextToken&&this.opts.getRuntime().revokeManagedRoomContextToken?.(u.managedRoomContextToken),this.disposed?new Error("queue_stopped"):new O("queued_dispatch_cancelled");const c=u??null,h=c?.sessionMode==="manager"?c.managerConfig:null,I=e.length===1?t.text:G(e),M=U(e.flatMap(g=>g.attachments??[])),k=l||o?.kind==="manager_event"&&!!u,v=k?u.agentSessionId?.startsWith("managed:")?x(this.opts.getRuntime(),t):u.agentSessionId:r.length>0?x(this.opts.getRuntime(),t):t.agentSessionId??null,D=u?Q().find(g=>g.sessionId===t.sessionId):null,p=u?.effectiveModelId!==void 0?w(u.effectiveModelId):w(D?.modelId)??w(t.modelId),_=u?.effectiveModelId!==void 0?"room_effective_model":w(D?.modelId)?"persisted_session_model":w(t.modelId)?"queued_message_model":"pi_default_model";return await this.opts.dispatchQueuedReq({type:"req",id:`queue-send-${t.id}-${Date.now()}`,method:"chat.send",params:{...L(F()),sessionId:t.sessionId,text:I,agentType:k?u.agentType:t.agentType,sessionMode:c?.sessionMode??t.sessionMode,managerConfig:c?h:t.managerConfig,workDir:k?u.workDir:t.workDir,agentSessionId:v,modelId:p,modelSelectionSource:_,systemPrompt:u?.systemPrompt??t.systemPrompt??null,managerDefaultWorkerAgentType:c?c.managerDefaultWorkerAgentType:t.managerDefaultWorkerAgentType,managerDefaultWorkerModelId:c?c.managerDefaultWorkerModelId:t.managerDefaultWorkerModelId,reasoningEffort:t.reasoningEffort??void 0,clientMessageId:t.clientMessageId??t.id,attachments:M,externalChannel:s?void 0:t.externalChannel,replyTarget:s?void 0:t.replyTarget,roomContextRegistryKey:s?void 0:u?.roomContextRegistryKey,activationCauseMessageId:s?void 0:r.at(-1)?.causeMessageId,rootCauseMessageId:s?void 0:r.at(-1)?.rootCauseMessageId,activationSequence:s?void 0:r.at(-1)?.sequence,activationHopCount:s?void 0:r.at(-1)?.hopCount,managedRecoverySource:o?.kind==="manager_event"?"manager_event":l?"managed_direct":r.length>0?"managed_room":void 0,managerEventId:o?.kind==="manager_event"?o.eventId:void 0,managedWorkerParentSessionId:d?.kind==="manager_worker"?d.parentSessionId:void 0,managerWorkerRoomOrigin:d?.kind==="manager_worker"?d.roomOrigin:void 0,managerWorkerNativeFull:d?.kind==="manager_worker"&&this.opts.getRuntime().managerRuntime?.isExternalWorkerController(d.parentSessionId,t.workDir)||void 0,managedRoomContextToken:u?.managedRoomContextToken,scheduledDelivery:!!n,suppressExternalOwnerEcho:r.length>0||!!n||void 0,queuedBatchItems:e.map(g=>{const S=K(g);return s?{...S,systemPrompt:u?.systemPrompt??null,externalChannel:null,replyTarget:null}:S}),waitForDispatch:!0}},u??void 0)??{}}markExternalQueued(e,t){const n=m(),r=new Set(e.map(l=>l.id)),o=n.sessions[e[0].sessionId]??[];let i=!1;for(const l of o)r.has(l.id)&&(l.externalQueuedSubmissionId=t||l.id,l.updatedAt=j(),i=!0);i&&y(n)}async isSessionBusy(e){const t=this.opts.getRuntime().recoveryBarrier;if(t?.isDispatchFrozen()||t?.isRecovering(e))return!0;const n=this.opts.getRuntime().sessions.get(e);if(!n)return!1;if(n.currentRunId){if(!(n.currentRunId.startsWith("dispatch:")&&!!this.opts.getRuntime().runJournal&&!n.journalRunId)||(n.adapter.getStatus?await n.adapter.getStatus().catch(()=>null):null)?.active)return!0;this.logLifecycle("drain.recovered-stale-dispatch",e,{staleRunId:n.currentRunId}),n.currentRunId=null,n.currentRunPhase=null}if(!n.adapter.getStatus)return!1;const r=await n.adapter.getStatus().catch(()=>null);return r?.active?(r.runId&&(n.currentRunId=r.runId,n.currentRunPhase=r.runPhase??n.currentRunPhase),!0):!1}broadcast(e){this.opts.getRuntime().client.sendEvent({type:"event",event:"session.queue.update",payload:{queue:this.getSnapshot(e)}})}}export{Be as ChatQueueManager,Le as TerminalQueuedChatDispatchError,be as purgeQueuedSessionData};
@@ -1 +1 @@
1
- const c="codex_desktop_send_unavailable",p=["gemini","openclaw"],r=["claude","codex","workbuddy","cursor","opencode","pi","pi-coding-agent"],a=new Set(r);function s(e){return a.has(e)}function i(e){return e.startsWith("custom:")||/^acp:[a-z0-9][a-z0-9._-]{0,63}$/.test(e)||s(e)}function l(e){const n=[],o=new Set;for(const t of e)!i(t)||o.has(t)||(o.add(t),n.push(t));return n}function A(e){if(!e?.length)return[];const n=[],o=new Set;for(const t of e)!i(t.type)||o.has(t.type)||(o.add(t.type),n.push(t));return n}function u(e){return e.nativeSessionVisibility==="internal"||e.id.startsWith("sess_worker_")||e.agentType==="manager"||e.sessionMode==="manager"||!!e.agentIdentityId}export{r as AVAILABLE_BUILTIN_AGENT_TYPES,c as CODEX_DESKTOP_SEND_UNAVAILABLE,p as DISABLED_BUILTIN_AGENT_TYPES,A as filterAvailableAgentInfos,l as filterAvailableAgentTypes,i as isAvailableAgentType,s as isAvailableBuiltinAgentType,u as isInternalSession};
1
+ const p="codex_desktop_send_unavailable",a=["gemini","openclaw"],i=["claude","codex","workbuddy","cursor","opencode","pi","pi-coding-agent"],s=new Set(i);function c(e){return typeof e.supportsAgent=="boolean"?e.supportsAgent:e.supportsManagedAgent===!0||e.supportsManagedNativeFull===!0}function A(e,n){return Array.isArray(e.supportedAgentExecutionModes)?e.supportedAgentExecutionModes.includes(n):n==="native-full"?e.supportsManagedNativeFull===!0:e.supportsManagedAgent===!0}function u(e){return s.has(e)}function r(e){return e.startsWith("custom:")||/^acp:[a-z0-9][a-z0-9._-]{0,63}$/.test(e)||u(e)}function l(e){const n=[],o=new Set;for(const t of e)!r(t)||o.has(t)||(o.add(t),n.push(t));return n}function d(e){if(!e?.length)return[];const n=[],o=new Set;for(const t of e)!r(t.type)||o.has(t.type)||(o.add(t.type),n.push(t));return n}function f(e){return e.nativeSessionVisibility==="internal"||e.id.startsWith("sess_worker_")||e.agentType==="manager"||e.sessionMode==="manager"||!!e.agentIdentityId}export{i as AVAILABLE_BUILTIN_AGENT_TYPES,p as CODEX_DESKTOP_SEND_UNAVAILABLE,a as DISABLED_BUILTIN_AGENT_TYPES,c as agentInfoSupportsAgent,A as agentInfoSupportsExecutionMode,d as filterAvailableAgentInfos,l as filterAvailableAgentTypes,r as isAvailableAgentType,u as isAvailableBuiltinAgentType,f as isInternalSession};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shennian",
3
- "version": "0.5.2",
3
+ "version": "0.5.3",
4
4
  "description": "Shennian — AI Agent Control Plane CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1 +0,0 @@
1
- import{spawn as i}from"node:child_process";function s(e,r=!1){if(!(!e.pid||e.exitCode!==null||e.signalCode!==null)){if(process.platform==="win32"){i("taskkill",["/PID",String(e.pid),"/T",...r?["/F"]:[]],{stdio:"ignore",windowsHide:!0}).unref();return}try{process.kill(-e.pid,r?"SIGKILL":"SIGTERM")}catch{e.kill(r?"SIGKILL":"SIGTERM")}}}export{s as terminateProcessTree};