* fix(codex): full-auto approvals survive relay unavailability, typed failure classification, usage line after fallback
- full-auto (approvalPolicy never + danger-full-access) exec approvals no
longer get declined when the native hook relay is unreachable BEFORE
invocation; an invoked relay's explicit deny, malformed output, or nonzero
exit still fails closed (#107447)
- startup timeout/abort and request-timeout classification use typed error
discriminants instead of message prose; EPIPE detection walks error causes;
compaction keeps the message-based thread-not-found gate because codex-rs
exposes no dedicated code (its own contract test asserts the message) and
the generic -32600 would over-match unrelated invalid requests (#99270)
- /status keeps the Codex usage/quota line for sessions whose persisted
agentHarnessId is codex even when the effective runtime fell back to
OpenClaw Default; never-codex sessions remain excluded (#105184)
* chore(codex): keep startup error reason type module-local
* feat(channels): render live plan checklists from typed update_plan snapshots
Codex, Copilot, CLI, and embedded update_plan events now carry typed
{step, status} snapshots end to end instead of flattened strings. Slack,
Discord, Telegram, Matrix, and MS Teams render a live checklist in
progress drafts; Slack native task cards show the real plan with
position-keyed rows and id reconciliation. The embedded update_plan tool
is default-on for every model (tools.experimental.planTool: false opts
out). The shipped onPlanUpdate steps: string[] SDK field stays populated
during a deprecation window alongside the canonical planSteps.
* fix(auto-reply): align plan bridge types with SDK callback contract
* fix(auto-reply): split agent event bridge module and fix plan type boundaries
* fix(channels): satisfy oxlint on plan checklist helpers
The deleted text provider's usage hook was the only source for the /status
Codex subscription usage line. Harnesses can now contribute an optional
usage snapshot (provider hooks keep priority; only distinct synthetic hook
owners fall through), and the codex harness reports app-server rate limits
via account/rateLimits/read with the same conversion and account identity
as before. No text provider resurrected; deadcode and SDK surface gates
clean.
- null-vs-undefined runtime record type at the provider-move helper
- gateway models.list fixtures expect the new agentRuntime intent field
(codex/implicit for policy-backed OpenAI routes, openclaw/implicit for
synthetic routes without provider policy)
- split doctor cron legacy-repair into its own module to satisfy the
max-lines gate without suppressions; callers import directly
The live codex text provider was a redundant projection of the openai
catalog (exclusive provider ownership; the openai plugin's ChatGPT OAuth
discovery already serves gpt-5.6-* route-aware). Folding it:
- extensions/codex no longer registers a text provider, catalog entry, or
synthetic text auth; provider.ts/provider-catalog.ts/provider-discovery.ts
and the route-blind model-name heuristics are deleted; the narrow
post-harness reasoning fallback moves to an app-server-owned module
- openai thinking policy keys on explicit selected-route provenance
(api === openai-chatgpt-responses) instead of value-shape inference
- models.list gains an optional additive agentRuntime field (configured
intent); session agentHarnessId remains the execution proof
- doctor --fix migrates the shipped codex/* config shape end to end:
every model slot, provider-config merge with blocker-aware conflict
handling, sessions, cron payloads (two-phase: runtime policy persists
before cron refs rewrite), transcripts; migrated refs carry model-scoped
agentRuntime.id=codex preserving the shipped wizard semantics; auto
runtime policies normalize to codex with sibling fields preserved;
blocked provider conflicts retain the whole legacy namespace fail-closed
with an actionable warning
- the stale openai:default profile cleanup (#91352) was deliberately
deferred to a follow-up after review showed it needs per-agent identity
proofs; doctor keeps warning about unusable profiles
Fixes#105561Fixes#84637Fixes#90420
* fix(codex): settle plugin activation, align plugin/list with codex 0.144, bound discovery per turn
- plugin/list curated queries omit cwds and marketplaceKinds (0.144 semantics:
explicit kinds disable the automatic global remote catalog; cwds:[] never
suppressed it), and the missing-marketplace check recognizes the current
openai-curated-remote wire name via the shared predicate (#107305)
- curated plugin/list snapshots settle in a process-local metadata cache
(coalesced, invalidated on install/identity change/restart, 1h freshness
window matching the app-inventory cache) so a missing marketplace or plugin
no longer re-runs blocking discovery RPCs on every embedded-Codex turn;
fail-open local-only responses (upstream warns without a load error when the
remote catalog fetch fails) are never cached, and workspace-directory
queries stay live because external activation has no invalidation signal
- the whole plugin-config build shares one bounded startup deadline with
remaining-budget propagation per RPC and a deny-all apps fallback, so a hung
plugin/list cannot consume the turn (#107305)
- guarded thread requests (start/resume/fork under the native-config fence)
must carry a finite timeout or abort signal, closing the unbounded-fence-hold
window for raw callers (#106719 hardening)
* chore(codex): keep plugin metadata types and deadline builder module-local
Deadline behavior tests exercise the production provider composition instead
of a test-only export.
Move the Codex-specific PreToolUse loop relay switch into the Codex
plugin, preserve policy relays, and cover both normal and side turns.
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: marchpure <marchpure@users.noreply.github.com>
* test(codex): use allowlisted placeholder for auth-bridge api-key fixture
* fix(codex): model-scoped usage-limit blocks, structural 429 classification, no silent API-key billing
- usage-limit blocks written from Codex rate-limit resets are model-scoped via
a persisted blockedScope marker: healthy sibling models on the same auth
profile stay usable; a different/unknown model failing widens the block
profile-wide and never narrows back; legacy rows without the marker stay
profile-wide until they expire (#100556)
- Codex usage-limit failures now surface as status-429 Error objects at both
ingress paths (turn-start and streamed turn failure, wrapped at the event
projector), so core failover classification is structural instead of
matching message wording; profile blocking uses only rate-limit data whose
revision advanced during the turn
- usage-limit detection requires the structured codexErrorInfo signal; the
over-broad "usage limit" substring match that misclassified unrelated
errors as subscription limits is gone (#96815)
- subscription/OAuth routes can no longer silently fall back to env/auth.json
API keys: ambient key fallback is restricted to explicit api-key routes,
native-auth subscription routes verify the account is chatgpt-backed via
account/read, and shared app-server clients are partitioned by auth
requirement so pooled clients cannot cross billing modes (#106375)
- integrated e2e regression: usage-limit promptError -> same-model sibling
profile rotation -> model fallback with reason rate_limit
* chore(codex): keep CodexUsageLimitErrorResult type local
* fix(codex): use structured turn status for aborts, repair tool schemas, relay native results to middleware
- turn aborts are detected from the correlated turn/completed status instead
of byte-matching private codex-rs prose; the <turn_aborted> marker remains a
non-terminal user-interrupt hint (tags only, wording-independent) because the
app-server collapses all abort reasons into "interrupted" (#99268)
- dynamic-tool schemas are repaired before projection via the shared OpenAI
normalizer: annotation nulls stripped, type:null inferred from object/array
shape hints; unrepairable null constraints stay quarantined instead of
widening the schema (#106277, #97913)
- Codex-native tool results now flow through agentToolResultMiddleware at the
post_tool_use relay boundary (observe-only: the Codex PostToolUse contract
cannot replace a native tool response) (#95597)
* test(codex): regenerate prompt snapshots for normalized dynamic-tool schemas
The shared OpenAI strict-compat normalization now runs on Codex dynamic tools,
so empty object schemas gain additionalProperties:false and required:[] in the
snapshot payloads, matching what the OpenAI provider family sends.
- session_end with a provably different nextSessionKey (dashboard "New Chat",
fork child) no longer permanently retires the still-live parent Codex
binding; same-key rollovers, unknown-key ends, and terminal ends retire as
before (#106778)
- mirrored session-history reads treat well-formed non-Codex transcripts as an
empty mirror instead of a read failure, so codex harness hooks stop warning
on every non-Codex model run; corrupted session headers stay on the warn
path (#106556)
Successful Codex dynamic-tool results now use the shared failure classifier, preventing Skill Workshop and plugin lifecycle metadata from being persisted as failed calls.
Refs #107684.
Prepared head SHA: e5bfcdb085
Co-authored-by: Shakker <165377636+shakkernerd@users.noreply.github.com>
Reviewed-by: @shakkernerd
User-facing name is now OpenClaw (the system speaks); internal code name is
system-agent. Gateway methods crestodian.* -> openclaw.chat/openclaw.setup.*,
agent tool -> openclaw, reserved agent ids openclaw + retired crestodian.
openclaw setup routes: onboarding flags -> onboard, -m/--yes -> system agent,
bare configured interactive -> OpenClaw chat, unconfigured -> onboarding.
Hidden crestodian CLI and /crestodian TUI aliases kept; docs moved to
docs/cli/openclaw.md with redirect stub. macOS/Android strings in lockstep.
Refs #107237
Requester-scoped servers never enter harness-native MCP config: Codex
thread and CLI user-MCP projections partition them out (fail-closed,
static-partition fingerprints stay sender-independent so shared threads
never rotate). Codex delivers them as per-attempt dynamic tools through
a scoped-only runtime path on the same core manager, with a
session-stable advertised catalog so authed and unauthed senders share
one spec surface; unauthed calls get a clean not-connected tool error.
New SDK seam materializeRequesterScopedMcpToolsForHarnessRun lets any
future harness consume the same contract.
* feat(codex): read the account email with app-server usage
The Codex-harness usage snapshot now carries the account identity: the
usage fetch runs account/rateLimits/read and account/read over one
app-server session (new withCodexAppServerJsonClient seam, which the
single-request helper now delegates to), so the email is guaranteed to
belong to the same account as the windows. Identity stays best-effort;
rate limits survive an account read failure.
* style(test): scanner-safe app-server marker fixture
* test(codex): keep scanner-neutral hunks around app-server marker literals
* fix(codex): bound the best-effort account read within the usage deadline
Review P2: account/read shared the outer usage deadline, so a slow or hung
identity read could reject the whole snapshot with a timeout instead of
returning the already-fetched rate-limit windows. Race the account read
against a local timer bounded to min(4s, usageTimeoutMs/3) and drop the
identity on timeout; a regression test hangs account/read and asserts the
windows still return.
* fix(codex): send account/read params and bound identity by the remaining deadline
Second review round: account/read (GetAccount) requires a params object per
the app-server protocol, so send an empty {} (refreshToken defaults false);
without it a real app-server rejects the request. Bound the best-effort
identity read by the time left before the shared usage deadline (minus a
margin) instead of the original budget, so a slow rate-limit read can no
longer let the identity read trip the outer timeout and discard the
already-fetched windows.
* fix(codex): reserve the isolated shutdown budget in the usage deadline
Third review round: withCodexAppServerJsonClient awaits the isolated
client's closeAndWait inside the outer timeout, so a hung account/read
could reach the deadline during force-kill/exit cleanup and discard the
already-fetched windows. The usage read now passes a cheap isolatedShutdown
(force-kill 200ms + exit 300ms) and the identity bound reserves that plus a
250ms margin (750ms) of the remaining deadline, so cleanup always finishes
before the outer timeout.
* style(codex): rename scoped-request generic to avoid shadowing
* fix(codex): do not promote missing_tool_result on abort/interrupt
Keep synthetic tool.result rows for transcript integrity, but skip
promoting the missing-tool invariant to promptError when the turn is
already aborted or interrupted so mid-exec cancel paths keep abort
classification and assistant text (#104898).
* fix(codex): preserve explicit abort outcome
---------
Co-authored-by: Altay <altay@hey.com>
* refactor: use semver package for version ordering
* refactor: centralize semver validation
* chore: keep release notes in PR body
* refactor: update semver LOC ratchet
Omitted final on a confirmed message-tool-only source reply keeps main's terminate-on-delivery semantics and records a completed marker; only explicit final=false defers termination. Project the Codex-only final schema property in place on attempt-fresh tools instead of adding a public plugin-SDK clone export, resolving the SDK surface budget failure.
Distinguish progress from terminal source delivery across Codex telemetry,
payload suppression, terminal failure routing, and stranded-reply recovery.
Preserve legacy behavior when explicit markers are absent.