Providers and framework bridges¶
ProtoPrompt keeps provider SDKs outside the core dependency graph. Every adapter is lazy, capability-based, and tested without cloud credentials.
Provider conformance matrix¶
| Provider client | Extra | Chat | Embed | Exact input tokens | Native semantics |
|---|---|---|---|---|---|
OpenAIClient |
[openai] |
yes | yes | no | official SDK, custom base_url |
AnthropicClient |
[anthropic] |
yes | no | messages.count_tokens |
top-level system instructions, content/tool blocks |
GoogleGenAIClient |
[google] |
yes | yes | models.count_tokens |
Developer API key or Vertex AI ADC, Gemini roles/config |
BedrockConverseClient |
[bedrock] |
yes | no | Bedrock CountTokens |
boto3 credential chain, Converse/system/inference config |
OllamaClient |
[ollama] |
yes | yes | no | native /api/chat and /api/embed |
HttpxLLMClient |
[http] |
yes | yes | no | OpenAI-compatible HTTP only |
The compatibility range validated for 0.5 is Anthropic SDK 1.x, Google Gen
AI 2.20.x, and boto3 1.43.x. Minor versions inside those guarded ranges run
the same deterministic contract suite in CI.
Install only what one deployment needs:
pip install "protoprompt[anthropic]"
pip install "protoprompt[google]"
pip install "protoprompt[bedrock]"
Native clients¶
from protoprompt import CompositeLLMClient
from protoprompt.integrations import AnthropicClient, GoogleGenAIClient
claude = AnthropicClient(model="claude-sonnet-4-6")
gemini = GoogleGenAIClient(embed_model="gemini-embedding-001")
# Anthropic has no embedding API. Pair independent capabilities explicitly.
llm = CompositeLLMClient(chat_client=claude, embedding_client=gemini)
All three new adapters:
- move portable
system/developermessages to the provider's native system field; - retain native tool/config options instead of projecting them onto OpenAI parameters;
- expose
await client.count_tokens(messages)when the provider offers an exact billable count; - expose
aclose()and never own global SDK state.
Bedrock's boto3 calls execute through asyncio.to_thread, keeping the async
context pipeline non-blocking. IAM roles, web identity, profiles, and the
standard credential chain remain boto3's responsibility.
Token budgeting¶
ProviderTokenCounter is deterministic, local, and synchronous, which makes it
safe inside TokenBudgetedContextBuilder:
from protoprompt.tokens import ProviderTokenCounter
counter = ProviderTokenCounter("anthropic", model="claude-sonnet-4-6")
It uses provider-specific message overhead and tiktoken for OpenAI when that
extra is available, otherwise the multilingual regex estimator. This is a
budget signal, not a billing value. Use the provider client's async
count_tokens() at request-planning boundaries for an exact count. No hidden
network request occurs while assembling context.
PydanticAI¶
Install the slim package integration:
from pydantic_ai import Agent
from protoprompt.integrations import create_pydantic_ai_capability
agent = Agent(
"anthropic:claude-sonnet-4-6",
capabilities=[create_pydantic_ai_capability(memory_service)],
)
The bridge is a native ProcessHistory capability. It searches the
host-scoped MemoryService using the newest user prompt and adds recall only
to the model view. Retrieved text is a UserPromptPart, not a system prompt,
because memory is untrusted data. The original PydanticAI history is not
mutated.
The extra intentionally depends on pydantic-ai-slim, not the all-provider
meta-package. This avoids forcing PydanticAI's unrelated provider/MCP versions
into an application that already selected ProtoPrompt extras.
LlamaIndex¶
from llama_index.core.memory import Memory
from protoprompt.integrations import ProtoPromptMemoryBlock
block = ProtoPromptMemoryBlock(memory_service, top_k=5)
memory = Memory.from_defaults(
session_id="thread-a",
memory_blocks=[block],
insert_method="user",
)
ProtoPromptMemoryBlock is a native BaseMemoryBlock. It recalls through the
pinned service and returns content for LlamaIndex's normal memory insertion
pipeline. Automatic persistence of evicted chat messages is disabled by
default: call block.remember(...) for confirmed memory, or opt in with
auto_remember=True after reviewing that policy.
Google ADK support decision¶
The 2.8 spike found a technically viable extension point:
google.adk.memory.BaseMemoryService exposes search_memory() and session or
event ingestion. We are not shipping a native ADK adapter in 0.5.
Reasons:
- ADK selects
app_nameanduser_iddynamically, while ProtoPrompt's security boundary is a host-created, immutableMemoryServicescope. A safe bridge needs a trusted service factory and an explicit mapping policy, not a single global adapter. add_session_to_memory()implies automatic extraction from raw sessions; ProtoPrompt distinguishes raw history from confirmed durable memory.- Callback/request APIs have continued to move across recent ADK releases.
Implementing recall through
before_model_callbackwould create a fragile second integration path whenBaseMemoryServiceis the correct one.
Current recommendation: expose ProtoPrompt through the supported MCP server to
ADK agents, or build an application-local BaseMemoryService with a trusted
scope factory. Revisit native support when ADK's memory scope and incremental
ingestion contracts stabilize; the acceptance gate is tenant-isolation tests
plus an explicit ingestion policy.
See runnable recipes in examples/provider_clients.py,
examples/pydantic_ai_memory.py, and examples/llamaindex_memory.py.