LLM providers
Use any OpenAI-compatible API or Claude, or write your own adapter.
The guard only talks to the LLMProvider interface, so it works with any model. Provider formats (OpenAI tool_calls, Anthropic tool_use blocks) stay inside the adapters.
From the environment
Section titled “From the environment”providerFromEnv() reads:
LLM_PROVIDER=openai-compatible
LLM_BASE_URL=https://api.openai.com/v1
LLM_API_KEY=...
LLM_MODEL=gpt-4o-miniLLM_PROVIDER |
Needs |
|---|---|
openai-compatible |
LLM_BASE_URL, LLM_MODEL, and LLM_API_KEY if the endpoint requires one. |
anthropic |
LLM_API_KEY, LLM_MODEL. Import providerFromEnv from @intentlock/anthropic. |
fake (default when unset) |
Nothing. A scripted provider for tests. |
Any OpenAI-compatible endpoint works: OpenAI, Gemini’s OpenAI endpoint, Groq, or Ollama at http://localhost:11434/v1.
Constructing a provider
Section titled “Constructing a provider”import { AnthropicProvider } from "@intentlock/anthropic";
import { OpenAICompatibleProvider } from "@intentlock/guard";
const openai = new OpenAICompatibleProvider({
baseURL: "https://api.groq.com/openai/v1",
apiKey: process.env.LLM_API_KEY!,
model: "llama-3.3-70b-versatile",
});
const claude = new AnthropicProvider({
apiKey: process.env.ANTHROPIC_API_KEY!,
model: "claude-sonnet-5-5",
});Both take an optional timeoutMs.
Writing your own adapter
Section titled “Writing your own adapter”Implement LLMProvider: a name and a chat(request) method. Map your SDK’s tool-call format to ToolCallReq and back from ToolResult, and wrap its errors with toProviderError(name, err) so the guard can tell which ones are retryable.
import type { ChatRequest, ChatResponse, LLMProvider } from "@intentlock/guard";
import { toProviderError } from "@intentlock/guard";
class MyProvider implements LLMProvider {
readonly name = "my-llm";
async chat(request: ChatRequest): Promise<ChatResponse> {
try {
const reply = await myLlm.complete(request);
return { text: reply.text, toolCalls: reply.toolCalls };
} catch (err) {
throw toProviderError(this.name, err);
}
}
}A ToolCallReq is { id, name, args }; a ToolResult is { callId, content, isError }. Every tool call must get exactly one result, and the guard takes care of that.