archestra-dev-llm-providers
GitHub指导如何向 Archestra 平台添加新 LLM 提供商、配置代理适配器、处理流式传输及模型获取,涵盖后端路由、类型定义及前端密钥管理。
Trigger Scenarios
Install
npx skills add archestra-ai/archestra --skill archestra-dev-llm-providers -g -y
SKILL.md
Frontmatter
{
"name": "archestra-dev-llm-providers",
"description": "Use when adding an LLM provider, changing proxy adapters or provider routes, fixing streaming\/tool-call translation bugs, editing model fetchers or model handling, or touching provider credentials\/enums and model constants."
}
Archestra LLM Providers & Proxy
Use this skill before adding an LLM provider or changing provider translation, streaming, or model handling. Run commands from platform/ unless specifically instructed otherwise.
Provider surface map
One provider touches all of these (use github-copilot as the worked example — it is OpenAI-compatible, so it follows the default path; microsoft-365-copilot is the most recent full addition and shows the harder shape, with its own graph translator):
backend/src/types/llm-providers/<provider>/—api.ts,messages.ts,tools.ts,index.ts(some also havemodels.ts).index.tsdefault-exports a namespace (e.g.GithubCopilot) withAPI/Messages/Toolsplus aTypessub-namespace; register it intypes/llm-providers/index.ts. OpenAI-compatible providers re-export OpenAI schemas with.passthrough().backend/src/routes/proxy/adapters/<provider>.ts— exports<provider>AdapterFactory; re-export it fromadapters/index.ts.backend/src/routes/proxy/routes/<provider>.ts— Fastify plugin:fastifyHttpProxycatch-all withcreateProxyPreHandler(fromproxy-prehandler.ts), explicitPOST .../chat/completionshandlers (default-agent and:agentIdvariants) callinghandleLLMProxy, and model-listing GETs viaproxy-model-listing.ts. Register the plugin in BOTH places: re-export it frombackend/src/routes/index.ts(the main API surface iteratesObject.values(routes)) AND add it toregisterWorkerRoutesinserver.ts.shared/model-constants.ts— add toSupportedProvidersSchema,SupportedProvidersDiscriminatorSchema(<provider>:chatCompletionsfor OpenAI-compatible; others name their API shape, e.g.anthropic:messages,bedrock:converse), andproviderDisplayNames. Membership inPROVIDERS_WITH_OPTIONAL_API_KEY,PROVIDERS_REQUIRING_BASE_URL, andPROVIDERS_REQUIRING_PER_USER_CREDENTIALsilently changes auth behavior: per-user-credential providers get personal-scope keys only, no team/org/env fallback (see thegithub-copilotrationale comment there).backend/src/routes/chat/model-fetchers/— add a fetcher and register it in themodelFetchersrecord inmodel-fetchers/index.ts; itsRecord<SupportedProvider, ModelFetcher>type makes a missing provider a compile error.registry.ts#testProviderApiKeyuses it to validate keys on creation. Simple bearer/modelsendpoints reusemakeBearerFetcher/makeStaticFetcherfrombearer-fetcher.ts.- Message normalization for the chat feature lives in
backend/src/routes/chat/normalization/(notablyprepare-for-provider.ts) andprepare-model-messages.ts— provider-specific message-shape rules go here, not in the proxy adapters. - Frontend: provider key management at
frontend/src/app/llm/model-providers/page.tsx+frontend/src/components/create-llm-provider-api-key-dialog.tsx; provider icon atfrontend/public/icons/<provider>.png; model pickers (components/llm-model-select.tsx,components/chat/model-selector.tsx) useproviderDisplayNames. - Also:
backend/src/config.ts+.env.examplefor base-URL/key env vars,../docs/pages/platform-supported-llm-providers.md.
Default path: OpenAI-compatible
- Most new providers are OpenAI-compatible. Do not hand-roll a translator: call
createOpenAiCompatibleAdapterFactoryfromadapters/openai-compatible-adapter.tswithprovider,interactionType,getBaseUrl, andcreateClient— it reusesOpenAIRequestAdapter/OpenAIResponseAdapter/OpenAIStreamAdapterwholesale. Seeadapters/deepseek.ts(minimal) andadapters/github-copilot.ts(custom auth via a fetch wrapper, sincecreateClientis synchronous). - Providers with genuinely different wire formats get translator modules next to the adapter (
gemini-openai-translator.ts,bedrock-openai-translator.ts,cohere-openai-translator.ts,anthropic-openai-translator.ts) — fix translation bugs there, with a matching*.test.ts.
Guard rails
backend/src/routes/proxy/routes/provider-matrix.test.ts—providerConfigsByProviderissatisfies Record<SupportedProvider, ProviderTestConfig>, so adding a provider to the enum without a matrix entry (route plugin + adapter factory + endpoints) fails typecheck. The suite then exercises every provider's real route with a mocked client: declared-tool persistence, execution IDs, streaming tool calls, cost-optimized model substitution, TOON compression, and limit blocking.- The
modelFetchersrecord (above) enforces the same exhaustiveness for model listing.
Translation gotchas (real handling, check before "fixing")
- Empty assistant turns:
convertToModelMessagescan produce assistant messages with empty content that providers reject.buildModelMessagesForProviderinroutes/chat/prepare-model-messages.tsfilters them (isEmptyAssistantModelMessage) and then repairs unanswered tool calls (ensureToolCallsHaveResults) sotool_use/tool_resultadjacency holds. The Cohere proxy adapter (adapters/cohere.ts) does its own empty-assistant filtering. - Tool-call name repair: harmony-format models leak reasoning-channel sentinels into tool names (
name<|channel|>commentary).routes/chat/tool-call-repair.ts#repairHarmonyToolNamestrips them, gated on an exact match against registered tools; wired viaexperimental_repairToolCallinroutes/chat/routes.ts. - Provider message-shape rules: Gemini and Bedrock require the first non-system turn to be from the user —
ensureLeadingUserTurninprepare-model-messages.tsprepends one for both (the provider set gating it lives next to the function). Bedrock content rules (every message non-empty, user messages need a text part) are enforced innormalization/prepare-for-provider.ts(ensureBedrockMessageHasContent,ensureBedrockUserMessageHasTextPart); the same file decides per provider whether text documents stay nativedocumentblocks (Anthropic/Bedrock) or are inlined as decoded text (everyone else). - Output-token ceilings:
agents/agent-output-budget.ts#resolveAgentMaxOutputTokensclampsmaxOutputTokensto the model's real output limit from model metadata (sanitizeOutputLimitfromclients/models-dev-client.ts, 8192 fallback) and the operator ceiling — don't hardcode max-token values.
Validation
cd backend && npx vitest run src/routes/proxy/routes/provider-matrix.test.ts
cd backend && npx vitest run src/routes/proxy/adapters/<provider>*.test.ts # adapter/translator unit tests
pnpm type-check
- Manual end-to-end check:
PROVIDER_SMOKE_TEST.md(repo root ofplatform/) is a browser-automation smoke runbook covering chat, policies, TOON, and proxy flows — run it after provider/proxy changes that unit tests can't cover.
Related skills
archestra-dev-backend— general route/codegen/permission conventions (route shape,RouteId, endpoint permissions).archestra-dev-backend-tests— vitest projects, mocking rules, DB fixtures for the tests above.
Version History
- 3053975 Current 2026-08-12 09:05


