How AxonHub Implements Any SDK to Any Model Translation

AxonHub decouples client SDKs from LLM models by normalizing all requests into a generic agent.Message format and using provider-specific conversion layers to translate between the unified interface and native vendor SDKs.

The looplj/axonhub repository solves the fragmentation problem in AI development by enabling any SDK to any model translation through a unified abstraction layer. This architecture allows developers to switch between OpenAI, Anthropic, Vertex, and other providers without changing application code, as every vendor implements the same agent.Provider contract.

The Three-Layer Translation Architecture

Generic Data Model

At the core of the translation system lies a vendor-agnostic data model defined in axon/agent/message.go. This package declares universal types such as agent.Message, agent.ToolDefinition, and agent.Response that capture concepts common to all LLM APIs—roles (system, user, assistant, tool), content parts (text, images, tool calls), and metadata. By flattening vendor-specific extensions into this normalized structure, AxonHub ensures that upstream code remains agnostic to the underlying model provider.

Provider Interface Contract

The translation contract is enforced by the agent.Provider interface declared in axon/agent/provider.go. Every LLM vendor must implement two methods: Chat(ctx context.Context, model string, tools []ToolDefinition, messages []Message) (*Response, error) and ChatStream(ctx context.Context, model string, tools []ToolDefinition, messages []Message) (StreamIterator, error). This strict interface guarantees that any SDK generating a []agent.Message slice can invoke any provider without modification, achieving true any SDK to any model translation.

Bidirectional Conversion Layer

Each provider package contains a conversion layer that maps between the generic agent types and the vendor's native SDK structs. For example, axon/provider/anthropic/convert.go exports convertMessages to transform []agent.Message into Anthropic's MessageParam types, and convertResponse to translate Anthropic's Message back into agent.Response. These functions handle vendor-specific quirks—such as Anthropic's separate system prompt field or OpenAI's function calling format—while presenting a uniform interface to the rest of the system.

Step-by-Step Translation Flow

The any SDK to any model translation process follows a rigorous seven-step pipeline:

  1. Client builds generic request. Application code constructs a []agent.Message slice using the unified types from axon/agent/message.go, specifying roles and content without considering the target vendor.

  2. Hub resolves provider implementation. Based on the model name (e.g., "claude-3-sonnet-20240229"), AxonHub selects the corresponding agent.Provider implementation. The provider may be wrapped by reloadable.Provider from axon/provider/reloadable/reloadable.go to enable runtime swapping.

  3. Provider converts to vendor format. The provider's Chat method invokes conversion functions such as convertMessages in axon/provider/anthropic/convert.go to generate the vendor-specific request payload.

  4. Native SDK executes request. The generated struct (e.g., Anthropic's MessageParam) is passed to the vendor's official Go SDK, which handles HTTP transport and authentication.

  5. Vendor response is captured. The native SDK returns its proprietary response type (e.g., anthropic.Message), which the provider receives in its raw form.

  6. Provider converts to generic response. The provider calls convertResponse to map the vendor-specific payload back into agent.Response, normalizing message roles, content parts, and tool calls.

  7. Hub returns unified result. The caller receives a standard agent.Response containing []agent.Message, which can be processed by any downstream logic regardless of which LLM generated it.

For streaming workloads, providers implement ChatStream, converting each SSE event or chunk into the unified agent.StreamEvent type defined in axon/agent/provider.go.

Runtime Provider Swapping with Reloadable Providers

AxonHub's any SDK to any model translation includes a sophisticated runtime flexibility mechanism via reloadable.Provider in axon/provider/reloadable/reloadable.go. This wrapper implements the same agent.Provider interface while delegating to an underlying provider that can be swapped at runtime. When configuration changes or a new model version becomes available, the hub can update the provider instance without restarting the application or breaking existing client connections. This capability ensures that production systems can migrate between LLM vendors or upgrade model versions with zero downtime, all while maintaining the unified translation contract.

Practical Implementation: Calling Any Model Through the Unified API

The following example demonstrates how application code uses the any SDK to any model translation layer to invoke an Anthropic model. The identical pattern works for OpenAI, Vertex, or any other supported provider by simply changing the provider constructor.

package main

import (
	"context"
	"log"

	"github.com/looplj/axonhub/axon/agent"
	"github.com/looplj/axonhub/axon/provider/anthropic"
)

func main() {
	// Build a generic request using unified types
	messages := []agent.Message{
		{
			Role:    agent.RoleUser,
			Content: &agent.Content{Text: strPtr("Explain quantum tunnelling in two sentences.")},
		},
	}

	// Initialize the provider (swap anthropic.New for openai.New or vertex.New for any SDK to any model translation)
	prov := anthropic.New("<YOUR_ANTHROPIC_API_KEY>") // implements agent.Provider

	// Execute Chat through the unified interface
	resp, err := prov.Chat(context.Background(), "claude-3-sonnet-20240229", nil, messages)
	if err != nil {
		log.Fatalf("chat failed: %v", err)
	}

	// Process the normalized response
	for _, msg := range resp.Messages {
		if msg.Content != nil && msg.Content.Text != nil {
			log.Printf("Assistant: %s", *msg.Content.Text)
		}
	}
}

func strPtr(s string) *string { return &s }

This example illustrates the core principle of AxonHub's translation layer: once messages are normalized into []agent.Message, the same code path supports any LLM vendor without modification.

Key Source Files for Any SDK to Any Model Translation

Understanding the translation mechanism requires familiarity with these critical files in the looplj/axonhub repository:

  • axon/agent/message.go – Defines the generic Message, Content, ToolDefinition, and Response types that normalize vendor-specific structures.

  • axon/agent/provider.go – Declares the Provider interface contract with Chat and ChatStream methods, along with the StreamEvent type for unified streaming.

  • axon/provider/reloadable/reloadable.go – Implements the reloadable.Provider wrapper that enables runtime swapping of provider implementations without breaking the translation contract.

  • axon/provider/anthropic/convert.go – Contains convertMessages and convertResponse functions demonstrating bidirectional translation between generic agent types and Anthropic's SDK-specific structs.

  • axon/provider/anthropic/provider.go – Shows the concrete implementation of agent.Provider for Anthropic, including how it invokes the conversion layer and native SDK.

These files collectively demonstrate how AxonHub achieves any SDK to any model translation through strict interface contracts and bidirectional conversion mappings.

Summary

  • AxonHub enables any SDK to any model translation by normalizing all LLM interactions through the agent.Provider interface and generic agent.Message types.
  • Bidirectional conversion functions in each provider package (e.g., convertMessages and convertResponse in axon/provider/anthropic/convert.go) map between vendor-specific SDK structs and the unified data model.
  • Runtime flexibility is achieved through reloadable.Provider in axon/provider/reloadable/reloadable.go, allowing hot-swapping of LLM implementations without application restarts.
  • Unified streaming support via ChatStream methods and agent.StreamEvent types ensures consistent behavior across both synchronous and asynchronous model interactions.

Frequently Asked Questions

How does AxonHub handle vendor-specific features like Anthropic's system prompts or OpenAI's function calling?

AxonHub handles vendor-specific features through bidirectional conversion logic in each provider's convert.go file. For example, axon/provider/anthropic/convert.go extracts the system prompt from the generic []agent.Message slice and places it in Anthropic's dedicated System field, while convertResponse maps Anthropic's content blocks back to the unified agent.Content structure. This approach allows the generic model to capture common patterns while provider-specific code handles unique vendor implementations.

Can I switch between LLM providers without restarting my application?

Yes, AxonHub supports runtime provider swapping through the reloadable.Provider implementation in axon/provider/reloadable/reloadable.go. This wrapper implements the same agent.Provider interface as concrete providers like Anthropic or OpenAI, but delegates to an underlying provider that can be updated atomically. When configuration changes or you need to failover to a different model, the hub updates the underlying provider instance while maintaining the same interface contract, enabling zero-downtime migrations between LLM vendors.

What is the performance impact of the translation layer?

The translation layer adds minimal overhead consisting primarily of struct-to-struct memory mapping and type conversions. The generic agent.Message types in axon/agent/message.go are designed to align closely with common LLM API patterns, avoiding expensive transformations. Conversion functions like convertMessages in axon/provider/anthropic/convert.go perform straightforward field mappings without network I/O or serialization overhead beyond what the underlying vendor SDK already requires. For high-throughput applications, the reloadable.Provider allows hot-swapping to optimized provider implementations without code changes.

Does AxonHub support streaming responses from all providers?

Yes, AxonHub provides unified streaming support through the ChatStream method defined in axon/agent/provider.go. Each provider implementation converts native streaming events—such as Server-Sent Events (SSE) from OpenAI or Anthropic's streaming chunks—into the generic agent.StreamEvent type. This normalization ensures that client code can process streaming responses using a single iterator pattern regardless of the underlying LLM vendor, with the provider-specific conversion handling protocol differences transparently.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →