@langchain/core 0.2.10 → 0.2.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/documents/document.cjs +16 -0
- package/dist/documents/document.d.ts +21 -0
- package/dist/documents/document.js +16 -0
- package/dist/language_models/tests/chat_models.test.js +17 -0
- package/dist/messages/base.d.ts +3 -1
- package/dist/messages/utils.cjs +19 -10
- package/dist/messages/utils.js +19 -10
- package/dist/prompts/chat.cjs +22 -16
- package/dist/prompts/chat.d.ts +0 -1
- package/dist/prompts/chat.js +22 -16
- package/dist/prompts/image.cjs +1 -7
- package/dist/prompts/image.js +2 -8
- package/dist/prompts/template.cjs +10 -1
- package/dist/prompts/template.js +10 -1
- package/dist/prompts/tests/chat.mustache.test.js +28 -0
- package/dist/prompts/tests/chat.test.js +51 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -85,7 +85,7 @@ Rather than having to write multiple implementations for all of those, LCEL allo
|
|
|
85
85
|
|
|
86
86
|
For more check out the [LCEL docs](https://js.langchain.com/v0.2/docs/concepts#langchain-expression-language).
|
|
87
87
|
|
|
88
|
-

|
|
89
89
|
|
|
90
90
|
## 📕 Releases & Versioning
|
|
91
91
|
|
|
@@ -18,9 +18,25 @@ class Document {
|
|
|
18
18
|
writable: true,
|
|
19
19
|
value: void 0
|
|
20
20
|
});
|
|
21
|
+
// The ID field is optional at the moment.
|
|
22
|
+
// It will likely become required in a future major release after
|
|
23
|
+
// it has been adopted by enough vectorstore implementations.
|
|
24
|
+
/**
|
|
25
|
+
* An optional identifier for the document.
|
|
26
|
+
*
|
|
27
|
+
* Ideally this should be unique across the document collection and formatted
|
|
28
|
+
* as a UUID, but this will not be enforced.
|
|
29
|
+
*/
|
|
30
|
+
Object.defineProperty(this, "id", {
|
|
31
|
+
enumerable: true,
|
|
32
|
+
configurable: true,
|
|
33
|
+
writable: true,
|
|
34
|
+
value: void 0
|
|
35
|
+
});
|
|
21
36
|
this.pageContent =
|
|
22
37
|
fields.pageContent !== undefined ? fields.pageContent.toString() : "";
|
|
23
38
|
this.metadata = fields.metadata ?? {};
|
|
39
|
+
this.id = fields.id;
|
|
24
40
|
}
|
|
25
41
|
}
|
|
26
42
|
exports.Document = Document;
|
|
@@ -1,10 +1,24 @@
|
|
|
1
1
|
export interface DocumentInput<Metadata extends Record<string, any> = Record<string, any>> {
|
|
2
2
|
pageContent: string;
|
|
3
3
|
metadata?: Metadata;
|
|
4
|
+
/**
|
|
5
|
+
* An optional identifier for the document.
|
|
6
|
+
*
|
|
7
|
+
* Ideally this should be unique across the document collection and formatted
|
|
8
|
+
* as a UUID, but this will not be enforced.
|
|
9
|
+
*/
|
|
10
|
+
id?: string;
|
|
4
11
|
}
|
|
5
12
|
export interface DocumentInterface<Metadata extends Record<string, any> = Record<string, any>> {
|
|
6
13
|
pageContent: string;
|
|
7
14
|
metadata: Metadata;
|
|
15
|
+
/**
|
|
16
|
+
* An optional identifier for the document.
|
|
17
|
+
*
|
|
18
|
+
* Ideally this should be unique across the document collection and formatted
|
|
19
|
+
* as a UUID, but this will not be enforced.
|
|
20
|
+
*/
|
|
21
|
+
id?: string;
|
|
8
22
|
}
|
|
9
23
|
/**
|
|
10
24
|
* Interface for interacting with a document.
|
|
@@ -12,5 +26,12 @@ export interface DocumentInterface<Metadata extends Record<string, any> = Record
|
|
|
12
26
|
export declare class Document<Metadata extends Record<string, any> = Record<string, any>> implements DocumentInput, DocumentInterface {
|
|
13
27
|
pageContent: string;
|
|
14
28
|
metadata: Metadata;
|
|
29
|
+
/**
|
|
30
|
+
* An optional identifier for the document.
|
|
31
|
+
*
|
|
32
|
+
* Ideally this should be unique across the document collection and formatted
|
|
33
|
+
* as a UUID, but this will not be enforced.
|
|
34
|
+
*/
|
|
35
|
+
id?: string;
|
|
15
36
|
constructor(fields: DocumentInput<Metadata>);
|
|
16
37
|
}
|
|
@@ -15,8 +15,24 @@ export class Document {
|
|
|
15
15
|
writable: true,
|
|
16
16
|
value: void 0
|
|
17
17
|
});
|
|
18
|
+
// The ID field is optional at the moment.
|
|
19
|
+
// It will likely become required in a future major release after
|
|
20
|
+
// it has been adopted by enough vectorstore implementations.
|
|
21
|
+
/**
|
|
22
|
+
* An optional identifier for the document.
|
|
23
|
+
*
|
|
24
|
+
* Ideally this should be unique across the document collection and formatted
|
|
25
|
+
* as a UUID, but this will not be enforced.
|
|
26
|
+
*/
|
|
27
|
+
Object.defineProperty(this, "id", {
|
|
28
|
+
enumerable: true,
|
|
29
|
+
configurable: true,
|
|
30
|
+
writable: true,
|
|
31
|
+
value: void 0
|
|
32
|
+
});
|
|
18
33
|
this.pageContent =
|
|
19
34
|
fields.pageContent !== undefined ? fields.pageContent.toString() : "";
|
|
20
35
|
this.metadata = fields.metadata ?? {};
|
|
36
|
+
this.id = fields.id;
|
|
21
37
|
}
|
|
22
38
|
}
|
|
@@ -3,6 +3,23 @@ import { test } from "@jest/globals";
|
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
5
5
|
import { FakeChatModel, FakeListChatModel } from "../../utils/testing/index.js";
|
|
6
|
+
test("Test ChatModel accepts array shorthand for messages", async () => {
|
|
7
|
+
const model = new FakeChatModel({});
|
|
8
|
+
const response = await model.invoke([["human", "Hello there!"]]);
|
|
9
|
+
expect(response.content).toEqual("Hello there!");
|
|
10
|
+
});
|
|
11
|
+
test("Test ChatModel accepts object shorthand for messages", async () => {
|
|
12
|
+
const model = new FakeChatModel({});
|
|
13
|
+
const response = await model.invoke([
|
|
14
|
+
{
|
|
15
|
+
type: "human",
|
|
16
|
+
content: "Hello there!",
|
|
17
|
+
additional_kwargs: {},
|
|
18
|
+
example: true,
|
|
19
|
+
},
|
|
20
|
+
]);
|
|
21
|
+
expect(response.content).toEqual("Hello there!");
|
|
22
|
+
});
|
|
6
23
|
test("Test ChatModel uses callbacks", async () => {
|
|
7
24
|
const model = new FakeChatModel({});
|
|
8
25
|
let acc = "";
|
package/dist/messages/base.d.ts
CHANGED
|
@@ -140,7 +140,9 @@ export declare function _mergeLists(left?: any[], right?: any[]): any[] | undefi
|
|
|
140
140
|
export declare abstract class BaseMessageChunk extends BaseMessage {
|
|
141
141
|
abstract concat(chunk: BaseMessageChunk): BaseMessageChunk;
|
|
142
142
|
}
|
|
143
|
-
export type BaseMessageLike = BaseMessage |
|
|
143
|
+
export type BaseMessageLike = BaseMessage | ({
|
|
144
|
+
type: MessageType | "user" | "assistant" | "placeholder";
|
|
145
|
+
} & BaseMessageFields & Record<string, unknown>) | [
|
|
144
146
|
StringWithAutocomplete<MessageType | "user" | "assistant" | "placeholder">,
|
|
145
147
|
MessageContent
|
|
146
148
|
] | string;
|
package/dist/messages/utils.cjs
CHANGED
|
@@ -8,6 +8,21 @@ const function_js_1 = require("./function.cjs");
|
|
|
8
8
|
const human_js_1 = require("./human.cjs");
|
|
9
9
|
const system_js_1 = require("./system.cjs");
|
|
10
10
|
const tool_js_1 = require("./tool.cjs");
|
|
11
|
+
function _constructMessageFromParams(params) {
|
|
12
|
+
const { type, ...rest } = params;
|
|
13
|
+
if (type === "human" || type === "user") {
|
|
14
|
+
return new human_js_1.HumanMessage(rest);
|
|
15
|
+
}
|
|
16
|
+
else if (type === "ai" || type === "assistant") {
|
|
17
|
+
return new ai_js_1.AIMessage(rest);
|
|
18
|
+
}
|
|
19
|
+
else if (type === "system") {
|
|
20
|
+
return new system_js_1.SystemMessage(rest);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
throw new Error(`Unable to coerce message from array: only human, AI, or system message coercion is currently supported.`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
11
26
|
function coerceMessageLikeToMessage(messageLike) {
|
|
12
27
|
if (typeof messageLike === "string") {
|
|
13
28
|
return new human_js_1.HumanMessage(messageLike);
|
|
@@ -15,18 +30,12 @@ function coerceMessageLikeToMessage(messageLike) {
|
|
|
15
30
|
else if ((0, base_js_1.isBaseMessage)(messageLike)) {
|
|
16
31
|
return messageLike;
|
|
17
32
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
return
|
|
21
|
-
}
|
|
22
|
-
else if (type === "ai" || type === "assistant") {
|
|
23
|
-
return new ai_js_1.AIMessage({ content });
|
|
24
|
-
}
|
|
25
|
-
else if (type === "system") {
|
|
26
|
-
return new system_js_1.SystemMessage({ content });
|
|
33
|
+
if (Array.isArray(messageLike)) {
|
|
34
|
+
const [type, content] = messageLike;
|
|
35
|
+
return _constructMessageFromParams({ type, content });
|
|
27
36
|
}
|
|
28
37
|
else {
|
|
29
|
-
|
|
38
|
+
return _constructMessageFromParams(messageLike);
|
|
30
39
|
}
|
|
31
40
|
}
|
|
32
41
|
exports.coerceMessageLikeToMessage = coerceMessageLikeToMessage;
|
package/dist/messages/utils.js
CHANGED
|
@@ -5,6 +5,21 @@ import { FunctionMessage, FunctionMessageChunk, } from "./function.js";
|
|
|
5
5
|
import { HumanMessage, HumanMessageChunk } from "./human.js";
|
|
6
6
|
import { SystemMessage, SystemMessageChunk } from "./system.js";
|
|
7
7
|
import { ToolMessage } from "./tool.js";
|
|
8
|
+
function _constructMessageFromParams(params) {
|
|
9
|
+
const { type, ...rest } = params;
|
|
10
|
+
if (type === "human" || type === "user") {
|
|
11
|
+
return new HumanMessage(rest);
|
|
12
|
+
}
|
|
13
|
+
else if (type === "ai" || type === "assistant") {
|
|
14
|
+
return new AIMessage(rest);
|
|
15
|
+
}
|
|
16
|
+
else if (type === "system") {
|
|
17
|
+
return new SystemMessage(rest);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
throw new Error(`Unable to coerce message from array: only human, AI, or system message coercion is currently supported.`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
8
23
|
export function coerceMessageLikeToMessage(messageLike) {
|
|
9
24
|
if (typeof messageLike === "string") {
|
|
10
25
|
return new HumanMessage(messageLike);
|
|
@@ -12,18 +27,12 @@ export function coerceMessageLikeToMessage(messageLike) {
|
|
|
12
27
|
else if (isBaseMessage(messageLike)) {
|
|
13
28
|
return messageLike;
|
|
14
29
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
return
|
|
18
|
-
}
|
|
19
|
-
else if (type === "ai" || type === "assistant") {
|
|
20
|
-
return new AIMessage({ content });
|
|
21
|
-
}
|
|
22
|
-
else if (type === "system") {
|
|
23
|
-
return new SystemMessage({ content });
|
|
30
|
+
if (Array.isArray(messageLike)) {
|
|
31
|
+
const [type, content] = messageLike;
|
|
32
|
+
return _constructMessageFromParams({ type, content });
|
|
24
33
|
}
|
|
25
34
|
else {
|
|
26
|
-
|
|
35
|
+
return _constructMessageFromParams(messageLike);
|
|
27
36
|
}
|
|
28
37
|
}
|
|
29
38
|
/**
|
package/dist/prompts/chat.cjs
CHANGED
|
@@ -75,33 +75,37 @@ class MessagesPlaceholder extends BaseMessagePromptTemplate {
|
|
|
75
75
|
get inputVariables() {
|
|
76
76
|
return [this.variableName];
|
|
77
77
|
}
|
|
78
|
-
|
|
78
|
+
async formatMessages(values) {
|
|
79
|
+
const input = values[this.variableName];
|
|
79
80
|
if (this.optional && !input) {
|
|
80
|
-
return
|
|
81
|
+
return [];
|
|
81
82
|
}
|
|
82
83
|
else if (!input) {
|
|
83
|
-
const error = new Error(`
|
|
84
|
+
const error = new Error(`Field "${this.variableName}" in prompt uses a MessagesPlaceholder, which expects an array of BaseMessages as an input value. Received: undefined`);
|
|
84
85
|
error.name = "InputFormatError";
|
|
85
86
|
throw error;
|
|
86
87
|
}
|
|
87
|
-
let
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
88
|
+
let formattedMessages;
|
|
89
|
+
try {
|
|
90
|
+
if (Array.isArray(input)) {
|
|
91
|
+
formattedMessages = input.map(index_js_1.coerceMessageLikeToMessage);
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
formattedMessages = [(0, index_js_1.coerceMessageLikeToMessage)(input)];
|
|
95
|
+
}
|
|
96
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
93
97
|
}
|
|
94
|
-
|
|
98
|
+
catch (e) {
|
|
95
99
|
const readableInput = typeof input === "string" ? input : JSON.stringify(input, null, 2);
|
|
96
|
-
const error = new Error(
|
|
100
|
+
const error = new Error([
|
|
101
|
+
`Field "${this.variableName}" in prompt uses a MessagesPlaceholder, which expects an array of BaseMessages or coerceable values as input.`,
|
|
102
|
+
`Received value: ${readableInput}`,
|
|
103
|
+
`Additional message: ${e.message}`,
|
|
104
|
+
].join("\n\n"));
|
|
97
105
|
error.name = "InputFormatError";
|
|
98
106
|
throw error;
|
|
99
107
|
}
|
|
100
|
-
return
|
|
101
|
-
}
|
|
102
|
-
async formatMessages(values) {
|
|
103
|
-
this.validateInputOrThrow(values[this.variableName], this.variableName);
|
|
104
|
-
return values[this.variableName] ?? [];
|
|
108
|
+
return formattedMessages;
|
|
105
109
|
}
|
|
106
110
|
}
|
|
107
111
|
exports.MessagesPlaceholder = MessagesPlaceholder;
|
|
@@ -329,6 +333,7 @@ class _StringImageMessagePromptTemplate extends BaseMessagePromptTemplate {
|
|
|
329
333
|
imgTemplateObject = new image_js_1.ImagePromptTemplate({
|
|
330
334
|
template: imgTemplate,
|
|
331
335
|
inputVariables,
|
|
336
|
+
templateFormat: additionalOptions?.templateFormat,
|
|
332
337
|
});
|
|
333
338
|
}
|
|
334
339
|
else if (typeof imgTemplate === "object") {
|
|
@@ -348,6 +353,7 @@ class _StringImageMessagePromptTemplate extends BaseMessagePromptTemplate {
|
|
|
348
353
|
imgTemplateObject = new image_js_1.ImagePromptTemplate({
|
|
349
354
|
template: imgTemplate,
|
|
350
355
|
inputVariables,
|
|
356
|
+
templateFormat: additionalOptions?.templateFormat,
|
|
351
357
|
});
|
|
352
358
|
}
|
|
353
359
|
else {
|
package/dist/prompts/chat.d.ts
CHANGED
|
@@ -50,7 +50,6 @@ export declare class MessagesPlaceholder<RunInput extends InputValues = any> ext
|
|
|
50
50
|
constructor(variableName: Extract<keyof RunInput, string>);
|
|
51
51
|
constructor(fields: MessagesPlaceholderFields<Extract<keyof RunInput, string>>);
|
|
52
52
|
get inputVariables(): Extract<keyof RunInput, string>[];
|
|
53
|
-
validateInputOrThrow(input: Array<unknown> | undefined, variableName: Extract<keyof RunInput, string>): input is BaseMessage[];
|
|
54
53
|
formatMessages(values: TypedPromptInputValues<RunInput>): Promise<BaseMessage[]>;
|
|
55
54
|
}
|
|
56
55
|
/**
|
package/dist/prompts/chat.js
CHANGED
|
@@ -71,33 +71,37 @@ export class MessagesPlaceholder extends BaseMessagePromptTemplate {
|
|
|
71
71
|
get inputVariables() {
|
|
72
72
|
return [this.variableName];
|
|
73
73
|
}
|
|
74
|
-
|
|
74
|
+
async formatMessages(values) {
|
|
75
|
+
const input = values[this.variableName];
|
|
75
76
|
if (this.optional && !input) {
|
|
76
|
-
return
|
|
77
|
+
return [];
|
|
77
78
|
}
|
|
78
79
|
else if (!input) {
|
|
79
|
-
const error = new Error(`
|
|
80
|
+
const error = new Error(`Field "${this.variableName}" in prompt uses a MessagesPlaceholder, which expects an array of BaseMessages as an input value. Received: undefined`);
|
|
80
81
|
error.name = "InputFormatError";
|
|
81
82
|
throw error;
|
|
82
83
|
}
|
|
83
|
-
let
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
84
|
+
let formattedMessages;
|
|
85
|
+
try {
|
|
86
|
+
if (Array.isArray(input)) {
|
|
87
|
+
formattedMessages = input.map(coerceMessageLikeToMessage);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
formattedMessages = [coerceMessageLikeToMessage(input)];
|
|
91
|
+
}
|
|
92
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
89
93
|
}
|
|
90
|
-
|
|
94
|
+
catch (e) {
|
|
91
95
|
const readableInput = typeof input === "string" ? input : JSON.stringify(input, null, 2);
|
|
92
|
-
const error = new Error(
|
|
96
|
+
const error = new Error([
|
|
97
|
+
`Field "${this.variableName}" in prompt uses a MessagesPlaceholder, which expects an array of BaseMessages or coerceable values as input.`,
|
|
98
|
+
`Received value: ${readableInput}`,
|
|
99
|
+
`Additional message: ${e.message}`,
|
|
100
|
+
].join("\n\n"));
|
|
93
101
|
error.name = "InputFormatError";
|
|
94
102
|
throw error;
|
|
95
103
|
}
|
|
96
|
-
return
|
|
97
|
-
}
|
|
98
|
-
async formatMessages(values) {
|
|
99
|
-
this.validateInputOrThrow(values[this.variableName], this.variableName);
|
|
100
|
-
return values[this.variableName] ?? [];
|
|
104
|
+
return formattedMessages;
|
|
101
105
|
}
|
|
102
106
|
}
|
|
103
107
|
/**
|
|
@@ -321,6 +325,7 @@ class _StringImageMessagePromptTemplate extends BaseMessagePromptTemplate {
|
|
|
321
325
|
imgTemplateObject = new ImagePromptTemplate({
|
|
322
326
|
template: imgTemplate,
|
|
323
327
|
inputVariables,
|
|
328
|
+
templateFormat: additionalOptions?.templateFormat,
|
|
324
329
|
});
|
|
325
330
|
}
|
|
326
331
|
else if (typeof imgTemplate === "object") {
|
|
@@ -340,6 +345,7 @@ class _StringImageMessagePromptTemplate extends BaseMessagePromptTemplate {
|
|
|
340
345
|
imgTemplateObject = new ImagePromptTemplate({
|
|
341
346
|
template: imgTemplate,
|
|
342
347
|
inputVariables,
|
|
348
|
+
templateFormat: additionalOptions?.templateFormat,
|
|
343
349
|
});
|
|
344
350
|
}
|
|
345
351
|
else {
|
package/dist/prompts/image.cjs
CHANGED
|
@@ -81,13 +81,7 @@ class ImagePromptTemplate extends base_js_1.BasePromptTemplate {
|
|
|
81
81
|
const formatted = {};
|
|
82
82
|
for (const [key, value] of Object.entries(this.template)) {
|
|
83
83
|
if (typeof value === "string") {
|
|
84
|
-
formatted[key] =
|
|
85
|
-
const replacement = values[group];
|
|
86
|
-
return typeof replacement === "string" ||
|
|
87
|
-
typeof replacement === "number"
|
|
88
|
-
? String(replacement)
|
|
89
|
-
: match;
|
|
90
|
-
});
|
|
84
|
+
formatted[key] = (0, template_js_1.renderTemplate)(value, this.templateFormat, values);
|
|
91
85
|
}
|
|
92
86
|
else {
|
|
93
87
|
formatted[key] = value;
|
package/dist/prompts/image.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ImagePromptValue } from "../prompt_values.js";
|
|
2
2
|
import { BasePromptTemplate, } from "./base.js";
|
|
3
|
-
import { checkValidTemplate } from "./template.js";
|
|
3
|
+
import { checkValidTemplate, renderTemplate, } from "./template.js";
|
|
4
4
|
/**
|
|
5
5
|
* An image prompt template for a multimodal model.
|
|
6
6
|
*/
|
|
@@ -78,13 +78,7 @@ export class ImagePromptTemplate extends BasePromptTemplate {
|
|
|
78
78
|
const formatted = {};
|
|
79
79
|
for (const [key, value] of Object.entries(this.template)) {
|
|
80
80
|
if (typeof value === "string") {
|
|
81
|
-
formatted[key] = value
|
|
82
|
-
const replacement = values[group];
|
|
83
|
-
return typeof replacement === "string" ||
|
|
84
|
-
typeof replacement === "number"
|
|
85
|
-
? String(replacement)
|
|
86
|
-
: match;
|
|
87
|
-
});
|
|
81
|
+
formatted[key] = renderTemplate(value, this.templateFormat, values);
|
|
88
82
|
}
|
|
89
83
|
else {
|
|
90
84
|
formatted[key] = value;
|
|
@@ -5,6 +5,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.checkValidTemplate = exports.parseTemplate = exports.renderTemplate = exports.DEFAULT_PARSER_MAPPING = exports.DEFAULT_FORMATTER_MAPPING = exports.interpolateMustache = exports.interpolateFString = exports.parseMustache = exports.parseFString = void 0;
|
|
7
7
|
const mustache_1 = __importDefault(require("mustache"));
|
|
8
|
+
function configureMustache() {
|
|
9
|
+
// Use unescaped HTML
|
|
10
|
+
// https://github.com/janl/mustache.js?tab=readme-ov-file#variables
|
|
11
|
+
mustache_1.default.escape = (text) => text;
|
|
12
|
+
}
|
|
8
13
|
const parseFString = (template) => {
|
|
9
14
|
// Core logic replicated from internals of pythons built in Formatter class.
|
|
10
15
|
// https://github.com/python/cpython/blob/135ec7cefbaffd516b77362ad2b2ad1025af462e/Objects/stringlib/unicode_format.h#L700-L706
|
|
@@ -76,6 +81,7 @@ const mustacheTemplateToNodes = (template) => template.map((temp) => {
|
|
|
76
81
|
}
|
|
77
82
|
});
|
|
78
83
|
const parseMustache = (template) => {
|
|
84
|
+
configureMustache();
|
|
79
85
|
const parsed = mustache_1.default.parse(template);
|
|
80
86
|
return mustacheTemplateToNodes(parsed);
|
|
81
87
|
};
|
|
@@ -90,7 +96,10 @@ const interpolateFString = (template, values) => (0, exports.parseFString)(templ
|
|
|
90
96
|
return res + node.text;
|
|
91
97
|
}, "");
|
|
92
98
|
exports.interpolateFString = interpolateFString;
|
|
93
|
-
const interpolateMustache = (template, values) =>
|
|
99
|
+
const interpolateMustache = (template, values) => {
|
|
100
|
+
configureMustache();
|
|
101
|
+
return mustache_1.default.render(template, values);
|
|
102
|
+
};
|
|
94
103
|
exports.interpolateMustache = interpolateMustache;
|
|
95
104
|
exports.DEFAULT_FORMATTER_MAPPING = {
|
|
96
105
|
"f-string": exports.interpolateFString,
|
package/dist/prompts/template.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import mustache from "mustache";
|
|
2
|
+
function configureMustache() {
|
|
3
|
+
// Use unescaped HTML
|
|
4
|
+
// https://github.com/janl/mustache.js?tab=readme-ov-file#variables
|
|
5
|
+
mustache.escape = (text) => text;
|
|
6
|
+
}
|
|
2
7
|
export const parseFString = (template) => {
|
|
3
8
|
// Core logic replicated from internals of pythons built in Formatter class.
|
|
4
9
|
// https://github.com/python/cpython/blob/135ec7cefbaffd516b77362ad2b2ad1025af462e/Objects/stringlib/unicode_format.h#L700-L706
|
|
@@ -69,6 +74,7 @@ const mustacheTemplateToNodes = (template) => template.map((temp) => {
|
|
|
69
74
|
}
|
|
70
75
|
});
|
|
71
76
|
export const parseMustache = (template) => {
|
|
77
|
+
configureMustache();
|
|
72
78
|
const parsed = mustache.parse(template);
|
|
73
79
|
return mustacheTemplateToNodes(parsed);
|
|
74
80
|
};
|
|
@@ -81,7 +87,10 @@ export const interpolateFString = (template, values) => parseFString(template).r
|
|
|
81
87
|
}
|
|
82
88
|
return res + node.text;
|
|
83
89
|
}, "");
|
|
84
|
-
export const interpolateMustache = (template, values) =>
|
|
90
|
+
export const interpolateMustache = (template, values) => {
|
|
91
|
+
configureMustache();
|
|
92
|
+
return mustache.render(template, values);
|
|
93
|
+
};
|
|
85
94
|
export const DEFAULT_FORMATTER_MAPPING = {
|
|
86
95
|
"f-string": interpolateFString,
|
|
87
96
|
mustache: interpolateMustache,
|
|
@@ -78,6 +78,22 @@ test("Mustache template with image and chat prompts inside one template (fromMes
|
|
|
78
78
|
], {
|
|
79
79
|
templateFormat: "mustache",
|
|
80
80
|
});
|
|
81
|
+
const messages = await template.formatMessages({
|
|
82
|
+
name: "Bob",
|
|
83
|
+
image_url: "https://foo.com/bar.png",
|
|
84
|
+
other_var: "bar",
|
|
85
|
+
});
|
|
86
|
+
expect(messages).toEqual([
|
|
87
|
+
new HumanMessage({
|
|
88
|
+
content: [
|
|
89
|
+
{ type: "image_url", image_url: { url: "https://foo.com/bar.png" } },
|
|
90
|
+
{ type: "text", text: "bar" },
|
|
91
|
+
],
|
|
92
|
+
}),
|
|
93
|
+
new HumanMessage({
|
|
94
|
+
content: "hello Bob",
|
|
95
|
+
}),
|
|
96
|
+
]);
|
|
81
97
|
expect(template.inputVariables.sort()).toEqual([
|
|
82
98
|
"image_url",
|
|
83
99
|
"name",
|
|
@@ -97,5 +113,17 @@ test("Mustache image template with nested URL and chat prompts HumanMessagePromp
|
|
|
97
113
|
], {
|
|
98
114
|
templateFormat: "mustache",
|
|
99
115
|
});
|
|
116
|
+
const messages = await template.formatMessages({
|
|
117
|
+
name: "Bob",
|
|
118
|
+
image_url: "https://foo.com/bar.png",
|
|
119
|
+
});
|
|
120
|
+
expect(messages).toEqual([
|
|
121
|
+
new HumanMessage({
|
|
122
|
+
content: [
|
|
123
|
+
{ type: "text", text: "Bob" },
|
|
124
|
+
{ type: "image_url", image_url: { url: "https://foo.com/bar.png" } },
|
|
125
|
+
],
|
|
126
|
+
}),
|
|
127
|
+
]);
|
|
100
128
|
expect(template.inputVariables.sort()).toEqual(["image_url", "name"]);
|
|
101
129
|
});
|
|
@@ -258,7 +258,7 @@ test("Test MessagesPlaceholder not optional", async () => {
|
|
|
258
258
|
variableName: "foo",
|
|
259
259
|
});
|
|
260
260
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
261
|
-
await expect(prompt.formatMessages({})).rejects.toThrow('
|
|
261
|
+
await expect(prompt.formatMessages({})).rejects.toThrow('Field "foo" in prompt uses a MessagesPlaceholder, which expects an array of BaseMessages as an input value. Received: undefined');
|
|
262
262
|
});
|
|
263
263
|
test("Test MessagesPlaceholder shorthand in a chat prompt template should throw for invalid syntax", async () => {
|
|
264
264
|
expect(() => ChatPromptTemplate.fromMessages([["placeholder", "foo"]])).toThrow();
|
|
@@ -273,6 +273,56 @@ test("Test MessagesPlaceholder shorthand in a chat prompt template", async () =>
|
|
|
273
273
|
new AIMessage("how r u"),
|
|
274
274
|
]);
|
|
275
275
|
});
|
|
276
|
+
test("Test MessagesPlaceholder shorthand in a chat prompt template with object format", async () => {
|
|
277
|
+
const prompt = ChatPromptTemplate.fromMessages([["placeholder", "{foo}"]]);
|
|
278
|
+
const messages = await prompt.formatMessages({
|
|
279
|
+
foo: [
|
|
280
|
+
{
|
|
281
|
+
type: "system",
|
|
282
|
+
content: "some initial content",
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
type: "human",
|
|
286
|
+
content: [
|
|
287
|
+
{
|
|
288
|
+
text: "page: 1\ndescription: One Purchase Flow\ntimestamp: '2024-06-04T14:46:46.062Z'\ntype: navigate\nscreenshot_present: true\n",
|
|
289
|
+
type: "text",
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
text: "page: 3\ndescription: intent_str=buy,mode_str=redirect,screenName_str=order-completed,\ntimestamp: '2024-06-04T14:46:58.846Z'\ntype: Screen View\nscreenshot_present: false\n",
|
|
293
|
+
type: "text",
|
|
294
|
+
},
|
|
295
|
+
],
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
type: "assistant",
|
|
299
|
+
content: "some captivating response",
|
|
300
|
+
},
|
|
301
|
+
],
|
|
302
|
+
});
|
|
303
|
+
expect(messages).toEqual([
|
|
304
|
+
new SystemMessage("some initial content"),
|
|
305
|
+
new HumanMessage({
|
|
306
|
+
content: [
|
|
307
|
+
{
|
|
308
|
+
text: "page: 1\ndescription: One Purchase Flow\ntimestamp: '2024-06-04T14:46:46.062Z'\ntype: navigate\nscreenshot_present: true\n",
|
|
309
|
+
type: "text",
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
text: "page: 3\ndescription: intent_str=buy,mode_str=redirect,screenName_str=order-completed,\ntimestamp: '2024-06-04T14:46:58.846Z'\ntype: Screen View\nscreenshot_present: false\n",
|
|
313
|
+
type: "text",
|
|
314
|
+
},
|
|
315
|
+
],
|
|
316
|
+
}),
|
|
317
|
+
new AIMessage("some captivating response"),
|
|
318
|
+
]);
|
|
319
|
+
});
|
|
320
|
+
test("Test MessagesPlaceholder with invalid shorthand should throw", async () => {
|
|
321
|
+
const prompt = ChatPromptTemplate.fromMessages([["placeholder", "{foo}"]]);
|
|
322
|
+
await expect(() => prompt.formatMessages({
|
|
323
|
+
foo: [{ badFormatting: true }],
|
|
324
|
+
})).rejects.toThrow();
|
|
325
|
+
});
|
|
276
326
|
test("Test using partial", async () => {
|
|
277
327
|
const userPrompt = new PromptTemplate({
|
|
278
328
|
template: "{foo}{bar}",
|