create-langgraph-app 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/create.js +81 -100
  2. package/package.json +1 -1
package/dist/create.js CHANGED
@@ -72,17 +72,17 @@ function generateEnv(config) {
72
72
  }
73
73
  function generatePackageJson(config) {
74
74
  const deps = {
75
- "@langchain/core": "^1.1.39",
76
- "@langchain/langgraph": "^1.2.7",
77
- "@langchain/langgraph-supervisor": "^1.0.1",
75
+ "@langchain/core": "^1.1.48",
76
+ "@langchain/langgraph": "^1.3.2",
77
+ "@langchain/langgraph-supervisor": "^1.0.3",
78
78
  "@langchain/mcp-adapters": "^1.1.3",
79
- dotenv: "^17.4.0",
80
- fastify: "^5.8.4",
79
+ dotenv: "^17.4.2",
80
+ fastify: "^5.8.5",
81
81
  langchain: "^1.3.0",
82
- zod: "^4.3.6",
82
+ zod: "^4.4.3",
83
83
  };
84
84
  if (config.patterns.includes("swarm")) {
85
- deps["@langchain/langgraph-swarm"] = "^1.0.1";
85
+ deps["@langchain/langgraph-swarm"] = "^1.0.2";
86
86
  }
87
87
  if (config.patterns.includes("rag")) {
88
88
  deps["@langchain/textsplitters"] = "^1.0.1";
@@ -109,10 +109,10 @@ function generatePackageJson(config) {
109
109
  },
110
110
  dependencies: Object.fromEntries(Object.entries(deps).sort(([a], [b]) => a.localeCompare(b))),
111
111
  devDependencies: {
112
- "@types/node": "^25.5.2",
113
- tsx: "^4.21.0",
114
- typescript: "^6.0.2",
115
- vitest: "^4.1.2",
112
+ "@types/node": "^25.9.1",
113
+ tsx: "^4.22.4",
114
+ typescript: "^6.0.3",
115
+ vitest: "^4.1.8",
116
116
  },
117
117
  };
118
118
  return JSON.stringify(pkg, null, 2) + "\n";
@@ -157,6 +157,7 @@ const API_KEY_MAP: Record<LlmProvider, string> = {
157
157
 
158
158
  export const LLM_PROVIDER = resolveProvider();
159
159
 
160
+ // Fail fast: validate the selected provider's key at startup.
160
161
  const requiredKey = API_KEY_MAP[LLM_PROVIDER];
161
162
  if (requiredKey && !process.env[requiredKey]) {
162
163
  throw new Error(\`\${requiredKey} is required for provider "\${LLM_PROVIDER}" but not set in .env\`);
@@ -167,47 +168,54 @@ export const LLM_TEMPERATURE = Number(process.env.LLM_TEMPERATURE ?? 0);
167
168
  export const PORT = Number(process.env.PORT ?? 3000);
168
169
  `;
169
170
  }
170
- function generateLlmConfig() {
171
- return `import type { BaseChatModel } from "@langchain/core/language_models/chat_models";
172
- import { LLM_PROVIDER, LLM_MODEL, LLM_TEMPERATURE } from "./env";
173
-
174
- const DEFAULTS: Record<string, string> = {
175
- openai: "gpt-4o-mini",
176
- anthropic: "claude-sonnet-4-20250514",
177
- google: "gemini-2.0-flash",
178
- groq: "llama-3.3-70b-versatile",
179
- ollama: "llama3.2",
171
+ // Per-provider class + constructor shape. The generated llm.ts only imports the
172
+ // provider that was selected, so the scaffold depends on a single LLM SDK.
173
+ const PROVIDER_LLM = {
174
+ openai: { pkg: "@langchain/openai", className: "ChatOpenAI", modelArg: "modelName", defaultModel: "gpt-4o-mini" },
175
+ anthropic: { pkg: "@langchain/anthropic", className: "ChatAnthropic", modelArg: "modelName", defaultModel: "claude-sonnet-4-20250514" },
176
+ google: { pkg: "@langchain/google-genai", className: "ChatGoogleGenerativeAI", modelArg: "model", defaultModel: "gemini-2.0-flash" },
177
+ groq: { pkg: "@langchain/groq", className: "ChatGroq", modelArg: "model", defaultModel: "llama-3.3-70b-versatile" },
178
+ ollama: { pkg: "@langchain/ollama", className: "ChatOllama", modelArg: "model", defaultModel: "llama3.2" },
180
179
  };
180
+ function generateLlmConfig(config) {
181
+ const p = PROVIDER_LLM[config.provider] ?? PROVIDER_LLM.openai;
182
+ return `import type { BaseChatModel } from "@langchain/core/language_models/chat_models";
183
+ import { LLM_MODEL, LLM_TEMPERATURE } from "./env";
181
184
 
182
- function createLlm(): BaseChatModel {
183
- const model = LLM_MODEL ?? DEFAULTS[LLM_PROVIDER] ?? DEFAULTS.openai;
184
- const temperature = LLM_TEMPERATURE;
185
+ const DEFAULT_MODEL = "${p.defaultModel}";
185
186
 
186
- switch (LLM_PROVIDER) {
187
- case "anthropic": {
188
- const { ChatAnthropic } = require("@langchain/anthropic");
189
- return new ChatAnthropic({ modelName: model, temperature });
190
- }
191
- case "google": {
192
- const { ChatGoogleGenerativeAI } = require("@langchain/google-genai");
193
- return new ChatGoogleGenerativeAI({ modelName: model, temperature });
194
- }
195
- case "groq": {
196
- const { ChatGroq } = require("@langchain/groq");
197
- return new ChatGroq({ modelName: model, temperature });
198
- }
199
- case "ollama": {
200
- const { ChatOllama } = require("@langchain/ollama");
201
- return new ChatOllama({ model, temperature });
202
- }
203
- default: {
204
- const { ChatOpenAI } = require("@langchain/openai");
205
- return new ChatOpenAI({ modelName: model, temperature });
206
- }
207
- }
187
+ export interface LlmOptions {
188
+ model?: string;
189
+ temperature?: number;
190
+ }
191
+
192
+ async function createLlm(opts: LlmOptions = {}): Promise<BaseChatModel> {
193
+ const model = opts.model ?? LLM_MODEL ?? DEFAULT_MODEL;
194
+ const temperature = opts.temperature ?? LLM_TEMPERATURE;
195
+
196
+ const { ${p.className} } = await import("${p.pkg}");
197
+ return new ${p.className}({ ${p.modelArg}: model, temperature });
208
198
  }
209
199
 
210
- export const llm = createLlm();
200
+ let _default: Promise<BaseChatModel> | undefined;
201
+
202
+ /**
203
+ * Returns a chat model.
204
+ *
205
+ * Called with no options it returns a memoized, shared instance (nothing is
206
+ * constructed until first use). Pass options to build a distinct model, e.g. a
207
+ * cheap router and a strong worker:
208
+ *
209
+ * const router = await getLlm({ model: "${p.defaultModel}" });
210
+ * const worker = await getLlm({ model: "<a-stronger-model>" });
211
+ */
212
+ export function getLlm(opts?: LlmOptions): Promise<BaseChatModel> {
213
+ if (!opts || Object.keys(opts).length === 0) {
214
+ _default ??= createLlm();
215
+ return _default;
216
+ }
217
+ return createLlm(opts);
218
+ }
211
219
  `;
212
220
  }
213
221
  function generateAgentFactory() {
@@ -255,49 +263,12 @@ export function makeSupervisor({ checkpointer, store, ...params }: MakeSuperviso
255
263
  }
256
264
  `;
257
265
  }
258
- function generateSupervisorApp() {
259
- return `import { z } from "zod";
260
- import { tool } from "@langchain/core/tools";
261
- import { llm } from "./config/env";
262
- import { makeAgent } from "./agents/factory";
263
- import { makeSupervisor } from "./agents/supervisor";
264
-
265
- const add = tool(async ({ a, b }) => String(a + b), {
266
- name: "add", description: "Add two numbers",
267
- schema: z.object({ a: z.number(), b: z.number() }),
268
- });
269
-
270
- const multiply = tool(async ({ a, b }) => String(a * b), {
271
- name: "multiply", description: "Multiply two numbers",
272
- schema: z.object({ a: z.number(), b: z.number() }),
273
- });
274
-
275
- export function createApp() {
276
- const math = makeAgent({
277
- name: "math_expert", llm,
278
- tools: [add, multiply],
279
- system: "You are a math expert. Use tools to compute answers.",
280
- });
281
-
282
- const writer = makeAgent({
283
- name: "writer", llm, tools: [],
284
- system: "You write crisp, structured answers.",
285
- });
286
-
287
- return makeSupervisor({
288
- agents: [math, writer], llm,
289
- outputMode: "last_message",
290
- supervisorName: "supervisor",
291
- });
292
- }
293
- `;
294
- }
295
266
  // Pattern-specific: only files for selected patterns are generated
296
267
  function getPatternFiles(config) {
297
268
  const files = [];
298
269
  // Always include core files
299
270
  files.push({ path: "src/config/env.ts", content: generateEnvConfig(config) });
300
- files.push({ path: "src/config/llm.ts", content: generateLlmConfig() });
271
+ files.push({ path: "src/config/llm.ts", content: generateLlmConfig(config) });
301
272
  files.push({ path: "src/agents/factory.ts", content: generateAgentFactory() });
302
273
  files.push({ path: "src/agents/supervisor.ts", content: generateSupervisorHelper() });
303
274
  // Index file — imports vary by selected patterns
@@ -306,7 +277,7 @@ function getPatternFiles(config) {
306
277
  if (config.patterns.includes("supervisor")) {
307
278
  files.push({
308
279
  path: "src/apps/supervisor.ts",
309
- content: `import { llm } from "../config/llm";
280
+ content: `import { getLlm } from "../config/llm";
310
281
  import { z } from "zod";
311
282
  import { tool } from "@langchain/core/tools";
312
283
  import { makeAgent } from "../agents/factory";
@@ -317,7 +288,9 @@ const add = tool(async ({ a, b }) => String(a + b), {
317
288
  schema: z.object({ a: z.number(), b: z.number() }),
318
289
  });
319
290
 
320
- export function createSupervisorApp() {
291
+ export async function createSupervisorApp() {
292
+ const llm = await getLlm();
293
+
321
294
  const math = makeAgent({
322
295
  name: "math_expert", llm,
323
296
  tools: [add],
@@ -339,7 +312,7 @@ export function createSupervisorApp() {
339
312
  });
340
313
  imports.push(`import { createSupervisorApp } from "./apps/supervisor";`);
341
314
  demos.push(` console.log("=== Supervisor Demo ===");
342
- const supervisorApp = createSupervisorApp();
315
+ const supervisorApp = await createSupervisorApp();
343
316
  const sup = await supervisorApp.invoke(
344
317
  { messages: [{ role: "user", content: "What is 10 + 15?" }] },
345
318
  { configurable: { thread_id: "demo" } }
@@ -405,7 +378,7 @@ export function createHandoffTool({ agentName, description }: { agentName: strin
405
378
  });
406
379
  files.push({
407
380
  path: "src/apps/swarm.ts",
408
- content: `import { llm } from "../config/llm";
381
+ content: `import { getLlm } from "../config/llm";
409
382
  import { z } from "zod";
410
383
  import { tool } from "@langchain/core/tools";
411
384
  import { makeAgent } from "../agents/factory";
@@ -422,7 +395,9 @@ const multiply = tool(async ({ a, b }) => String(a * b), {
422
395
  schema: z.object({ a: z.number(), b: z.number() }),
423
396
  });
424
397
 
425
- export function createSwarmApp() {
398
+ export async function createSwarmApp() {
399
+ const llm = await getLlm();
400
+
426
401
  const alice = makeAgent({
427
402
  name: "alice", llm,
428
403
  tools: [add, createHandoffTool({ agentName: "bob" })],
@@ -444,7 +419,7 @@ export function createSwarmApp() {
444
419
  });
445
420
  imports.push(`import { createSwarmApp } from "./apps/swarm";`);
446
421
  demos.push(` console.log("\\n=== Swarm Demo ===");
447
- const swarmApp = createSwarmApp();
422
+ const swarmApp = await createSwarmApp();
448
423
  const swarm = await swarmApp.invoke(
449
424
  { messages: [{ role: "user", content: "add 5 and 7, then talk to bob and multiply by 3" }] },
450
425
  { configurable: { thread_id: "swarm-demo" } }
@@ -457,7 +432,7 @@ export function createSwarmApp() {
457
432
  content: `import { z } from "zod";
458
433
  import { tool } from "@langchain/core/tools";
459
434
  import { interrupt } from "@langchain/langgraph";
460
- import { llm } from "../config/llm";
435
+ import { getLlm } from "../config/llm";
461
436
  import { makeAgent } from "../agents/factory";
462
437
  import { makeSupervisor } from "../agents/supervisor";
463
438
 
@@ -479,7 +454,9 @@ const deleteRecord = tool(
479
454
  }
480
455
  );
481
456
 
482
- export function createInterruptApp() {
457
+ export async function createInterruptApp() {
458
+ const llm = await getLlm();
459
+
483
460
  const dbAdmin = makeAgent({
484
461
  name: "db_admin", llm,
485
462
  tools: [deleteRecord],
@@ -497,7 +474,7 @@ export function createInterruptApp() {
497
474
  imports.push(`import { Command } from "@langchain/langgraph";`);
498
475
  imports.push(`import { createInterruptApp } from "./apps/interrupt";`);
499
476
  demos.push(` console.log("\\n=== Human-in-the-Loop Demo ===");
500
- const interruptApp = createInterruptApp();
477
+ const interruptApp = await createInterruptApp();
501
478
  const hitlCfg = { configurable: { thread_id: "hitl-demo" } };
502
479
  await interruptApp.invoke(
503
480
  { messages: [{ role: "user", content: "delete record rec_2" }] },
@@ -514,7 +491,7 @@ export function createInterruptApp() {
514
491
  files.push({
515
492
  path: "src/apps/analyst.ts",
516
493
  content: `import { z } from "zod";
517
- import { llm } from "../config/llm";
494
+ import { getLlm } from "../config/llm";
518
495
  import { makeAgent } from "../agents/factory";
519
496
  import { makeSupervisor } from "../agents/supervisor";
520
497
 
@@ -524,7 +501,9 @@ const SummarySchema = z.object({
524
501
  sentiment: z.enum(["positive", "negative", "neutral"]),
525
502
  });
526
503
 
527
- export function createAnalystApp() {
504
+ export async function createAnalystApp() {
505
+ const llm = await getLlm();
506
+
528
507
  const analyst = makeAgent({
529
508
  name: "analyst", llm, tools: [],
530
509
  system: "Analyze text and produce structured summaries.",
@@ -541,7 +520,7 @@ export function createAnalystApp() {
541
520
  });
542
521
  imports.push(`import { createAnalystApp } from "./apps/analyst";`);
543
522
  demos.push(` console.log("\\n=== Structured Output Demo ===");
544
- const analystApp = createAnalystApp();
523
+ const analystApp = await createAnalystApp();
545
524
  const analysis = await analystApp.invoke(
546
525
  { messages: [{ role: "user", content: "Analyze: Revenue grew 25% but churn increased 8%." }] },
547
526
  { configurable: { thread_id: "analyst-demo" } }
@@ -551,14 +530,16 @@ export function createAnalystApp() {
551
530
  if (config.patterns.includes("rag")) {
552
531
  files.push({
553
532
  path: "src/apps/rag.ts",
554
- content: `import { llm } from "../config/llm";
533
+ content: `import { getLlm } from "../config/llm";
555
534
  import { makeAgent } from "../agents/factory";
556
535
  import { makeSupervisor } from "../agents/supervisor";
557
536
  // TODO: Add your vector store, embeddings, and retrieval tool here.
558
537
  // See the full starter kit for a complete RAG implementation:
559
538
  // https://github.com/ac12644/langgraph-starter-kit
560
539
 
561
- export function createRagApp() {
540
+ export async function createRagApp() {
541
+ const llm = await getLlm();
542
+
562
543
  const ragAgent = makeAgent({
563
544
  name: "rag_agent", llm, tools: [],
564
545
  system: "You are a knowledgeable assistant. Answer questions based on your knowledge.",
@@ -574,7 +555,7 @@ export function createRagApp() {
574
555
  });
575
556
  imports.push(`import { createRagApp } from "./apps/rag";`);
576
557
  demos.push(` console.log("\\n=== RAG Demo ===");
577
- const ragApp = createRagApp();
558
+ const ragApp = await createRagApp();
578
559
  const rag = await ragApp.invoke(
579
560
  { messages: [{ role: "user", content: "What is RAG and how does it work?" }] },
580
561
  { configurable: { thread_id: "rag-demo" } }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-langgraph-app",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Scaffold a new LangGraph multi-agent project in seconds",
5
5
  "type": "module",
6
6
  "bin": {