AbstractRuntime 0.0.1__tar.gz → 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 (104) hide show
  1. abstractruntime-0.2.0/CHANGELOG.md +132 -0
  2. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/PKG-INFO +1 -1
  3. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/ROADMAP.md +13 -12
  4. abstractruntime-0.2.0/docs/backlog/completed/010_examples_and_composition.md +59 -0
  5. abstractruntime-0.2.0/docs/backlog/completed/016_runtime_aware_parameters.md +240 -0
  6. abstractruntime-0.2.0/docs/backlog/planned/015_agent_integration_improvements.md +111 -0
  7. abstractruntime-0.2.0/docs/backlog/planned/017_limit_warnings_and_observability.md +141 -0
  8. abstractruntime-0.2.0/docs/limits.md +266 -0
  9. abstractruntime-0.2.0/examples/01_hello_world.py +60 -0
  10. abstractruntime-0.2.0/examples/02_ask_user.py +134 -0
  11. abstractruntime-0.2.0/examples/03_wait_until.py +94 -0
  12. abstractruntime-0.2.0/examples/04_multi_step.py +100 -0
  13. abstractruntime-0.2.0/examples/05_persistence.py +173 -0
  14. abstractruntime-0.2.0/examples/06_llm_integration.py +102 -0
  15. abstractruntime-0.2.0/examples/07_react_agent.py +124 -0
  16. abstractruntime-0.2.0/examples/README.md +45 -0
  17. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/pyproject.toml +1 -1
  18. abstractruntime-0.2.0/src/abstractruntime/core/__init__.py +26 -0
  19. abstractruntime-0.2.0/src/abstractruntime/core/config.py +101 -0
  20. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/core/models.py +44 -1
  21. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/core/runtime.py +165 -10
  22. abstractruntime-0.2.0/src/abstractruntime/core/vars.py +94 -0
  23. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/integrations/abstractcore/__init__.py +6 -2
  24. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/integrations/abstractcore/effect_handlers.py +34 -4
  25. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/integrations/abstractcore/factory.py +39 -2
  26. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/integrations/abstractcore/llm_client.py +132 -31
  27. abstractruntime-0.2.0/src/abstractruntime/integrations/abstractcore/tool_executor.py +168 -0
  28. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/storage/artifacts.py +31 -0
  29. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/storage/json_files.py +1 -1
  30. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/tests/test_artifacts.py +24 -0
  31. abstractruntime-0.2.0/tests/test_durable_toolsets.py +75 -0
  32. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/tests/test_integration_abstractcore.py +6 -0
  33. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/tests/test_retry_idempotency.py +23 -0
  34. abstractruntime-0.2.0/tests/test_trace_context_propagation.py +108 -0
  35. abstractruntime-0.0.1/docs/backlog/planned/010_examples_and_composition.md +0 -29
  36. abstractruntime-0.0.1/src/abstractruntime/core/__init__.py +0 -19
  37. abstractruntime-0.0.1/src/abstractruntime/integrations/abstractcore/tool_executor.py +0 -89
  38. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/.gitignore +0 -0
  39. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/LICENSE +0 -0
  40. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/README.md +0 -0
  41. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/adr/0001_layered_coupling_with_abstractcore.md +0 -0
  42. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/adr/0002_execution_modes_local_remote_hybrid.md +0 -0
  43. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/adr/0003_provenance_tamper_evident_hash_chain.md +0 -0
  44. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/adr/README.md +0 -0
  45. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/README.md +0 -0
  46. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/completed/001_runtime_kernel.md +0 -0
  47. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/completed/002_persistence_and_ledger.md +0 -0
  48. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/completed/003_wait_primitives.md +0 -0
  49. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/completed/004_scheduler_driver.md +0 -0
  50. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/completed/005_abstractcore_integration.md +0 -0
  51. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/completed/006_snapshots_bookmarks.md +0 -0
  52. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/completed/007_provenance_hash_chain.md +0 -0
  53. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/completed/009_artifact_store.md +0 -0
  54. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/completed/011_subworkflow_support.md +0 -0
  55. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/completed/012_run_store_query_and_scheduler_support.md +0 -0
  56. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/completed/013_effect_retries_and_idempotency.md +0 -0
  57. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/deprecated/001_integrations_abstractcore.md +0 -0
  58. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/deprecated/001_runtime_kernel.md +0 -0
  59. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/deprecated/002_persistence_and_ledger.md +0 -0
  60. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/deprecated/002_snapshots_bookmarks.md +0 -0
  61. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/deprecated/003_provenance_ledger_chain.md +0 -0
  62. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/deprecated/003_wait_resume_and_scheduler.md +0 -0
  63. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/deprecated/004_effect_handlers_and_integrations.md +0 -0
  64. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/deprecated/004_tests.md +0 -0
  65. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/deprecated/005_docs_updates.md +0 -0
  66. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/deprecated/005_examples_and_composition.md +0 -0
  67. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/deprecated/006_ai_fingerprint_and_provenance.md +0 -0
  68. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/deprecated/DEPRECATED_README.md +0 -0
  69. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/deprecated/README.md +0 -0
  70. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/deprecated/abstractruntime_docs_final_02a7373b.plan.md +0 -0
  71. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/planned/008_signatures_and_keys.md +0 -0
  72. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/planned/014_remote_tool_worker_executor.md +0 -0
  73. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/integrations/abstractcore.md +0 -0
  74. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/manual_testing.md +0 -0
  75. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/proposal.md +0 -0
  76. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/provenance.md +0 -0
  77. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/snapshots.md +0 -0
  78. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/__init__.py +0 -0
  79. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/core/policy.py +0 -0
  80. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/core/spec.py +0 -0
  81. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/identity/__init__.py +0 -0
  82. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/identity/fingerprint.py +0 -0
  83. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/integrations/__init__.py +0 -0
  84. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/integrations/abstractcore/logging.py +0 -0
  85. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/scheduler/__init__.py +0 -0
  86. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/scheduler/convenience.py +0 -0
  87. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/scheduler/registry.py +0 -0
  88. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/scheduler/scheduler.py +0 -0
  89. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/storage/__init__.py +0 -0
  90. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/storage/base.py +0 -0
  91. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/storage/in_memory.py +0 -0
  92. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/storage/ledger_chain.py +0 -0
  93. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/storage/snapshots.py +0 -0
  94. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/tests/README.md +0 -0
  95. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/tests/conftest.py +0 -0
  96. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/tests/test_integrations_abstractcore.py +0 -0
  97. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/tests/test_ledger_chain.py +0 -0
  98. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/tests/test_pause_resume.py +0 -0
  99. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/tests/test_queryable_run_store.py +0 -0
  100. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/tests/test_real_integration.py +0 -0
  101. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/tests/test_remote_llm_client.py +0 -0
  102. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/tests/test_scheduler.py +0 -0
  103. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/tests/test_snapshots.py +0 -0
  104. {abstractruntime-0.0.1 → abstractruntime-0.2.0}/tests/test_subworkflow.py +0 -0
@@ -0,0 +1,132 @@
1
+ # Changelog
2
+
3
+ All notable changes to AbstractRuntime will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.2.0] - 2025-12-17
9
+
10
+ ### Added
11
+
12
+ #### Core Runtime Features
13
+ - **Durable Workflow Execution**: Start/tick/resume semantics for long-running workflows that survive process restarts
14
+ - **WorkflowSpec**: Graph-based workflow definitions with node handlers keyed by ID
15
+ - **RunState**: Durable state management (`current_node`, `vars`, `waiting`, `status`)
16
+ - **Effect System**: Side-effect requests including `LLM_CALL`, `TOOL_CALLS`, `ASK_USER`, `WAIT_EVENT`, `WAIT_UNTIL`, `START_SUBWORKFLOW`
17
+ - **StepPlan**: Node execution plans that define effects and state transitions
18
+ - **Explicit Waiting States**: First-class support for pausing execution (`WaitReason`, `WaitState`)
19
+
20
+ #### Scheduler & Automation
21
+ - **Built-in Scheduler**: Zero-config background scheduler with polling thread for automatic run resumption
22
+ - **WorkflowRegistry**: Mapping from workflow_id to WorkflowSpec for dynamic workflow resolution
23
+ - **ScheduledRuntime**: High-level wrapper combining Runtime + Scheduler with simplified API
24
+ - **create_scheduled_runtime()**: Factory function for zero-config scheduler creation
25
+ - **Event Ingestion**: Support for external event delivery via `scheduler.resume_event()`
26
+ - **Scheduler Stats**: Built-in statistics tracking and callback support
27
+
28
+ #### Storage & Persistence
29
+ - **Append-only Ledger**: Execution journal with `StepRecord` entries for audit/debug/provenance
30
+ - **InMemoryRunStore**: In-memory run state storage for development and testing
31
+ - **InMemoryLedgerStore**: In-memory ledger storage for development and testing
32
+ - **JsonFileRunStore**: File-based persistent run state storage (one file per run)
33
+ - **JsonlLedgerStore**: JSONL-based persistent ledger storage
34
+ - **QueryableRunStore**: Interface for listing and filtering runs by status, workflow_id, actor_id, and time range
35
+ - **Artifacts System**: Storage for large payloads (documents, images, tool outputs) to avoid bloating checkpoints
36
+ - `ArtifactStore` interface with in-memory and file-based implementations
37
+ - `ArtifactRef` type for referencing stored artifacts
38
+ - Helper functions: `artifact_ref()`, `is_artifact_ref()`, `get_artifact_id()`, `resolve_artifact()`, `compute_artifact_id()`
39
+
40
+ #### Snapshots & Bookmarks
41
+ - **Snapshot System**: Named, searchable checkpoints of run state for debugging and experimentation
42
+ - **SnapshotStore**: Storage interface for snapshots with metadata (name, description, tags, timestamps)
43
+ - **InMemorySnapshotStore**: In-memory snapshot storage for development
44
+ - **JsonSnapshotStore**: File-based snapshot storage (one file per snapshot)
45
+ - **Snapshot Search**: Filter by run_id, tag, or substring match in name/description
46
+
47
+ #### Provenance & Accountability
48
+ - **Hash-Chained Ledger**: Tamper-evident ledger with `prev_hash` and `record_hash` for each step
49
+ - **HashChainedLedgerStore**: Decorator for adding hash chain verification to any ledger store
50
+ - **verify_ledger_chain()**: Verification function that detects modifications or reordering of ledger records
51
+ - **Actor Identity**: `ActorFingerprint` for attribution of workflow execution to specific actors
52
+ - **actor_id tracking**: Support for actor_id in both RunState and StepRecord for accountability
53
+
54
+ #### AbstractCore Integration
55
+ - **LLM_CALL Effect Handler**: Execute LLM calls via AbstractCore providers
56
+ - **TOOL_CALLS Effect Handler**: Execute tool calls with support for multiple execution modes
57
+ - **Three Execution Modes**:
58
+ - **Local**: In-process AbstractCore providers with local tool execution
59
+ - **Remote**: HTTP to AbstractCore server (`/v1/chat/completions`) with tool passthrough
60
+ - **Hybrid**: Remote LLM calls with local tool execution
61
+ - **Convenience Factories**: `create_local_runtime()`, `create_remote_runtime()`, `create_hybrid_runtime()`
62
+ - **Tool Execution Modes**:
63
+ - Executed mode (trusted local) with results
64
+ - Passthrough mode (untrusted/server) with waiting semantics
65
+ - **Layered Coupling**: AbstractCore integration as opt-in module to keep kernel dependency-light
66
+
67
+ #### Effect Policies & Reliability
68
+ - **EffectPolicy Protocol**: Configurable retry and idempotency policies for effects
69
+ - **DefaultEffectPolicy**: Default implementation with no retries
70
+ - **RetryPolicy**: Configurable retry behavior with max_attempts and backoff
71
+ - **NoRetryPolicy**: Explicit no-retry policy
72
+ - **compute_idempotency_key()**: Ledger-based deduplication to prevent duplicate side effects after crashes
73
+
74
+ #### Examples & Documentation
75
+ - **7 Runnable Examples**:
76
+ - `01_hello_world.py`: Minimal workflow demonstration
77
+ - `02_ask_user.py`: Pause/resume with user input
78
+ - `03_wait_until.py`: Scheduled resumption with time-based waiting
79
+ - `04_multi_step.py`: Branching workflow with conditional logic
80
+ - `05_persistence.py`: File-based storage demonstration
81
+ - `06_llm_integration.py`: AbstractCore LLM call integration
82
+ - `07_react_agent.py`: Full ReAct agent implementation with tools
83
+ - **Comprehensive Documentation**:
84
+ - Architecture Decision Records (ADRs) for key design choices
85
+ - Integration guides for AbstractCore
86
+ - Detailed documentation for snapshots and provenance
87
+ - Limits and constraints documentation
88
+ - ROADMAP with prioritized next steps
89
+
90
+ ### Technical Details
91
+
92
+ #### Architecture
93
+ - **Layered Design**: Clear separation between kernel, storage, integrations, and identity
94
+ - **Dependency-Light Kernel**: Core runtime remains stable with minimal dependencies
95
+ - **Graph-Based Execution**: All workflows represented as state machines/graphs for visualization and composition
96
+ - **JSON-Serializable State**: All run state and vars must be JSON-serializable for persistence
97
+
98
+ #### Test Coverage
99
+ - **81% Overall Coverage**: Comprehensive test suite with 57+ tests
100
+ - **Integration Tests**: Tests for AbstractCore integration, subworkflows, trace propagation
101
+ - **Core Tests**: Scheduler, snapshots, artifacts, pause/resume, retry/idempotency, ledger chain
102
+ - **Storage Tests**: Queryable run store, durable toolsets
103
+
104
+ #### Compatibility
105
+ - **Python 3.10+**: Supports Python 3.10, 3.11, 3.12, and 3.13
106
+ - **Development Status**: Planning/Alpha (moving toward Beta with 0.2.0)
107
+
108
+ ### Known Limitations
109
+
110
+ - Snapshot restore does not guarantee safety if workflow spec or node code has changed
111
+ - Subworkflow support (`START_SUBWORKFLOW`) is implemented but undergoing refinement
112
+ - Cryptographic signatures (non-forgeability) not yet implemented - current hash chain provides tamper-evidence only
113
+ - Remote tool worker service not yet implemented
114
+
115
+ ### Design Decisions
116
+
117
+ - **Kernel stays dependency-light**: Enables portability, stability, and clear integration boundaries
118
+ - **AbstractCore integration is opt-in**: Layered coupling prevents kernel breakage when AbstractCore changes
119
+ - **Hash chain before signatures**: Provides immediate value without key management complexity
120
+ - **Built-in scheduler (not external)**: Zero-config UX for simple cases
121
+ - **Graph representation for all workflows**: Enables visualization, checkpointing, and composition
122
+
123
+ ### Notes
124
+
125
+ AbstractRuntime is the durable execution substrate designed to pair with AbstractCore, AbstractAgent, and AbstractFlow. It enables workflows to interrupt, checkpoint, and resume across process restarts, making it suitable for long-running agent workflows that need to wait for user input, scheduled events, or external job completion.
126
+
127
+ ## [0.0.1] - Initial Development
128
+
129
+ Initial development version with basic proof-of-concept features.
130
+
131
+ [0.2.0]: https://github.com/lpalbou/abstractruntime/releases/tag/v0.2.0
132
+ [0.0.1]: https://github.com/lpalbou/abstractruntime/releases/tag/v0.0.1
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: AbstractRuntime
3
- Version: 0.0.1
3
+ Version: 0.2.0
4
4
  Summary: AbstractRuntime: a durable graph runner designed to pair with AbstractCore.
5
5
  Project-URL: AbstractCore (website), https://www.abstractcore.ai/
6
6
  Project-URL: AbstractCore (GitHub), https://github.com/lpalbou/abstractruntime
@@ -90,19 +90,20 @@ sr.stop()
90
90
 
91
91
  ---
92
92
 
93
- ### 2.2 Examples and Documentation
93
+ ### 2.2 Examples and Documentation ✅ COMPLETE
94
94
  **Priority: High** | **Effort: Low** | **Backlog: 010**
95
95
 
96
- **Why**: The MVP is functional but lacks concrete examples. Developers cannot understand how to build workflows without reading source code.
97
-
98
- **Deliverables**:
99
- - `examples/` directory with runnable workflows
100
- - ask_user interrupt example (pause for days, resume)
101
- - wait_until timer example
102
- - LLM call + tool execution example
103
- - Subworkflow composition example
96
+ **What shipped**:
97
+ - `examples/` directory with 7 runnable examples
98
+ - 01_hello_world.py - Minimal workflow
99
+ - 02_ask_user.py - Pause/resume with user input
100
+ - 03_wait_until.py - Scheduled resumption
101
+ - 04_multi_step.py - Branching workflow
102
+ - 05_persistence.py - File-based storage
103
+ - 06_llm_integration.py - AbstractCore LLM call
104
+ - 07_react_agent.py - Full ReAct agent with tools
104
105
 
105
- **Success criteria**: A developer can copy an example and have a working workflow in 5 minutes.
106
+ **Success criteria**: A developer can copy an example and have a working workflow in 5 minutes.
106
107
 
107
108
  ---
108
109
 
@@ -227,8 +228,8 @@ AbstractCore (LLM calls, tool execution, server API)
227
228
  | 4.2 | Remote Worker | 3-4 days |
228
229
 
229
230
  **Phase 1 (Core Completeness)**: ✅ Complete
230
- **Phase 2 (Composition)**: ~3-5 days
231
+ **Phase 2 (Composition)**: Examples complete, Subworkflow complete
231
232
  **Phase 3 (Production Readiness)**: ~1 week
232
233
  **Phase 4 (Advanced Features)**: ~2 weeks
233
234
 
234
- Remaining: ~3-4 weeks for full roadmap.
235
+ Remaining: ~2-3 weeks for full roadmap.
@@ -0,0 +1,59 @@
1
+ ## 010_examples_and_composition (COMPLETED 2025-12-13)
2
+
3
+ ### Goal
4
+ Provide concrete, runnable examples demonstrating the simplified API:
5
+ - Zero-config setup with `create_scheduled_runtime()`
6
+ - `run()` and `respond()` for simple workflows
7
+ - `ask_user` interrupt (pause for user input)
8
+ - `wait_until` (scheduled resumption)
9
+ - Tool passthrough (for AbstractCore integration)
10
+ - Workflow-as-node composition (after 011 is complete)
11
+
12
+ ### Deliverables
13
+ - `examples/` directory with runnable Python scripts
14
+ - Each example should be self-contained and copy-pasteable
15
+
16
+ ### Proposed Examples
17
+
18
+ 1. **01_hello_world.py** — Minimal workflow with zero-config
19
+ 2. **02_ask_user.py** — Pause for user input, resume with response
20
+ 3. **03_wait_until.py** — Schedule a task for later
21
+ 4. **04_multi_step.py** — Multi-node workflow with branching
22
+ 5. **05_persistence.py** — File-based storage, survive restart
23
+ 6. **06_llm_integration.py** — AbstractCore LLM call (requires abstractcore)
24
+ 7. **07_react_agent.py** — Full ReAct agent with tools (requires abstractcore + abstractagent)
25
+
26
+ ### Acceptance criteria
27
+ - A developer can copy an example and have it running in < 5 minutes
28
+ - Examples use the simplified API (`run()`, `respond()`)
29
+ - Each example has clear comments explaining what's happening
30
+ - Examples 1-5 work without external dependencies
31
+ - Examples 6-7 require abstractcore/abstractagent but are clearly documented
32
+
33
+ ### Priority
34
+ **HIGH** - This is the most impactful improvement for adoption. Without examples, developers cannot understand how to use the library.
35
+
36
+ ---
37
+
38
+ ## Completion Notes
39
+
40
+ **Completed:** 2025-12-13
41
+
42
+ **Deliverables:**
43
+ - Created `examples/` directory with 7 runnable examples
44
+ - All examples tested and working
45
+
46
+ **Examples implemented:**
47
+ 1. `01_hello_world.py` - Minimal workflow with zero-config ✅
48
+ 2. `02_ask_user.py` - Pause for user input, resume with response ✅
49
+ 3. `03_wait_until.py` - Schedule a task for later ✅
50
+ 4. `04_multi_step.py` - Multi-node workflow with branching ✅
51
+ 5. `05_persistence.py` - File-based storage, survive restart ✅
52
+ 6. `06_llm_integration.py` - AbstractCore LLM call ✅
53
+ 7. `07_react_agent.py` - Full ReAct agent with tools ✅
54
+
55
+ **Additional improvements made:**
56
+ - AbstractAgent now uses TOOL_CALLS effect for ledger recording
57
+ - Created RegistryToolExecutor for agent-specific tool execution
58
+ - Added observe_node to ReAct workflow for proper effect-based architecture
59
+
@@ -0,0 +1,240 @@
1
+ ## 016_runtime_aware_parameters (completed)
2
+
3
+ **Status**: Completed
4
+ **Completed**: 2025-12-16
5
+
6
+ ---
7
+
8
+ ## Final Report
9
+
10
+ ### What Was Implemented
11
+
12
+ Refactored AbstractRuntime to be aware of runtime parameters (max_iterations, max_tokens, max_history_messages) with a canonical `_limits` namespace in RunState.vars.
13
+
14
+ **Approach**: Hybrid enforcement (runtime provides info/warnings, workflow nodes enforce)
15
+ **Rollout**: Phased migration (3 phases)
16
+
17
+ | Component | Description |
18
+ |-----------|-------------|
19
+ | `RuntimeConfig` | Frozen dataclass for runtime limits and model capabilities |
20
+ | `LimitWarning` | Dataclass for limit warnings (warning/exceeded) |
21
+ | `LIMITS` constant | `"_limits"` namespace constant in vars.py |
22
+ | `ensure_limits()` | Helper to create/get `_limits` namespace with defaults |
23
+ | `Runtime.config` | Property to access RuntimeConfig |
24
+ | `Runtime.get_limit_status()` | Get structured limit status for a run |
25
+ | `Runtime.check_limits()` | Check if limits approaching/exceeded, returns warnings |
26
+ | `Runtime.update_limits()` | Update limits mid-session |
27
+ | `Agent.get_limit_status()` | Agent-level delegate to runtime |
28
+ | `Agent.update_limits()` | Agent-level delegate to runtime |
29
+
30
+ ### Key Features
31
+
32
+ 1. **Canonical `_limits` Namespace**: Single source of truth in RunState.vars
33
+ ```python
34
+ run.vars["_limits"] = {
35
+ "max_iterations": 25,
36
+ "current_iteration": 0,
37
+ "max_tokens": 32768,
38
+ "max_history_messages": -1,
39
+ "estimated_tokens_used": 0,
40
+ "warn_iterations_pct": 80,
41
+ "warn_tokens_pct": 80,
42
+ }
43
+ ```
44
+
45
+ 2. **Hybrid Enforcement Model**:
46
+ - Runtime provides limit info and warnings
47
+ - Workflow nodes enforce (check and transition)
48
+ - Clear separation of concerns
49
+
50
+ 3. **Model Capabilities Integration**:
51
+ - Factory queries LLM client for model capabilities
52
+ - Capabilities flow through RuntimeConfig to `_limits`
53
+ - max_tokens defaults to model's context window
54
+
55
+ 4. **Backward Compatibility**:
56
+ - Falls back to scratchpad if `_limits` missing
57
+ - All new parameters have sensible defaults
58
+ - No breaking changes to existing APIs
59
+
60
+ ### Files Added
61
+
62
+ | File | Description |
63
+ |------|-------------|
64
+ | `src/abstractruntime/core/config.py` | RuntimeConfig dataclass with to_limits_dict() and with_capabilities() |
65
+
66
+ ### Files Modified
67
+
68
+ | File | Changes |
69
+ |------|---------|
70
+ | `abstractruntime/core/vars.py` | Added LIMITS constant, ensure_limits(), get_limits() |
71
+ | `abstractruntime/core/models.py` | Added LimitWarning dataclass |
72
+ | `abstractruntime/core/runtime.py` | Added config property and 3 limit methods |
73
+ | `abstractruntime/core/__init__.py` | Exported new classes and functions |
74
+ | `abstractruntime/integrations/abstractcore/factory.py` | Config parameter, model capabilities |
75
+ | `abstractruntime/integrations/abstractcore/__init__.py` | Exported RuntimeConfig |
76
+ | `abstractagent/adapters/react_runtime.py` | Uses _limits namespace |
77
+ | `abstractagent/adapters/codeact_runtime.py` | Uses _limits namespace |
78
+ | `abstractagent/agents/react.py` | Added get_limit_status(), update_limits() |
79
+ | `abstractagent/agents/codeact.py` | Added get_limit_status(), update_limits() |
80
+ | `abstractagent/logic/react.py` | build_request() accepts vars parameter |
81
+ | `abstractagent/logic/codeact.py` | build_request() accepts vars parameter |
82
+ | `abstractflow/adapters/agent_adapter.py` | Populates _limits namespace |
83
+
84
+ ### Test Coverage
85
+
86
+ | Test Suite | Result |
87
+ |------------|--------|
88
+ | Phase 1: RuntimeConfig tests | PASS |
89
+ | Phase 1: vars.py tests | PASS |
90
+ | Phase 1: LimitWarning tests | PASS |
91
+ | Phase 1: Runtime limit methods | PASS |
92
+ | Phase 1: Exports tests | PASS |
93
+ | Phase 2: Factory exports | PASS |
94
+ | Phase 3: react_runtime | PASS |
95
+ | Phase 3: codeact_runtime | PASS |
96
+ | Phase 3: Logic classes | PASS |
97
+ | Backward compatibility | PASS |
98
+ | AbstractRuntime unit tests | 147 passed |
99
+ | AbstractAgent unit tests | 5 passed |
100
+
101
+ ### Usage Examples
102
+
103
+ #### Basic Usage
104
+ ```python
105
+ from abstractruntime.core import RuntimeConfig
106
+
107
+ # Create runtime with custom limits
108
+ config = RuntimeConfig(
109
+ max_iterations=50,
110
+ max_tokens=65536,
111
+ max_history_messages=100,
112
+ warn_iterations_pct=75,
113
+ )
114
+
115
+ runtime = create_local_runtime(
116
+ provider="ollama",
117
+ model="qwen3:4b",
118
+ config=config,
119
+ )
120
+ ```
121
+
122
+ #### Checking Limit Status
123
+ ```python
124
+ # Get limit status mid-run
125
+ status = runtime.get_limit_status(run_id)
126
+ print(f"Iterations: {status['iterations']['current']}/{status['iterations']['max']}")
127
+ # Output: Iterations: 5/50
128
+
129
+ if status['iterations']['warning']:
130
+ print("Approaching iteration limit!")
131
+ ```
132
+
133
+ #### Updating Limits Dynamically
134
+ ```python
135
+ # Update limits mid-session (e.g., from /max-tokens command)
136
+ runtime.update_limits(run_id, {"max_tokens": 131072})
137
+ ```
138
+
139
+ #### Agent-Level Access
140
+ ```python
141
+ agent = ReactAgent(runtime=runtime, max_iterations=25)
142
+ run_id = agent.start("Solve this problem")
143
+
144
+ # Check status through agent
145
+ status = agent.get_limit_status()
146
+
147
+ # Update limits through agent
148
+ agent.update_limits(max_tokens=65536)
149
+ ```
150
+
151
+ ### Architecture
152
+
153
+ ```
154
+ ┌─────────────────────────────────────┐
155
+ │ RuntimeConfig │
156
+ │ (frozen dataclass with defaults) │
157
+ └─────────────────┬───────────────────┘
158
+
159
+ ┌─────────────────▼───────────────────┐
160
+ │ Runtime │
161
+ │ - config property │
162
+ │ - start() initializes _limits │
163
+ │ - get_limit_status() │
164
+ │ - check_limits() → LimitWarning[] │
165
+ │ - update_limits() │
166
+ └─────────────────┬───────────────────┘
167
+
168
+ ┌─────────────────▼───────────────────┐
169
+ │ RunState.vars │
170
+ │ { │
171
+ │ "_limits": { │
172
+ │ "max_iterations": 25, │
173
+ │ "current_iteration": 0, │
174
+ │ "max_tokens": 32768, │
175
+ │ ... │
176
+ │ } │
177
+ │ } │
178
+ └─────────────────┬───────────────────┘
179
+
180
+ ┌────────────────────────────┼────────────────────────────┐
181
+ │ │ │
182
+ ▼ ▼ ▼
183
+ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
184
+ │ react_runtime │ │ codeact_runtime │ │ agent_adapter │
185
+ │ (reads _limits,│ │ (reads _limits,│ │ (populates │
186
+ │ enforces) │ │ enforces) │ │ _limits) │
187
+ └─────────────────┘ └─────────────────┘ └─────────────────┘
188
+ ```
189
+
190
+ ---
191
+
192
+ ## Original Proposal
193
+
194
+ ### Goal
195
+ Make AbstractRuntime aware of runtime parameters (max_iterations, max_tokens, max_history_messages) with:
196
+ - Canonical storage in RunState.vars
197
+ - Runtime-level introspection and control
198
+ - Mid-session updates capability
199
+
200
+ ### Context / Problem
201
+ Parameters were scattered with no single source of truth:
202
+
203
+ | Parameter | Location | Problem |
204
+ |-----------|----------|---------|
205
+ | `max_iterations` | `scratchpad` | Only in one place, but not runtime-managed |
206
+ | `max_tokens` | `Logic._max_tokens` | Lost on resume, not in RunState |
207
+ | `max_history_messages` | `Logic._max_history_messages` | Lost on resume, not in RunState |
208
+
209
+ The Runtime class had **zero awareness** of these limits.
210
+
211
+ ### Non-goals
212
+ - No automatic enforcement by runtime (nodes enforce)
213
+ - No observability events in this phase (future work)
214
+ - No token counting (estimated_tokens_used is placeholder)
215
+
216
+ ---
217
+
218
+ ### Proposed Design
219
+
220
+ 1. **New `_limits` namespace** in RunState.vars as canonical storage
221
+ 2. **RuntimeConfig dataclass** for configuration and defaults
222
+ 3. **Runtime enhancements**: config property, limit methods
223
+ 4. **Hybrid enforcement**: runtime provides info, nodes enforce
224
+ 5. **Phased migration**: backward compatibility with scratchpad
225
+
226
+ ---
227
+
228
+ ### Acceptance Criteria
229
+
230
+ - [x] RuntimeConfig with to_limits_dict() method
231
+ - [x] Runtime accepts config parameter
232
+ - [x] Runtime.start() initializes _limits from config
233
+ - [x] Runtime.get_limit_status() returns structured status
234
+ - [x] Runtime.check_limits() returns LimitWarning list
235
+ - [x] Runtime.update_limits() persists changes
236
+ - [x] Adapters read from _limits with scratchpad fallback
237
+ - [x] Logic classes accept vars for limit overrides
238
+ - [x] Agent classes expose limit methods
239
+ - [x] All unit tests pass
240
+ - [x] Backward compatibility verified
@@ -0,0 +1,111 @@
1
+ ## 015_agent_integration_improvements (planned)
2
+
3
+ > Update (2025-12-15): Much of this item has been addressed by the framework-wide durable tool execution work:
4
+ > - AbstractAgent's ReAct workflow now uses `EffectType.TOOL_CALLS` (ledger-recorded, retry/idempotency-capable).
5
+ > - Tool execution is via host-configured `ToolExecutor` (durable; no callables in `RunState.vars`).
6
+ > - BaseAgent save/load is reference-only and delegates to RunStore.
7
+ >
8
+ > Remaining work is mostly *ergonomics* (a tiny convenience constructor in the integration layer), not core correctness.
9
+
10
+ ### Goal
11
+ Improve the integration experience between AbstractRuntime and agent implementations (like AbstractAgent's ReactAgent).
12
+
13
+ ### Context
14
+ Based on building AbstractAgent on top of AbstractRuntime, several friction points were identified:
15
+
16
+ 1. **Verbose agent setup** - Creating an agent requires multiple steps:
17
+ ```python
18
+ from abstractruntime.integrations.abstractcore import MappingToolExecutor, create_local_runtime
19
+ from abstractagent.agents.react import ReactAgent
20
+ from abstractagent.tools import ALL_TOOLS
21
+
22
+ tools = list(ALL_TOOLS)
23
+ runtime = create_local_runtime(
24
+ provider="ollama",
25
+ model="...",
26
+ tool_executor=MappingToolExecutor.from_tools(tools),
27
+ )
28
+ agent = ReactAgent(runtime=runtime, tools=tools)
29
+ ```
30
+
31
+ 2. **Tool execution durability** - Tool callables must never be stored in `RunState.vars` (must be JSON-safe across resume).
32
+
33
+ 3. **No run_id persistence at agent level** - Resuming an agent across process restarts requires manually tracking the run_id.
34
+
35
+ ### Proposed Improvements
36
+
37
+ #### 1. Agent Factory Pattern
38
+ Add a convenience factory in the AbstractCore integration:
39
+
40
+ ```python
41
+ # Current (still a little verbose, but correct)
42
+ from abstractruntime.integrations.abstractcore import MappingToolExecutor, create_local_runtime
43
+ from abstractagent.agents.react import ReactAgent
44
+
45
+ tools = [...]
46
+ runtime = create_local_runtime(
47
+ provider="ollama",
48
+ model="...",
49
+ tool_executor=MappingToolExecutor.from_tools(tools),
50
+ )
51
+ agent = ReactAgent(runtime=runtime, tools=tools)
52
+
53
+ # Proposed (simple)
54
+ from abstractruntime.integrations.abstractcore import create_agent_runtime
55
+
56
+ runtime = create_agent_runtime(
57
+ provider="ollama",
58
+ model="qwen3:4b-instruct-2507-q4_K_M",
59
+ tools=[list_files, read_file], # Direct tool functions
60
+ )
61
+ ```
62
+
63
+ #### 2. TOOL_CALLS Effect for Agent Tool Execution
64
+ Modify the ReAct workflow to use TOOL_CALLS effect instead of direct execution (now implemented):
65
+
66
+ ```python
67
+ # Previous (pre-effect): direct execution in act_node
68
+ # result = tool_registry.execute_tool(tool_call)
69
+
70
+ # Proposed: Via effect system
71
+ return StepPlan(
72
+ node_id="act",
73
+ effect=Effect(
74
+ type=EffectType.TOOL_CALLS,
75
+ payload={"tool_calls": pending_tool_calls},
76
+ result_key="tool_results",
77
+ ),
78
+ next_node="observe",
79
+ )
80
+ ```
81
+
82
+ Benefits:
83
+ - Tool calls recorded in ledger
84
+ - Retry/idempotency support
85
+ - Consistent architecture
86
+
87
+ #### 3. Agent State Persistence
88
+ Add optional run_id persistence to ReactAgent (now supported via BaseAgent.save_state/load_state):
89
+
90
+ ```python
91
+ agent = ReactAgent(runtime=runtime, state_file="agent_state.json")
92
+ agent.start("task") # Saves run_id to file
93
+ # ... process restart ...
94
+ agent = ReactAgent(runtime=runtime, state_file="agent_state.json")
95
+ agent.resume_from_file() # Loads run_id and continues
96
+ ```
97
+
98
+ ### Acceptance Criteria
99
+ - [ ] Agent creation requires ≤3 lines of code for simple cases
100
+ - [x] Tool execution is recorded in the ledger
101
+ - [x] Agent can resume across process restarts with minimal code
102
+
103
+ ### Dependencies
104
+ - AbstractCore tool registry
105
+ - Existing TOOL_CALLS effect handler
106
+
107
+ ### Priority
108
+ Medium - Improves developer experience but not blocking
109
+
110
+ ### Effort
111
+ Medium - 2-3 days