langsmith 0.0.49 → 0.0.50

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.
@@ -1,11 +1,11 @@
1
1
  version: "3"
2
2
  services:
3
3
  langchain-playground:
4
- image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainplus-playground:latest
4
+ image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainplus-playground:${_LANGSMITH_IMAGE_VERSION-:latest}
5
5
  ports:
6
6
  - 3001:3001
7
7
  langchain-frontend:
8
- image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainplus-frontend-dynamic:latest
8
+ image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainplus-frontend-dynamic:${_LANGSMITH_IMAGE_VERSION-:latest}
9
9
  ports:
10
10
  - 80:80
11
11
  volumes:
@@ -15,7 +15,7 @@ services:
15
15
  - langchain-playground
16
16
  - langchain-hub
17
17
  langchain-backend:
18
- image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainplus-backend:latest
18
+ image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainplus-backend:${_LANGSMITH_IMAGE_VERSION-:latest}
19
19
  environment:
20
20
  - PORT=1984
21
21
  - LANGCHAIN_ENV=local_docker
@@ -28,14 +28,14 @@ services:
28
28
  - langchain-db
29
29
  - langchain-redis
30
30
  langchain-queue:
31
- image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainplus-backend:latest
31
+ image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainplus-backend:${_LANGSMITH_IMAGE_VERSION-:latest}
32
32
  environment:
33
33
  - LANGCHAIN_ENV=local_docker
34
34
  - LOG_LEVEL=warning
35
35
  - LANGSMITH_LICENSE_KEY=${LANGSMITH_LICENSE_KEY}
36
36
  entrypoint: "rq worker --with-scheduler -u redis://langchain-redis:6379 --serializer lc_database.queue.serializer.ORJSONSerializer --worker-class lc_database.queue.worker.Worker --connection-class lc_database.queue.connection.RedisRetry --job-class lc_database.queue.job.AsyncJob"
37
37
  langchain-hub:
38
- image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainhub-backend:latest
38
+ image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainhub-backend:${_LANGSMITH_IMAGE_VERSION-:latest}
39
39
  environment:
40
40
  - PORT=1985
41
41
  - LANGCHAIN_ENV=local_docker
package/dist/cli/main.cjs CHANGED
@@ -25,14 +25,12 @@ var __importStar = (this && this.__importStar) || function (mod) {
25
25
  };
26
26
  Object.defineProperty(exports, "__esModule", { value: true });
27
27
  const child_process = __importStar(require("child_process"));
28
- const fs = __importStar(require("fs"));
29
28
  const path = __importStar(require("path"));
30
29
  const util = __importStar(require("util"));
31
30
  const env_js_1 = require("../utils/env.cjs");
32
31
  const commander_1 = require("commander");
33
32
  const child_process_1 = require("child_process");
34
33
  const currentFileName = __filename;
35
- const currentDirName = __dirname;
36
34
  const program = new commander_1.Command();
37
35
  async function getDockerComposeCommand() {
38
36
  const exec = util.promisify(child_process.exec);
@@ -79,56 +77,12 @@ async function pprintServices(servicesStatus) {
79
77
  const portsStr = service["PublishedPorts"] || "";
80
78
  serviceMessage.push(serviceStr + stateStr + portsStr);
81
79
  }
82
- let langchainEndpoint = "http://localhost:1984";
83
- const usedNgrok = services.some((service) => service["Service"].includes("ngrok"));
84
- if (usedNgrok) {
85
- langchainEndpoint = await getNgrokUrl();
86
- }
87
80
  serviceMessage.push("\nTo connect, set the following environment variables" +
88
81
  " in your LangChain application:" +
89
82
  "\nLANGCHAIN_TRACING_V2=true" +
90
- `\nLANGCHAIN_ENDPOINT=${langchainEndpoint}`);
83
+ `\nLANGCHAIN_ENDPOINT=http://localhost:80/api`);
91
84
  console.info(serviceMessage.join("\n"));
92
85
  }
93
- async function getNgrokUrl() {
94
- const ngrokUrl = "http://localhost:4040/api/tunnels";
95
- try {
96
- // const response = await axios.get(ngrokUrl);
97
- const response = await fetch(ngrokUrl);
98
- if (response.status !== 200) {
99
- throw new Error(`Could not connect to ngrok console. ${response.status}, ${response.statusText}`);
100
- }
101
- const result = await response.json();
102
- const exposedUrl = result["tunnels"][0]["public_url"];
103
- return exposedUrl;
104
- }
105
- catch (error) {
106
- throw new Error(`Could not connect to ngrok console. ${error}`);
107
- }
108
- }
109
- async function createNgrokConfig(authToken) {
110
- const configPath = path.join(currentDirName, "ngrok_config.yaml");
111
- // Check if is a directory
112
- if (fs.existsSync(configPath) && fs.lstatSync(configPath).isDirectory()) {
113
- fs.rmdirSync(configPath, { recursive: true });
114
- }
115
- else if (fs.existsSync(configPath)) {
116
- fs.unlinkSync(configPath);
117
- }
118
- let ngrokConfig = `
119
- region: us
120
- tunnels:
121
- langchain:
122
- addr: langchain-backend:1984
123
- proto: http
124
- version: '2'
125
- `;
126
- if (authToken !== null) {
127
- ngrokConfig += `authtoken: ${authToken}`;
128
- }
129
- fs.writeFileSync(configPath, ngrokConfig);
130
- return configPath;
131
- }
132
86
  class SmithCommand {
133
87
  constructor({ dockerComposeCommand }) {
134
88
  Object.defineProperty(this, "dockerComposeCommand", {
@@ -143,29 +97,8 @@ class SmithCommand {
143
97
  writable: true,
144
98
  value: ""
145
99
  });
146
- Object.defineProperty(this, "dockerComposeDevFile", {
147
- enumerable: true,
148
- configurable: true,
149
- writable: true,
150
- value: ""
151
- });
152
- Object.defineProperty(this, "dockerComposeBetaFile", {
153
- enumerable: true,
154
- configurable: true,
155
- writable: true,
156
- value: ""
157
- });
158
- Object.defineProperty(this, "ngrokPath", {
159
- enumerable: true,
160
- configurable: true,
161
- writable: true,
162
- value: ""
163
- });
164
100
  this.dockerComposeCommand = dockerComposeCommand;
165
101
  this.dockerComposeFile = path.join(path.dirname(currentFileName), "docker-compose.yaml");
166
- this.dockerComposeDevFile = path.join(path.dirname(currentFileName), "docker-compose.dev.yaml");
167
- this.dockerComposeBetaFile = path.join(path.dirname(currentFileName), "docker-compose.beta.yaml");
168
- this.ngrokPath = path.join(path.dirname(currentFileName), "docker-compose.ngrok.yaml");
169
102
  }
170
103
  async executeCommand(command) {
171
104
  return new Promise((resolve, reject) => {
@@ -190,13 +123,14 @@ class SmithCommand {
190
123
  const dockerComposeCommand = await getDockerComposeCommand();
191
124
  return new SmithCommand({ dockerComposeCommand });
192
125
  }
193
- async pull({ stage = "prod" }) {
126
+ async pull({ stage = "prod", version = "latest" }) {
194
127
  if (stage === "dev") {
195
128
  (0, env_js_1.setEnvironmentVariable)("_LANGSMITH_IMAGE_PREFIX", "dev-");
196
129
  }
197
130
  else if (stage === "beta") {
198
131
  (0, env_js_1.setEnvironmentVariable)("_LANGSMITH_IMAGE_PREFIX", "rc-");
199
132
  }
133
+ (0, env_js_1.setEnvironmentVariable)("_LANGSMITH_IMAGE_VERSION", version);
200
134
  const command = [
201
135
  ...this.dockerComposeCommand,
202
136
  "-f",
@@ -205,18 +139,12 @@ class SmithCommand {
205
139
  ];
206
140
  await this.executeCommand(command);
207
141
  }
208
- async startLocal(stage = "prod") {
142
+ async startLocal() {
209
143
  const command = [
210
144
  ...this.dockerComposeCommand,
211
145
  "-f",
212
146
  this.dockerComposeFile,
213
147
  ];
214
- if (stage === "dev") {
215
- command.push("-f", this.dockerComposeDevFile);
216
- }
217
- else if (stage === "beta") {
218
- command.push("-f", this.dockerComposeBetaFile);
219
- }
220
148
  command.push("up", "--quiet-pull", "--wait");
221
149
  await this.executeCommand(command);
222
150
  console.info("LangSmith server is running at http://localhost:1984.\n" +
@@ -225,42 +153,13 @@ class SmithCommand {
225
153
  " locally, set the following environment variable" +
226
154
  " when running your LangChain application.");
227
155
  console.info("\tLANGCHAIN_TRACING_V2=true");
228
- }
229
- async startAndExpose(ngrokAuthToken, stage = "prod") {
230
- const configPath = await createNgrokConfig(ngrokAuthToken);
231
- const command = [
232
- ...this.dockerComposeCommand,
233
- "-f",
234
- this.dockerComposeFile,
235
- "-f",
236
- this.ngrokPath,
237
- ];
238
- if (stage === "dev") {
239
- command.push("-f", this.dockerComposeDevFile);
240
- }
241
- else if (stage === "beta") {
242
- command.push("-f", this.dockerComposeBetaFile);
243
- }
244
- command.push("up", "--quiet-pull", "--wait");
245
- await this.executeCommand(command);
246
- console.info("ngrok is running. You can view the dashboard at http://0.0.0.0:4040");
247
- const ngrokUrl = await getNgrokUrl();
248
- console.info("LangSmith server is running at http://localhost:1984." +
249
- "To view the app, navigate your browser to http://localhost:80" +
250
- "\n\nTo connect your LangChain application to the server" +
251
- " remotely, set the following environment variable" +
252
- " when running your LangChain application.");
253
- console.info("\tLANGCHAIN_TRACING_V2=true");
254
- console.info(`\tLANGCHAIN_ENDPOINT=${ngrokUrl}`);
255
- fs.unlinkSync(configPath);
156
+ console.info("\tLANGCHAIN_ENDPOINT=http://localhost:80/api");
256
157
  }
257
158
  async stop() {
258
159
  const command = [
259
160
  ...this.dockerComposeCommand,
260
161
  "-f",
261
162
  this.dockerComposeFile,
262
- "-f",
263
- this.ngrokPath,
264
163
  "down",
265
164
  ];
266
165
  await this.executeCommand(command);
@@ -302,8 +201,6 @@ class SmithCommand {
302
201
  }
303
202
  const startCommand = new commander_1.Command("start")
304
203
  .description("Start the LangSmith server")
305
- .option("--expose", "Expose the server to the internet via ngrok (requires ngrok to be installed)")
306
- .option("--ngrok-authtoken <ngrokAuthtoken>", "Your ngrok auth token. If this is set, --expose is implied.")
307
204
  .option("--stage <stage>", "Which version of LangSmith to run. Options: prod, dev, beta (default: prod)")
308
205
  .option("--openai-api-key <openaiApiKey>", "Your OpenAI API key. If not provided, the OpenAI API Key will be read" +
309
206
  " from the OPENAI_API_KEY environment variable. If neither are provided," +
@@ -311,27 +208,20 @@ const startCommand = new commander_1.Command("start")
311
208
  .option("--langsmith-license-key <langsmithLicenseKey>", "The LangSmith license key to use for LangSmith. If not provided, the LangSmith" +
312
209
  " License Key will be read from the LANGSMITH_LICENSE_KEY environment variable." +
313
210
  " If neither are provided, the Langsmith application will not spin up.")
211
+ .option("--version <version>", "The LangSmith version to use for LangSmith. Defaults to latest." +
212
+ " We recommend pegging this to the latest static version available at" +
213
+ " https://hub.docker.com/repository/docker/langchain/langchainplus-backend" +
214
+ " if you are using Langsmith in production.")
314
215
  .action(async (args) => {
315
216
  const smith = await SmithCommand.create();
316
- if (args.stage === "dev") {
317
- (0, env_js_1.setEnvironmentVariable)("_LANGSMITH_IMAGE_PREFIX", "dev-");
318
- }
319
- else if (args.stage === "beta") {
320
- (0, env_js_1.setEnvironmentVariable)("_LANGSMITH_IMAGE_PREFIX", "rc-");
321
- }
322
217
  if (args.openaiApiKey) {
323
218
  (0, env_js_1.setEnvironmentVariable)("OPENAI_API_KEY", args.openaiApiKey);
324
219
  }
325
220
  if (args.langsmithLicenseKey) {
326
221
  (0, env_js_1.setEnvironmentVariable)("LANGSMITH_LICENSE_KEY", args.langsmithLicenseKey);
327
222
  }
328
- await smith.pull({ stage: args.stage });
329
- if (args.expose) {
330
- await smith.startAndExpose(args.ngrokAuthtoken, args.stage);
331
- }
332
- else {
333
- await smith.startLocal(args.stage);
334
- }
223
+ await smith.pull({ stage: args.stage, version: args.version });
224
+ await smith.startLocal();
335
225
  });
336
226
  const stopCommand = new commander_1.Command("stop")
337
227
  .description("Stop the LangSmith server")
@@ -342,15 +232,13 @@ const stopCommand = new commander_1.Command("stop")
342
232
  const pullCommand = new commander_1.Command("pull")
343
233
  .description("Pull the latest version of the LangSmith server")
344
234
  .option("--stage <stage>", "Which version of LangSmith to pull. Options: prod, dev, beta (default: prod)")
235
+ .option("--version <version>", "The LangSmith version to use for LangSmith. Defaults to latest." +
236
+ " We recommend pegging this to the latest static version available at" +
237
+ " https://hub.docker.com/repository/docker/langchain/langchainplus-backend" +
238
+ " if you are using Langsmith in production.")
345
239
  .action(async (args) => {
346
240
  const smith = await SmithCommand.create();
347
- if (args.stage === "dev") {
348
- (0, env_js_1.setEnvironmentVariable)("_LANGSMITH_IMAGE_PREFIX", "dev-");
349
- }
350
- else if (args.stage === "beta") {
351
- (0, env_js_1.setEnvironmentVariable)("_LANGSMITH_IMAGE_PREFIX", "rc-");
352
- }
353
- await smith.pull({ stage: args.stage });
241
+ await smith.pull({ stage: args.stage, version: args.version });
354
242
  });
355
243
  const statusCommand = new commander_1.Command("status")
356
244
  .description("Get the status of the LangSmith server")
package/dist/cli/main.js CHANGED
@@ -1,12 +1,10 @@
1
1
  import * as child_process from "child_process";
2
- import * as fs from "fs";
3
2
  import * as path from "path";
4
3
  import * as util from "util";
5
4
  import { getLangChainEnvVars, getRuntimeEnvironment, setEnvironmentVariable, } from "../utils/env.js";
6
5
  import { Command } from "commander";
7
6
  import { spawn } from "child_process";
8
7
  const currentFileName = __filename;
9
- const currentDirName = __dirname;
10
8
  const program = new Command();
11
9
  async function getDockerComposeCommand() {
12
10
  const exec = util.promisify(child_process.exec);
@@ -53,56 +51,12 @@ async function pprintServices(servicesStatus) {
53
51
  const portsStr = service["PublishedPorts"] || "";
54
52
  serviceMessage.push(serviceStr + stateStr + portsStr);
55
53
  }
56
- let langchainEndpoint = "http://localhost:1984";
57
- const usedNgrok = services.some((service) => service["Service"].includes("ngrok"));
58
- if (usedNgrok) {
59
- langchainEndpoint = await getNgrokUrl();
60
- }
61
54
  serviceMessage.push("\nTo connect, set the following environment variables" +
62
55
  " in your LangChain application:" +
63
56
  "\nLANGCHAIN_TRACING_V2=true" +
64
- `\nLANGCHAIN_ENDPOINT=${langchainEndpoint}`);
57
+ `\nLANGCHAIN_ENDPOINT=http://localhost:80/api`);
65
58
  console.info(serviceMessage.join("\n"));
66
59
  }
67
- async function getNgrokUrl() {
68
- const ngrokUrl = "http://localhost:4040/api/tunnels";
69
- try {
70
- // const response = await axios.get(ngrokUrl);
71
- const response = await fetch(ngrokUrl);
72
- if (response.status !== 200) {
73
- throw new Error(`Could not connect to ngrok console. ${response.status}, ${response.statusText}`);
74
- }
75
- const result = await response.json();
76
- const exposedUrl = result["tunnels"][0]["public_url"];
77
- return exposedUrl;
78
- }
79
- catch (error) {
80
- throw new Error(`Could not connect to ngrok console. ${error}`);
81
- }
82
- }
83
- async function createNgrokConfig(authToken) {
84
- const configPath = path.join(currentDirName, "ngrok_config.yaml");
85
- // Check if is a directory
86
- if (fs.existsSync(configPath) && fs.lstatSync(configPath).isDirectory()) {
87
- fs.rmdirSync(configPath, { recursive: true });
88
- }
89
- else if (fs.existsSync(configPath)) {
90
- fs.unlinkSync(configPath);
91
- }
92
- let ngrokConfig = `
93
- region: us
94
- tunnels:
95
- langchain:
96
- addr: langchain-backend:1984
97
- proto: http
98
- version: '2'
99
- `;
100
- if (authToken !== null) {
101
- ngrokConfig += `authtoken: ${authToken}`;
102
- }
103
- fs.writeFileSync(configPath, ngrokConfig);
104
- return configPath;
105
- }
106
60
  class SmithCommand {
107
61
  constructor({ dockerComposeCommand }) {
108
62
  Object.defineProperty(this, "dockerComposeCommand", {
@@ -117,29 +71,8 @@ class SmithCommand {
117
71
  writable: true,
118
72
  value: ""
119
73
  });
120
- Object.defineProperty(this, "dockerComposeDevFile", {
121
- enumerable: true,
122
- configurable: true,
123
- writable: true,
124
- value: ""
125
- });
126
- Object.defineProperty(this, "dockerComposeBetaFile", {
127
- enumerable: true,
128
- configurable: true,
129
- writable: true,
130
- value: ""
131
- });
132
- Object.defineProperty(this, "ngrokPath", {
133
- enumerable: true,
134
- configurable: true,
135
- writable: true,
136
- value: ""
137
- });
138
74
  this.dockerComposeCommand = dockerComposeCommand;
139
75
  this.dockerComposeFile = path.join(path.dirname(currentFileName), "docker-compose.yaml");
140
- this.dockerComposeDevFile = path.join(path.dirname(currentFileName), "docker-compose.dev.yaml");
141
- this.dockerComposeBetaFile = path.join(path.dirname(currentFileName), "docker-compose.beta.yaml");
142
- this.ngrokPath = path.join(path.dirname(currentFileName), "docker-compose.ngrok.yaml");
143
76
  }
144
77
  async executeCommand(command) {
145
78
  return new Promise((resolve, reject) => {
@@ -164,13 +97,14 @@ class SmithCommand {
164
97
  const dockerComposeCommand = await getDockerComposeCommand();
165
98
  return new SmithCommand({ dockerComposeCommand });
166
99
  }
167
- async pull({ stage = "prod" }) {
100
+ async pull({ stage = "prod", version = "latest" }) {
168
101
  if (stage === "dev") {
169
102
  setEnvironmentVariable("_LANGSMITH_IMAGE_PREFIX", "dev-");
170
103
  }
171
104
  else if (stage === "beta") {
172
105
  setEnvironmentVariable("_LANGSMITH_IMAGE_PREFIX", "rc-");
173
106
  }
107
+ setEnvironmentVariable("_LANGSMITH_IMAGE_VERSION", version);
174
108
  const command = [
175
109
  ...this.dockerComposeCommand,
176
110
  "-f",
@@ -179,18 +113,12 @@ class SmithCommand {
179
113
  ];
180
114
  await this.executeCommand(command);
181
115
  }
182
- async startLocal(stage = "prod") {
116
+ async startLocal() {
183
117
  const command = [
184
118
  ...this.dockerComposeCommand,
185
119
  "-f",
186
120
  this.dockerComposeFile,
187
121
  ];
188
- if (stage === "dev") {
189
- command.push("-f", this.dockerComposeDevFile);
190
- }
191
- else if (stage === "beta") {
192
- command.push("-f", this.dockerComposeBetaFile);
193
- }
194
122
  command.push("up", "--quiet-pull", "--wait");
195
123
  await this.executeCommand(command);
196
124
  console.info("LangSmith server is running at http://localhost:1984.\n" +
@@ -199,42 +127,13 @@ class SmithCommand {
199
127
  " locally, set the following environment variable" +
200
128
  " when running your LangChain application.");
201
129
  console.info("\tLANGCHAIN_TRACING_V2=true");
202
- }
203
- async startAndExpose(ngrokAuthToken, stage = "prod") {
204
- const configPath = await createNgrokConfig(ngrokAuthToken);
205
- const command = [
206
- ...this.dockerComposeCommand,
207
- "-f",
208
- this.dockerComposeFile,
209
- "-f",
210
- this.ngrokPath,
211
- ];
212
- if (stage === "dev") {
213
- command.push("-f", this.dockerComposeDevFile);
214
- }
215
- else if (stage === "beta") {
216
- command.push("-f", this.dockerComposeBetaFile);
217
- }
218
- command.push("up", "--quiet-pull", "--wait");
219
- await this.executeCommand(command);
220
- console.info("ngrok is running. You can view the dashboard at http://0.0.0.0:4040");
221
- const ngrokUrl = await getNgrokUrl();
222
- console.info("LangSmith server is running at http://localhost:1984." +
223
- "To view the app, navigate your browser to http://localhost:80" +
224
- "\n\nTo connect your LangChain application to the server" +
225
- " remotely, set the following environment variable" +
226
- " when running your LangChain application.");
227
- console.info("\tLANGCHAIN_TRACING_V2=true");
228
- console.info(`\tLANGCHAIN_ENDPOINT=${ngrokUrl}`);
229
- fs.unlinkSync(configPath);
130
+ console.info("\tLANGCHAIN_ENDPOINT=http://localhost:80/api");
230
131
  }
231
132
  async stop() {
232
133
  const command = [
233
134
  ...this.dockerComposeCommand,
234
135
  "-f",
235
136
  this.dockerComposeFile,
236
- "-f",
237
- this.ngrokPath,
238
137
  "down",
239
138
  ];
240
139
  await this.executeCommand(command);
@@ -276,8 +175,6 @@ class SmithCommand {
276
175
  }
277
176
  const startCommand = new Command("start")
278
177
  .description("Start the LangSmith server")
279
- .option("--expose", "Expose the server to the internet via ngrok (requires ngrok to be installed)")
280
- .option("--ngrok-authtoken <ngrokAuthtoken>", "Your ngrok auth token. If this is set, --expose is implied.")
281
178
  .option("--stage <stage>", "Which version of LangSmith to run. Options: prod, dev, beta (default: prod)")
282
179
  .option("--openai-api-key <openaiApiKey>", "Your OpenAI API key. If not provided, the OpenAI API Key will be read" +
283
180
  " from the OPENAI_API_KEY environment variable. If neither are provided," +
@@ -285,27 +182,20 @@ const startCommand = new Command("start")
285
182
  .option("--langsmith-license-key <langsmithLicenseKey>", "The LangSmith license key to use for LangSmith. If not provided, the LangSmith" +
286
183
  " License Key will be read from the LANGSMITH_LICENSE_KEY environment variable." +
287
184
  " If neither are provided, the Langsmith application will not spin up.")
185
+ .option("--version <version>", "The LangSmith version to use for LangSmith. Defaults to latest." +
186
+ " We recommend pegging this to the latest static version available at" +
187
+ " https://hub.docker.com/repository/docker/langchain/langchainplus-backend" +
188
+ " if you are using Langsmith in production.")
288
189
  .action(async (args) => {
289
190
  const smith = await SmithCommand.create();
290
- if (args.stage === "dev") {
291
- setEnvironmentVariable("_LANGSMITH_IMAGE_PREFIX", "dev-");
292
- }
293
- else if (args.stage === "beta") {
294
- setEnvironmentVariable("_LANGSMITH_IMAGE_PREFIX", "rc-");
295
- }
296
191
  if (args.openaiApiKey) {
297
192
  setEnvironmentVariable("OPENAI_API_KEY", args.openaiApiKey);
298
193
  }
299
194
  if (args.langsmithLicenseKey) {
300
195
  setEnvironmentVariable("LANGSMITH_LICENSE_KEY", args.langsmithLicenseKey);
301
196
  }
302
- await smith.pull({ stage: args.stage });
303
- if (args.expose) {
304
- await smith.startAndExpose(args.ngrokAuthtoken, args.stage);
305
- }
306
- else {
307
- await smith.startLocal(args.stage);
308
- }
197
+ await smith.pull({ stage: args.stage, version: args.version });
198
+ await smith.startLocal();
309
199
  });
310
200
  const stopCommand = new Command("stop")
311
201
  .description("Stop the LangSmith server")
@@ -316,15 +206,13 @@ const stopCommand = new Command("stop")
316
206
  const pullCommand = new Command("pull")
317
207
  .description("Pull the latest version of the LangSmith server")
318
208
  .option("--stage <stage>", "Which version of LangSmith to pull. Options: prod, dev, beta (default: prod)")
209
+ .option("--version <version>", "The LangSmith version to use for LangSmith. Defaults to latest." +
210
+ " We recommend pegging this to the latest static version available at" +
211
+ " https://hub.docker.com/repository/docker/langchain/langchainplus-backend" +
212
+ " if you are using Langsmith in production.")
319
213
  .action(async (args) => {
320
214
  const smith = await SmithCommand.create();
321
- if (args.stage === "dev") {
322
- setEnvironmentVariable("_LANGSMITH_IMAGE_PREFIX", "dev-");
323
- }
324
- else if (args.stage === "beta") {
325
- setEnvironmentVariable("_LANGSMITH_IMAGE_PREFIX", "rc-");
326
- }
327
- await smith.pull({ stage: args.stage });
215
+ await smith.pull({ stage: args.stage, version: args.version });
328
216
  });
329
217
  const statusCommand = new Command("status")
330
218
  .description("Get the status of the LangSmith server")
package/dist/cli/main.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import * as child_process from "child_process";
2
- import * as fs from "fs";
3
2
  import * as path from "path";
4
3
  import * as util from "util";
5
4
 
@@ -13,8 +12,6 @@ import { Command } from "commander";
13
12
  import { spawn } from "child_process";
14
13
 
15
14
  const currentFileName = __filename;
16
- const currentDirName = __dirname;
17
-
18
15
  const program = new Command();
19
16
 
20
17
  async function getDockerComposeCommand(): Promise<string[]> {
@@ -69,71 +66,18 @@ async function pprintServices(servicesStatus: any[]) {
69
66
  serviceMessage.push(serviceStr + stateStr + portsStr);
70
67
  }
71
68
 
72
- let langchainEndpoint = "http://localhost:1984";
73
- const usedNgrok = services.some((service) =>
74
- service["Service"].includes("ngrok")
75
- );
76
- if (usedNgrok) {
77
- langchainEndpoint = await getNgrokUrl();
78
- }
79
-
80
69
  serviceMessage.push(
81
70
  "\nTo connect, set the following environment variables" +
82
71
  " in your LangChain application:" +
83
72
  "\nLANGCHAIN_TRACING_V2=true" +
84
- `\nLANGCHAIN_ENDPOINT=${langchainEndpoint}`
73
+ `\nLANGCHAIN_ENDPOINT=http://localhost:80/api`
85
74
  );
86
75
  console.info(serviceMessage.join("\n"));
87
76
  }
88
77
 
89
- async function getNgrokUrl(): Promise<string> {
90
- const ngrokUrl = "http://localhost:4040/api/tunnels";
91
- try {
92
- // const response = await axios.get(ngrokUrl);
93
- const response = await fetch(ngrokUrl);
94
- if (response.status !== 200) {
95
- throw new Error(
96
- `Could not connect to ngrok console. ${response.status}, ${response.statusText}`
97
- );
98
- }
99
- const result = await response.json();
100
- const exposedUrl = result["tunnels"][0]["public_url"];
101
- return exposedUrl;
102
- } catch (error) {
103
- throw new Error(`Could not connect to ngrok console. ${error}`);
104
- }
105
- }
106
-
107
- async function createNgrokConfig(authToken: string | null): Promise<string> {
108
- const configPath = path.join(currentDirName, "ngrok_config.yaml");
109
- // Check if is a directory
110
- if (fs.existsSync(configPath) && fs.lstatSync(configPath).isDirectory()) {
111
- fs.rmdirSync(configPath, { recursive: true });
112
- } else if (fs.existsSync(configPath)) {
113
- fs.unlinkSync(configPath);
114
- }
115
- let ngrokConfig = `
116
- region: us
117
- tunnels:
118
- langchain:
119
- addr: langchain-backend:1984
120
- proto: http
121
- version: '2'
122
- `;
123
-
124
- if (authToken !== null) {
125
- ngrokConfig += `authtoken: ${authToken}`;
126
- }
127
- fs.writeFileSync(configPath, ngrokConfig);
128
- return configPath;
129
- }
130
-
131
78
  class SmithCommand {
132
79
  dockerComposeCommand: string[] = [];
133
80
  dockerComposeFile = "";
134
- dockerComposeDevFile = "";
135
- dockerComposeBetaFile = "";
136
- ngrokPath = "";
137
81
 
138
82
  constructor({ dockerComposeCommand }: { dockerComposeCommand: string[] }) {
139
83
  this.dockerComposeCommand = dockerComposeCommand;
@@ -141,18 +85,6 @@ class SmithCommand {
141
85
  path.dirname(currentFileName),
142
86
  "docker-compose.yaml"
143
87
  );
144
- this.dockerComposeDevFile = path.join(
145
- path.dirname(currentFileName),
146
- "docker-compose.dev.yaml"
147
- );
148
- this.dockerComposeBetaFile = path.join(
149
- path.dirname(currentFileName),
150
- "docker-compose.beta.yaml"
151
- );
152
- this.ngrokPath = path.join(
153
- path.dirname(currentFileName),
154
- "docker-compose.ngrok.yaml"
155
- );
156
88
  }
157
89
 
158
90
  async executeCommand(command: string[]) {
@@ -183,12 +115,13 @@ class SmithCommand {
183
115
  return new SmithCommand({ dockerComposeCommand });
184
116
  }
185
117
 
186
- async pull({ stage = "prod" }) {
118
+ async pull({ stage = "prod", version = "latest" }) {
187
119
  if (stage === "dev") {
188
120
  setEnvironmentVariable("_LANGSMITH_IMAGE_PREFIX", "dev-");
189
121
  } else if (stage === "beta") {
190
122
  setEnvironmentVariable("_LANGSMITH_IMAGE_PREFIX", "rc-");
191
123
  }
124
+ setEnvironmentVariable("_LANGSMITH_IMAGE_VERSION", version);
192
125
 
193
126
  const command = [
194
127
  ...this.dockerComposeCommand,
@@ -199,19 +132,13 @@ class SmithCommand {
199
132
  await this.executeCommand(command);
200
133
  }
201
134
 
202
- async startLocal(stage = "prod") {
135
+ async startLocal() {
203
136
  const command = [
204
137
  ...this.dockerComposeCommand,
205
138
  "-f",
206
139
  this.dockerComposeFile,
207
140
  ];
208
141
 
209
- if (stage === "dev") {
210
- command.push("-f", this.dockerComposeDevFile);
211
- } else if (stage === "beta") {
212
- command.push("-f", this.dockerComposeBetaFile);
213
- }
214
-
215
142
  command.push("up", "--quiet-pull", "--wait");
216
143
  await this.executeCommand(command);
217
144
 
@@ -224,42 +151,7 @@ class SmithCommand {
224
151
  );
225
152
 
226
153
  console.info("\tLANGCHAIN_TRACING_V2=true");
227
- }
228
-
229
- async startAndExpose(ngrokAuthToken: string | null, stage = "prod") {
230
- const configPath = await createNgrokConfig(ngrokAuthToken);
231
- const command = [
232
- ...this.dockerComposeCommand,
233
- "-f",
234
- this.dockerComposeFile,
235
- "-f",
236
- this.ngrokPath,
237
- ];
238
-
239
- if (stage === "dev") {
240
- command.push("-f", this.dockerComposeDevFile);
241
- } else if (stage === "beta") {
242
- command.push("-f", this.dockerComposeBetaFile);
243
- }
244
-
245
- command.push("up", "--quiet-pull", "--wait");
246
- await this.executeCommand(command);
247
-
248
- console.info(
249
- "ngrok is running. You can view the dashboard at http://0.0.0.0:4040"
250
- );
251
- const ngrokUrl = await getNgrokUrl();
252
- console.info(
253
- "LangSmith server is running at http://localhost:1984." +
254
- "To view the app, navigate your browser to http://localhost:80" +
255
- "\n\nTo connect your LangChain application to the server" +
256
- " remotely, set the following environment variable" +
257
- " when running your LangChain application."
258
- );
259
- console.info("\tLANGCHAIN_TRACING_V2=true");
260
- console.info(`\tLANGCHAIN_ENDPOINT=${ngrokUrl}`);
261
-
262
- fs.unlinkSync(configPath);
154
+ console.info("\tLANGCHAIN_ENDPOINT=http://localhost:80/api");
263
155
  }
264
156
 
265
157
  async stop() {
@@ -267,8 +159,6 @@ class SmithCommand {
267
159
  ...this.dockerComposeCommand,
268
160
  "-f",
269
161
  this.dockerComposeFile,
270
- "-f",
271
- this.ngrokPath,
272
162
  "down",
273
163
  ];
274
164
  await this.executeCommand(command);
@@ -314,14 +204,6 @@ class SmithCommand {
314
204
 
315
205
  const startCommand = new Command("start")
316
206
  .description("Start the LangSmith server")
317
- .option(
318
- "--expose",
319
- "Expose the server to the internet via ngrok (requires ngrok to be installed)"
320
- )
321
- .option(
322
- "--ngrok-authtoken <ngrokAuthtoken>",
323
- "Your ngrok auth token. If this is set, --expose is implied."
324
- )
325
207
  .option(
326
208
  "--stage <stage>",
327
209
  "Which version of LangSmith to run. Options: prod, dev, beta (default: prod)"
@@ -338,25 +220,23 @@ const startCommand = new Command("start")
338
220
  " License Key will be read from the LANGSMITH_LICENSE_KEY environment variable." +
339
221
  " If neither are provided, the Langsmith application will not spin up."
340
222
  )
223
+ .option(
224
+ "--version <version>",
225
+ "The LangSmith version to use for LangSmith. Defaults to latest." +
226
+ " We recommend pegging this to the latest static version available at" +
227
+ " https://hub.docker.com/repository/docker/langchain/langchainplus-backend" +
228
+ " if you are using Langsmith in production."
229
+ )
341
230
  .action(async (args) => {
342
231
  const smith = await SmithCommand.create();
343
- if (args.stage === "dev") {
344
- setEnvironmentVariable("_LANGSMITH_IMAGE_PREFIX", "dev-");
345
- } else if (args.stage === "beta") {
346
- setEnvironmentVariable("_LANGSMITH_IMAGE_PREFIX", "rc-");
347
- }
348
232
  if (args.openaiApiKey) {
349
233
  setEnvironmentVariable("OPENAI_API_KEY", args.openaiApiKey);
350
234
  }
351
235
  if (args.langsmithLicenseKey) {
352
236
  setEnvironmentVariable("LANGSMITH_LICENSE_KEY", args.langsmithLicenseKey);
353
237
  }
354
- await smith.pull({ stage: args.stage });
355
- if (args.expose) {
356
- await smith.startAndExpose(args.ngrokAuthtoken, args.stage);
357
- } else {
358
- await smith.startLocal(args.stage);
359
- }
238
+ await smith.pull({ stage: args.stage, version: args.version });
239
+ await smith.startLocal();
360
240
  });
361
241
 
362
242
  const stopCommand = new Command("stop")
@@ -372,14 +252,16 @@ const pullCommand = new Command("pull")
372
252
  "--stage <stage>",
373
253
  "Which version of LangSmith to pull. Options: prod, dev, beta (default: prod)"
374
254
  )
255
+ .option(
256
+ "--version <version>",
257
+ "The LangSmith version to use for LangSmith. Defaults to latest." +
258
+ " We recommend pegging this to the latest static version available at" +
259
+ " https://hub.docker.com/repository/docker/langchain/langchainplus-backend" +
260
+ " if you are using Langsmith in production."
261
+ )
375
262
  .action(async (args) => {
376
263
  const smith = await SmithCommand.create();
377
- if (args.stage === "dev") {
378
- setEnvironmentVariable("_LANGSMITH_IMAGE_PREFIX", "dev-");
379
- } else if (args.stage === "beta") {
380
- setEnvironmentVariable("_LANGSMITH_IMAGE_PREFIX", "rc-");
381
- }
382
- await smith.pull({ stage: args.stage });
264
+ await smith.pull({ stage: args.stage, version: args.version });
383
265
  });
384
266
 
385
267
  const statusCommand = new Command("status")
package/dist/client.cjs CHANGED
@@ -145,6 +145,10 @@ class Client {
145
145
  this.webUrl = "http://localhost";
146
146
  return "http://localhost";
147
147
  }
148
+ else if (this.apiUrl.includes("/api")) {
149
+ this.webUrl = this.apiUrl.replace("/api", "");
150
+ return this.webUrl;
151
+ }
148
152
  else if (this.apiUrl.split(".", 1)[0].includes("dev")) {
149
153
  this.webUrl = "https://dev.smith.langchain.com";
150
154
  return "https://dev.smith.langchain.com";
package/dist/client.js CHANGED
@@ -119,6 +119,10 @@ export class Client {
119
119
  this.webUrl = "http://localhost";
120
120
  return "http://localhost";
121
121
  }
122
+ else if (this.apiUrl.includes("/api")) {
123
+ this.webUrl = this.apiUrl.replace("/api", "");
124
+ return this.webUrl;
125
+ }
122
126
  else if (this.apiUrl.split(".", 1)[0].includes("dev")) {
123
127
  this.webUrl = "https://dev.smith.langchain.com";
124
128
  return "https://dev.smith.langchain.com";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langsmith",
3
- "version": "0.0.49",
3
+ "version": "0.0.50",
4
4
  "description": "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform.",
5
5
  "files": [
6
6
  "dist/",
@@ -1,19 +0,0 @@
1
- version: '3'
2
- services:
3
- # TODO: Move to the regular docker-compose.yaml once deployed
4
- langchain-hub:
5
- image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainhub-backend:latest
6
- environment:
7
- - PORT=1985
8
- - LANGCHAIN_ENV=local_docker
9
- - LOG_LEVEL=warning
10
- - LANGSMITH_LICENSE_KEY=${LANGSMITH_LICENSE_KEY}
11
- ports:
12
- - 1985:1985
13
- depends_on:
14
- - langchain-db
15
- langchain-db:
16
- volumes:
17
- - rc-langchain-db-data:/var/lib/postgresql/data
18
- volumes:
19
- rc-langchain-db-data:
@@ -1,19 +0,0 @@
1
- version: '3'
2
- services:
3
- # TODO: Move to the regular docker-compose.yaml once deployed
4
- langchain-hub:
5
- image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainhub-backend:latest
6
- environment:
7
- - PORT=1985
8
- - LANGCHAIN_ENV=local_docker
9
- - LOG_LEVEL=warning
10
- - LANGSMITH_LICENSE_KEY=${LANGSMITH_LICENSE_KEY}
11
- ports:
12
- - 1985:1985
13
- depends_on:
14
- - langchain-db
15
- langchain-db:
16
- volumes:
17
- - dev-langchain-db-data:/var/lib/postgresql/data
18
- volumes:
19
- dev-langchain-db-data:
@@ -1,17 +0,0 @@
1
- version: '3'
2
- services:
3
- ngrok:
4
- image: ngrok/ngrok:latest
5
- restart: unless-stopped
6
- command:
7
- - "start"
8
- - "--all"
9
- - "--config"
10
- - "/etc/ngrok.yml"
11
- volumes:
12
- - ./ngrok_config.yaml:/etc/ngrok.yml
13
- ports:
14
- - 4040:4040
15
- langchain-backend:
16
- depends_on:
17
- - ngrok