mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-06-16 22:36:48 -07:00
56 lines
1.6 KiB
TypeScript
56 lines
1.6 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2026 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
import type { Content } from '@google/genai';
|
|
import type { ConcreteNode } from './types.js';
|
|
import { debugLogger } from '../../utils/debugLogger.js';
|
|
|
|
/**
|
|
* Reconstructs a valid Gemini Chat History from a list of Concrete Nodes.
|
|
* This process is "role-alternation-aware" and uses turnId to
|
|
* preserve original turn boundaries even if multiple turns have the same role.
|
|
*/
|
|
export function fromGraph(nodes: readonly ConcreteNode[]): Content[] {
|
|
debugLogger.log(
|
|
`[fromGraph] Reconstructing history from ${nodes.length} nodes`,
|
|
);
|
|
|
|
const history: Content[] = [];
|
|
let currentTurn: (Content & { _turnId?: string }) | null = null;
|
|
|
|
for (const node of nodes) {
|
|
const turnId = node.turnId;
|
|
|
|
// We start a new turn if:
|
|
// 1. We don't have a current turn.
|
|
// 2. The role changes (Standard alternation).
|
|
// 3. The turnId changes (Preserving distinct turns of the same role).
|
|
if (
|
|
!currentTurn ||
|
|
currentTurn.role !== node.role ||
|
|
currentTurn._turnId !== turnId
|
|
) {
|
|
currentTurn = {
|
|
role: node.role,
|
|
parts: [node.payload],
|
|
_turnId: turnId,
|
|
};
|
|
history.push(currentTurn);
|
|
} else {
|
|
currentTurn.parts = [...(currentTurn.parts || []), node.payload];
|
|
}
|
|
}
|
|
|
|
// Final cleanup: remove our internal tracking field
|
|
for (const turn of history) {
|
|
const t = turn as Content & { _turnId?: string };
|
|
delete t._turnId;
|
|
}
|
|
|
|
debugLogger.log(`[fromGraph] Reconstructed ${history.length} turns`);
|
|
return history;
|
|
}
|