@murmurations-ai/llm
v0.8.0
Published
Provider-agnostic LLM client for the Murmuration Harness — SecretValue auth, per-call cost hook, pluggable ProviderRegistry (ADR-0025).
Downloads
1,942
Readme
@murmurations-ai/llm
Typed LLM client for the Murmuration Harness. Four concurrent provider
adapters behind a single LLMClient interface:
| Provider | Priority | API |
| ------------- | -------- | ------------------------ |
| Google Gemini | P0 | Generative AI v1beta |
| Anthropic | P1 | Messages API v2023-06-01 |
| OpenAI | P1 | Chat Completions v1 |
| Ollama | P1 | Local HTTP /api/chat |
Designed by TypeScript / Runtime Agent #24. See
docs/adr/0014-llm-client.md for
the full rationale.
Why four adapters concurrently
The four-adapter mandate exists so the LLMClient interface cannot be
Gemini-shaped (or any-other-shaped) by accident. Cross-validation is
the test.
Key design choices
- Native
fetchin production. No vendor SDKs. SecretValueauth —reveal()called exactly once per paid adapter (grep-checkable).- Per-call cost hook — daemon-long-lived client cooperates with
per-wake
WakeCostBuilder. - Errors-as-values for expected failures;
AbortErrorre-throws. - Pricing stays out — the cost hook emits token counts only; the
daemon resolves price via
@murmurations-ai/llm/pricing(ADR-0015). - Streaming / tools / vision / JSON mode — all deferred to Phase 3+.
Usage
import { makeSecretKey } from "@murmurations-ai/core";
import { DotenvSecretsProvider } from "@murmurations-ai/secrets-dotenv";
import { createLLMClient } from "@murmurations-ai/llm";
const GEMINI_KEY = makeSecretKey("GEMINI_API_KEY");
const provider = new DotenvSecretsProvider({ envPath: ".env" });
await provider.load({ required: [GEMINI_KEY], optional: [] });
const llm = createLLMClient({
provider: "gemini",
token: provider.get(GEMINI_KEY),
tier: "balanced",
});
const result = await llm.complete({
model: "gemini-2.5-pro",
messages: [{ role: "user", content: "Hello, world." }],
maxOutputTokens: 200,
});
if (result.ok) {
console.log(result.value.content);
}Provider swap is a one-line config change:
const llm = createLLMClient({
provider: "ollama", // swap to local, no auth, zero cost
token: null,
model: "llama3.2",
});