diff --git a/src/main/model-resolver.ts b/src/main/model-resolver.ts index 3aea7494..89dc45ab 100644 --- a/src/main/model-resolver.ts +++ b/src/main/model-resolver.ts @@ -3,19 +3,29 @@ * that pi-ai's catalog does not ship out of the box. * * Today this only covers the two Fireworks connectors (`fireworks` and - * `fireworks-firepass`), which both speak the Anthropic-compatible endpoint - * at `https://api.fireworks.ai/inference` and require Bearer auth. For every - * other provider we delegate to pi-ai's `getModel` / `getModels`. + * `fireworks-firepass`). Fireworks is not a built-in pi-ai provider, so we + * route them through pi-ai's native `openai-completions` API against + * Fireworks' OpenAI-compatible endpoint. The earlier shim pointed the + * Anthropic SDK at Fireworks' `/v1/messages` path, which forced pi-ai to + * ship Claude-proprietary beta headers (`fine-grained-tool-streaming-*`, + * `anthropic-dangerous-direct-browser-access`, etc.) — Fireworks tolerates + * them inconsistently and the resulting streams frequently close with no + * tokens emitted, producing runs that report "succeeded" but did + * absolutely nothing. The OpenAI-compatible endpoint at + * `https://api.fireworks.ai/inference/v1` does not suffer the same + * problem and is the path Fireworks documents for tool-using clients. */ import log from "electron-log/main.js"; import { getModel, getModels, type Api, type Model } from "@mariozechner/pi-ai"; -const FIREWORKS_BASE_URL = "https://api.fireworks.ai/inference"; +// Fireworks' OpenAI-compatible root. The OpenAI SDK appends +// `/chat/completions`, `/models`, etc. to this baseURL. +const FIREWORKS_OPENAI_BASE_URL = "https://api.fireworks.ai/inference/v1"; const FIREWORKS_DEFAULT_CONTEXT = 128_000; const FIREWORKS_DEFAULT_MAX_TOKENS = 8192; -export const FIREWORKS_FIREPASS_MODEL_ID = "accounts/fireworks/routers/kimi-k2p5-turbo"; +export const FIREWORKS_FIREPASS_MODEL_ID = "accounts/fireworks/models/kimi-k2.5-turbo"; export const FIREWORKS_FIREPASS_MODEL_NAME = "Kimi K2.5 Turbo (Fire Pass)"; const FIREWORKS_CURATED_MODELS: Array<{ id: string; name: string; contextWindow?: number }> = [ @@ -26,13 +36,13 @@ const FIREWORKS_CURATED_MODELS: Array<{ id: string; name: string; contextWindow? { id: "accounts/fireworks/models/llama-v3p3-70b-instruct", name: "Llama 3.3 70B Instruct", contextWindow: 131_072 }, ]; -function buildFireworksModel(modelId: string, name?: string, contextWindow?: number): Model<"anthropic-messages"> { +function buildFireworksModel(modelId: string, name?: string, contextWindow?: number): Model<"openai-completions"> { return { id: modelId, name: name ?? modelId, - api: "anthropic-messages", + api: "openai-completions", provider: "fireworks", - baseUrl: FIREWORKS_BASE_URL, + baseUrl: FIREWORKS_OPENAI_BASE_URL, reasoning: false, input: ["text"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, @@ -41,10 +51,6 @@ function buildFireworksModel(modelId: string, name?: string, contextWindow?: num }; } -function isFireworksProvider(provider: string): boolean { - return provider === "fireworks" || provider === "fireworks-firepass"; -} - export function resolveModel(provider: string, modelId: string): Model | null { if (provider === "fireworks-firepass") { return buildFireworksModel(FIREWORKS_FIREPASS_MODEL_ID, FIREWORKS_FIREPASS_MODEL_NAME, 262_144); @@ -81,14 +87,12 @@ export function resolveModels(provider: string): Array<{ id: string; name: strin * Extra HTTP headers that must be merged into the streamSimple call for the * given provider. Returns undefined when no extra headers are required. * - * Fireworks' Anthropic-compat endpoint authenticates via `Authorization: Bearer`, - * not `x-api-key`. pi-ai's anthropic provider only sends `x-api-key`, so we - * inject the bearer header at the call site. + * Fireworks' OpenAI-compatible endpoint authenticates via the OpenAI + * SDK's native `apiKey` constructor — it already sends + * `Authorization: Bearer `. No per-provider header injection is + * needed; the helper stays in place as an extension point for future + * providers that do require hand-built headers. */ -export function resolveExtraStreamHeaders(provider: string, apiKey: string): Record | undefined { - if (!apiKey) return undefined; - if (isFireworksProvider(provider)) { - return { Authorization: `Bearer ${apiKey}` }; - } +export function resolveExtraStreamHeaders(_provider: string, _apiKey: string): Record | undefined { return undefined; }