AbstractRuntime 0.4.0__py3-none-any.whl → 0.4.1__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.
- abstractruntime/__init__.py +76 -1
- abstractruntime/core/config.py +68 -1
- abstractruntime/core/models.py +5 -0
- abstractruntime/core/policy.py +74 -3
- abstractruntime/core/runtime.py +1002 -126
- abstractruntime/core/vars.py +8 -2
- abstractruntime/evidence/recorder.py +1 -1
- abstractruntime/history_bundle.py +772 -0
- abstractruntime/integrations/abstractcore/__init__.py +3 -0
- abstractruntime/integrations/abstractcore/default_tools.py +127 -3
- abstractruntime/integrations/abstractcore/effect_handlers.py +2440 -99
- abstractruntime/integrations/abstractcore/embeddings_client.py +69 -0
- abstractruntime/integrations/abstractcore/factory.py +68 -20
- abstractruntime/integrations/abstractcore/llm_client.py +447 -15
- abstractruntime/integrations/abstractcore/mcp_worker.py +1 -0
- abstractruntime/integrations/abstractcore/session_attachments.py +946 -0
- abstractruntime/integrations/abstractcore/tool_executor.py +31 -10
- abstractruntime/integrations/abstractcore/workspace_scoped_tools.py +561 -0
- abstractruntime/integrations/abstractmemory/__init__.py +3 -0
- abstractruntime/integrations/abstractmemory/effect_handlers.py +946 -0
- abstractruntime/memory/active_context.py +6 -1
- abstractruntime/memory/kg_packets.py +164 -0
- abstractruntime/memory/memact_composer.py +175 -0
- abstractruntime/memory/recall_levels.py +163 -0
- abstractruntime/memory/token_budget.py +86 -0
- abstractruntime/storage/__init__.py +4 -1
- abstractruntime/storage/artifacts.py +158 -30
- abstractruntime/storage/base.py +17 -1
- abstractruntime/storage/commands.py +339 -0
- abstractruntime/storage/in_memory.py +41 -1
- abstractruntime/storage/json_files.py +195 -12
- abstractruntime/storage/observable.py +38 -1
- abstractruntime/storage/offloading.py +433 -0
- abstractruntime/storage/sqlite.py +836 -0
- abstractruntime/visualflow_compiler/__init__.py +29 -0
- abstractruntime/visualflow_compiler/adapters/__init__.py +11 -0
- abstractruntime/visualflow_compiler/adapters/agent_adapter.py +126 -0
- abstractruntime/visualflow_compiler/adapters/context_adapter.py +109 -0
- abstractruntime/visualflow_compiler/adapters/control_adapter.py +615 -0
- abstractruntime/visualflow_compiler/adapters/effect_adapter.py +1051 -0
- abstractruntime/visualflow_compiler/adapters/event_adapter.py +307 -0
- abstractruntime/visualflow_compiler/adapters/function_adapter.py +97 -0
- abstractruntime/visualflow_compiler/adapters/memact_adapter.py +114 -0
- abstractruntime/visualflow_compiler/adapters/subflow_adapter.py +74 -0
- abstractruntime/visualflow_compiler/adapters/variable_adapter.py +316 -0
- abstractruntime/visualflow_compiler/compiler.py +3832 -0
- abstractruntime/visualflow_compiler/flow.py +247 -0
- abstractruntime/visualflow_compiler/visual/__init__.py +13 -0
- abstractruntime/visualflow_compiler/visual/agent_ids.py +29 -0
- abstractruntime/visualflow_compiler/visual/builtins.py +1376 -0
- abstractruntime/visualflow_compiler/visual/code_executor.py +214 -0
- abstractruntime/visualflow_compiler/visual/executor.py +2804 -0
- abstractruntime/visualflow_compiler/visual/models.py +211 -0
- abstractruntime/workflow_bundle/__init__.py +52 -0
- abstractruntime/workflow_bundle/models.py +236 -0
- abstractruntime/workflow_bundle/packer.py +317 -0
- abstractruntime/workflow_bundle/reader.py +87 -0
- abstractruntime/workflow_bundle/registry.py +587 -0
- abstractruntime-0.4.1.dist-info/METADATA +177 -0
- abstractruntime-0.4.1.dist-info/RECORD +86 -0
- abstractruntime-0.4.0.dist-info/METADATA +0 -167
- abstractruntime-0.4.0.dist-info/RECORD +0 -49
- {abstractruntime-0.4.0.dist-info → abstractruntime-0.4.1.dist-info}/WHEEL +0 -0
- {abstractruntime-0.4.0.dist-info → abstractruntime-0.4.1.dist-info}/entry_points.txt +0 -0
- {abstractruntime-0.4.0.dist-info → abstractruntime-0.4.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -18,6 +18,7 @@ from .llm_client import (
|
|
|
18
18
|
LocalAbstractCoreLLMClient,
|
|
19
19
|
RemoteAbstractCoreLLMClient,
|
|
20
20
|
)
|
|
21
|
+
from .embeddings_client import AbstractCoreEmbeddingsClient, EmbeddingsResult
|
|
21
22
|
from .tool_executor import AbstractCoreToolExecutor, MappingToolExecutor, PassthroughToolExecutor, ToolExecutor
|
|
22
23
|
from .effect_handlers import build_effect_handlers
|
|
23
24
|
from .factory import (
|
|
@@ -33,6 +34,8 @@ __all__ = [
|
|
|
33
34
|
"AbstractCoreLLMClient",
|
|
34
35
|
"LocalAbstractCoreLLMClient",
|
|
35
36
|
"RemoteAbstractCoreLLMClient",
|
|
37
|
+
"AbstractCoreEmbeddingsClient",
|
|
38
|
+
"EmbeddingsResult",
|
|
36
39
|
"RuntimeConfig",
|
|
37
40
|
"ToolExecutor",
|
|
38
41
|
"MappingToolExecutor",
|
|
@@ -11,11 +11,43 @@ Design notes:
|
|
|
11
11
|
|
|
12
12
|
from __future__ import annotations
|
|
13
13
|
|
|
14
|
+
import os
|
|
14
15
|
from typing import Any, Callable, Dict, List, Sequence
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
ToolCallable = Callable[..., Any]
|
|
18
19
|
|
|
20
|
+
_COMMS_ENABLE_ENV_VARS = (
|
|
21
|
+
"ABSTRACT_ENABLE_COMMS_TOOLS",
|
|
22
|
+
"ABSTRACT_ENABLE_EMAIL_TOOLS",
|
|
23
|
+
"ABSTRACT_ENABLE_WHATSAPP_TOOLS",
|
|
24
|
+
"ABSTRACT_ENABLE_TELEGRAM_TOOLS",
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _env_flag(name: str) -> bool:
|
|
29
|
+
raw = os.getenv(name)
|
|
30
|
+
if raw is None:
|
|
31
|
+
return False
|
|
32
|
+
return str(raw).strip().lower() in {"1", "true", "yes", "y", "on"}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def comms_tools_enabled() -> bool:
|
|
36
|
+
"""Return True when the host explicitly opts into comms tools via env."""
|
|
37
|
+
return any(_env_flag(k) for k in _COMMS_ENABLE_ENV_VARS)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def email_tools_enabled() -> bool:
|
|
41
|
+
return _env_flag("ABSTRACT_ENABLE_COMMS_TOOLS") or _env_flag("ABSTRACT_ENABLE_EMAIL_TOOLS")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def whatsapp_tools_enabled() -> bool:
|
|
45
|
+
return _env_flag("ABSTRACT_ENABLE_COMMS_TOOLS") or _env_flag("ABSTRACT_ENABLE_WHATSAPP_TOOLS")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def telegram_tools_enabled() -> bool:
|
|
49
|
+
return _env_flag("ABSTRACT_ENABLE_COMMS_TOOLS") or _env_flag("ABSTRACT_ENABLE_TELEGRAM_TOOLS")
|
|
50
|
+
|
|
19
51
|
|
|
20
52
|
def _tool_name(func: ToolCallable) -> str:
|
|
21
53
|
tool_def = getattr(func, "_tool_definition", None)
|
|
@@ -36,12 +68,41 @@ def _tool_spec(func: ToolCallable) -> Dict[str, Any]:
|
|
|
36
68
|
|
|
37
69
|
return dict(ToolDefinition.from_function(func).to_dict())
|
|
38
70
|
|
|
71
|
+
def _normalize_tool_spec(spec: Dict[str, Any]) -> Dict[str, Any]:
|
|
72
|
+
"""Normalize ToolSpec quirks for better UI/LLM ergonomics.
|
|
73
|
+
|
|
74
|
+
This is a presentation layer: it must not change tool execution semantics.
|
|
75
|
+
"""
|
|
76
|
+
name = str(spec.get("name") or "").strip()
|
|
77
|
+
if not name:
|
|
78
|
+
return spec
|
|
79
|
+
|
|
80
|
+
# AbstractCore's `skim_*` tools accept multiple paths and can parse strings for
|
|
81
|
+
# backward compatibility, but the preferred shape is an array-of-strings.
|
|
82
|
+
if name in {"skim_files", "skim_folders"}:
|
|
83
|
+
params = spec.get("parameters")
|
|
84
|
+
if isinstance(params, dict):
|
|
85
|
+
paths_schema = params.get("paths")
|
|
86
|
+
if isinstance(paths_schema, dict):
|
|
87
|
+
desc = paths_schema.get("description")
|
|
88
|
+
normalized = {
|
|
89
|
+
"type": "array",
|
|
90
|
+
"items": {"type": "string"},
|
|
91
|
+
}
|
|
92
|
+
if isinstance(desc, str) and desc.strip():
|
|
93
|
+
normalized["description"] = desc.strip()
|
|
94
|
+
params["paths"] = normalized
|
|
95
|
+
|
|
96
|
+
return spec
|
|
97
|
+
|
|
39
98
|
|
|
40
99
|
def get_default_toolsets() -> Dict[str, Dict[str, Any]]:
|
|
41
100
|
"""Return default toolsets {id -> {label, tools:[callables]}}."""
|
|
42
101
|
from abstractcore.tools.common_tools import (
|
|
43
102
|
list_files,
|
|
103
|
+
skim_folders,
|
|
44
104
|
read_file,
|
|
105
|
+
skim_files,
|
|
45
106
|
search_files,
|
|
46
107
|
analyze_code,
|
|
47
108
|
write_file,
|
|
@@ -51,11 +112,11 @@ def get_default_toolsets() -> Dict[str, Dict[str, Any]]:
|
|
|
51
112
|
execute_command,
|
|
52
113
|
)
|
|
53
114
|
|
|
54
|
-
|
|
115
|
+
toolsets: Dict[str, Dict[str, Any]] = {
|
|
55
116
|
"files": {
|
|
56
117
|
"id": "files",
|
|
57
118
|
"label": "Files",
|
|
58
|
-
"tools": [list_files, search_files, analyze_code, read_file, write_file, edit_file],
|
|
119
|
+
"tools": [list_files, skim_folders, search_files, analyze_code, skim_files, read_file, write_file, edit_file],
|
|
59
120
|
},
|
|
60
121
|
"web": {
|
|
61
122
|
"id": "web",
|
|
@@ -69,6 +130,30 @@ def get_default_toolsets() -> Dict[str, Dict[str, Any]]:
|
|
|
69
130
|
},
|
|
70
131
|
}
|
|
71
132
|
|
|
133
|
+
if comms_tools_enabled():
|
|
134
|
+
comms: list[ToolCallable] = []
|
|
135
|
+
if email_tools_enabled():
|
|
136
|
+
from abstractcore.tools.comms_tools import list_email_accounts, list_emails, read_email, send_email
|
|
137
|
+
|
|
138
|
+
comms.extend([list_email_accounts, send_email, list_emails, read_email])
|
|
139
|
+
if whatsapp_tools_enabled():
|
|
140
|
+
from abstractcore.tools.comms_tools import list_whatsapp_messages, read_whatsapp_message, send_whatsapp_message
|
|
141
|
+
|
|
142
|
+
comms.extend([send_whatsapp_message, list_whatsapp_messages, read_whatsapp_message])
|
|
143
|
+
if telegram_tools_enabled():
|
|
144
|
+
from abstractcore.tools.telegram_tools import send_telegram_artifact, send_telegram_message
|
|
145
|
+
|
|
146
|
+
comms.extend([send_telegram_message, send_telegram_artifact])
|
|
147
|
+
|
|
148
|
+
if comms:
|
|
149
|
+
toolsets["comms"] = {
|
|
150
|
+
"id": "comms",
|
|
151
|
+
"label": "Comms",
|
|
152
|
+
"tools": comms,
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return toolsets
|
|
156
|
+
|
|
72
157
|
|
|
73
158
|
def get_default_tools() -> List[ToolCallable]:
|
|
74
159
|
"""Return the flattened list of all default tool callables."""
|
|
@@ -100,13 +185,52 @@ def list_default_tool_specs() -> List[Dict[str, Any]]:
|
|
|
100
185
|
|
|
101
186
|
out: list[Dict[str, Any]] = []
|
|
102
187
|
for tool in get_default_tools():
|
|
103
|
-
spec = _tool_spec(tool)
|
|
188
|
+
spec = _normalize_tool_spec(_tool_spec(tool))
|
|
104
189
|
name = str(spec.get("name") or "").strip()
|
|
105
190
|
if not name:
|
|
106
191
|
continue
|
|
107
192
|
spec["toolset"] = toolset_by_name.get(name) or "other"
|
|
108
193
|
out.append(spec)
|
|
109
194
|
|
|
195
|
+
# Runtime-owned tools (no host callable).
|
|
196
|
+
#
|
|
197
|
+
# Rationale: these tools require runtime context/state (e.g., session-scoped ArtifactStore access)
|
|
198
|
+
# and are executed inside the runtime effect handlers instead of via a host ToolExecutor.
|
|
199
|
+
out.append(
|
|
200
|
+
{
|
|
201
|
+
"name": "open_attachment",
|
|
202
|
+
"description": "Open a session attachment; returns text (excerpt or full if max_chars<=0) and attaches media for the next LLM call.",
|
|
203
|
+
"when_to_use": (
|
|
204
|
+
"Re-open a previously attached file; text returns an excerpt by default (or full when max_chars<=0), "
|
|
205
|
+
"media is attached as `media` on the next call. Do not call if it is already present in the current messages/media."
|
|
206
|
+
),
|
|
207
|
+
"parameters": {
|
|
208
|
+
"artifact_id": {"type": "string", "default": None},
|
|
209
|
+
"handle": {"type": "string", "default": None},
|
|
210
|
+
"expected_sha256": {"type": "string", "default": None},
|
|
211
|
+
"start_line": {"type": "integer", "default": 1},
|
|
212
|
+
"end_line": {"type": "integer", "default": None},
|
|
213
|
+
"max_chars": {"type": "integer", "default": 8000},
|
|
214
|
+
},
|
|
215
|
+
"required_args": [],
|
|
216
|
+
"examples": [
|
|
217
|
+
{
|
|
218
|
+
"description": "Open by artifact id (preferred)",
|
|
219
|
+
"arguments": {"artifact_id": "abc123", "start_line": 1, "end_line": 80},
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
"description": "Open by handle",
|
|
223
|
+
"arguments": {"handle": "@docs/architecture.md", "max_chars": 2000},
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
"description": "Open full text (no cap)",
|
|
227
|
+
"arguments": {"artifact_id": "abc123", "max_chars": 0},
|
|
228
|
+
},
|
|
229
|
+
],
|
|
230
|
+
"toolset": "files",
|
|
231
|
+
}
|
|
232
|
+
)
|
|
233
|
+
|
|
110
234
|
# Stable ordering: toolset then name
|
|
111
235
|
out.sort(key=lambda s: (str(s.get("toolset") or ""), str(s.get("name") or "")))
|
|
112
236
|
return out
|