Skip to main content

A lightweight async framework for structuring and running AI agents in Python

Project description

pygents

A lightweight async framework for structuring and running AI agents in Python. Define tools, queue turns, stream results.

Install

pip install pygents

Requires Python 3.12+.

Example

import asyncio
from pygents import Agent, Turn, tool

@tool()
async def greet(name: str) -> str:
    return f"Hello, {name}!"

async def main():
    agent = Agent("greeter", "Greets people", [greet])
    # Use kwargs:
    await agent.put(Turn("greet", kwargs={"name": "World"}))
    # Or positional args:
    await agent.put(Turn("greet", args=["World"]))

    async for turn, value in agent.run():
        print(value)  # "Hello, World!"

asyncio.run(main())

Tools are async functions. Turns say which tool to run and with what args. Agents process a queue of turns and stream results. The loop exits when the queue is empty.

Features

  • Streaming — agents yield (turn, value) as results are produced
  • Inter-agent messaging — agents can send turns to each other
  • Dynamic arguments — callable positional args and kwargs evaluated at runtime
  • Timeouts — per-turn, default 60s
  • Per-tool locking — opt-in serialization for shared state (lock is acquired inside the tool wrapper, so turn-level hooks run outside the tool lock)
  • Fixed kwargs — decorator kwargs (e.g. @tool(permission="admin")) are merged into every invocation; call-time kwargs override
  • Hooks@hook(hook_type, lock=..., **fixed_kwargs) decorator; hooks stored as a list and selected by type; turn, agent, tool, and memory hooks; same fixed_kwargs and lock options as tools
  • Subtools@my_tool.subtool() and doc_tree() for hierarchical tool docs (name, description, recursive subtools)
  • Serializationto_dict() / from_dict() for turns and agents

Design Decisions

Agent/Turn hook boundaryTurnHook covers events fired by the Turn itself (BEFORE_RUN, AFTER_RUN, ON_TIMEOUT, ON_ERROR, ON_COMPLETE). AgentHook covers agent-loop events (BEFORE_TURN, AFTER_TURN, ON_TURN_VALUE, BEFORE_PUT, AFTER_PUT, ON_PAUSE, ON_RESUME). ON_TURN_VALUE stays on Agent because it fires after routing (agent logic). Turn-lifecycle hooks can be registered on an agent via agent.turn_hooks (or the @agent.on_error / @agent.on_timeout / @agent.on_complete decorators) and are automatically propagated to every turn the agent runs.

Hook attachment style — Hooks are attached via method decorators on the instance (@agent.before_turn, @turn.on_complete, @my_tool.before_invoke) rather than constructor parameters. This keeps the API surface explicit and enables IDE autocompletion of hook signatures.

Subtools — Subtools are normal registered tools (in ToolRegistry) that are also attached to a parent for hierarchical documentation. Use @my_tool.subtool() to register a subtool; use doc_tree() on any tool to get a recursive structure of name, description, and subtools (no runtime timing). Registry keys are scoped to the parent (e.g. manage_users.create_user) so different parents can have subtools with the same short name; use that scoped name in turns and lookups. Agents given a root tool accept turns for that tool and all its subtools.

Tool call arguments — Invoking a tool with extra positional or keyword arguments does not raise; only the parameters accepted by the tool function are forwarded. Missing required parameters still raise TypeError when the underlying function is called. This allows callers (e.g. agents or external systems) to pass a superset of arguments without errors.

Tool schemas from type hints — Every decorated tool automatically derives metadata.input_schema and metadata.output_schema from its type hints. Schemas are best-effort JSON-schema-like dicts for common Python typing constructs (primitives, optionals, lists, dictionaries, unions, async generators) and are intended for documentation, UI generation, and validation in higher-level systems. If your project uses Pydantic, any parameter or return type that is a Pydantic model class is detected via its model_json_schema() / schema() method and that model schema is used directly, without pygents depending on Pydantic itself.

Docs

Full documentation: uv run mkdocs serve. MkDocs is an optional dependency—install with pip install -e ".[docs]" (or use uv run as above) so the library itself does not depend on it.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pygents-0.6.7.tar.gz (24.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pygents-0.6.7-py3-none-any.whl (28.0 kB view details)

Uploaded Python 3

File details

Details for the file pygents-0.6.7.tar.gz.

File metadata

  • Download URL: pygents-0.6.7.tar.gz
  • Upload date:
  • Size: 24.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.25

File hashes

Hashes for pygents-0.6.7.tar.gz
Algorithm Hash digest
SHA256 31a852c06586901baf8abfac7dd759f35cd102b2a1f9c1666635e70a088d98b1
MD5 792a97f6724c26631ee3d0ad8eaaca05
BLAKE2b-256 ef97c59c45071f7d1c6aa44325fac4642895074be4b6cc7434d054a91230f4f7

See more details on using hashes here.

File details

Details for the file pygents-0.6.7-py3-none-any.whl.

File metadata

  • Download URL: pygents-0.6.7-py3-none-any.whl
  • Upload date:
  • Size: 28.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.25

File hashes

Hashes for pygents-0.6.7-py3-none-any.whl
Algorithm Hash digest
SHA256 2e7243f56db195b65aa4c7ea454d620b16fcd79c9146aedfe907b1b945a9b231
MD5 442aee4b622cc872b51c25c1aaa2267c
BLAKE2b-256 ae46c4b77f340dea90e4e9cb05b0466f70830440174241f3e8e64cfbf34d6175

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page