AbstractRuntime 0.0.1__py3-none-any.whl → 0.4.0__py3-none-any.whl

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 (37) hide show
  1. abstractruntime/__init__.py +7 -2
  2. abstractruntime/core/__init__.py +9 -2
  3. abstractruntime/core/config.py +114 -0
  4. abstractruntime/core/event_keys.py +62 -0
  5. abstractruntime/core/models.py +55 -1
  6. abstractruntime/core/runtime.py +2609 -24
  7. abstractruntime/core/vars.py +189 -0
  8. abstractruntime/evidence/__init__.py +10 -0
  9. abstractruntime/evidence/recorder.py +325 -0
  10. abstractruntime/integrations/abstractcore/__init__.py +9 -2
  11. abstractruntime/integrations/abstractcore/constants.py +19 -0
  12. abstractruntime/integrations/abstractcore/default_tools.py +134 -0
  13. abstractruntime/integrations/abstractcore/effect_handlers.py +288 -9
  14. abstractruntime/integrations/abstractcore/factory.py +133 -11
  15. abstractruntime/integrations/abstractcore/llm_client.py +547 -42
  16. abstractruntime/integrations/abstractcore/mcp_worker.py +586 -0
  17. abstractruntime/integrations/abstractcore/observability.py +80 -0
  18. abstractruntime/integrations/abstractcore/summarizer.py +154 -0
  19. abstractruntime/integrations/abstractcore/tool_executor.py +544 -8
  20. abstractruntime/memory/__init__.py +21 -0
  21. abstractruntime/memory/active_context.py +746 -0
  22. abstractruntime/memory/active_memory.py +452 -0
  23. abstractruntime/memory/compaction.py +105 -0
  24. abstractruntime/rendering/__init__.py +17 -0
  25. abstractruntime/rendering/agent_trace_report.py +256 -0
  26. abstractruntime/rendering/json_stringify.py +136 -0
  27. abstractruntime/scheduler/scheduler.py +93 -2
  28. abstractruntime/storage/__init__.py +3 -1
  29. abstractruntime/storage/artifacts.py +51 -5
  30. abstractruntime/storage/json_files.py +16 -3
  31. abstractruntime/storage/observable.py +99 -0
  32. {abstractruntime-0.0.1.dist-info → abstractruntime-0.4.0.dist-info}/METADATA +5 -1
  33. abstractruntime-0.4.0.dist-info/RECORD +49 -0
  34. abstractruntime-0.4.0.dist-info/entry_points.txt +2 -0
  35. abstractruntime-0.0.1.dist-info/RECORD +0 -30
  36. {abstractruntime-0.0.1.dist-info → abstractruntime-0.4.0.dist-info}/WHEEL +0 -0
  37. {abstractruntime-0.0.1.dist-info → abstractruntime-0.4.0.dist-info}/licenses/LICENSE +0 -0
@@ -15,14 +15,19 @@ from __future__ import annotations
15
15
  from pathlib import Path
16
16
  from typing import Any, Dict, Optional
17
17
 
18
+ from ...core.config import RuntimeConfig
18
19
  from ...core.runtime import Runtime
19
20
  from ...storage.in_memory import InMemoryLedgerStore, InMemoryRunStore
20
21
  from ...storage.json_files import JsonFileRunStore, JsonlLedgerStore
21
22
  from ...storage.base import LedgerStore, RunStore
23
+ from ...storage.artifacts import FileArtifactStore, InMemoryArtifactStore, ArtifactStore
24
+ from ...storage.observable import ObservableLedgerStore, ObservableLedgerStoreProtocol
22
25
 
23
26
  from .effect_handlers import build_effect_handlers
24
- from .llm_client import LocalAbstractCoreLLMClient, RemoteAbstractCoreLLMClient
27
+ from .llm_client import MultiLocalAbstractCoreLLMClient, RemoteAbstractCoreLLMClient
25
28
  from .tool_executor import AbstractCoreToolExecutor, PassthroughToolExecutor, ToolExecutor
29
+ from .summarizer import AbstractCoreChatSummarizer
30
+ from .constants import DEFAULT_LLM_TIMEOUT_S, DEFAULT_TOOL_TIMEOUT_S
26
31
 
27
32
 
28
33
  def _default_in_memory_stores() -> tuple[RunStore, LedgerStore]:
@@ -34,6 +39,18 @@ def _default_file_stores(*, base_dir: str | Path) -> tuple[RunStore, LedgerStore
34
39
  base.mkdir(parents=True, exist_ok=True)
35
40
  return JsonFileRunStore(base), JsonlLedgerStore(base)
36
41
 
42
+ def _ensure_observable_ledger(ledger_store: LedgerStore) -> LedgerStore:
43
+ """Wrap a LedgerStore so Runtime.subscribe_ledger() is available (in-process).
44
+
45
+ Why:
46
+ - Real-time UI/UX often needs "step started" signals *before* a blocking effect
47
+ (LLM/tool HTTP) returns.
48
+ - The runtime kernel stays transport-agnostic; this is an optional decorator.
49
+ """
50
+ if isinstance(ledger_store, ObservableLedgerStoreProtocol):
51
+ return ledger_store
52
+ return ObservableLedgerStore(ledger_store)
53
+
37
54
 
38
55
  def create_local_runtime(
39
56
  *,
@@ -43,17 +60,86 @@ def create_local_runtime(
43
60
  run_store: Optional[RunStore] = None,
44
61
  ledger_store: Optional[LedgerStore] = None,
45
62
  tool_executor: Optional[ToolExecutor] = None,
63
+ tool_timeout_s: float = DEFAULT_TOOL_TIMEOUT_S,
46
64
  context: Optional[Any] = None,
47
65
  effect_policy: Optional[Any] = None,
66
+ config: Optional[RuntimeConfig] = None,
67
+ artifact_store: Optional[ArtifactStore] = None,
48
68
  ) -> Runtime:
69
+ """Create a runtime with local LLM execution via AbstractCore.
70
+
71
+ Args:
72
+ provider: LLM provider (e.g., "ollama", "openai")
73
+ model: Model name
74
+ llm_kwargs: Additional kwargs for LLM client
75
+ run_store: Storage for run state (default: in-memory)
76
+ ledger_store: Storage for ledger (default: in-memory)
77
+ tool_executor: Optional custom tool executor. If not provided, defaults
78
+ to `AbstractCoreToolExecutor()` (AbstractCore global tool registry).
79
+ context: Optional context object
80
+ effect_policy: Optional effect policy (retry, etc.)
81
+ config: Optional RuntimeConfig for limits and model capabilities.
82
+ If not provided, model capabilities are queried from the LLM client.
83
+
84
+ Note:
85
+ For durable execution, tool callables should never be stored in `RunState.vars`
86
+ or passed in effect payloads. Prefer `MappingToolExecutor.from_tools([...])`.
87
+ """
49
88
  if run_store is None or ledger_store is None:
50
89
  run_store, ledger_store = _default_in_memory_stores()
90
+ ledger_store = _ensure_observable_ledger(ledger_store)
91
+
92
+ if artifact_store is None:
93
+ artifact_store = InMemoryArtifactStore()
94
+
95
+ # Runtime authority: default LLM timeout for orchestrated workflows.
96
+ #
97
+ # We set this here (in the runtime layer) rather than relying on AbstractCore global config,
98
+ # so workflow behavior is consistent and controlled by the orchestrator.
99
+ effective_llm_kwargs: Dict[str, Any] = dict(llm_kwargs or {})
100
+ effective_llm_kwargs.setdefault("timeout", DEFAULT_LLM_TIMEOUT_S)
51
101
 
52
- llm_client = LocalAbstractCoreLLMClient(provider=provider, model=model, llm_kwargs=llm_kwargs)
53
- tools = tool_executor or AbstractCoreToolExecutor()
102
+ llm_client = MultiLocalAbstractCoreLLMClient(provider=provider, model=model, llm_kwargs=effective_llm_kwargs)
103
+ tools = tool_executor or AbstractCoreToolExecutor(timeout_s=tool_timeout_s)
104
+ # Orchestrator policy: enforce tool execution timeout at the runtime layer.
105
+ try:
106
+ setter = getattr(tools, "set_timeout_s", None)
107
+ if callable(setter):
108
+ setter(tool_timeout_s)
109
+ except Exception:
110
+ pass
54
111
  handlers = build_effect_handlers(llm=llm_client, tools=tools)
55
112
 
56
- return Runtime(run_store=run_store, ledger_store=ledger_store, effect_handlers=handlers, context=context, effect_policy=effect_policy)
113
+ # Query model capabilities and merge into config
114
+ capabilities = llm_client.get_model_capabilities()
115
+ if config is None:
116
+ config = RuntimeConfig(
117
+ provider=str(provider).strip() if isinstance(provider, str) and str(provider).strip() else None,
118
+ model=str(model).strip() if isinstance(model, str) and str(model).strip() else None,
119
+ model_capabilities=capabilities,
120
+ )
121
+ else:
122
+ # Merge capabilities into provided config
123
+ config = config.with_capabilities(capabilities)
124
+
125
+ # Create chat summarizer with token limits from config
126
+ # This enables adaptive chunking during MEMORY_COMPACT
127
+ summarizer = AbstractCoreChatSummarizer(
128
+ llm=llm_client._llm, # Use the underlying AbstractCore LLM instance
129
+ max_tokens=config.max_tokens if config.max_tokens is not None else -1,
130
+ max_output_tokens=config.max_output_tokens if config.max_output_tokens is not None else -1,
131
+ )
132
+
133
+ return Runtime(
134
+ run_store=run_store,
135
+ ledger_store=ledger_store,
136
+ effect_handlers=handlers,
137
+ context=context,
138
+ effect_policy=effect_policy,
139
+ config=config,
140
+ artifact_store=artifact_store,
141
+ chat_summarizer=summarizer,
142
+ )
57
143
 
58
144
 
59
145
  def create_remote_runtime(
@@ -61,14 +147,19 @@ def create_remote_runtime(
61
147
  server_base_url: str,
62
148
  model: str,
63
149
  headers: Optional[Dict[str, str]] = None,
64
- timeout_s: float = 60.0,
150
+ timeout_s: float = DEFAULT_LLM_TIMEOUT_S,
65
151
  run_store: Optional[RunStore] = None,
66
152
  ledger_store: Optional[LedgerStore] = None,
67
153
  tool_executor: Optional[ToolExecutor] = None,
68
154
  context: Optional[Any] = None,
155
+ artifact_store: Optional[ArtifactStore] = None,
69
156
  ) -> Runtime:
70
157
  if run_store is None or ledger_store is None:
71
158
  run_store, ledger_store = _default_in_memory_stores()
159
+ ledger_store = _ensure_observable_ledger(ledger_store)
160
+
161
+ if artifact_store is None:
162
+ artifact_store = InMemoryArtifactStore()
72
163
 
73
164
  llm_client = RemoteAbstractCoreLLMClient(
74
165
  server_base_url=server_base_url,
@@ -79,7 +170,13 @@ def create_remote_runtime(
79
170
  tools = tool_executor or PassthroughToolExecutor()
80
171
  handlers = build_effect_handlers(llm=llm_client, tools=tools)
81
172
 
82
- return Runtime(run_store=run_store, ledger_store=ledger_store, effect_handlers=handlers, context=context)
173
+ return Runtime(
174
+ run_store=run_store,
175
+ ledger_store=ledger_store,
176
+ effect_handlers=handlers,
177
+ context=context,
178
+ artifact_store=artifact_store,
179
+ )
83
180
 
84
181
 
85
182
  def create_hybrid_runtime(
@@ -87,15 +184,21 @@ def create_hybrid_runtime(
87
184
  server_base_url: str,
88
185
  model: str,
89
186
  headers: Optional[Dict[str, str]] = None,
90
- timeout_s: float = 60.0,
187
+ timeout_s: float = DEFAULT_LLM_TIMEOUT_S,
188
+ tool_timeout_s: float = DEFAULT_TOOL_TIMEOUT_S,
91
189
  run_store: Optional[RunStore] = None,
92
190
  ledger_store: Optional[LedgerStore] = None,
93
191
  context: Optional[Any] = None,
192
+ artifact_store: Optional[ArtifactStore] = None,
94
193
  ) -> Runtime:
95
194
  """Remote LLM via AbstractCore server, local tool execution."""
96
195
 
97
196
  if run_store is None or ledger_store is None:
98
197
  run_store, ledger_store = _default_in_memory_stores()
198
+ ledger_store = _ensure_observable_ledger(ledger_store)
199
+
200
+ if artifact_store is None:
201
+ artifact_store = InMemoryArtifactStore()
99
202
 
100
203
  llm_client = RemoteAbstractCoreLLMClient(
101
204
  server_base_url=server_base_url,
@@ -103,10 +206,22 @@ def create_hybrid_runtime(
103
206
  headers=headers,
104
207
  timeout_s=timeout_s,
105
208
  )
106
- tools = AbstractCoreToolExecutor()
209
+ tools = AbstractCoreToolExecutor(timeout_s=tool_timeout_s)
210
+ try:
211
+ setter = getattr(tools, "set_timeout_s", None)
212
+ if callable(setter):
213
+ setter(tool_timeout_s)
214
+ except Exception:
215
+ pass
107
216
  handlers = build_effect_handlers(llm=llm_client, tools=tools)
108
217
 
109
- return Runtime(run_store=run_store, ledger_store=ledger_store, effect_handlers=handlers, context=context)
218
+ return Runtime(
219
+ run_store=run_store,
220
+ ledger_store=ledger_store,
221
+ effect_handlers=handlers,
222
+ context=context,
223
+ artifact_store=artifact_store,
224
+ )
110
225
 
111
226
 
112
227
  def create_local_file_runtime(
@@ -116,8 +231,11 @@ def create_local_file_runtime(
116
231
  model: str,
117
232
  llm_kwargs: Optional[Dict[str, Any]] = None,
118
233
  context: Optional[Any] = None,
234
+ config: Optional[RuntimeConfig] = None,
235
+ tool_timeout_s: float = DEFAULT_TOOL_TIMEOUT_S,
119
236
  ) -> Runtime:
120
237
  run_store, ledger_store = _default_file_stores(base_dir=base_dir)
238
+ artifact_store = FileArtifactStore(base_dir)
121
239
  return create_local_runtime(
122
240
  provider=provider,
123
241
  model=model,
@@ -125,6 +243,9 @@ def create_local_file_runtime(
125
243
  run_store=run_store,
126
244
  ledger_store=ledger_store,
127
245
  context=context,
246
+ config=config,
247
+ artifact_store=artifact_store,
248
+ tool_timeout_s=tool_timeout_s,
128
249
  )
129
250
 
130
251
 
@@ -134,10 +255,11 @@ def create_remote_file_runtime(
134
255
  server_base_url: str,
135
256
  model: str,
136
257
  headers: Optional[Dict[str, str]] = None,
137
- timeout_s: float = 60.0,
258
+ timeout_s: float = DEFAULT_LLM_TIMEOUT_S,
138
259
  context: Optional[Any] = None,
139
260
  ) -> Runtime:
140
261
  run_store, ledger_store = _default_file_stores(base_dir=base_dir)
262
+ artifact_store = FileArtifactStore(base_dir)
141
263
  return create_remote_runtime(
142
264
  server_base_url=server_base_url,
143
265
  model=model,
@@ -146,5 +268,5 @@ def create_remote_file_runtime(
146
268
  run_store=run_store,
147
269
  ledger_store=ledger_store,
148
270
  context=context,
271
+ artifact_store=artifact_store,
149
272
  )
150
-