@m4trix/core 0.5.0 → 0.6.0
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/dist/api/index.d.ts +1 -1
- package/dist/helper/index.cjs +44 -18
- package/dist/helper/index.cjs.map +1 -1
- package/dist/helper/index.d.ts +21 -5
- package/dist/helper/index.js +44 -18
- package/dist/helper/index.js.map +1 -1
- package/dist/index.cjs +761 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +745 -20
- package/dist/index.js.map +1 -1
- package/dist/matrix/index.cjs +724 -0
- package/dist/matrix/index.cjs.map +1 -0
- package/dist/matrix/index.d.ts +398 -0
- package/dist/matrix/index.js +705 -0
- package/dist/matrix/index.js.map +1 -0
- package/dist/react/index.d.ts +1 -1
- package/dist/stream/index.d.ts +1 -1
- package/package.json +14 -8
- package/dist/api/index.d.cts +0 -74
- package/dist/helper/index.d.cts +0 -92
- package/dist/index.d.cts +0 -8
- package/dist/react/index.d.cts +0 -213
- package/dist/stream/index.d.cts +0 -304
- package/dist/ui/index.d.cts +0 -30
package/dist/api/index.d.ts
CHANGED
|
@@ -71,4 +71,4 @@ declare class SocketIoFactory {
|
|
|
71
71
|
private prefixEvent;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
export {
|
|
74
|
+
export { BaseMessage, Message, Role, SocketEventName, SocketIoFactory, TextMessage, VoiceMessage };
|
package/dist/helper/index.cjs
CHANGED
|
@@ -210,41 +210,67 @@ var TransformMessages = class _TransformMessages {
|
|
|
210
210
|
* Format messages according to the specified format type
|
|
211
211
|
*/
|
|
212
212
|
format(formatType) {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
213
|
+
const result = effect.Effect.runSync(
|
|
214
|
+
effect.pipe(
|
|
215
|
+
this.effect,
|
|
216
|
+
effect.Effect.map((messages) => {
|
|
217
|
+
if (formatType === "json" /* JSON */) {
|
|
218
|
+
return JSON.stringify(messages, null, 2);
|
|
219
|
+
}
|
|
220
|
+
const formatter = typeOnFormatter[formatType];
|
|
221
|
+
return formatter(messages);
|
|
222
|
+
})
|
|
223
|
+
)
|
|
222
224
|
);
|
|
225
|
+
return result;
|
|
223
226
|
}
|
|
224
227
|
// Sink methods
|
|
225
228
|
/**
|
|
226
|
-
|
|
227
|
-
|
|
229
|
+
* Convert to array - runs the effect and returns the result
|
|
230
|
+
return pipe(
|
|
231
|
+
this.effect,
|
|
232
|
+
Effect.map((messages) => {
|
|
233
|
+
if (formatType === FormatType.JSON) {
|
|
234
|
+
return JSON.stringify(messages, null, 2);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const formatter = typeOnFormatter[formatType];
|
|
238
|
+
return formatter(messages);
|
|
239
|
+
})
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Sink methods
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Convert to array - runs the effect and returns the result
|
|
247
|
+
*/
|
|
228
248
|
toArray() {
|
|
229
|
-
return this.effect;
|
|
249
|
+
return effect.Effect.runSync(this.effect);
|
|
230
250
|
}
|
|
231
251
|
/**
|
|
232
252
|
* Convert to string - runs the effect and returns JSON string
|
|
233
253
|
*/
|
|
234
254
|
toString() {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
255
|
+
const result = effect.Effect.runSync(
|
|
256
|
+
effect.pipe(
|
|
257
|
+
this.effect,
|
|
258
|
+
effect.Effect.map((messages) => JSON.stringify(messages, null, 2))
|
|
259
|
+
)
|
|
238
260
|
);
|
|
261
|
+
return result;
|
|
239
262
|
}
|
|
240
263
|
/**
|
|
241
264
|
* Get the count of messages
|
|
242
265
|
*/
|
|
243
266
|
count() {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
267
|
+
const result = effect.Effect.runSync(
|
|
268
|
+
effect.pipe(
|
|
269
|
+
this.effect,
|
|
270
|
+
effect.Effect.map((messages) => messages.length)
|
|
271
|
+
)
|
|
247
272
|
);
|
|
273
|
+
return result;
|
|
248
274
|
}
|
|
249
275
|
};
|
|
250
276
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/helper/transform-messages/TransformMessages.ts","../../src/helper/transform-messages/message-filter.ts","../../src/helper/transform-messages/formatter.ts"],"names":["AIMessage","i","msg"],"mappings":"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","sourcesContent":["import { BaseMessage, AIMessage, ToolMessage } from '@langchain/core/messages';\nimport { Effect, pipe } from 'effect';\nimport {\n MessageFilter,\n MessageFilterType,\n typeOnFilter,\n} from './message-filter';\nimport { FormatType, typeOnFormatter } from './formatter';\n\n/**\n * # Transform Messages\n * In order to manage the context size often you want to slice messages or only pass certain types of messages.\n * This class is a helper to do that.\n *\n * ## Example\n * ```ts\n * const messages = [\n * new HumanMessage('Hello, how are you?'),\n * new AIMessage('I am good, thank you!'),\n * ];\n *\n * const transformedMessages = TransformMessages.from(messages).filter(HumanAndAI).last(10).format(FormatType.Concise);\n *\n * ```\n */\n\nclass TransformMessages {\n private effect: Effect.Effect<Array<BaseMessage>, never, never>;\n\n private constructor(effect: Effect.Effect<Array<BaseMessage>, never, never>) {\n this.effect = effect;\n }\n\n /**\n * Create a new TransformMessages from an array of messages.\n */\n static from(messages: Array<BaseMessage>): TransformMessages {\n return new TransformMessages(Effect.succeed(messages));\n }\n\n /**\n * Filter messages based on a predicate function\n */\n filter(\n predicate: MessageFilter | MessageFilterType,\n tags?: Array<string>\n ): TransformMessages {\n let finalPredicate: MessageFilter;\n if (typeof predicate === 'string') {\n finalPredicate = typeOnFilter[predicate];\n } else {\n finalPredicate = predicate;\n }\n\n return new TransformMessages(\n pipe(\n this.effect,\n Effect.map((messages) =>\n messages.filter((message) => finalPredicate(message, tags))\n )\n )\n );\n }\n\n /**\n * Take only the last n messages, but safely.\n * Tool calls should not be separated from the last human message.\n * Ensures all tool call conversations in the last n messages are complete.\n */\n safelyTakeLast(\n n: number,\n pruneAfterNOvershootingMessages: number = 0\n ): TransformMessages {\n return new TransformMessages(\n pipe(\n this.effect,\n Effect.map((messages) => {\n const total = messages.length;\n if (n <= 0 || total === 0) return [];\n\n // Start with the last n messages\n const start = Math.max(0, total - n);\n const end = total;\n const lastSlice = messages.slice(start, end);\n\n // due to the fact that the calling AI message needs to be adjecent to the succeeding tool call message\n // we just need to check the last n messages for tool call ids\n\n // Check the first message if it is a tool call message\n // if it is iterate backwards until we find the AI message\n if (\n lastSlice[0] instanceof ToolMessage &&\n lastSlice[0].tool_call_id\n ) {\n let messagesToInclude: Array<BaseMessage> = [];\n const remainingMessages = messages.slice(0, start);\n for (let i = remainingMessages.length - 1; i >= 0; i--) {\n const msg = remainingMessages[i];\n if (\n pruneAfterNOvershootingMessages > 0 &&\n messagesToInclude.length - 1 >= pruneAfterNOvershootingMessages\n ) {\n messagesToInclude = [];\n // Return the slice but remove all the tool call messages that are at the beginning of the slice\n const filteredSlice: Array<BaseMessage> = [];\n let foundFirstNonToolMessage = false;\n for (let i = 0; i < lastSlice.length; i++) {\n const msg = lastSlice[i];\n if (msg instanceof ToolMessage) {\n if (foundFirstNonToolMessage) {\n filteredSlice.push(msg);\n }\n } else {\n foundFirstNonToolMessage = true;\n filteredSlice.push(msg);\n }\n }\n return filteredSlice;\n }\n if (msg instanceof AIMessage && Array.isArray(msg.tool_calls)) {\n messagesToInclude.push(msg);\n break;\n } else if (msg instanceof ToolMessage) {\n messagesToInclude.push(msg);\n } else {\n // This should not happen messages invalid\n throw new Error(\n 'Messages array invalid no adjacent AI message found'\n );\n }\n }\n return [...messagesToInclude.reverse(), ...lastSlice];\n } else {\n return lastSlice;\n }\n })\n )\n );\n }\n\n /**\n * Take only the last n messages\n */\n last(n: number): TransformMessages {\n return new TransformMessages(\n pipe(\n this.effect,\n Effect.map((messages) => messages.slice(-n))\n )\n );\n }\n\n /**\n * Take only the first n messages\n */\n first(n: number): TransformMessages {\n return new TransformMessages(\n pipe(\n this.effect,\n Effect.map((messages) => messages.slice(0, n))\n )\n );\n }\n\n /**\n * Skip the first n messages\n */\n skip(n: number): TransformMessages {\n return new TransformMessages(\n pipe(\n this.effect,\n Effect.map((messages) => messages.slice(n))\n )\n );\n }\n\n /**\n * Reverse the order of messages\n */\n reverse(): TransformMessages {\n return new TransformMessages(\n pipe(\n this.effect,\n Effect.map((messages) => [...messages].reverse())\n )\n );\n }\n\n /**\n * Map over messages with a transformation function\n */\n map<T extends BaseMessage>(\n fn: (message: BaseMessage) => T\n ): TransformMessages {\n return new TransformMessages(\n pipe(\n this.effect,\n Effect.map((messages) => messages.map(fn))\n )\n );\n }\n\n /**\n * Format messages according to the specified format type\n */\n format(formatType: FormatType): Effect.Effect<string, never, never> {\n return pipe(\n this.effect,\n Effect.map((messages) => {\n if (formatType === FormatType.JSON) {\n return JSON.stringify(messages, null, 2);\n }\n\n const formatter = typeOnFormatter[formatType];\n return formatter(messages);\n })\n );\n }\n\n // Sink methods\n\n /**\n * Convert to array - runs the effect and returns the result\n */\n toArray(): Effect.Effect<Array<BaseMessage>, never, never> {\n return this.effect;\n }\n\n /**\n * Convert to string - runs the effect and returns JSON string\n */\n toString(): Effect.Effect<string, never, never> {\n return pipe(\n this.effect,\n Effect.map((messages) => JSON.stringify(messages, null, 2))\n );\n }\n\n /**\n * Get the count of messages\n */\n count(): Effect.Effect<number, never, never> {\n return pipe(\n this.effect,\n Effect.map((messages) => messages.length)\n );\n }\n}\n\nexport { TransformMessages };\n","import { BaseMessage, HumanMessage, AIMessage } from '@langchain/core/messages';\n\n// Type for message filters\nexport type MessageFilter = (\n message: BaseMessage,\n tags?: Array<string>\n) => boolean;\n// Predefined filters\nconst humanAndAI: MessageFilter = (message) =>\n message instanceof HumanMessage || message instanceof AIMessage;\nconst humanOnly: MessageFilter = (message) => message instanceof HumanMessage;\nconst aiOnly: MessageFilter = (message) => message instanceof AIMessage;\n\nconst includingTags: MessageFilter = (message, tags) => {\n if (tags) {\n return tags.some((tag) =>\n Array.isArray(message.additional_kwargs?.tags)\n ? message.additional_kwargs?.tags.includes(tag)\n : false\n );\n }\n return true;\n};\n\nconst excludingTags: MessageFilter = (message, tags) => {\n if (tags) {\n return !tags.some((tag) =>\n Array.isArray(message.additional_kwargs?.tags)\n ? message.additional_kwargs?.tags.includes(tag)\n : false\n );\n }\n return true;\n};\n\nexport enum MessageFilterType {\n HumanAndAI = 'HumanAndAI',\n HumanOnly = 'HumanOnly',\n AIOnly = 'AIOnly',\n IncludingTags = 'IncludingTags',\n ExcludingTags = 'ExcludingTags',\n}\nexport const typeOnFilter = {\n [MessageFilterType.HumanAndAI]: humanAndAI,\n [MessageFilterType.HumanOnly]: humanOnly,\n [MessageFilterType.AIOnly]: aiOnly,\n [MessageFilterType.IncludingTags]: includingTags,\n [MessageFilterType.ExcludingTags]: excludingTags,\n};\n","import { AIMessage, BaseMessage } from '@langchain/core/messages';\n\n// Format types\nexport enum FormatType {\n Concise = 'concise',\n Verbose = 'verbose',\n RedactAi = 'redact-ai',\n RedactHuman = 'redact-human',\n JSON = 'json',\n}\n\n/**\n * Formats messages in a concise markdown format with alternating AI and Human prefixes.\n *\n * ### Example\n * ```markdown\n * AI: Hello, how are you?\n * Human: I am good, thank you!\n * AI: What is your name?\n * Human: My name is John.\n * AI: What is your favorite color?\n * Human: My favorite color is blue.\n * AI: What is your favorite food?\n * Human: My favorite food is pizza.\n * ```\n */\nfunction concise(messages: Array<BaseMessage>): string {\n return messages\n .map((message) => {\n const prefix = message instanceof AIMessage ? 'AI' : 'Human';\n return `${prefix}: ${message.content}`;\n })\n .join('\\n');\n}\n\n/**\n * Formats messages in a verbose markdown format with alternating AI and Human prefixes.\n *\n * ### Example\n * ```markdown\n * AI:\n * Hello, how are you?\n * -------------------\n * Human:\n * I am good, thank you!\n * -------------------\n * AI:\n * What is your name?\n * -------------------\n * Human:\n * My name is John.\n * ```\n */\nfunction verbose(messages: Array<BaseMessage>): string {\n return messages\n .map((message) => {\n const prefix = message instanceof AIMessage ? 'AI' : 'Human';\n return `${prefix}:\\n${message.content}`;\n })\n .join('\\n-------------------\\n');\n}\n\n/**\n * Formats messages in a concise markdown format, redacting AI messages with [...]\n *\n * ### Example\n * ```markdown\n * AI: [...]\n * Human: Hello, how are you?\n * AI: [...]\n * Human: I am good, thank you!\n * AI: [...]\n * Human: What is your name?\n * AI: [...]\n * Human: My name is John.\n * AI: [...]\n * ```\n */\nfunction redactAi(messages: Array<BaseMessage>): string {\n return messages\n .map((message) => {\n const prefix = message instanceof AIMessage ? 'AI' : 'Human';\n const content = message instanceof AIMessage ? '[...]' : message.content;\n return `${prefix}: ${content}`;\n })\n .join('\\n');\n}\n\n/**\n * Formats messages in a concise markdown format, redacting Human messages with [...]\n *\n * ### Example\n * ```markdown\n * AI: Hello, how are you?\n * Human: [...]\n * AI: What is your name?\n * Human: [...]\n * AI: What is your favorite color?\n * Human: [...]\n * AI: What is your favorite food?\n * Human: [...]\n * ```\n */\nfunction redactHuman(messages: Array<BaseMessage>): string {\n return messages\n .map((message) => {\n const prefix = message instanceof AIMessage ? 'AI' : 'Human';\n const content = message instanceof AIMessage ? '[...]' : message.content;\n return `${prefix}: ${content}`;\n })\n .join('\\n');\n}\nconst typeOnFormatter = {\n [FormatType.Concise]: concise,\n [FormatType.Verbose]: verbose,\n [FormatType.RedactAi]: redactAi,\n [FormatType.RedactHuman]: redactHuman,\n};\n\nexport { typeOnFormatter };\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/helper/transform-messages/TransformMessages.ts","../../src/helper/transform-messages/message-filter.ts","../../src/helper/transform-messages/formatter.ts"],"names":["AIMessage","i","msg"],"mappings":"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","sourcesContent":["import { BaseMessage, AIMessage, ToolMessage } from '@langchain/core/messages';\nimport { Effect, pipe } from 'effect';\nimport {\n MessageFilter,\n MessageFilterType,\n typeOnFilter,\n} from './message-filter';\nimport { FormatType, typeOnFormatter } from './formatter';\n\n/**\n * # Transform Messages\n * In order to manage the context size often you want to slice messages or only pass certain types of messages.\n * This class is a helper to do that.\n *\n * ## Example\n * ```ts\n * const messages = [\n * new HumanMessage('Hello, how are you?'),\n * new AIMessage('I am good, thank you!'),\n * ];\n *\n * const transformedMessages = TransformMessages.from(messages).filter(HumanAndAI).last(10).format(FormatType.Concise);\n *\n * ```\n */\n\nclass TransformMessages {\n private effect: Effect.Effect<Array<BaseMessage>, never, never>;\n\n private constructor(effect: Effect.Effect<Array<BaseMessage>, never, never>) {\n this.effect = effect;\n }\n\n /**\n * Create a new TransformMessages from an array of messages.\n */\n static from(messages: Array<BaseMessage>): TransformMessages {\n return new TransformMessages(Effect.succeed(messages));\n }\n\n /**\n * Filter messages based on a predicate function\n */\n filter(\n predicate: MessageFilter | MessageFilterType,\n tags?: Array<string>\n ): TransformMessages {\n let finalPredicate: MessageFilter;\n if (typeof predicate === 'string') {\n finalPredicate = typeOnFilter[predicate];\n } else {\n finalPredicate = predicate;\n }\n\n return new TransformMessages(\n pipe(\n this.effect,\n Effect.map((messages) =>\n messages.filter((message) => finalPredicate(message, tags))\n )\n )\n );\n }\n\n /**\n * Take only the last n messages, but safely.\n * Tool calls should not be separated from the last human message.\n * Ensures all tool call conversations in the last n messages are complete.\n */\n safelyTakeLast(\n n: number,\n pruneAfterNOvershootingMessages: number = 0\n ): TransformMessages {\n return new TransformMessages(\n pipe(\n this.effect,\n Effect.map((messages) => {\n const total = messages.length;\n if (n <= 0 || total === 0) return [];\n\n // Start with the last n messages\n const start = Math.max(0, total - n);\n const end = total;\n const lastSlice = messages.slice(start, end);\n\n // due to the fact that the calling AI message needs to be adjecent to the succeeding tool call message\n // we just need to check the last n messages for tool call ids\n\n // Check the first message if it is a tool call message\n // if it is iterate backwards until we find the AI message\n if (\n lastSlice[0] instanceof ToolMessage &&\n lastSlice[0].tool_call_id\n ) {\n let messagesToInclude: Array<BaseMessage> = [];\n const remainingMessages = messages.slice(0, start);\n for (let i = remainingMessages.length - 1; i >= 0; i--) {\n const msg = remainingMessages[i];\n if (\n pruneAfterNOvershootingMessages > 0 &&\n messagesToInclude.length - 1 >= pruneAfterNOvershootingMessages\n ) {\n messagesToInclude = [];\n // Return the slice but remove all the tool call messages that are at the beginning of the slice\n const filteredSlice: Array<BaseMessage> = [];\n let foundFirstNonToolMessage = false;\n for (let i = 0; i < lastSlice.length; i++) {\n const msg = lastSlice[i];\n if (msg instanceof ToolMessage) {\n if (foundFirstNonToolMessage) {\n filteredSlice.push(msg);\n }\n } else {\n foundFirstNonToolMessage = true;\n filteredSlice.push(msg);\n }\n }\n return filteredSlice;\n }\n if (msg instanceof AIMessage && Array.isArray(msg.tool_calls)) {\n messagesToInclude.push(msg);\n break;\n } else if (msg instanceof ToolMessage) {\n messagesToInclude.push(msg);\n } else {\n // This should not happen messages invalid\n throw new Error(\n 'Messages array invalid no adjacent AI message found'\n );\n }\n }\n return [...messagesToInclude.reverse(), ...lastSlice];\n } else {\n return lastSlice;\n }\n })\n )\n );\n }\n\n /**\n * Take only the last n messages\n */\n last(n: number): TransformMessages {\n return new TransformMessages(\n pipe(\n this.effect,\n Effect.map((messages) => messages.slice(-n))\n )\n );\n }\n\n /**\n * Take only the first n messages\n */\n first(n: number): TransformMessages {\n return new TransformMessages(\n pipe(\n this.effect,\n Effect.map((messages) => messages.slice(0, n))\n )\n );\n }\n\n /**\n * Skip the first n messages\n */\n skip(n: number): TransformMessages {\n return new TransformMessages(\n pipe(\n this.effect,\n Effect.map((messages) => messages.slice(n))\n )\n );\n }\n\n /**\n * Reverse the order of messages\n */\n reverse(): TransformMessages {\n return new TransformMessages(\n pipe(\n this.effect,\n Effect.map((messages) => [...messages].reverse())\n )\n );\n }\n\n /**\n * Map over messages with a transformation function\n */\n map<T extends BaseMessage>(\n fn: (message: BaseMessage) => T\n ): TransformMessages {\n return new TransformMessages(\n pipe(\n this.effect,\n Effect.map((messages) => messages.map(fn))\n )\n );\n }\n\n /**\n * Format messages according to the specified format type\n */\n format(formatType: FormatType): string {\n const result = Effect.runSync(\n pipe(\n this.effect,\n Effect.map((messages) => {\n if (formatType === FormatType.JSON) {\n return JSON.stringify(messages, null, 2);\n }\n const formatter = typeOnFormatter[formatType];\n return formatter(messages);\n })\n )\n );\n return result;\n }\n\n // Sink methods\n\n /**\n * Convert to array - runs the effect and returns the result\n return pipe(\n this.effect,\n Effect.map((messages) => {\n if (formatType === FormatType.JSON) {\n return JSON.stringify(messages, null, 2);\n }\n\n const formatter = typeOnFormatter[formatType];\n return formatter(messages);\n })\n );\n }\n\n // Sink methods\n\n /**\n * Convert to array - runs the effect and returns the result\n */\n toArray(): Array<BaseMessage> {\n return Effect.runSync(this.effect);\n }\n\n /**\n * Convert to string - runs the effect and returns JSON string\n */\n toString(): string {\n const result = Effect.runSync(\n pipe(\n this.effect,\n Effect.map((messages) => JSON.stringify(messages, null, 2))\n )\n );\n return result;\n }\n\n /**\n * Get the count of messages\n */\n count(): number {\n const result = Effect.runSync(\n pipe(\n this.effect,\n Effect.map((messages) => messages.length)\n )\n );\n return result;\n }\n}\n\nexport { TransformMessages };\n","import { BaseMessage, HumanMessage, AIMessage } from '@langchain/core/messages';\n\n// Type for message filters\nexport type MessageFilter = (\n message: BaseMessage,\n tags?: Array<string>\n) => boolean;\n// Predefined filters\nconst humanAndAI: MessageFilter = (message) =>\n message instanceof HumanMessage || message instanceof AIMessage;\nconst humanOnly: MessageFilter = (message) => message instanceof HumanMessage;\nconst aiOnly: MessageFilter = (message) => message instanceof AIMessage;\n\nconst includingTags: MessageFilter = (message, tags) => {\n if (tags) {\n return tags.some((tag) =>\n Array.isArray(message.additional_kwargs?.tags)\n ? message.additional_kwargs?.tags.includes(tag)\n : false\n );\n }\n return true;\n};\n\nconst excludingTags: MessageFilter = (message, tags) => {\n if (tags) {\n return !tags.some((tag) =>\n Array.isArray(message.additional_kwargs?.tags)\n ? message.additional_kwargs?.tags.includes(tag)\n : false\n );\n }\n return true;\n};\n\nexport enum MessageFilterType {\n HumanAndAI = 'HumanAndAI',\n HumanOnly = 'HumanOnly',\n AIOnly = 'AIOnly',\n IncludingTags = 'IncludingTags',\n ExcludingTags = 'ExcludingTags',\n}\nexport const typeOnFilter = {\n [MessageFilterType.HumanAndAI]: humanAndAI,\n [MessageFilterType.HumanOnly]: humanOnly,\n [MessageFilterType.AIOnly]: aiOnly,\n [MessageFilterType.IncludingTags]: includingTags,\n [MessageFilterType.ExcludingTags]: excludingTags,\n};\n","import { AIMessage, BaseMessage } from '@langchain/core/messages';\n\n// Format types\nexport enum FormatType {\n Concise = 'concise',\n Verbose = 'verbose',\n RedactAi = 'redact-ai',\n RedactHuman = 'redact-human',\n JSON = 'json',\n}\n\n/**\n * Formats messages in a concise markdown format with alternating AI and Human prefixes.\n *\n * ### Example\n * ```markdown\n * AI: Hello, how are you?\n * Human: I am good, thank you!\n * AI: What is your name?\n * Human: My name is John.\n * AI: What is your favorite color?\n * Human: My favorite color is blue.\n * AI: What is your favorite food?\n * Human: My favorite food is pizza.\n * ```\n */\nfunction concise(messages: Array<BaseMessage>): string {\n return messages\n .map((message) => {\n const prefix = message instanceof AIMessage ? 'AI' : 'Human';\n return `${prefix}: ${message.content}`;\n })\n .join('\\n');\n}\n\n/**\n * Formats messages in a verbose markdown format with alternating AI and Human prefixes.\n *\n * ### Example\n * ```markdown\n * AI:\n * Hello, how are you?\n * -------------------\n * Human:\n * I am good, thank you!\n * -------------------\n * AI:\n * What is your name?\n * -------------------\n * Human:\n * My name is John.\n * ```\n */\nfunction verbose(messages: Array<BaseMessage>): string {\n return messages\n .map((message) => {\n const prefix = message instanceof AIMessage ? 'AI' : 'Human';\n return `${prefix}:\\n${message.content}`;\n })\n .join('\\n-------------------\\n');\n}\n\n/**\n * Formats messages in a concise markdown format, redacting AI messages with [...]\n *\n * ### Example\n * ```markdown\n * AI: [...]\n * Human: Hello, how are you?\n * AI: [...]\n * Human: I am good, thank you!\n * AI: [...]\n * Human: What is your name?\n * AI: [...]\n * Human: My name is John.\n * AI: [...]\n * ```\n */\nfunction redactAi(messages: Array<BaseMessage>): string {\n return messages\n .map((message) => {\n const prefix = message instanceof AIMessage ? 'AI' : 'Human';\n const content = message instanceof AIMessage ? '[...]' : message.content;\n return `${prefix}: ${content}`;\n })\n .join('\\n');\n}\n\n/**\n * Formats messages in a concise markdown format, redacting Human messages with [...]\n *\n * ### Example\n * ```markdown\n * AI: Hello, how are you?\n * Human: [...]\n * AI: What is your name?\n * Human: [...]\n * AI: What is your favorite color?\n * Human: [...]\n * AI: What is your favorite food?\n * Human: [...]\n * ```\n */\nfunction redactHuman(messages: Array<BaseMessage>): string {\n return messages\n .map((message) => {\n const prefix = message instanceof AIMessage ? 'AI' : 'Human';\n const content = message instanceof AIMessage ? '[...]' : message.content;\n return `${prefix}: ${content}`;\n })\n .join('\\n');\n}\nconst typeOnFormatter = {\n [FormatType.Concise]: concise,\n [FormatType.Verbose]: verbose,\n [FormatType.RedactAi]: redactAi,\n [FormatType.RedactHuman]: redactHuman,\n};\n\nexport { typeOnFormatter };\n"]}
|
package/dist/helper/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { BaseMessage } from '@langchain/core/messages';
|
|
2
|
-
import { Effect } from 'effect';
|
|
3
2
|
|
|
4
3
|
declare enum FormatType {
|
|
5
4
|
Concise = "concise",
|
|
@@ -74,19 +73,36 @@ declare class TransformMessages {
|
|
|
74
73
|
/**
|
|
75
74
|
* Format messages according to the specified format type
|
|
76
75
|
*/
|
|
77
|
-
format(formatType: FormatType):
|
|
76
|
+
format(formatType: FormatType): string;
|
|
77
|
+
/**
|
|
78
|
+
* Convert to array - runs the effect and returns the result
|
|
79
|
+
return pipe(
|
|
80
|
+
this.effect,
|
|
81
|
+
Effect.map((messages) => {
|
|
82
|
+
if (formatType === FormatType.JSON) {
|
|
83
|
+
return JSON.stringify(messages, null, 2);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const formatter = typeOnFormatter[formatType];
|
|
87
|
+
return formatter(messages);
|
|
88
|
+
})
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Sink methods
|
|
93
|
+
|
|
78
94
|
/**
|
|
79
95
|
* Convert to array - runs the effect and returns the result
|
|
80
96
|
*/
|
|
81
|
-
toArray():
|
|
97
|
+
toArray(): Array<BaseMessage>;
|
|
82
98
|
/**
|
|
83
99
|
* Convert to string - runs the effect and returns JSON string
|
|
84
100
|
*/
|
|
85
|
-
toString():
|
|
101
|
+
toString(): string;
|
|
86
102
|
/**
|
|
87
103
|
* Get the count of messages
|
|
88
104
|
*/
|
|
89
|
-
count():
|
|
105
|
+
count(): number;
|
|
90
106
|
}
|
|
91
107
|
|
|
92
108
|
export { FormatType, MessageFilterType, TransformMessages };
|
package/dist/helper/index.js
CHANGED
|
@@ -208,41 +208,67 @@ var TransformMessages = class _TransformMessages {
|
|
|
208
208
|
* Format messages according to the specified format type
|
|
209
209
|
*/
|
|
210
210
|
format(formatType) {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
211
|
+
const result = Effect.runSync(
|
|
212
|
+
pipe(
|
|
213
|
+
this.effect,
|
|
214
|
+
Effect.map((messages) => {
|
|
215
|
+
if (formatType === "json" /* JSON */) {
|
|
216
|
+
return JSON.stringify(messages, null, 2);
|
|
217
|
+
}
|
|
218
|
+
const formatter = typeOnFormatter[formatType];
|
|
219
|
+
return formatter(messages);
|
|
220
|
+
})
|
|
221
|
+
)
|
|
220
222
|
);
|
|
223
|
+
return result;
|
|
221
224
|
}
|
|
222
225
|
// Sink methods
|
|
223
226
|
/**
|
|
224
|
-
|
|
225
|
-
|
|
227
|
+
* Convert to array - runs the effect and returns the result
|
|
228
|
+
return pipe(
|
|
229
|
+
this.effect,
|
|
230
|
+
Effect.map((messages) => {
|
|
231
|
+
if (formatType === FormatType.JSON) {
|
|
232
|
+
return JSON.stringify(messages, null, 2);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const formatter = typeOnFormatter[formatType];
|
|
236
|
+
return formatter(messages);
|
|
237
|
+
})
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Sink methods
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Convert to array - runs the effect and returns the result
|
|
245
|
+
*/
|
|
226
246
|
toArray() {
|
|
227
|
-
return this.effect;
|
|
247
|
+
return Effect.runSync(this.effect);
|
|
228
248
|
}
|
|
229
249
|
/**
|
|
230
250
|
* Convert to string - runs the effect and returns JSON string
|
|
231
251
|
*/
|
|
232
252
|
toString() {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
253
|
+
const result = Effect.runSync(
|
|
254
|
+
pipe(
|
|
255
|
+
this.effect,
|
|
256
|
+
Effect.map((messages) => JSON.stringify(messages, null, 2))
|
|
257
|
+
)
|
|
236
258
|
);
|
|
259
|
+
return result;
|
|
237
260
|
}
|
|
238
261
|
/**
|
|
239
262
|
* Get the count of messages
|
|
240
263
|
*/
|
|
241
264
|
count() {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
265
|
+
const result = Effect.runSync(
|
|
266
|
+
pipe(
|
|
267
|
+
this.effect,
|
|
268
|
+
Effect.map((messages) => messages.length)
|
|
269
|
+
)
|
|
245
270
|
);
|
|
271
|
+
return result;
|
|
246
272
|
}
|
|
247
273
|
};
|
|
248
274
|
|
package/dist/helper/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/helper/transform-messages/TransformMessages.ts","../../src/helper/transform-messages/message-filter.ts","../../src/helper/transform-messages/formatter.ts"],"names":["AIMessage","i","msg"],"mappings":"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","sourcesContent":["import { BaseMessage, AIMessage, ToolMessage } from '@langchain/core/messages';\nimport { Effect, pipe } from 'effect';\nimport {\n MessageFilter,\n MessageFilterType,\n typeOnFilter,\n} from './message-filter';\nimport { FormatType, typeOnFormatter } from './formatter';\n\n/**\n * # Transform Messages\n * In order to manage the context size often you want to slice messages or only pass certain types of messages.\n * This class is a helper to do that.\n *\n * ## Example\n * ```ts\n * const messages = [\n * new HumanMessage('Hello, how are you?'),\n * new AIMessage('I am good, thank you!'),\n * ];\n *\n * const transformedMessages = TransformMessages.from(messages).filter(HumanAndAI).last(10).format(FormatType.Concise);\n *\n * ```\n */\n\nclass TransformMessages {\n private effect: Effect.Effect<Array<BaseMessage>, never, never>;\n\n private constructor(effect: Effect.Effect<Array<BaseMessage>, never, never>) {\n this.effect = effect;\n }\n\n /**\n * Create a new TransformMessages from an array of messages.\n */\n static from(messages: Array<BaseMessage>): TransformMessages {\n return new TransformMessages(Effect.succeed(messages));\n }\n\n /**\n * Filter messages based on a predicate function\n */\n filter(\n predicate: MessageFilter | MessageFilterType,\n tags?: Array<string>\n ): TransformMessages {\n let finalPredicate: MessageFilter;\n if (typeof predicate === 'string') {\n finalPredicate = typeOnFilter[predicate];\n } else {\n finalPredicate = predicate;\n }\n\n return new TransformMessages(\n pipe(\n this.effect,\n Effect.map((messages) =>\n messages.filter((message) => finalPredicate(message, tags))\n )\n )\n );\n }\n\n /**\n * Take only the last n messages, but safely.\n * Tool calls should not be separated from the last human message.\n * Ensures all tool call conversations in the last n messages are complete.\n */\n safelyTakeLast(\n n: number,\n pruneAfterNOvershootingMessages: number = 0\n ): TransformMessages {\n return new TransformMessages(\n pipe(\n this.effect,\n Effect.map((messages) => {\n const total = messages.length;\n if (n <= 0 || total === 0) return [];\n\n // Start with the last n messages\n const start = Math.max(0, total - n);\n const end = total;\n const lastSlice = messages.slice(start, end);\n\n // due to the fact that the calling AI message needs to be adjecent to the succeeding tool call message\n // we just need to check the last n messages for tool call ids\n\n // Check the first message if it is a tool call message\n // if it is iterate backwards until we find the AI message\n if (\n lastSlice[0] instanceof ToolMessage &&\n lastSlice[0].tool_call_id\n ) {\n let messagesToInclude: Array<BaseMessage> = [];\n const remainingMessages = messages.slice(0, start);\n for (let i = remainingMessages.length - 1; i >= 0; i--) {\n const msg = remainingMessages[i];\n if (\n pruneAfterNOvershootingMessages > 0 &&\n messagesToInclude.length - 1 >= pruneAfterNOvershootingMessages\n ) {\n messagesToInclude = [];\n // Return the slice but remove all the tool call messages that are at the beginning of the slice\n const filteredSlice: Array<BaseMessage> = [];\n let foundFirstNonToolMessage = false;\n for (let i = 0; i < lastSlice.length; i++) {\n const msg = lastSlice[i];\n if (msg instanceof ToolMessage) {\n if (foundFirstNonToolMessage) {\n filteredSlice.push(msg);\n }\n } else {\n foundFirstNonToolMessage = true;\n filteredSlice.push(msg);\n }\n }\n return filteredSlice;\n }\n if (msg instanceof AIMessage && Array.isArray(msg.tool_calls)) {\n messagesToInclude.push(msg);\n break;\n } else if (msg instanceof ToolMessage) {\n messagesToInclude.push(msg);\n } else {\n // This should not happen messages invalid\n throw new Error(\n 'Messages array invalid no adjacent AI message found'\n );\n }\n }\n return [...messagesToInclude.reverse(), ...lastSlice];\n } else {\n return lastSlice;\n }\n })\n )\n );\n }\n\n /**\n * Take only the last n messages\n */\n last(n: number): TransformMessages {\n return new TransformMessages(\n pipe(\n this.effect,\n Effect.map((messages) => messages.slice(-n))\n )\n );\n }\n\n /**\n * Take only the first n messages\n */\n first(n: number): TransformMessages {\n return new TransformMessages(\n pipe(\n this.effect,\n Effect.map((messages) => messages.slice(0, n))\n )\n );\n }\n\n /**\n * Skip the first n messages\n */\n skip(n: number): TransformMessages {\n return new TransformMessages(\n pipe(\n this.effect,\n Effect.map((messages) => messages.slice(n))\n )\n );\n }\n\n /**\n * Reverse the order of messages\n */\n reverse(): TransformMessages {\n return new TransformMessages(\n pipe(\n this.effect,\n Effect.map((messages) => [...messages].reverse())\n )\n );\n }\n\n /**\n * Map over messages with a transformation function\n */\n map<T extends BaseMessage>(\n fn: (message: BaseMessage) => T\n ): TransformMessages {\n return new TransformMessages(\n pipe(\n this.effect,\n Effect.map((messages) => messages.map(fn))\n )\n );\n }\n\n /**\n * Format messages according to the specified format type\n */\n format(formatType: FormatType): Effect.Effect<string, never, never> {\n return pipe(\n this.effect,\n Effect.map((messages) => {\n if (formatType === FormatType.JSON) {\n return JSON.stringify(messages, null, 2);\n }\n\n const formatter = typeOnFormatter[formatType];\n return formatter(messages);\n })\n );\n }\n\n // Sink methods\n\n /**\n * Convert to array - runs the effect and returns the result\n */\n toArray(): Effect.Effect<Array<BaseMessage>, never, never> {\n return this.effect;\n }\n\n /**\n * Convert to string - runs the effect and returns JSON string\n */\n toString(): Effect.Effect<string, never, never> {\n return pipe(\n this.effect,\n Effect.map((messages) => JSON.stringify(messages, null, 2))\n );\n }\n\n /**\n * Get the count of messages\n */\n count(): Effect.Effect<number, never, never> {\n return pipe(\n this.effect,\n Effect.map((messages) => messages.length)\n );\n }\n}\n\nexport { TransformMessages };\n","import { BaseMessage, HumanMessage, AIMessage } from '@langchain/core/messages';\n\n// Type for message filters\nexport type MessageFilter = (\n message: BaseMessage,\n tags?: Array<string>\n) => boolean;\n// Predefined filters\nconst humanAndAI: MessageFilter = (message) =>\n message instanceof HumanMessage || message instanceof AIMessage;\nconst humanOnly: MessageFilter = (message) => message instanceof HumanMessage;\nconst aiOnly: MessageFilter = (message) => message instanceof AIMessage;\n\nconst includingTags: MessageFilter = (message, tags) => {\n if (tags) {\n return tags.some((tag) =>\n Array.isArray(message.additional_kwargs?.tags)\n ? message.additional_kwargs?.tags.includes(tag)\n : false\n );\n }\n return true;\n};\n\nconst excludingTags: MessageFilter = (message, tags) => {\n if (tags) {\n return !tags.some((tag) =>\n Array.isArray(message.additional_kwargs?.tags)\n ? message.additional_kwargs?.tags.includes(tag)\n : false\n );\n }\n return true;\n};\n\nexport enum MessageFilterType {\n HumanAndAI = 'HumanAndAI',\n HumanOnly = 'HumanOnly',\n AIOnly = 'AIOnly',\n IncludingTags = 'IncludingTags',\n ExcludingTags = 'ExcludingTags',\n}\nexport const typeOnFilter = {\n [MessageFilterType.HumanAndAI]: humanAndAI,\n [MessageFilterType.HumanOnly]: humanOnly,\n [MessageFilterType.AIOnly]: aiOnly,\n [MessageFilterType.IncludingTags]: includingTags,\n [MessageFilterType.ExcludingTags]: excludingTags,\n};\n","import { AIMessage, BaseMessage } from '@langchain/core/messages';\n\n// Format types\nexport enum FormatType {\n Concise = 'concise',\n Verbose = 'verbose',\n RedactAi = 'redact-ai',\n RedactHuman = 'redact-human',\n JSON = 'json',\n}\n\n/**\n * Formats messages in a concise markdown format with alternating AI and Human prefixes.\n *\n * ### Example\n * ```markdown\n * AI: Hello, how are you?\n * Human: I am good, thank you!\n * AI: What is your name?\n * Human: My name is John.\n * AI: What is your favorite color?\n * Human: My favorite color is blue.\n * AI: What is your favorite food?\n * Human: My favorite food is pizza.\n * ```\n */\nfunction concise(messages: Array<BaseMessage>): string {\n return messages\n .map((message) => {\n const prefix = message instanceof AIMessage ? 'AI' : 'Human';\n return `${prefix}: ${message.content}`;\n })\n .join('\\n');\n}\n\n/**\n * Formats messages in a verbose markdown format with alternating AI and Human prefixes.\n *\n * ### Example\n * ```markdown\n * AI:\n * Hello, how are you?\n * -------------------\n * Human:\n * I am good, thank you!\n * -------------------\n * AI:\n * What is your name?\n * -------------------\n * Human:\n * My name is John.\n * ```\n */\nfunction verbose(messages: Array<BaseMessage>): string {\n return messages\n .map((message) => {\n const prefix = message instanceof AIMessage ? 'AI' : 'Human';\n return `${prefix}:\\n${message.content}`;\n })\n .join('\\n-------------------\\n');\n}\n\n/**\n * Formats messages in a concise markdown format, redacting AI messages with [...]\n *\n * ### Example\n * ```markdown\n * AI: [...]\n * Human: Hello, how are you?\n * AI: [...]\n * Human: I am good, thank you!\n * AI: [...]\n * Human: What is your name?\n * AI: [...]\n * Human: My name is John.\n * AI: [...]\n * ```\n */\nfunction redactAi(messages: Array<BaseMessage>): string {\n return messages\n .map((message) => {\n const prefix = message instanceof AIMessage ? 'AI' : 'Human';\n const content = message instanceof AIMessage ? '[...]' : message.content;\n return `${prefix}: ${content}`;\n })\n .join('\\n');\n}\n\n/**\n * Formats messages in a concise markdown format, redacting Human messages with [...]\n *\n * ### Example\n * ```markdown\n * AI: Hello, how are you?\n * Human: [...]\n * AI: What is your name?\n * Human: [...]\n * AI: What is your favorite color?\n * Human: [...]\n * AI: What is your favorite food?\n * Human: [...]\n * ```\n */\nfunction redactHuman(messages: Array<BaseMessage>): string {\n return messages\n .map((message) => {\n const prefix = message instanceof AIMessage ? 'AI' : 'Human';\n const content = message instanceof AIMessage ? '[...]' : message.content;\n return `${prefix}: ${content}`;\n })\n .join('\\n');\n}\nconst typeOnFormatter = {\n [FormatType.Concise]: concise,\n [FormatType.Verbose]: verbose,\n [FormatType.RedactAi]: redactAi,\n [FormatType.RedactHuman]: redactHuman,\n};\n\nexport { typeOnFormatter };\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/helper/transform-messages/TransformMessages.ts","../../src/helper/transform-messages/message-filter.ts","../../src/helper/transform-messages/formatter.ts"],"names":["AIMessage","i","msg"],"mappings":"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","sourcesContent":["import { BaseMessage, AIMessage, ToolMessage } from '@langchain/core/messages';\nimport { Effect, pipe } from 'effect';\nimport {\n MessageFilter,\n MessageFilterType,\n typeOnFilter,\n} from './message-filter';\nimport { FormatType, typeOnFormatter } from './formatter';\n\n/**\n * # Transform Messages\n * In order to manage the context size often you want to slice messages or only pass certain types of messages.\n * This class is a helper to do that.\n *\n * ## Example\n * ```ts\n * const messages = [\n * new HumanMessage('Hello, how are you?'),\n * new AIMessage('I am good, thank you!'),\n * ];\n *\n * const transformedMessages = TransformMessages.from(messages).filter(HumanAndAI).last(10).format(FormatType.Concise);\n *\n * ```\n */\n\nclass TransformMessages {\n private effect: Effect.Effect<Array<BaseMessage>, never, never>;\n\n private constructor(effect: Effect.Effect<Array<BaseMessage>, never, never>) {\n this.effect = effect;\n }\n\n /**\n * Create a new TransformMessages from an array of messages.\n */\n static from(messages: Array<BaseMessage>): TransformMessages {\n return new TransformMessages(Effect.succeed(messages));\n }\n\n /**\n * Filter messages based on a predicate function\n */\n filter(\n predicate: MessageFilter | MessageFilterType,\n tags?: Array<string>\n ): TransformMessages {\n let finalPredicate: MessageFilter;\n if (typeof predicate === 'string') {\n finalPredicate = typeOnFilter[predicate];\n } else {\n finalPredicate = predicate;\n }\n\n return new TransformMessages(\n pipe(\n this.effect,\n Effect.map((messages) =>\n messages.filter((message) => finalPredicate(message, tags))\n )\n )\n );\n }\n\n /**\n * Take only the last n messages, but safely.\n * Tool calls should not be separated from the last human message.\n * Ensures all tool call conversations in the last n messages are complete.\n */\n safelyTakeLast(\n n: number,\n pruneAfterNOvershootingMessages: number = 0\n ): TransformMessages {\n return new TransformMessages(\n pipe(\n this.effect,\n Effect.map((messages) => {\n const total = messages.length;\n if (n <= 0 || total === 0) return [];\n\n // Start with the last n messages\n const start = Math.max(0, total - n);\n const end = total;\n const lastSlice = messages.slice(start, end);\n\n // due to the fact that the calling AI message needs to be adjecent to the succeeding tool call message\n // we just need to check the last n messages for tool call ids\n\n // Check the first message if it is a tool call message\n // if it is iterate backwards until we find the AI message\n if (\n lastSlice[0] instanceof ToolMessage &&\n lastSlice[0].tool_call_id\n ) {\n let messagesToInclude: Array<BaseMessage> = [];\n const remainingMessages = messages.slice(0, start);\n for (let i = remainingMessages.length - 1; i >= 0; i--) {\n const msg = remainingMessages[i];\n if (\n pruneAfterNOvershootingMessages > 0 &&\n messagesToInclude.length - 1 >= pruneAfterNOvershootingMessages\n ) {\n messagesToInclude = [];\n // Return the slice but remove all the tool call messages that are at the beginning of the slice\n const filteredSlice: Array<BaseMessage> = [];\n let foundFirstNonToolMessage = false;\n for (let i = 0; i < lastSlice.length; i++) {\n const msg = lastSlice[i];\n if (msg instanceof ToolMessage) {\n if (foundFirstNonToolMessage) {\n filteredSlice.push(msg);\n }\n } else {\n foundFirstNonToolMessage = true;\n filteredSlice.push(msg);\n }\n }\n return filteredSlice;\n }\n if (msg instanceof AIMessage && Array.isArray(msg.tool_calls)) {\n messagesToInclude.push(msg);\n break;\n } else if (msg instanceof ToolMessage) {\n messagesToInclude.push(msg);\n } else {\n // This should not happen messages invalid\n throw new Error(\n 'Messages array invalid no adjacent AI message found'\n );\n }\n }\n return [...messagesToInclude.reverse(), ...lastSlice];\n } else {\n return lastSlice;\n }\n })\n )\n );\n }\n\n /**\n * Take only the last n messages\n */\n last(n: number): TransformMessages {\n return new TransformMessages(\n pipe(\n this.effect,\n Effect.map((messages) => messages.slice(-n))\n )\n );\n }\n\n /**\n * Take only the first n messages\n */\n first(n: number): TransformMessages {\n return new TransformMessages(\n pipe(\n this.effect,\n Effect.map((messages) => messages.slice(0, n))\n )\n );\n }\n\n /**\n * Skip the first n messages\n */\n skip(n: number): TransformMessages {\n return new TransformMessages(\n pipe(\n this.effect,\n Effect.map((messages) => messages.slice(n))\n )\n );\n }\n\n /**\n * Reverse the order of messages\n */\n reverse(): TransformMessages {\n return new TransformMessages(\n pipe(\n this.effect,\n Effect.map((messages) => [...messages].reverse())\n )\n );\n }\n\n /**\n * Map over messages with a transformation function\n */\n map<T extends BaseMessage>(\n fn: (message: BaseMessage) => T\n ): TransformMessages {\n return new TransformMessages(\n pipe(\n this.effect,\n Effect.map((messages) => messages.map(fn))\n )\n );\n }\n\n /**\n * Format messages according to the specified format type\n */\n format(formatType: FormatType): string {\n const result = Effect.runSync(\n pipe(\n this.effect,\n Effect.map((messages) => {\n if (formatType === FormatType.JSON) {\n return JSON.stringify(messages, null, 2);\n }\n const formatter = typeOnFormatter[formatType];\n return formatter(messages);\n })\n )\n );\n return result;\n }\n\n // Sink methods\n\n /**\n * Convert to array - runs the effect and returns the result\n return pipe(\n this.effect,\n Effect.map((messages) => {\n if (formatType === FormatType.JSON) {\n return JSON.stringify(messages, null, 2);\n }\n\n const formatter = typeOnFormatter[formatType];\n return formatter(messages);\n })\n );\n }\n\n // Sink methods\n\n /**\n * Convert to array - runs the effect and returns the result\n */\n toArray(): Array<BaseMessage> {\n return Effect.runSync(this.effect);\n }\n\n /**\n * Convert to string - runs the effect and returns JSON string\n */\n toString(): string {\n const result = Effect.runSync(\n pipe(\n this.effect,\n Effect.map((messages) => JSON.stringify(messages, null, 2))\n )\n );\n return result;\n }\n\n /**\n * Get the count of messages\n */\n count(): number {\n const result = Effect.runSync(\n pipe(\n this.effect,\n Effect.map((messages) => messages.length)\n )\n );\n return result;\n }\n}\n\nexport { TransformMessages };\n","import { BaseMessage, HumanMessage, AIMessage } from '@langchain/core/messages';\n\n// Type for message filters\nexport type MessageFilter = (\n message: BaseMessage,\n tags?: Array<string>\n) => boolean;\n// Predefined filters\nconst humanAndAI: MessageFilter = (message) =>\n message instanceof HumanMessage || message instanceof AIMessage;\nconst humanOnly: MessageFilter = (message) => message instanceof HumanMessage;\nconst aiOnly: MessageFilter = (message) => message instanceof AIMessage;\n\nconst includingTags: MessageFilter = (message, tags) => {\n if (tags) {\n return tags.some((tag) =>\n Array.isArray(message.additional_kwargs?.tags)\n ? message.additional_kwargs?.tags.includes(tag)\n : false\n );\n }\n return true;\n};\n\nconst excludingTags: MessageFilter = (message, tags) => {\n if (tags) {\n return !tags.some((tag) =>\n Array.isArray(message.additional_kwargs?.tags)\n ? message.additional_kwargs?.tags.includes(tag)\n : false\n );\n }\n return true;\n};\n\nexport enum MessageFilterType {\n HumanAndAI = 'HumanAndAI',\n HumanOnly = 'HumanOnly',\n AIOnly = 'AIOnly',\n IncludingTags = 'IncludingTags',\n ExcludingTags = 'ExcludingTags',\n}\nexport const typeOnFilter = {\n [MessageFilterType.HumanAndAI]: humanAndAI,\n [MessageFilterType.HumanOnly]: humanOnly,\n [MessageFilterType.AIOnly]: aiOnly,\n [MessageFilterType.IncludingTags]: includingTags,\n [MessageFilterType.ExcludingTags]: excludingTags,\n};\n","import { AIMessage, BaseMessage } from '@langchain/core/messages';\n\n// Format types\nexport enum FormatType {\n Concise = 'concise',\n Verbose = 'verbose',\n RedactAi = 'redact-ai',\n RedactHuman = 'redact-human',\n JSON = 'json',\n}\n\n/**\n * Formats messages in a concise markdown format with alternating AI and Human prefixes.\n *\n * ### Example\n * ```markdown\n * AI: Hello, how are you?\n * Human: I am good, thank you!\n * AI: What is your name?\n * Human: My name is John.\n * AI: What is your favorite color?\n * Human: My favorite color is blue.\n * AI: What is your favorite food?\n * Human: My favorite food is pizza.\n * ```\n */\nfunction concise(messages: Array<BaseMessage>): string {\n return messages\n .map((message) => {\n const prefix = message instanceof AIMessage ? 'AI' : 'Human';\n return `${prefix}: ${message.content}`;\n })\n .join('\\n');\n}\n\n/**\n * Formats messages in a verbose markdown format with alternating AI and Human prefixes.\n *\n * ### Example\n * ```markdown\n * AI:\n * Hello, how are you?\n * -------------------\n * Human:\n * I am good, thank you!\n * -------------------\n * AI:\n * What is your name?\n * -------------------\n * Human:\n * My name is John.\n * ```\n */\nfunction verbose(messages: Array<BaseMessage>): string {\n return messages\n .map((message) => {\n const prefix = message instanceof AIMessage ? 'AI' : 'Human';\n return `${prefix}:\\n${message.content}`;\n })\n .join('\\n-------------------\\n');\n}\n\n/**\n * Formats messages in a concise markdown format, redacting AI messages with [...]\n *\n * ### Example\n * ```markdown\n * AI: [...]\n * Human: Hello, how are you?\n * AI: [...]\n * Human: I am good, thank you!\n * AI: [...]\n * Human: What is your name?\n * AI: [...]\n * Human: My name is John.\n * AI: [...]\n * ```\n */\nfunction redactAi(messages: Array<BaseMessage>): string {\n return messages\n .map((message) => {\n const prefix = message instanceof AIMessage ? 'AI' : 'Human';\n const content = message instanceof AIMessage ? '[...]' : message.content;\n return `${prefix}: ${content}`;\n })\n .join('\\n');\n}\n\n/**\n * Formats messages in a concise markdown format, redacting Human messages with [...]\n *\n * ### Example\n * ```markdown\n * AI: Hello, how are you?\n * Human: [...]\n * AI: What is your name?\n * Human: [...]\n * AI: What is your favorite color?\n * Human: [...]\n * AI: What is your favorite food?\n * Human: [...]\n * ```\n */\nfunction redactHuman(messages: Array<BaseMessage>): string {\n return messages\n .map((message) => {\n const prefix = message instanceof AIMessage ? 'AI' : 'Human';\n const content = message instanceof AIMessage ? '[...]' : message.content;\n return `${prefix}: ${content}`;\n })\n .join('\\n');\n}\nconst typeOnFormatter = {\n [FormatType.Concise]: concise,\n [FormatType.Verbose]: verbose,\n [FormatType.RedactAi]: redactAi,\n [FormatType.RedactHuman]: redactHuman,\n};\n\nexport { typeOnFormatter };\n"]}
|