agentx-dev 3.1.2__tar.gz → 3.1.3__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 (70) hide show
  1. agentx_dev-3.1.3/CHANGELOG.md +209 -0
  2. agentx_dev-3.1.3/CONTRIBUTING.md +105 -0
  3. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/MANIFEST.in +2 -0
  4. {agentx_dev-3.1.2/agentx_dev.egg-info → agentx_dev-3.1.3}/PKG-INFO +1 -1
  5. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/Runner/AgentRun.py +147 -26
  6. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/Runner/AsyncAgentRun.py +68 -3
  7. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/Tools.py +60 -41
  8. {agentx_dev-3.1.2 → agentx_dev-3.1.3/agentx_dev.egg-info}/PKG-INFO +1 -1
  9. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev.egg-info/SOURCES.txt +2 -0
  10. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/pyproject.toml +1 -1
  11. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/AGENTX.md +0 -0
  12. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/LICENSE +0 -0
  13. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/README.md +0 -0
  14. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/Agents/Agent.py +0 -0
  15. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/Agents/__init__.py +0 -0
  16. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/AsyncTools.py +0 -0
  17. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/AutoSetup.py +0 -0
  18. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/Cache.py +0 -0
  19. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/ChatModel.py +0 -0
  20. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/Compiler.py +0 -0
  21. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/Config.py +0 -0
  22. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/DefaultTools.py +0 -0
  23. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/Embeddings.py +0 -0
  24. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/Evals.py +0 -0
  25. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/Handoffs.py +0 -0
  26. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/Loader.py +0 -0
  27. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/MCP.py +0 -0
  28. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/Memory.py +0 -0
  29. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/Observability.py +0 -0
  30. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/Planner.py +0 -0
  31. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/Runner/__init__.py +0 -0
  32. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/Runner/promptTemplate.yaml +0 -0
  33. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/Session.py +0 -0
  34. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/Splitters.py +0 -0
  35. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/Streaming.py +0 -0
  36. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/Supervisor.py +0 -0
  37. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/VectorStores/__init__.py +0 -0
  38. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/VectorStores/chroma_store.py +0 -0
  39. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/VectorStores/pg_store.py +0 -0
  40. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/VectorStores/qdrant_store.py +0 -0
  41. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/WebTools.py +0 -0
  42. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/__init__.py +0 -0
  43. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/resources/__init__.py +0 -0
  44. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev/resources/promptTemplate.yaml +0 -0
  45. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev.egg-info/dependency_links.txt +0 -0
  46. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev.egg-info/requires.txt +0 -0
  47. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/agentx_dev.egg-info/top_level.txt +0 -0
  48. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/examples/README.md +0 -0
  49. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/examples/agentic_rag_demo.py +0 -0
  50. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/examples/async_example.py +0 -0
  51. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/examples/async_quickstart.py +0 -0
  52. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/examples/auto_features_example.py +0 -0
  53. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/examples/caching_example.py +0 -0
  54. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/examples/chatbot_example.py +0 -0
  55. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/examples/complete_example.py +0 -0
  56. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/examples/concurrent_example.py +0 -0
  57. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/examples/concurrent_tool_example.py +0 -0
  58. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/examples/file_agent_demo.py +0 -0
  59. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/examples/function_calling_demo.py +0 -0
  60. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/examples/mcp_demo.py +0 -0
  61. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/examples/observability_example.py +0 -0
  62. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/examples/orchestration_demo.py +0 -0
  63. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/examples/planner_example.py +0 -0
  64. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/examples/supervisor_codebase_analysis_demo.py +0 -0
  65. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/examples/supervisor_example.py +0 -0
  66. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/examples/sync_quickstart.py +0 -0
  67. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/examples/v3_1_1_features_demo.py +0 -0
  68. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/examples/v3_1_comprehensive_demo.py +0 -0
  69. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/examples/v3_1_features_demo.py +0 -0
  70. {agentx_dev-3.1.2 → agentx_dev-3.1.3}/setup.cfg +0 -0
@@ -0,0 +1,209 @@
1
+ # Changelog
2
+
3
+ All notable changes to `agentx-dev` are documented here. Format loosely
4
+ follows [Keep a Changelog](https://keepachangelog.com/); versioning is
5
+ [Semver](https://semver.org/).
6
+
7
+ ## [3.1.3] — 2026-07-22
8
+
9
+ Docs-only patch. No code changes since 3.1.2. Users on 3.1.2 don't
10
+ need to upgrade for functionality; upgrade to pick up the improved
11
+ onboarding docs bundled in the sdist.
12
+
13
+ ### Documentation
14
+
15
+ - **Tools doc rewritten to answer "how do I actually use these?"**
16
+ Added §0 `How each built-in tool is registered` as the entry
17
+ section. Two registration paths — auto vs manual — laid out in a
18
+ table on the first screen. Six runnable subsections covering every
19
+ combination:
20
+ - §0.1 DefaultTools via `Permissions(...)` (auto)
21
+ - §0.2 WebTools via `tools=[web_search_tool(), web_fetch_tool()]`
22
+ - §0.3 RAG via `TextSplitter` -> `VectorStore.add_documents` ->
23
+ `vector_search_tool(store)`
24
+ - §0.4 Handoffs via `handoff_tool` + `HandoffCoordinator`
25
+ - §0.5 Custom `StructuredTool` from scratch
26
+ - §0.6 Fully-loaded runner combining all of the above
27
+ - §0.7 Rules on name collisions, invisible-denied-capabilities,
28
+ async-tool behavior
29
+ The existing inventory + wrapper / controls / cheat-sheet sections
30
+ are unchanged; they now sit after the "how to use them" primer
31
+ instead of before it.
32
+
33
+ ## [3.1.2] — 2026-07-22
34
+
35
+ Patch release. Two independent fixes.
36
+
37
+ ### Fixed
38
+
39
+ - **`llm_judge` correctly parses YES/NO across providers.** The judge
40
+ parser was comparing the reply's first word to the literal string
41
+ `"YES"`. GPT-4o answers `"YES,"` (comma-suffixed), which failed the
42
+ equality check and marked every genuine PASS as FAIL. Claude replies
43
+ `"YES"` without punctuation so the bug hid during local development.
44
+ Fixed by matching `\b(YES|NO)\b` (word-boundary regex, case-
45
+ insensitive) at the start of the reply. Handles every real shape:
46
+ `YES`, `YES.`, `YES!`, `YES, exactly right`, `Yes.`, `yes -- reason`.
47
+ Ambiguous replies (`Maybe`, empty string) still fail closed.
48
+ - Regression test `test_llm_judge_parses_various_verdict_shapes`
49
+ covers 8 YES shapes, 5 NO shapes, and 4 ambiguous replies.
50
+
51
+ ### Added
52
+
53
+ - **`agentx_dev.Tools` is a one-stop tools namespace.** Users no
54
+ longer need to remember which module each tool lives in:
55
+
56
+ ```python
57
+ from agentx_dev.Tools import (
58
+ StandardTool, StructuredTool,
59
+ AsyncStandardTool, AsyncStructuredTool,
60
+ web_search_tool, web_fetch_tool,
61
+ vector_search_tool, handoff_tool,
62
+ DefaultTools, Permissions,
63
+ )
64
+ ```
65
+
66
+ Both this form and the pre-existing `from agentx_dev import X`
67
+ form coexist. Implementation uses PEP 562 module `__getattr__`
68
+ and `__dir__` so re-exports are lazy (no import cost for modules
69
+ the caller doesn't touch) and show up in IDE autocomplete +
70
+ `dir(agentx_dev.Tools)`.
71
+
72
+ ## [3.1.1] — 2026-07-21
73
+
74
+ Second batch of 3.1 features + a full docs + brand pass.
75
+
76
+ ### Added
77
+
78
+ **Streaming through orchestration**
79
+ - `Supervisor.stream()` / `AsyncSupervisor.astream()` emit
80
+ `plan_start` / `plan` / `dispatch` / `subtask_result` /
81
+ `synthesize_start` / `final` / `completion` events.
82
+ - `HandoffCoordinator.stream()` / `.astream()` emit `invoke` /
83
+ `completion` / `handoff` / `final` / `result` events per hop.
84
+ - Legacy `.run()` / `.arun()` refactored to consume the streams (no
85
+ code duplication).
86
+
87
+ **Prompt optimization — `Compiled`**
88
+ - New `agentx_dev.Compiler` module.
89
+ - `Compiled(runner_factory, trainset, ...)` iteratively refines a
90
+ runner's `system_addendum` against the eval harness. Half of
91
+ DSPy's power at a tenth of the surface.
92
+
93
+ **Anthropic Batch API**
94
+ - `Claude.batch(requests)` submits many prompts at Anthropic's 50%-off
95
+ batch rate, polls to completion, returns results in submission order.
96
+ - Per-request error dicts on failure; token usage funneled into
97
+ `TokenUsage` so cost tracking stays a single source of truth.
98
+
99
+ **Vector store adapters — `agentx_dev.VectorStores`**
100
+ - `ChromaVectorStore`, `QdrantVectorStore`, `PgVectorStore` — same
101
+ public shape as the in-memory `VectorStore` (`add` / `search` /
102
+ `delete` / `clear` / `__len__` / `embeddings`).
103
+ - `vector_search_tool()` and `SemanticMemory` accept any of them.
104
+ - SDK imports lazy; friendly `ImportError` when the underlying SDK
105
+ is missing.
106
+
107
+ **Trace viewer (`viewer/`)**
108
+ - Self-hosted single-page app that reads `FileHook` JSONL and renders
109
+ a timeline with type/text filters, summary sidebar, JSON drill-down.
110
+ - Works from `file://`, no server required.
111
+
112
+ **Docs site (`host/`)**
113
+ - Full editorial dark-first design system (JetBrains Mono headings,
114
+ Inter body, `#B8FF3E` electric-lime accent).
115
+ - Command palette (`Cmd+K`) with keyboard navigation and live search.
116
+ - Hero code snippet with hand-tinted syntax highlighting.
117
+ - Reading progress bar, breadcrumbs, header anchor links.
118
+ - Sidebar sliding active marker, collapsible groups.
119
+ - Code copy buttons, language labels.
120
+ - Right-rail auto-TOC with `IntersectionObserver` scrollspy.
121
+ - Dark/light theme toggle, persisted.
122
+ - Cache-busted assets so edits land on refresh without hard-reload.
123
+
124
+ **Brand identity (`brand/`)**
125
+ - Full brand kit: 5 SVG assets (`mark`, `mono`, `wordmark`, `logo-full`,
126
+ `app-icon`), `BRAND.md` strategy doc, rendered brand-kit HTML deck.
127
+ - Copy audit dropped "small" (weak) and "LangChain" references from
128
+ all marketing surfaces.
129
+ - Favicon wired into docs + trace viewer.
130
+
131
+ **Test suite (`tests/`)**
132
+ - Restored + expanded pytest suite: 127 tests passing (3 skipped for
133
+ absent optional SDKs).
134
+ - Coverage: parser + all `AgentType` variants, `ToolRegistry`
135
+ (dispatch / dup-guard / circuit-breaker / timeout), Permissions
136
+ (capability gating + sandbox + traversal), budgets (cost / rate /
137
+ retry / non-retryable HTTP), runner loop (streaming + output_schema
138
+ + chat history), embeddings + `VectorStore` + `SemanticMemory`,
139
+ handoffs (bounded hops + history sanitization), evals harness
140
+ (all assertion helpers + JSON case loaders), vector-store adapter
141
+ shape conformance.
142
+
143
+ **Docs (`docs/`)**
144
+ - Full docs tree (34 pages), including new pages for:
145
+ vector store adapters, prompt optimization, batch API, trace viewer,
146
+ and a **use-cases** landing (13 concrete scenarios with runnable code).
147
+ - Rewrote **Tools** page to enumerate every built-in tool with args,
148
+ return shape, capability flag, and use-case guidance.
149
+ - Rewrote **Agents** page to cover all four orchestration
150
+ architectures (Solo / Supervisor / Handoffs / Compiled) with
151
+ decision trees, worked examples, and cheat sheet.
152
+ - **Agentic RAG chatbot** as use case §13 — multi-query decomposition,
153
+ parallel retrieval, self-critique, citations, user memory.
154
+
155
+ **Examples**
156
+ - `examples/agentic_rag_demo.py` — the runnable version of the
157
+ agentic RAG use case. Auto-seeds a KB if none exists, `--demo` flag
158
+ runs a 3-turn scripted session proving user-notes recall works.
159
+
160
+ **Package**
161
+ - `[chroma]`, `[qdrant]`, `[pgvector]`, `[dev]` extras added.
162
+ - `[anthropic]` bumped to `>=0.36` (Batch API + prompt cache).
163
+
164
+ ### Fixed
165
+
166
+ - `AgentRunner._iter_run` in `bind_tools_natively=True` mode uses a
167
+ minimal system prompt instead of the AgentType template so the
168
+ ReAct `action/action_input` scaffold no longer fights the native
169
+ tool interface. Previously produced JSON-blob answers under GPT.
170
+ - `HandoffCoordinator._sanitize_history_for_next_agent` strips tool
171
+ and function role messages between hops so tool_call_ids from a
172
+ previous agent don't leak into the next model's call (OpenAI 400).
173
+ - Docs site marker positioning uses double-`requestAnimationFrame` +
174
+ `document.fonts.ready` so the sidebar accent bar lands on the
175
+ correct row even on a cold font cache.
176
+ - Primary hero CTA color uses `#doc .hero-cta a.primary` selector to
177
+ outrank `#doc a` link styling (previously rendered lime-on-lime
178
+ and was invisible).
179
+
180
+ ### Notes
181
+
182
+ - Package version bumped from `3.0.6` to `3.1.1`. The 3.1.0 release
183
+ did not ship publicly — 3.1.1 is the first 3.1-tagged PyPI release
184
+ and includes both batches of features.
185
+
186
+ ## [3.1.0] — internal only (commits 52840e7)
187
+
188
+ First batch of 3.1 features. Committed but not released to PyPI.
189
+ Merged into 3.1.1 for the public release.
190
+
191
+ ### Added
192
+ - Anthropic prompt caching (`Claude(enable_prompt_cache=True)`).
193
+ - Parallel per-turn tool dispatch in `AgentRunner`
194
+ (`bind_tools_natively=True`, `parallel_tool_workers`).
195
+ - Semantic memory (`SemanticMemory`, embeddings-backed retrieval).
196
+ - RAG core (`Embeddings`, `HashEmbeddings`, `OpenAIEmbeddings`,
197
+ `VectorStore`, `VectorHit`, `vector_search_tool()`).
198
+ - Agent-to-agent handoffs (`HandoffRequest`, `handoff_tool`,
199
+ `HandoffCoordinator`, `HandoffResult`).
200
+ - Evals harness (`EvalCase`, `EvalRunner`, `EvalReport`, 7 assertion
201
+ helpers, JSON case loader, `python -m agentx_dev.Evals run` CLI).
202
+ - `TokenUsage.cache_hit_ratio` property.
203
+
204
+ ## [3.0.6] — 2026-03 (baseline)
205
+
206
+ Security hardening baseline (SSRF guard on `web_fetch`, HMAC-signed
207
+ persistent state, scrubbed subprocess env, path sanitizer,
208
+ `permissions.json` mode 0o600, ReDoS guard on `grep`,
209
+ `invoke`/`ainvoke` accept bare strings and message lists).
@@ -0,0 +1,105 @@
1
+ # Contributing to agentx-dev
2
+
3
+ Thanks for your interest. This is a solo-authored framework, so a few
4
+ process choices are opinionated -- they exist to keep the surface area
5
+ small and the codebase readable.
6
+
7
+ ## Getting set up
8
+
9
+ ```bash
10
+ git clone https://github.com/shadrach098/Bruce_framework.git
11
+ cd Bruce_framework
12
+ python -m venv .venv && source .venv/bin/activate # or .venv\Scripts\activate on Windows
13
+ pip install -e ".[dev,anthropic]"
14
+ ```
15
+
16
+ Sanity check:
17
+
18
+ ```bash
19
+ pytest tests/ # should show 127 passing, 3 skipped
20
+ python -c "import agentx_dev; print(agentx_dev.__all__)"
21
+ ```
22
+
23
+ ## Before you open a PR
24
+
25
+ 1. **Run the tests.** `pytest tests/ -q` from the repo root.
26
+ 2. **Add tests** for whatever you changed. Every existing subsystem
27
+ has a `tests/test_<module>.py`; add cases there.
28
+ 3. **Keep the change focused.** One PR per feature or fix. If your
29
+ change touches five modules and adds three exports, split it.
30
+ 4. **Preserve existing behavior** unless the change is explicitly a
31
+ breaking one. Backwards-compat is a real value.
32
+ 5. **Update docs** if you added or changed a public API. `docs/`
33
+ holds the source; run `python host/build_data.py` to regenerate
34
+ the browsable site's `data.js`.
35
+
36
+ ## Commit + PR style
37
+
38
+ - **Commit messages:** `<type>: <short summary>` where type is one of
39
+ `feat` / `fix` / `docs` / `test` / `refactor` / `chore`. Follow
40
+ with a blank line and the body if the summary isn't enough. Look
41
+ at recent commits (`git log --oneline -20`) for the shape.
42
+ - **PR titles:** same shape as the commit message. If the PR has
43
+ multiple commits, the title summarizes the whole PR.
44
+ - **PR descriptions:** what changed, why, and one before/after
45
+ example if the change is user-visible.
46
+
47
+ ## What lands and what doesn't
48
+
49
+ Things that land easily:
50
+
51
+ - Bug fixes with a regression test.
52
+ - New tools that follow the existing patterns.
53
+ - Docs improvements (more examples, clearer explanations, fixing typos).
54
+ - New vector-store adapters or provider adapters that follow the
55
+ existing interface.
56
+ - Test coverage for uncovered paths.
57
+
58
+ Things that need discussion first (open an issue):
59
+
60
+ - New public classes or modules.
61
+ - Changes to public method signatures.
62
+ - Anything that grows the dependency footprint of the base install.
63
+ - Anything that reshapes the runner loop, `Supervisor`, or
64
+ `HandoffCoordinator`.
65
+
66
+ Things that don't land:
67
+
68
+ - Style-only refactors that reshape existing files.
69
+ - Adding a "generic" abstraction over one specific thing.
70
+ - Wrapping existing SDKs "for consistency."
71
+ - LangChain-compatibility shims.
72
+ - Auto-generated boilerplate.
73
+
74
+ ## Code style
75
+
76
+ - **Docstrings are the source of truth.** Every public class + method
77
+ gets one. Say *why* the choice was made, not just what it does.
78
+ - **No trailing summary comments** at the end of functions.
79
+ - **Type hints on public APIs.** Not needed on internal helpers if
80
+ the shape is obvious from three lines up.
81
+ - **Small files > large files**, but one-module features > splitting
82
+ a single concept across three files for tidiness.
83
+
84
+ ## Security-sensitive changes
85
+
86
+ The framework has explicit security surfaces:
87
+
88
+ - `Permissions` + sandbox enforcement in `DefaultTools.py`
89
+ - `run_python` HMAC-signed persistent state in `AutoSetup.py`
90
+ - SSRF guard in `WebTools.py`
91
+ - Session-id sanitizer in `DefaultTools.py`
92
+
93
+ If your change touches any of these, please:
94
+
95
+ 1. Add a test that exercises the security check.
96
+ 2. Add a note in the PR describing the threat model you considered.
97
+
98
+ See `AGENTX.md` at the repo root for the guardrails the framework
99
+ imposes on itself.
100
+
101
+ ## Questions?
102
+
103
+ Open an issue with the "question" label. Solo maintainer, so response
104
+ time varies -- a good repro / minimal example is the single biggest
105
+ help.
@@ -2,6 +2,8 @@ graft agentx_dev
2
2
  graft examples
3
3
  include AGENTX.md
4
4
  include README.md
5
+ include CHANGELOG.md
6
+ include CONTRIBUTING.md
5
7
  include LICENSE
6
8
  prune tests
7
9
  prune examples/_sandbox
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentx-dev
3
- Version: 3.1.2
3
+ Version: 3.1.3
4
4
  Summary: A production-grade Python framework for building LLM agents. Multi-provider chat, permission-gated tools, RAG (in-mem + Chroma/Qdrant/pgvector), semantic memory, Supervisor + Handoffs multi-agent orchestration with streaming, evals harness, prompt caching, Batch API, prompt-optimizer, MCP integration.
5
5
  Author-email: Bruce-Arhin Shadrach <brucearhin098@gmail.com>
6
6
  License: MIT License
@@ -1095,18 +1095,38 @@ def _read_action_input(parser_instance: BaseModel):
1095
1095
 
1096
1096
 
1097
1097
  class AgentRunner:
1098
- """
1099
- The main engine that orchestrates the agent's execution loop.
1098
+ """Sync agent runner. Connects a chat model, a prompt template, and a
1099
+ set of tools into a reason-act loop.
1100
+
1101
+ Typical use::
1100
1102
 
1101
- This class connects all the components of the framework: the LLM, the tools,
1102
- and the prompt. It manages the agent's state, including its conversational
1103
- history and internal scratchpad, and runs the primary "reason-act" cycle.
1103
+ from agentx_dev import AgentRunner, AgentType, Claude, Permissions
1104
1104
 
1105
- Set ``use_function_calling=True`` to route the AgentType parser through
1106
- the model's native tool-calling API (when supported) instead of parsing
1107
- JSON out of the assistant text. The parser model itself (e.g.
1108
- ``React_``) is forwarded as the forced tool, so the model returns
1109
- ``Thought``/``action``/``action_input`` as structured arguments.
1105
+ runner = AgentRunner(
1106
+ model=Claude(), # or GPT()
1107
+ agent=AgentType.ReAct,
1108
+ tools=[weather_tool], # your tools
1109
+ permissions=Permissions.full_access(["./workspace"]),
1110
+ )
1111
+ result = runner.invoke("What's the weather in Paris?")
1112
+ print(result.content)
1113
+
1114
+ The runner supports three execution modes, all set via constructor
1115
+ flags:
1116
+
1117
+ - **Text mode** (default) -- the model emits JSON matching the
1118
+ AgentType parser; the runner parses out the action and dispatches
1119
+ the tool. Works with any chat model.
1120
+ - **Function-calling mode** (``use_function_calling=True``) -- the
1121
+ AgentType parser itself is forwarded as the native FC tool.
1122
+ Requires the model to implement ``call_with_tools``.
1123
+ - **Native binding mode** (``bind_tools_natively=True``, 3.1) --
1124
+ your tools are bound directly as native FC tools; the AgentType
1125
+ parser is skipped. Multiple tool_use blocks in one turn dispatch
1126
+ concurrently on a bounded thread pool. Mutually exclusive with
1127
+ ``use_function_calling``.
1128
+
1129
+ For the async equivalent, see :class:`AsyncAgentRunner`.
1110
1130
  """
1111
1131
 
1112
1132
  def __init__(
@@ -1128,6 +1148,123 @@ class AgentRunner:
1128
1148
  system_addendum: Optional[str] = None,
1129
1149
  strict_tool_dispatch: bool = False,
1130
1150
  ):
1151
+ """Construct an ``AgentRunner``.
1152
+
1153
+ Args:
1154
+ model: The chat model backing every LLM call. Any
1155
+ ``BaseChatModel`` subclass -- ``Claude()``, ``GPT()``,
1156
+ or your own provider adapter.
1157
+ Agent: The prompt template + parser pair the runner uses.
1158
+ Accepts an ``AgentType`` member
1159
+ (``AgentType.ReAct`` / ``AgentType.Chain_of_Thought``
1160
+ / ``AgentType.Zero_Shot`` / ``AgentType.Few_Shot`` /
1161
+ ``AgentType.Instruction_Tuned``), a custom
1162
+ ``AgentFormatter`` instance you built, or a raw
1163
+ prompt-template string containing ``{tools}``,
1164
+ ``{tool_names}``, and ``{user_input}`` placeholders.
1165
+ Aliased as ``agent=`` (lowercase, PEP-8-friendly).
1166
+ Passing both ``Agent=`` and ``agent=`` raises
1167
+ ``TypeError`` -- pick one.
1168
+ tools: Tool instances the LLM can call. Each must be a
1169
+ ``StandardTool`` / ``StructuredTool`` /
1170
+ ``AsyncStandardTool`` / ``AsyncStructuredTool``.
1171
+ Defaults to an empty list. Framework guards apply
1172
+ automatically (duplicate-call, timeout, circuit
1173
+ breaker, cache, observability). Merged with any
1174
+ ``DefaultTools`` produced from ``permissions=`` below;
1175
+ collisions raise ``TypeError``.
1176
+ max_iterations: Cap on tool-calling cycles per invoke.
1177
+ Default 4. Bump for complex multi-step tasks. If the
1178
+ loop reaches the cap without a Final_Answer, the
1179
+ runner synthesizes a summary of what actually
1180
+ happened (last successful tool result + step list)
1181
+ so callers never get a bare "No final answer".
1182
+ auto_cache: When True (default), tool results are cached
1183
+ by ``(name, args)`` signature via
1184
+ ``get_global_cache()``. Second identical dispatch is
1185
+ a cache hit -- observability emits ``CACHE_HIT``.
1186
+ Disable when your tools have side effects
1187
+ (``send_email`` / ``write_file``) or time-varying
1188
+ outputs (``current_time`` / ``stock_price``).
1189
+ auto_memory: When True, the runner instantiates a default
1190
+ ``ConversationMemory`` and threads it as chat history
1191
+ automatically between invokes. Off by default; most
1192
+ real apps prefer explicit ``Session`` + custom
1193
+ ``BaseMemory`` (see the memory strategies guide).
1194
+ use_function_calling: When True, route the AgentType
1195
+ parser through the model's native tool-calling API
1196
+ (``call_with_tools``) instead of parsing JSON out of
1197
+ assistant text. Slightly higher accuracy on tool-call
1198
+ correctness. Requires the model to implement
1199
+ ``call_with_tools`` (GPT and Claude both do). Mutually
1200
+ exclusive with ``bind_tools_natively``.
1201
+ verbose: Print the running Thought / Action / Observation
1202
+ trace to stdout while the loop executes. Convenient
1203
+ during development; usually off in production.
1204
+ Independent of ``observability_enabled`` (which
1205
+ controls structured events, not stdout).
1206
+ bind_tools_natively: When True (3.1), the AgentType parser
1207
+ is bypassed and your tools are bound directly as
1208
+ native function-calling tools. The framework
1209
+ auto-registers a synthetic ``respond`` tool the model
1210
+ calls to end the loop. Multiple ``tool_use`` blocks
1211
+ per turn are dispatched concurrently on a bounded
1212
+ ``ThreadPoolExecutor``. Best latency for multi-tool
1213
+ turns. Mutually exclusive with
1214
+ ``use_function_calling``. Uses a minimal system
1215
+ prompt (not the AgentType template) so the parser
1216
+ scaffolding doesn't fight the native interface.
1217
+ parallel_tool_workers: Max concurrent dispatches per turn
1218
+ when ``bind_tools_natively=True``. Default 8. Actual
1219
+ worker count is ``min(this, number_of_tool_calls)``.
1220
+ Ignored when native binding is off. Only affects
1221
+ per-turn parallelism -- separate calls to
1222
+ ``runner.invoke`` remain sequential.
1223
+ agent: Lowercase PEP-8 alias for ``Agent``. Prefer this
1224
+ spelling in new code.
1225
+ permissions: A ``Permissions`` instance. When supplied,
1226
+ the framework calls ``DefaultTools.build(permissions)``
1227
+ and merges the resulting tools into ``tools=``. This
1228
+ is how you enable the sandboxed filesystem tools
1229
+ (``read_path`` / ``write_file`` / ``run_python``
1230
+ etc.) -- denied capabilities aren't registered, so
1231
+ the LLM literally cannot call them. Also injects a
1232
+ filesystem-sandbox description into the system
1233
+ prompt automatically. Name collisions with
1234
+ ``tools=`` raise ``TypeError`` at construction.
1235
+ include_denied_tools: When True, denied capabilities
1236
+ surface as no-op tools that return an error message
1237
+ ("this capability is disabled"). Useful for testing
1238
+ model behavior against a wider tool surface. Default
1239
+ False -- denied tools don't exist to the model.
1240
+ system_addendum: A role-specific instruction block
1241
+ appended to the AgentType template's system prompt.
1242
+ Use to encode a specialist contract
1243
+ (e.g. "you MUST call ``write_file`` at the end;
1244
+ never just describe the content"). When
1245
+ ``permissions=`` is also set, the auto-generated
1246
+ sandbox hint is prepended so the role text can
1247
+ reference paths. Set this to a lightweight cache
1248
+ miss beat -- Anthropic prompt caching kicks in when
1249
+ the addendum stays stable across calls.
1250
+ strict_tool_dispatch: When True, an unknown ``action``
1251
+ that looks like a tool identifier feeds an error
1252
+ observation back into the loop
1253
+ ("that tool doesn't exist; use one of X or
1254
+ Final_Answer") so the model can retry. Default
1255
+ False, which routes unknown actions to
1256
+ implicit-final. Turn on for models prone to
1257
+ misnaming tools (gpt-4o-mini).
1258
+
1259
+ Raises:
1260
+ TypeError: If both ``Agent`` and ``agent`` are passed, if
1261
+ ``Agent``/``agent`` is missing, if any item in
1262
+ ``tools`` is not a supported tool subclass, or if
1263
+ ``permissions`` isn't a ``Permissions`` instance.
1264
+ ValueError: If ``use_function_calling`` and
1265
+ ``bind_tools_natively`` are both True (mutually
1266
+ exclusive modes).
1267
+ """
1131
1268
  # PEP 8 alias: prefer lowercase `agent=`. Either argument works; passing
1132
1269
  # both raises so misuse is loud rather than silently ambiguous.
1133
1270
  if Agent is not None and agent is not None:
@@ -1173,23 +1310,7 @@ class AgentRunner:
1173
1310
  )
1174
1311
  tools = list(default_tools) + list(tools)
1175
1312
  auto_sandbox_hint = _build_sandbox_hint(permissions)
1176
- """
1177
- Initializes the AgentRunner.
1178
-
1179
- Args:
1180
- model (BaseChatModel): The LLM model.
1181
- Agent: The agent's prompt template (string, AgentFormattor, or AgentPrompt).
1182
- tools (List): A list of tool instances available to the agent.
1183
- max_iterations (Optional[int]): Maximum tool-calling cycles.
1184
- auto_cache (bool): Enable automatic tool result caching (default: True).
1185
- auto_memory (bool): Enable automatic memory management (default: False).
1186
- use_function_calling (bool): Route the AgentType parser through the
1187
- model's native tool-calling API. Requires the chat model to
1188
- implement ``call_with_tools`` (GPT and Claude do).
1189
1313
 
1190
- Raises:
1191
- TypeError: If any item in ``tools`` is not a StandardTool/StructuredTool.
1192
- """
1193
1314
  self.Query = ""
1194
1315
  self.Agent = Agent
1195
1316
  self.tools = tools
@@ -66,9 +66,27 @@ def _read_action_input(parser_instance: BaseModel):
66
66
 
67
67
 
68
68
  class AsyncAgentRunner:
69
- """
70
- Async version of AgentRunner with support for concurrent tool execution
71
- and native function calling.
69
+ """Async agent runner. Same reason-act loop as :class:`AgentRunner`
70
+ but every I/O path is awaitable.
71
+
72
+ Typical use::
73
+
74
+ import asyncio
75
+ from agentx_dev import AsyncAgentRunner, AgentType, Claude
76
+
77
+ runner = AsyncAgentRunner(
78
+ model=Claude(),
79
+ agent=AgentType.ReAct,
80
+ tools=[my_async_tool],
81
+ )
82
+ result = asyncio.run(runner.ainvoke("..."))
83
+
84
+ Accepts a mix of sync and async tools transparently. When at least
85
+ one async tool is registered, a ``batch_concurrent`` meta-tool is
86
+ auto-added so the LLM can dispatch several async calls in one turn
87
+ via ``asyncio.gather``. Combine with ``bind_tools_natively=True``
88
+ for the modern "parallel tool calls per turn" pattern where every
89
+ tool_use block in one assistant response is dispatched concurrently.
72
90
  """
73
91
 
74
92
  def __init__(
@@ -88,6 +106,53 @@ class AsyncAgentRunner:
88
106
  include_denied_tools: bool = False,
89
107
  strict_tool_dispatch: bool = False,
90
108
  ):
109
+ """Construct an ``AsyncAgentRunner``. Parameters mirror
110
+ :class:`AgentRunner` -- see that docstring for the full details;
111
+ the differences are noted here.
112
+
113
+ Args:
114
+ model: A ``BaseChatModel`` subclass. Both providers ship
115
+ sync + async paths, so ``Claude()`` and ``GPT()``
116
+ work here without changes.
117
+ Agent: The prompt template + parser pair. Same accepted
118
+ shapes as ``AgentRunner`` (``AgentType`` member,
119
+ custom ``AgentFormatter``, or raw string).
120
+ tools: Any mix of ``StandardTool`` / ``StructuredTool``
121
+ (sync) and ``AsyncStandardTool`` /
122
+ ``AsyncStructuredTool`` (async). Async tools use
123
+ ``asyncio.wait_for`` for cancellable timeouts; sync
124
+ tools run on the thread pool. When at least one async
125
+ tool is present, ``batch_concurrent`` is auto-added
126
+ so the LLM can batch calls via ``asyncio.gather``.
127
+ max_iterations: Loop cap per ``ainvoke``. Default 4.
128
+ auto_cache: Same as ``AgentRunner``: cache tool results
129
+ by ``(name, args)``. Default True.
130
+ auto_memory: Same as ``AgentRunner``. Default False.
131
+ use_function_calling: Route the AgentType parser through
132
+ native ``async_call_with_tools``. Mutually exclusive
133
+ with ``bind_tools_natively``.
134
+ verbose: Print step trace to stdout during ``ainvoke``.
135
+ bind_tools_natively: Bind user tools directly as native
136
+ FC tools; skip the AgentType parser. Multiple
137
+ ``tool_use`` blocks per turn dispatch concurrently
138
+ via ``asyncio.gather`` (no thread pool needed because
139
+ async tools are cancellable natively).
140
+ agent: PEP-8 lowercase alias for ``Agent``.
141
+ permissions: A ``Permissions`` instance -- auto-registers
142
+ the sandboxed ``DefaultTools`` and injects the
143
+ filesystem hint into the system prompt.
144
+ include_denied_tools: Surface denied capabilities as no-op
145
+ tools. Default False.
146
+ strict_tool_dispatch: Feed unknown-tool errors back into
147
+ the loop so the model can retry with a valid name.
148
+ Default False.
149
+
150
+ Raises:
151
+ TypeError: On missing / duplicate ``Agent``/``agent`` or
152
+ on a bad ``permissions`` type.
153
+ ValueError: On the mutually-exclusive combination of
154
+ ``use_function_calling`` and ``bind_tools_natively``.
155
+ """
91
156
  if Agent is not None and agent is not None:
92
157
  raise TypeError("AsyncAgentRunner received both 'Agent' and 'agent'; pass only one.")
93
158
  if agent is not None:
@@ -1,10 +1,26 @@
1
1
  """
2
- A lightweight framework for building LLM-powered agents that can use tools.
3
-
4
- This module provides the necessary components to define tools, format them for
5
- an agent prompt, and execute them within a loop controlled by an AgentRunner.
6
- It leverages Pydantic for structured data validation and generating schemas
7
- for function-calling APIs like OpenAI's.
2
+ Tool primitives + one-stop tools namespace for `agentx_dev`.
3
+
4
+ This module ships two things:
5
+
6
+ 1. The `StandardTool` and `StructuredTool` wrappers that adapt a
7
+ Python callable into something an LLM can call, with Pydantic-
8
+ validated arguments for the structured variant.
9
+ 2. A curated re-export surface (see the section at the bottom) so
10
+ users can import any built-in tool from a single namespace:
11
+
12
+ from agentx_dev.Tools import (
13
+ StandardTool, StructuredTool,
14
+ AsyncStandardTool, AsyncStructuredTool,
15
+ web_search_tool, web_fetch_tool,
16
+ vector_search_tool, handoff_tool,
17
+ DefaultTools, Permissions,
18
+ )
19
+
20
+ The tool wrappers are the foundation of the framework's function-
21
+ calling story -- every dispatched call, whether it's a filesystem
22
+ tool, a RAG search, or a user-supplied Slack notifier, flows through
23
+ these two classes.
8
24
  """
9
25
 
10
26
  from typing import Dict, Callable, List, Type
@@ -168,12 +184,13 @@ from typing import List, Dict, Any
168
184
 
169
185
 
170
186
  # ---------------------------------------------------------------------------
171
- # Convenience re-exports so `agentx_dev.Tools` is a one-stop namespace
187
+ # Convenience re-exports so `agentx_dev.Tools` is a one-stop namespace.
172
188
  #
173
189
  # Users can now import any tool from this module:
174
190
  #
175
191
  # from agentx_dev.Tools import (
176
192
  # StandardTool, StructuredTool, # wrappers (defined above)
193
+ # AsyncStandardTool, AsyncStructuredTool,# async wrappers
177
194
  # web_search_tool, web_fetch_tool, # web
178
195
  # vector_search_tool, # RAG
179
196
  # handoff_tool, # multi-agent
@@ -182,43 +199,45 @@ from typing import List, Dict, Any
182
199
  #
183
200
  # The top-level imports (from agentx_dev import ...) still work; this is
184
201
  # purely additive so callers who prefer the namespaced form get it too.
185
- # Lazy-import-inside-getattr keeps import time low and avoids circular
186
- # imports with modules that already import from Tools.py.
202
+ #
203
+ # Design note: previously this used a PEP 562 __getattr__ for lazy
204
+ # loading. That saved microseconds at import time but broke IDE
205
+ # autocomplete + syntax highlighting -- static analyzers can't see
206
+ # names that only exist inside a __getattr__ fallback. Since
207
+ # `agentx_dev/__init__.py` already eager-loads all these modules at
208
+ # top-level import anyway, the lazy-load was a false economy.
209
+ # Eager imports here just re-export symbols that are already in memory.
187
210
  # ---------------------------------------------------------------------------
188
211
 
189
- _TOOL_EXPORTS = {
190
- # Web tools
191
- "web_search_tool": ("agentx_dev.WebTools", "web_search_tool"),
192
- "web_fetch_tool": ("agentx_dev.WebTools", "web_fetch_tool"),
212
+ # Web
213
+ from agentx_dev.WebTools import web_search_tool, web_fetch_tool
214
+
215
+ # RAG
216
+ from agentx_dev.Embeddings import vector_search_tool
217
+
218
+ # Multi-agent handoffs
219
+ from agentx_dev.Handoffs import handoff_tool
220
+
221
+ # Async tool wrappers (siblings to Standard/Structured)
222
+ from agentx_dev.AsyncTools import AsyncStandardTool, AsyncStructuredTool
223
+
224
+ # Filesystem / permissions
225
+ from agentx_dev.DefaultTools import DefaultTools, Permissions
226
+
227
+
228
+ __all__ = [
229
+ # Wrappers defined in this module
230
+ "StandardTool", "StructuredTool",
231
+ "AsyncStandardTool", "AsyncStructuredTool",
232
+ # Web
233
+ "web_search_tool", "web_fetch_tool",
193
234
  # RAG
194
- "vector_search_tool": ("agentx_dev.Embeddings", "vector_search_tool"),
195
- # Multi-agent handoffs
196
- "handoff_tool": ("agentx_dev.Handoffs", "handoff_tool"),
197
- # Async tool wrappers (siblings to Standard/Structured)
198
- "AsyncStandardTool": ("agentx_dev.AsyncTools", "AsyncStandardTool"),
199
- "AsyncStructuredTool": ("agentx_dev.AsyncTools", "AsyncStructuredTool"),
200
- # Filesystem / permissions
201
- "DefaultTools": ("agentx_dev.DefaultTools", "DefaultTools"),
202
- "Permissions": ("agentx_dev.DefaultTools", "Permissions"),
203
- }
204
-
205
-
206
- def __getattr__(name):
207
- """PEP 562 module __getattr__: lazy-load re-exports on first access."""
208
- if name in _TOOL_EXPORTS:
209
- import importlib
210
- mod_name, attr_name = _TOOL_EXPORTS[name]
211
- mod = importlib.import_module(mod_name)
212
- obj = getattr(mod, attr_name)
213
- # Cache on the module so subsequent lookups skip the importlib call.
214
- globals()[name] = obj
215
- return obj
216
- raise AttributeError(f"module 'agentx_dev.Tools' has no attribute {name!r}")
217
-
218
-
219
- def __dir__():
220
- """Expose the re-exports to `dir(agentx_dev.Tools)` and IDE autocomplete."""
221
- return sorted(list(globals().keys()) + list(_TOOL_EXPORTS.keys()))
235
+ "vector_search_tool",
236
+ # Multi-agent
237
+ "handoff_tool",
238
+ # Sandbox
239
+ "DefaultTools", "Permissions",
240
+ ]
222
241
 
223
242
 
224
243
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentx-dev
3
- Version: 3.1.2
3
+ Version: 3.1.3
4
4
  Summary: A production-grade Python framework for building LLM agents. Multi-provider chat, permission-gated tools, RAG (in-mem + Chroma/Qdrant/pgvector), semantic memory, Supervisor + Handoffs multi-agent orchestration with streaming, evals harness, prompt caching, Batch API, prompt-optimizer, MCP integration.
5
5
  Author-email: Bruce-Arhin Shadrach <brucearhin098@gmail.com>
6
6
  License: MIT License
@@ -1,4 +1,6 @@
1
1
  AGENTX.md
2
+ CHANGELOG.md
3
+ CONTRIBUTING.md
2
4
  LICENSE
3
5
  MANIFEST.in
4
6
  README.md
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
 
3
3
  name = "agentx-dev"
4
- version = "3.1.2"
4
+ version = "3.1.3"
5
5
  description = "A production-grade Python framework for building LLM agents. Multi-provider chat, permission-gated tools, RAG (in-mem + Chroma/Qdrant/pgvector), semantic memory, Supervisor + Handoffs multi-agent orchestration with streaming, evals harness, prompt caching, Batch API, prompt-optimizer, MCP integration."
6
6
  authors = [{ name = "Bruce-Arhin Shadrach", email = "brucearhin098@gmail.com" }]
7
7
  # Best practice: link to the license file
File without changes
File without changes
File without changes
File without changes
File without changes