Skip to content

Commit

Permalink
Merge pull request langchain-ai#3795 from langchain-ai/nc/26dec/msg-p…
Browse files Browse the repository at this point in the history
…laceholder-optional

Implement optional message placeholder in js
  • Loading branch information
nfcampos authored Dec 26, 2023
2 parents 1eca176 + c556eda commit 5dfef00
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 5 deletions.
27 changes: 22 additions & 5 deletions langchain-core/src/prompts/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,22 +75,28 @@ export abstract class BaseMessagePromptTemplate<
*/
export interface MessagesPlaceholderFields<T extends string> {
variableName: T;
optional?: boolean;
}

/**
* Class that represents a placeholder for messages in a chat prompt. It
* extends the BaseMessagePromptTemplate.
*/
export class MessagesPlaceholder<
// eslint-disable-next-line @typescript-eslint/no-explicit-any
RunInput extends InputValues = any
> extends BaseMessagePromptTemplate<RunInput> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
RunInput extends InputValues = any
>
extends BaseMessagePromptTemplate<RunInput>
implements MessagesPlaceholderFields<Extract<keyof RunInput, string>>
{
static lc_name() {
return "MessagesPlaceholder";
}

variableName: Extract<keyof RunInput, string>;

optional: boolean;

constructor(variableName: Extract<keyof RunInput, string>);

constructor(
Expand All @@ -108,16 +114,27 @@ export class MessagesPlaceholder<
}
super(fields);
this.variableName = fields.variableName;
this.optional = fields.optional ?? false;
}

get inputVariables() {
return [this.variableName];
}

validateInputOrThrow(
input: Array<unknown>,
input: Array<unknown> | undefined,
variableName: Extract<keyof RunInput, string>
): input is BaseMessage[] {
if (this.optional && !input) {
return false;
} else if (!input) {
const error = new Error(
`Error: Field "${variableName}" in prompt uses a MessagesPlaceholder, which expects an array of BaseMessages as an input value. Received: undefined`
);
error.name = "InputFormatError";
throw error;
}

let isInputBaseMessage = false;

if (Array.isArray(input)) {
Expand Down Expand Up @@ -147,7 +164,7 @@ export class MessagesPlaceholder<
): Promise<BaseMessage[]> {
this.validateInputOrThrow(values[this.variableName], this.variableName);

return values[this.variableName];
return values[this.variableName] ?? [];
}
}

Expand Down
20 changes: 20 additions & 0 deletions langchain-core/src/prompts/tests/chat.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,26 @@ test("Test SimpleMessagePromptTemplate", async () => {
expect(messages).toEqual([new HumanMessage("Hello Foo, I'm Bar")]);
});

test("Test MessagesPlaceholder optional", async () => {
const prompt = new MessagesPlaceholder({
variableName: "foo",
optional: true,
});
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const messages = await prompt.formatMessages({} as any);
expect(messages).toEqual([]);
});

test("Test MessagesPlaceholder not optional", async () => {
const prompt = new MessagesPlaceholder({
variableName: "foo",
});
// eslint-disable-next-line @typescript-eslint/no-explicit-any
await expect(prompt.formatMessages({} as any)).rejects.toThrow(
'Error: Field "foo" in prompt uses a MessagesPlaceholder, which expects an array of BaseMessages as an input value. Received: undefined'
);
});

test("Test using partial", async () => {
const userPrompt = new PromptTemplate({
template: "{foo}{bar}",
Expand Down

0 comments on commit 5dfef00

Please sign in to comment.