Skip to content

cosmotron_mcp.inference.draft

draft_inference_spec

draft_inference_spec(session_dir: str, task_description: str = '', label: str | None = None) -> dict

Scaffold a typed InferenceSpec draft from the session SACC — deterministic, no LLM.

Reads the registered SACC to learn the run's probes and per-probe tomographic bin counts, then writes inference/{label}/inference_spec.draft.json with the structure filled (probes, per-bin prior slots pre-keyed to the actual tracers, standard DES-Y1 cosmology priors) and the value-level choices left as kind:"TODO" slots. This is the FIRST step of the recommended inference path (draft → fill via update_inference_specvalidate_inference_spec → human gate → compile_inference).

A literature-prior request in the task ("same priors as DESI DR2") is never fabricated: the reference is recorded in notes and returned as needs_literature for the orchestrator to resolve + human-confirm first.

Parameters:

Name Type Description Default
session_dir str

Session directory (must have a SACC data vector).

required
task_description str

Task text; used to seed sampler/priors and the spec notes. Defaults to the session's stored task.

''
label str | None

Spec label (names inference/{label}/); auto-derived from the catalogue stem + probes when omitted.

None

Returns:

Type Description
dict

{draft_path, label, summary, todo_count, gate_mode, needs_literature}.

dict

gate_mode is "gated" (human spec-approval gate active) or "skip".

Source code in cosmotron_mcp/server.py
@mcp.tool()
@sync_budget_guard
def draft_inference_spec(
    session_dir: str, task_description: str = "", label: str | None = None
) -> dict:
    """Scaffold a typed InferenceSpec draft from the session SACC — deterministic, no LLM.

    Reads the registered SACC to learn the run's probes and per-probe tomographic bin
    counts, then writes ``inference/{label}/inference_spec.draft.json`` with the structure
    filled (probes, per-bin prior slots pre-keyed to the actual tracers, standard DES-Y1
    cosmology priors) and the value-level choices left as ``kind:"TODO"`` slots. This is
    the FIRST step of the recommended inference path (draft → fill via
    `update_inference_spec` → `validate_inference_spec` → human gate → `compile_inference`).

    A literature-prior request in the task ("same priors as DESI DR2") is never
    fabricated: the reference is recorded in ``notes`` and returned as ``needs_literature``
    for the orchestrator to resolve + human-confirm first.

    Args:
        session_dir: Session directory (must have a SACC data vector).
        task_description: Task text; used to seed sampler/priors and the spec notes.
            Defaults to the session's stored task.
        label: Spec label (names ``inference/{label}/``); auto-derived from the
            catalogue stem + probes when omitted.

    Returns:
        ``{draft_path, label, summary, todo_count, gate_mode, needs_literature}``.
        ``gate_mode`` is ``"gated"`` (human spec-approval gate active) or ``"skip"``.
    """
    _require_human_gates(session_dir)
    result = _draft_inference_spec(session_dir, task_description=task_description,
                                   label=label)
    if not result.get("error"):
        _log_tool_call(session_dir, "draft_inference_spec",
                       {"task_description": task_description, "label": label})
    return result

update_inference_spec

update_inference_spec(session_dir: str, spec_path: str, updates: dict) -> dict

Deep-merge corrections into a draft spec, rewrite it, and revalidate — no LLM.

How the write-tool-free @inference agent fills a draft's kind:"TODO" slots: pass the corrected fragments (nested dicts merge; a leaf value such as a prior's params list is replaced wholesale) and get back the current schema-only validation state so the agent can see what remains.

Parameters:

Name Type Description Default
session_dir str

Session directory.

required
spec_path str

Path to the draft spec JSON (from draft_inference_spec).

required
updates dict

Partial spec dict to deep-merge in.

required

Returns:

Type Description
dict

{spec_path, todo_count, validation}validation is the

dict

validate_inference_spec result (schema-only, check_files=False).

Source code in cosmotron_mcp/server.py
@mcp.tool()
@sync_budget_guard
def update_inference_spec(session_dir: str, spec_path: str, updates: dict) -> dict:
    """Deep-merge corrections into a draft spec, rewrite it, and revalidate — no LLM.

    How the write-tool-free `@inference` agent fills a draft's ``kind:"TODO"`` slots: pass
    the corrected fragments (nested dicts merge; a leaf value such as a prior's ``params``
    list is replaced wholesale) and get back the current schema-only validation state so
    the agent can see what remains.

    Args:
        session_dir: Session directory.
        spec_path: Path to the draft spec JSON (from `draft_inference_spec`).
        updates: Partial spec dict to deep-merge in.

    Returns:
        ``{spec_path, todo_count, validation}`` — ``validation`` is the
        `validate_inference_spec` result (schema-only, ``check_files=False``).
    """
    _require_human_gates(session_dir)
    result = _update_inference_spec(session_dir, spec_path, updates)
    if not result.get("error"):
        _log_tool_call(session_dir, "update_inference_spec",
                       {"spec_path": spec_path, "updates": updates})
    return result