PtcRunner.SubAgent.Exposure (PtcRunner v0.11.0)

Copy Markdown View Source

Pure helpers for tool exposure resolution and filtering.

Tier 1a of the text-mode + PTC compute-tool plan (Plans/text-mode-ptc-compute-tool.md).

Each tool may declare expose: :native | :ptc_lisp | :both. When the field is missing/nil, the resolved value depends on the agent's mode per the plan's "Tool Exposure Policy" table:

output:ptc_transport:default expose:
:textnot :tool_call (or nil):native
:text:tool_call (combined):native
:ptc_lispany:ptc_lisp

This module is intentionally side-effect-free: validation lives in PtcRunner.SubAgent.Validator; runtime wiring (LLM request build, Lisp analyzer inventory) is wired in Tier 2/3.

Summary

Types

Mode descriptor accepted by effective_expose/2 and filter_by_expose/3.

Functions

Resolve a tool's effective expose: value for the given agent mode.

Filter a tool collection to those whose effective expose: is in allowed_set.

Types

mode()

@type mode() :: {atom(), atom() | nil} | struct()

Mode descriptor accepted by effective_expose/2 and filter_by_expose/3.

Either:

  • {output, ptc_transport} tuple — output is :text | :ptc_lisp, ptc_transport is :content | :tool_call | nil.

  • A PtcRunner.SubAgent.Definition.t() struct (the :output and :ptc_transport fields are read).

Functions

effective_expose(tool, mode)

@spec effective_expose(PtcRunner.Tool.t(), mode()) :: PtcRunner.Tool.expose_layer()

Resolve a tool's effective expose: value for the given agent mode.

If the tool has an explicit expose:, returns it unchanged. Otherwise applies the per-mode default per "Tool Exposure Policy."

Examples

iex> tool = %PtcRunner.Tool{name: "x", expose: nil}
iex> PtcRunner.SubAgent.Exposure.effective_expose(tool, {:text, nil})
:native

iex> tool = %PtcRunner.Tool{name: "x", expose: nil}
iex> PtcRunner.SubAgent.Exposure.effective_expose(tool, {:text, :tool_call})
:native

iex> tool = %PtcRunner.Tool{name: "x", expose: nil}
iex> PtcRunner.SubAgent.Exposure.effective_expose(tool, {:ptc_lisp, :content})
:ptc_lisp

iex> tool = %PtcRunner.Tool{name: "x", expose: :both}
iex> PtcRunner.SubAgent.Exposure.effective_expose(tool, {:text, nil})
:both

filter_by_expose(tools, mode, allowed_set)

@spec filter_by_expose(
  [PtcRunner.Tool.t()] | %{optional(String.t()) => PtcRunner.Tool.t()},
  mode(),
  [
    PtcRunner.Tool.expose_layer()
  ]
) :: [PtcRunner.Tool.t()]

Filter a tool collection to those whose effective expose: is in allowed_set.

  • tools — list of PtcRunner.Tool structs OR a map of name => PtcRunner.Tool. The output preserves the input shape's iteration order (lists keep order; maps are converted to a list of tools sorted by tool name, since map iteration order in Elixir is not guaranteed).
  • allowed_set — list/MapSet of :native | :ptc_lisp | :both.

Returns a list of PtcRunner.Tool structs.

Examples

iex> a = %PtcRunner.Tool{name: "a", expose: :native}
iex> b = %PtcRunner.Tool{name: "b", expose: :both}
iex> c = %PtcRunner.Tool{name: "c", expose: :ptc_lisp}
iex> result = PtcRunner.SubAgent.Exposure.filter_by_expose(
...>   [a, b, c], {:text, :tool_call}, [:native, :both]
...> )
iex> Enum.map(result, & &1.name)
["a", "b"]