create-agentmark 0.10.5 → 0.10.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -71,7 +71,7 @@ sdk.initTracing({ disableBatch: true });
71
71
  `;
72
72
  const staticTracingInit = `
73
73
  // Initialize tracing - traces will be sent to local dev server
74
- // Make sure to run "npm run agentmark dev" in another terminal first
74
+ // Make sure to run "npx agentmark dev" in another terminal first
75
75
  // To disable tracing, comment out sdk.initTracing() below
76
76
  const sdk = new AgentMarkSDK({
77
77
  apiKey: "",
@@ -242,7 +242,7 @@ AGENTMARK_APP_ID=your_agentmark_app_id
242
242
  `;
243
243
  return `${apiKeyName}=${apiKeyValue}
244
244
  ${cloudEnvVars}
245
- # Learn more: https://docs.agentmark.co/platform/getting_started/quickstart
245
+ # Learn more: https://docs.agentmark.co/getting-started/quickstart
246
246
  `;
247
247
  };
248
248
 
@@ -487,9 +487,10 @@ var setupPackageJson = (targetPath = ".", deploymentMode = "cloud", projectInfo
487
487
  console.log("Creating package.json...");
488
488
  execSync("npm init -y", { cwd: targetPath });
489
489
  }
490
+ const demoScript = deploymentMode === "static" ? "npx agentmark build --out dist/agentmark && npx tsx index.ts" : "npx tsx index.ts";
490
491
  if (isExistingProject && fs2.existsSync(packageJsonPath)) {
491
492
  const scriptsToAdd = {
492
- "demo": "npx tsx index.ts",
493
+ "demo": demoScript,
493
494
  "agentmark": "agentmark"
494
495
  };
495
496
  if (deploymentMode === "static") {
@@ -509,9 +510,12 @@ var setupPackageJson = (targetPath = ".", deploymentMode = "cloud", projectInfo
509
510
  const pkgJson = fs2.readJsonSync(packageJsonPath);
510
511
  pkgJson.name = pkgJson.name === "test" || !pkgJson.name ? "agentmark-example-app" : pkgJson.name;
511
512
  pkgJson.description = pkgJson.description || "A simple Node.js app using the Agentmark SDK";
513
+ if (pkgJson.type === "commonjs") {
514
+ delete pkgJson.type;
515
+ }
512
516
  const scripts = {
513
517
  ...pkgJson.scripts,
514
- "demo": "npx tsx index.ts",
518
+ "demo": demoScript,
515
519
  "agentmark": "agentmark"
516
520
  };
517
521
  if (deploymentMode === "static") {
@@ -641,7 +645,7 @@ object_config:
641
645
  - names
642
646
  test_settings:
643
647
  dataset: party.jsonl
644
- scores:
648
+ evals:
645
649
  - exact_match_json
646
650
  props:
647
651
  party_text: "We're having a party with Alice, Bob, and Carol."
@@ -757,12 +761,16 @@ var getClientConfigContent = (options) => {
757
761
  import { FileLoader } from "@agentmark-ai/loader-file";`;
758
762
  const loaderSetup = deploymentMode === "cloud" ? ` // ApiLoader works for both development and production
759
763
  // - Development: 'agentmark dev' sets AGENTMARK_BASE_URL to localhost
760
- // - Production: Set AGENTMARK_API_KEY and AGENTMARK_APP_ID for cloud
764
+ // - Production: Set AGENTMARK_API_KEY and AGENTMARK_APP_ID for cloud.
765
+ // AGENTMARK_BASE_URL overrides the default https://api.agentmark.co
766
+ // target \u2014 managed deployments use this to point back at the gateway
767
+ // that dispatched the job.
761
768
  const loader = process.env.NODE_ENV === 'development'
762
769
  ? ApiLoader.local({ baseUrl: process.env.AGENTMARK_BASE_URL || 'http://localhost:9418' })
763
770
  : ApiLoader.cloud({
764
771
  apiKey: process.env.AGENTMARK_API_KEY!,
765
772
  appId: process.env.AGENTMARK_APP_ID!,
773
+ baseUrl: process.env.AGENTMARK_BASE_URL,
766
774
  });` : ` const loader = process.env.NODE_ENV === 'development'
767
775
  ? ApiLoader.local({ baseUrl: process.env.AGENTMARK_BASE_URL || 'http://localhost:9418' })
768
776
  : new FileLoader('./dist/agentmark');`;
@@ -1136,6 +1144,19 @@ var createExampleApp = async (client, targetPath = ".", apiKey = "", adapter = "
1136
1144
  `${targetPath}/agentmark.client.ts`,
1137
1145
  getClientConfigContent({ provider: modelProvider, adapter, deploymentMode })
1138
1146
  );
1147
+ const gitignoreEntries = ["node_modules/", ".env", "*.agentmark-outputs/", "dist/"];
1148
+ if (shouldMergeFile(".gitignore", projectInfo, resolutions)) {
1149
+ const result = appendGitignore(targetPath, gitignoreEntries);
1150
+ if (result.added.length > 0) {
1151
+ console.log(`\u2705 Added to .gitignore: ${result.added.join(", ")}`);
1152
+ }
1153
+ if (result.skipped.length > 0) {
1154
+ console.log(`\u23ED\uFE0F Already in .gitignore: ${result.skipped.join(", ")}`);
1155
+ }
1156
+ } else {
1157
+ const gitignore = gitignoreEntries.join("\n");
1158
+ fs4.writeFileSync(`${targetPath}/.gitignore`, gitignore);
1159
+ }
1139
1160
  if (shouldMergeFile(".env", projectInfo, resolutions)) {
1140
1161
  const envVars = {};
1141
1162
  const apiKeyEnvVar = adapter === "claude-agent-sdk" ? "ANTHROPIC_API_KEY" : "OPENAI_API_KEY";
@@ -1158,19 +1179,6 @@ var createExampleApp = async (client, targetPath = ".", apiKey = "", adapter = "
1158
1179
  } else {
1159
1180
  fs4.writeFileSync(`${targetPath}/.env`, getEnvFileContent(modelProvider, apiKey, adapter, deploymentMode));
1160
1181
  }
1161
- const gitignoreEntries = ["node_modules/", ".env", "*.agentmark-outputs/", "dist/"];
1162
- if (shouldMergeFile(".gitignore", projectInfo, resolutions)) {
1163
- const result = appendGitignore(targetPath, gitignoreEntries);
1164
- if (result.added.length > 0) {
1165
- console.log(`\u2705 Added to .gitignore: ${result.added.join(", ")}`);
1166
- }
1167
- if (result.skipped.length > 0) {
1168
- console.log(`\u23ED\uFE0F Already in .gitignore: ${result.skipped.join(", ")}`);
1169
- }
1170
- } else {
1171
- const gitignore = gitignoreEntries.join("\n");
1172
- fs4.writeFileSync(`${targetPath}/.gitignore`, gitignore);
1173
- }
1174
1182
  if (!isExistingProject) {
1175
1183
  fs4.writeFileSync(
1176
1184
  `${targetPath}/index.ts`,
@@ -1219,15 +1227,23 @@ sdk.initTracing({ disableBatch: true });
1219
1227
  const adapter = new ${handlerClass}(client as any);
1220
1228
 
1221
1229
  export default async function handler(request: {
1222
- type: 'prompt-run' | 'dataset-run';
1230
+ type: 'prompt-run' | 'dataset-run' | 'get-evals';
1223
1231
  data: {
1224
- ast: any;
1232
+ ast?: any;
1225
1233
  customProps?: Record<string, unknown>;
1226
1234
  options?: { shouldStream?: boolean };
1227
1235
  experimentId?: string;
1228
1236
  datasetPath?: string;
1229
1237
  };
1230
1238
  }) {
1239
+ if (request.type === 'get-evals') {
1240
+ return {
1241
+ type: 'evals',
1242
+ result: JSON.stringify(Object.keys(client.getEvalRegistry())),
1243
+ traceId: '',
1244
+ };
1245
+ }
1246
+
1231
1247
  if (request.type === 'prompt-run') {
1232
1248
  return adapter.runPrompt(request.data.ast, {
1233
1249
  shouldStream: request.data.options?.shouldStream,
@@ -1327,20 +1343,11 @@ main().catch((err) => {
1327
1343
  console.log("\n" + "\u2550".repeat(70));
1328
1344
  console.log("Next Steps");
1329
1345
  console.log("\u2550".repeat(70));
1330
- const runCmd = packageManager?.runCmd ?? "npm run";
1331
- const pkgJsonPath = path2.join(targetPath, "package.json");
1332
- let agentmarkScriptName = "agentmark";
1333
- if (fs4.existsSync(pkgJsonPath)) {
1334
- const pkgJson = fs4.readJsonSync(pkgJsonPath);
1335
- if (pkgJson.scripts?.["agentmark:agentmark"]) {
1336
- agentmarkScriptName = "agentmark:agentmark";
1337
- }
1338
- }
1339
1346
  console.log("\n Get Started:");
1340
1347
  if (folderName !== "." && folderName !== "./" && !isExistingProject) {
1341
1348
  console.log(` $ cd ${folderName}`);
1342
1349
  }
1343
- console.log(` $ ${runCmd} ${agentmarkScriptName} dev
1350
+ console.log(` $ npx agentmark dev
1344
1351
  `);
1345
1352
  console.log("\u2500".repeat(70));
1346
1353
  console.log("Resources");
@@ -1467,7 +1474,8 @@ var setupMCPServer2 = (client, targetPath) => {
1467
1474
  return;
1468
1475
  }
1469
1476
  };
1470
- var getPyprojectContent = (projectName, adapter) => {
1477
+ var getPyprojectContent = (projectName, adapter, deploymentMode) => {
1478
+ const pyModules = deploymentMode === "cloud" ? `["agentmark_client", "main", "handler"]` : `["agentmark_client", "main"]`;
1471
1479
  if (adapter === "claude-agent-sdk") {
1472
1480
  return `[project]
1473
1481
  name = "${projectName}"
@@ -1475,9 +1483,9 @@ version = "0.1.0"
1475
1483
  description = "An AgentMark application using Claude Agent SDK"
1476
1484
  requires-python = ">=3.12"
1477
1485
  dependencies = [
1478
- "agentmark-sdk>=0.1.0",
1479
- "agentmark-claude-agent-sdk-v0>=0.1.0",
1480
- "agentmark-prompt-core>=0.1.0",
1486
+ "agentmark-sdk>=0.2.0",
1487
+ "agentmark-claude-agent-sdk-v0>=0.1.4",
1488
+ "agentmark-prompt-core>=0.1.2",
1481
1489
  "python-dotenv>=1.0.0",
1482
1490
  "claude-agent-sdk>=0.1.0",
1483
1491
  ]
@@ -1490,8 +1498,11 @@ dev = [
1490
1498
  ]
1491
1499
 
1492
1500
  [build-system]
1493
- requires = ["hatchling"]
1494
- build-backend = "hatchling.build"
1501
+ requires = ["setuptools>=61", "wheel"]
1502
+ build-backend = "setuptools.build_meta"
1503
+
1504
+ [tool.setuptools]
1505
+ py-modules = ${pyModules}
1495
1506
 
1496
1507
  [tool.pytest.ini_options]
1497
1508
  asyncio_mode = "auto"
@@ -1506,11 +1517,11 @@ version = "0.1.0"
1506
1517
  description = "An AgentMark application using Pydantic AI"
1507
1518
  requires-python = ">=3.12"
1508
1519
  dependencies = [
1509
- "agentmark-sdk>=0.1.0",
1510
- "agentmark-pydantic-ai-v0>=0.1.0",
1511
- "agentmark-prompt-core>=0.1.0",
1520
+ "agentmark-sdk>=0.2.0",
1521
+ "agentmark-pydantic-ai-v0>=0.1.4",
1522
+ "agentmark-prompt-core>=0.1.2",
1512
1523
  "python-dotenv>=1.0.0",
1513
- "pydantic-ai[openai]>=0.1.0",
1524
+ "pydantic-ai-slim[openai]>=1.0,<2.0",
1514
1525
  ]
1515
1526
 
1516
1527
  [project.optional-dependencies]
@@ -1519,12 +1530,13 @@ dev = [
1519
1530
  "pytest-asyncio>=0.21",
1520
1531
  "mypy>=1.0",
1521
1532
  ]
1522
- anthropic = ["pydantic-ai[anthropic]"]
1523
- gemini = ["pydantic-ai[gemini]"]
1524
1533
 
1525
1534
  [build-system]
1526
- requires = ["hatchling"]
1527
- build-backend = "hatchling.build"
1535
+ requires = ["setuptools>=61", "wheel"]
1536
+ build-backend = "setuptools.build_meta"
1537
+
1538
+ [tool.setuptools]
1539
+ py-modules = ${pyModules}
1528
1540
 
1529
1541
  [tool.pytest.ini_options]
1530
1542
  asyncio_mode = "auto"
@@ -1534,8 +1546,8 @@ strict = true
1534
1546
  `;
1535
1547
  };
1536
1548
  var getHandlerPyContent = (adapter) => {
1537
- const webhookClass = adapter === "claude-agent-sdk" ? "ClaudeAgentSDKWebhookHandler" : "PydanticAIWebhookHandler";
1538
- const webhookImport = adapter === "claude-agent-sdk" ? "from agentmark_claude_agent_sdk import ClaudeAgentSDKWebhookHandler" : "from agentmark_pydantic_ai_v0 import PydanticAIWebhookHandler";
1549
+ const webhookClass = adapter === "claude-agent-sdk" ? "ClaudeAgentWebhookHandler" : "PydanticAIWebhookHandler";
1550
+ const webhookImport = adapter === "claude-agent-sdk" ? "from agentmark_claude_agent_sdk_v0 import ClaudeAgentWebhookHandler" : "from agentmark_pydantic_ai_v0 import PydanticAIWebhookHandler";
1539
1551
  return `"""AgentMark handler for managed cloud deployments.
1540
1552
 
1541
1553
  This file is used by the AgentMark platform to execute prompts and experiments
@@ -1560,10 +1572,18 @@ adapter = ${webhookClass}(client)
1560
1572
 
1561
1573
 
1562
1574
  async def handler(request: dict):
1563
- """Handle prompt-run and dataset-run requests from the platform."""
1575
+ """Handle prompt-run, dataset-run, and get-evals requests from the platform."""
1564
1576
  req_type = request.get("type")
1565
1577
  data = request.get("data", {})
1566
1578
 
1579
+ if req_type == "get-evals":
1580
+ import json
1581
+ return {
1582
+ "type": "evals",
1583
+ "result": json.dumps(list(client.get_eval_registry().keys())),
1584
+ "traceId": "",
1585
+ }
1586
+
1567
1587
  if req_type == "prompt-run":
1568
1588
  return await adapter.run_prompt(data["ast"], {
1569
1589
  "shouldStream": data.get("options", {}).get("shouldStream", True),
@@ -1584,9 +1604,8 @@ var getAgentmarkClientContent = (deploymentMode, adapter) => {
1584
1604
  const isCloud = deploymentMode === "cloud";
1585
1605
  const loaderImport = isCloud ? `from agentmark.prompt_core import ApiLoader` : `from agentmark.prompt_core import FileLoader`;
1586
1606
  const loaderSetup = isCloud ? `# API loader for cloud deployment \u2014 fetches datasets from the AgentMark gateway
1587
- loader = ApiLoader.cloud()` : `# File loader for local development
1588
- project_root = Path(__file__).parent.resolve()
1589
- loader = FileLoader(base_dir=str(project_root))`;
1607
+ loader = ApiLoader.cloud()` : `# File loader for local development \u2014 reads pre-built prompts from the build output directory
1608
+ loader = FileLoader("./dist/agentmark")`;
1590
1609
  if (adapter === "claude-agent-sdk") {
1591
1610
  return `"""AgentMark client configuration.
1592
1611
 
@@ -1596,12 +1615,11 @@ Customize the model registry and eval registry as needed.
1596
1615
 
1597
1616
  import json
1598
1617
  import os
1599
- from pathlib import Path
1600
1618
  from dotenv import load_dotenv
1601
1619
 
1602
1620
  ${loaderImport}
1603
1621
  from agentmark.prompt_core import EvalRegistry
1604
- from agentmark_claude_agent_sdk import (
1622
+ from agentmark_claude_agent_sdk_v0 import (
1605
1623
  create_claude_agent_client,
1606
1624
  ClaudeAgentModelRegistry,
1607
1625
  )
@@ -1662,7 +1680,6 @@ Customize the model registry, tools, and eval registry as needed.
1662
1680
 
1663
1681
  import json
1664
1682
  import os
1665
- from pathlib import Path
1666
1683
  from dotenv import load_dotenv
1667
1684
 
1668
1685
  ${loaderImport}
@@ -1741,7 +1758,7 @@ sdk.init_tracing(disable_batch=True)
1741
1758
  `;
1742
1759
  const staticTracingInit = `
1743
1760
  # Initialize tracing - traces will be sent to local dev server
1744
- # Make sure to run "npm run agentmark dev" in another terminal first
1761
+ # Make sure to run "npx agentmark dev" in another terminal first
1745
1762
  # To disable tracing, comment out sdk.init_tracing() below
1746
1763
  sdk = AgentMarkSDK(
1747
1764
  api_key="",
@@ -1754,49 +1771,40 @@ sdk.init_tracing(disable_batch=True)
1754
1771
  if (adapter === "claude-agent-sdk") {
1755
1772
  return `"""Example usage of AgentMark with Claude Agent SDK.
1756
1773
 
1757
- Run with: python main.py
1774
+ Run with:
1775
+ npx agentmark build # compile party-planner.prompt.mdx -> dist/agentmark/*.json
1776
+ python main.py
1758
1777
  """
1759
1778
 
1760
1779
  import asyncio
1761
- import json
1762
1780
  import os
1763
- from pathlib import Path
1764
1781
 
1765
1782
  from agentmark_sdk import AgentMarkSDK
1766
- from agentmark_claude_agent_sdk import run_text_prompt
1783
+ from agentmark_claude_agent_sdk_v0 import traced_query
1767
1784
  from agentmark_client import client
1768
1785
  ${tracingInit}
1769
1786
 
1770
1787
  async def main():
1771
- """Run the party planner prompt."""
1772
- # Load the prompt AST (in production, use the API loader)
1773
- prompt_path = Path("agentmark/party-planner.prompt.mdx.json")
1774
-
1775
- if not prompt_path.exists():
1776
- print("Prompt file not found. Run 'agentmark build' first.")
1788
+ """Run the party planner prompt (object_config: extracts attendee names)."""
1789
+ # \`agentmark build\` writes pre-compiled prompts to dist/agentmark/.
1790
+ # The FileLoader reads them by name \u2014 extension is optional.
1791
+ try:
1792
+ prompt = await client.load_object_prompt("party-planner.prompt.mdx")
1793
+ except FileNotFoundError:
1794
+ print("Pre-built prompt not found. Run 'npx agentmark build' first.")
1777
1795
  return
1778
1796
 
1779
- with open(prompt_path) as f:
1780
- ast = json.load(f)
1781
-
1782
- # Load and format the prompt
1783
- prompt = await client.load_text_prompt(ast)
1784
- params = await prompt.format(props={
1785
- "numberOfGuests": 10,
1786
- "theme": "80s disco",
1787
- "dietaryRestrictions": ["vegetarian", "gluten-free"],
1797
+ adapted = await prompt.format(props={
1798
+ "party_text": "We're having a party with Alice, Bob, and Carol.",
1788
1799
  })
1789
1800
 
1790
- # Execute the prompt
1801
+ # Execute via Claude Agent SDK (streamed) with automatic OTEL tracing.
1802
+ # adapted.query.options.output_format is set to the object schema.
1791
1803
  print("Running party planner prompt...")
1792
- result = await run_text_prompt(params)
1793
-
1794
- print("\\n" + "=" * 50)
1795
- print("Party Plan:")
1796
1804
  print("=" * 50)
1797
- print(result.output)
1798
- print("\\n" + "-" * 50)
1799
- print(f"Tokens used: {result.usage}")
1805
+ async for message in traced_query(adapted):
1806
+ print(message)
1807
+ print("=" * 50)
1800
1808
 
1801
1809
 
1802
1810
  if __name__ == "__main__":
@@ -1805,47 +1813,44 @@ if __name__ == "__main__":
1805
1813
  }
1806
1814
  return `"""Example usage of AgentMark with Pydantic AI.
1807
1815
 
1808
- Run with: python main.py
1816
+ Run with:
1817
+ npx agentmark build # compile party-planner.prompt.mdx -> dist/agentmark/*.json
1818
+ python main.py
1809
1819
  """
1820
+ # To use a different LLM provider, install: pip install "pydantic-ai-slim[anthropic]" (or [google], [bedrock], etc.)
1810
1821
 
1811
1822
  import asyncio
1812
- import json
1813
1823
  import os
1814
- from pathlib import Path
1815
1824
 
1816
1825
  from agentmark_sdk import AgentMarkSDK
1817
- from agentmark_pydantic_ai_v0 import run_text_prompt
1826
+ from agentmark_pydantic_ai_v0 import run_object_prompt
1818
1827
  from agentmark_client import client
1819
1828
  ${tracingInit}
1820
1829
 
1821
1830
  async def main():
1822
- """Run the party planner prompt."""
1823
- # Load the prompt AST (in production, use the API loader)
1824
- prompt_path = Path("agentmark/party-planner.prompt.mdx.json")
1825
-
1826
- if not prompt_path.exists():
1827
- print("Prompt file not found. Run 'agentmark build' first.")
1831
+ """Run the party planner prompt (object_config: extracts attendee names)."""
1832
+ # \`agentmark build\` writes pre-compiled prompts to dist/agentmark/.
1833
+ # The FileLoader reads them by name \u2014 extension is optional, and it
1834
+ # extracts the inner AST from the { ast, metadata } wrapper for you.
1835
+ try:
1836
+ prompt = await client.load_object_prompt("party-planner.prompt.mdx")
1837
+ except FileNotFoundError:
1838
+ print("Pre-built prompt not found. Run 'npx agentmark build' first.")
1828
1839
  return
1829
1840
 
1830
- with open(prompt_path) as f:
1831
- ast = json.load(f)
1832
-
1833
- # Load and format the prompt
1834
- prompt = await client.load_text_prompt(ast)
1835
1841
  params = await prompt.format(props={
1836
- "numberOfGuests": 10,
1837
- "theme": "80s disco",
1838
- "dietaryRestrictions": ["vegetarian", "gluten-free"],
1842
+ "party_text": "We're having a party with Alice, Bob, and Carol.",
1839
1843
  })
1840
1844
 
1841
1845
  # Execute the prompt
1842
1846
  print("Running party planner prompt...")
1843
- result = await run_text_prompt(params)
1847
+ result = await run_object_prompt(params)
1844
1848
 
1845
1849
  print("\\n" + "=" * 50)
1846
- print("Party Plan:")
1850
+ print("Extracted attendees:")
1847
1851
  print("=" * 50)
1848
- print(result.output)
1852
+ # result.output is a Pydantic model instance with the schema's fields
1853
+ print(result.output.names)
1849
1854
  print("\\n" + "-" * 50)
1850
1855
  print(f"Tokens used: {result.usage.total_tokens}")
1851
1856
 
@@ -1855,10 +1860,10 @@ if __name__ == "__main__":
1855
1860
  `;
1856
1861
  };
1857
1862
  var getDevServerContent = (adapter) => {
1858
- const adapterPackage = adapter === "claude-agent-sdk" ? "agentmark_claude_agent_sdk" : "agentmark_pydantic_ai_v0";
1863
+ const adapterPackage = adapter === "claude-agent-sdk" ? "agentmark_claude_agent_sdk_v0" : "agentmark_pydantic_ai_v0";
1859
1864
  return `"""Auto-generated webhook server for AgentMark development.
1860
1865
 
1861
- This server is started by 'npm run agentmark dev' (agentmark dev) and handles
1866
+ This server is started by 'npx agentmark dev' (agentmark dev) and handles
1862
1867
  prompt execution requests from the CLI.
1863
1868
  """
1864
1869
 
@@ -1898,6 +1903,62 @@ OPENAI_API_KEY=${apiKey}
1898
1903
  # GOOGLE_API_KEY=your-key-here
1899
1904
  `;
1900
1905
  };
1906
+ var getReadmeContent = (projectName, adapter) => {
1907
+ const adapterName = adapter === "claude-agent-sdk" ? "Claude Agent SDK" : "Pydantic AI";
1908
+ const apiKeyEnvVar = adapter === "claude-agent-sdk" ? "ANTHROPIC_API_KEY" : "OPENAI_API_KEY";
1909
+ 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"';
1910
+ return `# ${projectName}
1911
+
1912
+ An AgentMark application using ${adapterName}.
1913
+
1914
+ ## Prerequisites
1915
+
1916
+ - Python 3.12+
1917
+ - **pip 26.1+** (older pip versions fail to resolve the dependency graph \u2014 see "Why pip 26.1?" below)
1918
+
1919
+ ## Setup
1920
+
1921
+ \`\`\`bash
1922
+ # 1. Create and activate a virtual environment
1923
+ python -m venv .venv
1924
+ source .venv/bin/activate # On Windows: .venv\\Scripts\\activate
1925
+
1926
+ # 2. Upgrade pip (REQUIRED \u2014 older pip cannot resolve pydantic-ai's transitive graph)
1927
+ python -m pip install --upgrade "pip>=26.1"
1928
+
1929
+ # 3. Install dependencies
1930
+ ${directInstallCmd}
1931
+
1932
+ # 4. Set your API key
1933
+ echo "${apiKeyEnvVar}=your-key-here" > .env
1934
+ \`\`\`
1935
+
1936
+ ## Run
1937
+
1938
+ \`\`\`bash
1939
+ # Start the AgentMark dev server (in another terminal)
1940
+ npx agentmark dev
1941
+
1942
+ # Run the example prompt
1943
+ python main.py
1944
+ \`\`\`
1945
+
1946
+ Then open [http://localhost:9418](http://localhost:9418) to view your traces.
1947
+
1948
+ ## Why pip 26.1?
1949
+
1950
+ The \`pydantic-ai-slim\` package transitively depends on \`mcp\`, \`fastmcp\`, and
1951
+ \`logfire\`, which together produce a deep dependency graph. Pip versions before
1952
+ 26.1 fall into long backtracking loops and abort with \`resolution-too-deep\`.
1953
+ Pip 26.1's resolver handles this graph efficiently. If you skip the upgrade and
1954
+ hit the error, run \`python -m pip install --upgrade pip\` and retry.
1955
+
1956
+ ## Resources
1957
+
1958
+ - [Documentation](https://docs.agentmark.co)
1959
+ - [GitHub](https://github.com/agentmark-ai/agentmark)
1960
+ `;
1961
+ };
1901
1962
  var getGitignoreContent = () => {
1902
1963
  return `# Python
1903
1964
  __pycache__/
@@ -1944,7 +2005,7 @@ var createPythonApp = async (client, targetPath = ".", apiKey = "", deploymentMo
1944
2005
  console.log(`Example prompts and datasets created in ${folderName}/agentmark/`);
1945
2006
  if (!isExistingProject) {
1946
2007
  const projectName = path3.basename(targetPath).replace(/[^a-zA-Z0-9_-]/g, "-");
1947
- fs5.writeFileSync(`${targetPath}/pyproject.toml`, getPyprojectContent(projectName, adapter));
2008
+ fs5.writeFileSync(`${targetPath}/pyproject.toml`, getPyprojectContent(projectName, adapter, deploymentMode));
1948
2009
  } else {
1949
2010
  console.log("\u23ED\uFE0F Skipped pyproject.toml (existing project)");
1950
2011
  }
@@ -2011,6 +2072,14 @@ var createPythonApp = async (client, targetPath = ".", apiKey = "", deploymentMo
2011
2072
  } else {
2012
2073
  fs5.writeFileSync(`${targetPath}/.gitignore`, getGitignoreContent());
2013
2074
  }
2075
+ if (!isExistingProject) {
2076
+ const readmePath = path3.join(targetPath, "README.md");
2077
+ if (!fs5.existsSync(readmePath)) {
2078
+ const projectName = path3.basename(targetPath).replace(/[^a-zA-Z0-9_-]/g, "-");
2079
+ fs5.writeFileSync(readmePath, getReadmeContent(projectName, adapter));
2080
+ console.log(`\u2705 Created README.md`);
2081
+ }
2082
+ }
2014
2083
  const agentmarkInternalDir = path3.join(targetPath, ".agentmark");
2015
2084
  fs5.ensureDirSync(agentmarkInternalDir);
2016
2085
  fs5.writeFileSync(path3.join(agentmarkInternalDir, "dev_server.py"), getDevServerContent(adapter));
@@ -2043,16 +2112,20 @@ var createPythonApp = async (client, targetPath = ".", apiKey = "", deploymentMo
2043
2112
  if (folderName !== "." && folderName !== "./" && !isExistingProject) {
2044
2113
  console.log(` $ cd ${folderName}`);
2045
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"';
2046
2117
  if (pythonVenv) {
2047
2118
  const activateCmd = process.platform === "win32" ? `${pythonVenv.name}\\Scripts\\activate` : `source ${pythonVenv.name}/bin/activate`;
2048
2119
  console.log(` $ ${activateCmd}`);
2049
- console.log(' $ pip install agentmark-pydantic-ai-v0 agentmark-prompt-core python-dotenv "pydantic-ai[openai]"');
2120
+ console.log(pipUpgradeCmd);
2121
+ console.log(pipInstallCmd);
2050
2122
  } else {
2051
2123
  console.log(" $ python -m venv .venv");
2052
2124
  console.log(" $ source .venv/bin/activate # On Windows: .venv\\Scripts\\activate");
2053
- console.log(' $ pip install -e ".[dev]"');
2125
+ console.log(pipUpgradeCmd);
2126
+ console.log(pipInstallCmd);
2054
2127
  }
2055
- console.log(" $ npm run agentmark dev\n");
2128
+ console.log(" $ npx agentmark dev\n");
2056
2129
  console.log("\u2500".repeat(70));
2057
2130
  console.log("Resources");
2058
2131
  console.log("\u2500".repeat(70));