Skip to content

Conversation

@ghoulr
Copy link
Contributor

@ghoulr ghoulr commented Nov 27, 2025

NOTICE: this PR is cooked by GPT-5.1-high, I've discussed the issues with it to confirm the problem and solution, reviewed the codes and tested for several hours in my local developement environment.

This is GPT-5.1-high talking:
———

Changes

  1. Avoid 400 No tool call found for function call output in non‑tool turns
  • File: lib/request/request-transformer.ts
    • In transformRequestBody():
      • Tool turns (when body.tools is present) behave exactly as before: all function_call / function_call_output items are preserved.
      • For non‑tool turns (no body.tools), after existing transformations, the code now filters out any input items with:
        • type === "function_call"
        • type === "function_call_output"
  • Motivation:
    • In final “summary” / “wrap‑up” turns, OpenCode can still include historical tool calls and outputs in input, even though no new tools will be invoked.
    • With store: false (stateless mode), the Codex backend expects every function_call_output in the request to have a matching function_call in the same input array. Historical residue without a matching call leads to:
      • No tool call found for function call output with call_id ... (400, invalid_request_error).
    • Those tool items are no longer needed for the summary response, so dropping them only in non‑tool turns is the simplest stateless fix that keeps tool behavior unchanged where it matters.
  • Tests:
    • File: test/request-transformer.test.ts
    • Added should drop function_call items when no tools present:
      • Builds a request with user message + function_call + function_call_output, and tools: undefined.
      • Asserts that after transformRequestBody only the user message remains in input, with no tool items sent.

———

  1. Robust GitHub latest‑release tag resolution (403‑resilient fallback)
  • File: lib/prompts/codex.ts
    • getLatestReleaseTag() now:
      1. Prefers the JSON API (unchanged happy path):
      2. Automatically falls back to HTML on failure:
        • If the API call fails (network error, non‑OK status such as 403, or missing tag_name), it does not throw immediately.
        • Instead, it requests https://github.com/openai/codex/releases/latest and:
          • First tries to parse the final response.url after redirects (typically /releases/tag/).
          • If that’s not usable, parses the HTML body for /openai/codex/releases/tag/ using a simple regex.
          • Only throws "Failed to determine latest release tag from GitHub" if both URL‑based and HTML‑based parsing fail.
    • Once the tag is determined, instructions are still fetched from:
  • Motivation:
    • Some environments hit 403 on api.github.com even with light usage (rate limits, corporate network rules, etc.), previously causing logs like:
      • [openai-codex-plugin] Failed to fetch codex-max instructions from GitHub: Failed to fetch latest release: 403
    • The plugin should still track the latest Codex release, but be resilient when api.github.com is unavailable. Falling back to the public github.com releases page keeps the behavior correct without introducing new configuration knobs.

———

Thanks for your plugin, it's super NEAT!

@numman-ali
Copy link
Owner

Thank you for doing the PR! It really helps in confirming the issue

I can see it happens on compacting - doing a deeper dive to see exactly what the issue is so that all edge cases are covered

@numman-ali numman-ali changed the title Fix orphan function_call outputs (400) and add robust GitHub fallback (403) fix: orphan function_call outputs (400) and add robust GitHub fallback (403) Nov 27, 2025
@numman-ali numman-ali merged commit 86417fe into numman-ali:main Nov 27, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants