Files
moltbot/extensions/github-copilot/models-defaults.ts
Peter Steinberger 0b8ee4616d fix(github-copilot): support Gemini image understanding
Fixes Copilot image understanding by exchanging OAuth tokens for Copilot API tokens, routing Copilot Gemini image requests through Chat Completions, and sending the prompt in user content with Copilot vision headers.

Real behavior proof:
- Old Responses route with real Copilot key reproduced `400 model gemini-3.1-pro-preview does not support Responses API`.
- Fixed route with the same real Copilot key returned `Cat`.
- Final CLI live smoke returned `ok: true` and `text: Cat` for `github-copilot/gemini-3.1-pro-preview`.

Verification:
- pnpm test src/media-understanding/image.test.ts extensions/github-copilot/models.test.ts extensions/github-copilot/stream.test.ts src/agents/pi-hooks/compaction-safeguard.test.ts -- --reporter=verbose
- pnpm check:changed via Blacksmith Testbox tbx_01krgt56pqmft8txekt017wke6, Actions run https://github.com/openclaw/openclaw/actions/runs/25803926150, exit 0.

Refs #80393, #80442.

Co-authored-by: Yang Haoyu <150496764+afunnyhy@users.noreply.github.com>
2026-05-13 15:20:27 +01:00

62 lines
1.8 KiB
TypeScript

import type { ModelDefinitionConfig } from "openclaw/plugin-sdk/provider-model-shared";
import {
resolveCopilotModelCompat,
resolveCopilotTransportApi,
resolveStaticCopilotModelOverride,
} from "./model-metadata.js";
const DEFAULT_CONTEXT_WINDOW = 128_000;
const DEFAULT_MAX_TOKENS = 8192;
// Copilot model ids vary by plan/org and can change.
// We keep this list intentionally broad; if a model isn't available Copilot will
// return an error and users can remove it from their config.
const DEFAULT_MODEL_IDS = [
"claude-haiku-4.5",
"claude-opus-4.5",
"claude-opus-4.6",
"claude-opus-4.7",
"claude-sonnet-4",
"claude-sonnet-4.6",
"claude-sonnet-4.5",
"gemini-2.5-pro",
"gemini-3-flash",
"gemini-3.1-pro",
"gpt-4.1",
"gpt-5-mini",
"gpt-5.2",
"gpt-5.2-codex",
"gpt-5.3-codex",
"gpt-5.4",
"gpt-5.4-mini",
"gpt-5.4-nano",
"gpt-5.5",
"grok-code-fast-1",
"raptor-mini",
"goldeneye",
] as const;
export function getDefaultCopilotModelIds(): string[] {
return [...DEFAULT_MODEL_IDS];
}
export function buildCopilotModelDefinition(modelId: string): ModelDefinitionConfig {
const id = modelId.trim();
if (!id) {
throw new Error("Model id required");
}
const staticOverride = resolveStaticCopilotModelOverride(id);
const compat = staticOverride?.compat ?? resolveCopilotModelCompat(id);
return {
id,
name: staticOverride?.name ?? id,
api: staticOverride?.api ?? resolveCopilotTransportApi(id),
reasoning: staticOverride?.reasoning ?? false,
input: staticOverride?.input ?? ["text", "image"],
cost: staticOverride?.cost ?? { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: staticOverride?.contextWindow ?? DEFAULT_CONTEXT_WINDOW,
maxTokens: staticOverride?.maxTokens ?? DEFAULT_MAX_TOKENS,
...(compat ? { compat } : {}),
};
}