agentx-dev 2.4__tar.gz → 3.0.1__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 (71) hide show
  1. agentx_dev-3.0.1/AGENTX.md +308 -0
  2. agentx_dev-3.0.1/LICENSE +21 -0
  3. agentx_dev-3.0.1/MANIFEST.in +11 -0
  4. agentx_dev-3.0.1/PKG-INFO +886 -0
  5. agentx_dev-3.0.1/README.md +835 -0
  6. agentx_dev-3.0.1/agentx_dev/Agents/Agent.py +402 -0
  7. agentx_dev-3.0.1/agentx_dev/AsyncTools.py +160 -0
  8. agentx_dev-3.0.1/agentx_dev/AutoSetup.py +164 -0
  9. agentx_dev-3.0.1/agentx_dev/Cache.py +471 -0
  10. agentx_dev-3.0.1/agentx_dev/ChatModel.py +1174 -0
  11. agentx_dev-3.0.1/agentx_dev/Config.py +144 -0
  12. agentx_dev-3.0.1/agentx_dev/DefaultTools.py +1738 -0
  13. agentx_dev-3.0.1/agentx_dev/Loader.py +287 -0
  14. agentx_dev-3.0.1/agentx_dev/MCP.py +426 -0
  15. agentx_dev-3.0.1/agentx_dev/Memory.py +447 -0
  16. agentx_dev-3.0.1/agentx_dev/Observability.py +494 -0
  17. agentx_dev-3.0.1/agentx_dev/Planner.py +271 -0
  18. agentx_dev-3.0.1/agentx_dev/Runner/AgentRun.py +1607 -0
  19. agentx_dev-3.0.1/agentx_dev/Runner/AsyncAgentRun.py +632 -0
  20. agentx_dev-3.0.1/agentx_dev/Runner/__init__.py +14 -0
  21. agentx_dev-3.0.1/agentx_dev/Session.py +261 -0
  22. agentx_dev-3.0.1/agentx_dev/Streaming.py +297 -0
  23. agentx_dev-3.0.1/agentx_dev/Supervisor.py +1026 -0
  24. {agentx_dev-2.4 → agentx_dev-3.0.1}/agentx_dev/Tools.py +40 -29
  25. agentx_dev-3.0.1/agentx_dev/WebTools.py +278 -0
  26. agentx_dev-3.0.1/agentx_dev/__init__.py +172 -0
  27. agentx_dev-3.0.1/agentx_dev/resources/promptTemplate.yaml +309 -0
  28. agentx_dev-3.0.1/agentx_dev.egg-info/PKG-INFO +886 -0
  29. agentx_dev-3.0.1/agentx_dev.egg-info/SOURCES.txt +53 -0
  30. agentx_dev-3.0.1/agentx_dev.egg-info/requires.txt +20 -0
  31. agentx_dev-3.0.1/agentx_dev.egg-info/top_level.txt +4 -0
  32. agentx_dev-3.0.1/examples/README.md +279 -0
  33. agentx_dev-3.0.1/examples/async_example.py +160 -0
  34. agentx_dev-3.0.1/examples/async_quickstart.py +81 -0
  35. agentx_dev-3.0.1/examples/auto_features_example.py +275 -0
  36. agentx_dev-3.0.1/examples/caching_example.py +215 -0
  37. agentx_dev-3.0.1/examples/chatbot_example.py +206 -0
  38. agentx_dev-3.0.1/examples/complete_example.py +339 -0
  39. agentx_dev-3.0.1/examples/concurrent_example.py +286 -0
  40. agentx_dev-3.0.1/examples/concurrent_tool_example.py +303 -0
  41. agentx_dev-3.0.1/examples/file_agent_demo.py +302 -0
  42. agentx_dev-3.0.1/examples/function_calling_demo.py +211 -0
  43. agentx_dev-3.0.1/examples/mcp_demo.py +308 -0
  44. agentx_dev-3.0.1/examples/observability_example.py +322 -0
  45. agentx_dev-3.0.1/examples/orchestration_demo.py +440 -0
  46. agentx_dev-3.0.1/examples/planner_example.py +93 -0
  47. agentx_dev-3.0.1/examples/supervisor_codebase_analysis_demo.py +238 -0
  48. agentx_dev-3.0.1/examples/supervisor_example.py +97 -0
  49. agentx_dev-3.0.1/examples/sync_quickstart.py +75 -0
  50. agentx_dev-3.0.1/pyproject.toml +55 -0
  51. agentx_dev-2.4/MANIFEST.in +0 -3
  52. agentx_dev-2.4/PKG-INFO +0 -115
  53. agentx_dev-2.4/README.md +0 -98
  54. agentx_dev-2.4/agentx_dev/Agents/Agent.py +0 -337
  55. agentx_dev-2.4/agentx_dev/ChatModel.py +0 -216
  56. agentx_dev-2.4/agentx_dev/Runner/AgentRun.py +0 -344
  57. agentx_dev-2.4/agentx_dev/Runner/__init__.py +0 -12
  58. agentx_dev-2.4/agentx_dev/Runner/promptTemplate.yaml +0 -139
  59. agentx_dev-2.4/agentx_dev/__init__.py +0 -10
  60. agentx_dev-2.4/agentx_dev/promptTemplate.yaml +0 -139
  61. agentx_dev-2.4/agentx_dev/resources/promptTemplate.yaml +0 -139
  62. agentx_dev-2.4/agentx_dev.egg-info/PKG-INFO +0 -115
  63. agentx_dev-2.4/agentx_dev.egg-info/SOURCES.txt +0 -20
  64. agentx_dev-2.4/agentx_dev.egg-info/requires.txt +0 -6
  65. agentx_dev-2.4/agentx_dev.egg-info/top_level.txt +0 -2
  66. agentx_dev-2.4/pyproject.toml +0 -41
  67. {agentx_dev-2.4 → agentx_dev-3.0.1}/agentx_dev/Agents/__init__.py +0 -0
  68. {agentx_dev-2.4/agentx_dev/Agents → agentx_dev-3.0.1/agentx_dev/Runner}/promptTemplate.yaml +0 -0
  69. {agentx_dev-2.4 → agentx_dev-3.0.1}/agentx_dev/resources/__init__.py +0 -0
  70. {agentx_dev-2.4 → agentx_dev-3.0.1}/agentx_dev.egg-info/dependency_links.txt +0 -0
  71. {agentx_dev-2.4 → agentx_dev-3.0.1}/setup.cfg +0 -0
@@ -0,0 +1,308 @@
1
+ # AGENTX.md — Project guide for agents running under agentx_dev
2
+
3
+ This file exists so any specialist that lands in this repo has ONE place to
4
+ read for the conventions, guardrails, and common patterns it should follow.
5
+ Read it BEFORE your first tool call. If the framework auto-injected the
6
+ sandbox hint into your system prompt, it also told you about this file.
7
+
8
+ The guide is written for the model, not the human. Terse, actionable, and
9
+ grouped by "when you're about to do X, here's what to know."
10
+
11
+ ---
12
+
13
+ ## 1. What you are
14
+
15
+ You are a specialist AgentRunner spawned or registered by a caller. Your job
16
+ is to complete ONE sub-task well and return structured findings the caller
17
+ can lift verbatim into the final answer. You are NOT a general assistant;
18
+ your tools + permissions are deliberately narrow.
19
+
20
+ - You have a system prompt, tool descriptions, and a task query.
21
+ - You do NOT see the caller's history or other specialists' outputs unless
22
+ they were passed in as `PRIOR FINDINGS` inside your task query.
23
+ - Your reply IS your deliverable — the caller (often a Supervisor) reads
24
+ ONLY your reply. Include actual data, not "task complete."
25
+
26
+ ---
27
+
28
+ ## 2. Framework guardrails you should know about
29
+
30
+ These fire automatically. Don't be surprised when they do.
31
+
32
+ ### 2a. Duplicate-call guard (tool layer)
33
+
34
+ If you call the same tool with the SAME arguments N times in a row:
35
+ - Call 1, 2 → normal.
36
+ - Call 3, 4 → response prepended with `[framework] WARNING: repeat call #N`.
37
+ - Call 5+ → `ToolError: refused. Framework prevents you from spinning on the
38
+ same call.`
39
+
40
+ **Rule:** if you see a WARNING prefix, your NEXT turn must change approach
41
+ or emit Final_Answer. Do NOT ignore it.
42
+
43
+ ### 2b. Consecutive-call loop guard (runner layer)
44
+
45
+ If you emit 3 identical `(action, args)` pairs in a row, the loop
46
+ force-terminates BEFORE dispatching the 3rd call. It synthesizes a
47
+ Final_Answer from the last successful tool result. Same lesson: don't
48
+ spiral on the same call.
49
+
50
+ ### 2c. Read-before-write safety
51
+
52
+ `write_file` refuses to overwrite an EXISTING file unless you've read it
53
+ this session — protects against clobbering content you haven't seen.
54
+
55
+ Escape hatches on `write_file(path, content, if_exists=...)`:
56
+ - `'refuse'` (default) — the safety above.
57
+ - `'rename'` — save under a fresh name (`report_1.md`, `report_2.md`, ...).
58
+ Use for deliverables when you don't want to overwrite prior runs.
59
+ - `'overwrite'` — force overwrite (no prior-read check).
60
+ - `'append'` — add content to the end of the existing file.
61
+
62
+ ### 2d. Filesystem sandbox
63
+
64
+ Every file op is confined to your `allowed_paths`. If you try to write to
65
+ `/etc/foo`, the tool refuses. The sandbox description is in your system
66
+ prompt under "FILESYSTEM SANDBOX." You can rely on it — don't try to
67
+ work around it.
68
+
69
+ ### 2e. Subprocess safety on `run_python` / `run_shell`
70
+
71
+ - Wall-clock timeout: `python_timeout_sec` / `shell_timeout_sec` on your Permissions.
72
+ - Output cap: `python_max_output_bytes` / `shell_max_output_bytes`.
73
+ - If your snippet loops or fetches a huge page, output gets truncated with a marker.
74
+
75
+ ---
76
+
77
+ ## 3. Tools you'll usually have
78
+
79
+ Only the ones your Permissions grant are wired. Names + shape:
80
+
81
+ - `read_path(path, offset=None, limit=None)` — read a file. Offset+limit give
82
+ line-numbered output like `cat -n`. Reading unlocks the file for edit/write.
83
+ - `list_directory(path)` — one level of listing.
84
+ - `find_files(glob, path='.', max_results=200)` — file search by name/glob.
85
+ Auto-skips noise dirs (`.git`, `node_modules`, `__pycache__`, `.venv`, etc.).
86
+ - `grep(pattern, path='.', glob='**/*', regex=False, case_sensitive=True, max_matches=100)`
87
+ — content search. Returns `file:line: match` records.
88
+ - `write_file(path, content, if_exists='refuse')` — see 2c.
89
+ - `edit_file(path, find, replace)` — exactly one match required. Reads the
90
+ file first if you haven't.
91
+ - `delete_path(path, recursive=False)` — refuses non-empty dir unless recursive.
92
+ - `move_file(source, destination)` — both endpoints inside sandbox.
93
+ - `run_python(code)` — fresh subprocess. `print()` what you want to see.
94
+ When `python_persistent_state=True`, a `state` dict is auto-loaded/saved
95
+ between calls — use it to pass data instead of re-defining.
96
+ - `run_shell(command, cwd=None)` — one-shot bash/PowerShell. NOT for
97
+ long-running processes; they hit the timeout.
98
+ - `web_search(query, num_results=5)` — DuckDuckGo (Wikipedia fallback). Only
99
+ present when you were spawned with `web` capability or explicitly given
100
+ the tool.
101
+ - `web_fetch(url, max_chars=50_000)` — GET a URL. If configured with
102
+ `cache_dir=`, the FULL response body lands on disk and the reply names
103
+ the path. Read the cached file in `run_python` instead of pasting HTML
104
+ into your code.
105
+
106
+ ---
107
+
108
+ ## 4. Structural code analysis — USE `ast`
109
+
110
+ If you're computing per-function or per-class metrics — LOC, method counts,
111
+ duplicate function names, cyclomatic complexity, call graphs — USE Python's
112
+ `ast` module inside `run_python`. Never use regex or `line.startswith('def ')`
113
+ for these. String heuristics:
114
+
115
+ - Miss nested defs.
116
+ - Count strings that contain the word "class" as classes.
117
+ - Attribute keywords (`for`/`while`) to the wrong function for CC.
118
+ - Produce obviously-wrong numbers (functions with CC=400, "function names"
119
+ that are actually Python keywords).
120
+
121
+ Sketch:
122
+
123
+ ```python
124
+ import ast
125
+ from pathlib import Path
126
+
127
+ for p in Path('./src').rglob('*.py'):
128
+ tree = ast.parse(p.read_text())
129
+ for node in ast.walk(tree):
130
+ if isinstance(node, ast.ClassDef):
131
+ method_count = sum(1 for c in ast.walk(node)
132
+ if isinstance(c, (ast.FunctionDef, ast.AsyncFunctionDef)))
133
+ print(f'{p}:{node.lineno}: class {node.name} → {method_count} methods')
134
+ ```
135
+
136
+ ---
137
+
138
+ ## 5. Your reply is your deliverable
139
+
140
+ The caller cannot re-run your queries. They cannot open files you wrote.
141
+ They see ONE thing: your final text.
142
+
143
+ - If you extracted 3 competitors, name them + positioning + URL in the reply.
144
+ - If you saved a report, include a concise summary of its contents.
145
+ - If you produced numbers, list them.
146
+ - If a fetch failed or a page didn't contain the field asked for, say so
147
+ plainly ("no phone numbers found on the page"). Never invent data.
148
+
149
+ **Never** end with just "task complete" or "saved to X." That's a status
150
+ message with no signal for the caller.
151
+
152
+ ---
153
+
154
+ ## 6. Common failure modes and what to do instead
155
+
156
+ | You did this | Do this instead |
157
+ |-------------------------------------------------|------------------------------------------------------------------------|
158
+ | Called the same tool + args twice | Use the previous result. If you need something different, change args. |
159
+ | Called `run_python` and it wasn't in your tools | Check your available tools. Ask for a different route or return partial data. |
160
+ | Pasted `'...'` as a placeholder inside a script | Fetch the real content inside the script itself, OR use `web_fetch(cache_dir=)` and `open()` the cached file. |
161
+ | Wrote code with `line.startswith('def ')` | Use `ast.parse` + `ast.walk` (see §4). |
162
+ | Returned "task complete" as your final answer | Return actual data. See §5. |
163
+ | `write_file` refused because file exists | Retry with `if_exists='rename'` (or `'overwrite'` if intentional). |
164
+ | Got `[framework] WARNING: repeat call #N` | STOP the repeat pattern. Change approach on the next turn. |
165
+ | Got `ToolError: refused. Framework prevents` | The loop is one step away from force-terminating. Emit Final_Answer. |
166
+ | `run_python` printed nothing | You forgot `print()`. Wrap the value. |
167
+
168
+ ---
169
+
170
+ ## 7. If you are a Supervisor / planner
171
+
172
+ You compose a plan of sub-tasks. Rules:
173
+
174
+ ### 7a. Minimum viable plan.
175
+
176
+ Every step is a full LLM call. Merge adjacent steps that would go to the
177
+ same specialist. If the whole task fits ONE specialist's scope, use ONE step.
178
+
179
+ ### 7b. Sub-agents run in isolation.
180
+
181
+ They do NOT see previous steps' output unless you paste findings into their
182
+ task query. The framework auto-threads them via `PRIOR FINDINGS` in
183
+ sequential mode.
184
+
185
+ ### 7c. No final "report" step.
186
+
187
+ The framework's synthesis stage already lifts sub-task results into the
188
+ user's final answer. A sub-task whose query is "summarize what was found"
189
+ is wasted.
190
+
191
+ ### 7d. Spawn rules (when `SpawnConfig.enabled=True`):
192
+
193
+ - **SPAWN** if the task requires a capability no registered specialist has:
194
+ - `code` for computation, aggregation, AST metrics, LOC counts.
195
+ - `web` for URL fetching, search.
196
+ - `files` for read/write/edit.
197
+ - `delete` for destructive file ops.
198
+ - **DO NOT SPAWN** if an existing specialist's tool set already covers the
199
+ capability. The framework REFUSES duplicate-capability spawns and
200
+ auto-reroutes follow-up dispatches. Emitting the spawn anyway just
201
+ wastes a plan slot and clutters the trace.
202
+
203
+ Spawn step shape:
204
+
205
+ ```json
206
+ {"agent": "__spawn__",
207
+ "name": "<short lowercase identifier used in later steps>",
208
+ "description": "<what this specialist does>",
209
+ "capabilities": ["code", "files"],
210
+ "rationale": "<one sentence: why existing specialists don't fit>"}
211
+ ```
212
+
213
+ ### 7e. Anti-fabrication in synthesis.
214
+
215
+ You will receive the specialists' replies. Use ONLY facts explicitly
216
+ present. If a specialist only sent a status message ("task complete"),
217
+ that data is MISSING — do not reconstruct what the file "probably"
218
+ contains. Say plainly: "the report was saved to X; open it to see the
219
+ details."
220
+
221
+ ---
222
+
223
+ ## 8. Custom tool authoring
224
+
225
+ If you're extending this framework with a new tool, the shape is one of:
226
+
227
+ ```python
228
+ from agentx_dev import StandardTool, StructuredTool
229
+ from pydantic import BaseModel, Field
230
+
231
+ # Single-string input — simplest form
232
+ def echo(text: str) -> str:
233
+ return f"echoed: {text}"
234
+
235
+ echo_tool = StandardTool(
236
+ func=echo, name="echo",
237
+ description="Echoes back a single string input.",
238
+ )
239
+
240
+ # Structured input — preferred when LLMs need to fill multiple fields
241
+ class SearchArgs(BaseModel):
242
+ query: str = Field(..., description="The search query.")
243
+ num_results: int = Field(5, description="How many results to return.")
244
+
245
+ def search(query: str, num_results: int = 5) -> str:
246
+ ...
247
+
248
+ search_tool = StructuredTool(
249
+ func=search, args_schema=SearchArgs,
250
+ name="search",
251
+ description="Web search. Returns numbered results.",
252
+ )
253
+ ```
254
+
255
+ Descriptions matter. LLMs pick tools based on the description. Be specific:
256
+ what does it do, what shape does the input take, what shape does the
257
+ output take, when to prefer it over another tool.
258
+
259
+ Add async variants (`AsyncStandardTool`, `AsyncStructuredTool`) when the
260
+ tool is I/O bound. Wire per-tool `timeout_sec=` and `circuit_breaker=`
261
+ if the tool can hang or fail transiently.
262
+
263
+ ---
264
+
265
+ ## 9. Persistent state in `run_python`
266
+
267
+ When `Permissions(python_persistent_state=True)`, every `run_python` call
268
+ gets a `state` dict auto-loaded from `<workspace>/.run_python_state.pkl`
269
+ and auto-saved at the end.
270
+
271
+ - Store reusable data across calls: `state['files'] = python_files`.
272
+ - Read it back next call: `python_files = state['files']`.
273
+ - Only picklable objects survive round trips; lambdas/threads/handles get
274
+ dropped with a stderr note listing dropped keys.
275
+ - Clear state with `state.clear()` or delete the hidden pickle.
276
+ - Enables Jupyter-like workflow: define once, use across many tool calls.
277
+
278
+ Without persistent state, each `run_python` starts fresh — combine setup
279
+ + analysis in ONE call to avoid re-definition.
280
+
281
+ ---
282
+
283
+ ## 10. Session directories (multi-run isolation)
284
+
285
+ Use `mint_session_dir("./workspace", prefix="run_")` before construction
286
+ to get a fresh subdirectory per run. Keeps deliverables from clobbering
287
+ each other when the same demo runs multiple times. Or use
288
+ `Permissions.new_session(base="./workspace")` — it mints the dir AND
289
+ returns a Permissions scoped to it.
290
+
291
+ ---
292
+
293
+ ## 11. When you get stuck
294
+
295
+ - If a tool errored, **read the error message.** It usually tells you the fix.
296
+ - If output is missing (`no output`), you forgot `print()`. Wrap the value.
297
+ - If you're not sure what tools you have, they're listed in your system prompt.
298
+ - If you're not sure about your sandbox, the FILESYSTEM SANDBOX block in
299
+ your system prompt lists it.
300
+ - If the task genuinely can't be done with your capabilities: emit a
301
+ Final_Answer that says so plainly, name what you tried, and let the
302
+ caller re-plan. Don't spin.
303
+
304
+ ---
305
+
306
+ **Bottom line:** narrow tools, narrow scope, return verbatim data, don't
307
+ loop. The framework's guardrails will save you from the worst spirals,
308
+ but you should never NEED them.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Bruce-Arhin Shadrach
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,11 @@
1
+ graft agentx_dev
2
+ graft examples
3
+ include AGENTX.md
4
+ include README.md
5
+ include LICENSE
6
+ prune tests
7
+ prune examples/_sandbox
8
+ prune examples/_sandbox_mcp
9
+ global-exclude __pycache__
10
+ global-exclude *.pyc
11
+ global-exclude *.pyo