gemini-cli / packages /core /src /context /graph /fromGraph.test.ts
SaylorTwift's picture
SaylorTwift HF Staff
Add files using upload-large-folder tool
7a1ad33 verified
Raw
History Blame Contribute Delete
4.78 kB
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { describe, it, expect } from 'vitest';
import { fromGraph } from './fromGraph.js';
import { NodeType, type ConcreteNode } from './types.js';
import { NodeIdService } from './nodeIdService.js';
describe('fromGraph', () => {
it('should reconstruct an empty history from empty nodes', () => {
expect(fromGraph([])).toEqual([]);
});
it('should reconstruct a single turn from a single node', () => {
const nodes: ConcreteNode[] = [
{
id: 'node_1',
turnId: 'turn_durable_1',
role: 'user',
type: NodeType.USER_PROMPT,
payload: { text: 'hello' },
timestamp: 100,
},
];
const history = fromGraph(nodes);
expect(history).toEqual([
{
id: 'durable_1',
content: {
role: 'user',
parts: [{ text: 'hello' }],
},
},
]);
});
it('should coalesce adjacent nodes with the same turnId into a single turn', () => {
const nodes: ConcreteNode[] = [
{
id: 'node_1',
turnId: 'turn_durable_1',
role: 'user',
type: NodeType.USER_PROMPT,
payload: { text: 'hello' },
timestamp: 100,
},
{
id: 'node_2',
turnId: 'turn_durable_1',
role: 'user',
type: NodeType.USER_PROMPT,
payload: { text: 'world' },
timestamp: 101,
},
];
const history = fromGraph(nodes);
expect(history).toEqual([
{
id: 'durable_1',
content: {
role: 'user',
parts: [{ text: 'hello' }, { text: 'world' }],
},
},
]);
});
it('should split turns when the role changes', () => {
const nodes: ConcreteNode[] = [
{
id: 'node_1',
turnId: 'turn_durable_1',
role: 'user',
type: NodeType.USER_PROMPT,
payload: { text: 'hello' },
timestamp: 100,
},
{
id: 'node_2',
turnId: 'turn_durable_2',
role: 'model',
type: NodeType.AGENT_THOUGHT,
payload: { text: 'hi' },
timestamp: 101,
},
];
const history = fromGraph(nodes);
expect(history).toEqual([
{
id: 'durable_1',
content: {
role: 'user',
parts: [{ text: 'hello' }],
},
},
{
id: 'durable_2',
content: {
role: 'model',
parts: [{ text: 'hi' }],
},
},
]);
});
it('should split turns when the turnId changes, even if role is the same', () => {
const nodes: ConcreteNode[] = [
{
id: 'node_1',
turnId: 'turn_durable_1',
role: 'user',
type: NodeType.USER_PROMPT,
payload: { text: 'hello' },
timestamp: 100,
},
{
id: 'node_2',
turnId: 'turn_durable_2',
role: 'user',
type: NodeType.USER_PROMPT,
payload: { text: 'world' },
timestamp: 101,
},
];
const history = fromGraph(nodes);
expect(history).toEqual([
{
id: 'durable_1',
content: {
role: 'user',
parts: [{ text: 'hello' }],
},
},
{
id: 'durable_2',
content: {
role: 'user',
parts: [{ text: 'world' }],
},
},
]);
});
it('should correctly strip the turn_ prefix from turnId', () => {
const nodes: ConcreteNode[] = [
{
id: 'node_1',
turnId: 'turn_my_stable_id_123',
role: 'user',
type: NodeType.USER_PROMPT,
payload: { text: 'hello' },
timestamp: 100,
},
];
const history = fromGraph(nodes);
expect(history[0].id).toBe('my_stable_id_123');
});
it('should handle orphan nodes gracefully', () => {
const nodes: ConcreteNode[] = [
{
id: 'node_1',
role: 'user',
type: NodeType.USER_PROMPT,
payload: { text: 'orphan part' },
timestamp: 100,
} as unknown as ConcreteNode,
];
const history = fromGraph(nodes);
expect(history[0].id).toBe('orphan');
expect(history[0].content.parts).toEqual([{ text: 'orphan part' }]);
});
it('should register identities with the NodeIdService if provided', () => {
const idService = new NodeIdService();
const payload = { text: 'hello' };
const nodes: ConcreteNode[] = [
{
id: 'node_1',
turnId: 'turn_1',
role: 'user',
type: NodeType.USER_PROMPT,
payload,
timestamp: 100,
},
];
fromGraph(nodes, idService);
// The payload object reference should map to the node ID
expect(idService.get(payload)).toBe('node_1');
});
});