LLM

The public solver API. SolverConfig is the validated, frozen configuration the framework builds from your TOML; the Solver is constructed per worker from it via Solver.from_config. A Session is created for each individual solve and records the transcript of one attempt.

For the internals of the solve loop (the LangGraph workflow, context compaction, retries), see the LLM Backend Design.

llm

EntryKind

Bases: StrEnum

The kind of a single transcript entry. Passed to Session.add to classify what an entry records — a prompt, an LLM response, a tool call or output, a failure, and so on — and used as the entry's label in the rendered session log.

Session

Session(*, solver_id: int, data_id: Any, run_index: int, total_runs: int, cancel: Event, on_status: Callable[[SolverStatus], None])

One per solver.solve() call. The single object through which a solver communicates with the rest of the framework for one solve.

Carries:

  • Identitysession_id, solver_id, data_id, run_index, total_runs. The orchestrator fills these in; the solver reads but doesn't set them.
  • Status reportingreport(state, session_length) updates the run's worker dashboard. Call whenever the solver's phase changes (e.g. starting an LLM turn, awaiting a tool, handing off to the checker).
  • Transcriptadd(kind, turn, fields) records one entry in the session log. Call close(reason, turn) exactly once at the end of the solve to flush the transcript to the configured session log file(s).

Lifetime is one solve: the orchestrator constructs a fresh Session for each call and discards it after. The solver should not retain a reference past solve() returning.

cancelled

cancelled() -> bool

True if the run is shutting down. Solvers should check this between LLM turns and raise InterruptedError to bail.

report

report(state: SolverState, session_length: int) -> None

Report a phase change to the dashboard. Cheap; call freely.

add

add(kind: EntryKind, turn: int, fields: dict[str, Any]) -> None

Append a transcript entry. Buffered until close.

close

close(reason: str, turn: int) -> None

Append a SESSION_END entry and flush the transcript. Call once per session, immediately before returning from solve.

Solver

Solver(llm: BaseChatModel, instruction_prompt: str, reformat_prompt: str, solution_adapter: SolutionAdapter[SolutionT], helper_llm: BaseChatModel | None = None, tools: tuple[BaseTool, ...] = (), user_system_prompt: str = '', context_window_size: int | None = None, context_compaction_threshold: float = 0.8, max_steps: int = 5, error_summarization_threshold: int = 500, solution_adaption_attempts: int = 3, rate_limit_backoff_seconds: tuple[int, ...] = (2, 4, 8, 16, 32))

The built-in LangChain/LangGraph solver. One instance is constructed per worker — usually via Solver.from_config from a validated SolverConfig — and reused across data items. Each solve call runs one attempt through the agentic workflow (reasoning, tool calls, context compaction, and solution adaption) and records a transcript on the provided Session.

For the internals of the solve loop see the LLM Backend Design docs.

Parameters:
  • llm (BaseChatModel) –

    Main LLM that powers the solver

  • instruction_prompt (str) –

    Instruction prompt template to fill with data in solve()

  • reformat_prompt (str) –

    Prompt that will be showed to the LLM when solution adapter fails to pare its answer

  • solution_adapter (SolutionAdapter[SolutionT]) –

    Parser that extracts SolutionT from LLM response

  • helper_llm (BaseChatModel | None, default: None ) –

    Cheaper LLM to replace the llm in less important tasks

  • tools (tuple[BaseTool, ...], default: () ) –

    Tools to bind to the llm

  • user_system_prompt (str, default: '' ) –

    Prompt to extend the base system prompt

  • context_window_size (int | None, default: None ) –

    Context window size of thellm. Set to None will lead to best-effort extraction. Defaults to 256k.

  • context_compaction_threshold (float, default: 0.8 ) –

    Context window occupancy ratio that will trigger compaction

  • max_steps (int, default: 5 ) –

    Max allowed steps to arrive at a solution (1 step ~ 1 inference)

  • error_summarization_threshold (int, default: 500 ) –

    Error messages of length >= inside tool outputs will be summarized

  • solution_adaption_attempts (int, default: 3 ) –

    Number of attempts to give the llm to reformat its answer before declaring parsing failure

  • rate_limit_backoff_seconds (tuple[int, ...], default: (2, 4, 8, 16, 32) ) –

    Seconds to wait before retrying after a rate limit from model providers

from_config classmethod

from_config(config: SolverConfig[SolutionT]) -> Solver[DataT, SolutionT]

Build a Solver from a validated :class:SolverConfig.

solve

solve(session: Session, data: DataT) -> Result[SolutionT]

Run one solve attempt for data and return the parsed solution.

Drives the agentic workflow to completion, reporting phase changes and recording the transcript through session; the session is closed before returning.

Parameters:
  • session (Session) –

    The per-attempt Session to report status through and log the transcript to.

  • data (DataT) –

    The problem instance to solve.

Returns:
  • Result[SolutionT]

    Ok wrapping the parsed SolutionT on success, or Err if the

  • Result[SolutionT]

    attempt failed (gave up at the step limit, parsing failure, or an

  • Result[SolutionT]

    internal error).

Raises:
  • InterruptedError

    If the run is cancelled mid-solve.

SolverConfig dataclass

SolverConfig(llm: BaseChatModel, instruction_prompt: str, reformat_prompt: str, solution_adapter: SolutionAdapter[SolutionT], helper_llm: BaseChatModel | None = None, tools: tuple[BaseTool, ...] = (), user_system_prompt: str = '', context_window_size: int | None = None, context_compaction_threshold: float = 0.8, max_steps: int = 5, error_summarization_threshold: int = 500, solution_adaption_attempts: int = 3, rate_limit_backoff_seconds: tuple[int, ...] = (2, 4, 8, 16, 32))

Fully validated configuration for the built-in LangChain-based Solver.

Mirrors Solver.__init__: the orchestrator constructs one Solver per worker from this config. Validation happens here (at construction time), so a misconfigured run fails before the CLI dashboard comes up.

llm instance-attribute

llm: BaseChatModel

Main LLM that powers the solver.

instruction_prompt instance-attribute

instruction_prompt: str

Instruction prompt template (mustache) filled with the data item in solve().

reformat_prompt instance-attribute

reformat_prompt: str

Prompt shown to the LLM when the solution adapter fails to parse its answer.

solution_adapter instance-attribute

solution_adapter: SolutionAdapter[SolutionT]

Parser that extracts SolutionT from the LLM response.

helper_llm class-attribute instance-attribute

helper_llm: BaseChatModel | None = None

Cheaper LLM used in less important tasks (compaction, summarization).

tools class-attribute instance-attribute

tools: tuple[BaseTool, ...] = ()

Tools to bind to llm.

user_system_prompt class-attribute instance-attribute

user_system_prompt: str = ''

Prompt appended to the base system prompt.

context_window_size class-attribute instance-attribute

context_window_size: int | None = None

Context window size of llm; None means best-effort extraction.

context_compaction_threshold class-attribute instance-attribute

context_compaction_threshold: float = 0.8

Context window occupancy ratio that triggers compaction.

max_steps class-attribute instance-attribute

max_steps: int = 5

Max allowed steps to arrive at a solution (1 step ~ 1 inference).

error_summarization_threshold class-attribute instance-attribute

error_summarization_threshold: int = 500

Error messages of at least this length inside tool outputs get summarized.

solution_adaption_attempts class-attribute instance-attribute

solution_adaption_attempts: int = 3

Attempts the LLM gets to reformat its answer before declaring parsing failure.

rate_limit_backoff_seconds class-attribute instance-attribute

rate_limit_backoff_seconds: tuple[int, ...] = (2, 4, 8, 16, 32)

Seconds to wait before retrying after a rate limit from the model provider. Must be non-empty; its length is the number of attempts a single LLM call gets.