agentx-kit 0.4.0__tar.gz → 0.5.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 (90) hide show
  1. agentx_kit-0.5.0/.agentx/llm_cache.sqlite +0 -0
  2. agentx_kit-0.5.0/.claude-plugin/marketplace.json +15 -0
  3. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/PKG-INFO +38 -1
  4. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/README.md +37 -0
  5. agentx_kit-0.5.0/integrations/claude-plugin/.claude-plugin/plugin.json +9 -0
  6. agentx_kit-0.5.0/integrations/claude-plugin/.mcp.json +8 -0
  7. agentx_kit-0.5.0/integrations/claude-plugin/README.md +29 -0
  8. agentx_kit-0.5.0/integrations/claude-plugin/commands/new-agent.md +14 -0
  9. agentx_kit-0.5.0/integrations/vscode/.vscodeignore +4 -0
  10. agentx_kit-0.5.0/integrations/vscode/README.md +34 -0
  11. agentx_kit-0.5.0/integrations/vscode/extension.js +87 -0
  12. agentx_kit-0.5.0/integrations/vscode/package.json +34 -0
  13. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/pyproject.toml +1 -1
  14. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/__init__.py +7 -1
  15. agentx_kit-0.5.0/src/agentx/cache.py +166 -0
  16. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/cli.py +32 -0
  17. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/connector/build.py +2 -1
  18. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/connector/recommend.py +4 -0
  19. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/dashboard/app.py +15 -0
  20. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/scaffold/generator.py +1 -0
  21. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/scaffold/spec.py +2 -1
  22. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/scaffold/templates/pkg/main.py.j2 +8 -0
  23. agentx_kit-0.5.0/tests/test_cache.py +60 -0
  24. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/.github/workflows/publish.yml +0 -0
  25. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/.gitignore +0 -0
  26. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/DESIGN.md +0 -0
  27. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/LICENSE +0 -0
  28. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/RESEARCH.md +0 -0
  29. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/config.py +0 -0
  30. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/connector/__init__.py +0 -0
  31. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/connector/server.py +0 -0
  32. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/dashboard/__init__.py +0 -0
  33. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/frameworks/__init__.py +0 -0
  34. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/frameworks/crewai_agent.py +0 -0
  35. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/frameworks/langchain_agent.py +0 -0
  36. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/guardrails.py +0 -0
  37. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/insights/__init__.py +0 -0
  38. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/insights/analyze.py +0 -0
  39. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/insights/log.py +0 -0
  40. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/insights/optimize.py +0 -0
  41. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/insights/tokens.py +0 -0
  42. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/memory/__init__.py +0 -0
  43. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/memory/store.py +0 -0
  44. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/observability.py +0 -0
  45. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/prompts/__init__.py +0 -0
  46. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/prompts/templates.py +0 -0
  47. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/providers/__init__.py +0 -0
  48. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/providers/base.py +0 -0
  49. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/providers/factory.py +0 -0
  50. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/providers/registry.py +0 -0
  51. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/rag/__init__.py +0 -0
  52. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/rag/pipeline.py +0 -0
  53. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/reliability.py +0 -0
  54. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/scaffold/__init__.py +0 -0
  55. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/scaffold/prompts_store.py +0 -0
  56. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/scaffold/templates/Dockerfile.j2 +0 -0
  57. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/scaffold/templates/README.md.j2 +0 -0
  58. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/scaffold/templates/ci.yml.j2 +0 -0
  59. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/scaffold/templates/docker-compose.yml.j2 +0 -0
  60. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/scaffold/templates/dockerignore.j2 +0 -0
  61. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/scaffold/templates/env.example.j2 +0 -0
  62. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/scaffold/templates/evals/dataset.json.j2 +0 -0
  63. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/scaffold/templates/evals/run_evals.py.j2 +0 -0
  64. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/scaffold/templates/gitignore.j2 +0 -0
  65. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/scaffold/templates/mcp_servers.json.j2 +0 -0
  66. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/scaffold/templates/pkg/__init__.py.j2 +0 -0
  67. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/scaffold/templates/pkg/agents.py.j2 +0 -0
  68. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/scaffold/templates/pkg/config.py.j2 +0 -0
  69. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/scaffold/templates/pkg/guardrails.py.j2 +0 -0
  70. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/scaffold/templates/pkg/memory.py.j2 +0 -0
  71. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/scaffold/templates/pkg/observability.py.j2 +0 -0
  72. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/scaffold/templates/pkg/prompts.py.j2 +0 -0
  73. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/scaffold/templates/pkg/rag.py.j2 +0 -0
  74. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/scaffold/templates/pkg/server.py.j2 +0 -0
  75. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/scaffold/templates/pkg/tools.py.j2 +0 -0
  76. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/scaffold/templates/pyproject.toml.j2 +0 -0
  77. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/scaffold/templates/skills_seed.json.j2 +0 -0
  78. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/scaffold/wizard.py +0 -0
  79. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/skills/__init__.py +0 -0
  80. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/skills/registry.py +0 -0
  81. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/structured.py +0 -0
  82. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/tools/__init__.py +0 -0
  83. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/tools/builtin.py +0 -0
  84. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/src/agentx/tools/mcp.py +0 -0
  85. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/tests/test_connector.py +0 -0
  86. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/tests/test_enterprise.py +0 -0
  87. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/tests/test_insights.py +0 -0
  88. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/tests/test_prompts.py +0 -0
  89. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/tests/test_providers.py +0 -0
  90. {agentx_kit-0.4.0 → agentx_kit-0.5.0}/tests/test_scaffold.py +0 -0
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "agentx-kit",
3
+ "owner": { "name": "AgentX", "url": "https://github.com/muhammadyahiya/agentx-kit" },
4
+ "metadata": {
5
+ "description": "AgentX-Kit — scaffold agent projects from a prompt, in Claude Code.",
6
+ "version": "0.1.0"
7
+ },
8
+ "plugins": [
9
+ {
10
+ "name": "agentx-kit",
11
+ "source": "./integrations/claude-plugin",
12
+ "description": "Scaffold complete LangChain/CrewAI agent projects from a single problem statement via AgentX-Kit's MCP tools."
13
+ }
14
+ ]
15
+ }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentx-kit
3
- Version: 0.4.0
3
+ Version: 0.5.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
@@ -291,6 +291,43 @@ The assistant calls AgentX-Kit's tools and you get a complete, runnable project:
291
291
 
292
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
293
 
294
+ ## 🧩 Editor & assistant integrations
295
+ The same connector powers ready-made integrations (see [`integrations/`](integrations/)):
296
+
297
+ - **VS Code extension** ([`integrations/vscode`](integrations/vscode)) — commands for
298
+ *New Agent Project*, *Open Prompt Dashboard*, *Add Prompt*, *Cache Stats*, and
299
+ *Register MCP Server for Copilot* (writes `.vscode/mcp.json`). Build with `vsce package`.
300
+ - **GitHub Copilot** (agent mode) — add the MCP server via `.vscode/mcp.json`:
301
+ ```jsonc
302
+ { "servers": { "agentx-kit": { "command": "agentx", "args": ["mcp"] } } }
303
+ ```
304
+ (the VS Code command above writes this for you), then ask Copilot to build an agent.
305
+ - **Claude Code plugin** ([`integrations/claude-plugin`](integrations/claude-plugin)):
306
+ ```text
307
+ /plugin marketplace add muhammadyahiya/agentx-kit
308
+ /plugin install agentx-kit@agentx-kit
309
+ /agentx-kit:new-agent a support agent that answers from our docs and serves an API
310
+ ```
311
+ - **Claude Desktop / Codex** — add the connector config from `agentx mcp --print-config`.
312
+
313
+ ## 💾 Response caching (cost & latency saver)
314
+ Caching is the top 2026 token-optimization lever. Turn on a **global LLM response
315
+ cache** and every provider call is served from a local store on repeat — no code changes:
316
+
317
+ ```python
318
+ from agentx import enable_caching, cache_stats
319
+ enable_caching() # all get_chat_model(...) calls are cached
320
+ ...
321
+ print(cache_stats()) # {'hit_rate': 0.6, 'tokens_saved': 12000, 'est_usd_saved': 0.024, ...}
322
+ ```
323
+ ```bash
324
+ agentx cache stats # hit rate + estimated tokens/$ saved
325
+ agentx cache clear
326
+ ```
327
+ Generated projects can enable it automatically (it's part of `--enterprise`), and the
328
+ **dashboard's Trends tab shows live hit-rate and $ saved**. TTL-capable, SQLite-backed
329
+ at `.agentx/llm_cache.sqlite`.
330
+
294
331
  ## 🏢 Enterprise pack
295
332
  Generate a production-shaped project with one flag — informed by a survey of
296
333
  CrewAI/LangGraph/create-llama/AgentStack/agno/pydantic-ai (see [RESEARCH.md](RESEARCH.md)):
@@ -187,6 +187,43 @@ The assistant calls AgentX-Kit's tools and you get a complete, runnable project:
187
187
 
188
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
189
 
190
+ ## 🧩 Editor & assistant integrations
191
+ The same connector powers ready-made integrations (see [`integrations/`](integrations/)):
192
+
193
+ - **VS Code extension** ([`integrations/vscode`](integrations/vscode)) — commands for
194
+ *New Agent Project*, *Open Prompt Dashboard*, *Add Prompt*, *Cache Stats*, and
195
+ *Register MCP Server for Copilot* (writes `.vscode/mcp.json`). Build with `vsce package`.
196
+ - **GitHub Copilot** (agent mode) — add the MCP server via `.vscode/mcp.json`:
197
+ ```jsonc
198
+ { "servers": { "agentx-kit": { "command": "agentx", "args": ["mcp"] } } }
199
+ ```
200
+ (the VS Code command above writes this for you), then ask Copilot to build an agent.
201
+ - **Claude Code plugin** ([`integrations/claude-plugin`](integrations/claude-plugin)):
202
+ ```text
203
+ /plugin marketplace add muhammadyahiya/agentx-kit
204
+ /plugin install agentx-kit@agentx-kit
205
+ /agentx-kit:new-agent a support agent that answers from our docs and serves an API
206
+ ```
207
+ - **Claude Desktop / Codex** — add the connector config from `agentx mcp --print-config`.
208
+
209
+ ## 💾 Response caching (cost & latency saver)
210
+ Caching is the top 2026 token-optimization lever. Turn on a **global LLM response
211
+ cache** and every provider call is served from a local store on repeat — no code changes:
212
+
213
+ ```python
214
+ from agentx import enable_caching, cache_stats
215
+ enable_caching() # all get_chat_model(...) calls are cached
216
+ ...
217
+ print(cache_stats()) # {'hit_rate': 0.6, 'tokens_saved': 12000, 'est_usd_saved': 0.024, ...}
218
+ ```
219
+ ```bash
220
+ agentx cache stats # hit rate + estimated tokens/$ saved
221
+ agentx cache clear
222
+ ```
223
+ Generated projects can enable it automatically (it's part of `--enterprise`), and the
224
+ **dashboard's Trends tab shows live hit-rate and $ saved**. TTL-capable, SQLite-backed
225
+ at `.agentx/llm_cache.sqlite`.
226
+
190
227
  ## 🏢 Enterprise pack
191
228
  Generate a production-shaped project with one flag — informed by a survey of
192
229
  CrewAI/LangGraph/create-llama/AgentStack/agno/pydantic-ai (see [RESEARCH.md](RESEARCH.md)):
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "agentx-kit",
3
+ "version": "0.1.0",
4
+ "description": "Scaffold complete provider-agnostic LangChain/CrewAI agent projects from a single problem statement, via AgentX-Kit's MCP tools.",
5
+ "author": { "name": "AgentX" },
6
+ "homepage": "https://github.com/muhammadyahiya/agentx-kit",
7
+ "license": "MIT",
8
+ "keywords": ["agents", "scaffold", "langchain", "crewai", "mcp"]
9
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "mcpServers": {
3
+ "agentx-kit": {
4
+ "command": "agentx",
5
+ "args": ["mcp"]
6
+ }
7
+ }
8
+ }
@@ -0,0 +1,29 @@
1
+ # AgentX-Kit — Claude Code plugin
2
+
3
+ Bundles AgentX-Kit's MCP server + a `/agentx-kit:new-agent` slash command so you
4
+ can scaffold a complete agent project from a single problem statement inside
5
+ Claude Code.
6
+
7
+ ## Prerequisite
8
+ ```bash
9
+ pip install "agentx-kit[connector]" # provides `agentx mcp`
10
+ ```
11
+
12
+ ## Install (from this repo's marketplace)
13
+ ```text
14
+ /plugin marketplace add muhammadyahiya/agentx-kit
15
+ /plugin install agentx-kit@agentx-kit
16
+ ```
17
+ Then use it:
18
+ ```text
19
+ /agentx-kit:new-agent a customer-support agent that answers from our docs and serves an API
20
+ ```
21
+
22
+ ## Or just add the MCP server (no plugin)
23
+ ```bash
24
+ claude mcp add agentx-kit -- agentx mcp
25
+ ```
26
+
27
+ The plugin ships:
28
+ - `.mcp.json` — registers the `agentx-kit` MCP server (`agentx mcp`).
29
+ - `commands/new-agent.md` — the `/agentx-kit:new-agent` workflow.
@@ -0,0 +1,14 @@
1
+ ---
2
+ description: Scaffold a complete AgentX-Kit agent project from a problem statement
3
+ argument-hint: <describe the agent / use case you want to build>
4
+ ---
5
+ Build a complete, runnable agent project for this request using the AgentX-Kit MCP tools:
6
+
7
+ **$ARGUMENTS**
8
+
9
+ Steps:
10
+ 1. Call `recommend_project` with the problem statement and briefly show the recommended stack (framework, provider, agents, features) + rationale.
11
+ 2. Ask the user to confirm or adjust (provider/framework/enterprise), then call `create_agent_project` with the problem statement and any overrides.
12
+ 3. Report the target directory, the generated file tree, and the exact run steps it returns. Offer to open key files (main.py, agents.py, prompts.json).
13
+
14
+ Keep it concise; the tools do the heavy lifting.
@@ -0,0 +1,4 @@
1
+ .vscode/**
2
+ **/*.map
3
+ .gitignore
4
+ node_modules/**
@@ -0,0 +1,34 @@
1
+ # AgentX-Kit — VS Code extension
2
+
3
+ Scaffold agent projects, open the prompt dashboard, and wire AgentX-Kit into
4
+ **GitHub Copilot** (agent mode) — without leaving VS Code.
5
+
6
+ ## Prerequisite
7
+ ```bash
8
+ pip install "agentx-kit[all]" # provides the `agentx` CLI the extension calls
9
+ ```
10
+
11
+ ## Commands (⇧⌘P)
12
+ - **AgentX: New Agent Project** — name + use case → `agentx new`
13
+ - **AgentX: Open Prompt Dashboard** — `agentx dashboard`
14
+ - **AgentX: Add Agent Prompt** — `agentx prompt set … -d`
15
+ - **AgentX: Show Response-Cache Stats** — `agentx cache stats`
16
+ - **AgentX: Register MCP Server for Copilot** — writes `.vscode/mcp.json` so Copilot
17
+ agent mode can call AgentX-Kit's tools (e.g. *"build a support agent over our docs"*).
18
+
19
+ Set a custom CLI path with the `agentx.command` setting.
20
+
21
+ ## Build / install locally
22
+ ```bash
23
+ npm install -g @vscode/vsce
24
+ cd integrations/vscode
25
+ vsce package # -> agentx-kit-0.1.0.vsix
26
+ code --install-extension agentx-kit-0.1.0.vsix
27
+ ```
28
+
29
+ ## Publish (needs a Marketplace publisher + PAT)
30
+ ```bash
31
+ vsce login <publisher>
32
+ vsce publish
33
+ ```
34
+ See https://code.visualstudio.com/api/working-with-extensions/publishing-extension.
@@ -0,0 +1,87 @@
1
+ // AgentX-Kit VS Code extension.
2
+ // Thin wrapper over the `agentx` CLI + MCP registration for Copilot/agent mode.
3
+ // Pure JS (no build step). Requires `pip install agentx-kit` on PATH.
4
+ const vscode = require("vscode");
5
+ const fs = require("fs");
6
+ const path = require("path");
7
+
8
+ function cli() {
9
+ return vscode.workspace.getConfiguration("agentx").get("command", "agentx");
10
+ }
11
+
12
+ function runInTerminal(name, commandLine) {
13
+ const term = vscode.window.createTerminal({ name });
14
+ term.show();
15
+ term.sendText(commandLine);
16
+ }
17
+
18
+ function workspaceRoot() {
19
+ const folders = vscode.workspace.workspaceFolders;
20
+ return folders && folders.length ? folders[0].uri.fsPath : process.cwd();
21
+ }
22
+
23
+ async function newProject() {
24
+ const name = await vscode.window.showInputBox({
25
+ prompt: "Project name", value: "my-agent",
26
+ });
27
+ if (!name) return;
28
+ const problem = await vscode.window.showInputBox({
29
+ prompt: "Describe the use case (optional — seeds the agent's prompt)", value: "",
30
+ });
31
+ const enterprise = await vscode.window.showQuickPick(["No", "Yes (tracing, guardrails, FastAPI, Docker, CI, evals, cache)"], {
32
+ placeHolder: "Enterprise pack?",
33
+ });
34
+ let cmd = `${cli()} new --yes --name ${JSON.stringify(name)}`;
35
+ if (problem) cmd += ` --prompt ${JSON.stringify(problem)}`;
36
+ if (enterprise && enterprise.startsWith("Yes")) cmd += " --enterprise";
37
+ runInTerminal("AgentX: new", cmd);
38
+ }
39
+
40
+ function dashboard() {
41
+ runInTerminal("AgentX: dashboard", `${cli()} dashboard`);
42
+ }
43
+
44
+ async function addPrompt() {
45
+ const agent = await vscode.window.showInputBox({ prompt: "Agent name", value: "assistant" });
46
+ if (!agent) return;
47
+ const text = await vscode.window.showInputBox({ prompt: "System prompt" });
48
+ if (text === undefined) return;
49
+ runInTerminal("AgentX: prompt", `${cli()} prompt set ${JSON.stringify(agent)} --text ${JSON.stringify(text)} -d`);
50
+ }
51
+
52
+ function cacheStats() {
53
+ runInTerminal("AgentX: cache", `${cli()} cache stats`);
54
+ }
55
+
56
+ // Write .vscode/mcp.json so GitHub Copilot (agent mode) / VS Code can use AgentX-Kit's MCP server.
57
+ async function registerMcp() {
58
+ const root = workspaceRoot();
59
+ const dir = path.join(root, ".vscode");
60
+ const file = path.join(dir, "mcp.json");
61
+ let config = { servers: {} };
62
+ try {
63
+ if (fs.existsSync(file)) config = JSON.parse(fs.readFileSync(file, "utf8"));
64
+ } catch (e) { /* start fresh on parse error */ }
65
+ config.servers = config.servers || {};
66
+ config.servers["agentx-kit"] = { command: cli(), args: ["mcp"] };
67
+ fs.mkdirSync(dir, { recursive: true });
68
+ fs.writeFileSync(file, JSON.stringify(config, null, 2));
69
+ vscode.window.showInformationMessage(
70
+ "AgentX-Kit MCP server registered in .vscode/mcp.json. Open Copilot Chat (Agent mode) and ask it to build an agent from a problem statement."
71
+ );
72
+ const doc = await vscode.workspace.openTextDocument(file);
73
+ vscode.window.showTextDocument(doc);
74
+ }
75
+
76
+ function activate(context) {
77
+ const reg = (id, fn) => context.subscriptions.push(vscode.commands.registerCommand(id, fn));
78
+ reg("agentx.newProject", newProject);
79
+ reg("agentx.dashboard", dashboard);
80
+ reg("agentx.addPrompt", addPrompt);
81
+ reg("agentx.cacheStats", cacheStats);
82
+ reg("agentx.registerMcp", registerMcp);
83
+ }
84
+
85
+ function deactivate() {}
86
+
87
+ module.exports = { activate, deactivate };
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "agentx-kit",
3
+ "displayName": "AgentX-Kit",
4
+ "description": "Scaffold provider-agnostic LangChain/CrewAI agent projects, open the prompt dashboard, and wire AgentX-Kit into Copilot — from VS Code.",
5
+ "version": "0.1.0",
6
+ "publisher": "agentx",
7
+ "engines": { "vscode": "^1.85.0" },
8
+ "categories": ["Machine Learning", "Snippets", "Other"],
9
+ "keywords": ["ai", "agents", "llm", "langchain", "crewai", "mcp", "scaffold", "copilot"],
10
+ "icon": "icon.png",
11
+ "repository": { "type": "git", "url": "https://github.com/muhammadyahiya/agentx-kit" },
12
+ "license": "MIT",
13
+ "main": "./extension.js",
14
+ "activationEvents": [],
15
+ "contributes": {
16
+ "commands": [
17
+ { "command": "agentx.newProject", "title": "AgentX: New Agent Project" },
18
+ { "command": "agentx.dashboard", "title": "AgentX: Open Prompt Dashboard" },
19
+ { "command": "agentx.addPrompt", "title": "AgentX: Add Agent Prompt" },
20
+ { "command": "agentx.cacheStats", "title": "AgentX: Show Response-Cache Stats" },
21
+ { "command": "agentx.registerMcp", "title": "AgentX: Register MCP Server for Copilot" }
22
+ ],
23
+ "configuration": {
24
+ "title": "AgentX-Kit",
25
+ "properties": {
26
+ "agentx.command": {
27
+ "type": "string",
28
+ "default": "agentx",
29
+ "description": "Path to the agentx CLI (from `pip install agentx-kit`)."
30
+ }
31
+ }
32
+ }
33
+ }
34
+ }
@@ -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.0"
4
+ version = "0.5.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"
@@ -16,7 +16,7 @@ is enough to get started.
16
16
  """
17
17
  from __future__ import annotations
18
18
 
19
- __version__ = "0.4.0"
19
+ __version__ = "0.5.0"
20
20
 
21
21
  from .providers import ( # noqa: E402
22
22
  ProviderSpec,
@@ -39,6 +39,7 @@ from .insights import ( # noqa: E402
39
39
  estimate_cost,
40
40
  optimize_prompt,
41
41
  )
42
+ from .cache import cache_stats, clear_cache, disable_caching, enable_caching # noqa: E402
42
43
 
43
44
  __all__ = [
44
45
  "__version__",
@@ -63,4 +64,9 @@ __all__ = [
63
64
  "optimize_prompt",
64
65
  "count_tokens",
65
66
  "estimate_cost",
67
+ # response caching
68
+ "enable_caching",
69
+ "disable_caching",
70
+ "cache_stats",
71
+ "clear_cache",
66
72
  ]
@@ -0,0 +1,166 @@
1
+ """LLM response caching — cut cost & latency across all providers.
2
+
3
+ Caching is the top token-optimization lever (2026): repeat/near-repeat calls are
4
+ served from a local store instead of the model. This is an **exact** response
5
+ cache implemented as a LangChain ``BaseCache`` and installed globally, so every
6
+ ``get_chat_model(...)`` call benefits automatically — no code changes.
7
+
8
+ from agentx.cache import enable_caching, cache_stats
9
+ enable_caching() # all subsequent LLM calls are cached
10
+ ...
11
+ print(cache_stats()) # hits, misses, est. tokens/$ saved
12
+
13
+ Persistence is a small SQLite file (default ``.agentx/llm_cache.sqlite``) with an
14
+ optional TTL. Stats track hit/miss and estimated tokens + USD saved (derived from
15
+ cached completion sizes — see ``agentx.insights.tokens``).
16
+ """
17
+ from __future__ import annotations
18
+
19
+ import hashlib
20
+ import sqlite3
21
+ import threading
22
+ import time
23
+ from pathlib import Path
24
+ from typing import Any
25
+
26
+ _DEFAULT_PATH = ".agentx/llm_cache.sqlite"
27
+ _lock = threading.Lock()
28
+
29
+
30
+ def _key(prompt: str, llm_string: str) -> str:
31
+ return hashlib.sha256(f"{llm_string}\x00{prompt}".encode("utf-8")).hexdigest()
32
+
33
+
34
+ def _model_from_llm_string(llm_string: str) -> str:
35
+ # llm_string is a serialized model descriptor; best-effort model name for costing.
36
+ for token in ("gpt-4o-mini", "gpt-4o", "gpt-4.1", "claude-3-5", "gemini-1.5", "llama"):
37
+ if token in llm_string:
38
+ return token
39
+ return "gpt-4o-mini"
40
+
41
+
42
+ class AgentXCache:
43
+ """A LangChain ``BaseCache`` backed by SQLite, with TTL + savings stats.
44
+
45
+ Implements ``lookup``/``update`` (and ``aclear``) so it can be passed to
46
+ ``langchain_core.globals.set_llm_cache``.
47
+ """
48
+
49
+ def __init__(self, path: str | Path = _DEFAULT_PATH, ttl: int | None = None):
50
+ self.path = Path(path)
51
+ self.path.parent.mkdir(parents=True, exist_ok=True)
52
+ self.ttl = ttl
53
+ self._init_db()
54
+
55
+ def _conn(self) -> sqlite3.Connection:
56
+ return sqlite3.connect(str(self.path))
57
+
58
+ def _init_db(self) -> None:
59
+ with _lock, self._conn() as c:
60
+ c.execute(
61
+ "CREATE TABLE IF NOT EXISTS cache "
62
+ "(key TEXT PRIMARY KEY, value TEXT, ts REAL, model TEXT, out_tokens INT)"
63
+ )
64
+ c.execute("CREATE TABLE IF NOT EXISTS stats (name TEXT PRIMARY KEY, val REAL)")
65
+ for name in ("hits", "misses", "tokens_saved"):
66
+ c.execute("INSERT OR IGNORE INTO stats(name, val) VALUES (?, 0)", (name,))
67
+
68
+ def _bump(self, conn: sqlite3.Connection, name: str, by: float = 1) -> None:
69
+ conn.execute("UPDATE stats SET val = val + ? WHERE name = ?", (by, name))
70
+
71
+ # ----- BaseCache interface -----
72
+ def lookup(self, prompt: str, llm_string: str) -> Any | None:
73
+ import warnings
74
+
75
+ from langchain_core.load import loads
76
+
77
+ key = _key(prompt, llm_string)
78
+ with _lock, self._conn() as c:
79
+ row = c.execute("SELECT value, ts, out_tokens FROM cache WHERE key = ?", (key,)).fetchone()
80
+ if not row:
81
+ self._bump(c, "misses")
82
+ return None
83
+ value, ts, out_tokens = row
84
+ if self.ttl is not None and (time.time() - ts) > self.ttl:
85
+ c.execute("DELETE FROM cache WHERE key = ?", (key,))
86
+ self._bump(c, "misses")
87
+ return None
88
+ self._bump(c, "hits")
89
+ self._bump(c, "tokens_saved", out_tokens or 0)
90
+ try:
91
+ # We wrote these values ourselves, so deserialization is trusted.
92
+ with warnings.catch_warnings():
93
+ warnings.simplefilter("ignore")
94
+ return loads(value)
95
+ except Exception: # noqa: BLE001 - corrupt entry
96
+ return None
97
+
98
+ def update(self, prompt: str, llm_string: str, return_val: Any) -> None:
99
+ from langchain_core.load import dumps
100
+
101
+ from .insights.tokens import count_tokens
102
+
103
+ key = _key(prompt, llm_string)
104
+ model = _model_from_llm_string(llm_string)
105
+ text = ""
106
+ try:
107
+ text = " ".join(getattr(g, "text", "") or "" for g in return_val)
108
+ except Exception: # noqa: BLE001
109
+ text = ""
110
+ out_tokens = count_tokens(text, model)
111
+ try:
112
+ payload = dumps(return_val)
113
+ except Exception: # noqa: BLE001 - non-serializable result; skip caching
114
+ return
115
+ with _lock, self._conn() as c:
116
+ c.execute(
117
+ "INSERT OR REPLACE INTO cache(key, value, ts, model, out_tokens) VALUES (?, ?, ?, ?, ?)",
118
+ (key, payload, time.time(), model, out_tokens),
119
+ )
120
+
121
+ def clear(self, **kwargs: Any) -> None:
122
+ with _lock, self._conn() as c:
123
+ c.execute("DELETE FROM cache")
124
+ c.execute("UPDATE stats SET val = 0")
125
+
126
+ def stats(self) -> dict:
127
+ with _lock, self._conn() as c:
128
+ rows = dict(c.execute("SELECT name, val FROM stats").fetchall())
129
+ entries = c.execute("SELECT COUNT(*) FROM cache").fetchone()[0]
130
+ hits, misses = int(rows.get("hits", 0)), int(rows.get("misses", 0))
131
+ total = hits + misses
132
+ tokens_saved = int(rows.get("tokens_saved", 0))
133
+ # Conservative blended estimate: $0.002 / 1K output tokens saved.
134
+ cost_saved = round(tokens_saved / 1000 * 0.002, 6)
135
+ return {
136
+ "entries": entries,
137
+ "hits": hits,
138
+ "misses": misses,
139
+ "hit_rate": round(hits / total, 3) if total else 0.0,
140
+ "tokens_saved": tokens_saved,
141
+ "est_usd_saved": cost_saved,
142
+ "path": str(self.path),
143
+ }
144
+
145
+
146
+ def enable_caching(path: str | Path = _DEFAULT_PATH, ttl: int | None = None) -> AgentXCache:
147
+ """Install a global LLM response cache. All providers benefit automatically."""
148
+ from langchain_core.globals import set_llm_cache
149
+
150
+ cache = AgentXCache(path, ttl=ttl)
151
+ set_llm_cache(cache)
152
+ return cache
153
+
154
+
155
+ def disable_caching() -> None:
156
+ from langchain_core.globals import set_llm_cache
157
+
158
+ set_llm_cache(None)
159
+
160
+
161
+ def cache_stats(path: str | Path = _DEFAULT_PATH) -> dict:
162
+ return AgentXCache(path).stats()
163
+
164
+
165
+ def clear_cache(path: str | Path = _DEFAULT_PATH) -> None:
166
+ AgentXCache(path).clear()
@@ -68,6 +68,38 @@ def dashboard(
68
68
  raise typer.Exit(1) from exc
69
69
 
70
70
 
71
+ cache_app = typer.Typer(help="Inspect/clear the local LLM response cache.", no_args_is_help=True)
72
+ app.add_typer(cache_app, name="cache")
73
+
74
+
75
+ @cache_app.command("stats")
76
+ def cache_stats_cmd(
77
+ path: Path = typer.Option(".agentx/llm_cache.sqlite", "--path", help="Cache DB path."),
78
+ ) -> None:
79
+ """Show cache hit rate and estimated tokens/$ saved."""
80
+ from .cache import cache_stats
81
+
82
+ s = cache_stats(path)
83
+ table = Table(title="LLM response cache")
84
+ table.add_column("metric", style="cyan")
85
+ table.add_column("value")
86
+ for k in ("entries", "hits", "misses", "hit_rate", "tokens_saved", "est_usd_saved"):
87
+ table.add_row(k, str(s[k]))
88
+ console.print(table)
89
+ console.print(f"[dim]{s['path']}[/]")
90
+
91
+
92
+ @cache_app.command("clear")
93
+ def cache_clear_cmd(
94
+ path: Path = typer.Option(".agentx/llm_cache.sqlite", "--path", help="Cache DB path."),
95
+ ) -> None:
96
+ """Clear all cached responses and reset stats."""
97
+ from .cache import clear_cache
98
+
99
+ clear_cache(path)
100
+ console.print("[green]✓[/] Cache cleared.")
101
+
102
+
71
103
  @app.command()
72
104
  def mcp(
73
105
  print_config: bool = typer.Option(False, "--print-config", help="Print MCP client config for Claude/Codex/Copilot and exit."),
@@ -10,7 +10,7 @@ from pathlib import Path
10
10
  from ..scaffold import AgentSpec, ProjectSpec, generate_project
11
11
  from .recommend import recommend_spec
12
12
 
13
- _ALL_FEATURES = ["rag", "memory", "mcp", "skills", "observability", "guardrails", "serve", "docker", "ci", "evals"]
13
+ _ALL_FEATURES = ["rag", "memory", "mcp", "skills", "observability", "guardrails", "serve", "docker", "ci", "evals", "cache"]
14
14
  _KEY_FILES_MAX = 6000
15
15
 
16
16
 
@@ -26,6 +26,7 @@ def _apply_features(spec: ProjectSpec, features: list[str]) -> None:
26
26
  spec.docker = "docker" in fl
27
27
  spec.ci = "ci" in fl
28
28
  spec.evals = "evals" in fl
29
+ spec.use_cache = "cache" in fl
29
30
 
30
31
 
31
32
  def build_project_from_statement(
@@ -65,6 +65,8 @@ def recommend_spec(problem_statement: str) -> dict:
65
65
  production = _has(text, "production", "enterprise", "scalable", "observability",
66
66
  "monitor", "trace", "secure", "reliable", "deploy", "high traffic")
67
67
  coding = _has(text, "coding", "write code", "code generation", "programming task")
68
+ cache = _has(text, "cache", "cost", "cheap", "latency", "high traffic", "high-traffic",
69
+ "fast response", "reduce cost", "save money", "repeated")
68
70
 
69
71
  features: list[str] = []
70
72
  if rag:
@@ -77,6 +79,8 @@ def recommend_spec(problem_statement: str) -> dict:
77
79
  features.append("skills")
78
80
  if serve or production:
79
81
  features.append("serve")
82
+ if cache or production:
83
+ features.append("cache")
80
84
  if production:
81
85
  features += ["observability", "guardrails", "docker", "ci", "evals"]
82
86
  # de-dupe, stable order
@@ -218,6 +218,21 @@ def _trends_panel():
218
218
  c2.metric("Total tokens", f"{agg['total_tokens']:,}")
219
219
  c3.metric("Total cost", f"${agg['total_cost_usd']:.4f}")
220
220
  c4.metric("Avg latency", f"{agg['avg_latency_ms']} ms")
221
+
222
+ # Response-cache savings (if caching has been used in this project).
223
+ cache_path = _PROJECT / ".agentx" / "llm_cache.sqlite"
224
+ if cache_path.exists():
225
+ try:
226
+ from agentx.cache import cache_stats
227
+
228
+ cs = cache_stats(cache_path)
229
+ st.markdown("###### 💾 Response cache")
230
+ d1, d2, d3 = st.columns(3)
231
+ d1.metric("Hit rate", f"{cs['hit_rate']:.0%}", help=f"{cs['hits']} hits / {cs['misses']} misses")
232
+ d2.metric("Tokens saved", f"{cs['tokens_saved']:,}")
233
+ d3.metric("Est. $ saved", f"${cs['est_usd_saved']:.4f}")
234
+ except Exception: # noqa: BLE001
235
+ pass
221
236
  rows = [r for r in log.events() if r.get("kind") == "run"]
222
237
  if not rows:
223
238
  st.info("No runs logged yet — use **Test run** to populate trends.")
@@ -134,6 +134,7 @@ def _write_manifest(target: Path, spec: ProjectSpec) -> Path:
134
134
  "docker": spec.docker,
135
135
  "ci": spec.ci,
136
136
  "evals": spec.evals,
137
+ "cache": spec.use_cache,
137
138
  },
138
139
  "extras": _extras(spec),
139
140
  "telemetry_opt_out": False,
@@ -52,6 +52,7 @@ class ProjectSpec(BaseModel):
52
52
  docker: bool = False # Dockerfile + docker-compose.yml
53
53
  ci: bool = False # GitHub Actions (lint + test [+ eval])
54
54
  evals: bool = False # LLM-as-judge eval harness (+ CI gate)
55
+ use_cache: bool = False # global LLM response cache (cost/latency saver)
55
56
  create_venv: bool = True
56
57
  run_sync: bool = False
57
58
  # When set, generated pyproject depends on agentx from this local path
@@ -61,7 +62,7 @@ class ProjectSpec(BaseModel):
61
62
  def enable_enterprise(self) -> "ProjectSpec":
62
63
  """Turn on the full enterprise feature set in one call."""
63
64
  self.observability = self.guardrails = self.serve = True
64
- self.docker = self.ci = self.evals = True
65
+ self.docker = self.ci = self.evals = self.use_cache = True
65
66
  return self
66
67
 
67
68
  @property
@@ -8,6 +8,8 @@ from dotenv import load_dotenv
8
8
  {% endif %}
9
9
  {% if spec.guardrails %}from .guardrails import guard_input, guard_output
10
10
  {% endif %}
11
+ {% if spec.use_cache %}from agentx.cache import enable_caching
12
+ {% endif %}
11
13
  {% if spec.framework == 'langgraph' %}
12
14
  from agentx.frameworks import run_agent
13
15
  from .agents import build_agents
@@ -17,6 +19,9 @@ def main() -> None:
17
19
  load_dotenv()
18
20
  {% if spec.observability %}
19
21
  init_observability()
22
+ {% endif %}
23
+ {% if spec.use_cache %}
24
+ enable_caching() # cache LLM responses → lower cost & latency
20
25
  {% endif %}
21
26
  agents = build_agents()
22
27
  agent_name, agent = next(iter(agents.items()))
@@ -52,6 +57,9 @@ def main() -> None:
52
57
  load_dotenv()
53
58
  {% if spec.observability %}
54
59
  init_observability()
60
+ {% endif %}
61
+ {% if spec.use_cache %}
62
+ enable_caching() # cache LLM responses → lower cost & latency
55
63
  {% endif %}
56
64
  print("🧬 {{ spec.slug }} (CrewAI). Type 'quit' to exit.\n")
57
65
  while True:
@@ -0,0 +1,60 @@
1
+ """Tests for the LLM response cache (BaseCache-backed, SQLite). No live LLM."""
2
+ import time
3
+
4
+ from agentx.cache import AgentXCache, cache_stats, clear_cache, enable_caching
5
+
6
+
7
+ def _gens(text: str):
8
+ from langchain_core.outputs import Generation
9
+
10
+ return [Generation(text=text)]
11
+
12
+
13
+ def test_cache_lookup_miss_then_hit(tmp_path):
14
+ cache = AgentXCache(tmp_path / "c.sqlite")
15
+ assert cache.lookup("hello", "llm::gpt-4o-mini") is None # miss
16
+ cache.update("hello", "llm::gpt-4o-mini", _gens("hi there"))
17
+ got = cache.lookup("hello", "llm::gpt-4o-mini")
18
+ assert got is not None
19
+ assert got[0].text == "hi there"
20
+
21
+
22
+ def test_cache_stats_track_hits_and_savings(tmp_path):
23
+ cache = AgentXCache(tmp_path / "c.sqlite")
24
+ cache.update("q", "llm::gpt-4o-mini", _gens("a fairly long cached answer " * 5))
25
+ cache.lookup("q", "llm::gpt-4o-mini") # hit
26
+ cache.lookup("nope", "llm::gpt-4o-mini") # miss
27
+ s = cache.stats()
28
+ assert s["hits"] == 1 and s["misses"] == 1
29
+ assert s["hit_rate"] == 0.5
30
+ assert s["tokens_saved"] > 0
31
+ assert s["est_usd_saved"] >= 0.0
32
+ assert s["entries"] == 1
33
+
34
+
35
+ def test_cache_ttl_expiry(tmp_path):
36
+ cache = AgentXCache(tmp_path / "c.sqlite", ttl=1)
37
+ cache.update("k", "llm::x", _gens("v"))
38
+ assert cache.lookup("k", "llm::x") is not None
39
+ time.sleep(1.2)
40
+ assert cache.lookup("k", "llm::x") is None # expired
41
+
42
+
43
+ def test_clear_cache(tmp_path):
44
+ p = tmp_path / "c.sqlite"
45
+ cache = AgentXCache(p)
46
+ cache.update("k", "llm::x", _gens("v"))
47
+ clear_cache(p)
48
+ assert cache_stats(p)["entries"] == 0
49
+ assert cache.lookup("k", "llm::x") is None
50
+
51
+
52
+ def test_enable_caching_installs_global(tmp_path):
53
+ from langchain_core.globals import get_llm_cache
54
+
55
+ from agentx.cache import disable_caching
56
+
57
+ cache = enable_caching(tmp_path / "c.sqlite")
58
+ assert get_llm_cache() is cache
59
+ disable_caching()
60
+ assert get_llm_cache() is None
File without changes
File without changes
File without changes
File without changes