openclaw/extensions/github-copilot/runtime-identity.ts
Finn763 53c0ca9754
fix(github-copilot): honor configured identity across model requests (#127965)
* fix(github-copilot): honor configured request identity

Honor existing provider request headers consistently across model discovery, setup, inference, and embeddings. Preserve the default identity and partition the live catalog by the configured identity.

Co-authored-by: Finn763 <165816600+Finn763@users.noreply.github.com>

* test(github-copilot): real-behavior wire-trace proof for #127965

* fix(github-copilot proof): print on-disk wire-trace.json sha256

* chore(github-copilot proof): drop pr-body.md from PR diff

* fix(github-copilot): finish identity checks and consolidate proof

Complete the typed provider fixture and keep the identity constant private. Retain canonical owner tests and real provider evidence; remove parallel copied mock implementations and generated PR-only traces while preserving the diagnostic commits in ancestry.

Co-authored-by: Finn763 <165816600+Finn763@users.noreply.github.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Finn763 <Finn763@users.noreply.github.com>
2026-08-27 01:29:28 -07:00

40 lines
1.7 KiB
TypeScript

import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
import { buildCopilotIdeHeaders } from "openclaw/plugin-sdk/provider-auth";
import { normalizeResolvedSecretInputString } from "openclaw/plugin-sdk/secret-input";
// GitHub's current fine-grained PAT contract is the Copilot CLI identity.
// Keep this provider-owned instead of changing the legacy public SDK constant.
const COPILOT_RUNTIME_INTEGRATION_ID = "copilot-developer-cli";
/** Keep catalog and inference identity aligned without forwarding unrelated configured secrets. */
export function buildCopilotRuntimeHeaders(params?: {
config?: OpenClawConfig;
headers?: Record<string, string>;
}): Record<string, string> {
const provider = params?.config?.models?.providers?.["github-copilot"];
let integrationId = COPILOT_RUNTIME_INTEGRATION_ID;
for (const headers of [provider?.headers, provider?.request?.headers, params?.headers]) {
for (const [name, value] of Object.entries(headers ?? {})) {
if (name.toLowerCase() === "copilot-integration-id") {
integrationId =
normalizeResolvedSecretInputString({
value,
path: "models.providers.github-copilot.headers.Copilot-Integration-Id",
}) ?? integrationId;
}
}
}
// HTTP header names are case-insensitive. Remove every authored spelling so
// native Headers/SDK merging cannot turn the identity into a comma-joined pair.
const headers = Object.fromEntries(
Object.entries(params?.headers ?? {}).filter(
([name]) => name.toLowerCase() !== "copilot-integration-id",
),
);
return {
...buildCopilotIdeHeaders(),
"Openai-Organization": "github-copilot",
...headers,
"Copilot-Integration-Id": integrationId,
};
}