create-agentmark 0.10.8 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +105 -1
- package/dist/index.js +307 -2410
- package/dist/index.js.map +1 -1
- package/package.json +5 -6
- package/dist/utils/examples/templates/index.d.ts +0 -111
- package/dist/utils/examples/templates/index.js +0 -809
- package/dist/utils/examples/templates/index.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,2274 +1,175 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
-
var __esm = (fn, res) => function __init() {
|
|
5
|
-
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
6
|
-
};
|
|
7
|
-
var __export = (target, all) => {
|
|
8
|
-
for (var name in all)
|
|
9
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
// src/utils/install-skill.ts
|
|
13
|
-
var install_skill_exports = {};
|
|
14
|
-
__export(install_skill_exports, {
|
|
15
|
-
installAgentmarkSkill: () => installAgentmarkSkill
|
|
16
|
-
});
|
|
17
|
-
import { execFileSync } from "child_process";
|
|
18
|
-
var shouldSkip, installAgentmarkSkill;
|
|
19
|
-
var init_install_skill = __esm({
|
|
20
|
-
"src/utils/install-skill.ts"() {
|
|
21
|
-
"use strict";
|
|
22
|
-
shouldSkip = () => process.env.VITEST === "true" || process.env.NODE_ENV === "test" || process.env.AGENTMARK_SKIP_SKILL_INSTALL === "1";
|
|
23
|
-
installAgentmarkSkill = (targetPath) => {
|
|
24
|
-
if (shouldSkip()) {
|
|
25
|
-
console.log("\n\u23ED\uFE0F Skipping agent skill install (test environment detected).");
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
try {
|
|
29
|
-
console.log("\n\u{1F4DA} Installing AgentMark agent skill...");
|
|
30
|
-
console.log(" (teaches Claude Code / Codex / Cursor / Copilot how to use AgentMark)");
|
|
31
|
-
execFileSync(
|
|
32
|
-
"npx",
|
|
33
|
-
["--yes", "skills", "add", "agentmark-ai/skills"],
|
|
34
|
-
{
|
|
35
|
-
cwd: targetPath,
|
|
36
|
-
stdio: "inherit"
|
|
37
|
-
}
|
|
38
|
-
);
|
|
39
|
-
console.log("\u2705 Agent skill installed at ./.agents/skills/agentmark/");
|
|
40
|
-
} catch (error) {
|
|
41
|
-
console.warn(
|
|
42
|
-
"\n\u26A0\uFE0F Could not install the AgentMark agent skill automatically."
|
|
43
|
-
);
|
|
44
|
-
console.warn(" You can install it later with:");
|
|
45
|
-
console.warn(" cd " + targetPath);
|
|
46
|
-
console.warn(" npx skills add agentmark-ai/skills");
|
|
47
|
-
if (error instanceof Error) {
|
|
48
|
-
console.warn(` Reason: ${error.message.split("\n")[0]}`);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
// src/index.ts
|
|
56
|
-
import fs8 from "fs-extra";
|
|
57
|
-
import path6 from "path";
|
|
58
|
-
import prompts2 from "prompts";
|
|
59
|
-
|
|
60
|
-
// src/utils/examples/create-example-app.ts
|
|
61
|
-
import fs4 from "fs-extra";
|
|
62
|
-
import * as path2 from "path";
|
|
63
|
-
|
|
64
|
-
// src/utils/examples/templates/adapters.ts
|
|
65
|
-
var createAdapterConfig = (provider) => {
|
|
66
|
-
return {
|
|
67
|
-
"ai-sdk": {
|
|
68
|
-
package: "@agentmark-ai/ai-sdk-v5-adapter",
|
|
69
|
-
dependencies: ["ai@^5", `@ai-sdk/${provider}@^2`],
|
|
70
|
-
classes: {
|
|
71
|
-
modelRegistry: "VercelAIModelRegistry",
|
|
72
|
-
webhookHandler: "VercelAdapterWebhookHandler"
|
|
73
|
-
}
|
|
74
|
-
},
|
|
75
|
-
mastra: {
|
|
76
|
-
package: "@agentmark-ai/mastra-v0-adapter",
|
|
77
|
-
dependencies: [
|
|
78
|
-
"@mastra/core@<0.20.0",
|
|
79
|
-
"@mastra/mcp@<0.13.4",
|
|
80
|
-
`@ai-sdk/${provider}@<2`,
|
|
81
|
-
"ai@^4"
|
|
82
|
-
],
|
|
83
|
-
classes: {
|
|
84
|
-
modelRegistry: "MastraModelRegistry",
|
|
85
|
-
webhookHandler: "MastraAdapterWebhookHandler"
|
|
86
|
-
}
|
|
87
|
-
},
|
|
88
|
-
"claude-agent-sdk": {
|
|
89
|
-
package: "@agentmark-ai/claude-agent-sdk-v0-adapter",
|
|
90
|
-
dependencies: ["@anthropic-ai/claude-agent-sdk@^0.1.0"],
|
|
91
|
-
classes: {
|
|
92
|
-
modelRegistry: "ClaudeAgentModelRegistry",
|
|
93
|
-
webhookHandler: "ClaudeAgentWebhookHandler"
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
};
|
|
98
|
-
function getAdapterConfig(adapter, provider) {
|
|
99
|
-
const config = createAdapterConfig(provider)[adapter];
|
|
100
|
-
if (!config) {
|
|
101
|
-
throw new Error(
|
|
102
|
-
`Unknown adapter: ${adapter}. Available adapters: ${Object.keys(
|
|
103
|
-
createAdapterConfig(provider)
|
|
104
|
-
).join(", ")}`
|
|
105
|
-
);
|
|
106
|
-
}
|
|
107
|
-
return config;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// src/utils/examples/templates/app-index.ts
|
|
111
|
-
var getIndexFileContent = (adapter = "ai-sdk", deploymentMode = "cloud") => {
|
|
112
|
-
const isCloud = deploymentMode === "cloud";
|
|
113
|
-
const tracingImport = `import { AgentMarkSDK } from "@agentmark-ai/sdk";
|
|
114
|
-
`;
|
|
115
|
-
const cloudTracingInit = `
|
|
116
|
-
// Initialize tracing - traces will be sent to AgentMark Cloud
|
|
117
|
-
// To disable tracing, comment out sdk.initTracing() below
|
|
118
|
-
const sdk = new AgentMarkSDK({
|
|
119
|
-
apiKey: process.env.AGENTMARK_API_KEY ?? "",
|
|
120
|
-
appId: process.env.AGENTMARK_APP_ID ?? "",
|
|
121
|
-
});
|
|
122
|
-
sdk.initTracing({ disableBatch: true });
|
|
123
|
-
`;
|
|
124
|
-
const staticTracingInit = `
|
|
125
|
-
// Initialize tracing - traces will be sent to local dev server
|
|
126
|
-
// Make sure to run "npx agentmark dev" in another terminal first
|
|
127
|
-
// To disable tracing, comment out sdk.initTracing() below
|
|
128
|
-
const sdk = new AgentMarkSDK({
|
|
129
|
-
apiKey: "",
|
|
130
|
-
appId: "",
|
|
131
|
-
baseUrl: "http://localhost:9418",
|
|
132
|
-
});
|
|
133
|
-
sdk.initTracing({ disableBatch: true });
|
|
134
|
-
`;
|
|
135
|
-
const tracingInit = isCloud ? cloudTracingInit : staticTracingInit;
|
|
136
|
-
if (adapter === "claude-agent-sdk") {
|
|
137
|
-
return `import "dotenv/config";
|
|
138
|
-
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
139
|
-
import { withTracing } from "@agentmark-ai/claude-agent-sdk-v0-adapter";
|
|
140
|
-
${tracingImport}import { client } from "./agentmark.client";
|
|
141
|
-
${tracingInit}
|
|
142
|
-
const telemetry = {
|
|
143
|
-
isEnabled: true,
|
|
144
|
-
metadata: {
|
|
145
|
-
trace_name: "customer-support",
|
|
146
|
-
user_id: "user-123",
|
|
147
|
-
session_id: "session-123",
|
|
148
|
-
session_name: "my-first-session",
|
|
149
|
-
},
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
const runCustomerSupport = async (customer_message: string) => {
|
|
153
|
-
const prompt = await client.loadTextPrompt("customer-support-agent");
|
|
154
|
-
const adapted = await prompt.format({
|
|
155
|
-
props: {
|
|
156
|
-
customer_question: customer_message,
|
|
157
|
-
},
|
|
158
|
-
telemetry,
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
// Execute with Claude Agent SDK using withTracing for telemetry
|
|
162
|
-
// The adapted object contains { query, telemetry } ready for withTracing()
|
|
163
|
-
const tracedResult = await withTracing(query, adapted);
|
|
164
|
-
|
|
165
|
-
// traceId is available immediately
|
|
166
|
-
console.log("Trace ID:", tracedResult.traceId);
|
|
167
|
-
|
|
168
|
-
let result = "";
|
|
169
|
-
for await (const message of tracedResult) {
|
|
170
|
-
if (message.type === "result" && message.subtype === "success") {
|
|
171
|
-
result = message.result || "";
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
return result;
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
const main = async () => {
|
|
179
|
-
try {
|
|
180
|
-
const user_message = "How long does shipping take?";
|
|
181
|
-
const assistant = await runCustomerSupport(user_message);
|
|
182
|
-
console.log("Customer support response:", assistant);
|
|
183
|
-
} catch (error) {
|
|
184
|
-
console.error(error);
|
|
185
|
-
}
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
main();
|
|
189
|
-
`;
|
|
190
|
-
} else if (adapter === "mastra") {
|
|
191
|
-
return `import "dotenv/config";
|
|
192
|
-
import { Agent } from "@mastra/core/agent";
|
|
193
|
-
${tracingImport}import { client } from "./agentmark.client";
|
|
194
|
-
${tracingInit}
|
|
195
|
-
const telemetry = {
|
|
196
|
-
isEnabled: true,
|
|
197
|
-
metadata: {
|
|
198
|
-
trace_name: "customer-support",
|
|
199
|
-
user_id: "user-123",
|
|
200
|
-
session_id: "session-123",
|
|
201
|
-
session_name: "my-first-session",
|
|
202
|
-
},
|
|
203
|
-
};
|
|
204
|
-
|
|
205
|
-
const runCustomerSupport = async (customer_message: string) => {
|
|
206
|
-
const prompt = await client.loadTextPrompt("customer-support-agent");
|
|
207
|
-
const agentConfig = await prompt.formatAgent({
|
|
208
|
-
options: {
|
|
209
|
-
telemetry,
|
|
210
|
-
},
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
const [messages, generateOptions] = await agentConfig.formatMessages({
|
|
214
|
-
props: {
|
|
215
|
-
customer_question: customer_message,
|
|
216
|
-
},
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
const agent = new Agent(agentConfig);
|
|
220
|
-
const response = await agent.generate(messages, generateOptions);
|
|
221
|
-
|
|
222
|
-
return (response as any).text || (response as any).content || String(response);
|
|
223
|
-
};
|
|
224
|
-
|
|
225
|
-
const main = async () => {
|
|
226
|
-
try {
|
|
227
|
-
const user_message = "How long does shipping take?";
|
|
228
|
-
const assistant = await runCustomerSupport(user_message);
|
|
229
|
-
console.log("Customer support response:", assistant);
|
|
230
|
-
} catch (error) {
|
|
231
|
-
console.error(error);
|
|
232
|
-
}
|
|
233
|
-
};
|
|
234
|
-
|
|
235
|
-
main();
|
|
236
|
-
`;
|
|
237
|
-
} else {
|
|
238
|
-
return `import "dotenv/config";
|
|
239
|
-
import { generateText } from "ai";
|
|
240
|
-
${tracingImport}import { client } from "./agentmark.client";
|
|
241
|
-
${tracingInit}
|
|
242
|
-
const telemetry = {
|
|
243
|
-
isEnabled: true,
|
|
244
|
-
metadata: {
|
|
245
|
-
trace_name: "customer-support",
|
|
246
|
-
user_id: "user-123",
|
|
247
|
-
session_id: "session-123",
|
|
248
|
-
session_name: "my-first-session",
|
|
249
|
-
},
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
const runCustomerSupport = async (customer_message: string) => {
|
|
253
|
-
const prompt = await client.loadTextPrompt("customer-support-agent");
|
|
254
|
-
const vercelInput = await prompt.format({
|
|
255
|
-
props: {
|
|
256
|
-
customer_question: customer_message,
|
|
257
|
-
},
|
|
258
|
-
telemetry,
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
const resp = await generateText(vercelInput);
|
|
262
|
-
|
|
263
|
-
return resp.text;
|
|
264
|
-
};
|
|
265
|
-
|
|
266
|
-
const main = async () => {
|
|
267
|
-
try {
|
|
268
|
-
const user_message = "How long does shipping take?";
|
|
269
|
-
const assistant = await runCustomerSupport(user_message);
|
|
270
|
-
console.log("Customer support response:", assistant);
|
|
271
|
-
} catch (error) {
|
|
272
|
-
console.error(error);
|
|
273
|
-
}
|
|
274
|
-
};
|
|
275
|
-
|
|
276
|
-
main();
|
|
277
|
-
`;
|
|
278
|
-
}
|
|
279
|
-
};
|
|
280
|
-
|
|
281
|
-
// src/utils/examples/templates/env.ts
|
|
282
|
-
var getEnvFileContent = (_modelProvider, apiKey = "", adapter = "ai-sdk", deploymentMode = "cloud") => {
|
|
283
|
-
const apiKeyValue = apiKey || "your_api_key_here";
|
|
284
|
-
const apiKeyName = adapter === "claude-agent-sdk" ? "ANTHROPIC_API_KEY" : "OPENAI_API_KEY";
|
|
285
|
-
const cloudEnvVars = deploymentMode === "cloud" ? `
|
|
286
|
-
# AgentMark Cloud \u2014 required for managed deployments
|
|
287
|
-
AGENTMARK_API_KEY=your_agentmark_api_key
|
|
288
|
-
AGENTMARK_APP_ID=your_agentmark_app_id
|
|
289
|
-
` : `
|
|
290
|
-
# Cloud deployment: Set these environment variables
|
|
291
|
-
# AGENTMARK_BASE_URL=https://api.agentmark.co
|
|
292
|
-
# AGENTMARK_API_KEY=your_agentmark_api_key
|
|
293
|
-
# AGENTMARK_APP_ID=your_agentmark_app_id
|
|
294
|
-
`;
|
|
295
|
-
return `${apiKeyName}=${apiKeyValue}
|
|
296
|
-
${cloudEnvVars}
|
|
297
|
-
# Learn more: https://docs.agentmark.co/getting-started/quickstart
|
|
298
|
-
`;
|
|
299
|
-
};
|
|
300
|
-
|
|
301
|
-
// src/utils/examples/templates/package-setup.ts
|
|
302
|
-
import fs2 from "fs-extra";
|
|
303
|
-
import { execSync } from "child_process";
|
|
304
|
-
|
|
305
|
-
// src/utils/file-merge.ts
|
|
306
|
-
import fs from "fs-extra";
|
|
307
|
-
import path from "path";
|
|
308
|
-
function mergePackageJson(targetPath, agentmarkDeps, agentmarkDevDeps, agentmarkScripts) {
|
|
309
|
-
const packageJsonPath = path.join(targetPath, "package.json");
|
|
310
|
-
const result = {
|
|
311
|
-
success: false,
|
|
312
|
-
warnings: [],
|
|
313
|
-
added: [],
|
|
314
|
-
skipped: []
|
|
315
|
-
};
|
|
316
|
-
try {
|
|
317
|
-
if (!fs.existsSync(packageJsonPath)) {
|
|
318
|
-
result.warnings.push("No existing package.json found");
|
|
319
|
-
return result;
|
|
320
|
-
}
|
|
321
|
-
const existing = fs.readJsonSync(packageJsonPath);
|
|
322
|
-
if (!existing.dependencies) {
|
|
323
|
-
existing.dependencies = {};
|
|
324
|
-
}
|
|
325
|
-
if (!existing.devDependencies) {
|
|
326
|
-
existing.devDependencies = {};
|
|
327
|
-
}
|
|
328
|
-
if (!existing.scripts) {
|
|
329
|
-
existing.scripts = {};
|
|
330
|
-
}
|
|
331
|
-
const deps = existing.dependencies;
|
|
332
|
-
const devDeps = existing.devDependencies;
|
|
333
|
-
const scripts = existing.scripts;
|
|
334
|
-
for (const [pkg, version] of Object.entries(agentmarkDeps)) {
|
|
335
|
-
if (deps[pkg]) {
|
|
336
|
-
result.skipped.push(`dependency: ${pkg} (already exists)`);
|
|
337
|
-
} else {
|
|
338
|
-
deps[pkg] = version;
|
|
339
|
-
result.added.push(`dependency: ${pkg}@${version}`);
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
for (const [pkg, version] of Object.entries(agentmarkDevDeps)) {
|
|
343
|
-
if (devDeps[pkg]) {
|
|
344
|
-
result.skipped.push(`devDependency: ${pkg} (already exists)`);
|
|
345
|
-
} else {
|
|
346
|
-
devDeps[pkg] = version;
|
|
347
|
-
result.added.push(`devDependency: ${pkg}@${version}`);
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
for (const [scriptName, scriptCmd] of Object.entries(agentmarkScripts)) {
|
|
351
|
-
if (scripts[scriptName]) {
|
|
352
|
-
const namespacedName = `agentmark:${scriptName}`;
|
|
353
|
-
if (scripts[namespacedName]) {
|
|
354
|
-
result.skipped.push(`script: ${scriptName}`);
|
|
355
|
-
result.warnings.push(
|
|
356
|
-
`Script "${scriptName}" and "${namespacedName}" both already exist. Skipping.`
|
|
357
|
-
);
|
|
358
|
-
} else {
|
|
359
|
-
scripts[namespacedName] = scriptCmd;
|
|
360
|
-
result.added.push(`script: ${namespacedName} (namespaced due to conflict)`);
|
|
361
|
-
result.warnings.push(
|
|
362
|
-
`Script "${scriptName}" already exists. Added as "${namespacedName}" instead.`
|
|
363
|
-
);
|
|
364
|
-
}
|
|
365
|
-
} else {
|
|
366
|
-
scripts[scriptName] = scriptCmd;
|
|
367
|
-
result.added.push(`script: ${scriptName}`);
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
fs.writeJsonSync(packageJsonPath, existing, { spaces: 2 });
|
|
371
|
-
result.success = true;
|
|
372
|
-
result.content = JSON.stringify(existing, null, 2);
|
|
373
|
-
return result;
|
|
374
|
-
} catch (error) {
|
|
375
|
-
result.warnings.push(`Error merging package.json: ${error}`);
|
|
376
|
-
return result;
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
function appendGitignore(targetPath, entries) {
|
|
380
|
-
const gitignorePath = path.join(targetPath, ".gitignore");
|
|
381
|
-
const result = {
|
|
382
|
-
success: false,
|
|
383
|
-
warnings: [],
|
|
384
|
-
added: [],
|
|
385
|
-
skipped: []
|
|
386
|
-
};
|
|
387
|
-
try {
|
|
388
|
-
let existingContent = "";
|
|
389
|
-
if (fs.existsSync(gitignorePath)) {
|
|
390
|
-
existingContent = fs.readFileSync(gitignorePath, "utf-8");
|
|
391
|
-
}
|
|
392
|
-
const existingEntries = new Set(
|
|
393
|
-
existingContent.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#")).map((line) => line.replace(/\/$/, ""))
|
|
394
|
-
// Remove trailing slashes for comparison
|
|
395
|
-
);
|
|
396
|
-
const entriesToAdd = [];
|
|
397
|
-
for (const entry of entries) {
|
|
398
|
-
const normalizedEntry = entry.replace(/\/$/, "");
|
|
399
|
-
if (existingEntries.has(normalizedEntry)) {
|
|
400
|
-
result.skipped.push(entry);
|
|
401
|
-
} else {
|
|
402
|
-
entriesToAdd.push(entry);
|
|
403
|
-
result.added.push(entry);
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
if (entriesToAdd.length > 0) {
|
|
407
|
-
let newContent = existingContent;
|
|
408
|
-
if (newContent && !newContent.endsWith("\n")) {
|
|
409
|
-
newContent += "\n";
|
|
410
|
-
}
|
|
411
|
-
if (newContent.trim()) {
|
|
412
|
-
newContent += "\n";
|
|
413
|
-
}
|
|
414
|
-
newContent += "# AgentMark\n";
|
|
415
|
-
newContent += entriesToAdd.join("\n");
|
|
416
|
-
newContent += "\n";
|
|
417
|
-
fs.writeFileSync(gitignorePath, newContent);
|
|
418
|
-
result.content = newContent;
|
|
419
|
-
}
|
|
420
|
-
result.success = true;
|
|
421
|
-
return result;
|
|
422
|
-
} catch (error) {
|
|
423
|
-
result.warnings.push(`Error appending to .gitignore: ${error}`);
|
|
424
|
-
return result;
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
function appendEnv(targetPath, envVars) {
|
|
428
|
-
const envPath = path.join(targetPath, ".env");
|
|
429
|
-
const result = {
|
|
430
|
-
success: false,
|
|
431
|
-
warnings: [],
|
|
432
|
-
added: [],
|
|
433
|
-
skipped: []
|
|
434
|
-
};
|
|
435
|
-
try {
|
|
436
|
-
let existingContent = "";
|
|
437
|
-
if (fs.existsSync(envPath)) {
|
|
438
|
-
existingContent = fs.readFileSync(envPath, "utf-8");
|
|
439
|
-
}
|
|
440
|
-
const existingKeys = /* @__PURE__ */ new Set();
|
|
441
|
-
const lines = existingContent.split("\n");
|
|
442
|
-
for (const line of lines) {
|
|
443
|
-
const trimmed = line.trim();
|
|
444
|
-
if (trimmed && !trimmed.startsWith("#")) {
|
|
445
|
-
const match = trimmed.match(/^([^=]+)=/);
|
|
446
|
-
if (match && match[1]) {
|
|
447
|
-
existingKeys.add(match[1]);
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
const varsToAdd = [];
|
|
452
|
-
for (const [key, value] of Object.entries(envVars)) {
|
|
453
|
-
if (existingKeys.has(key)) {
|
|
454
|
-
result.skipped.push(key);
|
|
455
|
-
} else {
|
|
456
|
-
varsToAdd.push([key, value]);
|
|
457
|
-
result.added.push(key);
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
if (varsToAdd.length > 0) {
|
|
461
|
-
let newContent = existingContent;
|
|
462
|
-
if (newContent && !newContent.endsWith("\n")) {
|
|
463
|
-
newContent += "\n";
|
|
464
|
-
}
|
|
465
|
-
if (newContent.trim()) {
|
|
466
|
-
newContent += "\n";
|
|
467
|
-
}
|
|
468
|
-
newContent += "# AgentMark\n";
|
|
469
|
-
for (const [key, value] of varsToAdd) {
|
|
470
|
-
newContent += `${key}=${value}
|
|
471
|
-
`;
|
|
472
|
-
}
|
|
473
|
-
fs.writeFileSync(envPath, newContent);
|
|
474
|
-
result.content = newContent;
|
|
475
|
-
}
|
|
476
|
-
result.success = true;
|
|
477
|
-
return result;
|
|
478
|
-
} catch (error) {
|
|
479
|
-
result.warnings.push(`Error appending to .env: ${error}`);
|
|
480
|
-
return result;
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
// src/utils/types.ts
|
|
485
|
-
var PACKAGE_MANAGERS = {
|
|
486
|
-
"yarn.lock": {
|
|
487
|
-
name: "yarn",
|
|
488
|
-
lockFile: "yarn.lock",
|
|
489
|
-
installCmd: "yarn install",
|
|
490
|
-
addCmd: "yarn add",
|
|
491
|
-
addDevCmd: "yarn add --dev",
|
|
492
|
-
runCmd: "yarn"
|
|
493
|
-
},
|
|
494
|
-
"pnpm-lock.yaml": {
|
|
495
|
-
name: "pnpm",
|
|
496
|
-
lockFile: "pnpm-lock.yaml",
|
|
497
|
-
installCmd: "pnpm install",
|
|
498
|
-
addCmd: "pnpm add",
|
|
499
|
-
addDevCmd: "pnpm add --save-dev",
|
|
500
|
-
runCmd: "pnpm"
|
|
501
|
-
},
|
|
502
|
-
"bun.lockb": {
|
|
503
|
-
name: "bun",
|
|
504
|
-
lockFile: "bun.lockb",
|
|
505
|
-
installCmd: "bun install",
|
|
506
|
-
addCmd: "bun add",
|
|
507
|
-
addDevCmd: "bun add --dev",
|
|
508
|
-
runCmd: "bun run"
|
|
509
|
-
},
|
|
510
|
-
"package-lock.json": {
|
|
511
|
-
name: "npm",
|
|
512
|
-
lockFile: "package-lock.json",
|
|
513
|
-
installCmd: "npm install",
|
|
514
|
-
addCmd: "npm install",
|
|
515
|
-
addDevCmd: "npm install --save-dev",
|
|
516
|
-
runCmd: "npm run"
|
|
517
|
-
}
|
|
518
|
-
};
|
|
519
|
-
var DEFAULT_PACKAGE_MANAGER = PACKAGE_MANAGERS["package-lock.json"];
|
|
520
|
-
var CONFLICT_FILES = [
|
|
521
|
-
{ path: "agentmark.json", type: "config", strategy: "prompt" },
|
|
522
|
-
{ path: "agentmark", type: "directory", strategy: "prompt" },
|
|
523
|
-
{ path: "agentmark.client.ts", type: "source", strategy: "prompt" },
|
|
524
|
-
{ path: "agentmark_client.py", type: "source", strategy: "prompt" },
|
|
525
|
-
{ path: ".gitignore", type: "dotfile", strategy: "append" },
|
|
526
|
-
{ path: ".env", type: "dotfile", strategy: "append" },
|
|
527
|
-
{ path: "package.json", type: "config", strategy: "merge" },
|
|
528
|
-
{ path: "index.ts", type: "source", strategy: "skip" },
|
|
529
|
-
{ path: "main.py", type: "source", strategy: "skip" },
|
|
530
|
-
{ path: "tsconfig.json", type: "config", strategy: "skip" },
|
|
531
|
-
{ path: "pyproject.toml", type: "config", strategy: "skip" }
|
|
532
|
-
];
|
|
533
|
-
|
|
534
|
-
// src/utils/examples/templates/package-setup.ts
|
|
535
|
-
var setupPackageJson = (targetPath = ".", deploymentMode = "cloud", projectInfo = null) => {
|
|
536
|
-
const packageJsonPath = `${targetPath}/package.json`;
|
|
537
|
-
const isExistingProject = projectInfo?.isExistingProject ?? false;
|
|
538
|
-
if (!fs2.existsSync(packageJsonPath)) {
|
|
539
|
-
console.log("Creating package.json...");
|
|
540
|
-
execSync("npm init -y", { cwd: targetPath });
|
|
541
|
-
}
|
|
542
|
-
const demoScript = deploymentMode === "static" ? "npx agentmark build --out dist/agentmark && npx tsx index.ts" : "npx tsx index.ts";
|
|
543
|
-
if (isExistingProject && fs2.existsSync(packageJsonPath)) {
|
|
544
|
-
const scriptsToAdd = {
|
|
545
|
-
"demo": demoScript,
|
|
546
|
-
"agentmark": "agentmark"
|
|
547
|
-
};
|
|
548
|
-
if (deploymentMode === "static") {
|
|
549
|
-
scriptsToAdd["build"] = "agentmark build --out dist/agentmark";
|
|
550
|
-
}
|
|
551
|
-
const result = mergePackageJson(targetPath, {}, {}, scriptsToAdd);
|
|
552
|
-
if (result.added.length > 0) {
|
|
553
|
-
console.log(`\u2705 Added to package.json: ${result.added.join(", ")}`);
|
|
554
|
-
}
|
|
555
|
-
if (result.skipped.length > 0) {
|
|
556
|
-
console.log(`\u23ED\uFE0F Skipped existing in package.json: ${result.skipped.join(", ")}`);
|
|
557
|
-
}
|
|
558
|
-
if (result.warnings.length > 0) {
|
|
559
|
-
result.warnings.forEach((w) => console.log(`\u26A0\uFE0F ${w}`));
|
|
560
|
-
}
|
|
561
|
-
} else {
|
|
562
|
-
const pkgJson = fs2.readJsonSync(packageJsonPath);
|
|
563
|
-
pkgJson.name = pkgJson.name === "test" || !pkgJson.name ? "agentmark-example-app" : pkgJson.name;
|
|
564
|
-
pkgJson.description = pkgJson.description || "A simple Node.js app using the Agentmark SDK";
|
|
565
|
-
if (pkgJson.type === "commonjs") {
|
|
566
|
-
delete pkgJson.type;
|
|
567
|
-
}
|
|
568
|
-
const scripts = {
|
|
569
|
-
...pkgJson.scripts,
|
|
570
|
-
"demo": demoScript,
|
|
571
|
-
"agentmark": "agentmark"
|
|
572
|
-
};
|
|
573
|
-
if (deploymentMode === "static") {
|
|
574
|
-
scripts["build"] = "agentmark build --out dist/agentmark";
|
|
575
|
-
}
|
|
576
|
-
pkgJson.scripts = scripts;
|
|
577
|
-
fs2.writeJsonSync(packageJsonPath, pkgJson, { spaces: 2 });
|
|
578
|
-
}
|
|
579
|
-
};
|
|
580
|
-
var installDependencies = (modelProvider, targetPath = ".", adapter = "ai-sdk", deploymentMode = "cloud", packageManager = null) => {
|
|
581
|
-
console.log("Installing required packages...");
|
|
582
|
-
console.log("This might take a moment...");
|
|
583
|
-
const adapterConfig = getAdapterConfig(adapter, modelProvider);
|
|
584
|
-
const pm = packageManager || DEFAULT_PACKAGE_MANAGER;
|
|
585
|
-
const npmSuffix = pm.name === "npm" ? " --legacy-peer-deps" : "";
|
|
586
|
-
try {
|
|
587
|
-
const devDeps = ["typescript", "ts-node", "@types/node", "@agentmark-ai/cli"];
|
|
588
|
-
const devDepsCmd = `${pm.addDevCmd} ${devDeps.join(" ")}${npmSuffix}`;
|
|
589
|
-
console.log(`Using ${pm.name} to install dependencies...`);
|
|
590
|
-
execSync(devDepsCmd, {
|
|
591
|
-
stdio: "inherit",
|
|
592
|
-
cwd: targetPath
|
|
593
|
-
});
|
|
594
|
-
const loaderPackages = deploymentMode === "static" ? ["@agentmark-ai/loader-api", "@agentmark-ai/loader-file"] : ["@agentmark-ai/loader-api"];
|
|
595
|
-
const deps = [
|
|
596
|
-
"dotenv",
|
|
597
|
-
"@agentmark-ai/prompt-core",
|
|
598
|
-
"@agentmark-ai/sdk",
|
|
599
|
-
adapterConfig.package,
|
|
600
|
-
...loaderPackages,
|
|
601
|
-
...adapterConfig.dependencies
|
|
602
|
-
];
|
|
603
|
-
const depsCmd = `${pm.addCmd} ${deps.join(" ")}${npmSuffix}`;
|
|
604
|
-
execSync(depsCmd, { stdio: "inherit", cwd: targetPath });
|
|
605
|
-
console.log("Packages installed successfully!");
|
|
606
|
-
} catch (error) {
|
|
607
|
-
console.error("Error installing packages:", error);
|
|
608
|
-
throw new Error(
|
|
609
|
-
"Failed to install required packages. Please check your network connection and try again."
|
|
610
|
-
);
|
|
611
|
-
}
|
|
612
|
-
};
|
|
613
|
-
|
|
614
|
-
// src/utils/examples/templates/tsconfig.ts
|
|
615
|
-
var getTsConfigContent = () => {
|
|
616
|
-
return {
|
|
617
|
-
"compilerOptions": {
|
|
618
|
-
"target": "ES2020",
|
|
619
|
-
"module": "NodeNext",
|
|
620
|
-
"moduleResolution": "NodeNext",
|
|
621
|
-
"esModuleInterop": true,
|
|
622
|
-
"forceConsistentCasingInFileNames": true,
|
|
623
|
-
"strict": true,
|
|
624
|
-
"skipLibCheck": true
|
|
625
|
-
}
|
|
626
|
-
};
|
|
627
|
-
};
|
|
628
|
-
|
|
629
|
-
// src/utils/examples/templates/animal-drawing-prompt.ts
|
|
630
|
-
var getAnimalDrawingPrompt = () => {
|
|
631
|
-
return `---
|
|
632
|
-
name: animal-drawing
|
|
633
|
-
image_config:
|
|
634
|
-
model_name: openai/dall-e-3
|
|
635
|
-
num_images: 1
|
|
636
|
-
size: 1024x1024
|
|
637
|
-
aspect_ratio: 1:1
|
|
638
|
-
test_settings:
|
|
639
|
-
dataset: animal.jsonl
|
|
640
|
-
props:
|
|
641
|
-
animal: "cat"
|
|
642
|
-
---
|
|
643
|
-
|
|
644
|
-
<ImagePrompt>
|
|
645
|
-
Draw a hyper-realistic picture of a {props.animal}
|
|
646
|
-
</ImagePrompt>`;
|
|
647
|
-
};
|
|
648
|
-
|
|
649
|
-
// src/utils/examples/templates/customer-support-prompt.ts
|
|
650
|
-
var getCustomerSupportPrompt = (model) => {
|
|
651
|
-
return `---
|
|
652
|
-
name: customer-support-agent
|
|
653
|
-
text_config:
|
|
654
|
-
model_name: ${model}
|
|
655
|
-
max_calls: 2
|
|
656
|
-
tools:
|
|
657
|
-
- search_knowledgebase
|
|
658
|
-
test_settings:
|
|
659
|
-
dataset: customer-query.jsonl
|
|
660
|
-
props:
|
|
661
|
-
customer_question: "I'm having trouble with my order. How long does shipping take?"
|
|
662
|
-
input_schema:
|
|
663
|
-
type: object
|
|
664
|
-
properties:
|
|
665
|
-
customer_question:
|
|
666
|
-
type: string
|
|
667
|
-
description: "The customer's question"
|
|
668
|
-
required:
|
|
669
|
-
- customer_question
|
|
670
|
-
---
|
|
671
|
-
|
|
672
|
-
<System>
|
|
673
|
-
You are a customer service agent for a company that sells products online. You are given a customer's question and you need to respond to the customer. You need to be friendly, professional, and helpful.
|
|
674
|
-
|
|
675
|
-
You have access to the following tool:
|
|
676
|
-
- search_knowledgebase: Search the company knowledgebase for information about shipping, warranty, and returns. Use this when customers ask about these topics.
|
|
677
|
-
</System>
|
|
678
|
-
|
|
679
|
-
<User>{props.customer_question}</User>`;
|
|
680
|
-
};
|
|
681
|
-
|
|
682
|
-
// src/utils/examples/templates/party-planner-prompt.ts
|
|
683
|
-
var getPartyPlannerPrompt = (model) => {
|
|
684
|
-
return `---
|
|
685
|
-
name: party-planner
|
|
686
|
-
object_config:
|
|
687
|
-
model_name: ${model}
|
|
688
|
-
schema:
|
|
689
|
-
type: object
|
|
690
|
-
properties:
|
|
691
|
-
names:
|
|
692
|
-
type: array
|
|
693
|
-
description: "List of names of people attending the party."
|
|
694
|
-
items:
|
|
695
|
-
type: string
|
|
696
|
-
required:
|
|
697
|
-
- names
|
|
698
|
-
test_settings:
|
|
699
|
-
dataset: party.jsonl
|
|
700
|
-
evals:
|
|
701
|
-
- exact_match_json
|
|
702
|
-
props:
|
|
703
|
-
party_text: "We're having a party with Alice, Bob, and Carol."
|
|
704
|
-
input_schema:
|
|
705
|
-
type: object
|
|
706
|
-
properties:
|
|
707
|
-
party_text:
|
|
708
|
-
type: string
|
|
709
|
-
description: "A block of text describing the upcoming party and attendees."
|
|
710
|
-
required:
|
|
711
|
-
- party_text
|
|
712
|
-
---
|
|
713
|
-
|
|
714
|
-
<System>
|
|
715
|
-
Extract the names of all people attending the party from the following text. Respond with a list of names only.
|
|
716
|
-
</System>
|
|
717
|
-
|
|
718
|
-
<User>
|
|
719
|
-
Text: {props.party_text}
|
|
720
|
-
</User>`;
|
|
721
|
-
};
|
|
722
|
-
|
|
723
|
-
// src/utils/examples/templates/story-teller-prompt.ts
|
|
724
|
-
var getStoryTellerPrompt = () => {
|
|
725
|
-
return `---
|
|
726
|
-
name: story-teller
|
|
727
|
-
speech_config:
|
|
728
|
-
model_name: openai/tts-1-hd
|
|
729
|
-
voice: "nova"
|
|
730
|
-
speed: 1.0
|
|
731
|
-
output_format: "mp3"
|
|
732
|
-
test_settings:
|
|
733
|
-
dataset: story.jsonl
|
|
734
|
-
props:
|
|
735
|
-
story: "Once upon a time, there was a cat who loved to play with a ball."
|
|
736
|
-
---
|
|
737
|
-
|
|
738
|
-
<System>
|
|
739
|
-
You are a storyteller for children. Make sure your story is engaging and interesting.
|
|
740
|
-
</System>
|
|
741
|
-
|
|
742
|
-
<SpeechPrompt>
|
|
743
|
-
- {props.story}
|
|
744
|
-
</SpeechPrompt>`;
|
|
745
|
-
};
|
|
746
|
-
|
|
747
|
-
// src/utils/examples/templates/datasets.ts
|
|
748
|
-
var getAnimalDataset = () => {
|
|
749
|
-
return `{"input": {"animal": "cat"}, "expected_output": "A realistic picture of a cat"}
|
|
750
|
-
{"input": {"animal": "dog"}, "expected_output": "A realistic picture of a dog"}
|
|
751
|
-
{"input": {"animal": "bird"}, "expected_output": "A realistic picture of a bird"}`;
|
|
752
|
-
};
|
|
753
|
-
var getCustomerQueryDataset = () => {
|
|
754
|
-
return `{"input": {"customer_question": "My package hasn't arrived yet. Can you help me track it?"}}
|
|
755
|
-
{"input": {"customer_question": "I received the wrong item in my order. What should I do?"}}
|
|
756
|
-
{"input": {"customer_question": "How do I return a product that I purchased last week?"}}`;
|
|
757
|
-
};
|
|
758
|
-
var getPartyDataset = () => {
|
|
759
|
-
return `{"input": {"party_text": "We're having a party with Alice, Bob, and Carol."}, "expected_output": "{\\"names\\": [\\"Alice\\", \\"Bob\\", \\"Carol\\"]}"}
|
|
760
|
-
{"input": {"party_text": "The guest list includes Dave, Emma, and Frank."}, "expected_output": "{\\"names\\": [\\"Dave\\", \\"Emma\\", \\"Frank\\"]}"}
|
|
761
|
-
{"input": {"party_text": "Join us for a celebration with Grace, Henry, and Isla."}, "expected_output": "{\\"names\\": [\\"Grace\\", \\"Henry\\", \\"Isla\\"]}"}`;
|
|
762
|
-
};
|
|
763
|
-
var getStoryDataset = () => {
|
|
764
|
-
return `{"input": {"story": "Once upon a time, the Moon woke up and found her glow missing! She floated around the sky asking stars, clouds, and even comets if they'd seen her light. It wasn't until she peeked into a mountain lake that she saw her glow shining back\u2014hidden in her own reflection! Laughing, she realized she had never lost it\u2014it was with her all along, just hiding beneath a cloudy sky."}}
|
|
765
|
-
{"input": {"story": "Benny was no ordinary banana\u2014he dreamed of becoming a superhero. One day, when a monkey slipped in the jungle and cried for help, Benny rolled into action, dodging vines and swinging from branches using his peel like a lasso. The monkey was saved, and from that day on, Benny was known as \\"The Peel of Justice,\\" the bravest fruit in the whole rainforest."}}
|
|
766
|
-
{"input": {"story": "In the town of Maplebrook, there was a library that whispered stories when no one was looking. Curious little Nia tiptoed in one rainy day and heard the books giggling softly. She opened one called The Secret Tunnel, and to her surprise, it sucked her in! She found herself riding a dragon through glittering caves. When she returned, the book winked shut\u2014waiting for its next reader to listen."}}`;
|
|
767
|
-
};
|
|
768
|
-
|
|
769
|
-
// src/utils/examples/templates/example-prompts.ts
|
|
770
|
-
import fs3 from "fs-extra";
|
|
771
|
-
var createExamplePrompts = (model, targetPath = ".", adapter = "ai-sdk") => {
|
|
772
|
-
fs3.ensureDirSync(`${targetPath}/agentmark`);
|
|
773
|
-
const noImageSupport = ["mastra", "claude-agent-sdk", "pydantic-ai"];
|
|
774
|
-
const noSpeechSupport = ["mastra", "claude-agent-sdk", "pydantic-ai"];
|
|
775
|
-
const skipImagePrompts = noImageSupport.includes(adapter);
|
|
776
|
-
const skipSpeechPrompts = noSpeechSupport.includes(adapter);
|
|
777
|
-
const usedModels = [];
|
|
778
|
-
if (!skipImagePrompts) {
|
|
779
|
-
const animalDrawingPrompt = getAnimalDrawingPrompt();
|
|
780
|
-
fs3.writeFileSync(`${targetPath}/agentmark/animal-drawing.prompt.mdx`, animalDrawingPrompt);
|
|
781
|
-
const animalDataset = getAnimalDataset();
|
|
782
|
-
fs3.writeFileSync(`${targetPath}/agentmark/animal.jsonl`, animalDataset);
|
|
783
|
-
usedModels.push("openai/dall-e-3");
|
|
784
|
-
}
|
|
785
|
-
const customerSupportPrompt = getCustomerSupportPrompt(model);
|
|
786
|
-
fs3.writeFileSync(`${targetPath}/agentmark/customer-support-agent.prompt.mdx`, customerSupportPrompt);
|
|
787
|
-
const customerQueryDataset = getCustomerQueryDataset();
|
|
788
|
-
fs3.writeFileSync(`${targetPath}/agentmark/customer-query.jsonl`, customerQueryDataset);
|
|
789
|
-
usedModels.push(model);
|
|
790
|
-
const partyPlannerPrompt = getPartyPlannerPrompt(model);
|
|
791
|
-
fs3.writeFileSync(`${targetPath}/agentmark/party-planner.prompt.mdx`, partyPlannerPrompt);
|
|
792
|
-
const partyDataset = getPartyDataset();
|
|
793
|
-
fs3.writeFileSync(`${targetPath}/agentmark/party.jsonl`, partyDataset);
|
|
794
|
-
if (!skipSpeechPrompts) {
|
|
795
|
-
const storyTellerPrompt = getStoryTellerPrompt();
|
|
796
|
-
fs3.writeFileSync(`${targetPath}/agentmark/story-teller.prompt.mdx`, storyTellerPrompt);
|
|
797
|
-
const storyDataset = getStoryDataset();
|
|
798
|
-
fs3.writeFileSync(`${targetPath}/agentmark/story.jsonl`, storyDataset);
|
|
799
|
-
usedModels.push("openai/tts-1-hd");
|
|
800
|
-
}
|
|
801
|
-
return [...new Set(usedModels)];
|
|
802
|
-
};
|
|
803
|
-
|
|
804
|
-
// src/utils/examples/templates/user-client-config.ts
|
|
805
|
-
var getClientConfigContent = (options) => {
|
|
806
|
-
const { provider, adapter, deploymentMode = "cloud" } = options;
|
|
807
|
-
const isMastra = adapter === "mastra";
|
|
808
|
-
const adapterConfig = getAdapterConfig(adapter, provider);
|
|
809
|
-
const { modelRegistry } = adapterConfig.classes;
|
|
810
|
-
const isClaudeAgentSdk = adapter === "claude-agent-sdk";
|
|
811
|
-
const providerImport = isClaudeAgentSdk ? "" : `import { ${provider} } from '@ai-sdk/${provider}';`;
|
|
812
|
-
const loaderImport = deploymentMode === "cloud" ? `import { ApiLoader } from "@agentmark-ai/loader-api";` : `import { ApiLoader } from "@agentmark-ai/loader-api";
|
|
813
|
-
import { FileLoader } from "@agentmark-ai/loader-file";`;
|
|
814
|
-
const loaderSetup = deploymentMode === "cloud" ? ` // ApiLoader works for both development and production
|
|
815
|
-
// - Development: 'agentmark dev' sets AGENTMARK_BASE_URL to localhost
|
|
816
|
-
// - Production: Set AGENTMARK_API_KEY and AGENTMARK_APP_ID for cloud.
|
|
817
|
-
// AGENTMARK_BASE_URL overrides the default https://api.agentmark.co
|
|
818
|
-
// target \u2014 managed deployments use this to point back at the gateway
|
|
819
|
-
// that dispatched the job.
|
|
820
|
-
const loader = process.env.NODE_ENV === 'development'
|
|
821
|
-
? ApiLoader.local({ baseUrl: process.env.AGENTMARK_BASE_URL || 'http://localhost:9418' })
|
|
822
|
-
: ApiLoader.cloud({
|
|
823
|
-
apiKey: process.env.AGENTMARK_API_KEY!,
|
|
824
|
-
appId: process.env.AGENTMARK_APP_ID!,
|
|
825
|
-
baseUrl: process.env.AGENTMARK_BASE_URL,
|
|
826
|
-
});` : ` const loader = process.env.NODE_ENV === 'development'
|
|
827
|
-
? ApiLoader.local({ baseUrl: process.env.AGENTMARK_BASE_URL || 'http://localhost:9418' })
|
|
828
|
-
: new FileLoader('./dist/agentmark');`;
|
|
829
|
-
const modelRegistrySetup = isClaudeAgentSdk ? `function createModelRegistry() {
|
|
830
|
-
// Claude Agent SDK accepts model names directly.
|
|
831
|
-
// Use createDefault() for simple pass-through of model names.
|
|
832
|
-
const modelRegistry = ${modelRegistry}.createDefault();
|
|
833
|
-
|
|
834
|
-
// To configure specific models (e.g., extended thinking), use:
|
|
835
|
-
// const modelRegistry = new ${modelRegistry}()
|
|
836
|
-
// .registerModels(/claude-.*-thinking/, (name) => ({
|
|
837
|
-
// model: name,
|
|
838
|
-
// maxThinkingTokens: 10000, // Enable extended thinking
|
|
839
|
-
// }))
|
|
840
|
-
// .registerModels("claude-sonnet-4-20250514", (name) => ({ model: name }));
|
|
841
|
-
|
|
842
|
-
return modelRegistry;
|
|
843
|
-
}` : `function createModelRegistry() {
|
|
844
|
-
const modelRegistry = new ${modelRegistry}()
|
|
845
|
-
.registerProviders({ ${provider} });
|
|
846
|
-
return modelRegistry;
|
|
847
|
-
}`;
|
|
848
|
-
const adapterOptionsImport = isClaudeAgentSdk ? `
|
|
849
|
-
// Claude Agent SDK adapter options
|
|
850
|
-
// See: https://github.com/anthropics/claude-agent-sdk
|
|
851
|
-
const adapterOptions = {
|
|
852
|
-
// Permission mode controls tool access:
|
|
853
|
-
// - 'default': Requires user approval for each tool use
|
|
854
|
-
// - 'acceptEdits': Auto-approve file edits only
|
|
855
|
-
// - 'bypassPermissions': Auto-approve all tools (use for automated pipelines)
|
|
856
|
-
// - 'plan': Planning mode only, no tool execution
|
|
857
|
-
permissionMode: 'bypassPermissions' as const,
|
|
858
|
-
|
|
859
|
-
// Maximum conversation turns before stopping
|
|
860
|
-
maxTurns: 20,
|
|
861
|
-
|
|
862
|
-
// Optional: Set working directory for file operations
|
|
863
|
-
// cwd: process.cwd(),
|
|
864
|
-
|
|
865
|
-
// Optional: Budget limit in USD
|
|
866
|
-
// maxBudgetUsd: 10.00,
|
|
867
|
-
|
|
868
|
-
// Optional: Restrict which tools the agent can use
|
|
869
|
-
// allowedTools: ['Read', 'Write', 'Glob'],
|
|
870
|
-
// disallowedTools: ['Bash'],
|
|
871
|
-
};` : "";
|
|
872
|
-
const toolImport = isClaudeAgentSdk ? `import { tool, createSdkMcpServer } from "@anthropic-ai/claude-agent-sdk";
|
|
873
|
-
import { z } from 'zod';` : isMastra ? `import { tool } from 'ai';
|
|
874
|
-
import type { ToolsInput } from '@mastra/core/agent';
|
|
875
|
-
import { z } from 'zod';` : `import { tool } from 'ai';
|
|
876
|
-
import type { Tool } from 'ai';
|
|
877
|
-
import { z } from 'zod';`;
|
|
878
|
-
const createClientCall = isClaudeAgentSdk ? `return createAgentMarkClient<AgentMarkTypes>({ loader, modelRegistry, evals, adapterOptions, mcpServers: { 'customer-support': customerSupportTools } });` : `return createAgentMarkClient<AgentMarkTypes>({ loader, modelRegistry, tools, evals });`;
|
|
879
|
-
const toolSchemaField = isMastra ? `parameters: z.object({ query: z.string().describe('The search query') })` : `inputSchema: z.object({ query: z.string().describe('The search query') })`;
|
|
880
|
-
const toolsReturnType = isMastra ? "ToolsInput" : "Record<string, Tool>";
|
|
881
|
-
const toolsSetup = isClaudeAgentSdk ? `
|
|
882
|
-
// Custom tools exposed as an MCP server \u2014 the SDK's native tool mechanism.
|
|
883
|
-
// The server name is used in mcpServers config; tool names are used in prompt files.
|
|
884
|
-
const knowledgeBase = tool(
|
|
885
|
-
'search_knowledgebase',
|
|
886
|
-
'Search the knowledge base for relevant articles',
|
|
887
|
-
{ query: z.string().describe('The search query') },
|
|
888
|
-
async ({ query }) => ({
|
|
889
|
-
content: [{ type: 'text' as const, text: JSON.stringify({
|
|
890
|
-
articles: [
|
|
891
|
-
{ topic: 'shipping', content: 'Standard shipping takes 3\u20135 business days.' },
|
|
892
|
-
{ topic: 'warranty', content: 'All products include a 1-year limited warranty.' },
|
|
893
|
-
{ topic: 'returns', content: 'You can return items within 30 days of delivery.' },
|
|
894
|
-
],
|
|
895
|
-
}) }],
|
|
896
|
-
})
|
|
897
|
-
);
|
|
898
|
-
|
|
899
|
-
const customerSupportTools = createSdkMcpServer({
|
|
900
|
-
name: 'customer-support',
|
|
901
|
-
tools: [knowledgeBase],
|
|
902
|
-
});` : `
|
|
903
|
-
function createTools(): ${toolsReturnType} {
|
|
904
|
-
return {
|
|
905
|
-
search_knowledgebase: tool({
|
|
906
|
-
description: 'Search the knowledge base for relevant articles',
|
|
907
|
-
${toolSchemaField},
|
|
908
|
-
execute: async ({ query }) => {
|
|
909
|
-
// Simulate search delay
|
|
910
|
-
await new Promise(resolve => setTimeout(resolve, 500));
|
|
911
|
-
|
|
912
|
-
// Return all three knowledge base articles
|
|
913
|
-
// The LLM will select the relevant one based on the query
|
|
914
|
-
return {
|
|
915
|
-
articles: [
|
|
916
|
-
{ topic: 'shipping', content: 'Standard shipping takes 3\u20135 business days.' },
|
|
917
|
-
{ topic: 'warranty', content: 'All products include a 1-year limited warranty.' },
|
|
918
|
-
{ topic: 'returns', content: 'You can return items within 30 days of delivery.' }
|
|
919
|
-
]
|
|
920
|
-
};
|
|
921
|
-
},
|
|
922
|
-
}),
|
|
923
|
-
};
|
|
924
|
-
}`;
|
|
925
|
-
const toolsVariable = isClaudeAgentSdk ? "" : ` const tools = createTools();`;
|
|
926
|
-
return `// agentmark.client.ts
|
|
927
|
-
import path from 'node:path';
|
|
928
|
-
import dotenv from 'dotenv';
|
|
929
|
-
dotenv.config({ path: path.resolve(__dirname, '.env') });
|
|
930
|
-
import { createAgentMarkClient, ${modelRegistry} } from "${adapterConfig.package}";
|
|
931
|
-
import type { EvalRegistry } from "@agentmark-ai/prompt-core";
|
|
932
|
-
${loaderImport}
|
|
933
|
-
import AgentMarkTypes from './agentmark.types';
|
|
934
|
-
${providerImport}
|
|
935
|
-
${toolImport}
|
|
936
|
-
${adapterOptionsImport}
|
|
937
|
-
|
|
938
|
-
${modelRegistrySetup}
|
|
939
|
-
${toolsSetup}
|
|
940
|
-
|
|
941
|
-
const evals: EvalRegistry = {
|
|
942
|
-
exact_match_json: async ({ output, expectedOutput }) => {
|
|
943
|
-
if (!expectedOutput) {
|
|
944
|
-
return { score: 0, label: 'error', reason: 'No expected output provided', passed: false };
|
|
945
|
-
}
|
|
946
|
-
try {
|
|
947
|
-
const ok = JSON.stringify(output) === JSON.stringify(JSON.parse(expectedOutput));
|
|
948
|
-
return {
|
|
949
|
-
score: ok ? 1 : 0,
|
|
950
|
-
label: ok ? 'correct' : 'incorrect',
|
|
951
|
-
reason: ok ? 'Exact match' : 'Mismatch',
|
|
952
|
-
passed: ok
|
|
953
|
-
};
|
|
954
|
-
} catch (e) {
|
|
955
|
-
return { score: 0, label: 'error', reason: 'Failed to parse expected output as JSON', passed: false };
|
|
956
|
-
}
|
|
957
|
-
},
|
|
958
|
-
};
|
|
959
|
-
|
|
960
|
-
function createClient() {
|
|
961
|
-
${loaderSetup}
|
|
962
|
-
const modelRegistry = createModelRegistry();
|
|
963
|
-
${toolsVariable}
|
|
964
|
-
${createClientCall}
|
|
965
|
-
}
|
|
966
|
-
|
|
967
|
-
export const client = createClient();
|
|
968
|
-
`;
|
|
969
|
-
};
|
|
970
|
-
|
|
971
|
-
// src/utils/examples/create-example-app.ts
|
|
972
|
-
import { fetchPromptsFrontmatter, generateTypeDefinitions } from "@agentmark-ai/shared-utils";
|
|
973
|
-
|
|
974
|
-
// src/utils/conflict-resolution.ts
|
|
975
|
-
import prompts from "prompts";
|
|
976
|
-
function getPromptableConflicts(conflictingFiles) {
|
|
977
|
-
return conflictingFiles.filter((file) => file.strategy === "prompt");
|
|
978
|
-
}
|
|
979
|
-
async function promptForSingleConflict(conflict) {
|
|
980
|
-
const typeLabel = conflict.type === "directory" ? "directory" : "file";
|
|
981
|
-
const { action } = await prompts({
|
|
982
|
-
type: "select",
|
|
983
|
-
name: "action",
|
|
984
|
-
message: `${conflict.path} already exists. What would you like to do?`,
|
|
985
|
-
choices: [
|
|
986
|
-
{
|
|
987
|
-
title: `Skip (keep existing ${typeLabel})`,
|
|
988
|
-
value: "skip",
|
|
989
|
-
description: `Don't modify the existing ${typeLabel}`
|
|
990
|
-
},
|
|
991
|
-
{
|
|
992
|
-
title: "Overwrite",
|
|
993
|
-
value: "overwrite",
|
|
994
|
-
description: `Replace with new AgentMark ${typeLabel}`
|
|
995
|
-
}
|
|
996
|
-
],
|
|
997
|
-
initial: 0
|
|
998
|
-
// Default to skip for safety
|
|
999
|
-
});
|
|
1000
|
-
return {
|
|
1001
|
-
path: conflict.path,
|
|
1002
|
-
action: action || "skip"
|
|
1003
|
-
};
|
|
1004
|
-
}
|
|
1005
|
-
async function promptForResolutions(conflictingFiles) {
|
|
1006
|
-
const promptableConflicts = getPromptableConflicts(conflictingFiles);
|
|
1007
|
-
if (promptableConflicts.length === 0) {
|
|
1008
|
-
return [];
|
|
1009
|
-
}
|
|
1010
|
-
console.log("\n\u26A0\uFE0F Found existing files that may conflict with AgentMark initialization:\n");
|
|
1011
|
-
const resolutions = [];
|
|
1012
|
-
for (const conflict of promptableConflicts) {
|
|
1013
|
-
const resolution = await promptForSingleConflict(conflict);
|
|
1014
|
-
resolutions.push(resolution);
|
|
1015
|
-
}
|
|
1016
|
-
console.log("");
|
|
1017
|
-
return resolutions;
|
|
1018
|
-
}
|
|
1019
|
-
function getResolutionAction(filePath, resolutions, conflictingFiles) {
|
|
1020
|
-
const userResolution = resolutions.find((r) => r.path === filePath);
|
|
1021
|
-
if (userResolution) {
|
|
1022
|
-
return userResolution.action;
|
|
1023
|
-
}
|
|
1024
|
-
const conflictFile = conflictingFiles.find((f) => f.path === filePath);
|
|
1025
|
-
if (conflictFile) {
|
|
1026
|
-
switch (conflictFile.strategy) {
|
|
1027
|
-
case "skip":
|
|
1028
|
-
return "skip";
|
|
1029
|
-
case "merge":
|
|
1030
|
-
return "merge";
|
|
1031
|
-
case "append":
|
|
1032
|
-
return "merge";
|
|
1033
|
-
// Append is a form of merge
|
|
1034
|
-
case "prompt":
|
|
1035
|
-
return "skip";
|
|
1036
|
-
}
|
|
1037
|
-
}
|
|
1038
|
-
return "overwrite";
|
|
1039
|
-
}
|
|
1040
|
-
function shouldMergeFile(filePath, projectInfo, resolutions) {
|
|
1041
|
-
if (!projectInfo || !projectInfo.isExistingProject) {
|
|
1042
|
-
return false;
|
|
1043
|
-
}
|
|
1044
|
-
const action = getResolutionAction(filePath, resolutions, projectInfo.conflictingFiles);
|
|
1045
|
-
return action === "merge";
|
|
1046
|
-
}
|
|
1047
|
-
function displayProjectDetectionSummary(projectInfo) {
|
|
1048
|
-
if (!projectInfo.isExistingProject) {
|
|
1049
|
-
return;
|
|
1050
|
-
}
|
|
1051
|
-
console.log("\n\u{1F4C1} Detected existing project:");
|
|
1052
|
-
console.log(` Type: ${projectInfo.type}`);
|
|
1053
|
-
if (projectInfo.type === "typescript") {
|
|
1054
|
-
console.log(` Package Manager: ${projectInfo.packageManager.name}`);
|
|
1055
|
-
}
|
|
1056
|
-
if (projectInfo.pythonVenv) {
|
|
1057
|
-
console.log(` Python Venv: ${projectInfo.pythonVenv.name}`);
|
|
1058
|
-
}
|
|
1059
|
-
if (projectInfo.hasAgentmarkDir) {
|
|
1060
|
-
console.log(" \u26A0\uFE0F AgentMark directory already exists");
|
|
1061
|
-
}
|
|
1062
|
-
console.log("");
|
|
1063
|
-
}
|
|
1064
|
-
|
|
1065
|
-
// src/utils/examples/create-example-app.ts
|
|
1066
|
-
var setupMCPServer = (client, targetPath) => {
|
|
1067
|
-
if (client === "skip") {
|
|
1068
|
-
console.log("Skipping MCP server setup.");
|
|
1069
|
-
return;
|
|
1070
|
-
}
|
|
1071
|
-
const folderName = targetPath;
|
|
1072
|
-
if (client === "vscode") {
|
|
1073
|
-
try {
|
|
1074
|
-
console.log(`Setting up MCP server for VS Code in ${folderName}...`);
|
|
1075
|
-
const vscodeDir = path2.join(targetPath, ".vscode");
|
|
1076
|
-
fs4.ensureDirSync(vscodeDir);
|
|
1077
|
-
const mcpConfig = {
|
|
1078
|
-
servers: {
|
|
1079
|
-
"agentmark-docs": {
|
|
1080
|
-
url: "https://docs.agentmark.co/mcp"
|
|
1081
|
-
}
|
|
1082
|
-
}
|
|
1083
|
-
};
|
|
1084
|
-
fs4.writeJsonSync(path2.join(vscodeDir, "mcp.json"), mcpConfig, { spaces: 2 });
|
|
1085
|
-
console.log(`\u2705 MCP server configured for VS Code in ${folderName}/.vscode/mcp.json`);
|
|
1086
|
-
} catch (error) {
|
|
1087
|
-
console.warn(`Warning: Could not set up MCP server for VS Code:`, error);
|
|
1088
|
-
console.log("See https://docs.agentmark.co/agentmark/further_reference/agentmark-mcp for setup instructions.");
|
|
1089
|
-
}
|
|
1090
|
-
return;
|
|
1091
|
-
}
|
|
1092
|
-
if (client === "zed") {
|
|
1093
|
-
try {
|
|
1094
|
-
console.log(`Setting up MCP server for Zed in ${folderName}...`);
|
|
1095
|
-
const zedDir = path2.join(targetPath, ".zed");
|
|
1096
|
-
fs4.ensureDirSync(zedDir);
|
|
1097
|
-
const zedConfig = {
|
|
1098
|
-
context_servers: {
|
|
1099
|
-
"agentmark-docs": {
|
|
1100
|
-
url: "https://docs.agentmark.co/mcp"
|
|
1101
|
-
}
|
|
1102
|
-
}
|
|
1103
|
-
};
|
|
1104
|
-
fs4.writeJsonSync(path2.join(zedDir, "settings.json"), zedConfig, { spaces: 2 });
|
|
1105
|
-
console.log(`\u2705 MCP server configured for Zed in ${folderName}/.zed/settings.json`);
|
|
1106
|
-
} catch (error) {
|
|
1107
|
-
console.warn(`Warning: Could not set up MCP server for Zed:`, error);
|
|
1108
|
-
console.log("See https://docs.agentmark.co/agentmark/further_reference/agentmark-mcp for setup instructions.");
|
|
1109
|
-
}
|
|
1110
|
-
return;
|
|
1111
|
-
}
|
|
1112
|
-
if (client === "cursor") {
|
|
1113
|
-
try {
|
|
1114
|
-
console.log(`Setting up MCP server for Cursor in ${folderName}...`);
|
|
1115
|
-
const cursorDir = path2.join(targetPath, ".cursor");
|
|
1116
|
-
fs4.ensureDirSync(cursorDir);
|
|
1117
|
-
const cursorConfig = {
|
|
1118
|
-
mcpServers: {
|
|
1119
|
-
"agentmark-docs": {
|
|
1120
|
-
url: "https://docs.agentmark.co/mcp"
|
|
1121
|
-
}
|
|
1122
|
-
}
|
|
1123
|
-
};
|
|
1124
|
-
fs4.writeJsonSync(path2.join(cursorDir, "mcp.json"), cursorConfig, { spaces: 2 });
|
|
1125
|
-
console.log(`\u2705 MCP server configured for Cursor in ${folderName}/.cursor/mcp.json`);
|
|
1126
|
-
} catch (error) {
|
|
1127
|
-
console.warn(`Warning: Could not set up MCP server for Cursor:`, error);
|
|
1128
|
-
console.log("See https://docs.agentmark.co/agentmark/further_reference/agentmark-mcp for setup instructions.");
|
|
1129
|
-
}
|
|
1130
|
-
return;
|
|
1131
|
-
}
|
|
1132
|
-
if (client === "claude-code") {
|
|
1133
|
-
try {
|
|
1134
|
-
console.log(`Setting up MCP server for Claude Code in ${folderName}...`);
|
|
1135
|
-
const mcpConfig = {
|
|
1136
|
-
mcpServers: {
|
|
1137
|
-
"agentmark-docs": {
|
|
1138
|
-
type: "http",
|
|
1139
|
-
url: "https://docs.agentmark.co/mcp"
|
|
1140
|
-
}
|
|
1141
|
-
}
|
|
1142
|
-
};
|
|
1143
|
-
fs4.writeJsonSync(path2.join(targetPath, ".mcp.json"), mcpConfig, { spaces: 2 });
|
|
1144
|
-
console.log(`\u2705 MCP server configured for Claude Code in ${folderName}/.mcp.json`);
|
|
1145
|
-
} catch (error) {
|
|
1146
|
-
console.warn(`Warning: Could not set up MCP server for Claude Code:`, error);
|
|
1147
|
-
console.log("See https://docs.agentmark.co/agentmark/further_reference/agentmark-mcp for setup instructions.");
|
|
1148
|
-
}
|
|
1149
|
-
return;
|
|
1150
|
-
}
|
|
1151
|
-
};
|
|
1152
|
-
var createExampleApp = async (client, targetPath = ".", apiKey = "", adapter = "ai-sdk", deploymentMode = "cloud", projectInfo = null, resolutions = []) => {
|
|
1153
|
-
try {
|
|
1154
|
-
const modelProvider = adapter === "claude-agent-sdk" ? "anthropic" : "openai";
|
|
1155
|
-
const model = adapter === "claude-agent-sdk" ? "anthropic/claude-sonnet-4-20250514" : "openai/gpt-4o";
|
|
1156
|
-
const isExistingProject = projectInfo?.isExistingProject ?? false;
|
|
1157
|
-
if (isExistingProject) {
|
|
1158
|
-
console.log("Adding AgentMark to existing project...");
|
|
1159
|
-
} else {
|
|
1160
|
-
console.log("Creating AgentMark example app...");
|
|
1161
|
-
}
|
|
1162
|
-
const folderName = targetPath;
|
|
1163
|
-
fs4.ensureDirSync(`${targetPath}/agentmark`);
|
|
1164
|
-
setupMCPServer(client, targetPath);
|
|
1165
|
-
const usedModels = createExamplePrompts(model, targetPath, adapter);
|
|
1166
|
-
console.log(`\u2705 Example prompts and datasets created in ${folderName}/agentmark/`);
|
|
1167
|
-
fs4.writeFileSync(
|
|
1168
|
-
`${targetPath}/agentmark.client.ts`,
|
|
1169
|
-
getClientConfigContent({ provider: modelProvider, adapter, deploymentMode })
|
|
1170
|
-
);
|
|
1171
|
-
const gitignoreEntries = ["node_modules/", ".env", "*.agentmark-outputs/", "dist/"];
|
|
1172
|
-
if (shouldMergeFile(".gitignore", projectInfo, resolutions)) {
|
|
1173
|
-
const result = appendGitignore(targetPath, gitignoreEntries);
|
|
1174
|
-
if (result.added.length > 0) {
|
|
1175
|
-
console.log(`\u2705 Added to .gitignore: ${result.added.join(", ")}`);
|
|
1176
|
-
}
|
|
1177
|
-
if (result.skipped.length > 0) {
|
|
1178
|
-
console.log(`\u23ED\uFE0F Already in .gitignore: ${result.skipped.join(", ")}`);
|
|
1179
|
-
}
|
|
1180
|
-
} else {
|
|
1181
|
-
const gitignore = gitignoreEntries.join("\n");
|
|
1182
|
-
fs4.writeFileSync(`${targetPath}/.gitignore`, gitignore);
|
|
1183
|
-
}
|
|
1184
|
-
if (shouldMergeFile(".env", projectInfo, resolutions)) {
|
|
1185
|
-
const envVars = {};
|
|
1186
|
-
const apiKeyEnvVar = adapter === "claude-agent-sdk" ? "ANTHROPIC_API_KEY" : "OPENAI_API_KEY";
|
|
1187
|
-
if (apiKey) {
|
|
1188
|
-
envVars[apiKeyEnvVar] = apiKey;
|
|
1189
|
-
} else {
|
|
1190
|
-
envVars[apiKeyEnvVar] = adapter === "claude-agent-sdk" ? "your-anthropic-api-key" : "your-openai-api-key";
|
|
1191
|
-
}
|
|
1192
|
-
if (deploymentMode === "cloud") {
|
|
1193
|
-
envVars["AGENTMARK_API_KEY"] = "your_agentmark_api_key";
|
|
1194
|
-
envVars["AGENTMARK_APP_ID"] = "your_agentmark_app_id";
|
|
1195
|
-
}
|
|
1196
|
-
const result = appendEnv(targetPath, envVars);
|
|
1197
|
-
if (result.added.length > 0) {
|
|
1198
|
-
console.log(`\u2705 Added to .env: ${result.added.join(", ")}`);
|
|
1199
|
-
}
|
|
1200
|
-
if (result.skipped.length > 0) {
|
|
1201
|
-
console.log(`\u23ED\uFE0F Skipped existing .env vars: ${result.skipped.join(", ")}`);
|
|
1202
|
-
}
|
|
1203
|
-
} else {
|
|
1204
|
-
fs4.writeFileSync(`${targetPath}/.env`, getEnvFileContent(modelProvider, apiKey, adapter, deploymentMode));
|
|
1205
|
-
}
|
|
1206
|
-
if (!isExistingProject) {
|
|
1207
|
-
fs4.writeFileSync(
|
|
1208
|
-
`${targetPath}/index.ts`,
|
|
1209
|
-
getIndexFileContent(adapter, deploymentMode)
|
|
1210
|
-
);
|
|
1211
|
-
} else {
|
|
1212
|
-
console.log("\u23ED\uFE0F Skipped index.ts (existing project)");
|
|
1213
|
-
}
|
|
1214
|
-
if (!isExistingProject) {
|
|
1215
|
-
fs4.writeJsonSync(`${targetPath}/tsconfig.json`, getTsConfigContent(), { spaces: 2 });
|
|
1216
|
-
} else {
|
|
1217
|
-
console.log("\u23ED\uFE0F Skipped tsconfig.json (existing project)");
|
|
1218
|
-
}
|
|
1219
|
-
const packageManager = projectInfo?.packageManager ?? null;
|
|
1220
|
-
setupPackageJson(targetPath, deploymentMode, projectInfo);
|
|
1221
|
-
installDependencies(modelProvider, targetPath, adapter, deploymentMode, packageManager);
|
|
1222
|
-
console.log("Generating types from prompts...");
|
|
1223
|
-
try {
|
|
1224
|
-
const agentmarkDir = path2.join(targetPath, "agentmark");
|
|
1225
|
-
const prompts3 = await fetchPromptsFrontmatter({ rootDir: agentmarkDir });
|
|
1226
|
-
const typeDefinitions = await generateTypeDefinitions(prompts3);
|
|
1227
|
-
fs4.writeFileSync(`${targetPath}/agentmark.types.ts`, typeDefinitions);
|
|
1228
|
-
} catch (error) {
|
|
1229
|
-
console.warn("Warning: Could not generate types automatically:", error);
|
|
1230
|
-
console.log("You can generate types later by running: npx agentmark generate-types --root-dir agentmark");
|
|
1231
|
-
fs4.writeFileSync(`${targetPath}/agentmark.types.ts`, `// Auto-generated types from AgentMark
|
|
1232
|
-
// Run 'npx agentmark generate-types --root-dir agentmark' to generate types
|
|
1233
|
-
export default interface AgentmarkTypes {}
|
|
1234
|
-
`);
|
|
1235
|
-
}
|
|
1236
|
-
if (deploymentMode === "cloud") {
|
|
1237
|
-
const handlerAdapterConfig = getAdapterConfig(adapter, modelProvider);
|
|
1238
|
-
const { webhookHandler: handlerClass } = handlerAdapterConfig.classes;
|
|
1239
|
-
const handlerContent = `import { ${handlerClass} } from '${handlerAdapterConfig.package}/runner';
|
|
1240
|
-
import { AgentMarkSDK } from '@agentmark-ai/sdk';
|
|
1241
|
-
import { client } from './agentmark.client';
|
|
1242
|
-
|
|
1243
|
-
// Initialize tracing \u2014 sends traces to AgentMark Cloud
|
|
1244
|
-
const sdk = new AgentMarkSDK({
|
|
1245
|
-
apiKey: process.env.AGENTMARK_API_KEY ?? '',
|
|
1246
|
-
appId: process.env.AGENTMARK_APP_ID ?? '',
|
|
1247
|
-
baseUrl: process.env.AGENTMARK_BASE_URL,
|
|
1248
|
-
});
|
|
1249
|
-
sdk.initTracing({ disableBatch: true });
|
|
1250
|
-
|
|
1251
|
-
const adapter = new ${handlerClass}(client as any);
|
|
1252
|
-
|
|
1253
|
-
export default async function handler(request: {
|
|
1254
|
-
type: 'prompt-run' | 'dataset-run' | 'get-evals';
|
|
1255
|
-
data: {
|
|
1256
|
-
ast?: any;
|
|
1257
|
-
customProps?: Record<string, unknown>;
|
|
1258
|
-
options?: { shouldStream?: boolean };
|
|
1259
|
-
experimentId?: string;
|
|
1260
|
-
datasetPath?: string;
|
|
1261
|
-
};
|
|
1262
|
-
}) {
|
|
1263
|
-
if (request.type === 'get-evals') {
|
|
1264
|
-
return {
|
|
1265
|
-
type: 'evals',
|
|
1266
|
-
result: JSON.stringify(Object.keys(client.getEvalRegistry())),
|
|
1267
|
-
traceId: '',
|
|
1268
|
-
};
|
|
1269
|
-
}
|
|
1270
|
-
|
|
1271
|
-
if (request.type === 'prompt-run') {
|
|
1272
|
-
return adapter.runPrompt(request.data.ast, {
|
|
1273
|
-
shouldStream: request.data.options?.shouldStream,
|
|
1274
|
-
customProps: request.data.customProps,
|
|
1275
|
-
});
|
|
1276
|
-
}
|
|
1277
|
-
|
|
1278
|
-
if (request.type === 'dataset-run') {
|
|
1279
|
-
return adapter.runExperiment(
|
|
1280
|
-
request.data.ast,
|
|
1281
|
-
request.data.experimentId ?? '',
|
|
1282
|
-
request.data.datasetPath,
|
|
1283
|
-
);
|
|
1284
|
-
}
|
|
1285
|
-
|
|
1286
|
-
throw new Error(\`Unknown request type: \${request.type}\`);
|
|
1287
|
-
}
|
|
1288
|
-
`;
|
|
1289
|
-
const handlerPath = path2.join(targetPath, "handler.ts");
|
|
1290
|
-
if (fs4.existsSync(handlerPath)) {
|
|
1291
|
-
console.log("\u23ED\uFE0F Skipped handler.ts (already exists - preserving customizations)");
|
|
1292
|
-
} else {
|
|
1293
|
-
fs4.writeFileSync(handlerPath, handlerContent);
|
|
1294
|
-
console.log(`\u2705 Created handler.ts for cloud deployment`);
|
|
1295
|
-
}
|
|
1296
|
-
}
|
|
1297
|
-
console.log("Creating development server entry point...");
|
|
1298
|
-
const adapterConfig = getAdapterConfig(adapter, modelProvider);
|
|
1299
|
-
const { webhookHandler } = adapterConfig.classes;
|
|
1300
|
-
const devEntryPath = path2.join(targetPath, "dev-entry.ts");
|
|
1301
|
-
const devEntryContent = `// Development webhook server entry point
|
|
1302
|
-
// This file is version controlled - customize as needed for your project
|
|
1303
|
-
|
|
1304
|
-
import { createWebhookServer } from '@agentmark-ai/cli/runner-server';
|
|
1305
|
-
import { ${webhookHandler} } from '${adapterConfig.package}/runner';
|
|
1306
|
-
import { AgentMarkSDK } from '@agentmark-ai/sdk';
|
|
1307
|
-
import path from 'path';
|
|
1308
|
-
|
|
1309
|
-
async function main() {
|
|
1310
|
-
const args = process.argv.slice(2);
|
|
1311
|
-
const webhookPortArg = args.find(arg => arg.startsWith('--webhook-port='));
|
|
1312
|
-
const apiServerPortArg = args.find(arg => arg.startsWith('--api-server-port='));
|
|
1313
|
-
|
|
1314
|
-
const webhookPort = webhookPortArg ? parseInt(webhookPortArg.split('=')[1]) : 9417;
|
|
1315
|
-
const apiServerPort = apiServerPortArg ? parseInt(apiServerPortArg.split('=')[1]) : 9418;
|
|
1316
|
-
const apiServerUrl = \`http://localhost:\${apiServerPort}\`;
|
|
1317
|
-
|
|
1318
|
-
// Set environment for development mode before importing client
|
|
1319
|
-
process.env.NODE_ENV = 'development';
|
|
1320
|
-
process.env.AGENTMARK_BASE_URL = apiServerUrl;
|
|
1321
|
-
|
|
1322
|
-
// Now import client - it will pick up the dev environment
|
|
1323
|
-
const { client } = await import('./agentmark.client.js');
|
|
1324
|
-
|
|
1325
|
-
// Initialize OpenTelemetry tracing to export traces to the API server
|
|
1326
|
-
const sdk = new AgentMarkSDK({
|
|
1327
|
-
apiKey: '',
|
|
1328
|
-
appId: '',
|
|
1329
|
-
baseUrl: apiServerUrl,
|
|
1330
|
-
});
|
|
1331
|
-
sdk.initTracing({ disableBatch: true });
|
|
1332
|
-
|
|
1333
|
-
const handler = new ${webhookHandler}(client as any);
|
|
1334
|
-
const templatesDirectory = path.join(process.cwd(), 'agentmark');
|
|
1335
|
-
|
|
1336
|
-
await createWebhookServer({
|
|
1337
|
-
port: webhookPort,
|
|
1338
|
-
handler,
|
|
1339
|
-
apiServerUrl,
|
|
1340
|
-
templatesDirectory
|
|
1341
|
-
});
|
|
1342
|
-
}
|
|
1343
|
-
|
|
1344
|
-
main().catch((err) => {
|
|
1345
|
-
console.error(err);
|
|
1346
|
-
process.exit(1);
|
|
1347
|
-
});
|
|
1348
|
-
`;
|
|
1349
|
-
if (fs4.existsSync(devEntryPath)) {
|
|
1350
|
-
console.log("\u23ED\uFE0F Skipped dev-entry.ts (already exists - preserving customizations)");
|
|
1351
|
-
} else {
|
|
1352
|
-
fs4.writeFileSync(devEntryPath, devEntryContent);
|
|
1353
|
-
console.log(`\u2705 Created dev-entry.ts at project root`);
|
|
1354
|
-
}
|
|
1355
|
-
const { installAgentmarkSkill: installAgentmarkSkill2 } = await Promise.resolve().then(() => (init_install_skill(), install_skill_exports));
|
|
1356
|
-
installAgentmarkSkill2(targetPath);
|
|
1357
|
-
console.log("\n\u2705 Agentmark initialization completed successfully!");
|
|
1358
|
-
console.log(
|
|
1359
|
-
`
|
|
1360
|
-
\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557
|
|
1361
|
-
\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2554\u255D
|
|
1362
|
-
\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2554\u255D
|
|
1363
|
-
\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2588\u2588\u2557
|
|
1364
|
-
\u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2557
|
|
1365
|
-
\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D
|
|
1366
|
-
|
|
1367
|
-
`
|
|
1368
|
-
);
|
|
1369
|
-
console.log("\n" + "\u2550".repeat(70));
|
|
1370
|
-
console.log("Next Steps");
|
|
1371
|
-
console.log("\u2550".repeat(70));
|
|
1372
|
-
console.log("\n Get Started:");
|
|
1373
|
-
if (folderName !== "." && folderName !== "./" && !isExistingProject) {
|
|
1374
|
-
console.log(` $ cd ${folderName}`);
|
|
1375
|
-
}
|
|
1376
|
-
console.log(` $ npx agentmark dev
|
|
1377
|
-
`);
|
|
1378
|
-
console.log("\u2500".repeat(70));
|
|
1379
|
-
console.log("Resources");
|
|
1380
|
-
console.log("\u2500".repeat(70));
|
|
1381
|
-
console.log(" Documentation: https://docs.agentmark.co");
|
|
1382
|
-
console.log("\u2550".repeat(70) + "\n");
|
|
1383
|
-
return usedModels;
|
|
1384
|
-
} catch (error) {
|
|
1385
|
-
console.error("Error creating example app:", error);
|
|
1386
|
-
throw error;
|
|
1387
|
-
}
|
|
1388
|
-
};
|
|
1389
2
|
|
|
1390
|
-
// src/
|
|
1391
|
-
import
|
|
1392
|
-
import
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import fs3 from "fs-extra";
|
|
5
|
+
import path3 from "path";
|
|
6
|
+
import prompts from "prompts";
|
|
7
|
+
import { pathToFileURL, fileURLToPath } from "url";
|
|
8
|
+
|
|
9
|
+
// src/utils/examples/mcp-config.ts
|
|
10
|
+
import fs from "fs-extra";
|
|
11
|
+
import * as path from "path";
|
|
12
|
+
var CLOUD_API_URL = "https://api.agentmark.co";
|
|
13
|
+
var LOCAL_DEV_URL = "http://localhost:9418";
|
|
14
|
+
var MCP_SERVER_PACKAGE = "@agentmark-ai/mcp-server";
|
|
15
|
+
function stdioEntry(apiUrl, includeType) {
|
|
16
|
+
const entry = {
|
|
17
|
+
command: "npx",
|
|
18
|
+
args: ["-y", MCP_SERVER_PACKAGE]
|
|
19
|
+
};
|
|
20
|
+
if (apiUrl !== CLOUD_API_URL) {
|
|
21
|
+
entry.env = { AGENTMARK_API_URL: apiUrl };
|
|
1397
22
|
}
|
|
1398
|
-
|
|
23
|
+
if (includeType) entry.type = "stdio";
|
|
24
|
+
return entry;
|
|
25
|
+
}
|
|
26
|
+
function writeMcpConfig(client, targetPath, opts = {}) {
|
|
27
|
+
if (client === "skip") return null;
|
|
28
|
+
const cloudUrl = opts.customApiUrl ?? CLOUD_API_URL;
|
|
29
|
+
const docsEntry = { url: "https://docs.agentmark.co/mcp" };
|
|
1399
30
|
if (client === "vscode") {
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
31
|
+
const vscodeDir = path.join(targetPath, ".vscode");
|
|
32
|
+
fs.ensureDirSync(vscodeDir);
|
|
33
|
+
const configPath = path.join(vscodeDir, "mcp.json");
|
|
34
|
+
const config = {
|
|
35
|
+
servers: {
|
|
36
|
+
"agentmark-docs": docsEntry,
|
|
37
|
+
"agentmark": stdioEntry(
|
|
38
|
+
cloudUrl,
|
|
39
|
+
/* includeType */
|
|
40
|
+
false
|
|
41
|
+
),
|
|
42
|
+
"agentmark-local": stdioEntry(
|
|
43
|
+
LOCAL_DEV_URL,
|
|
44
|
+
/* includeType */
|
|
45
|
+
false
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
fs.writeJsonSync(configPath, config, { spaces: 2 });
|
|
50
|
+
return { configPath };
|
|
1417
51
|
}
|
|
1418
52
|
if (client === "zed") {
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
53
|
+
const zedDir = path.join(targetPath, ".zed");
|
|
54
|
+
fs.ensureDirSync(zedDir);
|
|
55
|
+
const configPath = path.join(zedDir, "settings.json");
|
|
56
|
+
const config = {
|
|
57
|
+
context_servers: {
|
|
58
|
+
"agentmark-docs": docsEntry,
|
|
59
|
+
"agentmark": stdioEntry(
|
|
60
|
+
cloudUrl,
|
|
61
|
+
/* includeType */
|
|
62
|
+
false
|
|
63
|
+
),
|
|
64
|
+
"agentmark-local": stdioEntry(
|
|
65
|
+
LOCAL_DEV_URL,
|
|
66
|
+
/* includeType */
|
|
67
|
+
false
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
fs.writeJsonSync(configPath, config, { spaces: 2 });
|
|
72
|
+
return { configPath };
|
|
1436
73
|
}
|
|
1437
74
|
if (client === "cursor") {
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
75
|
+
const cursorDir = path.join(targetPath, ".cursor");
|
|
76
|
+
fs.ensureDirSync(cursorDir);
|
|
77
|
+
const configPath = path.join(cursorDir, "mcp.json");
|
|
78
|
+
const config = {
|
|
79
|
+
mcpServers: {
|
|
80
|
+
"agentmark-docs": docsEntry,
|
|
81
|
+
"agentmark": stdioEntry(
|
|
82
|
+
cloudUrl,
|
|
83
|
+
/* includeType */
|
|
84
|
+
false
|
|
85
|
+
),
|
|
86
|
+
"agentmark-local": stdioEntry(
|
|
87
|
+
LOCAL_DEV_URL,
|
|
88
|
+
/* includeType */
|
|
89
|
+
false
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
fs.writeJsonSync(configPath, config, { spaces: 2 });
|
|
94
|
+
return { configPath };
|
|
1455
95
|
}
|
|
1456
96
|
if (client === "claude-code") {
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
console.warn(`Warning: Could not set up MCP server for Claude Code:`, error);
|
|
1471
|
-
}
|
|
1472
|
-
return;
|
|
1473
|
-
}
|
|
1474
|
-
};
|
|
1475
|
-
var getPyprojectContent = (projectName, adapter, deploymentMode) => {
|
|
1476
|
-
const pyModules = deploymentMode === "cloud" ? `["agentmark_client", "main", "handler"]` : `["agentmark_client", "main"]`;
|
|
1477
|
-
if (adapter === "claude-agent-sdk") {
|
|
1478
|
-
return `[project]
|
|
1479
|
-
name = "${projectName}"
|
|
1480
|
-
version = "0.1.0"
|
|
1481
|
-
description = "An AgentMark application using Claude Agent SDK"
|
|
1482
|
-
requires-python = ">=3.12"
|
|
1483
|
-
dependencies = [
|
|
1484
|
-
"agentmark-sdk>=0.2.0",
|
|
1485
|
-
"agentmark-claude-agent-sdk-v0>=0.1.4",
|
|
1486
|
-
"agentmark-prompt-core>=0.1.2",
|
|
1487
|
-
"python-dotenv>=1.0.0",
|
|
1488
|
-
"claude-agent-sdk>=0.1.0",
|
|
1489
|
-
]
|
|
1490
|
-
|
|
1491
|
-
[project.optional-dependencies]
|
|
1492
|
-
dev = [
|
|
1493
|
-
"pytest>=7.0",
|
|
1494
|
-
"pytest-asyncio>=0.21",
|
|
1495
|
-
"mypy>=1.0",
|
|
1496
|
-
]
|
|
1497
|
-
|
|
1498
|
-
[build-system]
|
|
1499
|
-
requires = ["setuptools>=61", "wheel"]
|
|
1500
|
-
build-backend = "setuptools.build_meta"
|
|
1501
|
-
|
|
1502
|
-
[tool.setuptools]
|
|
1503
|
-
py-modules = ${pyModules}
|
|
1504
|
-
|
|
1505
|
-
[tool.pytest.ini_options]
|
|
1506
|
-
asyncio_mode = "auto"
|
|
1507
|
-
|
|
1508
|
-
[tool.mypy]
|
|
1509
|
-
strict = true
|
|
1510
|
-
`;
|
|
1511
|
-
}
|
|
1512
|
-
return `[project]
|
|
1513
|
-
name = "${projectName}"
|
|
1514
|
-
version = "0.1.0"
|
|
1515
|
-
description = "An AgentMark application using Pydantic AI"
|
|
1516
|
-
requires-python = ">=3.12"
|
|
1517
|
-
dependencies = [
|
|
1518
|
-
"agentmark-sdk>=0.2.0",
|
|
1519
|
-
"agentmark-pydantic-ai-v0>=0.1.4",
|
|
1520
|
-
"agentmark-prompt-core>=0.1.2",
|
|
1521
|
-
"python-dotenv>=1.0.0",
|
|
1522
|
-
"pydantic-ai-slim[openai]>=1.0,<2.0",
|
|
1523
|
-
]
|
|
1524
|
-
|
|
1525
|
-
[project.optional-dependencies]
|
|
1526
|
-
dev = [
|
|
1527
|
-
"pytest>=7.0",
|
|
1528
|
-
"pytest-asyncio>=0.21",
|
|
1529
|
-
"mypy>=1.0",
|
|
1530
|
-
]
|
|
1531
|
-
|
|
1532
|
-
[build-system]
|
|
1533
|
-
requires = ["setuptools>=61", "wheel"]
|
|
1534
|
-
build-backend = "setuptools.build_meta"
|
|
1535
|
-
|
|
1536
|
-
[tool.setuptools]
|
|
1537
|
-
py-modules = ${pyModules}
|
|
1538
|
-
|
|
1539
|
-
[tool.pytest.ini_options]
|
|
1540
|
-
asyncio_mode = "auto"
|
|
1541
|
-
|
|
1542
|
-
[tool.mypy]
|
|
1543
|
-
strict = true
|
|
1544
|
-
`;
|
|
1545
|
-
};
|
|
1546
|
-
var getHandlerPyContent = (adapter) => {
|
|
1547
|
-
const webhookClass = adapter === "claude-agent-sdk" ? "ClaudeAgentWebhookHandler" : "PydanticAIWebhookHandler";
|
|
1548
|
-
const webhookImport = adapter === "claude-agent-sdk" ? "from agentmark_claude_agent_sdk_v0 import ClaudeAgentWebhookHandler" : "from agentmark_pydantic_ai_v0 import PydanticAIWebhookHandler";
|
|
1549
|
-
return `"""AgentMark handler for managed cloud deployments.
|
|
1550
|
-
|
|
1551
|
-
This file is used by the AgentMark platform to execute prompts and experiments
|
|
1552
|
-
on deployed infrastructure. It mirrors the TypeScript handler.ts pattern.
|
|
1553
|
-
"""
|
|
1554
|
-
|
|
1555
|
-
import os
|
|
1556
|
-
|
|
1557
|
-
from agentmark_sdk import AgentMarkSDK
|
|
1558
|
-
${webhookImport}
|
|
1559
|
-
from agentmark_client import client
|
|
1560
|
-
|
|
1561
|
-
# Initialize tracing
|
|
1562
|
-
sdk = AgentMarkSDK(
|
|
1563
|
-
api_key=os.environ.get("AGENTMARK_API_KEY", ""),
|
|
1564
|
-
app_id=os.environ.get("AGENTMARK_APP_ID", ""),
|
|
1565
|
-
base_url=os.environ.get("AGENTMARK_BASE_URL"),
|
|
1566
|
-
)
|
|
1567
|
-
sdk.init_tracing(disable_batch=True)
|
|
1568
|
-
|
|
1569
|
-
adapter = ${webhookClass}(client)
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
async def handler(request: dict):
|
|
1573
|
-
"""Handle prompt-run, dataset-run, and get-evals requests from the platform."""
|
|
1574
|
-
req_type = request.get("type")
|
|
1575
|
-
data = request.get("data", {})
|
|
1576
|
-
|
|
1577
|
-
if req_type == "get-evals":
|
|
1578
|
-
import json
|
|
1579
|
-
return {
|
|
1580
|
-
"type": "evals",
|
|
1581
|
-
"result": json.dumps(list(client.get_eval_registry().keys())),
|
|
1582
|
-
"traceId": "",
|
|
1583
|
-
}
|
|
1584
|
-
|
|
1585
|
-
if req_type == "prompt-run":
|
|
1586
|
-
return await adapter.run_prompt(data["ast"], {
|
|
1587
|
-
"shouldStream": data.get("options", {}).get("shouldStream", True),
|
|
1588
|
-
"customProps": data.get("customProps"),
|
|
1589
|
-
})
|
|
1590
|
-
|
|
1591
|
-
if req_type == "dataset-run":
|
|
1592
|
-
return await adapter.run_experiment(
|
|
1593
|
-
data["ast"],
|
|
1594
|
-
data.get("experimentId", ""),
|
|
1595
|
-
data.get("datasetPath"),
|
|
97
|
+
const configPath = path.join(targetPath, ".mcp.json");
|
|
98
|
+
const config = {
|
|
99
|
+
mcpServers: {
|
|
100
|
+
"agentmark-docs": { type: "http", ...docsEntry },
|
|
101
|
+
"agentmark": stdioEntry(
|
|
102
|
+
cloudUrl,
|
|
103
|
+
/* includeType */
|
|
104
|
+
true
|
|
105
|
+
),
|
|
106
|
+
"agentmark-local": stdioEntry(
|
|
107
|
+
LOCAL_DEV_URL,
|
|
108
|
+
/* includeType */
|
|
109
|
+
true
|
|
1596
110
|
)
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
};
|
|
1601
|
-
var getAgentmarkClientContent = (deploymentMode, adapter) => {
|
|
1602
|
-
const isCloud = deploymentMode === "cloud";
|
|
1603
|
-
const loaderImport = isCloud ? `from agentmark.prompt_core import ApiLoader` : `from agentmark.prompt_core import FileLoader`;
|
|
1604
|
-
const loaderSetup = isCloud ? `# API loader for cloud deployment \u2014 fetches datasets from the AgentMark gateway
|
|
1605
|
-
loader = ApiLoader.cloud()` : `# File loader for local development \u2014 reads pre-built prompts from the build output directory
|
|
1606
|
-
loader = FileLoader("./dist/agentmark")`;
|
|
1607
|
-
if (adapter === "claude-agent-sdk") {
|
|
1608
|
-
return `"""AgentMark client configuration.
|
|
1609
|
-
|
|
1610
|
-
This file configures the AgentMark client with Claude Agent SDK adapter.
|
|
1611
|
-
Customize the model registry and eval registry as needed.
|
|
1612
|
-
"""
|
|
1613
|
-
|
|
1614
|
-
import json
|
|
1615
|
-
import os
|
|
1616
|
-
from dotenv import load_dotenv
|
|
1617
|
-
|
|
1618
|
-
${loaderImport}
|
|
1619
|
-
from agentmark.prompt_core import EvalRegistry
|
|
1620
|
-
from agentmark_claude_agent_sdk_v0 import (
|
|
1621
|
-
create_claude_agent_client,
|
|
1622
|
-
ClaudeAgentModelRegistry,
|
|
1623
|
-
)
|
|
1624
|
-
|
|
1625
|
-
# Load environment variables
|
|
1626
|
-
load_dotenv()
|
|
1627
|
-
|
|
1628
|
-
# Register the model providers your prompts use.
|
|
1629
|
-
# This maps "anthropic/claude-sonnet-4-20250514" in prompt files to the Claude Agent SDK.
|
|
1630
|
-
model_registry = ClaudeAgentModelRegistry()
|
|
1631
|
-
model_registry.register_providers({
|
|
1632
|
-
"anthropic": "anthropic",
|
|
1633
|
-
})
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
# Evaluation functions \u2014 used by experiments to score model outputs
|
|
1637
|
-
def exact_match_json(params):
|
|
1638
|
-
"""Check if output matches expected output exactly."""
|
|
1639
|
-
output = params.get("output")
|
|
1640
|
-
expected_output = params.get("expectedOutput")
|
|
1641
|
-
if not expected_output:
|
|
1642
|
-
return {"score": 0, "label": "error", "reason": "No expected output provided", "passed": False}
|
|
1643
|
-
try:
|
|
1644
|
-
actual = json.loads(output) if isinstance(output, str) else output
|
|
1645
|
-
expected = json.loads(expected_output) if isinstance(expected_output, str) else expected_output
|
|
1646
|
-
ok = actual == expected
|
|
1647
|
-
return {
|
|
1648
|
-
"score": 1 if ok else 0,
|
|
1649
|
-
"label": "correct" if ok else "incorrect",
|
|
1650
|
-
"reason": "Exact match" if ok else "Mismatch",
|
|
1651
|
-
"passed": ok,
|
|
1652
|
-
}
|
|
1653
|
-
except (json.JSONDecodeError, TypeError):
|
|
1654
|
-
return {"score": 0, "label": "error", "reason": "Failed to parse JSON", "passed": False}
|
|
1655
|
-
|
|
1656
|
-
evals: EvalRegistry = {
|
|
1657
|
-
"exact_match_json": exact_match_json,
|
|
1658
|
-
}
|
|
1659
|
-
|
|
1660
|
-
${loaderSetup}
|
|
1661
|
-
|
|
1662
|
-
# Create the client
|
|
1663
|
-
# Claude Agent SDK handles tools natively through the SDK
|
|
1664
|
-
client = create_claude_agent_client(
|
|
1665
|
-
model_registry=model_registry,
|
|
1666
|
-
evals=evals,
|
|
1667
|
-
loader=loader,
|
|
1668
|
-
)
|
|
1669
|
-
|
|
1670
|
-
__all__ = ["client"]
|
|
1671
|
-
`;
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
fs.writeJsonSync(configPath, config, { spaces: 2 });
|
|
114
|
+
return { configPath };
|
|
1672
115
|
}
|
|
1673
|
-
return
|
|
1674
|
-
|
|
1675
|
-
This file configures the AgentMark client with Pydantic AI adapter.
|
|
1676
|
-
Customize the model registry, tools, and eval registry as needed.
|
|
1677
|
-
"""
|
|
1678
|
-
|
|
1679
|
-
import json
|
|
1680
|
-
import os
|
|
1681
|
-
from dotenv import load_dotenv
|
|
1682
|
-
|
|
1683
|
-
${loaderImport}
|
|
1684
|
-
from agentmark.prompt_core import EvalRegistry
|
|
1685
|
-
from agentmark_pydantic_ai_v0 import (
|
|
1686
|
-
create_pydantic_ai_client,
|
|
1687
|
-
PydanticAIModelRegistry,
|
|
1688
|
-
)
|
|
1689
|
-
|
|
1690
|
-
# Load environment variables
|
|
1691
|
-
load_dotenv()
|
|
1692
|
-
|
|
1693
|
-
# Register the model providers your prompts use.
|
|
1694
|
-
# This maps "openai/gpt-4o" in prompt files to "openai:gpt-4o" for Pydantic AI.
|
|
1695
|
-
model_registry = PydanticAIModelRegistry()
|
|
1696
|
-
model_registry.register_providers({
|
|
1697
|
-
"openai": "openai",
|
|
1698
|
-
"anthropic": "anthropic",
|
|
1699
|
-
})
|
|
1700
|
-
|
|
1701
|
-
# Define tools as native pydantic-ai Tool objects or callables
|
|
1702
|
-
# Example:
|
|
1703
|
-
# def search(query: str) -> str:
|
|
1704
|
-
# return f"Search results for: {query}"
|
|
1705
|
-
# tools = [search]
|
|
1706
|
-
tools = []
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
# Evaluation functions \u2014 used by experiments to score model outputs
|
|
1710
|
-
def exact_match_json(params):
|
|
1711
|
-
"""Check if output matches expected output exactly."""
|
|
1712
|
-
output = params.get("output")
|
|
1713
|
-
expected_output = params.get("expectedOutput")
|
|
1714
|
-
if not expected_output:
|
|
1715
|
-
return {"score": 0, "label": "error", "reason": "No expected output provided", "passed": False}
|
|
1716
|
-
try:
|
|
1717
|
-
actual = json.loads(output) if isinstance(output, str) else output
|
|
1718
|
-
expected = json.loads(expected_output) if isinstance(expected_output, str) else expected_output
|
|
1719
|
-
ok = actual == expected
|
|
1720
|
-
return {
|
|
1721
|
-
"score": 1 if ok else 0,
|
|
1722
|
-
"label": "correct" if ok else "incorrect",
|
|
1723
|
-
"reason": "Exact match" if ok else "Mismatch",
|
|
1724
|
-
"passed": ok,
|
|
1725
|
-
}
|
|
1726
|
-
except (json.JSONDecodeError, TypeError):
|
|
1727
|
-
return {"score": 0, "label": "error", "reason": "Failed to parse JSON", "passed": False}
|
|
1728
|
-
|
|
1729
|
-
evals: EvalRegistry = {
|
|
1730
|
-
"exact_match_json": exact_match_json,
|
|
116
|
+
return null;
|
|
1731
117
|
}
|
|
1732
118
|
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
loader=loader,
|
|
1741
|
-
)
|
|
1742
|
-
|
|
1743
|
-
__all__ = ["client"]
|
|
1744
|
-
`;
|
|
1745
|
-
};
|
|
1746
|
-
var getMainPyContent = (adapter, deploymentMode = "cloud") => {
|
|
1747
|
-
const isCloud = deploymentMode === "cloud";
|
|
1748
|
-
const cloudTracingInit = `
|
|
1749
|
-
# Initialize tracing - traces will be sent to AgentMark Cloud
|
|
1750
|
-
# To disable tracing, comment out sdk.init_tracing() below
|
|
1751
|
-
sdk = AgentMarkSDK(
|
|
1752
|
-
api_key=os.environ.get("AGENTMARK_API_KEY", ""),
|
|
1753
|
-
app_id=os.environ.get("AGENTMARK_APP_ID", ""),
|
|
1754
|
-
)
|
|
1755
|
-
sdk.init_tracing(disable_batch=True)
|
|
1756
|
-
`;
|
|
1757
|
-
const staticTracingInit = `
|
|
1758
|
-
# Initialize tracing - traces will be sent to local dev server
|
|
1759
|
-
# Make sure to run "npx agentmark dev" in another terminal first
|
|
1760
|
-
# To disable tracing, comment out sdk.init_tracing() below
|
|
1761
|
-
sdk = AgentMarkSDK(
|
|
1762
|
-
api_key="",
|
|
1763
|
-
app_id="",
|
|
1764
|
-
base_url="http://localhost:9418",
|
|
1765
|
-
)
|
|
1766
|
-
sdk.init_tracing(disable_batch=True)
|
|
1767
|
-
`;
|
|
1768
|
-
const tracingInit = isCloud ? cloudTracingInit : staticTracingInit;
|
|
1769
|
-
if (adapter === "claude-agent-sdk") {
|
|
1770
|
-
return `"""Example usage of AgentMark with Claude Agent SDK.
|
|
1771
|
-
|
|
1772
|
-
Run with:
|
|
1773
|
-
npx agentmark build # compile party-planner.prompt.mdx -> dist/agentmark/*.json
|
|
1774
|
-
python main.py
|
|
1775
|
-
"""
|
|
1776
|
-
|
|
1777
|
-
import asyncio
|
|
1778
|
-
import os
|
|
1779
|
-
|
|
1780
|
-
from agentmark_sdk import AgentMarkSDK
|
|
1781
|
-
from agentmark_claude_agent_sdk_v0 import traced_query
|
|
1782
|
-
from agentmark_client import client
|
|
1783
|
-
${tracingInit}
|
|
1784
|
-
|
|
1785
|
-
async def main():
|
|
1786
|
-
"""Run the party planner prompt (object_config: extracts attendee names)."""
|
|
1787
|
-
# \`agentmark build\` writes pre-compiled prompts to dist/agentmark/.
|
|
1788
|
-
# The FileLoader reads them by name \u2014 extension is optional.
|
|
1789
|
-
try:
|
|
1790
|
-
prompt = await client.load_object_prompt("party-planner.prompt.mdx")
|
|
1791
|
-
except FileNotFoundError:
|
|
1792
|
-
print("Pre-built prompt not found. Run 'npx agentmark build' first.")
|
|
1793
|
-
return
|
|
1794
|
-
|
|
1795
|
-
adapted = await prompt.format(props={
|
|
1796
|
-
"party_text": "We're having a party with Alice, Bob, and Carol.",
|
|
1797
|
-
})
|
|
1798
|
-
|
|
1799
|
-
# Execute via Claude Agent SDK (streamed) with automatic OTEL tracing.
|
|
1800
|
-
# adapted.query.options.output_format is set to the object schema.
|
|
1801
|
-
print("Running party planner prompt...")
|
|
1802
|
-
print("=" * 50)
|
|
1803
|
-
async for message in traced_query(adapted):
|
|
1804
|
-
print(message)
|
|
1805
|
-
print("=" * 50)
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
if __name__ == "__main__":
|
|
1809
|
-
asyncio.run(main())
|
|
1810
|
-
`;
|
|
1811
|
-
}
|
|
1812
|
-
return `"""Example usage of AgentMark with Pydantic AI.
|
|
1813
|
-
|
|
1814
|
-
Run with:
|
|
1815
|
-
npx agentmark build # compile party-planner.prompt.mdx -> dist/agentmark/*.json
|
|
1816
|
-
python main.py
|
|
1817
|
-
"""
|
|
1818
|
-
# To use a different LLM provider, install: pip install "pydantic-ai-slim[anthropic]" (or [google], [bedrock], etc.)
|
|
1819
|
-
|
|
1820
|
-
import asyncio
|
|
1821
|
-
import os
|
|
1822
|
-
|
|
1823
|
-
from agentmark_sdk import AgentMarkSDK
|
|
1824
|
-
from agentmark_pydantic_ai_v0 import run_object_prompt
|
|
1825
|
-
from agentmark_client import client
|
|
1826
|
-
${tracingInit}
|
|
1827
|
-
|
|
1828
|
-
async def main():
|
|
1829
|
-
"""Run the party planner prompt (object_config: extracts attendee names)."""
|
|
1830
|
-
# \`agentmark build\` writes pre-compiled prompts to dist/agentmark/.
|
|
1831
|
-
# The FileLoader reads them by name \u2014 extension is optional, and it
|
|
1832
|
-
# extracts the inner AST from the { ast, metadata } wrapper for you.
|
|
1833
|
-
try:
|
|
1834
|
-
prompt = await client.load_object_prompt("party-planner.prompt.mdx")
|
|
1835
|
-
except FileNotFoundError:
|
|
1836
|
-
print("Pre-built prompt not found. Run 'npx agentmark build' first.")
|
|
1837
|
-
return
|
|
1838
|
-
|
|
1839
|
-
params = await prompt.format(props={
|
|
1840
|
-
"party_text": "We're having a party with Alice, Bob, and Carol.",
|
|
1841
|
-
})
|
|
1842
|
-
|
|
1843
|
-
# Execute the prompt
|
|
1844
|
-
print("Running party planner prompt...")
|
|
1845
|
-
result = await run_object_prompt(params)
|
|
1846
|
-
|
|
1847
|
-
print("\\n" + "=" * 50)
|
|
1848
|
-
print("Extracted attendees:")
|
|
1849
|
-
print("=" * 50)
|
|
1850
|
-
# result.output is a Pydantic model instance with the schema's fields
|
|
1851
|
-
print(result.output.names)
|
|
1852
|
-
print("\\n" + "-" * 50)
|
|
1853
|
-
print(f"Tokens used: {result.usage.total_tokens}")
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
if __name__ == "__main__":
|
|
1857
|
-
asyncio.run(main())
|
|
1858
|
-
`;
|
|
1859
|
-
};
|
|
1860
|
-
var getDevServerContent = (adapter) => {
|
|
1861
|
-
const adapterPackage = adapter === "claude-agent-sdk" ? "agentmark_claude_agent_sdk_v0" : "agentmark_pydantic_ai_v0";
|
|
1862
|
-
return `"""Auto-generated webhook server for AgentMark development.
|
|
1863
|
-
|
|
1864
|
-
This server is started by 'npx agentmark dev' (agentmark dev) and handles
|
|
1865
|
-
prompt execution requests from the CLI.
|
|
1866
|
-
"""
|
|
1867
|
-
|
|
1868
|
-
import argparse
|
|
1869
|
-
import sys
|
|
1870
|
-
from pathlib import Path
|
|
1871
|
-
|
|
1872
|
-
# Add parent directory to path for imports
|
|
1873
|
-
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
1874
|
-
|
|
1875
|
-
from ${adapterPackage} import create_webhook_server
|
|
1876
|
-
from agentmark_client import client
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
if __name__ == "__main__":
|
|
1880
|
-
parser = argparse.ArgumentParser()
|
|
1881
|
-
parser.add_argument("--webhook-port", type=int, default=9417)
|
|
1882
|
-
parser.add_argument("--api-server-port", type=int, default=9418)
|
|
1883
|
-
args = parser.parse_args()
|
|
1884
|
-
|
|
1885
|
-
create_webhook_server(client, args.webhook_port, args.api_server_port)
|
|
1886
|
-
`;
|
|
1887
|
-
};
|
|
1888
|
-
var getEnvContent = (apiKey, adapter) => {
|
|
1889
|
-
if (adapter === "claude-agent-sdk") {
|
|
1890
|
-
return `# Anthropic API Key
|
|
1891
|
-
ANTHROPIC_API_KEY=${apiKey}
|
|
1892
|
-
`;
|
|
119
|
+
// src/utils/install-skill.ts
|
|
120
|
+
import { execFileSync } from "child_process";
|
|
121
|
+
var shouldSkip = () => process.env.VITEST === "true" || process.env.NODE_ENV === "test" || process.env.AGENTMARK_SKIP_SKILL_INSTALL === "1";
|
|
122
|
+
var installAgentmarkSkill = (targetPath) => {
|
|
123
|
+
if (shouldSkip()) {
|
|
124
|
+
console.log("\n\u23ED\uFE0F Skipping agent skill install (test environment detected).");
|
|
125
|
+
return;
|
|
1893
126
|
}
|
|
1894
|
-
return `# OpenAI API Key
|
|
1895
|
-
OPENAI_API_KEY=${apiKey}
|
|
1896
|
-
|
|
1897
|
-
# For Anthropic models, add:
|
|
1898
|
-
# ANTHROPIC_API_KEY=your-key-here
|
|
1899
|
-
|
|
1900
|
-
# For Google Gemini models, add:
|
|
1901
|
-
# GOOGLE_API_KEY=your-key-here
|
|
1902
|
-
`;
|
|
1903
|
-
};
|
|
1904
|
-
var getReadmeContent = (projectName, adapter) => {
|
|
1905
|
-
const adapterName = adapter === "claude-agent-sdk" ? "Claude Agent SDK" : "Pydantic AI";
|
|
1906
|
-
const apiKeyEnvVar = adapter === "claude-agent-sdk" ? "ANTHROPIC_API_KEY" : "OPENAI_API_KEY";
|
|
1907
|
-
const directInstallCmd = adapter === "claude-agent-sdk" ? "pip install agentmark-sdk agentmark-claude-agent-sdk-v0 agentmark-prompt-core python-dotenv claude-agent-sdk" : 'pip install agentmark-sdk agentmark-pydantic-ai-v0 agentmark-prompt-core python-dotenv "pydantic-ai-slim[openai]>=1.0,<2.0"';
|
|
1908
|
-
return `# ${projectName}
|
|
1909
|
-
|
|
1910
|
-
An AgentMark application using ${adapterName}.
|
|
1911
|
-
|
|
1912
|
-
## Prerequisites
|
|
1913
|
-
|
|
1914
|
-
- Python 3.12+
|
|
1915
|
-
- **pip 26.1+** (older pip versions fail to resolve the dependency graph \u2014 see "Why pip 26.1?" below)
|
|
1916
|
-
|
|
1917
|
-
## Setup
|
|
1918
|
-
|
|
1919
|
-
\`\`\`bash
|
|
1920
|
-
# 1. Create and activate a virtual environment
|
|
1921
|
-
python -m venv .venv
|
|
1922
|
-
source .venv/bin/activate # On Windows: .venv\\Scripts\\activate
|
|
1923
|
-
|
|
1924
|
-
# 2. Upgrade pip (REQUIRED \u2014 older pip cannot resolve pydantic-ai's transitive graph)
|
|
1925
|
-
python -m pip install --upgrade "pip>=26.1"
|
|
1926
|
-
|
|
1927
|
-
# 3. Install dependencies
|
|
1928
|
-
${directInstallCmd}
|
|
1929
|
-
|
|
1930
|
-
# 4. Set your API key
|
|
1931
|
-
echo "${apiKeyEnvVar}=your-key-here" > .env
|
|
1932
|
-
\`\`\`
|
|
1933
|
-
|
|
1934
|
-
## Run
|
|
1935
|
-
|
|
1936
|
-
\`\`\`bash
|
|
1937
|
-
# Start the AgentMark dev server (in another terminal)
|
|
1938
|
-
npx agentmark dev
|
|
1939
|
-
|
|
1940
|
-
# Run the example prompt
|
|
1941
|
-
python main.py
|
|
1942
|
-
\`\`\`
|
|
1943
|
-
|
|
1944
|
-
Then open [http://localhost:9418](http://localhost:9418) to view your traces.
|
|
1945
|
-
|
|
1946
|
-
## Why pip 26.1?
|
|
1947
|
-
|
|
1948
|
-
The \`pydantic-ai-slim\` package transitively depends on \`mcp\`, \`fastmcp\`, and
|
|
1949
|
-
\`logfire\`, which together produce a deep dependency graph. Pip versions before
|
|
1950
|
-
26.1 fall into long backtracking loops and abort with \`resolution-too-deep\`.
|
|
1951
|
-
Pip 26.1's resolver handles this graph efficiently. If you skip the upgrade and
|
|
1952
|
-
hit the error, run \`python -m pip install --upgrade pip\` and retry.
|
|
1953
|
-
|
|
1954
|
-
## Resources
|
|
1955
|
-
|
|
1956
|
-
- [Documentation](https://docs.agentmark.co)
|
|
1957
|
-
- [GitHub](https://github.com/agentmark-ai/agentmark)
|
|
1958
|
-
`;
|
|
1959
|
-
};
|
|
1960
|
-
var getGitignoreContent = () => {
|
|
1961
|
-
return `# Python
|
|
1962
|
-
__pycache__/
|
|
1963
|
-
*.py[cod]
|
|
1964
|
-
*$py.class
|
|
1965
|
-
.venv/
|
|
1966
|
-
venv/
|
|
1967
|
-
.env
|
|
1968
|
-
|
|
1969
|
-
# AgentMark
|
|
1970
|
-
*.agentmark-outputs/
|
|
1971
|
-
.agentmark/
|
|
1972
|
-
|
|
1973
|
-
# IDE
|
|
1974
|
-
.idea/
|
|
1975
|
-
.vscode/
|
|
1976
|
-
*.swp
|
|
1977
|
-
|
|
1978
|
-
# Build
|
|
1979
|
-
dist/
|
|
1980
|
-
build/
|
|
1981
|
-
*.egg-info/
|
|
1982
|
-
|
|
1983
|
-
# Testing
|
|
1984
|
-
.pytest_cache/
|
|
1985
|
-
.coverage
|
|
1986
|
-
htmlcov/
|
|
1987
|
-
`;
|
|
1988
|
-
};
|
|
1989
|
-
var createPythonApp = async (client, targetPath = ".", apiKey = "", deploymentMode = "cloud", adapter = "pydantic-ai", projectInfo = null, resolutions = []) => {
|
|
1990
127
|
try {
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
const folderName = targetPath;
|
|
2000
|
-
fs5.ensureDirSync(`${targetPath}/agentmark`);
|
|
2001
|
-
setupMCPServer2(client, targetPath);
|
|
2002
|
-
const usedModels = createExamplePrompts(model, targetPath, adapter);
|
|
2003
|
-
console.log(`Example prompts and datasets created in ${folderName}/agentmark/`);
|
|
2004
|
-
if (!isExistingProject) {
|
|
2005
|
-
const projectName = path3.basename(targetPath).replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
2006
|
-
fs5.writeFileSync(`${targetPath}/pyproject.toml`, getPyprojectContent(projectName, adapter, deploymentMode));
|
|
2007
|
-
} else {
|
|
2008
|
-
console.log("\u23ED\uFE0F Skipped pyproject.toml (existing project)");
|
|
2009
|
-
}
|
|
2010
|
-
fs5.writeFileSync(`${targetPath}/agentmark_client.py`, getAgentmarkClientContent(deploymentMode, adapter));
|
|
2011
|
-
if (deploymentMode === "cloud") {
|
|
2012
|
-
const handlerPath = path3.join(targetPath, "handler.py");
|
|
2013
|
-
if (fs5.existsSync(handlerPath)) {
|
|
2014
|
-
console.log("\u23ED\uFE0F Skipped handler.py (already exists - preserving customizations)");
|
|
2015
|
-
} else {
|
|
2016
|
-
fs5.writeFileSync(handlerPath, getHandlerPyContent(adapter));
|
|
2017
|
-
console.log(`\u2705 Created handler.py for cloud deployment`);
|
|
2018
|
-
}
|
|
2019
|
-
}
|
|
2020
|
-
if (!isExistingProject) {
|
|
2021
|
-
fs5.writeFileSync(`${targetPath}/main.py`, getMainPyContent(adapter, deploymentMode));
|
|
2022
|
-
} else {
|
|
2023
|
-
console.log("\u23ED\uFE0F Skipped main.py (existing project)");
|
|
2024
|
-
}
|
|
2025
|
-
if (shouldMergeFile(".env", projectInfo, resolutions)) {
|
|
2026
|
-
const envVars = {};
|
|
2027
|
-
const apiKeyEnvVar = adapter === "claude-agent-sdk" ? "ANTHROPIC_API_KEY" : "OPENAI_API_KEY";
|
|
2028
|
-
if (apiKey) {
|
|
2029
|
-
envVars[apiKeyEnvVar] = apiKey;
|
|
2030
|
-
} else {
|
|
2031
|
-
envVars[apiKeyEnvVar] = adapter === "claude-agent-sdk" ? "your-anthropic-api-key" : "your-openai-api-key";
|
|
2032
|
-
}
|
|
2033
|
-
const result = appendEnv(targetPath, envVars);
|
|
2034
|
-
if (result.added.length > 0) {
|
|
2035
|
-
console.log(`\u2705 Added to .env: ${result.added.join(", ")}`);
|
|
2036
|
-
}
|
|
2037
|
-
if (result.skipped.length > 0) {
|
|
2038
|
-
console.log(`\u23ED\uFE0F Skipped existing .env vars: ${result.skipped.join(", ")}`);
|
|
2039
|
-
}
|
|
2040
|
-
} else {
|
|
2041
|
-
fs5.writeFileSync(`${targetPath}/.env`, getEnvContent(apiKey, adapter));
|
|
2042
|
-
}
|
|
2043
|
-
const gitignoreEntries = [
|
|
2044
|
-
"__pycache__/",
|
|
2045
|
-
"*.py[cod]",
|
|
2046
|
-
"*$py.class",
|
|
2047
|
-
".venv/",
|
|
2048
|
-
"venv/",
|
|
2049
|
-
".env",
|
|
2050
|
-
"*.agentmark-outputs/",
|
|
2051
|
-
".agentmark/",
|
|
2052
|
-
".idea/",
|
|
2053
|
-
".vscode/",
|
|
2054
|
-
"*.swp",
|
|
2055
|
-
"dist/",
|
|
2056
|
-
"build/",
|
|
2057
|
-
"*.egg-info/",
|
|
2058
|
-
".pytest_cache/",
|
|
2059
|
-
".coverage",
|
|
2060
|
-
"htmlcov/"
|
|
2061
|
-
];
|
|
2062
|
-
if (shouldMergeFile(".gitignore", projectInfo, resolutions)) {
|
|
2063
|
-
const result = appendGitignore(targetPath, gitignoreEntries);
|
|
2064
|
-
if (result.added.length > 0) {
|
|
2065
|
-
console.log(`\u2705 Added to .gitignore: ${result.added.join(", ")}`);
|
|
2066
|
-
}
|
|
2067
|
-
if (result.skipped.length > 0) {
|
|
2068
|
-
console.log(`\u23ED\uFE0F Already in .gitignore: ${result.skipped.join(", ")}`);
|
|
2069
|
-
}
|
|
2070
|
-
} else {
|
|
2071
|
-
fs5.writeFileSync(`${targetPath}/.gitignore`, getGitignoreContent());
|
|
2072
|
-
}
|
|
2073
|
-
if (!isExistingProject) {
|
|
2074
|
-
const readmePath = path3.join(targetPath, "README.md");
|
|
2075
|
-
if (!fs5.existsSync(readmePath)) {
|
|
2076
|
-
const projectName = path3.basename(targetPath).replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
2077
|
-
fs5.writeFileSync(readmePath, getReadmeContent(projectName, adapter));
|
|
2078
|
-
console.log(`\u2705 Created README.md`);
|
|
128
|
+
console.log("\n\u{1F4DA} Installing AgentMark agent skill...");
|
|
129
|
+
console.log(" (teaches Claude Code / Codex / Cursor / Copilot how to use AgentMark)");
|
|
130
|
+
execFileSync(
|
|
131
|
+
"npx",
|
|
132
|
+
["--yes", "skills", "add", "agentmark-ai/skills"],
|
|
133
|
+
{
|
|
134
|
+
cwd: targetPath,
|
|
135
|
+
stdio: "inherit"
|
|
2079
136
|
}
|
|
2080
|
-
}
|
|
2081
|
-
const agentmarkInternalDir = path3.join(targetPath, ".agentmark");
|
|
2082
|
-
fs5.ensureDirSync(agentmarkInternalDir);
|
|
2083
|
-
fs5.writeFileSync(path3.join(agentmarkInternalDir, "dev_server.py"), getDevServerContent(adapter));
|
|
2084
|
-
const pythonVenv = projectInfo?.pythonVenv;
|
|
2085
|
-
if (pythonVenv) {
|
|
2086
|
-
console.log(`
|
|
2087
|
-
\u{1F4E6} Detected existing Python venv: ${pythonVenv.name}`);
|
|
2088
|
-
console.log(" Remember to activate it before running AgentMark commands.");
|
|
2089
|
-
} else if (!isExistingProject) {
|
|
2090
|
-
console.log("Setting up Python environment...");
|
|
2091
|
-
console.log("Note: You'll need to set up a virtual environment and install dependencies.");
|
|
2092
|
-
console.log("");
|
|
2093
|
-
}
|
|
2094
|
-
const { installAgentmarkSkill: installAgentmarkSkill2 } = await Promise.resolve().then(() => (init_install_skill(), install_skill_exports));
|
|
2095
|
-
installAgentmarkSkill2(targetPath);
|
|
2096
|
-
console.log("\n\u2705 AgentMark Python initialization completed successfully!");
|
|
2097
|
-
console.log(
|
|
2098
|
-
`
|
|
2099
|
-
\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
|
|
2100
|
-
\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
|
|
2101
|
-
\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
|
|
2102
|
-
\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
|
|
2103
|
-
\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
|
|
2104
|
-
\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
|
|
2105
|
-
+ AgentMark
|
|
2106
|
-
`
|
|
2107
137
|
);
|
|
2108
|
-
console.log("\
|
|
2109
|
-
console.log("Next Steps");
|
|
2110
|
-
console.log("\u2550".repeat(70));
|
|
2111
|
-
console.log("\n Get Started:");
|
|
2112
|
-
if (folderName !== "." && folderName !== "./" && !isExistingProject) {
|
|
2113
|
-
console.log(` $ cd ${folderName}`);
|
|
2114
|
-
}
|
|
2115
|
-
const pipInstallCmd = adapter === "claude-agent-sdk" ? " $ pip install agentmark-sdk agentmark-claude-agent-sdk-v0 agentmark-prompt-core python-dotenv claude-agent-sdk" : ' $ pip install agentmark-sdk agentmark-pydantic-ai-v0 agentmark-prompt-core python-dotenv "pydantic-ai-slim[openai]>=1.0,<2.0"';
|
|
2116
|
-
const pipUpgradeCmd = ' $ python -m pip install --upgrade "pip>=26.1"';
|
|
2117
|
-
if (pythonVenv) {
|
|
2118
|
-
const activateCmd = process.platform === "win32" ? `${pythonVenv.name}\\Scripts\\activate` : `source ${pythonVenv.name}/bin/activate`;
|
|
2119
|
-
console.log(` $ ${activateCmd}`);
|
|
2120
|
-
console.log(pipUpgradeCmd);
|
|
2121
|
-
console.log(pipInstallCmd);
|
|
2122
|
-
} else {
|
|
2123
|
-
console.log(" $ python -m venv .venv");
|
|
2124
|
-
console.log(" $ source .venv/bin/activate # On Windows: .venv\\Scripts\\activate");
|
|
2125
|
-
console.log(pipUpgradeCmd);
|
|
2126
|
-
console.log(pipInstallCmd);
|
|
2127
|
-
}
|
|
2128
|
-
console.log(" $ npx agentmark dev\n");
|
|
2129
|
-
console.log("\u2500".repeat(70));
|
|
2130
|
-
console.log("Resources");
|
|
2131
|
-
console.log("\u2500".repeat(70));
|
|
2132
|
-
console.log(" Documentation: https://docs.agentmark.co");
|
|
2133
|
-
console.log("\u2550".repeat(70) + "\n");
|
|
2134
|
-
return usedModels;
|
|
138
|
+
console.log("\u2705 Agent skill installed at ./.agents/skills/agentmark/");
|
|
2135
139
|
} catch (error) {
|
|
2136
|
-
console.
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
// src/utils/package-manager.ts
|
|
2146
|
-
import fs6 from "fs-extra";
|
|
2147
|
-
import path4 from "path";
|
|
2148
|
-
function detectPackageManager(targetPath) {
|
|
2149
|
-
const lockFiles = ["yarn.lock", "pnpm-lock.yaml", "bun.lockb", "package-lock.json"];
|
|
2150
|
-
for (const lockFile of lockFiles) {
|
|
2151
|
-
if (fs6.existsSync(path4.join(targetPath, lockFile))) {
|
|
2152
|
-
const config = PACKAGE_MANAGERS[lockFile];
|
|
2153
|
-
if (config) {
|
|
2154
|
-
return config;
|
|
2155
|
-
}
|
|
2156
|
-
}
|
|
2157
|
-
}
|
|
2158
|
-
return DEFAULT_PACKAGE_MANAGER;
|
|
2159
|
-
}
|
|
2160
|
-
|
|
2161
|
-
// src/utils/project-detection.ts
|
|
2162
|
-
var IS_WINDOWS = process.platform === "win32";
|
|
2163
|
-
function detectTypeScriptProject(targetPath) {
|
|
2164
|
-
const indicators = ["package.json", "tsconfig.json", "node_modules"];
|
|
2165
|
-
return indicators.some((file) => fs7.existsSync(path5.join(targetPath, file)));
|
|
2166
|
-
}
|
|
2167
|
-
function detectPythonProject(targetPath) {
|
|
2168
|
-
const indicators = ["pyproject.toml", "requirements.txt", "setup.py", ".venv", "venv"];
|
|
2169
|
-
return indicators.some((file) => fs7.existsSync(path5.join(targetPath, file)));
|
|
2170
|
-
}
|
|
2171
|
-
function detectPythonVenv(targetPath) {
|
|
2172
|
-
const venvNames = [".venv", "venv"];
|
|
2173
|
-
for (const name of venvNames) {
|
|
2174
|
-
const venvPath = path5.join(targetPath, name);
|
|
2175
|
-
if (fs7.existsSync(venvPath) && fs7.statSync(venvPath).isDirectory()) {
|
|
2176
|
-
const binDir = IS_WINDOWS ? "Scripts" : "bin";
|
|
2177
|
-
const binPath = path5.join(venvPath, binDir);
|
|
2178
|
-
if (fs7.existsSync(binPath)) {
|
|
2179
|
-
const pipExe = IS_WINDOWS ? "pip.exe" : "pip";
|
|
2180
|
-
return {
|
|
2181
|
-
path: venvPath,
|
|
2182
|
-
name,
|
|
2183
|
-
activateCmd: IS_WINDOWS ? `${name}\\Scripts\\activate` : `source ${name}/bin/activate`,
|
|
2184
|
-
pipPath: path5.join(binPath, pipExe)
|
|
2185
|
-
};
|
|
2186
|
-
}
|
|
2187
|
-
}
|
|
2188
|
-
}
|
|
2189
|
-
const envVenv = process.env.VIRTUAL_ENV;
|
|
2190
|
-
if (envVenv && fs7.existsSync(envVenv)) {
|
|
2191
|
-
const resolvedTarget = path5.resolve(targetPath);
|
|
2192
|
-
const resolvedVenv = path5.resolve(envVenv);
|
|
2193
|
-
const isInsideTarget = resolvedVenv.startsWith(resolvedTarget + path5.sep) || resolvedVenv === resolvedTarget;
|
|
2194
|
-
if (!isInsideTarget) {
|
|
2195
|
-
console.warn(
|
|
2196
|
-
`\u26A0\uFE0F Note: VIRTUAL_ENV (${envVenv}) points outside the target directory. It will not be used for this initialization.`
|
|
2197
|
-
);
|
|
2198
|
-
return null;
|
|
2199
|
-
}
|
|
2200
|
-
const binDir = IS_WINDOWS ? "Scripts" : "bin";
|
|
2201
|
-
const pipExe = IS_WINDOWS ? "pip.exe" : "pip";
|
|
2202
|
-
const name = path5.basename(envVenv);
|
|
2203
|
-
return {
|
|
2204
|
-
path: envVenv,
|
|
2205
|
-
name,
|
|
2206
|
-
activateCmd: IS_WINDOWS ? `${name}\\Scripts\\activate` : `source ${name}/bin/activate`,
|
|
2207
|
-
pipPath: path5.join(envVenv, binDir, pipExe)
|
|
2208
|
-
};
|
|
2209
|
-
}
|
|
2210
|
-
return null;
|
|
2211
|
-
}
|
|
2212
|
-
function detectConflictingFiles(targetPath) {
|
|
2213
|
-
const existingConflicts = [];
|
|
2214
|
-
for (const conflictFile of CONFLICT_FILES) {
|
|
2215
|
-
const fullPath = path5.join(targetPath, conflictFile.path);
|
|
2216
|
-
if (fs7.existsSync(fullPath)) {
|
|
2217
|
-
existingConflicts.push(conflictFile);
|
|
140
|
+
console.warn(
|
|
141
|
+
"\n\u26A0\uFE0F Could not install the AgentMark agent skill automatically."
|
|
142
|
+
);
|
|
143
|
+
console.warn(" You can install it later with:");
|
|
144
|
+
console.warn(" cd " + targetPath);
|
|
145
|
+
console.warn(" npx skills add agentmark-ai/skills");
|
|
146
|
+
if (error instanceof Error) {
|
|
147
|
+
console.warn(` Reason: ${error.message.split("\n")[0]}`);
|
|
2218
148
|
}
|
|
2219
149
|
}
|
|
2220
|
-
|
|
2221
|
-
}
|
|
2222
|
-
function detectProjectInfo(targetPath) {
|
|
2223
|
-
const isTypeScript = detectTypeScriptProject(targetPath);
|
|
2224
|
-
const isPython = detectPythonProject(targetPath);
|
|
2225
|
-
const isExistingProject = isTypeScript || isPython;
|
|
2226
|
-
let type = "unknown";
|
|
2227
|
-
if (isTypeScript && !isPython) {
|
|
2228
|
-
type = "typescript";
|
|
2229
|
-
} else if (isPython && !isTypeScript) {
|
|
2230
|
-
type = "python";
|
|
2231
|
-
} else if (isTypeScript && isPython) {
|
|
2232
|
-
type = "typescript";
|
|
2233
|
-
}
|
|
2234
|
-
const packageManager = detectPackageManager(targetPath);
|
|
2235
|
-
const conflictingFiles = detectConflictingFiles(targetPath);
|
|
2236
|
-
const hasAgentmarkDir = fs7.existsSync(path5.join(targetPath, "agentmark"));
|
|
2237
|
-
const pythonVenv = detectPythonVenv(targetPath);
|
|
2238
|
-
return {
|
|
2239
|
-
isExistingProject,
|
|
2240
|
-
type,
|
|
2241
|
-
packageManager,
|
|
2242
|
-
conflictingFiles,
|
|
2243
|
-
hasAgentmarkDir,
|
|
2244
|
-
pythonVenv
|
|
2245
|
-
};
|
|
2246
|
-
}
|
|
2247
|
-
function isCurrentDirectory(folderName) {
|
|
2248
|
-
return folderName === "." || folderName === "./" || folderName === ".\\";
|
|
2249
|
-
}
|
|
150
|
+
};
|
|
2250
151
|
|
|
2251
152
|
// src/utils/git-init.ts
|
|
2252
|
-
import { execSync
|
|
153
|
+
import { execSync } from "child_process";
|
|
2253
154
|
function initGitRepo(targetPath) {
|
|
2254
155
|
try {
|
|
2255
156
|
try {
|
|
2256
|
-
|
|
157
|
+
execSync("git --version", { stdio: "ignore" });
|
|
2257
158
|
} catch {
|
|
2258
159
|
console.log("\u26A0\uFE0F git not found \u2014 skipping repository initialization");
|
|
2259
160
|
return false;
|
|
2260
161
|
}
|
|
2261
162
|
try {
|
|
2262
|
-
|
|
163
|
+
execSync("git rev-parse --is-inside-work-tree", {
|
|
2263
164
|
cwd: targetPath,
|
|
2264
165
|
stdio: "ignore"
|
|
2265
166
|
});
|
|
2266
167
|
return false;
|
|
2267
168
|
} catch {
|
|
2268
169
|
}
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
170
|
+
execSync("git init", { cwd: targetPath, stdio: "ignore" });
|
|
171
|
+
execSync("git add -A", { cwd: targetPath, stdio: "ignore" });
|
|
172
|
+
execSync(
|
|
2272
173
|
'git -c user.name="create-agentmark" -c user.email="noreply" commit -m "Initial commit from create-agentmark"',
|
|
2273
174
|
{ cwd: targetPath, stdio: "ignore" }
|
|
2274
175
|
);
|
|
@@ -2280,204 +181,200 @@ function initGitRepo(targetPath) {
|
|
|
2280
181
|
}
|
|
2281
182
|
}
|
|
2282
183
|
|
|
184
|
+
// src/utils/project-detection.ts
|
|
185
|
+
import fs2 from "fs-extra";
|
|
186
|
+
import path2 from "path";
|
|
187
|
+
var TYPESCRIPT_INDICATORS = ["package.json", "tsconfig.json", "node_modules"];
|
|
188
|
+
var PYTHON_INDICATORS = ["pyproject.toml", "requirements.txt", "setup.py", ".venv", "venv"];
|
|
189
|
+
function detectTypeScriptProject(targetPath) {
|
|
190
|
+
return TYPESCRIPT_INDICATORS.some((file) => fs2.existsSync(path2.join(targetPath, file)));
|
|
191
|
+
}
|
|
192
|
+
function detectPythonProject(targetPath) {
|
|
193
|
+
return PYTHON_INDICATORS.some((file) => fs2.existsSync(path2.join(targetPath, file)));
|
|
194
|
+
}
|
|
195
|
+
function detectProjectInfo(targetPath) {
|
|
196
|
+
return {
|
|
197
|
+
isExistingProject: detectTypeScriptProject(targetPath) || detectPythonProject(targetPath),
|
|
198
|
+
hasAgentmarkJson: fs2.existsSync(path2.join(targetPath, "agentmark.json")),
|
|
199
|
+
hasAgentmarkDir: fs2.existsSync(path2.join(targetPath, "agentmark"))
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
function isCurrentDirectory(folderName) {
|
|
203
|
+
return folderName === "." || folderName === "./" || folderName === ".\\";
|
|
204
|
+
}
|
|
205
|
+
|
|
2283
206
|
// src/index.ts
|
|
2284
|
-
var
|
|
2285
|
-
var
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
207
|
+
var ALL_CLIENTS = ["claude-code", "cursor", "vscode", "zed"];
|
|
208
|
+
var AGENTMARK_JSON = {
|
|
209
|
+
$schema: "https://raw.githubusercontent.com/agentmark-ai/agentmark/refs/heads/main/packages/cli/agentmark.schema.json",
|
|
210
|
+
version: "2.0.0",
|
|
211
|
+
mdxVersion: "1.0",
|
|
212
|
+
agentmarkPath: ".",
|
|
213
|
+
// Seed one model so the dashboard prompt editor isn't an empty dropdown on
|
|
214
|
+
// first run. Add more with `npx agentmark pull-models` (writes provider/model
|
|
215
|
+
// entries here) — see https://docs.agentmark.co/configure/model-schemas.
|
|
216
|
+
builtInModels: ["openai/gpt-5.5"]
|
|
217
|
+
};
|
|
218
|
+
var parseArgs = (argv = process.argv.slice(2)) => {
|
|
2289
219
|
const result = {};
|
|
2290
|
-
for (let i = 0; i <
|
|
2291
|
-
const arg =
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
result.path = args[++i];
|
|
2310
|
-
break;
|
|
2311
|
-
case "--adapter":
|
|
2312
|
-
result.adapter = args[++i];
|
|
2313
|
-
break;
|
|
2314
|
-
case "--api-key":
|
|
2315
|
-
result.apiKey = args[++i];
|
|
2316
|
-
break;
|
|
2317
|
-
case "--client":
|
|
2318
|
-
result.client = args[++i];
|
|
2319
|
-
break;
|
|
220
|
+
for (let i = 0; i < argv.length; i++) {
|
|
221
|
+
const arg = argv[i];
|
|
222
|
+
if (arg === "--path") {
|
|
223
|
+
result.path = argv[++i];
|
|
224
|
+
} else if (arg === "--client") {
|
|
225
|
+
const value = argv[++i];
|
|
226
|
+
if (!value) throw new Error("--client requires a value");
|
|
227
|
+
const ids = value === "all" ? [...ALL_CLIENTS] : value.split(",").map((s) => s.trim()).filter(Boolean);
|
|
228
|
+
result.clients = [...result.clients ?? [], ...ids];
|
|
229
|
+
} else if (arg === "--overwrite") {
|
|
230
|
+
result.overwrite = true;
|
|
231
|
+
} else if (arg === "--api-url") {
|
|
232
|
+
const value = argv[++i];
|
|
233
|
+
if (!value || !/^https?:\/\//.test(value)) {
|
|
234
|
+
throw new Error(`--api-url requires a full http(s) URL (got "${value}")`);
|
|
235
|
+
}
|
|
236
|
+
result.apiUrl = value;
|
|
237
|
+
} else if (arg && !arg.startsWith("--") && !result.path) {
|
|
238
|
+
result.path = arg;
|
|
2320
239
|
}
|
|
2321
240
|
}
|
|
2322
241
|
return result;
|
|
2323
242
|
};
|
|
2324
|
-
var
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
$schema: "https://raw.githubusercontent.com/agentmark-ai/agentmark/refs/heads/main/packages/cli/agentmark.schema.json",
|
|
2328
|
-
version: "2.0.0",
|
|
2329
|
-
mdxVersion: "1.0",
|
|
2330
|
-
agentmarkPath: "."
|
|
2331
|
-
};
|
|
2332
|
-
console.log("Initializing project.");
|
|
2333
|
-
let folderName = cliArgs.path;
|
|
243
|
+
var clientLabel = (id) => id === "vscode" ? "VS Code" : id === "zed" ? "Zed" : id === "cursor" ? "Cursor" : id === "claude-code" ? "Claude Code" : id;
|
|
244
|
+
var resolveTargetPath = async (cliPath) => {
|
|
245
|
+
let folderName = cliPath;
|
|
2334
246
|
if (!folderName) {
|
|
2335
|
-
const
|
|
247
|
+
const cwd = process.cwd();
|
|
248
|
+
const cwdHasProject = fs3.existsSync(path3.join(cwd, "package.json")) || fs3.existsSync(path3.join(cwd, "pyproject.toml"));
|
|
249
|
+
const response = await prompts({
|
|
2336
250
|
name: "folderName",
|
|
2337
251
|
type: "text",
|
|
2338
|
-
message: "Where would you like to
|
|
2339
|
-
initial: "my-agentmark-app"
|
|
252
|
+
message: "Where would you like to set up AgentMark?",
|
|
253
|
+
initial: cwdHasProject ? "." : "my-agentmark-app"
|
|
2340
254
|
});
|
|
2341
255
|
folderName = response.folderName;
|
|
2342
256
|
}
|
|
257
|
+
if (!folderName) return null;
|
|
2343
258
|
const isCurrentDir = isCurrentDirectory(folderName);
|
|
2344
|
-
const targetPath = isCurrentDir ? process.cwd() :
|
|
2345
|
-
if (!isCurrentDir)
|
|
2346
|
-
|
|
259
|
+
const targetPath = isCurrentDir ? process.cwd() : path3.resolve(folderName);
|
|
260
|
+
if (!isCurrentDir) fs3.ensureDirSync(targetPath);
|
|
261
|
+
return { targetPath, isCurrentDir };
|
|
262
|
+
};
|
|
263
|
+
var resolveClients = async (cliClients) => {
|
|
264
|
+
if (cliClients && cliClients.length > 0) {
|
|
265
|
+
for (const c of cliClients) {
|
|
266
|
+
if (!ALL_CLIENTS.includes(c)) {
|
|
267
|
+
throw new Error(`Invalid client "${c}". Valid: ${ALL_CLIENTS.join(", ")}`);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return cliClients;
|
|
271
|
+
}
|
|
272
|
+
const response = await prompts({
|
|
273
|
+
name: "clients",
|
|
274
|
+
type: "multiselect",
|
|
275
|
+
message: "Wire AgentMark MCP into which IDE clients?",
|
|
276
|
+
instructions: false,
|
|
277
|
+
hint: "Space to toggle. Enter to submit. Skip all = empty selection.",
|
|
278
|
+
choices: ALL_CLIENTS.map((id) => ({
|
|
279
|
+
title: clientLabel(id),
|
|
280
|
+
value: id,
|
|
281
|
+
selected: true
|
|
282
|
+
}))
|
|
283
|
+
});
|
|
284
|
+
return response.clients ?? [];
|
|
285
|
+
};
|
|
286
|
+
var shouldWriteAgentmarkJson = async (filePath, overwrite) => {
|
|
287
|
+
if (!fs3.existsSync(filePath)) return true;
|
|
288
|
+
if (overwrite) return true;
|
|
289
|
+
const { action } = await prompts({
|
|
290
|
+
type: "select",
|
|
291
|
+
name: "action",
|
|
292
|
+
message: "agentmark.json already exists. What would you like to do?",
|
|
293
|
+
choices: [
|
|
294
|
+
{ title: "Skip (keep existing)", value: "skip" },
|
|
295
|
+
{ title: "Overwrite with default config", value: "overwrite" }
|
|
296
|
+
],
|
|
297
|
+
initial: 0
|
|
298
|
+
});
|
|
299
|
+
return action === "overwrite";
|
|
300
|
+
};
|
|
301
|
+
var main = async () => {
|
|
302
|
+
const cliArgs = parseArgs();
|
|
303
|
+
const target = await resolveTargetPath(cliArgs.path);
|
|
304
|
+
if (!target) {
|
|
305
|
+
console.log("Aborted.");
|
|
306
|
+
return;
|
|
2347
307
|
}
|
|
308
|
+
const { targetPath } = target;
|
|
2348
309
|
const projectInfo = detectProjectInfo(targetPath);
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
path: f.path,
|
|
2356
|
-
action: "overwrite"
|
|
2357
|
-
}));
|
|
310
|
+
const clients = await resolveClients(cliArgs.clients);
|
|
311
|
+
console.log("");
|
|
312
|
+
const agentmarkJsonPath = path3.join(targetPath, "agentmark.json");
|
|
313
|
+
if (await shouldWriteAgentmarkJson(agentmarkJsonPath, cliArgs.overwrite)) {
|
|
314
|
+
fs3.writeJsonSync(agentmarkJsonPath, AGENTMARK_JSON, { spaces: 2 });
|
|
315
|
+
console.log("\u2705 agentmark.json");
|
|
2358
316
|
} else {
|
|
2359
|
-
|
|
2360
|
-
}
|
|
2361
|
-
let language = cliArgs.language;
|
|
2362
|
-
if (!language) {
|
|
2363
|
-
const response = await prompts2({
|
|
2364
|
-
name: "language",
|
|
2365
|
-
type: "select",
|
|
2366
|
-
message: "Which language would you like to use?",
|
|
2367
|
-
choices: [
|
|
2368
|
-
{ title: "TypeScript", value: "typescript" },
|
|
2369
|
-
{ title: "Python", value: "python" }
|
|
2370
|
-
]
|
|
2371
|
-
});
|
|
2372
|
-
language = response.language;
|
|
2373
|
-
}
|
|
2374
|
-
let adapter = cliArgs.adapter;
|
|
2375
|
-
if (!adapter) {
|
|
2376
|
-
if (language === "python") {
|
|
2377
|
-
const response = await prompts2({
|
|
2378
|
-
name: "adapter",
|
|
2379
|
-
type: "select",
|
|
2380
|
-
message: "Which adapter would you like to use?",
|
|
2381
|
-
choices: [
|
|
2382
|
-
{ title: "Pydantic AI", value: "pydantic-ai" },
|
|
2383
|
-
{ title: "Claude Agent SDK", value: "claude-agent-sdk" }
|
|
2384
|
-
]
|
|
2385
|
-
});
|
|
2386
|
-
adapter = response.adapter;
|
|
2387
|
-
} else {
|
|
2388
|
-
const response = await prompts2({
|
|
2389
|
-
name: "adapter",
|
|
2390
|
-
type: "select",
|
|
2391
|
-
message: "Which adapter would you like to use?",
|
|
2392
|
-
choices: [
|
|
2393
|
-
{ title: "AI SDK (Vercel)", value: "ai-sdk" },
|
|
2394
|
-
{ title: "Claude Agent SDK", value: "claude-agent-sdk" },
|
|
2395
|
-
{ title: "Mastra", value: "mastra" }
|
|
2396
|
-
]
|
|
2397
|
-
});
|
|
2398
|
-
adapter = response.adapter;
|
|
2399
|
-
}
|
|
2400
|
-
}
|
|
2401
|
-
const validAdapters = language === "python" ? VALID_ADAPTERS_PY : VALID_ADAPTERS_TS;
|
|
2402
|
-
if (!validAdapters.includes(adapter)) {
|
|
2403
|
-
console.error(`Invalid adapter "${adapter}" for ${language}. Valid: ${validAdapters.join(", ")}`);
|
|
2404
|
-
process.exit(1);
|
|
2405
|
-
}
|
|
2406
|
-
let apiKey = cliArgs.apiKey ?? "";
|
|
2407
|
-
if (!cliArgs.apiKey && cliArgs.apiKey !== "") {
|
|
2408
|
-
const apiKeyName = adapter === "claude-agent-sdk" ? "Anthropic" : "OpenAI";
|
|
2409
|
-
const { providedApiKey } = await prompts2({
|
|
2410
|
-
name: "providedApiKey",
|
|
2411
|
-
type: "password",
|
|
2412
|
-
message: `Enter your ${apiKeyName} API key (or press Enter to skip):`,
|
|
2413
|
-
initial: ""
|
|
2414
|
-
});
|
|
2415
|
-
apiKey = providedApiKey || "";
|
|
2416
|
-
}
|
|
2417
|
-
let deploymentMode = cliArgs.deploymentMode;
|
|
2418
|
-
if (!deploymentMode) {
|
|
2419
|
-
const response = await prompts2({
|
|
2420
|
-
name: "deploymentMode",
|
|
2421
|
-
type: "select",
|
|
2422
|
-
message: "Use AgentMark Cloud or manage yourself?",
|
|
2423
|
-
choices: [
|
|
2424
|
-
{
|
|
2425
|
-
title: "AgentMark Cloud (recommended)",
|
|
2426
|
-
value: "cloud",
|
|
2427
|
-
description: "Have AgentMark cloud manage prompts, datasets, traces, experiments, alerts & more"
|
|
2428
|
-
},
|
|
2429
|
-
{
|
|
2430
|
-
title: "Self-hosted",
|
|
2431
|
-
value: "static",
|
|
2432
|
-
description: "Self-manage your prompts, datasets, traces & experiments"
|
|
2433
|
-
}
|
|
2434
|
-
]
|
|
2435
|
-
});
|
|
2436
|
-
deploymentMode = response.deploymentMode;
|
|
2437
|
-
}
|
|
2438
|
-
let client = cliArgs.client;
|
|
2439
|
-
if (!client) {
|
|
2440
|
-
const response = await prompts2({
|
|
2441
|
-
name: "client",
|
|
2442
|
-
type: "select",
|
|
2443
|
-
message: "Make your IDE an AgentMark expert",
|
|
2444
|
-
choices: [
|
|
2445
|
-
{ title: "Claude Code", value: "claude-code" },
|
|
2446
|
-
{ title: "Cursor", value: "cursor" },
|
|
2447
|
-
{ title: "VS Code", value: "vscode" },
|
|
2448
|
-
{ title: "Zed", value: "zed" },
|
|
2449
|
-
{ title: "Skip", value: "skip" }
|
|
2450
|
-
]
|
|
2451
|
-
});
|
|
2452
|
-
client = response.client;
|
|
2453
|
-
}
|
|
2454
|
-
if (!VALID_CLIENTS.includes(client)) {
|
|
2455
|
-
console.error(`Invalid client "${client}". Valid: ${VALID_CLIENTS.join(", ")}`);
|
|
2456
|
-
process.exit(1);
|
|
317
|
+
console.log("\u23ED\uFE0F agentmark.json (kept existing)");
|
|
2457
318
|
}
|
|
2458
|
-
|
|
2459
|
-
if (
|
|
2460
|
-
|
|
319
|
+
const agentmarkDirPath = path3.join(targetPath, "agentmark");
|
|
320
|
+
if (!fs3.existsSync(agentmarkDirPath)) {
|
|
321
|
+
fs3.ensureDirSync(agentmarkDirPath);
|
|
322
|
+
fs3.writeFileSync(path3.join(agentmarkDirPath, ".gitkeep"), "");
|
|
323
|
+
console.log("\u2705 agentmark/ (empty, ready for your .prompt.mdx files)");
|
|
2461
324
|
} else {
|
|
2462
|
-
|
|
2463
|
-
}
|
|
2464
|
-
config.builtInModels = usedModels;
|
|
2465
|
-
if (deploymentMode === "cloud") {
|
|
2466
|
-
config.handler = language === "python" ? "handler.py" : "handler.ts";
|
|
325
|
+
console.log("\u23ED\uFE0F agentmark/ (kept existing)");
|
|
2467
326
|
}
|
|
2468
|
-
const
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
327
|
+
for (const client of clients) {
|
|
328
|
+
try {
|
|
329
|
+
const result = writeMcpConfig(client, targetPath, { customApiUrl: cliArgs.apiUrl });
|
|
330
|
+
if (result) {
|
|
331
|
+
const rel = path3.relative(targetPath, result.configPath) || result.configPath;
|
|
332
|
+
console.log(`\u2705 MCP wired (${clientLabel(client)}): ${rel}`);
|
|
333
|
+
}
|
|
334
|
+
} catch (err) {
|
|
335
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
336
|
+
console.warn(`\u26A0\uFE0F Could not write MCP config for ${clientLabel(client)}: ${message}`);
|
|
337
|
+
}
|
|
2474
338
|
}
|
|
339
|
+
installAgentmarkSkill(targetPath);
|
|
2475
340
|
if (!projectInfo.isExistingProject) {
|
|
2476
341
|
initGitRepo(targetPath);
|
|
2477
342
|
}
|
|
343
|
+
console.log("");
|
|
344
|
+
console.log("\u2728 AgentMark is wired up.");
|
|
345
|
+
console.log("");
|
|
346
|
+
console.log(" Next: open this project in Claude Code, Cursor, VS Code, or Zed and say:");
|
|
347
|
+
console.log("");
|
|
348
|
+
console.log(' "Set up AgentMark in this project."');
|
|
349
|
+
console.log("");
|
|
350
|
+
console.log(" The AgentMark skill will detect your stack, propose the wiring against");
|
|
351
|
+
console.log(" the docs MCP (https://docs.agentmark.co/mcp), and integrate adaptively.");
|
|
352
|
+
};
|
|
353
|
+
var isDirectlyInvoked = () => {
|
|
354
|
+
const entry = process.argv[1];
|
|
355
|
+
if (!entry) return false;
|
|
356
|
+
try {
|
|
357
|
+
const entryReal = pathToFileURL(fs3.realpathSync(entry)).href;
|
|
358
|
+
const selfReal = pathToFileURL(fs3.realpathSync(fileURLToPath(import.meta.url))).href;
|
|
359
|
+
return entryReal === selfReal;
|
|
360
|
+
} catch {
|
|
361
|
+
return false;
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
if (isDirectlyInvoked()) {
|
|
365
|
+
main().catch((error) => {
|
|
366
|
+
console.error("Error:", error);
|
|
367
|
+
process.exit(1);
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
export {
|
|
371
|
+
AGENTMARK_JSON,
|
|
372
|
+
ALL_CLIENTS,
|
|
373
|
+
clientLabel,
|
|
374
|
+
main,
|
|
375
|
+
parseArgs,
|
|
376
|
+
resolveClients,
|
|
377
|
+
resolveTargetPath,
|
|
378
|
+
shouldWriteAgentmarkJson
|
|
2478
379
|
};
|
|
2479
|
-
main().catch((error) => {
|
|
2480
|
-
console.error("Error:", error);
|
|
2481
|
-
process.exit(1);
|
|
2482
|
-
});
|
|
2483
380
|
//# sourceMappingURL=index.js.map
|