shennian 0.4.69 → 0.4.72

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.
Files changed (106) hide show
  1. package/dist/publish-build-manifest.json +150 -90
  2. package/dist/src/agent-env.js +4 -4
  3. package/dist/src/agents/adapter.d.ts +7 -3
  4. package/dist/src/agents/auth-status.d.ts +4 -0
  5. package/dist/src/agents/auth-status.js +2 -0
  6. package/dist/src/agents/claude.js +4 -4
  7. package/dist/src/agents/codex-protocol.d.ts +103 -0
  8. package/dist/src/agents/codex-protocol.js +3 -0
  9. package/dist/src/agents/codex-runtime.d.ts +91 -0
  10. package/dist/src/agents/codex-runtime.js +14 -0
  11. package/dist/src/agents/codex.d.ts +15 -91
  12. package/dist/src/agents/codex.js +2 -17
  13. package/dist/src/agents/command-spec.js +4 -3
  14. package/dist/src/agents/detect.js +1 -1
  15. package/dist/src/agents/manager.d.ts +4 -3
  16. package/dist/src/agents/manager.js +4 -4
  17. package/dist/src/agents/model-registry/discovery.js +3 -3
  18. package/dist/src/agents/model-registry/parsers.js +4 -4
  19. package/dist/src/agents/model-registry/service.d.ts +6 -2
  20. package/dist/src/agents/model-registry/service.js +1 -1
  21. package/dist/src/agents/model-registry/types.d.ts +9 -1
  22. package/dist/src/agents/model-registry/types.js +1 -1
  23. package/dist/src/agents/opencode.d.ts +4 -0
  24. package/dist/src/agents/opencode.js +1 -1
  25. package/dist/src/commands/agent-readiness.d.ts +17 -0
  26. package/dist/src/commands/agent-readiness.js +2 -0
  27. package/dist/src/commands/agent.js +2 -2
  28. package/dist/src/commands/daemon-instance-lock.js +1 -1
  29. package/dist/src/commands/daemon-process.d.ts +1 -0
  30. package/dist/src/commands/daemon-process.js +1 -1
  31. package/dist/src/commands/daemon-service-spec.d.ts +28 -0
  32. package/dist/src/commands/daemon-service-spec.js +1 -0
  33. package/dist/src/commands/daemon-start-wait.d.ts +1 -1
  34. package/dist/src/commands/daemon-start-wait.js +1 -1
  35. package/dist/src/commands/daemon-state.d.ts +57 -0
  36. package/dist/src/commands/daemon-state.js +1 -0
  37. package/dist/src/commands/daemon-windows.d.ts +8 -0
  38. package/dist/src/commands/daemon-windows.js +10 -10
  39. package/dist/src/commands/daemon.d.ts +4 -64
  40. package/dist/src/commands/daemon.js +13 -13
  41. package/dist/src/commands/manager.js +1 -1
  42. package/dist/src/commands/upgrade.js +1 -1
  43. package/dist/src/commands/worker.d.ts +11 -0
  44. package/dist/src/commands/worker.js +2 -0
  45. package/dist/src/daemon-ipc/agent-readiness.d.ts +14 -0
  46. package/dist/src/daemon-ipc/agent-readiness.js +1 -0
  47. package/dist/src/daemon-ipc/control.d.ts +1 -1
  48. package/dist/src/daemon-ipc/control.js +1 -1
  49. package/dist/src/index.js +3 -3
  50. package/dist/src/manager/prompt.d.ts +1 -1
  51. package/dist/src/manager/prompt.js +6 -6
  52. package/dist/src/manager/registry.d.ts +48 -2
  53. package/dist/src/manager/registry.js +1 -1
  54. package/dist/src/manager/runtime.d.ts +2 -2
  55. package/dist/src/manager/runtime.js +6 -6
  56. package/dist/src/manager/worker-ipc.d.ts +7 -0
  57. package/dist/src/manager/worker-ipc.js +1 -1
  58. package/dist/src/native-fusion/local-repository.d.ts +6 -1
  59. package/dist/src/native-fusion/local-repository.js +2 -2
  60. package/dist/src/native-fusion/service.d.ts +2 -0
  61. package/dist/src/native-fusion/service.js +2 -2
  62. package/dist/src/native-fusion/source-visibility-audit.d.ts +16 -0
  63. package/dist/src/native-fusion/source-visibility-audit.js +1 -0
  64. package/dist/src/native-fusion/source-visibility.d.ts +25 -0
  65. package/dist/src/native-fusion/source-visibility.js +1 -0
  66. package/dist/src/native-fusion/state.d.ts +1 -0
  67. package/dist/src/native-fusion/state.js +2 -2
  68. package/dist/src/native-fusion/types.d.ts +5 -0
  69. package/dist/src/room/managed-room-binding.d.ts +2 -0
  70. package/dist/src/room/managed-room-binding.js +1 -1
  71. package/dist/src/room/room-binding-client.d.ts +1 -0
  72. package/dist/src/room/room-binding-client.js +1 -1
  73. package/dist/src/runtime-distribution.d.ts +13 -0
  74. package/dist/src/runtime-distribution.js +1 -0
  75. package/dist/src/security/managed-agent-policy.d.ts +7 -0
  76. package/dist/src/security/managed-agent-policy.js +1 -1
  77. package/dist/src/session/handlers/agent-workspace-validation.d.ts +1 -0
  78. package/dist/src/session/handlers/agent-workspace-validation.js +1 -1
  79. package/dist/src/session/handlers/agents.d.ts +7 -1
  80. package/dist/src/session/handlers/agents.js +1 -1
  81. package/dist/src/session/handlers/chat-context.d.ts +31 -0
  82. package/dist/src/session/handlers/chat-context.js +1 -0
  83. package/dist/src/session/handlers/chat-events.d.ts +1 -1
  84. package/dist/src/session/handlers/chat-events.js +2 -2
  85. package/dist/src/session/handlers/chat-session-lifecycle.d.ts +2 -2
  86. package/dist/src/session/handlers/chat-session-lifecycle.js +1 -1
  87. package/dist/src/session/handlers/chat.d.ts +3 -29
  88. package/dist/src/session/handlers/chat.js +1 -1
  89. package/dist/src/session/manager.js +2 -2
  90. package/dist/src/session/queue-helpers.js +2 -2
  91. package/dist/src/session/queue-message.d.ts +2 -0
  92. package/dist/src/session/queue.d.ts +7 -1
  93. package/dist/src/session/queue.js +1 -1
  94. package/dist/src/session/queued-chat-dispatch.d.ts +4 -1
  95. package/dist/src/session/queued-chat-dispatch.js +1 -1
  96. package/dist/src/session/store.d.ts +4 -2
  97. package/dist/src/session/store.js +2 -2
  98. package/dist/src/session/types.d.ts +1 -0
  99. package/dist/src/upgrade/engine.js +2 -2
  100. package/dist/src/upgrade/scheduler.js +1 -1
  101. package/dist/src/upgrade/updater-launcher.js +3 -3
  102. package/node_modules/@shennian/wire/dist/room.d.ts +2 -0
  103. package/node_modules/@shennian/wire/dist/session-sync.d.ts +2 -1
  104. package/node_modules/@shennian/wire/dist/session.d.ts +25 -1
  105. package/node_modules/@shennian/wire/dist/session.js +8 -0
  106. package/package.json +1 -1
@@ -1 +1 @@
1
- import{createAgent as v}from"../../agents/adapter.js";import{ManagerModeAdapter as R}from"../../agents/manager.js";import{bindAdapterEvents as A}from"./chat-events.js";import{configureAdapterForSession as w,externalChannelEnv as h,managedProviderEnv as q,revokeManagedRoomContextToken as b}from"./chat-adapter-config.js";function E(r,e){if(r.processedReqIds.add(e),r.processedReqIds.size>1e3){const n=r.processedReqIds.values().next().value;r.processedReqIds.delete(n)}}async function C(r,e){b(r,e),e.heartbeatTimer&&(clearInterval(e.heartbeatTimer),e.heartbeatTimer=null),e.adapter.removeAllListeners(),await e.adapter.stop().catch(()=>{})}function k(r,e,n,a,t,u,l){return l?r.send(e,n,a,t,u,l):u?.trim()?r.send(e,n,a,t,u):t?.length?r.send(e,n,a,t):a?r.send(e,n,a):r.send(e,n)}function M(r,e,n,a,t,u,l){return r.prepareSend?r.prepareSend(e,n,a,t,u,l):Promise.resolve()}async function P(r,e,n,a,t,u,l,c,s,d="user"){r.evictIdleSessions();const p=v(n);if(!p)throw new Error(`Unsupported agent: ${n}`);const o=a==="manager"&&n!=="manager"?new R(p,n):p;w(o,e,n,l,c,null,s,r.managedRoomExecutor),d==="internal"?await o.start(e,t,u,{nativeSessionVisibility:d}):await o.start(e,t,u);const f={adapter:o,workDir:t,agentType:n,sessionMode:a,nativeSessionVisibility:d,agentSessionId:u??null,lastActiveAt:Date.now(),currentRunId:null,currentRunPhase:null,nextEventSeq:0,heartbeatSeq:0,heartbeatTimer:null,pendingTextEvent:null,externalChannel:l??null,externalReplyTarget:c??null,externalChannelEnv:{...q(n),...h(e,l,c)},managedRoomContextToken:null,journalRunId:null};return r.sessions.set(e,f),A(r,e,n,o),f}export{P as createActiveSession,C as disposeSession,M as prepareAdapterTurn,E as rememberProcessedReqId,k as sendAdapterTurn};
1
+ import{createAgent as A}from"../../agents/adapter.js";import{ManagerModeAdapter as h}from"../../agents/manager.js";import{registerInternalNativeSource as q}from"../../native-fusion/source-visibility.js";import{recordSession as w}from"../store.js";import{configureAdapterForSession as x,externalChannelEnv as E,managedProviderEnv as S,revokeManagedRoomContextToken as b}from"./chat-adapter-config.js";import{bindAdapterEvents as C}from"./chat-events.js";function M(n,r){if(n.processedReqIds.add(r),n.processedReqIds.size>1e3){const e=n.processedReqIds.values().next().value;n.processedReqIds.delete(e)}}async function N(n,r){b(n,r),r.heartbeatTimer&&(clearInterval(r.heartbeatTimer),r.heartbeatTimer=null),r.adapter.removeAllListeners(),await r.adapter.stop().catch(()=>{})}function U(n,r,e,u,a,t,l){return l?n.send(r,e,u,a,t,l):t?.trim()?n.send(r,e,u,a,t):a?.length?n.send(r,e,u,a):u?n.send(r,e,u):n.send(r,e)}function $(n,r,e,u,a,t,l){return n.prepareSend?n.prepareSend(r,e,u,a,t,l):Promise.resolve()}async function B(n,r,e,u,a,t,l,d,R,o="user"){n.evictIdleSessions();const p=A(e);if(!p)throw new Error(`Unsupported agent: ${e}`);const c=u==="manager"&&e!=="manager"?new h(p,e):p;x(c,r,e,l,d,null,R,n.managedRoomExecutor),w({sessionId:r,agentType:e,sessionMode:u,workDir:a,agentSessionId:t,nativeSessionVisibility:o}),c.on("nativeSession",(v,m)=>{o==="internal"&&q(r,v,m),w({sessionId:r,agentType:e,workDir:a,agentSessionId:m,nativeSessionVisibility:o})}),o==="internal"&&(e==="codex"||e==="manager")?await c.start(r,a,t,{nativeSessionVisibility:o}):await c.start(r,a,t);const f={adapter:c,workDir:a,agentType:e,sessionMode:u,nativeSessionVisibility:o,agentSessionId:t??null,lastActiveAt:Date.now(),currentRunId:null,currentRunPhase:null,nextEventSeq:0,heartbeatSeq:0,heartbeatTimer:null,pendingTextEvent:null,externalChannel:l??null,externalReplyTarget:d??null,externalChannelEnv:{...S(e),...E(r,l,d)},managedRoomContextToken:null,journalRunId:null};return n.sessions.set(r,f),C(n,r,e,c),f}export{B as createActiveSession,N as disposeSession,$ as prepareAdapterTurn,M as rememberProcessedReqId,U as sendAdapterTurn};
@@ -1,32 +1,6 @@
1
- import type { AgentSendContext } from '../../agents/adapter.js';
2
- import { type ReqFrame, type AgentType, type SessionMode } from '@shennian/wire';
1
+ import { type ReqFrame } from '@shennian/wire';
3
2
  import type { SessionManagerRuntime } from '../types.js';
4
- import type { CompiledManagedAgentPolicy } from '../../security/managed-agent-policy.js';
5
- import { type ManagedRoomPromptSnapshot } from '../../room/managed-prompt-composer.js';
6
- export type ChatSendExecutionContext = (AgentSendContext & {
7
- source: 'room_activation';
8
- /** Local-only snapshot produced by RoomActivationService; never accepted from Relay input. */
9
- managedAgentPolicy: CompiledManagedAgentPolicy;
10
- managedRoomPromptSnapshot: ManagedRoomPromptSnapshot;
11
- }) | {
12
- /** A Worker event may reuse the Room's current permission ceiling, but it
13
- * is a private Manager continuation and must never receive Room tools. */
14
- source: 'manager_event';
15
- managedAgentPolicy: CompiledManagedAgentPolicy;
16
- managedRoomPolicyVersion: string;
17
- managedRuntimePolicyHash: string | null;
18
- };
19
- export declare function validateManagedRoomExecutionContext(context: ChatSendExecutionContext, systemPrompt: string | null | undefined, managedRoomContextToken: string | null | undefined): void;
20
- export declare function sendSessionUpdateEvent(runtime: SessionManagerRuntime, input: {
21
- sessionId: string;
22
- agentType: AgentType;
23
- sessionMode?: SessionMode;
24
- managerConfig?: import('@shennian/wire').ManagerConfig | null;
25
- workDir: string;
26
- agentSessionId?: string | null;
27
- modelId?: string;
28
- managerDefaultWorkerAgentType?: AgentType | null;
29
- managerDefaultWorkerModelId?: string | null;
30
- }): void;
3
+ import { type ChatSendExecutionContext } from './chat-context.js';
4
+ export { sendSessionUpdateEvent, validateManagedRoomExecutionContext, type ChatSendExecutionContext, } from './chat-context.js';
31
5
  export declare function handleChatSend(runtime: SessionManagerRuntime, req: ReqFrame, context?: ChatSendExecutionContext): Promise<void>;
32
6
  export declare function handleChatAbort(runtime: SessionManagerRuntime, req: ReqFrame): Promise<void>;
@@ -1 +1 @@
1
- import de from"node:os";import{createHash as Q,randomUUID as Ae}from"node:crypto";import{buildUserMessagePayload as le}from"@shennian/wire";import{reportLog as T}from"../../log-reporter.js";import{appendMessage as ce,getDaemonInstallationId as ge,getMessageDeliveryStatus as Me,recordSession as Ee,upsertMessage as _}from"../store.js";import{mergeProjectedSessions as De}from"../projection.js";import{parsePersonalAttachmentReferences as Te}from"../attachment-reference.js";import{assertFinishedAttachmentReferences as be,markAttachmentReferences as Ce}from"../attachment-transfer-store.js";import{requestSessionIndexPublish as R}from"../index-publisher.js";import{getPersonalSyncIdentity as $e}from"../../personal-sync/epoch.js";import{isTrustedManagerEvent as xe}from"../manager-event-authority.js";import{buildManagedAgentPermissionPrompt as We}from"../../room/managed-prompt-composer.js";import{getNativeSourceAgentType as qe}from"./chat-events.js";import{configureAdapterForSession as ue,maybeResolveClaudeImportedWorkDir as je,replaceManagedRoomContextToken as me,revokeManagedRoomContextToken as pe}from"./chat-adapter-config.js";import{createActiveSession as Fe,disposeSession as x,prepareAdapterTurn as Be,rememberProcessedReqId as Je,sendAdapterTurn as fe}from"./chat-session-lifecycle.js";function Oe(e,n,o){if(e.source!=="room_activation")throw new Error("managed_room_execution_context_required");if(!e.managedAgentPolicy)throw new Error("managed_agent_policy_missing");const l=e.managedRoomPromptSnapshot;if(!l)throw new Error("managed_room_prompt_snapshot_missing");if(!n?.trim())throw new Error("managed_room_prompt_incomplete");if(!o||!/^mrc_[A-Za-z0-9_-]{43}$/.test(o))throw new Error("managed_room_context_unavailable");const a=Q("sha256").update(JSON.stringify({requestedPolicy:e.managedAgentPolicy.requestedPolicy,enforcement:e.managedAgentPolicy.enforcement})).digest("hex"),b=Q("sha256").update(e.managedAgentPolicy.adapterPolicy.workDir).digest("hex");if(l.runtimePermissionPolicyHash!==a||l.resolvedWorkDirHash!==b||l.enforcementLevel!==e.managedAgentPolicy.enforcement.level)throw new Error("managed_room_prompt_snapshot_mismatch")}function ye(e,n){return`Agent send failed: ${n instanceof Error?n.message:String(n)}`}function He(e,n){Ee({sessionId:n.sessionId,agentType:n.agentType,sessionMode:n.sessionMode,managerConfig:n.managerConfig,workDir:n.workDir,agentSessionId:n.agentSessionId??null,modelId:n.modelId??null,managerDefaultWorkerAgentType:n.managerDefaultWorkerAgentType,managerDefaultWorkerModelId:n.managerDefaultWorkerModelId}),e.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:n.sessionId,agentType:n.agentType,sessionMode:n.sessionMode,managerConfig:n.managerConfig,agentSessionId:n.agentSessionId??null,modelId:n.modelId??null,workDir:n.workDir,status:"active",externalChannel:null}}})}function ze(e,n){const o=e.sessions.get(n),l=o?.currentRunId;if(!o||!l)return;const a=o.nextEventSeq;e.runTextAcc.delete(`${n}:${l}`),pe(e,o),o.pendingTextEvent=null,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:l,seq:a},seq:a,id:`agent-evt-${l}-${a}`}),o.journalRunId&&(e.runJournal?.remove(n,o.journalRunId),e.recoveryBarrier?.end(n),o.journalRunId=null),e.chatQueue?.noteTerminal(n)}async function dn(e,n,o){const l=o?n.params.managedRoomContextToken??null:null;let a=!1;try{await Ne(e,n,o,()=>{a=!0})}finally{l&&!a&&e.revokeManagedRoomContextToken?.(l)}}async function Ne(e,n,o,l){if(e.processedReqIds.has(n.id)){e.client.sendRes({type:"res",id:n.id,ok:!0});return}const{sessionId:a,text:b,agentType:A,sessionMode:ve,managerConfig:Z,workDir:he,agentSessionId:m,modelId:h,systemPrompt:G,managerDefaultWorkerAgentType:W,managerDefaultWorkerModelId:q,reasoningEffort:j,clientMessageId:Ie,sessionListProjection:_e,waitForDispatch:X,responseId:Re,managedRoomContextToken:I,suppressExternalOwnerEcho:we,queuedBatchItems:F,managedWorkerParentSessionId:u,managerWorkerRoomOrigin:B,managerWorkerNativeFull:J,managedRecoverySource:M}=n.params,c=Re||n.id,Y=n.params;if((Y.managerEventId||Y.managerEventRoomOrigin||u||B||J||M)&&!xe(n))throw new Error("manager_event_source_untrusted");De(_e);const C=null,O="";if(o?.source==="room_activation"&&(Oe(o,G,I),A==="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(!I||!/^mrc_[A-Za-z0-9_-]{43}$/.test(I))throw new Error("managed_room_context_unavailable")}if(Je(e,n.id),!a||!b){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(a)&&await e.recoveryBarrier.wait(a);const d=A,w=d==="manager"||ve==="manager"?"manager":"standard";w==="manager"&&e.managerRuntime?.setManagerWorkerDefaults(a,W??null,q??null);const E=(d==="claude"||d==="codex"||d==="workbuddy"||d==="pi-coding-agent"||d.startsWith("acp:"))&&typeof j=="string"&&j.trim()?j.trim():void 0,f=e.resolvePath(je(d,he||de.homedir(),m)||de.homedir()),y=o?.managedAgentPolicy??(u?e.managerRuntime?.getManagedAgentPolicyForWorker(u,f)??null:null);if(u&&!J&&!y)throw new Error("managed_worker_permission_context_unavailable");const H=d==="codex"&&(o?.source==="room_activation"||o?.source==="manager_event"||u)?"internal":"user",z=u&&y?We({requestedPolicy:y.requestedPolicy,enforcement:y.enforcement,resolvedWorkDir:y.adapterPolicy.workDir}):G??null,ke=f,$=Te(n.params.attachments);$?.length&&be(f,$);const p={text:b,attachments:$,localized:!1};let t=e.sessions.get(a);if(t){if(t.lastActiveAt=Date.now(),t.agentType!==d||(t.sessionMode??(t.agentType==="manager"?"manager":"standard"))!==w||t.workDir!==f||(t.nativeSessionVisibility??"user")!==H||JSON.stringify(t.externalChannel??null)!==JSON.stringify(C??null)){e.sessions.delete(a);try{await x(e,t)}catch{e.processedReqIds.delete(n.id)}t=void 0}else if(m&&t.agentSessionId!==m)try{await t.adapter.resume(m),t.agentSessionId=m}catch{e.sessions.delete(a);try{await x(e,t)}catch{e.processedReqIds.delete(n.id)}t=void 0}}if(!t)try{t=await Fe(e,a,d,w,f,m,C,O,y,H)}catch(r){const i=r instanceof Error&&r.message.startsWith("Unsupported agent:")?r.message:`Failed to start ${A}: ${r instanceof Error?r.message:String(r)}`;console.error(`[chat.send] start failed reqId=${n.id} sessionId=${a} agentType=${A} workDir=${f} agentSessionId=${m??""}: ${i}`),e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:a,message:i,runId:"",seq:0}}),e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:c,ok:!1,error:i});return}const g={id:Ie??`user-${n.id}`,sessionId:a,role:"user",ts:Date.now(),payload:le(p.text,p.attachments)},ee=Array.isArray(F)&&F.length>0?F.map(r=>({id:r.clientMessageId??r.id,sessionId:a,role:M==="manager_event"||n.params.scheduledDelivery===!0?"agent":"user",ts:M==="manager_event"?Date.parse(r.createdAt):g.ts,payload:le(r.text,r.attachments)})):null,k=ee??[g],N=Me(a,g.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){(o?.source==="room_activation"||o?.source==="manager_event")&&ue(t.adapter,a,d,C,O,I,o.managedAgentPolicy,e.managedRoomExecutor);try{await Be(t.adapter,p.text,h,E,p.attachments,z,o?.source==="room_activation"?{source:"room_activation"}:o?.source==="manager_event"?{source:"managed_private"}:void 0)}catch(r){e.processedReqIds.delete(n.id),e.sessions.delete(a),await x(e,t),e.client.sendRes({type:"res",id:c,ok:!1,error:r instanceof Error?r.message:String(r)});return}}T({level:"info",sessionId:a,wsEvent:"chat.send.start",metadata:{reqId:n.id,agentType:d,sessionMode:w,managerConfig:Z??null,modelId:h,managerDefaultWorkerAgentType:W??null,managerDefaultWorkerModelId:q??null,reasoningEffort:E,...o?.source==="room_activation"?{managedRoomPromptSnapshot:o.managedRoomPromptSnapshot}:{}}});const S=(r,i)=>({...$e(ge()),sessionId:a,clientMessageId:g.id,messageId:g.id,deliveryState:r,bodyRevision:i,committedAt:new Date(g.ts).toISOString()}),U=r=>{e.nativeFusion?.registerManagedSend({sessionId:a,agentType:d,sourceAgentType:qe(d,h),canonicalMessageId:g.id,sourceSessionKey:t.agentSessionId??m??null,text:p.text,managedEchoPolicy:r?.deliveryMode==="external_owner_queue"&&!we?"import_following":"suppress_following",externalRunId:r?.deliveryMode==="external_owner_queue"?`codex-external-${r.queuedSubmissionId??g.id}`:null})},ae=()=>{t.currentRunId||(t.currentRunId=`dispatch:${n.id}`,t.currentRunPhase="thinking",t.nextEventSeq=0)},oe=()=>{if(!e.runJournal||t.journalRunId)return;const r=`run:${Ae()}`;e.runJournal.begin({daemonInstallationId:ge(),sessionId:a,runId:r,clientMessageId:g.id,agentType:d,sessionMode:w,workDir:f,agentSessionId:t.agentSessionId??m??null,modelId:h??null,reasoningEffort:E??null,nativeSessionVisibility:H,providerRunId:null,source:M==="manager_event"?"manager_event":o?.source==="room_activation"?M==="managed_direct"?"managed_direct":"managed_room":u?"manager_worker":"personal",parentSessionId:u??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: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)??(y?Q("sha256").update(JSON.stringify({requestedPolicy:y.requestedPolicy,enforcement:y.enforcement})).digest("hex"):null)}),t.journalRunId=r},re=()=>{if(U(),ne){let r=0;for(const[i,s]of k.entries()){const v=_(a,s,"queued");i===0&&(r=v)}return S("queued",r)}try{He(e,{sessionId:a,agentType:d,sessionMode:w,managerConfig:Z??null,workDir:ke,agentSessionId:t.agentSessionId??m??null,modelId:h,managerDefaultWorkerAgentType:W??null,managerDefaultWorkerModelId:q??null});let r=0;for(const[i,s]of k.entries()){const v=ee?_(a,s,"committed"):ce(a,s,"committed");i===0&&(r=v)}return Ce(f,$??[]),R(e.client),S("committed",r)}catch(r){throw e.nativeFusion?.cancelManagedSend?.(g.id),r}},te=r=>{t.journalRunId&&e.runJournal?.update(a,t.journalRunId,{deliveryMode:r?.deliveryMode==="external_owner_queue"?"external_owner_queue":"direct",externalRunId:r?.deliveryMode==="external_owner_queue"?`codex-external-${r.queuedSubmissionId??g.id}`:null})},se=r=>{t.currentRunId||(t.nextEventSeq=0),te(r),U(r);const i=r?.deliveryMode==="external_owner_queue"?"queued":"executing";let s=0;for(const[v,D]of k.entries()){const P=_(a,D,i);v===0&&(s=P)}return R(e.client),S(i,s)},V=async(r,i)=>{e.nativeFusion?.cancelManagedSend?.(g.id);const s=ye(d,r);if(console.error(`[chat.send] send failed reqId=${n.id} sessionId=${a} agentType=${A} workDir=${f} agentSessionId=${t.agentSessionId??m??""}: ${s}`),t.adapter.hasPendingAuthenticationRetry?.()===!0){i&&e.client.sendRes({type:"res",id:c,ok:!0,payload:S("queued",0)});return}e.sessions.delete(a),t.journalRunId&&(e.runJournal?.update(a,t.journalRunId,{phase:"terminal"}),e.runJournal?.remove(a,t.journalRunId),e.recoveryBarrier?.end(a),t.journalRunId=null);try{await x(e,t)}catch{}if(e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:a,message:s,runId:"",seq:0}}),!i){const D={id:`agent-error-${n.id}-${Date.now()}`,sessionId:a,role:"agent",ts:Date.now(),payload:s};ce(a,D),R(e.client)}i&&(e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:c,ok:!1,error:s}))};if(X){try{re()}catch(s){e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:c,ok:!1,error:`Durable message commit failed: ${s instanceof Error?s.message:String(s)}`});return}oe(),ae();let r;try{(o?.source==="room_activation"||o?.source==="manager_event")&&(me(e,t,I),l());const s=p.attachments;u&&e.managerRuntime?.prepareWorkerTurnOrigin(a,B),r=await fe(t.adapter,p.text,h,E,s,z,o?.source==="room_activation"?{source:"room_activation"}:o?.source==="manager_event"?{source:"managed_private"}:void 0),T({level:"info",sessionId:a,wsEvent:"chat.send.done",metadata:{reqId:n.id}})}catch(s){if(u&&e.managerRuntime?.prepareWorkerTurnOrigin(a),t.adapter.hasPendingAuthenticationRetry?.()){let P=0;for(const[K,L]of k.entries()){const Pe=_(a,L,"queued");K===0&&(P=Pe)}R(e.client),await V(s,!1),e.client.sendRes({type:"res",id:c,ok:!0,payload:S("queued",P)});return}let v=0;for(const[P,K]of k.entries()){const L=_(a,K,"failed");P===0&&(v=L)}R(e.client);const D=ye(d,s);await V(s,!1),e.client.sendRes({type:"res",id:c,ok:!0,payload:{...S("failed",v),failureMessage:D}});return}const i=se(r??void 0);e.client.sendRes({type:"res",id:c,ok:!0,payload:{...i,...p.localized?{localizedAttachments:!0}:{},...r?.deliveryMode==="external_owner_queue"?{queued:!0,deliveryMode:r.deliveryMode,queuedSubmissionId:r.queuedSubmissionId}:{}}}),T({level:"info",sessionId:a,wsEvent:"chat.send.res",metadata:{reqId:n.id,ok:!0}});return}let ie;try{ie=re()}catch(r){e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:c,ok:!1,error:`Durable message commit failed: ${r instanceof Error?r.message:String(r)}`});return}oe(),ae(),(o?.source==="room_activation"||o?.source==="manager_event")&&(ue(t.adapter,a,d,C,O,I,o.managedAgentPolicy,e.managedRoomExecutor),me(e,t,I),l()),se(),e.client.sendRes({type:"res",id:c,ok:!0,payload:{...ie,...p.localized?{localizedAttachments:!0}:{}}}),T({level:"info",sessionId:a,wsEvent:"chat.send.res",metadata:{reqId:n.id,ok:!0}});const Se=p.attachments;u&&e.managerRuntime?.prepareWorkerTurnOrigin(a,B),fe(t.adapter,p.text,h,E,Se,z,o?.source==="room_activation"?{source:"room_activation"}:o?.source==="manager_event"?{source:"managed_private"}:void 0).then(r=>{if(r?.deliveryMode==="external_owner_queue"){te(r),U(r);for(const i of k)_(a,i,"queued");R(e.client)}T({level:"info",sessionId:a,wsEvent:"chat.send.done",metadata:{reqId:n.id}})}).catch(r=>{u&&e.managerRuntime?.prepareWorkerTurnOrigin(a),_(a,g,t.adapter.hasPendingAuthenticationRetry?.()?"queued":"failed"),R(e.client),V(r,!1)})}async function ln(e,n){const{sessionId:o,discardPending:l}=n.params,a=e.sessions.get(o);if(a){a.journalRunId&&e.runJournal?.markAborted(o,a.journalRunId),pe(e,a);try{await a.adapter.stop()}catch{e.client.sendRes({type:"res",id:n.id,ok:!1,error:"agent_stop_failed"});return}ze(e,o),e.activityPublisher?.publish(o,null)}l===!0&&e.chatQueue?.purgeSession(o),e.client.sendRes({type:"res",id:n.id,ok:!0})}export{ln as handleChatAbort,dn as handleChatSend,He as sendSessionUpdateEvent,Oe as validateManagedRoomExecutionContext};
1
+ import{buildUserMessagePayload as ie}from"@shennian/wire";import{createHash as Me,randomUUID as Ae}from"node:crypto";import de 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 be,markAttachmentReferences as Te}from"../attachment-transfer-store.js";import{requestSessionIndexPublish as _}from"../index-publisher.js";import{isTrustedManagerEvent as xe}from"../manager-event-authority.js";import{mergeProjectedSessions as Ce}from"../projection.js";import{appendMessage as le,getDaemonInstallationId as ce,getMessageDeliveryStatus as $e,upsertMessage as S}from"../store.js";import{configureAdapterForSession as ue,maybeResolveClaudeImportedWorkDir as We,replaceManagedRoomContextToken as ge,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 Be}from"./chat-events.js";import{createActiveSession as Je,disposeSession as C,prepareAdapterTurn as Oe,rememberProcessedReqId as ze,sendAdapterTurn as pe}from"./chat-session-lifecycle.js";import{sendSessionUpdateEvent as mn,validateManagedRoomExecutionContext as pn}from"./chat-context.js";function fe(e,o){return`Agent send failed: ${o instanceof Error?o.message:String(o)}`}function Ue(e,o){const t=e.sessions.get(o),u=t?.currentRunId;if(!t||!u)return;const n=t.nextEventSeq;e.runTextAcc.delete(`${o}:${u}`),me(e,t),t.pendingTextEvent=null,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:o,runId:u,seq:n},seq:n,id:`agent-evt-${u}-${n}`}),t.journalRunId&&(e.runJournal?.remove(o,t.journalRunId),e.recoveryBarrier?.end(o),t.journalRunId=null),e.chatQueue?.noteTerminal(o)}async function ln(e,o,t){const u=t?o.params.managedRoomContextToken??null:null;let n=!1;try{await He(e,o,t,()=>{n=!0})}finally{u&&!n&&e.revokeManagedRoomContextToken?.(u)}}async function He(e,o,t,u){if(e.processedReqIds.has(o.id)){e.client.sendRes({type:"res",id:o.id,ok:!0});return}const{sessionId:n,text:Q,agentType:A,sessionMode:ye,managerConfig:L,workDir:ve,agentSessionId:m,modelId:h,systemPrompt:Z,managerDefaultWorkerAgentType:$,managerDefaultWorkerModelId:W,reasoningEffort:q,clientMessageId:he,sessionListProjection:Ie,waitForDispatch:G,responseId:Re,managedRoomContextToken:I,suppressExternalOwnerEcho:_e,queuedBatchItems:j,managedWorkerParentSessionId:g,managerWorkerRoomOrigin:F,managerWorkerNativeFull:B,managedRecoverySource:P}=o.params,l=Re||o.id,X=o.params;if((X.managerEventId||X.managerEventRoomOrigin||g||F||B||P)&&!xe(o))throw new Error("manager_event_source_untrusted");Ce(Ie);const T=null,J="";if(t?.source==="room_activation"&&(Fe(t,Z,I),A==="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(!I||!/^mrc_[A-Za-z0-9_-]{43}$/.test(I))throw new Error("managed_room_context_unavailable")}if(ze(e,o.id),!n||!Q){e.processedReqIds.delete(o.id),e.client.sendRes({type:"res",id:l,ok:!1,error:"sessionId and text are required"});return}if(e.recoveryBarrier?.isDispatchFrozen()){e.processedReqIds.delete(o.id),e.client.sendRes({type:"res",id:l,ok:!1,error:"upgrade_in_progress"});return}e.recoveryBarrier?.isRecovering(n)&&await e.recoveryBarrier.wait(n);const d=A,R=d==="manager"||ye==="manager"?"manager":"standard";R==="manager"&&e.managerRuntime?.setManagerWorkerDefaults(n,$??null,W??null);const E=(d==="claude"||d==="codex"||d==="workbuddy"||d==="pi-coding-agent"||d.startsWith("acp:"))&&typeof q=="string"&&q.trim()?q.trim():void 0,y=e.resolvePath(We(d,ve||de.homedir(),m)||de.homedir()),f=t?.managedAgentPolicy??(g?e.managerRuntime?.getManagedAgentPolicyForWorker(g,y)??null:null);if(g&&!B&&!f)throw new Error("managed_worker_permission_context_unavailable");const O=qe(n,d,R,!!(f||g||t)),z=g&&f?Ee({requestedPolicy:f.requestedPolicy,enforcement:f.enforcement,resolvedWorkDir:f.adapterPolicy.workDir}):Z??null,Se=y,x=De(o.params.attachments);x?.length&&be(y,x);const p={text:Q,attachments:x,localized:!1};let r=e.sessions.get(n);if(r){if(r.lastActiveAt=Date.now(),r.agentType!==d||(r.sessionMode??(r.agentType==="manager"?"manager":"standard"))!==R||r.workDir!==y||(r.nativeSessionVisibility??"user")!==O||JSON.stringify(r.externalChannel??null)!==JSON.stringify(T??null)){e.sessions.delete(n);try{await C(e,r)}catch{e.processedReqIds.delete(o.id)}r=void 0}else if(m&&r.agentSessionId!==m)try{await r.adapter.resume(m),r.agentSessionId=m}catch{e.sessions.delete(n);try{await C(e,r)}catch{e.processedReqIds.delete(o.id)}r=void 0}}if(!r)try{r=await Je(e,n,d,R,y,m,T,J,f,O)}catch(a){const i=a instanceof Error&&a.message.startsWith("Unsupported agent:")?a.message:`Failed to start ${A}: ${a instanceof Error?a.message:String(a)}`;console.error(`[chat.send] start failed reqId=${o.id} sessionId=${n} agentType=${A} workDir=${y} agentSessionId=${m??""}: ${i}`),e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:n,message:i,runId:"",seq:0}}),e.processedReqIds.delete(o.id),e.client.sendRes({type:"res",id:l,ok:!1,error:i});return}const c={id:he??`user-${o.id}`,sessionId:n,role:"user",ts:Date.now(),payload:ie(p.text,p.attachments)},Y=Array.isArray(j)&&j.length>0?j.map(a=>({id:a.clientMessageId??a.id,sessionId:n,role:P==="manager_event"||o.params.scheduledDelivery===!0?"agent":"user",ts:P==="manager_event"?Date.parse(a.createdAt):c.ts,payload:ie(a.text,a.attachments)})):null,k=Y??[c],U=$e(n,c.id),ee=U.state==="queued";if(U.state!=="not_found"&&!ee){e.client.sendRes({type:"res",id:l,ok:!0,payload:U});return}if(G){(t?.source==="room_activation"||t?.source==="manager_event")&&ue(r.adapter,n,d,T,J,I,t.managedAgentPolicy,e.managedRoomExecutor);try{await Oe(r.adapter,p.text,h,E,p.attachments,z,t?.source==="room_activation"?{source:"room_activation"}:t?.source==="manager_event"?{source:"managed_private"}:void 0)}catch(a){e.processedReqIds.delete(o.id),e.sessions.delete(n),await C(e,r),e.client.sendRes({type:"res",id:l,ok:!1,error:a instanceof Error?a.message:String(a)});return}}b({level:"info",sessionId:n,wsEvent:"chat.send.start",metadata:{reqId:o.id,agentType:d,sessionMode:R,managerConfig:L??null,modelId:h,managerDefaultWorkerAgentType:$??null,managerDefaultWorkerModelId:W??null,reasoningEffort:E,...t?.source==="room_activation"?{managedRoomPromptSnapshot:t.managedRoomPromptSnapshot}:{}}});const w=(a,i)=>({...Pe(ce()),sessionId:n,clientMessageId:c.id,messageId:c.id,deliveryState:a,bodyRevision:i,committedAt:new Date(c.ts).toISOString()}),H=a=>{e.nativeFusion?.registerManagedSend({sessionId:n,agentType:d,sourceAgentType:Be(d,h),canonicalMessageId:c.id,sourceSessionKey:r.agentSessionId??m??null,text:p.text,managedEchoPolicy:a?.deliveryMode==="external_owner_queue"&&!_e?"import_following":"suppress_following",externalRunId:a?.deliveryMode==="external_owner_queue"?`codex-external-${a.queuedSubmissionId??c.id}`:null})},ne=()=>{r.currentRunId||(r.currentRunId=`dispatch:${o.id}`,r.currentRunPhase="thinking",r.nextEventSeq=0)},ae=()=>{if(!e.runJournal||r.journalRunId)return;const a=`run:${Ae()}`;e.runJournal.begin({daemonInstallationId:ce(),sessionId:n,runId:a,clientMessageId:c.id,agentType:d,sessionMode:R,workDir:y,agentSessionId:r.agentSessionId??m??null,modelId:h??null,reasoningEffort:E??null,nativeSessionVisibility:O,providerRunId:null,source:P==="manager_event"?"manager_event":t?.source==="room_activation"?P==="managed_direct"?"managed_direct":"managed_room":g?"manager_worker":"personal",parentSessionId:g??null,managerWorkerNativeFull:B===!0,roomContextRegistryKey:typeof o.params.roomContextRegistryKey=="string"?o.params.roomContextRegistryKey:null,activationCauseMessageId:typeof o.params.activationCauseMessageId=="string"?o.params.activationCauseMessageId:null,rootCauseMessageId:typeof o.params.rootCauseMessageId=="string"?o.params.rootCauseMessageId:null,activationSequence:typeof o.params.activationSequence=="string"?o.params.activationSequence:null,activationHopCount:typeof o.params.activationHopCount=="number"?o.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)??(f?Me("sha256").update(JSON.stringify({requestedPolicy:f.requestedPolicy,enforcement:f.enforcement})).digest("hex"):null)}),r.journalRunId=a},oe=()=>{if(H(),ee){let a=0;for(const[i,s]of k.entries()){const v=S(n,s,"queued");i===0&&(a=v)}return w("queued",a)}try{je(e,{sessionId:n,agentType:d,sessionMode:R,managerConfig:L??null,workDir:Se,agentSessionId:r.agentSessionId??m??null,modelId:h,managerDefaultWorkerAgentType:$??null,managerDefaultWorkerModelId:W??null});let a=0;for(const[i,s]of k.entries()){const v=Y?S(n,s,"committed"):le(n,s,"committed");i===0&&(a=v)}return Te(y,x??[]),_(e.client),w("committed",a)}catch(a){throw e.nativeFusion?.cancelManagedSend?.(c.id),a}},te=a=>{r.journalRunId&&e.runJournal?.update(n,r.journalRunId,{deliveryMode:a?.deliveryMode==="external_owner_queue"?"external_owner_queue":"direct",externalRunId:a?.deliveryMode==="external_owner_queue"?`codex-external-${a.queuedSubmissionId??c.id}`:null})},re=a=>{r.currentRunId||(r.nextEventSeq=0),te(a),H(a);const i=a?.deliveryMode==="external_owner_queue"?"queued":"executing";let s=0;for(const[v,D]of k.entries()){const M=S(n,D,i);v===0&&(s=M)}return _(e.client),w(i,s)},N=async(a,i)=>{e.nativeFusion?.cancelManagedSend?.(c.id);const s=fe(d,a);if(console.error(`[chat.send] send failed reqId=${o.id} sessionId=${n} agentType=${A} workDir=${y} agentSessionId=${r.agentSessionId??m??""}: ${s}`),r.adapter.hasPendingAuthenticationRetry?.()===!0){i&&e.client.sendRes({type:"res",id:l,ok:!0,payload:w("queued",0)});return}e.sessions.delete(n),r.journalRunId&&(e.runJournal?.update(n,r.journalRunId,{phase:"terminal"}),e.runJournal?.remove(n,r.journalRunId),e.recoveryBarrier?.end(n),r.journalRunId=null);try{await C(e,r)}catch{}if(e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:n,message:s,runId:"",seq:0}}),!i){const D={id:`agent-error-${o.id}-${Date.now()}`,sessionId:n,role:"agent",ts:Date.now(),payload:s};le(n,D),_(e.client)}i&&(e.processedReqIds.delete(o.id),e.client.sendRes({type:"res",id:l,ok:!1,error:s}))};if(G){try{oe()}catch(s){e.processedReqIds.delete(o.id),e.client.sendRes({type:"res",id:l,ok:!1,error:`Durable message commit failed: ${s instanceof Error?s.message:String(s)}`});return}ae(),ne();let a;try{(t?.source==="room_activation"||t?.source==="manager_event")&&(ge(e,r,I),u());const s=p.attachments;g&&e.managerRuntime?.prepareWorkerTurnOrigin(n,F),a=await pe(r.adapter,p.text,h,E,s,z,t?.source==="room_activation"?{source:"room_activation"}:t?.source==="manager_event"?{source:"managed_private"}:void 0),b({level:"info",sessionId:n,wsEvent:"chat.send.done",metadata:{reqId:o.id}})}catch(s){if(g&&e.managerRuntime?.prepareWorkerTurnOrigin(n),r.adapter.hasPendingAuthenticationRetry?.()){let M=0;for(const[V,K]of k.entries()){const we=S(n,K,"queued");V===0&&(M=we)}_(e.client),await N(s,!1),e.client.sendRes({type:"res",id:l,ok:!0,payload:w("queued",M)});return}let v=0;for(const[M,V]of k.entries()){const K=S(n,V,"failed");M===0&&(v=K)}_(e.client);const D=fe(d,s);await N(s,!1),e.client.sendRes({type:"res",id:l,ok:!0,payload:{...w("failed",v),failureMessage:D}});return}const i=re(a??void 0);e.client.sendRes({type:"res",id:l,ok:!0,payload:{...i,...p.localized?{localizedAttachments:!0}:{},...a?.deliveryMode==="external_owner_queue"?{queued:!0,deliveryMode:a.deliveryMode,queuedSubmissionId:a.queuedSubmissionId}:{}}}),b({level:"info",sessionId:n,wsEvent:"chat.send.res",metadata:{reqId:o.id,ok:!0}});return}let se;try{se=oe()}catch(a){e.processedReqIds.delete(o.id),e.client.sendRes({type:"res",id:l,ok:!1,error:`Durable message commit failed: ${a instanceof Error?a.message:String(a)}`});return}ae(),ne(),(t?.source==="room_activation"||t?.source==="manager_event")&&(ue(r.adapter,n,d,T,J,I,t.managedAgentPolicy,e.managedRoomExecutor),ge(e,r,I),u()),re(),e.client.sendRes({type:"res",id:l,ok:!0,payload:{...se,...p.localized?{localizedAttachments:!0}:{}}}),b({level:"info",sessionId:n,wsEvent:"chat.send.res",metadata:{reqId:o.id,ok:!0}});const ke=p.attachments;g&&e.managerRuntime?.prepareWorkerTurnOrigin(n,F),pe(r.adapter,p.text,h,E,ke,z,t?.source==="room_activation"?{source:"room_activation"}:t?.source==="manager_event"?{source:"managed_private"}:void 0).then(a=>{if(a?.deliveryMode==="external_owner_queue"){te(a),H(a);for(const i of k)S(n,i,"queued");_(e.client)}b({level:"info",sessionId:n,wsEvent:"chat.send.done",metadata:{reqId:o.id}})}).catch(a=>{g&&e.managerRuntime?.prepareWorkerTurnOrigin(n),S(n,c,r.adapter.hasPendingAuthenticationRetry?.()?"queued":"failed"),_(e.client),N(a,!1)})}async function cn(e,o){const{sessionId:t,discardPending:u}=o.params,n=e.sessions.get(t);if(n){n.journalRunId&&e.runJournal?.markAborted(t,n.journalRunId),me(e,n);try{await n.adapter.stop()}catch{e.client.sendRes({type:"res",id:o.id,ok:!1,error:"agent_stop_failed"});return}Ue(e,t),e.activityPublisher?.publish(t,null)}u===!0&&e.chatQueue?.purgeSession(t),e.client.sendRes({type:"res",id:o.id,ok:!0})}export{cn as handleChatAbort,ln as handleChatSend,mn as sendSessionUpdateEvent,pn as validateManagedRoomExecutionContext};
@@ -1,3 +1,3 @@
1
- import{SESSION_SYNC_PROTOCOL_VERSION as g,SESSION_SYNC_DATA_EPOCH as f}from"@shennian/wire";import h from"node:crypto";import{getRegisteredAgents as k,unregisterAgent as I}from"../agents/adapter.js";import{resetCommandSpecCache as A}from"../agents/command-spec.js";import{loadConfig as T}from"../config/index.js";import{handleUpgradeStart as P,handleUpgradeStatus as C}from"../commands/upgrade.js";import{handleAgentsRefresh as M,handleModelsRefresh as D,refreshMachineAgents as x}from"./handlers/agents.js";import{AcpDiscoveryWatcher as E}from"../agents/acp/watcher.js";import{handleAgentCapabilitiesList as F}from"./handlers/agent-capabilities.js";import{handleAgentConfigClear as O,handleAgentConfigGet as _,handleAgentConfigTest as Q,handleAgentConfigUpsert as j}from"./handlers/agent-config.js";import{handleChatAbort as B,handleChatSend as U}from"./handlers/chat.js";import{recoverJournaledRun as z}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 J}from"./handlers/message-status.js";import{handleAgentWorkspaceValidation as N}from"./handlers/agent-workspace-validation.js";import{handleVoiceSessionBodyWindow as V}from"./handlers/voice-window.js";import{handleRemoteAccessPause as L}from"./handlers/remote-access.js";import{cleanupPendingTransfers as G,handleFsLs as Y,handleFsRead as K,handleFsRename as X,handleFsWrite as Z,handleFsTransferAbort as q,handleFsTransferChunk as ee,handleFsTransferFinish as se,handleFsTransferStart as te,handleFsExportMarkdownPdf as ae,handleFsExportMarkdownPdfSetup as re,handleFsArchiveZip as ne}from"./handlers/fs.js";import{handleRegionProbe as ie,handleRegionSwitch as oe,handleUpgradeSetPolicy as ce}from"./handlers/control.js";import{ManagerRuntimeService as le,setManagerRuntimeService as v}from"../manager/runtime.js";import{ChatQueueManager as de}from"./queue.js";import{createAuthorizedFsRoot as he,createAuthorizedFsRootAsync as ue,resolveAuthorizedPath as pe,resolveAuthorizedPathAsync as me,resolveSessionWorkDir as ge}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 fe}from"../agents/custom.js";import{handleManagedRoomBind as ve,handleManagedRoomRestart as ye,discardPreBindingSession as Re}from"./handlers/room-managed.js";import{getDaemonInstallationId as u,listSessionRecords as p,purgeCanonicalSession as be,purgeSessionRecord as Se,recordSession as we,upsertMessage as ke}from"./store.js";import{requestSessionIndexPublish as Ie}from"./index-publisher.js";import{reportUpgradeAggregateMetric as Ae}from"../log-reporter.js";import{PersonalHistorySubscriptions as Te}from"./history-subscriptions.js";import{sweepAttachmentTransfers as Pe}from"./attachment-transfer-store.js";import{NativeSourceDeletionStore as Ce}from"../native-fusion/native-source-deletions.js";import{purgeToolDetails as Me}from"./tool-detail-store.js";import{readDeletionSyncRevision as De,writeDeletionSyncRevision as y}from"./deletion-sync-state.js";import{assertDeletionSyncRunnable as xe,clearDeletionSyncFailure as Ee,DeletionSyncRetryWaitError as Fe,DeletionSyncTerminalError as Oe,recordDeletionSyncFailure as m}from"./deletion-sync-state.js";import{NativeSessionCleanupOutbox as _e}from"./native-cleanup-outbox.js";import{assertPersonalSyncIdentity as c}from"../personal-sync/epoch.js";import{ActiveRunJournal as Qe}from"./run-recovery/journal.js";import{RunRecoveryBarrier as je}from"./run-recovery/barrier.js";import{RunRecoveryCoordinator as Be}from"./run-recovery/coordinator.js";import{ProjectFsHandleStore as Ue}from"./project-fs-store.js";import{handleProjectFsRequest as ze}from"./handlers/project-fs.js";import{handleAgentPermissionResponse as We,handleAcpAgentRequest as $e}from"./handlers/agent-control.js";import{validateDeletionSyncResponse as He}from"./deletion-sync-validation.js";import{dispatchManagedChat as Je,dispatchQueuedChat as Ne,interruptQueuedChat as Ve}from"./queued-chat-dispatch.js";const Le=50;import{resolveSessionWorkDir as Xs}from"../fs/boundary.js";class Gs{client;nativeFusion;cliVersion;upgradePolicyController;managedRoomBinder;remoteAccessPauseController;managedRoomContextRevoker;managedRoomExecutor;trustedProjectFsRequestResolver;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 je;recoveryCoordinator;recoveryPass=null;prepareManagedRecovery;projectFsHandleStore=new Ue;constructor(e,t=null,s,n=null,r=null,d=null,o=null,R=null,b=null,S=null){this.client=e,this.nativeFusion=t,this.cliVersion=s,this.upgradePolicyController=n,this.managedRoomBinder=r,this.remoteAccessPauseController=d,this.managedRoomContextRevoker=o,this.managedRoomExecutor=R,this.trustedProjectFsRequestResolver=S,this.runJournal=b??new Qe(u());for(const a of this.runJournal.loadPendingReconciliation().records)this.recoveryBarrier.begin(a.sessionId);this.recoveryCoordinator=new Be({journal:this.runJournal,barrier:this.recoveryBarrier,recover:(a,i)=>z(this.getRuntime(),a,i),commitTerminal:(a,i)=>this.commitRecoveryTerminal(a,i),isCanonicalTerminal:a=>{const i=p().find(w=>w.sessionId===a.sessionId),l=`terminal:${h.createHash("sha256").update(`${a.runId}\0`).digest("hex")}`;return i?.lastAttentionId===l},onOutcome:a=>Ae({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 le({getRuntime:()=>this.getRuntime(),dispatchReq:a=>this.handleReq(a,{propagateErrors:!0})}),this.chatQueue=new de({getRuntime:()=>this.getRuntime(),dispatchReq:a=>this.handleReq(a),dispatchManagedReq:(a,i)=>Je(this.getRuntime(),a,i),dispatchQueuedReq:(a,i)=>Ne(this.getRuntime(),a,i),interruptQueuedSession:a=>Ve(this.getRuntime(),a)}),this.historySubscriptions=new Te(this.client),this.nativeCleanupOutbox=new _e({logger:console.info}),this.acpDiscoveryWatcher=new E(async()=>{A(),await x(this.getRuntime())}),this.nativeFusion?.setExternalTerminalHandler?.(a=>{this.handleExternalTerminal(a)}),this.nativeCleanupOutbox.start(),v(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(()=>{this.publishManagedActivitySnapshots().catch(a=>{console.error("[session.activity] managed probe failed",a)})},15e3),this.activityProbeTimer.unref?.(),this.attachmentCleanupTimer=setInterval(()=>{const a=new Set([...p().map(i=>i.workDir),...Array.from(this.pendingTransfers.values()).map(i=>i.rootPath)]);for(const i of a)try{Pe(this.resolvePath(i))}catch(l){console.error("[attachment.cleanup] failed",l instanceof Error?l.message:String(l))}},6e4),this.attachmentCleanupTimer.unref?.()}executeManagedManagerAction(e){return this.managerRuntime.executeScopedWorkerAction(e.managerSessionId,e.action,e.params,e.roomOrigin)}getRuntime(){return{client:this.client,pendingTransfers:this.pendingTransfers,processedReqIds:this.processedReqIds,reloadCustomAgents:()=>this.reloadCustomAgents(),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=t.result==="interrupted_by_upgrade"?`\u4EFB\u52A1\u56E0\u795E\u5FF5\u5347\u7EA7\u800C\u4E2D\u65AD\uFF08${t.reason}\uFF09\u3002\u539F\u4F1A\u8BDD\u5DF2\u4FDD\u7559\uFF0C\u53EF\u7EE7\u7EED\u53D1\u9001\u65B0\u6D88\u606F\u3002
1
+ import{SESSION_SYNC_PROTOCOL_VERSION as g,SESSION_SYNC_DATA_EPOCH as f}from"@shennian/wire";import h from"node:crypto";import{getRegisteredAgents as k,unregisterAgent as I}from"../agents/adapter.js";import{resetCommandSpecCache as A}from"../agents/command-spec.js";import{loadConfig as T}from"../config/index.js";import{handleUpgradeStart as P,handleUpgradeStatus as C}from"../commands/upgrade.js";import{handleAgentsRefresh as M,handleModelsRefresh as D,refreshMachineAgents as x}from"./handlers/agents.js";import{AcpDiscoveryWatcher as E}from"../agents/acp/watcher.js";import{handleAgentCapabilitiesList as F}from"./handlers/agent-capabilities.js";import{handleAgentConfigClear as O,handleAgentConfigGet as _,handleAgentConfigTest as Q,handleAgentConfigUpsert as j}from"./handlers/agent-config.js";import{handleChatAbort as B,handleChatSend as U}from"./handlers/chat.js";import{recoverJournaledRun as z}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 J}from"./handlers/message-status.js";import{handleAgentWorkspaceValidation as N}from"./handlers/agent-workspace-validation.js";import{handleVoiceSessionBodyWindow as V}from"./handlers/voice-window.js";import{handleRemoteAccessPause as L}from"./handlers/remote-access.js";import{cleanupPendingTransfers as G,handleFsLs as Y,handleFsRead as K,handleFsRename as X,handleFsWrite as Z,handleFsTransferAbort as q,handleFsTransferChunk as ee,handleFsTransferFinish as se,handleFsTransferStart as te,handleFsExportMarkdownPdf as ae,handleFsExportMarkdownPdfSetup as ne,handleFsArchiveZip as re}from"./handlers/fs.js";import{handleRegionProbe as ie,handleRegionSwitch as oe,handleUpgradeSetPolicy as ce}from"./handlers/control.js";import{ManagerRuntimeService as le,setManagerRuntimeService as v}from"../manager/runtime.js";import{ChatQueueManager as de}from"./queue.js";import{createAuthorizedFsRoot as he,createAuthorizedFsRootAsync as ue,resolveAuthorizedPath as me,resolveAuthorizedPathAsync as pe,resolveSessionWorkDir as ge}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 fe}from"../agents/custom.js";import{handleManagedRoomBind as ve,handleManagedRoomRestart as ye,discardPreBindingSession as Re}from"./handlers/room-managed.js";import{getDaemonInstallationId as u,listSessionRecords as m,purgeCanonicalSession as be,purgeSessionRecord as Se,recordSession as we,upsertMessage as ke}from"./store.js";import{requestSessionIndexPublish as Ie}from"./index-publisher.js";import{reportUpgradeAggregateMetric as Ae}from"../log-reporter.js";import{PersonalHistorySubscriptions as Te}from"./history-subscriptions.js";import{sweepAttachmentTransfers as Pe}from"./attachment-transfer-store.js";import{NativeSourceDeletionStore as Ce}from"../native-fusion/native-source-deletions.js";import{purgeToolDetails as Me}from"./tool-detail-store.js";import{readDeletionSyncRevision as De,writeDeletionSyncRevision as y}from"./deletion-sync-state.js";import{assertDeletionSyncRunnable as xe,clearDeletionSyncFailure as Ee,DeletionSyncRetryWaitError as Fe,DeletionSyncTerminalError as Oe,recordDeletionSyncFailure as p}from"./deletion-sync-state.js";import{NativeSessionCleanupOutbox as _e}from"./native-cleanup-outbox.js";import{assertPersonalSyncIdentity as c}from"../personal-sync/epoch.js";import{ActiveRunJournal as Qe}from"./run-recovery/journal.js";import{RunRecoveryBarrier as je}from"./run-recovery/barrier.js";import{RunRecoveryCoordinator as Be}from"./run-recovery/coordinator.js";import{ProjectFsHandleStore as Ue}from"./project-fs-store.js";import{handleProjectFsRequest as ze}from"./handlers/project-fs.js";import{handleAgentPermissionResponse as We,handleAcpAgentRequest as $e}from"./handlers/agent-control.js";import{validateDeletionSyncResponse as He}from"./deletion-sync-validation.js";import{dispatchManagedChat as Je,dispatchQueuedChat as Ne,interruptQueuedChat as Ve}from"./queued-chat-dispatch.js";const Le=50;import{resolveSessionWorkDir as Xs}from"../fs/boundary.js";class Gs{client;nativeFusion;cliVersion;upgradePolicyController;managedRoomBinder;remoteAccessPauseController;managedRoomContextRevoker;managedRoomExecutor;trustedProjectFsRequestResolver;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 je;recoveryCoordinator;recoveryPass=null;prepareManagedRecovery;projectFsHandleStore=new Ue;constructor(e,t=null,s,r=null,n=null,d=null,o=null,R=null,b=null,S=null){this.client=e,this.nativeFusion=t,this.cliVersion=s,this.upgradePolicyController=r,this.managedRoomBinder=n,this.remoteAccessPauseController=d,this.managedRoomContextRevoker=o,this.managedRoomExecutor=R,this.trustedProjectFsRequestResolver=S,this.runJournal=b??new Qe(u());for(const a of this.runJournal.loadPendingReconciliation().records)this.recoveryBarrier.begin(a.sessionId);this.recoveryCoordinator=new Be({journal:this.runJournal,barrier:this.recoveryBarrier,recover:(a,i)=>z(this.getRuntime(),a,i),commitTerminal:(a,i)=>this.commitRecoveryTerminal(a,i),isCanonicalTerminal:a=>{const i=m().find(w=>w.sessionId===a.sessionId),l=`terminal:${h.createHash("sha256").update(`${a.runId}\0`).digest("hex")}`;return i?.lastAttentionId===l},onOutcome:a=>Ae({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 le({getRuntime:()=>this.getRuntime(),dispatchReq:a=>this.handleReq(a,{propagateErrors:!0})}),this.chatQueue=new de({getRuntime:()=>this.getRuntime(),dispatchReq:a=>this.handleReq(a),dispatchManagedReq:(a,i)=>Je(this.getRuntime(),a,i),dispatchQueuedReq:(a,i)=>Ne(this.getRuntime(),a,i),interruptQueuedSession:a=>Ve(this.getRuntime(),a)}),this.historySubscriptions=new Te(this.client),this.nativeCleanupOutbox=new _e({logger:console.info}),this.acpDiscoveryWatcher=new E(async()=>{A(),await x(this.getRuntime())}),this.nativeFusion?.setExternalTerminalHandler?.(a=>{this.handleExternalTerminal(a)}),this.nativeFusion?.setExternalClaimHandler?.((a,i)=>{this.chatQueue.noteExternalClaim(a,i)}),this.nativeCleanupOutbox.start(),v(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(()=>{this.publishManagedActivitySnapshots().catch(a=>{console.error("[session.activity] managed probe failed",a)})},15e3),this.activityProbeTimer.unref?.(),this.attachmentCleanupTimer=setInterval(()=>{const a=new Set([...m().map(i=>i.workDir),...Array.from(this.pendingTransfers.values()).map(i=>i.rootPath)]);for(const i of a)try{Pe(this.resolvePath(i))}catch(l){console.error("[attachment.cleanup] failed",l instanceof Error?l.message:String(l))}},6e4),this.attachmentCleanupTimer.unref?.()}executeManagedManagerAction(e){return this.managerRuntime.executeScopedWorkerAction(e.managerSessionId,e.action,e.params,e.roomOrigin)}getRuntime(){return{client:this.client,pendingTransfers:this.pendingTransfers,processedReqIds:this.processedReqIds,reloadCustomAgents:()=>this.reloadCustomAgents(),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 r=t.result==="interrupted_by_upgrade"?`\u4EFB\u52A1\u56E0\u795E\u5FF5\u5347\u7EA7\u800C\u4E2D\u65AD\uFF08${t.reason}\uFF09\u3002\u539F\u4F1A\u8BDD\u5DF2\u4FDD\u7559\uFF0C\u53EF\u7EE7\u7EED\u53D1\u9001\u65B0\u6D88\u606F\u3002
2
2
  Task interrupted by the Shennian upgrade (${t.reason}). The session is preserved and ready for a new message.`:`\u795E\u5FF5\u5347\u7EA7\u540E\u672A\u80FD\u6062\u590D\u4EFB\u52A1\uFF08${t.reason}\uFF09\u3002\u539F\u4F1A\u8BDD\u5DF2\u4FDD\u7559\uFF0C\u53EF\u91CD\u8BD5\u6216\u7EE7\u7EED\u53D1\u9001\u65B0\u6D88\u606F\u3002
3
- The task could not be recovered after the Shennian upgrade (${t.reason}). The session is preserved; retry or send a new message.`;ke(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})}),we({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}),Ie(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=p().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 Re(this.getRuntime(),e)}discardPendingManagedRoomMessages(e){return this.chatQueue.discardPendingManagedRoomMessages(e)}async synchronizeSessionDeletions(){xe();try{await this.synchronizeSessionDeletionsOnce(),Ee()}catch(e){if(e instanceof Fe||e instanceof Oe)throw e;const t=e instanceof Error?e.message:String(e),s=/offline|not connected|disconnect|timed out|timeout|temporar|unavailable|ECONN|ENOTFOUND|EIO|EBUSY/i.test(t)?"transport_unavailable":/invalid (?:deletion sync|session deletion)|deletion revision gap/i.test(t)?"invalid_deletion_sync_response":"deletion_sync_failed";throw console.warn("[session.deletions] retrying failed synchronization",{code:s}),m({code:s,retryable:!0}),e}}async synchronizeSessionDeletionsOnce(){const e=u(),t=De(),s=await this.client.sendReq({type:"req",id:`session-deletions-sync-${h.randomUUID()}`,method:"session.deletions.sync",params:{protocolVersion:g,dataEpoch:f,daemonInstallationId:e,afterRevision:t}});if(!s.ok){const o=s.rejection;throw o?(m({code:o.code,retryable:o.retryable&&o.requiredAction==="retry"}),new Error(o.code)):(m({code:"unstructured_rejection",retryable:!0}),new Error(s.error??"unstructured_rejection"))}const n=s.payload;c(n),He(n,t);let r=n.baselineRevision;r>t&&y(r);for(const o of n.deletions)o.deletionRevision<=r||(await this.applySessionDeletion(o),r=o.deletionRevision,y(r));if(r!==n.latestRevision)throw new Error(`deletion revision gap: applied ${r}, latest ${n.latestRevision}`);if(r===0)return;const d=await this.client.sendReq({type:"req",id:`session-deletions-ack-${h.randomUUID()}`,method:"session.deletions.ack",params:{protocolVersion:g,dataEpoch:f,daemonInstallationId:e,deletionRevision:r}});if(!d.ok)throw new Error(d.error??"session deletion acknowledgement failed")}async applySessionDeletion(e){const t=new Ce({daemonInstallationId:u()});t.recordSession(e);for(const n of e.sources){const r=t.find(n.agentType,n.sourceSessionKey);r&&r.sessionId!==e.sessionId||t.record({...e,...n})}this.runJournal.markSessionAborted(e.sessionId),this.recoveryBarrier.end(e.sessionId);const s=this.sessions.get(e.sessionId);if(s){this.revokeManagedRoomToken(s);try{await s.adapter.stop()}catch{}this.sessions.delete(e.sessionId)}this.historySubscriptions.closeSession(e.sessionId),this.nativeFusion?.handleSessionDeleted(e.sessionId),this.chatQueue.purgeSession(e.sessionId),Me(e.sessionId),be(e.sessionId),Se(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 k())t.startsWith("custom:")&&I(t);const e=T();for(const[t,s]of Object.entries(e.customAgents??{}))fe(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");c(e.params),this.recoveryBarrier.isDispatchFrozen()||this.recoveryBarrier.isRecovering(String(e.params.sessionId??""))?n={durableQueueHandoff:await this.chatQueue.handleEnqueue({...e,method:"chat.enqueue"})}:await U(s,e);break;case"chat.enqueue":c(e.params),n={durableQueueHandoff:await this.chatQueue.handleEnqueue(e)};break;case"chat.queue.get":c(e.params),await this.chatQueue.handleGet(e);break;case"chat.queue.edit":c(e.params),await this.chatQueue.handleEdit(e);break;case"chat.queue.delete":c(e.params),await this.chatQueue.handleDelete(e);break;case"chat.queue.promote":c(e.params),await this.chatQueue.handlePromote(e);break;case"chat.abort":c(e.params),await B(s,e);break;case"session.refresh":c(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":J(s,e);break;case"session.tool.detail":await $(s,e);break;case"voice.session.body.window":V(s,e);break;case"session.title.set":await H(s,e);break;case"room.agent.bind-managed":await ve(s,this.managedRoomBinder,e);break;case"room.agent.restart-managed":await ye(s,this.managedRoomBinder,e);break;case"fs.ls":await Y(s,e);break;case"project.fs.open":case"project.fs.list":case"project.fs.read":case"project.fs.close":await ze(this.client,this.projectFsHandleStore,e,this.trustedProjectFsRequestResolver);break;case"fs.read":await K(s,e);break;case"fs.write":await Z(s,e);break;case"fs.export.markdown-pdf":await ae(s,e);break;case"fs.export.markdown-pdf.setup":await re(s,e);break;case"fs.archive.zip":await ne(s,e);break;case"fs.rename":await X(s,e);break;case"fs.transfer.start":await te(s,e);break;case"fs.transfer.chunk":await ee(s,e);break;case"fs.transfer.finish":await se(s,e);break;case"fs.transfer.abort":await q(s,e);break;case"region.probe":await ie(s,e);break;case"region.switch":await oe(s,e);break;case"upgrade.start":await P(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 C(this.client,e.id,{currentVersion:this.cliVersion});break;case"upgrade.set-policy":await ce(s,e);break;case"machine.remote-access.pause":await L(this.client,this.remoteAccessPauseController,e);break;case"agents.refresh":await M(s,e);break;case"agent.permission.respond":await We(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 $e(s,e);break;case"models.refresh":await D(s,e);break;case"agent.config.get":await _(s,e);break;case"agent.config.upsert":await j(s,e);break;case"agent.config.clear":await O(s,e);break;case"agent.config.test":await Q(s,e);break;case"agent.workspace.validate":await N(s,e);break;case"agent.capabilities.list":await F(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<Le)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 ge(e)}resolveAuthorizedPath(e,t){return pe(e,he(t))}async resolveAuthorizedPathAsync(e,t){return me(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(),G(this.getRuntime()),await this.managerRuntime.stop(),v(null)}revokeManagedRoomToken(e){const t=e.managedRoomContextToken;e.managedRoomContextToken=null,t&&this.managedRoomContextRevoker?.(t)}}export{Gs as SessionManager,Xs as resolveSessionWorkDir};
3
+ The task could not be recovered after the Shennian upgrade (${t.reason}). The session is preserved; retry or send a new message.`;ke(e.sessionId,{id:`upgrade-recovery-terminal-${e.runId}`,sessionId:e.sessionId,role:"agent",ts:Date.now(),payload:JSON.stringify({v:1,type:"error",content:r,error:!0,recoveryState:t.result,recoveryReason:t.reason})}),we({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:r}),Ie(this.client);const n=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:n,reason:t.reason}:{state:"recovery_failed",sessionId:e.sessionId,runId:e.providerRunId??e.runId,seq:n,reason:t.reason,...t.message?{message:t.message}:{}},seq:n,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 r=m().find(n=>n.sessionId===s.params.sessionId);return{context:s.context,params:{...s.params,modelId:r?.modelId??s.params.modelId,sessionMode:r?.sessionMode??s.params.sessionMode,managerConfig:r?.managerConfig??s.params.managerConfig,managerDefaultWorkerAgentType:r?.managerDefaultWorkerAgentType??s.params.managerDefaultWorkerAgentType,managerDefaultWorkerModelId:r?.managerDefaultWorkerModelId??s.params.managerDefaultWorkerModelId}}});await this.chatQueue.enqueueManagedRoomBatch(t)}async retireManagedRoomSession(e){this.chatQueue.purgeSession(e),await Re(this.getRuntime(),e)}discardPendingManagedRoomMessages(e){return this.chatQueue.discardPendingManagedRoomMessages(e)}async synchronizeSessionDeletions(){xe();try{await this.synchronizeSessionDeletionsOnce(),Ee()}catch(e){if(e instanceof Fe||e instanceof Oe)throw e;const t=e instanceof Error?e.message:String(e),s=/offline|not connected|disconnect|timed out|timeout|temporar|unavailable|ECONN|ENOTFOUND|EIO|EBUSY/i.test(t)?"transport_unavailable":/invalid (?:deletion sync|session deletion)|deletion revision gap/i.test(t)?"invalid_deletion_sync_response":"deletion_sync_failed";throw console.warn("[session.deletions] retrying failed synchronization",{code:s}),p({code:s,retryable:!0}),e}}async synchronizeSessionDeletionsOnce(){const e=u(),t=De(),s=await this.client.sendReq({type:"req",id:`session-deletions-sync-${h.randomUUID()}`,method:"session.deletions.sync",params:{protocolVersion:g,dataEpoch:f,daemonInstallationId:e,afterRevision:t}});if(!s.ok){const o=s.rejection;throw o?(p({code:o.code,retryable:o.retryable&&o.requiredAction==="retry"}),new Error(o.code)):(p({code:"unstructured_rejection",retryable:!0}),new Error(s.error??"unstructured_rejection"))}const r=s.payload;c(r),He(r,t);let n=r.baselineRevision;n>t&&y(n);for(const o of r.deletions)o.deletionRevision<=n||(await this.applySessionDeletion(o),n=o.deletionRevision,y(n));if(n!==r.latestRevision)throw new Error(`deletion revision gap: applied ${n}, latest ${r.latestRevision}`);if(n===0)return;const d=await this.client.sendReq({type:"req",id:`session-deletions-ack-${h.randomUUID()}`,method:"session.deletions.ack",params:{protocolVersion:g,dataEpoch:f,daemonInstallationId:e,deletionRevision:n}});if(!d.ok)throw new Error(d.error??"session deletion acknowledgement failed")}async applySessionDeletion(e){const t=new Ce({daemonInstallationId:u()});t.recordSession(e);for(const r of e.sources){const n=t.find(r.agentType,r.sourceSessionKey);n&&n.sessionId!==e.sessionId||t.record({...e,...r})}this.runJournal.markSessionAborted(e.sessionId),this.recoveryBarrier.end(e.sessionId);const s=this.sessions.get(e.sessionId);if(s){this.revokeManagedRoomToken(s);try{await s.adapter.stop()}catch{}this.sessions.delete(e.sessionId)}this.historySubscriptions.closeSession(e.sessionId),this.nativeFusion?.handleSessionDeleted(e.sessionId),this.chatQueue.purgeSession(e.sessionId),Me(e.sessionId),be(e.sessionId),Se(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 r=new Date().toISOString();this.publishSessionActivity(e,{sessionId:e,runId:s.runId||t.currentRunId,runPhase:s.runPhase,startedAt:new Date(t.lastActiveAt).toISOString(),updatedAt:r,canStop:s.canStop??!0});const n=t.heartbeatSeq++;this.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"heartbeat",sessionId:e,runId:s.runId||t.currentRunId,seq:n,runPhase:s.runPhase,canStop:s.canStop??!0},seq:n,id:`agent-status-${s.runId||t.currentRunId}-${Date.now()}`})}}reloadCustomAgents(){for(const t of k())t.startsWith("custom:")&&I(t);const e=T();for(const[t,s]of Object.entries(e.customAgents??{}))fe(t,s)}async handleReq(e,t={}){const s=this.getRuntime();let r;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");c(e.params),this.recoveryBarrier.isDispatchFrozen()||this.recoveryBarrier.isRecovering(String(e.params.sessionId??""))?r={durableQueueHandoff:await this.chatQueue.handleEnqueue({...e,method:"chat.enqueue"})}:await U(s,e);break;case"chat.enqueue":c(e.params),r={durableQueueHandoff:await this.chatQueue.handleEnqueue(e)};break;case"chat.queue.get":c(e.params),await this.chatQueue.handleGet(e);break;case"chat.queue.edit":c(e.params),await this.chatQueue.handleEdit(e);break;case"chat.queue.delete":c(e.params),await this.chatQueue.handleDelete(e);break;case"chat.queue.promote":c(e.params),await this.chatQueue.handlePromote(e);break;case"chat.abort":c(e.params),await B(s,e);break;case"session.refresh":c(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":J(s,e);break;case"session.tool.detail":await $(s,e);break;case"voice.session.body.window":V(s,e);break;case"session.title.set":await H(s,e);break;case"room.agent.bind-managed":await ve(s,this.managedRoomBinder,e);break;case"room.agent.restart-managed":await ye(s,this.managedRoomBinder,e);break;case"fs.ls":await Y(s,e);break;case"project.fs.open":case"project.fs.list":case"project.fs.read":case"project.fs.close":await ze(this.client,this.projectFsHandleStore,e,this.trustedProjectFsRequestResolver);break;case"fs.read":await K(s,e);break;case"fs.write":await Z(s,e);break;case"fs.export.markdown-pdf":await ae(s,e);break;case"fs.export.markdown-pdf.setup":await ne(s,e);break;case"fs.archive.zip":await re(s,e);break;case"fs.rename":await X(s,e);break;case"fs.transfer.start":await te(s,e);break;case"fs.transfer.chunk":await ee(s,e);break;case"fs.transfer.finish":await se(s,e);break;case"fs.transfer.abort":await q(s,e);break;case"region.probe":await ie(s,e);break;case"region.switch":await oe(s,e);break;case"upgrade.start":await P(this.client,e.id,e.params.version,{currentVersion:this.cliVersion,confirmedMajor:e.params.confirmedMajor===!0,prepareForUpgrade:n=>this.prepareForUpgrade(n),cancelUpgradePreparation:()=>this.cancelUpgradePreparation(),shutdownAfterHandoff:()=>{setTimeout(()=>process.kill(process.pid,"SIGTERM"),100).unref?.()}});break;case"upgrade.status":await C(this.client,e.id,{currentVersion:this.cliVersion});break;case"upgrade.set-policy":await ce(s,e);break;case"machine.remote-access.pause":await L(this.client,this.remoteAccessPauseController,e);break;case"agents.refresh":await M(s,e);break;case"agent.permission.respond":await We(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 $e(s,e);break;case"models.refresh":await D(s,e);break;case"agent.config.get":await _(s,e);break;case"agent.config.upsert":await j(s,e);break;case"agent.config.clear":await O(s,e);break;case"agent.config.test":await Q(s,e);break;case"agent.workspace.validate":await N(s,e);break;case"agent.capabilities.list":await F(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(n){if(t.propagateErrors)throw n;this.client.sendRes({type:"res",id:e.id,ok:!1,error:n instanceof Error?n.message:String(n)})}finally{this.activeRequests--}return r}evictIdleSessions(){if(this.sessions.size<Le)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 ge(e)}resolveAuthorizedPath(e,t){return me(e,he(t))}async resolveAuthorizedPathAsync(e,t){return pe(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(),G(this.getRuntime()),await this.managerRuntime.stop(),v(null)}revokeManagedRoomToken(e){const t=e.managedRoomContextToken;e.managedRoomContextToken=null,t&&this.managedRoomContextRevoker?.(t)}}export{Gs as SessionManager,Xs as resolveSessionWorkDir};
@@ -1,4 +1,4 @@
1
- import{listSessionRecords as p}from"./store.js";function x(n,r){return n?{roomOrigin:n.roomOrigin,allowedRoomActions:n.roomOrigin?["send"]:[],managerEvent:!0}:r?{allowedRoomActions:[]}:void 0}function I(n,r){const e=u(r);if(e)return n.find(i=>u(i)===e)??null;if(r.origin!=="external")return null;const t=f(r);return n.find(i=>f(i)===t)??null}function b(n){const{origin:r,managedRoom:e,managedAgentDirect:t,trigger:i,...a}=n;return a}function M(n){const r=n.reduce((o,g)=>{const l=s(g);return o===null||l<o?l:o},null);if(r===null)return[];const e=n.filter(o=>s(o)===r),t=e[0];if(!t)return[];if(d(t))return[t];if(t.trigger?.kind==="manager_worker"||t.trigger?.kind==="scheduled")return[t];const i=m(t),a=[];for(const o of e){if(m(o)!==i)break;a.push(o)}return a}function d(n){if(n.origin==="external"||n.origin==="room"||n.managedRoom)return!1;const r=n.trigger?.kind;return r==null||r==="personal"||r==="managed_direct"}function _(n){return n?.trim()||void 0}function D(n,r){const e=n.find(t=>t.id===r&&d(t));return e?[e]:[]}function s(n){const r=c(n).kind;return r==="personal"||r==="managed_direct"?0:r==="manager_event"||r==="manager_worker"?1:2}function c(n){const r=n.trigger;return r?r.kind==="room_activation"?{kind:r.kind,registryKey:r.registryKey}:r.kind==="manager_worker"?{kind:r.kind,parentSessionId:r.parentSessionId,roomOrigin:r.roomOrigin??null}:r.kind==="manager_event"?{kind:r.kind,roomOrigin:r.roomOrigin??null}:{kind:r.kind}:n.managedRoom?{kind:"room_activation",registryKey:n.managedRoom.registryKey}:n.managedAgentDirect?{kind:"managed_direct"}:{kind:"personal"}}function m(n){return JSON.stringify({agentType:n.agentType,sessionMode:n.sessionMode??null,workDir:n.workDir,agentSessionId:n.agentSessionId??null,modelId:_(n.modelId)??null,systemPrompt:n.systemPrompt??null,reasoningEffort:n.reasoningEffort??null,managerConfig:n.managerConfig??null,managerDefaultWorkerAgentType:n.managerDefaultWorkerAgentType??null,managerDefaultWorkerModelId:n.managerDefaultWorkerModelId??null,externalChannel:n.externalChannel??null,replyTarget:n.replyTarget??null,roomRegistryKey:n.managedRoom?.registryKey??null,trigger:c(n)})}function R(n){return n.every(r=>r.managedRoom)?`[\u7FA4\u6D88\u606F]
1
+ import{listSessionRecords as p}from"./store.js";function x(n,r){return n?{roomOrigin:n.roomOrigin,allowedRoomActions:n.roomOrigin?["send"]:[],managerEvent:!0}:r?{allowedRoomActions:[]}:void 0}function I(n,r){const e=u(r);if(e)return n.find(o=>u(o)===e)??null;if(r.origin!=="external")return null;const t=f(r);return n.find(o=>f(o)===t)??null}function b(n){const{origin:r,managedRoom:e,managedAgentDirect:t,trigger:o,externalQueuedSubmissionId:a,...i}=n;return i}function M(n){const r=n.reduce((i,g)=>{const l=s(g);return i===null||l<i?l:i},null);if(r===null)return[];const e=n.filter(i=>s(i)===r),t=e[0];if(!t)return[];if(d(t))return[t];if(t.trigger?.kind==="manager_worker"||t.trigger?.kind==="scheduled")return[t];const o=m(t),a=[];for(const i of e){if(m(i)!==o)break;a.push(i)}return a}function d(n){if(n.origin==="external"||n.origin==="room"||n.managedRoom)return!1;const r=n.trigger?.kind;return r==null||r==="personal"||r==="managed_direct"}function _(n){return n?.trim()||void 0}function S(n,r){const e=n.find(t=>t.id===r&&d(t));return e?[e]:[]}function s(n){const r=c(n).kind;return r==="personal"||r==="managed_direct"?0:r==="manager_event"||r==="manager_worker"?1:2}function c(n){const r=n.trigger;return r?r.kind==="room_activation"?{kind:r.kind,registryKey:r.registryKey}:r.kind==="manager_worker"?{kind:r.kind,parentSessionId:r.parentSessionId,roomOrigin:r.roomOrigin??null}:r.kind==="manager_event"?{kind:r.kind,roomOrigin:r.roomOrigin??null}:{kind:r.kind}:n.managedRoom?{kind:"room_activation",registryKey:n.managedRoom.registryKey}:n.managedAgentDirect?{kind:"managed_direct"}:{kind:"personal"}}function m(n){return JSON.stringify({agentType:n.agentType,sessionMode:n.sessionMode??null,workDir:n.workDir,agentSessionId:n.agentSessionId??null,modelId:_(n.modelId)??null,systemPrompt:n.systemPrompt??null,reasoningEffort:n.reasoningEffort??null,managerConfig:n.managerConfig??null,managerDefaultWorkerAgentType:n.managerDefaultWorkerAgentType??null,managerDefaultWorkerModelId:n.managerDefaultWorkerModelId??null,externalChannel:n.externalChannel??null,replyTarget:n.replyTarget??null,roomRegistryKey:n.managedRoom?.registryKey??null,trigger:c(n)})}function D(n){return n.every(r=>r.managedRoom)?`[\u7FA4\u6D88\u606F]
2
2
  ${n.map(r=>y(r.text)).filter(Boolean).join(`
3
3
 
4
4
  `)}`:`[\u8FDE\u7EED\u7528\u6237\u6D88\u606F]
@@ -8,4 +8,4 @@ ${r.text.trim()}`).join(`
8
8
  `)}`}function y(n){const r=n.trim(),e=r.match(/^\[群消息\][ \t]+<([^>\n]+)>\n([\s\S]*)$/);return e?`<${e[1]}>
9
9
  ${e[2]}`:r.startsWith(`[\u7FA4\u6D88\u606F]
10
10
  `)?r.slice(6):r}function f(n){const r=u(n);return r?`id:${r}`:["body",k(n.text),...(n.attachments??[]).map(e=>e.path||`${e.name}:${e.mimeType}`)].join(`
11
- `)}function u(n){const r=typeof n.clientMessageId=="string"?n.clientMessageId.trim():"";if(r)return r;const e=typeof n.id=="string"?n.id.trim():"";return e&&!e.startsWith("queue-")?e:""}function S(n){const r=new Set,e=[];for(const t of n){const i=t.path||`${t.name}:${t.mimeType}`;r.has(i)||(r.add(i),e.push(t))}return e.length?e:void 0}function k(n){return String(n||"").replace(/\s+/g," ").trim()}function $(n,r){const e=n.toLowerCase();if(e.includes("managed claim session conflicts with source binding"))return"managed_claim_source_binding_conflict";const t=e.match(/\b(?:managed_(?:agent|room)|agent_validation|acp|native)_[a-z0-9_]+\b/)?.[0];return t||(e.includes("no rollout found")?"missing_rollout":e.includes("managed_room_permission_snapshot_mismatch")?"managed_room_permission_snapshot_mismatch":e.includes("managed_room_prompt_snapshot_mismatch")?"managed_room_prompt_snapshot_mismatch":e.includes("managed_room_turn_preparer_unavailable")?"managed_room_turn_preparer_unavailable":e.includes("timeout")?"timeout":e.includes("connection")?"connection_error":r)}function v(n,r){if(n.sessions.has(r.sessionId))return null;const e=p().find(t=>t.sessionId===r.sessionId)?.agentSessionId?.trim();return!e||e.startsWith("managed:")?null:e}export{$ as classifyQueueError,S as dedupeQueuedAttachments,I as findDuplicateQueuedMessage,R as formatQueuedBatch,d as isControllableQueueMessage,x as managedDirectTurnOptions,_ as normalizeQueuedModelId,v as resolveManagedRoomNativeSessionId,b as stripLocalQueueFields,M as takeCompatibleBatch,D as takeControllableMessage};
11
+ `)}function u(n){const r=typeof n.clientMessageId=="string"?n.clientMessageId.trim():"";if(r)return r;const e=typeof n.id=="string"?n.id.trim():"";return e&&!e.startsWith("queue-")?e:""}function R(n){const r=new Set,e=[];for(const t of n){const o=t.path||`${t.name}:${t.mimeType}`;r.has(o)||(r.add(o),e.push(t))}return e.length?e:void 0}function k(n){return String(n||"").replace(/\s+/g," ").trim()}function $(n,r){const e=n.toLowerCase();if(e.includes("managed claim session conflicts with source binding"))return"managed_claim_source_binding_conflict";const t=e.match(/\b(?:managed_(?:agent|room)|agent_validation|acp|native)_[a-z0-9_]+\b/)?.[0];return t||(e.includes("no rollout found")?"missing_rollout":e.includes("managed_room_permission_snapshot_mismatch")?"managed_room_permission_snapshot_mismatch":e.includes("managed_room_prompt_snapshot_mismatch")?"managed_room_prompt_snapshot_mismatch":e.includes("managed_room_turn_preparer_unavailable")?"managed_room_turn_preparer_unavailable":e.includes("timeout")?"timeout":e.includes("connection")?"connection_error":r)}function v(n,r){if(n.sessions.has(r.sessionId))return null;const e=p().find(t=>t.sessionId===r.sessionId)?.agentSessionId?.trim();return!e||e.startsWith("managed:")?null:e}export{$ as classifyQueueError,R as dedupeQueuedAttachments,I as findDuplicateQueuedMessage,D as formatQueuedBatch,d as isControllableQueueMessage,x as managedDirectTurnOptions,_ as normalizeQueuedModelId,v as resolveManagedRoomNativeSessionId,b as stripLocalQueueFields,M as takeCompatibleBatch,S as takeControllableMessage};
@@ -7,6 +7,8 @@ export type LocalQueuedChatMessage = QueuedChatMessage & {
7
7
  /** Legacy persisted fields remain readable until all v1 queue files drain. */
8
8
  managedRoom?: ManagedRoomTriggerContext;
9
9
  managedAgentDirect?: true;
10
+ /** Codex accepted this item into an externally-owned native queue. */
11
+ externalQueuedSubmissionId?: string;
10
12
  };
11
13
  export type InternalEnqueueParams = ChatEnqueueParams & {
12
14
  managedWorkerParentSessionId?: string;
@@ -29,11 +29,15 @@ export declare class ChatQueueManager {
29
29
  getRuntime: () => SessionManagerRuntime;
30
30
  dispatchReq: LocalReqDispatcher;
31
31
  dispatchManagedReq?: (req: ReqFrame, prepared: PreparedManagedRoomTurn) => Promise<void>;
32
- dispatchQueuedReq: (req: ReqFrame, prepared?: PreparedManagedRoomTurn) => Promise<void>;
32
+ dispatchQueuedReq: (req: ReqFrame, prepared?: PreparedManagedRoomTurn) => Promise<void | {
33
+ deliveryMode?: string;
34
+ queuedSubmissionId?: string;
35
+ }>;
33
36
  interruptQueuedSession?: (sessionId: string) => Promise<void>;
34
37
  });
35
38
  stop(): void;
36
39
  getSnapshot(sessionId: string): ChatQueueSnapshot;
40
+ private isImmediateSendAvailable;
37
41
  setManagedRoomTurnPreparer(prepare: (contexts: ManagedRoomQueueContext[]) => Promise<PreparedManagedRoomTurn>): void;
38
42
  setManagedAgentDirectTurnPreparer(prepare: ManagedAgentDirectTurnPreparer): void;
39
43
  enqueueManagedRoomBatch(inputs: Array<{
@@ -57,10 +61,12 @@ export declare class ChatQueueManager {
57
61
  private wakeSession;
58
62
  private drainIdleQueues;
59
63
  private drainNext;
64
+ noteExternalClaim(sessionId: string, canonicalMessageId: string): void;
60
65
  private canInjectActiveBatch;
61
66
  private removeBatch;
62
67
  private logLifecycle;
63
68
  private dispatchQueuedMessages;
69
+ private markExternalQueued;
64
70
  private isSessionBusy;
65
71
  private broadcast;
66
72
  }
@@ -1 +1 @@
1
- import{NativeSourceDeletionStore as U}from"../native-fusion/native-source-deletions.js";import{QueueRetryScheduler as V}from"./queue-retry.js";import{findDuplicateQueuedMessage as P,stripLocalQueueFields as T,takeCompatibleBatch as X,formatQueuedBatch as B,dedupeQueuedAttachments as Q,classifyQueueError as F,isControllableQueueMessage as C,takeControllableMessage as Y,normalizeQueuedModelId as W,resolveManagedRoomNativeSessionId as q,managedDirectTurnOptions as b}from"./queue-helpers.js";import{CODEX_DESKTOP_SEND_UNAVAILABLE as Z}from"@shennian/wire";import{isCodexThreadTailInterrupted as ee}from"../native-fusion/codex-files.js";import{mergeProjectedSessions as te}from"./projection.js";import{assertFinishedAttachmentReferences as L,markAttachmentReferences as O}from"./attachment-transfer-store.js";import{appendMessage as j,getMessageDeliveryStatus as _,listSessionRecords as N,recordSession as z,tombstoneMessage as $,upsertMessage as x}from"./store.js";import{requestSessionIndexPublish as w}from"./index-publisher.js";import{clearPersistedManagerRoomOrigins as se,purgeQueuedSessionData as ne,readQueue as m,writeQueue as S}from"./queue-storage.js";import{getNativeSourceAgentType as ie}from"./handlers/chat-events.js";import{parsePersonalAttachmentReferences as K}from"./attachment-reference.js";import{getPersonalSyncIdentity as A}from"../personal-sync/epoch.js";import{getDaemonInstallationId as E}from"../personal-sync/identity.js";import{isTrustedManagerEvent as ae}from"./manager-event-authority.js";import{TerminalQueuedChatDispatchError as v,nowIso as J,queueEnvelope as R,queueMessageFromParams as G}from"./queue-message.js";import{purgeQueuedSessionData as De}from"./queue-storage.js";import{TerminalQueuedChatDispatchError as Ce}from"./queue-message.js";class Re{opts;validateScheduledTarget;async enqueueScheduled(e){return this.handleEnqueue(e,!0)}draining=new Set;promoting=new Set;disposed=!1;retries=new V(e=>{this.wakeSession(e)});deletions=new U;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){const s=m().sessions[e]??[],t=this.inFlightMessageIds.get(e);return{...A(E()),sessionId:e,busy:!!this.opts.getRuntime().sessions.get(e)?.currentRunId,pending:s.map(T),controllablePending:s.filter(n=>C(n)&&!t?.has(n.id)).map(T)}}setManagedRoomTurnPreparer(e){this.prepareManagedRoomTurn=e}setManagedAgentDirectTurnPreparer(e){this.prepareManagedAgentDirectTurn=e}async enqueueManagedRoomBatch(e){if(e.length===0)return;const s=this.opts.getRuntime(),t=m(),n=new Set,i=new Map;let d=!1;for(const o of e){const a=o.params;if(this.deletions.hasSession(a.sessionId)){delete t.sessions[a.sessionId],d=!0;continue}if(!a.sessionId||!a.text||!a.agentType||!a.workDir)throw new Error("sessionId, text, agentType and workDir are required");const u=G({...A(E()),...a});u.origin="room",u.managedRoom=o.context,u.trigger={kind:"room_activation",...o.context};const c=t.sessions[a.sessionId]??[],g=P(c,u),M=u.clientMessageId??u.id,k=_(a.sessionId,M);if(!g&&k.state==="not_found")c.push(u),t.sessions[a.sessionId]=c,i.set(`${u.sessionId}\0${M}`,u),n.add(a.sessionId),d=!0;else if(g&&k.state==="not_found")i.set(`${g.sessionId}\0${M}`,g),n.add(a.sessionId);else if(g&&k.state==="queued")n.add(a.sessionId);else if(g){const I=c.filter(y=>y.id!==g.id);I.length?t.sessions[a.sessionId]=I:delete t.sessions[a.sessionId],d=!0}}d&&S(t);let r;for(const o of n)try{for(const a of i.values())a.sessionId===o&&(j(o,R(a),"queued"),z({sessionId:o,agentType:a.agentType,sessionMode:a.sessionMode,managerConfig:a.managerConfig,workDir:a.workDir,agentSessionId:q(s,a),modelId:a.modelId}));this.logLifecycle("enqueue.persisted",o,{origin:"room",pendingCount:m().sessions[o]?.length??0}),this.broadcast(o),this.wakeSession(o)}catch(a){r=a,this.logLifecycle("enqueue.commit-failed",o,{failureClass:F(a instanceof Error?a.message:"","canonical_commit_failed")},"error"),this.retries.schedule(o,!0)}if(n.size&&w(s.client),r)throw r}async handleEnqueue(e,s=!1){const t=this.opts.getRuntime(),n=e.params;if(n.scheduledTask&&!s)throw new Error("schedule_source_untrusted");if((n.managerEventId||n.managerEventRoomOrigin||n.managedWorkerParentSessionId||n.managerWorkerRoomOrigin||e.params.managerWorkerNativeFull||e.params.managedRecoverySource)&&!ae(e))throw new Error("manager_event_source_untrusted");const i=!!(s&&n.scheduledTask?.bindingId);if(te(n.sessionListProjection),!n.sessionId||!n.text||!n.agentType||!n.workDir)return t.client.sendRes({type:"res",id:e.id,ok:!1,error:"sessionId, text, agentType and workDir are required"}),!1;const d=b(n.managerEventId?{roomOrigin:n.managerEventRoomOrigin}:null,!!n.managedAgentDirect),r=n.managedAgentDirect||i?await this.prepareManagedAgentDirectTurn?.(n.sessionId,d):null;if((n.managedAgentDirect||i)&&!r)throw new Error("managed_agent_context_unavailable");const o=r?N().find(H=>H.sessionId===n.sessionId):null,a=r?{...n,...r,agentType:r.agentType,sessionMode:r.sessionMode,managerConfig:r.managerConfig,workDir:r.workDir,agentSessionId:r.agentSessionId?.startsWith("managed:")?o?.agentSessionId&&!o.agentSessionId.startsWith("managed:")?o.agentSessionId:null:r.agentSessionId,modelId:o?.modelId??void 0,systemPrompt:r.systemPrompt,externalChannel:n.managedAgentDirect?null:n.externalChannel,replyTarget:n.managedAgentDirect?null:n.replyTarget,managerDefaultWorkerAgentType:r.managerDefaultWorkerAgentType,managerDefaultWorkerModelId:r.managerDefaultWorkerModelId}:n,u=t.resolvePath(a.workDir),c=K(a.attachments);c?.length&&L(u,c);const g={text:a.text,attachments:c,localized:!1},M=t.sessions.get(a.sessionId);if(a.agentType==="codex"&&a.agentSessionId&&M?.currentRunId?.startsWith("dispatch:")&&ee(a.agentSessionId))return t.client.sendRes({type:"res",id:e.id,ok:!1,error:Z}),!1;r?.managedRoomContextToken&&t.revokeManagedRoomContextToken?.(r.managedRoomContextToken);const k=await this.isSessionBusy(a.sessionId),I=m(),y=I.sessions[a.sessionId]??[],h=G({...a,text:g.text,attachments:g.attachments,systemPrompt:r?null:a.systemPrompt});r&&(n.managedAgentDirect&&(h.managedAgentDirect=!0),h.trigger?.kind!=="manager_event"&&h.trigger?.kind!=="scheduled"&&(h.trigger={kind:"managed_direct"}));const D=h.clientMessageId??h.id,l=_(a.sessionId,D);if(l.state!=="not_found")return t.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queued:l.state==="queued",queueMessageId:h.id,...l,queue:this.getSnapshot(a.sessionId)}}),!0;const f=P(y,h);f||(I.sessions[a.sessionId]=[...y,h],S(I));const p=f??h;return z({sessionId:p.sessionId,agentType:p.agentType,sessionMode:p.sessionMode,managerConfig:p.managerConfig,workDir:p.workDir,agentSessionId:p.agentSessionId,modelId:p.modelId}),j(p.sessionId,R(p),"queued"),O(t.resolvePath(p.workDir),p.attachments??[]),w(t.client),this.logLifecycle("enqueue.persisted",a.sessionId,{origin:a.origin??"app",queueMessageId:p.id,pendingCount:(m().sessions[a.sessionId]??[]).length}),this.broadcast(a.sessionId),t.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queued:!0,queueMessageId:f?.id??h.id,..._(a.sessionId,f?.clientMessageId??f?.id??h.clientMessageId??h.id),queue:this.getSnapshot(a.sessionId),...g.localized?{localizedAttachments:!0}:{}}}),k?this.retries.schedule(a.sessionId):this.wakeSession(a.sessionId),!0}async handleGet(e){const s=this.opts.getRuntime(),t=e.params;if(!t.sessionId){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"sessionId is required"});return}s.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queue:this.getSnapshot(t.sessionId)}})}async handleEdit(e){const s=this.opts.getRuntime(),t=e.params;if(!t.sessionId||!t.queueMessageId||!t.text){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"sessionId, queueMessageId and text are required"});return}const n=m(),i=n.sessions[t.sessionId]??[],d=i.findIndex(a=>a.id===t.queueMessageId);if(d<0){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"Queued message not found"});return}if(!C(i[d])||this.inFlightMessageIds.get(t.sessionId)?.has(t.queueMessageId)){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"managed_agent_queue_mutation_forbidden"});return}const r=K(t.attachments),o=s.resolvePath(i[d].workDir);r?.length&&L(o,r),i[d]={...i[d],text:t.text,attachments:r,updatedAt:J()},n.sessions[t.sessionId]=i,S(n),x(t.sessionId,R(i[d]),"queued"),i[d].attachments?.length&&O(o,i[d].attachments??[]),w(s.client),this.broadcast(t.sessionId),s.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queue:this.getSnapshot(t.sessionId)}})}async handleDelete(e){const s=this.opts.getRuntime(),t=e.params;if(!t.sessionId||!t.queueMessageId){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"sessionId and queueMessageId are required"});return}const n=m(),i=n.sessions[t.sessionId]??[],d=i.find(o=>o.id===t.queueMessageId);if(d&&(!C(d)||this.inFlightMessageIds.get(t.sessionId)?.has(t.queueMessageId))){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"managed_agent_queue_mutation_forbidden"});return}const r=i.filter(o=>o.id!==t.queueMessageId);if(r.length===i.length){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"Queued message not found"});return}r.length?n.sessions[t.sessionId]=r:delete n.sessions[t.sessionId],S(n),$(t.sessionId,d?.clientMessageId??d?.id??t.queueMessageId),w(s.client),this.broadcast(t.sessionId),s.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queue:this.getSnapshot(t.sessionId)}})}async handlePromote(e){const s=this.opts.getRuntime(),t=e.params,n=d=>s.client.sendRes({type:"res",id:e.id,ok:!1,error:d});if(!t.sessionId||!t.queueMessageId){n("sessionId and queueMessageId are required");return}if(this.promoting.has(t.sessionId)){n("queue_promotion_in_progress");return}this.promoting.add(t.sessionId);let i=[];try{for(;this.draining.has(t.sessionId);)await new Promise(o=>setTimeout(o,5));if(i=Y(m().sessions[t.sessionId]??[],t.queueMessageId),!i.length){n("Queued message not found");return}this.inFlightMessageIds.set(t.sessionId,new Set(i.map(o=>o.id)));const d=s.sessions.get(t.sessionId);let r="idle";if(d?.currentRunId)if(this.canInjectActiveBatch(d,i)){const o=i.length===1?i[0].text:B(i),a=i[0].clientMessageId??i[0].id;s.nativeFusion?.registerManagedSend({sessionId:t.sessionId,agentType:i[0].agentType,sourceAgentType:ie(i[0].agentType,i[0].modelId),canonicalMessageId:a,sourceSessionKey:d.agentSessionId,text:o,managedEchoPolicy:"suppress_following"});const u=Date.now();try{await d.adapter.injectActiveInput({text:o,attachments:Q(i.flatMap(c=>c.attachments??[])),clientMessageId:a})}catch(c){throw s.nativeFusion?.cancelManagedSend(a),c}for(const c of i)x(t.sessionId,{...R(c),ts:u},"executing");this.removeBatch(t.sessionId,i),r="injected"}else{if(!this.opts.interruptQueuedSession)throw new Error("queue_interrupt_unavailable");await this.opts.interruptQueuedSession(t.sessionId),await this.dispatchQueuedMessages(i),this.removeBatch(t.sessionId,i),r="restarted"}else await this.dispatchQueuedMessages(i),this.removeBatch(t.sessionId,i);w(s.client),this.broadcast(t.sessionId),s.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queue:this.getSnapshot(t.sessionId),promotedMessageIds:i.map(o=>o.id),mode:r}})}catch(d){n(d instanceof Error?d.message:"queue_promotion_failed"),this.broadcast(t.sessionId)}finally{this.inFlightMessageIds.delete(t.sessionId),this.promoting.delete(t.sessionId),m().sessions[t.sessionId]?.length&&this.wakeSession(t.sessionId)}}noteTerminal(e){this.wakeSession(e)}purgeSession(e){ne(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 s=m(),t=s.sessions[e]??[],n=this.inFlightMessageIds.get(e)??new Set,i=t.filter(r=>r.managedRoom&&!n.has(r.id));if(i.length===0)return 0;const d=t.filter(r=>!i.includes(r));d.length?s.sessions[e]=d:delete s.sessions[e],S(s);for(const r of i)$(e,r.clientMessageId??r.id);return w(this.opts.getRuntime().client),this.logLifecycle("managed-room.discarded-paused",e,{discardedCount:i.length,pendingCount:d.length}),this.broadcast(e),i.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 s of Object.keys(e.sessions))this.wakeSession(s)}async drainNext(e){if(this.disposed||this.draining.has(e)||this.promoting.has(e))return;this.draining.add(e);let s=!1,t=!1,n=[];try{if(this.deletions.hasSession(e)){this.purgeSession(e);return}if(await this.isSessionBusy(e)){const u=m().sessions[e]?.length??0,c=this.deferredLogState.get(e),g=Date.now();(!c||c.pendingCount!==u||g-c.at>=3e4)&&(this.logLifecycle("drain.deferred",e,{pendingCount:u}),this.deferredLogState.set(e,{at:g,pendingCount:u}));return}this.deferredLogState.delete(e);const i=m(),d=i.sessions[e]??[],r=d.filter(u=>{const c=u.clientMessageId??u.id,g=_(e,c).state;return g==="queued"||g==="not_found"});r.length!==d.length&&(r.length?i.sessions[e]=r:delete i.sessions[e],S(i),this.logLifecycle("drain.pruned-terminal",e,{prunedCount:d.length-r.length,pendingCount:r.length}));const o=X(r);if(o.length===0){this.broadcast(e);return}n=o,this.inFlightMessageIds.set(e,new Set(o.map(u=>u.id))),this.logLifecycle("dispatch.start",e,{batchCount:o.length,queueMessageId:o[0].id,origin:o[0].origin??"app"});for(const u of o)x(e,R(u),"queued");await this.dispatchQueuedMessages(o);const a=this.removeBatch(e,o);this.logLifecycle("dispatch.accepted",e,{batchCount:o.length,queueMessageId:o[0].id,pendingCount:a}),this.deferredLogState.delete(e),s=a>0,this.broadcast(e)}catch(i){const d=F(i instanceof Error?i.message:String(i),i instanceof v?"terminal_dispatch_failed":"transient_dispatch_failed"),r=n[0],o=!!(r&&!r.trigger&&!r.clientMessageId&&Date.now()-Date.parse(r.createdAt)>=10*6e4&&this.opts.getRuntime().managerRuntime?.isManagedWorkerSession(e));if(i instanceof v||d==="managed_claim_source_binding_conflict"||o){const u=this.removeBatch(e,n);this.logLifecycle("dispatch.terminal-failure",e,{batchCount:n.length,queueMessageId:n[0]?.id,pendingCount:u,failureClass:o?"stale_legacy_managed_worker_dispatch_failure":d},"error"),s=u>0}else t=!0,this.logLifecycle("dispatch.transient-failure",e,{failureClass:d},"error");this.broadcast(e)}finally{this.inFlightMessageIds.delete(e),this.draining.delete(e),m().sessions[e]?.length?s?queueMicrotask(()=>this.wakeSession(e)):this.retries.schedule(e,t):this.retries.cancel(e)}}canInjectActiveBatch(e,s){if(!e.adapter.supportsActiveInput||!e.adapter.injectActiveInput||!e.journalRunId)return!1;const t=this.opts.getRuntime().runJournal?.get(s[0].sessionId,e.journalRunId),n=s[0].trigger?.kind==="managed_direct"||s[0].managedAgentDirect?null:"personal";return!!(n&&s[0].systemPrompt==null&&t&&t.source===n&&t.deliveryMode==="direct"&&t.agentType===s[0].agentType&&t.workDir===e.workDir&&t.agentSessionId===e.agentSessionId&&t.modelId===(s[0].modelId??null)&&t.reasoningEffort===(s[0].reasoningEffort??null))}removeBatch(e,s){if(s.length===0)return m().sessions[e]?.length??0;const t=m(),n=new Set(s.map(d=>d.id)),i=(t.sessions[e]??[]).filter(d=>!n.has(d.id));return i.length?t.sessions[e]=i:delete t.sessions[e],S(t),i.length}logLifecycle(e,s,t,n="info"){const i=`[chat.queue] ${JSON.stringify({at:J(),event:e,sessionId:s,...t})}`;n==="error"?console.error(i):console.info(i)}async dispatchQueuedMessages(e){const s=e[0],t=s.trigger?.kind==="scheduled"?s.trigger:null;if(t&&await this.validateScheduledTarget?.({sessionId:s.sessionId,...t})!=="ready")throw new v("schedule_target_unavailable");const n=e.flatMap(l=>{if(l.trigger?.kind==="room_activation"){const{kind:f,...p}=l.trigger;return[p]}return!l.trigger&&l.managedRoom?[l.managedRoom]:[]}),i=e.find(l=>l.trigger?.kind==="manager_event")?.trigger,d=e.some(l=>l.trigger?.kind==="managed_direct"||!!l.managedAgentDirect),r=d||!!t?.bindingId,o=e.find(l=>l.trigger?.kind==="manager_worker")?.trigger,a=i?.kind==="manager_event"||d,u=n.length>0?await this.prepareManagedRoomTurn?.(n):r||i?.kind==="manager_event"?await this.prepareManagedAgentDirectTurn?.(s.sessionId,b(i?.kind==="manager_event"?i:null,d)):void 0;if(n.length>0&&!u)throw new Error("managed_room_turn_preparer_unavailable");if(r&&!u)throw new Error("managed_agent_context_unavailable");if(i?.kind==="manager_event"&&this.opts.getRuntime().managerRuntime?.isManagedRoomBoundManager(s.sessionId)&&!u)throw new Error("managed_agent_context_unavailable");const c=new Set((m().sessions[s.sessionId]??[]).map(l=>l.id));if(this.disposed||this.deletions.hasSession(s.sessionId)||e.some(l=>!c.has(l.id)))throw u?.managedRoomContextToken&&this.opts.getRuntime().revokeManagedRoomContextToken?.(u.managedRoomContextToken),this.disposed?new Error("queue_stopped"):new v("queued_dispatch_cancelled");const g=u??null,M=g?.sessionMode==="manager"?g.managerConfig:null,k=e.length===1?s.text:B(e),I=Q(e.flatMap(l=>l.attachments??[])),y=r||i?.kind==="manager_event"&&!!u,h=y?u.agentSessionId?.startsWith("managed:")?q(this.opts.getRuntime(),s):u.agentSessionId:n.length>0?q(this.opts.getRuntime(),s):s.agentSessionId??null,D=u?N().find(l=>l.sessionId===s.sessionId):null;await this.opts.dispatchQueuedReq({type:"req",id:`queue-send-${s.id}-${Date.now()}`,method:"chat.send",params:{...A(E()),sessionId:s.sessionId,text:k,agentType:y?u.agentType:s.agentType,sessionMode:g?.sessionMode??s.sessionMode,managerConfig:g?M:s.managerConfig,workDir:y?u.workDir:s.workDir,agentSessionId:h,modelId:W(D?.modelId)??W(s.modelId),systemPrompt:u?.systemPrompt??s.systemPrompt??null,managerDefaultWorkerAgentType:g?g.managerDefaultWorkerAgentType:s.managerDefaultWorkerAgentType,managerDefaultWorkerModelId:g?g.managerDefaultWorkerModelId:s.managerDefaultWorkerModelId,reasoningEffort:s.reasoningEffort??void 0,clientMessageId:s.clientMessageId??s.id,attachments:I,externalChannel:a?void 0:s.externalChannel,replyTarget:a?void 0:s.replyTarget,roomContextRegistryKey:a?void 0:u?.roomContextRegistryKey,activationCauseMessageId:a?void 0:n.at(-1)?.causeMessageId,rootCauseMessageId:a?void 0:n.at(-1)?.rootCauseMessageId,activationSequence:a?void 0:n.at(-1)?.sequence,activationHopCount:a?void 0:n.at(-1)?.hopCount,managedRecoverySource:i?.kind==="manager_event"?"manager_event":r?"managed_direct":n.length>0?"managed_room":void 0,managerEventId:i?.kind==="manager_event"?i.eventId:void 0,managedWorkerParentSessionId:o?.kind==="manager_worker"?o.parentSessionId:void 0,managerWorkerRoomOrigin:o?.kind==="manager_worker"?o.roomOrigin:void 0,managerWorkerNativeFull:o?.kind==="manager_worker"&&this.opts.getRuntime().managerRuntime?.isNativeSkillManager(o.parentSessionId,s.workDir)||void 0,managedRoomContextToken:u?.managedRoomContextToken,scheduledDelivery:!!t,suppressExternalOwnerEcho:n.length>0||!!t||void 0,queuedBatchItems:e.map(l=>{const f=T(l);return a?{...f,systemPrompt:u?.systemPrompt??null,externalChannel:null,replyTarget:null}:f}),waitForDispatch:!0}},u??void 0)}async isSessionBusy(e){const s=this.opts.getRuntime().recoveryBarrier;if(s?.isDispatchFrozen()||s?.isRecovering(e))return!0;const t=this.opts.getRuntime().sessions.get(e);if(!t)return!1;if(t.currentRunId){if(!(t.currentRunId.startsWith("dispatch:")&&!!this.opts.getRuntime().runJournal&&!t.journalRunId)||(t.adapter.getStatus?await t.adapter.getStatus().catch(()=>null):null)?.active)return!0;this.logLifecycle("drain.recovered-stale-dispatch",e,{staleRunId:t.currentRunId}),t.currentRunId=null,t.currentRunPhase=null}if(!t.adapter.getStatus)return!1;const n=await t.adapter.getStatus().catch(()=>null);return n?.active?(n.runId&&(t.currentRunId=n.runId,t.currentRunPhase=n.runPhase??t.currentRunPhase),!0):!1}broadcast(e){this.opts.getRuntime().client.sendEvent({type:"event",event:"session.queue.update",payload:{queue:this.getSnapshot(e)}})}}export{Re as ChatQueueManager,Ce as TerminalQueuedChatDispatchError,De as purgeQueuedSessionData};
1
+ import{NativeSourceDeletionStore as U}from"../native-fusion/native-source-deletions.js";import{QueueRetryScheduler as V}from"./queue-retry.js";import{findDuplicateQueuedMessage as Q,stripLocalQueueFields as _,takeCompatibleBatch as X,formatQueuedBatch as P,dedupeQueuedAttachments as B,classifyQueueError as W,isControllableQueueMessage as v,takeControllableMessage as Y,normalizeQueuedModelId as F,resolveManagedRoomNativeSessionId as T,managedDirectTurnOptions as L}from"./queue-helpers.js";import{CODEX_DESKTOP_SEND_UNAVAILABLE as Z}from"@shennian/wire";import{isCodexThreadTailInterrupted as ee}from"../native-fusion/codex-files.js";import{mergeProjectedSessions as te}from"./projection.js";import{assertFinishedAttachmentReferences as j,markAttachmentReferences as O}from"./attachment-transfer-store.js";import{appendMessage as N,getMessageDeliveryStatus as x,listSessionRecords as z,recordSession as $,tombstoneMessage as J,upsertMessage as C}from"./store.js";import{requestSessionIndexPublish as w}from"./index-publisher.js";import{clearPersistedManagerRoomOrigins as se,purgeQueuedSessionData as ne,readQueue as m,writeQueue as y}from"./queue-storage.js";import{getNativeSourceAgentType as ie}from"./handlers/chat-events.js";import{parsePersonalAttachmentReferences as K}from"./attachment-reference.js";import{getPersonalSyncIdentity as b}from"../personal-sync/epoch.js";import{getDaemonInstallationId as E}from"../personal-sync/identity.js";import{isTrustedManagerEvent as ae}from"./manager-event-authority.js";import{TerminalQueuedChatDispatchError as D,nowIso as A,queueEnvelope as R,queueMessageFromParams as G}from"./queue-message.js";import{purgeQueuedSessionData as xe}from"./queue-storage.js";import{TerminalQueuedChatDispatchError as qe}from"./queue-message.js";class Re{opts;validateScheduledTarget;async enqueueScheduled(e){return this.handleEnqueue(e,!0)}draining=new Set;promoting=new Set;disposed=!1;retries=new V(e=>{this.wakeSession(e)});deletions=new U;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){const s=m().sessions[e]??[],t=this.inFlightMessageIds.get(e),i=this.isImmediateSendAvailable(e),n=s.filter(a=>v(a)).map(a=>({..._(a),pendingState:a.externalQueuedSubmissionId?"provider_queued":t?.has(a.id)?"submitting":"waiting",canDelete:!a.externalQueuedSubmissionId&&!t?.has(a.id),canPromote:!a.externalQueuedSubmissionId&&!t?.has(a.id)&&i}));return{...b(E()),sessionId:e,busy:!!this.opts.getRuntime().sessions.get(e)?.currentRunId,pending:s.map(_),controllablePending:s.filter(a=>v(a)&&!a.externalQueuedSubmissionId&&!t?.has(a.id)).map(_),visiblePending:n}}isImmediateSendAvailable(e){const s=this.opts.getRuntime(),t=s.sessions.get(e);return t?.currentRunId?t.journalRunId?s.runJournal?.get(e,t.journalRunId)?.deliveryMode==="direct":!1:!0}setManagedRoomTurnPreparer(e){this.prepareManagedRoomTurn=e}setManagedAgentDirectTurnPreparer(e){this.prepareManagedAgentDirectTurn=e}async enqueueManagedRoomBatch(e){if(e.length===0)return;const s=this.opts.getRuntime(),t=m(),i=new Set,n=new Map;let a=!1;for(const d of e){const r=d.params;if(this.deletions.hasSession(r.sessionId)){delete t.sessions[r.sessionId],a=!0;continue}if(!r.sessionId||!r.text||!r.agentType||!r.workDir)throw new Error("sessionId, text, agentType and workDir are required");const u=G({...b(E()),...r});u.origin="room",u.managedRoom=d.context,u.trigger={kind:"room_activation",...d.context};const l=t.sessions[r.sessionId]??[],g=Q(l,u),f=u.clientMessageId??u.id,k=x(r.sessionId,f);if(!g&&k.state==="not_found")l.push(u),t.sessions[r.sessionId]=l,n.set(`${u.sessionId}\0${f}`,u),i.add(r.sessionId),a=!0;else if(g&&k.state==="not_found")n.set(`${g.sessionId}\0${f}`,g),i.add(r.sessionId);else if(g&&k.state==="queued")i.add(r.sessionId);else if(g){const M=l.filter(S=>S.id!==g.id);M.length?t.sessions[r.sessionId]=M:delete t.sessions[r.sessionId],a=!0}}a&&y(t);let o;for(const d of i)try{for(const r of n.values())r.sessionId===d&&(N(d,R(r),"queued"),$({sessionId:d,agentType:r.agentType,sessionMode:r.sessionMode,managerConfig:r.managerConfig,workDir:r.workDir,agentSessionId:T(s,r),modelId:r.modelId}));this.logLifecycle("enqueue.persisted",d,{origin:"room",pendingCount:m().sessions[d]?.length??0}),this.broadcast(d),this.wakeSession(d)}catch(r){o=r,this.logLifecycle("enqueue.commit-failed",d,{failureClass:W(r instanceof Error?r.message:"","canonical_commit_failed")},"error"),this.retries.schedule(d,!0)}if(i.size&&w(s.client),o)throw o}async handleEnqueue(e,s=!1){const t=this.opts.getRuntime(),i=e.params;if(i.scheduledTask&&!s)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 n=!!(s&&i.scheduledTask?.bindingId);if(te(i.sessionListProjection),!i.sessionId||!i.text||!i.agentType||!i.workDir)return t.client.sendRes({type:"res",id:e.id,ok:!1,error:"sessionId, text, agentType and workDir are required"}),!1;const a=L(i.managerEventId?{roomOrigin:i.managerEventRoomOrigin}:null,!!i.managedAgentDirect),o=i.managedAgentDirect||n?await this.prepareManagedAgentDirectTurn?.(i.sessionId,a):null;if((i.managedAgentDirect||n)&&!o)throw new Error("managed_agent_context_unavailable");const d=o?z().find(H=>H.sessionId===i.sessionId):null,r=o?{...i,...o,agentType:o.agentType,sessionMode:o.sessionMode,managerConfig:o.managerConfig,workDir:o.workDir,agentSessionId:o.agentSessionId?.startsWith("managed:")?d?.agentSessionId&&!d.agentSessionId.startsWith("managed:")?d.agentSessionId:null:o.agentSessionId,modelId:d?.modelId??void 0,systemPrompt:o.systemPrompt,externalChannel:i.managedAgentDirect?null:i.externalChannel,replyTarget:i.managedAgentDirect?null:i.replyTarget,managerDefaultWorkerAgentType:o.managerDefaultWorkerAgentType,managerDefaultWorkerModelId:o.managerDefaultWorkerModelId}:i,u=t.resolvePath(r.workDir),l=K(r.attachments);l?.length&&j(u,l);const g={text:r.text,attachments:l,localized:!1},f=t.sessions.get(r.sessionId);if(r.agentType==="codex"&&r.agentSessionId&&f?.currentRunId?.startsWith("dispatch:")&&ee(r.agentSessionId))return t.client.sendRes({type:"res",id:e.id,ok:!1,error:Z}),!1;o?.managedRoomContextToken&&t.revokeManagedRoomContextToken?.(o.managedRoomContextToken);const k=await this.isSessionBusy(r.sessionId),M=m(),S=M.sessions[r.sessionId]??[],h=G({...r,text:g.text,attachments:g.attachments,systemPrompt:o?null:r.systemPrompt});o&&(i.managedAgentDirect&&(h.managedAgentDirect=!0),h.trigger?.kind!=="manager_event"&&h.trigger?.kind!=="scheduled"&&(h.trigger={kind:"managed_direct"}));const q=h.clientMessageId??h.id,c=x(r.sessionId,q);if(c.state!=="not_found")return t.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queued:c.state==="queued",queueMessageId:h.id,...c,queue:this.getSnapshot(r.sessionId)}}),!0;const I=Q(S,h);I||(M.sessions[r.sessionId]=[...S,h],y(M));const p=I??h;return $({sessionId:p.sessionId,agentType:p.agentType,sessionMode:p.sessionMode,managerConfig:p.managerConfig,workDir:p.workDir,agentSessionId:p.agentSessionId,modelId:p.modelId}),N(p.sessionId,R(p),"queued"),O(t.resolvePath(p.workDir),p.attachments??[]),w(t.client),this.logLifecycle("enqueue.persisted",r.sessionId,{origin:r.origin??"app",queueMessageId:p.id,pendingCount:(m().sessions[r.sessionId]??[]).length}),this.broadcast(r.sessionId),t.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queued:!0,queueMessageId:I?.id??h.id,...x(r.sessionId,I?.clientMessageId??I?.id??h.clientMessageId??h.id),queue:this.getSnapshot(r.sessionId),...g.localized?{localizedAttachments:!0}:{}}}),k?this.retries.schedule(r.sessionId):this.wakeSession(r.sessionId),!0}async handleGet(e){const s=this.opts.getRuntime(),t=e.params;if(!t.sessionId){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"sessionId is required"});return}s.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queue:this.getSnapshot(t.sessionId)}})}async handleEdit(e){const s=this.opts.getRuntime(),t=e.params;if(!t.sessionId||!t.queueMessageId||!t.text){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"sessionId, queueMessageId and text are required"});return}const i=m(),n=i.sessions[t.sessionId]??[],a=n.findIndex(r=>r.id===t.queueMessageId);if(a<0){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"Queued message not found"});return}if(!v(n[a])||n[a].externalQueuedSubmissionId||this.inFlightMessageIds.get(t.sessionId)?.has(t.queueMessageId)){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"managed_agent_queue_mutation_forbidden"});return}const o=K(t.attachments),d=s.resolvePath(n[a].workDir);o?.length&&j(d,o),n[a]={...n[a],text:t.text,attachments:o,updatedAt:A()},i.sessions[t.sessionId]=n,y(i),C(t.sessionId,R(n[a]),"queued"),n[a].attachments?.length&&O(d,n[a].attachments??[]),w(s.client),this.broadcast(t.sessionId),s.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queue:this.getSnapshot(t.sessionId)}})}async handleDelete(e){const s=this.opts.getRuntime(),t=e.params;if(!t.sessionId||!t.queueMessageId){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"sessionId and queueMessageId are required"});return}const i=m(),n=i.sessions[t.sessionId]??[],a=n.find(d=>d.id===t.queueMessageId);if(a&&(!v(a)||a.externalQueuedSubmissionId||this.inFlightMessageIds.get(t.sessionId)?.has(t.queueMessageId))){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"managed_agent_queue_mutation_forbidden"});return}const o=n.filter(d=>d.id!==t.queueMessageId);if(o.length===n.length){s.client.sendRes({type:"res",id:e.id,ok:!1,error:"Queued message not found"});return}o.length?i.sessions[t.sessionId]=o:delete i.sessions[t.sessionId],y(i),J(t.sessionId,a?.clientMessageId??a?.id??t.queueMessageId),w(s.client),this.broadcast(t.sessionId),s.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queue:this.getSnapshot(t.sessionId)}})}async handlePromote(e){const s=this.opts.getRuntime(),t=e.params,i=a=>s.client.sendRes({type:"res",id:e.id,ok:!1,error:a});if(!t.sessionId||!t.queueMessageId){i("sessionId and queueMessageId are required");return}if(this.promoting.has(t.sessionId)){i("queue_promotion_in_progress");return}this.promoting.add(t.sessionId);let n=[];try{for(;this.draining.has(t.sessionId);)await new Promise(d=>setTimeout(d,5));if(n=Y(m().sessions[t.sessionId]??[],t.queueMessageId),!n.length){i("Queued message not found");return}if(n[0].externalQueuedSubmissionId||!this.isImmediateSendAvailable(t.sessionId)){i("queue_immediate_send_unavailable");return}this.inFlightMessageIds.set(t.sessionId,new Set(n.map(d=>d.id)));const a=s.sessions.get(t.sessionId);let o="idle";if(a?.currentRunId)if(this.canInjectActiveBatch(a,n)){const d=n.length===1?n[0].text:P(n),r=n[0].clientMessageId??n[0].id;s.nativeFusion?.registerManagedSend({sessionId:t.sessionId,agentType:n[0].agentType,sourceAgentType:ie(n[0].agentType,n[0].modelId),canonicalMessageId:r,sourceSessionKey:a.agentSessionId,text:d,managedEchoPolicy:"suppress_following"});const u=Date.now();try{await a.adapter.injectActiveInput({text:d,attachments:B(n.flatMap(l=>l.attachments??[])),clientMessageId:r})}catch(l){throw s.nativeFusion?.cancelManagedSend(r),l}for(const l of n)C(t.sessionId,{...R(l),ts:u},"executing");this.removeBatch(t.sessionId,n),o="injected"}else{if(!this.opts.interruptQueuedSession)throw new Error("queue_interrupt_unavailable");await this.opts.interruptQueuedSession(t.sessionId);const d=await this.dispatchQueuedMessages(n);d.deliveryMode==="external_owner_queue"?this.markExternalQueued(n,d.queuedSubmissionId):(this.removeBatch(t.sessionId,n),o="restarted")}else{const d=await this.dispatchQueuedMessages(n);d.deliveryMode==="external_owner_queue"?this.markExternalQueued(n,d.queuedSubmissionId):this.removeBatch(t.sessionId,n)}w(s.client),this.broadcast(t.sessionId),s.client.sendRes({type:"res",id:e.id,ok:!0,payload:{queue:this.getSnapshot(t.sessionId),promotedMessageIds:n.map(d=>d.id),mode:o}})}catch(a){i(a instanceof Error?a.message:"queue_promotion_failed"),this.broadcast(t.sessionId)}finally{this.inFlightMessageIds.delete(t.sessionId),this.promoting.delete(t.sessionId),m().sessions[t.sessionId]?.length&&this.wakeSession(t.sessionId)}}noteTerminal(e){const s=m().sessions[e]?.find(t=>!!t.externalQueuedSubmissionId);s&&this.noteExternalClaim(e,s.clientMessageId??s.id),this.wakeSession(e)}purgeSession(e){ne(e),this.retries.cancel(e)}discardPendingManagedRoomMessages(e){if(this.deletions.hasSession(e)){const o=m().sessions[e]?.length??0;return this.purgeSession(e),o}const s=m(),t=s.sessions[e]??[],i=this.inFlightMessageIds.get(e)??new Set,n=t.filter(o=>o.managedRoom&&!i.has(o.id));if(n.length===0)return 0;const a=t.filter(o=>!n.includes(o));a.length?s.sessions[e]=a:delete s.sessions[e],y(s);for(const o of n)J(e,o.clientMessageId??o.id);return w(this.opts.getRuntime().client),this.logLifecycle("managed-room.discarded-paused",e,{discardedCount:n.length,pendingCount:a.length}),this.broadcast(e),n.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 s of Object.keys(e.sessions))this.wakeSession(s)}async drainNext(e){if(this.disposed||this.draining.has(e)||this.promoting.has(e))return;this.draining.add(e);let s=!1,t=!1,i=[];try{if(this.deletions.hasSession(e)){this.purgeSession(e);return}if(await this.isSessionBusy(e)){const l=m().sessions[e]?.length??0,g=this.deferredLogState.get(e),f=Date.now();(!g||g.pendingCount!==l||f-g.at>=3e4)&&(this.logLifecycle("drain.deferred",e,{pendingCount:l}),this.deferredLogState.set(e,{at:f,pendingCount:l}));return}this.deferredLogState.delete(e);const n=m(),a=n.sessions[e]??[],o=a.filter(l=>{const g=l.clientMessageId??l.id,f=x(e,g).state;return f==="queued"||f==="not_found"});if(o.length!==a.length&&(o.length?n.sessions[e]=o:delete n.sessions[e],y(n),this.logLifecycle("drain.pruned-terminal",e,{prunedCount:a.length-o.length,pendingCount:o.length})),o.some(l=>!!l.externalQueuedSubmissionId)){this.broadcast(e);return}const d=X(o);if(d.length===0){this.broadcast(e);return}i=d,this.inFlightMessageIds.set(e,new Set(d.map(l=>l.id))),this.logLifecycle("dispatch.start",e,{batchCount:d.length,queueMessageId:d[0].id,origin:d[0].origin??"app"}),this.broadcast(e);for(const l of d)C(e,R(l),"queued");const r=await this.dispatchQueuedMessages(d);if(r.deliveryMode==="external_owner_queue"){this.markExternalQueued(d,r.queuedSubmissionId),this.logLifecycle("dispatch.external-queued",e,{batchCount:d.length,queueMessageId:d[0].id}),this.broadcast(e);return}const u=this.removeBatch(e,d);this.logLifecycle("dispatch.accepted",e,{batchCount:d.length,queueMessageId:d[0].id,pendingCount:u}),this.deferredLogState.delete(e),s=u>0,this.broadcast(e)}catch(n){const a=W(n instanceof Error?n.message:String(n),n instanceof D?"terminal_dispatch_failed":"transient_dispatch_failed"),o=i[0],d=!!(o&&!o.trigger&&!o.clientMessageId&&Date.now()-Date.parse(o.createdAt)>=10*6e4&&this.opts.getRuntime().managerRuntime?.isManagedWorkerSession(e));if(n instanceof D||a==="managed_claim_source_binding_conflict"||d){const u=this.removeBatch(e,i);this.logLifecycle("dispatch.terminal-failure",e,{batchCount:i.length,queueMessageId:i[0]?.id,pendingCount:u,failureClass:d?"stale_legacy_managed_worker_dispatch_failure":a},"error"),s=u>0}else t=!0,this.logLifecycle("dispatch.transient-failure",e,{failureClass:a},"error");this.broadcast(e)}finally{this.inFlightMessageIds.delete(e),this.draining.delete(e);const n=m().sessions[e]??[];n.length?(this.broadcast(e),n.some(a=>!!a.externalQueuedSubmissionId)?this.retries.cancel(e):s?queueMicrotask(()=>this.wakeSession(e)):this.retries.schedule(e,t)):this.retries.cancel(e)}}noteExternalClaim(e,s){const t=m(),i=t.sessions[e]??[],n=i.filter(a=>(a.clientMessageId??a.id)!==s);n.length!==i.length&&(n.length?t.sessions[e]=n:delete t.sessions[e],y(t),this.broadcast(e))}canInjectActiveBatch(e,s){if(!e.adapter.supportsActiveInput||!e.adapter.injectActiveInput||!e.journalRunId)return!1;const t=this.opts.getRuntime().runJournal?.get(s[0].sessionId,e.journalRunId),i=s[0].trigger?.kind==="managed_direct"||s[0].managedAgentDirect?null:"personal";return!!(i&&s[0].systemPrompt==null&&t&&t.source===i&&t.deliveryMode==="direct"&&t.agentType===s[0].agentType&&t.workDir===e.workDir&&t.agentSessionId===e.agentSessionId&&t.modelId===(s[0].modelId??null)&&t.reasoningEffort===(s[0].reasoningEffort??null))}removeBatch(e,s){if(s.length===0)return m().sessions[e]?.length??0;const t=m(),i=new Set(s.map(a=>a.id)),n=(t.sessions[e]??[]).filter(a=>!i.has(a.id));return n.length?t.sessions[e]=n:delete t.sessions[e],y(t),n.length}logLifecycle(e,s,t,i="info"){const n=`[chat.queue] ${JSON.stringify({at:A(),event:e,sessionId:s,...t})}`;i==="error"?console.error(n):console.info(n)}async dispatchQueuedMessages(e){const s=e[0],t=s.trigger?.kind==="scheduled"?s.trigger:null;if(t&&await this.validateScheduledTarget?.({sessionId:s.sessionId,...t})!=="ready")throw new D("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]:[]}),n=e.find(c=>c.trigger?.kind==="manager_event")?.trigger,a=e.some(c=>c.trigger?.kind==="managed_direct"||!!c.managedAgentDirect),o=a||!!t?.bindingId,d=e.find(c=>c.trigger?.kind==="manager_worker")?.trigger,r=n?.kind==="manager_event"||a,u=i.length>0?await this.prepareManagedRoomTurn?.(i):o||n?.kind==="manager_event"?await this.prepareManagedAgentDirectTurn?.(s.sessionId,L(n?.kind==="manager_event"?n:null,a)):void 0;if(i.length>0&&!u)throw new Error("managed_room_turn_preparer_unavailable");if(o&&!u)throw new Error("managed_agent_context_unavailable");if(n?.kind==="manager_event"&&this.opts.getRuntime().managerRuntime?.isManagedRoomBoundManager(s.sessionId)&&!u)throw new Error("managed_agent_context_unavailable");const l=new Set((m().sessions[s.sessionId]??[]).map(c=>c.id));if(this.disposed||this.deletions.hasSession(s.sessionId)||e.some(c=>!l.has(c.id)))throw u?.managedRoomContextToken&&this.opts.getRuntime().revokeManagedRoomContextToken?.(u.managedRoomContextToken),this.disposed?new Error("queue_stopped"):new D("queued_dispatch_cancelled");const g=u??null,f=g?.sessionMode==="manager"?g.managerConfig:null,k=e.length===1?s.text:P(e),M=B(e.flatMap(c=>c.attachments??[])),S=o||n?.kind==="manager_event"&&!!u,h=S?u.agentSessionId?.startsWith("managed:")?T(this.opts.getRuntime(),s):u.agentSessionId:i.length>0?T(this.opts.getRuntime(),s):s.agentSessionId??null,q=u?z().find(c=>c.sessionId===s.sessionId):null;return await this.opts.dispatchQueuedReq({type:"req",id:`queue-send-${s.id}-${Date.now()}`,method:"chat.send",params:{...b(E()),sessionId:s.sessionId,text:k,agentType:S?u.agentType:s.agentType,sessionMode:g?.sessionMode??s.sessionMode,managerConfig:g?f:s.managerConfig,workDir:S?u.workDir:s.workDir,agentSessionId:h,modelId:F(q?.modelId)??F(s.modelId),systemPrompt:u?.systemPrompt??s.systemPrompt??null,managerDefaultWorkerAgentType:g?g.managerDefaultWorkerAgentType:s.managerDefaultWorkerAgentType,managerDefaultWorkerModelId:g?g.managerDefaultWorkerModelId:s.managerDefaultWorkerModelId,reasoningEffort:s.reasoningEffort??void 0,clientMessageId:s.clientMessageId??s.id,attachments:M,externalChannel:r?void 0:s.externalChannel,replyTarget:r?void 0:s.replyTarget,roomContextRegistryKey:r?void 0:u?.roomContextRegistryKey,activationCauseMessageId:r?void 0:i.at(-1)?.causeMessageId,rootCauseMessageId:r?void 0:i.at(-1)?.rootCauseMessageId,activationSequence:r?void 0:i.at(-1)?.sequence,activationHopCount:r?void 0:i.at(-1)?.hopCount,managedRecoverySource:n?.kind==="manager_event"?"manager_event":o?"managed_direct":i.length>0?"managed_room":void 0,managerEventId:n?.kind==="manager_event"?n.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,s.workDir)||void 0,managedRoomContextToken:u?.managedRoomContextToken,scheduledDelivery:!!t,suppressExternalOwnerEcho:i.length>0||!!t||void 0,queuedBatchItems:e.map(c=>{const I=_(c);return r?{...I,systemPrompt:u?.systemPrompt??null,externalChannel:null,replyTarget:null}:I}),waitForDispatch:!0}},u??void 0)??{}}markExternalQueued(e,s){const t=m(),i=new Set(e.map(o=>o.id)),n=t.sessions[e[0].sessionId]??[];let a=!1;for(const o of n)i.has(o.id)&&(o.externalQueuedSubmissionId=s||o.id,o.updatedAt=A(),a=!0);a&&y(t)}async isSessionBusy(e){const s=this.opts.getRuntime().recoveryBarrier;if(s?.isDispatchFrozen()||s?.isRecovering(e))return!0;const t=this.opts.getRuntime().sessions.get(e);if(!t)return!1;if(t.currentRunId){if(!(t.currentRunId.startsWith("dispatch:")&&!!this.opts.getRuntime().runJournal&&!t.journalRunId)||(t.adapter.getStatus?await t.adapter.getStatus().catch(()=>null):null)?.active)return!0;this.logLifecycle("drain.recovered-stale-dispatch",e,{staleRunId:t.currentRunId}),t.currentRunId=null,t.currentRunPhase=null}if(!t.adapter.getStatus)return!1;const i=await t.adapter.getStatus().catch(()=>null);return i?.active?(i.runId&&(t.currentRunId=i.runId,t.currentRunPhase=i.runPhase??t.currentRunPhase),!0):!1}broadcast(e){this.opts.getRuntime().client.sendEvent({type:"event",event:"session.queue.update",payload:{queue:this.getSnapshot(e)}})}}export{Re as ChatQueueManager,qe as TerminalQueuedChatDispatchError,xe as purgeQueuedSessionData};
@@ -5,5 +5,8 @@ import { type PreparedManagedRoomTurn } from './queue.js';
5
5
  export declare function managedChatContext(prepared: PreparedManagedRoomTurn): ChatSendExecutionContext;
6
6
  export declare function managedManagerEventContext(prepared: PreparedManagedRoomTurn): ChatSendExecutionContext;
7
7
  export declare function dispatchManagedChat(runtime: SessionManagerRuntime, req: ReqFrame, prepared: PreparedManagedRoomTurn): Promise<void>;
8
- export declare function dispatchQueuedChat(runtime: SessionManagerRuntime, req: ReqFrame, prepared?: PreparedManagedRoomTurn): Promise<void>;
8
+ export declare function dispatchQueuedChat(runtime: SessionManagerRuntime, req: ReqFrame, prepared?: PreparedManagedRoomTurn): Promise<{
9
+ deliveryMode?: string;
10
+ queuedSubmissionId?: string;
11
+ }>;
9
12
  export declare function interruptQueuedChat(runtime: SessionManagerRuntime, sessionId: string): Promise<void>;
@@ -1 +1 @@
1
- import{handleChatAbort as s,handleChatSend as r}from"./handlers/chat.js";import{TerminalQueuedChatDispatchError as h}from"./queue.js";import{markTrustedManagerEvent as u}from"./manager-event-authority.js";function d(e){return{source:"room_activation",managedAgentPolicy:e.managedAgentPolicy,managedRoomPromptSnapshot:e.managedRoomPromptSnapshot}}function f(e){return{source:"manager_event",managedAgentPolicy:e.managedAgentPolicy,managedRoomPolicyVersion:e.managedRoomPromptSnapshot.managedRoomPolicyVersion,managedRuntimePolicyHash:e.managedRoomPromptSnapshot.runtimePermissionPolicyHash}}async function p(e,i,a){await r(e,u(i),d(a))}async function P(e,i,a){const o={value:null},n=new Proxy(e.client,{get:(t,l)=>{if(l==="sendRes")return m=>{o.value=m};const c=Reflect.get(t,l,t);return typeof c=="function"?c.bind(t):c}});if(await r({...e,client:n},u(i),a?i.params.managedRecoverySource==="managed_room"||i.params.scheduledDelivery===!0?d(a):f(a):void 0),o.value?.payload?.deliveryState==="failed")throw new h(o.value.payload.failureMessage??o.value.error??"queued_chat_dispatch_failed");if(!o.value?.ok)throw new Error(o.value?.error??"queued_chat_dispatch_failed")}async function R(e,i){const a={value:null},o=new Proxy(e.client,{get:(n,t)=>t==="sendRes"?l=>{a.value=l}:typeof Reflect.get(n,t,n)=="function"?Reflect.get(n,t,n).bind(n):Reflect.get(n,t,n)});if(await s({...e,client:o},{type:"req",id:`queue-promote-abort-${Date.now()}`,method:"chat.abort",params:{sessionId:i,discardPending:!1}}),!a.value?.ok)throw new Error(a.value?.error??"agent_stop_failed")}export{p as dispatchManagedChat,P as dispatchQueuedChat,R as interruptQueuedChat,d as managedChatContext,f as managedManagerEventContext};
1
+ import{handleChatAbort as s,handleChatSend as d}from"./handlers/chat.js";import{TerminalQueuedChatDispatchError as h}from"./queue.js";import{markTrustedManagerEvent as r}from"./manager-event-authority.js";function c(e){return{source:"room_activation",managedAgentPolicy:e.managedAgentPolicy,managedRoomPromptSnapshot:e.managedRoomPromptSnapshot}}function f(e){return{source:"manager_event",managedAgentPolicy:e.managedAgentPolicy,managedRoomPolicyVersion:e.managedRoomPromptSnapshot.managedRoomPolicyVersion,managedRuntimePolicyHash:e.managedRoomPromptSnapshot.runtimePermissionPolicyHash}}async function p(e,i,o){await d(e,r(i),c(o))}async function P(e,i,o){const a={value:null},n=new Proxy(e.client,{get:(t,l)=>{if(l==="sendRes")return m=>{a.value=m};const u=Reflect.get(t,l,t);return typeof u=="function"?u.bind(t):u}});if(await d({...e,client:n},r(i),o?i.params.managedRecoverySource==="managed_room"||i.params.scheduledDelivery===!0?c(o):f(o):void 0),a.value?.payload?.deliveryState==="failed")throw new h(a.value.payload.failureMessage??a.value.error??"queued_chat_dispatch_failed");if(!a.value?.ok)throw new Error(a.value?.error??"queued_chat_dispatch_failed");return{deliveryMode:a.value.payload?.deliveryMode,queuedSubmissionId:a.value.payload?.queuedSubmissionId}}async function R(e,i){const o={value:null},a=new Proxy(e.client,{get:(n,t)=>t==="sendRes"?l=>{o.value=l}:typeof Reflect.get(n,t,n)=="function"?Reflect.get(n,t,n).bind(n):Reflect.get(n,t,n)});if(await s({...e,client:a},{type:"req",id:`queue-promote-abort-${Date.now()}`,method:"chat.abort",params:{sessionId:i,discardPending:!1}}),!o.value?.ok)throw new Error(o.value?.error??"agent_stop_failed")}export{p as dispatchManagedChat,P as dispatchQueuedChat,R as interruptQueuedChat,c as managedChatContext,f as managedManagerEventContext};
@@ -1,13 +1,14 @@
1
- import { type AgentType, type Envelope, type ManagerConfig, type SessionIndexUpdate, type SessionTitleGenerateResponse, type SessionTitleGenerationEligibility, type SessionDeliveryState, type SessionMessageStatusResponse, type SessionMode, type SessionTitleSource } from '@shennian/wire';
1
+ import { type AgentType, type Envelope, type ManagerConfig, type SessionDeliveryState, type SessionIndexUpdate, type SessionMessageStatusResponse, type SessionMode, type SessionTitleGenerateResponse, type SessionTitleGenerationEligibility, type SessionTitleSource } from '@shennian/wire';
2
+ import { getDaemonInstallationId } from '../personal-sync/identity.js';
2
3
  import { PERSONAL_SYNC_V1_ROOT_NAME } from '../personal-sync/paths.js';
3
4
  import { CanonicalSessionStore } from './canonical-store.js';
4
- import { getDaemonInstallationId } from '../personal-sync/identity.js';
5
5
  export { PERSONAL_SYNC_V1_ROOT_NAME };
6
6
  export type LocalSessionRecord = {
7
7
  daemonInstallationId: string;
8
8
  sessionId: string;
9
9
  agentType: AgentType;
10
10
  sessionMode?: SessionMode;
11
+ nativeSessionVisibility?: 'user' | 'internal';
11
12
  managerConfig?: ManagerConfig | null;
12
13
  workDir: string;
13
14
  agentSessionId?: string | null;
@@ -60,6 +61,7 @@ export declare function recordSession(input: {
60
61
  sessionId: string;
61
62
  agentType: AgentType;
62
63
  sessionMode?: SessionMode;
64
+ nativeSessionVisibility?: 'user' | 'internal';
63
65
  managerConfig?: ManagerConfig | null;
64
66
  workDir: string;
65
67
  agentSessionId?: string | null;
@@ -1,2 +1,2 @@
1
- import O from"node:crypto";import c from"node:fs";import A from"node:path";import{SESSION_SYNC_PROTOCOL_VERSION as x,SESSION_SYNC_DATA_EPOCH as I,SESSION_TITLE_SOURCE_PRIORITY as m,isToolPayload as P,sessionPreviewFromPayload as h}from"@shennian/wire";import{PERSONAL_SYNC_V1_ROOT_NAME as V,resolvePersonalSyncV1Path as G}from"../personal-sync/paths.js";import{CanonicalSessionStore as L}from"./canonical-store.js";import{getDaemonInstallationId as g}from"../personal-sync/identity.js";import{NativeSourceDeletionStore as q}from"../native-fusion/native-source-deletions.js";const D=120;function p(t){if(t.length<=D)return t;let e=t.slice(0,D);const n=e.charCodeAt(e.length-1);return n>=55296&&n<=56319&&(e=e.slice(0,-1)),e}let w=null,_=null;function R(){return G()}function u(){const t=A.join(R(),"canonical");return(!w||_!==t)&&(w=new L(t,g()),_=t),w}function k(){return A.join(R(),"session-index.json")}function d(){const t=k();if(!c.existsSync(t))return{};const e=JSON.parse(c.readFileSync(t,"utf8"));if(!e||typeof e!="object"||Array.isArray(e))throw new Error(`invalid personal session index: ${t}`);const n=g();for(const s of Object.values(e))if(s.daemonInstallationId!==n)throw new Error(`personal session index belongs to another daemon installation: ${t}`);return e}function S(t){J(k(),t)}function M(t){return h(t.payload,120)}function y(t){if(new q({rootDir:R(),daemonInstallationId:g()}).hasSession(t))throw new Error(`session_deleted:${t}`)}function j(t){y(t.sessionId),g();const e=d(),n=e[t.sessionId],s=new Date().toISOString(),i=u().getManifest(t.sessionId)?.bodyRevision??n?.bodyRevision??0,o=u().getManifest(t.sessionId),a=z(n,t),r=t.attentionId?.trim()||null,l=Array.from(new Set([...n?.seenAttentionIds??[],...n?.lastAttentionId?[n.lastAttentionId]:[]])),f=!!(r&&!l.includes(r)),v=t.lastMessagePreview===null?{preview:null,messageId:null,at:null}:t.lastMessagePreview!==void 0&&t.lastMessagePreviewMessageId&&t.lastMessagePreviewAt?{preview:t.lastMessagePreview,messageId:t.lastMessagePreviewMessageId,at:t.lastMessagePreviewAt}:{preview:n?.lastMessagePreview??null,messageId:n?.lastMessagePreviewMessageId??null,at:n?.lastMessagePreviewAt??null},b=Date.parse(t.lastVisibleEventAt??""),E=Date.parse(n?.lastVisibleEventAt??""),U=Number.isFinite(b)&&(!Number.isFinite(E)||b>=E)?t.lastVisibleEventAt:n?.lastVisibleEventAt??null,C={daemonInstallationId:g(),sessionId:t.sessionId,agentType:t.agentType,sessionMode:t.sessionMode??n?.sessionMode,managerConfig:t.managerConfig??n?.managerConfig??null,workDir:t.workDir,agentSessionId:t.agentSessionId??n?.agentSessionId??null,modelId:t.modelId??n?.modelId??null,managerDefaultWorkerAgentType:t.managerDefaultWorkerAgentType??n?.managerDefaultWorkerAgentType??null,managerDefaultWorkerModelId:t.managerDefaultWorkerModelId??n?.managerDefaultWorkerModelId??null,status:t.status??n?.status??"active",createdAt:n?.createdAt??s,updatedAt:s,lastActivityAt:t.lastActivityAt??n?.lastActivityAt??s,lastMessagePreview:v.preview,lastMessagePreviewMessageId:v.messageId,lastMessagePreviewAt:v.at,lastVisibleEventAt:U,localReady:n?.localReady===!0||t.localReady===!0,firstUserMessageId:n?.firstUserMessageId??t.firstUserMessageId??null,firstUserBodyRevision:n?.firstUserBodyRevision??t.firstUserBodyRevision??null,bodyRevision:i,indexRevision:(n?.indexRevision??0)+1,...a,firstAvailableSeq:o?.firstAvailableSeq??n?.firstAvailableSeq??null,visibleMessageCount:o?.visibleMessageCount??n?.visibleMessageCount??0,lastVisibleMessageId:o?.lastVisibleMessageId??n?.lastVisibleMessageId??null,attentionCount:(n?.attentionCount??0)+(f?1:0),lastAttentionId:f?r:n?.lastAttentionId??null,seenAttentionIds:f&&r?[...l,r]:l,lastBodyCommittedAt:o?.lastBodyCommittedAt??n?.lastBodyCommittedAt??null,deletionRevision:n?.deletionRevision??0,deletedAt:t.deletedAt??n?.deletedAt??null,syncedIndexRevision:n?.syncedIndexRevision??0,indexSyncState:"pending",indexSyncStateRevision:(n?.indexRevision??0)+1,indexSyncAttempts:0,indexSyncNextAttemptAt:null,indexSyncErrorCode:null,indexQuarantineCode:null,titleGenerationAttemptedAt:n?.titleGenerationAttemptedAt&&n.titleGenerationNextAttemptAt!==void 0?n.titleGenerationAttemptedAt:null,titleGenerationNextAttemptAt:n?.titleGenerationNextAttemptAt??null,titleGenerationAttempts:n?.titleGenerationAttempts??0};return e[t.sessionId]=C,S(e),C}function F(){return Object.values(d())}function se(t){if(!t)throw new Error("sessionId is required");const e=d();e[t]&&(delete e[t],S(e))}function oe(t){u().purgeSession(t)}function W(){const t=d();let e=!1;const n=new Date().toISOString();for(const[s,i]of Object.entries(t)){const o=p(i.title);if(o===i.title)continue;const a=i.indexRevision+1;t[s]={...i,title:o,indexRevision:a,indexSyncState:"pending",indexSyncStateRevision:a,indexSyncAttempts:0,indexSyncNextAttemptAt:null,indexSyncErrorCode:null,indexQuarantineCode:null,updatedAt:n},e=!0}e&&S(t)}function ae(){const t=g();return Y(),Q(),W(),F().filter(e=>{const n=e.indexSyncStateRevision===e.indexRevision;return e.indexQuarantineCode||n&&(e.indexSyncState==="quarantined"||e.indexSyncState==="terminal")||n&&e.indexSyncNextAttemptAt&&Date.parse(e.indexSyncNextAttemptAt)>Date.now()?!1:e.indexRevision>e.syncedIndexRevision&&e.localReady&&!!e.firstUserMessageId&&e.firstUserBodyRevision!=null}).sort((e,n)=>e.indexRevision-n.indexRevision).map(e=>{const n=!!(e.lastMessagePreview&&e.lastMessagePreviewMessageId&&e.lastMessagePreviewAt);return{protocolVersion:x,dataEpoch:I,daemonInstallationId:t,session:{id:e.sessionId,agentType:e.agentType,sessionMode:e.sessionMode,managerConfig:e.managerConfig,agentSessionId:e.agentSessionId??null,modelId:e.modelId??null,managerDefaultWorkerAgentType:e.managerDefaultWorkerAgentType??null,managerDefaultWorkerModelId:e.managerDefaultWorkerModelId??null,title:e.title,titleSource:e.titleSource,titleRevision:e.titleRevision,titleLockedByUser:e.titleLockedByUser,titleOriginEventId:e.titleOriginEventId,status:e.status??"active",workDir:e.workDir,lastMessagePreview:n?e.lastMessagePreview:null,lastMessagePreviewMessageId:n?e.lastMessagePreviewMessageId:null,lastMessagePreviewAt:n?e.lastMessagePreviewAt:null,lastVisibleEventAt:e.lastVisibleEventAt??e.lastMessagePreviewAt??null,bodyStorageMode:"machine_local",localReady:!0,firstUserBoundary:{role:"user",messageId:e.firstUserMessageId,bodyRevision:e.firstUserBodyRevision},bodyRevision:e.bodyRevision,indexRevision:e.indexRevision,firstAvailableSeq:e.firstAvailableSeq,visibleMessageCount:e.visibleMessageCount,lastVisibleMessageId:e.lastVisibleMessageId,attentionCount:e.attentionCount??0,lastAttentionId:e.lastAttentionId??null,lastBodyCommittedAt:e.lastBodyCommittedAt,deletionRevision:e.deletionRevision,lastActivityAt:e.lastActivityAt,createdAt:e.createdAt,updatedAt:e.updatedAt,deletedAt:e.deletedAt}}})}function le(t,e){const n=d(),s=n[t];if(!(!s||e<=s.syncedIndexRevision)){if(e>s.indexRevision)throw new Error(`cannot acknowledge future index revision ${e} for ${t}`);n[t]={...s,syncedIndexRevision:e,indexSyncState:"applied",indexSyncStateRevision:e,indexSyncAttempts:0,indexSyncNextAttemptAt:null,indexSyncErrorCode:null},S(n)}}function re(){const t=d();let e=0;const n=new Date().toISOString();for(const[s,i]of Object.entries(t)){if(i.deletedAt||i.indexQuarantineCode||!i.localReady)continue;const o=i.indexRevision+1;t[s]={...i,indexRevision:o,indexSyncState:"pending",indexSyncStateRevision:o,indexSyncAttempts:0,indexSyncNextAttemptAt:null,indexSyncErrorCode:null,updatedAt:n},e+=1}return e>0&&S(t),e}function de(t){const e=d(),n=e[t.sessionId];if(!n||n.indexRevision!==t.indexRevision)return"terminal";const i=(n.indexSyncStateRevision===t.indexRevision?n.indexSyncAttempts??0:0)+1;let o=t.disposition;o==="retry"&&i>=(t.maxAttempts??8)&&(o="terminal");const a=t.now??Date.now(),r=Math.min(5e3*2**Math.max(0,i-1),360*60*1e3),l=Math.round(r*.2*(Math.random()*2-1));return e[t.sessionId]={...n,indexSyncState:o==="retry"?"pending":o,indexSyncStateRevision:t.indexRevision,indexSyncAttempts:i,indexSyncNextAttemptAt:o==="retry"?new Date(a+r+l).toISOString():null,indexSyncErrorCode:t.code,indexQuarantineCode:o==="quarantined"?t.code:n.indexQuarantineCode??null},S(e),o}const $=2*6e4;function ce(t=Date.now(),e=$){const n=d(),s=[],i=new Date(t).toISOString();for(const o of Object.values(n)){if(o.titleSource!=="first_user_fallback"||o.titleLockedByUser||o.titleGenerationAttemptedAt||!o.title.trim()||o.syncedIndexRevision<o.indexRevision||o.titleGenerationNextAttemptAt&&Date.parse(o.titleGenerationNextAttemptAt)>t)continue;const a=o.status==="completed"||o.status==="failed",r=o.visibleMessageCount>=2;let l=null;if(o.agentType==="claude"&&r?l="agent_native_unavailable":a?l="terminal":r&&t-Date.parse(o.createdAt)>=e&&(l="grace_elapsed"),!l)continue;const f=h(o.title,240);if(!f)continue;const v=O.randomUUID();n[o.sessionId]={...o,titleGenerationAttemptedAt:i,titleGenerationNextAttemptAt:null,titleGenerationAttempts:(o.titleGenerationAttempts??0)+1},s.push({sessionId:o.sessionId,requestId:v,titleSeed:f,baseTitleRevision:o.titleRevision,eligibility:l})}return s.length>0&&S(n),s}function ue(t,e=Date.now()){const n=d(),s=n[t];if(!s?.titleGenerationAttemptedAt||s.titleSource!=="first_user_fallback")return null;const i=Math.max(1,s.titleGenerationAttempts??1),o=Math.min(10*6e4,3e4*2**Math.min(i-1,5)),a=new Date(e+o).toISOString();return n[t]={...s,titleGenerationAttemptedAt:null,titleGenerationNextAttemptAt:a},S(n),a}function ge(t,e){const s=d()[t];return!s||s.titleLockedByUser||m[s.titleSource]>=m.shennian_generated||e.titleRevision<=s.titleRevision?!1:(j({sessionId:t,agentType:s.agentType,sessionMode:s.sessionMode,managerConfig:s.managerConfig,workDir:s.workDir,agentSessionId:s.agentSessionId,modelId:s.modelId,status:s.status,title:e.title,titleSource:"shennian_generated",titleRevision:e.titleRevision,titleLockedByUser:!1,titleOriginEventId:e.titleOriginEventId}),!0)}function Se(t,e,n){y(t),g();const s=u().append(t,e,n);return T(t,e,s.bodyRevision),s.bodyRevision}function fe(t,e,n){y(t),g();const s=u().upsert(t,e,n);return T(t,e,s.bodyRevision),s.bodyRevision}function ve(t,e){const n=u().getMessageState(t,e);return!n||n.tombstoned||!n.message||!n.deliveryState?{protocolVersion:x,dataEpoch:I,daemonInstallationId:g(),state:"not_found",sessionId:t,clientMessageId:e}:{protocolVersion:x,dataEpoch:I,daemonInstallationId:g(),state:n.deliveryState,sessionId:t,clientMessageId:e,messageId:n.message.id,deliveryState:n.deliveryState,bodyRevision:n.lastRevision,committedAt:new Date(n.message.ts).toISOString()}}function me(t,e){y(t),g();const n=u().tombstone(t,e),s=d(),i=s[t];if(i){const o=e===i.lastMessagePreviewMessageId?N(t):{preview:i.lastMessagePreview??null,messageId:i.lastMessagePreviewMessageId??null,at:i.lastMessagePreviewAt??null};s[t]={...i,bodyRevision:n.bodyRevision,indexRevision:i.indexRevision+1,indexSyncState:"pending",indexSyncStateRevision:i.indexRevision+1,indexSyncAttempts:0,indexSyncNextAttemptAt:null,indexSyncErrorCode:null,updatedAt:new Date().toISOString(),lastMessagePreview:o.preview,lastMessagePreviewMessageId:o.messageId,lastMessagePreviewAt:o.at,lastVisibleEventAt:B(t)},S(s)}return n.bodyRevision}function T(t,e,n){const s=d(),i=s[t];if(!i)return;const o=M(e),a=o?{lastMessagePreview:o,lastMessagePreviewMessageId:e.id,lastMessagePreviewAt:new Date(e.ts).toISOString()}:null,r=o||P(e.payload)?new Date(e.ts).toISOString():i.lastVisibleEventAt,l=u().getManifest(t),f=e.role==="user"&&o&&!i.title?{title:p(o),titleSource:"first_user_fallback",titleRevision:i.titleRevision+1,titleLockedByUser:!1,titleOriginEventId:e.id}:null,v=e.role==="user"&&!i.localReady?{localReady:!0,firstUserMessageId:e.id,firstUserBodyRevision:n}:null;s[t]={...i,...f??{},...v??{},bodyRevision:n,indexRevision:i.indexRevision+1,indexSyncState:"pending",indexSyncStateRevision:i.indexRevision+1,indexSyncAttempts:0,indexSyncNextAttemptAt:null,indexSyncErrorCode:null,updatedAt:new Date().toISOString(),lastActivityAt:new Date(e.ts).toISOString(),lastVisibleEventAt:r,...a??{},firstAvailableSeq:l?.firstAvailableSeq??i.firstAvailableSeq,visibleMessageCount:l?.visibleMessageCount??i.visibleMessageCount,lastVisibleMessageId:l?.lastVisibleMessageId??i.lastVisibleMessageId,attentionCount:i.attentionCount??0,lastAttentionId:i.lastAttentionId??null,lastBodyCommittedAt:l?.lastBodyCommittedAt??i.lastBodyCommittedAt},S(s)}function N(t){let e;do{const n=u().readPage(t,{limit:500,beforeSequence:e});for(let s=n.entries.length-1;s>=0;s-=1){const i=n.entries[s],o=M(i.message);if(o)return{preview:o,messageId:i.message.id,at:new Date(i.message.ts).toISOString()}}if(!n.hasOlder||n.entries.length===0)break;e=n.entries[0].sequence}while(e!==void 0);return{preview:null,messageId:null,at:null}}function B(t){let e;do{const n=u().readPage(t,{limit:500,beforeSequence:e});for(let s=n.entries.length-1;s>=0;s-=1){const i=n.entries[s].message;if(!(!M(i)&&!P(i.payload)))return new Date(i.ts).toISOString()}if(!n.hasOlder||n.entries.length===0)break;e=n.entries[0].sequence}while(e!==void 0);return null}function Q(){const t=d();let e=!1;const n=new Date().toISOString();for(const[s,i]of Object.entries(t)){if(Object.prototype.hasOwnProperty.call(i,"lastVisibleEventAt"))continue;const o=i.indexRevision+1;t[s]={...i,lastVisibleEventAt:B(s)??i.lastMessagePreviewAt??null,indexRevision:o,indexSyncState:"pending",indexSyncStateRevision:o,indexSyncAttempts:0,indexSyncNextAttemptAt:null,indexSyncErrorCode:null,updatedAt:n},e=!0}e&&S(t)}function Y(){const t=d();let e=!1;const n=new Date().toISOString();for(const[s,i]of Object.entries(t)){if(Object.prototype.hasOwnProperty.call(i,"lastMessagePreviewMessageId")&&Object.prototype.hasOwnProperty.call(i,"lastMessagePreviewAt"))continue;const o=N(s);t[s]={...i,lastMessagePreview:o.preview,lastMessagePreviewMessageId:o.messageId,lastMessagePreviewAt:o.at,indexRevision:i.indexRevision+1,indexSyncState:"pending",indexSyncStateRevision:i.indexRevision+1,indexSyncAttempts:0,indexSyncNextAttemptAt:null,indexSyncErrorCode:null,updatedAt:n},e=!0}e&&S(t)}function z(t,e){const n={title:t?.title??"",titleSource:t?.titleSource??"first_user_fallback",titleRevision:t?.titleRevision??0,titleLockedByUser:t?.titleLockedByUser??!1,titleOriginEventId:t?.titleOriginEventId??null},s=p(e.title?.trim()??"");if(!s)return n;if(!e.titleSource)throw new Error("titleSource is required with title");if(n.title&&n.titleSource==="first_user_fallback"&&e.titleSource==="first_user_fallback")return n;const i=e.titleSource==="shennian_manual";if(e.titleLockedByUser!==void 0&&e.titleLockedByUser!==i)throw new Error("titleLockedByUser conflicts with titleSource");const o=s===n.title&&e.titleSource===n.titleSource,a=e.titleRevision??n.titleRevision+(o?0:1);if(!Number.isSafeInteger(a)||a<0)throw new Error("invalid titleRevision");const r=m[e.titleSource],l=m[n.titleSource];return r<l||a<n.titleRevision||o&&a===n.titleRevision||a===n.titleRevision&&!o?n:{title:s,titleSource:e.titleSource,titleRevision:a,titleLockedByUser:i,titleOriginEventId:e.titleOriginEventId??n.titleOriginEventId}}function ye(t,e){const n=e?.limit&&e.limit>0?Math.min(e.limit,500):500;let i=u().readRecent(t,n).messages;return e?.before!==void 0&&(i=i.filter(o=>o.ts<e.before)),[...i].sort((o,a)=>a.ts-o.ts)}function Ae(){return u().listSessionIds()}function xe(){return u()}function J(t,e){const n=A.dirname(t);c.mkdirSync(n,{recursive:!0,mode:448});const s=`${t}.tmp-${process.pid}-${O.randomBytes(6).toString("hex")}`;let i;try{if(i=c.openSync(s,"wx",384),c.writeFileSync(i,`${JSON.stringify(e,null,2)}
2
- `,"utf8"),c.fsyncSync(i),c.closeSync(i),i=void 0,c.renameSync(s,t),process.platform!=="win32"){const o=c.openSync(n,"r");try{c.fsyncSync(o)}finally{c.closeSync(o)}}}finally{i!==void 0&&c.closeSync(i);try{c.unlinkSync(s)}catch{}}}export{V as PERSONAL_SYNC_V1_ROOT_NAME,le as acknowledgeSessionIndexUpdate,Se as appendMessage,ge as applyGeneratedSessionTitle,ce as claimSessionTitleGenerationCandidates,ue as deferSessionTitleGeneration,xe as getCanonicalSessionStore,g as getDaemonInstallationId,ve as getMessageDeliveryStatus,ae as listPendingSessionIndexUpdates,F as listSessionRecords,Ae as listSessions,re as markAllSessionIndexesForRepublish,oe as purgeCanonicalSession,se as purgeSessionRecord,ye as readMessages,j as recordSession,de as recordSessionIndexRejection,me as tombstoneMessage,fe as upsertMessage};
1
+ import{SESSION_SYNC_DATA_EPOCH as x,SESSION_SYNC_PROTOCOL_VERSION as I,SESSION_TITLE_SOURCE_PRIORITY as y,isInternalSession as O,isToolPayload as P,sessionPreviewFromPayload as h}from"@shennian/wire";import D from"node:crypto";import c from"node:fs";import p from"node:path";import{NativeSourceDeletionStore as G}from"../native-fusion/native-source-deletions.js";import{registerInternalNativeSource as L}from"../native-fusion/source-visibility.js";import{getDaemonInstallationId as g}from"../personal-sync/identity.js";import{PERSONAL_SYNC_V1_ROOT_NAME as q,resolvePersonalSyncV1Path as j}from"../personal-sync/paths.js";import{CanonicalSessionStore as F}from"./canonical-store.js";const _=120;function w(t){if(t.length<=_)return t;let e=t.slice(0,_);const n=e.charCodeAt(e.length-1);return n>=55296&&n<=56319&&(e=e.slice(0,-1)),e}let M=null,k=null;function R(){return j()}function u(){const t=p.join(R(),"canonical");return(!M||k!==t)&&(M=new F(t,g()),k=t),M}function T(){return p.join(R(),"session-index.json")}function d(){const t=T();if(!c.existsSync(t))return{};const e=JSON.parse(c.readFileSync(t,"utf8"));if(!e||typeof e!="object"||Array.isArray(e))throw new Error(`invalid personal session index: ${t}`);const n=g();for(const s of Object.values(e))if(s.daemonInstallationId!==n)throw new Error(`personal session index belongs to another daemon installation: ${t}`);return e}function S(t){X(T(),t)}function b(t){return h(t.payload,120)}function A(t){if(new G({rootDir:R(),daemonInstallationId:g()}).hasSession(t))throw new Error(`session_deleted:${t}`)}function W(t){A(t.sessionId),g();const e=d(),n=e[t.sessionId],s=new Date().toISOString(),i=u().getManifest(t.sessionId)?.bodyRevision??n?.bodyRevision??0,o=u().getManifest(t.sessionId),a=H(n,t),r=t.attentionId?.trim()||null,l=Array.from(new Set([...n?.seenAttentionIds??[],...n?.lastAttentionId?[n.lastAttentionId]:[]])),f=!!(r&&!l.includes(r)),v=t.lastMessagePreview===null?{preview:null,messageId:null,at:null}:t.lastMessagePreview!==void 0&&t.lastMessagePreviewMessageId&&t.lastMessagePreviewAt?{preview:t.lastMessagePreview,messageId:t.lastMessagePreviewMessageId,at:t.lastMessagePreviewAt}:{preview:n?.lastMessagePreview??null,messageId:n?.lastMessagePreviewMessageId??null,at:n?.lastMessagePreviewAt??null},E=Date.parse(t.lastVisibleEventAt??""),C=Date.parse(n?.lastVisibleEventAt??""),U=Number.isFinite(E)&&(!Number.isFinite(C)||E>=C)?t.lastVisibleEventAt:n?.lastVisibleEventAt??null,m={daemonInstallationId:g(),sessionId:t.sessionId,agentType:t.agentType,sessionMode:t.sessionMode??n?.sessionMode,nativeSessionVisibility:O({...n,id:t.sessionId})||O({...n,...t,id:t.sessionId,sessionMode:t.sessionMode??n?.sessionMode})?"internal":"user",managerConfig:t.managerConfig??n?.managerConfig??null,workDir:t.workDir,agentSessionId:t.agentSessionId??n?.agentSessionId??null,modelId:t.modelId??n?.modelId??null,managerDefaultWorkerAgentType:t.managerDefaultWorkerAgentType??n?.managerDefaultWorkerAgentType??null,managerDefaultWorkerModelId:t.managerDefaultWorkerModelId??n?.managerDefaultWorkerModelId??null,status:t.status??n?.status??"active",createdAt:n?.createdAt??s,updatedAt:s,lastActivityAt:t.lastActivityAt??n?.lastActivityAt??s,lastMessagePreview:v.preview,lastMessagePreviewMessageId:v.messageId,lastMessagePreviewAt:v.at,lastVisibleEventAt:U,localReady:n?.localReady===!0||t.localReady===!0,firstUserMessageId:n?.firstUserMessageId??t.firstUserMessageId??null,firstUserBodyRevision:n?.firstUserBodyRevision??t.firstUserBodyRevision??null,bodyRevision:i,indexRevision:(n?.indexRevision??0)+1,...a,firstAvailableSeq:o?.firstAvailableSeq??n?.firstAvailableSeq??null,visibleMessageCount:o?.visibleMessageCount??n?.visibleMessageCount??0,lastVisibleMessageId:o?.lastVisibleMessageId??n?.lastVisibleMessageId??null,attentionCount:(n?.attentionCount??0)+(f?1:0),lastAttentionId:f?r:n?.lastAttentionId??null,seenAttentionIds:f&&r?[...l,r]:l,lastBodyCommittedAt:o?.lastBodyCommittedAt??n?.lastBodyCommittedAt??null,deletionRevision:n?.deletionRevision??0,deletedAt:t.deletedAt??n?.deletedAt??null,syncedIndexRevision:n?.syncedIndexRevision??0,indexSyncState:"pending",indexSyncStateRevision:(n?.indexRevision??0)+1,indexSyncAttempts:0,indexSyncNextAttemptAt:null,indexSyncErrorCode:null,indexQuarantineCode:null,titleGenerationAttemptedAt:n?.titleGenerationAttemptedAt&&n.titleGenerationNextAttemptAt!==void 0?n.titleGenerationAttemptedAt:null,titleGenerationNextAttemptAt:n?.titleGenerationNextAttemptAt??null,titleGenerationAttempts:n?.titleGenerationAttempts??0};return m.nativeSessionVisibility==="internal"&&m.agentSessionId&&L(m.sessionId,m.agentType,m.agentSessionId),e[t.sessionId]=m,S(e),m}function $(){return Object.values(d())}function le(t){if(!t)throw new Error("sessionId is required");const e=d();e[t]&&(delete e[t],S(e))}function re(t){u().purgeSession(t)}function Q(){const t=d();let e=!1;const n=new Date().toISOString();for(const[s,i]of Object.entries(t)){const o=w(i.title);if(o===i.title)continue;const a=i.indexRevision+1;t[s]={...i,title:o,indexRevision:a,indexSyncState:"pending",indexSyncStateRevision:a,indexSyncAttempts:0,indexSyncNextAttemptAt:null,indexSyncErrorCode:null,indexQuarantineCode:null,updatedAt:n},e=!0}e&&S(t)}function de(){const t=g();return J(),z(),Q(),$().filter(e=>{const n=e.indexSyncStateRevision===e.indexRevision;return e.indexQuarantineCode||n&&(e.indexSyncState==="quarantined"||e.indexSyncState==="terminal")||n&&e.indexSyncNextAttemptAt&&Date.parse(e.indexSyncNextAttemptAt)>Date.now()?!1:e.indexRevision>e.syncedIndexRevision&&e.localReady&&!!e.firstUserMessageId&&e.firstUserBodyRevision!=null}).sort((e,n)=>e.indexRevision-n.indexRevision).map(e=>{const n=!!(e.lastMessagePreview&&e.lastMessagePreviewMessageId&&e.lastMessagePreviewAt);return{protocolVersion:I,dataEpoch:x,daemonInstallationId:t,session:{id:e.sessionId,agentType:e.agentType,sessionMode:e.sessionMode,nativeSessionVisibility:e.nativeSessionVisibility,managerConfig:e.managerConfig,agentSessionId:e.agentSessionId??null,modelId:e.modelId??null,managerDefaultWorkerAgentType:e.managerDefaultWorkerAgentType??null,managerDefaultWorkerModelId:e.managerDefaultWorkerModelId??null,title:e.title,titleSource:e.titleSource,titleRevision:e.titleRevision,titleLockedByUser:e.titleLockedByUser,titleOriginEventId:e.titleOriginEventId,status:e.status??"active",workDir:e.workDir,lastMessagePreview:n?e.lastMessagePreview:null,lastMessagePreviewMessageId:n?e.lastMessagePreviewMessageId:null,lastMessagePreviewAt:n?e.lastMessagePreviewAt:null,lastVisibleEventAt:e.lastVisibleEventAt??e.lastMessagePreviewAt??null,bodyStorageMode:"machine_local",localReady:!0,firstUserBoundary:{role:"user",messageId:e.firstUserMessageId,bodyRevision:e.firstUserBodyRevision},bodyRevision:e.bodyRevision,indexRevision:e.indexRevision,firstAvailableSeq:e.firstAvailableSeq,visibleMessageCount:e.visibleMessageCount,lastVisibleMessageId:e.lastVisibleMessageId,attentionCount:e.attentionCount??0,lastAttentionId:e.lastAttentionId??null,lastBodyCommittedAt:e.lastBodyCommittedAt,deletionRevision:e.deletionRevision,lastActivityAt:e.lastActivityAt,createdAt:e.createdAt,updatedAt:e.updatedAt,deletedAt:e.deletedAt}}})}function ce(t,e){const n=d(),s=n[t];if(!(!s||e<=s.syncedIndexRevision)){if(e>s.indexRevision)throw new Error(`cannot acknowledge future index revision ${e} for ${t}`);n[t]={...s,syncedIndexRevision:e,indexSyncState:"applied",indexSyncStateRevision:e,indexSyncAttempts:0,indexSyncNextAttemptAt:null,indexSyncErrorCode:null},S(n)}}function ue(){const t=d();let e=0;const n=new Date().toISOString();for(const[s,i]of Object.entries(t)){if(i.deletedAt||i.indexQuarantineCode||!i.localReady)continue;const o=i.indexRevision+1;t[s]={...i,indexRevision:o,indexSyncState:"pending",indexSyncStateRevision:o,indexSyncAttempts:0,indexSyncNextAttemptAt:null,indexSyncErrorCode:null,updatedAt:n},e+=1}return e>0&&S(t),e}function ge(t){const e=d(),n=e[t.sessionId];if(!n||n.indexRevision!==t.indexRevision)return"terminal";const i=(n.indexSyncStateRevision===t.indexRevision?n.indexSyncAttempts??0:0)+1;let o=t.disposition;o==="retry"&&i>=(t.maxAttempts??8)&&(o="terminal");const a=t.now??Date.now(),r=Math.min(5e3*2**Math.max(0,i-1),360*60*1e3),l=Math.round(r*.2*(Math.random()*2-1));return e[t.sessionId]={...n,indexSyncState:o==="retry"?"pending":o,indexSyncStateRevision:t.indexRevision,indexSyncAttempts:i,indexSyncNextAttemptAt:o==="retry"?new Date(a+r+l).toISOString():null,indexSyncErrorCode:t.code,indexQuarantineCode:o==="quarantined"?t.code:n.indexQuarantineCode??null},S(e),o}const Y=2*6e4;function Se(t=Date.now(),e=Y){const n=d(),s=[],i=new Date(t).toISOString();for(const o of Object.values(n)){if(o.titleSource!=="first_user_fallback"||o.titleLockedByUser||o.titleGenerationAttemptedAt||!o.title.trim()||o.syncedIndexRevision<o.indexRevision||o.titleGenerationNextAttemptAt&&Date.parse(o.titleGenerationNextAttemptAt)>t)continue;const a=o.status==="completed"||o.status==="failed",r=o.visibleMessageCount>=2;let l=null;if(o.agentType==="claude"&&r?l="agent_native_unavailable":a?l="terminal":r&&t-Date.parse(o.createdAt)>=e&&(l="grace_elapsed"),!l)continue;const f=h(o.title,240);if(!f)continue;const v=D.randomUUID();n[o.sessionId]={...o,titleGenerationAttemptedAt:i,titleGenerationNextAttemptAt:null,titleGenerationAttempts:(o.titleGenerationAttempts??0)+1},s.push({sessionId:o.sessionId,requestId:v,titleSeed:f,baseTitleRevision:o.titleRevision,eligibility:l})}return s.length>0&&S(n),s}function fe(t,e=Date.now()){const n=d(),s=n[t];if(!s?.titleGenerationAttemptedAt||s.titleSource!=="first_user_fallback")return null;const i=Math.max(1,s.titleGenerationAttempts??1),o=Math.min(10*6e4,3e4*2**Math.min(i-1,5)),a=new Date(e+o).toISOString();return n[t]={...s,titleGenerationAttemptedAt:null,titleGenerationNextAttemptAt:a},S(n),a}function ve(t,e){const s=d()[t];return!s||s.titleLockedByUser||y[s.titleSource]>=y.shennian_generated||e.titleRevision<=s.titleRevision?!1:(W({sessionId:t,agentType:s.agentType,sessionMode:s.sessionMode,managerConfig:s.managerConfig,workDir:s.workDir,agentSessionId:s.agentSessionId,modelId:s.modelId,status:s.status,title:e.title,titleSource:"shennian_generated",titleRevision:e.titleRevision,titleLockedByUser:!1,titleOriginEventId:e.titleOriginEventId}),!0)}function me(t,e,n){A(t),g();const s=u().append(t,e,n);return N(t,e,s.bodyRevision),s.bodyRevision}function ye(t,e,n){A(t),g();const s=u().upsert(t,e,n);return N(t,e,s.bodyRevision),s.bodyRevision}function Ae(t,e){const n=u().getMessageState(t,e);return!n||n.tombstoned||!n.message||!n.deliveryState?{protocolVersion:I,dataEpoch:x,daemonInstallationId:g(),state:"not_found",sessionId:t,clientMessageId:e}:{protocolVersion:I,dataEpoch:x,daemonInstallationId:g(),state:n.deliveryState,sessionId:t,clientMessageId:e,messageId:n.message.id,deliveryState:n.deliveryState,bodyRevision:n.lastRevision,committedAt:new Date(n.message.ts).toISOString()}}function xe(t,e){A(t),g();const n=u().tombstone(t,e),s=d(),i=s[t];if(i){const o=e===i.lastMessagePreviewMessageId?V(t):{preview:i.lastMessagePreview??null,messageId:i.lastMessagePreviewMessageId??null,at:i.lastMessagePreviewAt??null};s[t]={...i,bodyRevision:n.bodyRevision,indexRevision:i.indexRevision+1,indexSyncState:"pending",indexSyncStateRevision:i.indexRevision+1,indexSyncAttempts:0,indexSyncNextAttemptAt:null,indexSyncErrorCode:null,updatedAt:new Date().toISOString(),lastMessagePreview:o.preview,lastMessagePreviewMessageId:o.messageId,lastMessagePreviewAt:o.at,lastVisibleEventAt:B(t)},S(s)}return n.bodyRevision}function N(t,e,n){const s=d(),i=s[t];if(!i)return;const o=b(e),a=o?{lastMessagePreview:o,lastMessagePreviewMessageId:e.id,lastMessagePreviewAt:new Date(e.ts).toISOString()}:null,r=o||P(e.payload)?new Date(e.ts).toISOString():i.lastVisibleEventAt,l=u().getManifest(t),f=e.role==="user"&&o&&!i.title?{title:w(o),titleSource:"first_user_fallback",titleRevision:i.titleRevision+1,titleLockedByUser:!1,titleOriginEventId:e.id}:null,v=e.role==="user"&&!i.localReady?{localReady:!0,firstUserMessageId:e.id,firstUserBodyRevision:n}:null;s[t]={...i,...f??{},...v??{},bodyRevision:n,indexRevision:i.indexRevision+1,indexSyncState:"pending",indexSyncStateRevision:i.indexRevision+1,indexSyncAttempts:0,indexSyncNextAttemptAt:null,indexSyncErrorCode:null,updatedAt:new Date().toISOString(),lastActivityAt:new Date(e.ts).toISOString(),lastVisibleEventAt:r,...a??{},firstAvailableSeq:l?.firstAvailableSeq??i.firstAvailableSeq,visibleMessageCount:l?.visibleMessageCount??i.visibleMessageCount,lastVisibleMessageId:l?.lastVisibleMessageId??i.lastVisibleMessageId,attentionCount:i.attentionCount??0,lastAttentionId:i.lastAttentionId??null,lastBodyCommittedAt:l?.lastBodyCommittedAt??i.lastBodyCommittedAt},S(s)}function V(t){let e;do{const n=u().readPage(t,{limit:500,beforeSequence:e});for(let s=n.entries.length-1;s>=0;s-=1){const i=n.entries[s],o=b(i.message);if(o)return{preview:o,messageId:i.message.id,at:new Date(i.message.ts).toISOString()}}if(!n.hasOlder||n.entries.length===0)break;e=n.entries[0].sequence}while(e!==void 0);return{preview:null,messageId:null,at:null}}function B(t){let e;do{const n=u().readPage(t,{limit:500,beforeSequence:e});for(let s=n.entries.length-1;s>=0;s-=1){const i=n.entries[s].message;if(!(!b(i)&&!P(i.payload)))return new Date(i.ts).toISOString()}if(!n.hasOlder||n.entries.length===0)break;e=n.entries[0].sequence}while(e!==void 0);return null}function z(){const t=d();let e=!1;const n=new Date().toISOString();for(const[s,i]of Object.entries(t)){if(Object.prototype.hasOwnProperty.call(i,"lastVisibleEventAt"))continue;const o=i.indexRevision+1;t[s]={...i,lastVisibleEventAt:B(s)??i.lastMessagePreviewAt??null,indexRevision:o,indexSyncState:"pending",indexSyncStateRevision:o,indexSyncAttempts:0,indexSyncNextAttemptAt:null,indexSyncErrorCode:null,updatedAt:n},e=!0}e&&S(t)}function J(){const t=d();let e=!1;const n=new Date().toISOString();for(const[s,i]of Object.entries(t)){if(Object.prototype.hasOwnProperty.call(i,"lastMessagePreviewMessageId")&&Object.prototype.hasOwnProperty.call(i,"lastMessagePreviewAt"))continue;const o=V(s);t[s]={...i,lastMessagePreview:o.preview,lastMessagePreviewMessageId:o.messageId,lastMessagePreviewAt:o.at,indexRevision:i.indexRevision+1,indexSyncState:"pending",indexSyncStateRevision:i.indexRevision+1,indexSyncAttempts:0,indexSyncNextAttemptAt:null,indexSyncErrorCode:null,updatedAt:n},e=!0}e&&S(t)}function H(t,e){const n={title:t?.title??"",titleSource:t?.titleSource??"first_user_fallback",titleRevision:t?.titleRevision??0,titleLockedByUser:t?.titleLockedByUser??!1,titleOriginEventId:t?.titleOriginEventId??null},s=w(e.title?.trim()??"");if(!s)return n;if(!e.titleSource)throw new Error("titleSource is required with title");if(n.title&&n.titleSource==="first_user_fallback"&&e.titleSource==="first_user_fallback")return n;const i=e.titleSource==="shennian_manual";if(e.titleLockedByUser!==void 0&&e.titleLockedByUser!==i)throw new Error("titleLockedByUser conflicts with titleSource");const o=s===n.title&&e.titleSource===n.titleSource,a=e.titleRevision??n.titleRevision+(o?0:1);if(!Number.isSafeInteger(a)||a<0)throw new Error("invalid titleRevision");const r=y[e.titleSource],l=y[n.titleSource];return r<l||a<n.titleRevision||o&&a===n.titleRevision||a===n.titleRevision&&!o?n:{title:s,titleSource:e.titleSource,titleRevision:a,titleLockedByUser:i,titleOriginEventId:e.titleOriginEventId??n.titleOriginEventId}}function Ie(t,e){const n=e?.limit&&e.limit>0?Math.min(e.limit,500):500;let i=u().readRecent(t,n).messages;return e?.before!==void 0&&(i=i.filter(o=>o.ts<e.before)),[...i].sort((o,a)=>a.ts-o.ts)}function pe(){return u().listSessionIds()}function we(){return u()}function X(t,e){const n=p.dirname(t);c.mkdirSync(n,{recursive:!0,mode:448});const s=`${t}.tmp-${process.pid}-${D.randomBytes(6).toString("hex")}`;let i;try{if(i=c.openSync(s,"wx",384),c.writeFileSync(i,`${JSON.stringify(e,null,2)}
2
+ `,"utf8"),c.fsyncSync(i),c.closeSync(i),i=void 0,c.renameSync(s,t),process.platform!=="win32"){const o=c.openSync(n,"r");try{c.fsyncSync(o)}finally{c.closeSync(o)}}}finally{i!==void 0&&c.closeSync(i);try{c.unlinkSync(s)}catch{}}}export{q as PERSONAL_SYNC_V1_ROOT_NAME,ce as acknowledgeSessionIndexUpdate,me as appendMessage,ve as applyGeneratedSessionTitle,Se as claimSessionTitleGenerationCandidates,fe as deferSessionTitleGeneration,we as getCanonicalSessionStore,g as getDaemonInstallationId,Ae as getMessageDeliveryStatus,de as listPendingSessionIndexUpdates,$ as listSessionRecords,pe as listSessions,ue as markAllSessionIndexesForRepublish,re as purgeCanonicalSession,le as purgeSessionRecord,Ie as readMessages,W as recordSession,ge as recordSessionIndexRejection,xe as tombstoneMessage,ye as upsertMessage};
@@ -47,6 +47,7 @@ export type ChatQueueService = {
47
47
  handleEdit(req: import('@shennian/wire').ReqFrame): Promise<void>;
48
48
  handleDelete(req: import('@shennian/wire').ReqFrame): Promise<void>;
49
49
  handlePromote(req: import('@shennian/wire').ReqFrame): Promise<void>;
50
+ noteExternalClaim(sessionId: string, canonicalMessageId: string): void;
50
51
  noteTerminal(sessionId: string): void;
51
52
  purgeSession(sessionId: string): void;
52
53
  getSnapshot(sessionId: string): import('@shennian/wire').ChatQueueSnapshot;