shennian 0.4.9 → 0.4.10

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.
@@ -46,8 +46,8 @@
46
46
  },
47
47
  {
48
48
  "file": "src/agents/codex.js",
49
- "beforeBytes": 65656,
50
- "afterBytes": 33627
49
+ "beforeBytes": 65975,
50
+ "afterBytes": 33808
51
51
  },
52
52
  {
53
53
  "file": "src/agents/command-spec.js",
@@ -646,8 +646,8 @@
646
646
  },
647
647
  {
648
648
  "file": "src/session/handlers/chat.js",
649
- "beforeBytes": 43941,
650
- "afterBytes": 18277
649
+ "beforeBytes": 44520,
650
+ "afterBytes": 18490
651
651
  },
652
652
  {
653
653
  "file": "src/session/handlers/control.js",
@@ -38,6 +38,8 @@ export type AgentSendContext = {
38
38
  export type AgentStartOptions = {
39
39
  /** Test-only callers can disable provider-native history persistence. */
40
40
  persistNativeSession?: boolean;
41
+ /** Keep an internal orchestration session out of the provider's user-facing task list. */
42
+ nativeSessionVisibility?: 'user' | 'internal';
41
43
  };
42
44
  export interface AgentAdapterEvents {
43
45
  agentEvent: [event: AgentEvent];
@@ -50,6 +50,7 @@ export declare class CodexAdapter extends AgentAdapter {
50
50
  private managedTurnReplay;
51
51
  private managedAsyncRecovery;
52
52
  private persistNativeSession;
53
+ private nativeSessionVisibility;
53
54
  constructor(options?: {
54
55
  modelInstructionsFile?: string;
55
56
  hidden?: boolean;
@@ -1,12 +1,12 @@
1
- import{spawnSync as O}from"node:child_process";import{createInterface as S}from"node:readline";import{createHash as w,randomUUID as b}from"node:crypto";import g from"node:path";import{AgentAdapter as q,registerAgent as N}from"./adapter.js";import{resolveBuiltinCommand as y,spawnAgentCommand as x}from"./command-spec.js";import{buildAgentProcessEnv as D,buildManagedAgentProcessEnv as L}from"../agent-env.js";import{ensurePlatformInstructionsFile as F}from"./platform-instructions.js";import{CODEX_DESKTOP_SEND_UNAVAILABLE as C}from"@shennian/wire";import{isCodexThreadTailInterrupted as $}from"../native-fusion/codex-files.js";import{resolveManagedAgentAdapterEnforcement as U}from"../security/managed-agent-policy.js";import{registerManagedAgentRuntimeSecurity as W}from"../security/managed-agent-runtime.js";import{CODEX_MANAGED_ROOM_DYNAMIC_TOOLS as z,CodexManagedRoomToolBinding as B}from"./codex-managed-room-tools.js";import{assertCodexManagedPermissionProfile as R,CODEX_MANAGED_RUNTIME_SECURITY as G,compileCodexManagedPermissions as J,extractCodexMcpServerNames as H}from"./codex-managed-permissions.js";import{CODEX_APP_SERVER_CLIENT_INFO as V,extractAppServerErrorMessage as E,formatCodexErrorMessage as X,formatTransientCodexStatus as K,isCodexCollabAgentItem as Q,isCodexCollabAgentToolName as T,isCodexLegacyCollabAgentItem as Y,isCodexUnsupportedEffortError as j,isMissingCodexRolloutError as v,isTransientCodexErrorMessage as Z,looksLikeCodexInteractiveAuthPrompt as ee,looksLikeFatalCodexStderr as te,normalizeCodexModelId as I,normalizeCodexReasoningEffort as re,normalizeCodexStderr as _,normalizeTerminalText as se,safeStringify as k,stripGitDirectiveArtifacts as ne}from"./codex-utils.js";import{isCodexUnsupportedEffortError as be,isMissingCodexRolloutError as qe,normalizeCodexModelId as Ne,normalizeCodexReasoningEffort as De}from"./codex-utils.js";W("codex",G);function P(o){const e=o instanceof Error?o.message:String(o);return/already has an active writer|thread-store conflict/i.test(e)}function ie(o){const e=o instanceof Error?o.message:String(o);return/paginated(?:_threads|\s+(?:thread\s+)?history)?.*(?:not supported|unsupported|unavailable)/i.test(e)||/(?:not supported|unsupported|unavailable).*paginated(?:_threads|\s+(?:thread\s+)?history)?/i.test(e)}function oe(o){const e=o instanceof Error?o.message:String(o);return/unknown field [`'"]?excludeTurns/i.test(e)||/excludeTurns.*(?:not supported|unsupported|unavailable)/i.test(e)}function ae(o){const e=o instanceof Error?o.message:String(o);return/(?:method not found|unknown method).*(?:project\/list|project\/create)/i.test(e)||/(?:project\/list|project\/create).*(?:not supported|unsupported|unavailable)/i.test(e)}function de(o,e){const t=g.resolve(e);let r;for(const s of o)if(s.id)for(const i of s.roots??[]){if(!i.path)continue;const n=g.resolve(i.path),a=g.relative(n,t);!(a===""||!a.startsWith("..")&&!g.isAbsolute(a))||n.length<=(r?.rootLength??-1)||(r={id:s.id,rootLength:n.length})}return r?.id}function le(o,e){const t=e?.flatMap(s=>ce(s)).filter(s=>!/^https?:\/\//i.test(s.path)).filter(s=>s.path);return{type:"text",text:he(o,e),text_elements:[],...t?.length?{local_images:t}:{}}}function ce(o){if(o.kind==="image")return o.previewData?[{path:o.path,data:o.previewData,mimeType:o.mimeType}]:[{path:o.path}];if(o.mimeType.startsWith("video/")){const e=ue(o.path);return e?[{path:e}]:[]}return[]}function ue(o){if(!o||/^https?:\/\//i.test(o))return null;const e=g.extname(o),r=`${e?o.slice(0,-e.length):o}.preview.png`;return O("ffmpeg",["-y","-ss","0","-i",o,"-frames:v","1","-vf","scale=320:-1",r],{stdio:"ignore",timeout:15e3}).status===0?r:null}function he(o,e){const t=e?.filter(i=>i.kind!=="image").filter(i=>i.path&&!/^https?:\/\//i.test(i.path));if(!t?.length||t.every(i=>o.includes(i.path)))return o;const s=t.map((i,n)=>{const a=i.name||`attachment-${n+1}`,d=i.mimeType?` (${i.mimeType})`:"";return`[${A(a)}${d}](<${i.path}>)`});return[o,"",...s].join(`
1
+ import{spawnSync as b}from"node:child_process";import{createInterface as S}from"node:readline";import{createHash as w,randomUUID as O}from"node:crypto";import g from"node:path";import{AgentAdapter as q,registerAgent as N}from"./adapter.js";import{resolveBuiltinCommand as T,spawnAgentCommand as x}from"./command-spec.js";import{buildAgentProcessEnv as D,buildManagedAgentProcessEnv as L}from"../agent-env.js";import{ensurePlatformInstructionsFile as F}from"./platform-instructions.js";import{CODEX_DESKTOP_SEND_UNAVAILABLE as C}from"@shennian/wire";import{isCodexThreadTailInterrupted as $}from"../native-fusion/codex-files.js";import{resolveManagedAgentAdapterEnforcement as U}from"../security/managed-agent-policy.js";import{registerManagedAgentRuntimeSecurity as W}from"../security/managed-agent-runtime.js";import{CODEX_MANAGED_ROOM_DYNAMIC_TOOLS as z,CodexManagedRoomToolBinding as B}from"./codex-managed-room-tools.js";import{assertCodexManagedPermissionProfile as R,CODEX_MANAGED_RUNTIME_SECURITY as G,compileCodexManagedPermissions as V,extractCodexMcpServerNames as J}from"./codex-managed-permissions.js";import{CODEX_APP_SERVER_CLIENT_INFO as H,extractAppServerErrorMessage as E,formatCodexErrorMessage as X,formatTransientCodexStatus as K,isCodexCollabAgentItem as Q,isCodexCollabAgentToolName as v,isCodexLegacyCollabAgentItem as Y,isCodexUnsupportedEffortError as j,isMissingCodexRolloutError as y,isTransientCodexErrorMessage as Z,looksLikeCodexInteractiveAuthPrompt as ee,looksLikeFatalCodexStderr as te,normalizeCodexModelId as I,normalizeCodexReasoningEffort as re,normalizeCodexStderr as _,normalizeTerminalText as se,safeStringify as k,stripGitDirectiveArtifacts as ne}from"./codex-utils.js";import{isCodexUnsupportedEffortError as Oe,isMissingCodexRolloutError as qe,normalizeCodexModelId as Ne,normalizeCodexReasoningEffort as De}from"./codex-utils.js";W("codex",G);function P(o){const e=o instanceof Error?o.message:String(o);return/already has an active writer|thread-store conflict/i.test(e)}function ie(o){const e=o instanceof Error?o.message:String(o);return/paginated(?:_threads|\s+(?:thread\s+)?history)?.*(?:not supported|unsupported|unavailable)/i.test(e)||/(?:not supported|unsupported|unavailable).*paginated(?:_threads|\s+(?:thread\s+)?history)?/i.test(e)}function oe(o){const e=o instanceof Error?o.message:String(o);return/unknown field [`'"]?excludeTurns/i.test(e)||/excludeTurns.*(?:not supported|unsupported|unavailable)/i.test(e)}function ae(o){const e=o instanceof Error?o.message:String(o);return/(?:method not found|unknown method).*(?:project\/list|project\/create)/i.test(e)||/(?:project\/list|project\/create).*(?:not supported|unsupported|unavailable)/i.test(e)}function de(o,e){const t=g.resolve(e);let r;for(const s of o)if(s.id)for(const i of s.roots??[]){if(!i.path)continue;const n=g.resolve(i.path),a=g.relative(n,t);!(a===""||!a.startsWith("..")&&!g.isAbsolute(a))||n.length<=(r?.rootLength??-1)||(r={id:s.id,rootLength:n.length})}return r?.id}function le(o,e){const t=e?.flatMap(s=>ce(s)).filter(s=>!/^https?:\/\//i.test(s.path)).filter(s=>s.path);return{type:"text",text:he(o,e),text_elements:[],...t?.length?{local_images:t}:{}}}function ce(o){if(o.kind==="image")return o.previewData?[{path:o.path,data:o.previewData,mimeType:o.mimeType}]:[{path:o.path}];if(o.mimeType.startsWith("video/")){const e=ue(o.path);return e?[{path:e}]:[]}return[]}function ue(o){if(!o||/^https?:\/\//i.test(o))return null;const e=g.extname(o),r=`${e?o.slice(0,-e.length):o}.preview.png`;return b("ffmpeg",["-y","-ss","0","-i",o,"-frames:v","1","-vf","scale=320:-1",r],{stdio:"ignore",timeout:15e3}).status===0?r:null}function he(o,e){const t=e?.filter(i=>i.kind!=="image").filter(i=>i.path&&!/^https?:\/\//i.test(i.path));if(!t?.length||t.every(i=>o.includes(i.path)))return o;const s=t.map((i,n)=>{const a=i.name||`attachment-${n+1}`,d=i.mimeType?` (${i.mimeType})`:"";return`[${A(a)}${d}](<${i.path}>)`});return[o,"",...s].join(`
2
2
  `)}function pe(o,e){const t=e?.filter(s=>s.path&&!/^https?:\/\//i.test(s.path)&&!o.includes(s.path));if(!t?.length)return o;const r=t.map((s,i)=>{const n=A(s.name||`attachment-${i+1}`);return s.kind==="image"?`![${n}](<${s.path}>)`:`[${n}](<${s.path}>)`});return[o,"",...r].join(`
3
- `)}function me(o,e,t){return["queue","--thread",o,"--message",pe(e,t)]}function A(o){return o.replace(/[[\]\\]/g,"\\$&")}class ge extends q{options;type="codex";process=null;workDir=null;seq=0;runId="";pendingUsage;agentSessionId=null;hasEmittedText=!1;textTail="";terminalState="open";forceCloseTimer=null;stderrBuf="";rpcSeq=1;pendingRequests=new Map;appServerReady=null;appServerStartupError=null;activeTurnId=null;deltaItemIds=new Set;lastTransientStatus="";agentSystemPrompt="";managedAgentPolicy=null;managedPermissionConfig=null;configurationRestartRequired=!1;managedRoomTools=new B;configuredManagedRoomContextToken=null;configuredManagedRoomExecutor=null;managedRoomToolThreadId=null;preparedExternalOwnerThreadId=null;managedTurnReplay=null;managedAsyncRecovery=null;persistNativeSession=!0;constructor(e={}){super(),this.options=e}externalChannel=null;shennianSessionId=null;extraEnv={};configure(e){const t=this.configurationFingerprint();this.shennianSessionId=e.sessionId??null,this.externalChannel=e.externalChannel??null,this.extraEnv=e.env??{},"managedAgentPolicy"in e&&(this.managedAgentPolicy=e.managedAgentPolicy??null),("managedRoomContextToken"in e||"managedRoomExecutor"in e)&&(this.managedRoomTools.deactivateTurn(),this.configuredManagedRoomContextToken=e.managedRoomContextToken?.trim()||null,this.configuredManagedRoomExecutor=e.managedRoomExecutor??null),this.managedAgentPolicy&&(this.workDir=this.managedAgentPolicy.adapterPolicy.workDir);const r=this.configurationFingerprint();t!==r&&this.process&&(this.configurationRestartRequired=!0)}configurationFingerprint(){const e=Object.keys(this.extraEnv).sort().map(t=>[t,this.extraEnv[t]??null]);return w("sha256").update(JSON.stringify({sessionId:this.shennianSessionId,externalChannel:this.externalChannel,env:e,managedAgentPolicy:this.managedAgentPolicy})).digest("hex")}buildProcessEnv(e={}){if(!this.managedAgentPolicy)return D({...e,...this.extraEnv});const t=Object.fromEntries(Object.entries(this.extraEnv).filter(([r])=>r!=="SHENNIAN_MANAGED_ROOM_CONTEXT"&&r!=="SHENNIAN_MANAGED_ROOM_IPC_ROOT"));return L({agentType:"codex",providerEnv:t,sessionEnv:t,runtimeEnv:e})}async start(e,t,r,s){this.workDir=this.managedAgentPolicy?.adapterPolicy.workDir??t,this.seq=0,this.persistNativeSession=s?.persistNativeSession!==!1,r&&(this.agentSessionId=r)}async prepareSend(e,t,r,s,i,n){const a=i?.trim()??"";if(a!==this.agentSystemPrompt&&(this.agentSystemPrompt=a,this.process&&await this.killProcess(!0)),!(!this.agentSessionId||this.activeTurnId)){this.preparedExternalOwnerThreadId=null;try{await this.ensureAppServer(I(t))}catch(d){if(!P(d))throw d;if(n?.source==="room_activation")throw new Error("codex_managed_thread_owned_externally",{cause:d});if(this.isThreadTailInterrupted(this.agentSessionId))throw new Error(C,{cause:d});this.preparedExternalOwnerThreadId=this.agentSessionId}}}async send(e,t,r,s,i,n){if(n?.source==="room_activation"&&!this.managedAgentPolicy)throw new Error("managed_agent_policy_missing");if(n?.source==="room_activation"&&(!this.configuredManagedRoomContextToken||!this.configuredManagedRoomExecutor))throw new Error("codex_managed_room_tool_context_unavailable");this.activeTurnId&&(await this.interruptActiveTurn().catch(()=>{}),await this.killProcess(!0)),this.configurationRestartRequired&&this.process&&await this.killProcess(!0),this.configurationRestartRequired=!1;const a=I(t),d=re(r),c=i?.trim()??"";if(c!==this.agentSystemPrompt&&(this.agentSystemPrompt=c,this.process&&await this.killProcess(!0)),n?.source==="room_activation"&&this.managedRoomTools.configure(this.configuredManagedRoomContextToken,this.configuredManagedRoomExecutor),this.runId=b(),this.seq=0,this.resetRunState(),this.agentSessionId&&this.preparedExternalOwnerThreadId===this.agentSessionId)return this.preparedExternalOwnerThreadId=null,{deliveryMode:"external_owner_queue",queuedSubmissionId:await this.enqueueForExternalOwner(this.agentSessionId,e,s)};try{await this.ensureAppServer(a)}catch(h){if(!this.agentSessionId||!P(h))throw h;if(n?.source==="room_activation")throw new Error("codex_managed_thread_owned_externally",{cause:h});if(this.isThreadTailInterrupted(this.agentSessionId))throw new Error(C,{cause:h});return{deliveryMode:"external_owner_queue",queuedSubmissionId:await this.enqueueForExternalOwner(this.agentSessionId,e,s)}}const l=this.agentSessionId;if(!l)throw new Error("codex app-server did not create a thread");this.emitEvent({state:"start",agentSessionId:l}),this.managedTurnReplay=this.managedPermissionConfig?{text:e,modelId:a,reasoningEffort:d,attachments:s,recoveryCount:0}:null;const p=await this.startTurnWithRecovery(l,e,a,d,s),m=this.agentSessionId??l;if(this.activeTurnId=p.turn?.id??null,this.managedRoomToolThreadId===m&&this.activeTurnId&&!this.managedRoomTools.bindTurn(m,this.activeTurnId))throw await this.killProcess(),new Error("codex_managed_room_turn_binding_failed");return{deliveryMode:"direct"}}isThreadTailInterrupted(e){return this.options.isThreadTailInterrupted?.(e)??$(e)}async enqueueForExternalOwner(e,t,r){const s=y("codex");if(!s)throw new Error('Command "codex" not found. Is OpenAI Codex CLI installed?');const i=me(e,t,r),n=x(s,i,{cwd:this.workDir??void 0,stdio:["ignore","pipe","pipe"],env:this.buildProcessEnv({NO_COLOR:"1"})});return await new Promise((a,d)=>{let c="",l="",p=!1;const m=(u,f)=>{p||(p=!0,clearTimeout(h),u?d(u):a(f))},h=setTimeout(()=>{n.kill("SIGTERM"),m(new Error("Codex Desktop message queue timed out"))},6e4);h.unref?.(),n.stdout?.on("data",u=>{c+=u.toString()}),n.stderr?.on("data",u=>{l+=u.toString()}),n.once("error",u=>m(u)),n.once("close",u=>{const f=`${c}
4
- ${l}`.trim();if(u!==0){m(new Error(f||`codex queue exited with code ${u??"unknown"}`));return}const M=f.match(/Queued message\s+([^\s]+)\s+for thread/i)?.[1];m(void 0,M)})})}async resume(e){await this.killProcess(),this.agentSessionId=e,this.resetTextState()}async setTitle(e,t,r){const s=e.trim(),i=t.replace(/\s+/g," ").trim();!s||!i||(this.agentSessionId=s,r?.trim()&&(this.workDir=r),await this.ensureAppServer(),await this.sendRpc("thread/name/set",{threadId:s,name:i}))}async stop(){this.managedRoomTools.deactivateTurn(),await this.interruptActiveTurn().catch(()=>{}),await this.killProcess()}async getStatus(){const e=this.agentSessionId,t=this.activeTurnId;if(!e||!this.process)return{active:!1,runId:t,runPhase:null,canStop:!1};let r=null;try{r=(await this.sendRpc("thread/read",{threadId:e,includeTurns:!1},5e3)).thread?.status??null}catch{}const s=r?.type==="active"||!!t;return{active:s,runId:t,runPhase:s?this.mapThreadStatusToRunPhase(r):null,canStop:!!(s&&t&&this.process)}}spawnCodex(e){const t=y("codex");if(!t){this.emit("error",new Error('Command "codex" not found. Is OpenAI Codex CLI installed?'));return}const r=x(t,e,{cwd:this.workDir??void 0,stdio:["ignore","pipe","pipe"],env:this.buildProcessEnv()});this.process=r,S({input:r.stdout}).on("line",n=>{if(n.trim())try{const a=JSON.parse(n);this.handleStreamEvent(a)}catch{this.emitEvent({state:"delta",text:n})}});let i="";r.stderr?.on("data",n=>{i+=n.toString()}),r.on("close",n=>{this.process===r&&(this.process=null,this.clearForceCloseTimer(),this.handleProcessClose(n,i))}),r.on("error",n=>{this.process===r&&(this.process=null,n.code==="ENOENT"?this.emit("error",new Error('Command "codex" not found. Is OpenAI Codex CLI installed?')):this.emit("error",n))})}spawnAppServer(){const e=y("codex");if(!e){this.emit("error",new Error('Command "codex" not found. Is OpenAI Codex CLI installed?'));return}const t=["app-server","--listen","stdio://"],r=this.options.modelInstructionsFile??F(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,this.agentSystemPrompt);r&&t.push("-c",`model_instructions_file=${JSON.stringify(r)}`);const s=x(e,t,{cwd:this.workDir??void 0,stdio:["pipe","pipe","pipe"],env:this.buildProcessEnv({NO_COLOR:"1"})});this.process=s,this.stderrBuf="",this.appServerStartupError=null,S({input:s.stdout}).on("line",n=>{if(!n.trim())return;let a;try{a=JSON.parse(n)}catch{this.handleAppServerNonJsonStdout(n);return}this.handleAppServerMessage(a)}),s.stderr?.on("data",n=>{this.stderrBuf+=n.toString()}),s.on("close",n=>{if(this.process!==s)return;const a=this.activeTurnId!=null;this.process=null,this.appServerReady=null,this.activeTurnId=null,this.managedRoomTools.reset(),this.clearConfiguredManagedRoomContext(),this.rejectAllPending(new Error(_(this.stderrBuf)||`codex app-server exited with code ${n}`)),this.terminalState==="open"&&a&&this.handleProcessClose(n,this.stderrBuf)}),s.on("error",n=>{this.process===s&&(this.process=null,this.managedRoomTools.reset(),this.clearConfiguredManagedRoomContext(),this.rejectAllPending(n),n.code==="ENOENT"?this.emit("error",new Error('Command "codex" not found. Is OpenAI Codex CLI installed?')):this.emit("error",n))})}async ensureAppServer(e){return this.appServerReady?this.appServerReady:(this.spawnAppServer(),this.appServerReady=this.initializeAppServer(e).catch(async t=>{throw this.appServerReady=null,await this.killProcess(),t}),this.appServerReady)}async initializeAppServer(e){const t=I(e);await this.sendRpc("initialize",{clientInfo:V,capabilities:{experimentalApi:!0}}),this.managedPermissionConfig=this.managedAgentPolicy?await this.buildManagedPermissionConfig():null;const r=!!(this.configuredManagedRoomContextToken||this.configuredManagedRoomExecutor);if(this.managedPermissionConfig&&r&&!this.managedRoomTools.isConfigured()&&(this.managedRoomTools.configure(this.configuredManagedRoomContextToken,this.configuredManagedRoomExecutor),!this.managedRoomTools.isConfigured()))throw new Error("codex_managed_room_tool_context_unavailable");if(this.agentSessionId&&this.managedPermissionConfig&&r&&this.agentSessionId!==this.managedRoomToolThreadId){if(!this.managedRoomTools.isConfigured())throw new Error("codex_managed_room_tool_context_unavailable");this.agentSessionId=null}if(this.agentSessionId){const c={threadId:this.agentSessionId,cwd:this.workDir,approvalPolicy:"never",...this.managedPermissionConfig?{config:this.managedPermissionConfig.threadConfig}:{sandbox:"danger-full-access"},persistExtendedHistory:!0,...this.options.hidden||!this.persistNativeSession?{threadSource:"subagent"}:{},...t?{model:t}:{}};let l;try{l=await this.sendRpc("thread/resume",{...c,excludeTurns:!0})}catch(p){if(!oe(p))throw p;l=await this.sendRpc("thread/resume",c)}this.agentSessionId=l.thread?.id??this.agentSessionId,this.managedPermissionConfig&&(R(l,this.managedPermissionConfig.profileId),r&&(this.managedRoomTools.bindThread(this.agentSessionId),this.managedRoomToolThreadId=this.agentSessionId));return}const s=this.options.hidden||!this.persistNativeSession,i=s?void 0:await this.resolveCodexProjectId(),n={cwd:this.workDir,approvalPolicy:"never",...this.managedPermissionConfig?{config:this.managedPermissionConfig.threadConfig}:{sandbox:"danger-full-access"},serviceName:"Shennian",threadSource:s?"subagent":"user",experimentalRawEvents:!1,persistExtendedHistory:!0,...this.managedPermissionConfig&&r?{dynamicTools:z}:{},...i?{projectId:i}:{},...t?{model:t}:{}};let a;if(s&&!this.managedPermissionConfig)a=await this.sendRpc("thread/start",n);else try{a=await this.sendRpc("thread/start",{...n,historyMode:"paginated"})}catch(c){throw ie(c)?new Error("\u5F53\u524D Codex CLI \u4E0D\u652F\u6301\u521B\u5EFA\u53EF\u5728 Codex Desktop \u4E2D\u7EE7\u7EED\u7684\u65B0\u4F1A\u8BDD\uFF0C\u8BF7\u624B\u52A8\u5347\u7EA7 Codex CLI \u540E\u91CD\u8BD5\u3002\u795E\u5FF5\u4E0D\u4F1A\u81EA\u52A8\u5347\u7EA7\uFF0C\u4E5F\u4E0D\u4F1A\u964D\u7EA7\u521B\u5EFA\u4E0D\u53EF\u89C1\u7684 legacy \u4F1A\u8BDD\u3002",{cause:c}):c}const d=a.thread?.id;if(!d)throw new Error("codex app-server thread/start returned no thread id");this.managedPermissionConfig&&(R(a,this.managedPermissionConfig.profileId),r&&(this.managedRoomTools.bindThread(d),this.managedRoomToolThreadId=d)),this.agentSessionId=d}async buildManagedPermissionConfig(){const e=this.managedAgentPolicy;if(!e)throw new Error("managed_agent_policy_missing");const t=e.adapterPolicy.externalCapabilities.mcp?[]:H(await this.sendRpc("config/read",{cwd:e.adapterPolicy.workDir}));return J(U(e),e.adapterPolicy.workDir,{configuredMcpServerNames:t,shellSubprocessPolicy:e.environmentPolicy.shellSubprocess})}async resolveCodexProjectId(){const e=this.workDir?.trim();if(e)try{const t=[];let r;do{const c=await this.sendRpc("project/list",{limit:100,...r?{cursor:r}:{}});t.push(...c.data??[]),r=c.nextCursor}while(r);const s=de(t,e);if(s)return s;const i=g.resolve(e),n=`shennian-project-${w("sha256").update(i).digest("hex")}`,d=(await this.sendRpc("project/create",{idempotencyKey:n,name:g.basename(i)||i,roots:[{path:i}],metadata:{createdBy:"Shennian"}})).project?.id;if(!d)throw new Error("codex app-server project/create returned no project id");return d}catch(t){throw ae(t)?new Error("\u5F53\u524D Codex CLI \u4E0D\u652F\u6301\u521B\u5EFA\u53EF\u5F52\u5C5E\u5230 Codex Desktop \u9879\u76EE\u7684\u65B0\u4F1A\u8BDD\uFF0C\u8BF7\u624B\u52A8\u5347\u7EA7 Codex CLI \u540E\u91CD\u8BD5\u3002\u795E\u5FF5\u4E0D\u4F1A\u81EA\u52A8\u5347\u7EA7\uFF0C\u4E5F\u4E0D\u4F1A\u76F4\u63A5\u4FEE\u6539 Codex Desktop \u7684\u79C1\u6709\u4FA7\u680F\u7D22\u5F15\u3002",{cause:t}):t}}async startTurnWithRecovery(e,t,r,s,i){try{return await this.startTurn(e,t,r,s,i)}catch(n){if(!v(n))throw n;if(this.managedPermissionConfig){this.logManagedThreadLifecycle("rollout.missing",{threadId:e,recovery:"recreate"}),await this.killProcess(!0),this.agentSessionId=null,this.managedRoomToolThreadId=null,await this.ensureAppServer(r);const a=this.agentSessionId;if(!a)throw new Error("codex app-server did not recreate the managed thread",{cause:n});return this.logManagedThreadLifecycle("thread.recreated",{previousThreadId:e,threadId:a}),this.emitEvent({state:"start",agentSessionId:a}),await this.startFreshManagedTurnWithReadinessRetry(a,t,r,s,i)}return await this.killProcess(),await this.ensureAppServer(r),await this.startTurn(e,t,r,s,i)}}async startFreshManagedTurnWithReadinessRetry(e,t,r,s,i){const n=[0,100,300,1e3];let a;for(let d=0;d<n.length;d+=1){const c=n[d];c>0&&await new Promise(l=>setTimeout(l,c));try{const l=await this.startTurn(e,t,r,s,i);return d>0&&this.logManagedThreadLifecycle("rollout.ready",{threadId:e,attempt:d+1}),l}catch(l){if(a=l,!v(l)||d===n.length-1)throw l;this.logManagedThreadLifecycle("rollout.retry",{threadId:e,attempt:d+2,delayMs:n[d+1]})}}throw a}logManagedThreadLifecycle(e,t){console.error(`[codex.managed] ${JSON.stringify({event:e,...t})}`)}async startTurn(e,t,r,s,i){try{return await this.sendRpc("turn/start",{threadId:e,input:[le(t,i)],approvalPolicy:"never",...this.managedPermissionConfig?{}:{sandboxPolicy:{type:"dangerFullAccess"}},...r?{model:r}:{},...s?{effort:s}:{}})}catch(n){throw s&&j(n)?new Error(`Codex app-server does not accept reasoning effort "${s}" for this turn. Refresh models or upgrade Codex CLI, then retry.`,{cause:n}):n}}async interruptActiveTurn(){const e=this.agentSessionId,t=this.activeTurnId;this.activeTurnId=null,this.managedRoomTools.deactivateTurn(),!(!e||!t||!this.process)&&await this.sendRpc("turn/interrupt",{threadId:e,turnId:t},5e3)}sendRpc(e,t,r=6e4){if(this.appServerStartupError)return Promise.reject(this.appServerStartupError);const s=this.process;if(!s?.stdin)return Promise.reject(new Error("codex app-server is not running"));const i=this.rpcSeq++,n=JSON.stringify({id:i,method:e,params:t});return new Promise((a,d)=>{const c=setTimeout(()=>{this.pendingRequests.delete(i),d(new Error(`codex app-server request timed out: ${e}`))},r);this.pendingRequests.set(i,{resolve:a,reject:d,timer:c}),s.stdin.write(`${n}
5
- `,l=>{l&&(clearTimeout(c),this.pendingRequests.delete(i),d(l))})})}handleAppServerMessage(e){if(e.method==="item/tool/call"&&e.id!=null){this.handleManagedRoomToolCall(e.id,e.params??{});return}if(e.id!=null){const r=typeof e.id=="number"?this.pendingRequests.get(e.id):void 0;r&&(clearTimeout(r.timer),this.pendingRequests.delete(e.id),e.error?r.reject(new Error(e.error.message||`codex app-server error ${e.error.code??""}`.trim())):r.resolve(e.result))}if(!e.method)return;const t=e.params??{};switch(e.method){case"turn/started":{const r=typeof t.turn=="object"&&t.turn!==null?t.turn:null,s=typeof r?.id=="string"?r.id:null,i=typeof t.threadId=="string"?t.threadId:"";s&&(this.activeTurnId=s,this.managedRoomToolThreadId===i&&!this.managedRoomTools.bindTurn(i,s)&&this.emitErrorIfOpen("codex_managed_room_turn_binding_failed"));break}case"thread/status/changed":{const r=typeof t.threadId=="string"?t.threadId:"";if(r&&this.agentSessionId&&r!==this.agentSessionId)break;const s=typeof t.status=="object"&&t.status!==null?t.status:null;s?.type==="active"&&this.emitEvent({state:"heartbeat",runPhase:this.mapThreadStatusToRunPhase(s)});break}case"item/agentMessage/delta":{const r=typeof t.itemId=="string"?t.itemId:"";r&&this.deltaItemIds.add(r),typeof t.delta=="string"&&this.emitText(t.delta);break}case"item/completed":this.handleAppServerCompletedItem(t);break;case"thread/tokenUsage/updated":this.handleAppServerUsage(t);break;case"turn/completed":{const r=typeof t.turn=="object"&&t.turn!==null?t.turn:null,s=typeof r?.id=="string"?r.id:null;(!this.activeTurnId||s===this.activeTurnId)&&(this.activeTurnId=null,this.managedRoomTools.deactivateTurn(),this.emitFinalIfOpen());break}case"turn/failed":{const r=E(t);if(this.scheduleManagedAsyncRolloutRecovery(r))return;this.emitErrorIfOpen(r||"turn failed");break}case"error":{const r=E(t);if(Z(r)){this.emitTransientStatus(r);return}if(this.scheduleManagedAsyncRolloutRecovery(r))return;this.emitErrorIfOpen(r);break}}}scheduleManagedAsyncRolloutRecovery(e){if(!this.managedPermissionConfig||!this.managedTurnReplay||!v(new Error(e)))return!1;if(this.managedAsyncRecovery)return!0;if(this.managedTurnReplay.recoveryCount>=2)return!1;this.managedTurnReplay.recoveryCount+=1;const t=this.managedTurnReplay.recoveryCount;return this.logManagedThreadLifecycle("rollout.failed-async",{threadId:this.agentSessionId,recoveryCount:t}),this.managedAsyncRecovery=this.recoverManagedTurnAfterAsyncRolloutFailure().catch(r=>{const s=v(r)?"no rollout found after managed thread recovery":r instanceof Error?r.message:"managed thread recovery failed";this.emitErrorIfOpen(s)}).finally(()=>{this.managedAsyncRecovery=null}),!0}async recoverManagedTurnAfterAsyncRolloutFailure(){const e=this.managedTurnReplay,t=this.agentSessionId;if(!e||!t||this.terminalState!=="open")return;this.activeTurnId=null,this.managedRoomTools.deactivateTurn(),await this.killProcess(!0),this.agentSessionId=null,this.managedRoomToolThreadId=null,await this.ensureAppServer(e.modelId);const r=this.agentSessionId;if(!r)throw new Error("codex app-server did not recreate the managed thread");this.logManagedThreadLifecycle("thread.recreated-async",{previousThreadId:t,threadId:r,recoveryCount:e.recoveryCount}),this.emitEvent({state:"start",agentSessionId:r});const s=await this.startFreshManagedTurnWithReadinessRetry(r,e.text,e.modelId,e.reasoningEffort,e.attachments);if(this.activeTurnId=s.turn?.id??null,this.managedRoomToolThreadId===r&&this.activeTurnId&&!this.managedRoomTools.bindTurn(r,this.activeTurnId))throw new Error("codex_managed_room_turn_binding_failed")}async handleManagedRoomToolCall(e,t){const r=await this.managedRoomTools.execute(t);if(this.writeAppServerResponse(e,r),r.success&&t.tool==="shennian_room_send"){const s=typeof t.arguments=="object"&&t.arguments!==null?t.arguments:null,i=typeof s?.text=="string"?s.text.trim():"";i&&this.emitText(i,"block")}}writeAppServerResponse(e,t){const r=this.process;r?.stdin&&r.stdin.write(`${JSON.stringify({id:e,result:t})}
3
+ `)}function me(o,e,t){return["queue","--thread",o,"--message",pe(e,t)]}function A(o){return o.replace(/[[\]\\]/g,"\\$&")}class ge extends q{options;type="codex";process=null;workDir=null;seq=0;runId="";pendingUsage;agentSessionId=null;hasEmittedText=!1;textTail="";terminalState="open";forceCloseTimer=null;stderrBuf="";rpcSeq=1;pendingRequests=new Map;appServerReady=null;appServerStartupError=null;activeTurnId=null;deltaItemIds=new Set;lastTransientStatus="";agentSystemPrompt="";managedAgentPolicy=null;managedPermissionConfig=null;configurationRestartRequired=!1;managedRoomTools=new B;configuredManagedRoomContextToken=null;configuredManagedRoomExecutor=null;managedRoomToolThreadId=null;preparedExternalOwnerThreadId=null;managedTurnReplay=null;managedAsyncRecovery=null;persistNativeSession=!0;nativeSessionVisibility="user";constructor(e={}){super(),this.options=e}externalChannel=null;shennianSessionId=null;extraEnv={};configure(e){const t=this.configurationFingerprint();this.shennianSessionId=e.sessionId??null,this.externalChannel=e.externalChannel??null,this.extraEnv=e.env??{},"managedAgentPolicy"in e&&(this.managedAgentPolicy=e.managedAgentPolicy??null),("managedRoomContextToken"in e||"managedRoomExecutor"in e)&&(this.managedRoomTools.deactivateTurn(),this.configuredManagedRoomContextToken=e.managedRoomContextToken?.trim()||null,this.configuredManagedRoomExecutor=e.managedRoomExecutor??null),this.managedAgentPolicy&&(this.workDir=this.managedAgentPolicy.adapterPolicy.workDir);const r=this.configurationFingerprint();t!==r&&this.process&&(this.configurationRestartRequired=!0)}configurationFingerprint(){const e=Object.keys(this.extraEnv).sort().map(t=>[t,this.extraEnv[t]??null]);return w("sha256").update(JSON.stringify({sessionId:this.shennianSessionId,externalChannel:this.externalChannel,env:e,managedAgentPolicy:this.managedAgentPolicy})).digest("hex")}buildProcessEnv(e={}){if(!this.managedAgentPolicy)return D({...e,...this.extraEnv});const t=Object.fromEntries(Object.entries(this.extraEnv).filter(([r])=>r!=="SHENNIAN_MANAGED_ROOM_CONTEXT"&&r!=="SHENNIAN_MANAGED_ROOM_IPC_ROOT"));return L({agentType:"codex",providerEnv:t,sessionEnv:t,runtimeEnv:e})}async start(e,t,r,s){this.workDir=this.managedAgentPolicy?.adapterPolicy.workDir??t,this.seq=0,this.persistNativeSession=s?.persistNativeSession!==!1,this.nativeSessionVisibility=s?.nativeSessionVisibility??"user",r&&(this.agentSessionId=r)}async prepareSend(e,t,r,s,i,n){const a=i?.trim()??"";if(a!==this.agentSystemPrompt&&(this.agentSystemPrompt=a,this.process&&await this.killProcess(!0)),!(!this.agentSessionId||this.activeTurnId)){this.preparedExternalOwnerThreadId=null;try{await this.ensureAppServer(I(t))}catch(d){if(!P(d))throw d;if(n?.source==="room_activation")throw new Error("codex_managed_thread_owned_externally",{cause:d});if(this.isThreadTailInterrupted(this.agentSessionId))throw new Error(C,{cause:d});this.preparedExternalOwnerThreadId=this.agentSessionId}}}async send(e,t,r,s,i,n){if(n?.source==="room_activation"&&!this.managedAgentPolicy)throw new Error("managed_agent_policy_missing");if(n?.source==="room_activation"&&(!this.configuredManagedRoomContextToken||!this.configuredManagedRoomExecutor))throw new Error("codex_managed_room_tool_context_unavailable");this.activeTurnId&&(await this.interruptActiveTurn().catch(()=>{}),await this.killProcess(!0)),this.configurationRestartRequired&&this.process&&await this.killProcess(!0),this.configurationRestartRequired=!1;const a=I(t),d=re(r),c=i?.trim()??"";if(c!==this.agentSystemPrompt&&(this.agentSystemPrompt=c,this.process&&await this.killProcess(!0)),n?.source==="room_activation"&&this.managedRoomTools.configure(this.configuredManagedRoomContextToken,this.configuredManagedRoomExecutor),this.runId=O(),this.seq=0,this.resetRunState(),this.agentSessionId&&this.preparedExternalOwnerThreadId===this.agentSessionId)return this.preparedExternalOwnerThreadId=null,{deliveryMode:"external_owner_queue",queuedSubmissionId:await this.enqueueForExternalOwner(this.agentSessionId,e,s)};try{await this.ensureAppServer(a)}catch(h){if(!this.agentSessionId||!P(h))throw h;if(n?.source==="room_activation")throw new Error("codex_managed_thread_owned_externally",{cause:h});if(this.isThreadTailInterrupted(this.agentSessionId))throw new Error(C,{cause:h});return{deliveryMode:"external_owner_queue",queuedSubmissionId:await this.enqueueForExternalOwner(this.agentSessionId,e,s)}}const l=this.agentSessionId;if(!l)throw new Error("codex app-server did not create a thread");this.emitEvent({state:"start",agentSessionId:l}),this.managedTurnReplay=this.managedPermissionConfig?{text:e,modelId:a,reasoningEffort:d,attachments:s,recoveryCount:0}:null;const p=await this.startTurnWithRecovery(l,e,a,d,s),m=this.agentSessionId??l;if(this.activeTurnId=p.turn?.id??null,this.managedRoomToolThreadId===m&&this.activeTurnId&&!this.managedRoomTools.bindTurn(m,this.activeTurnId))throw await this.killProcess(),new Error("codex_managed_room_turn_binding_failed");return{deliveryMode:"direct"}}isThreadTailInterrupted(e){return this.options.isThreadTailInterrupted?.(e)??$(e)}async enqueueForExternalOwner(e,t,r){const s=T("codex");if(!s)throw new Error('Command "codex" not found. Is OpenAI Codex CLI installed?');const i=me(e,t,r),n=x(s,i,{cwd:this.workDir??void 0,stdio:["ignore","pipe","pipe"],env:this.buildProcessEnv({NO_COLOR:"1"})});return await new Promise((a,d)=>{let c="",l="",p=!1;const m=(u,f)=>{p||(p=!0,clearTimeout(h),u?d(u):a(f))},h=setTimeout(()=>{n.kill("SIGTERM"),m(new Error("Codex Desktop message queue timed out"))},6e4);h.unref?.(),n.stdout?.on("data",u=>{c+=u.toString()}),n.stderr?.on("data",u=>{l+=u.toString()}),n.once("error",u=>m(u)),n.once("close",u=>{const f=`${c}
4
+ ${l}`.trim();if(u!==0){m(new Error(f||`codex queue exited with code ${u??"unknown"}`));return}const M=f.match(/Queued message\s+([^\s]+)\s+for thread/i)?.[1];m(void 0,M)})})}async resume(e){await this.killProcess(),this.agentSessionId=e,this.resetTextState()}async setTitle(e,t,r){const s=e.trim(),i=t.replace(/\s+/g," ").trim();!s||!i||(this.agentSessionId=s,r?.trim()&&(this.workDir=r),await this.ensureAppServer(),await this.sendRpc("thread/name/set",{threadId:s,name:i}))}async stop(){this.managedRoomTools.deactivateTurn(),await this.interruptActiveTurn().catch(()=>{}),await this.killProcess()}async getStatus(){const e=this.agentSessionId,t=this.activeTurnId;if(!e||!this.process)return{active:!1,runId:t,runPhase:null,canStop:!1};let r=null;try{r=(await this.sendRpc("thread/read",{threadId:e,includeTurns:!1},5e3)).thread?.status??null}catch{}const s=r?.type==="active"||!!t;return{active:s,runId:t,runPhase:s?this.mapThreadStatusToRunPhase(r):null,canStop:!!(s&&t&&this.process)}}spawnCodex(e){const t=T("codex");if(!t){this.emit("error",new Error('Command "codex" not found. Is OpenAI Codex CLI installed?'));return}const r=x(t,e,{cwd:this.workDir??void 0,stdio:["ignore","pipe","pipe"],env:this.buildProcessEnv()});this.process=r,S({input:r.stdout}).on("line",n=>{if(n.trim())try{const a=JSON.parse(n);this.handleStreamEvent(a)}catch{this.emitEvent({state:"delta",text:n})}});let i="";r.stderr?.on("data",n=>{i+=n.toString()}),r.on("close",n=>{this.process===r&&(this.process=null,this.clearForceCloseTimer(),this.handleProcessClose(n,i))}),r.on("error",n=>{this.process===r&&(this.process=null,n.code==="ENOENT"?this.emit("error",new Error('Command "codex" not found. Is OpenAI Codex CLI installed?')):this.emit("error",n))})}spawnAppServer(){const e=T("codex");if(!e){this.emit("error",new Error('Command "codex" not found. Is OpenAI Codex CLI installed?'));return}const t=["app-server","--listen","stdio://"],r=this.options.modelInstructionsFile??F(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,this.agentSystemPrompt);r&&t.push("-c",`model_instructions_file=${JSON.stringify(r)}`);const s=x(e,t,{cwd:this.workDir??void 0,stdio:["pipe","pipe","pipe"],env:this.buildProcessEnv({NO_COLOR:"1"})});this.process=s,this.stderrBuf="",this.appServerStartupError=null,S({input:s.stdout}).on("line",n=>{if(!n.trim())return;let a;try{a=JSON.parse(n)}catch{this.handleAppServerNonJsonStdout(n);return}this.handleAppServerMessage(a)}),s.stderr?.on("data",n=>{this.stderrBuf+=n.toString()}),s.on("close",n=>{if(this.process!==s)return;const a=this.activeTurnId!=null;this.process=null,this.appServerReady=null,this.activeTurnId=null,this.managedRoomTools.reset(),this.clearConfiguredManagedRoomContext(),this.rejectAllPending(new Error(_(this.stderrBuf)||`codex app-server exited with code ${n}`)),this.terminalState==="open"&&a&&this.handleProcessClose(n,this.stderrBuf)}),s.on("error",n=>{this.process===s&&(this.process=null,this.managedRoomTools.reset(),this.clearConfiguredManagedRoomContext(),this.rejectAllPending(n),n.code==="ENOENT"?this.emit("error",new Error('Command "codex" not found. Is OpenAI Codex CLI installed?')):this.emit("error",n))})}async ensureAppServer(e){return this.appServerReady?this.appServerReady:(this.spawnAppServer(),this.appServerReady=this.initializeAppServer(e).catch(async t=>{throw this.appServerReady=null,await this.killProcess(),t}),this.appServerReady)}async initializeAppServer(e){const t=I(e);await this.sendRpc("initialize",{clientInfo:H,capabilities:{experimentalApi:!0}}),this.managedPermissionConfig=this.managedAgentPolicy?await this.buildManagedPermissionConfig():null;const r=!!(this.configuredManagedRoomContextToken||this.configuredManagedRoomExecutor);if(this.managedPermissionConfig&&r&&!this.managedRoomTools.isConfigured()&&(this.managedRoomTools.configure(this.configuredManagedRoomContextToken,this.configuredManagedRoomExecutor),!this.managedRoomTools.isConfigured()))throw new Error("codex_managed_room_tool_context_unavailable");if(this.agentSessionId&&this.managedPermissionConfig&&r&&this.agentSessionId!==this.managedRoomToolThreadId){if(!this.managedRoomTools.isConfigured())throw new Error("codex_managed_room_tool_context_unavailable");this.agentSessionId=null}if(this.agentSessionId){const c={threadId:this.agentSessionId,cwd:this.workDir,approvalPolicy:"never",...this.managedPermissionConfig?{config:this.managedPermissionConfig.threadConfig}:{sandbox:"danger-full-access"},persistExtendedHistory:!0,...this.options.hidden||this.nativeSessionVisibility==="internal"||!this.persistNativeSession?{threadSource:"subagent"}:{},...t?{model:t}:{}};let l;try{l=await this.sendRpc("thread/resume",{...c,excludeTurns:!0})}catch(p){if(!oe(p))throw p;l=await this.sendRpc("thread/resume",c)}this.agentSessionId=l.thread?.id??this.agentSessionId,this.managedPermissionConfig&&(R(l,this.managedPermissionConfig.profileId),r&&(this.managedRoomTools.bindThread(this.agentSessionId),this.managedRoomToolThreadId=this.agentSessionId));return}const s=this.options.hidden||this.nativeSessionVisibility==="internal"||!this.persistNativeSession,i=s?void 0:await this.resolveCodexProjectId(),n={cwd:this.workDir,approvalPolicy:"never",...this.managedPermissionConfig?{config:this.managedPermissionConfig.threadConfig}:{sandbox:"danger-full-access"},serviceName:"Shennian",threadSource:s?"subagent":"user",experimentalRawEvents:!1,persistExtendedHistory:!0,...this.managedPermissionConfig&&r?{dynamicTools:z}:{},...i?{projectId:i}:{},...t?{model:t}:{}};let a;if(s&&!this.managedPermissionConfig)a=await this.sendRpc("thread/start",n);else try{a=await this.sendRpc("thread/start",{...n,historyMode:"paginated"})}catch(c){throw ie(c)?new Error("\u5F53\u524D Codex CLI \u4E0D\u652F\u6301\u521B\u5EFA\u53EF\u5728 Codex Desktop \u4E2D\u7EE7\u7EED\u7684\u65B0\u4F1A\u8BDD\uFF0C\u8BF7\u624B\u52A8\u5347\u7EA7 Codex CLI \u540E\u91CD\u8BD5\u3002\u795E\u5FF5\u4E0D\u4F1A\u81EA\u52A8\u5347\u7EA7\uFF0C\u4E5F\u4E0D\u4F1A\u964D\u7EA7\u521B\u5EFA\u4E0D\u53EF\u89C1\u7684 legacy \u4F1A\u8BDD\u3002",{cause:c}):c}const d=a.thread?.id;if(!d)throw new Error("codex app-server thread/start returned no thread id");this.managedPermissionConfig&&(R(a,this.managedPermissionConfig.profileId),r&&(this.managedRoomTools.bindThread(d),this.managedRoomToolThreadId=d)),this.agentSessionId=d}async buildManagedPermissionConfig(){const e=this.managedAgentPolicy;if(!e)throw new Error("managed_agent_policy_missing");const t=e.adapterPolicy.externalCapabilities.mcp?[]:J(await this.sendRpc("config/read",{cwd:e.adapterPolicy.workDir}));return V(U(e),e.adapterPolicy.workDir,{configuredMcpServerNames:t,shellSubprocessPolicy:e.environmentPolicy.shellSubprocess})}async resolveCodexProjectId(){const e=this.workDir?.trim();if(e)try{const t=[];let r;do{const c=await this.sendRpc("project/list",{limit:100,...r?{cursor:r}:{}});t.push(...c.data??[]),r=c.nextCursor}while(r);const s=de(t,e);if(s)return s;const i=g.resolve(e),n=`shennian-project-${w("sha256").update(i).digest("hex")}`,d=(await this.sendRpc("project/create",{idempotencyKey:n,name:g.basename(i)||i,roots:[{path:i}],metadata:{createdBy:"Shennian"}})).project?.id;if(!d)throw new Error("codex app-server project/create returned no project id");return d}catch(t){throw ae(t)?new Error("\u5F53\u524D Codex CLI \u4E0D\u652F\u6301\u521B\u5EFA\u53EF\u5F52\u5C5E\u5230 Codex Desktop \u9879\u76EE\u7684\u65B0\u4F1A\u8BDD\uFF0C\u8BF7\u624B\u52A8\u5347\u7EA7 Codex CLI \u540E\u91CD\u8BD5\u3002\u795E\u5FF5\u4E0D\u4F1A\u81EA\u52A8\u5347\u7EA7\uFF0C\u4E5F\u4E0D\u4F1A\u76F4\u63A5\u4FEE\u6539 Codex Desktop \u7684\u79C1\u6709\u4FA7\u680F\u7D22\u5F15\u3002",{cause:t}):t}}async startTurnWithRecovery(e,t,r,s,i){try{return await this.startTurn(e,t,r,s,i)}catch(n){if(!y(n))throw n;if(this.managedPermissionConfig){this.logManagedThreadLifecycle("rollout.missing",{threadId:e,recovery:"recreate"}),await this.killProcess(!0),this.agentSessionId=null,this.managedRoomToolThreadId=null,await this.ensureAppServer(r);const a=this.agentSessionId;if(!a)throw new Error("codex app-server did not recreate the managed thread",{cause:n});return this.logManagedThreadLifecycle("thread.recreated",{previousThreadId:e,threadId:a}),this.emitEvent({state:"start",agentSessionId:a}),await this.startFreshManagedTurnWithReadinessRetry(a,t,r,s,i)}return await this.killProcess(),await this.ensureAppServer(r),await this.startTurn(e,t,r,s,i)}}async startFreshManagedTurnWithReadinessRetry(e,t,r,s,i){const n=[0,100,300,1e3];let a;for(let d=0;d<n.length;d+=1){const c=n[d];c>0&&await new Promise(l=>setTimeout(l,c));try{const l=await this.startTurn(e,t,r,s,i);return d>0&&this.logManagedThreadLifecycle("rollout.ready",{threadId:e,attempt:d+1}),l}catch(l){if(a=l,!y(l)||d===n.length-1)throw l;this.logManagedThreadLifecycle("rollout.retry",{threadId:e,attempt:d+2,delayMs:n[d+1]})}}throw a}logManagedThreadLifecycle(e,t){console.error(`[codex.managed] ${JSON.stringify({event:e,...t})}`)}async startTurn(e,t,r,s,i){try{return await this.sendRpc("turn/start",{threadId:e,input:[le(t,i)],approvalPolicy:"never",...this.managedPermissionConfig?{}:{sandboxPolicy:{type:"dangerFullAccess"}},...r?{model:r}:{},...s?{effort:s}:{}})}catch(n){throw s&&j(n)?new Error(`Codex app-server does not accept reasoning effort "${s}" for this turn. Refresh models or upgrade Codex CLI, then retry.`,{cause:n}):n}}async interruptActiveTurn(){const e=this.agentSessionId,t=this.activeTurnId;this.activeTurnId=null,this.managedRoomTools.deactivateTurn(),!(!e||!t||!this.process)&&await this.sendRpc("turn/interrupt",{threadId:e,turnId:t},5e3)}sendRpc(e,t,r=6e4){if(this.appServerStartupError)return Promise.reject(this.appServerStartupError);const s=this.process;if(!s?.stdin)return Promise.reject(new Error("codex app-server is not running"));const i=this.rpcSeq++,n=JSON.stringify({id:i,method:e,params:t});return new Promise((a,d)=>{const c=setTimeout(()=>{this.pendingRequests.delete(i),d(new Error(`codex app-server request timed out: ${e}`))},r);this.pendingRequests.set(i,{resolve:a,reject:d,timer:c}),s.stdin.write(`${n}
5
+ `,l=>{l&&(clearTimeout(c),this.pendingRequests.delete(i),d(l))})})}handleAppServerMessage(e){if(e.method==="item/tool/call"&&e.id!=null){this.handleManagedRoomToolCall(e.id,e.params??{});return}if(e.id!=null){const r=typeof e.id=="number"?this.pendingRequests.get(e.id):void 0;r&&(clearTimeout(r.timer),this.pendingRequests.delete(e.id),e.error?r.reject(new Error(e.error.message||`codex app-server error ${e.error.code??""}`.trim())):r.resolve(e.result))}if(!e.method)return;const t=e.params??{};switch(e.method){case"turn/started":{const r=typeof t.turn=="object"&&t.turn!==null?t.turn:null,s=typeof r?.id=="string"?r.id:null,i=typeof t.threadId=="string"?t.threadId:"";s&&(this.activeTurnId=s,this.managedRoomToolThreadId===i&&!this.managedRoomTools.bindTurn(i,s)&&this.emitErrorIfOpen("codex_managed_room_turn_binding_failed"));break}case"thread/status/changed":{const r=typeof t.threadId=="string"?t.threadId:"";if(r&&this.agentSessionId&&r!==this.agentSessionId)break;const s=typeof t.status=="object"&&t.status!==null?t.status:null;s?.type==="active"&&this.emitEvent({state:"heartbeat",runPhase:this.mapThreadStatusToRunPhase(s)});break}case"item/agentMessage/delta":{const r=typeof t.itemId=="string"?t.itemId:"";r&&this.deltaItemIds.add(r),typeof t.delta=="string"&&this.emitText(t.delta);break}case"item/completed":this.handleAppServerCompletedItem(t);break;case"thread/tokenUsage/updated":this.handleAppServerUsage(t);break;case"turn/completed":{const r=typeof t.turn=="object"&&t.turn!==null?t.turn:null,s=typeof r?.id=="string"?r.id:null;(!this.activeTurnId||s===this.activeTurnId)&&(this.activeTurnId=null,this.managedRoomTools.deactivateTurn(),this.emitFinalIfOpen());break}case"turn/failed":{const r=E(t);if(this.scheduleManagedAsyncRolloutRecovery(r))return;this.emitErrorIfOpen(r||"turn failed");break}case"error":{const r=E(t);if(Z(r)){this.emitTransientStatus(r);return}if(this.scheduleManagedAsyncRolloutRecovery(r))return;this.emitErrorIfOpen(r);break}}}scheduleManagedAsyncRolloutRecovery(e){if(!this.managedPermissionConfig||!this.managedTurnReplay||!y(new Error(e)))return!1;if(this.managedAsyncRecovery)return!0;if(this.managedTurnReplay.recoveryCount>=2)return!1;this.managedTurnReplay.recoveryCount+=1;const t=this.managedTurnReplay.recoveryCount;return this.logManagedThreadLifecycle("rollout.failed-async",{threadId:this.agentSessionId,recoveryCount:t}),this.managedAsyncRecovery=this.recoverManagedTurnAfterAsyncRolloutFailure().catch(r=>{const s=y(r)?"no rollout found after managed thread recovery":r instanceof Error?r.message:"managed thread recovery failed";this.emitErrorIfOpen(s)}).finally(()=>{this.managedAsyncRecovery=null}),!0}async recoverManagedTurnAfterAsyncRolloutFailure(){const e=this.managedTurnReplay,t=this.agentSessionId;if(!e||!t||this.terminalState!=="open")return;this.activeTurnId=null,this.managedRoomTools.deactivateTurn(),await this.killProcess(!0),this.agentSessionId=null,this.managedRoomToolThreadId=null,await this.ensureAppServer(e.modelId);const r=this.agentSessionId;if(!r)throw new Error("codex app-server did not recreate the managed thread");this.logManagedThreadLifecycle("thread.recreated-async",{previousThreadId:t,threadId:r,recoveryCount:e.recoveryCount}),this.emitEvent({state:"start",agentSessionId:r});const s=await this.startFreshManagedTurnWithReadinessRetry(r,e.text,e.modelId,e.reasoningEffort,e.attachments);if(this.activeTurnId=s.turn?.id??null,this.managedRoomToolThreadId===r&&this.activeTurnId&&!this.managedRoomTools.bindTurn(r,this.activeTurnId))throw new Error("codex_managed_room_turn_binding_failed")}async handleManagedRoomToolCall(e,t){const r=await this.managedRoomTools.execute(t);if(this.writeAppServerResponse(e,r),r.success&&t.tool==="shennian_room_send"){const s=typeof t.arguments=="object"&&t.arguments!==null?t.arguments:null,i=typeof s?.text=="string"?s.text.trim():"";i&&this.emitText(i,"block")}}writeAppServerResponse(e,t){const r=this.process;r?.stdin&&r.stdin.write(`${JSON.stringify({id:e,result:t})}
6
6
  `)}mapThreadStatusToRunPhase(e){const t=e?.type==="active"&&Array.isArray(e.activeFlags)?e.activeFlags:[];return t.includes("waitingOnApproval")?"waiting_approval":t.includes("waitingOnUserInput")?"waiting_user_input":"thinking"}handleAppServerNonJsonStdout(e){const t=se(e);ee(t)&&this.failAppServerStartup(new Error("Codex \u672A\u767B\u5F55\u3002\u8BF7\u5148\u5728\u8FD9\u53F0\u7535\u8111\u7684\u7EC8\u7AEF\u8FD0\u884C `codex`\uFF0C\u6309\u63D0\u793A\u5B8C\u6210 ChatGPT \u767B\u5F55\u6216\u914D\u7F6E API key\uFF0C\u7136\u540E\u518D\u56DE\u5230\u795E\u5FF5\u53D1\u9001\u6D88\u606F\u3002"))}failAppServerStartup(e){this.appServerStartupError||(this.appServerStartupError=e,this.rejectAllPending(e),this.process?.kill("SIGTERM"))}handleAppServerCompletedItem(e){const t=typeof e.item=="object"&&e.item!==null?e.item:null;if(!(!t||typeof t.type!="string")&&!Q(t))switch(t.type){case"agentMessage":{const r=typeof t.id=="string"?t.id:"";if(r&&this.deltaItemIds.has(r))return;typeof t.text=="string"&&this.emitText(t.text,"block");break}case"commandExecution":{const r=typeof t.command=="string"?t.command:"",s=typeof t.aggregatedOutput=="string"?t.aggregatedOutput:"";r&&this.emitEvent({state:"tool-call",name:"command_execution",args:{command:r}}),this.emitEvent({state:"tool-result",name:"command_execution",result:[s,t.exitCode!=null?`
7
- (exit ${t.exitCode})`:""].join("").trim()});break}case"mcpToolCall":case"dynamicToolCall":{const r=typeof t.tool=="string"?t.tool:t.type;if(T(r))return;const s=typeof t.arguments=="object"&&t.arguments!==null?t.arguments:{};this.emitEvent({state:"tool-call",name:r,args:s}),this.emitEvent({state:"tool-result",name:r,result:k(t.error??t.result??t.contentItems??"")});break}case"fileChange":break;case"approvalRequest":case"approval_request":case"permissionRequest":case"permission_request":case"userInputRequired":case"user_input_required":{this.emitApprovalPending(t);break}}}handleAppServerUsage(e){const t=typeof e.tokenUsage=="object"&&e.tokenUsage!==null?e.tokenUsage:null,r=typeof t?.last=="object"&&t.last!==null?t.last:null,s=typeof t?.total=="object"&&t.total!==null?t.total:null,i=r??s;if(!i)return;const n=typeof i.inputTokens=="number"?i.inputTokens:void 0,a=typeof i.outputTokens=="number"?i.outputTokens:void 0;(n!=null||a!=null)&&(this.pendingUsage={inputTokens:n??0,outputTokens:a??0})}handleCodexItemLine(e){const t=e.item;if(t?.type&&!Y(t))switch(t.type){case"agent_message":case"reasoning":{e.type==="item.completed"&&t.text&&this.emitText(t.text,"block");break}case"command_execution":{if(e.type==="item.started"&&t.command&&this.emitEvent({state:"tool-call",name:"command_execution",args:{command:t.command}}),e.type==="item.completed"){const r=[t.aggregated_output??"",t.exit_code!=null?`
8
- (exit ${t.exit_code})`:""];this.emitEvent({state:"tool-result",name:"command_execution",result:r.join("").trim()||String(t.status??"")})}break}case"mcp_tool_call":{if(t.tool&&T(t.tool))return;if(e.type==="item.started"&&this.emitEvent({state:"tool-call",name:t.tool??"mcp_tool",args:{server:t.server,...t.arguments&&typeof t.arguments=="object"?t.arguments:{}}}),e.type==="item.completed"){const r=t.error&&typeof t.error=="object"?t.error.message:void 0;this.emitEvent({state:"tool-result",name:t.tool??"mcp_tool",result:r??k(t.result)})}break}case"file_change":break;case"web_search":{e.type==="item.completed"&&t.query&&this.emitText(`[web_search] ${t.query}`,"block");break}case"todo_list":{if(e.type==="item.completed"&&t.items?.length){const r=t.items.map(s=>`- [${s.completed?"x":" "}] ${s.text}`).join(`
9
- `);this.emitText(r,"block")}break}case"approval_request":case"approvalRequest":case"permission_request":case"permissionRequest":case"user_input_required":case"userInputRequired":{(e.type==="item.started"||e.type==="item.completed")&&this.emitApprovalPending(t);break}case"error":{e.type==="item.completed"&&t.message&&this.emitEvent({state:"error",message:t.message});break}default:break}}handleStreamEvent(e){const t=e.type??e.event;switch(t?.startsWith("item.")&&this.handleCodexItemLine(e),t){case"turn.completed":{const s=e.usage;if(s){const i=s.input_tokens??s.prompt_tokens,n=s.output_tokens??s.completion_tokens;(i!=null||n!=null)&&(this.pendingUsage={inputTokens:i??0,outputTokens:n??0})}this.emitFinalIfOpen();return}case"turn.failed":{const s=typeof e.error=="object"&&e.error?.message?e.error.message:typeof e.error=="string"?e.error:"turn failed";this.emitErrorIfOpen(s);return}case"error":{const s=typeof e.message=="string"?e.message:"";if(s.includes("Reconnecting"))return;this.emitErrorIfOpen(s||(typeof e.error=="string"?e.error:"stream error"));return}case"thread.started":{const s=e.thread_id??e.session_id??e.id;typeof s=="string"&&s&&(this.agentSessionId=s,this.emitEvent({state:"start",agentSessionId:this.agentSessionId}));return}case"turn.started":return}if(t?.startsWith("item."))return;switch(e.type??e.event){case"message":case"text":case"content":{const s=e.content??e.text;s&&this.emitText(s);break}case"function_call":case"tool_call":{if(this.isApprovalLikeName(e.name)){this.emitApprovalPending(e);break}if(e.name&&T(e.name))return;this.emitEvent({state:"tool-call",name:e.name,args:e.arguments??e.input});break}case"function_call_output":case"tool_result":{if(e.name&&T(e.name))return;this.emitEvent({state:"tool-result",name:e.name,result:e.output??e.result});break}case"approval_request":case"approvalRequest":case"permission_request":case"permissionRequest":case"user_input_required":case"userInputRequired":{this.emitApprovalPending(e);break}case"error":break;case"done":case"completed":{e.usage&&(this.pendingUsage={inputTokens:e.usage.prompt_tokens??e.usage.input_tokens??0,outputTokens:e.usage.completion_tokens??e.usage.output_tokens??0}),this.emitFinalIfOpen();break}}}emitEvent(e){if(this.terminalState!=="open"&&e.state!=="final"&&e.state!=="error"&&e.state!=="aborted")return;const t={...e,runId:this.runId,seq:this.seq++};this.emit("agentEvent",t)}isApprovalLikeName(e){return typeof e!="string"?!1:/approval|permission|confirm|user[_-]?input|request[_-]?user/i.test(e)}emitApprovalPending(e){const t=typeof e.command=="string"?e.command:"",r=typeof e.title=="string"&&e.title.trim()?e.title:"\u9700\u8981\u7528\u6237\u786E\u8BA4",s=typeof e.prompt=="string"?e.prompt:typeof e.reason=="string"?e.reason:typeof e.message=="string"?e.message:t?`Codex \u8BF7\u6C42\u6267\u884C\u547D\u4EE4\uFF1A${t}`:"Codex \u6B63\u5728\u7B49\u5F85\u7528\u6237\u786E\u8BA4\u540E\u7EE7\u7EED\u3002";this.emitEvent({state:"approval-pending",approval:{title:r,content:s,source:"codex",actionHint:"\u5F53\u524D\u795E\u5FF5\u6682\u4E0D\u652F\u6301\u8FDC\u7A0B\u786E\u8BA4\uFF0C\u8BF7\u56DE\u5230\u8FD0\u884C Codex \u7684\u7535\u8111/\u7EC8\u7AEF\u5B8C\u6210\u786E\u8BA4\u3002"}})}async killProcess(e=!1){const t=this.process;if(this.appServerReady=null,this.activeTurnId=null,this.managedRoomTools.reset(),e||this.clearConfiguredManagedRoomContext(),!t){this.rejectAllPending(new Error("codex app-server stopped"));return}this.process=null,this.clearForceCloseTimer(),t.kill("SIGTERM"),await new Promise(r=>{t.on("close",r),setTimeout(()=>{t.kill("SIGKILL"),r()},3e3)}),this.rejectAllPending(new Error("codex app-server stopped"))}rejectAllPending(e){for(const[t,r]of this.pendingRequests.entries())clearTimeout(r.timer),r.reject(e),this.pendingRequests.delete(t)}handleProcessClose(e,t){const r=_(t);if(e!==0&&e!==null){const s=r||`codex exited with code ${e}`;this.emitErrorIfOpen(s)}else te(r)?this.emitErrorIfOpen(r):this.emitFinalIfOpen();this.pendingUsage=void 0}emitFinalIfOpen(){this.terminalState==="open"&&(this.terminalState="final",this.managedTurnReplay=null,this.managedRoomTools.deactivateTurn(),this.clearConfiguredManagedRoomContext(),this.emitEvent({state:"final",usage:this.pendingUsage,agentSessionId:this.agentSessionId??void 0}),this.killProcess().catch(()=>{}))}emitErrorIfOpen(e){this.terminalState==="open"&&(this.terminalState="error",this.managedTurnReplay=null,this.managedRoomTools.deactivateTurn(),this.clearConfiguredManagedRoomContext(),this.emitEvent({state:"error",message:X(e)}),this.scheduleProcessClose())}resetRunState(){this.pendingUsage=void 0,this.terminalState="open",this.deltaItemIds.clear(),this.lastTransientStatus="",this.clearForceCloseTimer(),this.resetTextState()}clearConfiguredManagedRoomContext(){this.configuredManagedRoomContextToken=null,this.configuredManagedRoomExecutor=null}emitTransientStatus(e){const t=K(e);!t||t===this.lastTransientStatus||this.terminalState!=="open"||(this.lastTransientStatus=t,this.emitEvent({state:"delta",text:`${t}
7
+ (exit ${t.exitCode})`:""].join("").trim()});break}case"mcpToolCall":case"dynamicToolCall":{const r=typeof t.tool=="string"?t.tool:t.type;if(v(r))return;const s=typeof t.arguments=="object"&&t.arguments!==null?t.arguments:{};this.emitEvent({state:"tool-call",name:r,args:s}),this.emitEvent({state:"tool-result",name:r,result:k(t.error??t.result??t.contentItems??"")});break}case"fileChange":break;case"approvalRequest":case"approval_request":case"permissionRequest":case"permission_request":case"userInputRequired":case"user_input_required":{this.emitApprovalPending(t);break}}}handleAppServerUsage(e){const t=typeof e.tokenUsage=="object"&&e.tokenUsage!==null?e.tokenUsage:null,r=typeof t?.last=="object"&&t.last!==null?t.last:null,s=typeof t?.total=="object"&&t.total!==null?t.total:null,i=r??s;if(!i)return;const n=typeof i.inputTokens=="number"?i.inputTokens:void 0,a=typeof i.outputTokens=="number"?i.outputTokens:void 0;(n!=null||a!=null)&&(this.pendingUsage={inputTokens:n??0,outputTokens:a??0})}handleCodexItemLine(e){const t=e.item;if(t?.type&&!Y(t))switch(t.type){case"agent_message":case"reasoning":{e.type==="item.completed"&&t.text&&this.emitText(t.text,"block");break}case"command_execution":{if(e.type==="item.started"&&t.command&&this.emitEvent({state:"tool-call",name:"command_execution",args:{command:t.command}}),e.type==="item.completed"){const r=[t.aggregated_output??"",t.exit_code!=null?`
8
+ (exit ${t.exit_code})`:""];this.emitEvent({state:"tool-result",name:"command_execution",result:r.join("").trim()||String(t.status??"")})}break}case"mcp_tool_call":{if(t.tool&&v(t.tool))return;if(e.type==="item.started"&&this.emitEvent({state:"tool-call",name:t.tool??"mcp_tool",args:{server:t.server,...t.arguments&&typeof t.arguments=="object"?t.arguments:{}}}),e.type==="item.completed"){const r=t.error&&typeof t.error=="object"?t.error.message:void 0;this.emitEvent({state:"tool-result",name:t.tool??"mcp_tool",result:r??k(t.result)})}break}case"file_change":break;case"web_search":{e.type==="item.completed"&&t.query&&this.emitText(`[web_search] ${t.query}`,"block");break}case"todo_list":{if(e.type==="item.completed"&&t.items?.length){const r=t.items.map(s=>`- [${s.completed?"x":" "}] ${s.text}`).join(`
9
+ `);this.emitText(r,"block")}break}case"approval_request":case"approvalRequest":case"permission_request":case"permissionRequest":case"user_input_required":case"userInputRequired":{(e.type==="item.started"||e.type==="item.completed")&&this.emitApprovalPending(t);break}case"error":{e.type==="item.completed"&&t.message&&this.emitEvent({state:"error",message:t.message});break}default:break}}handleStreamEvent(e){const t=e.type??e.event;switch(t?.startsWith("item.")&&this.handleCodexItemLine(e),t){case"turn.completed":{const s=e.usage;if(s){const i=s.input_tokens??s.prompt_tokens,n=s.output_tokens??s.completion_tokens;(i!=null||n!=null)&&(this.pendingUsage={inputTokens:i??0,outputTokens:n??0})}this.emitFinalIfOpen();return}case"turn.failed":{const s=typeof e.error=="object"&&e.error?.message?e.error.message:typeof e.error=="string"?e.error:"turn failed";this.emitErrorIfOpen(s);return}case"error":{const s=typeof e.message=="string"?e.message:"";if(s.includes("Reconnecting"))return;this.emitErrorIfOpen(s||(typeof e.error=="string"?e.error:"stream error"));return}case"thread.started":{const s=e.thread_id??e.session_id??e.id;typeof s=="string"&&s&&(this.agentSessionId=s,this.emitEvent({state:"start",agentSessionId:this.agentSessionId}));return}case"turn.started":return}if(t?.startsWith("item."))return;switch(e.type??e.event){case"message":case"text":case"content":{const s=e.content??e.text;s&&this.emitText(s);break}case"function_call":case"tool_call":{if(this.isApprovalLikeName(e.name)){this.emitApprovalPending(e);break}if(e.name&&v(e.name))return;this.emitEvent({state:"tool-call",name:e.name,args:e.arguments??e.input});break}case"function_call_output":case"tool_result":{if(e.name&&v(e.name))return;this.emitEvent({state:"tool-result",name:e.name,result:e.output??e.result});break}case"approval_request":case"approvalRequest":case"permission_request":case"permissionRequest":case"user_input_required":case"userInputRequired":{this.emitApprovalPending(e);break}case"error":break;case"done":case"completed":{e.usage&&(this.pendingUsage={inputTokens:e.usage.prompt_tokens??e.usage.input_tokens??0,outputTokens:e.usage.completion_tokens??e.usage.output_tokens??0}),this.emitFinalIfOpen();break}}}emitEvent(e){if(this.terminalState!=="open"&&e.state!=="final"&&e.state!=="error"&&e.state!=="aborted")return;const t={...e,runId:this.runId,seq:this.seq++};this.emit("agentEvent",t)}isApprovalLikeName(e){return typeof e!="string"?!1:/approval|permission|confirm|user[_-]?input|request[_-]?user/i.test(e)}emitApprovalPending(e){const t=typeof e.command=="string"?e.command:"",r=typeof e.title=="string"&&e.title.trim()?e.title:"\u9700\u8981\u7528\u6237\u786E\u8BA4",s=typeof e.prompt=="string"?e.prompt:typeof e.reason=="string"?e.reason:typeof e.message=="string"?e.message:t?`Codex \u8BF7\u6C42\u6267\u884C\u547D\u4EE4\uFF1A${t}`:"Codex \u6B63\u5728\u7B49\u5F85\u7528\u6237\u786E\u8BA4\u540E\u7EE7\u7EED\u3002";this.emitEvent({state:"approval-pending",approval:{title:r,content:s,source:"codex",actionHint:"\u5F53\u524D\u795E\u5FF5\u6682\u4E0D\u652F\u6301\u8FDC\u7A0B\u786E\u8BA4\uFF0C\u8BF7\u56DE\u5230\u8FD0\u884C Codex \u7684\u7535\u8111/\u7EC8\u7AEF\u5B8C\u6210\u786E\u8BA4\u3002"}})}async killProcess(e=!1){const t=this.process;if(this.appServerReady=null,this.activeTurnId=null,this.managedRoomTools.reset(),e||this.clearConfiguredManagedRoomContext(),!t){this.rejectAllPending(new Error("codex app-server stopped"));return}this.process=null,this.clearForceCloseTimer(),t.kill("SIGTERM"),await new Promise(r=>{t.on("close",r),setTimeout(()=>{t.kill("SIGKILL"),r()},3e3)}),this.rejectAllPending(new Error("codex app-server stopped"))}rejectAllPending(e){for(const[t,r]of this.pendingRequests.entries())clearTimeout(r.timer),r.reject(e),this.pendingRequests.delete(t)}handleProcessClose(e,t){const r=_(t);if(e!==0&&e!==null){const s=r||`codex exited with code ${e}`;this.emitErrorIfOpen(s)}else te(r)?this.emitErrorIfOpen(r):this.emitFinalIfOpen();this.pendingUsage=void 0}emitFinalIfOpen(){this.terminalState==="open"&&(this.terminalState="final",this.managedTurnReplay=null,this.managedRoomTools.deactivateTurn(),this.clearConfiguredManagedRoomContext(),this.emitEvent({state:"final",usage:this.pendingUsage,agentSessionId:this.agentSessionId??void 0}),this.killProcess().catch(()=>{}))}emitErrorIfOpen(e){this.terminalState==="open"&&(this.terminalState="error",this.managedTurnReplay=null,this.managedRoomTools.deactivateTurn(),this.clearConfiguredManagedRoomContext(),this.emitEvent({state:"error",message:X(e)}),this.scheduleProcessClose())}resetRunState(){this.pendingUsage=void 0,this.terminalState="open",this.deltaItemIds.clear(),this.lastTransientStatus="",this.clearForceCloseTimer(),this.resetTextState()}clearConfiguredManagedRoomContext(){this.configuredManagedRoomContextToken=null,this.configuredManagedRoomExecutor=null}emitTransientStatus(e){const t=K(e);!t||t===this.lastTransientStatus||this.terminalState!=="open"||(this.lastTransientStatus=t,this.emitEvent({state:"delta",text:`${t}
10
10
  `,thinking:!0}))}resetTextState(){this.hasEmittedText=!1,this.textTail=""}emitText(e,t="delta"){if(!e)return;let r=ne(e);r&&(t==="block"&&this.hasEmittedText&&!r.startsWith(`
11
11
  `)&&(this.textTail.endsWith(`
12
12
  `)?r=`
@@ -14,4 +14,4 @@ ${r}`:this.textTail.endsWith(`
14
14
 
15
15
  `)||(r=`
16
16
 
17
- ${r}`)),this.hasEmittedText=!0,this.textTail=(this.textTail+r).slice(-4),this.emitEvent({state:"delta",text:r}))}scheduleProcessClose(){const e=this.process;!e||this.forceCloseTimer||(this.forceCloseTimer=setTimeout(()=>{this.forceCloseTimer=null,this.process===e&&(e.kill("SIGTERM"),setTimeout(()=>{this.process===e&&e.kill("SIGKILL")},1e3))},250))}clearForceCloseTimer(){this.forceCloseTimer&&(clearTimeout(this.forceCloseTimer),this.forceCloseTimer=null)}}N("codex",()=>new ge);export{ge as CodexAdapter,me as buildCodexQueueArgs,pe as buildCodexQueuedText,P as isCodexActiveWriterError,oe as isCodexExcludeTurnsUnsupportedError,ie as isCodexPaginatedHistoryUnsupportedError,ae as isCodexProjectApiUnsupportedError,be as isCodexUnsupportedEffortError,qe as isMissingCodexRolloutError,Ne as normalizeCodexModelId,De as normalizeCodexReasoningEffort,de as selectCodexProjectIdForWorkDir};
17
+ ${r}`)),this.hasEmittedText=!0,this.textTail=(this.textTail+r).slice(-4),this.emitEvent({state:"delta",text:r}))}scheduleProcessClose(){const e=this.process;!e||this.forceCloseTimer||(this.forceCloseTimer=setTimeout(()=>{this.forceCloseTimer=null,this.process===e&&(e.kill("SIGTERM"),setTimeout(()=>{this.process===e&&e.kill("SIGKILL")},1e3))},250))}clearForceCloseTimer(){this.forceCloseTimer&&(clearTimeout(this.forceCloseTimer),this.forceCloseTimer=null)}}N("codex",()=>new ge);export{ge as CodexAdapter,me as buildCodexQueueArgs,pe as buildCodexQueuedText,P as isCodexActiveWriterError,oe as isCodexExcludeTurnsUnsupportedError,ie as isCodexPaginatedHistoryUnsupportedError,ae as isCodexProjectApiUnsupportedError,Oe as isCodexUnsupportedEffortError,qe as isMissingCodexRolloutError,Ne as normalizeCodexModelId,De as normalizeCodexReasoningEffort,de as selectCodexProjectIdForWorkDir};
@@ -1,2 +1,2 @@
1
- import de from"node:os";import{createHash as K}from"node:crypto";import{createAgent as Ee}from"../../agents/adapter.js";import{buildApprovalPendingPayload as Me,buildUserMessagePayload as ie}from"@shennian/wire";import{ManagerModeAdapter as xe}from"../../agents/manager.js";import{reportLog as D}from"../../log-reporter.js";import{lookupClaudeTranscriptCwd as Te}from"../../native-fusion/parsers.js";import{appendMessage as b,getDaemonInstallationId as le,getMessageDeliveryStatus as _e,recordSession as H,upsertMessage as z}from"../store.js";import{mergeProjectedSessions as De}from"../projection.js";import{buildManagedAgentEnv as be}from"../../agents/config-status.js";import{parsePersonalAttachmentReferences as qe}from"../attachment-reference.js";import{assertFinishedAttachmentReferences as Pe,markAttachmentReferences as $e}from"../attachment-transfer-store.js";import{requestSessionIndexPublish as x}from"../index-publisher.js";import{writeToolDetail as ve}from"../tool-detail-store.js";import{getPersonalSyncIdentity as ce}from"../../personal-sync/epoch.js";import{buildManagedAgentPermissionPrompt as Ce}from"../../room/managed-prompt-composer.js";import{getManagedRoomIpcRoot as We,MANAGED_ROOM_IPC_ROOT_ENV as Oe}from"../../daemon-ipc/paths.js";function Ne(e,t,a){if(!e.managedAgentPolicy)throw new Error("managed_agent_policy_missing");const s=e.managedRoomPromptSnapshot;if(!s)throw new Error("managed_room_prompt_snapshot_missing");if(!t?.trim())throw new Error("managed_room_prompt_incomplete");if(!a||!/^mrc_[A-Za-z0-9_-]{43}$/.test(a))throw new Error("managed_room_context_unavailable");const r=K("sha256").update(JSON.stringify({requestedPolicy:e.managedAgentPolicy.requestedPolicy,enforcement:e.managedAgentPolicy.enforcement})).digest("hex"),l=K("sha256").update(e.managedAgentPolicy.adapterPolicy.workDir).digest("hex");if(s.runtimePermissionPolicyHash!==r||s.resolvedWorkDirHash!==l||s.enforcementLevel!==e.managedAgentPolicy.enforcement.level)throw new Error("managed_room_prompt_snapshot_mismatch")}function Fe(e){const t=e.indexOf(`
2
- `),a=t>0?Math.min(t,80):Math.min(e.length,80);return e.slice(0,a)}function ue(e,t,a){return`${e}:${K("sha256").update(`${t}\0${a??""}`).digest("hex")}`}function He(e,t,a={}){if(e.state==="tool-call"||e.state==="tool-result"){const s={runId:e.runId,sourceSeq:e.seq};return{state:e.state,runId:e.runId,seq:e.seq,sessionId:t,detailRef:s,status:e.state==="tool-call"?"running":"completed",detailAvailable:!0,...e.durationMs!==void 0?{durationMs:e.durationMs}:{},...e.name?{name:e.name}:{},...e.source?{source:e.source}:{},...e.agentSessionId?{agentSessionId:e.agentSessionId}:{},...a}}return{...e,sessionId:t,...a}}const ze=3e4;function Be(e){return e.state==="heartbeat"?e.runPhase??null:e.state==="tool-call"||e.state==="tool-result"?"tool_running":e.state==="approval-pending"?"waiting_approval":e.state==="delta"?e.thinking?"thinking":"streaming_text":e.state==="init"||e.state==="start"?"thinking":null}function ge(e,t){return`Agent send failed: ${t instanceof Error?t.message:String(t)}`}function fe(e,t){return e!=="manager"?e:t==="claude"?"claude":"codex"}function Le(e,t){H({sessionId:t.sessionId,agentType:t.agentType,sessionMode:t.sessionMode,managerConfig:t.managerConfig,workDir:t.workDir,agentSessionId:t.agentSessionId??null,modelId:t.modelId??null,managerDefaultWorkerAgentType:t.managerDefaultWorkerAgentType,managerDefaultWorkerModelId:t.managerDefaultWorkerModelId}),e.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:t.sessionId,agentType:t.agentType,sessionMode:t.sessionMode,managerConfig:t.managerConfig,agentSessionId:t.agentSessionId??null,modelId:t.modelId??null,workDir:t.workDir,status:"active",externalChannel:null}}})}function me(e){return be(e)}function pe(e,t,a){return{}}function X(e,t,a,s,r,l,c,R){const S=a==="codex";e.configure?.({sessionId:t,externalChannel:s??null,env:{...me(a),...pe(t,s,r),...l&&!S?{SHENNIAN_MANAGED_ROOM_CONTEXT:l,[Oe]:We()}:{}},...c?{managedAgentPolicy:c}:{},...S?{managedRoomContextToken:l??null,managedRoomExecutor:l?R??null:null}:{}})}function he(e,t,a){const s=t.managedRoomContextToken;s&&s!==a&&e.revokeManagedRoomContextToken?.(s),t.managedRoomContextToken=a}function v(e,t){const a=t?.managedRoomContextToken;!t||!a||(t.managedRoomContextToken=null,e.revokeManagedRoomContextToken?.(a))}function Ue(e,t,a){if(e!=="claude"||!a)return t;const s=t.trim();return!!s&&s.startsWith("-")&&!s.includes("/")?Te(a)??t:t}function Je(e,t,a,s){let r=null;function l(n,o={}){e.client.sendAgentEvent({type:"event",event:"agent",payload:He(n,t,o),seq:n.seq,id:`agent-evt-${n.runId}-${n.seq}`})}function c(n){n?.heartbeatTimer&&(clearInterval(n.heartbeatTimer),n.heartbeatTimer=null)}function R(n){if(!n.currentRunId||!n.currentRunPhase)return;const o=n.heartbeatSeq++;e.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"heartbeat",sessionId:t,runId:n.currentRunId,seq:o,runPhase:n.currentRunPhase},seq:o,id:`agent-heartbeat-${n.currentRunId}-${o}-${Date.now()}`})}function S(n){!n||n.heartbeatTimer||(n.heartbeatTimer=setInterval(()=>{R(n)},ze),n.heartbeatTimer.unref?.())}function h(n){const o=n?.pendingTextEvent;!n||!o||!o.text||(b(t,{id:`agent-${o.runId}-${o.seq}`,sessionId:t,role:"agent",ts:Date.now(),payload:o.text}),x(e.client),l({state:"delta",runId:o.runId,seq:o.seq,text:o.text,thinking:o.thinking||void 0}),n.pendingTextEvent=null)}s.on("agentEvent",n=>{const o=e.sessions.get(t),q=Be(n),T=n.state==="final"||n.state==="error"||n.state==="aborted";if(o&&(o.nextEventSeq=n.seq+1,T||(o.currentRunId=n.runId),!T&&q&&(o.currentRunPhase=q,S(o)),n.agentSessionId&&(o.agentSessionId=n.agentSessionId)),e.managerRuntime?.noteAgentEvent(t,n),n.state==="delta"&&n.thinking)return;n.state!=="delta"&&D({level:"info",sessionId:t,wsEvent:`agent.${n.state}`,wsDirection:"out",metadata:{runId:n.runId,seq:n.seq,agentType:a}});let k=!1;if(n.state==="tool-call"||n.state==="tool-result"){const m=`agent-${n.runId}-${n.seq}`;ve({sessionId:t,toolCallId:m,detailRevision:n.seq,ts:Date.now(),name:n.name??"tool",...n.args!==void 0?{args:n.args}:{},...n.result!==void 0?{result:n.result}:{},status:n.state==="tool-call"?"running":"completed",...n.durationMs!==void 0?{durationMs:n.durationMs}:{},detailRef:{runId:n.runId,sourceSeq:n.seq}}),b(t,{id:m,sessionId:t,role:"agent",ts:Date.now(),payload:JSON.stringify({v:1,type:n.state==="tool-call"?"tool_use":"tool_result",name:n.name,toolCallId:m,status:n.state==="tool-call"?"running":"completed",...n.durationMs!==void 0?{durationMs:n.durationMs}:{},detailRef:{runId:n.runId,sourceSeq:n.seq},detailRevision:n.seq,detailAvailable:!0,resultOmitted:n.state==="tool-result"})}),k=!0}else n.state==="approval-pending"?(b(t,{id:`agent-${n.runId||"run"}-${n.seq}`,sessionId:t,role:"agent",ts:Date.now(),payload:Me(n.approval)}),k=!0,o&&H({sessionId:t,agentType:a,workDir:o.workDir,agentSessionId:o.agentSessionId,attentionId:ue("approval",n.runId,n.seq)})):(n.state==="error"||n.state==="aborted")&&n.message&&(b(t,{id:`agent-${n.runId||"run"}-${n.seq}`,sessionId:t,role:"agent",ts:Date.now(),payload:n.message}),k=!0);k&&x(e.client);const A=`${t}:${n.runId}`;if(n.state==="delta"&&!n.thinking&&n.text&&e.runTextAcc.set(A,(e.runTextAcc.get(A)??"")+n.text),n.agentSessionId&&n.agentSessionId!==r&&(r=n.agentSessionId,e.nativeFusion?.noteManagedSourceSession(t,fe(a,n.source),n.agentSessionId),o&&H({sessionId:t,agentType:a,workDir:o.workDir,agentSessionId:n.agentSessionId}),e.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:t,agentType:a,agentSessionId:n.agentSessionId}}})),n.state==="delta"){const m=n.text??"";if(!m)return;o?.pendingTextEvent&&o.pendingTextEvent.runId!==n.runId&&h(o),o&&!o.pendingTextEvent&&(o.pendingTextEvent={runId:n.runId,seq:n.seq,text:"",thinking:!1}),o?.pendingTextEvent&&(o.pendingTextEvent.text+=m,o.pendingTextEvent.seq=n.seq);return}let C={};if(n.state==="final"){h(o);const m=e.runTextAcc.get(A)??"";m&&(C={messageSummary:Fe(m)}),e.runTextAcc.delete(A)}else n.state==="error"||n.state==="aborted"?(h(o),e.runTextAcc.delete(A)):(n.state==="tool-call"||n.state==="tool-result"||n.state==="approval-pending")&&h(o);T&&o?.currentRunId===n.runId&&(v(e,o),o.currentRunId=null,o.currentRunPhase=null,o.nextEventSeq=0,c(o),e.chatQueue?.noteTerminal(t),H({sessionId:t,agentType:a,workDir:o.workDir,agentSessionId:o.agentSessionId,status:n.state==="final"?"completed":"failed",attentionId:ue("terminal",n.runId),lastActivityAt:new Date().toISOString()}),x(e.client)),l(n,C)}),s.on("error",n=>{console.error(`[chat.send] adapter error sessionId=${t} agentType=${a}: ${n.message}`),v(e,e.sessions.get(t)),e.sessions.delete(t),e.chatQueue?.noteTerminal(t),e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:t,message:n.message,runId:"",seq:0}})})}function Qe(e,t){if(e.processedReqIds.add(t),e.processedReqIds.size>1e3){const a=e.processedReqIds.values().next().value;e.processedReqIds.delete(a)}}async function B(e,t){v(e,t),t.heartbeatTimer&&(clearInterval(t.heartbeatTimer),t.heartbeatTimer=null),t.adapter.removeAllListeners(),await t.adapter.stop().catch(()=>{})}function ye(e,t,a,s,r,l,c){return c?e.send(t,a,s,r,l,c):l?.trim()?e.send(t,a,s,r,l):r?.length?e.send(t,a,s,r):s?e.send(t,a,s):e.send(t,a)}function Ve(e,t,a,s,r,l,c){return e.prepareSend?e.prepareSend(t,a,s,r,l,c):Promise.resolve()}async function je(e,t,a,s,r,l,c,R,S){e.evictIdleSessions();const h=Ee(a);if(!h)throw new Error(`Unsupported agent: ${a}`);const n=s==="manager"&&a!=="manager"?new xe(h,a):h;X(n,t,a,c,R,null,S,e.managedRoomExecutor),await n.start(t,r,l);const o={adapter:n,workDir:r,agentType:a,sessionMode:s,agentSessionId:l??null,lastActiveAt:Date.now(),currentRunId:null,currentRunPhase:null,nextEventSeq:0,heartbeatSeq:0,heartbeatTimer:null,pendingTextEvent:null,externalChannel:c??null,externalReplyTarget:R??null,externalChannelEnv:{...me(a),...pe(t,c,R)},managedRoomContextToken:null};return e.sessions.set(t,o),Je(e,t,a,n),o}function Ge(e,t){const a=e.sessions.get(t),s=a?.currentRunId;if(!a||!s)return;const r=a.nextEventSeq;e.runTextAcc.delete(`${t}:${s}`),v(e,a),a.pendingTextEvent=null,a.currentRunId=null,a.currentRunPhase=null,a.nextEventSeq=0,a.heartbeatTimer&&(clearInterval(a.heartbeatTimer),a.heartbeatTimer=null),e.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"aborted",sessionId:t,runId:s,seq:r},seq:r,id:`agent-evt-${s}-${r}`}),e.chatQueue?.noteTerminal(t)}async function pt(e,t,a){const s=a?t.params.managedRoomContextToken??null:null;let r=!1;try{await Ke(e,t,a,()=>{r=!0})}finally{s&&!r&&e.revokeManagedRoomContextToken?.(s)}}async function Ke(e,t,a,s){if(e.processedReqIds.has(t.id)){e.client.sendRes({type:"res",id:t.id,ok:!0});return}const{sessionId:r,text:l,agentType:c,sessionMode:R,managerConfig:S,workDir:h,agentSessionId:n,modelId:o,systemPrompt:q,managerDefaultWorkerAgentType:T,managerDefaultWorkerModelId:k,reasoningEffort:A,clientMessageId:C,sessionListProjection:m,waitForDispatch:Y,responseId:Ie,managedRoomContextToken:P,suppressExternalOwnerEcho:Re,queuedBatchItems:L,managedWorkerParentSessionId:W}=t.params,y=Ie||t.id;De(m);const O=null,U="";if(a?.source==="room_activation"&&(Ne(a,q,P),c==="manager"))throw new Error("managed_agent_manager_mode_unsupported");if(Qe(e,t.id),!r||!l){e.processedReqIds.delete(t.id),e.client.sendRes({type:"res",id:y,ok:!1,error:"sessionId and text are required"});return}const g=c,$=g==="manager"||R==="manager"?"manager":"standard";$==="manager"&&e.managerRuntime?.setManagerWorkerDefaults(r,T??null,k??null);const N=(g==="claude"||g==="codex"||g==="workbuddy"||g==="pi-coding-agent")&&typeof A=="string"&&A.trim()?A.trim():void 0,w=e.resolvePath(Ue(g,h||de.homedir(),n)||de.homedir()),_=a?.managedAgentPolicy??(W?e.managerRuntime?.getManagedAgentPolicyForWorker(W,w)??null:null);if(W&&!_)throw new Error("managed_worker_permission_context_unavailable");const J=W&&_?Ce({requestedPolicy:_.requestedPolicy,enforcement:_.enforcement,resolvedWorkDir:_.adapterPolicy.workDir}):q,Se=w,F=qe(t.params.attachments);F?.length&&Pe(w,F);const p={text:l,attachments:F,localized:!1};let i=e.sessions.get(r);if(i){if(i.lastActiveAt=Date.now(),i.agentType!==g||(i.sessionMode??(i.agentType==="manager"?"manager":"standard"))!==$||i.workDir!==w||JSON.stringify(i.externalChannel??null)!==JSON.stringify(O??null)){e.sessions.delete(r);try{await B(e,i)}catch{e.processedReqIds.delete(t.id)}i=void 0}else if(n&&i.agentSessionId!==n)try{await i.adapter.resume(n),i.agentSessionId=n}catch{e.sessions.delete(r);try{await B(e,i)}catch{e.processedReqIds.delete(t.id)}i=void 0}}if(!i)try{i=await je(e,r,g,$,w,n,O,U,_)}catch(d){const f=d instanceof Error&&d.message.startsWith("Unsupported agent:")?d.message:`Failed to start ${c}: ${d instanceof Error?d.message:String(d)}`;console.error(`[chat.send] start failed reqId=${t.id} sessionId=${r} agentType=${c} workDir=${w} agentSessionId=${n??""}: ${f}`),e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:r,message:f,runId:"",seq:0}}),e.processedReqIds.delete(t.id),e.client.sendRes({type:"res",id:y,ok:!1,error:f});return}const I={id:C??`user-${t.id}`,sessionId:r,role:"user",ts:Date.now(),payload:ie(p.text,p.attachments)},Z=Array.isArray(L)&&L.length>0?L.map(d=>({id:d.clientMessageId??d.id,sessionId:r,role:"user",ts:Date.parse(d.createdAt),payload:ie(d.text,d.attachments)})):null,Q=Z??[I],E=_e(r,I.id),ee=E.state==="queued";if(E.state!=="not_found"&&!ee){e.client.sendRes({type:"res",id:y,ok:!0,payload:E});return}if(Y){a?.source==="room_activation"&&X(i.adapter,r,g,O,U,P,a.managedAgentPolicy,e.managedRoomExecutor);try{await Ve(i.adapter,p.text,o,N,p.attachments,J,a?{source:a.source}:void 0)}catch(d){e.processedReqIds.delete(t.id),e.sessions.delete(r),await B(e,i),e.client.sendRes({type:"res",id:y,ok:!1,error:d instanceof Error?d.message:String(d)});return}}D({level:"info",sessionId:r,wsEvent:"chat.send.start",metadata:{reqId:t.id,agentType:g,sessionMode:$,managerConfig:S??null,modelId:o,managerDefaultWorkerAgentType:T??null,managerDefaultWorkerModelId:k??null,reasoningEffort:N,...a?.source==="room_activation"?{managedRoomPromptSnapshot:a.managedRoomPromptSnapshot}:{}}});const V=(d,f)=>({...ce(le()),sessionId:r,clientMessageId:I.id,messageId:I.id,deliveryState:d,bodyRevision:f,committedAt:new Date(I.ts).toISOString()}),te=d=>{e.nativeFusion?.registerManagedSend({sessionId:r,agentType:g,sourceAgentType:fe(g,o),canonicalMessageId:I.id,sourceSessionKey:i.agentSessionId??n??null,text:p.text,managedEchoPolicy:d?.deliveryMode==="external_owner_queue"&&!Re?"import_following":"suppress_following",externalRunId:d?.deliveryMode==="external_owner_queue"?`codex-external-${d.queuedSubmissionId??I.id}`:null})},ne=()=>{i.currentRunId||(i.currentRunId=`dispatch:${t.id}`,i.currentRunPhase="thinking",i.nextEventSeq=0)},ae=()=>{if(te(),ee)return{...ce(le()),sessionId:r,clientMessageId:E.clientMessageId,messageId:E.messageId,deliveryState:E.deliveryState,bodyRevision:E.bodyRevision,committedAt:E.committedAt};try{Le(e,{sessionId:r,agentType:g,sessionMode:$,managerConfig:S??null,workDir:Se,agentSessionId:i.agentSessionId??n??null,modelId:o,managerDefaultWorkerAgentType:T??null,managerDefaultWorkerModelId:k??null});let d=0;for(const[f,u]of Q.entries()){const M=Z?z(r,u,"committed"):b(r,u,"committed");f===0&&(d=M)}return $e(w,F??[]),x(e.client),V("committed",d)}catch(d){throw e.nativeFusion?.cancelManagedSend?.(I.id),d}},re=d=>{i.currentRunId||(i.nextEventSeq=0),te(d);const f=d?.deliveryMode==="external_owner_queue"?"queued":"executing";let u=0;for(const[M,j]of Q.entries()){const G=z(r,j,f);M===0&&(u=G)}return x(e.client),V(f,u)},oe=async(d,f)=>{e.nativeFusion?.cancelManagedSend?.(I.id);const u=ge(g,d);console.error(`[chat.send] send failed reqId=${t.id} sessionId=${r} agentType=${c} workDir=${w} agentSessionId=${i.agentSessionId??n??""}: ${u}`),e.sessions.delete(r);try{await B(e,i)}catch{}if(e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:r,message:u,runId:"",seq:0}}),!f){const M={id:`agent-error-${t.id}-${Date.now()}`,sessionId:r,role:"agent",ts:Date.now(),payload:u};b(r,M),x(e.client)}f&&(e.processedReqIds.delete(t.id),e.client.sendRes({type:"res",id:y,ok:!1,error:u}))};if(Y){try{ae()}catch(u){e.processedReqIds.delete(t.id),e.client.sendRes({type:"res",id:y,ok:!1,error:`Durable message commit failed: ${u instanceof Error?u.message:String(u)}`});return}ne();let d;try{a?.source==="room_activation"&&(he(e,i,P),s());const u=p.attachments;d=await ye(i.adapter,p.text,o,N,u,J,a?{source:a.source}:void 0),D({level:"info",sessionId:r,wsEvent:"chat.send.done",metadata:{reqId:t.id}})}catch(u){let M=0;for(const[G,ke]of Q.entries()){const we=z(r,ke,"failed");G===0&&(M=we)}x(e.client);const j=ge(g,u);await oe(u,!1),e.client.sendRes({type:"res",id:y,ok:!0,payload:{...V("failed",M),failureMessage:j}});return}const f=re(d??void 0);e.client.sendRes({type:"res",id:y,ok:!0,payload:{...f,...p.localized?{localizedAttachments:!0}:{},...d?.deliveryMode==="external_owner_queue"?{queued:!0,deliveryMode:d.deliveryMode,queuedSubmissionId:d.queuedSubmissionId}:{}}}),D({level:"info",sessionId:r,wsEvent:"chat.send.res",metadata:{reqId:t.id,ok:!0}});return}let se;try{se=ae()}catch(d){e.processedReqIds.delete(t.id),e.client.sendRes({type:"res",id:y,ok:!1,error:`Durable message commit failed: ${d instanceof Error?d.message:String(d)}`});return}ne(),a?.source==="room_activation"&&(X(i.adapter,r,g,O,U,P,a.managedAgentPolicy,e.managedRoomExecutor),he(e,i,P),s()),re(),e.client.sendRes({type:"res",id:y,ok:!0,payload:{...se,...p.localized?{localizedAttachments:!0}:{}}}),D({level:"info",sessionId:r,wsEvent:"chat.send.res",metadata:{reqId:t.id,ok:!0}});const Ae=p.attachments;ye(i.adapter,p.text,o,N,Ae,J,a?{source:a.source}:void 0).then(()=>{D({level:"info",sessionId:r,wsEvent:"chat.send.done",metadata:{reqId:t.id}})}).catch(d=>{z(r,I,"failed"),x(e.client),oe(d,!1)})}async function ht(e,t){const{sessionId:a}=t.params,s=e.sessions.get(a);if(s){v(e,s);try{await s.adapter.stop()}catch{e.client.sendRes({type:"res",id:t.id,ok:!1,error:"agent_stop_failed"});return}Ge(e,a),e.activityPublisher?.publish(a,null)}e.client.sendRes({type:"res",id:t.id,ok:!0})}export{ht as handleChatAbort,pt as handleChatSend,Le as sendSessionUpdateEvent};
1
+ import ie from"node:os";import{createHash as K}from"node:crypto";import{createAgent as Me}from"../../agents/adapter.js";import{buildApprovalPendingPayload as xe,buildUserMessagePayload as le}from"@shennian/wire";import{ManagerModeAdapter as Te}from"../../agents/manager.js";import{reportLog as b}from"../../log-reporter.js";import{lookupClaudeTranscriptCwd as _e}from"../../native-fusion/parsers.js";import{appendMessage as q,getDaemonInstallationId as ce,getMessageDeliveryStatus as De,recordSession as H,upsertMessage as z}from"../store.js";import{mergeProjectedSessions as be}from"../projection.js";import{buildManagedAgentEnv as qe}from"../../agents/config-status.js";import{parsePersonalAttachmentReferences as Pe}from"../attachment-reference.js";import{assertFinishedAttachmentReferences as $e,markAttachmentReferences as ve}from"../attachment-transfer-store.js";import{requestSessionIndexPublish as T}from"../index-publisher.js";import{writeToolDetail as Ce}from"../tool-detail-store.js";import{getPersonalSyncIdentity as ue}from"../../personal-sync/epoch.js";import{buildManagedAgentPermissionPrompt as We}from"../../room/managed-prompt-composer.js";import{getManagedRoomIpcRoot as Oe,MANAGED_ROOM_IPC_ROOT_ENV as Ne}from"../../daemon-ipc/paths.js";function Fe(e,t,a){if(!e.managedAgentPolicy)throw new Error("managed_agent_policy_missing");const s=e.managedRoomPromptSnapshot;if(!s)throw new Error("managed_room_prompt_snapshot_missing");if(!t?.trim())throw new Error("managed_room_prompt_incomplete");if(!a||!/^mrc_[A-Za-z0-9_-]{43}$/.test(a))throw new Error("managed_room_context_unavailable");const o=K("sha256").update(JSON.stringify({requestedPolicy:e.managedAgentPolicy.requestedPolicy,enforcement:e.managedAgentPolicy.enforcement})).digest("hex"),l=K("sha256").update(e.managedAgentPolicy.adapterPolicy.workDir).digest("hex");if(s.runtimePermissionPolicyHash!==o||s.resolvedWorkDirHash!==l||s.enforcementLevel!==e.managedAgentPolicy.enforcement.level)throw new Error("managed_room_prompt_snapshot_mismatch")}function He(e){const t=e.indexOf(`
2
+ `),a=t>0?Math.min(t,80):Math.min(e.length,80);return e.slice(0,a)}function ge(e,t,a){return`${e}:${K("sha256").update(`${t}\0${a??""}`).digest("hex")}`}function ze(e,t,a={}){if(e.state==="tool-call"||e.state==="tool-result"){const s={runId:e.runId,sourceSeq:e.seq};return{state:e.state,runId:e.runId,seq:e.seq,sessionId:t,detailRef:s,status:e.state==="tool-call"?"running":"completed",detailAvailable:!0,...e.durationMs!==void 0?{durationMs:e.durationMs}:{},...e.name?{name:e.name}:{},...e.source?{source:e.source}:{},...e.agentSessionId?{agentSessionId:e.agentSessionId}:{},...a}}return{...e,sessionId:t,...a}}const Be=3e4;function Le(e){return e.state==="heartbeat"?e.runPhase??null:e.state==="tool-call"||e.state==="tool-result"?"tool_running":e.state==="approval-pending"?"waiting_approval":e.state==="delta"?e.thinking?"thinking":"streaming_text":e.state==="init"||e.state==="start"?"thinking":null}function fe(e,t){return`Agent send failed: ${t instanceof Error?t.message:String(t)}`}function me(e,t){return e!=="manager"?e:t==="claude"?"claude":"codex"}function Ue(e,t){H({sessionId:t.sessionId,agentType:t.agentType,sessionMode:t.sessionMode,managerConfig:t.managerConfig,workDir:t.workDir,agentSessionId:t.agentSessionId??null,modelId:t.modelId??null,managerDefaultWorkerAgentType:t.managerDefaultWorkerAgentType,managerDefaultWorkerModelId:t.managerDefaultWorkerModelId}),e.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:t.sessionId,agentType:t.agentType,sessionMode:t.sessionMode,managerConfig:t.managerConfig,agentSessionId:t.agentSessionId??null,modelId:t.modelId??null,workDir:t.workDir,status:"active",externalChannel:null}}})}function pe(e){return qe(e)}function he(e,t,a){return{}}function X(e,t,a,s,o,l,c,R){const S=a==="codex";e.configure?.({sessionId:t,externalChannel:s??null,env:{...pe(a),...he(t,s,o),...l&&!S?{SHENNIAN_MANAGED_ROOM_CONTEXT:l,[Ne]:Oe()}:{}},...c?{managedAgentPolicy:c}:{},...S?{managedRoomContextToken:l??null,managedRoomExecutor:l?R??null:null}:{}})}function ye(e,t,a){const s=t.managedRoomContextToken;s&&s!==a&&e.revokeManagedRoomContextToken?.(s),t.managedRoomContextToken=a}function C(e,t){const a=t?.managedRoomContextToken;!t||!a||(t.managedRoomContextToken=null,e.revokeManagedRoomContextToken?.(a))}function Je(e,t,a){if(e!=="claude"||!a)return t;const s=t.trim();return!!s&&s.startsWith("-")&&!s.includes("/")?_e(a)??t:t}function Qe(e,t,a,s){let o=null;function l(n,r={}){e.client.sendAgentEvent({type:"event",event:"agent",payload:ze(n,t,r),seq:n.seq,id:`agent-evt-${n.runId}-${n.seq}`})}function c(n){n?.heartbeatTimer&&(clearInterval(n.heartbeatTimer),n.heartbeatTimer=null)}function R(n){if(!n.currentRunId||!n.currentRunPhase)return;const r=n.heartbeatSeq++;e.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"heartbeat",sessionId:t,runId:n.currentRunId,seq:r,runPhase:n.currentRunPhase},seq:r,id:`agent-heartbeat-${n.currentRunId}-${r}-${Date.now()}`})}function S(n){!n||n.heartbeatTimer||(n.heartbeatTimer=setInterval(()=>{R(n)},Be),n.heartbeatTimer.unref?.())}function h(n){const r=n?.pendingTextEvent;!n||!r||!r.text||(q(t,{id:`agent-${r.runId}-${r.seq}`,sessionId:t,role:"agent",ts:Date.now(),payload:r.text}),T(e.client),l({state:"delta",runId:r.runId,seq:r.seq,text:r.text,thinking:r.thinking||void 0}),n.pendingTextEvent=null)}s.on("agentEvent",n=>{const r=e.sessions.get(t),w=Le(n),_=n.state==="final"||n.state==="error"||n.state==="aborted";if(r&&(r.nextEventSeq=n.seq+1,_||(r.currentRunId=n.runId),!_&&w&&(r.currentRunPhase=w,S(r)),n.agentSessionId&&(r.agentSessionId=n.agentSessionId)),e.managerRuntime?.noteAgentEvent(t,n),n.state==="delta"&&n.thinking)return;n.state!=="delta"&&b({level:"info",sessionId:t,wsEvent:`agent.${n.state}`,wsDirection:"out",metadata:{runId:n.runId,seq:n.seq,agentType:a}});let k=!1;if(n.state==="tool-call"||n.state==="tool-result"){const m=`agent-${n.runId}-${n.seq}`;Ce({sessionId:t,toolCallId:m,detailRevision:n.seq,ts:Date.now(),name:n.name??"tool",...n.args!==void 0?{args:n.args}:{},...n.result!==void 0?{result:n.result}:{},status:n.state==="tool-call"?"running":"completed",...n.durationMs!==void 0?{durationMs:n.durationMs}:{},detailRef:{runId:n.runId,sourceSeq:n.seq}}),q(t,{id:m,sessionId:t,role:"agent",ts:Date.now(),payload:JSON.stringify({v:1,type:n.state==="tool-call"?"tool_use":"tool_result",name:n.name,toolCallId:m,status:n.state==="tool-call"?"running":"completed",...n.durationMs!==void 0?{durationMs:n.durationMs}:{},detailRef:{runId:n.runId,sourceSeq:n.seq},detailRevision:n.seq,detailAvailable:!0,resultOmitted:n.state==="tool-result"})}),k=!0}else n.state==="approval-pending"?(q(t,{id:`agent-${n.runId||"run"}-${n.seq}`,sessionId:t,role:"agent",ts:Date.now(),payload:xe(n.approval)}),k=!0,r&&H({sessionId:t,agentType:a,workDir:r.workDir,agentSessionId:r.agentSessionId,attentionId:ge("approval",n.runId,n.seq)})):(n.state==="error"||n.state==="aborted")&&n.message&&(q(t,{id:`agent-${n.runId||"run"}-${n.seq}`,sessionId:t,role:"agent",ts:Date.now(),payload:n.message}),k=!0);k&&T(e.client);const A=`${t}:${n.runId}`;if(n.state==="delta"&&!n.thinking&&n.text&&e.runTextAcc.set(A,(e.runTextAcc.get(A)??"")+n.text),n.agentSessionId&&n.agentSessionId!==o&&(o=n.agentSessionId,e.nativeFusion?.noteManagedSourceSession(t,me(a,n.source),n.agentSessionId),r&&H({sessionId:t,agentType:a,workDir:r.workDir,agentSessionId:n.agentSessionId}),e.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:t,agentType:a,agentSessionId:n.agentSessionId}}})),n.state==="delta"){const m=n.text??"";if(!m)return;r?.pendingTextEvent&&r.pendingTextEvent.runId!==n.runId&&h(r),r&&!r.pendingTextEvent&&(r.pendingTextEvent={runId:n.runId,seq:n.seq,text:"",thinking:!1}),r?.pendingTextEvent&&(r.pendingTextEvent.text+=m,r.pendingTextEvent.seq=n.seq);return}let W={};if(n.state==="final"){h(r);const m=e.runTextAcc.get(A)??"";m&&(W={messageSummary:He(m)}),e.runTextAcc.delete(A)}else n.state==="error"||n.state==="aborted"?(h(r),e.runTextAcc.delete(A)):(n.state==="tool-call"||n.state==="tool-result"||n.state==="approval-pending")&&h(r);_&&r?.currentRunId===n.runId&&(C(e,r),r.currentRunId=null,r.currentRunPhase=null,r.nextEventSeq=0,c(r),e.chatQueue?.noteTerminal(t),H({sessionId:t,agentType:a,workDir:r.workDir,agentSessionId:r.agentSessionId,status:n.state==="final"?"completed":"failed",attentionId:ge("terminal",n.runId),lastActivityAt:new Date().toISOString()}),T(e.client)),l(n,W)}),s.on("error",n=>{console.error(`[chat.send] adapter error sessionId=${t} agentType=${a}: ${n.message}`),C(e,e.sessions.get(t)),e.sessions.delete(t),e.chatQueue?.noteTerminal(t),e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:t,message:n.message,runId:"",seq:0}})})}function Ve(e,t){if(e.processedReqIds.add(t),e.processedReqIds.size>1e3){const a=e.processedReqIds.values().next().value;e.processedReqIds.delete(a)}}async function B(e,t){C(e,t),t.heartbeatTimer&&(clearInterval(t.heartbeatTimer),t.heartbeatTimer=null),t.adapter.removeAllListeners(),await t.adapter.stop().catch(()=>{})}function Ie(e,t,a,s,o,l,c){return c?e.send(t,a,s,o,l,c):l?.trim()?e.send(t,a,s,o,l):o?.length?e.send(t,a,s,o):s?e.send(t,a,s):e.send(t,a)}function je(e,t,a,s,o,l,c){return e.prepareSend?e.prepareSend(t,a,s,o,l,c):Promise.resolve()}async function Ge(e,t,a,s,o,l,c,R,S,h="user"){e.evictIdleSessions();const n=Me(a);if(!n)throw new Error(`Unsupported agent: ${a}`);const r=s==="manager"&&a!=="manager"?new Te(n,a):n;X(r,t,a,c,R,null,S,e.managedRoomExecutor),h==="internal"?await r.start(t,o,l,{nativeSessionVisibility:h}):await r.start(t,o,l);const w={adapter:r,workDir:o,agentType:a,sessionMode:s,nativeSessionVisibility:h,agentSessionId:l??null,lastActiveAt:Date.now(),currentRunId:null,currentRunPhase:null,nextEventSeq:0,heartbeatSeq:0,heartbeatTimer:null,pendingTextEvent:null,externalChannel:c??null,externalReplyTarget:R??null,externalChannelEnv:{...pe(a),...he(t,c,R)},managedRoomContextToken:null};return e.sessions.set(t,w),Qe(e,t,a,r),w}function Ke(e,t){const a=e.sessions.get(t),s=a?.currentRunId;if(!a||!s)return;const o=a.nextEventSeq;e.runTextAcc.delete(`${t}:${s}`),C(e,a),a.pendingTextEvent=null,a.currentRunId=null,a.currentRunPhase=null,a.nextEventSeq=0,a.heartbeatTimer&&(clearInterval(a.heartbeatTimer),a.heartbeatTimer=null),e.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"aborted",sessionId:t,runId:s,seq:o},seq:o,id:`agent-evt-${s}-${o}`}),e.chatQueue?.noteTerminal(t)}async function ht(e,t,a){const s=a?t.params.managedRoomContextToken??null:null;let o=!1;try{await Xe(e,t,a,()=>{o=!0})}finally{s&&!o&&e.revokeManagedRoomContextToken?.(s)}}async function Xe(e,t,a,s){if(e.processedReqIds.has(t.id)){e.client.sendRes({type:"res",id:t.id,ok:!0});return}const{sessionId:o,text:l,agentType:c,sessionMode:R,managerConfig:S,workDir:h,agentSessionId:n,modelId:r,systemPrompt:w,managerDefaultWorkerAgentType:_,managerDefaultWorkerModelId:k,reasoningEffort:A,clientMessageId:W,sessionListProjection:m,waitForDispatch:Y,responseId:Re,managedRoomContextToken:P,suppressExternalOwnerEcho:Se,queuedBatchItems:L,managedWorkerParentSessionId:$}=t.params,y=Re||t.id;be(m);const O=null,U="";if(a?.source==="room_activation"&&(Fe(a,w,P),c==="manager"))throw new Error("managed_agent_manager_mode_unsupported");if(Ve(e,t.id),!o||!l){e.processedReqIds.delete(t.id),e.client.sendRes({type:"res",id:y,ok:!1,error:"sessionId and text are required"});return}const g=c,v=g==="manager"||R==="manager"?"manager":"standard";v==="manager"&&e.managerRuntime?.setManagerWorkerDefaults(o,_??null,k??null);const N=(g==="claude"||g==="codex"||g==="workbuddy"||g==="pi-coding-agent")&&typeof A=="string"&&A.trim()?A.trim():void 0,E=e.resolvePath(Je(g,h||ie.homedir(),n)||ie.homedir()),D=a?.managedAgentPolicy??($?e.managerRuntime?.getManagedAgentPolicyForWorker($,E)??null:null);if($&&!D)throw new Error("managed_worker_permission_context_unavailable");const Z=g==="codex"&&(a?.source==="room_activation"||$)?"internal":"user",J=$&&D?We({requestedPolicy:D.requestedPolicy,enforcement:D.enforcement,resolvedWorkDir:D.adapterPolicy.workDir}):w,Ae=E,F=Pe(t.params.attachments);F?.length&&$e(E,F);const p={text:l,attachments:F,localized:!1};let i=e.sessions.get(o);if(i){if(i.lastActiveAt=Date.now(),i.agentType!==g||(i.sessionMode??(i.agentType==="manager"?"manager":"standard"))!==v||i.workDir!==E||(i.nativeSessionVisibility??"user")!==Z||JSON.stringify(i.externalChannel??null)!==JSON.stringify(O??null)){e.sessions.delete(o);try{await B(e,i)}catch{e.processedReqIds.delete(t.id)}i=void 0}else if(n&&i.agentSessionId!==n)try{await i.adapter.resume(n),i.agentSessionId=n}catch{e.sessions.delete(o);try{await B(e,i)}catch{e.processedReqIds.delete(t.id)}i=void 0}}if(!i)try{i=await Ge(e,o,g,v,E,n,O,U,D,Z)}catch(d){const f=d instanceof Error&&d.message.startsWith("Unsupported agent:")?d.message:`Failed to start ${c}: ${d instanceof Error?d.message:String(d)}`;console.error(`[chat.send] start failed reqId=${t.id} sessionId=${o} agentType=${c} workDir=${E} agentSessionId=${n??""}: ${f}`),e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:o,message:f,runId:"",seq:0}}),e.processedReqIds.delete(t.id),e.client.sendRes({type:"res",id:y,ok:!1,error:f});return}const I={id:W??`user-${t.id}`,sessionId:o,role:"user",ts:Date.now(),payload:le(p.text,p.attachments)},ee=Array.isArray(L)&&L.length>0?L.map(d=>({id:d.clientMessageId??d.id,sessionId:o,role:"user",ts:Date.parse(d.createdAt),payload:le(d.text,d.attachments)})):null,Q=ee??[I],M=De(o,I.id),te=M.state==="queued";if(M.state!=="not_found"&&!te){e.client.sendRes({type:"res",id:y,ok:!0,payload:M});return}if(Y){a?.source==="room_activation"&&X(i.adapter,o,g,O,U,P,a.managedAgentPolicy,e.managedRoomExecutor);try{await je(i.adapter,p.text,r,N,p.attachments,J,a?{source:a.source}:void 0)}catch(d){e.processedReqIds.delete(t.id),e.sessions.delete(o),await B(e,i),e.client.sendRes({type:"res",id:y,ok:!1,error:d instanceof Error?d.message:String(d)});return}}b({level:"info",sessionId:o,wsEvent:"chat.send.start",metadata:{reqId:t.id,agentType:g,sessionMode:v,managerConfig:S??null,modelId:r,managerDefaultWorkerAgentType:_??null,managerDefaultWorkerModelId:k??null,reasoningEffort:N,...a?.source==="room_activation"?{managedRoomPromptSnapshot:a.managedRoomPromptSnapshot}:{}}});const V=(d,f)=>({...ue(ce()),sessionId:o,clientMessageId:I.id,messageId:I.id,deliveryState:d,bodyRevision:f,committedAt:new Date(I.ts).toISOString()}),ne=d=>{e.nativeFusion?.registerManagedSend({sessionId:o,agentType:g,sourceAgentType:me(g,r),canonicalMessageId:I.id,sourceSessionKey:i.agentSessionId??n??null,text:p.text,managedEchoPolicy:d?.deliveryMode==="external_owner_queue"&&!Se?"import_following":"suppress_following",externalRunId:d?.deliveryMode==="external_owner_queue"?`codex-external-${d.queuedSubmissionId??I.id}`:null})},ae=()=>{i.currentRunId||(i.currentRunId=`dispatch:${t.id}`,i.currentRunPhase="thinking",i.nextEventSeq=0)},re=()=>{if(ne(),te)return{...ue(ce()),sessionId:o,clientMessageId:M.clientMessageId,messageId:M.messageId,deliveryState:M.deliveryState,bodyRevision:M.bodyRevision,committedAt:M.committedAt};try{Ue(e,{sessionId:o,agentType:g,sessionMode:v,managerConfig:S??null,workDir:Ae,agentSessionId:i.agentSessionId??n??null,modelId:r,managerDefaultWorkerAgentType:_??null,managerDefaultWorkerModelId:k??null});let d=0;for(const[f,u]of Q.entries()){const x=ee?z(o,u,"committed"):q(o,u,"committed");f===0&&(d=x)}return ve(E,F??[]),T(e.client),V("committed",d)}catch(d){throw e.nativeFusion?.cancelManagedSend?.(I.id),d}},oe=d=>{i.currentRunId||(i.nextEventSeq=0),ne(d);const f=d?.deliveryMode==="external_owner_queue"?"queued":"executing";let u=0;for(const[x,j]of Q.entries()){const G=z(o,j,f);x===0&&(u=G)}return T(e.client),V(f,u)},se=async(d,f)=>{e.nativeFusion?.cancelManagedSend?.(I.id);const u=fe(g,d);console.error(`[chat.send] send failed reqId=${t.id} sessionId=${o} agentType=${c} workDir=${E} agentSessionId=${i.agentSessionId??n??""}: ${u}`),e.sessions.delete(o);try{await B(e,i)}catch{}if(e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:o,message:u,runId:"",seq:0}}),!f){const x={id:`agent-error-${t.id}-${Date.now()}`,sessionId:o,role:"agent",ts:Date.now(),payload:u};q(o,x),T(e.client)}f&&(e.processedReqIds.delete(t.id),e.client.sendRes({type:"res",id:y,ok:!1,error:u}))};if(Y){try{re()}catch(u){e.processedReqIds.delete(t.id),e.client.sendRes({type:"res",id:y,ok:!1,error:`Durable message commit failed: ${u instanceof Error?u.message:String(u)}`});return}ae();let d;try{a?.source==="room_activation"&&(ye(e,i,P),s());const u=p.attachments;d=await Ie(i.adapter,p.text,r,N,u,J,a?{source:a.source}:void 0),b({level:"info",sessionId:o,wsEvent:"chat.send.done",metadata:{reqId:t.id}})}catch(u){let x=0;for(const[G,ke]of Q.entries()){const Ee=z(o,ke,"failed");G===0&&(x=Ee)}T(e.client);const j=fe(g,u);await se(u,!1),e.client.sendRes({type:"res",id:y,ok:!0,payload:{...V("failed",x),failureMessage:j}});return}const f=oe(d??void 0);e.client.sendRes({type:"res",id:y,ok:!0,payload:{...f,...p.localized?{localizedAttachments:!0}:{},...d?.deliveryMode==="external_owner_queue"?{queued:!0,deliveryMode:d.deliveryMode,queuedSubmissionId:d.queuedSubmissionId}:{}}}),b({level:"info",sessionId:o,wsEvent:"chat.send.res",metadata:{reqId:t.id,ok:!0}});return}let de;try{de=re()}catch(d){e.processedReqIds.delete(t.id),e.client.sendRes({type:"res",id:y,ok:!1,error:`Durable message commit failed: ${d instanceof Error?d.message:String(d)}`});return}ae(),a?.source==="room_activation"&&(X(i.adapter,o,g,O,U,P,a.managedAgentPolicy,e.managedRoomExecutor),ye(e,i,P),s()),oe(),e.client.sendRes({type:"res",id:y,ok:!0,payload:{...de,...p.localized?{localizedAttachments:!0}:{}}}),b({level:"info",sessionId:o,wsEvent:"chat.send.res",metadata:{reqId:t.id,ok:!0}});const we=p.attachments;Ie(i.adapter,p.text,r,N,we,J,a?{source:a.source}:void 0).then(()=>{b({level:"info",sessionId:o,wsEvent:"chat.send.done",metadata:{reqId:t.id}})}).catch(d=>{z(o,I,"failed"),T(e.client),se(d,!1)})}async function yt(e,t){const{sessionId:a}=t.params,s=e.sessions.get(a);if(s){C(e,s);try{await s.adapter.stop()}catch{e.client.sendRes({type:"res",id:t.id,ok:!1,error:"agent_stop_failed"});return}Ke(e,a),e.activityPublisher?.publish(a,null)}e.client.sendRes({type:"res",id:t.id,ok:!0})}export{yt as handleChatAbort,ht as handleChatSend,Ue as sendSessionUpdateEvent};
@@ -10,6 +10,7 @@ export type ActiveSession = {
10
10
  workDir: string;
11
11
  agentType: AgentType;
12
12
  sessionMode?: SessionMode;
13
+ nativeSessionVisibility?: 'user' | 'internal';
13
14
  agentSessionId: string | null;
14
15
  lastActiveAt: number;
15
16
  currentRunId: string | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shennian",
3
- "version": "0.4.9",
3
+ "version": "0.4.10",
4
4
  "description": "Shennian — AI Agent Control Plane CLI",
5
5
  "type": "module",
6
6
  "bin": {