oc_chat
Loading...
Searching...
No Matches
oc_chat.benchmarks.runner Namespace Reference

Classes

class  _CannedPromptDriver

Functions

bool ensure_provider_registered (str provider_name)
Iterator[Path|None] autosave_suppression (bool persist)
tuple[int, str] effective_sub_loop_prompt (list|None tool_schemas)
"ChatSession" _compose_session ("Agent" agent, str model)
tuple[int, int|None] _messages_sizes ("ChatSession" session)
None _run_warmup ("Agent" agent, "ChatSession" session, str first_prompt)
ProviderResult run_scenario_for_provider (*, str provider_name, str|None model, Scenario scenario, bool warmup=False, bool persist=False, PriceTable|None price_table=None)
RunReport run_benchmark (*, Scenario scenario, list[str] providers, str|None model=None, str|None mode=None, bool warmup=False, bool persist=False, PriceTable|None price_table=None)

Detailed Description

The live benchmark driver — register, compose, isolate, run, report.

Purpose
-------
Reproduce the **real REPL/startup composition path** (not the bare
``Agent`` path) so the measured surface is the one Plan 135 changes,
then drive a scenario's scripted turns and assemble a
:class:`~oc_chat.benchmarks.report.RunReport`. Per run (plan §3.2):

1. register the provider (own helper) before any ``Agent(...)``;
2. apply the mode via ``init_runtime_settings`` (scenario-mode
   authoritative; a conflicting ``--mode`` is a clean error);
3. build the agent, then compose the session through
   ``_create_new_session`` — the model passed outright (plan 220 P1;
   the model choice is an interactive drill-down now) and only the
   session NAME answered by a canned ``PromptDriver`` (inherits
   whatever composition Plan 135 changes — no copy-drift);
4-5. wrap everything in a benchmark-local autosave-suppression policy
   that patches **all four** write bindings so a default run never
   touches the user's session store;
6. (optional ``--warmup``) warm the server prefix on a *throwaway*
   ``Agent`` + cloned session with its own presenter, fully discarded;
7. drive each turn, labelling turn 1 cold (warmup-aware);
8. capture the effective sub-loop prompt + composed ``messages[0]`` /
   ``messages[1]`` (nullable) sizes + effective mode/profile.

Responsibilities
----------------
- :func:`ensure_provider_registered` — import a provider bundle.
- :func:`autosave_suppression` — the four-binding persistence guard.
- :func:`effective_sub_loop_prompt` — version-independent sub-loop
  prompt size.
- :func:`run_scenario_for_provider` / :func:`run_benchmark` — drive +
  assemble reports.

Diagnostics
-----------
Domain: OC_CHAT.MAIN
Levels:
    L2 — lifecycle events
    L3 — semantic details
    L4 — deep tracing

Contracts
---------
- Default (``persist=False``) runs leave the real sessions dir
  untouched (chat log / metadata no-op'd; both ``save_tool_artifact``
  bindings redirected to a temp dir that still returns a valid Path).
- Warmup never pollutes the measured session or presenter (separate
  throwaway agent + presenter + cloned session, all discarded).
- A conflicting ``mode`` vs the scenario's mode raises ``ValueError``
  (the CLI turns it into a clean exit-1).

Dependencies
------------
- oc_diagnostics (structured debug logging via _dbg)
- oc_chat.core.agent (lazy; Agent, AgentConfig)
- oc_chat.core.startup (lazy; _create_new_session)
- oc_chat.core.settings (lazy; init_runtime_settings, runtime_mode, active_profile)
- oc_chat.core.provider_plugin (lazy; registry)
- oc_chat.benchmarks.presenter (BenchmarkPresenter - the measurement tap for measured and warmup turns)
- oc_chat.benchmarks.metrics (aggregate_run, derived_full_miss_cost - run totals and the cold full-miss cost)
- oc_chat.benchmarks.report (ProviderResult, RunReport - the per-provider result and the run report)
- oc_chat.benchmarks.scenarios (Scenario - the scripted turns and declared mode)
- oc_chat.benchmarks.prices (PriceTable, load_prices - prices the run from its token totals)
- oc_chat.core.api_context (lazy; its save_tool_artifact binding, redirected to a temp dir)
- oc_chat.core.deployment_shape (lazy; check_deployment_shape - the deployment-shape gate before a provider import and a run)
- oc_chat.core.persistence (lazy; its save_tool_artifact binding, redirected to a temp dir)
- oc_chat.core.react_loop (lazy; its chat-log and metadata save bindings, suppressed)
- oc_chat.core.risk_profile (lazy; resolve_risk_profile - the profile the deployment-shape gate checks against)
- oc_chat.core.session (lazy; ChatSession - type hints for the composed and warmup sessions)
- oc_chat.core.sub_loop (lazy; the sub-loop prompt builder or run_sub_loop default, for the prompt size)
- oc_chat.tools.filesystem (lazy; _sandbox_root - the write sandbox the deployment-shape gate checks)
- providers (not imported; the provider bundle loaded by name through importlib so it self-registers)

Function Documentation

◆ _compose_session()

"ChatSession" oc_chat.benchmarks.runner._compose_session ( "Agent" agent,
str model )
protected
Compose the measured session via ``_create_new_session`` (real path).

Plan 220 P1: *model* is handed over directly rather than scripted at a
prompt, so composition stays non-interactive now that the model choice
is an interactive drill-down. The session is still composed by the SAME
function the REPL uses — that is the whole point of this helper — and
``_create_new_session`` cannot return ``None`` here, because ``None``
means "the operator abandoned the lane picker" and the picker is not
reached when the model is supplied.

Definition at line 265 of file runner.py.

Here is the caller graph for this function:

◆ _messages_sizes()

tuple[int, int | None] oc_chat.benchmarks.runner._messages_sizes ( "ChatSession" session)
protected
``(messages[0] size, messages[1] size or None when absent)``.

Definition at line 290 of file runner.py.

Here is the caller graph for this function:

◆ _run_warmup()

None oc_chat.benchmarks.runner._run_warmup ( "Agent" agent,
"ChatSession" session,
str first_prompt )
protected
Warm the server prefix without touching the measured run.

Runs on a throwaway ``Agent`` with its own presenter and a clone of
the composed session (carrying its ``model``/``reasoning_effort``);
all three are discarded. Logs the warmup token cost to the console.

Definition at line 300 of file runner.py.

Here is the caller graph for this function:

◆ autosave_suppression()

Iterator[Path | None] oc_chat.benchmarks.runner.autosave_suppression ( bool persist)
Suppress every session-store write binding unless *persist*.

Patches ``react_loop.save_chat_log`` / ``save_session_metadata``
(chat log + metadata) and **both** ``save_tool_artifact`` bindings —
``api_context`` (module-level) and ``persistence`` (the lazy binding
``sub_loop`` re-fetches; ``react_loop`` calls it at neither). The
artifact patch **redirects to a temp dir and returns a valid Path**
(not a None-returning no-op) so ``sub_loop``'s
``str(save_tool_artifact(...))`` and the effective-prompt transcript
fallback keep working. Yields the temp dir (or ``None`` when
persisting).

Definition at line 152 of file runner.py.

Here is the caller graph for this function:

◆ effective_sub_loop_prompt()

tuple[int, str] oc_chat.benchmarks.runner.effective_sub_loop_prompt ( list | None tool_schemas)
Return ``(size, source)`` for the prompt the sub-loop actually uses.

Order of preference (plan §3.3): (a) a callable builder if Plan 135
introduces one; (b) the live default of ``run_sub_loop``'s
``system_prompt`` parameter when it is a full prompt string (today);
(c) ``unavailable`` rather than a fabricated number.

Definition at line 229 of file runner.py.

Here is the caller graph for this function:

◆ ensure_provider_registered()

bool oc_chat.benchmarks.runner.ensure_provider_registered ( str provider_name)
Import ``providers.<name>`` so it self-registers. Return success.

Never raises: an unimportable/unknown provider returns ``False`` so
the caller decides (single-provider → clean error; multi → skip).

Definition at line 109 of file runner.py.

Here is the caller graph for this function:

◆ run_benchmark()

RunReport oc_chat.benchmarks.runner.run_benchmark ( * ,
Scenario scenario,
list[str] providers,
str | None model = None,
str | None mode = None,
bool warmup = False,
bool persist = False,
PriceTable | None price_table = None )
Run *scenario* across *providers* with per-provider isolation.

Each provider is wrapped in its own try/except: a failure records a
``status="error"`` entry and the run continues (one provider can
never abort the whole run). A ``mode`` that conflicts with the
scenario's declared mode raises ``ValueError`` before any run.

Definition at line 435 of file runner.py.

Here is the call graph for this function:

◆ run_scenario_for_provider()

ProviderResult oc_chat.benchmarks.runner.run_scenario_for_provider ( * ,
str provider_name,
str | None model,
Scenario scenario,
bool warmup = False,
bool persist = False,
PriceTable | None price_table = None )
Run *scenario* against one provider and return a :class:`ProviderResult`.

Definition at line 333 of file runner.py.

Here is the call graph for this function:
Here is the caller graph for this function: