Skip to content

LLMStrategy capabilities (serializable + registerable) + pydantic-ai v2#784

Draft
jduerholt wants to merge 1 commit into
mainfrom
feature/llm-tools
Draft

LLMStrategy capabilities (serializable + registerable) + pydantic-ai v2#784
jduerholt wants to merge 1 commit into
mainfrom
feature/llm-tools

Conversation

@jduerholt

Copy link
Copy Markdown
Contributor

Summary

Brings the LLM recommender to the next level: a serializable + registerable capability system for LLMStrategy, plus migration to pydantic-ai v2. Capabilities are typed, serializable config; a mapper reconstructs the live pydantic-ai capability (including its tool functions) at runtime — mirroring the existing LLM-provider triplet (data model + tagged union + mapper + register).

As the first capability, experiment presentation moves from a prompt-dump (with n_recent/n_top knobs) to a tool-only ExperimentAccessCapability the model queries on demand.

What's included

Capability triplet (mirrors AnyLLMProvider + LLM_MAP + register_llm_provider)

  • bofire/data_models/llm/capability.pyLLMCapability base + ExperimentAccessCapability
  • AnyLLMCapability union + register_llm_capability(); LLMStrategy.capabilities field (default-on via default_factory, replace-semantics documented)
  • bofire/llm/capabilities_mapper.pyCAPABILITY_MAP + register/map
  • bofire/llm/experiment_tools.pyFunctionToolset of inspect_recent/inspect_top/inspect_near/summary_stats/list_pending_candidates; per-query logic in unit-testable pure functions

Tool-only experiment access

  • Removed n_recent_experiments / n_top_experiments and the prompt-dump path
  • The capability instructions surface only counts (metadata, not a predefined view) to motivate tool use
  • Strategy deps refactored _LLMDepsLLMContext (domain + experiments + pending candidates)
  • The output_validator feasibility gate is unchanged — capabilities enrich, never bypass domain.validate_candidates

pydantic-ai v2 migration

  • output_retriesretries={"output": N}, OpenAIModelOpenAIChatModel, pin pydantic-ai>=2,<3

Design notes

  • Serialization boundary: config serializes; the mapper is the code that rebuilds tools. Custom capabilities round-trip only where their mapper is registered (same as custom providers).
  • Why capabilities, not a bare tool system: v2's capability bundles instructions + tools + model settings + hooks; "skill" and "tool" collapse into one primitive, one registry, one mapper.
  • Future capabilities (MCPCapability, RAG, BO-as-a-tool, sandboxed code analysis) drop into the same slot without redesign.

Verification

  • 1418 passed, 5 skipped across tests/bofire/data_models, test_llm, bofire/llm, test_register (incl. exact serialization round-trip for the default capability)
  • ruff check clean, formatted; ty check bofire exits 0 (new modules produce zero diagnostics)

Follow-ups (out of scope)

  • asyncio.run() in _ask throws inside a running event loop (Jupyter); matters more once a deep/agentic harness lands.

🤖 Generated with Claude Code

…to pydantic-ai v2

Introduces a capability system for the LLM recommender, mirroring the existing
LLM-provider triplet (data model + tagged union + mapper + register). Capabilities
are typed, serializable config; the mapper rebuilds the live pydantic-ai capability
(including its tool functions) at runtime.

- Data model: LLMCapability base + ExperimentAccessCapability, AnyLLMCapability
  union, register_llm_capability(); LLMStrategy gains a capabilities field
  (default-on ExperimentAccessCapability via default_factory).
- Functional: bofire/llm/capabilities_mapper.py (CAPABILITY_MAP/register/map) and
  experiment_tools.py (FunctionToolset: recent/top/near/summary/pending). Strategy
  deps refactored from _LLMDeps to LLMContext (domain + experiments + pending
  candidates). The output_validator feasibility gate is unchanged.
- Experiment presentation is now tool-only: removed n_recent_experiments /
  n_top_experiments and the prompt-dump path; the model inspects experiments on
  demand via tool calls, with counts surfaced in the capability instructions.
- pydantic-ai v2 migration: output_retries -> retries={"output": N},
  OpenAIModel -> OpenAIChatModel, pin pydantic-ai>=2,<3.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant