agentx-kit 0.2.0__tar.gz → 0.4.0__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.
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/PKG-INFO +61 -1
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/README.md +51 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/pyproject.toml +5 -1
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/__init__.py +12 -1
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/cli.py +70 -0
- agentx_kit-0.4.0/src/agentx/connector/__init__.py +18 -0
- agentx_kit-0.4.0/src/agentx/connector/build.py +111 -0
- agentx_kit-0.4.0/src/agentx/connector/recommend.py +116 -0
- agentx_kit-0.4.0/src/agentx/connector/server.py +108 -0
- agentx_kit-0.4.0/src/agentx/dashboard/__init__.py +40 -0
- agentx_kit-0.4.0/src/agentx/dashboard/app.py +270 -0
- agentx_kit-0.4.0/src/agentx/insights/__init__.py +18 -0
- agentx_kit-0.4.0/src/agentx/insights/analyze.py +85 -0
- agentx_kit-0.4.0/src/agentx/insights/log.py +88 -0
- agentx_kit-0.4.0/src/agentx/insights/optimize.py +80 -0
- agentx_kit-0.4.0/src/agentx/insights/tokens.py +97 -0
- agentx_kit-0.4.0/tests/test_connector.py +70 -0
- agentx_kit-0.4.0/tests/test_insights.py +94 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/.github/workflows/publish.yml +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/.gitignore +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/DESIGN.md +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/LICENSE +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/RESEARCH.md +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/config.py +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/frameworks/__init__.py +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/frameworks/crewai_agent.py +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/frameworks/langchain_agent.py +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/guardrails.py +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/memory/__init__.py +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/memory/store.py +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/observability.py +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/prompts/__init__.py +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/prompts/templates.py +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/providers/__init__.py +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/providers/base.py +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/providers/factory.py +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/providers/registry.py +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/rag/__init__.py +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/rag/pipeline.py +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/reliability.py +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/__init__.py +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/generator.py +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/prompts_store.py +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/spec.py +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/Dockerfile.j2 +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/README.md.j2 +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/ci.yml.j2 +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/docker-compose.yml.j2 +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/dockerignore.j2 +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/env.example.j2 +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/evals/dataset.json.j2 +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/evals/run_evals.py.j2 +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/gitignore.j2 +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/mcp_servers.json.j2 +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pkg/__init__.py.j2 +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pkg/agents.py.j2 +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pkg/config.py.j2 +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pkg/guardrails.py.j2 +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pkg/main.py.j2 +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pkg/memory.py.j2 +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pkg/observability.py.j2 +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pkg/prompts.py.j2 +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pkg/rag.py.j2 +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pkg/server.py.j2 +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pkg/tools.py.j2 +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pyproject.toml.j2 +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/skills_seed.json.j2 +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/wizard.py +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/skills/__init__.py +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/skills/registry.py +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/structured.py +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/tools/__init__.py +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/tools/builtin.py +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/tools/mcp.py +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/tests/test_enterprise.py +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/tests/test_prompts.py +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/tests/test_providers.py +0 -0
- {agentx_kit-0.2.0 → agentx_kit-0.4.0}/tests/test_scaffold.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentx-kit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: An open-source, provider-agnostic agentic framework + interactive project scaffolder for LangChain and CrewAI. Pick your LLM provider, agents, RAG, memory, MCP tools and skills — generate a ready-to-run uv project.
|
|
5
5
|
Project-URL: Homepage, https://github.com/muhammadyahiya/agentx-kit
|
|
6
6
|
Project-URL: Repository, https://github.com/muhammadyahiya/agentx-kit
|
|
@@ -48,7 +48,10 @@ Requires-Dist: mcp>=1.2.0; extra == 'all'
|
|
|
48
48
|
Requires-Dist: openinference-instrumentation-langchain>=0.1.0; extra == 'all'
|
|
49
49
|
Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.20.0; extra == 'all'
|
|
50
50
|
Requires-Dist: opentelemetry-sdk>=1.20.0; extra == 'all'
|
|
51
|
+
Requires-Dist: pandas>=2.0.0; extra == 'all'
|
|
51
52
|
Requires-Dist: sse-starlette>=2.0.0; extra == 'all'
|
|
53
|
+
Requires-Dist: streamlit>=1.40.0; extra == 'all'
|
|
54
|
+
Requires-Dist: tiktoken>=0.7.0; extra == 'all'
|
|
52
55
|
Requires-Dist: uvicorn[standard]>=0.29.0; extra == 'all'
|
|
53
56
|
Provides-Extra: anthropic
|
|
54
57
|
Requires-Dist: langchain-anthropic>=0.2.0; extra == 'anthropic'
|
|
@@ -56,8 +59,14 @@ Provides-Extra: azure
|
|
|
56
59
|
Requires-Dist: langchain-openai>=0.2.0; extra == 'azure'
|
|
57
60
|
Provides-Extra: bedrock
|
|
58
61
|
Requires-Dist: langchain-aws>=0.2.0; extra == 'bedrock'
|
|
62
|
+
Provides-Extra: connector
|
|
63
|
+
Requires-Dist: mcp>=1.2.0; extra == 'connector'
|
|
59
64
|
Provides-Extra: crewai
|
|
60
65
|
Requires-Dist: crewai>=0.70.0; extra == 'crewai'
|
|
66
|
+
Provides-Extra: dashboard
|
|
67
|
+
Requires-Dist: pandas>=2.0.0; extra == 'dashboard'
|
|
68
|
+
Requires-Dist: streamlit>=1.40.0; extra == 'dashboard'
|
|
69
|
+
Requires-Dist: tiktoken>=0.7.0; extra == 'dashboard'
|
|
61
70
|
Provides-Extra: dev
|
|
62
71
|
Requires-Dist: pytest-cov>=5.0.0; extra == 'dev'
|
|
63
72
|
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
@@ -233,6 +242,55 @@ agentx prompt remove reviewer
|
|
|
233
242
|
A blank `system_prompt` is auto-derived from the agent's role + goal. You can also
|
|
234
243
|
just open `prompts.json` in an editor — the CLI is a convenience, not a gate.
|
|
235
244
|
|
|
245
|
+
## 📊 Prompt dashboard (observability + optimization)
|
|
246
|
+
A Streamlit workbench to **understand and refine how your prompts talk to the LLM** —
|
|
247
|
+
launch it any time:
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
pip install "agentx-kit[dashboard]"
|
|
251
|
+
agentx dashboard # opens http://localhost:8501
|
|
252
|
+
agentx prompt set assistant -d # edit a prompt AND open the dashboard
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
It gives you, live as you edit:
|
|
256
|
+
- **Token count, context-window utilization gauge, and cost estimate** (tiktoken-accurate).
|
|
257
|
+
- **Quality score (0–100)** with a checklist (role / goal / output-format / examples / constraints / specificity) and **concrete suggestions + limit warnings**.
|
|
258
|
+
- **✨ One-click LLM optimization** — refines the prompt while preserving intent, shows a **diff + rationale + token delta**, and can **apply the result straight back to `prompts.json`**.
|
|
259
|
+
- **▶️ Test run** — send the prompt to the model and see the response with **tokens in/out, latency, and cost**.
|
|
260
|
+
- **📈 Usage trends** — tokens, cost, and latency over time, logged locally to `.agentx/insights.jsonl`.
|
|
261
|
+
|
|
262
|
+
Run it inside a generated AgentX project and it reads/writes that project's
|
|
263
|
+
`prompts.json`; run it anywhere else for a free-form prompt scratchpad.
|
|
264
|
+
|
|
265
|
+
## 🔌 Use as a connector (Claude / Copilot / Codex)
|
|
266
|
+
AgentX-Kit ships an **MCP server**, so any MCP-capable assistant can scaffold a
|
|
267
|
+
complete project from **a single prompt with your problem statement**.
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
pip install "agentx-kit[connector]"
|
|
271
|
+
agentx mcp --print-config # prints the client config below
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
Add it to your client (then restart it):
|
|
275
|
+
```jsonc
|
|
276
|
+
// Claude Desktop / Codex / Copilot — under "mcpServers"
|
|
277
|
+
{ "mcpServers": { "agentx-kit": { "command": "agentx", "args": ["mcp"] } } }
|
|
278
|
+
```
|
|
279
|
+
```bash
|
|
280
|
+
# Claude Code one-liner
|
|
281
|
+
claude mcp add agentx-kit -- agentx mcp
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
Now just ask, in plain language:
|
|
285
|
+
> *“Build a customer-support agent that answers from our product docs and serves a REST API.”*
|
|
286
|
+
|
|
287
|
+
The assistant calls AgentX-Kit's tools and you get a complete, runnable project:
|
|
288
|
+
- **`recommend_project(problem_statement)`** — suggests framework, provider, agent count, and features.
|
|
289
|
+
- **`create_agent_project(problem_statement, …)`** — generates the project (infers RAG/serve/memory/etc. from the statement, or take explicit overrides / `enterprise=true`) and returns the file tree + key file contents + run steps.
|
|
290
|
+
- **`list_providers`**, **`analyze_prompt`**, **`optimize_prompt`** — provider list + prompt insights.
|
|
291
|
+
|
|
292
|
+
So from one sentence the assistant produces a pre-wired project (prompts already seeded from your use case), ready to `uv sync && uv run`.
|
|
293
|
+
|
|
236
294
|
## 🏢 Enterprise pack
|
|
237
295
|
Generate a production-shaped project with one flag — informed by a survey of
|
|
238
296
|
CrewAI/LangGraph/create-llama/AgentStack/agno/pydantic-ai (see [RESEARCH.md](RESEARCH.md)):
|
|
@@ -281,6 +339,8 @@ llm = build_resilient_chat("openai", "gpt-4o-mini", fallbacks=[("anthropic", "cl
|
|
|
281
339
|
| `mcp` | `langchain-mcp-adapters` | MCP tools |
|
|
282
340
|
| `observability` | `opentelemetry-*`, `openinference-*` | tracing |
|
|
283
341
|
| `server` | `fastapi`, `uvicorn` | serving |
|
|
342
|
+
| `dashboard` | `streamlit`, `tiktoken`, `pandas` | prompt observability dashboard |
|
|
343
|
+
| `connector` | `mcp` | MCP server for Claude/Copilot/Codex |
|
|
284
344
|
| `all` | everything above | kitchen sink |
|
|
285
345
|
|
|
286
346
|
See [DESIGN.md](DESIGN.md) for the architecture and [RESEARCH.md](RESEARCH.md) for the competitive analysis behind these features.
|
|
@@ -138,6 +138,55 @@ agentx prompt remove reviewer
|
|
|
138
138
|
A blank `system_prompt` is auto-derived from the agent's role + goal. You can also
|
|
139
139
|
just open `prompts.json` in an editor — the CLI is a convenience, not a gate.
|
|
140
140
|
|
|
141
|
+
## 📊 Prompt dashboard (observability + optimization)
|
|
142
|
+
A Streamlit workbench to **understand and refine how your prompts talk to the LLM** —
|
|
143
|
+
launch it any time:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
pip install "agentx-kit[dashboard]"
|
|
147
|
+
agentx dashboard # opens http://localhost:8501
|
|
148
|
+
agentx prompt set assistant -d # edit a prompt AND open the dashboard
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
It gives you, live as you edit:
|
|
152
|
+
- **Token count, context-window utilization gauge, and cost estimate** (tiktoken-accurate).
|
|
153
|
+
- **Quality score (0–100)** with a checklist (role / goal / output-format / examples / constraints / specificity) and **concrete suggestions + limit warnings**.
|
|
154
|
+
- **✨ One-click LLM optimization** — refines the prompt while preserving intent, shows a **diff + rationale + token delta**, and can **apply the result straight back to `prompts.json`**.
|
|
155
|
+
- **▶️ Test run** — send the prompt to the model and see the response with **tokens in/out, latency, and cost**.
|
|
156
|
+
- **📈 Usage trends** — tokens, cost, and latency over time, logged locally to `.agentx/insights.jsonl`.
|
|
157
|
+
|
|
158
|
+
Run it inside a generated AgentX project and it reads/writes that project's
|
|
159
|
+
`prompts.json`; run it anywhere else for a free-form prompt scratchpad.
|
|
160
|
+
|
|
161
|
+
## 🔌 Use as a connector (Claude / Copilot / Codex)
|
|
162
|
+
AgentX-Kit ships an **MCP server**, so any MCP-capable assistant can scaffold a
|
|
163
|
+
complete project from **a single prompt with your problem statement**.
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
pip install "agentx-kit[connector]"
|
|
167
|
+
agentx mcp --print-config # prints the client config below
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Add it to your client (then restart it):
|
|
171
|
+
```jsonc
|
|
172
|
+
// Claude Desktop / Codex / Copilot — under "mcpServers"
|
|
173
|
+
{ "mcpServers": { "agentx-kit": { "command": "agentx", "args": ["mcp"] } } }
|
|
174
|
+
```
|
|
175
|
+
```bash
|
|
176
|
+
# Claude Code one-liner
|
|
177
|
+
claude mcp add agentx-kit -- agentx mcp
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Now just ask, in plain language:
|
|
181
|
+
> *“Build a customer-support agent that answers from our product docs and serves a REST API.”*
|
|
182
|
+
|
|
183
|
+
The assistant calls AgentX-Kit's tools and you get a complete, runnable project:
|
|
184
|
+
- **`recommend_project(problem_statement)`** — suggests framework, provider, agent count, and features.
|
|
185
|
+
- **`create_agent_project(problem_statement, …)`** — generates the project (infers RAG/serve/memory/etc. from the statement, or take explicit overrides / `enterprise=true`) and returns the file tree + key file contents + run steps.
|
|
186
|
+
- **`list_providers`**, **`analyze_prompt`**, **`optimize_prompt`** — provider list + prompt insights.
|
|
187
|
+
|
|
188
|
+
So from one sentence the assistant produces a pre-wired project (prompts already seeded from your use case), ready to `uv sync && uv run`.
|
|
189
|
+
|
|
141
190
|
## 🏢 Enterprise pack
|
|
142
191
|
Generate a production-shaped project with one flag — informed by a survey of
|
|
143
192
|
CrewAI/LangGraph/create-llama/AgentStack/agno/pydantic-ai (see [RESEARCH.md](RESEARCH.md)):
|
|
@@ -186,6 +235,8 @@ llm = build_resilient_chat("openai", "gpt-4o-mini", fallbacks=[("anthropic", "cl
|
|
|
186
235
|
| `mcp` | `langchain-mcp-adapters` | MCP tools |
|
|
187
236
|
| `observability` | `opentelemetry-*`, `openinference-*` | tracing |
|
|
188
237
|
| `server` | `fastapi`, `uvicorn` | serving |
|
|
238
|
+
| `dashboard` | `streamlit`, `tiktoken`, `pandas` | prompt observability dashboard |
|
|
239
|
+
| `connector` | `mcp` | MCP server for Claude/Copilot/Codex |
|
|
189
240
|
| `all` | everything above | kitchen sink |
|
|
190
241
|
|
|
191
242
|
See [DESIGN.md](DESIGN.md) for the architecture and [RESEARCH.md](RESEARCH.md) for the competitive analysis behind these features.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
# PyPI distribution name (import name + CLI stay `agentx`; `agentx` was taken).
|
|
3
3
|
name = "agentx-kit"
|
|
4
|
-
version = "0.
|
|
4
|
+
version = "0.4.0"
|
|
5
5
|
description = "An open-source, provider-agnostic agentic framework + interactive project scaffolder for LangChain and CrewAI. Pick your LLM provider, agents, RAG, memory, MCP tools and skills — generate a ready-to-run uv project."
|
|
6
6
|
readme = "README.md"
|
|
7
7
|
requires-python = ">=3.10,<3.14"
|
|
@@ -59,6 +59,8 @@ observability = [
|
|
|
59
59
|
"openinference-instrumentation-langchain>=0.1.0",
|
|
60
60
|
]
|
|
61
61
|
server = ["fastapi>=0.110.0", "uvicorn[standard]>=0.29.0", "sse-starlette>=2.0.0"]
|
|
62
|
+
dashboard = ["streamlit>=1.40.0", "tiktoken>=0.7.0", "pandas>=2.0.0"]
|
|
63
|
+
connector = ["mcp>=1.2.0"]
|
|
62
64
|
|
|
63
65
|
# ---- Bundles ----
|
|
64
66
|
all = [
|
|
@@ -71,6 +73,8 @@ all = [
|
|
|
71
73
|
"opentelemetry-sdk>=1.20.0", "opentelemetry-exporter-otlp-proto-http>=1.20.0",
|
|
72
74
|
"openinference-instrumentation-langchain>=0.1.0",
|
|
73
75
|
"fastapi>=0.110.0", "uvicorn[standard]>=0.29.0", "sse-starlette>=2.0.0",
|
|
76
|
+
"streamlit>=1.40.0", "tiktoken>=0.7.0", "pandas>=2.0.0",
|
|
77
|
+
"mcp>=1.2.0",
|
|
74
78
|
]
|
|
75
79
|
dev = ["pytest>=8.0.0", "pytest-cov>=5.0.0"]
|
|
76
80
|
|
|
@@ -16,7 +16,7 @@ is enough to get started.
|
|
|
16
16
|
"""
|
|
17
17
|
from __future__ import annotations
|
|
18
18
|
|
|
19
|
-
__version__ = "0.
|
|
19
|
+
__version__ = "0.4.0"
|
|
20
20
|
|
|
21
21
|
from .providers import ( # noqa: E402
|
|
22
22
|
ProviderSpec,
|
|
@@ -33,6 +33,12 @@ from .reliability import ( # noqa: E402
|
|
|
33
33
|
build_resilient_chat,
|
|
34
34
|
)
|
|
35
35
|
from .structured import structured_model # noqa: E402
|
|
36
|
+
from .insights import ( # noqa: E402
|
|
37
|
+
analyze_prompt,
|
|
38
|
+
count_tokens,
|
|
39
|
+
estimate_cost,
|
|
40
|
+
optimize_prompt,
|
|
41
|
+
)
|
|
36
42
|
|
|
37
43
|
__all__ = [
|
|
38
44
|
"__version__",
|
|
@@ -52,4 +58,9 @@ __all__ = [
|
|
|
52
58
|
"apply_guards",
|
|
53
59
|
"GuardrailError",
|
|
54
60
|
"structured_model",
|
|
61
|
+
# prompt insights
|
|
62
|
+
"analyze_prompt",
|
|
63
|
+
"optimize_prompt",
|
|
64
|
+
"count_tokens",
|
|
65
|
+
"estimate_cost",
|
|
55
66
|
]
|
|
@@ -46,6 +46,58 @@ def providers() -> None:
|
|
|
46
46
|
console.print(table)
|
|
47
47
|
|
|
48
48
|
|
|
49
|
+
@app.command()
|
|
50
|
+
def dashboard(
|
|
51
|
+
port: int = typer.Option(8501, "--port", help="Port for the dashboard server."),
|
|
52
|
+
provider: str = typer.Option(None, "--provider", help="Default provider to preselect."),
|
|
53
|
+
model: str = typer.Option(None, "--model", help="Default model to preselect."),
|
|
54
|
+
project: Path = typer.Option(None, "--project", help="Project dir (default: cwd; auto-detects prompts.json)."),
|
|
55
|
+
) -> None:
|
|
56
|
+
"""Launch the prompt observability & optimization dashboard (Streamlit).
|
|
57
|
+
|
|
58
|
+
A workbench to edit a prompt and see token usage, context-window utilization,
|
|
59
|
+
cost, quality suggestions, one-click LLM optimization, and test runs — live.
|
|
60
|
+
"""
|
|
61
|
+
from .dashboard import launch
|
|
62
|
+
|
|
63
|
+
console.print(f"[cyan]Launching AgentX dashboard on http://localhost:{port} …[/] (Ctrl+C to stop)")
|
|
64
|
+
try:
|
|
65
|
+
launch(port=port, provider=provider, model=model, project=str(project) if project else None)
|
|
66
|
+
except RuntimeError as exc:
|
|
67
|
+
console.print(f"[red]{exc}[/]")
|
|
68
|
+
raise typer.Exit(1) from exc
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@app.command()
|
|
72
|
+
def mcp(
|
|
73
|
+
print_config: bool = typer.Option(False, "--print-config", help="Print MCP client config for Claude/Codex/Copilot and exit."),
|
|
74
|
+
) -> None:
|
|
75
|
+
"""Run AgentX-Kit as an MCP server (connector for Claude / Copilot / Codex).
|
|
76
|
+
|
|
77
|
+
Once connected, a single prompt with a problem statement generates a complete
|
|
78
|
+
project. Add it to a client with the config from `agentx mcp --print-config`.
|
|
79
|
+
"""
|
|
80
|
+
if print_config:
|
|
81
|
+
import json
|
|
82
|
+
|
|
83
|
+
from .connector import client_config
|
|
84
|
+
|
|
85
|
+
cfg = client_config()
|
|
86
|
+
console.print("[bold]MCP client config[/] (Claude Desktop / Claude Code / Codex / Copilot):\n")
|
|
87
|
+
console.print(json.dumps(cfg, indent=2))
|
|
88
|
+
console.print("\n[bold]Claude Code one-liner:[/]")
|
|
89
|
+
console.print(" claude mcp add agentx-kit -- agentx mcp")
|
|
90
|
+
console.print("\n[dim]Add the JSON under \"mcpServers\" in your client's MCP config "
|
|
91
|
+
"(e.g. claude_desktop_config.json), then restart the client.[/]")
|
|
92
|
+
return
|
|
93
|
+
try:
|
|
94
|
+
from .connector import run
|
|
95
|
+
except RuntimeError as exc:
|
|
96
|
+
console.print(f"[red]{exc}[/]")
|
|
97
|
+
raise typer.Exit(1) from exc
|
|
98
|
+
run() # stdio; no console output (the client drives it)
|
|
99
|
+
|
|
100
|
+
|
|
49
101
|
def _result_panel(result, spec: ProjectSpec) -> None:
|
|
50
102
|
lines = [f"[bold green]✓[/] Project '{spec.slug}' created at:", f" {result.target_dir}", ""]
|
|
51
103
|
lines += [f" • {m}" for m in result.messages]
|
|
@@ -156,6 +208,20 @@ def _read_text_arg(text: str | None, from_file: Path | None) -> str:
|
|
|
156
208
|
return (text or "").strip()
|
|
157
209
|
|
|
158
210
|
|
|
211
|
+
def _maybe_launch_dashboard(launch_flag: bool, project_dir: Path) -> None:
|
|
212
|
+
"""Open the prompt dashboard after an edit if requested."""
|
|
213
|
+
if not launch_flag:
|
|
214
|
+
console.print(" [dim]Tip: run `agentx dashboard` to tune this prompt live.[/]")
|
|
215
|
+
return
|
|
216
|
+
from .dashboard import launch
|
|
217
|
+
|
|
218
|
+
console.print("[cyan]Opening dashboard…[/]")
|
|
219
|
+
try:
|
|
220
|
+
launch(project=str(project_dir))
|
|
221
|
+
except RuntimeError as exc:
|
|
222
|
+
console.print(f"[yellow]{exc}[/]")
|
|
223
|
+
|
|
224
|
+
|
|
159
225
|
@prompt_app.command("list")
|
|
160
226
|
def prompt_list(project: Path = typer.Option(None, "--project", help="Project dir (default: search from cwd).")) -> None:
|
|
161
227
|
"""List agents and their (resolved) prompts."""
|
|
@@ -177,6 +243,7 @@ def prompt_set(
|
|
|
177
243
|
text: str = typer.Option("", "--text", "-t", help="New system prompt text."),
|
|
178
244
|
from_file: Path = typer.Option(None, "--file", "-f", help="Read prompt text from a file."),
|
|
179
245
|
project: Path = typer.Option(None, "--project"),
|
|
246
|
+
dash: bool = typer.Option(False, "--dashboard", "-d", help="Open the dashboard after saving."),
|
|
180
247
|
) -> None:
|
|
181
248
|
"""Set/replace an existing agent's system prompt."""
|
|
182
249
|
path = _resolve_prompts_file(project)
|
|
@@ -190,6 +257,7 @@ def prompt_set(
|
|
|
190
257
|
console.print(f"[red]{exc}[/]")
|
|
191
258
|
raise typer.Exit(1) from exc
|
|
192
259
|
console.print(f"[green]✓[/] Updated prompt for '{agent}'.")
|
|
260
|
+
_maybe_launch_dashboard(dash, path.parent)
|
|
193
261
|
|
|
194
262
|
|
|
195
263
|
@prompt_app.command("add")
|
|
@@ -200,6 +268,7 @@ def prompt_add(
|
|
|
200
268
|
text: str = typer.Option("", "--text", "-t", help="System prompt (blank = auto from role/goal)."),
|
|
201
269
|
from_file: Path = typer.Option(None, "--file", "-f"),
|
|
202
270
|
project: Path = typer.Option(None, "--project"),
|
|
271
|
+
dash: bool = typer.Option(False, "--dashboard", "-d", help="Open the dashboard after saving."),
|
|
203
272
|
) -> None:
|
|
204
273
|
"""Add a new agent; the project picks it up automatically on next run."""
|
|
205
274
|
path = _resolve_prompts_file(project)
|
|
@@ -209,6 +278,7 @@ def prompt_add(
|
|
|
209
278
|
console.print(f"[red]{exc}[/]")
|
|
210
279
|
raise typer.Exit(1) from exc
|
|
211
280
|
console.print(f"[green]✓[/] Added agent '{agent}'. It will run on next start — no code changes needed.")
|
|
281
|
+
_maybe_launch_dashboard(dash, path.parent)
|
|
212
282
|
|
|
213
283
|
|
|
214
284
|
@prompt_app.command("remove")
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""MCP connector — expose AgentX-Kit to Claude / Copilot / Codex.
|
|
2
|
+
|
|
3
|
+
`recommend_spec` and `build_project_from_statement` are pure (no MCP dep);
|
|
4
|
+
`build_server`/`run` require ``agentx-kit[connector]``.
|
|
5
|
+
"""
|
|
6
|
+
from .build import build_project_from_statement
|
|
7
|
+
from .recommend import recommend_spec
|
|
8
|
+
|
|
9
|
+
__all__ = ["recommend_spec", "build_project_from_statement", "build_server", "run", "client_config"]
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def __getattr__(name: str):
|
|
13
|
+
# Lazy: only import the MCP SDK when the server is actually requested.
|
|
14
|
+
if name in ("build_server", "run", "client_config"):
|
|
15
|
+
from . import server
|
|
16
|
+
|
|
17
|
+
return getattr(server, name)
|
|
18
|
+
raise AttributeError(name)
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"""Turn a problem statement (+ optional overrides) into a generated project.
|
|
2
|
+
|
|
3
|
+
Pure orchestration over the scaffolder — no MCP dependency — so it's testable
|
|
4
|
+
and reusable. The MCP tools in ``server.py`` are thin wrappers around this.
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from ..scaffold import AgentSpec, ProjectSpec, generate_project
|
|
11
|
+
from .recommend import recommend_spec
|
|
12
|
+
|
|
13
|
+
_ALL_FEATURES = ["rag", "memory", "mcp", "skills", "observability", "guardrails", "serve", "docker", "ci", "evals"]
|
|
14
|
+
_KEY_FILES_MAX = 6000
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _apply_features(spec: ProjectSpec, features: list[str]) -> None:
|
|
18
|
+
fl = set(features or [])
|
|
19
|
+
spec.use_rag = "rag" in fl
|
|
20
|
+
spec.memory = "both" if "memory" in fl else "none"
|
|
21
|
+
spec.use_mcp = "mcp" in fl
|
|
22
|
+
spec.use_skills = "skills" in fl
|
|
23
|
+
spec.observability = "observability" in fl
|
|
24
|
+
spec.guardrails = "guardrails" in fl
|
|
25
|
+
spec.serve = "serve" in fl
|
|
26
|
+
spec.docker = "docker" in fl
|
|
27
|
+
spec.ci = "ci" in fl
|
|
28
|
+
spec.evals = "evals" in fl
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def build_project_from_statement(
|
|
32
|
+
problem_statement: str,
|
|
33
|
+
name: str = "",
|
|
34
|
+
framework: str = "",
|
|
35
|
+
provider: str = "",
|
|
36
|
+
model: str = "",
|
|
37
|
+
agents: int = 0,
|
|
38
|
+
features: list[str] | None = None,
|
|
39
|
+
enterprise: bool = False,
|
|
40
|
+
output_dir: str = "",
|
|
41
|
+
create_venv: bool = False,
|
|
42
|
+
overwrite: bool = True,
|
|
43
|
+
) -> dict:
|
|
44
|
+
"""Generate a complete project for a problem statement; return a summary."""
|
|
45
|
+
rec = recommend_spec(problem_statement)
|
|
46
|
+
name = name or rec["name"]
|
|
47
|
+
framework = framework or rec["framework"]
|
|
48
|
+
provider = provider or rec["provider"]
|
|
49
|
+
model = model or rec["model"]
|
|
50
|
+
n_agents = agents or rec["agents"]
|
|
51
|
+
feats = list(features) if features is not None else list(rec["features"])
|
|
52
|
+
|
|
53
|
+
# First agent carries the role/goal/prompt derived from the problem statement.
|
|
54
|
+
agent_specs = [AgentSpec(name="assistant" if n_agents == 1 else "agent_1",
|
|
55
|
+
role=rec["role"], goal=rec["goal"], system_prompt=rec["system_prompt"])]
|
|
56
|
+
for i in range(1, n_agents):
|
|
57
|
+
agent_specs.append(AgentSpec(name=f"agent_{i + 1}", role=rec["role"]))
|
|
58
|
+
|
|
59
|
+
spec = ProjectSpec(
|
|
60
|
+
name=name, framework=framework, provider=provider, model=model,
|
|
61
|
+
agents=agent_specs, prompt_style="custom", create_venv=create_venv,
|
|
62
|
+
)
|
|
63
|
+
if enterprise:
|
|
64
|
+
spec.enable_enterprise()
|
|
65
|
+
feats = _ALL_FEATURES
|
|
66
|
+
else:
|
|
67
|
+
_apply_features(spec, feats)
|
|
68
|
+
|
|
69
|
+
target = Path(output_dir).expanduser() if output_dir else Path.cwd() / spec.slug
|
|
70
|
+
result = generate_project(spec, target, overwrite=overwrite)
|
|
71
|
+
root = result.target_dir
|
|
72
|
+
|
|
73
|
+
# Collect a compact view for the calling LLM.
|
|
74
|
+
tree = sorted(str(p.relative_to(root)) for p in root.glob("**/*") if p.is_file())
|
|
75
|
+
pkg = spec.package
|
|
76
|
+
key_paths = [
|
|
77
|
+
"pyproject.toml", "prompts.json", "agentx.json",
|
|
78
|
+
f"src/{pkg}/main.py", f"src/{pkg}/agents.py", f"src/{pkg}/prompts.py",
|
|
79
|
+
]
|
|
80
|
+
if spec.serve:
|
|
81
|
+
key_paths.append(f"src/{pkg}/server.py")
|
|
82
|
+
key_files = {}
|
|
83
|
+
for rel in key_paths:
|
|
84
|
+
fp = root / rel
|
|
85
|
+
if fp.exists():
|
|
86
|
+
key_files[rel] = fp.read_text(encoding="utf-8")[:_KEY_FILES_MAX]
|
|
87
|
+
|
|
88
|
+
run_cmd = (
|
|
89
|
+
f"uv run uvicorn {pkg}.server:app --reload" if spec.serve else f"uv run {spec.slug}"
|
|
90
|
+
)
|
|
91
|
+
next_steps = [
|
|
92
|
+
f"cd {root.name}",
|
|
93
|
+
"cp .env.example .env # add your provider API key(s)",
|
|
94
|
+
"uv venv && uv sync",
|
|
95
|
+
run_cmd,
|
|
96
|
+
]
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
"ok": True,
|
|
100
|
+
"target_dir": str(root),
|
|
101
|
+
"name": spec.slug,
|
|
102
|
+
"framework": framework,
|
|
103
|
+
"provider": provider,
|
|
104
|
+
"model": model or "(provider default)",
|
|
105
|
+
"agents": [a.name for a in agent_specs],
|
|
106
|
+
"features": feats,
|
|
107
|
+
"rationale": rec["rationale"],
|
|
108
|
+
"file_tree": tree,
|
|
109
|
+
"key_files": key_files,
|
|
110
|
+
"next_steps": next_steps,
|
|
111
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"""Map a natural-language problem statement to a recommended ProjectSpec.
|
|
2
|
+
|
|
3
|
+
Pure and dependency-free so it's testable and usable without the MCP SDK. The
|
|
4
|
+
connector uses this to turn a single user prompt into a complete project.
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import re
|
|
9
|
+
|
|
10
|
+
_STOP = {
|
|
11
|
+
"a", "an", "the", "for", "with", "that", "this", "and", "or", "to", "of", "in",
|
|
12
|
+
"on", "is", "are", "be", "build", "create", "make", "want", "need", "should",
|
|
13
|
+
"able", "can", "will", "agent", "agents", "ai", "app", "application", "using",
|
|
14
|
+
"use", "my", "our", "me", "you", "it", "system", "assistant", "bot", "help",
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
_ROLE_MAP = [
|
|
18
|
+
(("support", "ticket", "helpdesk", "customer"), "Customer Support Agent"),
|
|
19
|
+
(("research", "literature", "analyze papers", "summarize papers"), "Research Agent"),
|
|
20
|
+
(("code", "developer", "programming", "refactor", "review pull"), "Coding Assistant"),
|
|
21
|
+
(("data", "analytics", "sql", "report", "dashboard"), "Data Analyst"),
|
|
22
|
+
(("sales", "lead", "crm", "outreach"), "Sales Assistant"),
|
|
23
|
+
(("legal", "contract", "compliance", "policy"), "Compliance Assistant"),
|
|
24
|
+
(("medical", "clinical", "patient", "health"), "Clinical Assistant"),
|
|
25
|
+
(("devops", "infrastructure", "kubernetes", "deploy"), "DevOps Assistant"),
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _has(text: str, *kw: str) -> bool:
|
|
30
|
+
return any(k in text for k in kw)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _slug_from(text: str) -> str:
|
|
34
|
+
words = [w for w in re.findall(r"[a-z0-9]+", text.lower()) if w not in _STOP and len(w) > 2]
|
|
35
|
+
picked = words[:3] or ["agentx", "app"]
|
|
36
|
+
return "-".join(picked)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _role_for(text: str) -> str:
|
|
40
|
+
for keys, role in _ROLE_MAP:
|
|
41
|
+
if _has(text, *keys):
|
|
42
|
+
return role
|
|
43
|
+
return "Assistant"
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def recommend_spec(problem_statement: str) -> dict:
|
|
47
|
+
"""Return a recommended spec dict + rationale for a problem statement."""
|
|
48
|
+
text = (problem_statement or "").lower().strip()
|
|
49
|
+
|
|
50
|
+
multi = _has(text, "multi-agent", "multi agent", "multiple agents", "team of",
|
|
51
|
+
"crew", "collaborat", "debate", "researcher and", "reviewer", "planner")
|
|
52
|
+
framework = "crewai" if multi else "langgraph"
|
|
53
|
+
|
|
54
|
+
rag = _has(text, "document", "knowledge", "docs", "rag", "retriev", "pdf",
|
|
55
|
+
"manual", "faq", "knowledge base", " kb", "our data", "company data",
|
|
56
|
+
"search through", "cite", "sources")
|
|
57
|
+
memory = _has(text, "remember", "conversation history", "multi-turn", "multi turn",
|
|
58
|
+
"across sessions", "previous", "chat history", "follow-up", "follow up")
|
|
59
|
+
mcp = _has(text, "mcp", "external tool", "integrate with", "third-party", "third party",
|
|
60
|
+
"plugin", "connect to", "external api")
|
|
61
|
+
skills = _has(text, "guideline", "standard", "compliance", "policy", "style guide",
|
|
62
|
+
"best practice", "framework method")
|
|
63
|
+
serve = _has(text, "api", "endpoint", "serve", "rest", "http", "backend",
|
|
64
|
+
"microservice", "webhook", "chat ui", "web app")
|
|
65
|
+
production = _has(text, "production", "enterprise", "scalable", "observability",
|
|
66
|
+
"monitor", "trace", "secure", "reliable", "deploy", "high traffic")
|
|
67
|
+
coding = _has(text, "coding", "write code", "code generation", "programming task")
|
|
68
|
+
|
|
69
|
+
features: list[str] = []
|
|
70
|
+
if rag:
|
|
71
|
+
features.append("rag")
|
|
72
|
+
if memory:
|
|
73
|
+
features.append("memory")
|
|
74
|
+
if mcp:
|
|
75
|
+
features.append("mcp")
|
|
76
|
+
if skills:
|
|
77
|
+
features.append("skills")
|
|
78
|
+
if serve or production:
|
|
79
|
+
features.append("serve")
|
|
80
|
+
if production:
|
|
81
|
+
features += ["observability", "guardrails", "docker", "ci", "evals"]
|
|
82
|
+
# de-dupe, stable order
|
|
83
|
+
seen: list[str] = []
|
|
84
|
+
for f in features:
|
|
85
|
+
if f not in seen:
|
|
86
|
+
seen.append(f)
|
|
87
|
+
|
|
88
|
+
agents = 3 if framework == "crewai" else 1
|
|
89
|
+
role = _role_for(text)
|
|
90
|
+
goal = (problem_statement or "Help the user accomplish their task accurately.").strip()
|
|
91
|
+
system_prompt = (
|
|
92
|
+
f"You are a {role}. {goal} "
|
|
93
|
+
"Be accurate and concise, use your tools/knowledge before guessing, "
|
|
94
|
+
"cite sources when available, and ask for clarification when the request is ambiguous."
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
rationale = (
|
|
98
|
+
f"Chose **{framework}** ({'multi-agent collaboration detected' if multi else 'single-agent task'}); "
|
|
99
|
+
f"features: {', '.join(seen) or 'none'}. "
|
|
100
|
+
f"{'RAG (knowledge grounding). ' if rag else ''}"
|
|
101
|
+
f"{'Serving/API layer. ' if serve or production else ''}"
|
|
102
|
+
f"{'Full enterprise pack (tracing/guardrails/docker/CI/evals). ' if production else ''}"
|
|
103
|
+
).strip()
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
"name": _slug_from(text),
|
|
107
|
+
"framework": framework,
|
|
108
|
+
"provider": "openai",
|
|
109
|
+
"model": "",
|
|
110
|
+
"agents": agents,
|
|
111
|
+
"role": role,
|
|
112
|
+
"goal": goal[:300],
|
|
113
|
+
"system_prompt": system_prompt[:600],
|
|
114
|
+
"features": seen,
|
|
115
|
+
"rationale": rationale,
|
|
116
|
+
}
|