Time-Travel Debugging

advanced15 mintime-travel.ts

A multi-step run went somewhere unexpected. You want to replay it from a step, or fork it with a different instruction and diff the paths.

What it shows

  • Checkpoint every step with TimeTravel
  • Replay, fork with new input and compare

The code

time-travel.ts
import { Agent, Cogitator, InMemoryCheckpointStore, TimeTravel, tool } from '@cogitator-ai/core';
import { z } from 'zod';

const apiKey = process.env.GOOGLE_API_KEY;
if (!apiKey) throw new Error('Set GOOGLE_API_KEY');

const inventory: Record<string, number> = { wood: 100, stone: 80, iron: 30, gold: 5 };
const recipes: Record<string, Record<string, number>> = {
  wooden_sword: { wood: 10 },
  stone_pickaxe: { wood: 5, stone: 15 },
  iron_armor: { iron: 20, wood: 5 },
  gold_ring: { gold: 2 },
};

const checkInventory = tool({
  name: 'check_inventory',
  description: 'Check current inventory of materials',
  parameters: z.object({}),
  execute: async () => ({ ...inventory }),
});

const craft = tool({
  name: 'craft',
  description: 'Craft an item: wooden_sword, stone_pickaxe, iron_armor or gold_ring',
  parameters: z.object({ item: z.string() }),
  execute: async ({ item }) => {
    const recipe = recipes[item];
    if (!recipe) return { error: `Unknown item: ${item}` };
    for (const [material, amount] of Object.entries(recipe)) {
      if ((inventory[material] ?? 0) < amount) return { error: `Not enough ${material}` };
    }
    for (const [material, amount] of Object.entries(recipe)) inventory[material] -= amount;
    return { crafted: item, remaining: { ...inventory } };
  },
});

const cog = new Cogitator({ llm: { providers: { google: { apiKey } } } });
const timeTravel = new TimeTravel(cog, { checkpointStore: new InMemoryCheckpointStore() });

const crafter = new Agent({
  name: 'crafter',
  model: 'google/gemini-3.5-flash-lite',
  instructions: 'You are a game crafting assistant. Check inventory first, then craft what is asked.',
  tools: [checkInventory, craft],
  temperature: 0.2,
  maxIterations: 10,
});

const original = await cog.run(crafter, {
  input: 'Check our inventory, then craft a stone_pickaxe and a wooden_sword.',
});
console.log('Original path:', original.toolCalls.map((call) => call.name).join(' -> '));

const checkpoints = await timeTravel.checkpointAll(original, 'craft-session');
console.log(`Saved ${checkpoints.length} checkpoints`);

const replay = await timeTravel.replay(crafter, checkpoints[0].id, { mode: 'live' });
console.log(`Replayed ${replay.stepsReplayed} steps, executed ${replay.stepsExecuted} new ones`);

const fork = await timeTravel.forkWithNewInput(
  crafter,
  checkpoints[0].id,
  'Craft a gold_ring and an iron_armor instead. Check inventory first.',
  'alt-craft-path'
);
console.log('Fork path:', fork.result.toolCalls.map((call) => call.name).join(' -> '));

const diff = await timeTravel.compareWithOriginal(fork.result);
console.log(timeTravel.formatDiff(diff));

await cog.close();

Run it

install · bash
pnpm add @cogitator-ai/core zod
EnvironmentGOOGLE_API_KEY
run · bash
GOOGLE_API_KEY=your-key npx tsx time-travel.ts

Or run the full example from a clone of the repository (keys in .env):

repository · bash
npx tsx examples/core/08-time-travel.ts

Learn more