mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-07-09 01:27:41 -07:00
strong owner
This commit is contained in:
@@ -8,25 +8,27 @@ import type { Content } from '@google/genai';
|
||||
import type { ConcreteNode } from './types.js';
|
||||
import { debugLogger } from '../../utils/debugLogger.js';
|
||||
import type { NodeIdService } from './nodeIdService.js';
|
||||
import type { HistoryTurn } from '../../core/agentChatHistory.js';
|
||||
|
||||
/**
|
||||
* Reconstructs a valid Gemini Chat History from a list of Concrete Nodes.
|
||||
* Reconstructs a list of HistoryTurns 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.
|
||||
* preserve original turn boundaries and IDs.
|
||||
*/
|
||||
export function fromGraph(
|
||||
nodes: readonly ConcreteNode[],
|
||||
idService?: NodeIdService,
|
||||
): Content[] {
|
||||
): HistoryTurn[] {
|
||||
debugLogger.log(
|
||||
`[fromGraph] Reconstructing history from ${nodes.length} nodes`,
|
||||
);
|
||||
|
||||
const history: Content[] = [];
|
||||
let currentTurn: (Content & { _turnId?: string }) | null = null;
|
||||
const history: HistoryTurn[] = [];
|
||||
let currentTurn: { id: string; content: Content } | null = null;
|
||||
|
||||
for (const node of nodes) {
|
||||
const turnId = node.turnId;
|
||||
const turnId = node.turnId || 'orphan';
|
||||
const durableId = turnId.startsWith('turn_') ? turnId.slice(5) : turnId;
|
||||
|
||||
// Register the payload in the identity service to ensure stability
|
||||
// even if the turn content changes (e.g. after GC backstop).
|
||||
@@ -40,26 +42,25 @@ export function fromGraph(
|
||||
// 3. The turnId changes (Preserving distinct turns of the same role).
|
||||
if (
|
||||
!currentTurn ||
|
||||
currentTurn.role !== node.role ||
|
||||
currentTurn._turnId !== turnId
|
||||
currentTurn.content.role !== node.role ||
|
||||
currentTurn.id !== durableId
|
||||
) {
|
||||
currentTurn = {
|
||||
role: node.role,
|
||||
parts: [node.payload],
|
||||
_turnId: turnId,
|
||||
id: durableId,
|
||||
content: {
|
||||
role: node.role,
|
||||
parts: [node.payload],
|
||||
},
|
||||
};
|
||||
history.push(currentTurn);
|
||||
} else {
|
||||
currentTurn.parts = [...(currentTurn.parts || []), node.payload];
|
||||
currentTurn.content.parts = [
|
||||
...(currentTurn.content.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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user