agentpause 0.2.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 (36) hide show
  1. agentpause-0.2.0/LICENSE +21 -0
  2. agentpause-0.2.0/PKG-INFO +213 -0
  3. agentpause-0.2.0/README.md +190 -0
  4. agentpause-0.2.0/pyproject.toml +33 -0
  5. agentpause-0.2.0/setup.cfg +4 -0
  6. agentpause-0.2.0/src/agentpause/__init__.py +46 -0
  7. agentpause-0.2.0/src/agentpause/adapters/__init__.py +8 -0
  8. agentpause-0.2.0/src/agentpause/adapters/langgraph.py +205 -0
  9. agentpause-0.2.0/src/agentpause/adapters/litellm.py +338 -0
  10. agentpause-0.2.0/src/agentpause/breaker.py +88 -0
  11. agentpause-0.2.0/src/agentpause/errors.py +66 -0
  12. agentpause-0.2.0/src/agentpause/estimator.py +106 -0
  13. agentpause-0.2.0/src/agentpause/fallback.py +74 -0
  14. agentpause-0.2.0/src/agentpause/retry.py +57 -0
  15. agentpause-0.2.0/src/agentpause/risk.py +138 -0
  16. agentpause-0.2.0/src/agentpause/scheduler.py +336 -0
  17. agentpause-0.2.0/src/agentpause/state.py +99 -0
  18. agentpause-0.2.0/src/agentpause.egg-info/PKG-INFO +213 -0
  19. agentpause-0.2.0/src/agentpause.egg-info/SOURCES.txt +34 -0
  20. agentpause-0.2.0/src/agentpause.egg-info/dependency_links.txt +1 -0
  21. agentpause-0.2.0/src/agentpause.egg-info/requires.txt +9 -0
  22. agentpause-0.2.0/src/agentpause.egg-info/top_level.txt +1 -0
  23. agentpause-0.2.0/tests/test_async.py +198 -0
  24. agentpause-0.2.0/tests/test_breaker.py +121 -0
  25. agentpause-0.2.0/tests/test_estimator.py +63 -0
  26. agentpause-0.2.0/tests/test_fallback.py +92 -0
  27. agentpause-0.2.0/tests/test_io_tpm.py +128 -0
  28. agentpause-0.2.0/tests/test_langgraph_adapter.py +170 -0
  29. agentpause-0.2.0/tests/test_litellm_adapter.py +160 -0
  30. agentpause-0.2.0/tests/test_money_and_hooks.py +138 -0
  31. agentpause-0.2.0/tests/test_quantile.py +65 -0
  32. agentpause-0.2.0/tests/test_risk.py +45 -0
  33. agentpause-0.2.0/tests/test_robustness.py +242 -0
  34. agentpause-0.2.0/tests/test_scheduler.py +120 -0
  35. agentpause-0.2.0/tests/test_state.py +55 -0
  36. agentpause-0.2.0/tests/test_wait_and_rpm.py +201 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Andrea Ciampolillo
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.
@@ -0,0 +1,213 @@
1
+ Metadata-Version: 2.4
2
+ Name: agentpause
3
+ Version: 0.2.0
4
+ Summary: Predictive scheduling for autonomous LLM agents: suspend gracefully before rate limits, resume without losing work.
5
+ Author: Andrea Lelio Ciampolillo
6
+ License: MIT
7
+ Keywords: llm,agents,rate-limiting,checkpointing,scheduler
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
13
+ Requires-Python: >=3.9
14
+ Description-Content-Type: text/markdown
15
+ License-File: LICENSE
16
+ Provides-Extra: dev
17
+ Requires-Dist: pytest>=7.0; extra == "dev"
18
+ Provides-Extra: litellm
19
+ Requires-Dist: litellm>=1.40; extra == "litellm"
20
+ Provides-Extra: langgraph
21
+ Requires-Dist: langgraph>=0.2; extra == "langgraph"
22
+ Dynamic: license-file
23
+
24
+ # agentpause
25
+
26
+ **Predictive scheduling for autonomous LLM agents.** Suspend an agent gracefully
27
+ *before* it hits a provider rate limit, and resume it without redoing work.
28
+
29
+ The core works on any provider — cloud (OpenAI, Anthropic, Groq) or local — because
30
+ it only serializes application-level state. True KV-cache warm start is an optional
31
+ plugin for self-hosted runtimes (llama.cpp, vLLM).
32
+
33
+ ## Measured results (from the accompanying research)
34
+
35
+ | Experiment | Result |
36
+ |---|---|
37
+ | Simulation, 300 runs/config | reactive baseline crashes up to 100% → predictive **0%** (k=4), token waste −80% |
38
+ | Real provider (Groq free, 6K TPM) | multi-window task completed with **zero 429 errors** |
39
+ | vs LangGraph's MemorySaver (200 runs) | LangGraph: 7.8 × 429/run, 9,239 tokens wasted; predictive: **0 and 0** |
40
+ | End-to-end A/B (thinking models, 4B/8B) | recovery **54×–93× faster**; total task time −19% |
41
+
42
+ Reproduce them yourself with a free key: `python scripts/benchmark_groq.py`.
43
+
44
+ > Status: **early alpha (0.1)**. Core components, the high-level
45
+ > `PredictiveScheduler` API, the LiteLLM adapter (any provider), the LangGraph
46
+ > adapter, runnable examples, and a full test suite are in place; the optional
47
+ > KV-cache plugin is next.
48
+
49
+ ## Quick example
50
+
51
+ ```python
52
+ from agentpause import PredictiveScheduler
53
+
54
+ sched = PredictiveScheduler(backend=my_llm_call, telemetry=my_rate_limit_reader)
55
+
56
+ with sched.session("task-1") as s: # resumes automatically if interrupted before
57
+ for question in questions[s.step:]: # skip steps finished before a suspend
58
+ s.add_user(question)
59
+ if s.should_suspend(): # predictive check, *before* the call
60
+ s.checkpoint()
61
+ break # stop cleanly; rerun to resume
62
+ reply = s.call()
63
+ else:
64
+ s.complete() # task done: drop the checkpoint
65
+ ```
66
+
67
+ `backend` is any callable `messages -> (reply, tokens_used)`; `telemetry` is any
68
+ callable `() -> remaining_tokens`. See `examples/quickstart.py` for a runnable demo
69
+ (no API keys needed) that suspends mid-task and resumes on the next run.
70
+
71
+ ## Real providers via LiteLLM
72
+
73
+ The LiteLLM adapter supplies both callables for 100+ providers (OpenAI, Groq,
74
+ Anthropic, local servers, ...), reading the budget from each response's
75
+ rate-limit headers and refreshing stale readings with a tiny telemetry ping:
76
+
77
+ ```python
78
+ from agentpause import PredictiveScheduler
79
+ from agentpause.adapters.litellm import LiteLLMAdapter
80
+
81
+ adapter = LiteLLMAdapter(model="groq/llama-3.1-8b-instant")
82
+ sched = PredictiveScheduler(backend=adapter.backend, telemetry=adapter.telemetry)
83
+ ```
84
+
85
+ Install with `pip install -e ".[litellm]"`; see `examples/litellm_groq.py`.
86
+ To validate against your own provider (frontier models included):
87
+ `python scripts/validate_provider.py gpt-4o-mini`.
88
+
89
+ Rate-limit headers by provider (defaults target the OpenAI-style names):
90
+
91
+ | Provider | remaining tokens | remaining requests | reset |
92
+ |---|---|---|---|
93
+ | OpenAI | `x-ratelimit-remaining-tokens` | `x-ratelimit-remaining-requests` | `x-ratelimit-reset-tokens` (`1s`, `6m0s`) |
94
+ | Groq | `x-ratelimit-remaining-tokens` | `x-ratelimit-remaining-requests` | `x-ratelimit-reset-tokens` (`7.66s`, `2m59.56s`) |
95
+ | Anthropic | `anthropic-ratelimit-tokens-remaining` | `anthropic-ratelimit-requests-remaining` | RFC 3339 timestamp — set `remaining_header=` etc. |
96
+
97
+ Header names differ? Override them: `LiteLLMAdapter(model=..., remaining_header="...", requests_header="...", reset_header="...")`.
98
+
99
+ ## Beyond tokens: RPM and wait-vs-suspend
100
+
101
+ Telemetry can be richer than a token count. `adapter.budget` reports all
102
+ three dimensions providers expose — remaining tokens (TPM), remaining
103
+ requests (RPM), and seconds until the window resets — and unlocks the
104
+ three-valued decision:
105
+
106
+ ```python
107
+ sched = PredictiveScheduler(backend=adapter.backend, telemetry=adapter.budget)
108
+
109
+ d = session.next_action() # "continue" | "wait" | "checkpoint"
110
+ ```
111
+
112
+ `wait` fires when the budget does not fit **but** the window resets within
113
+ `wait_threshold_s` (default 15 s): a short in-place pause is cheaper than a
114
+ full suspend/resume cycle. Exhausted requests (RPM = 0) block the call even
115
+ with plenty of tokens left. Plain-int telemetry keeps working unchanged.
116
+
117
+ ## Async
118
+
119
+ Every entry point has an async twin — same rules, same guarantees, never
120
+ blocks the event loop:
121
+
122
+ ```python
123
+ adapter = LiteLLMAdapter(model="groq/llama-3.1-8b-instant")
124
+ sched = PredictiveScheduler(backend=None, async_backend=adapter.abackend,
125
+ telemetry=adapter.telemetry)
126
+ reply = await session.acall() # retry/backoff via asyncio.sleep
127
+ await guard.acheck(state["messages"]) # async LangGraph nodes
128
+ ```
129
+
130
+ For sharper input estimates, wire the per-model tokenizer:
131
+ `PredictiveScheduler(..., count_tokens=adapter.count_tokens)` (falls back to
132
+ the ~4 chars/token heuristic if the tokenizer is unavailable).
133
+
134
+ ## When prediction fails anyway
135
+
136
+ Estimates are statistical — a 429 can still slip through. agentpause survives
137
+ it instead of crashing:
138
+
139
+ - **typed errors**: everything derives from `AgentPauseError`
140
+ (`RateLimitHit`, `TelemetryError`, `CheckpointError`, `BackendError`);
141
+ - **retry with backoff**: unexpected 429s are retried (provider `retry-after`
142
+ honored, else exponential backoff — see `RetryPolicy`);
143
+ - **hits are feedback**: each one bumps `safety_k` up (capped at `k_max`),
144
+ so the scheduler grows more cautious on workloads it underestimates;
145
+ - **clean failure**: a failed call leaves the session state untouched —
146
+ no phantom steps, resumes stay consistent.
147
+
148
+ ## LangGraph integration
149
+
150
+ `AgentPauseGuard` adds the predictive gate to any LangGraph node — LangGraph
151
+ persists reactively (after nodes), the guard pauses *before* the call that
152
+ would hit the rate limit, via LangGraph's own `interrupt()` + checkpointer:
153
+
154
+ ```python
155
+ from agentpause.adapters.langgraph import AgentPauseGuard
156
+
157
+ guard = AgentPauseGuard(telemetry=adapter.telemetry) # e.g. from LiteLLMAdapter
158
+
159
+ def agent_node(state):
160
+ guard.check(state["messages"]) # pauses the graph here if needed
161
+ reply = llm.invoke(state["messages"])
162
+ guard.record(state["messages"], reply.usage_metadata["total_tokens"])
163
+ ...
164
+ ```
165
+
166
+ Resume the paused thread with `graph.invoke(Command(resume=True), config)`.
167
+ On resume the guard re-reads telemetry fresh — never from the checkpoint.
168
+ Install with `pip install -e ".[langgraph]"`; see `examples/langgraph_quickstart.py`.
169
+
170
+ ## Why
171
+
172
+ Current agent frameworks persist state *reactively*: they checkpoint after a step
173
+ completes and crash when the provider returns HTTP 429. `agentpause` adds a
174
+ *predictive* layer that estimates the next step's cost, compares it against the
175
+ remaining rate-limit budget, and suspends cleanly before the error — then resumes
176
+ from the exact step.
177
+
178
+ This library is the engineering counterpart of the research preprint *"A
179
+ Resource-Aware Predictive Scheduler for Autonomous LLM Agents"*.
180
+
181
+ ## Components (v0.1)
182
+
183
+ | Module | Role |
184
+ |--------|------|
185
+ | `PredictiveScheduler` / `Session` | the high-level API: `session()`, `should_suspend()`, `call()`, `checkpoint()` |
186
+ | `Estimator` | predicts next-step token cost with a moving-average error correction (ε) and tracks σ |
187
+ | `should_checkpoint` / `RiskModel` | the suspension rule (`remaining < estimated + k·σ`) and a diagnostic risk score |
188
+ | `Budget` / `decide` | three-dimensional telemetry (TPM, RPM, reset time) and the three-valued rule: continue / wait / checkpoint |
189
+ | `StateStore` / `Checkpoint` | atomic logical checkpointing with idempotency keys — works on any provider |
190
+ | `adapters.litellm.LiteLLMAdapter` | backend + telemetry for any LiteLLM-supported provider (headers → budget, stale reading → 1-token ping) |
191
+ | `adapters.langgraph.AgentPauseGuard` | predictive gate for LangGraph nodes: `check()` interrupts the graph before the fatal call, `record()` trains the estimator |
192
+
193
+ ## Install (from source, during development)
194
+
195
+ ```bash
196
+ git clone https://github.com/<user>/agentpause
197
+ cd agentpause
198
+ pip install -e ".[dev]"
199
+ pytest
200
+ ```
201
+
202
+ ## Roadmap
203
+
204
+ - [x] Core components + test suite
205
+ - [x] `PredictiveScheduler` high-level API (`session()`, `should_suspend()`, `call()`)
206
+ - [x] Runnable quickstart example (no keys)
207
+ - [x] LiteLLM adapter (works with any provider)
208
+ - [x] LangGraph adapter (interrupt + checkpointer)
209
+ - [ ] Optional KV-cache plugin for llama.cpp / vLLM (true warm start)
210
+
211
+ ## License
212
+
213
+ MIT
@@ -0,0 +1,190 @@
1
+ # agentpause
2
+
3
+ **Predictive scheduling for autonomous LLM agents.** Suspend an agent gracefully
4
+ *before* it hits a provider rate limit, and resume it without redoing work.
5
+
6
+ The core works on any provider — cloud (OpenAI, Anthropic, Groq) or local — because
7
+ it only serializes application-level state. True KV-cache warm start is an optional
8
+ plugin for self-hosted runtimes (llama.cpp, vLLM).
9
+
10
+ ## Measured results (from the accompanying research)
11
+
12
+ | Experiment | Result |
13
+ |---|---|
14
+ | Simulation, 300 runs/config | reactive baseline crashes up to 100% → predictive **0%** (k=4), token waste −80% |
15
+ | Real provider (Groq free, 6K TPM) | multi-window task completed with **zero 429 errors** |
16
+ | vs LangGraph's MemorySaver (200 runs) | LangGraph: 7.8 × 429/run, 9,239 tokens wasted; predictive: **0 and 0** |
17
+ | End-to-end A/B (thinking models, 4B/8B) | recovery **54×–93× faster**; total task time −19% |
18
+
19
+ Reproduce them yourself with a free key: `python scripts/benchmark_groq.py`.
20
+
21
+ > Status: **early alpha (0.1)**. Core components, the high-level
22
+ > `PredictiveScheduler` API, the LiteLLM adapter (any provider), the LangGraph
23
+ > adapter, runnable examples, and a full test suite are in place; the optional
24
+ > KV-cache plugin is next.
25
+
26
+ ## Quick example
27
+
28
+ ```python
29
+ from agentpause import PredictiveScheduler
30
+
31
+ sched = PredictiveScheduler(backend=my_llm_call, telemetry=my_rate_limit_reader)
32
+
33
+ with sched.session("task-1") as s: # resumes automatically if interrupted before
34
+ for question in questions[s.step:]: # skip steps finished before a suspend
35
+ s.add_user(question)
36
+ if s.should_suspend(): # predictive check, *before* the call
37
+ s.checkpoint()
38
+ break # stop cleanly; rerun to resume
39
+ reply = s.call()
40
+ else:
41
+ s.complete() # task done: drop the checkpoint
42
+ ```
43
+
44
+ `backend` is any callable `messages -> (reply, tokens_used)`; `telemetry` is any
45
+ callable `() -> remaining_tokens`. See `examples/quickstart.py` for a runnable demo
46
+ (no API keys needed) that suspends mid-task and resumes on the next run.
47
+
48
+ ## Real providers via LiteLLM
49
+
50
+ The LiteLLM adapter supplies both callables for 100+ providers (OpenAI, Groq,
51
+ Anthropic, local servers, ...), reading the budget from each response's
52
+ rate-limit headers and refreshing stale readings with a tiny telemetry ping:
53
+
54
+ ```python
55
+ from agentpause import PredictiveScheduler
56
+ from agentpause.adapters.litellm import LiteLLMAdapter
57
+
58
+ adapter = LiteLLMAdapter(model="groq/llama-3.1-8b-instant")
59
+ sched = PredictiveScheduler(backend=adapter.backend, telemetry=adapter.telemetry)
60
+ ```
61
+
62
+ Install with `pip install -e ".[litellm]"`; see `examples/litellm_groq.py`.
63
+ To validate against your own provider (frontier models included):
64
+ `python scripts/validate_provider.py gpt-4o-mini`.
65
+
66
+ Rate-limit headers by provider (defaults target the OpenAI-style names):
67
+
68
+ | Provider | remaining tokens | remaining requests | reset |
69
+ |---|---|---|---|
70
+ | OpenAI | `x-ratelimit-remaining-tokens` | `x-ratelimit-remaining-requests` | `x-ratelimit-reset-tokens` (`1s`, `6m0s`) |
71
+ | Groq | `x-ratelimit-remaining-tokens` | `x-ratelimit-remaining-requests` | `x-ratelimit-reset-tokens` (`7.66s`, `2m59.56s`) |
72
+ | Anthropic | `anthropic-ratelimit-tokens-remaining` | `anthropic-ratelimit-requests-remaining` | RFC 3339 timestamp — set `remaining_header=` etc. |
73
+
74
+ Header names differ? Override them: `LiteLLMAdapter(model=..., remaining_header="...", requests_header="...", reset_header="...")`.
75
+
76
+ ## Beyond tokens: RPM and wait-vs-suspend
77
+
78
+ Telemetry can be richer than a token count. `adapter.budget` reports all
79
+ three dimensions providers expose — remaining tokens (TPM), remaining
80
+ requests (RPM), and seconds until the window resets — and unlocks the
81
+ three-valued decision:
82
+
83
+ ```python
84
+ sched = PredictiveScheduler(backend=adapter.backend, telemetry=adapter.budget)
85
+
86
+ d = session.next_action() # "continue" | "wait" | "checkpoint"
87
+ ```
88
+
89
+ `wait` fires when the budget does not fit **but** the window resets within
90
+ `wait_threshold_s` (default 15 s): a short in-place pause is cheaper than a
91
+ full suspend/resume cycle. Exhausted requests (RPM = 0) block the call even
92
+ with plenty of tokens left. Plain-int telemetry keeps working unchanged.
93
+
94
+ ## Async
95
+
96
+ Every entry point has an async twin — same rules, same guarantees, never
97
+ blocks the event loop:
98
+
99
+ ```python
100
+ adapter = LiteLLMAdapter(model="groq/llama-3.1-8b-instant")
101
+ sched = PredictiveScheduler(backend=None, async_backend=adapter.abackend,
102
+ telemetry=adapter.telemetry)
103
+ reply = await session.acall() # retry/backoff via asyncio.sleep
104
+ await guard.acheck(state["messages"]) # async LangGraph nodes
105
+ ```
106
+
107
+ For sharper input estimates, wire the per-model tokenizer:
108
+ `PredictiveScheduler(..., count_tokens=adapter.count_tokens)` (falls back to
109
+ the ~4 chars/token heuristic if the tokenizer is unavailable).
110
+
111
+ ## When prediction fails anyway
112
+
113
+ Estimates are statistical — a 429 can still slip through. agentpause survives
114
+ it instead of crashing:
115
+
116
+ - **typed errors**: everything derives from `AgentPauseError`
117
+ (`RateLimitHit`, `TelemetryError`, `CheckpointError`, `BackendError`);
118
+ - **retry with backoff**: unexpected 429s are retried (provider `retry-after`
119
+ honored, else exponential backoff — see `RetryPolicy`);
120
+ - **hits are feedback**: each one bumps `safety_k` up (capped at `k_max`),
121
+ so the scheduler grows more cautious on workloads it underestimates;
122
+ - **clean failure**: a failed call leaves the session state untouched —
123
+ no phantom steps, resumes stay consistent.
124
+
125
+ ## LangGraph integration
126
+
127
+ `AgentPauseGuard` adds the predictive gate to any LangGraph node — LangGraph
128
+ persists reactively (after nodes), the guard pauses *before* the call that
129
+ would hit the rate limit, via LangGraph's own `interrupt()` + checkpointer:
130
+
131
+ ```python
132
+ from agentpause.adapters.langgraph import AgentPauseGuard
133
+
134
+ guard = AgentPauseGuard(telemetry=adapter.telemetry) # e.g. from LiteLLMAdapter
135
+
136
+ def agent_node(state):
137
+ guard.check(state["messages"]) # pauses the graph here if needed
138
+ reply = llm.invoke(state["messages"])
139
+ guard.record(state["messages"], reply.usage_metadata["total_tokens"])
140
+ ...
141
+ ```
142
+
143
+ Resume the paused thread with `graph.invoke(Command(resume=True), config)`.
144
+ On resume the guard re-reads telemetry fresh — never from the checkpoint.
145
+ Install with `pip install -e ".[langgraph]"`; see `examples/langgraph_quickstart.py`.
146
+
147
+ ## Why
148
+
149
+ Current agent frameworks persist state *reactively*: they checkpoint after a step
150
+ completes and crash when the provider returns HTTP 429. `agentpause` adds a
151
+ *predictive* layer that estimates the next step's cost, compares it against the
152
+ remaining rate-limit budget, and suspends cleanly before the error — then resumes
153
+ from the exact step.
154
+
155
+ This library is the engineering counterpart of the research preprint *"A
156
+ Resource-Aware Predictive Scheduler for Autonomous LLM Agents"*.
157
+
158
+ ## Components (v0.1)
159
+
160
+ | Module | Role |
161
+ |--------|------|
162
+ | `PredictiveScheduler` / `Session` | the high-level API: `session()`, `should_suspend()`, `call()`, `checkpoint()` |
163
+ | `Estimator` | predicts next-step token cost with a moving-average error correction (ε) and tracks σ |
164
+ | `should_checkpoint` / `RiskModel` | the suspension rule (`remaining < estimated + k·σ`) and a diagnostic risk score |
165
+ | `Budget` / `decide` | three-dimensional telemetry (TPM, RPM, reset time) and the three-valued rule: continue / wait / checkpoint |
166
+ | `StateStore` / `Checkpoint` | atomic logical checkpointing with idempotency keys — works on any provider |
167
+ | `adapters.litellm.LiteLLMAdapter` | backend + telemetry for any LiteLLM-supported provider (headers → budget, stale reading → 1-token ping) |
168
+ | `adapters.langgraph.AgentPauseGuard` | predictive gate for LangGraph nodes: `check()` interrupts the graph before the fatal call, `record()` trains the estimator |
169
+
170
+ ## Install (from source, during development)
171
+
172
+ ```bash
173
+ git clone https://github.com/<user>/agentpause
174
+ cd agentpause
175
+ pip install -e ".[dev]"
176
+ pytest
177
+ ```
178
+
179
+ ## Roadmap
180
+
181
+ - [x] Core components + test suite
182
+ - [x] `PredictiveScheduler` high-level API (`session()`, `should_suspend()`, `call()`)
183
+ - [x] Runnable quickstart example (no keys)
184
+ - [x] LiteLLM adapter (works with any provider)
185
+ - [x] LangGraph adapter (interrupt + checkpointer)
186
+ - [ ] Optional KV-cache plugin for llama.cpp / vLLM (true warm start)
187
+
188
+ ## License
189
+
190
+ MIT
@@ -0,0 +1,33 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "agentpause"
7
+ version = "0.2.0"
8
+ description = "Predictive scheduling for autonomous LLM agents: suspend gracefully before rate limits, resume without losing work."
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "Andrea Lelio Ciampolillo" }]
13
+ keywords = ["llm", "agents", "rate-limiting", "checkpointing", "scheduler"]
14
+ classifiers = [
15
+ "Development Status :: 3 - Alpha",
16
+ "Intended Audience :: Developers",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Programming Language :: Python :: 3",
19
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
20
+ ]
21
+ dependencies = []
22
+
23
+ [project.optional-dependencies]
24
+ dev = ["pytest>=7.0"]
25
+ litellm = ["litellm>=1.40"]
26
+ langgraph = ["langgraph>=0.2"]
27
+
28
+ [tool.setuptools.packages.find]
29
+ where = ["src"]
30
+
31
+ [tool.pytest.ini_options]
32
+ pythonpath = ["src", "."]
33
+ testpaths = ["tests"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,46 @@
1
+ """agentpause — predictive scheduling for autonomous LLM agents.
2
+
3
+ Suspend an agent gracefully *before* it hits a provider rate limit, and resume
4
+ it without redoing work. The core works on any provider (cloud or local); true
5
+ KV-cache warm start is an optional plugin for self-hosted runtimes.
6
+ """
7
+
8
+ from .errors import (
9
+ AgentPauseError,
10
+ BackendError,
11
+ CheckpointError,
12
+ RateLimitHit,
13
+ TelemetryError,
14
+ )
15
+ from .breaker import CircuitBreaker, CircuitOpenError
16
+ from .estimator import Estimator
17
+ from .fallback import FallbackBackend
18
+ from .retry import RetryPolicy
19
+ from .risk import Budget, Decision, RiskModel, decide, should_checkpoint
20
+ from .state import Checkpoint, StateStore
21
+ from .scheduler import PredictiveScheduler, Session
22
+
23
+ __version__ = "0.2.0"
24
+
25
+ __all__ = [
26
+ "PredictiveScheduler",
27
+ "Session",
28
+ "Estimator",
29
+ "RiskModel",
30
+ "Budget",
31
+ "Decision",
32
+ "decide",
33
+ "should_checkpoint",
34
+ "Checkpoint",
35
+ "StateStore",
36
+ "RetryPolicy",
37
+ "FallbackBackend",
38
+ "CircuitBreaker",
39
+ "CircuitOpenError",
40
+ "AgentPauseError",
41
+ "RateLimitHit",
42
+ "TelemetryError",
43
+ "CheckpointError",
44
+ "BackendError",
45
+ "__version__",
46
+ ]
@@ -0,0 +1,8 @@
1
+ """Provider adapters: turn real LLM providers into the two callables
2
+ (backend, telemetry) that :class:`agentpause.PredictiveScheduler` expects.
3
+
4
+ Adapters are optional — the core has zero dependencies. Import them
5
+ explicitly, e.g.::
6
+
7
+ from agentpause.adapters.litellm import LiteLLMAdapter
8
+ """