Skip to content

fix(deps): update dependency subagents-pydantic-ai to >=0.2.12 - autoclosed - #189

Closed
renovate[bot] wants to merge 1 commit into
mainfrom
renovate/vstorm-co-packages
Closed

fix(deps): update dependency subagents-pydantic-ai to >=0.2.12 - autoclosed#189
renovate[bot] wants to merge 1 commit into
mainfrom
renovate/vstorm-co-packages

Conversation

@renovate

@renovate renovate Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

This PR contains the following updates:

Package Change Age Confidence
subagents-pydantic-ai (changelog) >=0.2.10>=0.2.12 age confidence

Release Notes

vstorm-co/subagents-pydantic-ai (subagents-pydantic-ai)

v0.2.12

Correctness, typing, and documentation pass over the whole library. Every public
entry point keeps its name and signature, so no import or call site changes.

Fixed
  • Task statuses leaked their enum member name to the model. TaskStatus is a
    str-mixin Enum, and Python 3.11 changed Enum.__format__ for mixin enums, so
    check_task reported Status: TaskStatus.WAITING_FOR_ANSWER on 3.11+ while the
    tool descriptions and docs promised waiting_for_answer. list_active_tasks and
    wait_tasks had the same leak. Statuses, priorities, and message types now render
    as their values on every supported Python.
  • Deferred tools and human approval could not work inside a subagent.
    except Exception around the run swallowed pydantic-ai's control-flow signals
    (CallDeferred, ApprovalRequired, SkipModelRequest, SkipToolValidation,
    SkipToolExecution) and turned them into a string result the parent read as a
    finished task. Those signals, UserError, and a shared UsageLimitExceeded now
    propagate. A background delegation cannot suspend at all, so it reports a failed
    status explaining to delegate with mode="sync" instead.
  • A failed delegation looked like a successful one. A crash returned
    "Error executing task: ..." as a normal tool result, so pydantic-ai's retry
    budget never engaged and the failure could be folded into a final answer. Failures
    now reach the parent as ModelRetry. See contain_errors and on_failure under
    Added.
  • Background tasks outlived their parent run. Nothing cancelled the
    asyncio.Task behind a background delegation when the run ended, so it kept
    executing against torn-down deps, and one blocked in ask_parent waited out the
    full timeout. SubAgentCapability now cancels its run's tasks in a wrap_run
    finalizer, and TaskManager.cancel_all() exposes the same thing to the toolset API.
  • Tasks were not isolated per run. One toolset instance is typically built per
    agent and shared by every run it serves, so any run could inspect, answer, steer,
    or cancel another run's task by id. Handles record parent_run_id and the tools
    refuse ids belonging to another run.
  • hard_cancel could overwrite a completed task's result. The guard was
    if not task.done(), which is still true while the task runs its finally, so a
    cancel arriving in that window replaced the real result with cancelled.
    TaskHandle.finish() makes the first terminal transition win.
  • The library wrote a private attribute onto the caller's deps object.
    deps._subagent_state = {...} raised AttributeError for a deps class declared
    frozen=True or slots=True, both of which SubAgentDepsProtocol allows. The
    state is a typed SubAgentState carried in a ContextVar instead. Reading a
    caller-injected deps._subagent_state still works.
  • Timestamps were naive local time. TaskHandle.created_at, started_at, and
    completed_at are timezone-aware UTC, so elapsed time and eviction order stay
    correct across a DST transition.
  • get_subagent_system_prompt(include_dual_mode=...) was accepted and ignored.
    It now appends DUAL_MODE_SYSTEM_PROMPT when asked. The default changed to
    False, so output is unchanged for callers that never passed it.
  • Steering could be spliced into the wrong place. Parent-to-child steering
    appended UserPromptParts directly into a graph node's request. It now goes
    through pydantic-ai's AgentRun.enqueue, so core places the parts and they can
    never land between a tool call and its return.
  • The retry driver had drifted from the loop it mirrors. Agent.run drains the
    wrapped event stream after the handler returns, unconditionally; the copy drained
    only when there was no handler, leaving stream wrappers unfinished for a handler
    that stopped reading early.
  • 409 Conflict and 425 Too Early were retried as transient. Both signal a request
    the server rejected on its merits, so replaying it unchanged is not expected to
    help.
  • A message-bus handler that raised was silently swallowed by a bare
    except Exception: pass. Failures are logged and delivery continues.
  • asyncio.get_event_loop() inside a coroutine (deprecated since 3.10) is now
    get_running_loop().
  • Cancelling a finished task reported "not found", inviting the model to conclude
    the work was lost. It now reports the task's status and points at check_task.
  • make typecheck-mypy was broken. The module = "tests.*" override never
    matched, because tests/ had no __init__.py and mypy named the modules
    test_toolset rather than tests.test_toolset; the target reported 583 errors the
    config intended to relax. It is green and runs in CI.
Added
  • contain_errors on create_subagent_toolset, SubAgentCapability, and
    SubAgentConfig. Defaults to True: an unexpected subagent crash becomes a
    ModelRetry for the parent, logged with its traceback, so one failed delegation
    cannot abort the run. Set False to let crashes propagate.
  • on_failure on SubAgentConfig. Returns a steering message to the parent as
    an ordinary tool result instead of raising ModelRetry, for a failure where
    re-delegating is pointless.
  • ask_timeout_seconds on create_subagent_toolset and SubAgentCapability,
    replacing a hardcoded 300-second wait in ask_parent.
  • SubAgentToolset is a real class. It was an alias for
    create_subagent_toolset, whose result had task_manager,
    message_history_store, and get_total_usage attached afterwards behind three
    type: ignore comments. It is now a FunctionToolset subclass with those as typed
    members, and create_subagent_toolset() returns an instance —
    SubAgentToolset(subagents=[...]), toolset.task_manager, and
    isinstance(t, FunctionToolset) all keep working.
  • TaskHandle.finish() and TaskHandle.is_finished for idempotent terminal
    transitions, plus TERMINAL_STATUSES and utcnow as exports.
  • TaskManager.cancel_all() and TaskManager.resolve_answer().
  • SubAgentToolset.answer_task() and SubAgentToolset.steer_task() — the
    Python halves of the answer_subagent and send_message_to_subagent tools, for
    an application that drives delegation itself instead of letting a model call the
    tools. Both return a bool rather than raising. The tools now delegate to them,
    so there is one implementation.
  • SubAgentSpec covers the whole serialisable config. It mirrored 11 keys, so a
    YAML-defined subagent could not set max_retries, any retry_* option,
    agent_kwargs, on_failure, or contain_errors — the loader silently ignored
    what it had no field for. It also validates now: max_retries cannot be negative,
    retry_backoff_multiplier cannot shrink the delay, and retry_max_delay cannot
    sit below retry_initial_delay (which pinned every retry to the cap instead of
    backing off). tests/test_spec.py fails if the config gains a serialisable key
    the spec cannot carry.
Removed
  • SubAgentDepsProtocol.subagents. The library never read it, so every
    application carried a dict for nothing. Dropping a requirement only widens what
    satisfies the protocol, so a deps class that still declares the field is
    unaffected.
Changed (breaking)
  • delegate requires a name. A one-shot specialist was labelled
    oneshot-{task_id}, which told an operator reading logs or a TaskHandle
    nothing about what the specialist was for. The caller now supplies the label
    (letters, numbers, hyphens, validated the same way as create_agent), and it
    becomes TaskHandle.subagent_name. Naming a one-shot still does not register it:
    it does not count toward max_agents, cannot be reached via task, and reports
    no chat trace. Any code or prompt that calls delegate must pass name.
Changed
  • SubAgentConfig enforces its required keys. name, description, and
    instructions were documented as required but optional to the type checker, and
    the library indexed them directly, so a config missing one raised KeyError mid
    delegation. Call sites are unchanged; both type checkers now catch it.
  • Typing bar raised to match pydantic-ai-harness. pyright runs in strict
    mode, src/ has no type: ignore, mypy strict covers tests as well as source, and
    ruff's complexity ceiling dropped from 30 to 15 with no per-function noqa.
    TaskHandle.usage is RunUsage | None, finish_reason is FinishReason | None,
    and TaskManager.handles is dict[str, TaskHandle].
  • ToolsetFactory returns a Sequence, so a factory annotated
    list[FunctionToolset[MyDeps]] satisfies it — list is invariant.
  • toolset.py split into focused modules (_execution, _observability,
    _chat_trace, _state), with the historical names still importable from
    subagents_pydantic_ai.toolset.
  • Documentation. New pages for observability,
    steering, chat traces,
    failure handling, and
    usage limits; API reference pages for the
    registry, message bus, retry, spec, and dynamic-agent helpers; a changelog page.
    Corrected the stale tool and feature tables on the index, the
    general_purpose_config parameter that never existed, and the nesting guide's
    claim that max_nesting_depth enforces a limit — it does not, the gate is what
    toolsets_factory hands the child. Snippets in docs/ and README.md are now
    checked for syntax and API drift by tests/test_docs.py.

v0.2.11

Compare Source

Added
  • Configurable delegation modes, including one-shot delegate (#​50). delegation_configuration on create_subagent_toolset and SubAgentCapability picks which delegation entry points the orchestrator sees, so an application exposes only the delegation behaviour it needs instead of every creation and execution option at once:

    • "default": task only
    • "persisted": create_agent + task
    • "persisted_and_oneshot": create_agent + task + delegate
    • "oneshot_only": delegate only

    "default" is the existing tool surface, so upgrading adds nothing to a deployed orchestrator. Async lifecycle tools (check_task, wait_tasks, answer_subagent, send_message_to_subagent, cancellation) remain available in every mode.

  • One-shot delegation via delegate. Builds an ephemeral specialist from instructions and runs its task in a single call, for ad-hoc work that does not deserve a named, reusable agent. A one-shot never enters the registry, never counts against max_agents, and cannot collide with a persisted agent's name. It also reports no Chat Trace ID and stores no history: task can never resolve an unregistered specialist, so the id would be unredeemable, and keeping its history would let a one-shot fan-out evict genuinely continuable conversations from the max_chat_traces LRU.

  • Dynamic specialists configurable from the subagent toolset. create_subagent_toolset and SubAgentCapability now take allowed_models, capabilities_map, default_agent_factory, and max_agents, previously reachable only through create_agent_factory_toolset. The shared validation and construction path lives in the new dynamic_agent.py, so both entry points enforce identical rules. Note that "persisted" and "persisted_and_oneshot" cannot be combined with create_agent_factory_toolset on one agent — both define a create_agent tool and pydantic-ai rejects duplicate tool names across toolsets. Pair "default" with the factory toolset over a shared registry when the parent also needs list_agents / remove_agent; see the dynamic-agents guide.

  • Configuration a mode cannot reach is rejected at construction. Hiding a tool also hides everything only that tool reads, so create_subagent_toolset and SubAgentCapability raise ValueError rather than silently dropping arguments that could never take effect: "oneshot_only" rejects subagents and registry (both reachable only through task), and "default" rejects allowed_models, capabilities_map, and default_agent_factory (read only by create_agent and delegate).

Fixed
  • can_ask_questions was a no-op for dynamically created agents. Agents built at runtime never received the ask_parent toolset that statically compiled subagents get, so a dynamic agent configured to ask its parent had no tool with which to do it. The toolset now injects ask_parent when executing a registry-backed or one-shot agent. A custom default_agent_factory must not attach its own ask_parent, or the tool name is duplicated at run time.
Changed
  • registry and default_agent_factory are precisely typed. registry is now DynamicAgentRegistry | None (was Any), since the toolset calls get_compiled, list_agents, exists, and register on it directly, and default_agent_factory uses the new public AgentFactory alias (was Any) across create_subagent_toolset, create_agent_factory_toolset, and SubAgentCapability. Runtime behaviour is unchanged, but a downstream type-checker may now flag a duck-typed registry object.

Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Enabled.

Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@coveralls

coveralls commented Jul 31, 2026

Copy link
Copy Markdown

Coverage Report for CI Build 30671013267

Coverage remained the same at 100.0%

Details

  • Coverage remained the same as the base build.
  • Patch coverage: No coverable lines changed in this PR.
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 6891
Covered Lines: 6891
Line Coverage: 100.0%
Coverage Strength: 1.0 hits per line

💛 - Coveralls

@renovate
renovate Bot force-pushed the renovate/vstorm-co-packages branch from 0a5d894 to 4ee7844 Compare July 31, 2026 22:47
@renovate renovate Bot changed the title fix(deps): update dependency subagents-pydantic-ai to >=0.2.11 fix(deps): update dependency subagents-pydantic-ai to >=0.2.12 Jul 31, 2026
@renovate renovate Bot changed the title fix(deps): update dependency subagents-pydantic-ai to >=0.2.12 fix(deps): update dependency subagents-pydantic-ai to >=0.2.12 - autoclosed Jul 31, 2026
@renovate renovate Bot closed this Jul 31, 2026
@renovate
renovate Bot deleted the renovate/vstorm-co-packages branch July 31, 2026 23:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant