# `PtcRunner.Upstream.Eval`
[🔗](https://github.com/andreasronge/ptc_runner/blob/main/lib/ptc_runner/upstream/eval.ex#L1)

High-level Lisp orchestration over the upstream runtime.

Sits above the low-level `PtcRunner.Upstream.Runtime` server: builds a
per-run `RunContext`, assembles the eval callbacks (`tools:` /
`discovery_exec:`), and runs PTC-Lisp programs against them.

# `eval_options`

```elixir
@spec eval_options(struct()) :: keyword()
```

# `run_context`

```elixir
@spec run_context(
  struct() | pid(),
  keyword()
) :: {:ok, struct()} | {:error, term()}
```

# `run_lisp`

```elixir
@spec run_lisp(struct() | pid(), String.t(), keyword()) ::
  {:ok, PtcRunner.Step.t()} | {:error, PtcRunner.Step.t()}
```

# `run_subagent`

```elixir
@spec run_subagent(struct() | pid(), PtcRunner.SubAgent.Definition.t(), keyword()) ::
  {{:ok, PtcRunner.Step.t()} | {:error, PtcRunner.Step.t()}, [map()]}
```

Run a multi-turn `PtcRunner.SubAgent` over an upstream runtime.

This is the first-class SubAgent↔upstream bridge. It owns **one**
`RunContext` spanning the entire multi-turn run (so the ledger, caps, and
discovery cache aggregate across all turns), derives the upstream `"call"`
tool + discovery hook from it, enriches the agent's tool map **before** prompt
generation so the capability is prompt-visible, and threads the runtime handle
into every turn so attach-time prelude `requires` validation runs fail-closed.
The SubAgent loop never opens a `RunContext`; this function does.

Returns `{result, records}` where `result` is the `SubAgent.run/2` result and
`records` are the drained upstream call records (mirrors
`run_lisp_with_records/3`).

## Options

All `SubAgent.run/2` opts are forwarded, plus:

  * the upstream context-limit keys (`:max_tool_calls`, `:max_catalog_ops`,
    `:call_timeout_ms`, `:max_response_bytes`, `:max_catalog_result_bytes`) —
    consumed to build the `RunContext`, not forwarded to `SubAgent.run`.
  * `:on_upstream_call` — optional `((args -> result) -> (args -> result))`
    decorator wrapping the upstream `"call"` fn, e.g. a server-side ledger
    that records attempts before dispatch. The mcp ledger lives here.
  * `:allow_call_override` — when `true`, a local `"call"` tool on the agent is
    kept instead of raising on the collision (tests/stubs only).

`:discovery_exec` and `:runtime` are bridge-owned; any caller-supplied values
for those keys are ignored.

The `agent` argument must be a `%PtcRunner.SubAgent.Definition{}` (as built by
`SubAgent.new/1`): the bridge merges the upstream `"call"` tool into the
agent's `.tools` map and re-enters the internal `PtcRunner.SubAgent.Runner.run/2`
rather than the public facade.

# `with_run_context`

```elixir
@spec with_run_context(struct() | pid(), keyword(), (struct() -&gt; term())) ::
  {term(), [map()]}
```

---

*Consult [api-reference.md](api-reference.md) for complete listing*
