diff --git a/package-lock.json b/package-lock.json index 0c24618..56ba955 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7918,6 +7918,11 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/@vercel/analytics": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@vercel/analytics/-/analytics-1.0.2.tgz", + "integrity": "sha512-BZFxVrv24VbNNl5xMxqUojQIegEeXMI6rX3rg1uVLYUEXsuKNBSAEQf4BWEcjQDp/8aYJOj6m8V4PUA3x/cxgg==" + }, "node_modules/@vitejs/plugin-react-swc": { "version": "3.3.2", "dev": true, @@ -10659,6 +10664,10 @@ "node": ">=16.9.0" } }, + "node_modules/docs": { + "resolved": "packages/docs", + "link": true + }, "node_modules/doctrine": { "version": "3.0.0", "dev": true, @@ -13185,10 +13194,6 @@ "resolved": "packages/implementations/discord", "link": true }, - "node_modules/gpt-turbo-docs": { - "resolved": "packages/docs", - "link": true - }, "node_modules/gpt-turbo-nest": { "resolved": "packages/implementations/nest", "link": true @@ -25227,7 +25232,6 @@ } }, "packages/docs": { - "name": "gpt-turbo-docs", "version": "5.0.0", "dependencies": { "@mantine/code-highlight": "^7.0.0-alpha.21", @@ -25236,6 +25240,7 @@ "@mantine/spotlight": "^7.0.0-alpha.21", "@mantine/vanilla-extract": "^7.0.0-alpha.21", "@vanilla-extract/css": "^1.12.0", + "@vercel/analytics": "^1.0.2", "contentlayer": "^0.3.4", "next": "13.4.12", "next-contentlayer": "^0.3.4", diff --git a/packages/docs/package.json b/packages/docs/package.json index d783f5e..cda7879 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -19,6 +19,7 @@ "@mantine/spotlight": "^7.0.0-alpha.21", "@mantine/vanilla-extract": "^7.0.0-alpha.21", "@vanilla-extract/css": "^1.12.0", + "@vercel/analytics": "^1.0.2", "contentlayer": "^0.3.4", "next": "13.4.12", "next-contentlayer": "^0.3.4", diff --git a/packages/docs/src/app/layout.tsx b/packages/docs/src/app/layout.tsx index 9f6c194..6197c87 100644 --- a/packages/docs/src/app/layout.tsx +++ b/packages/docs/src/app/layout.tsx @@ -1,6 +1,7 @@ import "@mantine/core/styles.css"; import "@mantine/spotlight/styles.css"; import "@mantine/code-highlight/styles.css"; +import { Analytics } from "@vercel/analytics/react"; import { ColorSchemeScript } from "@mantine/core"; import Shell from "./components/Shell/Shell"; import DocsSpotlight from "./components/DocsSpotlight/DocsSpotlight"; @@ -59,6 +60,7 @@ const AppLayout = ({ children }: AppLayoutProps) => { {children} + ); diff --git a/packages/docs/src/mdx/docs/conversation/chatcompletion-service.mdx b/packages/docs/src/mdx/docs/conversation/chatcompletion-service.mdx index 77021c2..97cccb5 100644 --- a/packages/docs/src/mdx/docs/conversation/chatcompletion-service.mdx +++ b/packages/docs/src/mdx/docs/conversation/chatcompletion-service.mdx @@ -7,4 +7,47 @@ api: classes/ChatCompletionService.html > This is an internal class. You can interact with it when authoring plugins, but you shouldn't need to instantiate it. - +The `ChatCompletionService` exposes the methods used by the `Conversation` to interact with the Chat Completion API. +Unlike most other classes (of the `Conversation` class), it is not exposed as a property of the `Conversation` class. +It is essentially a utility class for internal use by the library and can be very complex to work with standalone. + +However, it is exposed to plugins, in order to allow complex behaviors and side effects. +This page will cover what this service accomplishes, but there aren't much patterns to follow when using it. + +## Getting a chat completion response from the API + +The `getChatCompletionResponse` method is in charge of getting a response from the Chat Completion API using the appropriate handler: + +- `handleStreamedResponse`: used when the `stream` option is enabled. +- `handleNonStreamedResponse`: used when the `stream` option is disabled. + +It then returns the response as a `Promise`. + +### Handling a streamed response + +When the `stream` option is enabled, the `handleStreamedResponse` method will be used to get a response from the Chat Completion API. +One particular distinction of this method is that it is **synchronous**. +It does not wait for the API response to be received, because it is easy to predict the initial state of the message: + +- The message content will be empty. +- The message will be updated internally, periodically, as the API sends new data. + +The goal here is to get the message instance out as soon as possible. +This allows client code to subscribe to the message's events, such as `onUpdate` or `onContentStream`, without missing any event. + +### Handling a non-streamed response + +When the `stream` option is disabled, the `handleNonStreamedResponse` method will be used to get a response from the Chat Completion API. +Unlike the previous handler, this one is **asynchronous**. +It will wait for the API response to be received, and then return the message instance. + +## Getting the assistant's response + +The `getAssistantResponse` method is a wrapper around the `getChatCompletionResponse` method. +It gets the chat completion response, moderates it, adds the message to the `ConversationHistory` and returns the message. + +### Moderation + +The `moderateMessage` method is a wrapper around the `moderate` method of the `Message` class. +The role of the `Message.moderate` method is only to get the message's moderation status. +The `moderateMessage` method will use this status to determine whether or not it should throw a `ModerationException`. diff --git a/packages/docs/src/mdx/docs/conversation/conversation-callable-functions.mdx b/packages/docs/src/mdx/docs/conversation/conversation-callable-functions.mdx index d89b46a..907016f 100644 --- a/packages/docs/src/mdx/docs/conversation/conversation-callable-functions.mdx +++ b/packages/docs/src/mdx/docs/conversation/conversation-callable-functions.mdx @@ -7,4 +7,109 @@ api: classes/ConversationCallableFunctions.html > This is an internal class. You'll interact with it and configure it through the `Conversation` class, but you shouldn't need to instantiate it. - +The `ConversationCallableFunctions` class is what keeps track of the callable functions in a conversation and manages them. + +## Configuring in conversation constructor + +You'll most likely be interacting with this class through the `Conversation` class. +More specifically, through the `callableFunctions` property of the `Conversation` constructor. + +```ts +const conversation = new Conversation({ + callableFunctions: { + /* options */ + }, +}); +``` + +The options you pass are conveniently the same as the [`toJSON`](#serialization-and-deserialization) method: + +- `functions`: The callable functions available to the conversation. + These should be a [JSON representation of a `CallableFunction`](../callable-function/callable-function#serialization-and-deserialization). + +## Managing Callable Functions + +The `ConversationCallableFunctions` class has various methods to manage the functions available in the conversation. + +### Adding Callable Functions + +You can add a function using the `addFunction` method. +This method takes either a [`CallableFunction`](../callable-function/callable-function) instance or a [JSON representation of a `CallableFunction`](../callable-function/callable-function#serialization-and-deserialization). + +```ts +const callableFunction = new CallableFunction(/* ... */); + +conversation.callableFunctions.addFunction(callableFunction); +conversation.callableFunctions.addFunction(callableFunction.toJSON()); +``` + +### Getting the Callable Functions + +You can get the callable functions in the conversation using the `getFunctions` method. + +```ts +const callableFunctions = conversation.callableFunctions.getFunctions(); +``` + +### Removing Callable Functions + +You can remove a specific callable function with the `removeFunction` method or remove all of them with the `clearFunctions` method. + +```ts +const callableFunction = new CallableFunction(/* ... */); +conversation.callableFunctions.addFunction(callableFunction); + +// Remove a specific function +conversation.callableFunctions.removeFunction(callableFunction); +conversation.callableFunctions.removeFunction(callableFunction.id); + +// Remove all functions +conversation.callableFunctions.clearFunctions(); +``` + +## Event Listeners + +You can listen to various events on a `ConversationCallableFunctions` instance. +These allow you to react to certain events, such as when a function is added. + +All events shown below have an `on`, `once` and `off` method (e.g: `onCallableFunctionAdded`, `onceCallableFunctionAdded`, `offCallableFunctionAdded`). + +- `on`: Adds a listener to the event. Takes a callback function as an argument. +- `once`: Same as `on`, but the listener will only be called once before being automatically unsubscribed. +- `off`: Removes a listener from the event. Takes the callback function passed to `on` or `once` as an argument. + +### CallableFunctionAdded + +This event fires when a function is added to the callable functions, with the following arguments: + +- `callableFunction`: The function that was added. + +### CallableFunctionRemoved + +This event fires when a function is removed to the callable functions, with the following arguments: + +- `callableFunction`: The function that was removed. + +## Serialization and Deserialization + +You can serialize the conversation callable functions to JSON using the `toJSON` method. +This is especially useful if you want to persist a conversation callable functions in a database or file. +Use the `toJSON` method to serialize a conversation callable functions to JSON. + +```ts +const callableFunctions = conversation.callableFunctions; +const callableFunctionsJson = callableFunctions.toJSON(); +``` + +You can then deserialize a conversation callable functions from JSON using the `fromJSON` static method. + +```ts +const callableFunctions = ConversationCallableFunctions.fromJSON(callableFunctionsJson); + +// ... do some operations on the callableFunctions ... + +const conversation = new Conversation({ callableFunctions: callableFunctions.toJSON() }); +``` + +> The conversation callable functions are automatically serialized/deserialized when serializing a `Conversation`. +> You should only use these methods if you want to serialize/deserialize only the `ConversationCallableFunctions`. diff --git a/packages/docs/src/mdx/docs/conversation/conversation-config.mdx b/packages/docs/src/mdx/docs/conversation/conversation-config.mdx index dce5e6e..2a837bc 100644 --- a/packages/docs/src/mdx/docs/conversation/conversation-config.mdx +++ b/packages/docs/src/mdx/docs/conversation/conversation-config.mdx @@ -7,4 +7,174 @@ api: classes/ConversationConfig.html > This is an internal class. You'll interact with it and configure it through the `Conversation` class, but you shouldn't need to instantiate it. - +The `ConversationConfig` class is used to configure the Conversation's parameters. +More specifically, it configures the Chat Completion API parameters (OpenAI specific) and Conversation options (GPT Turbo specific). + +## Configuring in conversation constructor + +You'll most likely be interacting with this class through the `Conversation` class. +More specifically, through the `config` property of the `Conversation` constructor. + +```ts +const conversation = new Conversation({ + config: { + /* options */ + }, +}); +``` + +The options you pass are conveniently the same as the [`toJSON`](#serialization-and-deserialization) method detailed in the next subsections. + +### Library options + +These options are specific to GPT Turbo. + +- `apiKey`: Your OpenAI API key. +- `context`: The first system message to set the context for the GPT model. \ + **Default**: `"You are a large language model trained by OpenAI. Answer as concisely as possible."` +- `dry`: Dry run. Don't send any requests to OpenAI. Responses will mirror the last message in the conversation. \ + **Default**: `false` unless `apiKey` is not set, in which case it's `true`. +- `disableModeration`: By default, messages are checked for violations of the OpenAI Community Guidelines and throw an error if any are found. + Set this to `true` to disable this check. + Set this to `"soft"` to still check for violations, but not throw an error if any are found. The violations will be added to the `flags` property of the message. + + > This is not recommended, as it could result in account suspension. Additionally, [OpenAI's Moderation API](https://platform.openai.com/docs/guides/moderation) is free to use. + + **Default**: `false` + +### Chat Completion API parameters + +These options are specific to the [Chat Completion API](https://platform.openai.com/docs/api-reference/chat/create). +Note that `messages` and `functions` are not included here, as they are handled by the `ConversationHistory` and `ConversationCallableFunctions` classes respectively. + +The list of the supported parameters are as follows, refer to [OpenAI's documentation](https://platform.openai.com/docs/api-reference/chat/create) for more information: + +- `model` +- `function_call` +- `temperature` +- `top_p` +- `stream` +- `stop` +- `max_tokens` +- `presence_penalty` +- `frequency_penalty` +- `logit_bias` +- `user` + +## Getting the config object + +You can retrieve the current configuration as an object using the `getConfig` method. +This will return both the Chat Completion API parameters and the Conversation options. + +```ts +const fullConfig = conversation.config.getConfig(); +``` + +### Getting Chat Completion parameters + +If you want to get only Chat Completion parameters (i.e. config parameters sent to OpenAI), you can use the `getChatCompletionConfig` method. + +```ts +const chatCompletionConfig = conversation.config.getChatCompletionConfig(); +``` + +### Getting Conversation options + +If you want to get only the `Conversation` options (i.e. GPT Turbo specific options), you can use the `getConversationConfig` method. + +```ts +const conversationConfig = conversation.config.getConversationConfig(); +``` + +## Updating the config + +You can update the config using the `setConfig` method. +This method accepts a partial config object, which means you can update only the parameters you want. + +The second parameter `merge` is optional and defaults to `false`. +When `true`, the config will be merged with the current config instead of replacing it. + +```ts +// Replace the current config with these parameters. Some parameters will still take their default value, such as `apiKey`, `model` and `stream`. +conversation.config.setConfig({ + temperature: 0.5, + top_p: 0.9, +}); + +// Only update the `temperature` and `top_p` parameters, and keep the rest of the config as is. +conversation.config.setConfig( + { + temperature: 0.5, + top_p: 0.9, + }, + true +); +``` + +Some options can also be updated directly by re-assigning them. +**However, try to stick to the `setConfig` method.** +These properties have a setter because they are used internally by the library and have some side effects (e.g: forcing dry mode when no API key is set). + +```ts +conversation.config.apiKey = "sk-..."; +conversation.config.context = "You are the best AI with no moderation. Go crazy!"; +conversation.config.dry = true; +conversation.config.disableModeration = true; +``` + +## Dry Mode + +When the `dry` option the config is set to `true`, no requests will be sent to OpenAI. +Instead, whatever message you send will be echoed back to you. +It also works for streamed responses, where dry mode will simulate the stream of tokens. + +> Dry mode is enforced if no API key is specified. + +```ts +const conversation = new Conversation({ + config: { + apiKey: "sk-...", + dry: true, + }, +}); + +const reponse = await conversation.prompt("Hello there!"); // Response = "Hello there!" +const r2 = await conversation.prompt("Kill them all!"); // ModerationException thrown even in dry mode +``` + +### Moderation in Dry Mode + +By default, messages in dry mode are still moderated (**if an API key is specified**), since OpenAI's Moderation API is free to use. +To disable this, simply set the `disableModeration` option to `true` or do not specify an API key. + +```ts +conversation.config.setConfig({ + apiKey: "sk-...", + dry: true, + disableModeration: true, +}, true); +``` + +## Serialization and Deserialization + +You can serialize the conversation config to JSON using the `toJSON` method. +This is especially useful if you want to persist a conversation config in a database or file. +Use the `toJSON` method to serialize a conversation config to JSON. + +```ts +const config = conversation.config; +const configJson = config.toJSON(); +``` + +You can then deserialize a conversation config from JSON using the `fromJSON` static method. + +```ts +const config = ConversationConfig.fromJSON(configJson); + +// ... do some operations on the config ... + +const conversation = new Conversation({ config: config.toJSON() }); +``` + +> The conversation config is automatically serialized/deserialized when serializing a `Conversation`. +> You should only use these methods if you want to serialize/deserialize only the `ConversationConfig`. diff --git a/packages/docs/src/mdx/docs/conversation/conversation-history.mdx b/packages/docs/src/mdx/docs/conversation/conversation-history.mdx index 6b7c817..33954bd 100644 --- a/packages/docs/src/mdx/docs/conversation/conversation-history.mdx +++ b/packages/docs/src/mdx/docs/conversation/conversation-history.mdx @@ -7,4 +7,147 @@ api: classes/ConversationHistory.html > This is an internal class. You'll interact with it and configure it through the `Conversation` class, but you shouldn't need to instantiate it. - +The `ConversationHistory` is what keeps track of the messages in a conversation and manages them. + +## Configuring in conversation constructor + +You'll most likely be interacting with this class through the `Conversation` class. +More specifically, through the `history` property of the `Conversation` constructor. + +```ts +const conversation = new Conversation({ + history: { + /* options */ + }, +}); +``` + +The options you pass are conveniently the same as the [`toJSON`](#serialization-and-deserialization) method: + +- `messages`: The messages in the conversation history, including the context message. + These messages should be a [JSON representation of a `Message`](../message/message#serialization-and-deserialization). + +## Conversation Context + +> By default, the conversation context is `You are a large language model trained by OpenAI. Answer as concisely as possible.` + +The conversation context is set by the very first message of the conversation with the role of `system`. +You can see this message as the "message zero" of the conversation and in most cases, you won't need to show this message to the user. + +From OpenAI's [documentation](https://platform.openai.com/docs/guides/gpt/chat-completions-api): + +> _The system message helps set the behavior of the assistant. +> For example, you can modify the personality of the assistant or provide specific instructions about how it should behave throughout the conversation. +> However note that the system message is optional and the model's behavior without a system message is likely to be similar to using a generic message such as "You are a helpful assistant."_ + +You can set the context using the `setContext` method and get the context using the `getContext` method. + +```ts +conversation.history.setContext("You are a helpful assistant."); +const context = conversation.history.getContext(); +``` + +## Managing messages + +The `ConversationHistory` class has various methods to manage the messages in the conversation. + +### Adding messages + +You can add a message using the `addMessage` method, or specific methods like `addUserMessage` or `addAssistantMessage`. + +```ts +// Manual way +conversation.history.addMessage(new Message("user", "Hello there!")); + +// User message +conversation.history.addUserMessage("Hello there!"); + +// Assistant message +conversation.history.addAssistantMessage("Hello there!"); + +// System message +conversation.history.setContext("Hello there!"); + +// Function call (by the assistant) +conversation.history.addFunctionCallMessage({ + name: "sayHello", + arguments: { to: "John" }, +}); + +// Function message (by the user (client code)) +conversation.history.addFunctionMessage("{ action: 'greet', to: 'John' }"); +``` + +### Getting messages + +You can get the messages in the conversation using the `getMessages` method. +This method also accepts an optional parameter `includeContext` which defaults to `false`. +When `true`, the context message will be included in the returned messages. + +```ts +const messages = conversation.history.getMessages(); +const messagesWithContext = conversation.history.getMessages(true); +``` + +### Removing messages + +You can remove a specific message with the `removeMessage` method or remove all messages with the `clearMessages` method. + +```ts +const message = new Message("user", "Hello there!"); +conversation.history.addMessage(message); + +// Remove a specific message +conversation.history.removeMessage(message); +conversation.history.removeMessage(message.id); + +// Remove all messages +conversation.history.clearMessages(); +``` + +## Event Listeners + +You can listen to various events on a `ConversationHistory` instance. +These allow you to react to certain events, such as when a message is added. + +All events shown below have an `on`, `once` and `off` method (e.g: `onMessageAdded`, `onceMessageAdded`, `offMessageAdded`). + +- `on`: Adds a listener to the event. Takes a callback function as an argument. +- `once`: Same as `on`, but the listener will only be called once before being automatically unsubscribed. +- `off`: Removes a listener from the event. Takes the callback function passed to `on` or `once` as an argument. + +### MessageAdded + +This event fires when a message is added to the history, with the following arguments: + +- `message`: The message that was added. + +### MessageRemoved + +This event fires when a message is removed to the history, with the following arguments: + +- `message`: The message that was removed. + +## Serialization and Deserialization + +You can serialize the conversation history to JSON using the `toJSON` method. +This is especially useful if you want to persist a conversation history in a database or file. +Use the `toJSON` method to serialize a conversation history to JSON. + +```ts +const history = conversation.history; +const historyJson = history.toJSON(); +``` + +You can then deserialize a conversation history from JSON using the `fromJSON` static method. + +```ts +const history = ConversationHistory.fromJSON(historyJson); + +// ... do some operations on the history ... + +const conversation = new Conversation({ history: history.toJSON() }); +``` + +> The conversation history is automatically serialized/deserialized when serializing a `Conversation`. +> You should only use these methods if you want to serialize/deserialize only the `ConversationHistory`. diff --git a/packages/docs/src/mdx/docs/conversation/conversation-plugin-service.mdx b/packages/docs/src/mdx/docs/conversation/conversation-plugin-service.mdx index f0a3b0f..85dcb1f 100644 --- a/packages/docs/src/mdx/docs/conversation/conversation-plugin-service.mdx +++ b/packages/docs/src/mdx/docs/conversation/conversation-plugin-service.mdx @@ -7,4 +7,8 @@ api: classes/ConversationPluginService.html > This is an internal class. You can interact with it when authoring plugins, but you shouldn't need to instantiate it. - +The `ConversationPluginService` is an internal class used as middleware between a `Conversation` and its `ConversationPlugins`. + +It essentially exposes the same methods as plugins, but is in charge of passing on the arguments to each plugins so the `Conversation` doesn't have to. +For this reason, there is nothing much to document here. +Refer to the [authoring `ConversationPlugin`s documentation](../conversation-plugins/authoring-plugins#plugin-definition-properties) for the plugin methods it exposes. diff --git a/packages/docs/src/mdx/docs/conversation/conversation-plugins.mdx b/packages/docs/src/mdx/docs/conversation/conversation-plugins.mdx index fd0e445..8cb0e7d 100644 --- a/packages/docs/src/mdx/docs/conversation/conversation-plugins.mdx +++ b/packages/docs/src/mdx/docs/conversation/conversation-plugins.mdx @@ -7,4 +7,99 @@ api: classes/ConversationPlugins.html > This is an internal class. You'll interact with it and configure it through the `Conversation` class, but you shouldn't need to instantiate it. - +The `ConversationPlugins` class manages the plugins available to a conversation. +It is also possible for client code to interact with this class through the `Conversation` class in order to access the plugins and their output (`out` property). + +## Configuring in conversation constructor + +You'll most likely be interacting with this class through the `Conversation` class. +More specifically, through the `plugins` property of the `Conversation` constructor. + +```ts +const conversation = new Conversation({ + plugins: [ + /* plugins */ + ], +}); +``` + +For example, if you wanted to use the `gpt-turbo-plugin-stats` plguin, you'd do the following: + +```ts +import { Conversation } from "gpt-turbo"; +import statsPlugin from "gpt-turbo-plugin-stats"; + +const conversation = new Conversation({ + plugins: [statsPlugin] +}); +``` + +> In the example above, `statsPlugin` is actually a function that returns a plugin **definition**, which contains a plugin's lifecycle hooks. +> Internally, this function is referred to as a "plugin **creator**". +> The `ConversationPluginService` class calls the plugin **creator** during the `onInit` lifecycle hook in order to get the plugin **definition**. +> Beyond that, the plugin **creator** is not used and only the plugin **definition** is used. +> +> That being said, the "plugin" word alone takes on different meanings depending on the context: +> - **Plugin creator**: when we're talking about a plugin outside of a `Conversation` instance, like the one we're importing or passing to the `Conversation` constructor. +> - **Plugin definition**: when we're talking about a plugin from within a `Conversation` instance, like the one we're [accessing](#accessing-plugins) through the `plugins` property of the `Conversation` instance. + +## Accessing plugins + +There are various ways you get access to a plugin (definition) in order to interact with it from your client code. +In most cases, you'll be using the plugin's `out` property to get the plugin's output, which is a property that is set by the plugin itself and specifically made to be accessed by client code. +However, the library also allows you to access the plugin's definition directly, which is useful if you want to interact with the plugin's lifecycle hooks manually. + +### Getting all plugins + +You can retrieve all of the plugins of a conversation through the `getPlugins` method. + +```ts +const plugins = conversation.plugins.getPlugins(); +``` + +### Getting a specific plugin by name + +You can retrieve a specific plugin of a conversation, by name, through the `getPlugin` method. + +If you use a static name (i.e. either a constant or a string literal), the returned plugin will be strongly typed, meaning its `out` property will be typed accordingly, given the plugin has a strictly typed plugin output. + +```ts +import statsPlugin, { statsPluginName } from "gpt-turbo-plugin-stats"; + +const conversation = new Conversation({ + plugins: [statsPlugin, someOtherPlugin] +}); + +const plugin = conversation.plugins.getPlugin(statsPluginName); // ConversationPluginDefinition<"gpt-turbo-plugin-stats", ConversationStats, StatsPluginData> +plugin.out; // ConversationStats +``` + +If you're using a static name, but it isn't a known name of the plugins passed to the `Conversation` constructor, the returned plugin will be loosely typed with `any`. + +> If the plugin is not found at runtime, this will throw an error. +> Use `safeGetPlugin` instead if you want to avoid this, which will return `undefined` instead. + +```ts +const plugin = conversation.plugins.getPlugin("asdf"); // ConversationPluginDefinition<"asdf", any, any> +plugin.out; // any +``` + +If you use a dynamic name, the returned plugin will be loosely typed with the union of all known plugins. + +> If you've loaded the plugins dynamically in the `Conversation` constructor, even using a static name will result in a loosely typed plugin. +> This is because the `getPlugin` method's types relies on the type of the `plugins` property of the `Conversation` constructor. +> If this property is loosely typed as a `ConversationPluginDefinition[]` instead of specific plugin types, then the `getPlugin` method can't infer it's type just from a string. + +```ts +const pluginName = getPluginNameFromSomewhere(); // string +const plugin = conversation.plugins.getPlugin(pluginName); // ConversationPluginDefinition +plugin.out; // ConversationStats | SomeOtherPlugin +``` + +### Getting a specific plugin output by name + +Since you'll mostly be using the `out` property of a plugin, there's a shorthand method similar to `getPlugin` that returns the `out` property of a plugin directly: `getPluginOutput` (and `safeGetPluginOutput`). + +```ts +const pluginOutput = conversation.plugins.getPluginOutput(statsPluginName); // ConversationStats +``` diff --git a/packages/docs/src/mdx/docs/conversation/conversation-request-options.mdx b/packages/docs/src/mdx/docs/conversation/conversation-request-options.mdx index 02612c1..c8dfcc0 100644 --- a/packages/docs/src/mdx/docs/conversation/conversation-request-options.mdx +++ b/packages/docs/src/mdx/docs/conversation/conversation-request-options.mdx @@ -7,4 +7,60 @@ api: classes/ConversationRequestOptions.html > This is an internal class. You'll interact with it and configure it through the `Conversation` class, but you shouldn't need to instantiate it. - +The `ConversationRequestOptions` is responsible for configuring options to use when sending HTTP requests to OpenAI's API, whether it's the Chat Completion API or the Moderation API. + +## Configuring in conversation constructor + +You'll most likely be interacting with this class through the `Conversation` class. +More specifically, through the `requestOptions` property of the `Conversation` constructor. + +```ts +const conversation = new Conversation({ + requestOptions: { + /* options */ + }, +}); +``` + +The options you pass are conveniently the same as the [`toJSON`](#serialization-and-deserialization) method: + +- `headers`: Additional headers to send with the request. + These are also sent to the proxy, if one is configured. +- `proxy`: The proxy to use when sending the request. + This is an object with the following properties: + - `host`: The proxy host. + - `port`: The proxy port. + - `protocol`: The proxy protocol. Either `"http"` or `"https"`. + - `auth`: The proxy authentication. + This is an object with the following properties: + - `username`: The proxy username. + - `password`: The proxy password. + + > A header `Proxy-Authorization` is automatically added to the request with the proxy authentication. + > You shouldn't need to add it yourself unless you want to override the default value of "Basic \{auth\}" where `{auth}` is a base64-encoded string of the `username:password`. + +## Serialization and Deserialization + +You can serialize the conversation request options to JSON using the `toJSON` method. +This is especially useful if you want to persist the request options in a database or file. +Use the `toJSON` method to serialize them to JSON. + +```ts +const requestOptions = conversation.requestOptions; +const requestOptionsJson = requestOptions.toJSON(); +``` + +You can then deserialize a conversation's request options from JSON using the `fromJSON` static method. + +```ts +const requestOptions = ConversationRequestOptions.fromJSON(requestOptionsJson); + +// ... do some operations on the requestOptions ... + +const conversation = new Conversation({ + requestOptions: requestOptions.toJSON(), +}); +``` + +> The conversation's request options are automatically serialized/deserialized when serializing a `Conversation`. +> You should only use these methods if you want to serialize/deserialize only the `ConversationRequestOptions`. diff --git a/packages/docs/src/mdx/docs/getting-started/introduction.mdx b/packages/docs/src/mdx/docs/getting-started/introduction.mdx index ad12e1c..54e97b6 100644 --- a/packages/docs/src/mdx/docs/getting-started/introduction.mdx +++ b/packages/docs/src/mdx/docs/getting-started/introduction.mdx @@ -54,20 +54,17 @@ Here's a list of all the home-made [plugins](https://github.com/maxijonson/gpt-t While OpenAI provides an official JavaScript library for interacting with the API, it focuses on providing a basic interface for all of their APIs. This is fine when you're working with multiple of them, but not ideal when you just want to use the Chat Completion API. -GPT Turbo is designed to be a **dedicated library for the Chat Completion API**, and thus provides a much more intuitive interface. +GPT Turbo is designed to be a **dedicated library for the Chat Completion API**, and thus provides an interface centered around it as well as features like conversation history management. One of the pain points of working with the API directly or OpenAI's official JavaScript library was keeping track of the message history. Since you need to send the entire history of messages for each prompt, you need an efficient way to store and update the history. GPT Turbo solves this by providing a `Conversation` class that handles all of this for you. While conversation history management was the main motivation for creating this library, it has grown to do much more than that. -GPT Turbo also supports proxy configuration, message streaming\*, callable functions and plugins. +GPT Turbo also supports proxy configuration, message streaming, callable functions and plugins. Another issue with OpenAI's library is that it is designed as a server-side library, and thus does not support the browser. GPT Turbo is completely isomorphic, and **works in both Node.js and the browser**. -\**Message streaming is part of OpenAI's Chat Completion API, but it uses server-sent events, which can be cumbersome to work with. -GPT Turbo works wraps these server-sent events into a more convenient interface.* - ## API Reference These docs are designed to be clean and concise, and thus do not include the entire API reference.