diff --git a/langchain-core/src/messages/index.ts b/langchain-core/src/messages/index.ts index cdbcaf93604a..91835e46c426 100644 --- a/langchain-core/src/messages/index.ts +++ b/langchain-core/src/messages/index.ts @@ -35,8 +35,7 @@ export type MessageType = | "generic" | "system" | "function" - | "tool" - | "placeholder"; + | "tool"; type ImageDetail = "auto" | "low" | "high"; @@ -406,39 +405,6 @@ export class AIMessageChunk extends BaseMessageChunk { } } -export class PlaceholderMessage extends BaseMessage { - static lc_name() { - return "PlaceholderMessage"; - } - - _getType(): MessageType { - return "placeholder"; - } -} - -export class PlaceholderMessageChunk extends BaseMessageChunk { - static lc_name() { - return "PlaceholderMessageChunk"; - } - - _getType(): MessageType { - return "placeholder"; - } - - concat(chunk: PlaceholderMessageChunk) { - return new PlaceholderMessageChunk({ - content: mergeContent(this.content, chunk.content), - additional_kwargs: _mergeDicts( - this.additional_kwargs, - chunk.additional_kwargs - ), - response_metadata: _mergeDicts( - this.response_metadata, - chunk.response_metadata - ), - }); - } -} /** * Represents a system message in a conversation. */ @@ -664,7 +630,12 @@ export class ChatMessage export type BaseMessageLike = | BaseMessage - | [StringWithAutocomplete, MessageContent] + | [ + StringWithAutocomplete< + MessageType | "user" | "assistant" | "placeholder" + >, + MessageContent + ] | string; export function isBaseMessage( @@ -697,8 +668,6 @@ export function coerceMessageLikeToMessage( return new AIMessage({ content }); } else if (type === "system") { return new SystemMessage({ content }); - } else if (type === "placeholder") { - return new PlaceholderMessage({ content }); } else { throw new Error( `Unable to coerce message from array: only human, AI, or system message coercion is currently supported.` diff --git a/langchain-core/src/prompts/chat.ts b/langchain-core/src/prompts/chat.ts index 45e4563fa263..83b61d8547db 100644 --- a/langchain-core/src/prompts/chat.ts +++ b/langchain-core/src/prompts/chat.ts @@ -6,7 +6,6 @@ import { AIMessage, HumanMessage, SystemMessage, - PlaceholderMessage, BaseMessage, ChatMessage, type BaseMessageLike, @@ -348,8 +347,7 @@ interface _ImageTemplateParam { type MessageClass = | typeof HumanMessage | typeof AIMessage - | typeof SystemMessage - | typeof PlaceholderMessage; + | typeof SystemMessage; type ChatMessageClass = typeof ChatMessage; @@ -644,19 +642,6 @@ export class SystemMessagePromptTemplate< } } -export class MessagesPlaceholderPromptTemplate< - // eslint-disable-next-line @typescript-eslint/no-explicit-any - RunInput extends InputValues = any -> extends MessagesPlaceholder { - static _messageClass(): typeof PlaceholderMessage { - return PlaceholderMessage; - } - - static lc_name() { - return "MessagesPlaceholderPromptTemplate"; - } -} - /** * Interface for the input of a ChatPromptTemplate. */ @@ -701,6 +686,23 @@ function _coerceMessagePromptTemplateLike( ) { return messagePromptTemplateLike; } + if ( + Array.isArray(messagePromptTemplateLike) && + messagePromptTemplateLike[0] === "placeholder" + ) { + const messageContent = messagePromptTemplateLike[1]; + if ( + typeof messageContent !== "string" || + messageContent[0] !== "{" || + messageContent[messageContent.length - 1] !== "}" + ) { + throw new Error( + `Invalid placeholder template: "${messagePromptTemplateLike[1]}". Expected a variable name surrounded by curly braces.` + ); + } + const variableName = messageContent.slice(1, -1); + return new MessagesPlaceholder({ variableName, optional: true }); + } const message = coerceMessageLikeToMessage(messagePromptTemplateLike); if (message._getType() === "human") { return HumanMessagePromptTemplate.fromTemplate(message.content); @@ -708,8 +710,6 @@ function _coerceMessagePromptTemplateLike( return AIMessagePromptTemplate.fromTemplate(message.content); } else if (message._getType() === "system") { return SystemMessagePromptTemplate.fromTemplate(message.content); - } else if (message._getType() === "placeholder") { - return new MessagesPlaceholderPromptTemplate(message.content as string); } else if (ChatMessage.isInstance(message)) { return ChatMessagePromptTemplate.fromTemplate( message.content as string, diff --git a/langchain-core/src/prompts/tests/chat.test.ts b/langchain-core/src/prompts/tests/chat.test.ts index bc6c003e0b1f..d5a4b859f5a6 100644 --- a/langchain-core/src/prompts/tests/chat.test.ts +++ b/langchain-core/src/prompts/tests/chat.test.ts @@ -306,6 +306,23 @@ test("Test MessagesPlaceholder not optional", async () => { ); }); +test.only("Test MessagesPlaceholder shorthand in a chat prompt template should throw for invalid syntax", async () => { + expect(() => + ChatPromptTemplate.fromMessages([["placeholder", "foo"]]) + ).toThrow(); +}); + +test.only("Test MessagesPlaceholder shorthand in a chat prompt template", async () => { + const prompt = ChatPromptTemplate.fromMessages([["placeholder", "{foo}"]]); + const messages = await prompt.formatMessages({ + foo: [new HumanMessage("Hi there!"), new AIMessage("how r u")], + }); + expect(messages).toEqual([ + new HumanMessage("Hi there!"), + new AIMessage("how r u"), + ]); +}); + test("Test using partial", async () => { const userPrompt = new PromptTemplate({ template: "{foo}{bar}",