diff --git a/docs/specification.md b/docs/specification.md index 49693dfb8..3c71f6d15 100644 --- a/docs/specification.md +++ b/docs/specification.md @@ -309,6 +309,11 @@ The following standards are integrated into the architecture: agents resource type list [<REGEX>] agents resource type show <NAME> +agents provider add --config|-c <FILE> [--update] +agents provider remove [--yes|-y] <NAME> +agents provider list [--all] [--namespace|-n <NS>] +agents provider show <NAME> + agents resource add [(--description|-d) <DESC>] [--update] <TYPE> <NAME> [type-specific-flags...] agents resource remove [--yes|-y] <NAME> agents resource list [--all] [(--type|-t) <TYPE>] @@ -10562,6 +10567,72 @@ Show detailed information about a resource type, including its full schema. - "Resource type details loaded" ``` +#### agents provider + +**Purpose** +Manage LLM provider registrations. Providers encapsulate LLM SDK integrations and are referenced by actors via the `provider/model` notation. Commands in this group operate on provider definitions stored in YAML configuration files or discovered via entry points. + +##### agents provider add + +
agents provider add --config|-c <FILE> [--update]
+ +**Purpose** +Register or update a provider definition. The provider becomes available immediately for actor references (e.g., `local/my-provider/my-model`). + +**Arguments** + +- `--config/-c FILE`: Path to the provider YAML file (required). The file must declare the provider's `name`, implementation module/class, and any required environment variables. +- `--update`: If the provider already exists, replace the registration in place. Without this flag, attempting to register an existing provider fails. + +**Examples** + +=== "Rich" + +

+    $ agents provider add --config providers/my-custom-provider.yaml
+
+    ╭─ Provider Registered ─────────────────────────────╮
+    │ Name: local/my-llm-provider                    │
+    │ Module: my_package.providers.my_llm         │
+    │ Class: MyLLMProvider                        │
+    │ Models: my-model-v1, my-model-v2            │
+    ╰────────────────────────────────────────────────────╯
+
+    ✓ OK Provider local/my-llm-provider registered
+    
+ +=== "Plain" + + ``` + $ agents provider add --config providers/my-custom-provider.yaml + + Provider Registered + Name: local/my-llm-provider + Module: my_package.providers.my_llm + Class: MyLLMProvider + Models: my-model-v1, my-model-v2 + + [OK] Provider local/my-llm-provider registered + ``` + +##### agents provider list + +
agents provider list [--all] [(--namespace|-n) <NS>]
+ +List registered providers. By default only user-defined providers are shown; pass `--all` to include built-ins. `--namespace` filters by namespace prefix. + +##### agents provider show + +
agents provider show <NAME>
+ +Display the full provider definition, including environment requirements and supported models. + +##### agents provider remove + +
agents provider remove [--yes|-y] <NAME>
+ +Remove a provider registration. Built-in providers cannot be removed. + #### agents resource !!! info "Purpose" @@ -18561,6 +18632,8 @@ A plan's ==phase== indicates "what step of the lifecycle it is in." Separately, | :---- | :-------: | :---------- | | `queued` | No | Waiting for compute/worker | | `processing` | No | Currently running | + | `awaiting_approval` | No | Paused pending human approval due to guard budget caps or automation profile thresholds | + | `blocked` | No | Guard violation or safety constraint prevented progress; requires user intervention or correction | | `errored` | Yes | Failed; includes error metadata | | `complete` | Yes | Finished successfully | | `cancelled` | Yes | User/system cancelled; safe terminal | @@ -18571,11 +18644,15 @@ A plan's ==phase== indicates "what step of the lifecycle it is in." Separately, | :---- | :-------: | :---------- | | `queued` | No | Waiting for compute/worker | | `processing` | No | Currently running — diff review, conflict resolution, validation | + | `awaiting_merge_resolution` | No | Merge conflicts detected; waiting for user to resolve sandbox conflicts | | `errored` | Yes | Failed; includes error metadata | | `applied` | Yes | ==Changes successfully committed== to real resources | | `constrained` | Yes | Cannot complete within current strategy's constraints; may trigger reversion to Strategize | | `cancelled` | Yes | User/system cancelled; safe terminal | +!!! note "Guard-driven states" + Plans enter `awaiting_approval` when budget-related guards pause execution and resume once the user approves additional budget. Plans enter `blocked` when a denylist or retry guard prevents a tool invocation; the user must cancel, correct, or adjust the automation profile before the plan can continue. During Apply, merge conflicts transition the plan to `awaiting_merge_resolution`; completing conflict resolution and re-running `agents plan apply` returns the plan to `processing`. + #### Plan Identity and Traceability Every plan should have: @@ -28823,10 +28900,12 @@ A `SafetyProfile` may also be attached directly to an `Action` (via the `safety_ | `require_human_approval` | boolean | `false` | Require human approval before each action step | When `true`, every action step pauses for explicit human approval before execution. | | `allowed_skill_categories` | list[string] | `[]` (all) | Skill categories permitted for execution | When non-empty, only skills in the listed categories may be used. Empty list means all categories are allowed. | | `max_cost_per_plan` | float \| null | `null` | Maximum cost in USD per plan execution | When set, the plan is paused or terminated if the cost limit is reached. `null` means no limit. Must be <= `max_total_cost` when both are set. | +| `max_tokens_per_plan` | int \| null | `null` | Maximum total LLM tokens per plan execution | When set, the plan pauses in `awaiting_approval` once the cumulative token usage would exceed the limit. | +| `max_wall_clock_seconds` | int \| null | `null` | Maximum wall-clock time allowed for the plan | When set, exceeding the limit pauses the plan in `awaiting_approval` until the user approves extending the budget. | | `max_total_cost` | float \| null | `null` | Maximum total cost in USD across all plans | When set, execution is paused or terminated if the aggregate cost limit is reached. `null` means no limit. | -| `max_retries_per_step` | integer | `3` | Maximum retry attempts per action step | Limits the number of retries for a single step before escalating to the user. Range: 0–100. | +| `max_retries_per_step` | integer | `3` | Maximum retry attempts per tool invocation | Limits retries for a single tool before escalating to the user. Range: 0–100. | -**Relationship to Automation Guards**: The `SafetyProfile.max_total_cost` field sets a **plan-level** budget cap (broad scope), while `AutomationGuard.max_total_cost` sets a **per-invocation** budget cap (narrow scope). These operate at different granularities and both may be active simultaneously — the tighter constraint takes precedence at any given point. +**Relationship to Automation Guards**: The `SafetyProfile` budget fields (`max_cost_per_plan`, `max_tokens_per_plan`, `max_wall_clock_seconds`) set **plan-level** caps. The `AutomationGuard` sub-model can further constrain individual tool invocations (per-invocation cost caps, tool allowlists/denylists, retry limits). Both layers may be active simultaneously — the tightest constraint in effect takes precedence at any moment. #### Automation Guard Sub-Model @@ -29283,8 +29362,8 @@ Guards are evaluated in strict priority order. The first guard that triggers cau - `max_tokens_per_plan` (tokens): Total tokens consumed would exceed the cap → same pause behavior. - `max_wall_clock_seconds` (seconds): Elapsed time since plan start would exceed the cap → plan paused. 3. **Tool call limits** — Checked per-actor per-invocation: - - `max_tool_calls_per_actor`: Total tool calls by this actor in this plan would exceed the limit → actor invocation rejected. - - `max_retries_per_tool`: Retry count for this specific tool in this plan would exceed the limit → tool invocation rejected, plan enters `blocked` state. + - `max_tool_calls_per_step`: Total tool calls by this actor in this plan would exceed the limit → actor invocation rejected. + - `max_retries_per_step`: Retry count for this specific tool in this plan would exceed the limit → tool invocation rejected, plan enters `blocked` state. #### GuardEnforcer Component @@ -29383,6 +29462,17 @@ class PlanEvent: The `A2aEventQueue` provides the publish/subscribe interface: ```python +from dataclasses import dataclass +from collections.abc import AsyncIterator + +@dataclass +class SubscriptionHandle: + """Active subscription returned by `subscribe`.""" + + id: str + iterator: AsyncIterator[PlanEvent] + + class A2aEventQueue: """In-process async event queue for plan lifecycle events.""" @@ -29394,19 +29484,21 @@ class A2aEventQueue: self, event_types: list[str] | None = None, # None = subscribe to all plan_id: str | None = None, # None = all plans - ) -> AsyncIterator[PlanEvent]: + ) -> SubscriptionHandle: """ - Subscribe to events. Returns an async iterator that yields events - matching the filter criteria. Caller must consume events promptly - to avoid backpressure. + Subscribe to events. Returns a SubscriptionHandle containing the + subscription ID and an async iterator that yields matching events. + Callers must consume events promptly to avoid backpressure. """ ... - async def unsubscribe(self, subscription_id: str) -> None: - """Cancel a subscription.""" + async def unsubscribe(self, subscription: SubscriptionHandle | str) -> None: + """Cancel a subscription by handle or subscription ID.""" ... ``` +`SubscriptionHandle` allows callers to manage long-lived subscriptions safely. The handle's `iterator` yields events, while the `id` is used when calling `unsubscribe()` or when storing subscriptions for later cancellation. + #### Local vs. Server Mode | Mode | Implementation | Persistence | @@ -47240,7 +47332,7 @@ provider: - MY_LLM_BASE_URL ``` -Register with: `agents actor add --config providers/my-custom-provider.yaml` +Register with: `agents provider add --config providers/my-custom-provider.yaml` ##### Actor YAML with Custom Provider