AbstractAgent 0.3.0__tar.gz → 0.3.4__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 (78) hide show
  1. abstractagent-0.3.4/PKG-INFO +157 -0
  2. abstractagent-0.3.4/README.md +130 -0
  3. abstractagent-0.3.4/pyproject.toml +51 -0
  4. {abstractagent-0.3.0 → abstractagent-0.3.4}/src/abstractagent/adapters/codeact_runtime.py +86 -5
  5. abstractagent-0.3.4/src/abstractagent/adapters/generation_params.py +82 -0
  6. abstractagent-0.3.4/src/abstractagent/adapters/media.py +45 -0
  7. {abstractagent-0.3.0 → abstractagent-0.3.4}/src/abstractagent/adapters/memact_runtime.py +248 -10
  8. abstractagent-0.3.4/src/abstractagent/adapters/react_runtime.py +1612 -0
  9. {abstractagent-0.3.0 → abstractagent-0.3.4}/src/abstractagent/agents/base.py +31 -0
  10. {abstractagent-0.3.0 → abstractagent-0.3.4}/src/abstractagent/agents/codeact.py +36 -0
  11. {abstractagent-0.3.0 → abstractagent-0.3.4}/src/abstractagent/agents/memact.py +37 -1
  12. {abstractagent-0.3.0 → abstractagent-0.3.4}/src/abstractagent/agents/react.py +44 -6
  13. {abstractagent-0.3.0 → abstractagent-0.3.4}/src/abstractagent/logic/builtins.py +58 -0
  14. {abstractagent-0.3.0 → abstractagent-0.3.4}/src/abstractagent/logic/codeact.py +4 -1
  15. {abstractagent-0.3.0 → abstractagent-0.3.4}/src/abstractagent/logic/memact.py +2 -1
  16. {abstractagent-0.3.0 → abstractagent-0.3.4}/src/abstractagent/logic/react.py +37 -56
  17. {abstractagent-0.3.0 → abstractagent-0.3.4}/src/abstractagent/tools/__init__.py +6 -0
  18. abstractagent-0.3.4/src/abstractagent.egg-info/PKG-INFO +157 -0
  19. {abstractagent-0.3.0 → abstractagent-0.3.4}/src/abstractagent.egg-info/SOURCES.txt +16 -5
  20. abstractagent-0.3.4/src/abstractagent.egg-info/requires.txt +24 -0
  21. {abstractagent-0.3.0 → abstractagent-0.3.4}/tests/test_active_context_policy_adoption.py +4 -4
  22. {abstractagent-0.3.0 → abstractagent-0.3.4}/tests/test_agent_plan_review_modes.py +11 -48
  23. abstractagent-0.3.4/tests/test_generation_params_media_policies.py +28 -0
  24. abstractagent-0.3.4/tests/test_llm_call_payload_requires_prompt_or_messages.py +84 -0
  25. abstractagent-0.3.4/tests/test_open_attachment_tool_available.py +29 -0
  26. abstractagent-0.3.4/tests/test_react_active_attachments_disable_tools_first_iteration.py +144 -0
  27. abstractagent-0.3.4/tests/test_react_adapter_forwards_context_attachments_media.py +46 -0
  28. abstractagent-0.3.4/tests/test_react_delegate_agent_tool.py +85 -0
  29. {abstractagent-0.3.0 → abstractagent-0.3.4}/tests/test_react_logic.py +9 -0
  30. abstractagent-0.3.4/tests/test_react_loop_context_transcript_levels.py +281 -0
  31. abstractagent-0.3.4/tests/test_react_loop_followthrough_retry.py +99 -0
  32. abstractagent-0.3.4/tests/test_react_loop_side_effect_dedupe_comms.py +77 -0
  33. abstractagent-0.3.4/tests/test_react_loop_truncated_output_retry.py +209 -0
  34. abstractagent-0.3.4/tests/test_react_max_iterations_concludes.py +186 -0
  35. abstractagent-0.3.4/tests/test_react_planish_heuristic.py +29 -0
  36. {abstractagent-0.3.0 → abstractagent-0.3.4}/tests/test_react_workflow_system_prompt_and_tools_override.py +29 -0
  37. abstractagent-0.3.4/tests/test_react_workflow_toolset_refresh.py +73 -0
  38. abstractagent-0.3.4/tests/test_tool_observe_emits_result_for_tui.py +103 -0
  39. abstractagent-0.3.0/PKG-INFO +0 -133
  40. abstractagent-0.3.0/README.md +0 -120
  41. abstractagent-0.3.0/pyproject.toml +0 -25
  42. abstractagent-0.3.0/src/abstractagent/adapters/react_runtime.py +0 -1437
  43. abstractagent-0.3.0/src/abstractagent.egg-info/PKG-INFO +0 -133
  44. abstractagent-0.3.0/src/abstractagent.egg-info/requires.txt +0 -5
  45. abstractagent-0.3.0/tests/test_prompt_deobservation.py +0 -95
  46. abstractagent-0.3.0/tests/test_react_runtime_parse_sanitizes_observation_transcripts.py +0 -66
  47. abstractagent-0.3.0/tests/test_react_runtime_tool_loop_guard.py +0 -148
  48. abstractagent-0.3.0/tests/test_react_runtime_verifier_policy.py +0 -97
  49. abstractagent-0.3.0/tests/test_toolcall_queue_and_review_prompt.py +0 -289
  50. {abstractagent-0.3.0 → abstractagent-0.3.4}/LICENSE +0 -0
  51. {abstractagent-0.3.0 → abstractagent-0.3.4}/setup.cfg +0 -0
  52. {abstractagent-0.3.0 → abstractagent-0.3.4}/src/abstractagent/__init__.py +0 -0
  53. {abstractagent-0.3.0 → abstractagent-0.3.4}/src/abstractagent/adapters/__init__.py +0 -0
  54. {abstractagent-0.3.0 → abstractagent-0.3.4}/src/abstractagent/agents/__init__.py +0 -0
  55. {abstractagent-0.3.0 → abstractagent-0.3.4}/src/abstractagent/logic/__init__.py +0 -0
  56. {abstractagent-0.3.0 → abstractagent-0.3.4}/src/abstractagent/logic/types.py +0 -0
  57. {abstractagent-0.3.0 → abstractagent-0.3.4}/src/abstractagent/repl.py +0 -0
  58. {abstractagent-0.3.0 → abstractagent-0.3.4}/src/abstractagent/sandbox/__init__.py +0 -0
  59. {abstractagent-0.3.0 → abstractagent-0.3.4}/src/abstractagent/sandbox/interface.py +0 -0
  60. {abstractagent-0.3.0 → abstractagent-0.3.4}/src/abstractagent/sandbox/local.py +0 -0
  61. {abstractagent-0.3.0 → abstractagent-0.3.4}/src/abstractagent/scripts/__init__.py +0 -0
  62. {abstractagent-0.3.0 → abstractagent-0.3.4}/src/abstractagent/scripts/lmstudio_tool_eval.py +0 -0
  63. {abstractagent-0.3.0 → abstractagent-0.3.4}/src/abstractagent/tools/code_execution.py +0 -0
  64. {abstractagent-0.3.0 → abstractagent-0.3.4}/src/abstractagent/tools/self_improve.py +0 -0
  65. {abstractagent-0.3.0 → abstractagent-0.3.4}/src/abstractagent.egg-info/dependency_links.txt +0 -0
  66. {abstractagent-0.3.0 → abstractagent-0.3.4}/src/abstractagent.egg-info/entry_points.txt +0 -0
  67. {abstractagent-0.3.0 → abstractagent-0.3.4}/src/abstractagent.egg-info/top_level.txt +0 -0
  68. {abstractagent-0.3.0 → abstractagent-0.3.4}/tests/test_agents_integration_llm.py +0 -0
  69. {abstractagent-0.3.0 → abstractagent-0.3.4}/tests/test_base_agent_trace_accessors.py +0 -0
  70. {abstractagent-0.3.0 → abstractagent-0.3.4}/tests/test_builtin_tool_specs_optional_defaults.py +0 -0
  71. {abstractagent-0.3.0 → abstractagent-0.3.4}/tests/test_codeact_logic.py +0 -0
  72. {abstractagent-0.3.0 → abstractagent-0.3.4}/tests/test_codeact_runtime_verifier_policy.py +0 -0
  73. {abstractagent-0.3.0 → abstractagent-0.3.4}/tests/test_memact_session_memory.py +0 -0
  74. {abstractagent-0.3.0 → abstractagent-0.3.4}/tests/test_memact_workflow.py +0 -0
  75. {abstractagent-0.3.0 → abstractagent-0.3.4}/tests/test_memory_recall_tool.py +0 -0
  76. {abstractagent-0.3.0 → abstractagent-0.3.4}/tests/test_run_start_seeds_runtime_provider_model.py +0 -0
  77. {abstractagent-0.3.0 → abstractagent-0.3.4}/tests/test_session_memory.py +0 -0
  78. {abstractagent-0.3.0 → abstractagent-0.3.4}/tests/test_tools_editing.py +0 -0
@@ -0,0 +1,157 @@
1
+ Metadata-Version: 2.4
2
+ Name: abstractagent
3
+ Version: 0.3.4
4
+ Summary: Agent implementations using AbstractRuntime and AbstractCore
5
+ Requires-Python: >=3.10
6
+ Description-Content-Type: text/markdown
7
+ License-File: LICENSE
8
+ Requires-Dist: abstractcore[tools]>=2.13.11
9
+ Requires-Dist: abstractruntime>=0.4.7
10
+ Provides-Extra: apple
11
+ Requires-Dist: abstractcore[apple]>=2.13.11; extra == "apple"
12
+ Requires-Dist: abstractruntime[apple]>=0.4.7; extra == "apple"
13
+ Provides-Extra: gpu
14
+ Requires-Dist: abstractcore[gpu]>=2.13.11; extra == "gpu"
15
+ Requires-Dist: abstractruntime[gpu]>=0.4.7; extra == "gpu"
16
+ Provides-Extra: all-apple
17
+ Requires-Dist: abstractcore[all-apple]>=2.13.11; extra == "all-apple"
18
+ Requires-Dist: abstractruntime[all-apple]>=0.4.7; extra == "all-apple"
19
+ Provides-Extra: all-gpu
20
+ Requires-Dist: abstractcore[all-gpu]>=2.13.11; extra == "all-gpu"
21
+ Requires-Dist: abstractruntime[all-gpu]>=0.4.7; extra == "all-gpu"
22
+ Provides-Extra: dev
23
+ Requires-Dist: pytest>=7.0; extra == "dev"
24
+ Provides-Extra: test
25
+ Requires-Dist: pytest>=7.0; extra == "test"
26
+ Dynamic: license-file
27
+
28
+ # AbstractAgent
29
+
30
+ Agent patterns (ReAct / CodeAct / MemAct) built on **AbstractRuntime** (durable execution) and **AbstractCore** (tools + LLM integration).
31
+
32
+ AbstractAgent is part of the **AbstractFramework** ecosystem:
33
+ - AbstractFramework (ecosystem overview): https://github.com/lpalbou/AbstractFramework
34
+ - AbstractCore (providers + tool schemas): https://github.com/lpalbou/abstractcore
35
+ - AbstractRuntime (durable workflows + storage/ledger): https://github.com/lpalbou/abstractruntime
36
+
37
+ Start here: [`docs/getting-started.md`](docs/getting-started.md) (then [`docs/README.md`](docs/README.md) for the full index)
38
+
39
+ ## How it fits (high level)
40
+
41
+ ```mermaid
42
+ flowchart LR
43
+ Host[Your app / service] --> Agent[AbstractAgent<br/>ReAct / CodeAct / MemAct]
44
+ Agent --> RT[AbstractRuntime<br/>WorkflowSpec + Effects]
45
+ RT --> Core[AbstractCore<br/>LLM + tool-call normalization]
46
+ RT --> Stores[RunStore + LedgerStore]
47
+ Agent --> Tools[Tool callables<br/>(abstractcore common_tools + agent tools)]
48
+ ```
49
+
50
+ ## Documentation
51
+
52
+ - Getting started: [`docs/getting-started.md`](docs/getting-started.md)
53
+ - API reference: [`docs/api.md`](docs/api.md)
54
+ - FAQ / troubleshooting: [`docs/faq.md`](docs/faq.md)
55
+ - Architecture (diagrams): [`docs/architecture.md`](docs/architecture.md)
56
+ - Changelog: [`CHANGELOG.md`](CHANGELOG.md)
57
+ - Contributing: [`CONTRIBUTING.md`](CONTRIBUTING.md)
58
+ - Security: [`SECURITY.md`](SECURITY.md)
59
+ - Acknowledgements: [`ACKNOWLEDMENTS.md`](ACKNOWLEDMENTS.md)
60
+
61
+ ## What you get
62
+
63
+ - **ReAct**: tool-first Reason → Act → Observe loop
64
+ - **CodeAct**: executes Python (tool call or fenced ` ```python``` ` blocks)
65
+ - **MemAct**: memory-enhanced agent using runtime-owned Active Memory
66
+ - **Durable runs**: pause/resume via `run_id` + runtime stores
67
+ - **Tool control**: explicit tool bundles + per-run allowlists
68
+ - **Observability**: durable ledger of LLM calls, tool calls, and waits
69
+
70
+ Where this lives in code (source of truth):
71
+ - Agents: `src/abstractagent/agents/*`
72
+ - Workflows/adapters: `src/abstractagent/adapters/*_runtime.py`
73
+ - Prompting/parsing logic (runtime-agnostic): `src/abstractagent/logic/*`
74
+ - Default tool bundle: `src/abstractagent/tools/__init__.py`
75
+
76
+ ## Requirements
77
+
78
+ - Python `>=3.10` (see `pyproject.toml`)
79
+
80
+ ## Installation
81
+
82
+ From source (development):
83
+
84
+ ```bash
85
+ pip install -e .
86
+ ```
87
+
88
+ With dev dependencies:
89
+
90
+ ```bash
91
+ pip install -e ".[dev]"
92
+ ```
93
+
94
+ From PyPI:
95
+
96
+ ```bash
97
+ pip install abstractagent
98
+ ```
99
+
100
+ Native Python hardware profile cascades are available for deployment manifests:
101
+ `abstractagent[apple]`, `abstractagent[gpu]`, `abstractagent[all-apple]`, and
102
+ `abstractagent[all-gpu]`. These delegate to the matching AbstractCore and
103
+ AbstractRuntime profiles; AbstractAgent itself remains provider/runtime agnostic.
104
+
105
+ Note: the repository may be ahead of the latest published PyPI release. To verify what you installed:
106
+
107
+ ```bash
108
+ python -c "import importlib.metadata as md; print(md.version('abstractagent'))"
109
+ ```
110
+
111
+ ## Quick start (ReAct)
112
+
113
+ ```python
114
+ from abstractagent import create_react_agent
115
+
116
+ agent = create_react_agent(provider="ollama", model="qwen3:1.7b-q4_K_M")
117
+ agent.start("List the files in the current directory")
118
+ state = agent.run_to_completion()
119
+ print(state.output["answer"])
120
+ ```
121
+
122
+ ## Persistence (resume across restarts)
123
+
124
+ By default, the factory helpers use an in-memory runtime store. For resume across process restarts,
125
+ pass a persistent `RunStore`/`LedgerStore` (example below uses JSON files).
126
+
127
+ ```python
128
+ from abstractagent import create_react_agent
129
+ from abstractruntime.storage.json_files import JsonFileRunStore, JsonlLedgerStore
130
+
131
+ run_store = JsonFileRunStore(".runs")
132
+ ledger_store = JsonlLedgerStore(".runs")
133
+
134
+ agent = create_react_agent(run_store=run_store, ledger_store=ledger_store)
135
+ agent.start("Long running task")
136
+ agent.save_state("agent_state.json")
137
+
138
+ # ... later / after restart ...
139
+
140
+ agent2 = create_react_agent(run_store=run_store, ledger_store=ledger_store)
141
+ agent2.load_state("agent_state.json")
142
+ state = agent2.run_to_completion()
143
+ print(state.output["answer"])
144
+ ```
145
+
146
+ More details: [`docs/persistence.md`](docs/persistence.md)
147
+
148
+ ## CLI
149
+
150
+ This repository still installs a `react-agent` entrypoint, but it is **deprecated** and only prints a migration hint
151
+ (see `src/abstractagent/repl.py` and `pyproject.toml`).
152
+
153
+ Interactive UX lives in **AbstractCode**.
154
+
155
+ ## License
156
+
157
+ MIT (see `LICENSE`).
@@ -0,0 +1,130 @@
1
+ # AbstractAgent
2
+
3
+ Agent patterns (ReAct / CodeAct / MemAct) built on **AbstractRuntime** (durable execution) and **AbstractCore** (tools + LLM integration).
4
+
5
+ AbstractAgent is part of the **AbstractFramework** ecosystem:
6
+ - AbstractFramework (ecosystem overview): https://github.com/lpalbou/AbstractFramework
7
+ - AbstractCore (providers + tool schemas): https://github.com/lpalbou/abstractcore
8
+ - AbstractRuntime (durable workflows + storage/ledger): https://github.com/lpalbou/abstractruntime
9
+
10
+ Start here: [`docs/getting-started.md`](docs/getting-started.md) (then [`docs/README.md`](docs/README.md) for the full index)
11
+
12
+ ## How it fits (high level)
13
+
14
+ ```mermaid
15
+ flowchart LR
16
+ Host[Your app / service] --> Agent[AbstractAgent<br/>ReAct / CodeAct / MemAct]
17
+ Agent --> RT[AbstractRuntime<br/>WorkflowSpec + Effects]
18
+ RT --> Core[AbstractCore<br/>LLM + tool-call normalization]
19
+ RT --> Stores[RunStore + LedgerStore]
20
+ Agent --> Tools[Tool callables<br/>(abstractcore common_tools + agent tools)]
21
+ ```
22
+
23
+ ## Documentation
24
+
25
+ - Getting started: [`docs/getting-started.md`](docs/getting-started.md)
26
+ - API reference: [`docs/api.md`](docs/api.md)
27
+ - FAQ / troubleshooting: [`docs/faq.md`](docs/faq.md)
28
+ - Architecture (diagrams): [`docs/architecture.md`](docs/architecture.md)
29
+ - Changelog: [`CHANGELOG.md`](CHANGELOG.md)
30
+ - Contributing: [`CONTRIBUTING.md`](CONTRIBUTING.md)
31
+ - Security: [`SECURITY.md`](SECURITY.md)
32
+ - Acknowledgements: [`ACKNOWLEDMENTS.md`](ACKNOWLEDMENTS.md)
33
+
34
+ ## What you get
35
+
36
+ - **ReAct**: tool-first Reason → Act → Observe loop
37
+ - **CodeAct**: executes Python (tool call or fenced ` ```python``` ` blocks)
38
+ - **MemAct**: memory-enhanced agent using runtime-owned Active Memory
39
+ - **Durable runs**: pause/resume via `run_id` + runtime stores
40
+ - **Tool control**: explicit tool bundles + per-run allowlists
41
+ - **Observability**: durable ledger of LLM calls, tool calls, and waits
42
+
43
+ Where this lives in code (source of truth):
44
+ - Agents: `src/abstractagent/agents/*`
45
+ - Workflows/adapters: `src/abstractagent/adapters/*_runtime.py`
46
+ - Prompting/parsing logic (runtime-agnostic): `src/abstractagent/logic/*`
47
+ - Default tool bundle: `src/abstractagent/tools/__init__.py`
48
+
49
+ ## Requirements
50
+
51
+ - Python `>=3.10` (see `pyproject.toml`)
52
+
53
+ ## Installation
54
+
55
+ From source (development):
56
+
57
+ ```bash
58
+ pip install -e .
59
+ ```
60
+
61
+ With dev dependencies:
62
+
63
+ ```bash
64
+ pip install -e ".[dev]"
65
+ ```
66
+
67
+ From PyPI:
68
+
69
+ ```bash
70
+ pip install abstractagent
71
+ ```
72
+
73
+ Native Python hardware profile cascades are available for deployment manifests:
74
+ `abstractagent[apple]`, `abstractagent[gpu]`, `abstractagent[all-apple]`, and
75
+ `abstractagent[all-gpu]`. These delegate to the matching AbstractCore and
76
+ AbstractRuntime profiles; AbstractAgent itself remains provider/runtime agnostic.
77
+
78
+ Note: the repository may be ahead of the latest published PyPI release. To verify what you installed:
79
+
80
+ ```bash
81
+ python -c "import importlib.metadata as md; print(md.version('abstractagent'))"
82
+ ```
83
+
84
+ ## Quick start (ReAct)
85
+
86
+ ```python
87
+ from abstractagent import create_react_agent
88
+
89
+ agent = create_react_agent(provider="ollama", model="qwen3:1.7b-q4_K_M")
90
+ agent.start("List the files in the current directory")
91
+ state = agent.run_to_completion()
92
+ print(state.output["answer"])
93
+ ```
94
+
95
+ ## Persistence (resume across restarts)
96
+
97
+ By default, the factory helpers use an in-memory runtime store. For resume across process restarts,
98
+ pass a persistent `RunStore`/`LedgerStore` (example below uses JSON files).
99
+
100
+ ```python
101
+ from abstractagent import create_react_agent
102
+ from abstractruntime.storage.json_files import JsonFileRunStore, JsonlLedgerStore
103
+
104
+ run_store = JsonFileRunStore(".runs")
105
+ ledger_store = JsonlLedgerStore(".runs")
106
+
107
+ agent = create_react_agent(run_store=run_store, ledger_store=ledger_store)
108
+ agent.start("Long running task")
109
+ agent.save_state("agent_state.json")
110
+
111
+ # ... later / after restart ...
112
+
113
+ agent2 = create_react_agent(run_store=run_store, ledger_store=ledger_store)
114
+ agent2.load_state("agent_state.json")
115
+ state = agent2.run_to_completion()
116
+ print(state.output["answer"])
117
+ ```
118
+
119
+ More details: [`docs/persistence.md`](docs/persistence.md)
120
+
121
+ ## CLI
122
+
123
+ This repository still installs a `react-agent` entrypoint, but it is **deprecated** and only prints a migration hint
124
+ (see `src/abstractagent/repl.py` and `pyproject.toml`).
125
+
126
+ Interactive UX lives in **AbstractCode**.
127
+
128
+ ## License
129
+
130
+ MIT (see `LICENSE`).
@@ -0,0 +1,51 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "abstractagent"
7
+ version = "0.3.4"
8
+ description = "Agent implementations using AbstractRuntime and AbstractCore"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ dependencies = [
12
+ "abstractcore[tools]>=2.13.11",
13
+ "abstractruntime>=0.4.7",
14
+ ]
15
+
16
+ [project.optional-dependencies]
17
+ apple = [
18
+ "abstractcore[apple]>=2.13.11",
19
+ "abstractruntime[apple]>=0.4.7",
20
+ ]
21
+ gpu = [
22
+ "abstractcore[gpu]>=2.13.11",
23
+ "abstractruntime[gpu]>=0.4.7",
24
+ ]
25
+ all-apple = [
26
+ "abstractcore[all-apple]>=2.13.11",
27
+ "abstractruntime[all-apple]>=0.4.7",
28
+ ]
29
+ all-gpu = [
30
+ "abstractcore[all-gpu]>=2.13.11",
31
+ "abstractruntime[all-gpu]>=0.4.7",
32
+ ]
33
+ dev = [
34
+ "pytest>=7.0",
35
+ ]
36
+ test = [
37
+ "pytest>=7.0",
38
+ ]
39
+
40
+ [tool.setuptools.packages.find]
41
+ where = ["src"]
42
+
43
+ [project.scripts]
44
+ react-agent = "abstractagent.repl:main"
45
+
46
+ [tool.pytest.ini_options]
47
+ markers = [
48
+ "basic: Level A (contract/unit) tests",
49
+ "integration: Level B (integration/local) tests",
50
+ "e2e: Level C (end-to-end/real infra) tests (opt-in)",
51
+ ]
@@ -11,6 +11,8 @@ from abstractruntime import Effect, EffectType, RunState, StepPlan, WorkflowSpec
11
11
  from abstractruntime.core.vars import ensure_limits, ensure_namespaces
12
12
  from abstractruntime.memory.active_context import ActiveContextPolicy
13
13
 
14
+ from .generation_params import runtime_llm_params
15
+ from .media import extract_media_from_context
14
16
  from ..logic.codeact import CodeActLogic
15
17
 
16
18
 
@@ -215,6 +217,7 @@ def create_codeact_workflow(
215
217
  if keep < 200:
216
218
  keep = max_chars
217
219
  suffix = ""
220
+ #[WARNING:TRUNCATION] bounded message content for LLM payload
218
221
  return text[:keep].rstrip() + suffix
219
222
 
220
223
  out: List[Dict[str, str]] = []
@@ -335,7 +338,10 @@ def create_codeact_workflow(
335
338
 
336
339
  emit("plan_request", {"tools": allow})
337
340
 
338
- payload: Dict[str, Any] = {"prompt": prompt, "params": {"temperature": 0.2}}
341
+ payload: Dict[str, Any] = {"prompt": prompt, "params": runtime_llm_params(runtime_ns, extra={"temperature": 0.2})}
342
+ media = extract_media_from_context(context)
343
+ if media:
344
+ payload["media"] = media
339
345
  sys = _system_prompt(runtime_ns)
340
346
  if isinstance(sys, str) and sys.strip():
341
347
  payload["system_prompt"] = sys
@@ -431,11 +437,16 @@ def create_codeact_workflow(
431
437
  "messages": _sanitize_llm_messages(messages_view, limits=limits),
432
438
  "tools": list(tool_specs),
433
439
  }
440
+ media = extract_media_from_context(context)
441
+ if media:
442
+ payload["media"] = media
434
443
  sys = _system_prompt(runtime_ns) or req.system_prompt
435
444
  if isinstance(sys, str) and sys.strip():
436
445
  payload["system_prompt"] = sys
446
+ params: Dict[str, Any] = {}
437
447
  if req.max_tokens is not None:
438
- payload["params"] = {"max_tokens": req.max_tokens}
448
+ params["max_tokens"] = req.max_tokens
449
+ payload["params"] = runtime_llm_params(runtime_ns, extra=params)
439
450
 
440
451
  return StepPlan(
441
452
  node_id="reason",
@@ -560,6 +571,7 @@ def create_codeact_workflow(
560
571
  "remember",
561
572
  "remember_note",
562
573
  "compact_memory",
574
+ "delegate_agent",
563
575
  }
564
576
 
565
577
  tool_queue: List[Dict[str, Any]] = []
@@ -635,6 +647,68 @@ def create_codeact_workflow(
635
647
  next_node="handle_user_response",
636
648
  )
637
649
 
650
+ if name == "delegate_agent":
651
+ delegated_task = str(args.get("task") or "").strip()
652
+ delegated_context = str(args.get("context") or "").strip()
653
+
654
+ tools_raw = args.get("tools")
655
+ if tools_raw is None:
656
+ # Inherit the current allowlist, but avoid recursive delegation and avoid waiting on ask_user
657
+ # unless explicitly enabled.
658
+ child_allow = [t for t in allow if t not in {"delegate_agent", "ask_user"}]
659
+ else:
660
+ child_allow = _normalize_allowlist(tools_raw)
661
+
662
+ if not delegated_task:
663
+ temp["tool_results"] = {
664
+ "results": [
665
+ {
666
+ "call_id": str(tc.get("call_id") or ""),
667
+ "name": "delegate_agent",
668
+ "success": False,
669
+ "output": None,
670
+ "error": "delegate_agent requires a non-empty task",
671
+ }
672
+ ]
673
+ }
674
+ return StepPlan(node_id="act", next_node="observe")
675
+
676
+ combined_task = delegated_task
677
+ if delegated_context:
678
+ combined_task = f"{delegated_task}\n\nContext:\n{delegated_context}"
679
+
680
+ sub_vars: Dict[str, Any] = {
681
+ "context": {"task": combined_task, "messages": []},
682
+ "_runtime": {
683
+ "allowed_tools": list(child_allow),
684
+ "system_prompt_extra": (
685
+ "You are a delegated sub-agent.\n"
686
+ "- Focus ONLY on the delegated task.\n"
687
+ "- Use ONLY the allowed tools when needed.\n"
688
+ "- Do not ask the user questions; if blocked, state assumptions and proceed.\n"
689
+ "- Return a concise result suitable for the parent agent to act on.\n"
690
+ ),
691
+ },
692
+ "_limits": {"max_iterations": 10},
693
+ }
694
+
695
+ payload = {
696
+ "workflow_id": str(getattr(run, "workflow_id", "") or "codeact_agent"),
697
+ "vars": sub_vars,
698
+ "async": False,
699
+ "include_traces": False,
700
+ # Tool-mode wrapper so the parent receives a normal tool observation (no run failure on child failure).
701
+ "wrap_as_tool_result": True,
702
+ "tool_name": "delegate_agent",
703
+ "call_id": str(tc.get("call_id") or ""),
704
+ }
705
+ emit("delegate_agent", {"tools": list(child_allow), "call_id": payload.get("call_id")})
706
+ return StepPlan(
707
+ node_id="act",
708
+ effect=Effect(type=EffectType.START_SUBWORKFLOW, payload=payload, result_key="_temp.tool_results"),
709
+ next_node="observe",
710
+ )
711
+
638
712
  if name == "recall_memory":
639
713
  payload = dict(args)
640
714
  payload.setdefault("tool_name", "recall_memory")
@@ -730,13 +804,14 @@ def create_codeact_workflow(
730
804
  )
731
805
 
732
806
  def execute_code_node(run: RunState, ctx) -> StepPlan:
733
- _, _, _, temp, _ = ensure_codeact_vars(run)
807
+ _, _, runtime_ns, temp, _ = ensure_codeact_vars(run)
734
808
  code = temp.get("pending_code")
735
809
  if not isinstance(code, str) or not code.strip():
736
810
  return StepPlan(node_id="execute_code", next_node="reason")
737
811
 
738
812
  temp.pop("pending_code", None)
739
813
  emit("act", {"tool": "execute_python", "args": {"code": "(inline)", "timeout_s": 10.0}})
814
+ allow = _effective_allowlist(runtime_ns)
740
815
 
741
816
  return StepPlan(
742
817
  node_id="execute_code",
@@ -749,7 +824,8 @@ def create_codeact_workflow(
749
824
  "arguments": {"code": code, "timeout_s": 10.0},
750
825
  "call_id": "code",
751
826
  }
752
- ]
827
+ ],
828
+ "allowed_tools": list(allow),
753
829
  },
754
830
  result_key="_temp.tool_results",
755
831
  ),
@@ -794,6 +870,7 @@ def create_codeact_workflow(
794
870
  # Keep a bounded preview for huge tool outputs to avoid bloating traces/ledgers.
795
871
  preview = rendered
796
872
  if len(preview) > 1000:
873
+ #[WARNING:TRUNCATION] bounded preview for observability payloads
797
874
  preview = preview[:1000] + f"\n… (truncated, {len(rendered):,} chars total)"
798
875
  emit("observe", {"tool": name, "success": success, "result": preview})
799
876
  context["messages"].append(
@@ -870,6 +947,7 @@ def create_codeact_workflow(
870
947
  if keep < 200:
871
948
  keep = max_chars
872
949
  suffix = ""
950
+ #[WARNING:TRUNCATION] bounded transcript blocks for prompt reconstruction
873
951
  return s[:keep].rstrip() + suffix
874
952
 
875
953
  def _format_allowed_tools() -> str:
@@ -1002,8 +1080,11 @@ def create_codeact_workflow(
1002
1080
  "prompt": prompt,
1003
1081
  "response_schema": schema,
1004
1082
  "response_schema_name": "CodeActVerifier",
1005
- "params": {"temperature": 0.2},
1083
+ "params": runtime_llm_params(runtime_ns, extra={"temperature": 0.2}),
1006
1084
  }
1085
+ media = extract_media_from_context(context)
1086
+ if media:
1087
+ payload["media"] = media
1007
1088
  sys = _system_prompt(runtime_ns)
1008
1089
  if sys is not None:
1009
1090
  payload["system_prompt"] = sys
@@ -0,0 +1,82 @@
1
+ """Helpers for consistent generation params in AbstractAgent adapters.
2
+
3
+ These adapters build `EffectType.LLM_CALL` payloads for AbstractRuntime. We want
4
+ to expose a uniform `(temperature, seed)` interface across agents while keeping
5
+ backward compatibility with older runs that may not have these keys in
6
+ `vars["_runtime"]`.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from typing import Any, Dict, Optional
12
+
13
+
14
+ def normalize_seed(seed: Any) -> Optional[int]:
15
+ """Return a provider-ready seed or None when unset/random.
16
+
17
+ Policy:
18
+ - None or any negative value -> None (meaning: do not send seed).
19
+ - bool values are ignored (JSON booleans are ints in Python).
20
+ - numeric-ish values -> int(seed) if >= 0.
21
+ """
22
+ try:
23
+ if seed is None or isinstance(seed, bool):
24
+ return None
25
+ seed_i = int(seed)
26
+ return seed_i if seed_i >= 0 else None
27
+ except Exception:
28
+ return None
29
+
30
+
31
+ def runtime_llm_params(
32
+ runtime_ns: Dict[str, Any],
33
+ *,
34
+ extra: Optional[Dict[str, Any]] = None,
35
+ default_temperature: float = 0.7,
36
+ ) -> Dict[str, Any]:
37
+ """Merge `runtime_ns` sampling controls into an LLM_CALL params dict.
38
+
39
+ Precedence:
40
+ 1) `runtime_ns.temperature` / `runtime_ns.seed` when present
41
+ 2) `extra.temperature` / `extra.seed` (step-specific defaults)
42
+ 3) `default_temperature` (only for temperature)
43
+ """
44
+ out: Dict[str, Any] = dict(extra or {})
45
+
46
+ # Temperature: always provide a float (provider-agnostic).
47
+ temp_val = runtime_ns.get("temperature") if isinstance(runtime_ns, dict) else None
48
+ if temp_val is None:
49
+ temp_val = out.get("temperature")
50
+ if temp_val is None:
51
+ temp_val = default_temperature
52
+ try:
53
+ out["temperature"] = float(temp_val)
54
+ except Exception:
55
+ out["temperature"] = float(default_temperature)
56
+
57
+ # Seed: only include when explicitly set (>= 0).
58
+ seed_val = runtime_ns.get("seed") if isinstance(runtime_ns, dict) else None
59
+ if seed_val is None:
60
+ seed_val = out.get("seed")
61
+ seed_norm = normalize_seed(seed_val)
62
+ if seed_norm is not None:
63
+ out["seed"] = seed_norm
64
+ else:
65
+ out.pop("seed", None)
66
+
67
+ # Pass-through media policies (runtime-owned defaults).
68
+ #
69
+ # This keeps thin clients simple: they can set `_runtime.audio_policy` (and
70
+ # optional language hints) once at run start, and all LLM_CALL steps inherit it.
71
+ if isinstance(runtime_ns, dict):
72
+ audio_policy = runtime_ns.get("audio_policy")
73
+ if "audio_policy" not in out and isinstance(audio_policy, str) and audio_policy.strip():
74
+ out["audio_policy"] = audio_policy.strip()
75
+
76
+ stt_language = runtime_ns.get("stt_language")
77
+ if stt_language is None:
78
+ stt_language = runtime_ns.get("audio_language")
79
+ if "stt_language" not in out and isinstance(stt_language, str) and stt_language.strip():
80
+ out["stt_language"] = stt_language.strip()
81
+
82
+ return out
@@ -0,0 +1,45 @@
1
+ """Helpers for attachment/media plumbing in runtime-backed agents."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, Dict, List, Optional
6
+
7
+
8
+ def extract_media_from_context(context: Dict[str, Any]) -> Optional[List[Any]]:
9
+ """Return a normalized `media` list from a runtime `context` dict.
10
+
11
+ Supported keys (best-effort):
12
+ - `context["attachments"]`: preferred (artifact refs)
13
+ - `context["media"]`: legacy/alternate
14
+ """
15
+ raw = context.get("attachments")
16
+ if raw is None:
17
+ raw = context.get("media")
18
+
19
+ if isinstance(raw, tuple):
20
+ items = list(raw)
21
+ else:
22
+ items = raw
23
+
24
+ if not isinstance(items, list) or not items:
25
+ return None
26
+
27
+ out: List[Any] = []
28
+ for item in items:
29
+ if isinstance(item, str):
30
+ s = item.strip()
31
+ if s:
32
+ out.append(s)
33
+ continue
34
+
35
+ if isinstance(item, dict):
36
+ # Prefer artifact refs; accept both {"$artifact": "..."} and {"artifact_id": "..."}.
37
+ aid = item.get("$artifact")
38
+ if not (isinstance(aid, str) and aid.strip()):
39
+ aid = item.get("artifact_id")
40
+ if isinstance(aid, str) and aid.strip():
41
+ out.append(dict(item))
42
+ continue
43
+
44
+ return out or None
45
+