The client's quickstart

The client, stalwart_agents.client, in five minutes. To build an agent instead, start with Build an agent.

Install the package, set your key, and activate the licensed runtime once:

pip install stalwart-agents
export QLS_API_KEY=qls_live_...
stalwart licence activate

The runtime reads each turn and checks each tool call on this machine. Where it cannot run, set QLS_ROUTER_URL to the enterprise qls-router you run in your own environment.

Route a conversation

from stalwart_agents.client import Client

client = Client()
version = client.register_catalogue(mcp_tools_list, agent="desk")
chat = client.session("desk", catalogue=version)
plan = chat.read("show me the stock in depot HB-7")
for step in plan.steps:
    if step.kind == "tool":
        print("call", step.selection.tool, dict(step.selection.arguments))
    elif step.kind == "ask":
        print("ask", step.selection.question)

Each step names the rule that made it in step.decided_by. A plan whose outcome is declined runs nothing.

Stream a long solve

for event in client.verify_guardrail("policy.co", "execute_transfer_funds", "is_authenticated",
                                     profile="enumerate", stream=True):
    print(event.type, event.data)

The iterator ends at the job's terminal event. A dropped connection is resumed where it stopped; if streaming keeps failing through your network, the iterator yields one stream_degraded event and carries on by polling.

Test your routing offline

from stalwart_agents.client.testing import replay

with Client(api_key="unused", router_url="https://qls-router.internal", transport=replay(cassette_path)) as offline:
    plan = offline.session("desk", catalogue=catalogue, session_id="s1").read("show me the stock")

Record the cassette once against your router, with stalwart_agents.client.testing.record(path) as the transport; a replay sends nothing, so any router URL does. A turn that was not recorded raises CassetteMiss; a catalogue that has moved since raises CassetteStale.