(
definition: AgentDefinition,
relay: MessageTransport,
workDir: string,
credentialManager?: CredentialManager,
extraEnv?: Record<string, string>,
goal?: string,
preambleProvider?: PreambleProvider,
onRunComplete?: RunCompleteCallback,
timeBudgetMs?: number,
hasAutonomousWork?: AutonomousWorkChecker,
envProvider?: EnvironmentProvider,
)
| 134 | private lastSpawnResumeMissed = false; |
| 135 | |
| 136 | constructor( |
| 137 | definition: AgentDefinition, |
| 138 | relay: MessageTransport, |
| 139 | workDir: string, |
| 140 | credentialManager?: CredentialManager, |
| 141 | extraEnv?: Record<string, string>, |
| 142 | goal?: string, |
| 143 | preambleProvider?: PreambleProvider, |
| 144 | onRunComplete?: RunCompleteCallback, |
| 145 | timeBudgetMs?: number, |
| 146 | hasAutonomousWork?: AutonomousWorkChecker, |
| 147 | envProvider?: EnvironmentProvider, |
| 148 | ) { |
| 149 | // `idle_cached` is Claude-only: the resume mechanism relies on capturing |
| 150 | // Claude's `system/init` session id and passing it back as `--resume <id>`. |
| 151 | // Codex has no equivalent in this runtime today, so pairing `idle_cached` |
| 152 | // with a non-Claude runtime would silently degrade to `on-demand` |
| 153 | // semantics (no preserved context). |
| 154 | // |
| 155 | // Reject at construction using the *effective* runtime (i.e. honoring the |
| 156 | // `WANMAN_RUNTIME` env override, not just the declared `agent.runtime`) |
| 157 | // so an operator who runs `WANMAN_RUNTIME=codex wanman start` against an |
| 158 | // agents.json with idle_cached agents sees the problem at startup, not |
| 159 | // after wondering why context is being lost across triggers. |
| 160 | if (definition.lifecycle === 'idle_cached') { |
| 161 | const effectiveRuntime = resolveAgentRuntime(definition); |
| 162 | if (effectiveRuntime !== 'claude') { |
| 163 | const declared = definition.runtime ?? '(default)'; |
| 164 | const overridden = process.env['WANMAN_RUNTIME'] && process.env['WANMAN_RUNTIME'] !== definition.runtime |
| 165 | ? ` (forced by WANMAN_RUNTIME=${process.env['WANMAN_RUNTIME']})` |
| 166 | : ''; |
| 167 | throw new Error( |
| 168 | `Agent "${definition.name}" has lifecycle "idle_cached" but the effective runtime is "${effectiveRuntime}"${overridden}. ` |
| 169 | + `idle_cached only works with the Claude runtime — it relies on \`claude --resume\` to restore conversation context across triggers, ` |
| 170 | + `which Codex has no equivalent for in this runtime. ` |
| 171 | + `Either keep the runtime as "claude" (declared: "${declared}") or change the lifecycle to "on-demand".` |
| 172 | ); |
| 173 | } |
| 174 | } |
| 175 | |
| 176 | this.definition = definition; |
| 177 | this.relay = relay; |
| 178 | this.workDir = workDir; |
| 179 | this.credentialManager = credentialManager; |
| 180 | this.extraEnv = extraEnv ?? {}; |
| 181 | this.goal = goal; |
| 182 | this.preambleProvider = preambleProvider; |
| 183 | this.onRunComplete = onRunComplete; |
| 184 | this.timeBudgetMs = timeBudgetMs; |
| 185 | this.hasAutonomousWork = hasAutonomousWork; |
| 186 | this.envProvider = envProvider; |
| 187 | } |
| 188 | |
| 189 | /** |
| 190 | * Start the agent. Behaviour depends on the configured lifecycle: |
nothing calls this directly
no test coverage detected