create-agentmark 0.6.0 → 0.7.0
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/dist/index.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import
|
|
5
|
-
import
|
|
4
|
+
import fs8 from "fs-extra";
|
|
5
|
+
import path6 from "path";
|
|
6
|
+
import prompts2 from "prompts";
|
|
6
7
|
|
|
7
8
|
// src/utils/examples/create-example-app.ts
|
|
8
|
-
import
|
|
9
|
-
import * as
|
|
9
|
+
import fs4 from "fs-extra";
|
|
10
|
+
import * as path2 from "path";
|
|
10
11
|
|
|
11
12
|
// src/utils/providers.ts
|
|
12
13
|
var Providers = {
|
|
@@ -22,6 +23,17 @@ var Providers = {
|
|
|
22
23
|
],
|
|
23
24
|
imageModels: ["dall-e-3", "dall-e-2"],
|
|
24
25
|
speechModels: ["tts-1", "tts-1-hd"]
|
|
26
|
+
},
|
|
27
|
+
anthropic: {
|
|
28
|
+
label: "Anthropic",
|
|
29
|
+
languageModels: [
|
|
30
|
+
"claude-sonnet-4-20250514",
|
|
31
|
+
"claude-opus-4-20250514",
|
|
32
|
+
"claude-3-5-sonnet-20241022",
|
|
33
|
+
"claude-3-5-haiku-20241022"
|
|
34
|
+
],
|
|
35
|
+
imageModels: [],
|
|
36
|
+
speechModels: []
|
|
25
37
|
}
|
|
26
38
|
};
|
|
27
39
|
|
|
@@ -49,6 +61,15 @@ var createAdapterConfig = (provider) => {
|
|
|
49
61
|
toolRegistry: "MastraToolRegistry",
|
|
50
62
|
webhookHandler: "MastraAdapterWebhookHandler"
|
|
51
63
|
}
|
|
64
|
+
},
|
|
65
|
+
"claude-agent-sdk": {
|
|
66
|
+
package: "@agentmark-ai/claude-agent-sdk-adapter",
|
|
67
|
+
dependencies: ["@anthropic-ai/claude-agent-sdk@^0.1.0"],
|
|
68
|
+
classes: {
|
|
69
|
+
modelRegistry: "ClaudeAgentModelRegistry",
|
|
70
|
+
toolRegistry: "ClaudeAgentToolRegistry",
|
|
71
|
+
webhookHandler: "ClaudeAgentWebhookHandler"
|
|
72
|
+
}
|
|
52
73
|
}
|
|
53
74
|
};
|
|
54
75
|
};
|
|
@@ -66,7 +87,61 @@ function getAdapterConfig(adapter, provider) {
|
|
|
66
87
|
|
|
67
88
|
// src/utils/examples/templates/app-index.ts
|
|
68
89
|
var getIndexFileContent = (adapter = "ai-sdk") => {
|
|
69
|
-
if (adapter === "
|
|
90
|
+
if (adapter === "claude-agent-sdk") {
|
|
91
|
+
return `import "dotenv/config";
|
|
92
|
+
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
93
|
+
import { withTracing } from "@agentmark-ai/claude-agent-sdk-adapter";
|
|
94
|
+
import { client } from "./agentmark.client";
|
|
95
|
+
|
|
96
|
+
const telemetry = {
|
|
97
|
+
isEnabled: true,
|
|
98
|
+
metadata: {
|
|
99
|
+
trace_name: "customer-support",
|
|
100
|
+
user_id: "user-123",
|
|
101
|
+
session_id: "session-123",
|
|
102
|
+
session_name: "my-first-session",
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const runCustomerSupport = async (customer_message: string) => {
|
|
107
|
+
const prompt = await client.loadTextPrompt("customer-support-agent");
|
|
108
|
+
const adapted = await prompt.format({
|
|
109
|
+
props: {
|
|
110
|
+
customer_question: customer_message,
|
|
111
|
+
},
|
|
112
|
+
telemetry,
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// Execute with Claude Agent SDK using withTracing for telemetry
|
|
116
|
+
// The adapted object contains { query, telemetry } ready for withTracing()
|
|
117
|
+
const tracedResult = await withTracing(query, adapted);
|
|
118
|
+
|
|
119
|
+
// traceId is available immediately
|
|
120
|
+
console.log("Trace ID:", tracedResult.traceId);
|
|
121
|
+
|
|
122
|
+
let result = "";
|
|
123
|
+
for await (const message of tracedResult) {
|
|
124
|
+
if (message.type === "result" && message.subtype === "success") {
|
|
125
|
+
result = message.result || "";
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return result;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const main = async () => {
|
|
133
|
+
try {
|
|
134
|
+
const user_message = "How long does shipping take?";
|
|
135
|
+
const assistant = await runCustomerSupport(user_message);
|
|
136
|
+
console.log("Customer support response:", assistant);
|
|
137
|
+
} catch (error) {
|
|
138
|
+
console.error(error);
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
main();
|
|
143
|
+
`;
|
|
144
|
+
} else if (adapter === "mastra") {
|
|
70
145
|
return `import "dotenv/config";
|
|
71
146
|
import { Agent } from "@mastra/core/agent";
|
|
72
147
|
import { client } from "./agentmark.client";
|
|
@@ -158,70 +233,328 @@ main();
|
|
|
158
233
|
};
|
|
159
234
|
|
|
160
235
|
// src/utils/examples/templates/env.ts
|
|
161
|
-
var getEnvFileContent = (_modelProvider, apiKey = "") => {
|
|
236
|
+
var getEnvFileContent = (_modelProvider, apiKey = "", adapter = "ai-sdk") => {
|
|
162
237
|
const apiKeyValue = apiKey || "your_api_key_here";
|
|
238
|
+
const apiKeyName = adapter === "claude-agent-sdk" ? "ANTHROPIC_API_KEY" : "OPENAI_API_KEY";
|
|
163
239
|
return `# Cloud deployment: Set these environment variables
|
|
164
240
|
# AGENTMARK_BASE_URL=https://api.agentmark.co
|
|
165
241
|
# AGENTMARK_API_KEY=your_agentmark_api_key
|
|
166
242
|
# AGENTMARK_APP_ID=your_agentmark_app_id
|
|
167
243
|
# Learn more: https://docs.agentmark.co/platform/getting_started/quickstart
|
|
168
244
|
|
|
169
|
-
|
|
245
|
+
${apiKeyName}=${apiKeyValue}
|
|
170
246
|
`;
|
|
171
247
|
};
|
|
172
248
|
|
|
173
249
|
// src/utils/examples/templates/package-setup.ts
|
|
250
|
+
import fs2 from "fs-extra";
|
|
251
|
+
import { execSync } from "child_process";
|
|
252
|
+
|
|
253
|
+
// src/utils/file-merge.ts
|
|
174
254
|
import fs from "fs-extra";
|
|
175
|
-
import
|
|
176
|
-
|
|
255
|
+
import path from "path";
|
|
256
|
+
function mergePackageJson(targetPath, agentmarkDeps, agentmarkDevDeps, agentmarkScripts) {
|
|
257
|
+
const packageJsonPath = path.join(targetPath, "package.json");
|
|
258
|
+
const result = {
|
|
259
|
+
success: false,
|
|
260
|
+
warnings: [],
|
|
261
|
+
added: [],
|
|
262
|
+
skipped: []
|
|
263
|
+
};
|
|
264
|
+
try {
|
|
265
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
266
|
+
result.warnings.push("No existing package.json found");
|
|
267
|
+
return result;
|
|
268
|
+
}
|
|
269
|
+
const existing = fs.readJsonSync(packageJsonPath);
|
|
270
|
+
if (!existing.dependencies) {
|
|
271
|
+
existing.dependencies = {};
|
|
272
|
+
}
|
|
273
|
+
if (!existing.devDependencies) {
|
|
274
|
+
existing.devDependencies = {};
|
|
275
|
+
}
|
|
276
|
+
if (!existing.scripts) {
|
|
277
|
+
existing.scripts = {};
|
|
278
|
+
}
|
|
279
|
+
const deps = existing.dependencies;
|
|
280
|
+
const devDeps = existing.devDependencies;
|
|
281
|
+
const scripts = existing.scripts;
|
|
282
|
+
for (const [pkg, version] of Object.entries(agentmarkDeps)) {
|
|
283
|
+
if (deps[pkg]) {
|
|
284
|
+
result.skipped.push(`dependency: ${pkg} (already exists)`);
|
|
285
|
+
} else {
|
|
286
|
+
deps[pkg] = version;
|
|
287
|
+
result.added.push(`dependency: ${pkg}@${version}`);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
for (const [pkg, version] of Object.entries(agentmarkDevDeps)) {
|
|
291
|
+
if (devDeps[pkg]) {
|
|
292
|
+
result.skipped.push(`devDependency: ${pkg} (already exists)`);
|
|
293
|
+
} else {
|
|
294
|
+
devDeps[pkg] = version;
|
|
295
|
+
result.added.push(`devDependency: ${pkg}@${version}`);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
for (const [scriptName, scriptCmd] of Object.entries(agentmarkScripts)) {
|
|
299
|
+
if (scripts[scriptName]) {
|
|
300
|
+
const namespacedName = `agentmark:${scriptName}`;
|
|
301
|
+
if (scripts[namespacedName]) {
|
|
302
|
+
result.skipped.push(`script: ${scriptName}`);
|
|
303
|
+
result.warnings.push(
|
|
304
|
+
`Script "${scriptName}" and "${namespacedName}" both already exist. Skipping.`
|
|
305
|
+
);
|
|
306
|
+
} else {
|
|
307
|
+
scripts[namespacedName] = scriptCmd;
|
|
308
|
+
result.added.push(`script: ${namespacedName} (namespaced due to conflict)`);
|
|
309
|
+
result.warnings.push(
|
|
310
|
+
`Script "${scriptName}" already exists. Added as "${namespacedName}" instead.`
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
} else {
|
|
314
|
+
scripts[scriptName] = scriptCmd;
|
|
315
|
+
result.added.push(`script: ${scriptName}`);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
fs.writeJsonSync(packageJsonPath, existing, { spaces: 2 });
|
|
319
|
+
result.success = true;
|
|
320
|
+
result.content = JSON.stringify(existing, null, 2);
|
|
321
|
+
return result;
|
|
322
|
+
} catch (error) {
|
|
323
|
+
result.warnings.push(`Error merging package.json: ${error}`);
|
|
324
|
+
return result;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
function appendGitignore(targetPath, entries) {
|
|
328
|
+
const gitignorePath = path.join(targetPath, ".gitignore");
|
|
329
|
+
const result = {
|
|
330
|
+
success: false,
|
|
331
|
+
warnings: [],
|
|
332
|
+
added: [],
|
|
333
|
+
skipped: []
|
|
334
|
+
};
|
|
335
|
+
try {
|
|
336
|
+
let existingContent = "";
|
|
337
|
+
if (fs.existsSync(gitignorePath)) {
|
|
338
|
+
existingContent = fs.readFileSync(gitignorePath, "utf-8");
|
|
339
|
+
}
|
|
340
|
+
const existingEntries = new Set(
|
|
341
|
+
existingContent.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#")).map((line) => line.replace(/\/$/, ""))
|
|
342
|
+
// Remove trailing slashes for comparison
|
|
343
|
+
);
|
|
344
|
+
const entriesToAdd = [];
|
|
345
|
+
for (const entry of entries) {
|
|
346
|
+
const normalizedEntry = entry.replace(/\/$/, "");
|
|
347
|
+
if (existingEntries.has(normalizedEntry)) {
|
|
348
|
+
result.skipped.push(entry);
|
|
349
|
+
} else {
|
|
350
|
+
entriesToAdd.push(entry);
|
|
351
|
+
result.added.push(entry);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
if (entriesToAdd.length > 0) {
|
|
355
|
+
let newContent = existingContent;
|
|
356
|
+
if (newContent && !newContent.endsWith("\n")) {
|
|
357
|
+
newContent += "\n";
|
|
358
|
+
}
|
|
359
|
+
if (newContent.trim()) {
|
|
360
|
+
newContent += "\n";
|
|
361
|
+
}
|
|
362
|
+
newContent += "# AgentMark\n";
|
|
363
|
+
newContent += entriesToAdd.join("\n");
|
|
364
|
+
newContent += "\n";
|
|
365
|
+
fs.writeFileSync(gitignorePath, newContent);
|
|
366
|
+
result.content = newContent;
|
|
367
|
+
}
|
|
368
|
+
result.success = true;
|
|
369
|
+
return result;
|
|
370
|
+
} catch (error) {
|
|
371
|
+
result.warnings.push(`Error appending to .gitignore: ${error}`);
|
|
372
|
+
return result;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
function appendEnv(targetPath, envVars) {
|
|
376
|
+
const envPath = path.join(targetPath, ".env");
|
|
377
|
+
const result = {
|
|
378
|
+
success: false,
|
|
379
|
+
warnings: [],
|
|
380
|
+
added: [],
|
|
381
|
+
skipped: []
|
|
382
|
+
};
|
|
383
|
+
try {
|
|
384
|
+
let existingContent = "";
|
|
385
|
+
if (fs.existsSync(envPath)) {
|
|
386
|
+
existingContent = fs.readFileSync(envPath, "utf-8");
|
|
387
|
+
}
|
|
388
|
+
const existingKeys = /* @__PURE__ */ new Set();
|
|
389
|
+
const lines = existingContent.split("\n");
|
|
390
|
+
for (const line of lines) {
|
|
391
|
+
const trimmed = line.trim();
|
|
392
|
+
if (trimmed && !trimmed.startsWith("#")) {
|
|
393
|
+
const match = trimmed.match(/^([^=]+)=/);
|
|
394
|
+
if (match && match[1]) {
|
|
395
|
+
existingKeys.add(match[1]);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
const varsToAdd = [];
|
|
400
|
+
for (const [key, value] of Object.entries(envVars)) {
|
|
401
|
+
if (existingKeys.has(key)) {
|
|
402
|
+
result.skipped.push(key);
|
|
403
|
+
} else {
|
|
404
|
+
varsToAdd.push([key, value]);
|
|
405
|
+
result.added.push(key);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
if (varsToAdd.length > 0) {
|
|
409
|
+
let newContent = existingContent;
|
|
410
|
+
if (newContent && !newContent.endsWith("\n")) {
|
|
411
|
+
newContent += "\n";
|
|
412
|
+
}
|
|
413
|
+
if (newContent.trim()) {
|
|
414
|
+
newContent += "\n";
|
|
415
|
+
}
|
|
416
|
+
newContent += "# AgentMark\n";
|
|
417
|
+
for (const [key, value] of varsToAdd) {
|
|
418
|
+
newContent += `${key}=${value}
|
|
419
|
+
`;
|
|
420
|
+
}
|
|
421
|
+
fs.writeFileSync(envPath, newContent);
|
|
422
|
+
result.content = newContent;
|
|
423
|
+
}
|
|
424
|
+
result.success = true;
|
|
425
|
+
return result;
|
|
426
|
+
} catch (error) {
|
|
427
|
+
result.warnings.push(`Error appending to .env: ${error}`);
|
|
428
|
+
return result;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// src/utils/types.ts
|
|
433
|
+
var PACKAGE_MANAGERS = {
|
|
434
|
+
"yarn.lock": {
|
|
435
|
+
name: "yarn",
|
|
436
|
+
lockFile: "yarn.lock",
|
|
437
|
+
installCmd: "yarn install",
|
|
438
|
+
addCmd: "yarn add",
|
|
439
|
+
addDevCmd: "yarn add --dev",
|
|
440
|
+
runCmd: "yarn"
|
|
441
|
+
},
|
|
442
|
+
"pnpm-lock.yaml": {
|
|
443
|
+
name: "pnpm",
|
|
444
|
+
lockFile: "pnpm-lock.yaml",
|
|
445
|
+
installCmd: "pnpm install",
|
|
446
|
+
addCmd: "pnpm add",
|
|
447
|
+
addDevCmd: "pnpm add --save-dev",
|
|
448
|
+
runCmd: "pnpm"
|
|
449
|
+
},
|
|
450
|
+
"bun.lockb": {
|
|
451
|
+
name: "bun",
|
|
452
|
+
lockFile: "bun.lockb",
|
|
453
|
+
installCmd: "bun install",
|
|
454
|
+
addCmd: "bun add",
|
|
455
|
+
addDevCmd: "bun add --dev",
|
|
456
|
+
runCmd: "bun run"
|
|
457
|
+
},
|
|
458
|
+
"package-lock.json": {
|
|
459
|
+
name: "npm",
|
|
460
|
+
lockFile: "package-lock.json",
|
|
461
|
+
installCmd: "npm install",
|
|
462
|
+
addCmd: "npm install",
|
|
463
|
+
addDevCmd: "npm install --save-dev",
|
|
464
|
+
runCmd: "npm run"
|
|
465
|
+
}
|
|
466
|
+
};
|
|
467
|
+
var DEFAULT_PACKAGE_MANAGER = PACKAGE_MANAGERS["package-lock.json"];
|
|
468
|
+
var CONFLICT_FILES = [
|
|
469
|
+
{ path: "agentmark.json", type: "config", strategy: "prompt" },
|
|
470
|
+
{ path: "agentmark", type: "directory", strategy: "prompt" },
|
|
471
|
+
{ path: "agentmark.client.ts", type: "source", strategy: "prompt" },
|
|
472
|
+
{ path: "agentmark_client.py", type: "source", strategy: "prompt" },
|
|
473
|
+
{ path: ".gitignore", type: "dotfile", strategy: "append" },
|
|
474
|
+
{ path: ".env", type: "dotfile", strategy: "append" },
|
|
475
|
+
{ path: "package.json", type: "config", strategy: "merge" },
|
|
476
|
+
{ path: "index.ts", type: "source", strategy: "skip" },
|
|
477
|
+
{ path: "main.py", type: "source", strategy: "skip" },
|
|
478
|
+
{ path: "tsconfig.json", type: "config", strategy: "skip" },
|
|
479
|
+
{ path: "pyproject.toml", type: "config", strategy: "skip" }
|
|
480
|
+
];
|
|
481
|
+
|
|
482
|
+
// src/utils/examples/templates/package-setup.ts
|
|
483
|
+
var setupPackageJson = (targetPath = ".", deploymentMode = "cloud", projectInfo = null) => {
|
|
177
484
|
const packageJsonPath = `${targetPath}/package.json`;
|
|
178
|
-
|
|
485
|
+
const isExistingProject = projectInfo?.isExistingProject ?? false;
|
|
486
|
+
if (!fs2.existsSync(packageJsonPath)) {
|
|
179
487
|
console.log("Creating package.json...");
|
|
180
488
|
execSync("npm init -y", { cwd: targetPath });
|
|
181
489
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
"
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
490
|
+
if (isExistingProject && fs2.existsSync(packageJsonPath)) {
|
|
491
|
+
const scriptsToAdd = {
|
|
492
|
+
"demo": "npx tsx index.ts",
|
|
493
|
+
"dev": "agentmark dev",
|
|
494
|
+
"prompt": "agentmark run-prompt",
|
|
495
|
+
"experiment": "agentmark run-experiment"
|
|
496
|
+
};
|
|
497
|
+
if (deploymentMode === "static") {
|
|
498
|
+
scriptsToAdd["build"] = "agentmark build --out dist/agentmark";
|
|
499
|
+
}
|
|
500
|
+
const result = mergePackageJson(targetPath, {}, {}, scriptsToAdd);
|
|
501
|
+
if (result.added.length > 0) {
|
|
502
|
+
console.log(`\u2705 Added to package.json: ${result.added.join(", ")}`);
|
|
503
|
+
}
|
|
504
|
+
if (result.skipped.length > 0) {
|
|
505
|
+
console.log(`\u23ED\uFE0F Skipped existing in package.json: ${result.skipped.join(", ")}`);
|
|
506
|
+
}
|
|
507
|
+
if (result.warnings.length > 0) {
|
|
508
|
+
result.warnings.forEach((w) => console.log(`\u26A0\uFE0F ${w}`));
|
|
509
|
+
}
|
|
510
|
+
} else {
|
|
511
|
+
const pkgJson = fs2.readJsonSync(packageJsonPath);
|
|
512
|
+
pkgJson.name = pkgJson.name === "test" || !pkgJson.name ? "agentmark-example-app" : pkgJson.name;
|
|
513
|
+
pkgJson.description = pkgJson.description || "A simple Node.js app using the Agentmark SDK";
|
|
514
|
+
const devScript = "agentmark dev";
|
|
515
|
+
const scripts = {
|
|
516
|
+
...pkgJson.scripts,
|
|
517
|
+
"demo": "npx tsx index.ts",
|
|
518
|
+
"dev": devScript,
|
|
519
|
+
"prompt": "agentmark run-prompt",
|
|
520
|
+
"experiment": "agentmark run-experiment"
|
|
521
|
+
};
|
|
522
|
+
if (deploymentMode === "static") {
|
|
523
|
+
scripts["build"] = "agentmark build --out dist/agentmark";
|
|
524
|
+
}
|
|
525
|
+
pkgJson.scripts = scripts;
|
|
526
|
+
pkgJson.overrides = {
|
|
527
|
+
...pkgJson.overrides,
|
|
528
|
+
"axios": "^1.7.9"
|
|
529
|
+
};
|
|
530
|
+
fs2.writeJsonSync(packageJsonPath, pkgJson, { spaces: 2 });
|
|
195
531
|
}
|
|
196
|
-
pkgJson.scripts = scripts;
|
|
197
|
-
pkgJson.overrides = {
|
|
198
|
-
...pkgJson.overrides,
|
|
199
|
-
"axios": "^1.7.9"
|
|
200
|
-
};
|
|
201
|
-
fs.writeJsonSync(packageJsonPath, pkgJson, { spaces: 2 });
|
|
202
532
|
};
|
|
203
|
-
var installDependencies = (modelProvider, targetPath = ".", adapter = "ai-sdk", deploymentMode = "cloud") => {
|
|
533
|
+
var installDependencies = (modelProvider, targetPath = ".", adapter = "ai-sdk", deploymentMode = "cloud", packageManager = null) => {
|
|
204
534
|
console.log("Installing required packages...");
|
|
205
535
|
console.log("This might take a moment...");
|
|
206
536
|
const adapterConfig = getAdapterConfig(adapter, modelProvider);
|
|
537
|
+
const pm = packageManager || DEFAULT_PACKAGE_MANAGER;
|
|
538
|
+
const npmSuffix = pm.name === "npm" ? " --legacy-peer-deps" : "";
|
|
207
539
|
try {
|
|
208
|
-
const
|
|
540
|
+
const devDeps = ["typescript", "ts-node", "@types/node", "@agentmark-ai/cli"];
|
|
541
|
+
const devDepsCmd = `${pm.addDevCmd} ${devDeps.join(" ")}${npmSuffix}`;
|
|
542
|
+
console.log(`Using ${pm.name} to install dependencies...`);
|
|
209
543
|
execSync(devDepsCmd, {
|
|
210
544
|
stdio: "inherit",
|
|
211
545
|
cwd: targetPath
|
|
212
546
|
});
|
|
213
547
|
const loaderPackages = deploymentMode === "static" ? ["@agentmark-ai/loader-api", "@agentmark-ai/loader-file"] : ["@agentmark-ai/loader-api"];
|
|
214
|
-
const
|
|
215
|
-
"install",
|
|
548
|
+
const deps = [
|
|
216
549
|
"dotenv",
|
|
217
550
|
"@agentmark-ai/prompt-core",
|
|
218
551
|
"@agentmark-ai/sdk",
|
|
219
552
|
adapterConfig.package,
|
|
220
553
|
...loaderPackages,
|
|
221
|
-
...adapterConfig.dependencies
|
|
222
|
-
"--legacy-peer-deps"
|
|
554
|
+
...adapterConfig.dependencies
|
|
223
555
|
];
|
|
224
|
-
|
|
556
|
+
const depsCmd = `${pm.addCmd} ${deps.join(" ")}${npmSuffix}`;
|
|
557
|
+
execSync(depsCmd, { stdio: "inherit", cwd: targetPath });
|
|
225
558
|
console.log("Packages installed successfully!");
|
|
226
559
|
} catch (error) {
|
|
227
560
|
console.error("Error installing packages:", error);
|
|
@@ -395,28 +728,32 @@ var getStoryDataset = () => {
|
|
|
395
728
|
};
|
|
396
729
|
|
|
397
730
|
// src/utils/examples/templates/example-prompts.ts
|
|
398
|
-
import
|
|
731
|
+
import fs3 from "fs-extra";
|
|
399
732
|
var createExamplePrompts = (model, targetPath = ".", adapter = "ai-sdk") => {
|
|
400
|
-
|
|
401
|
-
|
|
733
|
+
fs3.ensureDirSync(`${targetPath}/agentmark`);
|
|
734
|
+
const noImageSupport = ["mastra", "claude-agent-sdk"];
|
|
735
|
+
const noSpeechSupport = ["mastra", "claude-agent-sdk"];
|
|
736
|
+
const skipImagePrompts = noImageSupport.includes(adapter);
|
|
737
|
+
const skipSpeechPrompts = noSpeechSupport.includes(adapter);
|
|
738
|
+
if (!skipImagePrompts) {
|
|
402
739
|
const animalDrawingPrompt = getAnimalDrawingPrompt();
|
|
403
|
-
|
|
740
|
+
fs3.writeFileSync(`${targetPath}/agentmark/animal-drawing.prompt.mdx`, animalDrawingPrompt);
|
|
404
741
|
const animalDataset = getAnimalDataset();
|
|
405
|
-
|
|
742
|
+
fs3.writeFileSync(`${targetPath}/agentmark/animal.jsonl`, animalDataset);
|
|
406
743
|
}
|
|
407
744
|
const customerSupportPrompt = getCustomerSupportPrompt(model);
|
|
408
|
-
|
|
745
|
+
fs3.writeFileSync(`${targetPath}/agentmark/customer-support-agent.prompt.mdx`, customerSupportPrompt);
|
|
409
746
|
const customerQueryDataset = getCustomerQueryDataset();
|
|
410
|
-
|
|
747
|
+
fs3.writeFileSync(`${targetPath}/agentmark/customer-query.jsonl`, customerQueryDataset);
|
|
411
748
|
const partyPlannerPrompt = getPartyPlannerPrompt(model);
|
|
412
|
-
|
|
749
|
+
fs3.writeFileSync(`${targetPath}/agentmark/party-planner.prompt.mdx`, partyPlannerPrompt);
|
|
413
750
|
const partyDataset = getPartyDataset();
|
|
414
|
-
|
|
415
|
-
if (
|
|
751
|
+
fs3.writeFileSync(`${targetPath}/agentmark/party.jsonl`, partyDataset);
|
|
752
|
+
if (!skipSpeechPrompts) {
|
|
416
753
|
const storyTellerPrompt = getStoryTellerPrompt();
|
|
417
|
-
|
|
754
|
+
fs3.writeFileSync(`${targetPath}/agentmark/story-teller.prompt.mdx`, storyTellerPrompt);
|
|
418
755
|
const storyDataset = getStoryDataset();
|
|
419
|
-
|
|
756
|
+
fs3.writeFileSync(`${targetPath}/agentmark/story.jsonl`, storyDataset);
|
|
420
757
|
}
|
|
421
758
|
};
|
|
422
759
|
|
|
@@ -425,8 +762,9 @@ var getClientConfigContent = (options) => {
|
|
|
425
762
|
const { provider, languageModels, adapter, deploymentMode = "cloud" } = options;
|
|
426
763
|
const adapterConfig = getAdapterConfig(adapter, provider);
|
|
427
764
|
const { modelRegistry, toolRegistry } = adapterConfig.classes;
|
|
428
|
-
const
|
|
429
|
-
const
|
|
765
|
+
const isClaudeAgentSdk = adapter === "claude-agent-sdk";
|
|
766
|
+
const providerImport = isClaudeAgentSdk ? "" : `import { ${provider} } from '@ai-sdk/${provider}';`;
|
|
767
|
+
const extraModelRegs = provider === "openai" && !isClaudeAgentSdk ? `.registerModels(["dall-e-3"], (name: string) => ${provider}.image(name))
|
|
430
768
|
.registerModels(["tts-1-hd"], (name: string) => ${provider}.speech(name))` : "";
|
|
431
769
|
const loaderImport = deploymentMode === "cloud" ? `import { ApiLoader } from "@agentmark-ai/loader-api";` : `import { ApiLoader } from "@agentmark-ai/loader-api";
|
|
432
770
|
import { FileLoader } from "@agentmark-ai/loader-file";`;
|
|
@@ -441,6 +779,51 @@ import { FileLoader } from "@agentmark-ai/loader-file";`;
|
|
|
441
779
|
});` : ` const loader = process.env.NODE_ENV === 'development'
|
|
442
780
|
? ApiLoader.local({ baseUrl: process.env.AGENTMARK_BASE_URL || 'http://localhost:9418' })
|
|
443
781
|
: new FileLoader('./dist/agentmark');`;
|
|
782
|
+
const modelRegistrySetup = isClaudeAgentSdk ? `function createModelRegistry() {
|
|
783
|
+
// Claude Agent SDK accepts model names directly.
|
|
784
|
+
// Use createDefault() for simple pass-through of model names.
|
|
785
|
+
const modelRegistry = ${modelRegistry}.createDefault();
|
|
786
|
+
|
|
787
|
+
// To configure specific models (e.g., extended thinking), use:
|
|
788
|
+
// const modelRegistry = new ${modelRegistry}()
|
|
789
|
+
// .registerModels(/claude-.*-thinking/, (name) => ({
|
|
790
|
+
// model: name,
|
|
791
|
+
// maxThinkingTokens: 10000, // Enable extended thinking
|
|
792
|
+
// }))
|
|
793
|
+
// .registerModels("claude-sonnet-4-20250514", (name) => ({ model: name }));
|
|
794
|
+
|
|
795
|
+
return modelRegistry;
|
|
796
|
+
}` : `function createModelRegistry() {
|
|
797
|
+
const modelRegistry = new ${modelRegistry}()
|
|
798
|
+
.registerModels(${JSON.stringify(languageModels)}, (name: string) => ${provider}(name))
|
|
799
|
+
${extraModelRegs};
|
|
800
|
+
return modelRegistry;
|
|
801
|
+
}`;
|
|
802
|
+
const adapterOptionsImport = isClaudeAgentSdk ? `
|
|
803
|
+
// Claude Agent SDK adapter options
|
|
804
|
+
// See: https://github.com/anthropics/claude-agent-sdk
|
|
805
|
+
const adapterOptions = {
|
|
806
|
+
// Permission mode controls tool access:
|
|
807
|
+
// - 'default': Requires user approval for each tool use
|
|
808
|
+
// - 'acceptEdits': Auto-approve file edits only
|
|
809
|
+
// - 'bypassPermissions': Auto-approve all tools (use for automated pipelines)
|
|
810
|
+
// - 'plan': Planning mode only, no tool execution
|
|
811
|
+
permissionMode: 'bypassPermissions' as const,
|
|
812
|
+
|
|
813
|
+
// Maximum conversation turns before stopping
|
|
814
|
+
maxTurns: 20,
|
|
815
|
+
|
|
816
|
+
// Optional: Set working directory for file operations
|
|
817
|
+
// cwd: process.cwd(),
|
|
818
|
+
|
|
819
|
+
// Optional: Budget limit in USD
|
|
820
|
+
// maxBudgetUsd: 10.00,
|
|
821
|
+
|
|
822
|
+
// Optional: Restrict which tools the agent can use
|
|
823
|
+
// allowedTools: ['Read', 'Write', 'Glob'],
|
|
824
|
+
// disallowedTools: ['Bash'],
|
|
825
|
+
};` : "";
|
|
826
|
+
const createClientCall = isClaudeAgentSdk ? `return createAgentMarkClient<AgentMarkTypes, typeof toolRegistry>({ loader, modelRegistry, toolRegistry, evalRegistry, adapterOptions });` : `return createAgentMarkClient<AgentMarkTypes, typeof toolRegistry>({ loader, modelRegistry, toolRegistry, evalRegistry });`;
|
|
444
827
|
return `// agentmark.client.ts
|
|
445
828
|
import path from 'node:path';
|
|
446
829
|
import dotenv from 'dotenv';
|
|
@@ -449,13 +832,9 @@ import { createAgentMarkClient, ${modelRegistry}, ${toolRegistry}, EvalRegistry
|
|
|
449
832
|
${loaderImport}
|
|
450
833
|
import AgentMarkTypes, { Tools } from './agentmark.types';
|
|
451
834
|
${providerImport}
|
|
835
|
+
${adapterOptionsImport}
|
|
452
836
|
|
|
453
|
-
|
|
454
|
-
const modelRegistry = new ${modelRegistry}()
|
|
455
|
-
.registerModels(${JSON.stringify(languageModels)}, (name: string) => ${provider}(name))
|
|
456
|
-
${extraModelRegs};
|
|
457
|
-
return modelRegistry;
|
|
458
|
-
}
|
|
837
|
+
${modelRegistrySetup}
|
|
459
838
|
|
|
460
839
|
function createToolRegistry() {
|
|
461
840
|
const toolRegistry = new ${toolRegistry}<Tools>()
|
|
@@ -502,7 +881,7 @@ ${loaderSetup}
|
|
|
502
881
|
const modelRegistry = createModelRegistry();
|
|
503
882
|
const toolRegistry = createToolRegistry();
|
|
504
883
|
const evalRegistry = createEvalRegistry();
|
|
505
|
-
|
|
884
|
+
${createClientCall}
|
|
506
885
|
}
|
|
507
886
|
|
|
508
887
|
export const client = createClient();
|
|
@@ -511,6 +890,99 @@ export const client = createClient();
|
|
|
511
890
|
|
|
512
891
|
// src/utils/examples/create-example-app.ts
|
|
513
892
|
import { fetchPromptsFrontmatter, generateTypeDefinitions } from "@agentmark-ai/shared-utils";
|
|
893
|
+
|
|
894
|
+
// src/utils/conflict-resolution.ts
|
|
895
|
+
import prompts from "prompts";
|
|
896
|
+
function getPromptableConflicts(conflictingFiles) {
|
|
897
|
+
return conflictingFiles.filter((file) => file.strategy === "prompt");
|
|
898
|
+
}
|
|
899
|
+
async function promptForSingleConflict(conflict) {
|
|
900
|
+
const typeLabel = conflict.type === "directory" ? "directory" : "file";
|
|
901
|
+
const { action } = await prompts({
|
|
902
|
+
type: "select",
|
|
903
|
+
name: "action",
|
|
904
|
+
message: `${conflict.path} already exists. What would you like to do?`,
|
|
905
|
+
choices: [
|
|
906
|
+
{
|
|
907
|
+
title: `Skip (keep existing ${typeLabel})`,
|
|
908
|
+
value: "skip",
|
|
909
|
+
description: `Don't modify the existing ${typeLabel}`
|
|
910
|
+
},
|
|
911
|
+
{
|
|
912
|
+
title: "Overwrite",
|
|
913
|
+
value: "overwrite",
|
|
914
|
+
description: `Replace with new AgentMark ${typeLabel}`
|
|
915
|
+
}
|
|
916
|
+
],
|
|
917
|
+
initial: 0
|
|
918
|
+
// Default to skip for safety
|
|
919
|
+
});
|
|
920
|
+
return {
|
|
921
|
+
path: conflict.path,
|
|
922
|
+
action: action || "skip"
|
|
923
|
+
};
|
|
924
|
+
}
|
|
925
|
+
async function promptForResolutions(conflictingFiles) {
|
|
926
|
+
const promptableConflicts = getPromptableConflicts(conflictingFiles);
|
|
927
|
+
if (promptableConflicts.length === 0) {
|
|
928
|
+
return [];
|
|
929
|
+
}
|
|
930
|
+
console.log("\n\u26A0\uFE0F Found existing files that may conflict with AgentMark initialization:\n");
|
|
931
|
+
const resolutions = [];
|
|
932
|
+
for (const conflict of promptableConflicts) {
|
|
933
|
+
const resolution = await promptForSingleConflict(conflict);
|
|
934
|
+
resolutions.push(resolution);
|
|
935
|
+
}
|
|
936
|
+
console.log("");
|
|
937
|
+
return resolutions;
|
|
938
|
+
}
|
|
939
|
+
function getResolutionAction(filePath, resolutions, conflictingFiles) {
|
|
940
|
+
const userResolution = resolutions.find((r) => r.path === filePath);
|
|
941
|
+
if (userResolution) {
|
|
942
|
+
return userResolution.action;
|
|
943
|
+
}
|
|
944
|
+
const conflictFile = conflictingFiles.find((f) => f.path === filePath);
|
|
945
|
+
if (conflictFile) {
|
|
946
|
+
switch (conflictFile.strategy) {
|
|
947
|
+
case "skip":
|
|
948
|
+
return "skip";
|
|
949
|
+
case "merge":
|
|
950
|
+
return "merge";
|
|
951
|
+
case "append":
|
|
952
|
+
return "merge";
|
|
953
|
+
// Append is a form of merge
|
|
954
|
+
case "prompt":
|
|
955
|
+
return "skip";
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
return "overwrite";
|
|
959
|
+
}
|
|
960
|
+
function shouldMergeFile(filePath, projectInfo, resolutions) {
|
|
961
|
+
if (!projectInfo || !projectInfo.isExistingProject) {
|
|
962
|
+
return false;
|
|
963
|
+
}
|
|
964
|
+
const action = getResolutionAction(filePath, resolutions, projectInfo.conflictingFiles);
|
|
965
|
+
return action === "merge";
|
|
966
|
+
}
|
|
967
|
+
function displayProjectDetectionSummary(projectInfo) {
|
|
968
|
+
if (!projectInfo.isExistingProject) {
|
|
969
|
+
return;
|
|
970
|
+
}
|
|
971
|
+
console.log("\n\u{1F4C1} Detected existing project:");
|
|
972
|
+
console.log(` Type: ${projectInfo.type}`);
|
|
973
|
+
if (projectInfo.type === "typescript") {
|
|
974
|
+
console.log(` Package Manager: ${projectInfo.packageManager.name}`);
|
|
975
|
+
}
|
|
976
|
+
if (projectInfo.pythonVenv) {
|
|
977
|
+
console.log(` Python Venv: ${projectInfo.pythonVenv.name}`);
|
|
978
|
+
}
|
|
979
|
+
if (projectInfo.hasAgentmarkDir) {
|
|
980
|
+
console.log(" \u26A0\uFE0F AgentMark directory already exists");
|
|
981
|
+
}
|
|
982
|
+
console.log("");
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
// src/utils/examples/create-example-app.ts
|
|
514
986
|
var setupMCPServer = (client, targetPath) => {
|
|
515
987
|
if (client === "skip") {
|
|
516
988
|
console.log("Skipping MCP server setup.");
|
|
@@ -520,16 +992,23 @@ var setupMCPServer = (client, targetPath) => {
|
|
|
520
992
|
if (client === "vscode") {
|
|
521
993
|
try {
|
|
522
994
|
console.log(`Setting up MCP server for VS Code in ${folderName}...`);
|
|
523
|
-
const vscodeDir =
|
|
524
|
-
|
|
995
|
+
const vscodeDir = path2.join(targetPath, ".vscode");
|
|
996
|
+
fs4.ensureDirSync(vscodeDir);
|
|
525
997
|
const mcpConfig = {
|
|
526
998
|
servers: {
|
|
527
999
|
"agentmark-docs": {
|
|
528
1000
|
url: "https://docs.agentmark.co/mcp"
|
|
1001
|
+
},
|
|
1002
|
+
"agentmark-traces": {
|
|
1003
|
+
command: "npx",
|
|
1004
|
+
args: ["@agentmark-ai/mcp-server"],
|
|
1005
|
+
env: {
|
|
1006
|
+
AGENTMARK_URL: "http://localhost:9418"
|
|
1007
|
+
}
|
|
529
1008
|
}
|
|
530
1009
|
}
|
|
531
1010
|
};
|
|
532
|
-
|
|
1011
|
+
fs4.writeJsonSync(path2.join(vscodeDir, "mcp.json"), mcpConfig, { spaces: 2 });
|
|
533
1012
|
console.log(`\u2705 MCP server configured for VS Code in ${folderName}/.vscode/mcp.json`);
|
|
534
1013
|
} catch (error) {
|
|
535
1014
|
console.warn(`Warning: Could not set up MCP server for VS Code:`, error);
|
|
@@ -540,16 +1019,23 @@ var setupMCPServer = (client, targetPath) => {
|
|
|
540
1019
|
if (client === "zed") {
|
|
541
1020
|
try {
|
|
542
1021
|
console.log(`Setting up MCP server for Zed in ${folderName}...`);
|
|
543
|
-
const zedDir =
|
|
544
|
-
|
|
1022
|
+
const zedDir = path2.join(targetPath, ".zed");
|
|
1023
|
+
fs4.ensureDirSync(zedDir);
|
|
545
1024
|
const zedConfig = {
|
|
546
1025
|
context_servers: {
|
|
547
1026
|
"agentmark-docs": {
|
|
548
1027
|
url: "https://docs.agentmark.co/mcp"
|
|
1028
|
+
},
|
|
1029
|
+
"agentmark-traces": {
|
|
1030
|
+
command: "npx",
|
|
1031
|
+
args: ["@agentmark-ai/mcp-server"],
|
|
1032
|
+
env: {
|
|
1033
|
+
AGENTMARK_URL: "http://localhost:9418"
|
|
1034
|
+
}
|
|
549
1035
|
}
|
|
550
1036
|
}
|
|
551
1037
|
};
|
|
552
|
-
|
|
1038
|
+
fs4.writeJsonSync(path2.join(zedDir, "settings.json"), zedConfig, { spaces: 2 });
|
|
553
1039
|
console.log(`\u2705 MCP server configured for Zed in ${folderName}/.zed/settings.json`);
|
|
554
1040
|
} catch (error) {
|
|
555
1041
|
console.warn(`Warning: Could not set up MCP server for Zed:`, error);
|
|
@@ -560,16 +1046,23 @@ var setupMCPServer = (client, targetPath) => {
|
|
|
560
1046
|
if (client === "cursor") {
|
|
561
1047
|
try {
|
|
562
1048
|
console.log(`Setting up MCP server for Cursor in ${folderName}...`);
|
|
563
|
-
const cursorDir =
|
|
564
|
-
|
|
1049
|
+
const cursorDir = path2.join(targetPath, ".cursor");
|
|
1050
|
+
fs4.ensureDirSync(cursorDir);
|
|
565
1051
|
const cursorConfig = {
|
|
566
1052
|
mcpServers: {
|
|
567
1053
|
"agentmark-docs": {
|
|
568
1054
|
url: "https://docs.agentmark.co/mcp"
|
|
1055
|
+
},
|
|
1056
|
+
"agentmark-traces": {
|
|
1057
|
+
command: "npx",
|
|
1058
|
+
args: ["@agentmark-ai/mcp-server"],
|
|
1059
|
+
env: {
|
|
1060
|
+
AGENTMARK_URL: "http://localhost:9418"
|
|
1061
|
+
}
|
|
569
1062
|
}
|
|
570
1063
|
}
|
|
571
1064
|
};
|
|
572
|
-
|
|
1065
|
+
fs4.writeJsonSync(path2.join(cursorDir, "mcp.json"), cursorConfig, { spaces: 2 });
|
|
573
1066
|
console.log(`\u2705 MCP server configured for Cursor in ${folderName}/.cursor/mcp.json`);
|
|
574
1067
|
} catch (error) {
|
|
575
1068
|
console.warn(`Warning: Could not set up MCP server for Cursor:`, error);
|
|
@@ -585,10 +1078,17 @@ var setupMCPServer = (client, targetPath) => {
|
|
|
585
1078
|
"agentmark-docs": {
|
|
586
1079
|
type: "http",
|
|
587
1080
|
url: "https://docs.agentmark.co/mcp"
|
|
1081
|
+
},
|
|
1082
|
+
"agentmark-traces": {
|
|
1083
|
+
command: "npx",
|
|
1084
|
+
args: ["@agentmark-ai/mcp-server"],
|
|
1085
|
+
env: {
|
|
1086
|
+
AGENTMARK_URL: "http://localhost:9418"
|
|
1087
|
+
}
|
|
588
1088
|
}
|
|
589
1089
|
}
|
|
590
1090
|
};
|
|
591
|
-
|
|
1091
|
+
fs4.writeJsonSync(path2.join(targetPath, ".mcp.json"), mcpConfig, { spaces: 2 });
|
|
592
1092
|
console.log(`\u2705 MCP server configured for Claude Code in ${folderName}/.mcp.json`);
|
|
593
1093
|
} catch (error) {
|
|
594
1094
|
console.warn(`Warning: Could not set up MCP server for Claude Code:`, error);
|
|
@@ -597,48 +1097,90 @@ var setupMCPServer = (client, targetPath) => {
|
|
|
597
1097
|
return;
|
|
598
1098
|
}
|
|
599
1099
|
};
|
|
600
|
-
var createExampleApp = async (client, targetPath = ".", apiKey = "", adapter = "ai-sdk", deploymentMode = "cloud") => {
|
|
1100
|
+
var createExampleApp = async (client, targetPath = ".", apiKey = "", adapter = "ai-sdk", deploymentMode = "cloud", projectInfo = null, resolutions = []) => {
|
|
601
1101
|
try {
|
|
602
|
-
const modelProvider = "openai";
|
|
603
|
-
const model = "gpt-4o";
|
|
604
|
-
|
|
1102
|
+
const modelProvider = adapter === "claude-agent-sdk" ? "anthropic" : "openai";
|
|
1103
|
+
const model = adapter === "claude-agent-sdk" ? "claude-sonnet-4-20250514" : "gpt-4o";
|
|
1104
|
+
const isExistingProject = projectInfo?.isExistingProject ?? false;
|
|
1105
|
+
if (isExistingProject) {
|
|
1106
|
+
console.log("Adding AgentMark to existing project...");
|
|
1107
|
+
} else {
|
|
1108
|
+
console.log("Creating AgentMark example app...");
|
|
1109
|
+
}
|
|
605
1110
|
const folderName = targetPath;
|
|
606
|
-
|
|
1111
|
+
fs4.ensureDirSync(`${targetPath}/agentmark`);
|
|
607
1112
|
setupMCPServer(client, targetPath);
|
|
608
1113
|
createExamplePrompts(model, targetPath, adapter);
|
|
609
1114
|
console.log(`\u2705 Example prompts and datasets created in ${folderName}/agentmark/`);
|
|
610
1115
|
const langModels = Providers[modelProvider].languageModels.slice(0, 1);
|
|
611
|
-
|
|
1116
|
+
fs4.writeFileSync(
|
|
612
1117
|
`${targetPath}/agentmark.client.ts`,
|
|
613
1118
|
getClientConfigContent({ provider: modelProvider, languageModels: langModels, adapter, deploymentMode })
|
|
614
1119
|
);
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
1120
|
+
if (shouldMergeFile(".env", projectInfo, resolutions)) {
|
|
1121
|
+
const envVars = {};
|
|
1122
|
+
const apiKeyEnvVar = adapter === "claude-agent-sdk" ? "ANTHROPIC_API_KEY" : "OPENAI_API_KEY";
|
|
1123
|
+
if (apiKey) {
|
|
1124
|
+
envVars[apiKeyEnvVar] = apiKey;
|
|
1125
|
+
} else {
|
|
1126
|
+
envVars[apiKeyEnvVar] = adapter === "claude-agent-sdk" ? "your-anthropic-api-key" : "your-openai-api-key";
|
|
1127
|
+
}
|
|
1128
|
+
const result = appendEnv(targetPath, envVars);
|
|
1129
|
+
if (result.added.length > 0) {
|
|
1130
|
+
console.log(`\u2705 Added to .env: ${result.added.join(", ")}`);
|
|
1131
|
+
}
|
|
1132
|
+
if (result.skipped.length > 0) {
|
|
1133
|
+
console.log(`\u23ED\uFE0F Skipped existing .env vars: ${result.skipped.join(", ")}`);
|
|
1134
|
+
}
|
|
1135
|
+
} else {
|
|
1136
|
+
fs4.writeFileSync(`${targetPath}/.env`, getEnvFileContent(modelProvider, apiKey, adapter));
|
|
1137
|
+
}
|
|
1138
|
+
const gitignoreEntries = ["node_modules/", ".env", "*.agentmark-outputs/", ".agentmark/", "dist/"];
|
|
1139
|
+
if (shouldMergeFile(".gitignore", projectInfo, resolutions)) {
|
|
1140
|
+
const result = appendGitignore(targetPath, gitignoreEntries);
|
|
1141
|
+
if (result.added.length > 0) {
|
|
1142
|
+
console.log(`\u2705 Added to .gitignore: ${result.added.join(", ")}`);
|
|
1143
|
+
}
|
|
1144
|
+
if (result.skipped.length > 0) {
|
|
1145
|
+
console.log(`\u23ED\uFE0F Already in .gitignore: ${result.skipped.join(", ")}`);
|
|
1146
|
+
}
|
|
1147
|
+
} else {
|
|
1148
|
+
const gitignore = gitignoreEntries.join("\n");
|
|
1149
|
+
fs4.writeFileSync(`${targetPath}/.gitignore`, gitignore);
|
|
1150
|
+
}
|
|
1151
|
+
if (!isExistingProject) {
|
|
1152
|
+
fs4.writeFileSync(
|
|
1153
|
+
`${targetPath}/index.ts`,
|
|
1154
|
+
getIndexFileContent(adapter)
|
|
1155
|
+
);
|
|
1156
|
+
} else {
|
|
1157
|
+
console.log("\u23ED\uFE0F Skipped index.ts (existing project)");
|
|
1158
|
+
}
|
|
1159
|
+
if (!isExistingProject) {
|
|
1160
|
+
fs4.writeJsonSync(`${targetPath}/tsconfig.json`, getTsConfigContent(), { spaces: 2 });
|
|
1161
|
+
} else {
|
|
1162
|
+
console.log("\u23ED\uFE0F Skipped tsconfig.json (existing project)");
|
|
1163
|
+
}
|
|
1164
|
+
const packageManager = projectInfo?.packageManager ?? null;
|
|
1165
|
+
setupPackageJson(targetPath, deploymentMode, projectInfo);
|
|
1166
|
+
installDependencies(modelProvider, targetPath, adapter, deploymentMode, packageManager);
|
|
625
1167
|
console.log("Generating types from prompts...");
|
|
626
1168
|
try {
|
|
627
|
-
const agentmarkDir =
|
|
628
|
-
const
|
|
629
|
-
const typeDefinitions = await generateTypeDefinitions(
|
|
630
|
-
|
|
1169
|
+
const agentmarkDir = path2.join(targetPath, "agentmark");
|
|
1170
|
+
const prompts3 = await fetchPromptsFrontmatter({ rootDir: agentmarkDir });
|
|
1171
|
+
const typeDefinitions = await generateTypeDefinitions(prompts3);
|
|
1172
|
+
fs4.writeFileSync(`${targetPath}/agentmark.types.ts`, typeDefinitions);
|
|
631
1173
|
} catch (error) {
|
|
632
1174
|
console.warn("Warning: Could not generate types automatically:", error);
|
|
633
1175
|
console.log("You can generate types later by running: npx agentmark generate-types --root-dir agentmark");
|
|
634
|
-
|
|
1176
|
+
fs4.writeFileSync(`${targetPath}/agentmark.types.ts`, `// Auto-generated types from AgentMark
|
|
635
1177
|
// Run 'npx agentmark generate-types --root-dir agentmark' to generate types
|
|
636
1178
|
export default interface AgentmarkTypes {}
|
|
637
1179
|
`);
|
|
638
1180
|
}
|
|
639
1181
|
console.log("Creating development server entry point...");
|
|
640
|
-
const agentmarkInternalDir =
|
|
641
|
-
|
|
1182
|
+
const agentmarkInternalDir = path2.join(targetPath, ".agentmark");
|
|
1183
|
+
fs4.ensureDirSync(agentmarkInternalDir);
|
|
642
1184
|
const adapterConfig = getAdapterConfig(adapter, modelProvider);
|
|
643
1185
|
const { webhookHandler } = adapterConfig.classes;
|
|
644
1186
|
const devEntryContent = `// Auto-generated webhook server entry point
|
|
@@ -689,7 +1231,7 @@ main().catch((err) => {
|
|
|
689
1231
|
process.exit(1);
|
|
690
1232
|
});
|
|
691
1233
|
`;
|
|
692
|
-
|
|
1234
|
+
fs4.writeFileSync(path2.join(agentmarkInternalDir, "dev-entry.ts"), devEntryContent);
|
|
693
1235
|
console.log("\n\u2705 Agentmark initialization completed successfully!");
|
|
694
1236
|
console.log(
|
|
695
1237
|
`
|
|
@@ -705,11 +1247,21 @@ main().catch((err) => {
|
|
|
705
1247
|
console.log("\n" + "\u2550".repeat(70));
|
|
706
1248
|
console.log("Next Steps");
|
|
707
1249
|
console.log("\u2550".repeat(70));
|
|
1250
|
+
const runCmd = packageManager?.runCmd ?? "npm run";
|
|
1251
|
+
const pkgJsonPath = path2.join(targetPath, "package.json");
|
|
1252
|
+
let devScriptName = "dev";
|
|
1253
|
+
if (fs4.existsSync(pkgJsonPath)) {
|
|
1254
|
+
const pkgJson = fs4.readJsonSync(pkgJsonPath);
|
|
1255
|
+
if (pkgJson.scripts?.["agentmark:dev"]) {
|
|
1256
|
+
devScriptName = "agentmark:dev";
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
708
1259
|
console.log("\n Get Started:");
|
|
709
|
-
if (folderName !== "." && folderName !== "./") {
|
|
1260
|
+
if (folderName !== "." && folderName !== "./" && !isExistingProject) {
|
|
710
1261
|
console.log(` $ cd ${folderName}`);
|
|
711
1262
|
}
|
|
712
|
-
console.log(
|
|
1263
|
+
console.log(` $ ${runCmd} ${devScriptName}
|
|
1264
|
+
`);
|
|
713
1265
|
console.log("\u2500".repeat(70));
|
|
714
1266
|
console.log("Resources");
|
|
715
1267
|
console.log("\u2500".repeat(70));
|
|
@@ -722,8 +1274,8 @@ main().catch((err) => {
|
|
|
722
1274
|
};
|
|
723
1275
|
|
|
724
1276
|
// src/utils/examples/create-python-app.ts
|
|
725
|
-
import
|
|
726
|
-
import * as
|
|
1277
|
+
import fs5 from "fs-extra";
|
|
1278
|
+
import * as path3 from "path";
|
|
727
1279
|
var setupMCPServer2 = (client, targetPath) => {
|
|
728
1280
|
if (client === "skip") {
|
|
729
1281
|
console.log("Skipping MCP server setup.");
|
|
@@ -733,16 +1285,23 @@ var setupMCPServer2 = (client, targetPath) => {
|
|
|
733
1285
|
if (client === "vscode") {
|
|
734
1286
|
try {
|
|
735
1287
|
console.log(`Setting up MCP server for VS Code in ${folderName}...`);
|
|
736
|
-
const vscodeDir =
|
|
737
|
-
|
|
1288
|
+
const vscodeDir = path3.join(targetPath, ".vscode");
|
|
1289
|
+
fs5.ensureDirSync(vscodeDir);
|
|
738
1290
|
const mcpConfig = {
|
|
739
1291
|
servers: {
|
|
740
1292
|
"agentmark-docs": {
|
|
741
1293
|
url: "https://docs.agentmark.co/mcp"
|
|
1294
|
+
},
|
|
1295
|
+
"agentmark-traces": {
|
|
1296
|
+
command: "npx",
|
|
1297
|
+
args: ["@agentmark-ai/mcp-server"],
|
|
1298
|
+
env: {
|
|
1299
|
+
AGENTMARK_URL: "http://localhost:9418"
|
|
1300
|
+
}
|
|
742
1301
|
}
|
|
743
1302
|
}
|
|
744
1303
|
};
|
|
745
|
-
|
|
1304
|
+
fs5.writeJsonSync(path3.join(vscodeDir, "mcp.json"), mcpConfig, { spaces: 2 });
|
|
746
1305
|
console.log(`MCP server configured for VS Code in ${folderName}/.vscode/mcp.json`);
|
|
747
1306
|
} catch (error) {
|
|
748
1307
|
console.warn(`Warning: Could not set up MCP server for VS Code:`, error);
|
|
@@ -752,16 +1311,23 @@ var setupMCPServer2 = (client, targetPath) => {
|
|
|
752
1311
|
if (client === "zed") {
|
|
753
1312
|
try {
|
|
754
1313
|
console.log(`Setting up MCP server for Zed in ${folderName}...`);
|
|
755
|
-
const zedDir =
|
|
756
|
-
|
|
1314
|
+
const zedDir = path3.join(targetPath, ".zed");
|
|
1315
|
+
fs5.ensureDirSync(zedDir);
|
|
757
1316
|
const zedConfig = {
|
|
758
1317
|
context_servers: {
|
|
759
1318
|
"agentmark-docs": {
|
|
760
1319
|
url: "https://docs.agentmark.co/mcp"
|
|
1320
|
+
},
|
|
1321
|
+
"agentmark-traces": {
|
|
1322
|
+
command: "npx",
|
|
1323
|
+
args: ["@agentmark-ai/mcp-server"],
|
|
1324
|
+
env: {
|
|
1325
|
+
AGENTMARK_URL: "http://localhost:9418"
|
|
1326
|
+
}
|
|
761
1327
|
}
|
|
762
1328
|
}
|
|
763
1329
|
};
|
|
764
|
-
|
|
1330
|
+
fs5.writeJsonSync(path3.join(zedDir, "settings.json"), zedConfig, { spaces: 2 });
|
|
765
1331
|
console.log(`MCP server configured for Zed in ${folderName}/.zed/settings.json`);
|
|
766
1332
|
} catch (error) {
|
|
767
1333
|
console.warn(`Warning: Could not set up MCP server for Zed:`, error);
|
|
@@ -771,16 +1337,23 @@ var setupMCPServer2 = (client, targetPath) => {
|
|
|
771
1337
|
if (client === "cursor") {
|
|
772
1338
|
try {
|
|
773
1339
|
console.log(`Setting up MCP server for Cursor in ${folderName}...`);
|
|
774
|
-
const cursorDir =
|
|
775
|
-
|
|
1340
|
+
const cursorDir = path3.join(targetPath, ".cursor");
|
|
1341
|
+
fs5.ensureDirSync(cursorDir);
|
|
776
1342
|
const cursorConfig = {
|
|
777
1343
|
mcpServers: {
|
|
778
1344
|
"agentmark-docs": {
|
|
779
1345
|
url: "https://docs.agentmark.co/mcp"
|
|
1346
|
+
},
|
|
1347
|
+
"agentmark-traces": {
|
|
1348
|
+
command: "npx",
|
|
1349
|
+
args: ["@agentmark-ai/mcp-server"],
|
|
1350
|
+
env: {
|
|
1351
|
+
AGENTMARK_URL: "http://localhost:9418"
|
|
1352
|
+
}
|
|
780
1353
|
}
|
|
781
1354
|
}
|
|
782
1355
|
};
|
|
783
|
-
|
|
1356
|
+
fs5.writeJsonSync(path3.join(cursorDir, "mcp.json"), cursorConfig, { spaces: 2 });
|
|
784
1357
|
console.log(`MCP server configured for Cursor in ${folderName}/.cursor/mcp.json`);
|
|
785
1358
|
} catch (error) {
|
|
786
1359
|
console.warn(`Warning: Could not set up MCP server for Cursor:`, error);
|
|
@@ -795,10 +1368,17 @@ var setupMCPServer2 = (client, targetPath) => {
|
|
|
795
1368
|
"agentmark-docs": {
|
|
796
1369
|
type: "http",
|
|
797
1370
|
url: "https://docs.agentmark.co/mcp"
|
|
1371
|
+
},
|
|
1372
|
+
"agentmark-traces": {
|
|
1373
|
+
command: "npx",
|
|
1374
|
+
args: ["@agentmark-ai/mcp-server"],
|
|
1375
|
+
env: {
|
|
1376
|
+
AGENTMARK_URL: "http://localhost:9418"
|
|
1377
|
+
}
|
|
798
1378
|
}
|
|
799
1379
|
}
|
|
800
1380
|
};
|
|
801
|
-
|
|
1381
|
+
fs5.writeJsonSync(path3.join(targetPath, ".mcp.json"), mcpConfig, { spaces: 2 });
|
|
802
1382
|
console.log(`MCP server configured for Claude Code in ${folderName}/.mcp.json`);
|
|
803
1383
|
} catch (error) {
|
|
804
1384
|
console.warn(`Warning: Could not set up MCP server for Claude Code:`, error);
|
|
@@ -806,7 +1386,42 @@ var setupMCPServer2 = (client, targetPath) => {
|
|
|
806
1386
|
return;
|
|
807
1387
|
}
|
|
808
1388
|
};
|
|
809
|
-
var getPyprojectContent = (projectName) => {
|
|
1389
|
+
var getPyprojectContent = (projectName, adapter) => {
|
|
1390
|
+
if (adapter === "claude-agent-sdk") {
|
|
1391
|
+
return `[project]
|
|
1392
|
+
name = "${projectName}"
|
|
1393
|
+
version = "0.1.0"
|
|
1394
|
+
description = "An AgentMark application using Claude Agent SDK"
|
|
1395
|
+
requires-python = ">=3.12"
|
|
1396
|
+
dependencies = [
|
|
1397
|
+
"agentmark-claude-agent-sdk>=0.1.0",
|
|
1398
|
+
"agentmark-prompt-core>=0.1.0",
|
|
1399
|
+
"python-dotenv>=1.0.0",
|
|
1400
|
+
"claude-agent-sdk>=0.1.0",
|
|
1401
|
+
]
|
|
1402
|
+
|
|
1403
|
+
[project.optional-dependencies]
|
|
1404
|
+
dev = [
|
|
1405
|
+
"pytest>=7.0",
|
|
1406
|
+
"pytest-asyncio>=0.21",
|
|
1407
|
+
"mypy>=1.0",
|
|
1408
|
+
]
|
|
1409
|
+
otel = [
|
|
1410
|
+
"opentelemetry-api>=1.20",
|
|
1411
|
+
"opentelemetry-sdk>=1.20",
|
|
1412
|
+
]
|
|
1413
|
+
|
|
1414
|
+
[build-system]
|
|
1415
|
+
requires = ["hatchling"]
|
|
1416
|
+
build-backend = "hatchling.build"
|
|
1417
|
+
|
|
1418
|
+
[tool.pytest.ini_options]
|
|
1419
|
+
asyncio_mode = "auto"
|
|
1420
|
+
|
|
1421
|
+
[tool.mypy]
|
|
1422
|
+
strict = true
|
|
1423
|
+
`;
|
|
1424
|
+
}
|
|
810
1425
|
return `[project]
|
|
811
1426
|
name = "${projectName}"
|
|
812
1427
|
version = "0.1.0"
|
|
@@ -839,7 +1454,58 @@ asyncio_mode = "auto"
|
|
|
839
1454
|
strict = true
|
|
840
1455
|
`;
|
|
841
1456
|
};
|
|
842
|
-
var getAgentmarkClientContent = (_deploymentMode) => {
|
|
1457
|
+
var getAgentmarkClientContent = (_deploymentMode, adapter) => {
|
|
1458
|
+
if (adapter === "claude-agent-sdk") {
|
|
1459
|
+
return `"""AgentMark client configuration.
|
|
1460
|
+
|
|
1461
|
+
This file configures the AgentMark client with Claude Agent SDK adapter.
|
|
1462
|
+
Customize the model registry and tool registry as needed.
|
|
1463
|
+
"""
|
|
1464
|
+
|
|
1465
|
+
import os
|
|
1466
|
+
from pathlib import Path
|
|
1467
|
+
from dotenv import load_dotenv
|
|
1468
|
+
|
|
1469
|
+
from agentmark.prompt_core import FileLoader
|
|
1470
|
+
from agentmark_claude_agent_sdk import (
|
|
1471
|
+
create_claude_agent_client,
|
|
1472
|
+
create_default_model_registry,
|
|
1473
|
+
ClaudeAgentToolRegistry,
|
|
1474
|
+
)
|
|
1475
|
+
|
|
1476
|
+
# Load environment variables
|
|
1477
|
+
load_dotenv()
|
|
1478
|
+
|
|
1479
|
+
# Configure model registry with default mappings
|
|
1480
|
+
# Supports: claude-* models
|
|
1481
|
+
model_registry = create_default_model_registry()
|
|
1482
|
+
|
|
1483
|
+
# Configure tool registry for custom tools
|
|
1484
|
+
tool_registry = ClaudeAgentToolRegistry()
|
|
1485
|
+
|
|
1486
|
+
# Example tool registration:
|
|
1487
|
+
# tool_registry.register(
|
|
1488
|
+
# "search",
|
|
1489
|
+
# lambda args, ctx: f"Search results for: {args['query']}",
|
|
1490
|
+
# description="Search the web",
|
|
1491
|
+
# parameters={"type": "object", "properties": {"query": {"type": "string"}}, "required": ["query"]},
|
|
1492
|
+
# )
|
|
1493
|
+
|
|
1494
|
+
# Create file loader for local development
|
|
1495
|
+
# Uses the project root as base directory for resolving relative paths
|
|
1496
|
+
project_root = Path(__file__).parent.resolve()
|
|
1497
|
+
loader = FileLoader(base_dir=str(project_root))
|
|
1498
|
+
|
|
1499
|
+
# Create the client
|
|
1500
|
+
client = create_claude_agent_client(
|
|
1501
|
+
model_registry=model_registry,
|
|
1502
|
+
tool_registry=tool_registry,
|
|
1503
|
+
loader=loader,
|
|
1504
|
+
)
|
|
1505
|
+
|
|
1506
|
+
__all__ = ["client"]
|
|
1507
|
+
`;
|
|
1508
|
+
}
|
|
843
1509
|
return `"""AgentMark client configuration.
|
|
844
1510
|
|
|
845
1511
|
This file configures the AgentMark client with Pydantic AI adapter.
|
|
@@ -888,7 +1554,57 @@ client = create_pydantic_ai_client(
|
|
|
888
1554
|
__all__ = ["client"]
|
|
889
1555
|
`;
|
|
890
1556
|
};
|
|
891
|
-
var getMainPyContent = () => {
|
|
1557
|
+
var getMainPyContent = (adapter) => {
|
|
1558
|
+
if (adapter === "claude-agent-sdk") {
|
|
1559
|
+
return `"""Example usage of AgentMark with Claude Agent SDK.
|
|
1560
|
+
|
|
1561
|
+
Run with: python main.py
|
|
1562
|
+
"""
|
|
1563
|
+
|
|
1564
|
+
import asyncio
|
|
1565
|
+
import json
|
|
1566
|
+
from pathlib import Path
|
|
1567
|
+
|
|
1568
|
+
from agentmark_claude_agent_sdk import run_text_prompt
|
|
1569
|
+
from agentmark_client import client
|
|
1570
|
+
|
|
1571
|
+
|
|
1572
|
+
async def main():
|
|
1573
|
+
"""Run the party planner prompt."""
|
|
1574
|
+
# Load the prompt AST (in production, use the API loader)
|
|
1575
|
+
prompt_path = Path("agentmark/party-planner.prompt.mdx.json")
|
|
1576
|
+
|
|
1577
|
+
if not prompt_path.exists():
|
|
1578
|
+
print("Prompt file not found. Run 'agentmark build' first.")
|
|
1579
|
+
return
|
|
1580
|
+
|
|
1581
|
+
with open(prompt_path) as f:
|
|
1582
|
+
ast = json.load(f)
|
|
1583
|
+
|
|
1584
|
+
# Load and format the prompt
|
|
1585
|
+
prompt = await client.load_text_prompt(ast)
|
|
1586
|
+
params = await prompt.format(props={
|
|
1587
|
+
"numberOfGuests": 10,
|
|
1588
|
+
"theme": "80s disco",
|
|
1589
|
+
"dietaryRestrictions": ["vegetarian", "gluten-free"],
|
|
1590
|
+
})
|
|
1591
|
+
|
|
1592
|
+
# Execute the prompt
|
|
1593
|
+
print("Running party planner prompt...")
|
|
1594
|
+
result = await run_text_prompt(params)
|
|
1595
|
+
|
|
1596
|
+
print("\\n" + "=" * 50)
|
|
1597
|
+
print("Party Plan:")
|
|
1598
|
+
print("=" * 50)
|
|
1599
|
+
print(result.output)
|
|
1600
|
+
print("\\n" + "-" * 50)
|
|
1601
|
+
print(f"Tokens used: {result.usage}")
|
|
1602
|
+
|
|
1603
|
+
|
|
1604
|
+
if __name__ == "__main__":
|
|
1605
|
+
asyncio.run(main())
|
|
1606
|
+
`;
|
|
1607
|
+
}
|
|
892
1608
|
return `"""Example usage of AgentMark with Pydantic AI.
|
|
893
1609
|
|
|
894
1610
|
Run with: python main.py
|
|
@@ -938,7 +1654,8 @@ if __name__ == "__main__":
|
|
|
938
1654
|
asyncio.run(main())
|
|
939
1655
|
`;
|
|
940
1656
|
};
|
|
941
|
-
var getDevServerContent = () => {
|
|
1657
|
+
var getDevServerContent = (adapter) => {
|
|
1658
|
+
const adapterPackage = adapter === "claude-agent-sdk" ? "agentmark_claude_agent_sdk" : "agentmark_pydantic_ai_v0";
|
|
942
1659
|
return `"""Auto-generated webhook server for AgentMark development.
|
|
943
1660
|
|
|
944
1661
|
This server is started by 'npm run dev' (agentmark dev) and handles
|
|
@@ -952,7 +1669,7 @@ from pathlib import Path
|
|
|
952
1669
|
# Add parent directory to path for imports
|
|
953
1670
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
954
1671
|
|
|
955
|
-
from
|
|
1672
|
+
from ${adapterPackage} import create_webhook_server
|
|
956
1673
|
from agentmark_client import client
|
|
957
1674
|
|
|
958
1675
|
|
|
@@ -965,7 +1682,12 @@ if __name__ == "__main__":
|
|
|
965
1682
|
create_webhook_server(client, args.webhook_port, args.api_server_port)
|
|
966
1683
|
`;
|
|
967
1684
|
};
|
|
968
|
-
var getEnvContent = (apiKey) => {
|
|
1685
|
+
var getEnvContent = (apiKey, adapter) => {
|
|
1686
|
+
if (adapter === "claude-agent-sdk") {
|
|
1687
|
+
return `# Anthropic API Key
|
|
1688
|
+
ANTHROPIC_API_KEY=${apiKey}
|
|
1689
|
+
`;
|
|
1690
|
+
}
|
|
969
1691
|
return `# OpenAI API Key
|
|
970
1692
|
OPENAI_API_KEY=${apiKey}
|
|
971
1693
|
|
|
@@ -1005,28 +1727,95 @@ build/
|
|
|
1005
1727
|
htmlcov/
|
|
1006
1728
|
`;
|
|
1007
1729
|
};
|
|
1008
|
-
var createPythonApp = async (client, targetPath = ".", apiKey = "", deploymentMode = "cloud") => {
|
|
1730
|
+
var createPythonApp = async (client, targetPath = ".", apiKey = "", deploymentMode = "cloud", adapter = "pydantic-ai", projectInfo = null, resolutions = []) => {
|
|
1009
1731
|
try {
|
|
1010
|
-
const model = "gpt-4o";
|
|
1011
|
-
|
|
1732
|
+
const model = adapter === "claude-agent-sdk" ? "claude-sonnet-4-20250514" : "gpt-4o";
|
|
1733
|
+
const adapterDisplayName = adapter === "claude-agent-sdk" ? "Claude Agent SDK" : "Pydantic AI";
|
|
1734
|
+
const isExistingProject = projectInfo?.isExistingProject ?? false;
|
|
1735
|
+
if (isExistingProject) {
|
|
1736
|
+
console.log(`Adding AgentMark to existing Python project with ${adapterDisplayName}...`);
|
|
1737
|
+
} else {
|
|
1738
|
+
console.log(`Creating AgentMark Python app with ${adapterDisplayName}...`);
|
|
1739
|
+
}
|
|
1012
1740
|
const folderName = targetPath;
|
|
1013
|
-
|
|
1741
|
+
fs5.ensureDirSync(`${targetPath}/agentmark`);
|
|
1014
1742
|
setupMCPServer2(client, targetPath);
|
|
1015
|
-
createExamplePrompts(model, targetPath,
|
|
1743
|
+
createExamplePrompts(model, targetPath, adapter);
|
|
1016
1744
|
console.log(`Example prompts and datasets created in ${folderName}/agentmark/`);
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1745
|
+
if (!isExistingProject) {
|
|
1746
|
+
const projectName = path3.basename(targetPath).replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
1747
|
+
fs5.writeFileSync(`${targetPath}/pyproject.toml`, getPyprojectContent(projectName, adapter));
|
|
1748
|
+
} else {
|
|
1749
|
+
console.log("\u23ED\uFE0F Skipped pyproject.toml (existing project)");
|
|
1750
|
+
}
|
|
1751
|
+
fs5.writeFileSync(`${targetPath}/agentmark_client.py`, getAgentmarkClientContent(deploymentMode, adapter));
|
|
1752
|
+
if (!isExistingProject) {
|
|
1753
|
+
fs5.writeFileSync(`${targetPath}/main.py`, getMainPyContent(adapter));
|
|
1754
|
+
} else {
|
|
1755
|
+
console.log("\u23ED\uFE0F Skipped main.py (existing project)");
|
|
1756
|
+
}
|
|
1757
|
+
if (shouldMergeFile(".env", projectInfo, resolutions)) {
|
|
1758
|
+
const envVars = {};
|
|
1759
|
+
const apiKeyEnvVar = adapter === "claude-agent-sdk" ? "ANTHROPIC_API_KEY" : "OPENAI_API_KEY";
|
|
1760
|
+
if (apiKey) {
|
|
1761
|
+
envVars[apiKeyEnvVar] = apiKey;
|
|
1762
|
+
} else {
|
|
1763
|
+
envVars[apiKeyEnvVar] = adapter === "claude-agent-sdk" ? "your-anthropic-api-key" : "your-openai-api-key";
|
|
1764
|
+
}
|
|
1765
|
+
const result = appendEnv(targetPath, envVars);
|
|
1766
|
+
if (result.added.length > 0) {
|
|
1767
|
+
console.log(`\u2705 Added to .env: ${result.added.join(", ")}`);
|
|
1768
|
+
}
|
|
1769
|
+
if (result.skipped.length > 0) {
|
|
1770
|
+
console.log(`\u23ED\uFE0F Skipped existing .env vars: ${result.skipped.join(", ")}`);
|
|
1771
|
+
}
|
|
1772
|
+
} else {
|
|
1773
|
+
fs5.writeFileSync(`${targetPath}/.env`, getEnvContent(apiKey, adapter));
|
|
1774
|
+
}
|
|
1775
|
+
const gitignoreEntries = [
|
|
1776
|
+
"__pycache__/",
|
|
1777
|
+
"*.py[cod]",
|
|
1778
|
+
"*$py.class",
|
|
1779
|
+
".venv/",
|
|
1780
|
+
"venv/",
|
|
1781
|
+
".env",
|
|
1782
|
+
"*.agentmark-outputs/",
|
|
1783
|
+
".agentmark/",
|
|
1784
|
+
".idea/",
|
|
1785
|
+
".vscode/",
|
|
1786
|
+
"*.swp",
|
|
1787
|
+
"dist/",
|
|
1788
|
+
"build/",
|
|
1789
|
+
"*.egg-info/",
|
|
1790
|
+
".pytest_cache/",
|
|
1791
|
+
".coverage",
|
|
1792
|
+
"htmlcov/"
|
|
1793
|
+
];
|
|
1794
|
+
if (shouldMergeFile(".gitignore", projectInfo, resolutions)) {
|
|
1795
|
+
const result = appendGitignore(targetPath, gitignoreEntries);
|
|
1796
|
+
if (result.added.length > 0) {
|
|
1797
|
+
console.log(`\u2705 Added to .gitignore: ${result.added.join(", ")}`);
|
|
1798
|
+
}
|
|
1799
|
+
if (result.skipped.length > 0) {
|
|
1800
|
+
console.log(`\u23ED\uFE0F Already in .gitignore: ${result.skipped.join(", ")}`);
|
|
1801
|
+
}
|
|
1802
|
+
} else {
|
|
1803
|
+
fs5.writeFileSync(`${targetPath}/.gitignore`, getGitignoreContent());
|
|
1804
|
+
}
|
|
1805
|
+
const agentmarkInternalDir = path3.join(targetPath, ".agentmark");
|
|
1806
|
+
fs5.ensureDirSync(agentmarkInternalDir);
|
|
1807
|
+
fs5.writeFileSync(path3.join(agentmarkInternalDir, "dev_server.py"), getDevServerContent(adapter));
|
|
1808
|
+
const pythonVenv = projectInfo?.pythonVenv;
|
|
1809
|
+
if (pythonVenv) {
|
|
1810
|
+
console.log(`
|
|
1811
|
+
\u{1F4E6} Detected existing Python venv: ${pythonVenv.name}`);
|
|
1812
|
+
console.log(" Remember to activate it before running AgentMark commands.");
|
|
1813
|
+
} else if (!isExistingProject) {
|
|
1814
|
+
console.log("Setting up Python environment...");
|
|
1815
|
+
console.log("Note: You'll need to set up a virtual environment and install dependencies.");
|
|
1816
|
+
console.log("");
|
|
1817
|
+
}
|
|
1818
|
+
console.log("\n\u2705 AgentMark Python initialization completed successfully!");
|
|
1030
1819
|
console.log(
|
|
1031
1820
|
`
|
|
1032
1821
|
\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2557
|
|
@@ -1042,12 +1831,18 @@ var createPythonApp = async (client, targetPath = ".", apiKey = "", deploymentMo
|
|
|
1042
1831
|
console.log("Next Steps");
|
|
1043
1832
|
console.log("\u2550".repeat(70));
|
|
1044
1833
|
console.log("\n Get Started:");
|
|
1045
|
-
if (folderName !== "." && folderName !== "./") {
|
|
1834
|
+
if (folderName !== "." && folderName !== "./" && !isExistingProject) {
|
|
1046
1835
|
console.log(` $ cd ${folderName}`);
|
|
1047
1836
|
}
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1837
|
+
if (pythonVenv) {
|
|
1838
|
+
const activateCmd = process.platform === "win32" ? `${pythonVenv.name}\\Scripts\\activate` : `source ${pythonVenv.name}/bin/activate`;
|
|
1839
|
+
console.log(` $ ${activateCmd}`);
|
|
1840
|
+
console.log(' $ pip install agentmark-pydantic-ai agentmark-prompt-core python-dotenv "pydantic-ai[openai]"');
|
|
1841
|
+
} else {
|
|
1842
|
+
console.log(" $ python -m venv .venv");
|
|
1843
|
+
console.log(" $ source .venv/bin/activate # On Windows: .venv\\Scripts\\activate");
|
|
1844
|
+
console.log(' $ pip install -e ".[dev]"');
|
|
1845
|
+
}
|
|
1051
1846
|
console.log(" $ npm run dev\n");
|
|
1052
1847
|
console.log("\u2500".repeat(70));
|
|
1053
1848
|
console.log("Resources");
|
|
@@ -1060,6 +1855,116 @@ var createPythonApp = async (client, targetPath = ".", apiKey = "", deploymentMo
|
|
|
1060
1855
|
}
|
|
1061
1856
|
};
|
|
1062
1857
|
|
|
1858
|
+
// src/utils/project-detection.ts
|
|
1859
|
+
import fs7 from "fs-extra";
|
|
1860
|
+
import path5 from "path";
|
|
1861
|
+
|
|
1862
|
+
// src/utils/package-manager.ts
|
|
1863
|
+
import fs6 from "fs-extra";
|
|
1864
|
+
import path4 from "path";
|
|
1865
|
+
function detectPackageManager(targetPath) {
|
|
1866
|
+
const lockFiles = ["yarn.lock", "pnpm-lock.yaml", "bun.lockb", "package-lock.json"];
|
|
1867
|
+
for (const lockFile of lockFiles) {
|
|
1868
|
+
if (fs6.existsSync(path4.join(targetPath, lockFile))) {
|
|
1869
|
+
const config = PACKAGE_MANAGERS[lockFile];
|
|
1870
|
+
if (config) {
|
|
1871
|
+
return config;
|
|
1872
|
+
}
|
|
1873
|
+
}
|
|
1874
|
+
}
|
|
1875
|
+
return DEFAULT_PACKAGE_MANAGER;
|
|
1876
|
+
}
|
|
1877
|
+
|
|
1878
|
+
// src/utils/project-detection.ts
|
|
1879
|
+
var IS_WINDOWS = process.platform === "win32";
|
|
1880
|
+
function detectTypeScriptProject(targetPath) {
|
|
1881
|
+
const indicators = ["package.json", "tsconfig.json", "node_modules"];
|
|
1882
|
+
return indicators.some((file) => fs7.existsSync(path5.join(targetPath, file)));
|
|
1883
|
+
}
|
|
1884
|
+
function detectPythonProject(targetPath) {
|
|
1885
|
+
const indicators = ["pyproject.toml", "requirements.txt", "setup.py", ".venv", "venv"];
|
|
1886
|
+
return indicators.some((file) => fs7.existsSync(path5.join(targetPath, file)));
|
|
1887
|
+
}
|
|
1888
|
+
function detectPythonVenv(targetPath) {
|
|
1889
|
+
const venvNames = [".venv", "venv"];
|
|
1890
|
+
for (const name of venvNames) {
|
|
1891
|
+
const venvPath = path5.join(targetPath, name);
|
|
1892
|
+
if (fs7.existsSync(venvPath) && fs7.statSync(venvPath).isDirectory()) {
|
|
1893
|
+
const binDir = IS_WINDOWS ? "Scripts" : "bin";
|
|
1894
|
+
const binPath = path5.join(venvPath, binDir);
|
|
1895
|
+
if (fs7.existsSync(binPath)) {
|
|
1896
|
+
const pipExe = IS_WINDOWS ? "pip.exe" : "pip";
|
|
1897
|
+
return {
|
|
1898
|
+
path: venvPath,
|
|
1899
|
+
name,
|
|
1900
|
+
activateCmd: IS_WINDOWS ? `${name}\\Scripts\\activate` : `source ${name}/bin/activate`,
|
|
1901
|
+
pipPath: path5.join(binPath, pipExe)
|
|
1902
|
+
};
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1906
|
+
const envVenv = process.env.VIRTUAL_ENV;
|
|
1907
|
+
if (envVenv && fs7.existsSync(envVenv)) {
|
|
1908
|
+
const resolvedTarget = path5.resolve(targetPath);
|
|
1909
|
+
const resolvedVenv = path5.resolve(envVenv);
|
|
1910
|
+
const isInsideTarget = resolvedVenv.startsWith(resolvedTarget + path5.sep) || resolvedVenv === resolvedTarget;
|
|
1911
|
+
if (!isInsideTarget) {
|
|
1912
|
+
console.warn(
|
|
1913
|
+
`\u26A0\uFE0F Note: VIRTUAL_ENV (${envVenv}) points outside the target directory. It will not be used for this initialization.`
|
|
1914
|
+
);
|
|
1915
|
+
return null;
|
|
1916
|
+
}
|
|
1917
|
+
const binDir = IS_WINDOWS ? "Scripts" : "bin";
|
|
1918
|
+
const pipExe = IS_WINDOWS ? "pip.exe" : "pip";
|
|
1919
|
+
const name = path5.basename(envVenv);
|
|
1920
|
+
return {
|
|
1921
|
+
path: envVenv,
|
|
1922
|
+
name,
|
|
1923
|
+
activateCmd: IS_WINDOWS ? `${name}\\Scripts\\activate` : `source ${name}/bin/activate`,
|
|
1924
|
+
pipPath: path5.join(envVenv, binDir, pipExe)
|
|
1925
|
+
};
|
|
1926
|
+
}
|
|
1927
|
+
return null;
|
|
1928
|
+
}
|
|
1929
|
+
function detectConflictingFiles(targetPath) {
|
|
1930
|
+
const existingConflicts = [];
|
|
1931
|
+
for (const conflictFile of CONFLICT_FILES) {
|
|
1932
|
+
const fullPath = path5.join(targetPath, conflictFile.path);
|
|
1933
|
+
if (fs7.existsSync(fullPath)) {
|
|
1934
|
+
existingConflicts.push(conflictFile);
|
|
1935
|
+
}
|
|
1936
|
+
}
|
|
1937
|
+
return existingConflicts;
|
|
1938
|
+
}
|
|
1939
|
+
function detectProjectInfo(targetPath) {
|
|
1940
|
+
const isTypeScript = detectTypeScriptProject(targetPath);
|
|
1941
|
+
const isPython = detectPythonProject(targetPath);
|
|
1942
|
+
const isExistingProject = isTypeScript || isPython;
|
|
1943
|
+
let type = "unknown";
|
|
1944
|
+
if (isTypeScript && !isPython) {
|
|
1945
|
+
type = "typescript";
|
|
1946
|
+
} else if (isPython && !isTypeScript) {
|
|
1947
|
+
type = "python";
|
|
1948
|
+
} else if (isTypeScript && isPython) {
|
|
1949
|
+
type = "typescript";
|
|
1950
|
+
}
|
|
1951
|
+
const packageManager = detectPackageManager(targetPath);
|
|
1952
|
+
const conflictingFiles = detectConflictingFiles(targetPath);
|
|
1953
|
+
const hasAgentmarkDir = fs7.existsSync(path5.join(targetPath, "agentmark"));
|
|
1954
|
+
const pythonVenv = detectPythonVenv(targetPath);
|
|
1955
|
+
return {
|
|
1956
|
+
isExistingProject,
|
|
1957
|
+
type,
|
|
1958
|
+
packageManager,
|
|
1959
|
+
conflictingFiles,
|
|
1960
|
+
hasAgentmarkDir,
|
|
1961
|
+
pythonVenv
|
|
1962
|
+
};
|
|
1963
|
+
}
|
|
1964
|
+
function isCurrentDirectory(folderName) {
|
|
1965
|
+
return folderName === "." || folderName === "./" || folderName === ".\\";
|
|
1966
|
+
}
|
|
1967
|
+
|
|
1063
1968
|
// src/index.ts
|
|
1064
1969
|
var parseArgs = () => {
|
|
1065
1970
|
const args = process.argv.slice(2);
|
|
@@ -1087,17 +1992,25 @@ var main = async () => {
|
|
|
1087
1992
|
agentmarkPath: "."
|
|
1088
1993
|
};
|
|
1089
1994
|
console.log("Initializing project.");
|
|
1090
|
-
const { folderName } = await
|
|
1995
|
+
const { folderName } = await prompts2({
|
|
1091
1996
|
name: "folderName",
|
|
1092
1997
|
type: "text",
|
|
1093
1998
|
message: "Where would you like to create your AgentMark app?",
|
|
1094
1999
|
initial: "my-agentmark-app"
|
|
1095
2000
|
});
|
|
1096
|
-
const
|
|
1097
|
-
|
|
2001
|
+
const isCurrentDir = isCurrentDirectory(folderName);
|
|
2002
|
+
const targetPath = isCurrentDir ? process.cwd() : path6.resolve(folderName);
|
|
2003
|
+
if (!isCurrentDir) {
|
|
2004
|
+
fs8.ensureDirSync(targetPath);
|
|
2005
|
+
}
|
|
2006
|
+
const projectInfo = detectProjectInfo(targetPath);
|
|
2007
|
+
if (projectInfo.isExistingProject) {
|
|
2008
|
+
displayProjectDetectionSummary(projectInfo);
|
|
2009
|
+
}
|
|
2010
|
+
const resolutions = await promptForResolutions(projectInfo.conflictingFiles);
|
|
1098
2011
|
let language = cliArgs.language;
|
|
1099
2012
|
if (!language) {
|
|
1100
|
-
const response = await
|
|
2013
|
+
const response = await prompts2({
|
|
1101
2014
|
name: "language",
|
|
1102
2015
|
type: "select",
|
|
1103
2016
|
message: "Which language would you like to use?",
|
|
@@ -1108,34 +2021,44 @@ var main = async () => {
|
|
|
1108
2021
|
});
|
|
1109
2022
|
language = response.language;
|
|
1110
2023
|
}
|
|
1111
|
-
config.builtInModels = ["gpt-4o"];
|
|
1112
|
-
let apiKey = "";
|
|
1113
|
-
const { providedApiKey } = await prompts({
|
|
1114
|
-
name: "providedApiKey",
|
|
1115
|
-
type: "password",
|
|
1116
|
-
message: `Enter your OpenAI API key (or press Enter to skip):`,
|
|
1117
|
-
initial: ""
|
|
1118
|
-
});
|
|
1119
|
-
apiKey = providedApiKey || "";
|
|
1120
2024
|
let adapter;
|
|
1121
2025
|
if (language === "python") {
|
|
1122
|
-
|
|
1123
|
-
|
|
2026
|
+
const response = await prompts2({
|
|
2027
|
+
name: "adapter",
|
|
2028
|
+
type: "select",
|
|
2029
|
+
message: "Which adapter would you like to use?",
|
|
2030
|
+
choices: [
|
|
2031
|
+
{ title: "Pydantic AI", value: "pydantic-ai" },
|
|
2032
|
+
{ title: "Claude Agent SDK", value: "claude-agent-sdk" }
|
|
2033
|
+
]
|
|
2034
|
+
});
|
|
2035
|
+
adapter = response.adapter;
|
|
1124
2036
|
} else {
|
|
1125
|
-
const response = await
|
|
2037
|
+
const response = await prompts2({
|
|
1126
2038
|
name: "adapter",
|
|
1127
2039
|
type: "select",
|
|
1128
2040
|
message: "Which adapter would you like to use?",
|
|
1129
2041
|
choices: [
|
|
1130
2042
|
{ title: "AI SDK (Vercel)", value: "ai-sdk" },
|
|
2043
|
+
{ title: "Claude Agent SDK", value: "claude-agent-sdk" },
|
|
1131
2044
|
{ title: "Mastra", value: "mastra" }
|
|
1132
2045
|
]
|
|
1133
2046
|
});
|
|
1134
2047
|
adapter = response.adapter;
|
|
1135
2048
|
}
|
|
2049
|
+
config.builtInModels = adapter === "claude-agent-sdk" ? ["claude-sonnet-4-20250514"] : ["gpt-4o"];
|
|
2050
|
+
const apiKeyName = adapter === "claude-agent-sdk" ? "Anthropic" : "OpenAI";
|
|
2051
|
+
let apiKey = "";
|
|
2052
|
+
const { providedApiKey } = await prompts2({
|
|
2053
|
+
name: "providedApiKey",
|
|
2054
|
+
type: "password",
|
|
2055
|
+
message: `Enter your ${apiKeyName} API key (or press Enter to skip):`,
|
|
2056
|
+
initial: ""
|
|
2057
|
+
});
|
|
2058
|
+
apiKey = providedApiKey || "";
|
|
1136
2059
|
let deploymentMode = cliArgs.deploymentMode;
|
|
1137
2060
|
if (!deploymentMode) {
|
|
1138
|
-
const response = await
|
|
2061
|
+
const response = await prompts2({
|
|
1139
2062
|
name: "deploymentMode",
|
|
1140
2063
|
type: "select",
|
|
1141
2064
|
message: "Use AgentMark Cloud or manage yourself?",
|
|
@@ -1154,7 +2077,7 @@ var main = async () => {
|
|
|
1154
2077
|
});
|
|
1155
2078
|
deploymentMode = response.deploymentMode;
|
|
1156
2079
|
}
|
|
1157
|
-
const { client } = await
|
|
2080
|
+
const { client } = await prompts2({
|
|
1158
2081
|
name: "client",
|
|
1159
2082
|
type: "select",
|
|
1160
2083
|
message: "Make your IDE an AgentMark expert",
|
|
@@ -1167,11 +2090,17 @@ var main = async () => {
|
|
|
1167
2090
|
]
|
|
1168
2091
|
});
|
|
1169
2092
|
if (language === "python") {
|
|
1170
|
-
await createPythonApp(client, targetPath, apiKey, deploymentMode);
|
|
2093
|
+
await createPythonApp(client, targetPath, apiKey, deploymentMode, adapter, projectInfo, resolutions);
|
|
1171
2094
|
} else {
|
|
1172
|
-
await createExampleApp(client, targetPath, apiKey, adapter, deploymentMode);
|
|
2095
|
+
await createExampleApp(client, targetPath, apiKey, adapter, deploymentMode, projectInfo, resolutions);
|
|
2096
|
+
}
|
|
2097
|
+
const agentmarkJsonPath = path6.join(targetPath, "agentmark.json");
|
|
2098
|
+
const agentmarkJsonResolution = resolutions.find((r) => r.path === "agentmark.json");
|
|
2099
|
+
if (!fs8.existsSync(agentmarkJsonPath) || agentmarkJsonResolution?.action === "overwrite") {
|
|
2100
|
+
fs8.writeJsonSync(agentmarkJsonPath, config, { spaces: 2 });
|
|
2101
|
+
} else if (agentmarkJsonResolution?.action === "skip") {
|
|
2102
|
+
console.log("\u23ED\uFE0F Skipped agentmark.json (keeping existing file)");
|
|
1173
2103
|
}
|
|
1174
|
-
fs5.writeJsonSync(`${targetPath}/agentmark.json`, config, { spaces: 2 });
|
|
1175
2104
|
};
|
|
1176
2105
|
main().catch((error) => {
|
|
1177
2106
|
console.error("Error:", error);
|