Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: reorganize code structure #48

Merged
merged 10 commits into from
Aug 1, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,148 changes: 697 additions & 451 deletions docs/api.md

Large diffs are not rendered by default.

137 changes: 76 additions & 61 deletions src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ import { ReadStream } from 'fs';
import { v4 as uuidv4 } from 'uuid';

import { LiteralClient } from '.';
import {
Dataset,
DatasetExperiment,
DatasetExperimentItem,
DatasetItem,
DatasetType
} from './evaluation/dataset';
import { Score, ScoreConstructor } from './evaluation/score';
import {
GenerationsFilter,
GenerationsOrderBy,
Expand All @@ -16,32 +24,23 @@ import {
ThreadsFilter,
ThreadsOrderBy
} from './filter';
import { Attachment } from './observability/attachment';
import {
Generation,
IGenerationMessage,
PersistedGeneration
} from './generation';
} from './observability/generation';
import { Step, StepType } from './observability/step';
import { CleanThreadFields, Thread } from './observability/thread';
import { Prompt } from './prompt-engineering/prompt';
import {
Attachment,
CleanThreadFields,
Dataset,
DatasetExperiment,
DatasetExperimentItem,
DatasetItem,
DatasetType,
Environment,
Maybe,
OmitUtils,
PaginatedResponse,
Prompt,
Score,
ScoreConstructor,
Step,
StepType,
Thread,
User,
Utils
} from './types';
} from './utils';

// eslint-disable-next-line @typescript-eslint/no-var-requires
const packageJson = require('../package.json');
Expand Down Expand Up @@ -118,13 +117,6 @@ steps {
${stepFields}
}`;

/**
* Serializes the step object with a suffix ID to each key.
*
* @param object - The step object to serialize.
* @param id - The numeric identifier to append to each key in the serialized object.
* @returns A new object with serialized key-value pairs where each key is suffixed with the provided id.
*/
function serialize(object: Utils, id: number) {
const result: any = {};

Expand All @@ -135,12 +127,6 @@ function serialize(object: Utils, id: number) {
return result;
}

/**
* Constructs a variables object for GraphQL queries by serializing each step with a unique suffix.
*
* @param objects - An array of `Step` objects to be serialized and added to the variables object.
* @returns An object containing serialized steps with keys suffixed by their index in the input array.
*/
function variablesBuilder(objects: Utils[]) {
let variables: any = {};
for (let i = 0; i < objects.length; i++) {
Expand All @@ -161,13 +147,6 @@ function generationsVariablesBuilder(
return variables;
}

/**
* Builds a string for GraphQL field definitions for ingesting multiple steps.
* Each step's fields are suffixed with its index to create unique variable names.
*
* @param steps - An array of `Step` objects. Each `Step` object represents a step to be ingested.
* @returns A string containing GraphQL field definitions for all provided steps.
*/
function ingestStepsFieldsBuilder(steps: Step[]) {
let generated = '';
for (let id = 0; id < steps.length; id++) {
Expand All @@ -191,14 +170,6 @@ function ingestStepsFieldsBuilder(steps: Step[]) {
return generated;
}

/**
* Constructs the arguments for a GraphQL mutation to ingest multiple steps.
* Each step is transformed into a call to the `ingestStep` mutation with parameters
* suffixed by the step's index to ensure uniqueness.
*
* @param steps - An array of `Step` objects. Each `Step` object represents a step to be ingested.
* @returns A string containing the GraphQL mutation arguments for all provided steps.
*/
function ingestStepsArgsBuilder(steps: Step[]) {
let generated = '';
for (let id = 0; id < steps.length; id++) {
Expand Down Expand Up @@ -228,12 +199,6 @@ function ingestStepsArgsBuilder(steps: Step[]) {
return generated;
}

/**
* Constructs a complete GraphQL mutation query for adding multiple steps.
*
* @param steps - An array of `Step` objects to be ingested. This parameter is required.
* @returns A string representing the complete GraphQL mutation for adding steps.
*/
function ingestStepsQueryBuilder(steps: Step[]) {
return `
mutation AddStep(${ingestStepsFieldsBuilder(steps)}) {
Expand Down Expand Up @@ -616,7 +581,6 @@ export class API {
return result.data.deleteStep.id;
}

// Upload
/**
* Uploads a file to a specified thread. This method supports uploading either through direct content or via a file path.
* It first signs the upload through a pre-configured endpoint and then proceeds to upload the file using the signed URL.
Expand All @@ -630,7 +594,6 @@ export class API {
* @returns An object containing the `objectKey` of the uploaded file and the signed `url`, or `null` values if the upload fails.
* @throws {Error} Throws an error if neither `content` nor `path` is provided, or if the server response is invalid.
*/

async uploadFile(params: UploadFileParamsWithContent): Promise<{
objectKey: Maybe<string>;
url: Maybe<string>;
Expand Down Expand Up @@ -718,6 +681,21 @@ export class API {
}
}

/**
* Uploads a file to a specified thread and creates an attachment object.
* If called inside a context, the attachment will be added to the current step and thread.
*
* @param params - The parameters for uploading a file, including:
* @param params.name - The name of the file.
* @param params.metadata - Additional metadata for the file as a key-value pair object.
* @param params.content - The content of the file to upload. Optional if `path` is provided.
* @param params.path - The path to the file to upload. Optional if `content` is provided.
* @param params.id - The unique identifier for the file. If not provided, a UUID will be generated.
* @param params.threadId - The unique identifier of the thread to which the file is being uploaded.
* @param params.mime - The MIME type of the file. Defaults to 'application/octet-stream' if not provided.
* @returns An object containing the `objectKey` of the uploaded file and the signed `url`, or `null` values if the upload fails.
* @throws {Error} Throws an error if neither `content` nor `path` is provided, or if the server response is invalid.
*/
async createAttachment(
params: UploadFileParamsWithContent & CreateAttachmentParams
): Promise<Attachment>;
Expand Down Expand Up @@ -764,7 +742,6 @@ export class API {
return attachment;
}

// Generation
/**
* Retrieves a paginated list of Generations based on the provided filters and sorting order.
*
Expand Down Expand Up @@ -874,7 +851,6 @@ export class API {
return response.data.createGeneration as PersistedGeneration;
}

// Thread
/**
* Upserts a Thread with new information.
*
Expand All @@ -892,6 +868,7 @@ export class API {
metadata?: Maybe<Record<string, any>>;
participantId?: Maybe<string>;
tags?: Maybe<string[]>;
environment?: Maybe<Environment>;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We add environment from Willy's developments last week?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, turns out it wasn't taken into account in this case

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm not sure we need this. The environment is passed as a HTTP header at the sdk level. it should not show in function signatures.

Furthermore, I don't think it is useful on attachments since the attachments are linked to steps and steps have an environment.

}): Promise<CleanThreadFields>;

/**
Expand All @@ -910,15 +887,17 @@ export class API {
name?: Maybe<string>,
metadata?: Maybe<Record<string, any>>,
participantId?: Maybe<string>,
tags?: Maybe<string[]>
tags?: Maybe<string[]>,
environment?: Maybe<Environment>
): Promise<CleanThreadFields>;

async upsertThread(
threadIdOrOptions: any,
name?: Maybe<string>,
metadata?: Maybe<Record<string, any>>,
participantId?: Maybe<string>,
tags?: Maybe<string[]>
tags?: Maybe<string[]>,
environment?: Maybe<Environment>
): Promise<CleanThreadFields> {
let threadId = threadIdOrOptions;
if (typeof threadIdOrOptions === 'object') {
Expand All @@ -927,6 +906,13 @@ export class API {
metadata = threadIdOrOptions.metadata;
participantId = threadIdOrOptions.participantId;
tags = threadIdOrOptions.tags;
environment = threadIdOrOptions.environment;
}

const originalEnvironment = this.environment;

if (environment && environment !== originalEnvironment) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are we adding this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed that the environment was part of ThreadConstructor, like for example i can do client.thread({ environment: 'prod' }).wrap but then it is completely ignored by the code.

This code in upsertThread just updates the api.environment for the time it takes to upsert the thread, then reverts the change.

I'm not sure what you mean about attachments though ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is legacy, from now on environment is handled at the header level. We are just keeping the arg for backward compatiblity

this.environment = environment;
}

const query = `
Expand Down Expand Up @@ -958,6 +944,11 @@ export class API {
};

const response = await this.makeGqlCall(query, variables);

if (environment && environment !== originalEnvironment) {
this.environment = originalEnvironment;
}

return new Thread(this.client, response.data.upsertThread);
}

Expand Down Expand Up @@ -1077,7 +1068,6 @@ export class API {
return response.data.deleteThread.id;
}

// User
/**
* Retrieves a list of users with optional filters.
*
Expand Down Expand Up @@ -1282,7 +1272,6 @@ export class API {
return result.data.deleteParticipant.id;
}

// Score
/**
* Get all scores connected to the platform.
*
Expand Down Expand Up @@ -1502,8 +1491,6 @@ export class API {
return result.data.deleteScore;
}

// Dataset

/**
* List all datasets in the platform.
*
Expand Down Expand Up @@ -1805,6 +1792,13 @@ export class API {
return new DatasetItem(result.data.addGenerationToDataset);
}

/**
* Adds multiple generation items to a dataset.
*
* @param datasetId - The unique identifier of the dataset. This parameter is required.
* @param generationIds - An array of unique identifiers for the generations to be added. This parameter is required.
* @returns An array of `DatasetItem` instances populated with the data of the newly added generations
*/
public async addGenerationsToDataset(
datasetId: string,
generationIds: string[]
Expand All @@ -1816,6 +1810,15 @@ export class API {
return Object.values(result.data).map((x: any) => new DatasetItem(x));
}

/**
* Creates a new dataset experiment.
* @param datasetExperiment
* @param datasetExperiment.name The name of the dataset experiment.
* @param datasetExperiment.datasetId The dataset ID to associate with the experiment.
* @param datasetExperiment.promptId The prompt ID to associate with the experiment.
* @param datasetExperiment.params The parameters for the experiment as a key-value pair object or an array of the same.
* @returns The newly created dataset experiment object.
*/
public async createExperiment(datasetExperiment: {
name: string;
datasetId?: string;
Expand All @@ -1840,6 +1843,18 @@ export class API {
return new DatasetExperiment(this, result.data.createDatasetExperiment);
}

/**
* Creates a new dataset experiment item.
*
* @param parameters
* @param parameters.datasetExperimentId The dataset experiment ID to associate with the item (required)
* @param parameters.scores An array of scores to associate with the item (required)
* @param parameters.datasetItemId The ID of the dataset item (optional)
* @param parameters.experimentRunId The ID of the experiment run (optional)
* @param parameters.input The input data for the item (optional)
* @param parameters.output The output data for the item (optional)
* @returns The dataset experiment object.
*/
public async createExperimentItem({
datasetExperimentId,
datasetItemId,
Expand Down Expand Up @@ -1881,7 +1896,6 @@ export class API {
});
}

// Prompt
/**
* Create a new prompt lineage.
*
Expand Down Expand Up @@ -1935,6 +1949,7 @@ export class API {
* @param name The name of the prompt to retrieve or create.
* @param templateMessages A list of template messages for the prompt.
* @param settings Optional settings for the prompt.
* @param tools Optional tools for the prompt.
* @returns The prompt that was retrieved or created.
*/
public async getOrCreatePrompt(
Expand Down Expand Up @@ -2050,7 +2065,7 @@ export class API {
return await this.getPromptWithQuery(query, { name, version });
}

public async getPromptWithQuery(
private async getPromptWithQuery(
query: string,
variables: Record<string, any>
) {
Expand Down
Loading
Loading