feat(ai-client): multi-provider compat — native Anthropic/Google + URL tolerance

- TEXT/VISION: add native Anthropic & Google Gemini paths via Vercel AI SDK,
  selectable through TEXT_PROVIDER / VISION_PROVIDER (default openai_compatible)
- IMAGE: expand to openai (gpt-image) / google (Nano Banana) via AI SDK
  alongside the existing Runware task-array and OpenAI-compatible REST paths
- normalizeBaseUrl: tolerate URLs with/without /v1 (or /chat/completions);
  append the per-protocol version segment only for bare hosts
- config: readProvider() reads *_PROVIDER; types: ProviderProtocol + provider?
- deps: @ai-sdk/anthropic, @ai-sdk/google; docs in .env.example + README

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
yuanzonghao
2026-06-04 15:51:53 +08:00
parent a4dc57a1b6
commit 83fd5717e7
10 changed files with 614 additions and 67 deletions
+31
View File
@@ -268,10 +268,41 @@ export type VisionClassify = "insert-beat" | "change-scene";
// Provider config
// ──────────────────────────────────────────────────────────────────────
/**
* Wire protocol used to talk to a model provider. Which values are valid
* depends on the model role — each ai-client adapter accepts its own subset
* and falls back to a sensible default for anything else:
*
* openai_compatible text / vision / image — OpenAI Chat Completions +
* `/images/generations` (self-implemented fetch; the
* default for text/vision when unset)
* anthropic text / vision — native Anthropic Messages (AI SDK)
* google text / vision / image — native Gemini (AI SDK); image
* uses the Nano Banana family
* openai image only — OpenAI gpt-image via AI SDK,
* unlocks reference-image editing (for text/vision use
* openai_compatible, which already speaks OpenAI's format)
* runware image only — Runware task-array protocol
* (self-implemented; the default for runware.ai URLs)
*/
export type ProviderProtocol =
| "openai_compatible"
| "anthropic"
| "google"
| "openai"
| "runware";
export type ProviderConfig = {
baseUrl: string;
apiKey: string;
model: string;
/**
* Wire protocol. When unset, callers apply a role-specific default:
* text/vision → "openai_compatible"; image → inferred from baseUrl
* (runware.ai → "runware", otherwise "openai_compatible") so existing
* deployments keep working without setting *_PROVIDER.
*/
provider?: ProviderProtocol;
};
export type TtsConfig = {