Skip to content
ModePot

Build an agent-backed bound operation

Download this guide as Markdown

Use this pattern when the application owns identifiers and exact operations, but a bounded semantic choice belongs to the agent. The example uses the keyless test model and a harmless local operation. Keyless does not mean dry-run: capability code executes for real. Never attach destructive or privileged operations to a test-model endpoint.

Install summonpot[serve] and save as agent_summary.py:

from typing import Literal
from pydantic import BaseModel, Field
from summonpot import AgentChoice, Exactly, FromRequest, Operation, Required, Summon
class SummaryRequest(BaseModel):
topic: str = Field(min_length=1, max_length=200)
class SummaryResponse(BaseModel):
summary: str
style: Literal["brief", "detailed"]
def build_summary(topic: str, style: Literal["brief", "detailed"]) -> SummaryResponse:
"""Build a deterministic local summary candidate."""
limit = 80 if style == "brief" else 240
return SummaryResponse(summary=topic[:limit], style=style)
summary_operation = Operation(
build_summary,
bind={"topic": FromRequest("topic"), "style": AgentChoice()},
output=SummaryResponse,
)
summon = Summon("summary-api")
@summon("/summarize")
def summarize(
request: SummaryRequest,
result=Required(summary_operation, calls=Exactly(1)),
) -> SummaryResponse:
"""Summarize the request topic and choose a brief or detailed style."""
...
if __name__ == "__main__":
summon.serve(host="127.0.0.1", port=8000)

Run the local server:

Terminal window
SUMMONPOT_MODEL=test python agent_summary.py

Call the public HTTP route from another terminal:

Terminal window
curl -i -X POST http://127.0.0.1:8000/summarize \
-H 'Content-Type: application/json' \
-d '{"topic":"A concise contract separates trusted request data from bounded choices."}'

The test model supplies placeholder agent output, not a useful semantic answer; the operation still runs. The response must validate as SummaryResponse, and Required means the operation must succeed before a successful final output. Do not treat the final text as proof that it reproduces the operation result: local schema validation constrains shape and types, not semantic provenance.

  • SummaryRequest validates caller input. FromRequest("topic") injects that validated topic; it is absent from the model-visible operation arguments.
  • AgentChoice() is the only model-controlled argument in this declaration. It grants a choice within the registered build_summary callable, not permission to select another function or trusted customer identity.
  • Required(..., calls=Exactly(1)) sets the mandatory operation and call bound. Runtime state enforces the bound; the prompt alone is not enforcement.
  • output=SummaryResponse validates operation output before it can count as a successful required call. The endpoint response is separately validated.

Operation outputs and valid-looking final responses do not imply authorization, atomicity, idempotency, exactly-once completion, or a causal link between returned text and operation result. Enforce access control in the operation; design retries and side effects explicitly.

  1. Do not make a customer ID an AgentChoice; bind trusted request fields and authorize them in application code.
  2. Do not expect keyless model output to exercise the semantic behavior of a real provider. This is a wiring check, not quality evaluation.
  3. Do not expose shell, raw database connections, arbitrary SQL, or broad service objects as capabilities.
  4. Do not assume a failed output validation undoes an operation that already had side effects.
  5. Do not switch to Operation(fn) with missing bindings to get a permissive fallback; unsupported explicit declarations fail at registration.

The runtime-enforced bound-operation slice supports the explicit FromRequest and direct AgentChoice binding vocabulary with compatible receiving types and exact output contracts. The no-model path is stricter and permits no unresolved AgentChoice. Bare callable dependencies remain on the legacy agent path. FromResult, FromContext, after, collection-backed choices, broader graph execution, and multi-operation deterministic compilation are planned/rejected for the current explicit runtime slice. See the reference and roadmap.

For exact model-free execution, use Build a model-free endpoint. For provider/runtime setup and HTTP errors, see Operations and troubleshooting.