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.
Files changed (78) hide show
  1. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/PKG-INFO +61 -1
  2. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/README.md +51 -0
  3. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/pyproject.toml +5 -1
  4. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/__init__.py +12 -1
  5. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/cli.py +70 -0
  6. agentx_kit-0.4.0/src/agentx/connector/__init__.py +18 -0
  7. agentx_kit-0.4.0/src/agentx/connector/build.py +111 -0
  8. agentx_kit-0.4.0/src/agentx/connector/recommend.py +116 -0
  9. agentx_kit-0.4.0/src/agentx/connector/server.py +108 -0
  10. agentx_kit-0.4.0/src/agentx/dashboard/__init__.py +40 -0
  11. agentx_kit-0.4.0/src/agentx/dashboard/app.py +270 -0
  12. agentx_kit-0.4.0/src/agentx/insights/__init__.py +18 -0
  13. agentx_kit-0.4.0/src/agentx/insights/analyze.py +85 -0
  14. agentx_kit-0.4.0/src/agentx/insights/log.py +88 -0
  15. agentx_kit-0.4.0/src/agentx/insights/optimize.py +80 -0
  16. agentx_kit-0.4.0/src/agentx/insights/tokens.py +97 -0
  17. agentx_kit-0.4.0/tests/test_connector.py +70 -0
  18. agentx_kit-0.4.0/tests/test_insights.py +94 -0
  19. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/.github/workflows/publish.yml +0 -0
  20. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/.gitignore +0 -0
  21. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/DESIGN.md +0 -0
  22. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/LICENSE +0 -0
  23. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/RESEARCH.md +0 -0
  24. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/config.py +0 -0
  25. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/frameworks/__init__.py +0 -0
  26. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/frameworks/crewai_agent.py +0 -0
  27. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/frameworks/langchain_agent.py +0 -0
  28. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/guardrails.py +0 -0
  29. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/memory/__init__.py +0 -0
  30. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/memory/store.py +0 -0
  31. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/observability.py +0 -0
  32. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/prompts/__init__.py +0 -0
  33. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/prompts/templates.py +0 -0
  34. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/providers/__init__.py +0 -0
  35. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/providers/base.py +0 -0
  36. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/providers/factory.py +0 -0
  37. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/providers/registry.py +0 -0
  38. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/rag/__init__.py +0 -0
  39. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/rag/pipeline.py +0 -0
  40. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/reliability.py +0 -0
  41. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/__init__.py +0 -0
  42. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/generator.py +0 -0
  43. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/prompts_store.py +0 -0
  44. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/spec.py +0 -0
  45. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/Dockerfile.j2 +0 -0
  46. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/README.md.j2 +0 -0
  47. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/ci.yml.j2 +0 -0
  48. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/docker-compose.yml.j2 +0 -0
  49. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/dockerignore.j2 +0 -0
  50. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/env.example.j2 +0 -0
  51. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/evals/dataset.json.j2 +0 -0
  52. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/evals/run_evals.py.j2 +0 -0
  53. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/gitignore.j2 +0 -0
  54. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/mcp_servers.json.j2 +0 -0
  55. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pkg/__init__.py.j2 +0 -0
  56. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pkg/agents.py.j2 +0 -0
  57. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pkg/config.py.j2 +0 -0
  58. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pkg/guardrails.py.j2 +0 -0
  59. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pkg/main.py.j2 +0 -0
  60. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pkg/memory.py.j2 +0 -0
  61. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pkg/observability.py.j2 +0 -0
  62. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pkg/prompts.py.j2 +0 -0
  63. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pkg/rag.py.j2 +0 -0
  64. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pkg/server.py.j2 +0 -0
  65. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pkg/tools.py.j2 +0 -0
  66. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/pyproject.toml.j2 +0 -0
  67. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/templates/skills_seed.json.j2 +0 -0
  68. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/scaffold/wizard.py +0 -0
  69. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/skills/__init__.py +0 -0
  70. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/skills/registry.py +0 -0
  71. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/structured.py +0 -0
  72. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/tools/__init__.py +0 -0
  73. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/tools/builtin.py +0 -0
  74. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/src/agentx/tools/mcp.py +0 -0
  75. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/tests/test_enterprise.py +0 -0
  76. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/tests/test_prompts.py +0 -0
  77. {agentx_kit-0.2.0 → agentx_kit-0.4.0}/tests/test_providers.py +0 -0
  78. {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.2.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.2.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.2.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
+ }