create-agentmark 0.5.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
|
|
|
@@ -29,7 +41,7 @@ var Providers = {
|
|
|
29
41
|
var createAdapterConfig = (provider) => {
|
|
30
42
|
return {
|
|
31
43
|
"ai-sdk": {
|
|
32
|
-
package: "@agentmark/ai-sdk-v5-adapter",
|
|
44
|
+
package: "@agentmark-ai/ai-sdk-v5-adapter",
|
|
33
45
|
dependencies: ["ai@^5", `@ai-sdk/${provider}@^2`],
|
|
34
46
|
classes: {
|
|
35
47
|
modelRegistry: "VercelAIModelRegistry",
|
|
@@ -38,7 +50,7 @@ var createAdapterConfig = (provider) => {
|
|
|
38
50
|
}
|
|
39
51
|
},
|
|
40
52
|
mastra: {
|
|
41
|
-
package: "@agentmark/mastra-v0-adapter",
|
|
53
|
+
package: "@agentmark-ai/mastra-v0-adapter",
|
|
42
54
|
dependencies: [
|
|
43
55
|
"@mastra/core@<0.20.0",
|
|
44
56
|
"@mastra/mcp@<0.13.4",
|
|
@@ -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";
|
|
@@ -74,11 +149,10 @@ import { client } from "./agentmark.client";
|
|
|
74
149
|
const telemetry = {
|
|
75
150
|
isEnabled: true,
|
|
76
151
|
metadata: {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
sessionName: "my-first-session",
|
|
152
|
+
trace_name: "customer-support",
|
|
153
|
+
user_id: "user-123",
|
|
154
|
+
session_id: "session-123",
|
|
155
|
+
session_name: "my-first-session",
|
|
82
156
|
},
|
|
83
157
|
};
|
|
84
158
|
|
|
@@ -122,11 +196,10 @@ import { client } from "./agentmark.client";
|
|
|
122
196
|
const telemetry = {
|
|
123
197
|
isEnabled: true,
|
|
124
198
|
metadata: {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
sessionName: "my-first-session",
|
|
199
|
+
trace_name: "customer-support",
|
|
200
|
+
user_id: "user-123",
|
|
201
|
+
session_id: "session-123",
|
|
202
|
+
session_name: "my-first-session",
|
|
130
203
|
},
|
|
131
204
|
};
|
|
132
205
|
|
|
@@ -160,70 +233,328 @@ main();
|
|
|
160
233
|
};
|
|
161
234
|
|
|
162
235
|
// src/utils/examples/templates/env.ts
|
|
163
|
-
var getEnvFileContent = (_modelProvider, apiKey = "") => {
|
|
236
|
+
var getEnvFileContent = (_modelProvider, apiKey = "", adapter = "ai-sdk") => {
|
|
164
237
|
const apiKeyValue = apiKey || "your_api_key_here";
|
|
238
|
+
const apiKeyName = adapter === "claude-agent-sdk" ? "ANTHROPIC_API_KEY" : "OPENAI_API_KEY";
|
|
165
239
|
return `# Cloud deployment: Set these environment variables
|
|
166
240
|
# AGENTMARK_BASE_URL=https://api.agentmark.co
|
|
167
241
|
# AGENTMARK_API_KEY=your_agentmark_api_key
|
|
168
242
|
# AGENTMARK_APP_ID=your_agentmark_app_id
|
|
169
243
|
# Learn more: https://docs.agentmark.co/platform/getting_started/quickstart
|
|
170
244
|
|
|
171
|
-
|
|
245
|
+
${apiKeyName}=${apiKeyValue}
|
|
172
246
|
`;
|
|
173
247
|
};
|
|
174
248
|
|
|
175
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
|
|
176
254
|
import fs from "fs-extra";
|
|
177
|
-
import
|
|
178
|
-
|
|
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) => {
|
|
179
484
|
const packageJsonPath = `${targetPath}/package.json`;
|
|
180
|
-
|
|
485
|
+
const isExistingProject = projectInfo?.isExistingProject ?? false;
|
|
486
|
+
if (!fs2.existsSync(packageJsonPath)) {
|
|
181
487
|
console.log("Creating package.json...");
|
|
182
488
|
execSync("npm init -y", { cwd: targetPath });
|
|
183
489
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
"
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
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 });
|
|
197
531
|
}
|
|
198
|
-
pkgJson.scripts = scripts;
|
|
199
|
-
pkgJson.overrides = {
|
|
200
|
-
...pkgJson.overrides,
|
|
201
|
-
"axios": "^1.7.9"
|
|
202
|
-
};
|
|
203
|
-
fs.writeJsonSync(packageJsonPath, pkgJson, { spaces: 2 });
|
|
204
532
|
};
|
|
205
|
-
var installDependencies = (modelProvider, targetPath = ".", adapter = "ai-sdk", deploymentMode = "cloud") => {
|
|
533
|
+
var installDependencies = (modelProvider, targetPath = ".", adapter = "ai-sdk", deploymentMode = "cloud", packageManager = null) => {
|
|
206
534
|
console.log("Installing required packages...");
|
|
207
535
|
console.log("This might take a moment...");
|
|
208
536
|
const adapterConfig = getAdapterConfig(adapter, modelProvider);
|
|
537
|
+
const pm = packageManager || DEFAULT_PACKAGE_MANAGER;
|
|
538
|
+
const npmSuffix = pm.name === "npm" ? " --legacy-peer-deps" : "";
|
|
209
539
|
try {
|
|
210
|
-
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...`);
|
|
211
543
|
execSync(devDepsCmd, {
|
|
212
544
|
stdio: "inherit",
|
|
213
545
|
cwd: targetPath
|
|
214
546
|
});
|
|
215
|
-
const loaderPackages = deploymentMode === "static" ? ["@agentmark/loader-api", "@agentmark/loader-file"] : ["@agentmark/loader-api"];
|
|
216
|
-
const
|
|
217
|
-
"install",
|
|
547
|
+
const loaderPackages = deploymentMode === "static" ? ["@agentmark-ai/loader-api", "@agentmark-ai/loader-file"] : ["@agentmark-ai/loader-api"];
|
|
548
|
+
const deps = [
|
|
218
549
|
"dotenv",
|
|
219
|
-
"@agentmark/prompt-core",
|
|
220
|
-
"@agentmark/sdk",
|
|
550
|
+
"@agentmark-ai/prompt-core",
|
|
551
|
+
"@agentmark-ai/sdk",
|
|
221
552
|
adapterConfig.package,
|
|
222
553
|
...loaderPackages,
|
|
223
|
-
...adapterConfig.dependencies
|
|
224
|
-
"--legacy-peer-deps"
|
|
554
|
+
...adapterConfig.dependencies
|
|
225
555
|
];
|
|
226
|
-
|
|
556
|
+
const depsCmd = `${pm.addCmd} ${deps.join(" ")}${npmSuffix}`;
|
|
557
|
+
execSync(depsCmd, { stdio: "inherit", cwd: targetPath });
|
|
227
558
|
console.log("Packages installed successfully!");
|
|
228
559
|
} catch (error) {
|
|
229
560
|
console.error("Error installing packages:", error);
|
|
@@ -397,28 +728,32 @@ var getStoryDataset = () => {
|
|
|
397
728
|
};
|
|
398
729
|
|
|
399
730
|
// src/utils/examples/templates/example-prompts.ts
|
|
400
|
-
import
|
|
731
|
+
import fs3 from "fs-extra";
|
|
401
732
|
var createExamplePrompts = (model, targetPath = ".", adapter = "ai-sdk") => {
|
|
402
|
-
|
|
403
|
-
|
|
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) {
|
|
404
739
|
const animalDrawingPrompt = getAnimalDrawingPrompt();
|
|
405
|
-
|
|
740
|
+
fs3.writeFileSync(`${targetPath}/agentmark/animal-drawing.prompt.mdx`, animalDrawingPrompt);
|
|
406
741
|
const animalDataset = getAnimalDataset();
|
|
407
|
-
|
|
742
|
+
fs3.writeFileSync(`${targetPath}/agentmark/animal.jsonl`, animalDataset);
|
|
408
743
|
}
|
|
409
744
|
const customerSupportPrompt = getCustomerSupportPrompt(model);
|
|
410
|
-
|
|
745
|
+
fs3.writeFileSync(`${targetPath}/agentmark/customer-support-agent.prompt.mdx`, customerSupportPrompt);
|
|
411
746
|
const customerQueryDataset = getCustomerQueryDataset();
|
|
412
|
-
|
|
747
|
+
fs3.writeFileSync(`${targetPath}/agentmark/customer-query.jsonl`, customerQueryDataset);
|
|
413
748
|
const partyPlannerPrompt = getPartyPlannerPrompt(model);
|
|
414
|
-
|
|
749
|
+
fs3.writeFileSync(`${targetPath}/agentmark/party-planner.prompt.mdx`, partyPlannerPrompt);
|
|
415
750
|
const partyDataset = getPartyDataset();
|
|
416
|
-
|
|
417
|
-
if (
|
|
751
|
+
fs3.writeFileSync(`${targetPath}/agentmark/party.jsonl`, partyDataset);
|
|
752
|
+
if (!skipSpeechPrompts) {
|
|
418
753
|
const storyTellerPrompt = getStoryTellerPrompt();
|
|
419
|
-
|
|
754
|
+
fs3.writeFileSync(`${targetPath}/agentmark/story-teller.prompt.mdx`, storyTellerPrompt);
|
|
420
755
|
const storyDataset = getStoryDataset();
|
|
421
|
-
|
|
756
|
+
fs3.writeFileSync(`${targetPath}/agentmark/story.jsonl`, storyDataset);
|
|
422
757
|
}
|
|
423
758
|
};
|
|
424
759
|
|
|
@@ -427,11 +762,12 @@ var getClientConfigContent = (options) => {
|
|
|
427
762
|
const { provider, languageModels, adapter, deploymentMode = "cloud" } = options;
|
|
428
763
|
const adapterConfig = getAdapterConfig(adapter, provider);
|
|
429
764
|
const { modelRegistry, toolRegistry } = adapterConfig.classes;
|
|
430
|
-
const
|
|
431
|
-
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))
|
|
432
768
|
.registerModels(["tts-1-hd"], (name: string) => ${provider}.speech(name))` : "";
|
|
433
|
-
const loaderImport = deploymentMode === "cloud" ? `import { ApiLoader } from "@agentmark/loader-api";` : `import { ApiLoader } from "@agentmark/loader-api";
|
|
434
|
-
import { FileLoader } from "@agentmark/loader-file";`;
|
|
769
|
+
const loaderImport = deploymentMode === "cloud" ? `import { ApiLoader } from "@agentmark-ai/loader-api";` : `import { ApiLoader } from "@agentmark-ai/loader-api";
|
|
770
|
+
import { FileLoader } from "@agentmark-ai/loader-file";`;
|
|
435
771
|
const loaderSetup = deploymentMode === "cloud" ? ` // ApiLoader works for both development and production
|
|
436
772
|
// - Development: 'agentmark dev' sets AGENTMARK_BASE_URL to localhost
|
|
437
773
|
// - Production: Set AGENTMARK_API_KEY and AGENTMARK_APP_ID for cloud
|
|
@@ -443,6 +779,51 @@ import { FileLoader } from "@agentmark/loader-file";`;
|
|
|
443
779
|
});` : ` const loader = process.env.NODE_ENV === 'development'
|
|
444
780
|
? ApiLoader.local({ baseUrl: process.env.AGENTMARK_BASE_URL || 'http://localhost:9418' })
|
|
445
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 });`;
|
|
446
827
|
return `// agentmark.client.ts
|
|
447
828
|
import path from 'node:path';
|
|
448
829
|
import dotenv from 'dotenv';
|
|
@@ -451,13 +832,9 @@ import { createAgentMarkClient, ${modelRegistry}, ${toolRegistry}, EvalRegistry
|
|
|
451
832
|
${loaderImport}
|
|
452
833
|
import AgentMarkTypes, { Tools } from './agentmark.types';
|
|
453
834
|
${providerImport}
|
|
835
|
+
${adapterOptionsImport}
|
|
454
836
|
|
|
455
|
-
|
|
456
|
-
const modelRegistry = new ${modelRegistry}()
|
|
457
|
-
.registerModels(${JSON.stringify(languageModels)}, (name: string) => ${provider}(name))
|
|
458
|
-
${extraModelRegs};
|
|
459
|
-
return modelRegistry;
|
|
460
|
-
}
|
|
837
|
+
${modelRegistrySetup}
|
|
461
838
|
|
|
462
839
|
function createToolRegistry() {
|
|
463
840
|
const toolRegistry = new ${toolRegistry}<Tools>()
|
|
@@ -504,7 +881,7 @@ ${loaderSetup}
|
|
|
504
881
|
const modelRegistry = createModelRegistry();
|
|
505
882
|
const toolRegistry = createToolRegistry();
|
|
506
883
|
const evalRegistry = createEvalRegistry();
|
|
507
|
-
|
|
884
|
+
${createClientCall}
|
|
508
885
|
}
|
|
509
886
|
|
|
510
887
|
export const client = createClient();
|
|
@@ -512,7 +889,100 @@ export const client = createClient();
|
|
|
512
889
|
};
|
|
513
890
|
|
|
514
891
|
// src/utils/examples/create-example-app.ts
|
|
515
|
-
import { fetchPromptsFrontmatter, generateTypeDefinitions } from "@agentmark/shared-utils";
|
|
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
|
|
516
986
|
var setupMCPServer = (client, targetPath) => {
|
|
517
987
|
if (client === "skip") {
|
|
518
988
|
console.log("Skipping MCP server setup.");
|
|
@@ -522,16 +992,23 @@ var setupMCPServer = (client, targetPath) => {
|
|
|
522
992
|
if (client === "vscode") {
|
|
523
993
|
try {
|
|
524
994
|
console.log(`Setting up MCP server for VS Code in ${folderName}...`);
|
|
525
|
-
const vscodeDir =
|
|
526
|
-
|
|
995
|
+
const vscodeDir = path2.join(targetPath, ".vscode");
|
|
996
|
+
fs4.ensureDirSync(vscodeDir);
|
|
527
997
|
const mcpConfig = {
|
|
528
998
|
servers: {
|
|
529
999
|
"agentmark-docs": {
|
|
530
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
|
+
}
|
|
531
1008
|
}
|
|
532
1009
|
}
|
|
533
1010
|
};
|
|
534
|
-
|
|
1011
|
+
fs4.writeJsonSync(path2.join(vscodeDir, "mcp.json"), mcpConfig, { spaces: 2 });
|
|
535
1012
|
console.log(`\u2705 MCP server configured for VS Code in ${folderName}/.vscode/mcp.json`);
|
|
536
1013
|
} catch (error) {
|
|
537
1014
|
console.warn(`Warning: Could not set up MCP server for VS Code:`, error);
|
|
@@ -542,16 +1019,23 @@ var setupMCPServer = (client, targetPath) => {
|
|
|
542
1019
|
if (client === "zed") {
|
|
543
1020
|
try {
|
|
544
1021
|
console.log(`Setting up MCP server for Zed in ${folderName}...`);
|
|
545
|
-
const zedDir =
|
|
546
|
-
|
|
1022
|
+
const zedDir = path2.join(targetPath, ".zed");
|
|
1023
|
+
fs4.ensureDirSync(zedDir);
|
|
547
1024
|
const zedConfig = {
|
|
548
1025
|
context_servers: {
|
|
549
1026
|
"agentmark-docs": {
|
|
550
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
|
+
}
|
|
551
1035
|
}
|
|
552
1036
|
}
|
|
553
1037
|
};
|
|
554
|
-
|
|
1038
|
+
fs4.writeJsonSync(path2.join(zedDir, "settings.json"), zedConfig, { spaces: 2 });
|
|
555
1039
|
console.log(`\u2705 MCP server configured for Zed in ${folderName}/.zed/settings.json`);
|
|
556
1040
|
} catch (error) {
|
|
557
1041
|
console.warn(`Warning: Could not set up MCP server for Zed:`, error);
|
|
@@ -562,16 +1046,23 @@ var setupMCPServer = (client, targetPath) => {
|
|
|
562
1046
|
if (client === "cursor") {
|
|
563
1047
|
try {
|
|
564
1048
|
console.log(`Setting up MCP server for Cursor in ${folderName}...`);
|
|
565
|
-
const cursorDir =
|
|
566
|
-
|
|
1049
|
+
const cursorDir = path2.join(targetPath, ".cursor");
|
|
1050
|
+
fs4.ensureDirSync(cursorDir);
|
|
567
1051
|
const cursorConfig = {
|
|
568
1052
|
mcpServers: {
|
|
569
1053
|
"agentmark-docs": {
|
|
570
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
|
+
}
|
|
571
1062
|
}
|
|
572
1063
|
}
|
|
573
1064
|
};
|
|
574
|
-
|
|
1065
|
+
fs4.writeJsonSync(path2.join(cursorDir, "mcp.json"), cursorConfig, { spaces: 2 });
|
|
575
1066
|
console.log(`\u2705 MCP server configured for Cursor in ${folderName}/.cursor/mcp.json`);
|
|
576
1067
|
} catch (error) {
|
|
577
1068
|
console.warn(`Warning: Could not set up MCP server for Cursor:`, error);
|
|
@@ -587,10 +1078,17 @@ var setupMCPServer = (client, targetPath) => {
|
|
|
587
1078
|
"agentmark-docs": {
|
|
588
1079
|
type: "http",
|
|
589
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
|
+
}
|
|
590
1088
|
}
|
|
591
1089
|
}
|
|
592
1090
|
};
|
|
593
|
-
|
|
1091
|
+
fs4.writeJsonSync(path2.join(targetPath, ".mcp.json"), mcpConfig, { spaces: 2 });
|
|
594
1092
|
console.log(`\u2705 MCP server configured for Claude Code in ${folderName}/.mcp.json`);
|
|
595
1093
|
} catch (error) {
|
|
596
1094
|
console.warn(`Warning: Could not set up MCP server for Claude Code:`, error);
|
|
@@ -599,70 +1097,112 @@ var setupMCPServer = (client, targetPath) => {
|
|
|
599
1097
|
return;
|
|
600
1098
|
}
|
|
601
1099
|
};
|
|
602
|
-
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 = []) => {
|
|
603
1101
|
try {
|
|
604
|
-
const modelProvider = "openai";
|
|
605
|
-
const model = "gpt-4o";
|
|
606
|
-
|
|
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
|
+
}
|
|
607
1110
|
const folderName = targetPath;
|
|
608
|
-
|
|
1111
|
+
fs4.ensureDirSync(`${targetPath}/agentmark`);
|
|
609
1112
|
setupMCPServer(client, targetPath);
|
|
610
1113
|
createExamplePrompts(model, targetPath, adapter);
|
|
611
1114
|
console.log(`\u2705 Example prompts and datasets created in ${folderName}/agentmark/`);
|
|
612
1115
|
const langModels = Providers[modelProvider].languageModels.slice(0, 1);
|
|
613
|
-
|
|
1116
|
+
fs4.writeFileSync(
|
|
614
1117
|
`${targetPath}/agentmark.client.ts`,
|
|
615
1118
|
getClientConfigContent({ provider: modelProvider, languageModels: langModels, adapter, deploymentMode })
|
|
616
1119
|
);
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
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);
|
|
627
1167
|
console.log("Generating types from prompts...");
|
|
628
1168
|
try {
|
|
629
|
-
const agentmarkDir =
|
|
630
|
-
const
|
|
631
|
-
const typeDefinitions = await generateTypeDefinitions(
|
|
632
|
-
|
|
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);
|
|
633
1173
|
} catch (error) {
|
|
634
1174
|
console.warn("Warning: Could not generate types automatically:", error);
|
|
635
1175
|
console.log("You can generate types later by running: npx agentmark generate-types --root-dir agentmark");
|
|
636
|
-
|
|
1176
|
+
fs4.writeFileSync(`${targetPath}/agentmark.types.ts`, `// Auto-generated types from AgentMark
|
|
637
1177
|
// Run 'npx agentmark generate-types --root-dir agentmark' to generate types
|
|
638
1178
|
export default interface AgentmarkTypes {}
|
|
639
1179
|
`);
|
|
640
1180
|
}
|
|
641
1181
|
console.log("Creating development server entry point...");
|
|
642
|
-
const agentmarkInternalDir =
|
|
643
|
-
|
|
644
|
-
const adapterConfig = getAdapterConfig(adapter);
|
|
1182
|
+
const agentmarkInternalDir = path2.join(targetPath, ".agentmark");
|
|
1183
|
+
fs4.ensureDirSync(agentmarkInternalDir);
|
|
1184
|
+
const adapterConfig = getAdapterConfig(adapter, modelProvider);
|
|
645
1185
|
const { webhookHandler } = adapterConfig.classes;
|
|
646
1186
|
const devEntryContent = `// Auto-generated webhook server entry point
|
|
647
1187
|
// To customize, create a dev-server.ts file in your project root
|
|
648
1188
|
|
|
649
|
-
import { createWebhookServer } from '@agentmark/cli/runner-server';
|
|
1189
|
+
import { createWebhookServer } from '@agentmark-ai/cli/runner-server';
|
|
650
1190
|
import { ${webhookHandler} } from '${adapterConfig.package}/runner';
|
|
651
|
-
import { AgentMarkSDK } from '@agentmark/sdk';
|
|
1191
|
+
import { AgentMarkSDK } from '@agentmark-ai/sdk';
|
|
652
1192
|
import path from 'path';
|
|
653
1193
|
|
|
654
1194
|
async function main() {
|
|
655
1195
|
const args = process.argv.slice(2);
|
|
656
1196
|
const webhookPortArg = args.find(arg => arg.startsWith('--webhook-port='));
|
|
657
|
-
const
|
|
1197
|
+
const apiServerPortArg = args.find(arg => arg.startsWith('--api-server-port='));
|
|
658
1198
|
|
|
659
1199
|
const webhookPort = webhookPortArg ? parseInt(webhookPortArg.split('=')[1]) : 9417;
|
|
660
|
-
const
|
|
661
|
-
const
|
|
1200
|
+
const apiServerPort = apiServerPortArg ? parseInt(apiServerPortArg.split('=')[1]) : 9418;
|
|
1201
|
+
const apiServerUrl = \`http://localhost:\${apiServerPort}\`;
|
|
662
1202
|
|
|
663
1203
|
// Set environment for development mode before importing client
|
|
664
1204
|
process.env.NODE_ENV = 'development';
|
|
665
|
-
process.env.AGENTMARK_BASE_URL =
|
|
1205
|
+
process.env.AGENTMARK_BASE_URL = apiServerUrl;
|
|
666
1206
|
|
|
667
1207
|
// Now import client - it will pick up the dev environment
|
|
668
1208
|
const { client } = await import('../agentmark.client.js');
|
|
@@ -671,7 +1211,7 @@ async function main() {
|
|
|
671
1211
|
const sdk = new AgentMarkSDK({
|
|
672
1212
|
apiKey: '',
|
|
673
1213
|
appId: '',
|
|
674
|
-
baseUrl:
|
|
1214
|
+
baseUrl: apiServerUrl,
|
|
675
1215
|
});
|
|
676
1216
|
sdk.initTracing({ disableBatch: true });
|
|
677
1217
|
|
|
@@ -681,7 +1221,7 @@ async function main() {
|
|
|
681
1221
|
await createWebhookServer({
|
|
682
1222
|
port: webhookPort,
|
|
683
1223
|
handler,
|
|
684
|
-
|
|
1224
|
+
apiServerUrl,
|
|
685
1225
|
templatesDirectory
|
|
686
1226
|
});
|
|
687
1227
|
}
|
|
@@ -691,7 +1231,7 @@ main().catch((err) => {
|
|
|
691
1231
|
process.exit(1);
|
|
692
1232
|
});
|
|
693
1233
|
`;
|
|
694
|
-
|
|
1234
|
+
fs4.writeFileSync(path2.join(agentmarkInternalDir, "dev-entry.ts"), devEntryContent);
|
|
695
1235
|
console.log("\n\u2705 Agentmark initialization completed successfully!");
|
|
696
1236
|
console.log(
|
|
697
1237
|
`
|
|
@@ -707,11 +1247,21 @@ main().catch((err) => {
|
|
|
707
1247
|
console.log("\n" + "\u2550".repeat(70));
|
|
708
1248
|
console.log("Next Steps");
|
|
709
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
|
+
}
|
|
710
1259
|
console.log("\n Get Started:");
|
|
711
|
-
if (folderName !== "." && folderName !== "./") {
|
|
1260
|
+
if (folderName !== "." && folderName !== "./" && !isExistingProject) {
|
|
712
1261
|
console.log(` $ cd ${folderName}`);
|
|
713
1262
|
}
|
|
714
|
-
console.log(
|
|
1263
|
+
console.log(` $ ${runCmd} ${devScriptName}
|
|
1264
|
+
`);
|
|
715
1265
|
console.log("\u2500".repeat(70));
|
|
716
1266
|
console.log("Resources");
|
|
717
1267
|
console.log("\u2500".repeat(70));
|
|
@@ -723,18 +1273,715 @@ main().catch((err) => {
|
|
|
723
1273
|
}
|
|
724
1274
|
};
|
|
725
1275
|
|
|
1276
|
+
// src/utils/examples/create-python-app.ts
|
|
1277
|
+
import fs5 from "fs-extra";
|
|
1278
|
+
import * as path3 from "path";
|
|
1279
|
+
var setupMCPServer2 = (client, targetPath) => {
|
|
1280
|
+
if (client === "skip") {
|
|
1281
|
+
console.log("Skipping MCP server setup.");
|
|
1282
|
+
return;
|
|
1283
|
+
}
|
|
1284
|
+
const folderName = targetPath;
|
|
1285
|
+
if (client === "vscode") {
|
|
1286
|
+
try {
|
|
1287
|
+
console.log(`Setting up MCP server for VS Code in ${folderName}...`);
|
|
1288
|
+
const vscodeDir = path3.join(targetPath, ".vscode");
|
|
1289
|
+
fs5.ensureDirSync(vscodeDir);
|
|
1290
|
+
const mcpConfig = {
|
|
1291
|
+
servers: {
|
|
1292
|
+
"agentmark-docs": {
|
|
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
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
};
|
|
1304
|
+
fs5.writeJsonSync(path3.join(vscodeDir, "mcp.json"), mcpConfig, { spaces: 2 });
|
|
1305
|
+
console.log(`MCP server configured for VS Code in ${folderName}/.vscode/mcp.json`);
|
|
1306
|
+
} catch (error) {
|
|
1307
|
+
console.warn(`Warning: Could not set up MCP server for VS Code:`, error);
|
|
1308
|
+
}
|
|
1309
|
+
return;
|
|
1310
|
+
}
|
|
1311
|
+
if (client === "zed") {
|
|
1312
|
+
try {
|
|
1313
|
+
console.log(`Setting up MCP server for Zed in ${folderName}...`);
|
|
1314
|
+
const zedDir = path3.join(targetPath, ".zed");
|
|
1315
|
+
fs5.ensureDirSync(zedDir);
|
|
1316
|
+
const zedConfig = {
|
|
1317
|
+
context_servers: {
|
|
1318
|
+
"agentmark-docs": {
|
|
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
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
};
|
|
1330
|
+
fs5.writeJsonSync(path3.join(zedDir, "settings.json"), zedConfig, { spaces: 2 });
|
|
1331
|
+
console.log(`MCP server configured for Zed in ${folderName}/.zed/settings.json`);
|
|
1332
|
+
} catch (error) {
|
|
1333
|
+
console.warn(`Warning: Could not set up MCP server for Zed:`, error);
|
|
1334
|
+
}
|
|
1335
|
+
return;
|
|
1336
|
+
}
|
|
1337
|
+
if (client === "cursor") {
|
|
1338
|
+
try {
|
|
1339
|
+
console.log(`Setting up MCP server for Cursor in ${folderName}...`);
|
|
1340
|
+
const cursorDir = path3.join(targetPath, ".cursor");
|
|
1341
|
+
fs5.ensureDirSync(cursorDir);
|
|
1342
|
+
const cursorConfig = {
|
|
1343
|
+
mcpServers: {
|
|
1344
|
+
"agentmark-docs": {
|
|
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
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
};
|
|
1356
|
+
fs5.writeJsonSync(path3.join(cursorDir, "mcp.json"), cursorConfig, { spaces: 2 });
|
|
1357
|
+
console.log(`MCP server configured for Cursor in ${folderName}/.cursor/mcp.json`);
|
|
1358
|
+
} catch (error) {
|
|
1359
|
+
console.warn(`Warning: Could not set up MCP server for Cursor:`, error);
|
|
1360
|
+
}
|
|
1361
|
+
return;
|
|
1362
|
+
}
|
|
1363
|
+
if (client === "claude-code") {
|
|
1364
|
+
try {
|
|
1365
|
+
console.log(`Setting up MCP server for Claude Code in ${folderName}...`);
|
|
1366
|
+
const mcpConfig = {
|
|
1367
|
+
mcpServers: {
|
|
1368
|
+
"agentmark-docs": {
|
|
1369
|
+
type: "http",
|
|
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
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
};
|
|
1381
|
+
fs5.writeJsonSync(path3.join(targetPath, ".mcp.json"), mcpConfig, { spaces: 2 });
|
|
1382
|
+
console.log(`MCP server configured for Claude Code in ${folderName}/.mcp.json`);
|
|
1383
|
+
} catch (error) {
|
|
1384
|
+
console.warn(`Warning: Could not set up MCP server for Claude Code:`, error);
|
|
1385
|
+
}
|
|
1386
|
+
return;
|
|
1387
|
+
}
|
|
1388
|
+
};
|
|
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
|
+
}
|
|
1425
|
+
return `[project]
|
|
1426
|
+
name = "${projectName}"
|
|
1427
|
+
version = "0.1.0"
|
|
1428
|
+
description = "An AgentMark application using Pydantic AI"
|
|
1429
|
+
requires-python = ">=3.12"
|
|
1430
|
+
dependencies = [
|
|
1431
|
+
"agentmark-pydantic-ai>=0.1.0",
|
|
1432
|
+
"agentmark-prompt-core>=0.1.0",
|
|
1433
|
+
"python-dotenv>=1.0.0",
|
|
1434
|
+
"pydantic-ai[openai]>=0.1.0",
|
|
1435
|
+
]
|
|
1436
|
+
|
|
1437
|
+
[project.optional-dependencies]
|
|
1438
|
+
dev = [
|
|
1439
|
+
"pytest>=7.0",
|
|
1440
|
+
"pytest-asyncio>=0.21",
|
|
1441
|
+
"mypy>=1.0",
|
|
1442
|
+
]
|
|
1443
|
+
anthropic = ["pydantic-ai[anthropic]"]
|
|
1444
|
+
gemini = ["pydantic-ai[gemini]"]
|
|
1445
|
+
|
|
1446
|
+
[build-system]
|
|
1447
|
+
requires = ["hatchling"]
|
|
1448
|
+
build-backend = "hatchling.build"
|
|
1449
|
+
|
|
1450
|
+
[tool.pytest.ini_options]
|
|
1451
|
+
asyncio_mode = "auto"
|
|
1452
|
+
|
|
1453
|
+
[tool.mypy]
|
|
1454
|
+
strict = true
|
|
1455
|
+
`;
|
|
1456
|
+
};
|
|
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
|
+
}
|
|
1509
|
+
return `"""AgentMark client configuration.
|
|
1510
|
+
|
|
1511
|
+
This file configures the AgentMark client with Pydantic AI adapter.
|
|
1512
|
+
Customize the model registry and tool registry as needed.
|
|
1513
|
+
"""
|
|
1514
|
+
|
|
1515
|
+
import os
|
|
1516
|
+
from pathlib import Path
|
|
1517
|
+
from dotenv import load_dotenv
|
|
1518
|
+
|
|
1519
|
+
from agentmark.prompt_core import FileLoader
|
|
1520
|
+
from agentmark_pydantic_ai_v0 import (
|
|
1521
|
+
create_pydantic_ai_client,
|
|
1522
|
+
create_default_model_registry,
|
|
1523
|
+
PydanticAIToolRegistry,
|
|
1524
|
+
)
|
|
1525
|
+
|
|
1526
|
+
# Load environment variables
|
|
1527
|
+
load_dotenv()
|
|
1528
|
+
|
|
1529
|
+
# Configure model registry with default mappings
|
|
1530
|
+
# Supports: gpt-*, claude-*, gemini-*, etc.
|
|
1531
|
+
model_registry = create_default_model_registry()
|
|
1532
|
+
|
|
1533
|
+
# Configure tool registry for custom tools
|
|
1534
|
+
tool_registry = PydanticAIToolRegistry()
|
|
1535
|
+
|
|
1536
|
+
# Example tool registration:
|
|
1537
|
+
# @tool_registry.register("search")
|
|
1538
|
+
# async def search_web(args: dict, ctx: dict | None) -> str:
|
|
1539
|
+
# query = args["query"]
|
|
1540
|
+
# return f"Search results for: {query}"
|
|
1541
|
+
|
|
1542
|
+
# Create file loader for local development
|
|
1543
|
+
# Uses the project root as base directory for resolving relative paths
|
|
1544
|
+
project_root = Path(__file__).parent.resolve()
|
|
1545
|
+
loader = FileLoader(base_dir=str(project_root))
|
|
1546
|
+
|
|
1547
|
+
# Create the client
|
|
1548
|
+
client = create_pydantic_ai_client(
|
|
1549
|
+
model_registry=model_registry,
|
|
1550
|
+
tool_registry=tool_registry,
|
|
1551
|
+
loader=loader,
|
|
1552
|
+
)
|
|
1553
|
+
|
|
1554
|
+
__all__ = ["client"]
|
|
1555
|
+
`;
|
|
1556
|
+
};
|
|
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
|
+
}
|
|
1608
|
+
return `"""Example usage of AgentMark with Pydantic AI.
|
|
1609
|
+
|
|
1610
|
+
Run with: python main.py
|
|
1611
|
+
"""
|
|
1612
|
+
|
|
1613
|
+
import asyncio
|
|
1614
|
+
import json
|
|
1615
|
+
from pathlib import Path
|
|
1616
|
+
|
|
1617
|
+
from agentmark_pydantic_ai_v0 import run_text_prompt
|
|
1618
|
+
from agentmark_client import client
|
|
1619
|
+
|
|
1620
|
+
|
|
1621
|
+
async def main():
|
|
1622
|
+
"""Run the party planner prompt."""
|
|
1623
|
+
# Load the prompt AST (in production, use the API loader)
|
|
1624
|
+
prompt_path = Path("agentmark/party-planner.prompt.mdx.json")
|
|
1625
|
+
|
|
1626
|
+
if not prompt_path.exists():
|
|
1627
|
+
print("Prompt file not found. Run 'agentmark build' first.")
|
|
1628
|
+
return
|
|
1629
|
+
|
|
1630
|
+
with open(prompt_path) as f:
|
|
1631
|
+
ast = json.load(f)
|
|
1632
|
+
|
|
1633
|
+
# Load and format the prompt
|
|
1634
|
+
prompt = await client.load_text_prompt(ast)
|
|
1635
|
+
params = await prompt.format(props={
|
|
1636
|
+
"numberOfGuests": 10,
|
|
1637
|
+
"theme": "80s disco",
|
|
1638
|
+
"dietaryRestrictions": ["vegetarian", "gluten-free"],
|
|
1639
|
+
})
|
|
1640
|
+
|
|
1641
|
+
# Execute the prompt
|
|
1642
|
+
print("Running party planner prompt...")
|
|
1643
|
+
result = await run_text_prompt(params)
|
|
1644
|
+
|
|
1645
|
+
print("\\n" + "=" * 50)
|
|
1646
|
+
print("Party Plan:")
|
|
1647
|
+
print("=" * 50)
|
|
1648
|
+
print(result.output)
|
|
1649
|
+
print("\\n" + "-" * 50)
|
|
1650
|
+
print(f"Tokens used: {result.usage.total_tokens}")
|
|
1651
|
+
|
|
1652
|
+
|
|
1653
|
+
if __name__ == "__main__":
|
|
1654
|
+
asyncio.run(main())
|
|
1655
|
+
`;
|
|
1656
|
+
};
|
|
1657
|
+
var getDevServerContent = (adapter) => {
|
|
1658
|
+
const adapterPackage = adapter === "claude-agent-sdk" ? "agentmark_claude_agent_sdk" : "agentmark_pydantic_ai_v0";
|
|
1659
|
+
return `"""Auto-generated webhook server for AgentMark development.
|
|
1660
|
+
|
|
1661
|
+
This server is started by 'npm run dev' (agentmark dev) and handles
|
|
1662
|
+
prompt execution requests from the CLI.
|
|
1663
|
+
"""
|
|
1664
|
+
|
|
1665
|
+
import argparse
|
|
1666
|
+
import sys
|
|
1667
|
+
from pathlib import Path
|
|
1668
|
+
|
|
1669
|
+
# Add parent directory to path for imports
|
|
1670
|
+
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
1671
|
+
|
|
1672
|
+
from ${adapterPackage} import create_webhook_server
|
|
1673
|
+
from agentmark_client import client
|
|
1674
|
+
|
|
1675
|
+
|
|
1676
|
+
if __name__ == "__main__":
|
|
1677
|
+
parser = argparse.ArgumentParser()
|
|
1678
|
+
parser.add_argument("--webhook-port", type=int, default=9417)
|
|
1679
|
+
parser.add_argument("--api-server-port", type=int, default=9418)
|
|
1680
|
+
args = parser.parse_args()
|
|
1681
|
+
|
|
1682
|
+
create_webhook_server(client, args.webhook_port, args.api_server_port)
|
|
1683
|
+
`;
|
|
1684
|
+
};
|
|
1685
|
+
var getEnvContent = (apiKey, adapter) => {
|
|
1686
|
+
if (adapter === "claude-agent-sdk") {
|
|
1687
|
+
return `# Anthropic API Key
|
|
1688
|
+
ANTHROPIC_API_KEY=${apiKey}
|
|
1689
|
+
`;
|
|
1690
|
+
}
|
|
1691
|
+
return `# OpenAI API Key
|
|
1692
|
+
OPENAI_API_KEY=${apiKey}
|
|
1693
|
+
|
|
1694
|
+
# For Anthropic models, add:
|
|
1695
|
+
# ANTHROPIC_API_KEY=your-key-here
|
|
1696
|
+
|
|
1697
|
+
# For Google Gemini models, add:
|
|
1698
|
+
# GOOGLE_API_KEY=your-key-here
|
|
1699
|
+
`;
|
|
1700
|
+
};
|
|
1701
|
+
var getGitignoreContent = () => {
|
|
1702
|
+
return `# Python
|
|
1703
|
+
__pycache__/
|
|
1704
|
+
*.py[cod]
|
|
1705
|
+
*$py.class
|
|
1706
|
+
.venv/
|
|
1707
|
+
venv/
|
|
1708
|
+
.env
|
|
1709
|
+
|
|
1710
|
+
# AgentMark
|
|
1711
|
+
*.agentmark-outputs/
|
|
1712
|
+
.agentmark/
|
|
1713
|
+
|
|
1714
|
+
# IDE
|
|
1715
|
+
.idea/
|
|
1716
|
+
.vscode/
|
|
1717
|
+
*.swp
|
|
1718
|
+
|
|
1719
|
+
# Build
|
|
1720
|
+
dist/
|
|
1721
|
+
build/
|
|
1722
|
+
*.egg-info/
|
|
1723
|
+
|
|
1724
|
+
# Testing
|
|
1725
|
+
.pytest_cache/
|
|
1726
|
+
.coverage
|
|
1727
|
+
htmlcov/
|
|
1728
|
+
`;
|
|
1729
|
+
};
|
|
1730
|
+
var createPythonApp = async (client, targetPath = ".", apiKey = "", deploymentMode = "cloud", adapter = "pydantic-ai", projectInfo = null, resolutions = []) => {
|
|
1731
|
+
try {
|
|
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
|
+
}
|
|
1740
|
+
const folderName = targetPath;
|
|
1741
|
+
fs5.ensureDirSync(`${targetPath}/agentmark`);
|
|
1742
|
+
setupMCPServer2(client, targetPath);
|
|
1743
|
+
createExamplePrompts(model, targetPath, adapter);
|
|
1744
|
+
console.log(`Example prompts and datasets created in ${folderName}/agentmark/`);
|
|
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!");
|
|
1819
|
+
console.log(
|
|
1820
|
+
`
|
|
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
|
|
1822
|
+
\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u255A\u2588\u2588\u2557 \u2588\u2588\u2554\u255D\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551
|
|
1823
|
+
\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u255A\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551
|
|
1824
|
+
\u2588\u2588\u2554\u2550\u2550\u2550\u255D \u255A\u2588\u2588\u2554\u255D \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551
|
|
1825
|
+
\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551
|
|
1826
|
+
\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D
|
|
1827
|
+
+ AgentMark
|
|
1828
|
+
`
|
|
1829
|
+
);
|
|
1830
|
+
console.log("\n" + "\u2550".repeat(70));
|
|
1831
|
+
console.log("Next Steps");
|
|
1832
|
+
console.log("\u2550".repeat(70));
|
|
1833
|
+
console.log("\n Get Started:");
|
|
1834
|
+
if (folderName !== "." && folderName !== "./" && !isExistingProject) {
|
|
1835
|
+
console.log(` $ cd ${folderName}`);
|
|
1836
|
+
}
|
|
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
|
+
}
|
|
1846
|
+
console.log(" $ npm run dev\n");
|
|
1847
|
+
console.log("\u2500".repeat(70));
|
|
1848
|
+
console.log("Resources");
|
|
1849
|
+
console.log("\u2500".repeat(70));
|
|
1850
|
+
console.log(" Documentation: https://docs.agentmark.co");
|
|
1851
|
+
console.log("\u2550".repeat(70) + "\n");
|
|
1852
|
+
} catch (error) {
|
|
1853
|
+
console.error("Error creating Python app:", error);
|
|
1854
|
+
throw error;
|
|
1855
|
+
}
|
|
1856
|
+
};
|
|
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
|
+
|
|
726
1968
|
// src/index.ts
|
|
727
1969
|
var parseArgs = () => {
|
|
728
1970
|
const args = process.argv.slice(2);
|
|
729
1971
|
let deploymentMode;
|
|
1972
|
+
let language;
|
|
730
1973
|
for (const arg of args) {
|
|
731
1974
|
if (arg === "--cloud") {
|
|
732
1975
|
deploymentMode = "cloud";
|
|
733
1976
|
} else if (arg === "--self-host") {
|
|
734
1977
|
deploymentMode = "static";
|
|
1978
|
+
} else if (arg === "--python") {
|
|
1979
|
+
language = "python";
|
|
1980
|
+
} else if (arg === "--typescript") {
|
|
1981
|
+
language = "typescript";
|
|
735
1982
|
}
|
|
736
1983
|
}
|
|
737
|
-
return { deploymentMode };
|
|
1984
|
+
return { deploymentMode, language };
|
|
738
1985
|
};
|
|
739
1986
|
var main = async () => {
|
|
740
1987
|
const cliArgs = parseArgs();
|
|
@@ -745,35 +1992,73 @@ var main = async () => {
|
|
|
745
1992
|
agentmarkPath: "."
|
|
746
1993
|
};
|
|
747
1994
|
console.log("Initializing project.");
|
|
748
|
-
const { folderName } = await
|
|
1995
|
+
const { folderName } = await prompts2({
|
|
749
1996
|
name: "folderName",
|
|
750
1997
|
type: "text",
|
|
751
1998
|
message: "Where would you like to create your AgentMark app?",
|
|
752
1999
|
initial: "my-agentmark-app"
|
|
753
2000
|
});
|
|
754
|
-
const
|
|
755
|
-
|
|
756
|
-
|
|
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);
|
|
2011
|
+
let language = cliArgs.language;
|
|
2012
|
+
if (!language) {
|
|
2013
|
+
const response = await prompts2({
|
|
2014
|
+
name: "language",
|
|
2015
|
+
type: "select",
|
|
2016
|
+
message: "Which language would you like to use?",
|
|
2017
|
+
choices: [
|
|
2018
|
+
{ title: "TypeScript", value: "typescript" },
|
|
2019
|
+
{ title: "Python", value: "python" }
|
|
2020
|
+
]
|
|
2021
|
+
});
|
|
2022
|
+
language = response.language;
|
|
2023
|
+
}
|
|
2024
|
+
let adapter;
|
|
2025
|
+
if (language === "python") {
|
|
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;
|
|
2036
|
+
} else {
|
|
2037
|
+
const response = await prompts2({
|
|
2038
|
+
name: "adapter",
|
|
2039
|
+
type: "select",
|
|
2040
|
+
message: "Which adapter would you like to use?",
|
|
2041
|
+
choices: [
|
|
2042
|
+
{ title: "AI SDK (Vercel)", value: "ai-sdk" },
|
|
2043
|
+
{ title: "Claude Agent SDK", value: "claude-agent-sdk" },
|
|
2044
|
+
{ title: "Mastra", value: "mastra" }
|
|
2045
|
+
]
|
|
2046
|
+
});
|
|
2047
|
+
adapter = response.adapter;
|
|
2048
|
+
}
|
|
2049
|
+
config.builtInModels = adapter === "claude-agent-sdk" ? ["claude-sonnet-4-20250514"] : ["gpt-4o"];
|
|
2050
|
+
const apiKeyName = adapter === "claude-agent-sdk" ? "Anthropic" : "OpenAI";
|
|
757
2051
|
let apiKey = "";
|
|
758
|
-
const { providedApiKey } = await
|
|
2052
|
+
const { providedApiKey } = await prompts2({
|
|
759
2053
|
name: "providedApiKey",
|
|
760
2054
|
type: "password",
|
|
761
|
-
message: `Enter your
|
|
2055
|
+
message: `Enter your ${apiKeyName} API key (or press Enter to skip):`,
|
|
762
2056
|
initial: ""
|
|
763
2057
|
});
|
|
764
2058
|
apiKey = providedApiKey || "";
|
|
765
|
-
const { adapter } = await prompts({
|
|
766
|
-
name: "adapter",
|
|
767
|
-
type: "select",
|
|
768
|
-
message: "Which adapter would you like to use?",
|
|
769
|
-
choices: [
|
|
770
|
-
{ title: "AI SDK (Vercel)", value: "ai-sdk" },
|
|
771
|
-
{ title: "Mastra", value: "mastra" }
|
|
772
|
-
]
|
|
773
|
-
});
|
|
774
2059
|
let deploymentMode = cliArgs.deploymentMode;
|
|
775
2060
|
if (!deploymentMode) {
|
|
776
|
-
const response = await
|
|
2061
|
+
const response = await prompts2({
|
|
777
2062
|
name: "deploymentMode",
|
|
778
2063
|
type: "select",
|
|
779
2064
|
message: "Use AgentMark Cloud or manage yourself?",
|
|
@@ -792,7 +2077,7 @@ var main = async () => {
|
|
|
792
2077
|
});
|
|
793
2078
|
deploymentMode = response.deploymentMode;
|
|
794
2079
|
}
|
|
795
|
-
const { client } = await
|
|
2080
|
+
const { client } = await prompts2({
|
|
796
2081
|
name: "client",
|
|
797
2082
|
type: "select",
|
|
798
2083
|
message: "Make your IDE an AgentMark expert",
|
|
@@ -804,8 +2089,18 @@ var main = async () => {
|
|
|
804
2089
|
{ title: "Skip", value: "skip" }
|
|
805
2090
|
]
|
|
806
2091
|
});
|
|
807
|
-
|
|
808
|
-
|
|
2092
|
+
if (language === "python") {
|
|
2093
|
+
await createPythonApp(client, targetPath, apiKey, deploymentMode, adapter, projectInfo, resolutions);
|
|
2094
|
+
} else {
|
|
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)");
|
|
2103
|
+
}
|
|
809
2104
|
};
|
|
810
2105
|
main().catch((error) => {
|
|
811
2106
|
console.error("Error:", error);
|