Severian's picture
Upload 7464 files
c211499
raw
history blame
37.9 kB
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Client = void 0;
const uuid = __importStar(require("uuid"));
const async_caller_js_1 = require("./utils/async_caller.cjs");
const messages_js_1 = require("./utils/messages.cjs");
const env_js_1 = require("./utils/env.cjs");
// utility functions
const isLocalhost = (url) => {
const strippedUrl = url.replace("http://", "").replace("https://", "");
const hostname = strippedUrl.split("/")[0].split(":")[0];
return (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1");
};
const raiseForStatus = async (response, operation) => {
// consume the response body to release the connection
// https://undici.nodejs.org/#/?id=garbage-collection
const body = await response.text();
if (!response.ok) {
throw new Error(`Failed to ${operation}: ${response.status} ${response.statusText} ${body}`);
}
};
async function toArray(iterable) {
const result = [];
for await (const item of iterable) {
result.push(item);
}
return result;
}
function trimQuotes(str) {
if (str === undefined) {
return undefined;
}
return str
.trim()
.replace(/^"(.*)"$/, "$1")
.replace(/^'(.*)'$/, "$1");
}
function hideInputs(inputs) {
if ((0, env_js_1.getEnvironmentVariable)("LANGCHAIN_HIDE_INPUTS") === "true") {
return {};
}
return inputs;
}
function hideOutputs(outputs) {
if ((0, env_js_1.getEnvironmentVariable)("LANGCHAIN_HIDE_OUTPUTS") === "true") {
return {};
}
return outputs;
}
function assertUuid(str) {
if (!uuid.validate(str)) {
throw new Error(`Invalid UUID: ${str}`);
}
}
class Client {
constructor(config = {}) {
Object.defineProperty(this, "apiKey", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "apiUrl", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "webUrl", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "caller", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "timeout_ms", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "_tenantId", {
enumerable: true,
configurable: true,
writable: true,
value: null
});
const defaultConfig = Client.getDefaultClientConfig();
this.apiUrl = trimQuotes(config.apiUrl ?? defaultConfig.apiUrl) ?? "";
this.apiKey = trimQuotes(config.apiKey ?? defaultConfig.apiKey);
this.webUrl = trimQuotes(config.webUrl ?? defaultConfig.webUrl);
this.validateApiKeyIfHosted();
this.timeout_ms = config.timeout_ms ?? 4000;
this.caller = new async_caller_js_1.AsyncCaller(config.callerOptions ?? {});
}
static getDefaultClientConfig() {
const apiKey = (0, env_js_1.getEnvironmentVariable)("LANGCHAIN_API_KEY");
const apiUrl = (0, env_js_1.getEnvironmentVariable)("LANGCHAIN_ENDPOINT") ??
(apiKey ? "https://api.smith.langchain.com" : "http://localhost:1984");
return {
apiUrl: apiUrl,
apiKey: apiKey,
webUrl: undefined,
};
}
validateApiKeyIfHosted() {
const isLocal = isLocalhost(this.apiUrl);
if (!isLocal && !this.apiKey) {
throw new Error("API key must be provided when using hosted LangSmith API");
}
}
getHostUrl() {
if (this.webUrl) {
return this.webUrl;
}
else if (isLocalhost(this.apiUrl)) {
this.webUrl = "http://localhost";
return "http://localhost";
}
else if (this.apiUrl.split(".", 1)[0].includes("dev")) {
this.webUrl = "https://dev.smith.langchain.com";
return "https://dev.smith.langchain.com";
}
else {
this.webUrl = "https://smith.langchain.com";
return "https://smith.langchain.com";
}
}
get headers() {
const headers = {};
if (this.apiKey) {
headers["x-api-key"] = `${this.apiKey}`;
}
return headers;
}
async _getResponse(path, queryParams) {
const paramsString = queryParams?.toString() ?? "";
const url = `${this.apiUrl}${path}?${paramsString}`;
const response = await this.caller.call(fetch, url, {
method: "GET",
headers: this.headers,
signal: AbortSignal.timeout(this.timeout_ms),
});
if (!response.ok) {
throw new Error(`Failed to fetch ${path}: ${response.status} ${response.statusText}`);
}
return response;
}
async _get(path, queryParams) {
const response = await this._getResponse(path, queryParams);
return response.json();
}
async *_getPaginated(path, queryParams = new URLSearchParams()) {
let offset = Number(queryParams.get("offset")) || 0;
const limit = Number(queryParams.get("limit")) || 100;
while (true) {
queryParams.set("offset", String(offset));
queryParams.set("limit", String(limit));
const url = `${this.apiUrl}${path}?${queryParams}`;
const response = await this.caller.call(fetch, url, {
method: "GET",
headers: this.headers,
signal: AbortSignal.timeout(this.timeout_ms),
});
if (!response.ok) {
throw new Error(`Failed to fetch ${path}: ${response.status} ${response.statusText}`);
}
const items = await response.json();
if (items.length === 0) {
break;
}
yield items;
if (items.length < limit) {
break;
}
offset += items.length;
}
}
async createRun(run) {
const headers = { ...this.headers, "Content-Type": "application/json" };
const extra = run.extra ?? {};
const runtimeEnv = await (0, env_js_1.getRuntimeEnvironment)();
const session_name = run.project_name;
delete run.project_name;
const runCreate = {
session_name,
...run,
extra: {
...run.extra,
runtime: {
...runtimeEnv,
...extra.runtime,
},
},
};
runCreate.inputs = hideInputs(runCreate.inputs);
if (runCreate.outputs) {
runCreate.outputs = hideOutputs(runCreate.outputs);
}
const response = await this.caller.call(fetch, `${this.apiUrl}/runs`, {
method: "POST",
headers,
body: JSON.stringify(runCreate),
signal: AbortSignal.timeout(this.timeout_ms),
});
await raiseForStatus(response, "create run");
}
async updateRun(runId, run) {
assertUuid(runId);
if (run.inputs) {
run.inputs = hideInputs(run.inputs);
}
if (run.outputs) {
run.outputs = hideOutputs(run.outputs);
}
const headers = { ...this.headers, "Content-Type": "application/json" };
const response = await this.caller.call(fetch, `${this.apiUrl}/runs/${runId}`, {
method: "PATCH",
headers,
body: JSON.stringify(run),
signal: AbortSignal.timeout(this.timeout_ms),
});
await raiseForStatus(response, "update run");
}
async readRun(runId, { loadChildRuns } = { loadChildRuns: false }) {
assertUuid(runId);
let run = await this._get(`/runs/${runId}`);
if (loadChildRuns && run.child_run_ids) {
run = await this._loadChildRuns(run);
}
return run;
}
async getRunUrl({ runId, run, projectOpts, }) {
if (run !== undefined) {
let sessionId;
if (run.session_id) {
sessionId = run.session_id;
}
else if (projectOpts?.projectName) {
sessionId = (await this.readProject({ projectName: projectOpts?.projectName })).id;
}
else if (projectOpts?.projectId) {
sessionId = projectOpts?.projectId;
}
else {
const project = await this.readProject({
projectName: (0, env_js_1.getEnvironmentVariable)("LANGCHAIN_PROJECT") || "default",
});
sessionId = project.id;
}
const tenantId = await this._getTenantId();
return `${this.getHostUrl()}/o/${tenantId}/projects/p/${sessionId}/r/${run.id}?poll=true`;
}
else if (runId !== undefined) {
const run_ = await this.readRun(runId);
if (!run_.app_path) {
throw new Error(`Run ${runId} has no app_path`);
}
const baseUrl = this.getHostUrl();
return `${baseUrl}${run_.app_path}`;
}
else {
throw new Error("Must provide either runId or run");
}
}
async _loadChildRuns(run) {
const childRuns = await toArray(this.listRuns({ id: run.child_run_ids }));
const treemap = {};
const runs = {};
// TODO: make dotted order required when the migration finishes
childRuns.sort((a, b) => (a?.dotted_order ?? "").localeCompare(b?.dotted_order ?? ""));
for (const childRun of childRuns) {
if (childRun.parent_run_id === null ||
childRun.parent_run_id === undefined) {
throw new Error(`Child run ${childRun.id} has no parent`);
}
if (!(childRun.parent_run_id in treemap)) {
treemap[childRun.parent_run_id] = [];
}
treemap[childRun.parent_run_id].push(childRun);
runs[childRun.id] = childRun;
}
run.child_runs = treemap[run.id] || [];
for (const runId in treemap) {
if (runId !== run.id) {
runs[runId].child_runs = treemap[runId];
}
}
return run;
}
async *listRuns({ projectId, projectName, parentRunId, referenceExampleId, startTime, executionOrder, runType, error, id, limit, offset, query, filter, }) {
const queryParams = new URLSearchParams();
let projectId_ = projectId;
if (projectName) {
if (projectId) {
throw new Error("Only one of projectId or projectName may be given");
}
projectId_ = (await this.readProject({ projectName })).id;
}
if (projectId_) {
queryParams.append("session", projectId_);
}
if (parentRunId) {
queryParams.append("parent_run", parentRunId);
}
if (referenceExampleId) {
queryParams.append("reference_example", referenceExampleId);
}
if (startTime) {
queryParams.append("start_time", startTime.toISOString());
}
if (executionOrder) {
queryParams.append("execution_order", executionOrder.toString());
}
if (runType) {
queryParams.append("run_type", runType);
}
if (error !== undefined) {
queryParams.append("error", error.toString());
}
if (id !== undefined) {
for (const id_ of id) {
queryParams.append("id", id_);
}
}
if (limit !== undefined) {
queryParams.append("limit", limit.toString());
}
if (offset !== undefined) {
queryParams.append("offset", offset.toString());
}
if (query !== undefined) {
queryParams.append("query", query);
}
if (filter !== undefined) {
queryParams.append("filter", filter);
}
for await (const runs of this._getPaginated("/runs", queryParams)) {
yield* runs;
}
}
async shareRun(runId, { shareId } = {}) {
const data = {
run_id: runId,
share_token: shareId || uuid.v4(),
};
assertUuid(runId);
const response = await this.caller.call(fetch, `${this.apiUrl}/runs/${runId}/share`, {
method: "PUT",
headers: this.headers,
body: JSON.stringify(data),
signal: AbortSignal.timeout(this.timeout_ms),
});
const result = await response.json();
if (result === null || !("share_token" in result)) {
throw new Error("Invalid response from server");
}
return `${this.getHostUrl()}/public/${result["share_token"]}/r`;
}
async unshareRun(runId) {
assertUuid(runId);
const response = await this.caller.call(fetch, `${this.apiUrl}/runs/${runId}/share`, {
method: "DELETE",
headers: this.headers,
signal: AbortSignal.timeout(this.timeout_ms),
});
await raiseForStatus(response, "unshare run");
}
async readRunSharedLink(runId) {
assertUuid(runId);
const response = await this.caller.call(fetch, `${this.apiUrl}/runs/${runId}/share`, {
method: "GET",
headers: this.headers,
signal: AbortSignal.timeout(this.timeout_ms),
});
const result = await response.json();
if (result === null || !("share_token" in result)) {
return undefined;
}
return `${this.getHostUrl()}/public/${result["share_token"]}/r`;
}
async listSharedRuns(shareToken, { runIds, } = {}) {
const queryParams = new URLSearchParams({
share_token: shareToken,
});
if (runIds !== undefined) {
for (const runId of runIds) {
queryParams.append("id", runId);
}
}
assertUuid(shareToken);
const response = await this.caller.call(fetch, `${this.apiUrl}/public/${shareToken}/runs${queryParams}`, {
method: "GET",
headers: this.headers,
signal: AbortSignal.timeout(this.timeout_ms),
});
const runs = await response.json();
return runs;
}
async readDatasetSharedSchema(datasetId, datasetName) {
if (!datasetId && !datasetName) {
throw new Error("Either datasetId or datasetName must be given");
}
if (!datasetId) {
const dataset = await this.readDataset({ datasetName });
datasetId = dataset.id;
}
assertUuid(datasetId);
const response = await this.caller.call(fetch, `${this.apiUrl}/datasets/${datasetId}/share`, {
method: "GET",
headers: this.headers,
signal: AbortSignal.timeout(this.timeout_ms),
});
const shareSchema = await response.json();
shareSchema.url = `${this.getHostUrl()}/public/${shareSchema.share_token}/d`;
return shareSchema;
}
async shareDataset(datasetId, datasetName) {
if (!datasetId && !datasetName) {
throw new Error("Either datasetId or datasetName must be given");
}
if (!datasetId) {
const dataset = await this.readDataset({ datasetName });
datasetId = dataset.id;
}
const data = {
dataset_id: datasetId,
};
assertUuid(datasetId);
const response = await this.caller.call(fetch, `${this.apiUrl}/datasets/${datasetId}/share`, {
method: "PUT",
headers: this.headers,
body: JSON.stringify(data),
signal: AbortSignal.timeout(this.timeout_ms),
});
const shareSchema = await response.json();
shareSchema.url = `${this.getHostUrl()}/public/${shareSchema.share_token}/d`;
return shareSchema;
}
async unshareDataset(datasetId) {
assertUuid(datasetId);
const response = await this.caller.call(fetch, `${this.apiUrl}/datasets/${datasetId}/share`, {
method: "DELETE",
headers: this.headers,
signal: AbortSignal.timeout(this.timeout_ms),
});
await raiseForStatus(response, "unshare dataset");
}
async readSharedDataset(shareToken) {
assertUuid(shareToken);
const response = await this.caller.call(fetch, `${this.apiUrl}/public/${shareToken}/datasets`, {
method: "GET",
headers: this.headers,
signal: AbortSignal.timeout(this.timeout_ms),
});
const dataset = await response.json();
return dataset;
}
async createProject({ projectName, projectExtra, upsert, referenceDatasetId, }) {
const upsert_ = upsert ? `?upsert=true` : "";
const endpoint = `${this.apiUrl}/sessions${upsert_}`;
const body = {
name: projectName,
};
if (projectExtra !== undefined) {
body["extra"] = projectExtra;
}
if (referenceDatasetId !== undefined) {
body["reference_dataset_id"] = referenceDatasetId;
}
const response = await this.caller.call(fetch, endpoint, {
method: "POST",
headers: { ...this.headers, "Content-Type": "application/json" },
body: JSON.stringify(body),
signal: AbortSignal.timeout(this.timeout_ms),
});
const result = await response.json();
if (!response.ok) {
throw new Error(`Failed to create session ${projectName}: ${response.status} ${response.statusText}`);
}
return result;
}
async readProject({ projectId, projectName, }) {
let path = "/sessions";
const params = new URLSearchParams();
if (projectId !== undefined && projectName !== undefined) {
throw new Error("Must provide either projectName or projectId, not both");
}
else if (projectId !== undefined) {
assertUuid(projectId);
path += `/${projectId}`;
}
else if (projectName !== undefined) {
params.append("name", projectName);
}
else {
throw new Error("Must provide projectName or projectId");
}
const response = await this._get(path, params);
let result;
if (Array.isArray(response)) {
if (response.length === 0) {
throw new Error(`Project[id=${projectId}, name=${projectName}] not found`);
}
result = response[0];
}
else {
result = response;
}
return result;
}
async _getTenantId() {
if (this._tenantId !== null) {
return this._tenantId;
}
const queryParams = new URLSearchParams({ limit: "1" });
for await (const projects of this._getPaginated("/sessions", queryParams)) {
this._tenantId = projects[0].tenant_id;
return projects[0].tenant_id;
}
throw new Error("No projects found to resolve tenant.");
}
async *listProjects({ projectIds, name, nameContains, referenceDatasetId, referenceDatasetName, referenceFree, } = {}) {
const params = new URLSearchParams();
if (projectIds !== undefined) {
for (const projectId of projectIds) {
params.append("id", projectId);
}
}
if (name !== undefined) {
params.append("name", name);
}
if (nameContains !== undefined) {
params.append("name_contains", nameContains);
}
if (referenceDatasetId !== undefined) {
params.append("reference_dataset", referenceDatasetId);
}
else if (referenceDatasetName !== undefined) {
const dataset = await this.readDataset({
datasetName: referenceDatasetName,
});
params.append("reference_dataset", dataset.id);
}
if (referenceFree !== undefined) {
params.append("reference_free", referenceFree.toString());
}
for await (const projects of this._getPaginated("/sessions", params)) {
yield* projects;
}
}
async deleteProject({ projectId, projectName, }) {
let projectId_;
if (projectId === undefined && projectName === undefined) {
throw new Error("Must provide projectName or projectId");
}
else if (projectId !== undefined && projectName !== undefined) {
throw new Error("Must provide either projectName or projectId, not both");
}
else if (projectId === undefined) {
projectId_ = (await this.readProject({ projectName })).id;
}
else {
projectId_ = projectId;
}
assertUuid(projectId_);
const response = await this.caller.call(fetch, `${this.apiUrl}/sessions/${projectId_}`, {
method: "DELETE",
headers: this.headers,
signal: AbortSignal.timeout(this.timeout_ms),
});
await raiseForStatus(response, `delete session ${projectId_} (${projectName})`);
}
async uploadCsv({ csvFile, fileName, inputKeys, outputKeys, description, dataType, name, }) {
const url = `${this.apiUrl}/datasets/upload`;
const formData = new FormData();
formData.append("file", csvFile, fileName);
inputKeys.forEach((key) => {
formData.append("input_keys", key);
});
outputKeys.forEach((key) => {
formData.append("output_keys", key);
});
if (description) {
formData.append("description", description);
}
if (dataType) {
formData.append("data_type", dataType);
}
if (name) {
formData.append("name", name);
}
const response = await this.caller.call(fetch, url, {
method: "POST",
headers: this.headers,
body: formData,
signal: AbortSignal.timeout(this.timeout_ms),
});
if (!response.ok) {
const result = await response.json();
if (result.detail && result.detail.includes("already exists")) {
throw new Error(`Dataset ${fileName} already exists`);
}
throw new Error(`Failed to upload CSV: ${response.status} ${response.statusText}`);
}
const result = await response.json();
return result;
}
async createDataset(name, { description, dataType, } = {}) {
const body = {
name,
description,
};
if (dataType) {
body.data_type = dataType;
}
const response = await this.caller.call(fetch, `${this.apiUrl}/datasets`, {
method: "POST",
headers: { ...this.headers, "Content-Type": "application/json" },
body: JSON.stringify(body),
signal: AbortSignal.timeout(this.timeout_ms),
});
if (!response.ok) {
const result = await response.json();
if (result.detail && result.detail.includes("already exists")) {
throw new Error(`Dataset ${name} already exists`);
}
throw new Error(`Failed to create dataset ${response.status} ${response.statusText}`);
}
const result = await response.json();
return result;
}
async readDataset({ datasetId, datasetName, }) {
let path = "/datasets";
// limit to 1 result
const params = new URLSearchParams({ limit: "1" });
if (datasetId !== undefined && datasetName !== undefined) {
throw new Error("Must provide either datasetName or datasetId, not both");
}
else if (datasetId !== undefined) {
assertUuid(datasetId);
path += `/${datasetId}`;
}
else if (datasetName !== undefined) {
params.append("name", datasetName);
}
else {
throw new Error("Must provide datasetName or datasetId");
}
const response = await this._get(path, params);
let result;
if (Array.isArray(response)) {
if (response.length === 0) {
throw new Error(`Dataset[id=${datasetId}, name=${datasetName}] not found`);
}
result = response[0];
}
else {
result = response;
}
return result;
}
async readDatasetOpenaiFinetuning({ datasetId, datasetName, }) {
const path = "/datasets";
if (datasetId !== undefined) {
// do nothing
}
else if (datasetName !== undefined) {
datasetId = (await this.readDataset({ datasetName })).id;
}
else {
throw new Error("Must provide datasetName or datasetId");
}
const response = await this._getResponse(`${path}/${datasetId}/openai_ft`);
const datasetText = await response.text();
const dataset = datasetText
.trim()
.split("\n")
.map((line) => JSON.parse(line));
return dataset;
}
async *listDatasets({ limit = 100, offset = 0, datasetIds, datasetName, datasetNameContains, } = {}) {
const path = "/datasets";
const params = new URLSearchParams({
limit: limit.toString(),
offset: offset.toString(),
});
if (datasetIds !== undefined) {
for (const id_ of datasetIds) {
params.append("id", id_);
}
}
if (datasetName !== undefined) {
params.append("name", datasetName);
}
if (datasetNameContains !== undefined) {
params.append("name_contains", datasetNameContains);
}
for await (const datasets of this._getPaginated(path, params)) {
yield* datasets;
}
}
async deleteDataset({ datasetId, datasetName, }) {
let path = "/datasets";
let datasetId_ = datasetId;
if (datasetId !== undefined && datasetName !== undefined) {
throw new Error("Must provide either datasetName or datasetId, not both");
}
else if (datasetName !== undefined) {
const dataset = await this.readDataset({ datasetName });
datasetId_ = dataset.id;
}
if (datasetId_ !== undefined) {
assertUuid(datasetId_);
path += `/${datasetId_}`;
}
else {
throw new Error("Must provide datasetName or datasetId");
}
const response = await this.caller.call(fetch, this.apiUrl + path, {
method: "DELETE",
headers: this.headers,
signal: AbortSignal.timeout(this.timeout_ms),
});
if (!response.ok) {
throw new Error(`Failed to delete ${path}: ${response.status} ${response.statusText}`);
}
await response.json();
}
async createExample(inputs, outputs, { datasetId, datasetName, createdAt, exampleId }) {
let datasetId_ = datasetId;
if (datasetId_ === undefined && datasetName === undefined) {
throw new Error("Must provide either datasetName or datasetId");
}
else if (datasetId_ !== undefined && datasetName !== undefined) {
throw new Error("Must provide either datasetName or datasetId, not both");
}
else if (datasetId_ === undefined) {
const dataset = await this.readDataset({ datasetName });
datasetId_ = dataset.id;
}
const createdAt_ = createdAt || new Date();
const data = {
dataset_id: datasetId_,
inputs,
outputs,
created_at: createdAt_.toISOString(),
id: exampleId,
};
const response = await this.caller.call(fetch, `${this.apiUrl}/examples`, {
method: "POST",
headers: { ...this.headers, "Content-Type": "application/json" },
body: JSON.stringify(data),
signal: AbortSignal.timeout(this.timeout_ms),
});
if (!response.ok) {
throw new Error(`Failed to create example: ${response.status} ${response.statusText}`);
}
const result = await response.json();
return result;
}
async createLLMExample(input, generation, options) {
return this.createExample({ input }, { output: generation }, options);
}
async createChatExample(input, generations, options) {
const finalInput = input.map((message) => {
if ((0, messages_js_1.isLangChainMessage)(message)) {
return (0, messages_js_1.convertLangChainMessageToExample)(message);
}
return message;
});
const finalOutput = (0, messages_js_1.isLangChainMessage)(generations)
? (0, messages_js_1.convertLangChainMessageToExample)(generations)
: generations;
return this.createExample({ input: finalInput }, { output: finalOutput }, options);
}
async readExample(exampleId) {
assertUuid(exampleId);
const path = `/examples/${exampleId}`;
return await this._get(path);
}
async *listExamples({ datasetId, datasetName, exampleIds, } = {}) {
let datasetId_;
if (datasetId !== undefined && datasetName !== undefined) {
throw new Error("Must provide either datasetName or datasetId, not both");
}
else if (datasetId !== undefined) {
datasetId_ = datasetId;
}
else if (datasetName !== undefined) {
const dataset = await this.readDataset({ datasetName });
datasetId_ = dataset.id;
}
else {
throw new Error("Must provide a datasetName or datasetId");
}
const params = new URLSearchParams({ dataset: datasetId_ });
if (exampleIds !== undefined) {
for (const id_ of exampleIds) {
params.append("id", id_);
}
}
for await (const examples of this._getPaginated("/examples", params)) {
yield* examples;
}
}
async deleteExample(exampleId) {
assertUuid(exampleId);
const path = `/examples/${exampleId}`;
const response = await this.caller.call(fetch, this.apiUrl + path, {
method: "DELETE",
headers: this.headers,
signal: AbortSignal.timeout(this.timeout_ms),
});
if (!response.ok) {
throw new Error(`Failed to delete ${path}: ${response.status} ${response.statusText}`);
}
await response.json();
}
async updateExample(exampleId, update) {
assertUuid(exampleId);
const response = await this.caller.call(fetch, `${this.apiUrl}/examples/${exampleId}`, {
method: "PATCH",
headers: { ...this.headers, "Content-Type": "application/json" },
body: JSON.stringify(update),
signal: AbortSignal.timeout(this.timeout_ms),
});
if (!response.ok) {
throw new Error(`Failed to update example ${exampleId}: ${response.status} ${response.statusText}`);
}
const result = await response.json();
return result;
}
async evaluateRun(run, evaluator, { sourceInfo, loadChildRuns, } = { loadChildRuns: false }) {
let run_;
if (typeof run === "string") {
run_ = await this.readRun(run, { loadChildRuns });
}
else if (typeof run === "object" && "id" in run) {
run_ = run;
}
else {
throw new Error(`Invalid run type: ${typeof run}`);
}
let referenceExample = undefined;
if (run_.reference_example_id !== null &&
run_.reference_example_id !== undefined) {
referenceExample = await this.readExample(run_.reference_example_id);
}
const feedbackResult = await evaluator.evaluateRun(run_, referenceExample);
let sourceInfo_ = sourceInfo ?? {};
if (feedbackResult.evaluatorInfo) {
sourceInfo_ = { ...sourceInfo_, ...feedbackResult.evaluatorInfo };
}
return await this.createFeedback(run_.id, feedbackResult.key, {
score: feedbackResult.score,
value: feedbackResult.value,
comment: feedbackResult.comment,
correction: feedbackResult.correction,
sourceInfo: sourceInfo_,
feedbackSourceType: "model",
});
}
async createFeedback(runId, key, { score, value, correction, comment, sourceInfo, feedbackSourceType = "api", sourceRunId, feedbackId, eager = false, }) {
const feedback_source = {
type: feedbackSourceType ?? "api",
metadata: sourceInfo ?? {},
};
if (sourceRunId !== undefined &&
feedback_source?.metadata !== undefined &&
!feedback_source.metadata["__run"]) {
feedback_source.metadata["__run"] = { run_id: sourceRunId };
}
if (feedback_source?.metadata !== undefined &&
feedback_source.metadata["__run"]?.run_id !== undefined) {
assertUuid(feedback_source.metadata["__run"].run_id);
}
const feedback = {
id: feedbackId ?? uuid.v4(),
run_id: runId,
key,
score,
value,
correction,
comment,
feedback_source: feedback_source,
};
const url = `${this.apiUrl}/feedback` + (eager ? "/eager" : "");
const response = await this.caller.call(fetch, url, {
method: "POST",
headers: { ...this.headers, "Content-Type": "application/json" },
body: JSON.stringify(feedback),
signal: AbortSignal.timeout(this.timeout_ms),
});
await raiseForStatus(response, "create feedback");
return feedback;
}
async updateFeedback(feedbackId, { score, value, correction, comment, }) {
const feedbackUpdate = {};
if (score !== undefined && score !== null) {
feedbackUpdate["score"] = score;
}
if (value !== undefined && value !== null) {
feedbackUpdate["value"] = value;
}
if (correction !== undefined && correction !== null) {
feedbackUpdate["correction"] = correction;
}
if (comment !== undefined && comment !== null) {
feedbackUpdate["comment"] = comment;
}
assertUuid(feedbackId);
const response = await this.caller.call(fetch, `${this.apiUrl}/feedback/${feedbackId}`, {
method: "PATCH",
headers: { ...this.headers, "Content-Type": "application/json" },
body: JSON.stringify(feedbackUpdate),
signal: AbortSignal.timeout(this.timeout_ms),
});
await raiseForStatus(response, "update feedback");
}
async readFeedback(feedbackId) {
assertUuid(feedbackId);
const path = `/feedback/${feedbackId}`;
const response = await this._get(path);
return response;
}
async deleteFeedback(feedbackId) {
assertUuid(feedbackId);
const path = `/feedback/${feedbackId}`;
const response = await this.caller.call(fetch, this.apiUrl + path, {
method: "DELETE",
headers: this.headers,
signal: AbortSignal.timeout(this.timeout_ms),
});
if (!response.ok) {
throw new Error(`Failed to delete ${path}: ${response.status} ${response.statusText}`);
}
await response.json();
}
async *listFeedback({ runIds, feedbackKeys, feedbackSourceTypes, } = {}) {
const queryParams = new URLSearchParams();
if (runIds) {
queryParams.append("run", runIds.join(","));
}
if (feedbackKeys) {
for (const key of feedbackKeys) {
queryParams.append("key", key);
}
}
if (feedbackSourceTypes) {
for (const type of feedbackSourceTypes) {
queryParams.append("source", type);
}
}
for await (const feedbacks of this._getPaginated("/feedback", queryParams)) {
yield* feedbacks;
}
}
}
exports.Client = Client;