@axonpush/wizard 0.0.1
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.
- package/README.md +49 -0
- package/dist/bin.js +432 -0
- package/package.json +33 -0
- package/skills/anthropic/SKILL.md +52 -0
- package/skills/core/SKILL.md +43 -0
- package/skills/crewai/SKILL.md +54 -0
- package/skills/langchain/SKILL.md +47 -0
- package/skills/openai-agents/SKILL.md +49 -0
package/README.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# @axonpush/wizard
|
|
2
|
+
|
|
3
|
+
AI-powered wizard that integrates the [AxonPush](https://github.com/axonpush/axonpush-python) Python SDK into your AI agent project using Claude Code.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx @axonpush/wizard
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
The wizard will:
|
|
12
|
+
1. Detect your project's AI framework (LangChain, OpenAI Agents, Anthropic, CrewAI)
|
|
13
|
+
2. Ask for your AxonPush credentials
|
|
14
|
+
3. Use Claude Code to install the SDK and add integration code to your project
|
|
15
|
+
|
|
16
|
+
## Options
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
--integration, -i Framework (langchain, openai-agents, anthropic, crewai, core)
|
|
20
|
+
--api-key AxonPush API key
|
|
21
|
+
--tenant-id AxonPush tenant/organization ID
|
|
22
|
+
--base-url AxonPush server URL (default: http://localhost:3000)
|
|
23
|
+
--install-dir Project directory (default: current directory)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Non-interactive
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npx @axonpush/wizard \
|
|
30
|
+
--integration langchain \
|
|
31
|
+
--api-key ak_your_key \
|
|
32
|
+
--tenant-id 1
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Supported Frameworks
|
|
36
|
+
|
|
37
|
+
| Framework | Extra | Integration |
|
|
38
|
+
|-----------|-------|-------------|
|
|
39
|
+
| LangChain / LangGraph | `axonpush[langchain]` | Callback handler for chains and agents |
|
|
40
|
+
| OpenAI Agents SDK | `axonpush[openai-agents]` | Run hooks for agent lifecycle |
|
|
41
|
+
| Anthropic / Claude | `axonpush[anthropic]` | Tracer wrapping messages.create() |
|
|
42
|
+
| CrewAI | `axonpush[crewai]` | Step and task callbacks |
|
|
43
|
+
| Core SDK | `axonpush` | Direct event publishing |
|
|
44
|
+
|
|
45
|
+
## Requirements
|
|
46
|
+
|
|
47
|
+
- Node.js 20+
|
|
48
|
+
- Claude Code CLI installed and authenticated
|
|
49
|
+
- A Python project to integrate into
|
package/dist/bin.js
ADDED
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/bin.ts
|
|
4
|
+
import yargs from "yargs";
|
|
5
|
+
import { hideBin } from "yargs/helpers";
|
|
6
|
+
|
|
7
|
+
// src/run.ts
|
|
8
|
+
import prompts from "prompts";
|
|
9
|
+
import chalk from "chalk";
|
|
10
|
+
import ora from "ora";
|
|
11
|
+
|
|
12
|
+
// src/lib/constants.ts
|
|
13
|
+
var Integration = /* @__PURE__ */ ((Integration2) => {
|
|
14
|
+
Integration2["langchain"] = "langchain";
|
|
15
|
+
Integration2["openaiAgents"] = "openai-agents";
|
|
16
|
+
Integration2["anthropic"] = "anthropic";
|
|
17
|
+
Integration2["crewai"] = "crewai";
|
|
18
|
+
Integration2["core"] = "core";
|
|
19
|
+
return Integration2;
|
|
20
|
+
})(Integration || {});
|
|
21
|
+
var INTEGRATION_LABELS = {
|
|
22
|
+
["langchain" /* langchain */]: "LangChain / LangGraph",
|
|
23
|
+
["openai-agents" /* openaiAgents */]: "OpenAI Agents SDK",
|
|
24
|
+
["anthropic" /* anthropic */]: "Anthropic / Claude",
|
|
25
|
+
["crewai" /* crewai */]: "CrewAI",
|
|
26
|
+
["core" /* core */]: "Core SDK (no framework)"
|
|
27
|
+
};
|
|
28
|
+
var DEFAULT_BASE_URL = "http://localhost:3000";
|
|
29
|
+
|
|
30
|
+
// src/frameworks/langchain.ts
|
|
31
|
+
var LANGCHAIN_CONFIG = {
|
|
32
|
+
name: "LangChain / LangGraph",
|
|
33
|
+
integration: "langchain" /* langchain */,
|
|
34
|
+
packageExtra: "langchain",
|
|
35
|
+
detection: {
|
|
36
|
+
packages: ["langchain", "langchain-core", "langchain-openai", "langchain-anthropic", "langgraph"],
|
|
37
|
+
imports: ["from langchain", "import langchain", "from langgraph"]
|
|
38
|
+
},
|
|
39
|
+
prompts: {
|
|
40
|
+
integrationHint: 'Add AxonPushCallbackHandler to chain.invoke() via config={"callbacks": [handler]}'
|
|
41
|
+
},
|
|
42
|
+
skillDir: "skills/langchain"
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// src/frameworks/openai-agents.ts
|
|
46
|
+
var OPENAI_AGENTS_CONFIG = {
|
|
47
|
+
name: "OpenAI Agents SDK",
|
|
48
|
+
integration: "openai-agents" /* openaiAgents */,
|
|
49
|
+
packageExtra: "openai-agents",
|
|
50
|
+
detection: {
|
|
51
|
+
packages: ["openai-agents", "agents"],
|
|
52
|
+
imports: ["from agents import", "from agents.", "import agents"]
|
|
53
|
+
},
|
|
54
|
+
prompts: {
|
|
55
|
+
integrationHint: "Add AxonPushRunHooks as the hooks parameter to Runner.run(agent, input, hooks=hooks)"
|
|
56
|
+
},
|
|
57
|
+
skillDir: "skills/openai-agents"
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// src/frameworks/anthropic.ts
|
|
61
|
+
var ANTHROPIC_CONFIG = {
|
|
62
|
+
name: "Anthropic / Claude",
|
|
63
|
+
integration: "anthropic" /* anthropic */,
|
|
64
|
+
packageExtra: "anthropic",
|
|
65
|
+
detection: {
|
|
66
|
+
packages: ["anthropic"],
|
|
67
|
+
imports: ["import anthropic", "from anthropic"]
|
|
68
|
+
},
|
|
69
|
+
prompts: {
|
|
70
|
+
integrationHint: "Wrap anthropic_client.messages.create() with tracer.create_message() or tracer.acreate_message()"
|
|
71
|
+
},
|
|
72
|
+
skillDir: "skills/anthropic"
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// src/frameworks/crewai.ts
|
|
76
|
+
var CREWAI_CONFIG = {
|
|
77
|
+
name: "CrewAI",
|
|
78
|
+
integration: "crewai" /* crewai */,
|
|
79
|
+
packageExtra: "crewai",
|
|
80
|
+
detection: {
|
|
81
|
+
packages: ["crewai"],
|
|
82
|
+
imports: ["from crewai", "import crewai"]
|
|
83
|
+
},
|
|
84
|
+
prompts: {
|
|
85
|
+
integrationHint: "Add step_callback=callbacks.on_step and task_callback=callbacks.on_task_complete to Crew(), call on_crew_start() before and on_crew_end() after kickoff()"
|
|
86
|
+
},
|
|
87
|
+
skillDir: "skills/crewai"
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
// src/frameworks/core.ts
|
|
91
|
+
var CORE_CONFIG = {
|
|
92
|
+
name: "Core SDK (no framework)",
|
|
93
|
+
integration: "core" /* core */,
|
|
94
|
+
packageExtra: "",
|
|
95
|
+
detection: {
|
|
96
|
+
packages: [],
|
|
97
|
+
imports: []
|
|
98
|
+
},
|
|
99
|
+
prompts: {
|
|
100
|
+
integrationHint: "Create an AxonPush client and use client.events.publish() to send events from your code"
|
|
101
|
+
},
|
|
102
|
+
skillDir: "skills/core"
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
// src/lib/registry.ts
|
|
106
|
+
var FRAMEWORK_REGISTRY = {
|
|
107
|
+
["langchain" /* langchain */]: LANGCHAIN_CONFIG,
|
|
108
|
+
["openai-agents" /* openaiAgents */]: OPENAI_AGENTS_CONFIG,
|
|
109
|
+
["anthropic" /* anthropic */]: ANTHROPIC_CONFIG,
|
|
110
|
+
["crewai" /* crewai */]: CREWAI_CONFIG,
|
|
111
|
+
["core" /* core */]: CORE_CONFIG
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
// src/lib/detection.ts
|
|
115
|
+
import fs from "fs";
|
|
116
|
+
import path from "path";
|
|
117
|
+
function detectPackageManager(dir) {
|
|
118
|
+
if (fs.existsSync(path.join(dir, "uv.lock"))) return "uv";
|
|
119
|
+
if (fs.existsSync(path.join(dir, "poetry.lock"))) return "poetry";
|
|
120
|
+
return "pip";
|
|
121
|
+
}
|
|
122
|
+
function detectFrameworks(dir) {
|
|
123
|
+
const deps = readDependencies(dir);
|
|
124
|
+
const detected = [];
|
|
125
|
+
for (const [integration, config] of Object.entries(FRAMEWORK_REGISTRY)) {
|
|
126
|
+
if (integration === "core" /* core */) continue;
|
|
127
|
+
const match = config.detection.packages.some((pkg) => deps.has(pkg));
|
|
128
|
+
if (match) detected.push(integration);
|
|
129
|
+
}
|
|
130
|
+
if (detected.length === 0) {
|
|
131
|
+
const importMatches = scanImports(dir);
|
|
132
|
+
detected.push(...importMatches);
|
|
133
|
+
}
|
|
134
|
+
return detected;
|
|
135
|
+
}
|
|
136
|
+
function readDependencies(dir) {
|
|
137
|
+
const deps = /* @__PURE__ */ new Set();
|
|
138
|
+
const pyproject = path.join(dir, "pyproject.toml");
|
|
139
|
+
if (fs.existsSync(pyproject)) {
|
|
140
|
+
const content = fs.readFileSync(pyproject, "utf-8");
|
|
141
|
+
const depMatches = content.matchAll(/["']([a-zA-Z0-9_-]+)(?:\[.*?\])?(?:[><=!~].*)?\s*["']/g);
|
|
142
|
+
for (const m of depMatches) deps.add(m[1].toLowerCase());
|
|
143
|
+
}
|
|
144
|
+
const reqTxt = path.join(dir, "requirements.txt");
|
|
145
|
+
if (fs.existsSync(reqTxt)) {
|
|
146
|
+
const lines = fs.readFileSync(reqTxt, "utf-8").split("\n");
|
|
147
|
+
for (const line of lines) {
|
|
148
|
+
const trimmed = line.trim();
|
|
149
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
150
|
+
const name = trimmed.split(/[><=!~\[;]/)[0].trim().toLowerCase();
|
|
151
|
+
if (name) deps.add(name);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return deps;
|
|
155
|
+
}
|
|
156
|
+
function scanImports(dir) {
|
|
157
|
+
const detected = [];
|
|
158
|
+
const pyFiles = findPyFiles(dir, 3);
|
|
159
|
+
for (const file of pyFiles) {
|
|
160
|
+
const content = fs.readFileSync(file, "utf-8");
|
|
161
|
+
for (const [integration, config] of Object.entries(FRAMEWORK_REGISTRY)) {
|
|
162
|
+
if (integration === "core" /* core */) continue;
|
|
163
|
+
if (config.detection.imports.some((pattern) => content.includes(pattern))) {
|
|
164
|
+
if (!detected.includes(integration)) {
|
|
165
|
+
detected.push(integration);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return detected;
|
|
171
|
+
}
|
|
172
|
+
function findPyFiles(dir, maxDepth, depth = 0) {
|
|
173
|
+
if (depth > maxDepth) return [];
|
|
174
|
+
const files = [];
|
|
175
|
+
try {
|
|
176
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
177
|
+
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "__pycache__" || entry.name === ".venv") continue;
|
|
178
|
+
const full = path.join(dir, entry.name);
|
|
179
|
+
if (entry.isDirectory()) {
|
|
180
|
+
files.push(...findPyFiles(full, maxDepth, depth + 1));
|
|
181
|
+
} else if (entry.name.endsWith(".py")) {
|
|
182
|
+
files.push(full);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
} catch {
|
|
186
|
+
}
|
|
187
|
+
return files;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// src/lib/agent-runner.ts
|
|
191
|
+
import fs2 from "fs";
|
|
192
|
+
import path2 from "path";
|
|
193
|
+
|
|
194
|
+
// src/lib/commandments.ts
|
|
195
|
+
var COMMANDMENTS = [
|
|
196
|
+
"Never hardcode API keys or secrets in source files. Always use environment variables loaded from .env.",
|
|
197
|
+
"Use the set_env_values wizard tool to create/update .env files. Never use the Write tool for .env.",
|
|
198
|
+
"Use the detect_package_manager wizard tool before installing packages.",
|
|
199
|
+
"Always read a file before modifying it. Never guess file contents.",
|
|
200
|
+
"Add axonpush imports at the top of the file alongside other imports.",
|
|
201
|
+
"Do not remove or modify existing functionality. Only add AxonPush integration code.",
|
|
202
|
+
"If unsure which file to modify, use Glob and Grep to find the main agent/chain entry point.",
|
|
203
|
+
"For LangChain: add handler via config={'callbacks': [handler]} in chain.invoke() or agent_executor.invoke().",
|
|
204
|
+
"For OpenAI Agents: pass hooks=hooks to Runner.run().",
|
|
205
|
+
"For Anthropic: wrap messages.create() with tracer.create_message() or tracer.acreate_message().",
|
|
206
|
+
"For CrewAI: add step_callback=callbacks.on_step and task_callback=callbacks.on_task_complete to Crew().",
|
|
207
|
+
"Always import os at the top if using os.environ for credentials.",
|
|
208
|
+
"Create the AxonPush client as a module-level singleton, not inside each function call.",
|
|
209
|
+
"Use channel_id=1 as placeholder if no channel ID is provided.",
|
|
210
|
+
"When done, briefly summarize what files were changed and what the user should do next."
|
|
211
|
+
];
|
|
212
|
+
function getCommandments() {
|
|
213
|
+
return COMMANDMENTS.map((c, i) => `${i + 1}. ${c}`).join("\n");
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// src/lib/agent-interface.ts
|
|
217
|
+
async function runAgent(prompt, cwd, onStatus) {
|
|
218
|
+
const { query } = await import("@anthropic-ai/claude-code");
|
|
219
|
+
const messages = [];
|
|
220
|
+
const response = query({
|
|
221
|
+
prompt,
|
|
222
|
+
options: {
|
|
223
|
+
cwd,
|
|
224
|
+
allowedTools: [
|
|
225
|
+
"Read",
|
|
226
|
+
"Write",
|
|
227
|
+
"Edit",
|
|
228
|
+
"Glob",
|
|
229
|
+
"Grep",
|
|
230
|
+
"Bash"
|
|
231
|
+
],
|
|
232
|
+
systemPrompt: `You are an expert Python developer integrating the AxonPush observability SDK into a project. Follow these rules:
|
|
233
|
+
|
|
234
|
+
${getCommandments()}`
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
for await (const message of response) {
|
|
238
|
+
messages.push(message);
|
|
239
|
+
if (message.type === "assistant" && message.content) {
|
|
240
|
+
const content = String(message.content);
|
|
241
|
+
const lines = content.split("\n");
|
|
242
|
+
for (const line of lines) {
|
|
243
|
+
const trimmed = line.trim();
|
|
244
|
+
if (trimmed) {
|
|
245
|
+
onStatus(trimmed);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// src/lib/agent-runner.ts
|
|
253
|
+
function buildPrompt(opts) {
|
|
254
|
+
const skillPath = path2.resolve(__dirname, "..", "..", opts.config.skillDir, "SKILL.md");
|
|
255
|
+
let skillContent = "";
|
|
256
|
+
try {
|
|
257
|
+
skillContent = fs2.readFileSync(skillPath, "utf-8");
|
|
258
|
+
} catch {
|
|
259
|
+
const altPath = path2.resolve(process.cwd(), opts.config.skillDir, "SKILL.md");
|
|
260
|
+
try {
|
|
261
|
+
skillContent = fs2.readFileSync(altPath, "utf-8");
|
|
262
|
+
} catch {
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
const pkgCmd = opts.packageManager === "uv" ? `uv add "axonpush${opts.config.packageExtra ? `[${opts.config.packageExtra}]` : ""}"` : opts.packageManager === "poetry" ? `poetry add "axonpush${opts.config.packageExtra ? `[${opts.config.packageExtra}]` : ""}"` : `pip install "axonpush${opts.config.packageExtra ? `[${opts.config.packageExtra}]` : ""}"`;
|
|
266
|
+
return `You are integrating the AxonPush Python SDK into this project.
|
|
267
|
+
|
|
268
|
+
## Project Info
|
|
269
|
+
- Directory: ${opts.projectDir}
|
|
270
|
+
- Package manager: ${opts.packageManager}
|
|
271
|
+
- Framework: ${opts.config.name}
|
|
272
|
+
- Integration hint: ${opts.config.prompts.integrationHint}
|
|
273
|
+
|
|
274
|
+
## Credentials (use these in .env)
|
|
275
|
+
- AXONPUSH_API_KEY=${opts.apiKey}
|
|
276
|
+
- AXONPUSH_TENANT_ID=${opts.tenantId}
|
|
277
|
+
- AXONPUSH_BASE_URL=${opts.baseUrl}
|
|
278
|
+
|
|
279
|
+
## Steps
|
|
280
|
+
|
|
281
|
+
1. Install the SDK:
|
|
282
|
+
Run: ${pkgCmd}
|
|
283
|
+
|
|
284
|
+
2. Create or update .env in the project root with the credentials above.
|
|
285
|
+
If .env already exists, append the AXONPUSH_ variables (don't overwrite existing vars).
|
|
286
|
+
|
|
287
|
+
3. Find the main agent/chain entry point in the project. Look for:
|
|
288
|
+
- Files importing ${opts.config.detection.imports[0] || "the AI framework"}
|
|
289
|
+
- Files with main() or if __name__ == "__main__"
|
|
290
|
+
- app.py, main.py, agent.py, or similar
|
|
291
|
+
|
|
292
|
+
4. Add AxonPush integration code following the reference below.
|
|
293
|
+
|
|
294
|
+
5. Make sure os is imported if using os.environ.
|
|
295
|
+
|
|
296
|
+
${skillContent ? `## Skill Reference
|
|
297
|
+
|
|
298
|
+
${skillContent}` : ""}
|
|
299
|
+
|
|
300
|
+
When done, summarize what you changed.`;
|
|
301
|
+
}
|
|
302
|
+
async function agentRunner(opts, onStatus) {
|
|
303
|
+
const prompt = buildPrompt(opts);
|
|
304
|
+
await runAgent(prompt, opts.projectDir, onStatus);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// src/run.ts
|
|
308
|
+
async function run(args) {
|
|
309
|
+
const projectDir = args.installDir || process.cwd();
|
|
310
|
+
console.log();
|
|
311
|
+
console.log(chalk.bold(" AxonPush Wizard"));
|
|
312
|
+
console.log(chalk.dim(" AI-powered SDK integration\n"));
|
|
313
|
+
let integration;
|
|
314
|
+
if (args.integration && args.integration in Integration) {
|
|
315
|
+
integration = args.integration;
|
|
316
|
+
console.log(chalk.green(` Framework: ${INTEGRATION_LABELS[integration]} (from flag)`));
|
|
317
|
+
} else {
|
|
318
|
+
const detected = detectFrameworks(projectDir);
|
|
319
|
+
const pkgMgr = detectPackageManager(projectDir);
|
|
320
|
+
console.log(chalk.dim(` Project: ${projectDir}`));
|
|
321
|
+
console.log(chalk.dim(` Package manager: ${pkgMgr}`));
|
|
322
|
+
if (detected.length === 1) {
|
|
323
|
+
integration = detected[0];
|
|
324
|
+
console.log(chalk.green(` Detected: ${INTEGRATION_LABELS[integration]}
|
|
325
|
+
`));
|
|
326
|
+
} else if (detected.length > 1) {
|
|
327
|
+
console.log(chalk.yellow(` Multiple frameworks detected: ${detected.map((d) => INTEGRATION_LABELS[d]).join(", ")}
|
|
328
|
+
`));
|
|
329
|
+
const { choice } = await prompts({
|
|
330
|
+
type: "select",
|
|
331
|
+
name: "choice",
|
|
332
|
+
message: "Which framework integration?",
|
|
333
|
+
choices: detected.map((d) => ({ title: INTEGRATION_LABELS[d], value: d }))
|
|
334
|
+
});
|
|
335
|
+
if (!choice) process.exit(0);
|
|
336
|
+
integration = choice;
|
|
337
|
+
} else {
|
|
338
|
+
console.log(chalk.yellow(" No AI framework detected.\n"));
|
|
339
|
+
const { choice } = await prompts({
|
|
340
|
+
type: "select",
|
|
341
|
+
name: "choice",
|
|
342
|
+
message: "Choose an integration",
|
|
343
|
+
choices: Object.entries(INTEGRATION_LABELS).map(([value, title]) => ({ title, value }))
|
|
344
|
+
});
|
|
345
|
+
if (!choice) process.exit(0);
|
|
346
|
+
integration = choice;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
const config = FRAMEWORK_REGISTRY[integration];
|
|
350
|
+
let apiKey = args.apiKey;
|
|
351
|
+
let tenantId = args.tenantId;
|
|
352
|
+
let baseUrl = args.baseUrl || DEFAULT_BASE_URL;
|
|
353
|
+
if (!apiKey) {
|
|
354
|
+
const res = await prompts({ type: "password", name: "value", message: "AxonPush API Key" });
|
|
355
|
+
apiKey = res.value;
|
|
356
|
+
if (!apiKey) process.exit(0);
|
|
357
|
+
}
|
|
358
|
+
if (!tenantId) {
|
|
359
|
+
const res = await prompts({ type: "text", name: "value", message: "Tenant ID", initial: "1" });
|
|
360
|
+
tenantId = res.value;
|
|
361
|
+
if (!tenantId) process.exit(0);
|
|
362
|
+
}
|
|
363
|
+
if (!args.baseUrl) {
|
|
364
|
+
const res = await prompts({ type: "text", name: "value", message: "Base URL", initial: DEFAULT_BASE_URL });
|
|
365
|
+
baseUrl = res.value || DEFAULT_BASE_URL;
|
|
366
|
+
}
|
|
367
|
+
console.log();
|
|
368
|
+
const spinner = ora("Running Claude Code agent...").start();
|
|
369
|
+
try {
|
|
370
|
+
await agentRunner(
|
|
371
|
+
{
|
|
372
|
+
config,
|
|
373
|
+
projectDir,
|
|
374
|
+
packageManager: detectPackageManager(projectDir),
|
|
375
|
+
apiKey,
|
|
376
|
+
tenantId,
|
|
377
|
+
baseUrl
|
|
378
|
+
},
|
|
379
|
+
(msg) => {
|
|
380
|
+
spinner.text = msg;
|
|
381
|
+
}
|
|
382
|
+
);
|
|
383
|
+
spinner.succeed("AxonPush integrated!");
|
|
384
|
+
} catch (error) {
|
|
385
|
+
spinner.fail("Agent failed");
|
|
386
|
+
console.error(chalk.red(`
|
|
387
|
+
${error instanceof Error ? error.message : error}`));
|
|
388
|
+
process.exit(1);
|
|
389
|
+
}
|
|
390
|
+
console.log();
|
|
391
|
+
console.log(chalk.green(" Next steps:"));
|
|
392
|
+
console.log(chalk.dim(" 1. Run your agent and check the AxonPush dashboard"));
|
|
393
|
+
console.log(chalk.dim(` 2. View traces at ${baseUrl.replace("3000", "5173")}/traces`));
|
|
394
|
+
console.log();
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// src/bin.ts
|
|
398
|
+
yargs(hideBin(process.argv)).scriptName("axonpush-wizard").usage("$0 [options]").option("integration", {
|
|
399
|
+
alias: "i",
|
|
400
|
+
type: "string",
|
|
401
|
+
describe: "Framework integration (langchain, openai-agents, anthropic, crewai, core)"
|
|
402
|
+
}).option("api-key", {
|
|
403
|
+
type: "string",
|
|
404
|
+
describe: "AxonPush API key"
|
|
405
|
+
}).option("tenant-id", {
|
|
406
|
+
type: "string",
|
|
407
|
+
describe: "AxonPush tenant/organization ID"
|
|
408
|
+
}).option("base-url", {
|
|
409
|
+
type: "string",
|
|
410
|
+
describe: "AxonPush server URL"
|
|
411
|
+
}).option("install-dir", {
|
|
412
|
+
type: "string",
|
|
413
|
+
describe: "Project directory to integrate into (default: cwd)"
|
|
414
|
+
}).option("debug", {
|
|
415
|
+
type: "boolean",
|
|
416
|
+
default: false,
|
|
417
|
+
describe: "Enable debug output"
|
|
418
|
+
}).command(
|
|
419
|
+
"$0",
|
|
420
|
+
"Integrate AxonPush into your AI agent project",
|
|
421
|
+
() => {
|
|
422
|
+
},
|
|
423
|
+
async (argv) => {
|
|
424
|
+
await run({
|
|
425
|
+
integration: argv.integration,
|
|
426
|
+
apiKey: argv["api-key"],
|
|
427
|
+
tenantId: argv["tenant-id"],
|
|
428
|
+
baseUrl: argv["base-url"],
|
|
429
|
+
installDir: argv["install-dir"]
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
).help().parse();
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@axonpush/wizard",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "AI-powered wizard to integrate AxonPush into your AI agent project",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"axonpush-wizard": "dist/bin.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "dist/index.js",
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"skills"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsup",
|
|
16
|
+
"dev": "tsx src/bin.ts",
|
|
17
|
+
"start": "node dist/bin.js"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@anthropic-ai/claude-code": "^0.2.20",
|
|
21
|
+
"chalk": "^5.4.1",
|
|
22
|
+
"ora": "^8.2.0",
|
|
23
|
+
"prompts": "^2.4.2",
|
|
24
|
+
"yargs": "^17.7.2"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/prompts": "^2.4.9",
|
|
28
|
+
"@types/yargs": "^17.0.33",
|
|
29
|
+
"tsup": "^8.4.0",
|
|
30
|
+
"tsx": "^4.19.0",
|
|
31
|
+
"typescript": "^5.7.0"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: anthropic
|
|
3
|
+
description: Integrate AxonPush tracing into a project using the Anthropic Python SDK
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# AxonPush + Anthropic/Claude Integration
|
|
7
|
+
|
|
8
|
+
Integrate AxonPush tracing into a project using the Anthropic Python SDK.
|
|
9
|
+
|
|
10
|
+
## What gets added
|
|
11
|
+
|
|
12
|
+
- `AxonPushAnthropicTracer` that wraps `messages.create()` to trace conversations, tool use, and responses
|
|
13
|
+
- Events: `conversation.turn`, `tool.*.start`, `agent.response`, `tool.result`
|
|
14
|
+
|
|
15
|
+
## Reference Code (Sync)
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
import os
|
|
19
|
+
from axonpush import AxonPush
|
|
20
|
+
from axonpush.integrations.anthropic import AxonPushAnthropicTracer
|
|
21
|
+
|
|
22
|
+
axonpush_client = AxonPush(
|
|
23
|
+
api_key=os.environ["AXONPUSH_API_KEY"],
|
|
24
|
+
tenant_id=os.environ["AXONPUSH_TENANT_ID"],
|
|
25
|
+
base_url=os.environ.get("AXONPUSH_BASE_URL", "http://localhost:3000"),
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
tracer = AxonPushAnthropicTracer(
|
|
29
|
+
client=axonpush_client,
|
|
30
|
+
channel_id=1, # Replace with your channel ID
|
|
31
|
+
agent_id="claude-agent",
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
# Instead of: response = anthropic_client.messages.create(model=..., messages=...)
|
|
35
|
+
# Use: response = tracer.create_message(anthropic_client, model=..., messages=...)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Reference Code (Async)
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
# Use AsyncAxonPush instead:
|
|
42
|
+
# response = await tracer.acreate_message(async_anthropic_client, model=..., messages=...)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Steps
|
|
46
|
+
|
|
47
|
+
1. Install `axonpush[anthropic]` using the project's package manager
|
|
48
|
+
2. Add AXONPUSH_API_KEY, AXONPUSH_TENANT_ID, AXONPUSH_BASE_URL to .env
|
|
49
|
+
3. Find files that call `client.messages.create()` (the Anthropic API)
|
|
50
|
+
4. Add imports and create the tracer
|
|
51
|
+
5. Replace `anthropic_client.messages.create(...)` with `tracer.create_message(anthropic_client, ...)`
|
|
52
|
+
6. For tool results, add `tracer.send_tool_result(tool_use_id, result)` calls
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: core
|
|
3
|
+
description: Integrate AxonPush event publishing directly without framework-specific callbacks
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# AxonPush Core SDK Integration
|
|
7
|
+
|
|
8
|
+
Integrate AxonPush event publishing directly (no framework-specific callbacks).
|
|
9
|
+
|
|
10
|
+
## What gets added
|
|
11
|
+
|
|
12
|
+
- `AxonPush` client for publishing custom events
|
|
13
|
+
- Use `client.events.publish()` to send events from anywhere in your code
|
|
14
|
+
|
|
15
|
+
## Reference Code
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
import os
|
|
19
|
+
from axonpush import AxonPush, EventType
|
|
20
|
+
|
|
21
|
+
axonpush_client = AxonPush(
|
|
22
|
+
api_key=os.environ["AXONPUSH_API_KEY"],
|
|
23
|
+
tenant_id=os.environ["AXONPUSH_TENANT_ID"],
|
|
24
|
+
base_url=os.environ.get("AXONPUSH_BASE_URL", "http://localhost:3000"),
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
# Publish events from your code:
|
|
28
|
+
# axonpush_client.events.publish(
|
|
29
|
+
# identifier="my.event",
|
|
30
|
+
# payload={"key": "value"},
|
|
31
|
+
# channel_id=1,
|
|
32
|
+
# agent_id="my-agent",
|
|
33
|
+
# event_type=EventType.CUSTOM,
|
|
34
|
+
# )
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Steps
|
|
38
|
+
|
|
39
|
+
1. Install `axonpush` using the project's package manager
|
|
40
|
+
2. Add AXONPUSH_API_KEY, AXONPUSH_TENANT_ID, AXONPUSH_BASE_URL to .env
|
|
41
|
+
3. Find the main entry point of the project
|
|
42
|
+
4. Add imports and create the client as a module-level singleton
|
|
43
|
+
5. Add example publish calls at key points (e.g., start, end, error handling)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: crewai
|
|
3
|
+
description: Integrate AxonPush tracing into a CrewAI project
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# AxonPush + CrewAI Integration
|
|
7
|
+
|
|
8
|
+
Integrate AxonPush tracing into a CrewAI project.
|
|
9
|
+
|
|
10
|
+
## What gets added
|
|
11
|
+
|
|
12
|
+
- `AxonPushCrewCallbacks` with manual callback methods for crew lifecycle
|
|
13
|
+
- Events: `crew.start`, `crew.end`, `agent.step`, `tool.*.start`, `tool.*.end`, `task.complete`
|
|
14
|
+
|
|
15
|
+
## Reference Code
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
import os
|
|
19
|
+
from axonpush import AxonPush
|
|
20
|
+
from axonpush.integrations.crewai import AxonPushCrewCallbacks
|
|
21
|
+
|
|
22
|
+
axonpush_client = AxonPush(
|
|
23
|
+
api_key=os.environ["AXONPUSH_API_KEY"],
|
|
24
|
+
tenant_id=os.environ["AXONPUSH_TENANT_ID"],
|
|
25
|
+
base_url=os.environ.get("AXONPUSH_BASE_URL", "http://localhost:3000"),
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
axonpush_callbacks = AxonPushCrewCallbacks(
|
|
29
|
+
client=axonpush_client,
|
|
30
|
+
channel_id=1, # Replace with your channel ID
|
|
31
|
+
agent_id="crewai",
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
# Usage:
|
|
35
|
+
# axonpush_callbacks.on_crew_start()
|
|
36
|
+
# crew = Crew(
|
|
37
|
+
# agents=[...],
|
|
38
|
+
# tasks=[...],
|
|
39
|
+
# step_callback=axonpush_callbacks.on_step,
|
|
40
|
+
# task_callback=axonpush_callbacks.on_task_complete,
|
|
41
|
+
# )
|
|
42
|
+
# result = crew.kickoff()
|
|
43
|
+
# axonpush_callbacks.on_crew_end(result)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Steps
|
|
47
|
+
|
|
48
|
+
1. Install `axonpush[crewai]` using the project's package manager
|
|
49
|
+
2. Add AXONPUSH_API_KEY, AXONPUSH_TENANT_ID, AXONPUSH_BASE_URL to .env
|
|
50
|
+
3. Find the file where `Crew(...)` is instantiated
|
|
51
|
+
4. Add imports and create the callbacks object
|
|
52
|
+
5. Add `step_callback=axonpush_callbacks.on_step` and `task_callback=axonpush_callbacks.on_task_complete` to `Crew()`
|
|
53
|
+
6. Add `axonpush_callbacks.on_crew_start()` before `crew.kickoff()`
|
|
54
|
+
7. Add `axonpush_callbacks.on_crew_end(result)` after
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: langchain
|
|
3
|
+
description: Integrate AxonPush tracing into a LangChain or LangGraph project
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# AxonPush + LangChain Integration
|
|
7
|
+
|
|
8
|
+
Integrate AxonPush tracing into a LangChain or LangGraph project.
|
|
9
|
+
|
|
10
|
+
## What gets added
|
|
11
|
+
|
|
12
|
+
- `AxonPushCallbackHandler` that auto-traces chain/LLM/tool lifecycle events
|
|
13
|
+
- Events: `chain.start`, `chain.end`, `llm.start`, `llm.end`, `tool.*.start`, `tool.end`
|
|
14
|
+
|
|
15
|
+
## Reference Code
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
import os
|
|
19
|
+
from axonpush import AxonPush
|
|
20
|
+
from axonpush.integrations.langchain import AxonPushCallbackHandler
|
|
21
|
+
|
|
22
|
+
axonpush_client = AxonPush(
|
|
23
|
+
api_key=os.environ["AXONPUSH_API_KEY"],
|
|
24
|
+
tenant_id=os.environ["AXONPUSH_TENANT_ID"],
|
|
25
|
+
base_url=os.environ.get("AXONPUSH_BASE_URL", "http://localhost:3000"),
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
axonpush_handler = AxonPushCallbackHandler(
|
|
29
|
+
client=axonpush_client,
|
|
30
|
+
channel_id=1, # Replace with your channel ID
|
|
31
|
+
agent_id="my-agent",
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
# For any chain:
|
|
35
|
+
# result = chain.invoke(input, config={"callbacks": [axonpush_handler]})
|
|
36
|
+
|
|
37
|
+
# For an agent executor:
|
|
38
|
+
# result = agent_executor.invoke(input, config={"callbacks": [axonpush_handler]})
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Steps
|
|
42
|
+
|
|
43
|
+
1. Install `axonpush[langchain]` using the project's package manager
|
|
44
|
+
2. Add AXONPUSH_API_KEY, AXONPUSH_TENANT_ID, AXONPUSH_BASE_URL to .env
|
|
45
|
+
3. Find the main file where chains/agents are invoked
|
|
46
|
+
4. Add the imports and client initialization (as module-level code)
|
|
47
|
+
5. Add `config={"callbacks": [axonpush_handler]}` to `.invoke()` calls
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: openai-agents
|
|
3
|
+
description: Integrate AxonPush tracing into a project using the OpenAI Agents SDK
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# AxonPush + OpenAI Agents SDK Integration
|
|
7
|
+
|
|
8
|
+
Integrate AxonPush tracing into a project using the OpenAI Agents SDK.
|
|
9
|
+
|
|
10
|
+
## What gets added
|
|
11
|
+
|
|
12
|
+
- `AxonPushRunHooks` that traces agent runs, tool calls, and handoffs
|
|
13
|
+
- Events: `agent.run.start`, `agent.run.end`, `tool.*.start`, `tool.*.end`, `agent.handoff`
|
|
14
|
+
|
|
15
|
+
## Reference Code
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
import os
|
|
19
|
+
from axonpush import AsyncAxonPush
|
|
20
|
+
from axonpush.integrations.openai_agents import AxonPushRunHooks
|
|
21
|
+
|
|
22
|
+
axonpush_client = AsyncAxonPush(
|
|
23
|
+
api_key=os.environ["AXONPUSH_API_KEY"],
|
|
24
|
+
tenant_id=os.environ["AXONPUSH_TENANT_ID"],
|
|
25
|
+
base_url=os.environ.get("AXONPUSH_BASE_URL", "http://localhost:3000"),
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
axonpush_hooks = AxonPushRunHooks(
|
|
29
|
+
client=axonpush_client,
|
|
30
|
+
channel_id=1, # Replace with your channel ID
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
# Usage:
|
|
34
|
+
# result = await Runner.run(agent, input="...", hooks=axonpush_hooks)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Steps
|
|
38
|
+
|
|
39
|
+
1. Install `axonpush[openai-agents]` using the project's package manager
|
|
40
|
+
2. Add AXONPUSH_API_KEY, AXONPUSH_TENANT_ID, AXONPUSH_BASE_URL to .env
|
|
41
|
+
3. Find the main file where Runner.run() is called
|
|
42
|
+
4. Add the imports and AsyncAxonPush client (this SDK is async-only)
|
|
43
|
+
5. Pass `hooks=axonpush_hooks` to `Runner.run()`
|
|
44
|
+
|
|
45
|
+
## Important
|
|
46
|
+
|
|
47
|
+
- OpenAI Agents SDK is **async-only**, so use `AsyncAxonPush` (not `AxonPush`)
|
|
48
|
+
- Make sure to close the client when done: `await axonpush_client.close()`
|
|
49
|
+
- Or use `async with AsyncAxonPush(...) as client:` context manager
|