Skip to main content

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:

FieldTypeDescription
messagestringAgent response text.
tool_callsarrayTool calls made by the agent. Use [] if none.

Optional fields:

FieldTypeDescription
metricsobjectRuntime 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.