@langchain/core 1.1.30 → 1.1.31
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/CHANGELOG.md +13 -0
- package/dist/language_models/base.cjs +1 -1
- package/dist/language_models/base.js +1 -1
- package/dist/load/import_map.cjs +2 -0
- package/dist/load/import_map.cjs.map +1 -1
- package/dist/load/import_map.js +4 -2
- package/dist/load/import_map.js.map +1 -1
- package/dist/runnables/base.cjs +1 -1
- package/dist/runnables/base.cjs.map +1 -1
- package/dist/runnables/base.js +2 -2
- package/dist/runnables/base.js.map +1 -1
- package/dist/{utils/testing → testing}/fake_model_builder.cjs +6 -6
- package/dist/testing/fake_model_builder.cjs.map +1 -0
- package/dist/{utils/testing → testing}/fake_model_builder.d.cts +12 -12
- package/dist/testing/fake_model_builder.d.cts.map +1 -0
- package/dist/{utils/testing → testing}/fake_model_builder.d.ts +13 -13
- package/dist/{utils/testing/fake_model_builder.d.cts.map → testing/fake_model_builder.d.ts.map} +1 -1
- package/dist/{utils/testing → testing}/fake_model_builder.js +6 -6
- package/dist/testing/fake_model_builder.js.map +1 -0
- package/dist/testing/index.cjs +41 -0
- package/dist/testing/index.cjs.map +1 -0
- package/dist/testing/index.d.cts +3 -0
- package/dist/testing/index.d.ts +3 -0
- package/dist/testing/index.js +23 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/matchers.cjs +213 -0
- package/dist/testing/matchers.cjs.map +1 -0
- package/dist/testing/matchers.d.cts +94 -0
- package/dist/testing/matchers.d.cts.map +1 -0
- package/dist/testing/matchers.d.ts +94 -0
- package/dist/testing/matchers.d.ts.map +1 -0
- package/dist/testing/matchers.js +203 -0
- package/dist/testing/matchers.js.map +1 -0
- package/dist/utils/testing/index.cjs +1 -4
- package/dist/utils/testing/index.cjs.map +1 -1
- package/dist/utils/testing/index.d.cts +1 -2
- package/dist/utils/testing/index.d.ts +1 -2
- package/dist/utils/testing/index.js +2 -4
- package/dist/utils/testing/index.js.map +1 -1
- package/package.json +15 -3
- package/dist/utils/testing/fake_model_builder.cjs.map +0 -1
- package/dist/utils/testing/fake_model_builder.d.ts.map +0 -1
- package/dist/utils/testing/fake_model_builder.js.map +0 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
const require_base = require('
|
|
2
|
-
const require_ai = require('
|
|
3
|
-
const require_base$1 = require('
|
|
4
|
-
require('
|
|
5
|
-
const require_language_models_chat_models = require('
|
|
1
|
+
const require_base = require('../messages/base.cjs');
|
|
2
|
+
const require_ai = require('../messages/ai.cjs');
|
|
3
|
+
const require_base$1 = require('../runnables/base.cjs');
|
|
4
|
+
require('../messages/index.cjs');
|
|
5
|
+
const require_language_models_chat_models = require('../language_models/chat_models.cjs');
|
|
6
6
|
|
|
7
|
-
//#region src/
|
|
7
|
+
//#region src/testing/fake_model_builder.ts
|
|
8
8
|
function deriveContent(messages) {
|
|
9
9
|
return messages.map((m) => m.text).filter(Boolean).join("-");
|
|
10
10
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fake_model_builder.cjs","names":["BaseChatModel","BaseMessage","RunnableLambda","AIMessage"],"sources":["../../src/testing/fake_model_builder.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { CallbackManagerForLLMRun } from \"../callbacks/manager.js\";\nimport {\n BaseChatModel,\n BaseChatModelCallOptions,\n} from \"../language_models/chat_models.js\";\nimport {\n BaseLanguageModelInput,\n StructuredOutputMethodOptions,\n StructuredOutputMethodParams,\n} from \"../language_models/base.js\";\nimport { BaseMessage, AIMessage } from \"../messages/index.js\";\nimport type { ToolCall } from \"../messages/tool.js\";\nimport type { ChatResult } from \"../outputs.js\";\nimport { Runnable, RunnableLambda } from \"../runnables/base.js\";\nimport { StructuredTool } from \"../tools/index.js\";\nimport type { InteropZodType } from \"../utils/types/zod.js\";\nimport type { ToolSpec } from \"../utils/testing/chat_models.js\";\n\ntype ResponseFactory = (messages: BaseMessage[]) => BaseMessage | Error;\n\ntype QueueEntry =\n | { kind: \"message\"; message: BaseMessage }\n | { kind: \"toolCalls\"; toolCalls: ToolCall[] }\n | { kind: \"error\"; error: Error }\n | { kind: \"factory\"; factory: ResponseFactory };\n\ninterface FakeModelCall {\n messages: BaseMessage[];\n options: any;\n}\n\nfunction deriveContent(messages: BaseMessage[]): string {\n return messages\n .map((m) => m.text)\n .filter(Boolean)\n .join(\"-\");\n}\n\nlet idCounter = 0;\nfunction nextToolCallId(): string {\n idCounter += 1;\n return `fake_tc_${idCounter}`;\n}\n\n/**\n * A fake chat model for testing, created via {@link fakeModel}.\n *\n * Queue responses with `.respond()` and `.respondWithTools()`, then\n * pass the instance directly wherever a chat model is expected.\n *\n * Each builder method queues a model response consumed in order per `invoke()`:\n *\n * `.respond(entry)` — enqueue a `BaseMessage`, `Error`, or factory function.\n *\n * `.respondWithTools(toolCalls[])` — enqueue an `AIMessage` with the given\n * tool calls. Content is derived from the input messages automatically.\n *\n * Both can be mixed freely in one chain. When all queued responses are\n * consumed, further invocations throw.\n *\n * Additional configuration:\n * - `.alwaysThrow(error)` — every call throws (overrides the queue)\n * - `.structuredResponse(value)` — value returned by `withStructuredOutput()`\n *\n * The model records all invocations in `.calls` / `.callCount`.\n */\nclass FakeBuiltModel extends BaseChatModel {\n private queue: QueueEntry[] = [];\n\n private _alwaysThrowError: Error | undefined;\n\n private _structuredResponseValue: any;\n\n private _tools: (StructuredTool | ToolSpec)[] = [];\n\n private _callIndex = 0;\n\n private _calls: FakeModelCall[] = [];\n\n get calls(): FakeModelCall[] {\n return this._calls;\n }\n\n get callCount(): number {\n return this._calls.length;\n }\n\n constructor() {\n super({});\n }\n\n _llmType(): string {\n return \"fake-model-builder\";\n }\n\n _combineLLMOutput() {\n return [];\n }\n\n respond(entry: BaseMessage | Error | ResponseFactory): this {\n if (typeof entry === \"function\") {\n this.queue.push({ kind: \"factory\", factory: entry });\n } else if (BaseMessage.isInstance(entry)) {\n this.queue.push({ kind: \"message\", message: entry });\n } else {\n this.queue.push({ kind: \"error\", error: entry });\n }\n return this;\n }\n\n respondWithTools(\n toolCalls: Array<{ name: string; args: Record<string, any>; id?: string }>\n ): this {\n this.queue.push({\n kind: \"toolCalls\",\n toolCalls: toolCalls.map((tc) => ({\n name: tc.name,\n args: tc.args,\n id: tc.id ?? nextToolCallId(),\n type: \"tool_call\" as const,\n })),\n });\n return this;\n }\n\n alwaysThrow(error: Error): this {\n this._alwaysThrowError = error;\n return this;\n }\n\n structuredResponse(value: Record<string, any>): this {\n this._structuredResponseValue = value;\n return this;\n }\n\n bindTools(tools: (StructuredTool | ToolSpec)[]) {\n const merged = [...this._tools, ...tools];\n const next = new FakeBuiltModel();\n next.queue = this.queue;\n next._alwaysThrowError = this._alwaysThrowError;\n next._structuredResponseValue = this._structuredResponseValue;\n next._tools = merged;\n next._calls = this._calls;\n next._callIndex = this._callIndex;\n\n return next.withConfig({} as BaseChatModelCallOptions);\n }\n\n withStructuredOutput<\n RunOutput extends Record<string, any> = Record<string, any>,\n >(\n _params:\n | StructuredOutputMethodParams<RunOutput, boolean>\n | InteropZodType<RunOutput>\n | Record<string, any>,\n _config?: StructuredOutputMethodOptions<boolean>\n ):\n | Runnable<BaseLanguageModelInput, RunOutput>\n | Runnable<\n BaseLanguageModelInput,\n { raw: BaseMessage; parsed: RunOutput }\n > {\n const { _structuredResponseValue } = this;\n return RunnableLambda.from(async () => {\n return _structuredResponseValue as RunOutput;\n }) as Runnable;\n }\n\n async _generate(\n messages: BaseMessage[],\n options?: this[\"ParsedCallOptions\"],\n _runManager?: CallbackManagerForLLMRun\n ): Promise<ChatResult> {\n this._calls.push({ messages: [...messages], options });\n\n const currentCallIndex = this._callIndex;\n this._callIndex += 1;\n\n if (this._alwaysThrowError) {\n throw this._alwaysThrowError;\n }\n\n const entry = this.queue[currentCallIndex];\n if (!entry) {\n throw new Error(\n `FakeModel: no response queued for invocation ${currentCallIndex} (${this.queue.length} total queued).`\n );\n }\n\n if (entry.kind === \"error\") {\n throw entry.error;\n }\n\n if (entry.kind === \"factory\") {\n const result = entry.factory(messages);\n if (!BaseMessage.isInstance(result)) {\n throw result;\n }\n return {\n generations: [{ text: \"\", message: result }],\n };\n }\n\n if (entry.kind === \"message\") {\n return {\n generations: [{ text: \"\", message: entry.message }],\n };\n }\n\n const content = deriveContent(messages);\n const message = new AIMessage({\n content,\n id: currentCallIndex.toString(),\n tool_calls:\n entry.toolCalls.length > 0\n ? entry.toolCalls.map((tc) => ({\n ...tc,\n type: \"tool_call\" as const,\n }))\n : undefined,\n });\n\n return {\n generations: [{ text: content, message }],\n llmOutput: {},\n };\n }\n}\n\n/**\n * Creates a fake chat model for testing.\n *\n * @example\n * ```typescript\n * const model = fakeModel()\n * .respondWithTools([{ name: \"search\", args: { query: \"weather\" } }])\n * .respond(new AIMessage(\"Sunny and warm.\"));\n *\n * const r1 = await model.invoke([new HumanMessage(\"What's the weather?\")]);\n * // r1.tool_calls[0].name === \"search\"\n *\n * const r2 = await model.invoke([new HumanMessage(\"Thanks\")]);\n * // r2.content === \"Sunny and warm.\"\n * ```\n */\nexport function fakeModel(): FakeBuiltModel {\n return new FakeBuiltModel();\n}\n"],"mappings":"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"}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { BaseMessage } from "
|
|
2
|
-
import { AIMessageChunk } from "
|
|
3
|
-
import { MessageStructure, MessageToolSet } from "
|
|
4
|
-
import { ChatResult } from "
|
|
5
|
-
import { InteropZodType } from "../types/zod.cjs";
|
|
6
|
-
import { CallbackManagerForLLMRun } from "
|
|
7
|
-
import { Runnable } from "
|
|
8
|
-
import { BaseLanguageModelInput, StructuredOutputMethodOptions, StructuredOutputMethodParams } from "
|
|
9
|
-
import { StructuredTool } from "
|
|
10
|
-
import { BaseChatModel, BaseChatModelCallOptions } from "
|
|
11
|
-
import { ToolSpec } from "
|
|
1
|
+
import { BaseMessage } from "../messages/base.cjs";
|
|
2
|
+
import { AIMessageChunk } from "../messages/ai.cjs";
|
|
3
|
+
import { MessageStructure, MessageToolSet } from "../messages/message.cjs";
|
|
4
|
+
import { ChatResult } from "../outputs.cjs";
|
|
5
|
+
import { InteropZodType } from "../utils/types/zod.cjs";
|
|
6
|
+
import { CallbackManagerForLLMRun } from "../callbacks/manager.cjs";
|
|
7
|
+
import { Runnable } from "../runnables/base.cjs";
|
|
8
|
+
import { BaseLanguageModelInput, StructuredOutputMethodOptions, StructuredOutputMethodParams } from "../language_models/base.cjs";
|
|
9
|
+
import { StructuredTool } from "../tools/index.cjs";
|
|
10
|
+
import { BaseChatModel, BaseChatModelCallOptions } from "../language_models/chat_models.cjs";
|
|
11
|
+
import { ToolSpec } from "../utils/testing/chat_models.cjs";
|
|
12
12
|
|
|
13
|
-
//#region src/
|
|
13
|
+
//#region src/testing/fake_model_builder.d.ts
|
|
14
14
|
type ResponseFactory = (messages: BaseMessage[]) => BaseMessage | Error;
|
|
15
15
|
interface FakeModelCall {
|
|
16
16
|
messages: BaseMessage[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fake_model_builder.d.cts","names":[],"sources":["../../src/testing/fake_model_builder.ts"],"mappings":";;;;;;;;;;;;;KAmBK,eAAA,IAAmB,QAAA,EAAU,WAAA,OAAkB,WAAA,GAAc,KAAA;AAAA,UAQxD,aAAA;EACR,QAAA,EAAU,WAAA;EACV,OAAA;AAAA;;;;;;;;;;;;;;AAVqE;;;;;;;;;cAgDjE,cAAA,SAAuB,aAAA;EAAA,QACnB,KAAA;EAAA,QAEA,iBAAA;EAAA,QAEA,wBAAA;EAAA,QAEA,MAAA;EAAA,QAEA,UAAA;EAAA,QAEA,MAAA;EAAA,IAEJ,KAAA,CAAA,GAAS,aAAA;EAAA,IAIT,SAAA,CAAA;EAIJ,WAAA,CAAA;EAIA,QAAA,CAAA;EAIA,iBAAA,CAAA;EAIA,OAAA,CAAQ,KAAA,EAAO,WAAA,GAAc,KAAA,GAAQ,eAAA;EAWrC,gBAAA,CACE,SAAA,EAAW,KAAA;IAAQ,IAAA;IAAc,IAAA,EAAM,MAAA;IAAqB,EAAA;EAAA;EAc9D,WAAA,CAAY,KAAA,EAAO,KAAA;EAKnB,kBAAA,CAAmB,KAAA,EAAO,MAAA;EAK1B,SAAA,CAAU,KAAA,GAAQ,cAAA,GAAiB,QAAA,MAAW,QAAA,CAAA,sBAAA,EAAA,cAAA,CAAA,gBAAA,CAAA,cAAA,IAAA,wBAAA;EAa9C,oBAAA,mBACoB,MAAA,gBAAsB,MAAA,cAAA,CAExC,OAAA,EACI,4BAAA,CAA6B,SAAA,aAC7B,cAAA,CAAe,SAAA,IACf,MAAA,eACJ,OAAA,GAAU,6BAAA,YAER,QAAA,CAAS,sBAAA,EAAwB,SAAA,IACjC,QAAA,CACE,sBAAA;IACE,GAAA,EAAK,WAAA;IAAa,MAAA,EAAQ,SAAA;EAAA;EAQ5B,SAAA,CACJ,QAAA,EAAU,WAAA,IACV,OAAA,8BACA,WAAA,GAAc,wBAAA,GACb,OAAA,CAAQ,UAAA;AAAA;;;;;;;;;;;;;;;;;iBAyEG,SAAA,CAAA,GAAa,cAAA"}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { BaseMessage } from "
|
|
2
|
-
import { AIMessageChunk } from "
|
|
3
|
-
import { MessageStructure, MessageToolSet } from "
|
|
4
|
-
import { ChatResult } from "
|
|
5
|
-
import { InteropZodType } from "../types/zod.js";
|
|
6
|
-
import { CallbackManagerForLLMRun } from "
|
|
7
|
-
import { Runnable } from "
|
|
8
|
-
import { BaseLanguageModelInput, StructuredOutputMethodOptions, StructuredOutputMethodParams } from "
|
|
9
|
-
import "
|
|
10
|
-
import { StructuredTool } from "
|
|
11
|
-
import { BaseChatModel, BaseChatModelCallOptions } from "
|
|
12
|
-
import { ToolSpec } from "
|
|
1
|
+
import { BaseMessage } from "../messages/base.js";
|
|
2
|
+
import { AIMessageChunk } from "../messages/ai.js";
|
|
3
|
+
import { MessageStructure, MessageToolSet } from "../messages/message.js";
|
|
4
|
+
import { ChatResult } from "../outputs.js";
|
|
5
|
+
import { InteropZodType } from "../utils/types/zod.js";
|
|
6
|
+
import { CallbackManagerForLLMRun } from "../callbacks/manager.js";
|
|
7
|
+
import { Runnable } from "../runnables/base.js";
|
|
8
|
+
import { BaseLanguageModelInput, StructuredOutputMethodOptions, StructuredOutputMethodParams } from "../language_models/base.js";
|
|
9
|
+
import "../messages/index.js";
|
|
10
|
+
import { StructuredTool } from "../tools/index.js";
|
|
11
|
+
import { BaseChatModel, BaseChatModelCallOptions } from "../language_models/chat_models.js";
|
|
12
|
+
import { ToolSpec } from "../utils/testing/chat_models.js";
|
|
13
13
|
|
|
14
|
-
//#region src/
|
|
14
|
+
//#region src/testing/fake_model_builder.d.ts
|
|
15
15
|
type ResponseFactory = (messages: BaseMessage[]) => BaseMessage | Error;
|
|
16
16
|
interface FakeModelCall {
|
|
17
17
|
messages: BaseMessage[];
|
package/dist/{utils/testing/fake_model_builder.d.cts.map → testing/fake_model_builder.d.ts.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fake_model_builder.d.
|
|
1
|
+
{"version":3,"file":"fake_model_builder.d.ts","names":[],"sources":["../../src/testing/fake_model_builder.ts"],"mappings":";;;;;;;;;;;;;;KAmBK,eAAA,IAAmB,QAAA,EAAU,WAAA,OAAkB,WAAA,GAAc,KAAA;AAAA,UAQxD,aAAA;EACR,QAAA,EAAU,WAAA;EACV,OAAA;AAAA;AAZ8D;;;;;;;;;;;;;;AAEO;;;;;;;;AAFP,cAkD1D,cAAA,SAAuB,aAAA;EAAA,QACnB,KAAA;EAAA,QAEA,iBAAA;EAAA,QAEA,wBAAA;EAAA,QAEA,MAAA;EAAA,QAEA,UAAA;EAAA,QAEA,MAAA;EAAA,IAEJ,KAAA,CAAA,GAAS,aAAA;EAAA,IAIT,SAAA,CAAA;EAIJ,WAAA,CAAA;EAIA,QAAA,CAAA;EAIA,iBAAA,CAAA;EAIA,OAAA,CAAQ,KAAA,EAAO,WAAA,GAAc,KAAA,GAAQ,eAAA;EAWrC,gBAAA,CACE,SAAA,EAAW,KAAA;IAAQ,IAAA;IAAc,IAAA,EAAM,MAAA;IAAqB,EAAA;EAAA;EAc9D,WAAA,CAAY,KAAA,EAAO,KAAA;EAKnB,kBAAA,CAAmB,KAAA,EAAO,MAAA;EAK1B,SAAA,CAAU,KAAA,GAAQ,cAAA,GAAiB,QAAA,MAAW,QAAA,CAAA,sBAAA,EAAA,cAAA,CAAA,gBAAA,CAAA,cAAA,IAAA,wBAAA;EAa9C,oBAAA,mBACoB,MAAA,gBAAsB,MAAA,cAAA,CAExC,OAAA,EACI,4BAAA,CAA6B,SAAA,aAC7B,cAAA,CAAe,SAAA,IACf,MAAA,eACJ,OAAA,GAAU,6BAAA,YAER,QAAA,CAAS,sBAAA,EAAwB,SAAA,IACjC,QAAA,CACE,sBAAA;IACE,GAAA,EAAK,WAAA;IAAa,MAAA,EAAQ,SAAA;EAAA;EAQ5B,SAAA,CACJ,QAAA,EAAU,WAAA,IACV,OAAA,8BACA,WAAA,GAAc,wBAAA,GACb,OAAA,CAAQ,UAAA;AAAA;;;;;;;;;;;;;;;;;iBAyEG,SAAA,CAAA,GAAa,cAAA"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { BaseMessage } from "
|
|
2
|
-
import { AIMessage } from "
|
|
3
|
-
import { RunnableLambda } from "
|
|
4
|
-
import "
|
|
5
|
-
import { BaseChatModel } from "
|
|
1
|
+
import { BaseMessage } from "../messages/base.js";
|
|
2
|
+
import { AIMessage } from "../messages/ai.js";
|
|
3
|
+
import { RunnableLambda } from "../runnables/base.js";
|
|
4
|
+
import "../messages/index.js";
|
|
5
|
+
import { BaseChatModel } from "../language_models/chat_models.js";
|
|
6
6
|
|
|
7
|
-
//#region src/
|
|
7
|
+
//#region src/testing/fake_model_builder.ts
|
|
8
8
|
function deriveContent(messages) {
|
|
9
9
|
return messages.map((m) => m.text).filter(Boolean).join("-");
|
|
10
10
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fake_model_builder.js","names":[],"sources":["../../src/testing/fake_model_builder.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { CallbackManagerForLLMRun } from \"../callbacks/manager.js\";\nimport {\n BaseChatModel,\n BaseChatModelCallOptions,\n} from \"../language_models/chat_models.js\";\nimport {\n BaseLanguageModelInput,\n StructuredOutputMethodOptions,\n StructuredOutputMethodParams,\n} from \"../language_models/base.js\";\nimport { BaseMessage, AIMessage } from \"../messages/index.js\";\nimport type { ToolCall } from \"../messages/tool.js\";\nimport type { ChatResult } from \"../outputs.js\";\nimport { Runnable, RunnableLambda } from \"../runnables/base.js\";\nimport { StructuredTool } from \"../tools/index.js\";\nimport type { InteropZodType } from \"../utils/types/zod.js\";\nimport type { ToolSpec } from \"../utils/testing/chat_models.js\";\n\ntype ResponseFactory = (messages: BaseMessage[]) => BaseMessage | Error;\n\ntype QueueEntry =\n | { kind: \"message\"; message: BaseMessage }\n | { kind: \"toolCalls\"; toolCalls: ToolCall[] }\n | { kind: \"error\"; error: Error }\n | { kind: \"factory\"; factory: ResponseFactory };\n\ninterface FakeModelCall {\n messages: BaseMessage[];\n options: any;\n}\n\nfunction deriveContent(messages: BaseMessage[]): string {\n return messages\n .map((m) => m.text)\n .filter(Boolean)\n .join(\"-\");\n}\n\nlet idCounter = 0;\nfunction nextToolCallId(): string {\n idCounter += 1;\n return `fake_tc_${idCounter}`;\n}\n\n/**\n * A fake chat model for testing, created via {@link fakeModel}.\n *\n * Queue responses with `.respond()` and `.respondWithTools()`, then\n * pass the instance directly wherever a chat model is expected.\n *\n * Each builder method queues a model response consumed in order per `invoke()`:\n *\n * `.respond(entry)` — enqueue a `BaseMessage`, `Error`, or factory function.\n *\n * `.respondWithTools(toolCalls[])` — enqueue an `AIMessage` with the given\n * tool calls. Content is derived from the input messages automatically.\n *\n * Both can be mixed freely in one chain. When all queued responses are\n * consumed, further invocations throw.\n *\n * Additional configuration:\n * - `.alwaysThrow(error)` — every call throws (overrides the queue)\n * - `.structuredResponse(value)` — value returned by `withStructuredOutput()`\n *\n * The model records all invocations in `.calls` / `.callCount`.\n */\nclass FakeBuiltModel extends BaseChatModel {\n private queue: QueueEntry[] = [];\n\n private _alwaysThrowError: Error | undefined;\n\n private _structuredResponseValue: any;\n\n private _tools: (StructuredTool | ToolSpec)[] = [];\n\n private _callIndex = 0;\n\n private _calls: FakeModelCall[] = [];\n\n get calls(): FakeModelCall[] {\n return this._calls;\n }\n\n get callCount(): number {\n return this._calls.length;\n }\n\n constructor() {\n super({});\n }\n\n _llmType(): string {\n return \"fake-model-builder\";\n }\n\n _combineLLMOutput() {\n return [];\n }\n\n respond(entry: BaseMessage | Error | ResponseFactory): this {\n if (typeof entry === \"function\") {\n this.queue.push({ kind: \"factory\", factory: entry });\n } else if (BaseMessage.isInstance(entry)) {\n this.queue.push({ kind: \"message\", message: entry });\n } else {\n this.queue.push({ kind: \"error\", error: entry });\n }\n return this;\n }\n\n respondWithTools(\n toolCalls: Array<{ name: string; args: Record<string, any>; id?: string }>\n ): this {\n this.queue.push({\n kind: \"toolCalls\",\n toolCalls: toolCalls.map((tc) => ({\n name: tc.name,\n args: tc.args,\n id: tc.id ?? nextToolCallId(),\n type: \"tool_call\" as const,\n })),\n });\n return this;\n }\n\n alwaysThrow(error: Error): this {\n this._alwaysThrowError = error;\n return this;\n }\n\n structuredResponse(value: Record<string, any>): this {\n this._structuredResponseValue = value;\n return this;\n }\n\n bindTools(tools: (StructuredTool | ToolSpec)[]) {\n const merged = [...this._tools, ...tools];\n const next = new FakeBuiltModel();\n next.queue = this.queue;\n next._alwaysThrowError = this._alwaysThrowError;\n next._structuredResponseValue = this._structuredResponseValue;\n next._tools = merged;\n next._calls = this._calls;\n next._callIndex = this._callIndex;\n\n return next.withConfig({} as BaseChatModelCallOptions);\n }\n\n withStructuredOutput<\n RunOutput extends Record<string, any> = Record<string, any>,\n >(\n _params:\n | StructuredOutputMethodParams<RunOutput, boolean>\n | InteropZodType<RunOutput>\n | Record<string, any>,\n _config?: StructuredOutputMethodOptions<boolean>\n ):\n | Runnable<BaseLanguageModelInput, RunOutput>\n | Runnable<\n BaseLanguageModelInput,\n { raw: BaseMessage; parsed: RunOutput }\n > {\n const { _structuredResponseValue } = this;\n return RunnableLambda.from(async () => {\n return _structuredResponseValue as RunOutput;\n }) as Runnable;\n }\n\n async _generate(\n messages: BaseMessage[],\n options?: this[\"ParsedCallOptions\"],\n _runManager?: CallbackManagerForLLMRun\n ): Promise<ChatResult> {\n this._calls.push({ messages: [...messages], options });\n\n const currentCallIndex = this._callIndex;\n this._callIndex += 1;\n\n if (this._alwaysThrowError) {\n throw this._alwaysThrowError;\n }\n\n const entry = this.queue[currentCallIndex];\n if (!entry) {\n throw new Error(\n `FakeModel: no response queued for invocation ${currentCallIndex} (${this.queue.length} total queued).`\n );\n }\n\n if (entry.kind === \"error\") {\n throw entry.error;\n }\n\n if (entry.kind === \"factory\") {\n const result = entry.factory(messages);\n if (!BaseMessage.isInstance(result)) {\n throw result;\n }\n return {\n generations: [{ text: \"\", message: result }],\n };\n }\n\n if (entry.kind === \"message\") {\n return {\n generations: [{ text: \"\", message: entry.message }],\n };\n }\n\n const content = deriveContent(messages);\n const message = new AIMessage({\n content,\n id: currentCallIndex.toString(),\n tool_calls:\n entry.toolCalls.length > 0\n ? entry.toolCalls.map((tc) => ({\n ...tc,\n type: \"tool_call\" as const,\n }))\n : undefined,\n });\n\n return {\n generations: [{ text: content, message }],\n llmOutput: {},\n };\n }\n}\n\n/**\n * Creates a fake chat model for testing.\n *\n * @example\n * ```typescript\n * const model = fakeModel()\n * .respondWithTools([{ name: \"search\", args: { query: \"weather\" } }])\n * .respond(new AIMessage(\"Sunny and warm.\"));\n *\n * const r1 = await model.invoke([new HumanMessage(\"What's the weather?\")]);\n * // r1.tool_calls[0].name === \"search\"\n *\n * const r2 = await model.invoke([new HumanMessage(\"Thanks\")]);\n * // r2.content === \"Sunny and warm.\"\n * ```\n */\nexport function fakeModel(): FakeBuiltModel {\n return new FakeBuiltModel();\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
|
|
3
|
+
const require_matchers = require('./matchers.cjs');
|
|
4
|
+
const require_fake_model_builder = require('./fake_model_builder.cjs');
|
|
5
|
+
|
|
6
|
+
//#region src/testing/index.ts
|
|
7
|
+
var testing_exports = /* @__PURE__ */ require_runtime.__exportAll({
|
|
8
|
+
fakeModel: () => require_fake_model_builder.fakeModel,
|
|
9
|
+
langchainMatchers: () => require_matchers.langchainMatchers,
|
|
10
|
+
toBeAIMessage: () => require_matchers.toBeAIMessage,
|
|
11
|
+
toBeHumanMessage: () => require_matchers.toBeHumanMessage,
|
|
12
|
+
toBeSystemMessage: () => require_matchers.toBeSystemMessage,
|
|
13
|
+
toBeToolMessage: () => require_matchers.toBeToolMessage,
|
|
14
|
+
toContainToolCall: () => require_matchers.toContainToolCall,
|
|
15
|
+
toHaveBeenInterrupted: () => require_matchers.toHaveBeenInterrupted,
|
|
16
|
+
toHaveStructuredResponse: () => require_matchers.toHaveStructuredResponse,
|
|
17
|
+
toHaveToolCallCount: () => require_matchers.toHaveToolCallCount,
|
|
18
|
+
toHaveToolCalls: () => require_matchers.toHaveToolCalls,
|
|
19
|
+
toHaveToolMessages: () => require_matchers.toHaveToolMessages
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
//#endregion
|
|
23
|
+
exports.fakeModel = require_fake_model_builder.fakeModel;
|
|
24
|
+
exports.langchainMatchers = require_matchers.langchainMatchers;
|
|
25
|
+
Object.defineProperty(exports, 'testing_exports', {
|
|
26
|
+
enumerable: true,
|
|
27
|
+
get: function () {
|
|
28
|
+
return testing_exports;
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
exports.toBeAIMessage = require_matchers.toBeAIMessage;
|
|
32
|
+
exports.toBeHumanMessage = require_matchers.toBeHumanMessage;
|
|
33
|
+
exports.toBeSystemMessage = require_matchers.toBeSystemMessage;
|
|
34
|
+
exports.toBeToolMessage = require_matchers.toBeToolMessage;
|
|
35
|
+
exports.toContainToolCall = require_matchers.toContainToolCall;
|
|
36
|
+
exports.toHaveBeenInterrupted = require_matchers.toHaveBeenInterrupted;
|
|
37
|
+
exports.toHaveStructuredResponse = require_matchers.toHaveStructuredResponse;
|
|
38
|
+
exports.toHaveToolCallCount = require_matchers.toHaveToolCallCount;
|
|
39
|
+
exports.toHaveToolCalls = require_matchers.toHaveToolCalls;
|
|
40
|
+
exports.toHaveToolMessages = require_matchers.toHaveToolMessages;
|
|
41
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../../src/testing/index.ts"],"sourcesContent":["export * from \"./matchers.js\";\nexport { fakeModel } from \"./fake_model_builder.js\";\n"],"mappings":""}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { LangChainMatchers, langchainMatchers, toBeAIMessage, toBeHumanMessage, toBeSystemMessage, toBeToolMessage, toContainToolCall, toHaveBeenInterrupted, toHaveStructuredResponse, toHaveToolCallCount, toHaveToolCalls, toHaveToolMessages } from "./matchers.cjs";
|
|
2
|
+
import { fakeModel } from "./fake_model_builder.cjs";
|
|
3
|
+
export { LangChainMatchers, fakeModel, langchainMatchers, toBeAIMessage, toBeHumanMessage, toBeSystemMessage, toBeToolMessage, toContainToolCall, toHaveBeenInterrupted, toHaveStructuredResponse, toHaveToolCallCount, toHaveToolCalls, toHaveToolMessages };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { LangChainMatchers, langchainMatchers, toBeAIMessage, toBeHumanMessage, toBeSystemMessage, toBeToolMessage, toContainToolCall, toHaveBeenInterrupted, toHaveStructuredResponse, toHaveToolCallCount, toHaveToolCalls, toHaveToolMessages } from "./matchers.js";
|
|
2
|
+
import { fakeModel } from "./fake_model_builder.js";
|
|
3
|
+
export { LangChainMatchers, fakeModel, langchainMatchers, toBeAIMessage, toBeHumanMessage, toBeSystemMessage, toBeToolMessage, toContainToolCall, toHaveBeenInterrupted, toHaveStructuredResponse, toHaveToolCallCount, toHaveToolCalls, toHaveToolMessages };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { __exportAll } from "../_virtual/_rolldown/runtime.js";
|
|
2
|
+
import { langchainMatchers, toBeAIMessage, toBeHumanMessage, toBeSystemMessage, toBeToolMessage, toContainToolCall, toHaveBeenInterrupted, toHaveStructuredResponse, toHaveToolCallCount, toHaveToolCalls, toHaveToolMessages } from "./matchers.js";
|
|
3
|
+
import { fakeModel } from "./fake_model_builder.js";
|
|
4
|
+
|
|
5
|
+
//#region src/testing/index.ts
|
|
6
|
+
var testing_exports = /* @__PURE__ */ __exportAll({
|
|
7
|
+
fakeModel: () => fakeModel,
|
|
8
|
+
langchainMatchers: () => langchainMatchers,
|
|
9
|
+
toBeAIMessage: () => toBeAIMessage,
|
|
10
|
+
toBeHumanMessage: () => toBeHumanMessage,
|
|
11
|
+
toBeSystemMessage: () => toBeSystemMessage,
|
|
12
|
+
toBeToolMessage: () => toBeToolMessage,
|
|
13
|
+
toContainToolCall: () => toContainToolCall,
|
|
14
|
+
toHaveBeenInterrupted: () => toHaveBeenInterrupted,
|
|
15
|
+
toHaveStructuredResponse: () => toHaveStructuredResponse,
|
|
16
|
+
toHaveToolCallCount: () => toHaveToolCallCount,
|
|
17
|
+
toHaveToolCalls: () => toHaveToolCalls,
|
|
18
|
+
toHaveToolMessages: () => toHaveToolMessages
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
//#endregion
|
|
22
|
+
export { fakeModel, langchainMatchers, testing_exports, toBeAIMessage, toBeHumanMessage, toBeSystemMessage, toBeToolMessage, toContainToolCall, toHaveBeenInterrupted, toHaveStructuredResponse, toHaveToolCallCount, toHaveToolCalls, toHaveToolMessages };
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/testing/index.ts"],"sourcesContent":["export * from \"./matchers.js\";\nexport { fakeModel } from \"./fake_model_builder.js\";\n"],"mappings":""}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
const require_base = require('../messages/base.cjs');
|
|
2
|
+
const require_messages_tool = require('../messages/tool.cjs');
|
|
3
|
+
const require_ai = require('../messages/ai.cjs');
|
|
4
|
+
const require_human = require('../messages/human.cjs');
|
|
5
|
+
const require_system = require('../messages/system.cjs');
|
|
6
|
+
require('../messages/index.cjs');
|
|
7
|
+
|
|
8
|
+
//#region src/testing/matchers.ts
|
|
9
|
+
function getMessageTypeName(msg) {
|
|
10
|
+
if (!require_base.BaseMessage.isInstance(msg)) return typeof msg;
|
|
11
|
+
return msg.constructor.name || msg.type;
|
|
12
|
+
}
|
|
13
|
+
function makeMessageTypeMatcher(typeName, isInstance) {
|
|
14
|
+
return function(received, expected) {
|
|
15
|
+
const { isNot, utils } = this;
|
|
16
|
+
if (!isInstance(received)) return {
|
|
17
|
+
pass: false,
|
|
18
|
+
message: () => `${utils.matcherHint(`toBe${typeName}`, void 0, void 0)}\n\nExpected: ${isNot ? "not " : ""}${typeName}\nReceived: ${getMessageTypeName(received)}`,
|
|
19
|
+
actual: getMessageTypeName(received),
|
|
20
|
+
expected: typeName
|
|
21
|
+
};
|
|
22
|
+
if (expected === void 0) return {
|
|
23
|
+
pass: true,
|
|
24
|
+
message: () => `${utils.matcherHint(`toBe${typeName}`, void 0, void 0)}\n\nExpected: not ${typeName}\nReceived: ${typeName}`
|
|
25
|
+
};
|
|
26
|
+
const msg = received;
|
|
27
|
+
if (typeof expected === "string") return {
|
|
28
|
+
pass: msg.content === expected,
|
|
29
|
+
message: () => `${utils.matcherHint(`toBe${typeName}`, void 0, void 0)}\n\nExpected: ${typeName} with content ${utils.printExpected(expected)}\nReceived: ${typeName} with content ${utils.printReceived(msg.content)}`,
|
|
30
|
+
actual: msg.content,
|
|
31
|
+
expected
|
|
32
|
+
};
|
|
33
|
+
return {
|
|
34
|
+
pass: Object.entries(expected).every(([key, value]) => this.equals(msg[key], value)),
|
|
35
|
+
message: () => {
|
|
36
|
+
const receivedFields = {};
|
|
37
|
+
for (const key of Object.keys(expected)) receivedFields[key] = msg[key];
|
|
38
|
+
return `${utils.matcherHint(`toBe${typeName}`, void 0, void 0)}\n\nExpected: ${typeName} matching ${utils.printExpected(expected)}\nReceived: ${typeName} with ${utils.printReceived(receivedFields)}`;
|
|
39
|
+
},
|
|
40
|
+
actual: (() => {
|
|
41
|
+
const receivedFields = {};
|
|
42
|
+
for (const key of Object.keys(expected)) receivedFields[key] = msg[key];
|
|
43
|
+
return receivedFields;
|
|
44
|
+
})(),
|
|
45
|
+
expected
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
const toBeHumanMessage = makeMessageTypeMatcher("HumanMessage", require_human.HumanMessage.isInstance);
|
|
50
|
+
const toBeAIMessage = makeMessageTypeMatcher("AIMessage", require_ai.AIMessage.isInstance);
|
|
51
|
+
const toBeSystemMessage = makeMessageTypeMatcher("SystemMessage", require_system.SystemMessage.isInstance);
|
|
52
|
+
const toBeToolMessage = makeMessageTypeMatcher("ToolMessage", require_messages_tool.ToolMessage.isInstance);
|
|
53
|
+
function toHaveToolCalls(received, expected) {
|
|
54
|
+
const { isNot, utils } = this;
|
|
55
|
+
if (!require_ai.AIMessage.isInstance(received)) return {
|
|
56
|
+
pass: false,
|
|
57
|
+
message: () => `${utils.matcherHint("toHaveToolCalls")}\n\nExpected: AIMessage\nReceived: ${getMessageTypeName(received)}`
|
|
58
|
+
};
|
|
59
|
+
const actual = received.tool_calls ?? [];
|
|
60
|
+
if (actual.length !== expected.length) return {
|
|
61
|
+
pass: false,
|
|
62
|
+
message: () => `${utils.matcherHint("toHaveToolCalls")}\n\nExpected ${isNot ? "not " : ""}${expected.length} tool call(s), received ${actual.length}`,
|
|
63
|
+
actual: actual.length,
|
|
64
|
+
expected: expected.length
|
|
65
|
+
};
|
|
66
|
+
const unmatched = expected.filter((exp) => !actual.some((tc) => Object.entries(exp).every(([key, value]) => this.equals(tc[key], value))));
|
|
67
|
+
if (unmatched.length > 0) return {
|
|
68
|
+
pass: false,
|
|
69
|
+
message: () => `${utils.matcherHint("toHaveToolCalls")}\n\nCould not find matching tool call(s) for:\n${utils.printExpected(unmatched)}\nReceived tool calls: ${utils.printReceived(actual.map((tc) => ({
|
|
70
|
+
name: tc.name,
|
|
71
|
+
id: tc.id,
|
|
72
|
+
args: tc.args
|
|
73
|
+
})))}`,
|
|
74
|
+
actual: actual.map((tc) => ({
|
|
75
|
+
name: tc.name,
|
|
76
|
+
id: tc.id,
|
|
77
|
+
args: tc.args
|
|
78
|
+
})),
|
|
79
|
+
expected
|
|
80
|
+
};
|
|
81
|
+
return {
|
|
82
|
+
pass: true,
|
|
83
|
+
message: () => `${utils.matcherHint("toHaveToolCalls")}\n\nExpected AIMessage not to have matching tool calls`
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function toHaveToolCallCount(received, expected) {
|
|
87
|
+
const { isNot, utils } = this;
|
|
88
|
+
if (!require_ai.AIMessage.isInstance(received)) return {
|
|
89
|
+
pass: false,
|
|
90
|
+
message: () => `${utils.matcherHint("toHaveToolCallCount")}\n\nExpected: AIMessage\nReceived: ${getMessageTypeName(received)}`
|
|
91
|
+
};
|
|
92
|
+
const actual = received.tool_calls?.length ?? 0;
|
|
93
|
+
return {
|
|
94
|
+
pass: actual === expected,
|
|
95
|
+
message: () => `${utils.matcherHint("toHaveToolCallCount")}\n\nExpected ${isNot ? "not " : ""}${expected} tool call(s)\nReceived: ${actual}`,
|
|
96
|
+
actual,
|
|
97
|
+
expected
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function toContainToolCall(received, expected) {
|
|
101
|
+
const { isNot, utils } = this;
|
|
102
|
+
if (!require_ai.AIMessage.isInstance(received)) return {
|
|
103
|
+
pass: false,
|
|
104
|
+
message: () => `${utils.matcherHint("toContainToolCall")}\n\nExpected: AIMessage\nReceived: ${getMessageTypeName(received)}`
|
|
105
|
+
};
|
|
106
|
+
const actual = received.tool_calls ?? [];
|
|
107
|
+
return {
|
|
108
|
+
pass: actual.some((tc) => Object.entries(expected).every(([key, value]) => this.equals(tc[key], value))),
|
|
109
|
+
message: () => `${utils.matcherHint("toContainToolCall")}\n\nExpected AIMessage ${isNot ? "not " : ""}to contain a tool call matching ${utils.printExpected(expected)}\nReceived tool calls: ${utils.printReceived(actual.map((tc) => ({
|
|
110
|
+
name: tc.name,
|
|
111
|
+
id: tc.id
|
|
112
|
+
})))}`,
|
|
113
|
+
actual: actual.map((tc) => ({
|
|
114
|
+
name: tc.name,
|
|
115
|
+
id: tc.id
|
|
116
|
+
})),
|
|
117
|
+
expected
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function toHaveToolMessages(received, expected) {
|
|
121
|
+
const { isNot, utils } = this;
|
|
122
|
+
if (!Array.isArray(received)) return {
|
|
123
|
+
pass: false,
|
|
124
|
+
message: () => `${utils.matcherHint("toHaveToolMessages")}\n\nExpected an array of messages\nReceived: ${typeof received}`
|
|
125
|
+
};
|
|
126
|
+
const toolMessages = received.filter(require_messages_tool.ToolMessage.isInstance);
|
|
127
|
+
if (toolMessages.length !== expected.length) return {
|
|
128
|
+
pass: false,
|
|
129
|
+
message: () => `${utils.matcherHint("toHaveToolMessages")}\n\nExpected ${isNot ? "not " : ""}${expected.length} tool message(s), found ${toolMessages.length}`,
|
|
130
|
+
actual: toolMessages.length,
|
|
131
|
+
expected: expected.length
|
|
132
|
+
};
|
|
133
|
+
for (let i = 0; i < expected.length; i++) if (!Object.entries(expected[i]).every(([key, value]) => this.equals(toolMessages[i][key], value))) return {
|
|
134
|
+
pass: false,
|
|
135
|
+
message: () => {
|
|
136
|
+
const receivedFields = {};
|
|
137
|
+
for (const key of Object.keys(expected[i])) receivedFields[key] = toolMessages[i][key];
|
|
138
|
+
return `${utils.matcherHint("toHaveToolMessages")}\n\nTool message at index ${i} did not match:\nExpected: ${utils.printExpected(expected[i])}\nReceived: ${utils.printReceived(receivedFields)}`;
|
|
139
|
+
},
|
|
140
|
+
actual: toolMessages[i],
|
|
141
|
+
expected: expected[i]
|
|
142
|
+
};
|
|
143
|
+
return {
|
|
144
|
+
pass: true,
|
|
145
|
+
message: () => `${utils.matcherHint("toHaveToolMessages")}\n\nExpected messages not to contain matching tool messages`
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
function toHaveBeenInterrupted(received, expectedValue) {
|
|
149
|
+
const { isNot, utils } = this;
|
|
150
|
+
const interrupts = received?.__interrupt__;
|
|
151
|
+
if (!(Array.isArray(interrupts) && interrupts.length > 0)) return {
|
|
152
|
+
pass: false,
|
|
153
|
+
message: () => `${utils.matcherHint("toHaveBeenInterrupted")}\n\nExpected result ${isNot ? "not " : ""}to have been interrupted\nReceived __interrupt__: ${utils.printReceived(interrupts)}`
|
|
154
|
+
};
|
|
155
|
+
if (expectedValue === void 0) return {
|
|
156
|
+
pass: true,
|
|
157
|
+
message: () => `${utils.matcherHint("toHaveBeenInterrupted")}\n\nExpected result not to have been interrupted\nReceived ${interrupts.length} interrupt(s)`
|
|
158
|
+
};
|
|
159
|
+
const actualValue = interrupts[0]?.value;
|
|
160
|
+
return {
|
|
161
|
+
pass: this.equals(actualValue, expectedValue),
|
|
162
|
+
message: () => `${utils.matcherHint("toHaveBeenInterrupted")}\n\nExpected interrupt value: ${utils.printExpected(expectedValue)}\nReceived interrupt value: ${utils.printReceived(actualValue)}`,
|
|
163
|
+
actual: actualValue,
|
|
164
|
+
expected: expectedValue
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
function toHaveStructuredResponse(received, expected) {
|
|
168
|
+
const { isNot, utils } = this;
|
|
169
|
+
const structuredResponse = received?.structuredResponse;
|
|
170
|
+
if (!(structuredResponse !== void 0)) return {
|
|
171
|
+
pass: false,
|
|
172
|
+
message: () => `${utils.matcherHint("toHaveStructuredResponse")}\n\nExpected result ${isNot ? "not " : ""}to have a structured response\nReceived structuredResponse: undefined`
|
|
173
|
+
};
|
|
174
|
+
if (expected === void 0) return {
|
|
175
|
+
pass: true,
|
|
176
|
+
message: () => `${utils.matcherHint("toHaveStructuredResponse")}\n\nExpected result not to have a structured response`
|
|
177
|
+
};
|
|
178
|
+
return {
|
|
179
|
+
pass: Object.entries(expected).every(([key, value]) => this.equals(structuredResponse[key], value)),
|
|
180
|
+
message: () => `${utils.matcherHint("toHaveStructuredResponse")}\n\nExpected structured response: ${utils.printExpected(expected)}\nReceived structured response: ${utils.printReceived(structuredResponse)}`,
|
|
181
|
+
actual: structuredResponse,
|
|
182
|
+
expected
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* All matcher functions bundled for convenient use with `expect.extend()`.
|
|
187
|
+
*/
|
|
188
|
+
const langchainMatchers = {
|
|
189
|
+
toBeHumanMessage,
|
|
190
|
+
toBeAIMessage,
|
|
191
|
+
toBeSystemMessage,
|
|
192
|
+
toBeToolMessage,
|
|
193
|
+
toHaveToolCalls,
|
|
194
|
+
toHaveToolCallCount,
|
|
195
|
+
toContainToolCall,
|
|
196
|
+
toHaveToolMessages,
|
|
197
|
+
toHaveBeenInterrupted,
|
|
198
|
+
toHaveStructuredResponse
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
//#endregion
|
|
202
|
+
exports.langchainMatchers = langchainMatchers;
|
|
203
|
+
exports.toBeAIMessage = toBeAIMessage;
|
|
204
|
+
exports.toBeHumanMessage = toBeHumanMessage;
|
|
205
|
+
exports.toBeSystemMessage = toBeSystemMessage;
|
|
206
|
+
exports.toBeToolMessage = toBeToolMessage;
|
|
207
|
+
exports.toContainToolCall = toContainToolCall;
|
|
208
|
+
exports.toHaveBeenInterrupted = toHaveBeenInterrupted;
|
|
209
|
+
exports.toHaveStructuredResponse = toHaveStructuredResponse;
|
|
210
|
+
exports.toHaveToolCallCount = toHaveToolCallCount;
|
|
211
|
+
exports.toHaveToolCalls = toHaveToolCalls;
|
|
212
|
+
exports.toHaveToolMessages = toHaveToolMessages;
|
|
213
|
+
//# sourceMappingURL=matchers.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matchers.cjs","names":["BaseMessage","HumanMessage","AIMessage","SystemMessage","ToolMessage"],"sources":["../../src/testing/matchers.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { BaseMessage } from \"../messages/index.js\";\nimport { HumanMessage } from \"../messages/index.js\";\nimport { AIMessage } from \"../messages/index.js\";\nimport { SystemMessage } from \"../messages/index.js\";\nimport { ToolMessage } from \"../messages/index.js\";\n\n/**\n * The `this` context that Vitest and Jest provide to custom matchers\n * via `expect.extend`.\n *\n * Compatible with both frameworks:\n * - https://vitest.dev/guide/extending-matchers.html\n * - https://jestjs.io/docs/expect#expectextendmatchers\n */\ninterface ExpectExtendThis {\n isNot?: boolean;\n equals(a: unknown, b: unknown): boolean;\n utils: {\n matcherHint(name: string, received?: string, expected?: string): string;\n printReceived(value: unknown): string;\n printExpected(value: unknown): string;\n };\n}\n\ninterface ExpectationResult {\n pass: boolean;\n message: () => string;\n actual?: unknown;\n expected?: unknown;\n}\n\nfunction getMessageTypeName(msg: unknown): string {\n if (!BaseMessage.isInstance(msg)) return typeof msg;\n return msg.constructor.name || msg.type;\n}\n\nfunction makeMessageTypeMatcher(\n typeName: string,\n isInstance: (obj: unknown) => boolean\n) {\n return function (\n this: ExpectExtendThis,\n received: unknown,\n expected?: string | Record<string, unknown>\n ): ExpectationResult {\n const { isNot, utils } = this;\n\n const instancePass = isInstance(received);\n if (!instancePass) {\n return {\n pass: false,\n message: () =>\n `${utils.matcherHint(`toBe${typeName}`, undefined, undefined)}\\n\\n` +\n `Expected: ${isNot ? \"not \" : \"\"}${typeName}\\n` +\n `Received: ${getMessageTypeName(received)}`,\n actual: getMessageTypeName(received),\n expected: typeName,\n };\n }\n\n if (expected === undefined) {\n return {\n pass: true,\n message: () =>\n `${utils.matcherHint(`toBe${typeName}`, undefined, undefined)}\\n\\n` +\n `Expected: not ${typeName}\\n` +\n `Received: ${typeName}`,\n };\n }\n\n const msg = received as BaseMessage;\n if (typeof expected === \"string\") {\n const contentPass = msg.content === expected;\n return {\n pass: contentPass,\n message: () =>\n `${utils.matcherHint(`toBe${typeName}`, undefined, undefined)}\\n\\n` +\n `Expected: ${typeName} with content ${utils.printExpected(expected)}\\n` +\n `Received: ${typeName} with content ${utils.printReceived(msg.content)}`,\n actual: msg.content,\n expected,\n };\n }\n\n const fieldsPass = Object.entries(expected).every(([key, value]) =>\n this.equals((msg as any)[key], value)\n );\n return {\n pass: fieldsPass,\n message: () => {\n const receivedFields: Record<string, unknown> = {};\n for (const key of Object.keys(expected)) {\n receivedFields[key] = (msg as any)[key];\n }\n return (\n `${utils.matcherHint(`toBe${typeName}`, undefined, undefined)}\\n\\n` +\n `Expected: ${typeName} matching ${utils.printExpected(expected)}\\n` +\n `Received: ${typeName} with ${utils.printReceived(receivedFields)}`\n );\n },\n actual: (() => {\n const receivedFields: Record<string, unknown> = {};\n for (const key of Object.keys(expected)) {\n receivedFields[key] = (msg as any)[key];\n }\n return receivedFields;\n })(),\n expected,\n };\n };\n}\n\nexport const toBeHumanMessage = makeMessageTypeMatcher(\n \"HumanMessage\",\n HumanMessage.isInstance\n);\n\nexport const toBeAIMessage = makeMessageTypeMatcher(\n \"AIMessage\",\n AIMessage.isInstance\n);\n\nexport const toBeSystemMessage = makeMessageTypeMatcher(\n \"SystemMessage\",\n SystemMessage.isInstance\n);\n\nexport const toBeToolMessage = makeMessageTypeMatcher(\n \"ToolMessage\",\n ToolMessage.isInstance\n);\n\nexport function toHaveToolCalls(\n this: ExpectExtendThis,\n received: unknown,\n expected: Array<Record<string, unknown>>\n): ExpectationResult {\n const { isNot, utils } = this;\n\n if (!AIMessage.isInstance(received)) {\n return {\n pass: false,\n message: () =>\n `${utils.matcherHint(\"toHaveToolCalls\")}\\n\\n` +\n `Expected: AIMessage\\n` +\n `Received: ${getMessageTypeName(received)}`,\n };\n }\n\n const actual = received.tool_calls ?? [];\n\n if (actual.length !== expected.length) {\n return {\n pass: false,\n message: () =>\n `${utils.matcherHint(\"toHaveToolCalls\")}\\n\\n` +\n `Expected ${isNot ? \"not \" : \"\"}${expected.length} tool call(s), received ${actual.length}`,\n actual: actual.length,\n expected: expected.length,\n };\n }\n\n const unmatched = expected.filter(\n (exp) =>\n !actual.some((tc) =>\n Object.entries(exp).every(([key, value]) =>\n this.equals((tc as any)[key], value)\n )\n )\n );\n\n if (unmatched.length > 0) {\n return {\n pass: false,\n message: () =>\n `${utils.matcherHint(\"toHaveToolCalls\")}\\n\\n` +\n `Could not find matching tool call(s) for:\\n` +\n `${utils.printExpected(unmatched)}\\n` +\n `Received tool calls: ${utils.printReceived(actual.map((tc) => ({ name: tc.name, id: tc.id, args: tc.args })))}`,\n actual: actual.map((tc) => ({ name: tc.name, id: tc.id, args: tc.args })),\n expected,\n };\n }\n\n return {\n pass: true,\n message: () =>\n `${utils.matcherHint(\"toHaveToolCalls\")}\\n\\n` +\n `Expected AIMessage not to have matching tool calls`,\n };\n}\n\nexport function toHaveToolCallCount(\n this: ExpectExtendThis,\n received: unknown,\n expected: number\n): ExpectationResult {\n const { isNot, utils } = this;\n\n if (!AIMessage.isInstance(received)) {\n return {\n pass: false,\n message: () =>\n `${utils.matcherHint(\"toHaveToolCallCount\")}\\n\\n` +\n `Expected: AIMessage\\n` +\n `Received: ${getMessageTypeName(received)}`,\n };\n }\n\n const actual = received.tool_calls?.length ?? 0;\n const pass = actual === expected;\n\n return {\n pass,\n message: () =>\n `${utils.matcherHint(\"toHaveToolCallCount\")}\\n\\n` +\n `Expected ${isNot ? \"not \" : \"\"}${expected} tool call(s)\\n` +\n `Received: ${actual}`,\n actual,\n expected,\n };\n}\n\nexport function toContainToolCall(\n this: ExpectExtendThis,\n received: unknown,\n expected: Record<string, unknown>\n): ExpectationResult {\n const { isNot, utils } = this;\n\n if (!AIMessage.isInstance(received)) {\n return {\n pass: false,\n message: () =>\n `${utils.matcherHint(\"toContainToolCall\")}\\n\\n` +\n `Expected: AIMessage\\n` +\n `Received: ${getMessageTypeName(received)}`,\n };\n }\n\n const actual = received.tool_calls ?? [];\n const found = actual.some((tc) =>\n Object.entries(expected).every(([key, value]) =>\n this.equals((tc as any)[key], value)\n )\n );\n\n return {\n pass: found,\n message: () =>\n `${utils.matcherHint(\"toContainToolCall\")}\\n\\n` +\n `Expected AIMessage ${isNot ? \"not \" : \"\"}to contain a tool call matching ${utils.printExpected(expected)}\\n` +\n `Received tool calls: ${utils.printReceived(actual.map((tc) => ({ name: tc.name, id: tc.id })))}`,\n actual: actual.map((tc) => ({ name: tc.name, id: tc.id })),\n expected,\n };\n}\n\nexport function toHaveToolMessages(\n this: ExpectExtendThis,\n received: unknown,\n expected: Array<Record<string, unknown>>\n): ExpectationResult {\n const { isNot, utils } = this;\n\n if (!Array.isArray(received)) {\n return {\n pass: false,\n message: () =>\n `${utils.matcherHint(\"toHaveToolMessages\")}\\n\\n` +\n `Expected an array of messages\\n` +\n `Received: ${typeof received}`,\n };\n }\n\n const toolMessages = (received as BaseMessage[]).filter(\n ToolMessage.isInstance\n );\n\n if (toolMessages.length !== expected.length) {\n return {\n pass: false,\n message: () =>\n `${utils.matcherHint(\"toHaveToolMessages\")}\\n\\n` +\n `Expected ${isNot ? \"not \" : \"\"}${expected.length} tool message(s), found ${toolMessages.length}`,\n actual: toolMessages.length,\n expected: expected.length,\n };\n }\n\n for (let i = 0; i < expected.length; i++) {\n const match = Object.entries(expected[i]).every(([key, value]) =>\n this.equals((toolMessages[i] as any)[key], value)\n );\n if (!match) {\n return {\n pass: false,\n message: () => {\n const receivedFields: Record<string, unknown> = {};\n for (const key of Object.keys(expected[i])) {\n receivedFields[key] = (toolMessages[i] as any)[key];\n }\n return (\n `${utils.matcherHint(\"toHaveToolMessages\")}\\n\\n` +\n `Tool message at index ${i} did not match:\\n` +\n `Expected: ${utils.printExpected(expected[i])}\\n` +\n `Received: ${utils.printReceived(receivedFields)}`\n );\n },\n actual: toolMessages[i],\n expected: expected[i],\n };\n }\n }\n\n return {\n pass: true,\n message: () =>\n `${utils.matcherHint(\"toHaveToolMessages\")}\\n\\n` +\n `Expected messages not to contain matching tool messages`,\n };\n}\n\nexport function toHaveBeenInterrupted(\n this: ExpectExtendThis,\n received: unknown,\n expectedValue?: unknown\n): ExpectationResult {\n const { isNot, utils } = this;\n\n const result = received as Record<string, any>;\n const interrupts = result?.__interrupt__;\n const hasInterrupt = Array.isArray(interrupts) && interrupts.length > 0;\n\n if (!hasInterrupt) {\n return {\n pass: false,\n message: () =>\n `${utils.matcherHint(\"toHaveBeenInterrupted\")}\\n\\n` +\n `Expected result ${isNot ? \"not \" : \"\"}to have been interrupted\\n` +\n `Received __interrupt__: ${utils.printReceived(interrupts)}`,\n };\n }\n\n if (expectedValue === undefined) {\n return {\n pass: true,\n message: () =>\n `${utils.matcherHint(\"toHaveBeenInterrupted\")}\\n\\n` +\n `Expected result not to have been interrupted\\n` +\n `Received ${interrupts.length} interrupt(s)`,\n };\n }\n\n const actualValue = interrupts[0]?.value;\n const valuePass = this.equals(actualValue, expectedValue);\n\n return {\n pass: valuePass,\n message: () =>\n `${utils.matcherHint(\"toHaveBeenInterrupted\")}\\n\\n` +\n `Expected interrupt value: ${utils.printExpected(expectedValue)}\\n` +\n `Received interrupt value: ${utils.printReceived(actualValue)}`,\n actual: actualValue,\n expected: expectedValue,\n };\n}\n\nexport function toHaveStructuredResponse(\n this: ExpectExtendThis,\n received: unknown,\n expected?: Record<string, unknown>\n): ExpectationResult {\n const { isNot, utils } = this;\n\n const result = received as Record<string, any>;\n const structuredResponse = result?.structuredResponse;\n const isDefined = structuredResponse !== undefined;\n\n if (!isDefined) {\n return {\n pass: false,\n message: () =>\n `${utils.matcherHint(\"toHaveStructuredResponse\")}\\n\\n` +\n `Expected result ${isNot ? \"not \" : \"\"}to have a structured response\\n` +\n `Received structuredResponse: undefined`,\n };\n }\n\n if (expected === undefined) {\n return {\n pass: true,\n message: () =>\n `${utils.matcherHint(\"toHaveStructuredResponse\")}\\n\\n` +\n `Expected result not to have a structured response`,\n };\n }\n\n const fieldsPass = Object.entries(expected).every(([key, value]) =>\n this.equals(structuredResponse[key], value)\n );\n\n return {\n pass: fieldsPass,\n message: () =>\n `${utils.matcherHint(\"toHaveStructuredResponse\")}\\n\\n` +\n `Expected structured response: ${utils.printExpected(expected)}\\n` +\n `Received structured response: ${utils.printReceived(structuredResponse)}`,\n actual: structuredResponse,\n expected,\n };\n}\n\n/**\n * All matcher functions bundled for convenient use with `expect.extend()`.\n */\nexport const langchainMatchers = {\n toBeHumanMessage,\n toBeAIMessage,\n toBeSystemMessage,\n toBeToolMessage,\n toHaveToolCalls,\n toHaveToolCallCount,\n toContainToolCall,\n toHaveToolMessages,\n toHaveBeenInterrupted,\n toHaveStructuredResponse,\n};\n\nexport interface LangChainMatchers<R = unknown> {\n toBeHumanMessage(expected?: string | { content?: string; id?: string }): R;\n toBeAIMessage(expected?: string | { content?: string; name?: string }): R;\n toBeSystemMessage(\n expected?: string | { content?: string; additional_kwargs?: object }\n ): R;\n toBeToolMessage(\n expected?:\n | string\n | {\n content?: string;\n name?: string;\n status?: string;\n tool_call_id?: string;\n }\n ): R;\n toHaveToolCalls(\n expected: Array<{\n name?: string;\n id?: string;\n args?: Record<string, unknown>;\n }>\n ): R;\n toHaveToolCallCount(expected: number): R;\n toContainToolCall(expected: {\n name?: string;\n id?: string;\n args?: Record<string, unknown>;\n }): R;\n toHaveToolMessages(\n expected: Array<{\n content?: string;\n name?: string;\n status?: string;\n tool_call_id?: string;\n }>\n ): R;\n toHaveBeenInterrupted(expectedValue?: unknown): R;\n toHaveStructuredResponse(expected?: Record<string, unknown>): R;\n}\n\ndeclare module \"vitest\" {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n interface Matchers<T = any> extends LangChainMatchers<T> {}\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
//#region src/testing/matchers.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The `this` context that Vitest and Jest provide to custom matchers
|
|
4
|
+
* via `expect.extend`.
|
|
5
|
+
*
|
|
6
|
+
* Compatible with both frameworks:
|
|
7
|
+
* - https://vitest.dev/guide/extending-matchers.html
|
|
8
|
+
* - https://jestjs.io/docs/expect#expectextendmatchers
|
|
9
|
+
*/
|
|
10
|
+
interface ExpectExtendThis {
|
|
11
|
+
isNot?: boolean;
|
|
12
|
+
equals(a: unknown, b: unknown): boolean;
|
|
13
|
+
utils: {
|
|
14
|
+
matcherHint(name: string, received?: string, expected?: string): string;
|
|
15
|
+
printReceived(value: unknown): string;
|
|
16
|
+
printExpected(value: unknown): string;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
interface ExpectationResult {
|
|
20
|
+
pass: boolean;
|
|
21
|
+
message: () => string;
|
|
22
|
+
actual?: unknown;
|
|
23
|
+
expected?: unknown;
|
|
24
|
+
}
|
|
25
|
+
declare const toBeHumanMessage: (this: ExpectExtendThis, received: unknown, expected?: string | Record<string, unknown> | undefined) => ExpectationResult;
|
|
26
|
+
declare const toBeAIMessage: (this: ExpectExtendThis, received: unknown, expected?: string | Record<string, unknown> | undefined) => ExpectationResult;
|
|
27
|
+
declare const toBeSystemMessage: (this: ExpectExtendThis, received: unknown, expected?: string | Record<string, unknown> | undefined) => ExpectationResult;
|
|
28
|
+
declare const toBeToolMessage: (this: ExpectExtendThis, received: unknown, expected?: string | Record<string, unknown> | undefined) => ExpectationResult;
|
|
29
|
+
declare function toHaveToolCalls(this: ExpectExtendThis, received: unknown, expected: Array<Record<string, unknown>>): ExpectationResult;
|
|
30
|
+
declare function toHaveToolCallCount(this: ExpectExtendThis, received: unknown, expected: number): ExpectationResult;
|
|
31
|
+
declare function toContainToolCall(this: ExpectExtendThis, received: unknown, expected: Record<string, unknown>): ExpectationResult;
|
|
32
|
+
declare function toHaveToolMessages(this: ExpectExtendThis, received: unknown, expected: Array<Record<string, unknown>>): ExpectationResult;
|
|
33
|
+
declare function toHaveBeenInterrupted(this: ExpectExtendThis, received: unknown, expectedValue?: unknown): ExpectationResult;
|
|
34
|
+
declare function toHaveStructuredResponse(this: ExpectExtendThis, received: unknown, expected?: Record<string, unknown>): ExpectationResult;
|
|
35
|
+
/**
|
|
36
|
+
* All matcher functions bundled for convenient use with `expect.extend()`.
|
|
37
|
+
*/
|
|
38
|
+
declare const langchainMatchers: {
|
|
39
|
+
toBeHumanMessage: (this: ExpectExtendThis, received: unknown, expected?: string | Record<string, unknown> | undefined) => ExpectationResult;
|
|
40
|
+
toBeAIMessage: (this: ExpectExtendThis, received: unknown, expected?: string | Record<string, unknown> | undefined) => ExpectationResult;
|
|
41
|
+
toBeSystemMessage: (this: ExpectExtendThis, received: unknown, expected?: string | Record<string, unknown> | undefined) => ExpectationResult;
|
|
42
|
+
toBeToolMessage: (this: ExpectExtendThis, received: unknown, expected?: string | Record<string, unknown> | undefined) => ExpectationResult;
|
|
43
|
+
toHaveToolCalls: typeof toHaveToolCalls;
|
|
44
|
+
toHaveToolCallCount: typeof toHaveToolCallCount;
|
|
45
|
+
toContainToolCall: typeof toContainToolCall;
|
|
46
|
+
toHaveToolMessages: typeof toHaveToolMessages;
|
|
47
|
+
toHaveBeenInterrupted: typeof toHaveBeenInterrupted;
|
|
48
|
+
toHaveStructuredResponse: typeof toHaveStructuredResponse;
|
|
49
|
+
};
|
|
50
|
+
interface LangChainMatchers<R = unknown> {
|
|
51
|
+
toBeHumanMessage(expected?: string | {
|
|
52
|
+
content?: string;
|
|
53
|
+
id?: string;
|
|
54
|
+
}): R;
|
|
55
|
+
toBeAIMessage(expected?: string | {
|
|
56
|
+
content?: string;
|
|
57
|
+
name?: string;
|
|
58
|
+
}): R;
|
|
59
|
+
toBeSystemMessage(expected?: string | {
|
|
60
|
+
content?: string;
|
|
61
|
+
additional_kwargs?: object;
|
|
62
|
+
}): R;
|
|
63
|
+
toBeToolMessage(expected?: string | {
|
|
64
|
+
content?: string;
|
|
65
|
+
name?: string;
|
|
66
|
+
status?: string;
|
|
67
|
+
tool_call_id?: string;
|
|
68
|
+
}): R;
|
|
69
|
+
toHaveToolCalls(expected: Array<{
|
|
70
|
+
name?: string;
|
|
71
|
+
id?: string;
|
|
72
|
+
args?: Record<string, unknown>;
|
|
73
|
+
}>): R;
|
|
74
|
+
toHaveToolCallCount(expected: number): R;
|
|
75
|
+
toContainToolCall(expected: {
|
|
76
|
+
name?: string;
|
|
77
|
+
id?: string;
|
|
78
|
+
args?: Record<string, unknown>;
|
|
79
|
+
}): R;
|
|
80
|
+
toHaveToolMessages(expected: Array<{
|
|
81
|
+
content?: string;
|
|
82
|
+
name?: string;
|
|
83
|
+
status?: string;
|
|
84
|
+
tool_call_id?: string;
|
|
85
|
+
}>): R;
|
|
86
|
+
toHaveBeenInterrupted(expectedValue?: unknown): R;
|
|
87
|
+
toHaveStructuredResponse(expected?: Record<string, unknown>): R;
|
|
88
|
+
}
|
|
89
|
+
declare module "vitest" {
|
|
90
|
+
interface Matchers<T = any> extends LangChainMatchers<T> {}
|
|
91
|
+
}
|
|
92
|
+
//#endregion
|
|
93
|
+
export { LangChainMatchers, langchainMatchers, toBeAIMessage, toBeHumanMessage, toBeSystemMessage, toBeToolMessage, toContainToolCall, toHaveBeenInterrupted, toHaveStructuredResponse, toHaveToolCallCount, toHaveToolCalls, toHaveToolMessages };
|
|
94
|
+
//# sourceMappingURL=matchers.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matchers.d.cts","names":[],"sources":["../../src/testing/matchers.ts"],"mappings":";;;;;;;;;UAeU,gBAAA;EACR,KAAA;EACA,MAAA,CAAO,CAAA,WAAY,CAAA;EACnB,KAAA;IACE,WAAA,CAAY,IAAA,UAAc,QAAA,WAAmB,QAAA;IAC7C,aAAA,CAAc,KAAA;IACd,aAAA,CAAc,KAAA;EAAA;AAAA;AAAA,UAIR,iBAAA;EACR,IAAA;EACA,OAAA;EACA,MAAA;EACA,QAAA;AAAA;AAAA,cAoFW,gBAAA,GAAgB,IAAA,EAAA,gBAAA,EAAA,QAAA,WAAA,QAAA,YAAA,MAAA,kCAAA,iBAAA;AAAA,cAKhB,aAAA,GAAa,IAAA,EAAA,gBAAA,EAAA,QAAA,WAAA,QAAA,YAAA,MAAA,kCAAA,iBAAA;AAAA,cAKb,iBAAA,GAAiB,IAAA,EAAA,gBAAA,EAAA,QAAA,WAAA,QAAA,YAAA,MAAA,kCAAA,iBAAA;AAAA,cAKjB,eAAA,GAAe,IAAA,EAAA,gBAAA,EAAA,QAAA,WAAA,QAAA,YAAA,MAAA,kCAAA,iBAAA;AAAA,iBAKZ,eAAA,CACd,IAAA,EAAM,gBAAA,EACN,QAAA,WACA,QAAA,EAAU,KAAA,CAAM,MAAA,qBACf,iBAAA;AAAA,iBAwDa,mBAAA,CACd,IAAA,EAAM,gBAAA,EACN,QAAA,WACA,QAAA,WACC,iBAAA;AAAA,iBA2Ba,iBAAA,CACd,IAAA,EAAM,gBAAA,EACN,QAAA,WACA,QAAA,EAAU,MAAA,oBACT,iBAAA;AAAA,iBA+Ba,kBAAA,CACd,IAAA,EAAM,gBAAA,EACN,QAAA,WACA,QAAA,EAAU,KAAA,CAAM,MAAA,qBACf,iBAAA;AAAA,iBA6Da,qBAAA,CACd,IAAA,EAAM,gBAAA,EACN,QAAA,WACA,aAAA,aACC,iBAAA;AAAA,iBAyCa,wBAAA,CACd,IAAA,EAAM,gBAAA,EACN,QAAA,WACA,QAAA,GAAW,MAAA,oBACV,iBAAA;;;;cA4CU,iBAAA;;;;;;;;;;;;UAaI,iBAAA;EACf,gBAAA,CAAiB,QAAA;IAAsB,OAAA;IAAkB,EAAA;EAAA,IAAgB,CAAA;EACzE,aAAA,CAAc,QAAA;IAAsB,OAAA;IAAkB,IAAA;EAAA,IAAkB,CAAA;EACxE,iBAAA,CACE,QAAA;IAAsB,OAAA;IAAkB,iBAAA;EAAA,IACvC,CAAA;EACH,eAAA,CACE,QAAA;IAGM,OAAA;IACA,IAAA;IACA,MAAA;IACA,YAAA;EAAA,IAEL,CAAA;EACH,eAAA,CACE,QAAA,EAAU,KAAA;IACR,IAAA;IACA,EAAA;IACA,IAAA,GAAO,MAAA;EAAA,KAER,CAAA;EACH,mBAAA,CAAoB,QAAA,WAAmB,CAAA;EACvC,iBAAA,CAAkB,QAAA;IAChB,IAAA;IACA,EAAA;IACA,IAAA,GAAO,MAAA;EAAA,IACL,CAAA;EACJ,kBAAA,CACE,QAAA,EAAU,KAAA;IACR,OAAA;IACA,IAAA;IACA,MAAA;IACA,YAAA;EAAA,KAED,CAAA;EACH,qBAAA,CAAsB,aAAA,aAA0B,CAAA;EAChD,wBAAA,CAAyB,QAAA,GAAW,MAAA,oBAA0B,CAAA;AAAA;AAAA;EAAA,UAKpD,QAAA,kBAA0B,iBAAA,CAAkB,CAAA;AAAA"}
|