Tool Execution
Sealing and running a tool call against a trajectory with seal_decision, exec_tool, and commit_step.
Overview
Tools aren't registered with a decorator. Each call goes through three plain functions from trajectory_ir.runtime: seal the decision, run the tool, then commit the result.
seal_decision()
Canonicalizes a planned tool call (RFC 8785 JCS), hashes it with SHA256, and writes a DECISION_SEAL to the trajectory's metadata log before anything runs.
def seal_decision(
trajectory: Trajectory,
payload: dict,
effect_class: EffectClass = EffectClass.PURE,
) -> str:Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
trajectory | Trajectory | required | The trajectory to write the seal to. |
payload | dict | required | The tool name and arguments being sealed. |
effect_class | EffectClass | PURE | Safety classification for the call. See EffectClass. |
Returns: the SHA256 hash of the canonicalized payload, this is the Node Identity for the decision.
exec_tool()
Runs a tool against a seal produced by seal_decision().
def exec_tool(
trajectory: Trajectory,
seal: str,
tool: Callable[..., Any],
*args: Any,
**kwargs: Any,
) -> Any:Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
trajectory | Trajectory | required | The trajectory the seal belongs to. |
seal | str | required | Node hash returned by seal_decision(). |
tool | Callable | required | The function to execute. |
*args / **kwargs | Arguments passed through to tool. |
Returns: whatever tool returns.
If the process is interrupted mid-call and effect_class was NON_IDEMPOTENT_WRITE, the seal is left dangling. resume() won't retry it on its own, the trajectory comes back BLOCKED_NEEDS_GATE until it's cleared manually.
commit_step()
Appends the tool's result to the trajectory log as an Observation node, closing out the seal from seal_decision().
def commit_step(
trajectory: Trajectory,
seal: str,
result: Any,
metadata: Optional[dict] = None,
) -> str:Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
trajectory | Trajectory | required | The trajectory to append to. |
seal | str | required | Node hash of the seal this result closes out. |
result | Any | required | The value to record as the observation. |
metadata | dict | None | None | Optional extra fields stored alongside the observation. |
Returns: the SHA256 hash of the appended Observation node.
Example
from trajectory_ir.runtime import seal_decision, exec_tool, commit_step
from trajectory_ir.effects import EffectClass
def send_email(to: str, body: str) -> str:
return f"Email sent to {to}"
seal = seal_decision(
traj,
payload={"tool": "send_email", "args": {"to": "a@example.com", "body": "hi"}},
effect_class=EffectClass.NON_IDEMPOTENT_WRITE,
)
result = exec_tool(traj, seal, send_email, "a@example.com", "hi")
commit_step(traj, seal, result)