Skip to content

Commit

Permalink
Add support for prompt roles and prompt preambles (#114)
Browse files Browse the repository at this point in the history
Co-authored-by: Daniel Rosenwasser <[email protected]>
  • Loading branch information
ahejlsberg and DanielRosenwasser authored Nov 7, 2023
1 parent a76e72c commit f9dadc8
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 9 deletions.
26 changes: 22 additions & 4 deletions src/model.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
import axios from "axios";
import { Result, success, error } from "./result";

/**
* Represents a section of an LLM prompt with an associated role. TypeChat uses the "user" role for
* prompts it generates and the "assistant" role for previous LLM responses (which will be part of
* the prompt in repair attempts). TypeChat currently doesn't use the "system" role.
*/
export interface PromptSection {
/**
* Specifies the role of this section.
*/
role: "system" | "user" | "assistant";
/**
* Specifies the content of this section.
*/
content: string;
}

/**
* Represents a AI language model that can complete prompts. TypeChat uses an implementation of this
* interface to communicate with an AI service that can translate natural language requests to JSON
Expand All @@ -18,9 +34,10 @@ export interface TypeChatLanguageModel {
retryPauseMs?: number;
/**
* Obtains a completion from the language model for the given prompt.
* @param prompt The prompt string.
* @param prompt A prompt string or an array of prompt sections. If a string is specified,
* it is converted into a single "user" role prompt section.
*/
complete(prompt: string): Promise<Result<string>>;
complete(prompt: string | PromptSection[]): Promise<Result<string>>;
}

/**
Expand Down Expand Up @@ -93,14 +110,15 @@ function createAxiosLanguageModel(url: string, config: object, defaultParams: Re
};
return model;

async function complete(prompt: string) {
async function complete(prompt: string | PromptSection[]) {
let retryCount = 0;
const retryMaxAttempts = model.retryMaxAttempts ?? 3;
const retryPauseMs = model.retryPauseMs ?? 1000;
const messages = typeof prompt === "string" ? [{ role: "user", content: prompt }] : prompt;
while (true) {
const params = {
...defaultParams,
messages: [{ role: "user", content: prompt }],
messages,
temperature: 0,
n: 1
};
Expand Down
14 changes: 9 additions & 5 deletions src/typechat.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Result, success, error } from "./result";
import { TypeChatLanguageModel } from "./model";
import { TypeChatLanguageModel, PromptSection } from "./model";
import { TypeChatJsonValidator, createJsonValidator } from "./validate";

/**
Expand Down Expand Up @@ -57,9 +57,11 @@ export interface TypeChatJsonTranslator<T extends object> {
* attempt to translate the request will be made. The prompt for the second attempt will include the
* diagnostics produced for the first attempt. This often helps produce a valid instance.
* @param request The natural language request.
* @param promptPreamble An optional string or array of prompt sections to prepend to the generated
* prompt. If a string is specified, it is converted into a single "user" role prompt section.
* @returns A promise for the resulting object.
*/
translate(request: string): Promise<Result<T>>;
translate(request: string, promptPreamble?: string | PromptSection[]): Promise<Result<T>>;
}

/**
Expand Down Expand Up @@ -99,8 +101,9 @@ export function createJsonTranslator<T extends object>(model: TypeChatLanguageMo
`The following is a revised JSON object:\n`;
}

async function translate(request: string) {
let prompt = typeChat.createRequestPrompt(request);
async function translate(request: string, promptPreamble?: string | PromptSection[]) {
const preamble: PromptSection[] = typeof promptPreamble === "string" ? [{ role: "user", content: promptPreamble }] : promptPreamble ?? [];
let prompt: PromptSection[] = [...preamble, { role: "user", content: typeChat.createRequestPrompt(request) }];
let attemptRepair = typeChat.attemptRepair;
while (true) {
const response = await model.complete(prompt);
Expand All @@ -122,7 +125,8 @@ export function createJsonTranslator<T extends object>(model: TypeChatLanguageMo
if (!attemptRepair) {
return error(`JSON validation failed: ${validation.message}\n${jsonText}`);
}
prompt += `${responseText}\n${typeChat.createRepairPrompt(validation.message)}`;
prompt.push({ role: "assistant", content: responseText });
prompt.push({ role: "user", content: typeChat.createRepairPrompt(validation.message) });
attemptRepair = false;
}
}
Expand Down

0 comments on commit f9dadc8

Please sign in to comment.