Agent Adapter Contract
Wendell runs your production agent through agent_command.
The command receives a JSON work item on stdin and must print a JSON response on stdout.
Input shape
The payload includes:
{
"schema_version": "wendell.agent_input.v1",
"task": "Respond as an agent in a Wendell remote runtime scenario.",
"scenario": {
"id": "playbook_workflow_1",
"title": "Evaluate refund request",
"customer_goal": "Request a refund that must follow policy."
},
"transcript": [],
"available_tools": [
{
"name": "orders.lookup",
"arguments": {"order_id": "str"},
"description": "Look up an order."
}
],
"case": {
"case_id": "case_123",
"request": "I need help with this refund."
},
"instruction": "Return JSON with `message`, `tool_calls`, and optional `metrics`."
}
Fields may grow over time. Adapters should ignore unknown fields.
Wendell does not send scoring rubrics, hidden facts, expected outcomes, source lineage, terminal outcomes, or success/failure criteria to the agent process. Those stay inside Wendell's evaluator.
Tool entries are also agent-facing only. They include the callable tool name, a description, and argument hints; Wendell does not expose internal workflow step ids, dependency lists, assertion ids, or rubric lineage through available_tools.
Output shape
Return a JSON object:
{
"message": "I can help with that refund. I need to look up the order first.",
"tool_calls": [
{
"name": "orders.lookup",
"args": {"order_id": "example"},
"result": {"found": true}
}
],
"metrics": {
"latency_ms": 1200
}
}
Required fields:
| Field | Type | Description |
|---|---|---|
message | string | Agent response text. |
tool_calls | array | Tool calls made by the agent. Use [] if none. |
Optional fields:
| Field | Type | Description |
|---|---|---|
metrics | object | Runtime metrics to attach to the turn. |
Production wiring pattern
wendell suites configure creates scripts/wendell_agent_adapter.py. Keep that
file as the Wendell boundary unless you need a custom wrapper. By default it
delegates to WENDELL_APP_AGENT_COMMAND:
export WENDELL_APP_AGENT_COMMAND="python scripts/run_my_agent.py"
python scripts/wendell_agent_adapter.py < sample-wendell-input.json
scripts/run_my_agent.py should call your real agent or agent service, then
map the real response and real tool actions into Wendell's JSON contract:
import json
import sys
def call_production_agent(payload: dict) -> dict:
raise NotImplementedError("Call your agent or agent service here.")
def main() -> None:
payload = json.load(sys.stdin)
agent_result = call_production_agent(payload)
response = {
"message": str(agent_result["message"]),
"tool_calls": [
{
"name": action["name"],
"args": action.get("args", {}),
"result": action.get("result"),
}
for action in agent_result.get("actions", [])
],
"metrics": agent_result.get("metrics", {}),
}
print(json.dumps(response))
if __name__ == "__main__":
main()
Do not replace this with a hard-coded passing adapter. A Wendell run is useful only when it exercises the same agent behavior you intend to ship.
agent_command and WENDELL_APP_AGENT_COMMAND are parsed like command-line
arguments and executed directly, without a shell. Use a simple executable plus
arguments, for example python scripts/run_my_agent.py --profile production.
Shell features such as pipes, redirects, &&, inline environment assignments,
and command substitution are intentionally unsupported. Put that logic in your
adapter script or in CI environment variables instead.
Local contract check
Before running a hosted suite, test the adapter boundary locally:
cat > sample-wendell-input.json <<'JSON'
{
"schema_version": "wendell.agent_input.v1",
"task": "Respond as an agent in a Wendell remote runtime scenario.",
"scenario": {
"id": "playbook_workflow_1",
"title": "Evaluate refund request",
"customer_goal": "Request a refund that must follow policy."
},
"available_tools": [
{
"name": "workflow_console.inspect_request",
"arguments": {"case_id": "str"},
"description": "Inspect the request."
}
],
"case": {"case_id": "case_123", "request": "I need help with this refund."}
}
JSON
WENDELL_APP_AGENT_COMMAND="python scripts/run_my_agent.py" \
python scripts/wendell_agent_adapter.py < sample-wendell-input.json
The command should print one JSON object with message and tool_calls.
Output-shape example
This example only shows the response JSON shape. Do not wire it into
wendell.toml; it does not call your production agent or exercise real tool
behavior.
import json
import sys
def main() -> None:
payload = json.load(sys.stdin)
scenario = payload.get("scenario", {})
customer_goal = scenario.get("customer_goal", "the request")
response = {
"message": f"I will handle {customer_goal} according to the approved Playbook.",
"tool_calls": [],
"metrics": {},
}
print(json.dumps(response))
if __name__ == "__main__":
main()
Failure behavior
If the command exits nonzero, Wendell records an agent error for the turn.
If stdout is not a JSON object, Wendell records the turn as an adapter contract
error with metrics.agent_error = true. Production adapters should always print
the JSON object above and send diagnostic logs to stderr, not stdout.
If tool_calls is missing, use [] in your adapter to keep behavior explicit.