Raxol. AgentClientProtocol. MethodTable
(Raxol Agent Client Protocol v0.1.0)
Copy Markdown
View Source
Single source of truth for the ACP method vocabulary: every wire method
string, its direction, its JSON-RPC kind, the callback atom used for both
the behaviour @callback and the Router dispatch clause, its
param/result schema modules, its capability gate, and its layer.
The method set follows the pinned ACP JSON Schema schema-v1.19.0
(meta.json), not the f1729 reference implementation — f1729 has
session/fork/session/set_model (not in the pinned oracle) and lacks
session/delete/session/close/logout/$/cancel_request (which the
oracle has). The table is literal data in this module: the oracle copy at
priv/schema-oracle/v1/meta.json is a dev/test file in the repository, not
shipped in the package and not read at compile time; the package's test
suite checks the table against it.
What lives here vs. what doesn't
This module owns rows/0, rows/1, rows_for_side/1, capability_for/1,
the :capability column data, and the compile-time table invariants below
(incl. invariant 7 guarding the capability paths). The negotiated-caps
PREDICATE (Capabilities.negotiated?/2) and the Connection-side
pre-filter for layer: :protocol/:session_control rows are consumers of
this table, not implemented here.
Compile-time invariants (raise CompileError on violation)
{direction, wire}is unique across all rows.kind: :notificationimpliesresult == nil;kind: :requestimpliesresult != nil.callbackis unique per handling side (the set of callbacks visible torows_for_side(:agent)has no duplicates, ignoringnil; ditto:client) — the anti-name-drift invariant.layer in [:protocol, :session_control]if and only ifcallback == nil.ext == nilrows must not start with"_";ext == :raxolrows must start with"_raxol/"; a"$/"wire prefix is only allowed onlayer: :protocolrows.
A sixth check (every params/result module referenced must exist and
export from_json/1) runs in the package's test suite rather than at
compile time, to avoid compile-order knots between this module and the
Schema.* modules it references.
Summary
Types
How a row is capability-gated
Which side sends this row's wire method.
nil for the core v1.19.0 surface; :raxol for registered _raxol/* vendor rows.
JSON-RPC 2.0 shape: does this method get a reply?
:app — has an app-level @callback and Router dispatch clause.
:protocol — protocol-level ($/cancel_request); Connection pre-filters
before Router.decode/4 is ever called.
:session_control — app-shaped wire method, but Connection-routed with NO
app callback (currently only session/cancel).
Functions
The literal top-level field atoms of a side's capability struct (drift-guarded by invariant 7 + tests).
The capability gate for a wire method, normalized for
Raxol.AgentClientProtocol.Capabilities.negotiated?/2
Register a compile-time dependency on this table's SOURCE FILE into the calling module.
All table rows, in declaration order (agent methods, then client methods, then protocol methods).
Rows whose direction matches exactly.
Rows a given handling side must be able to decode/dispatch: :agent sees
everything sent :client_to_agent plus :both; :client sees everything
sent :agent_to_client plus :both.
Types
@type capability() :: nil | :never | {:agent | :client, [atom()]}
How a row is capability-gated:
nil— baseline method, always available (no capability gate).{:agent | :client, path}— a field path into the receiver's own negotiated capability struct (Schema.AgentTypes.AgentCapabilitiesfor:agent,Schema.ClientTypes.ClientCapabilitiesfor:client).Raxol.AgentClientProtocol.Capabilities.negotiated?/2walks the path; a truthy leaf ⇒ negotiated, anything else (missing field,nil,false) ⇒ NOT negotiated (fail closed). The path uses Elixir struct field atoms, not the JSON wire keys, because the snapshot resolved against is the decoded struct — see invariant 7 and the ORACLE-DIVERGENCE note below.:never— the oracle gates this method by a capability the ported Elixir capability structs cannot express, so it is unconditionally NOT negotiated (fail closed,-32601). No row currently uses it.
ORACLE-DIVERGENCE (schema-oracle v1.19.0 vs. ported f1729 structs)
The pinned oracle's capability tree is richer than the Elixir structs ported from the older f1729 snapshot; three oracle leaves that f1729 lacks are ported so their methods gate on a real path:
sessionCapabilities.{delete,close}— ported asSchema.AgentTypes.SessionDeleteCapabilities/SessionCloseCapabilitiesonto theSessionCapabilitiesstruct'sdelete/closefields.session/delete/session/closegate on{:agent, [:session_capabilities, :delete | :close]}.agentCapabilities.auth.logout— ported asSchema.AgentTypes.AgentAuthCapabilities/LogoutCapabilitiesonto theAgentCapabilitiesstruct'sauthfield.logoutgates on{:agent, [:auth, :logout]}.- JSON-key vs struct-field: paths name Elixir struct fields
(
[:session_capabilities, :list],[:file_system, :read_text_file], …), not oracle JSON keys ([:sessions, :list],[:fs, :read_text_file]), which resolve against neither the oracle JSON nor the struct; invariant 7 guards the first segment against drift.
@type direction() :: :client_to_agent | :agent_to_client | :both
Which side sends this row's wire method.
@type ext() :: nil | :raxol
nil for the core v1.19.0 surface; :raxol for registered _raxol/* vendor rows.
@type kind() :: :request | :notification
JSON-RPC 2.0 shape: does this method get a reply?
@type layer() :: :app | :protocol | :session_control
:app — has an app-level @callback and Router dispatch clause.
:protocol — protocol-level ($/cancel_request); Connection pre-filters
before Router.decode/4 is ever called.
:session_control — app-shaped wire method, but Connection-routed with NO
app callback (currently only session/cancel).
Functions
@spec cap_fields(:agent | :client) :: [atom()]
The literal top-level field atoms of a side's capability struct (drift-guarded by invariant 7 + tests).
The capability gate for a wire method, normalized for
Raxol.AgentClientProtocol.Capabilities.negotiated?/2:
:none— baseline method, always available (tablecapability: nil).:never— unrepresentable in the ported caps model; fail closed.{:agent | :client, path}— a field path into the receiver's own caps.:unknown_method—methodis not in the table (decode/4will-32601it; the caller MUST NOT treat this as a capability denial).
Register a compile-time dependency on this table's SOURCE FILE into the calling module.
Any module that expands rows/0 data into its own compiled output — the
Router decode/dispatch/result_marker clauses, the Agent/Client @callback
surface — MUST call this in its module body. A plain rows/0 call is only an
EXPORTS dependency (recompile when rows/0's API changes); a row-DATA edit does
not change that signature, so without this an incremental build leaves the
generated code stale (a new row present in the table but absent from
Router/Agent until a mix clean).
@external_resource forces the caller to recompile whenever this file changes.
@spec rows() :: [row()]
All table rows, in declaration order (agent methods, then client methods, then protocol methods).
Rows whose direction matches exactly.
@spec rows_for_side(:agent | :client) :: [row()]
Rows a given handling side must be able to decode/dispatch: :agent sees
everything sent :client_to_agent plus :both; :client sees everything
sent :agent_to_client plus :both.