Skip to content

fix(copilot): synthetic user messages (tool results, attachments) incorrectly billed as user-initiated #15822

Description

@Juhwa-Lee1023

Summary

When the GitHub Copilot provider determines the x-initiator header value, it checks the role of the last message in the request body. However, tool results, image attachments, and other agent-produced content are transported as messages with role: \"user\" in all three API flavours (Completions, Responses, Anthropic Messages).

This means agentic turns — where the last message contains only tool results or file attachments — are mis-classified as user-initiated and billed against the user's Copilot premium quota instead of the agent budget.

Affected code

packages/opencode/src/plugin/copilot.ts — the isAgent calculation inside the custom fetch wrapper:

// Completions API (line ~80)
isAgent: last?.role !== "user",   // ❌ bare role check misses synthetic messages

// Responses API (line ~92)
isAgent: last?.role !== "user",   // ❌ same problem

// Messages API (line ~114) — partial fix only, covers tool_result but not other types
isAgent: !(last?.role === "user" && hasNonToolCalls),

Expected behavior

Messages whose content consists entirely of agent-produced parts (tool results, attachments, images) should set x-initiator: agent, not x-initiator: user.

Steps to reproduce

  1. Configure opencode with GitHub Copilot
  2. Start an agentic session that invokes tools
  3. Observe that each tool-result turn sends x-initiator: user, consuming premium quota

Related

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

coreAnything pertaining to core functionality of the application (opencode server stuff)

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions