Skip to content

Tool invocation

A tool call goes through three stages: the model emits a toolCalls[] entry, the oracle dispatches it via IToolDelegate, and the result is fed back as another assistant turn.

The dispatch path

LLM:               returns InferResponse { toolCalls: [{ id, name, arguments }] }


oracle:            for each call, find the matching MatrixToolProjection (by name)


IToolDelegate:     buildTools(runId) returned a NativeToolDef whose handler does:
   │                 RequestReply.execute(ctx, projection.target, projection.op, args)


ISecurityDelegate: isInSubtree(target) && isCommandAllowed(op) ? proceed : reject


bus:               actor at `target` runs the op, returns a result


OracleSink:        records start/end times, emits 'tool.call' and 'tool.result' frames


oracle:            packages the result into a tool message and runs another inference turn

Native tool oracle

The actual loop driver is nativeToolOracle in @open-matrix/inference (packages/oracle/piai/src/nativeToolOracle.ts). It uses native tool calling on whichever provider is configured. executeActorOracle (oracle/executeActorOracle.ts) wraps it with:

  • The system prompt assembly.
  • Tool wrapping (defaultWrapToolsWithSink in oracle/executeActorOracle.ts) that decorates each tool with sink callbacks.
  • Cancellation via OracleCallbacks.checkCancelled.
  • Inference metering via OracleCallbacks.recordInferenceCall.

Calls into Matrix actors: McpBridgeActor

For the actor-edit and repo-coding contexts that ship a matrix_invoke tool, the implementation routes through McpBridgeActor mounted at system.tools.mcpBridge (tools/McpBridgeActor.ts). The bridge:

  1. Receives tool.invoke with { target, op, payload }.
  2. Validates the call against the active permission set.
  3. Calls RequestReply.execute(ctx, target, op, payload) from a privileged context.
  4. Returns the result with timing/error metadata.

This indirection is what makes a single matrix_invoke tool generic across all actors — the LLM picks the target/op at runtime instead of needing a tool per (target, op) pair.

Calls in situated workers

For Claude Code or Codex workers, the projection works in reverse: configureWorkerToolProjection (runtime/configureWorkerTools.ts) registers the Matrix tools on the worker SDK's native tool surface. When the worker calls them, the worker's own tool runner sends the call back through system.tools.mcpBridge so the same security/audit path applies.

Timing and timeouts

AgentActor honours four timeout knobs (AgentActorProps):

  • toolTimeoutMs — per-tool-call cap (default 15s).
  • introspectTimeoutMs — for $introspect calls.
  • inferTimeoutMs — per-inference-call cap.
  • promptTimeoutMs — total time for one $prompt.

Every timeout fails with the corresponding MX_AGENT_ERRORS code rather than crashing the loop.

See also

Source: projects/matrix-3/packages/agents/src/oracle/executeActorOracle.ts, projects/matrix-3/packages/agents/src/tools/McpBridgeActor.ts, projects/matrix-3/packages/agents/src/runtime/configureWorkerTools.ts.