Getting Started

This guide will get you set up and ready to use the Composable CLI and SDK.

Composable Studio

In order to create and manage your interaction you need to login to the Composable Studio. This is a web application in which you can create and manage your interactions.

In order to access and use your interactions from outside the Studio application, you can use the Composable CLI. If you want to integrate your interactions in your own application you can use the Composable SDK.

There is a second and more efficient way to integrate the interactions in your own application by using code generation. Code generation will generate high level classes along with TypeScript interfaces to easily access your interactions. We will talk about code generation at the end of this guide.

We will cover the basics of the CLI and of the SDK in the following sections. For full documentation see the projects themselves. Let's start with a quick look at the installation and basic usage of these tools.

Composable CLI

This is a command line application that can be used to access your Composable projects. It was designed to fulfill the following main use cases:

  • List and switch between your Composable projects
  • List the existing interactions and execution environments
  • Run interactions once or multiple times over a set of different data inputs
  • Generate data inputs to run the interactions against
  • Search through the history of runs to inspect detailed results

Requirements

A TTY terminal and, as for the SDK, Node version 18 or higher is required.

Installation

npm -g install @becomposable/cli

Basic Usage

Let's list all the projects in the organization owning the API KEY:

composable -k {YOUR_API_KEY} projects

To access a project you must pass the project ID too. Let's list the interactions inside a project:

composable -k {YOUR_API_KEY} -p {PROJECT_ID} interactions

To simplify using the CLI command options which can get quite long, you can create profiles to store common arguments like the API key, the target project or the target server.

To create a profile run:

composable config add

and follow the interactive prompts.

Once you have created a profile you can use it to run commands without having to pass the arguments every time. The last created profile will be automatically selected as the defualt profile. To switch to another profile use the composable config user {PROFILE_NAME} command.

Now the following command:

composable interactions

will list the interactions using the current profile api key and target project.

Let's run an interaction. We will use the run command.

composable run {INTERACTION_ID}

This command has plenty of options. It is not the scope of this guide to explain them all.

To summarize we can run an interaction once or multiple times on a set of data inputs (specfified from a file using --input or inline using --data) we can run a interaction by giving some.

When running a single interaction the response will be, by default, streamed on the console.

You can also tag runs to be able to easily search for them later using composable runs.

Example:

composable run --tags testing {INTERACTION_1_ID}
composable run --tags testing {INTERACTION_2_ID}
# then, later retrieve the run results having the testing_session tag
composable runs --tags testing

Composable SDK

This is a JavaScript SDK that can be used in both Node.js and in the browser.

Requirements

Node version 18 or higher is required (the fetch API is required). It will also work with node version 17.5 by using the --experimental-fetch flag

Installation

npm install @becomposable/client

Basic Usage

Listing the projects in an organization:

import {ComposableClient} from "@becomposable/client"

const client = new ComposableClient({
    apikey: "YOUR_API_KEY_HERE"
})

const projects = await client.projects.list();

for (const project of projects) {
  console.log(project.name+': '+project.id);
}

You can see in the previous example how we initialize the ComposableClient with the API key. The API key will authenticate us on the server and will select the organization to which the key belongs.

Let's list now the interactions in a project

import { ComposableClient } from "@becomposable/client"

const client = new ComposableClient({
    apikey: "YOUR_API_KEY_HERE",
})

const interactions = await client.interactions.list();

for (const interaction of interactions) {
    console.log(interaction.name + ': ' + interaction.id);
}

In the example above, you see we added a projectId option when instantiating the client. This is the ID of the project we want to access.

Both the API key and the project ID are set when initializing the client and will be used for all the requests made with that client.

You can change the project ID at any time by setting it directly on the client:

client.project = "New Project ID"

Let's suppose we created an interaction named "Which Color" which is sending to the LLM an object name to get in response one of its possible colors.

Suppose interactionId is the ID of the interaction. We can run it as follows:

import { ComposableClient } from "@becomposable/client"

const client = new ComposableClient({
    apikey: "YOUR_API_KEY_HERE",
})

// Note that the interactionId argument must be a valid interaction ID which belongs to the project you are connected to.
const run = await client.interactions.execute(interactionId, {
    data: { object: "sky" }
});

console.log(run.result);

The response of the LLM will be:

{
    "color": "blue"
}

Code Generation

Let's look deeper at the interaction execution above. You can notice the interaction takes some data as input, input which is used to generate the prompt sent to the LLM. Also, the interaction instructs the LLM to respond in JSON and not in plain text. Otherwise, in complex cases it will be difficult to parse the result and structure it.

In our example the input data is quite simple: {object: string}. Same the result data: {color: string}. But in real world applications the input and response data may be quite complex.

This is why in real life applications managing the input and output data structures becomes hard without having a strong typing system. Here is where code generation becomes handy.

In short, code generation will generate high level classes along with TypeScript interfaces which describe the input and the output data. Let's suppose we generated the code for the interaction above. The generated code will look like this:

import { ComposableClient, ComposableClientProps, InteractionBase } from "@becomposable/client";

/**
 * WhichColor input type
 */
export interface WhichColorProps {
    object: string;
}

/**
 * WhichColor result type
 */
export interface WhichColorResult {
    color: string;
}

/**
 * WhichColor
 */
export class WhichColor extends InteractionBase<WhichColorProps, WhichColorResult> {
    readonly projectId = "654df9de09676ad3b8631dc3";
    constructor(clientOrProps: ComposableClient | ComposableClientProps) {
        super ("6554cf617eae1c28ef5f3d40", clientOrProps);
        this.client.project = this.projectId;
    }
}

And to execute the interaction we can do:

import { WhichColor } from "./WhichColor/index.js"

const wcolor = new WhichColor({
    apikey: "YOUR_API_KEY_HERE"
});

const run = await wcolor.execute({
    data: { object: "sky" }
});

console.log(run.result);

As you can see, the interaction execution code is quite similar with the one we used before, when directly using the SDK.

The big difference is that the code using the generated interface class is strongly typed. In the SDK execution example we can put anything as the data value. Also we don't have any hint about what contains the run.result.

Using the generated class, we have a strong typing system which will help us to write better code and to avoid errors.

Generating Classes

The code generation is done using the Composable CLI.

Here are some basic examples on how the code generation works. For a complete documentation look into the CLI documentation.

To generate the code for an interaction you need to know the interaction class name (which is the Pascal Case version of the interaction name). You can find the interaction class name by using the command composable interaction {interactionId}.

Let's suppose we want to generate the code for the interaction named "Which Color". We simply run:

composable codegen WhichColor

This will generate a interactions/WhichColor folder in the current directory.

You can change the target directory using the -d, --dir option. For example:

composable codegen WhichColor -d ./

will put the WhichColor folder in the current directory.

If you want to generate the code for all the interactions in a project you should ommit the interaction class name: composable codegen.

Interaction class anatomy

The code generated for an interaction will always be saved in a directory having the same name as the interaction class name. The directory will contain multiple files, depending on the interaction and on the options used at generation time.

The structure of the directory is:

{interactionClassName}/
    index.ts
    draft.ts
    v2.ts
    v3.ts
    ...
    v{latestVersion}.ts

The index.ts file will always exist. The other files are generated only if requested. But at least one of these files will be present. The default generation behavior is to export the draft and the last published version.

The index.ts will just re-export one of the other files. By default it will re-export the latest published version, or, if no versions exists, the draft version.

You can control which versions are generated and which version is re-exported by the index.ts file using the options of the composable codegen command.

What's next?

Great, you're now set up with an API client and have made your first request to the API. Here are a few links that might be handy as you venture further into Composable:

Was this page helpful?