@langchain/langgraph-cli 1.5.1 → 1.5.2-dev.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.
@@ -326,15 +326,21 @@ async function resolveBuildMode(remoteBuildFlag) {
326
326
  }
327
327
  return [!supported, localBuildError];
328
328
  }
329
- async function resolveDeployment(client, step, deploymentId, name, notFoundMessage) {
329
+ async function resolveDeployment(client, step, deploymentId, name, notFoundMessage, agent) {
330
330
  if (deploymentId) {
331
331
  emitter.step(step, `Using deployment ${deploymentId}`);
332
332
  await callWithOptionalTenant(client, (c) => c.getDeployment(deploymentId));
333
333
  return { deploymentId, needsCreation: false, step: step + 1 };
334
334
  }
335
- emitter.step(step, `Looking up deployment '${name}'`);
336
- const response = await callWithOptionalTenant(client, (c) => c.listDeployments(name));
337
- const foundId = findDeploymentIdByName(response, name);
335
+ emitter.step(step, agent
336
+ ? `Looking up agent '${agent.agent_id}' in ${agent.environment}`
337
+ : `Looking up deployment '${name}'`);
338
+ const response = await callWithOptionalTenant(client, (c) => c.listDeployments(name, agent?.agent_id, agent?.environment));
339
+ let foundId = findDeploymentIdByName(response, name);
340
+ if (agent && Array.isArray(response.resources)) {
341
+ const found = response.resources.find((dep) => rec(dep).id && !rec(dep).is_preview);
342
+ foundId = found ? String(rec(found).id) : null;
343
+ }
338
344
  if (foundId) {
339
345
  emitter.info(`Found existing deployment (ID: ${foundId})`);
340
346
  return { deploymentId: foundId, needsCreation: false, step: step + 1 };
@@ -343,17 +349,28 @@ async function resolveDeployment(client, step, deploymentId, name, notFoundMessa
343
349
  return { deploymentId: undefined, needsCreation: true, step: step + 1 };
344
350
  }
345
351
  async function createDeployment(client, step, args) {
346
- emitter.step(step, `Creating deployment '${args.name}'`);
347
- const created = await client.createDeployment({
348
- name: args.name,
349
- deploymentType: args.deploymentType,
350
- source: args.source,
351
- secrets: args.secrets,
352
- });
352
+ emitter.step(step, args.agent
353
+ ? `Creating deployment for agent '${args.agent.agent_id}' in ${args.agent.environment}`
354
+ : `Creating deployment '${args.name}'`);
355
+ let created;
356
+ try {
357
+ created = await client.createDeployment(args);
358
+ }
359
+ catch (error) {
360
+ if (args.agent &&
361
+ error instanceof HostBackendError &&
362
+ error.statusCode === 409) {
363
+ throw new HostBackendError("This agent already has a deployment in this environment.", 409);
364
+ }
365
+ throw error;
366
+ }
353
367
  const id = typeof created.id === "string" ? created.id : undefined;
354
368
  if (!id) {
355
369
  throw new HostBackendError("POST /v2/deployments succeeded but response missing a valid 'id'");
356
370
  }
371
+ if (args.agent && created.name) {
372
+ emitter.info(`Deployment name: ${created.name}`);
373
+ }
357
374
  emitter.info(`Deployment ID: ${id}`, { deployment_id: id });
358
375
  return { id, step: step + 1 };
359
376
  }
@@ -802,12 +819,42 @@ async function runRemoteBuild(args) {
802
819
  await archive.cleanup();
803
820
  }
804
821
  }
822
+ // ---------------------------------------------------------------------------
823
+ // Main deploy orchestration
824
+ // ---------------------------------------------------------------------------
825
+ function resolveAgentOptions(opts) {
826
+ const agentId = opts.agentId ?? (process.env.LANGSMITH_AGENT_ID || undefined);
827
+ const agentEnvironment = opts.agentEnvironment ??
828
+ (process.env.LANGSMITH_AGENT_ENVIRONMENT || undefined);
829
+ if (agentId !== undefined || agentEnvironment !== undefined) {
830
+ emitter.note("Note: --agent-id and --agent-environment flags are in private beta");
831
+ }
832
+ if (agentId !== undefined && !agentId.trim()) {
833
+ throw new Error("--agent-id must not be empty.");
834
+ }
835
+ if (agentEnvironment !== undefined &&
836
+ !["development", "staging", "production"].includes(agentEnvironment)) {
837
+ throw new Error("--agent-environment must be development, staging, or production.");
838
+ }
839
+ return { agentId, agentEnvironment };
840
+ }
805
841
  async function runDeploy(dockerBuildArgs, opts, remoteBuildFlag) {
806
842
  emitter = new Emitter(opts.json);
807
843
  noInput = !opts.input;
808
844
  emitter.note("Note: 'langgraphjs deploy' is in beta. Expect frequent updates and improvements.");
809
845
  if (!opts.json)
810
846
  process.stdout.write("\n");
847
+ const { agentId, agentEnvironment } = resolveAgentOptions(opts);
848
+ let agent;
849
+ if (agentId !== undefined || agentEnvironment !== undefined) {
850
+ if (!agentId || !agentEnvironment) {
851
+ throw new Error("--agent-id and --agent-environment are required together.");
852
+ }
853
+ if (opts.name !== undefined || opts.deploymentId !== undefined) {
854
+ throw new Error("--agent-id and --agent-environment cannot be combined with --name or --deployment-id.");
855
+ }
856
+ agent = { agent_id: agentId, environment: agentEnvironment };
857
+ }
811
858
  if (!["dev", "prod"].includes(opts.deploymentType)) {
812
859
  throw new Error(`Invalid --deployment-type '${opts.deploymentType}' (expected 'dev' or 'prod').`);
813
860
  }
@@ -820,16 +867,16 @@ async function runDeploy(dockerBuildArgs, opts, remoteBuildFlag) {
820
867
  const envVars = await parseEnvFromConfig(rawConfig, configPath);
821
868
  let name = opts.name;
822
869
  let deploymentId = opts.deploymentId;
823
- if (!deploymentId && !name) {
870
+ if (!agent && !deploymentId && !name) {
824
871
  name = envVars[DEPLOYMENT_NAME_ENV] ?? process.env[DEPLOYMENT_NAME_ENV];
825
872
  }
826
- if (!deploymentId && !name) {
873
+ if (!agent && !deploymentId && !name) {
827
874
  const defaultName = normalizeName(path.basename(process.cwd()));
828
875
  name = noInput
829
876
  ? defaultName
830
877
  : await promptText("Deployment name", defaultName);
831
878
  }
832
- if (name && !deploymentId) {
879
+ if (!agent && name && !deploymentId) {
833
880
  name = normalizeName(name);
834
881
  if (!noInput) {
835
882
  const envPath = await resolveEnvPath(rawConfig, configPath);
@@ -851,12 +898,13 @@ async function runDeploy(dockerBuildArgs, opts, remoteBuildFlag) {
851
898
  let step = 1;
852
899
  const resolved = await resolveDeployment(client, step, deploymentId, name, useRemoteBuild
853
900
  ? "No deployment found. Will create."
854
- : "No deployment found. Will create after build.");
901
+ : "No deployment found. Will create after build.", agent);
855
902
  deploymentId = resolved.deploymentId;
856
903
  step = resolved.step;
857
904
  if (resolved.needsCreation) {
858
905
  const created = await createDeployment(client, step, {
859
- name: name,
906
+ name,
907
+ agent,
860
908
  deploymentType: opts.deploymentType,
861
909
  source: useRemoteBuild ? "internal_source" : "internal_docker",
862
910
  secrets,
@@ -948,8 +996,9 @@ async function runDeploy(dockerBuildArgs, opts, remoteBuildFlag) {
948
996
  async function runList(opts) {
949
997
  emitter = new Emitter(false);
950
998
  noInput = false;
999
+ const { agentId, agentEnvironment } = resolveAgentOptions(opts);
951
1000
  const client = await createHostBackendClient(opts.hostUrl, opts.apiKey);
952
- const response = await callWithOptionalTenant(client, (c) => c.listDeployments(opts.nameContains));
1001
+ const response = await callWithOptionalTenant(client, (c) => c.listDeployments(opts.nameContains, agentId, agentEnvironment));
953
1002
  const resources = Array.isArray(rec(response).resources)
954
1003
  ? rec(response).resources
955
1004
  : [];
@@ -1107,6 +1156,8 @@ const deploy = builder
1107
1156
  .option("--api-key <key>", "API key (or LANGGRAPH_HOST_API_KEY / LANGSMITH_API_KEY / LANGCHAIN_API_KEY).")
1108
1157
  .option("--name <name>", "Deployment name (or LANGSMITH_DEPLOYMENT_NAME). Defaults to the current directory name.")
1109
1158
  .option("--deployment-id <id>", "ID of an existing deployment to update.")
1159
+ .option("--agent-id <id>", "Agent ID (or LANGSMITH_AGENT_ID).")
1160
+ .option("--agent-environment <environment>", "Agent environment: development, staging, or production (or LANGSMITH_AGENT_ENVIRONMENT).")
1110
1161
  .option("--deployment-type <type>", "Deployment type when creating: 'dev' or 'prod'.", "dev")
1111
1162
  .option("--no-wait", "Skip waiting for deployment status.")
1112
1163
  .option("--verbose", "Show more output from the server logs.", false)
@@ -1141,6 +1192,8 @@ const deploy = builder
1141
1192
  deploy
1142
1193
  .command("list")
1143
1194
  .description("[Beta] List LangSmith Deployments.")
1195
+ .option("--agent-id <id>", "Agent ID (or LANGSMITH_AGENT_ID).")
1196
+ .option("--agent-environment <environment>", "Agent environment: development, staging, or production (or LANGSMITH_AGENT_ENVIRONMENT).")
1144
1197
  .option("--api-key <key>", "API key.")
1145
1198
  .option("--host-url <url>", "Host backend URL.", DEFAULT_HOST_URL)
1146
1199
  .option("--name-contains <value>", "Only show deployments whose names contain this value.", "")
@@ -160,7 +160,7 @@ export class HostBackendClient {
160
160
  */
161
161
  createDeployment(args) {
162
162
  const payload = {
163
- name: args.name,
163
+ ...(args.agent ? { agent: args.agent } : { name: args.name }),
164
164
  source: args.source,
165
165
  source_config: { deployment_type: args.deploymentType },
166
166
  source_revision_config: {},
@@ -179,9 +179,13 @@ export class HostBackendClient {
179
179
  * @param nameContains - Optional substring filter on deployment names.
180
180
  * @returns A paginated response object with a `resources` array.
181
181
  */
182
- listDeployments(nameContains = "") {
182
+ listDeployments(nameContains = "", agentId, agentEnvironment) {
183
183
  return this.request("GET", "/v2/deployments", {
184
- params: { name_contains: nameContains },
184
+ params: {
185
+ name_contains: nameContains,
186
+ agent_id: agentId,
187
+ agent_environment: agentEnvironment,
188
+ },
185
189
  });
186
190
  }
187
191
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/langgraph-cli",
3
- "version": "1.5.1",
3
+ "version": "1.5.2-dev.0",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": "^18.19.0 || >=20.16.0"
@@ -39,8 +39,8 @@
39
39
  "winston-console-format": "^1.0.8",
40
40
  "yaml": "^2.8.3",
41
41
  "zod": "^3.25.76 || ^4",
42
- "create-langgraph": "1.1.5",
43
- "@langchain/langgraph-api": "1.5.1"
42
+ "@langchain/langgraph-api": "1.5.2-dev.0",
43
+ "create-langgraph": "1.1.5"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@types/babel__code-frame": "^7.0.6",