Skip to content

feat(opencode): add a setting that turns prompt-time recall off - #2455

Merged
hidb4ai merged 1 commit into
oceanbase:masterfrom
Fengzdadi:feat/opencode-prompt-recall-setting
Nov 4, 2026
Merged

hidb4ai merged 1 commit into
oceanbase:masterfrom
Fengzdadi:feat/opencode-prompt-recall-setting

Conversation

@Fengzdadi

Copy link
Copy Markdown
Contributor

Which issue or RFC does this PR close?

Part of #2250 (step 5 of the plan, starting with OpenCode). Gateway design: RFC #2199. The Codex setting is #2453.

Rationale for this change

When OpenCode's model traffic goes through the gateway, the gateway prepares and injects prepared context for each turn. Core's before_send check (_require_bound_markers in src/powercontext/builtin/runtime/context_check.py) rejects any BEGIN_POWERCONTEXT_PREPARED_CONTEXT_V1 or BEGIN_POWERCONTEXT_PREPARED_TEXT_V1 block that the gateway did not declare. On each turn the OpenCode plugin's chat.message hook calls prepare, and experimental.chat.messages.transform appends a synthetic text part with the prepared content to the current user message. With the plugin installed, every turn through the gateway fails:

  • each check returns 422, which the Server log names context-binding-required;
  • the gateway answers 503 gate_paused;
  • OpenCode retries six times per message, and the turn fails.

The gateway already recognizes OpenCode's x-opencode-session-id (gateway/README.md), so OpenCode through the gateway is an intended setup. As for Codex, only the host's configuration knows where its model requests go, so the signal is a plugin setting.

What changes are included in this PR?

  • integrations/opencode/plugins/powercontext/src/config.ts: new field promptRecall, read from POWERCONTEXT_OPENCODE_PROMPT_RECALL, default true, next to capturePrompts. It accepts the same boolean spellings as the other flags.
  • integrations/opencode/plugins/powercontext/src/index.ts (prepareTurn):
    • With promptRecall false, the plugin skips the /v1/context/prepare call. No content is cached for the turn, so the messages transform adds no synthetic part.
    • Prompt capture still follows capturePrompts, and it still resolves the Session Scope it needs.
    • When both settings are off, prepareTurn returns before resolving the Scope, so the plugin sends no request for the prompt.
    • No new log event: with recall off, the plugin writes no context_prepare entry. With both off, it also no longer writes the capture_content_source capture_disabled entry that capture-off alone still writes.
  • Unchanged, each under its own setting or none:
    • Session Scope resolution on session.created and session.updated.
    • The pc_* tools.
    • The GUIDANCE system text, which contains no marker.
    • The TUI. Its token-savings status reads statistics for the Scope the plugin resolves, so with recall off it counts the gateway's preparations only when PC_GATEWAY_DEFAULT_SCOPE is that same Scope.
  • lib/index.js, lib/tui.js and lib/tui.d.ts are rebuilt; make opencode-test confirms the committed bundle is current.
  • Docs:
    • docs/en/docs/integrations/opencode.md and docs/zh/docs/integrations/opencode.md:
      • a pointer in "Understand the behavior";
      • the setting and its default in "Configure the connection" (this guide has no settings table);
      • a short section, "Leave prompt-time context to the gateway", like the one feat(codex): add a setting that turns prompt-time recall off #2453 adds for Codex. It pairs the setting with POWERCONTEXT_OPENCODE_CAPTURE_PROMPTS=false and PC_GATEWAY_SEDIMENT=on, and names the Scope difference below.
      • The section also says to configure OpenCode's gateway provider with @ai-sdk/openai (the Responses route), because streamed Chat Completions turns don't complete through the gateway (below).
      • The OpenCode plugin has no bootstrap context, so the Codex bootstrap-dedup caveat does not apply.
    • The plugin README gets one paragraph and the setting in its list.
  • Tests:
    • tests/plugin.spec.ts: with recall off, the plugin resolves the Scope and captures, sends no prepare, and the transform adds nothing; with recall and capture both off, it makes no fetch call and adds nothing.
    • tests/config.spec.ts: the default is true; false turns recall off without changing capture; an invalid value is rejected.
    • The existing tests are unchanged.

What changes once the gateway owns prompt-time context

This comes from the gateway, not from this PR, and the docs state it:

Gateway observations from the run

These belong with the gateway follow-ups in #2250 and don't block this setting.

  • Chat Completions with streaming does not complete through the gateway. OpenCode always streams. On /gateway/v1/chat/completions the gateway forwards stream: true upstream and hands the SSE to before_release. Core's check accepts only application/json carriers there, so the release is withheld as carrier_unsupported and the gateway answers 409. Without allow_streaming=true on the target, before_send withholds streaming_unsupported first. This happens with or without the plugin. On /gateway/v1/responses the gateway sends a non-streaming upstream request and replays SSE, so the runs below use the Responses route (@ai-sdk/openai).
  • With the plugin's block in the message, the gateway injects nothing. The gateway's own prepare query includes the plugin's synthetic text and came back empty. So the rejected requests carry only the plugin's block, as in the PC_GATEWAY_INJECTION=off row of feat(integrations): keep host plugins thin and make them work behind the gateway #2250.
  • OpenCode's title request is treated as a turn. OpenCode sends a separate title-generation request with the same x-opencode-session-id. The gateway prepares and injects for it and, with sediment on, captures it as its own gw-turn Source: two messages produced three gateway Sources.

Are there any user-facing changes?

Yes, opt-in only:

  • New setting: POWERCONTEXT_OPENCODE_PROMPT_RECALL, default true.
  • Without the setting, the plugin behaves exactly as before.
  • With false, the OpenCode plugin sends no preparation request and injects no prepared context.
  • Settings, local state and Scope resolution keep their names and behavior.
  • No Server API change, no persisted-format change.

How was this change tested?

  • make opencode-test: install, 110 tests, typecheck, build, and git diff --exit-code on lib/: passed.

  • make check: passed (prek hooks, ruff, ty, manifest tests).

  • uv run pytest tests/test_opencode_cli.py tests/test_opencode_installation.py tests/test_full_capability_docs.py tests/test_docs_remote_access_contract.py "tests/test_integration_guidance_evaluation.py::test_native_adapter_handoff_uses_real_request_mapping_and_response_envelopes[opencode]" tests/e2e/test_opencode_plugin_host.py: passed. The e2e host test skipped because OpenCode is not on PATH.

  • make unit-test: 7766 passed, 365 skipped, 13 failed. None of the failing tests touch the OpenCode plugin; feat(codex): add a setting that turns prompt-time recall off #2453 reported the same failures on macOS:

    • 9 in tests/test_source_management.py, which read /proc/<pid>/stat, a Linux-only path;
    • 4 in tests/test_ci_installation_roles.py, which install wheels into fresh environments.
  • Real host: OpenCode 1.19.5 (npm opencode-ai, macOS arm64), unmodified.

    • Setup:
      • Each scenario used an isolated OpenCode home. The plugin was installed the way the e2e host test installs it: lib/index.js copied to config/opencode/plugins/. @opencode-ai/plugin was resolved offline from the plugin's own lock file.
      • The Server was built from upstream/master 63e9665, then from this branch, with enforced auth and enforcing context protection.
      • The gateway was the Rust gateway in the combined deployment (PC_GATEWAY_CORE_UDS), with injection at its default. The gateway/ tree is unchanged since 9c8f061.
      • The model was a local recording upstream on the Responses route. OpenCode sent max_output_tokens from the model's limit.output, so no shim was needed.
      • OpenCode reached the gateway through a recording proxy, which also served as the plugin's Server URL. A recording tap sat between the gateway and Core.
    • Each scenario sent two messages in one session (opencode run --format json, then opencode run --continue).
    Code Plugin settings Gateway Prepares per message, plugin / gateway Prepared blocks in each upstream request Result Sources per message
    master defaults not used 1 / 0 1, the plugin's PREPARED_CONTEXT_V1 part Both turns complete 1, the plugin's
    master no plugin sediment off 0 / 1 1, the gateway's PREPARED_TEXT_V1 block Both turns complete none
    master and this branch defaults sediment off 1 / 1 only the title request reaches the upstream Every check carrying the plugin's block returns 422 (12 per run); the Server log names context-binding-required. The gateway answers 503 gate_paused; OpenCode retries six times per message, and the turn fails. 1, the plugin's
    this branch PROMPT_RECALL=false, CAPTURE_PROMPTS=false PC_GATEWAY_SEDIMENT=on 0 / 1 1, the gateway's block Both turns complete; before_send and before_release allow 1, the gateway's gw-turn-*, plus one for the first title request
    this branch PROMPT_RECALL=false, capture default sediment off 0 / 1 1, the gateway's block Both turns complete 1, the plugin's opencode-user-prompt:*
    • Prepare counts leave out the title request; on the first message the gateway also prepared once for it.
    • With recall and capture both off, the plugin sent only the Scope resolutions from its session events: no prepare and no capture.
    • In each before_send check of the completed runs, the gateway declared one prepared context, and the carrier held exactly that block.
    • A first pair of runs on the Chat Completions route showed the same 422/503 failure with the plugin, plus the 409 described above.
    • Only OpenCode was run, through opencode run; the TUI was not exercised. The payloads were real OpenCode requests; the upstream was recorded, not a provider.

AI usage statement

This PR was prepared with Claude Code (Claude Opus 5.5). It made the change, the tests and the docs, ran the checks, and ran the real OpenCode host behind the gateway. I reviewed the change and the results.

POWERCONTEXT_OPENCODE_PROMPT_RECALL (default true) lets the OpenCode plugin
leave prompt-time context to the PowerContext gateway. Behind the gateway,
Core's before_send check rejects any prepared-context block the gateway did
not inject, so the plugin's synthetic context part made every turn fail.

With the setting false, chat.message sends no prepare request and the
messages transform adds no context. Prompt capture keeps its own setting;
with both off, the plugin sends no request for a prompt.

Part of oceanbase#2250.
Copilot AI balanced review requested due to automatic review settings November 4, 2026 06:37

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@PsiACE PsiACE left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, Thanks

@AlexStocks AlexStocks added the 1.5.1 v1.5.1 release tracking label Nov 4, 2026

@hidb4ai hidb4ai left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at 0c9b1a6. No blocking issues found: disabling prompt recall leaves capture independently controlled, and the default behavior is preserved. No new database tables or callable public APIs; the new configuration flag and gateway Scope/Responses-route constraints are documented.

Plugin tests, type checking, bundle reproducibility, and focused Python checks passed. Independent full OpenCode/gateway acceptance remains unverified: the local OpenCode probe timed out during dependency initialization before plugin activation.

@hidb4ai
hidb4ai merged commit 2853ed9 into oceanbase:master Nov 4, 2026
39 checks passed
jackie-cqz added a commit to jackie-cqz/powercontext that referenced this pull request Nov 4, 2026
Bring in the two commits that landed since the previous merge: the website
SEO and Markdown export changes (oceanbase#2454) and the OpenCode setting that turns
prompt-time recall off (oceanbase#2455). The merge is textually clean. Neither commit
touches `src/`, so nothing needed to follow the access-control, scheduler, or
helper moves.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

1.5.1 v1.5.1 release tracking

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants