Source code for cadaques.core.protocols

"""The dual architecture: the :class:`Oracle` and :class:`Driver` protocols.

CADAQUES is agnostic on both sides of the discovery loop:

* an **Oracle** is anything that answers queries at a declared price —
  a simulator, a laboratory instrument, an analytic function;
* a **Driver** is anything that decides what to ask next — random
  search, Bayesian optimization, gradient methods, an LLM agent.

Both sides are metered: the campaign runner charges oracle queries
*and* driver decisions against one budget.
"""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any, Mapping, Protocol, Sequence, runtime_checkable

from .cost import BudgetView, Cost


[docs] @dataclass(frozen=True) class Query: """A single question to an Oracle. ``params`` are the design/search variables; ``fidelity`` are the knobs that trade accuracy for cost (lattice size, mesh density, integration time, ...). Keeping fidelity explicit is what makes multi-fidelity, cost-aware campaigns first-class citizens. """ params: Mapping[str, Any] fidelity: Mapping[str, Any] = field(default_factory=dict) tag: str = ""
[docs] @dataclass(frozen=True) class Result: """An Oracle's answer, carrying its *settled* (actual) cost.""" query: Query value: float cost: Cost info: Mapping[str, Any] = field(default_factory=dict)
[docs] @runtime_checkable class Oracle(Protocol): """Anything that answers queries at a price. ``price`` declares the expected cost *ex ante* so the runner can check affordability before committing; ``evaluate`` performs the query and reports the *settled* cost inside the Result. Real oracles deviate from their declared price — the ledger records both, and that discrepancy is itself an observable. """ def price(self, query: Query) -> Cost: ... def evaluate(self, query: Query) -> Result: ...
[docs] @runtime_checkable class Driver(Protocol): """Anything that decides what to ask next. ``propose`` receives the full history and a read-only view of the budget, enabling budget-aware strategies. ``observe`` feeds the settled result back. Drivers that incur their own accountable costs beyond wall time (e.g. LLM tokens) may expose a ``last_proposal_cost`` attribute, which the runner will charge. """ def propose(self, history: Sequence[Result], budget: BudgetView) -> Query: ... def observe(self, result: Result) -> None: ...