Skip to content

fix(github): drop trailing assistant prefill for Copilot chat - #5802

Merged
diegosouzapw merged 5 commits into
release/v3.8.43from
fix/port-pr-2143-github-prefill
Jul 2, 2026
Merged

diegosouzapw merged 5 commits into
release/v3.8.43from
fix/port-pr-2143-github-prefill

Conversation

@diegosouzapw

@diegosouzapw diegosouzapw commented Jul 1, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

GitHub Copilot's /chat/completions rejects (400) a request whose last message is an assistant prefill. This strips trailing assistant message(s) before dispatching to GitHub Copilot, scoped to the GitHub executor only (real Anthropic/OpenAI upstreams honor prefill, so the shared translator is untouched).

Changes

  • open-sse/executors/github.ts — new dropTrailingAssistantPrefill(messages) method, called at the end of transformRequest (right after sanitizeChatCompletionsMessage). Returns the same array reference when the conversation already ends in user/tool (no-op); never empties an assistant-only array; null/empty safe.
  • Two pre-existing executor-github.test.ts fixtures that incidentally ended in a bare trailing assistant were given a realistic trailing user/tool turn so they keep testing their original intent (response_format injection, tool_calls pass-through) instead of tripping the new guard — no assertions removed or weakened.

Attribution

Thanks to @baslr for the original implementation.

Testing

TDD (Hard Rule #18): new tests/unit/executor-github-prefill-sanitize.test.ts (8 cases) fails before the method exists (7/8 red), passes after (8/8). Full executor-github.test.ts + related GitHub-executor suites green (25/25). typecheck:core, eslint, check:any-budget:t11 clean.

GitHub Copilot's /chat/completions endpoint rejects a conversation that
ends with an assistant message: "This model does not support assistant
message prefill. The conversation must end with a user message."
(HTTP 400). Anthropic clients such as newest Claude Desktop send a
trailing assistant turn as a prefill seed — the Anthropic API honors
it, but Copilot does not.

Add a self-contained GithubExecutor.dropTrailingAssistantPrefill()
that strips trailing assistant message(s) before dispatch, called at
the end of transformRequest right after the existing
sanitizeChatCompletionsMessage map. Scoped to the GitHub executor
only — the shared translator/contextManager and other providers that
do honor prefill (e.g. Mistral's dedicated Set) are untouched. Never
empties the array (an assistant-only conversation keeps its last
message); no-op (same array reference) when the conversation already
ends with a user/tool message.

Two pre-existing executor-github.test.ts fixtures incidentally ended
in a bare trailing assistant message while testing unrelated behavior
(reasoning-field stripping, tool_calls pass-through); extended them
with a trailing user/tool turn so they keep exercising their original
intent instead of tripping the new prefill guard.

Regression guard: tests/unit/executor-github-prefill-sanitize.test.ts
(8 cases — single/multiple trailing assistant, user/tool no-op with
reference identity, assistant-only never-empty, null/empty safety,
and two end-to-end transformRequest checks).

Port of decolua/9router#2143.

Co-authored-by: Manuel <baslr@users.noreply.github.com>
Inspired-by: decolua/9router#2143
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request introduces a mechanism to drop trailing assistant messages (prefill seeds) from conversations sent to the GitHub Copilot executor, preventing HTTP 400 errors. It adds a helper method dropTrailingAssistantPrefill and corresponding unit tests, while updating existing tests to prevent unexpected message stripping. The reviewer suggested making the role check case-insensitive to handle potential variations in role casing (such as Assistant or ASSISTANT) robustly.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

dropTrailingAssistantPrefill(messages: any): any {
if (!Array.isArray(messages) || messages.length === 0) return messages;
let end = messages.length;
while (end > 1 && messages[end - 1]?.role === "assistant") end--;

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.

medium

The check for the assistant role is case-sensitive (messages[end - 1]?.role === "assistant"). However, some clients may send roles in mixed-case or uppercase (e.g., "Assistant" or "ASSISTANT"). To ensure robustness and prevent unexpected HTTP 400 errors from GitHub Copilot, the role check should be case-insensitive, similar to how it is handled in transformRequest.

Suggested change
while (end > 1 && messages[end - 1]?.role === "assistant") end--;
while (end > 1 && typeof messages[end - 1]?.role === "string" && messages[end - 1].role.toLowerCase() === "assistant") end--;

@diegosouzapw
diegosouzapw merged commit e7ae29d into release/v3.8.43 Jul 2, 2026
2 of 3 checks passed
@diegosouzapw diegosouzapw mentioned this pull request Jul 2, 2026
@diegosouzapw
diegosouzapw deleted the fix/port-pr-2143-github-prefill branch July 3, 2026 04:58
tkgo11 pushed a commit to tkgo11/OmniRoute that referenced this pull request Sep 23, 2026
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.

1 participant