Core Docs

Provider Model

Provider Model



How core.ai abstracts LLM providers into a unified interface.

Supported Providers



ProviderModelsStreamingVisionTool UseExtended Thinking




OpenAIGPT-4o, GPT-4, o1, o3SSE✅✅✅ (o1/o3)
AnthropicClaude Sonnet, Opus, HaikuSSE✅✅✅
GoogleGemini Pro, FlashSSE✅✅✅

Provider Adapter Pattern



Each provider gets an adapter class. The adapter translates between core.ai's internal format and the provider's native API format.

Internal Format  →  OpenAIAdapter     →  OpenAI API
Internal Format → AnthropicAdapter → Anthropic API
Internal Format → GoogleAdapter → Google API


What adapters handle:
  • Message format translation (roles, content blocks, tool calls)

  • Image encoding (base64 vs URL, depending on provider)

  • Streaming chunk normalization

  • Tool definition format (JSON Schema variations)

  • Error mapping (provider-specific error codes → unified internal codes)

What adapters do NOT handle:
  • Conversation state (that's core.ai's job)

  • Cost calculation (that's the cost engine's job)

  • Retry logic (that's the request orchestrator's job)

Internal Message Format



core.ai uses one internal message format. Provider adapters translate in/out.

User Message


{
"role": "user",
"content": "What is the differential diagnosis for chest pain?",
"media": [
{
"type": "image",
"media_id": 42,
"url": "https://storage.medkronos.com/compressed/abc123.webp"
}
]
}


Assistant Message (text only)


{
"role": "assistant",
"content": "The differential diagnosis for chest pain includes..."
}


Assistant Message (with tool calls)


{
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_abc123",
"name": "web_search",
"arguments": {"query": "chest pain differential diagnosis"}
}
]
}


Tool Result Message


{
"role": "tool",
"tool_call_id": "call_abc123",
"tool_name": "web_search",
"content": "{\"results\": [...]}",
"tool_status": "success"
}


System Message


{
"role": "system",
"content": "You are a clinical reasoning assistant..."
}


Provider Translation Examples



Tool Calls



Internal → OpenAI:
{
"role": "assistant",
"content": null,
"tool_calls": [
{"id": "call_abc", "type": "function", "function": {"name": "web_search", "arguments": "{\"query\":\"...\"}"}}
]
}


Internal → Anthropic:
{
"role": "assistant",
"content": [
{"type": "tool_use", "id": "toolu_abc", "name": "web_search", "input": {"query": "..."}}
]
}


Internal → Google:
{
"role": "model",
"parts": [
{"functionCall": {"name": "web_search", "args": {"query": "..."}}}
]
}


Tool Results



Internal → OpenAI:
{"role": "tool", "tool_call_id": "call_abc", "content": "{\"results\": [...]}"}


Internal → Anthropic:
{"role": "user", "content": [{"type": "tool_result", "tool_use_id": "toolu_abc", "content": "{\"results\": [...]}"}]}


Internal → Google:
{"role": "function", "parts": [{"functionResponse": {"name": "web_search", "response": {"results": [...]}}}]}


The adapters handle all of this. The rest of core.ai only deals with the internal format.

Streaming Protocol



All providers support SSE (Server-Sent Events). Each adapter normalizes provider-specific chunk formats into a common internal chunk format.

Provider → core.ai (raw chunks)



OpenAI:
data: {"choices":[{"delta":{"content":"Hello"}}]}


Anthropic:
event: content_block_delta
data: {"delta":{"type":"text_delta","text":"Hello"}}


Google:
data: {"candidates":[{"content":{"parts":[{"text":"Hello"}]}}]}


core.ai → Client (normalized chunks)



See Conversation Flow for the full SSE protocol including trace events.

Model-per-Message



The conversation stores a default_model_slug for UI pre-selection, but every message can override it. Each assistant message records the model that actually generated it.

Implications:
  • Switching models mid-conversation breaks prompt cache (providers cache by prefix)

  • This is acceptable — the cost savings from model flexibility outweigh cache hits

  • The UI should warn users when switching: "Switching models will reset prompt cache"

  • Each model has different capabilities (vision, tool use, thinking) — the UI should indicate which features are available per model

Model Capability Registry



core.ai maintains a registry of model capabilities, used for UI hints and request validation.

{
"gpt-4o": {
"provider": "openai",
"context_window": 128000,
"max_output": 16384,
"supports_vision": true,
"supports_tools": true,
"supports_thinking": false,
"supports_streaming": true
},
"claude-sonnet-4-20250514": {
"provider": "anthropic",
"context_window": 200000,
"max_output": 8192,
"supports_vision": true,
"supports_tools": true,
"supports_thinking": true,
"supports_streaming": true
}
}


This is a static config (JSON file or hardcoded), not a database table. Updated when new models are added.

Related