Repository navigation
feat(codex): add a setting that turns prompt-time recall off - #2453
Conversation
There was a problem hiding this comment.
Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.
An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.
hidb4ai
left a comment
There was a problem hiding this comment.
Reviewed commit 9d1ea0c42574447afd9227008161a70d8cf650b1. I found no blocking code defect in the prompt-recall opt-out.
Merge readiness is still blocked by code-seekdb (3.14, 0): the job exceeded its 30-minute limit during unified-migration tests. CI result failed because that dependency was cancelled. The diff does not change the migration or workflow paths.
Please rerun the timed-out job, addressing its execution budget if the timeout repeats, and get the CI gate green before merging. Rerunning only the aggregate gate will not rerun the missing validation.
POWERCONTEXT_CODEX_PROMPT_RECALL=false makes the UserPromptSubmit hook send no preparation request and inject no context, for Codex setups whose model traffic goes through the gateway, which prepares and injects each turn. Prompt capture keeps its own setting; with both off the hook sends nothing. Part of oceanbase#2250.
9d1ea0c to
b518bcd
Compare
There was a problem hiding this comment.
Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.
An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.
hidb4ai
left a comment
There was a problem hiding this comment.
Re-reviewed b518bcdcce48f2935c09a67404a23ef461272479. The prompt-recall patch is unchanged after rebasing, and I found no blocking code defect. CI still has two validation blockers:
- code-seekdb (3.11, 0):
Test unified migrations with embedded seekdbexceeded its 25-minute step limit. The overall job now allows 60 minutes, so the previous job-budget increase has not completed this validation. - Candidate macos-arm64: downloading
email_validator-2.3.0-py3-none-any.whlfromfiles.pythonhosted.orgfailed with curl exit 35 (Recv failure: Operation timed out). The subsequent candidate build/consumption and bundled launcher/Ops checks were skipped.
Please rerun both failed jobs and get the CI gate green. If the migration step times out again, address its execution budget or runtime. These failures are in paths untouched by this PR; rerunning only the aggregate gate will not complete the missing checks.
Which issue or RFC does this PR close?
Part of #2250 (step 1 of the plan). Gateway design: RFC #2199.
Rationale for this change
When Codex's model traffic goes through the gateway, the gateway prepares and injects prepared context for each turn. Core's
before_sendcheck (_require_bound_markersinsrc/powercontext/builtin/runtime/context_check.py) rejects anyBEGIN_POWERCONTEXT_PREPARED_CONTEXT_V1orBEGIN_POWERCONTEXT_PREPARED_TEXT_V1block that the gateway did not declare. The Codex plugin'sUserPromptSubmithook adds such a block on every prompt. So with the plugin installed, every turn through the gateway fails: the check returns 422context-binding-required, and the gateway answers 503gate_paused. This happens even withPC_GATEWAY_INJECTION=off(see the table in #2250).Only the host's configuration knows, before a turn starts, where its model request will go. So the signal is a plugin setting, not a Server-wide owner flag. A Server-wide flag would also silence hosts the gateway does not carry, such as Claude Code.
What changes are included in this PR?
integrations/codex/plugins/powercontext/settings.py: new fieldprompt_recall: bool = True, read fromPOWERCONTEXT_CODEX_PROMPT_RECALL, next tocapture_prompts.integrations/codex/plugins/powercontext/hooks/recall.py:prompt_recallfalse, the hook skips the/v1/context/preparecall and returns noadditionalContext.capture_prompts, and it still resolves the Scope it needs.Unchanged, each under its own setting:
SessionStart: the bootstrap and the session binding. ItsBOOTSTRAP_CONTEXT_V1marker is not one the check covers.PreToolUse: MCP Scope binding.Stop(token savings): it reads statistics for the Scope the plugin resolves and does not depend on a prepare in the same turn. With recall off, it counts the gateway's preparations only whenPC_GATEWAY_DEFAULT_SCOPEis that same Scope.Docs:
docs/en/docs/integrations/codex.mdanddocs/zh/docs/integrations/codex.md:falseis needed and pairs it withPOWERCONTEXT_CODEX_CAPTURE_PROMPTS=falseandPC_GATEWAY_SEDIMENT=on. It also names the two differences once the gateway owns prompt-time context (below).Tests: two new Codex hook characterization cases in
tests/fixtures/hook_characterization/codex.json:prompt-recall-can-be-disabled: the hook sends Scope resolution and the capture. It sends no prepare and writes nothing to stdout.prompt-recall-and-capture-can-be-disabled: no request, no output.The existing cases are byte-identical: the fixture diff adds 117 lines and deletes none, and
claude-code.jsonis unchanged.scripts/integration_manifest.pystill finds the prepare, capture and flush routes inrecall.py, so the hook inventory andintegration-manifest-docs-checkare unchanged.What changes once the gateway owns prompt-time context
These come from the gateway, not from this PR, and the docs state them. They are gateway follow-ups and do not block this setting.
PC_GATEWAY_DEFAULT_SCOPE(gateway/crates/pc-gateway-app/src/main.rs). It does not use the Scope the plugin binds for the Session or workspace. The first gateway follow-up in feat(integrations): keep host plugins thin and make them work behind the gateway #2250 covers this: resolve the Scope from the Session binding.bootstrap_receipt_id, so the Runtime leaves out Memory the bootstrap package already injected. The gateway never sends one;gateway/has no reference to it. With bootstrap on and recall off, that Memory can appear again in the gateway's context.Overlap with #2317
#2317 (open) also changes
hooks/recall.py, bothcodex.mddocs andcodex.json. A trial merge of this branch with #2317's head c77d5c4 is clean. On the merged tree,tests/test_hook_characterization.pyandtests/codex_pluginpass (448 passed, 4 skipped). Whichever PR lands second will mergeupstream/masterand resolve any overlap.Are there any user-facing changes?
Yes, opt-in only:
POWERCONTEXT_CODEX_PROMPT_RECALL, defaulttrue.false, the Codex plugin sends no preparation request and injects no prepared context.How was this change tested?
uv run pytest tests/test_hook_characterization.py tests/codex_plugin tests/test_integration_manifest*.py: 465 passed, 4 skipped.make check: passed (prek hooks, ruff, ty, manifest tests).make unit-test: 7756 passed, 366 skipped, 17 failed. None of the failing tests touch the Codex plugin:tests/test_source_management.py, which read/proc/<pid>/stat, a Linux-only path, on macOS;tests/test_ci_installation_roles.py, which install wheels into fresh environments;tests/builtin/runtime/test_artifact_processing.py, which failed under parallel load and passed when rerun on their own.Real host: Codex CLI 0.166.0-alpha.5.1, unmodified (bundled with Codex.app, macOS).
codex plugin marketplace addandcodex plugin add.--dangerously-bypass-hook-trustwas not used.PC_GATEWAY_CORE_UDS). Thegateway/tree is unchanged since 9c8f061."max_output_tokens":4096to Codex's/gateway/v1/responsesbodies. Without it, Core stops Codex at 409output_limit_required.codex exec --json, thencodex exec resume --last).PROMPT_RECALL=false,CAPTURE_PROMPTS=falsePC_GATEWAY_SEDIMENT=onPREPARED_TEXT_V1block in the user messagebefore_sendandbefore_releaseallowgw-turn-*PROMPT_RECALL=false, capture defaultcodex-user-prompt:*context-binding-required. The gateway answers 503gate_paused. Codex sends 30 requests per message, and the turn fails.SessionStartrequests and Codex's model request.Stophook still resolved the Scope and loaded statistics. Codex ran noStophook for the failed turns of the default row.before_sendcheck, the gateway declared one prepared context, and the carrier held exactly that block.AI usage statement
This PR was prepared with Claude Code (Claude Opus 5.5). It made the change, the fixtures and the docs, ran the checks, and ran the real Codex host behind the gateway. I reviewed the change and the results.