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.
- abstractruntime-0.2.0/CHANGELOG.md +132 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/PKG-INFO +1 -1
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/ROADMAP.md +13 -12
- abstractruntime-0.2.0/docs/backlog/completed/010_examples_and_composition.md +59 -0
- abstractruntime-0.2.0/docs/backlog/completed/016_runtime_aware_parameters.md +240 -0
- abstractruntime-0.2.0/docs/backlog/planned/015_agent_integration_improvements.md +111 -0
- abstractruntime-0.2.0/docs/backlog/planned/017_limit_warnings_and_observability.md +141 -0
- abstractruntime-0.2.0/docs/limits.md +266 -0
- abstractruntime-0.2.0/examples/01_hello_world.py +60 -0
- abstractruntime-0.2.0/examples/02_ask_user.py +134 -0
- abstractruntime-0.2.0/examples/03_wait_until.py +94 -0
- abstractruntime-0.2.0/examples/04_multi_step.py +100 -0
- abstractruntime-0.2.0/examples/05_persistence.py +173 -0
- abstractruntime-0.2.0/examples/06_llm_integration.py +102 -0
- abstractruntime-0.2.0/examples/07_react_agent.py +124 -0
- abstractruntime-0.2.0/examples/README.md +45 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/pyproject.toml +1 -1
- abstractruntime-0.2.0/src/abstractruntime/core/__init__.py +26 -0
- abstractruntime-0.2.0/src/abstractruntime/core/config.py +101 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/core/models.py +44 -1
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/core/runtime.py +165 -10
- abstractruntime-0.2.0/src/abstractruntime/core/vars.py +94 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/integrations/abstractcore/__init__.py +6 -2
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/integrations/abstractcore/effect_handlers.py +34 -4
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/integrations/abstractcore/factory.py +39 -2
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/integrations/abstractcore/llm_client.py +132 -31
- abstractruntime-0.2.0/src/abstractruntime/integrations/abstractcore/tool_executor.py +168 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/storage/artifacts.py +31 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/storage/json_files.py +1 -1
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/tests/test_artifacts.py +24 -0
- abstractruntime-0.2.0/tests/test_durable_toolsets.py +75 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/tests/test_integration_abstractcore.py +6 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/tests/test_retry_idempotency.py +23 -0
- abstractruntime-0.2.0/tests/test_trace_context_propagation.py +108 -0
- abstractruntime-0.0.1/docs/backlog/planned/010_examples_and_composition.md +0 -29
- abstractruntime-0.0.1/src/abstractruntime/core/__init__.py +0 -19
- abstractruntime-0.0.1/src/abstractruntime/integrations/abstractcore/tool_executor.py +0 -89
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/.gitignore +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/LICENSE +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/README.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/adr/0001_layered_coupling_with_abstractcore.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/adr/0002_execution_modes_local_remote_hybrid.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/adr/0003_provenance_tamper_evident_hash_chain.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/adr/README.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/README.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/completed/001_runtime_kernel.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/completed/002_persistence_and_ledger.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/completed/003_wait_primitives.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/completed/004_scheduler_driver.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/completed/005_abstractcore_integration.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/completed/006_snapshots_bookmarks.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/completed/007_provenance_hash_chain.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/completed/009_artifact_store.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/completed/011_subworkflow_support.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/completed/012_run_store_query_and_scheduler_support.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/completed/013_effect_retries_and_idempotency.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/deprecated/001_integrations_abstractcore.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/deprecated/001_runtime_kernel.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/deprecated/002_persistence_and_ledger.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/deprecated/002_snapshots_bookmarks.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/deprecated/003_provenance_ledger_chain.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/deprecated/003_wait_resume_and_scheduler.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/deprecated/004_effect_handlers_and_integrations.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/deprecated/004_tests.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/deprecated/005_docs_updates.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/deprecated/005_examples_and_composition.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/deprecated/006_ai_fingerprint_and_provenance.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/deprecated/DEPRECATED_README.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/deprecated/README.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/deprecated/abstractruntime_docs_final_02a7373b.plan.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/planned/008_signatures_and_keys.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/backlog/planned/014_remote_tool_worker_executor.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/integrations/abstractcore.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/manual_testing.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/proposal.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/provenance.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/docs/snapshots.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/__init__.py +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/core/policy.py +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/core/spec.py +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/identity/__init__.py +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/identity/fingerprint.py +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/integrations/__init__.py +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/integrations/abstractcore/logging.py +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/scheduler/__init__.py +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/scheduler/convenience.py +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/scheduler/registry.py +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/scheduler/scheduler.py +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/storage/__init__.py +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/storage/base.py +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/storage/in_memory.py +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/storage/ledger_chain.py +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/src/abstractruntime/storage/snapshots.py +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/tests/README.md +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/tests/conftest.py +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/tests/test_integrations_abstractcore.py +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/tests/test_ledger_chain.py +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/tests/test_pause_resume.py +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/tests/test_queryable_run_store.py +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/tests/test_real_integration.py +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/tests/test_remote_llm_client.py +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/tests/test_scheduler.py +0 -0
- {abstractruntime-0.0.1 → abstractruntime-0.2.0}/tests/test_snapshots.py +0 -0
- {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
|
|
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
|
-
**
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
-
|
|
100
|
-
-
|
|
101
|
-
-
|
|
102
|
-
-
|
|
103
|
-
-
|
|
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)**:
|
|
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
|
|
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
|