Skip to content

v0.2.0rc2

Pre-release
Pre-release

Choose a tag to compare

@tcdent tcdent released this 10 Apr 18:43
· 11 commits to main since this release

Second release candidate for 0.2.0. Completes the async migration and
stabilizes the worker pool architecture.

Breaking Changes

Fully async database layer

  • configure_engine() and get_session() now require an async SQLAlchemy engine (AsyncEngine) and return AsyncSession
  • Database URLs must use async drivers (e.g. sqlite+aiosqlite://, postgresql+asyncpg://)
  • sqlalchemy[asyncio] is now a core dependency; aiosqlite added as dev dependency

Async activity query API

  • activity.list(), activity.detail(), and activity.count_active() are now async and accept AsyncSession
  • Activity handlers are now async (async def __call__)

Removed session parameter from activity mutations

  • activity.create(), activity.update(), activity.complete(), and activity.error() no longer accept a session parameter — the handler owns its own session lifecycle

Queue priority parameter

  • BaseQueueBackend.push() signature changed from high_priority: bool to priority: Priority | None
  • Affects Redis, Kafka, and any custom queue backend implementations

New Features

CLI entrypoint

  • New agentexec CLI command via [project.scripts]

Activity model create() classmethod

  • Activity.create() encapsulates record + initial log entry creation in one async call

Async engine disposal

  • dispose_engine() ensures the async engine's background threads exit cleanly on shutdown

Architecture Changes

Worker pool refactor

  • Workers now use the spawn multiprocessing start method with explicit context — no inherited state
  • StateEvent replaced with stdlib multiprocessing.Event — removes dependency on the state backend for shutdown coordination
  • Event handling and scheduling extracted into _EventHandler and _Scheduler classes
  • Worker processes are now daemonic with SIGINT ignored — clean shutdown driven by the event
  • pool.start() handles CancelledError directly for Ctrl+C shutdown

Logging overhaul

  • Removed worker/logging.py and core/logging.py — all modules use stdlib logging.getLogger(__name__)
  • Spawned workers bootstrap a StreamHandler on the root logger so logs reach stderr
  • Pool messages use logger.info/logger.error instead of print()

Bug Fixes

  • Fixed crash when worker receives a task for an unregistered task name (now logs error and skips)
  • Failed tasks now log full tracebacks via logger.exception instead of logger.error
  • Kafka consumer handles None message values without crashing
  • ActivityUpdated.status is now Status enum instead of raw string
  • raise e instead of bare raise in task execution for clearer tracebacks

Improvements

  • Dependency groups use PEP 735 [dependency-groups] instead of [tool.uv]
  • Ruff line-length increased to 110
  • Removed verbose docstring examples and redundant comments throughout activity models
  • selectinload for eager loading of activity logs in get_by_agent_id
  • Redis backend adds type: ignore annotations for redis-py async stubs