Extending Archestra
Each extension point is a typed registry. Add a provider or connector to one enum, and pnpm type-check lists most of the files that need an entry. This page covers that loop and the steps the compiler misses. Paths are relative to platform/.
Add an LLM Provider
A new provider gets the LLM Proxy's guardrails, logging, and cost tracking, and shows up in Chat's model picker. Most providers speak OpenAI Chat Completions and reuse OpenAI's schemas and adapter. Copy DeepSeek (deepseek), which is wired into every surface below.
Coding agents should load ../.agents/skills/archestra-dev-llm-providers/SKILL.md first. It maps every file a provider touches.
Start With the Provider Enum
Most of the wiring is a typed record, so the compiler lists it for you.
- In
shared/model-constants.ts, add the provider ID toSupportedProvidersSchema, and<provider>:chatCompletionstoSupportedProvidersDiscriminatorSchema. - Add the provider's schemas to
backend/src/types/interaction.ts, then runpnpm codegen. - Run
pnpm type-check, and add an entry to each record it reports. These include the Chat model fetcher, the client config, the error handlers, the provider test matrix, and the frontend key form.
Build an OpenAI-Compatible Provider
- Types: create
backend/src/types/llm-providers/<provider>/withapi.ts,messages.ts,tools.ts, andindex.ts. Re-export OpenAI's schemas with.passthrough()to keep custom fields. Export the namespace frombackend/src/types/llm-providers/index.ts. - Adapter: create
backend/src/routes/proxy/adapters/<provider>.tswithcreateOpenAiCompatibleAdapterFactory, and export it fromadapters/index.ts. - Proxy route: copy
backend/src/routes/proxy/routes/deepseek.ts. Register the route IDs inshared/routes.ts, export the plugin frombackend/src/routes/index.ts, and add it toregisterWorkerRoutesinbackend/src/server.ts. - Configuration: in
backend/src/config.ts, exposellm.<provider>.baseUrlandchat.<provider>.apiKey. Add both to.env.exampleand to the Configuration reference.
Build a Provider With Its Own API
A provider with its own wire format, such as Anthropic, Gemini, Bedrock, or Cohere, also needs:
- Zod request, response, message, and tool schemas in
backend/src/types/llm-providers/<provider>/. - Implementations of
LLMRequestAdapter,LLMResponseAdapter,LLMStreamAdapter, andLLMProviderfrombackend/src/types/llm-provider.ts. - A translator to and from OpenAI Chat Completions, in
backend/src/routes/proxy/adapters/<provider>-openai.tsand<provider>-openai-translator.ts, with a matching test.
Finish the Steps the Compiler Misses
- Model sync: map the provider's models.dev ID in
MODELS_DEV_PROVIDER_MAPinshared/model-constants.ts, so model metadata and prices sync. - Logos: add
frontend/public/icons/<provider>.pngfor the API key form, and a monochromefrontend/public/model-logos/<provider>.svgmapped inproviderToLogoProviderinfrontend/src/lib/provider-logos.ts. - Model Router: to make the provider routable, add it to
MODEL_ROUTER_SUPPORTED_PROVIDERSand to the router's maps inbackend/src/routes/proxy/routes/model-router.ts. A native provider also needs a case ingetTranslatedModelRouterProvider. - OpenCode: to offer it in OpenCode, add it to
OPENCODE_PASSTHROUGH_PROVIDER_ROUTESinshared/opencode-provider-routes.ts. - Docs: add a row to the provider table in
../docs/pages/llm-proxy/providers/index.md.
To check it works, run the provider matrix, then walk PROVIDER_SMOKE_TEST.md in the running app:
pnpm --dir backend exec vitest run src/routes/proxy/routes/provider-matrix.rollback.test.ts
- The server refuses to start when the Model Router lists in
shared/andmodel-router.tsdisagree.type-checkdoes not catch this.
Add a Knowledge Connector
Sync an issue tracker, wiki, or drive into a knowledge base on a schedule, so agents can answer from it. A connector is a backend class with a config schema, a checkpoint schema, and a generator that yields document batches.
Define the Schemas
In backend/src/types/knowledge-connector.ts, add a type literal and the two schemas. Use connectorUrlSchema for URL fields:
const ACME = z.literal("acme");
export const AcmeConfigSchema = z.object({
type: ACME,
acmeBaseUrl: connectorUrlSchema,
projectKeys: z.array(z.string()).optional(),
});
export const AcmeCheckpointSchema = z.object({
type: ACME,
lastSyncedAt: z.string().optional(),
});
Then add ACME to USER_SELECTABLE_CONNECTOR_TYPES, and both schemas to the ConnectorConfigSchema and ConnectorCheckpointSchema unions. type-check does not flag a schema missing from a union.
Write the Connector
Create backend/src/knowledge-base/connectors/acme/acme-connector.ts, extending BaseConnector:
validateConfig(config)checks the config and returns{ valid, error? }.testConnection({ config, credentials })proves the credentials work with one light API call.sync({ config, credentials, checkpoint })is an async generator that yields document batches with updated checkpoints. Pass the newest item's timestamp tobuildCheckpoint, not the clock time.- Call the API through
fetchWithRetry(), which has a 30-second timeout and exponential backoff, andrateLimit().
Register It
- Add the factory to
connectorRegistryinbackend/src/knowledge-base/connectors/registry.ts, and the display name toCONNECTOR_TYPE_LABELSinshared/knowledge-base.ts. - Run
pnpm codegen, thenpnpm type-checkto find what the frontend form needs. - Create
frontend/src/app/knowledge/knowledge-bases/_parts/acme-config-fields.tsxand register it inconnector-dialog-config.tsx. - Add the icon to
frontend/public/icons/and toCONNECTOR_ICON_MAPin_parts/connector-icons.tsx.type-checkdoes not flag a missing icon. - Add
../docs/pages/knowledge/connectors/acme.md, and a row with a<span id="acme">anchor in the connectors index. The connector dialog's docs link points at that anchor.
To check it works, add tests in acme-connector.test.ts and run them:
pnpm --dir backend exec vitest run src/knowledge-base/connectors/acme
Add a Retrieval Backend
Swap the search index without touching ingestion, querying, or access control. PostgreSQL with pgvector is the only backend Archestra ships. An external index ranks results, while PostgreSQL stays the store for documents, access control, and citations.
Implement the Interface
Implement every method of KnowledgeRetrievalBackend from backend/src/knowledge-base/retrieval-backend.ts, in retrieval-backends/<name>/<name>-retrieval-backend.ts. backend/src/knowledge-base/RETRIEVAL_BACKENDS.md explains each method and the guarantees it must keep.
Set requiresResultVerification = true on an external backend. Archestra then reloads every candidate chunk from PostgreSQL and reapplies the connector, ACL, environment, and metadata-filter scope. The external index supplies only the ranking.
Wire It In
- Expose the connection settings under
kbinbackend/src/config.ts, with matchingARCHESTRA_KNOWLEDGE_BASE_*variables in.env.exampleand the Configuration reference. - Construct the backend in
backend/src/knowledge-base/retrieval-backends/registry.ts. The registry has no selector yet, so add an enum setting and a switch where the singleton is built. - Add a document-deletion hook. PostgreSQL deletes chunks by foreign-key cascade, which an external index never sees.
To check it works, run the query suite. It includes an alternate backend that returns forged fields:
pnpm --dir backend exec vitest run src/knowledge-base/query.test.ts
