(
userInput: Content,
modelOutput: Content[],
automaticFunctionCallingHistory?: Content[],
)
| 490 | } |
| 491 | |
| 492 | private recordHistory( |
| 493 | userInput: Content, |
| 494 | modelOutput: Content[], |
| 495 | automaticFunctionCallingHistory?: Content[], |
| 496 | ) { |
| 497 | const nonThoughtModelOutput = modelOutput.filter( |
| 498 | (content) => !this.isThoughtContent(content), |
| 499 | ); |
| 500 | |
| 501 | let outputContents: Content[] = []; |
| 502 | if ( |
| 503 | nonThoughtModelOutput.length > 0 && |
| 504 | nonThoughtModelOutput.every((content) => content.role !== undefined) |
| 505 | ) { |
| 506 | outputContents = nonThoughtModelOutput; |
| 507 | } else if (nonThoughtModelOutput.length === 0 && modelOutput.length > 0) { |
| 508 | // This case handles when the model returns only a thought. |
| 509 | // We don't want to add an empty model response in this case. |
| 510 | } else { |
| 511 | // When not a function response appends an empty content when model returns empty response, so that the |
| 512 | // history is always alternating between user and model. |
| 513 | // Workaround for: https://b.corp.google.com/issues/420354090 |
| 514 | if (!isFunctionResponse(userInput)) { |
| 515 | outputContents.push({ |
| 516 | role: 'model', |
| 517 | parts: [], |
| 518 | } as Content); |
| 519 | } |
| 520 | } |
| 521 | if ( |
| 522 | automaticFunctionCallingHistory && |
| 523 | automaticFunctionCallingHistory.length > 0 |
| 524 | ) { |
| 525 | this.history.push( |
| 526 | ...extractCuratedHistory(automaticFunctionCallingHistory), |
| 527 | ); |
| 528 | } else { |
| 529 | this.history.push(userInput); |
| 530 | } |
| 531 | |
| 532 | // Consolidate adjacent model roles in outputContents |
| 533 | const consolidatedOutputContents: Content[] = []; |
| 534 | for (const content of outputContents) { |
| 535 | if (this.isThoughtContent(content)) { |
| 536 | continue; |
| 537 | } |
| 538 | const lastContent = |
| 539 | consolidatedOutputContents[consolidatedOutputContents.length - 1]; |
| 540 | if (this.isTextContent(lastContent) && this.isTextContent(content)) { |
| 541 | // If both current and last are text, combine their text into the lastContent's first part |
| 542 | // and append any other parts from the current content. |
| 543 | lastContent.parts[0].text += content.parts[0].text || ''; |
| 544 | if (content.parts.length > 1) { |
| 545 | lastContent.parts.push(...content.parts.slice(1)); |
| 546 | } |
| 547 | } else { |
| 548 | consolidatedOutputContents.push(content); |
| 549 | } |
no test coverage detected