From c89f6e7ac61e0dd5404888df87555627efce6087 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Wed, 21 Jan 2026 15:09:56 -0600 Subject: [PATCH] add chat.headers hook, adjust codex and copilot plugins to use it --- packages/opencode/src/plugin/codex.ts | 11 +++++++++-- packages/opencode/src/plugin/copilot.ts | 18 ++++++++++++++++-- packages/opencode/src/session/llm.ts | 23 ++++++++++++++++------- packages/plugin/src/index.ts | 4 ++++ 4 files changed, 45 insertions(+), 11 deletions(-) diff --git a/packages/opencode/src/plugin/codex.ts b/packages/opencode/src/plugin/codex.ts index fc172dad9..3e31c6ce4 100644 --- a/packages/opencode/src/plugin/codex.ts +++ b/packages/opencode/src/plugin/codex.ts @@ -1,7 +1,8 @@ import type { Hooks, PluginInput } from "@opencode-ai/plugin" import { Log } from "../util/log" -import { OAUTH_DUMMY_KEY } from "../auth" -import { ProviderTransform } from "../provider/transform" +import { Installation } from "../installation" +import { Auth, OAUTH_DUMMY_KEY } from "../auth" +import os from "os" const log = Log.create({ service: "plugin.codex" }) @@ -489,5 +490,11 @@ export async function CodexAuthPlugin(input: PluginInput): Promise { }, ], }, + "chat.headers": async (input, output) => { + if (input.model.providerID !== "openai") return + output.headers.originator = "opencode" + output.headers["User-Agent"] = `opencode/${Installation.VERSION} (${os.platform()} ${os.release()}; ${os.arch()})` + output.headers.session_id = input.sessionID + }, } } diff --git a/packages/opencode/src/plugin/copilot.ts b/packages/opencode/src/plugin/copilot.ts index 932b3fd6a..bf0f91dcd 100644 --- a/packages/opencode/src/plugin/copilot.ts +++ b/packages/opencode/src/plugin/copilot.ts @@ -6,7 +6,6 @@ const CLIENT_ID = "Ov23li8tweQw6odWQebz" // Add a small safety buffer when polling to avoid hitting the server // slightly too early due to clock skew / timer drift. const OAUTH_POLLING_SAFETY_MARGIN_MS = 3000 // 3 seconds - function normalizeDomain(url: string) { return url.replace(/^https?:\/\//, "").replace(/\/$/, "") } @@ -19,6 +18,7 @@ function getUrls(domain: string) { } export async function CopilotAuthPlugin(input: PluginInput): Promise { + const sdk = input.client return { auth: { provider: "github-copilot", @@ -83,11 +83,11 @@ export async function CopilotAuthPlugin(input: PluginInput): Promise { }) const headers: Record = { + "x-initiator": isAgent ? "agent" : "user", ...(init?.headers as Record), "User-Agent": `opencode/${Installation.VERSION}`, Authorization: `Bearer ${info.refresh}`, "Openai-Intent": "conversation-edits", - "X-Initiator": isAgent ? "agent" : "user", } if (isVision) { @@ -265,5 +265,19 @@ export async function CopilotAuthPlugin(input: PluginInput): Promise { }, ], }, + "chat.headers": async (input, output) => { + if (!input.model.providerID.includes("github-copilot")) return + const session = await sdk.session + .get({ + path: { + id: input.sessionID, + }, + throwOnError: true, + }) + .catch(() => undefined) + if (!session || !session.data.parentID) return + // TODO: mark subagent sessions as agent initiated once copilot gives ok + // output.headers["x-initiator"] = "agent" + }, } } diff --git a/packages/opencode/src/session/llm.ts b/packages/opencode/src/session/llm.ts index 1029b45ea..e73f20403 100644 --- a/packages/opencode/src/session/llm.ts +++ b/packages/opencode/src/session/llm.ts @@ -53,6 +53,7 @@ export namespace LLM { .tag("sessionID", input.sessionID) .tag("small", (input.small ?? false).toString()) .tag("agent", input.agent.name) + .tag("mode", input.agent.mode) l.info("stream", { modelID: input.model.id, providerID: input.model.providerID, @@ -131,6 +132,20 @@ export namespace LLM { }, ) + const { headers } = await Plugin.trigger( + "chat.headers", + { + sessionID: input.sessionID, + agent: input.agent, + model: input.model, + provider, + message: input.user, + }, + { + headers: {}, + }, + ) + const maxOutputTokens = isCodex ? undefined : ProviderTransform.maxOutputTokens( @@ -198,13 +213,6 @@ export namespace LLM { maxOutputTokens, abortSignal: input.abort, headers: { - ...(isCodex - ? { - originator: "opencode", - "User-Agent": `opencode/${Installation.VERSION} (${os.platform()} ${os.release()}; ${os.arch()})`, - session_id: input.sessionID, - } - : undefined), ...(input.model.providerID.startsWith("opencode") ? { "x-opencode-project": Instance.project.id, @@ -218,6 +226,7 @@ export namespace LLM { } : undefined), ...input.model.headers, + ...headers, }, maxRetries: input.retries ?? 0, messages: [ diff --git a/packages/plugin/src/index.ts b/packages/plugin/src/index.ts index 36a4657d7..d02c8bfe5 100644 --- a/packages/plugin/src/index.ts +++ b/packages/plugin/src/index.ts @@ -172,6 +172,10 @@ export interface Hooks { input: { sessionID: string; agent: string; model: Model; provider: ProviderContext; message: UserMessage }, output: { temperature: number; topP: number; topK: number; options: Record }, ) => Promise + "chat.headers"?: ( + input: { sessionID: string; agent: string; model: Model; provider: ProviderContext; message: UserMessage }, + output: { headers: Record }, + ) => Promise "permission.ask"?: (input: Permission, output: { status: "ask" | "deny" | "allow" }) => Promise "command.execute.before"?: ( input: { command: string; sessionID: string; arguments: string },