langsmith 0.0.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.
- package/README.md +262 -0
- package/client.cjs +1 -0
- package/client.d.ts +1 -0
- package/client.js +1 -0
- package/dist/cli/docker-compose.ngrok.yaml +17 -0
- package/dist/cli/docker-compose.yaml +43 -0
- package/dist/cli/main.cjs +278 -0
- package/dist/cli/main.d.ts +1 -0
- package/dist/cli/main.js +252 -0
- package/dist/cli/main.ts +292 -0
- package/dist/client.cjs +588 -0
- package/dist/client.d.ts +130 -0
- package/dist/client.js +561 -0
- package/dist/evaluation/evaluator.cjs +2 -0
- package/dist/evaluation/evaluator.d.ts +12 -0
- package/dist/evaluation/evaluator.js +1 -0
- package/dist/evaluation/index.cjs +5 -0
- package/dist/evaluation/index.d.ts +2 -0
- package/dist/evaluation/index.js +1 -0
- package/dist/evaluation/string_evaluator.cjs +66 -0
- package/dist/evaluation/string_evaluator.d.ts +30 -0
- package/dist/evaluation/string_evaluator.js +62 -0
- package/dist/index.cjs +7 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/dist/run_trees.cjs +232 -0
- package/dist/run_trees.d.ts +47 -0
- package/dist/run_trees.js +205 -0
- package/dist/schemas.cjs +2 -0
- package/dist/schemas.d.ts +117 -0
- package/dist/schemas.js +1 -0
- package/dist/utils/async_caller.cjs +111 -0
- package/dist/utils/async_caller.d.ts +37 -0
- package/dist/utils/async_caller.js +104 -0
- package/dist/utils/env.cjs +80 -0
- package/dist/utils/env.d.ts +22 -0
- package/dist/utils/env.js +68 -0
- package/evaluation.cjs +1 -0
- package/evaluation.d.ts +1 -0
- package/evaluation.js +1 -0
- package/index.cjs +1 -0
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/package.json +121 -0
- package/run_trees.cjs +1 -0
- package/run_trees.d.ts +1 -0
- package/run_trees.js +1 -0
- package/schemas.cjs +1 -0
- package/schemas.d.ts +1 -0
- package/schemas.js +1 -0
package/dist/cli/main.js
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import * as util from "util";
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
import * as child_process from "child_process";
|
|
6
|
+
import { setEnvironmentVariable } from "../utils/env.js";
|
|
7
|
+
const currentFileName = __filename;
|
|
8
|
+
const currentDirName = __dirname;
|
|
9
|
+
const exec = util.promisify(child_process.exec);
|
|
10
|
+
const program = new Command();
|
|
11
|
+
async function getDockerComposeCommand() {
|
|
12
|
+
try {
|
|
13
|
+
await exec("docker compose --version");
|
|
14
|
+
return ["docker", "compose"];
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
try {
|
|
18
|
+
await exec("docker-compose --version");
|
|
19
|
+
return ["docker-compose"];
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
throw new Error("Neither 'docker compose' nor 'docker-compose' commands are available. Please install the Docker server following the instructions for your operating system at https://docs.docker.com/engine/install/");
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
async function pprintServices(servicesStatus) {
|
|
27
|
+
const services = [];
|
|
28
|
+
for (const service of servicesStatus) {
|
|
29
|
+
const serviceStatus = {
|
|
30
|
+
Service: String(service["Service"]),
|
|
31
|
+
Status: String(service["Status"]),
|
|
32
|
+
};
|
|
33
|
+
const publishers = service["Publishers"] || [];
|
|
34
|
+
if (publishers) {
|
|
35
|
+
serviceStatus["PublishedPorts"] = publishers
|
|
36
|
+
.map((publisher) => String(publisher["PublishedPort"]))
|
|
37
|
+
.join(", ");
|
|
38
|
+
}
|
|
39
|
+
services.push(serviceStatus);
|
|
40
|
+
}
|
|
41
|
+
const maxServiceLen = Math.max(...services.map((service) => service["Service"].length));
|
|
42
|
+
const maxStateLen = Math.max(...services.map((service) => service["Status"].length));
|
|
43
|
+
const serviceMessage = [
|
|
44
|
+
"\n" +
|
|
45
|
+
"Service".padEnd(maxServiceLen + 2) +
|
|
46
|
+
"Status".padEnd(maxStateLen + 2) +
|
|
47
|
+
"Published Ports",
|
|
48
|
+
];
|
|
49
|
+
for (const service of services) {
|
|
50
|
+
const serviceStr = service["Service"].padEnd(maxServiceLen + 2);
|
|
51
|
+
const stateStr = service["Status"].padEnd(maxStateLen + 2);
|
|
52
|
+
const portsStr = service["PublishedPorts"] || "";
|
|
53
|
+
serviceMessage.push(serviceStr + stateStr + portsStr);
|
|
54
|
+
}
|
|
55
|
+
let langchainEndpoint = "http://localhost:1984";
|
|
56
|
+
const usedNgrok = services.some((service) => service["Service"].includes("ngrok"));
|
|
57
|
+
if (usedNgrok) {
|
|
58
|
+
langchainEndpoint = await getNgrokUrl();
|
|
59
|
+
}
|
|
60
|
+
serviceMessage.push("\nTo connect, set the following environment variables" +
|
|
61
|
+
" in your LangChain application:" +
|
|
62
|
+
"\nLANGCHAIN_TRACING_V2=true" +
|
|
63
|
+
`\nLANGCHAIN_ENDPOINT=${langchainEndpoint}`);
|
|
64
|
+
console.info(serviceMessage.join("\n"));
|
|
65
|
+
}
|
|
66
|
+
async function getNgrokUrl() {
|
|
67
|
+
const ngrokUrl = "http://localhost:4040/api/tunnels";
|
|
68
|
+
try {
|
|
69
|
+
// const response = await axios.get(ngrokUrl);
|
|
70
|
+
const response = await fetch(ngrokUrl);
|
|
71
|
+
if (response.status !== 200) {
|
|
72
|
+
throw new Error(`Could not connect to ngrok console. ${response.status}, ${response.statusText}`);
|
|
73
|
+
}
|
|
74
|
+
const result = await response.json();
|
|
75
|
+
const exposedUrl = result["tunnels"][0]["public_url"];
|
|
76
|
+
return exposedUrl;
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
throw new Error(`Could not connect to ngrok console. ${error}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async function createNgrokConfig(authToken) {
|
|
83
|
+
const configPath = path.join(currentDirName, "ngrok_config.yaml");
|
|
84
|
+
// Check if is a directory
|
|
85
|
+
if (fs.existsSync(configPath) && fs.lstatSync(configPath).isDirectory()) {
|
|
86
|
+
fs.rmdirSync(configPath, { recursive: true });
|
|
87
|
+
}
|
|
88
|
+
else if (fs.existsSync(configPath)) {
|
|
89
|
+
fs.unlinkSync(configPath);
|
|
90
|
+
}
|
|
91
|
+
let ngrokConfig = `
|
|
92
|
+
region: us
|
|
93
|
+
tunnels:
|
|
94
|
+
langchain:
|
|
95
|
+
addr: langchain-backend:1984
|
|
96
|
+
proto: http
|
|
97
|
+
version: '2'
|
|
98
|
+
`;
|
|
99
|
+
if (authToken !== null) {
|
|
100
|
+
ngrokConfig += `authtoken: ${authToken}`;
|
|
101
|
+
}
|
|
102
|
+
fs.writeFileSync(configPath, ngrokConfig);
|
|
103
|
+
return configPath;
|
|
104
|
+
}
|
|
105
|
+
class PlusCommand {
|
|
106
|
+
constructor({ dockerComposeCommand }) {
|
|
107
|
+
Object.defineProperty(this, "dockerComposeCommand", {
|
|
108
|
+
enumerable: true,
|
|
109
|
+
configurable: true,
|
|
110
|
+
writable: true,
|
|
111
|
+
value: []
|
|
112
|
+
});
|
|
113
|
+
Object.defineProperty(this, "dockerComposeFile", {
|
|
114
|
+
enumerable: true,
|
|
115
|
+
configurable: true,
|
|
116
|
+
writable: true,
|
|
117
|
+
value: ""
|
|
118
|
+
});
|
|
119
|
+
Object.defineProperty(this, "ngrokPath", {
|
|
120
|
+
enumerable: true,
|
|
121
|
+
configurable: true,
|
|
122
|
+
writable: true,
|
|
123
|
+
value: ""
|
|
124
|
+
});
|
|
125
|
+
this.dockerComposeCommand = dockerComposeCommand;
|
|
126
|
+
this.dockerComposeFile = path.join(path.dirname(currentFileName), "docker-compose.yaml");
|
|
127
|
+
this.ngrokPath = path.join(path.dirname(currentFileName), "docker-compose.ngrok.yaml");
|
|
128
|
+
}
|
|
129
|
+
static async create() {
|
|
130
|
+
const dockerComposeCommand = await getDockerComposeCommand();
|
|
131
|
+
return new PlusCommand({ dockerComposeCommand });
|
|
132
|
+
}
|
|
133
|
+
async start(args) {
|
|
134
|
+
if (args.dev) {
|
|
135
|
+
setEnvironmentVariable("_LANGCHAINPLUS_IMAGE_PREFIX", "rc-");
|
|
136
|
+
}
|
|
137
|
+
if (args.openaiApiKey) {
|
|
138
|
+
setEnvironmentVariable("OPENAI_API_KEY", args.openaiApiKey);
|
|
139
|
+
}
|
|
140
|
+
if (args.expose) {
|
|
141
|
+
await this.startAndExpose(args.ngrokAuthtoken);
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
await this.startLocal();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
async pull(args) {
|
|
148
|
+
if (args.dev) {
|
|
149
|
+
setEnvironmentVariable("_LANGCHAINPLUS_IMAGE_PREFIX", "rc-");
|
|
150
|
+
}
|
|
151
|
+
const command = [
|
|
152
|
+
...this.dockerComposeCommand,
|
|
153
|
+
"-f",
|
|
154
|
+
this.dockerComposeFile,
|
|
155
|
+
"pull",
|
|
156
|
+
];
|
|
157
|
+
await exec(command.join(" "));
|
|
158
|
+
}
|
|
159
|
+
async startLocal() {
|
|
160
|
+
const command = [
|
|
161
|
+
...this.dockerComposeCommand,
|
|
162
|
+
"-f",
|
|
163
|
+
this.dockerComposeFile,
|
|
164
|
+
"up",
|
|
165
|
+
"--pull=always",
|
|
166
|
+
"--quiet-pull",
|
|
167
|
+
"--wait",
|
|
168
|
+
];
|
|
169
|
+
await exec(command.join(" "));
|
|
170
|
+
console.info("LangSmith server is running at http://localhost:1984. To connect locally, set the following environment variable when running your LangChain application.");
|
|
171
|
+
console.info("\tLANGCHAIN_TRACING_V2=true");
|
|
172
|
+
}
|
|
173
|
+
async startAndExpose(ngrokAuthToken) {
|
|
174
|
+
const configPath = await createNgrokConfig(ngrokAuthToken);
|
|
175
|
+
const command = [
|
|
176
|
+
...this.dockerComposeCommand,
|
|
177
|
+
"-f",
|
|
178
|
+
this.dockerComposeFile,
|
|
179
|
+
"-f",
|
|
180
|
+
this.ngrokPath,
|
|
181
|
+
"up",
|
|
182
|
+
"--pull=always",
|
|
183
|
+
"--quiet-pull",
|
|
184
|
+
"--wait",
|
|
185
|
+
];
|
|
186
|
+
await exec(command.join(" "));
|
|
187
|
+
console.info("ngrok is running. You can view the dashboard at http://0.0.0.0:4040");
|
|
188
|
+
const ngrokUrl = await getNgrokUrl();
|
|
189
|
+
console.info("LangSmith server is running at http://localhost:1984. To connect remotely, set the following environment variable when running your LangChain application.");
|
|
190
|
+
console.info("\tLANGCHAIN_TRACING_V2=true");
|
|
191
|
+
console.info(`\tLANGCHAIN_ENDPOINT=${ngrokUrl}`);
|
|
192
|
+
fs.unlinkSync(configPath);
|
|
193
|
+
}
|
|
194
|
+
async stop() {
|
|
195
|
+
const command = [
|
|
196
|
+
...this.dockerComposeCommand,
|
|
197
|
+
"-f",
|
|
198
|
+
this.dockerComposeFile,
|
|
199
|
+
"-f",
|
|
200
|
+
this.ngrokPath,
|
|
201
|
+
"down",
|
|
202
|
+
];
|
|
203
|
+
await exec(command.join(" "));
|
|
204
|
+
}
|
|
205
|
+
async status() {
|
|
206
|
+
const command = [
|
|
207
|
+
...this.dockerComposeCommand,
|
|
208
|
+
"-f",
|
|
209
|
+
this.dockerComposeFile,
|
|
210
|
+
"ps",
|
|
211
|
+
"--format",
|
|
212
|
+
"json",
|
|
213
|
+
];
|
|
214
|
+
const result = await exec(command.join(" "));
|
|
215
|
+
const servicesStatus = JSON.parse(result.stdout);
|
|
216
|
+
if (servicesStatus) {
|
|
217
|
+
console.info("The LangSmith server is currently running.");
|
|
218
|
+
await pprintServices(servicesStatus);
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
console.info("The LangSmith server is not running.");
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
const startCommand = new Command("start")
|
|
226
|
+
.description("Start the LangSmith server")
|
|
227
|
+
.option("--expose", "Expose the server to the internet via ngrok (requires ngrok to be installed)")
|
|
228
|
+
.option("--ngrok-authtoken <ngrokAuthtoken>", "Your ngrok auth token. If this is set, --expose is implied.")
|
|
229
|
+
.option("--dev", "Run the development version of the LangSmith server")
|
|
230
|
+
.option("--openai-api-key <openaiApiKey>", "Your OpenAI API key. If this is set, the server will be able to process text and return enhanced plus results.")
|
|
231
|
+
.action(async (args) => (await PlusCommand.create()).start(args));
|
|
232
|
+
const stopCommand = new Command("stop")
|
|
233
|
+
.command("stop")
|
|
234
|
+
.description("Stop the LangSmith server")
|
|
235
|
+
.action(async () => (await PlusCommand.create()).stop());
|
|
236
|
+
const pullCommand = new Command("pull")
|
|
237
|
+
.command("pull")
|
|
238
|
+
.description("Pull the latest version of the LangSmith server")
|
|
239
|
+
.option("--dev", "Pull the development version of the LangSmith server")
|
|
240
|
+
.action(async (args) => (await PlusCommand.create()).pull(args));
|
|
241
|
+
const statusCommand = new Command("status")
|
|
242
|
+
.command("status")
|
|
243
|
+
.description("Get the status of the LangSmith server")
|
|
244
|
+
.action(async () => (await PlusCommand.create()).status());
|
|
245
|
+
program
|
|
246
|
+
.command("plus")
|
|
247
|
+
.description("Manage the LangSmith server")
|
|
248
|
+
.addCommand(startCommand)
|
|
249
|
+
.addCommand(stopCommand)
|
|
250
|
+
.addCommand(pullCommand)
|
|
251
|
+
.addCommand(statusCommand);
|
|
252
|
+
program.parse(process.argv);
|
package/dist/cli/main.ts
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import * as util from "util";
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
import * as child_process from "child_process";
|
|
6
|
+
import { setEnvironmentVariable } from "../utils/env.js";
|
|
7
|
+
|
|
8
|
+
const currentFileName = __filename;
|
|
9
|
+
const currentDirName = __dirname;
|
|
10
|
+
|
|
11
|
+
const exec = util.promisify(child_process.exec);
|
|
12
|
+
|
|
13
|
+
const program = new Command();
|
|
14
|
+
|
|
15
|
+
async function getDockerComposeCommand(): Promise<string[]> {
|
|
16
|
+
try {
|
|
17
|
+
await exec("docker compose --version");
|
|
18
|
+
return ["docker", "compose"];
|
|
19
|
+
} catch {
|
|
20
|
+
try {
|
|
21
|
+
await exec("docker-compose --version");
|
|
22
|
+
return ["docker-compose"];
|
|
23
|
+
} catch {
|
|
24
|
+
throw new Error(
|
|
25
|
+
"Neither 'docker compose' nor 'docker-compose' commands are available. Please install the Docker server following the instructions for your operating system at https://docs.docker.com/engine/install/"
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function pprintServices(servicesStatus: any[]) {
|
|
32
|
+
const services = [];
|
|
33
|
+
for (const service of servicesStatus) {
|
|
34
|
+
const serviceStatus: Record<string, string> = {
|
|
35
|
+
Service: String(service["Service"]),
|
|
36
|
+
Status: String(service["Status"]),
|
|
37
|
+
};
|
|
38
|
+
const publishers = service["Publishers"] || [];
|
|
39
|
+
if (publishers) {
|
|
40
|
+
serviceStatus["PublishedPorts"] = publishers
|
|
41
|
+
.map((publisher: any) => String(publisher["PublishedPort"]))
|
|
42
|
+
.join(", ");
|
|
43
|
+
}
|
|
44
|
+
services.push(serviceStatus);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const maxServiceLen = Math.max(
|
|
48
|
+
...services.map((service) => service["Service"].length)
|
|
49
|
+
);
|
|
50
|
+
const maxStateLen = Math.max(
|
|
51
|
+
...services.map((service) => service["Status"].length)
|
|
52
|
+
);
|
|
53
|
+
const serviceMessage = [
|
|
54
|
+
"\n" +
|
|
55
|
+
"Service".padEnd(maxServiceLen + 2) +
|
|
56
|
+
"Status".padEnd(maxStateLen + 2) +
|
|
57
|
+
"Published Ports",
|
|
58
|
+
];
|
|
59
|
+
for (const service of services) {
|
|
60
|
+
const serviceStr = service["Service"].padEnd(maxServiceLen + 2);
|
|
61
|
+
const stateStr = service["Status"].padEnd(maxStateLen + 2);
|
|
62
|
+
const portsStr = service["PublishedPorts"] || "";
|
|
63
|
+
serviceMessage.push(serviceStr + stateStr + portsStr);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let langchainEndpoint = "http://localhost:1984";
|
|
67
|
+
const usedNgrok = services.some((service) =>
|
|
68
|
+
service["Service"].includes("ngrok")
|
|
69
|
+
);
|
|
70
|
+
if (usedNgrok) {
|
|
71
|
+
langchainEndpoint = await getNgrokUrl();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
serviceMessage.push(
|
|
75
|
+
"\nTo connect, set the following environment variables" +
|
|
76
|
+
" in your LangChain application:" +
|
|
77
|
+
"\nLANGCHAIN_TRACING_V2=true" +
|
|
78
|
+
`\nLANGCHAIN_ENDPOINT=${langchainEndpoint}`
|
|
79
|
+
);
|
|
80
|
+
console.info(serviceMessage.join("\n"));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async function getNgrokUrl(): Promise<string> {
|
|
84
|
+
const ngrokUrl = "http://localhost:4040/api/tunnels";
|
|
85
|
+
try {
|
|
86
|
+
// const response = await axios.get(ngrokUrl);
|
|
87
|
+
const response = await fetch(ngrokUrl);
|
|
88
|
+
if (response.status !== 200) {
|
|
89
|
+
throw new Error(
|
|
90
|
+
`Could not connect to ngrok console. ${response.status}, ${response.statusText}`
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
const result = await response.json();
|
|
94
|
+
const exposedUrl = result["tunnels"][0]["public_url"];
|
|
95
|
+
return exposedUrl;
|
|
96
|
+
} catch (error) {
|
|
97
|
+
throw new Error(`Could not connect to ngrok console. ${error}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async function createNgrokConfig(authToken: string | null): Promise<string> {
|
|
102
|
+
const configPath = path.join(currentDirName, "ngrok_config.yaml");
|
|
103
|
+
// Check if is a directory
|
|
104
|
+
if (fs.existsSync(configPath) && fs.lstatSync(configPath).isDirectory()) {
|
|
105
|
+
fs.rmdirSync(configPath, { recursive: true });
|
|
106
|
+
} else if (fs.existsSync(configPath)) {
|
|
107
|
+
fs.unlinkSync(configPath);
|
|
108
|
+
}
|
|
109
|
+
let ngrokConfig = `
|
|
110
|
+
region: us
|
|
111
|
+
tunnels:
|
|
112
|
+
langchain:
|
|
113
|
+
addr: langchain-backend:1984
|
|
114
|
+
proto: http
|
|
115
|
+
version: '2'
|
|
116
|
+
`;
|
|
117
|
+
|
|
118
|
+
if (authToken !== null) {
|
|
119
|
+
ngrokConfig += `authtoken: ${authToken}`;
|
|
120
|
+
}
|
|
121
|
+
fs.writeFileSync(configPath, ngrokConfig);
|
|
122
|
+
return configPath;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
class PlusCommand {
|
|
126
|
+
dockerComposeCommand: string[] = [];
|
|
127
|
+
dockerComposeFile = "";
|
|
128
|
+
ngrokPath = "";
|
|
129
|
+
|
|
130
|
+
constructor({ dockerComposeCommand }: { dockerComposeCommand: string[] }) {
|
|
131
|
+
this.dockerComposeCommand = dockerComposeCommand;
|
|
132
|
+
this.dockerComposeFile = path.join(
|
|
133
|
+
path.dirname(currentFileName),
|
|
134
|
+
"docker-compose.yaml"
|
|
135
|
+
);
|
|
136
|
+
this.ngrokPath = path.join(
|
|
137
|
+
path.dirname(currentFileName),
|
|
138
|
+
"docker-compose.ngrok.yaml"
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
public static async create() {
|
|
143
|
+
const dockerComposeCommand = await getDockerComposeCommand();
|
|
144
|
+
return new PlusCommand({ dockerComposeCommand });
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async start(args: any) {
|
|
148
|
+
if (args.dev) {
|
|
149
|
+
setEnvironmentVariable("_LANGCHAINPLUS_IMAGE_PREFIX", "rc-");
|
|
150
|
+
}
|
|
151
|
+
if (args.openaiApiKey) {
|
|
152
|
+
setEnvironmentVariable("OPENAI_API_KEY", args.openaiApiKey);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (args.expose) {
|
|
156
|
+
await this.startAndExpose(args.ngrokAuthtoken);
|
|
157
|
+
} else {
|
|
158
|
+
await this.startLocal();
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
async pull(args: any) {
|
|
163
|
+
if (args.dev) {
|
|
164
|
+
setEnvironmentVariable("_LANGCHAINPLUS_IMAGE_PREFIX", "rc-");
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const command = [
|
|
168
|
+
...this.dockerComposeCommand,
|
|
169
|
+
"-f",
|
|
170
|
+
this.dockerComposeFile,
|
|
171
|
+
"pull",
|
|
172
|
+
];
|
|
173
|
+
await exec(command.join(" "));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
async startLocal() {
|
|
177
|
+
const command = [
|
|
178
|
+
...this.dockerComposeCommand,
|
|
179
|
+
"-f",
|
|
180
|
+
this.dockerComposeFile,
|
|
181
|
+
"up",
|
|
182
|
+
"--pull=always",
|
|
183
|
+
"--quiet-pull",
|
|
184
|
+
"--wait",
|
|
185
|
+
];
|
|
186
|
+
await exec(command.join(" "));
|
|
187
|
+
console.info(
|
|
188
|
+
"LangSmith server is running at http://localhost:1984. To connect locally, set the following environment variable when running your LangChain application."
|
|
189
|
+
);
|
|
190
|
+
console.info("\tLANGCHAIN_TRACING_V2=true");
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async startAndExpose(ngrokAuthToken: string | null) {
|
|
194
|
+
const configPath = await createNgrokConfig(ngrokAuthToken);
|
|
195
|
+
const command = [
|
|
196
|
+
...this.dockerComposeCommand,
|
|
197
|
+
"-f",
|
|
198
|
+
this.dockerComposeFile,
|
|
199
|
+
"-f",
|
|
200
|
+
this.ngrokPath,
|
|
201
|
+
"up",
|
|
202
|
+
"--pull=always",
|
|
203
|
+
"--quiet-pull",
|
|
204
|
+
"--wait",
|
|
205
|
+
];
|
|
206
|
+
await exec(command.join(" "));
|
|
207
|
+
console.info(
|
|
208
|
+
"ngrok is running. You can view the dashboard at http://0.0.0.0:4040"
|
|
209
|
+
);
|
|
210
|
+
const ngrokUrl = await getNgrokUrl();
|
|
211
|
+
console.info(
|
|
212
|
+
"LangSmith server is running at http://localhost:1984. To connect remotely, set the following environment variable when running your LangChain application."
|
|
213
|
+
);
|
|
214
|
+
console.info("\tLANGCHAIN_TRACING_V2=true");
|
|
215
|
+
console.info(`\tLANGCHAIN_ENDPOINT=${ngrokUrl}`);
|
|
216
|
+
|
|
217
|
+
fs.unlinkSync(configPath);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
async stop() {
|
|
221
|
+
const command = [
|
|
222
|
+
...this.dockerComposeCommand,
|
|
223
|
+
"-f",
|
|
224
|
+
this.dockerComposeFile,
|
|
225
|
+
"-f",
|
|
226
|
+
this.ngrokPath,
|
|
227
|
+
"down",
|
|
228
|
+
];
|
|
229
|
+
await exec(command.join(" "));
|
|
230
|
+
}
|
|
231
|
+
async status() {
|
|
232
|
+
const command = [
|
|
233
|
+
...this.dockerComposeCommand,
|
|
234
|
+
"-f",
|
|
235
|
+
this.dockerComposeFile,
|
|
236
|
+
"ps",
|
|
237
|
+
"--format",
|
|
238
|
+
"json",
|
|
239
|
+
];
|
|
240
|
+
const result = await exec(command.join(" "));
|
|
241
|
+
const servicesStatus = JSON.parse(result.stdout);
|
|
242
|
+
if (servicesStatus) {
|
|
243
|
+
console.info("The LangSmith server is currently running.");
|
|
244
|
+
await pprintServices(servicesStatus);
|
|
245
|
+
} else {
|
|
246
|
+
console.info("The LangSmith server is not running.");
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const startCommand = new Command("start")
|
|
252
|
+
.description("Start the LangSmith server")
|
|
253
|
+
.option(
|
|
254
|
+
"--expose",
|
|
255
|
+
"Expose the server to the internet via ngrok (requires ngrok to be installed)"
|
|
256
|
+
)
|
|
257
|
+
.option(
|
|
258
|
+
"--ngrok-authtoken <ngrokAuthtoken>",
|
|
259
|
+
"Your ngrok auth token. If this is set, --expose is implied."
|
|
260
|
+
)
|
|
261
|
+
.option("--dev", "Run the development version of the LangSmith server")
|
|
262
|
+
.option(
|
|
263
|
+
"--openai-api-key <openaiApiKey>",
|
|
264
|
+
"Your OpenAI API key. If this is set, the server will be able to process text and return enhanced plus results."
|
|
265
|
+
)
|
|
266
|
+
.action(async (args: string[]) => (await PlusCommand.create()).start(args));
|
|
267
|
+
|
|
268
|
+
const stopCommand = new Command("stop")
|
|
269
|
+
.command("stop")
|
|
270
|
+
.description("Stop the LangSmith server")
|
|
271
|
+
.action(async () => (await PlusCommand.create()).stop());
|
|
272
|
+
|
|
273
|
+
const pullCommand = new Command("pull")
|
|
274
|
+
.command("pull")
|
|
275
|
+
.description("Pull the latest version of the LangSmith server")
|
|
276
|
+
.option("--dev", "Pull the development version of the LangSmith server")
|
|
277
|
+
.action(async (args: string[]) => (await PlusCommand.create()).pull(args));
|
|
278
|
+
|
|
279
|
+
const statusCommand = new Command("status")
|
|
280
|
+
.command("status")
|
|
281
|
+
.description("Get the status of the LangSmith server")
|
|
282
|
+
.action(async () => (await PlusCommand.create()).status());
|
|
283
|
+
|
|
284
|
+
program
|
|
285
|
+
.command("plus")
|
|
286
|
+
.description("Manage the LangSmith server")
|
|
287
|
+
.addCommand(startCommand)
|
|
288
|
+
.addCommand(stopCommand)
|
|
289
|
+
.addCommand(pullCommand)
|
|
290
|
+
.addCommand(statusCommand);
|
|
291
|
+
|
|
292
|
+
program.parse(process.argv);
|