mirror of
https://github.com/openclaw/openclaw.git
synced 2026-10-03 17:53:39 +00:00
334 lines
20 KiB
Markdown
334 lines
20 KiB
Markdown
---
|
|
summary: "Dynamic tools, web search, image loading, turn liveness, and runtime boundaries"
|
|
read_when:
|
|
- You want to know which OpenClaw tools reach a Codex turn
|
|
- You are debugging turn liveness or parallel chats
|
|
- You need the ownership split between OpenClaw and Codex
|
|
title: "Codex runtime behavior"
|
|
sidebarTitle: "Runtime behavior"
|
|
---
|
|
|
|
What the Codex harness owns during a turn, and what stays with OpenClaw. Part of the [Codex harness](/plugins/codex-harness) guide; [Where each section moved](/plugins/codex-harness#where-each-section-moved) lists every section.
|
|
|
|
## Dynamic tools and web search
|
|
|
|
OpenClaw exposes `skills_search` and `skills_read` as host-owned dynamic tools
|
|
when eligible installed skills and tool policy permit them. Search includes
|
|
skills omitted from OpenClaw's bounded prompt directory. Reads use an exact
|
|
installed name and return complete instructions or an explicit refusal if the
|
|
turn's dynamic-tool output budget cannot hold them. These tools do not change
|
|
Codex's native `skills` namespace or install marketplace skills. See
|
|
[installed skill search](/tools/skills#search-installed-skills).
|
|
|
|
Codex dynamic tools default to `searchable` loading. OpenClaw normally does
|
|
not expose dynamic tools that duplicate Codex-native workspace operations:
|
|
`read`, `write`, `edit`, `apply_patch`, `exec`, `process`,
|
|
`get_goal`, `create_goal`, `update_goal`, `tool_call`, `tool_describe`,
|
|
and `tool_search`. Goal operations stay native to Codex,
|
|
so OpenClaw does not project a second goal store into Codex turns. Most
|
|
remaining OpenClaw integration tools, such as messaging, media, cron,
|
|
browser, nodes, gateway, `progress_card`, and `heartbeat_respond` are available through
|
|
Codex tool search under the `openclaw` namespace, keeping the initial model
|
|
context smaller. The restricted-turn shell fallback is the exception for
|
|
`exec` and `process` when a finite allowlist disables native Code Mode;
|
|
runtime allowlists and `codexDynamicToolsExclude` still apply.
|
|
When native shell remains active and Gateway access is policy-eligible,
|
|
OpenClaw instead publishes the distinct `gateway_exec` and `gateway_process`
|
|
names so native shell and the OpenClaw-managed environment path cannot be
|
|
confused.
|
|
|
|
Tools marked `catalogMode: "direct-only"`, including the OpenClaw `computer`
|
|
tool, use the `openclaw_direct` namespace instead. Codex treats that namespace
|
|
as `DirectModelOnly`, so those tools stay directly model-visible in normal and
|
|
code-mode-only threads rather than crossing nested Code Mode `tools.*` calls.
|
|
|
|
Web search uses Codex's hosted `web_search` tool by default when search is
|
|
enabled and no managed provider is selected. Native hosted search and
|
|
OpenClaw's managed `web_search` dynamic tool are mutually exclusive so
|
|
managed search cannot bypass native domain restrictions. OpenClaw uses the
|
|
managed tool when hosted search is unavailable, explicitly disabled, or
|
|
replaced by a selected managed provider. OpenClaw keeps Codex's standalone
|
|
`web.run` extension disabled because production app-server traffic rejects
|
|
its user-defined `web` namespace. `tools.web.search.enabled: false`
|
|
disables both paths, as do tool-disabled LLM-only runs. Codex treats
|
|
`"cached"` as a preference and resolves it to live external access for
|
|
unrestricted app-server turns. Automatic managed fallback fails closed when
|
|
native `allowedDomains` are set so the allowlist cannot be bypassed.
|
|
Persistent effective search-policy changes rotate the bound Codex thread
|
|
before the next turn; transient per-turn restrictions use a temporary
|
|
restricted thread and preserve the existing binding for later resume.
|
|
|
|
`sessions_yield`, `sessions_spawn`, and message-tool-only source replies stay
|
|
direct because they are turn-control or delegation contracts. Guidance still
|
|
prefers Codex's native `spawn_agent` as the primary Codex subagent surface,
|
|
while explicit OpenClaw or ACP delegation remains directly callable through
|
|
`sessions_spawn`. In Codex Code Mode, generic OpenClaw
|
|
dynamic-tool results are JSON text rather than JavaScript objects, so parse
|
|
JSON-looking results before reading fields. Codex also serializes nested
|
|
dynamic calls; submit several `sessions_spawn` calls in a bounded loop rather
|
|
than expecting `Promise.all` to launch them concurrently. Already-accepted
|
|
children can still overlap while later calls are submitted. See
|
|
[Swarm](/tools/swarm#use-swarm-from-other-harnesses) for a complete pattern.
|
|
Scheduled heartbeat user messages identify `heartbeat_respond` when structured
|
|
responses are enabled; the tool remains discoverable through Codex tool search.
|
|
|
|
Set `codexDynamicToolsLoading: "direct"` only when connecting to a custom
|
|
Codex app-server that cannot search deferred dynamic tools or when
|
|
debugging the full tool payload.
|
|
|
|
## Inspecting tool output
|
|
|
|
Long tool results have a collapsed preview in the Control UI. **Show full output**
|
|
opens the saved result as plain text; copy and download use that text, not the
|
|
preview. Reloading the conversation reads the same saved result. Inspection is
|
|
subject to the Gateway's message-size limits and configured transcript redaction.
|
|
Tool-output inspection requests the supported maximum of 2,000,000 characters per
|
|
text field; a result that remains capped is explicitly marked unavailable.
|
|
A preview limit does not mean Codex truncated the model's input.
|
|
|
|
OpenClaw preserves the complete tool-response text exposed by Codex's
|
|
`rawResponseItem/completed` notification, including whitespace and Codex's own
|
|
truncation notices. Structured responses retain their text blocks as JSON;
|
|
non-text payloads are marked omitted rather than copied into the text inspector.
|
|
OpenClaw associates the response with its tool-call ID before checkpointing the result. If only an execution event is available, the result is
|
|
labeled as execution output instead. Code-mode response IDs are distinct from
|
|
nested command IDs.
|
|
|
|
If a native patch or command fails before Codex emits its native item, the mirror
|
|
can recover a failed `apply_patch` or `bash` receipt from a single-call Code Mode
|
|
wrapper with literal input and unmodified `text` output, including a local input
|
|
variable. A completed script can still contain a failed command: its structured
|
|
nonzero exit code owns that outcome. Existing native items retain their own IDs;
|
|
unsupported wrappers and unknown responses remain outer `exec` evidence.
|
|
|
|
Neither event proves the exact final model input. Codex can apply additional
|
|
history truncation and context normalization after constructing the response;
|
|
its app-server does not expose that final request representation here. OpenClaw
|
|
labels this limitation rather than treating raw stdout as model-visible output.
|
|
|
|
Older records with the `OpenClaw truncated Codex native tool output` notice lost
|
|
the omitted text before persistence. They explicitly show that the full output
|
|
is unavailable. The same limitation applies when only a bounded execution
|
|
stream was received and no complete response or completion output arrived.
|
|
Opening, copying, or downloading such a record cannot recover its missing text.
|
|
|
|
## Background text completions
|
|
|
|
With local stdio transport and the default `appServer.homeScope: "agent"`, Codex
|
|
completions for memory narratives and session titles run in a fresh private Codex
|
|
home and workspace. They retain the selected model and scoped
|
|
authentication, with a read-only sandbox and no model-callable tools, apps, or MCP
|
|
servers. Ordinary user and project hooks cannot enter that private process;
|
|
administrator-managed hooks remain active.
|
|
|
|
Private completions support directly executable launchers and Node script
|
|
wrappers. Inline shell/eval commands and ambiguous launcher arguments fail with
|
|
an isolation error; use a directly executable wrapper for those custom launches.
|
|
|
|
User-home mode retains the native Codex account, even when an OpenClaw auth
|
|
profile also exists. Stdio proxies and remote transports retain their configured
|
|
server. These connections keep their existing restricted completion behavior
|
|
and reject managed hooks when their isolation cannot be verified. Managed
|
|
requirements that force a conflicting tool capability still reject the completion.
|
|
|
|
## Image loader ownership
|
|
|
|
For image-capable models with Codex native tools enabled, Codex owns
|
|
`view_image` and OpenClaw suppresses its duplicate loader. The native Codex
|
|
schema accepts one local filesystem `path`. For text-only models, or when the
|
|
native tool surface is disabled, OpenClaw supplies `view_image` with its
|
|
`path`/`paths` schema and delegated vision route. Callers must use the schema
|
|
advertised for the active run.
|
|
|
|
When OpenClaw restores conversation history into a Codex thread, saved images
|
|
stay beside their original messages inside the quoted history. The current
|
|
request and its attachments follow that history, so a later text or voice turn
|
|
does not present old screenshots as newly attached images. If context limits
|
|
remove an image's original message, its image input is omitted too; the saved
|
|
transcript and attachment remain unchanged.
|
|
|
|
Sending another attachment does not suppress generated images from the final
|
|
reply. OpenClaw omits a generated image only when it can match confirmed delivery
|
|
of that image to the reply destination. A partial delivery with uncertain
|
|
attachment outcomes can leave a duplicate image rather than lose an unsent one.
|
|
|
|
## Turn liveness and timeouts
|
|
|
|
Codex owns provider-stream liveness and native turn completion. OpenClaw waits
|
|
for the exact `turn/completed` outcome rather than interrupting a quiet turn or
|
|
treating assistant output as completion. Malformed completion payloads do not end
|
|
the run: OpenClaw waits for a valid native outcome instead of inventing missing
|
|
items, tool arguments, or completion states. The existing
|
|
`agents.defaults.timeoutSeconds` limit is an elapsed execution budget per
|
|
attempt: progress does not reset it, and `0` means unlimited execution.
|
|
OpenClaw still bounds its own requests, dynamic tools, cancellation, and local
|
|
settlement. See [Timeouts](/plugins/codex-harness-reference#timeouts) for those
|
|
budgets, Stop and replay behavior, and Doctor migration of retired idle settings.
|
|
|
|
Failed app-server startup waits for child shutdown before returning its error.
|
|
If startup times out or is canceled during process registration, cleanup joins
|
|
that registration and closes any late child. Cleanup can extend beyond the
|
|
startup deadline. A canceled caller leaves startup running when another caller
|
|
still owns it.
|
|
|
|
OpenClaw preserves assistant text supplied with the initial native item and
|
|
reasoning supplied with a completed item, even when Codex sends no text deltas.
|
|
Completed items, including empty messages, reconcile the transcript with Codex's
|
|
final content. Raw provider copies cannot restore text that Codex removed. Messages
|
|
marked for asynchronous delivery remain separate from the final reply when
|
|
Codex repeats them in the turn-completion summary.
|
|
|
|
## Cyber safety notices
|
|
|
|
The Control UI shows a notice above the composer when Codex reports cyber
|
|
safety buffering, a cyber-policy refusal, or a provider model reroute for
|
|
high-risk cyber activity. These notices use structured app-server events;
|
|
OpenClaw does not infer classifier activity from the assistant's wording.
|
|
|
|
Buffering means the provider is still processing the request. Its notice clears
|
|
when assistant output starts or the turn ends. A blocked notice remains until
|
|
the next turn or a session reset. A reroute notice reports the model selected
|
|
by the provider.
|
|
|
|
Gateway agent-event consumers receive these updates on the `notice` stream
|
|
with `phase: "provider_policy"`, `provider: "openai"`, `category: "cyber"`, and
|
|
a `state` of `buffering`, `blocked`, `fallback`, `escalated`, `unavailable`, or
|
|
`cleared`. Model fields are present when the upstream event provides them. A
|
|
suggested fallback model is informational and does not prove that the account
|
|
can use it.
|
|
|
|
## Automatic Daybreak escalation
|
|
|
|
OpenAI declines some defensive-cyber work on its general models and directs
|
|
approved workspaces to a Daybreak model instead. When a turn ends in a
|
|
cyber-policy refusal, OpenClaw retries it once on the configured Daybreak model
|
|
so the refused work reaches the tier allowed to answer it. This is on by
|
|
default and is configured under
|
|
`plugins.entries.codex.config.appServer.cyberFailover`.
|
|
|
|
Daybreak trails the general models in capability, so escalation stays scoped to
|
|
work that was actually refused:
|
|
|
|
- At most one escalated attempt per turn. A second refusal under Daybreak keeps
|
|
the block and stops.
|
|
- A turn already running on the configured Daybreak model is never escalated.
|
|
- A turn that already acted is never retried. Escalation requires the attempt's
|
|
own replay-safe verdict, so a turn refused after it sent a message, added a
|
|
cron entry, spawned a session, started a native continuation, or generated
|
|
media keeps its result. Cancellation, timeout, or a later failure also prevents
|
|
escalation even if the result retains a refusal diagnostic.
|
|
- Only a refused turn is ever routed to Daybreak. Every turn starts on the model
|
|
the session selected, and a turn that was not refused never reaches the weaker
|
|
tier.
|
|
- The retry does not mirror the prompt into the transcript a second time. The
|
|
refused attempt's own terminal row is discarded with its result rather than
|
|
staged, so a successful escalation returns the Daybreak answer; the refused
|
|
turn still exists upstream in the native Codex thread, which OpenClaw does not
|
|
rewrite.
|
|
- Only OpenAI's own cyber refusal on the current attempt escalates. Another
|
|
provider's refusal, another category, and a refusal inherited from an earlier
|
|
turn all leave the result untouched.
|
|
- Escalation never changes the session's stored model selection, and the only
|
|
retained state is the unauthorized-target record below, which is process-local
|
|
rather than persisted.
|
|
|
|
Authorization stays server-owned. `model/list` advertises Daybreak to every
|
|
client, so catalog presence does not prove entitlement: an unentitled workspace
|
|
still receives `401`/`403` on use, and each such attempt costs the transport's
|
|
full reconnect ladder. OpenClaw therefore treats the retry itself as the only
|
|
evidence and reports an `unavailable` notice rather than a silent block. If the
|
|
fallback target is denied without tool activity, side effects, native
|
|
continuation, or interruption, OpenClaw keeps the original refusal even when
|
|
the fallback produced no assistant message. Otherwise, its result is preserved
|
|
so those facts reach the runner.
|
|
|
|
Because entitlement belongs to the authenticated workspace and the target model
|
|
rather than to any one conversation, an unauthorized target is remembered once
|
|
for every session under that workspace and cannot be displaced by session churn.
|
|
A separate workspace that is entitled keeps escalating normally, and the record
|
|
releases on its own once `cooloffMs` elapses. Only one probe runs at a time for a
|
|
given workspace and target, so sibling sessions refused at the same moment do not
|
|
each pay the reconnect ladder before the first result lands.
|
|
|
|
## Parallel chats and thread ownership
|
|
|
|
Independent chats can share a Codex app-server and run concurrently. Resuming
|
|
an idle chat does not require unrelated chats, model discovery, or tool-catalog
|
|
reads to finish. OpenClaw coordinates its own lifecycle operations for each
|
|
native thread and preserves that thread's identity across ordinary resumes.
|
|
A closed, replaced, or retired client still cannot complete a stale handoff.
|
|
|
|
Managed local connections share a bounded inference relay. Up to 16 request
|
|
preparations and uploads run at once, with another 16 waiting in arrival order.
|
|
Responses keep streaming after their upload capacity is released, so a long
|
|
response does not block a seventeenth chat or native child from starting.
|
|
|
|
The relay allows up to 80 combined HTTP operations and WebSocket connections,
|
|
with room for 16 pending or closing admissions. It retains up to 64 usable
|
|
WebSockets and reclaims the oldest completed idle connection when either
|
|
transport needs room. Active responses and newly opened connections awaiting
|
|
their first request are not evicted. HTTP connections close after each response;
|
|
native WebSocket reuse remains intact. The separate limit of 64 admitted root
|
|
contexts is unchanged; transport capacity is not a count of saved conversations.
|
|
|
|
A new WebSocket waits before opening its upstream connection; admission and its
|
|
handshake share a 10-second deadline. HTTP admission and queued WebSocket
|
|
uploads wait at most 30 seconds. Cancelled or superseded queued work does not
|
|
reach the provider. Already-started preparation and transport cleanup keep their
|
|
capacity until their owning operation settles.
|
|
|
|
These limits apply across chats and native child agents sharing the relay.
|
|
Queue capacity or deadline exhaustion returns a retryable busy response.
|
|
Sustained overload can still fail a turn after Codex exhausts its retries.
|
|
|
|
If an admitted WebSocket cannot connect upstream, the relay returns HTTP `502`;
|
|
an upstream handshake deadline returns `504`. These errors use a fixed message
|
|
without credentials or model content. Native Codex keeps control of retries and
|
|
HTTPS fallback. Provider HTTP failures retain their original status and body.
|
|
|
|
After a completed provider failure, you can continue in the same chat with its
|
|
existing configuration. OpenClaw retains the configured native thread, including
|
|
for `/codex resume` of that chat's already-bound thread. Native provider policy refusals
|
|
end the current attempt without a native retry. OpenClaw's configured cyber
|
|
fallback described above is a separate attempt. A later user message is a
|
|
separate turn; it does not supply a native policy override or user confirmation.
|
|
|
|
With Codex app-server `0.153.4`, first-time adoption or changed configuration of a
|
|
loaded failed thread still requires native unloading. OpenClaw preserves the
|
|
thread and reports missing configuration confirmation instead of assuming the
|
|
changes took effect. Existing active-turn and parent-controlled-thread checks
|
|
still apply.
|
|
|
|
This coordination does not make native configuration replacement atomic against
|
|
Codex-internal controllers. Native subagent reloads or another native controller
|
|
can operate outside OpenClaw's thread queue. Avoid concurrently reconfiguring the
|
|
same native thread through multiple controllers; observing native teardown alone
|
|
does not reserve it against a subsequent native reload.
|
|
|
|
## Runtime boundaries
|
|
|
|
The Codex harness changes the low-level embedded agent executor only.
|
|
|
|
- OpenClaw dynamic tools are supported. Codex asks OpenClaw to execute
|
|
those tools, so OpenClaw remains in the execution path.
|
|
- Codex-native shell, patch, MCP, and native app tools are owned by Codex.
|
|
OpenClaw can observe or block selected native events through the
|
|
supported relay, but it does not rewrite native tool arguments.
|
|
- `gateway_exec` and `gateway_process` are OpenClaw-owned dynamic tools. They
|
|
deliberately re-enter Gateway exec preparation for agent-readable Secret
|
|
Store environment and protected egress; those values never flow into Codex
|
|
native shell.
|
|
- Codex owns native compaction. OpenClaw keeps a transcript mirror for
|
|
channel history, search, `/new`, `/reset`, and future model or harness
|
|
switching, but does not replace Codex compaction with an OpenClaw or
|
|
context-engine summarizer.
|
|
Completed commentary and tool activity are saved during the turn rather than
|
|
waiting for its final answer, preserving completed work across Gateway interruption.
|
|
- Media generation, media understanding, TTS, approvals, and messaging-tool
|
|
output continue through the matching OpenClaw provider/model settings.
|
|
- `tool_result_persist` applies to OpenClaw-owned transcript tool results,
|
|
not Codex-native tool result records.
|
|
|
|
For hook layers, supported V1 surfaces, native permission handling, queue
|
|
steering, Codex feedback upload mechanics, and compaction details, see
|
|
[Codex harness runtime](/plugins/codex-harness-runtime).
|