@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.
- package/dist/cli/deploy.mjs +70 -17
- package/dist/cli/utils/host-backend.mjs +7 -3
- package/package.json +3 -3
package/dist/cli/deploy.mjs
CHANGED
|
@@ -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,
|
|
336
|
-
|
|
337
|
-
|
|
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,
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
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
|
|
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: {
|
|
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.
|
|
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
|
-
"
|
|
43
|
-
"
|
|
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",
|