agent-runtime-kit 0.3.0__tar.gz → 0.5.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/CHANGELOG.md +102 -0
  2. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/PKG-INFO +74 -13
  3. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/README.md +72 -12
  4. agent_runtime_kit-0.5.0/docs/api-stability.md +110 -0
  5. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/docs/capability-matrix.md +28 -2
  6. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/docs/providers.md +83 -6
  7. agent_runtime_kit-0.5.0/docs/quickstart.md +131 -0
  8. agent_runtime_kit-0.5.0/docs/task-control.md +61 -0
  9. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/pyproject.toml +6 -3
  10. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/src/agent_runtime_kit/__init__.py +42 -0
  11. agent_runtime_kit-0.5.0/src/agent_runtime_kit/_control.py +234 -0
  12. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/src/agent_runtime_kit/_errors.py +36 -0
  13. agent_runtime_kit-0.5.0/src/agent_runtime_kit/_kit.py +775 -0
  14. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/src/agent_runtime_kit/_runtime.py +53 -32
  15. agent_runtime_kit-0.5.0/src/agent_runtime_kit/_schema.py +380 -0
  16. agent_runtime_kit-0.5.0/src/agent_runtime_kit/_types.py +887 -0
  17. agent_runtime_kit-0.5.0/src/agent_runtime_kit/adapters/_common.py +478 -0
  18. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/src/agent_runtime_kit/adapters/antigravity.py +212 -90
  19. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/src/agent_runtime_kit/adapters/claude.py +154 -80
  20. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/src/agent_runtime_kit/adapters/codex.py +175 -77
  21. agent_runtime_kit-0.5.0/src/agent_runtime_kit/adapters/diagnostics.py +42 -0
  22. agent_runtime_kit-0.5.0/src/agent_runtime_kit/compatibility.py +100 -0
  23. agent_runtime_kit-0.5.0/src/agent_runtime_kit/readiness.py +128 -0
  24. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/src/agent_runtime_kit/registry.py +45 -2
  25. agent_runtime_kit-0.5.0/src/agent_runtime_kit/support.py +138 -0
  26. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/src/agent_runtime_kit/testing/fakes.py +54 -1
  27. agent_runtime_kit-0.5.0/tests/test_adapter_common.py +173 -0
  28. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/tests/test_adapter_protocol.py +13 -0
  29. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/tests/test_antigravity_adapter.py +177 -11
  30. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/tests/test_claude_adapter.py +192 -4
  31. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/tests/test_codex_adapter.py +202 -14
  32. agent_runtime_kit-0.5.0/tests/test_control.py +662 -0
  33. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/tests/test_core.py +170 -0
  34. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/tests/test_events.py +40 -0
  35. agent_runtime_kit-0.5.0/tests/test_kit.py +480 -0
  36. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/tests/test_live_smoke.py +5 -5
  37. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/tests/test_mestre_compatibility.py +4 -1
  38. agent_runtime_kit-0.5.0/tests/test_readiness.py +662 -0
  39. agent_runtime_kit-0.5.0/tests/test_schema.py +273 -0
  40. agent_runtime_kit-0.5.0/tests/test_support.py +282 -0
  41. agent_runtime_kit-0.3.0/docs/api-stability.md +0 -56
  42. agent_runtime_kit-0.3.0/docs/mestre-migration.md +0 -25
  43. agent_runtime_kit-0.3.0/docs/quickstart.md +0 -47
  44. agent_runtime_kit-0.3.0/src/agent_runtime_kit/_types.py +0 -408
  45. agent_runtime_kit-0.3.0/src/agent_runtime_kit/adapters/_common.py +0 -334
  46. agent_runtime_kit-0.3.0/src/agent_runtime_kit/adapters/diagnostics.py +0 -18
  47. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/.gitignore +0 -0
  48. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/LICENSE +0 -0
  49. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/docs/live-smoke.md +0 -0
  50. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/docs/sdk-evolution-agent-design.md +0 -0
  51. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/docs/sdk-evolution-agent.md +0 -0
  52. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/examples/__init__.py +0 -0
  53. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/examples/run_same_task.py +0 -0
  54. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/examples/sdk_evolution_agent/__init__.py +0 -0
  55. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/examples/sdk_evolution_agent/__main__.py +0 -0
  56. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/examples/sdk_evolution_agent/auth.py +0 -0
  57. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/examples/sdk_evolution_agent/behavior.py +0 -0
  58. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/examples/sdk_evolution_agent/cli.py +0 -0
  59. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/examples/sdk_evolution_agent/collectors.py +0 -0
  60. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/examples/sdk_evolution_agent/current_state.py +0 -0
  61. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/examples/sdk_evolution_agent/events.py +0 -0
  62. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/examples/sdk_evolution_agent/models.py +0 -0
  63. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/examples/sdk_evolution_agent/pr.py +0 -0
  64. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/examples/sdk_evolution_agent/release_notes.py +0 -0
  65. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/examples/sdk_evolution_agent/report.py +0 -0
  66. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/examples/sdk_evolution_agent/schemas.py +0 -0
  67. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/examples/sdk_evolution_agent/snapshots.py +0 -0
  68. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/examples/sdk_evolution_agent/stages.py +0 -0
  69. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/src/agent_runtime_kit/adapters/__init__.py +0 -0
  70. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/src/agent_runtime_kit/events.py +0 -0
  71. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/src/agent_runtime_kit/py.typed +0 -0
  72. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/src/agent_runtime_kit/testing/__init__.py +0 -0
  73. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/tests/test_optional_dependencies.py +0 -0
  74. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/tests/test_provider_diagnostics.py +0 -0
  75. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/tests/test_sdk_contract.py +0 -0
  76. {agent_runtime_kit-0.3.0 → agent_runtime_kit-0.5.0}/tests/test_sdk_evolution_agent.py +0 -0
@@ -5,6 +5,108 @@ All notable changes to this project are documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## 0.5.0 - 2026-07-11
9
+
10
+ ### Added
11
+
12
+ - Core JSON Schema validation via `jsonschema`, including construction-time
13
+ schema checks and `OutputSchemaError` for malformed definitions.
14
+ - `AgentResult.parsed_output_available` distinguishes a valid JSON `null` from
15
+ absent or rejected structured output.
16
+ - All built-in adapters and public fake runtimes now validate returned values
17
+ against `output_schema` locally, including textual JSON fallbacks.
18
+ - `AgentResult.is_success` provides one canonical success predicate.
19
+ - `TaskSupportReport`, `TaskSupportProvider`, and `validate_task()` provide
20
+ side-effect-free task preflight without adding a requirement to the
21
+ `AgentRuntime` protocol. Registry and `AgentKit` helpers preserve custom
22
+ runtime validation and capability-based fallback for older runtimes.
23
+ - `COMPATIBILITY_MANIFEST` records each built-in adapter's install extra,
24
+ import module, accepted SDK range, tested lockfile version, and runtime binary
25
+ versions such as `openai-codex-cli-bin`.
26
+ - `RuntimeReadiness`, `ReadinessStatus`, the optional
27
+ `RuntimeReadinessProvider`, and bounded async `check_readiness()` probes
28
+ distinguish `READY_TO_ATTEMPT`, `NOT_READY`, and `INDETERMINATE` without
29
+ running an agent task. Registry, `AgentKit`, and provider-diagnostics helpers
30
+ expose the same async checks.
31
+ - Absolute `AgentTask.deadline` values, `AgentKit.run(timeout=...)`, typed
32
+ `AgentTaskTimeoutError`, and `FinishReason.TIMED_OUT` provide bounded task
33
+ execution across provider startup and reused-process queueing.
34
+ - Built-in runtimes and `AgentKit.cancel()` now return immutable
35
+ `CancellationReceipt` values with explicit request dispositions; legacy
36
+ third-party `cancel()` methods returning `None` remain supported.
37
+
38
+ ### Changed
39
+
40
+ - BREAKING: built-in adapters no longer pin library-owned default model names.
41
+ Model selection now follows task field > legacy metadata > `default_model=`
42
+ constructor override > provider-native configuration. Provider-native calls
43
+ omit the model kwarg; results expose `model_source` and only report a model
44
+ value when known. Existing constructor overrides remain supported.
45
+ - Pydantic structured-output parsing now requests strict validation, so values
46
+ such as `"42"` no longer coerce into integer fields.
47
+ - BREAKING: task and value-object constructors now reject blank identities,
48
+ non-positive execution hints, invalid budgets, ambiguous session inputs,
49
+ duplicate MCP names, and conflicting tool filters.
50
+ - BREAKING: unknown `Usage` values, including cost, are `None` rather than zero;
51
+ an explicit provider-reported zero remains `0`/`0.0`.
52
+ - Capability declarations now distinguish budget, reasoning-effort, network,
53
+ tool-filter, and per-MCP-server environment support. Built-in `run()` methods
54
+ consume the same support report used by preflight, eliminating divergent
55
+ rejection paths.
56
+ - `availability()` is now strictly package-only and side-effect-free. Credential
57
+ and setup checks moved to async readiness probes: Codex uses the supported
58
+ account API with guaranteed cleanup, and Antigravity runs Google ADC discovery
59
+ off the event loop. Probe failures/timeouts are secret-safe and indeterminate.
60
+
61
+ ### Fixed
62
+
63
+ - `AgentKit.run(task=...)` now rejects every explicitly supplied per-field task
64
+ argument, including default-valued `sdk_executions=1` and empty tool lists,
65
+ instead of silently ignoring it.
66
+ - `ParsedResult[T]` clears an adapter's raw `parsed_output` when the adapter
67
+ reports failure, so the typed result surface never exposes unvalidated data.
68
+ - `AgentKit.aclose()` attempts to close every cached runtime before reraising
69
+ the first close error, preventing later resources from leaking.
70
+ - Permission- and budget-critical vendor options must now be explicit,
71
+ introspectable SDK parameters; opaque `**kwargs`, positional-only options,
72
+ and uninspectable callables fail closed.
73
+ - Configured model allow-lists, Antigravity MCP name syntax, disjoint
74
+ allow/deny lists, and Antigravity's legacy reasoning-effort alias are rejected
75
+ during static preflight instead of surfacing later or being silently ignored.
76
+ - A configured model allow-list now fails closed when model selection is
77
+ provider-native and therefore cannot be verified locally.
78
+ - Cancellation now binds to one active task generation, unregisters without a
79
+ cancellable lock window, emits at most one timeout/cancellation terminal, and
80
+ gives reusable provider-process teardown a bounded grace period under repeated
81
+ cancellation. Runtime instances stay quarantined from new work while detached
82
+ teardown remains pending.
83
+
84
+ ## 0.4.0 - 2026-07-02
85
+
86
+ ### Added
87
+
88
+ - `AgentKit`, a FastAPI-flavored hub over the registry: keyword-native
89
+ `await kit.run("claude", goal=..., permissions="strict", ...)` assembling
90
+ the frozen `AgentTask` internally (a prebuilt `task=` still passes through),
91
+ short aliases for the built-in kinds via the documented `KIND_ALIASES`
92
+ mapping, per-kind runtime caching closed by `aclose()`/`async with`,
93
+ `@kit.on(...)` sync/async event handlers that tee alongside a task's own
94
+ sink and can never break a run, and `@kit.runtime(...)` decorator
95
+ registration for third-party kinds.
96
+ - Typed structured output: `kit.run(..., output_type=SomeType)` derives the
97
+ wire schema from a dataclass/`TypedDict` (dependency-free, bounded subset,
98
+ fail-closed via the new `OutputTypeError`) or from a Pydantic-style model's
99
+ own `model_json_schema`, and validates `parsed_output` back into the type.
100
+ The result is `ParsedResult[T]` — a runtime-identical `AgentResult`
101
+ subclass with a typed `parsed` accessor; `AgentResult` itself stays
102
+ non-generic. Non-conforming payloads yield `finish_reason="failed"`, the
103
+ adapters' own structured-output convention.
104
+ - `PermissionProfile` accepts string literals for `mode`/`filesystem`
105
+ ("strict", "read-only", ...) and coerces them to real enum members at
106
+ construction; unknown values raise `ValueError` listing the vocabulary.
107
+ Previously a bare string silently matched none of the adapters' identity
108
+ checks and ran at the default posture.
109
+
8
110
  ## 0.3.0 - 2026-07-02
9
111
 
10
112
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent-runtime-kit
3
- Version: 0.3.0
3
+ Version: 0.5.0
4
4
  Summary: One typed runtime API for Claude, Codex, and Antigravity agent SDKs.
5
5
  Project-URL: Homepage, https://github.com/ebarti/agent-runtime-kit
6
6
  Project-URL: Repository, https://github.com/ebarti/agent-runtime-kit
@@ -18,6 +18,7 @@ Classifier: Programming Language :: Python :: 3.12
18
18
  Classifier: Programming Language :: Python :: 3.13
19
19
  Classifier: Typing :: Typed
20
20
  Requires-Python: >=3.10
21
+ Requires-Dist: jsonschema<5,>=4.18
21
22
  Provides-Extra: all
22
23
  Requires-Dist: claude-agent-sdk<0.3,>=0.2.87; extra == 'all'
23
24
  Requires-Dist: google-antigravity<0.2,>=0.1.2; extra == 'all'
@@ -46,7 +47,7 @@ capabilities visible.
46
47
  `agent-runtime-kit` is for Python developers who want to run coding-agent tasks
47
48
  through vendor runtimes without rewriting their application around each SDK. It
48
49
  normalizes the runtime boundary: task inputs, capability checks, event streams,
49
- tool audits, availability diagnostics, and typed results.
50
+ tool audits, package/readiness diagnostics, and typed results.
50
51
 
51
52
  The library keeps vendor differences visible. Claude, Codex, and Antigravity
52
53
  still expose different capabilities, permission models, setup requirements, and
@@ -55,7 +56,7 @@ shape instead of hiding them behind a lowest-common-denominator wrapper.
55
56
 
56
57
  The package is intentionally not a router, benchmark harness, queue, hosted
57
58
  service, or full agent framework. It is the reusable layer underneath those
58
- systems: task models, runtime capabilities, event sinks, availability
59
+ systems: task models, runtime capabilities, event sinks, package/readiness
59
60
  diagnostics, and adapters.
60
61
 
61
62
  ## Install
@@ -66,7 +67,7 @@ If you want all first-party runtimes available, install the `all` extra:
66
67
  pip install "agent-runtime-kit[all]"
67
68
  ```
68
69
 
69
- Install the dependency-free core when you only need the public models, fake
70
+ Install the vendor-SDK-free core when you only need the public models, fake
70
71
  runtime, registry, diagnostics types, or you plan to add provider SDKs later:
71
72
 
72
73
  ```bash
@@ -108,18 +109,53 @@ are added through optional extras.
108
109
 
109
110
  ## Real Providers
110
111
 
112
+ `AgentKit` is the keyword-native hub: it registers the built-in runtimes,
113
+ caches them per kind, and turns Python types into structured output.
114
+
115
+ ```python
116
+ import asyncio
117
+ from dataclasses import dataclass
118
+
119
+ from agent_runtime_kit import AgentKit, ReadinessStatus
120
+
121
+
122
+ @dataclass
123
+ class RepoSummary:
124
+ name: str
125
+ languages: list[str]
126
+
127
+
128
+ async def main() -> None:
129
+ async with AgentKit() as kit:
130
+ readiness = await kit.readiness_for("claude")
131
+ if readiness.status is ReadinessStatus.NOT_READY:
132
+ raise RuntimeError(readiness.message)
133
+ result = await kit.run(
134
+ "claude",
135
+ goal="Summarize this repository",
136
+ permissions="strict",
137
+ output_type=RepoSummary,
138
+ )
139
+ print(result.parsed.languages if result.parsed else result.error)
140
+
141
+
142
+ asyncio.run(main())
143
+ ```
144
+
145
+ Adapters also work standalone when you need vendor-specific configuration:
146
+
111
147
  ```python
112
148
  import asyncio
113
149
 
114
- from agent_runtime_kit import AgentTask
150
+ from agent_runtime_kit import AgentTask, ReadinessStatus, check_readiness
115
151
  from agent_runtime_kit.adapters import ClaudeAgentRuntime
116
152
 
117
153
 
118
154
  async def main() -> None:
119
155
  runtime = ClaudeAgentRuntime(default_model="claude-sonnet-4-6")
120
- diagnostic = runtime.availability()
121
- if not diagnostic.available:
122
- raise RuntimeError(diagnostic.message)
156
+ readiness = await check_readiness(runtime)
157
+ if readiness.status is ReadinessStatus.NOT_READY:
158
+ raise RuntimeError(readiness.message)
123
159
  result = await runtime.run(AgentTask(goal="Summarize this repository"))
124
160
  print(result.output)
125
161
 
@@ -138,10 +174,35 @@ a field (for example only Claude maps `budget_usd`; Codex and Antigravity reject
138
174
  it with a typed `UnsupportedTaskInputError`) the adapter raises rather than
139
175
  silently dropping it.
140
176
 
141
- `AgentResult` returns output, finish reason (see `FinishReason`), parsed
142
- structured output, usage, cost, session id, tool-call audits, and provider
143
- metadata. `artifacts` is a reserved field: no built-in runtime populates it yet,
144
- so it is always an empty tuple today.
177
+ Model selection follows one explicit precedence chain: `AgentTask.model`, then
178
+ legacy `metadata["model"]`, then an adapter's `default_model=` constructor
179
+ override, then the provider's native configuration/default. Adapters omit the
180
+ vendor model option at the final step rather than pinning a library-owned model.
181
+ Results record `metadata["model_source"]`; `metadata["model"]` appears only when
182
+ the kit knows the selected value.
183
+
184
+ Call `validate_task(runtime, task)` (or `kit.validate_task("codex", task)`) to
185
+ inspect every statically detectable incompatibility before dispatch. The
186
+ returned `TaskSupportReport` is side-effect-free and lists source fields such as
187
+ `budget_usd` and `permissions.network`; `run()` still fails closed on the first
188
+ issue. Third-party runtimes can opt into provider-specific checks with the
189
+ `TaskSupportProvider` protocol, while older `AgentRuntime` implementations
190
+ continue to work through capability-based fallback checks.
191
+
192
+ `availability()` is deliberately synchronous, side-effect-free, and package-only.
193
+ Use `await check_readiness(runtime)` (or `kit.readiness_for(...)`) for an explicit,
194
+ bounded credential/setup probe. `READY_TO_ATTEMPT` means setup was positively
195
+ detected, not that a future provider call is guaranteed to succeed;
196
+ `INDETERMINATE` lets callers decide whether to attempt provider-chain or local
197
+ login authentication. Probe failures and timeouts never include credential values.
198
+
199
+ `AgentResult` returns output, finish reason (see `FinishReason`), locally
200
+ validated structured output, usage, cost, session id, tool-call audits, and
201
+ provider metadata. `is_success` is true only for a natural, error-free
202
+ completion. Unknown usage and cost fields are `None`; reported zero remains
203
+ distinct. `parsed_output_available` distinguishes an absent payload from valid
204
+ JSON `null` (both use `parsed_output=None`). `artifacts` is a reserved field: no
205
+ built-in runtime populates it yet, so it is always an empty tuple today.
145
206
 
146
207
  ## Docs
147
208
 
@@ -150,5 +211,5 @@ so it is always an empty tuple today.
150
211
  - [Capability matrix](https://github.com/ebarti/agent-runtime-kit/blob/main/docs/capability-matrix.md)
151
212
  - [API stability](https://github.com/ebarti/agent-runtime-kit/blob/main/docs/api-stability.md)
152
213
  - [Live smoke tests](https://github.com/ebarti/agent-runtime-kit/blob/main/docs/live-smoke.md)
153
- - [Mestre migration notes](https://github.com/ebarti/agent-runtime-kit/blob/main/docs/mestre-migration.md)
214
+ - [Deadlines and cancellation](https://github.com/ebarti/agent-runtime-kit/blob/main/docs/task-control.md)
154
215
  - [SDK evolution agent](https://github.com/ebarti/agent-runtime-kit/blob/main/docs/sdk-evolution-agent.md)
@@ -14,7 +14,7 @@ capabilities visible.
14
14
  `agent-runtime-kit` is for Python developers who want to run coding-agent tasks
15
15
  through vendor runtimes without rewriting their application around each SDK. It
16
16
  normalizes the runtime boundary: task inputs, capability checks, event streams,
17
- tool audits, availability diagnostics, and typed results.
17
+ tool audits, package/readiness diagnostics, and typed results.
18
18
 
19
19
  The library keeps vendor differences visible. Claude, Codex, and Antigravity
20
20
  still expose different capabilities, permission models, setup requirements, and
@@ -23,7 +23,7 @@ shape instead of hiding them behind a lowest-common-denominator wrapper.
23
23
 
24
24
  The package is intentionally not a router, benchmark harness, queue, hosted
25
25
  service, or full agent framework. It is the reusable layer underneath those
26
- systems: task models, runtime capabilities, event sinks, availability
26
+ systems: task models, runtime capabilities, event sinks, package/readiness
27
27
  diagnostics, and adapters.
28
28
 
29
29
  ## Install
@@ -34,7 +34,7 @@ If you want all first-party runtimes available, install the `all` extra:
34
34
  pip install "agent-runtime-kit[all]"
35
35
  ```
36
36
 
37
- Install the dependency-free core when you only need the public models, fake
37
+ Install the vendor-SDK-free core when you only need the public models, fake
38
38
  runtime, registry, diagnostics types, or you plan to add provider SDKs later:
39
39
 
40
40
  ```bash
@@ -76,18 +76,53 @@ are added through optional extras.
76
76
 
77
77
  ## Real Providers
78
78
 
79
+ `AgentKit` is the keyword-native hub: it registers the built-in runtimes,
80
+ caches them per kind, and turns Python types into structured output.
81
+
82
+ ```python
83
+ import asyncio
84
+ from dataclasses import dataclass
85
+
86
+ from agent_runtime_kit import AgentKit, ReadinessStatus
87
+
88
+
89
+ @dataclass
90
+ class RepoSummary:
91
+ name: str
92
+ languages: list[str]
93
+
94
+
95
+ async def main() -> None:
96
+ async with AgentKit() as kit:
97
+ readiness = await kit.readiness_for("claude")
98
+ if readiness.status is ReadinessStatus.NOT_READY:
99
+ raise RuntimeError(readiness.message)
100
+ result = await kit.run(
101
+ "claude",
102
+ goal="Summarize this repository",
103
+ permissions="strict",
104
+ output_type=RepoSummary,
105
+ )
106
+ print(result.parsed.languages if result.parsed else result.error)
107
+
108
+
109
+ asyncio.run(main())
110
+ ```
111
+
112
+ Adapters also work standalone when you need vendor-specific configuration:
113
+
79
114
  ```python
80
115
  import asyncio
81
116
 
82
- from agent_runtime_kit import AgentTask
117
+ from agent_runtime_kit import AgentTask, ReadinessStatus, check_readiness
83
118
  from agent_runtime_kit.adapters import ClaudeAgentRuntime
84
119
 
85
120
 
86
121
  async def main() -> None:
87
122
  runtime = ClaudeAgentRuntime(default_model="claude-sonnet-4-6")
88
- diagnostic = runtime.availability()
89
- if not diagnostic.available:
90
- raise RuntimeError(diagnostic.message)
123
+ readiness = await check_readiness(runtime)
124
+ if readiness.status is ReadinessStatus.NOT_READY:
125
+ raise RuntimeError(readiness.message)
91
126
  result = await runtime.run(AgentTask(goal="Summarize this repository"))
92
127
  print(result.output)
93
128
 
@@ -106,10 +141,35 @@ a field (for example only Claude maps `budget_usd`; Codex and Antigravity reject
106
141
  it with a typed `UnsupportedTaskInputError`) the adapter raises rather than
107
142
  silently dropping it.
108
143
 
109
- `AgentResult` returns output, finish reason (see `FinishReason`), parsed
110
- structured output, usage, cost, session id, tool-call audits, and provider
111
- metadata. `artifacts` is a reserved field: no built-in runtime populates it yet,
112
- so it is always an empty tuple today.
144
+ Model selection follows one explicit precedence chain: `AgentTask.model`, then
145
+ legacy `metadata["model"]`, then an adapter's `default_model=` constructor
146
+ override, then the provider's native configuration/default. Adapters omit the
147
+ vendor model option at the final step rather than pinning a library-owned model.
148
+ Results record `metadata["model_source"]`; `metadata["model"]` appears only when
149
+ the kit knows the selected value.
150
+
151
+ Call `validate_task(runtime, task)` (or `kit.validate_task("codex", task)`) to
152
+ inspect every statically detectable incompatibility before dispatch. The
153
+ returned `TaskSupportReport` is side-effect-free and lists source fields such as
154
+ `budget_usd` and `permissions.network`; `run()` still fails closed on the first
155
+ issue. Third-party runtimes can opt into provider-specific checks with the
156
+ `TaskSupportProvider` protocol, while older `AgentRuntime` implementations
157
+ continue to work through capability-based fallback checks.
158
+
159
+ `availability()` is deliberately synchronous, side-effect-free, and package-only.
160
+ Use `await check_readiness(runtime)` (or `kit.readiness_for(...)`) for an explicit,
161
+ bounded credential/setup probe. `READY_TO_ATTEMPT` means setup was positively
162
+ detected, not that a future provider call is guaranteed to succeed;
163
+ `INDETERMINATE` lets callers decide whether to attempt provider-chain or local
164
+ login authentication. Probe failures and timeouts never include credential values.
165
+
166
+ `AgentResult` returns output, finish reason (see `FinishReason`), locally
167
+ validated structured output, usage, cost, session id, tool-call audits, and
168
+ provider metadata. `is_success` is true only for a natural, error-free
169
+ completion. Unknown usage and cost fields are `None`; reported zero remains
170
+ distinct. `parsed_output_available` distinguishes an absent payload from valid
171
+ JSON `null` (both use `parsed_output=None`). `artifacts` is a reserved field: no
172
+ built-in runtime populates it yet, so it is always an empty tuple today.
113
173
 
114
174
  ## Docs
115
175
 
@@ -118,5 +178,5 @@ so it is always an empty tuple today.
118
178
  - [Capability matrix](https://github.com/ebarti/agent-runtime-kit/blob/main/docs/capability-matrix.md)
119
179
  - [API stability](https://github.com/ebarti/agent-runtime-kit/blob/main/docs/api-stability.md)
120
180
  - [Live smoke tests](https://github.com/ebarti/agent-runtime-kit/blob/main/docs/live-smoke.md)
121
- - [Mestre migration notes](https://github.com/ebarti/agent-runtime-kit/blob/main/docs/mestre-migration.md)
181
+ - [Deadlines and cancellation](https://github.com/ebarti/agent-runtime-kit/blob/main/docs/task-control.md)
122
182
  - [SDK evolution agent](https://github.com/ebarti/agent-runtime-kit/blob/main/docs/sdk-evolution-agent.md)
@@ -0,0 +1,110 @@
1
+ # API stability & versioning
2
+
3
+ `agent-runtime-kit` is pre-1.0 (`0.x`) and follows semantic versioning with the
4
+ usual pre-1.0 caveat: **breaking changes may land in a minor release** (`0.N`)
5
+ while the API is being shaped toward 1.0. Patch releases (`0.N.P`) are additive
6
+ or bug-fix only.
7
+
8
+ ## Public API
9
+
10
+ The supported surface is exactly what `agent_runtime_kit.__all__` exports (and
11
+ the vendor adapters under `agent_runtime_kit.adapters`). Anything whose module or
12
+ name begins with an underscore (`agent_runtime_kit._types`,
13
+ `agent_runtime_kit._runtime`, etc.) is internal and may change without notice —
14
+ import the names from the top-level package instead.
15
+
16
+ `agent_runtime_kit.testing` is public and intended for downstream test suites
17
+ (fake runtimes and event sinks).
18
+
19
+ ## Compatibility guarantees within a 0.x line
20
+
21
+ - **Runtime kinds are open.** `AgentRuntimeKind.coerce` accepts namespaced
22
+ strings (e.g. `"x-myorg-agent"`), and the registry stores them, so a third
23
+ party can ship an adapter for a new runtime without forking the enum.
24
+ - **Every runtime exposes the async lifecycle** (`aclose`, `async with`) declared
25
+ by the `AgentRuntime` protocol. Stateless runtimes implement it as a no-op.
26
+ - **Cancellation receipts describe requests, not rollback.** Built-in runtimes
27
+ return an immutable `CancellationReceipt`; the protocol still permits `None`
28
+ for existing third-party runtimes, which `AgentKit` reports as
29
+ `LEGACY_UNCONFIRMED`. `AgentTask.deadline` is keyword-only and an expired task
30
+ raises `AgentTaskTimeoutError` with `FinishReason.TIMED_OUT` event semantics.
31
+ - **`finish_reason` values** come from `FinishReason`. The field is typed `str`
32
+ for forward-compatibility, so new reasons can be added without a type break;
33
+ compare against `FinishReason` members rather than bare literals.
34
+ - **Result/task mappings are read-only at the top level.** `AgentTask`/`AgentResult`
35
+ copy `Mapping` fields into read-only dicts at construction; in-place writes to
36
+ the mapping itself raise `TypeError`. The freeze is shallow — nested containers
37
+ are not copied or frozen — so treat the whole structure as immutable by
38
+ convention and compare by value. The wrappers remain plain `dict` subclasses,
39
+ so `dataclasses.asdict`, `pickle`, `copy.deepcopy`, and JSON serialization
40
+ keep working.
41
+ - **Constructors enforce domain invariants.** Goals and identifiers are
42
+ non-blank; execution hints are positive; counts and monetary values are
43
+ finite and non-negative; session start and resume inputs are mutually
44
+ exclusive; MCP server names and tool filters are unambiguous.
45
+ - **Unknown telemetry is not zero.** Every `Usage` field is nullable. `None`
46
+ means the provider did not report a value; `0` and `0.0` mean it explicitly
47
+ reported zero.
48
+ - **Unsupported inputs raise, they are not dropped.** An adapter that cannot honor
49
+ a task field raises `UnsupportedTaskInputError`; the one exception is
50
+ vendor-option drift, which is recorded in
51
+ `AgentResult.metadata["dropped_options"]` instead.
52
+ - **Task support can be inspected without dispatch.** `validate_task(runtime,
53
+ task)`, `RuntimeRegistry.validate_task_for(...)`, and `AgentKit.validate_task(...)`
54
+ return every statically detectable incompatibility as a `TaskSupportReport`.
55
+ `TaskSupportProvider` is an optional extension, not a new requirement on the
56
+ `AgentRuntime` protocol, so existing third-party runtimes retain structural
57
+ compatibility and use capability-based fallback checks.
58
+ - **Package availability and execution readiness are separate.** Synchronous
59
+ `availability()` is package-only and side-effect-free. The bounded async
60
+ `check_readiness()` helper uses the optional `RuntimeReadinessProvider`
61
+ extension without changing the `AgentRuntime` protocol. A third-party runtime
62
+ without the extension maps a missing package to `NOT_READY` and present
63
+ package to `INDETERMINATE`. `READY_TO_ATTEMPT` establishes only that known
64
+ setup signals are present; it is not a guarantee of future execution.
65
+ - **Providers own the default model.** With no task, legacy metadata, or
66
+ `default_model=` override, built-in adapters omit the SDK model option and let
67
+ the provider's supported configuration select it. The effective precedence is
68
+ task field, metadata alias, constructor override, provider-native. Result
69
+ metadata always records `model_source` and records `model` only when known.
70
+ A configured `supported_models` allow-list requires an explicit/verifiable
71
+ selection and fails closed on provider-native selection.
72
+ - **`AgentKit` is sugar, not a second API.** The hub assembles the same frozen
73
+ `AgentTask` and returns the same `AgentResult` the runtimes produce
74
+ (`ParsedResult` is a runtime-identical subclass adding only the typed
75
+ `parsed` accessor). Kind aliases are limited to the documented
76
+ `KIND_ALIASES` mapping; exact kind strings always work. `output_type=`
77
+ supports a bounded, documented subset of the typing system and raises
78
+ `OutputTypeError` on anything outside it (Pydantic-style models are used
79
+ through their own `model_json_schema`/`model_validate(strict=True)` when
80
+ present). Raw schemas are checked at construction and again at dispatch
81
+ because their nested values are only shallow-frozen. Every built-in adapter
82
+ validates returned structured values locally.
83
+ - **Structured-output presence is explicit.** `parsed_output_available` is true
84
+ for a validated payload, including JSON `null`. Existing non-null custom
85
+ runtime results opt in automatically; a custom runtime returning valid null
86
+ must set the flag explicitly.
87
+
88
+ ## Vendor SDK version policy
89
+
90
+ The vendor SDK extras are pinned with cautious upper bounds (e.g.
91
+ `claude-agent-sdk>=0.2.87,<0.3`) because those SDKs are themselves pre-1.0 and
92
+ have shipped breaking changes within a minor series. The bounds are raised
93
+ deliberately — after the contract tests and the SDK-evolution agent verify a new
94
+ version — rather than left unbounded. A weekly CI lane installs the latest vendor
95
+ SDKs *within the declared caps*, so drift inside an allowed range surfaces before
96
+ it reaches installed users; a release above a cap is by design invisible to that
97
+ lane until the cap is raised. A separate lane installs every direct dependency at
98
+ its declared floor so a stale minimum cannot sit undetected in the metadata.
99
+
100
+ `COMPATIBILITY_MANIFEST` is the machine-readable form of that policy. Each entry
101
+ records the install extra, import module, accepted SDK range, exact lockfile
102
+ version exercised by the repository, and any separately versioned runtime binary
103
+ (currently `openai-codex-cli-bin`). The manifest is tested against both
104
+ `pyproject.toml` and `uv.lock`; it is evidence of the committed test baseline,
105
+ not a claim that every version in the accepted range was exhaustively tested.
106
+
107
+ ## Deprecation
108
+
109
+ When a public name is slated for removal it will be kept working for at least one
110
+ minor release with a `DeprecationWarning` before it is dropped.
@@ -4,6 +4,7 @@
4
4
  |------------|------------------|------------------|------------------------|
5
5
  | Optional extra | `claude` | `codex` | `antigravity` |
6
6
  | Core import without extra | Yes | Yes | Yes |
7
+ | Model selection | Provider-native unless task/metadata/constructor overrides it | Provider-native unless task/metadata/constructor overrides it | Provider-native unless task/metadata/constructor overrides it |
7
8
  | Working directory | Yes | Yes | Yes |
8
9
  | Session resume | Yes | Yes | Yes |
9
10
  | Structured output | Native `output_format` when available | Native output schema / JSON parse fallback | Native response schema / JSON parse fallback |
@@ -11,15 +12,33 @@
11
12
  | Permission mapping | `permission_mode` | approval mode + sandbox | capabilities + policies |
12
13
  | Streaming output events | Yes — incremental `output.delta` while the SDK runs | No — a single `output.delta` at the end (non-streaming SDK) | Yes — from response chunks |
13
14
  | Tool audit events | Yes — streamed from message blocks | Yes — emitted from parsed `TurnResult` items after the turn | Yes — from tool chunks |
15
+ | Deadlines and cancellation | Absolute deadline + coroutine cancellation | Absolute deadline + coroutine cancellation | Absolute deadline + coroutine cancellation |
14
16
  | `vendor.turn` events | No | No | Yes — from thought/unknown chunks |
15
- | Missing package diagnostics | Yes (`AgentRuntimeUnavailableError`) | Yes (`AgentRuntimeUnavailableError`) | Yes (`AgentRuntimeUnavailableError`) |
16
- | Missing credential diagnostics | No — `availability()` reports available with an `auth_source` label; auth failures surface at `run()` | No — same as Claude (`auth_source` label; deferred) | Yes — `availability()` returns `MISSING_CREDENTIALS` when no API key / ADC-Vertex project is configured |
17
+ | Package availability | Sync, side-effect-free, package-only | Sync, side-effect-free, package-only | Sync, side-effect-free, package-only; never calls ADC |
18
+ | Async readiness | Direct API key/OAuth/Bedrock bearer signal → `READY_TO_ATTEMPT`; provider/local chains → `INDETERMINATE` | Supported `AsyncCodex.account(refresh_token=False)` probe; absent account → `NOT_READY` | API key or off-loop ADC/project probe; missing → `NOT_READY` |
19
+ | Probe failure/timeout | `INDETERMINATE` | `INDETERMINATE`, app-server always closed | `INDETERMINATE` |
17
20
  | Live smoke test | Opt-in | Opt-in | Opt-in |
18
21
 
19
22
  The matrix is intentionally not a lowest-common-denominator contract. Adapters
20
23
  reject unsupported inputs (see below) when silently dropping them would be
21
24
  misleading.
22
25
 
26
+ The public `AgentCapabilities` value also advertises the granular task controls
27
+ used by preflight: `budget`, `reasoning_effort`, `network_control`,
28
+ `tool_filters`, and `mcp_server_env`. Use `validate_task(runtime, task)` when a
29
+ concrete task is available; unlike a raw capability flag, its
30
+ `TaskSupportReport` preserves instance-specific rules such as a configured model
31
+ allow-list and reports all detectable issues at once.
32
+
33
+ For every provider, malformed schemas are rejected locally before dispatch and
34
+ returned structured values are validated locally after the SDK completes.
35
+ `parsed_output_available` distinguishes valid JSON `null` from no parsed value.
36
+
37
+ Deadlines cover provider startup and waits for a reused process. Cancellation
38
+ receipts acknowledge a request at the coroutine boundary; they do not imply
39
+ rollback of tool side effects that already completed. See
40
+ [Deadlines and cancellation](task-control.md).
41
+
23
42
  ## Permission mapping
24
43
 
25
44
  A single portable `PermissionMode` maps to each vendor's native controls. The
@@ -59,6 +78,13 @@ tool, uses the SDK's `disabled_tools` route).
59
78
  Each adapter raises `UnsupportedTaskInputError` for task fields it has no SDK
60
79
  surface to honor, rather than dropping them silently.
61
80
 
81
+ The same fields can be checked before dispatch through `validate_task`,
82
+ `RuntimeRegistry.validate_task_for`, or `AgentKit.validate_task`. Built-in
83
+ adapters additionally preflight configured model allow-lists. Antigravity also
84
+ checks its MCP server-name syntax and the SDK's prohibition on combining an
85
+ allow-list with a deny-list. SDK-version-dependent Antigravity tool vocabulary
86
+ is still validated at dispatch, after the installed SDK supplies its enum.
87
+
62
88
  | Field | Claude | Codex | Antigravity |
63
89
  |-------|--------|-------|-------------|
64
90
  | `budget_usd` | Mapped (`max_budget_usd`, fails closed under SDK drift) | Rejected | Rejected |