yggdrasil.loki.engines.claude_engine¶
claude_engine ¶
Anthropic (Claude) -backed :class:TokenEngine.
Two ways to authenticate, resolved in this order:
- API key —
ANTHROPIC_API_KEY(orapi_key=). Billed per token. - OAuth / subscription token — the credential Claude Code itself logs in
with, so Loki can reason without a separate billed API key when run on
a machine where you're signed into Claude Code. Taken from
ANTHROPIC_AUTH_TOKEN/CLAUDE_CODE_OAUTH_TOKEN, or the Claude Code credentials file (~/.claude/.credentials.json→claudeAiOauth). The SDK sends it as a bearer token; the request carries the OAuth beta header and the Claude Code system identity the grant is scoped to.
An API key wins when both are present. available() is true when either
is resolvable, so ygg loki lights up Claude on a logged-in Claude Code
box with no extra configuration.
ClaudeEngine ¶
ClaudeEngine(
*,
model: Optional[str] = None,
tier: Optional[str] = None,
api_key: Optional[str] = None,
auth_token: Optional[str] = None
)
Bases: TokenEngine
Reason via the Anthropic Messages API (anthropic SDK).
uses_oauth
property
¶
True when this engine will authenticate with a subscription token.
model_label
property
¶
Human label for status output — the pin, or the adaptive ceiling.
choose_tier ¶
choose_tier(
messages: Optional[list[dict[str, Any]]] = None,
system: Optional[str] = None,
) -> str
Adaptive tier for this request: "deep" or "fast".
Sizes on the message content (the actual work, not the fixed system boilerplate) and scans both message and system text for reasoning signals. Long or signalled requests get the deep tier; the rest stay fast. Override for a smarter policy.
resolve_model ¶
resolve_model(
*,
messages: Optional[list[dict[str, Any]]] = None,
system: Optional[str] = None,
tier: Optional[str] = None
) -> Optional[str]
The model id to use for this request.
An explicit self.model pin wins. Otherwise a forced tier (arg or
self.tier) selects from :attr:MODELS; with neither, the tier is
chosen adaptively. Falls back to :attr:default_model when the tier
isn't in the map.
generate ¶
generate(
prompt: str,
*,
system: Optional[str] = None,
tier: Optional[str] = None,
**options: Any
) -> str
Convenience: complete a single user prompt → reply text.
generate_stream ¶
generate_stream(
prompt: str,
*,
system: Optional[str] = None,
tier: Optional[str] = None,
**options: Any
) -> "Iterator[str]"
Convenience: stream a single user prompt → text chunks.