Swap providers
Goal: switch an agent from one LLM provider to another without rewriting any agent code.
Before you start: you have a working agent using one provider (see Configure a provider).
The same recipe, different wiring
Provider neutrality means your agent's identity — system prompt, tools, permission mode, child agents — never depends on which provider is serving it. The provider is wiring, injected at Client or query time. Swap it, and the same Options compiles to the same AgentSpec.
Before: Anthropic
from noeta.sdk import Client, Options, query
from noeta.llm.anthropic import AnthropicProvider
options = Options(
system_prompt="You are a concise assistant.",
name="concise-bot",
allowed_tools=None,
)
anthropic = AnthropicProvider(
model="claude-sonnet-4-5-20250929",
api_key="sk-ant-…",
)
client = Client(options, provider=anthropic, workspace_dir="./")After: OpenAI-compatible
from noeta.llm.openai_compat import OpenAICompatProvider
openai = OpenAICompatProvider(
model="gpt-5.5",
base_url="https://api.openai.com/v1",
api_key="sk-…",
)
# Same options, same client construction — only the provider changes
client = Client(options, provider=openai, workspace_dir="./")Nothing else changes: same Options, same tools, same Client usage. Your recorded history is also portable — EventLog entries are provider-agnostic, so a session started with Anthropic can resume with OpenAI.
Via query() (one-shot)
The query() convenience function also accepts a provider kwarg:
from noeta.sdk import query
result = query(
options,
goal="What is the capital of France?",
provider=openai, # or anthropic, or any provider
workspace_dir="./",
)
print(result.answer())Verify the swap
Run the same goal against both providers and confirm both produce a terminal answer:
for name, prov in [("anthropic", anthropic), ("openai", openai)]:
result = query(options, goal="Say hello.", provider=prov, workspace_dir="./")
print(f"{name}: {result.answer()}")Both should return a successful answer. The exact text will differ (different models), but both reach a terminal state.
What does not change
When you swap providers:
- Tool definitions — same
@toolfunctions, same names, same schemas. - Agent identity — the compiled
AgentSpecis identical becausecompile_optionsnever sees the provider. - EventLog format — recorded events are vendor-neutral. A log written with Anthropic can be folded with an OpenAI provider active.
- Permission model — same
permission_mode, same Guards.
What might change
- Tool calling format — the internal protocol normalizes this, but edge cases (e.g. parallel tool calls) may behave slightly differently across providers.
- Reasoning / extended thinking — providers that support extended thinking (Anthropic) vs those that do not may produce different internal traces.
- Token counts and pricing — obviously different per provider.
See also
- Provider neutrality — the design behind this
- Configure a provider — setup for each provider
- SDK reference —
Options,Client,querysignatures examples/swap_provider.py— runnable demonstration