Agentic schematic validation: datasheet extraction via Claude Console Skills, netlist/BOM design graph, per-IC direct datasheet review with page citations, capacitor derating, Next.js report UI. Extracted from the Pinscope cloud codebase. Auth and billing live in the private gateway repo behind stable seams (billing_hook.py, adapter files listed in CLAUDE.md).
101 lines
3.1 KiB
Python
101 lines
3.1 KiB
Python
"""Abstract LLMProvider + LLMSession interfaces."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from abc import ABC, abstractmethod
|
|
from typing import Protocol
|
|
|
|
from backend.services.llm.types import (
|
|
Completion,
|
|
Message,
|
|
ToolChoice,
|
|
ToolSchema,
|
|
)
|
|
|
|
|
|
class LLMSession(ABC):
|
|
"""A multi-turn conversation with provider-specific cache lifecycle.
|
|
|
|
Lifecycle::
|
|
|
|
session = await provider.create_session(model=..., system=...)
|
|
try:
|
|
messages = [Message("user", [
|
|
PdfBlock(path, cacheable=True),
|
|
TextBlock(context, cacheable=True),
|
|
])]
|
|
for turn in range(N):
|
|
completion = await session.complete(
|
|
messages=messages, tools=..., tool_choice=...,
|
|
)
|
|
# process tool_calls, append to messages, repeat
|
|
finally:
|
|
await session.close()
|
|
|
|
Caching: blocks with ``cacheable=True`` participate in provider caching.
|
|
Anthropic stamps ``cache_control: ephemeral`` on each cacheable block on
|
|
every call. Gemini collects all cacheable blocks (plus the system prompt)
|
|
on the first ``complete()`` call into a ``CachedContent`` object and
|
|
references it on subsequent calls. The system prompt is always cached.
|
|
"""
|
|
|
|
provider_name: str
|
|
"""Provider identifier ("anthropic", "gemini") — used for api_logs."""
|
|
model: str
|
|
|
|
@abstractmethod
|
|
async def complete(
|
|
self,
|
|
*,
|
|
messages: list[Message],
|
|
tools: list[ToolSchema] | None = None,
|
|
tool_choice: ToolChoice = "auto",
|
|
) -> Completion:
|
|
"""Run one inference turn."""
|
|
|
|
@abstractmethod
|
|
async def close(self) -> None:
|
|
"""Release any provider-side resources (e.g. delete a cache object).
|
|
Safe to call multiple times."""
|
|
|
|
|
|
class LLMProvider(Protocol):
|
|
"""Top-level provider interface."""
|
|
|
|
name: str
|
|
|
|
async def create_session(
|
|
self,
|
|
*,
|
|
model: str,
|
|
system: str,
|
|
max_tokens: int = 4096,
|
|
temperature: float | None = None,
|
|
) -> LLMSession:
|
|
"""Construct a session. ``system`` is always cached by the session.
|
|
|
|
``temperature`` — if not None, applied to every ``complete()`` call on
|
|
this session. ``None`` means use the provider's default. Set to 0.0
|
|
for deterministic-as-possible behavior in agentic loops where the same
|
|
inputs should produce the same outputs."""
|
|
...
|
|
|
|
async def run_skill(
|
|
self,
|
|
*,
|
|
skill_name: str,
|
|
model: str,
|
|
system: str,
|
|
user_text: str,
|
|
pdf_path: str | None,
|
|
output_tool: ToolSchema,
|
|
) -> tuple[dict, "Completion"]:
|
|
"""Execute a managed Skill and return (forced-tool input, Completion).
|
|
|
|
Anthropic uses Console Skills (skill_id + container + code_execution
|
|
beta). Gemini raises ``NotImplementedError`` — there is no
|
|
Gemini-managed-Skill equivalent today; if you want a Gemini path for
|
|
skill-style extraction, inline the SKILL.md content as ``system`` and
|
|
run validation locally."""
|
|
...
|