agentshim 0.14.0__tar.gz → 0.15.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 (88) hide show
  1. {agentshim-0.14.0 → agentshim-0.15.0}/CHANGELOG.md +72 -0
  2. agentshim-0.15.0/LICENSE +21 -0
  3. {agentshim-0.14.0 → agentshim-0.15.0}/PKG-INFO +7 -1
  4. {agentshim-0.14.0 → agentshim-0.15.0}/README.md +4 -0
  5. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/__init__.py +88 -1
  6. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/agent.py +14 -0
  7. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/core/__init__.py +45 -0
  8. agentshim-0.15.0/agentshim/core/checkpoints.py +67 -0
  9. agentshim-0.15.0/agentshim/core/clock.py +60 -0
  10. agentshim-0.15.0/agentshim/core/conversation.py +103 -0
  11. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/core/errors.py +77 -7
  12. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/core/events.py +23 -0
  13. agentshim-0.15.0/agentshim/core/ids.py +22 -0
  14. agentshim-0.15.0/agentshim/core/permissions.py +112 -0
  15. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/core/profile.py +26 -0
  16. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/core/schema.py +70 -26
  17. agentshim-0.15.0/agentshim/core/session_policy.py +604 -0
  18. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/core/turn.py +3 -0
  19. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/execution/__init__.py +21 -1
  20. agentshim-0.15.0/agentshim/execution/confinement.py +115 -0
  21. agentshim-0.15.0/agentshim/execution/docker.py +134 -0
  22. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/execution/executor.py +6 -0
  23. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/execution/host.py +142 -0
  24. agentshim-0.15.0/agentshim/execution/process.py +96 -0
  25. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/execution/transform.py +16 -0
  26. agentshim-0.15.0/agentshim/oneshot.py +194 -0
  27. agentshim-0.15.0/agentshim/providers/codex/app_server/__init__.py +49 -0
  28. agentshim-0.15.0/agentshim/providers/codex/app_server/_wire.py +351 -0
  29. agentshim-0.15.0/agentshim/providers/codex/app_server/protocol.py +5638 -0
  30. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/codex/provider.py +7 -0
  31. agentshim-0.15.0/agentshim/runtime.py +187 -0
  32. agentshim-0.15.0/agentshim/session.py +505 -0
  33. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/testing/__init__.py +60 -1
  34. agentshim-0.15.0/agentshim/testing/clock.py +52 -0
  35. agentshim-0.15.0/agentshim/testing/confinement.py +52 -0
  36. agentshim-0.15.0/agentshim/testing/contracts.py +428 -0
  37. agentshim-0.15.0/agentshim/testing/conversation.py +250 -0
  38. agentshim-0.15.0/agentshim/testing/process.py +198 -0
  39. {agentshim-0.14.0 → agentshim-0.15.0}/pyproject.toml +15 -1
  40. agentshim-0.15.0/tests/fixtures/codex_app_server/README.md +18 -0
  41. {agentshim-0.14.0 → agentshim-0.15.0}/.gitignore +0 -0
  42. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/core/_files.py +0 -0
  43. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/core/env.py +0 -0
  44. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/core/home.py +0 -0
  45. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/core/mcp.py +0 -0
  46. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/core/pricing.py +0 -0
  47. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/core/provider.py +0 -0
  48. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/core/skills.py +0 -0
  49. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/core/stream.py +0 -0
  50. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/core/usage.py +0 -0
  51. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/__init__.py +0 -0
  52. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/claude/__init__.py +0 -0
  53. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/claude/events.py +0 -0
  54. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/claude/failures.py +0 -0
  55. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/claude/hooks/__init__.py +0 -0
  56. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/claude/hooks/confine_reads.py +0 -0
  57. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/claude/parser.py +0 -0
  58. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/claude/provider.py +0 -0
  59. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/claude/sandbox.py +0 -0
  60. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/claude/scripted.py +0 -0
  61. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/claude/user_hooks.py +0 -0
  62. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/codex/__init__.py +0 -0
  63. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/codex/_toml.py +0 -0
  64. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/codex/events.py +0 -0
  65. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/codex/failures.py +0 -0
  66. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/codex/mcp_scope.py +0 -0
  67. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/codex/parser.py +0 -0
  68. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/codex/rules.py +0 -0
  69. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/codex/sandbox.py +0 -0
  70. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/codex/scripted.py +0 -0
  71. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/codex/skills.py +0 -0
  72. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/copilot/__init__.py +0 -0
  73. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/copilot/events.py +0 -0
  74. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/copilot/parser.py +0 -0
  75. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/copilot/provider.py +0 -0
  76. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/copilot/scripted.py +0 -0
  77. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/gemini/__init__.py +0 -0
  78. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/gemini/events.py +0 -0
  79. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/gemini/parser.py +0 -0
  80. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/gemini/provider.py +0 -0
  81. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/gemini/scripted.py +0 -0
  82. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/opencode/__init__.py +0 -0
  83. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/opencode/events.py +0 -0
  84. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/opencode/parser.py +0 -0
  85. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/opencode/provider.py +0 -0
  86. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/providers/opencode/scripted.py +0 -0
  87. {agentshim-0.14.0 → agentshim-0.15.0}/agentshim/py.typed +0 -0
  88. {agentshim-0.14.0 → agentshim-0.15.0}/tests/fixtures/codex/README.md +0 -0
@@ -1,5 +1,77 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.15.0 (2026-10-09)
4
+
5
+ ### Added
6
+
7
+ - Session tier. `Agent(provider, *, permissions, approvals, ...)` hands out
8
+ `Session`s: `prepare_turn(request, *, expect_conversation=None, pin=False) ->
9
+ TurnTicket` (the turn id exists before dispatch), `run(ticket, *, on_event=None)
10
+ -> Turn(result, continuity, turn_id, conversation_id)`, `interrupt()`,
11
+ `release()`, `adopt()`, `close()`. `Continuity` is `CONTINUED`, `RESET` or
12
+ `REPLACED`. Recovery is a pure `SessionPolicy` state machine: transient
13
+ retries on `RetryPolicy(delays)`, one fresh retry of a refused resume, a
14
+ backstop that forgets a resumed conversation after an unclassified failure,
15
+ renewal by `ProviderProfile.renewal` (`RenewalBudget`; Codex: 2 turns,
16
+ 10M input tokens or 600 s), idle release, and checkpoints through
17
+ `CheckpointStore` / `InMemoryCheckpointStore` / `Checkpoint`.
18
+ - Transport tier. `Transport.open(ConversationSpec) -> Conversation` with
19
+ `turn`, `interrupt`, `close`; `OneShotTransport` wraps the one-shot path
20
+ (bypass permissions only) and behaves exactly like `AgentSession`.
21
+ `CliAgent.derive(model=, event_handler=)` copies a checked agent.
22
+ - Errors: `TurnFailedError(kind, detail)` (now the base of `CliExitError`),
23
+ `TurnTimeoutError` (now the base of `CliTimeoutError`), `ContinuityError`,
24
+ `SessionStateError`, `TurnCancelledError`. Session code catches the base
25
+ types only.
26
+ - Events `TurnInterrupted` and `ApprovalDenied(kind, detail)`;
27
+ `TurnResult.interrupted` (default `False`).
28
+ - Test doubles `FakeTransport`, `FakeConversation`, `FakeTurn`,
29
+ `FakeCheckpointStore`, `fake_profile`, `turn_failed`, `resume_refused`,
30
+ `turn_timeout`, and contract suites `TransportContract`,
31
+ `ConversationContract`, `CheckpointStoreContract`.
32
+ - Docs: [sessions](https://vic-lsh.github.io/agentshim/sessions/).
33
+
34
+ ### Added (process layer)
35
+
36
+ - MIT license (`LICENSE`), declared in the package metadata.
37
+ - Long-lived processes: `CommandExecutor.spawn(SpawnRequest) -> Process` with a
38
+ pull-based output model (`StdoutLine`, `StderrLine`, `ProcessExited`),
39
+ implemented by `HostCommandExecutor` and `TransformingExecutor`.
40
+ `ProcessClosedError` reports a write to a closed or exited process.
41
+ - `Confinement` protocol, `confine(executor, confinement)` and
42
+ `DockerExecConfinement` (`docker exec` into a running container, with path
43
+ mapping and `reap()` of marked processes).
44
+ - `Clock`/`SystemClock`/`StopSignal` and `IdAllocator`/`RandomIds`.
45
+ - `NativeMode`, `NativePermissions`, `ApprovalPolicy` and
46
+ `ProviderProfile.native_permission_modes` (default `BYPASS` only).
47
+ - Test doubles `FakeProcess`, `FakePeer`, `EchoPeer`, `SilentPeer`,
48
+ `ReplayGates`, `GateMarker`, `FakeConfinement`, `FakeClock`, `SequentialIds`,
49
+ `FakeExecutor(peers=...)`, and contract suites `ProcessContract`,
50
+ `ConfinementContract`, `ClockContract` in `agentshim.testing.contracts`.
51
+ - Generated, typed Codex `app-server` protocol (`agentshim.providers.codex.app_server`):
52
+ frozen dataclasses for the requests, notifications, server requests and item
53
+ types a transport needs, tolerant `from_wire` for server messages, strict
54
+ `to_wire` for client messages, and `parse_server_message`. Regenerated from
55
+ the CLI's own JSON Schema by `scripts/generate_codex_protocol.py` (codex-cli
56
+ 0.160.0); not exported from the top-level package yet.
57
+
58
+ ### Fixed
59
+
60
+ - `DockerExecConfinement.reap()` raises the new `ReapError` unless the
61
+ container is gone or stopped, and the reap script fails when the container
62
+ lacks `tr`/`grep`, instead of reporting a clean sweep. `env` may not use the
63
+ reserved `AGENTSHIM_CONFINED` name.
64
+ - `Process.next_output(0)` on the host polls and returns already-queued output.
65
+
66
+ ## 0.14.1 (2026-10-04)
67
+
68
+ ### Fixed
69
+
70
+ - Schema normalization preserves descriptions, titles and examples, including
71
+ annotations alongside `$ref`, so structured-output field guidance reaches
72
+ the model. Only metadata rejected by the selected dialect is removed.
73
+ - The open schema dialect accepts `oneOf` variants, as Claude does.
74
+
3
75
  ## 0.14.0 (2026-10-04)
4
76
 
5
77
  Codex resumed turns report invocation usage. Additive.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Vic Shihang Li
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1,7 +1,9 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: agentshim
3
- Version: 0.14.0
3
+ Version: 0.15.0
4
4
  Summary: Provider-agnostic coding-agent CLI shims
5
+ License-Expression: MIT
6
+ License-File: LICENSE
5
7
  Requires-Python: >=3.10
6
8
  Requires-Dist: tomli>=2; python_full_version < '3.11'
7
9
  Provides-Extra: test
@@ -248,3 +250,7 @@ uv publish # release
248
250
 
249
251
  uv run --group docs mkdocs build --strict
250
252
  ```
253
+
254
+ ## License
255
+
256
+ MIT. See [LICENSE](LICENSE).
@@ -238,3 +238,7 @@ uv publish # release
238
238
 
239
239
  uv run --group docs mkdocs build --strict
240
240
  ```
241
+
242
+ ## License
243
+
244
+ MIT. See [LICENSE](LICENSE).
@@ -11,21 +11,32 @@ from .core import (
11
11
  AgentEvent,
12
12
  AgentEventHandler,
13
13
  AgentShimError,
14
+ ApprovalDenied,
15
+ ApprovalPolicy,
14
16
  ArgvContext,
15
17
  AssistantText,
18
+ Checkpoint,
19
+ CheckpointStore,
16
20
  CliCheckError,
17
21
  CliExitError,
18
22
  CliNotFoundError,
19
23
  CliTimeoutError,
24
+ Clock,
20
25
  CompositeEventHandler,
21
26
  ConfigFileInstallation,
22
27
  ConfigScope,
23
28
  ConsoleEventHandler,
24
29
  ContextualStreamParser,
30
+ Continuity,
31
+ ContinuityError,
32
+ Conversation,
33
+ ConversationSpec,
25
34
  EventHandlerBase,
26
35
  FailureKind,
27
36
  FlagsInstallation,
28
37
  HttpMcpServer,
38
+ IdAllocator,
39
+ InMemoryCheckpointStore,
29
40
  Lifecycle,
30
41
  McpConfigError,
31
42
  McpInstallation,
@@ -34,26 +45,37 @@ from .core import (
34
45
  McpServer,
35
46
  McpTransport,
36
47
  ModelPricing,
48
+ NativeMode,
49
+ NativePermissions,
37
50
  NoopInstallation,
38
51
  NullEventHandler,
39
52
  OutputSchema,
40
53
  OutputSchemaStyle,
41
54
  ParsedTurn,
42
55
  ParserContext,
56
+ PolicyConfig,
43
57
  PricingTable,
58
+ ProcessClosedError,
44
59
  Provider,
45
60
  ProviderCapabilityError,
46
61
  ProviderError,
47
62
  ProviderProfile,
48
63
  ProviderUsage,
64
+ RandomIds,
49
65
  RawOutput,
66
+ ReapError,
50
67
  Reasoning,
68
+ RenewalBudget,
69
+ RetryPolicy,
51
70
  RunFinished,
52
71
  RunStarted,
53
72
  SchemaDialect,
54
73
  SchemaDialectError,
74
+ SessionPolicy,
55
75
  SessionResumeError,
56
76
  SessionStarted,
77
+ SessionState,
78
+ SessionStateError,
57
79
  SkillInvoked,
58
80
  SkillScope,
59
81
  SkillsDiscovered,
@@ -62,14 +84,21 @@ from .core import (
62
84
  SkillTracker,
63
85
  Stderr,
64
86
  StdioMcpServer,
87
+ StopSignal,
65
88
  StreamParser,
89
+ SystemClock,
66
90
  TokenUsage,
67
91
  TokenWeights,
68
92
  ToolCall,
69
93
  ToolResult,
70
94
  ToolTracker,
95
+ Transport,
96
+ TurnCancelledError,
97
+ TurnFailedError,
98
+ TurnInterrupted,
71
99
  TurnRequest,
72
100
  TurnResult,
101
+ TurnTimeoutError,
73
102
  UsageReport,
74
103
  compact_json,
75
104
  compose_event_handlers,
@@ -92,27 +121,45 @@ from .execution import (
92
121
  CommandRequest,
93
122
  CommandResult,
94
123
  CommandStreamSink,
124
+ Confinement,
125
+ DockerExecConfinement,
95
126
  HostCommandExecutor,
127
+ HostProcess,
96
128
  NullSink,
129
+ Process,
130
+ ProcessExited,
131
+ ProcessOutput,
132
+ SpawnRequest,
133
+ StderrLine,
134
+ StdoutLine,
97
135
  TransformingExecutor,
136
+ confine,
98
137
  )
138
+ from .oneshot import OneShotTransport
99
139
  from .providers import get_provider, provider_names
100
140
  from .providers.claude import ClaudeHook, ClaudeProvider, SandboxConfig
101
141
  from .providers.codex import CodexProvider, CodexSandboxConfig
102
142
  from .providers.copilot import CopilotProvider
103
143
  from .providers.gemini import GeminiProvider
104
144
  from .providers.opencode import OpencodeProvider
145
+ from .runtime import Agent
146
+ from .session import Session, Turn, TurnTicket, map_mcp_servers
105
147
 
106
- __version__ = "0.14.0"
148
+ __version__ = "0.15.0"
107
149
 
108
150
  __all__ = [
151
+ "Agent",
109
152
  "AgentEvent",
110
153
  "AgentEventHandler",
111
154
  "AgentSession",
112
155
  "AgentShimError",
156
+ "ApprovalDenied",
157
+ "ApprovalPolicy",
113
158
  "ArgvContext",
114
159
  "AssistantText",
115
160
  "CallbackCommandStreamSink",
161
+ "Checkpoint",
162
+ "CheckpointStore",
116
163
  "ClaudeHook",
117
164
  "ClaudeProvider",
118
165
  "CliAgent",
@@ -120,6 +167,7 @@ __all__ = [
120
167
  "CliExitError",
121
168
  "CliNotFoundError",
122
169
  "CliTimeoutError",
170
+ "Clock",
123
171
  "CodexProvider",
124
172
  "CodexSandboxConfig",
125
173
  "CommandExecutor",
@@ -130,15 +178,24 @@ __all__ = [
130
178
  "CompositeEventHandler",
131
179
  "ConfigFileInstallation",
132
180
  "ConfigScope",
181
+ "Confinement",
133
182
  "ConsoleEventHandler",
134
183
  "ContextualStreamParser",
184
+ "Continuity",
185
+ "ContinuityError",
186
+ "Conversation",
187
+ "ConversationSpec",
135
188
  "CopilotProvider",
189
+ "DockerExecConfinement",
136
190
  "EventHandlerBase",
137
191
  "FailureKind",
138
192
  "FlagsInstallation",
139
193
  "GeminiProvider",
140
194
  "HostCommandExecutor",
195
+ "HostProcess",
141
196
  "HttpMcpServer",
197
+ "IdAllocator",
198
+ "InMemoryCheckpointStore",
142
199
  "Lifecycle",
143
200
  "McpConfigError",
144
201
  "McpInstallation",
@@ -147,56 +204,86 @@ __all__ = [
147
204
  "McpServer",
148
205
  "McpTransport",
149
206
  "ModelPricing",
207
+ "NativeMode",
208
+ "NativePermissions",
150
209
  "NoopInstallation",
151
210
  "NullEventHandler",
152
211
  "NullSink",
212
+ "OneShotTransport",
153
213
  "OpencodeProvider",
154
214
  "OutputSchema",
155
215
  "OutputSchemaStyle",
156
216
  "ParsedTurn",
157
217
  "ParserContext",
218
+ "PolicyConfig",
158
219
  "PricingTable",
220
+ "Process",
221
+ "ProcessClosedError",
222
+ "ProcessExited",
223
+ "ProcessOutput",
159
224
  "Provider",
160
225
  "ProviderCapabilityError",
161
226
  "ProviderError",
162
227
  "ProviderProfile",
163
228
  "ProviderUsage",
229
+ "RandomIds",
164
230
  "RawOutput",
231
+ "ReapError",
165
232
  "Reasoning",
233
+ "RenewalBudget",
234
+ "RetryPolicy",
166
235
  "RunFinished",
167
236
  "RunStarted",
168
237
  "SandboxConfig",
169
238
  "SchemaDialect",
170
239
  "SchemaDialectError",
240
+ "Session",
241
+ "SessionPolicy",
171
242
  "SessionResumeError",
172
243
  "SessionStarted",
244
+ "SessionState",
245
+ "SessionStateError",
173
246
  "SkillInvoked",
174
247
  "SkillScope",
175
248
  "SkillSignal",
176
249
  "SkillSummary",
177
250
  "SkillTracker",
178
251
  "SkillsDiscovered",
252
+ "SpawnRequest",
179
253
  "Stderr",
254
+ "StderrLine",
180
255
  "StdioMcpServer",
256
+ "StdoutLine",
257
+ "StopSignal",
181
258
  "StreamParser",
259
+ "SystemClock",
182
260
  "TokenUsage",
183
261
  "TokenWeights",
184
262
  "ToolCall",
185
263
  "ToolResult",
186
264
  "ToolTracker",
187
265
  "TransformingExecutor",
266
+ "Transport",
267
+ "Turn",
268
+ "TurnCancelledError",
269
+ "TurnFailedError",
270
+ "TurnInterrupted",
188
271
  "TurnRequest",
189
272
  "TurnResult",
273
+ "TurnTicket",
274
+ "TurnTimeoutError",
190
275
  "UsageReport",
191
276
  "__version__",
192
277
  "compact_json",
193
278
  "compose_event_handlers",
279
+ "confine",
194
280
  "cost_usd",
195
281
  "default_pricing",
196
282
  "dialect_problems",
197
283
  "get_provider",
198
284
  "install_config_file",
199
285
  "interactive_env",
286
+ "map_mcp_servers",
200
287
  "materialize",
201
288
  "normalize",
202
289
  "normalized_usage",
@@ -7,6 +7,7 @@ neither of them has to know that agents exist.
7
7
 
8
8
  from __future__ import annotations
9
9
 
10
+ import copy
10
11
  import posixpath
11
12
  import threading
12
13
  import time
@@ -116,6 +117,19 @@ class CliAgent:
116
117
  self.executor.check_binary(self.binary_path, self.env, timeout=check_timeout)
117
118
  self.log(f"{self.profile.display_name} ready at {self.binary_path}")
118
119
 
120
+ def derive(self, *, model: str | None, event_handler: AgentEventHandler) -> CliAgent:
121
+ """Return a copy that uses *model* and reports events to *event_handler*.
122
+
123
+ The binary lookup and health check are not repeated: the copy shares
124
+ the executor, environment and resolved binary of this agent. That is
125
+ what lets one checked install serve many conversations, each with its
126
+ own event routing.
127
+ """
128
+ clone = copy.copy(self)
129
+ clone.model = model
130
+ clone.event_handler = event_handler
131
+ return clone
132
+
119
133
  def start_session( # noqa: PLR0913 - one keyword per independent session option
120
134
  self,
121
135
  *,
@@ -7,6 +7,9 @@ this package may not do.
7
7
 
8
8
  from __future__ import annotations
9
9
 
10
+ from .checkpoints import Checkpoint, CheckpointStore, InMemoryCheckpointStore
11
+ from .clock import Clock, StopSignal, SystemClock
12
+ from .conversation import Conversation, ConversationSpec, Transport
10
13
  from .env import interactive_env
11
14
  from .errors import (
12
15
  AgentShimError,
@@ -14,15 +17,23 @@ from .errors import (
14
17
  CliExitError,
15
18
  CliNotFoundError,
16
19
  CliTimeoutError,
20
+ ContinuityError,
17
21
  FailureKind,
18
22
  McpConfigError,
23
+ ProcessClosedError,
19
24
  ProviderCapabilityError,
25
+ ReapError,
20
26
  SchemaDialectError,
21
27
  SessionResumeError,
28
+ SessionStateError,
29
+ TurnCancelledError,
30
+ TurnFailedError,
31
+ TurnTimeoutError,
22
32
  )
23
33
  from .events import (
24
34
  AgentEvent,
25
35
  AgentEventHandler,
36
+ ApprovalDenied,
26
37
  AssistantText,
27
38
  CompositeEventHandler,
28
39
  ConsoleEventHandler,
@@ -40,10 +51,12 @@ from .events import (
40
51
  Stderr,
41
52
  ToolCall,
42
53
  ToolResult,
54
+ TurnInterrupted,
43
55
  UsageReport,
44
56
  compose_event_handlers,
45
57
  )
46
58
  from .home import prepare_config_home
59
+ from .ids import IdAllocator, RandomIds
47
60
  from .mcp import (
48
61
  ConfigFileInstallation,
49
62
  FlagsInstallation,
@@ -54,6 +67,7 @@ from .mcp import (
54
67
  StdioMcpServer,
55
68
  install_config_file,
56
69
  )
70
+ from .permissions import ApprovalPolicy, NativeMode, NativePermissions
57
71
  from .pricing import ModelPricing, PricingTable, cost_usd, default_pricing, price_for
58
72
  from .profile import (
59
73
  ConfigScope,
@@ -61,6 +75,7 @@ from .profile import (
61
75
  McpScope,
62
76
  OutputSchemaStyle,
63
77
  ProviderProfile,
78
+ RenewalBudget,
64
79
  SchemaDialect,
65
80
  SkillScope,
66
81
  SkillSignal,
@@ -75,6 +90,7 @@ from .provider import (
75
90
  StreamParser,
76
91
  )
77
92
  from .schema import compact_json, dialect_problems, materialize, normalize
93
+ from .session_policy import Continuity, PolicyConfig, RetryPolicy, SessionPolicy, SessionState
78
94
  from .skills import SkillSummary, SkillTracker
79
95
  from .stream import ToolTracker, parse_json_object
80
96
  from .turn import OutputSchema, TurnRequest, TurnResult
@@ -84,21 +100,32 @@ __all__ = [
84
100
  "AgentEvent",
85
101
  "AgentEventHandler",
86
102
  "AgentShimError",
103
+ "ApprovalDenied",
104
+ "ApprovalPolicy",
87
105
  "ArgvContext",
88
106
  "AssistantText",
107
+ "Checkpoint",
108
+ "CheckpointStore",
89
109
  "CliCheckError",
90
110
  "CliExitError",
91
111
  "CliNotFoundError",
92
112
  "CliTimeoutError",
113
+ "Clock",
93
114
  "CompositeEventHandler",
94
115
  "ConfigFileInstallation",
95
116
  "ConfigScope",
96
117
  "ConsoleEventHandler",
97
118
  "ContextualStreamParser",
119
+ "Continuity",
120
+ "ContinuityError",
121
+ "Conversation",
122
+ "ConversationSpec",
98
123
  "EventHandlerBase",
99
124
  "FailureKind",
100
125
  "FlagsInstallation",
101
126
  "HttpMcpServer",
127
+ "IdAllocator",
128
+ "InMemoryCheckpointStore",
102
129
  "Lifecycle",
103
130
  "McpConfigError",
104
131
  "McpInstallation",
@@ -107,26 +134,37 @@ __all__ = [
107
134
  "McpServer",
108
135
  "McpTransport",
109
136
  "ModelPricing",
137
+ "NativeMode",
138
+ "NativePermissions",
110
139
  "NoopInstallation",
111
140
  "NullEventHandler",
112
141
  "OutputSchema",
113
142
  "OutputSchemaStyle",
114
143
  "ParsedTurn",
115
144
  "ParserContext",
145
+ "PolicyConfig",
116
146
  "PricingTable",
147
+ "ProcessClosedError",
117
148
  "Provider",
118
149
  "ProviderCapabilityError",
119
150
  "ProviderError",
120
151
  "ProviderProfile",
121
152
  "ProviderUsage",
153
+ "RandomIds",
122
154
  "RawOutput",
155
+ "ReapError",
123
156
  "Reasoning",
157
+ "RenewalBudget",
158
+ "RetryPolicy",
124
159
  "RunFinished",
125
160
  "RunStarted",
126
161
  "SchemaDialect",
127
162
  "SchemaDialectError",
163
+ "SessionPolicy",
128
164
  "SessionResumeError",
129
165
  "SessionStarted",
166
+ "SessionState",
167
+ "SessionStateError",
130
168
  "SkillInvoked",
131
169
  "SkillScope",
132
170
  "SkillSignal",
@@ -135,14 +173,21 @@ __all__ = [
135
173
  "SkillsDiscovered",
136
174
  "Stderr",
137
175
  "StdioMcpServer",
176
+ "StopSignal",
138
177
  "StreamParser",
178
+ "SystemClock",
139
179
  "TokenUsage",
140
180
  "TokenWeights",
141
181
  "ToolCall",
142
182
  "ToolResult",
143
183
  "ToolTracker",
184
+ "Transport",
185
+ "TurnCancelledError",
186
+ "TurnFailedError",
187
+ "TurnInterrupted",
144
188
  "TurnRequest",
145
189
  "TurnResult",
190
+ "TurnTimeoutError",
146
191
  "UsageReport",
147
192
  "compact_json",
148
193
  "compose_event_handlers",
@@ -0,0 +1,67 @@
1
+ """Durable record of which provider conversation a session was in.
2
+
3
+ A checkpoint is what a restarted process needs to continue a conversation: the
4
+ provider's id for it and the usage baseline of its last report. Where it is
5
+ stored is the caller's business, so the store is a protocol.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import threading
11
+ from dataclasses import dataclass
12
+ from typing import TYPE_CHECKING, Protocol
13
+
14
+ if TYPE_CHECKING:
15
+ from .usage import ProviderUsage
16
+
17
+
18
+ @dataclass(frozen=True)
19
+ class Checkpoint:
20
+ """A provider conversation a later process can resume.
21
+
22
+ ``usage`` is the conversation's most recent report, kept so a provider
23
+ whose usage is cumulative can still tell the next turn's increment.
24
+ """
25
+
26
+ conversation_id: str
27
+ usage: ProviderUsage | None = None
28
+
29
+
30
+ class CheckpointStore(Protocol):
31
+ """Where a session keeps its checkpoint between processes."""
32
+
33
+ def load(self, key: str) -> Checkpoint | None:
34
+ """Return the checkpoint saved under *key*, or ``None``."""
35
+ ...
36
+
37
+ def save(self, key: str, checkpoint: Checkpoint) -> None:
38
+ """Replace whatever is saved under *key*."""
39
+ ...
40
+
41
+ def clear(self, key: str) -> None:
42
+ """Forget *key*; clearing a key that holds nothing is not an error."""
43
+ ...
44
+
45
+
46
+ class InMemoryCheckpointStore:
47
+ """A ``CheckpointStore`` that lives and dies with the process."""
48
+
49
+ def __init__(self) -> None:
50
+ """Start empty."""
51
+ self._lock = threading.Lock()
52
+ self._items: dict[str, Checkpoint] = {}
53
+
54
+ def load(self, key: str) -> Checkpoint | None:
55
+ """Return the checkpoint saved under *key*, or ``None``."""
56
+ with self._lock:
57
+ return self._items.get(key)
58
+
59
+ def save(self, key: str, checkpoint: Checkpoint) -> None:
60
+ """Replace whatever is saved under *key*."""
61
+ with self._lock:
62
+ self._items[key] = checkpoint
63
+
64
+ def clear(self, key: str) -> None:
65
+ """Forget *key*."""
66
+ with self._lock:
67
+ self._items.pop(key, None)