OapiCodemode.Tools (oapi_codemode v0.2.0)

Copy Markdown View Source

Emits the two codemode tools as data plus handlers. Transport-agnostic: hosts wrap these into their own tool layers (gentility's CloudLoop.Tool, ele's UserMCP.Tool, or a gen_mcp server).

definitions/1 opts:

  • :registry (required) — the Registry server
  • :executor (required) — module implementing OapiCodemode.Executor
  • :resolver (required) — module implementing OapiCodemode.Credentials
  • :policy — :read_only (default) or :all
  • :max_result_tokens — default 6000
  • :max_calls — max intercepted request() calls per execute run, default 100; :infinity disables. Calls beyond the limit return an error payload to the sandbox; only the first refusal is logged, so the call log stays bounded even under an executor whose timeout is compute-only (ele P1; see Executor.SafeJS)
  • :timeout — sandbox timeout ms, default 30_000
  • :executor_opts — extra keyword opts forwarded verbatim to the executor's run/3 (e.g. [limits: %{max_memory: 256_000_000}] for Executor.ZapCode — spec globals cost well over their JSON size in the value-typed VM, so search over multi-MB specs needs more than zapcode's 64MB default). :timeout above is merged in unless already present here.
  • :search_tool_name — default "search_apis". Set a distinct name when a host emits per-API-instance tools.
  • :execute_tool_name — default "execute_api_code". A host that wants a separate mutating tool alongside the read-only one calls definitions/1 twice: once with the defaults (search + read-only execute), once with policy: :all, a distinct :execute_tool_name (e.g. "execute_api_mutations"), and include_search: false (search only needs to be offered once).
  • :include_search — default true. Set false to omit search_apis from the returned list (for the second call in the two-tool-variant pattern above).

I2: execute_api_code/execute_api_mutations are two separate tools with two separate names precisely so a host's tool-approval layer (e.g. ele's auto-approve-reads-but-confirm-writes policy) can gate on the name alone without inspecting arguments.

Handler contract: handler.(args, host_ctx) -> {:ok, json_string} | {:error, message}. host_ctx may carry :context (opaque identity for the credential resolver, never exposed to the sandbox), :api_allowlist (a list of registered API names this call may see and address — design §5 step 3, gentility's net_allowed_urls pattern; absent means all, [] means none; enforced at the request-dispatch boundary, with the sandbox globals filtered to match — but note the tool descriptions are built at definitions/1 time and are not allowlist-aware, so a host scoping per call should emit per-scope definitions if the description must not name the full set), :req_options (extra Req options, e.g. Req.Test plugs), and :annotate_call (a payload -> map() function run host-side on each intercepted call's response payload; its result is merged into that call's log entry, base keys winning). The annotator exists because the call log deliberately carries no response body: it is how a host records a host-observed classification of a response — e.g. "this 403 was a step-up refusal, not an ordinary denial" — somewhere sandbox code cannot forge or suppress. Per-API model-visible values belong in ApiConfig.sandbox_globals instead.

M6: the descriptions are a snapshot of registry state at the moment definitions/1 is called. A host that registers, re-registers, or unregisters an API afterwards must call definitions/1 again and re-emit the tools — otherwise the model is told about an API surface that no longer exists (the handlers themselves re-read the registry per call, so they stay correct; only the descriptions go stale).

Summary

Functions

Build the search_apis and execute_api_code tool definitions.

Functions

definitions(opts)

@spec definitions(keyword()) :: [
  %{
    name: String.t(),
    description: String.t(),
    input_schema: map(),
    handler: (map(), map() -> {:ok, String.t()} | {:error, String.t()})
  }
]

Build the search_apis and execute_api_code tool definitions.

See the moduledoc for the accepted opts and the handler contract.