Skip to main content

smooai-smooth-operator — the Python client for the smooth-operator protocol.

Smoo AI license lom.smoo.ai PyPI Python ≥ 3.11

smooai-smooth-operator — the native, fully-async Python client for the smooth-operator service.
Streaming agent turns, HITL resume, pydantic v2 models. One of five native SDKs over one schema-driven WebSocket protocol.


What is this?

The native async Python client for the smooth-operator WebSocket protocol. It connects to a running smooth-operator service (create a session, send a message, stream the agent's events back) — not the agent engine itself. The pydantic v2 models in smooth_operator._generated are generated from the language-neutral JSON Schemas in spec/ (and committed), using pydantic discriminated unions so events deserialize to the right concrete type. The wire is camelCase; you work in idiomatic snake_case.


30-second quickstart

uv add smooai-smooth-operator   # PyPI publish pending — install from the local path today

Until this package is published to PyPI, install it from a sibling checkout (uv add ../smooth-operator/python, or pip install -e path/to/smooth-operator/python). The PyPI distribution name is smooai-smooth-operator (the import package stays smooth_operator) — don't pip install smooth-operator from the public index until the SmooAI release lands.

import asyncio
from smooth_operator import SmoothAgentClient

async def main():
    client = SmoothAgentClient(url="ws://127.0.0.1:8787/ws")
    await client.connect()

    session = await client.create_conversation_session(agent_id=agent_id, user_name="Alice")

    turn = client.send_message(session_id=session.session_id, message="How long is your return window?")
    final = await turn                       # the terminal eventual_response
    print(final.data.payload.message_id)

asyncio.run(main())

(Point url at your own smooth-operator-server or the hosted endpoint.)


Watch it stream

send_message returns a turn you can async for over for live events and await for the authoritative terminal response.

turn = client.send_message(session_id=session.session_id, message="Where is my order?")

async for event in turn:
    if event.type == "stream_chunk":
        print(f"\n  ↳ node: {event.node}")          # workflow node boundary
    elif event.type == "stream_token":
        print(event.token, end="", flush=True)       # tokens, live
    elif event.type == "write_confirmation_required":
        # HITL: approve, and the resumed stream flows back into this same turn.
        await client.confirm_tool_action(
            session_id=session.session_id, request_id=turn.request_id, approved=True
        )

final = await turn                                    # the terminal eventual_response
print("\nmessageId:", final.data.payload.message_id)
%%{init: {'theme':'base','themeVariables':{'background':'#020618','primaryColor':'#0b1426','primaryTextColor':'#e6edf6','primaryBorderColor':'#2b3a52','lineColor':'#7c8aa0','actorBkg':'#0b1426','actorBorder':'#2b3a52','actorTextColor':'#e6edf6','signalColor':'#7c8aa0','signalTextColor':'#e6edf6','noteBkgColor':'#f49f0a','noteTextColor':'#1a0f00','noteBorderColor':'#ff6b6c','fontFamily':'ui-sans-serif, system-ui, sans-serif'}}}%%
sequenceDiagram
  participant App
  participant C as SmoothAgentClient
  participant S as Service
  App->>C: send_message(...)
  C->>S: { action: send_message }
  S-->>C: immediate_response (202)
  S-->>C: stream_token / stream_chunk …
  S-->>C: eventual_response (200)
  C-->>App: async-for yields events · await resolves final

camelCase wire, snake_case Python

The JSON wire form is camelCase (requestId, sessionId); the pydantic models use snake_case attributes with camelCase aliases and populate_by_name = True. So you construct/access with session.session_id, and model_dump(by_alias=True) emits the camelCase wire form.


Polyglot — one spec, five clients

%%{init: {'theme':'base','themeVariables':{'background':'#020618','primaryColor':'#0b1426','primaryTextColor':'#e6edf6','primaryBorderColor':'#2b3a52','lineColor':'#7c8aa0','secondaryColor':'#0b1426','tertiaryColor':'#0b1426','fontFamily':'ui-sans-serif, system-ui, sans-serif','clusterBkg':'#0b1426','clusterBorder':'#22304a'}}}%%
flowchart LR
  SPEC["spec/ (JSON Schema)"] --> PY["Python<br/>smooth_operator"]
  SPEC --> TS["TypeScript"]
  SPEC --> GO["Go"]
  SPEC --> NET[".NET (+ MEAI IChatClient facade)"]
  SPEC --> RS["Rust"]

Test-driven by default

Nothing here is vibe-coded — it's verified against a real LLM gateway.

%%{init: {'theme':'base','themeVariables':{'background':'#020618','primaryColor':'#0b1426','primaryTextColor':'#e6edf6','primaryBorderColor':'#2b3a52','lineColor':'#7c8aa0','secondaryColor':'#0b1426','tertiaryColor':'#0b1426','fontFamily':'ui-sans-serif, system-ui, sans-serif','clusterBkg':'#0b1426','clusterBorder':'#22304a'}}}%%
flowchart TD
  J["🎯 LLM-as-judge quality evals (Rust harness)"]
  E["🌐 Live cross-language E2E — this client boots the real server + drives a real claude-haiku-4-5 turn"]
  C["🧪 Conformance fixtures (shared across all 5 clients)"]
  U["⚡ Unit tests (discriminated-union parsing, alias round-trip, correlation)"]
  J --> E --> C --> U

26 tests. The live cross-language E2E boots a real smooth-operator-server subprocess (KB seeded) and drives a real claude-haiku-4-5 turn over WebSocket: ≥1 streamed event, a knowledge-grounded "17", per-session memory.

A real bug the live E2E caught (mocks masked it): agentId is UUID-typed in spec/, so pydantic rejected a bare string the lenient Go/TS clients accepted — surfacing a real cross-client string-vs-UUID alignment gap. A mock fixture using a valid UUID would have hidden it.

The proof story: an LLM-as-judge scored a multi-turn answer 1/5 (the runtime forgot turn 1's context); the failing eval drove a per-session-memory fix; it now scores 5/5 — a regression a substring test would have missed. See docs/EVALS.md.

Live tests are gated, never silently skipped — SMOOTH_AGENT_E2E=1 + SMOOAI_GATEWAY_KEY to run; skip cleanly otherwise.

uv run pytest                                          # no creds
SMOOTH_AGENT_E2E=1 uv run pytest -m e2e                # live cross-language E2E

Develop & regenerate

uv sync
uv run python -c "import smooth_operator"
uv run python scripts/generate.py    # regen pydantic models from ../spec via datamodel-code-generator

Smoo-powered or bring-your-own

Point url at the hosted lom.smoo.ai endpoint, or at your own self-hosted smooth-operator-server — same protocol, same client.

🧩 Part of Smoo AI

smooai-smooth-operator is built and open-sourced by Smoo AI — the AI-powered business platform with AI built into every product. It's the Python member of the polyglot SDK set (TypeScript · Python · Go · .NET · Rust) for the smooth-operator service.

  • 🌐 The service — smooth-operator (protocol, server, the five clients, AWS/k8s deploy)
  • 🧰 More open source from Smoo AI — smoo.ai/open-source
  • ☁️ Hosted — lom.smoo.ai runs smooth-operator for you, managed and multi-tenant

🔗 Links

📄 License

MIT © 2026 Smoo AI. See LICENSE.


Built by Smoo AI — AI built into every product.

Metadata

Release files for smooai-smooth-operator 1.40.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for smooai-smooth-operator 1.40.0
File Size Uploaded
smooai_smooth_operator-1.40.0.tar.gz 229.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for smooai-smooth-operator 1.40.0
File Interpreter ABI Platform
smooai_smooth_operator-1.40.0-py3-none-any.whl Python 3 none any Details

Total release size: 261.4 kB

Release files / smooai_smooth_operator-1.40.0.tar.gz

Download URL smooai_smooth_operator-1.40.0.tar.gz
Size 229.9 kB
Tags Source
SHA-256 checksum
How to use checksums
a5ad34a703a68bce120b605ade68601f69560e4a63aff3d02c22527c8147061b
BLAKE2b-256 checksum
How to use checksums
e504ed3e84f4fa453d61ff667173f272e84cfcd4dbf2c87d9db2a83534cfbe99
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.15

Release files / smooai_smooth_operator-1.40.0-py3-none-any.whl

Download URL smooai_smooth_operator-1.40.0-py3-none-any.whl
Size 31.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0a7a533f8a88a1b912e3959dd74c46cd5b1e71768d585d08726a73305935c2a8
BLAKE2b-256 checksum
How to use checksums
18d0807939868058b201111c78f03c968afe94ef6d85e65977e67ce11e42cda8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.15

Release history Release notifications | RSS feed

1.61.0

2 release files

1.60.0

2 release files

1.59.0

2 release files

1.58.9

2 release files

1.58.8

2 release files

1.58.7

2 release files

1.58.6

2 release files

1.58.5

2 release files

1.58.4

2 release files

1.58.3

2 release files

1.58.2

2 release files

1.58.1

2 release files

1.57.2

2 release files

1.57.1

2 release files

1.57.0

2 release files

1.56.7

2 release files

1.56.6

2 release files

1.56.5

2 release files

1.56.4

2 release files

1.56.3

2 release files

1.56.2

2 release files

1.56.1

2 release files

1.56.0

2 release files

1.55.2

2 release files

1.55.0

2 release files

1.54.3

2 release files

1.54.1

2 release files

1.54.0

2 release files

1.53.0

2 release files

1.52.3

2 release files

1.52.2

2 release files

1.52.1

2 release files

1.51.1

2 release files

1.50.3

2 release files

1.50.2

2 release files

1.49.1

2 release files

1.49.0

2 release files

1.48.0

2 release files

1.47.1

2 release files

1.47.0

2 release files

1.46.7

2 release files

1.46.6

2 release files

1.46.5

2 release files

1.46.4

2 release files

1.46.3

2 release files

1.46.1

2 release files

1.46.0

2 release files

1.45.3

2 release files

1.45.1

2 release files

1.45.0

2 release files

1.44.6

2 release files

1.44.5

2 release files

1.44.4

2 release files

1.44.3

2 release files

1.44.1

2 release files

1.44.0

2 release files

1.43.0

2 release files

1.42.0

2 release files

1.41.0

2 release files

This release

1.40.0 This release

2 release files

1.39.0

2 release files

1.36.9

2 release files

1.36.8

2 release files

1.36.7

2 release files

1.36.6

2 release files

1.36.2

2 release files

1.36.1

2 release files

1.36.0

2 release files

1.35.0

2 release files

1.34.0

2 release files

1.33.0

2 release files

1.32.1

2 release files

1.32.0

2 release files

1.30.0

2 release files

1.28.0

2 release files

1.27.2

2 release files

1.27.0

2 release files

1.26.0

2 release files

1.23.3

2 release files

1.23.2

2 release files

1.23.1

2 release files

1.23.0

2 release files

1.9.0

2 release files

1.8.0

2 release files

1.7.1

2 release files

1.7.0

2 release files

1.6.0

2 release files

1.4.0

2 release files

1.3.0

2 release files

1.2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page