How `packages/ai`, `packages/providers`, and `packages/sdk` Work Together in Magnitude's Provider System
packages/ai defines the core AI contract, packages/providers implements concrete AI services, and packages/sdk exposes the unified client API that bridges UI applications to underlying models.
Magnitude's architecture separates concerns into three distinct packages that collectively implement a flexible, provider-agnostic AI system. This layered design enables seamless swapping between OpenAI, Anthropic, local LLMs, and custom providers without changing client code. This article examines how packages/ai, packages/providers, and packages/sdk interact to deliver this abstraction.
The Three-Layer Architecture
| Package | Responsibility | Position in Stack |
|---|---|---|
packages/ai |
Core AI contract — types, schemas, and utility definitions for generic AI interactions | Provider-agnostic foundation |
packages/providers |
Concrete implementations — actual provider clients plus a runtime registry | Implementation layer |
packages/sdk |
Public client API — RPC bindings, connection handling, and convenience functions | Consumer-facing interface |
packages/ai: The Provider-Agnostic Contract
The @magnitudedev/ai package establishes the foundational types that decouple all other components from specific model implementations.
This package defines schemas for:
Prompt— standardized message structuresToolCallIdandToolDefinition— function-calling primitives- Streaming response chunks — incremental generation handling
All downstream packages import from @magnitudedev/ai to maintain type safety without vendor lock-in. The SDK specifically re-exports these core types in packages/sdk/src/index.ts:
// packages/sdk/src/index.ts — AI type re-exports
export * from "@magnitudedev/ai/provider/model";
export type {
ToolCallId,
Prompt,
ToolDefinition,
// ... additional AI primitives
} from "@magnitudedev/ai";
By centralizing these definitions, Magnitude ensures that adding a new provider requires zero changes to client-facing code.
packages/providers: Concrete Implementations and Registry
The @magnitudedev/providers package contains actual provider integrations — OpenAI, Anthropic, local LLMs, and extensible custom adapters.
Each provider exports a factory object satisfying the ProviderModel interface defined in @magnitudedev/ai. The package also maintains a runtime registry that maps provider identifiers to these factories, as documented in packages/providers/AGENTS.md.
When implementing a new provider, you conform to the AI contract:
// Example provider implementation inside packages/providers
import { ProviderModel } from "@magnitudedev/ai/provider/model";
export const myCoolProvider: ProviderModel = {
id: "mycool",
createClient: (config) => new MyCoolClient(config.apiKey),
// Must implement RPC shape from @magnitudedev/ai
};
The registry enables dynamic provider discovery — the SDK requests a provider by string ID, and the registry returns the appropriate factory without hardcoded imports.
packages/sdk: The Unified Client Interface
The @magnitudedev/sdk package is what applications actually import. It consumes both layers beneath it — AI types for safety, providers for execution — and exposes a clean surface for UI clients (cli, web, desktop).
Key responsibilities include:
- Re-exporting AI types so consumers need only one dependency
- RPC binding management via the ACN protocol (
@magnitudedev/acn-protocol) - Connection state handling for the daemon
- Convenience factories like
makeInferenceClient
From packages/sdk/src/index.ts:
// Central export hub pattern
export { MagnitudeClient } from "./client";
export { makeInferenceClient } from "./inference";
// Re-export provider model namespace for direct access
export * from "@magnitudedev/ai/provider/model";
Architectural Flow: From Client Call to Model Execution
The complete request path demonstrates how the three packages cooperate:
- Client imports from SDK
import { MagnitudeClient, makeInferenceClient } from "@magnitudedev/sdk";
const client = new MagnitudeClient({ endpoint: "http://localhost:3000" });
const inference = makeInferenceClient(client, {
providerId: "openai",
modelId: "gpt-4o-mini",
});
-
SDK resolves provider via registry — looks up
"openai"inpackages/providersregistry -
Provider instantiates concrete model — returns client adhering to
@magnitudedev/aiinterfaces -
SDK transmits RPC via ACN protocol —
@magnitudedev/acn-protocolhandles wire format -
Daemon executes provider's inference logic — actual API call to OpenAI, Anthropic, etc.
Key Inter-Package Dependencies
| Link | Mechanism | Source Location |
|---|---|---|
| AI types → SDK | Direct re-export | packages/sdk/src/index.ts lines 37-44 |
| Provider model namespace → SDK | Re-export for client access | packages/sdk/src/index.ts lines 45-46 |
| Provider registry → SDK | Runtime lookup (conceptual) | packages/providers/AGENTS.md |
| ACN protocol → SDK | RPC implementation | packages/acn-protocol/ |
Summary
packages/aiprovides provider-agnostic types and schemas — the contract that makes interchangeability possiblepackages/providerssupplies concrete implementations plus runtime registration — the realization layerpackages/sdkdelivers the unified client API — the single dependency for application developers, bridging to providers via ACN RPCs
This separation enables Magnitude to support new AI services by adding implementation packages without touching SDK or client code.
Frequently Asked Questions
How do I add a custom provider to Magnitude?
Implement the ProviderModel interface from @magnitudedev/ai in a new file under packages/providers, then register it in the provider registry. Your implementation must return a client that handles the RPC shapes defined in packages/acn-protocol. No changes to packages/sdk are required.
Can I use Magnitude's AI types without the full SDK?
Yes — import directly from @magnitudedev/ai. This is useful for building tooling that operates on Magnitude's data structures without needing RPC capabilities or provider connectivity.
Why does the SDK re-export @magnitudedev/ai/provider/model separately?
This namespace contains low-level model descriptors that client code may need to reference when specifying exact model variants. By re-exporting it, the SDK prevents consumers from adding a direct dependency on the providers package while preserving full type access.
What protocol do providers use to communicate with the daemon?
All provider communication flows through ACN (Agent Communication Network) protocol, defined in packages/acn-protocol/. The SDK serializes requests into this wire format; the daemon deserializes and routes to the appropriate provider implementation.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →