|
1 | 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ |
2 | 2 | import { describe, it, expect } from "vitest"; |
3 | 3 | import { ChatCompletionMessage } from "openai/resources"; |
| 4 | +import { AIMessage } from "@langchain/core/messages"; |
4 | 5 | import { |
5 | 6 | completionsApiContentBlockConverter, |
6 | 7 | convertCompletionsMessageToBaseMessage, |
| 8 | + convertMessagesToCompletionsMessageParams, |
7 | 9 | convertStandardContentBlockToCompletionsContentPart, |
8 | 10 | } from "../completions.js"; |
9 | 11 |
|
@@ -194,6 +196,102 @@ describe("convertCompletionsMessageToBaseMessage", () => { |
194 | 196 | }); |
195 | 197 | }); |
196 | 198 |
|
| 199 | + describe("convertMessagesToCompletionsMessageParams", () => { |
| 200 | + it("should preserve AIMessage content when tool_calls are present", () => { |
| 201 | + const message = new AIMessage({ |
| 202 | + content: |
| 203 | + "I'll check the status of item 730 for identifier X1110 to find out why it's not active.", |
| 204 | + tool_calls: [ |
| 205 | + { |
| 206 | + id: "call_zGKlzVl2Ee3Lyob4AsyqfGXb", |
| 207 | + name: "getStatus", |
| 208 | + args: { identifier: "X1110", itemId: "730" }, |
| 209 | + }, |
| 210 | + ], |
| 211 | + }); |
| 212 | + |
| 213 | + const result = convertMessagesToCompletionsMessageParams({ |
| 214 | + messages: [message], |
| 215 | + }); |
| 216 | + |
| 217 | + expect(result).toHaveLength(1); |
| 218 | + expect(result[0]).toEqual({ |
| 219 | + role: "assistant", |
| 220 | + content: |
| 221 | + "I'll check the status of item 730 for identifier X1110 to find out why it's not active.", |
| 222 | + tool_calls: [ |
| 223 | + { |
| 224 | + id: "call_zGKlzVl2Ee3Lyob4AsyqfGXb", |
| 225 | + type: "function", |
| 226 | + function: { |
| 227 | + name: "getStatus", |
| 228 | + arguments: '{"identifier":"X1110","itemId":"730"}', |
| 229 | + }, |
| 230 | + }, |
| 231 | + ], |
| 232 | + }); |
| 233 | + }); |
| 234 | + |
| 235 | + it("should handle AIMessage with empty content and tool_calls", () => { |
| 236 | + const message = new AIMessage({ |
| 237 | + content: "", |
| 238 | + tool_calls: [ |
| 239 | + { |
| 240 | + id: "call_123", |
| 241 | + name: "someFunction", |
| 242 | + args: { key: "value" }, |
| 243 | + }, |
| 244 | + ], |
| 245 | + }); |
| 246 | + |
| 247 | + const result = convertMessagesToCompletionsMessageParams({ |
| 248 | + messages: [message], |
| 249 | + }); |
| 250 | + |
| 251 | + expect(result).toHaveLength(1); |
| 252 | + expect(result[0]).toEqual({ |
| 253 | + role: "assistant", |
| 254 | + content: "", |
| 255 | + tool_calls: [ |
| 256 | + { |
| 257 | + id: "call_123", |
| 258 | + type: "function", |
| 259 | + function: { |
| 260 | + name: "someFunction", |
| 261 | + arguments: '{"key":"value"}', |
| 262 | + }, |
| 263 | + }, |
| 264 | + ], |
| 265 | + }); |
| 266 | + }); |
| 267 | + |
| 268 | + it("should preserve content with function_call in additional_kwargs", () => { |
| 269 | + const message = new AIMessage({ |
| 270 | + content: "Let me call a function for you.", |
| 271 | + additional_kwargs: { |
| 272 | + function_call: { |
| 273 | + name: "myFunction", |
| 274 | + arguments: '{"arg":"value"}', |
| 275 | + }, |
| 276 | + }, |
| 277 | + }); |
| 278 | + |
| 279 | + const result = convertMessagesToCompletionsMessageParams({ |
| 280 | + messages: [message], |
| 281 | + }); |
| 282 | + |
| 283 | + expect(result).toHaveLength(1); |
| 284 | + expect(result[0]).toEqual({ |
| 285 | + role: "assistant", |
| 286 | + content: "Let me call a function for you.", |
| 287 | + function_call: { |
| 288 | + name: "myFunction", |
| 289 | + arguments: '{"arg":"value"}', |
| 290 | + }, |
| 291 | + }); |
| 292 | + }); |
| 293 | + }); |
| 294 | + |
197 | 295 | describe("completionsApiContentBlockConverter.fromStandardFileBlock", () => { |
198 | 296 | it("throws when base64 file block is missing filename/name/title metadata", () => { |
199 | 297 | const block = { |
|
0 commit comments