/** * @file antigravity-transcript.test.js * @description An Antigravity (agy) session's conversation view: its * `transcript_full.jsonl` step log mapped to the Claude transcript shape — * the prompt out of ``, the model's thinking, text, tool calls * and tokens, each tool result tied to its call by step and an invalid call * marked an error — one "main" transcript, no subagent files, and a session * id that is no UUID finding nothing. The agy dir and the DB are temp dirs; * the steps are synthetic, in the shape agy 1.4 writes. * @author Nguyễn Ngọc Trí Vĩ */ const os = require("node:os"); const fs = require("node:fs"); const path = require("node:path"); const ROOT = fs.mkdtempSync(path.join(os.tmpdir(), "agenthub-agy-transcript-")); process.env.DASHBOARD_DB_PATH = path.join(ROOT, "dashboard.db"); process.env.AGENTHUB_GEMINI_DIR = path.join(ROOT, "gemini"); process.env.CLAUDE_HOME = path.join(ROOT, "claude"); const { describe, it, after } = require("node:test"); const assert = require("node:assert/strict"); const { db } = require("../db"); const agy = require("../lib/antigravity-usage"); let server; after(() => { server?.close(); fs.rmSync(ROOT, { recursive: true, force: true }); }); const ID = "57154e1a-65e5-4b51-a116-1890f5ca831f"; const AT = "2026-10-21T05:08:24Z"; function steps(id) { const dir = path.join( process.env.AGENTHUB_GEMINI_DIR, "antigravity-cli", "brain", id, ".system_generated", "logs" ); fs.mkdirSync(dir, { recursive: true }); const file = path.join(dir, "transcript_full.jsonl"); const lines = [ { step_index: 0, source: "USER_EXPLICIT", type: "USER_INPUT", status: "DONE", created_at: AT, content: "\nCreate c.txt\n\n\nThe current local time is: x.\n", }, { step_index: 1, source: "MODEL", type: "PLANNER_RESPONSE", status: "DONE", created_at: AT, input_tokens: 3889, cache_read_tokens: 768, output_tokens: 12, thinking: "Two commands.", content: "Running them now.", tool_calls: [ { name: "run_command", args: { CommandLine: "echo ok > c.txt" } }, { name: "read", args: { path: "c.txt" } }, ], }, { step_index: 2, source: "MODEL", type: "GENERIC", status: "DONE", created_at: AT, content: "Created At: x\nCompleted At: y\n\nThe command exited with code 0.\n", }, { step_index: 3, source: "MODEL", type: "GENERIC", status: "INVALID", error: 'unknown tool: "read"', created_at: AT, content: 'Created At: x\nCompleted At: y\nError invalid tool call: unknown tool: "read"', }, { step_index: 4, source: "MODEL", type: "PLANNER_RESPONSE", status: "DONE", created_at: AT, content: "Done.", }, ]; fs.writeFileSync(file, lines.map((l) => JSON.stringify(l)).join("\n") + "\n"); return file; } describe("an Antigravity session's conversation", () => { it("reads agy's step log in the Claude transcript shape", async () => { const file = steps(ID); assert.equal(agy.transcriptPath(ID), file); assert.equal(agy.transcriptPath("../../etc"), null); db.prepare( "INSERT INTO sessions (id, name, status, started_at, tool) VALUES (?, 'c', 'completed', ?, 'antigravity')" ).run(ID, AT); const { createApp, startServer } = require("../index"); server ||= await startServer(createApp(), 0); const BASE = `http://127.0.0.1:${server.address().port}`; const list = await (await fetch(`${BASE}/api/sessions/${ID}/transcripts`)).json(); assert.deepEqual( list.transcripts.map((t) => [t.id, t.type]), [["main", "main"]] ); const body = await (await fetch(`${BASE}/api/sessions/${ID}/transcript`)).json(); assert.deepEqual( body.messages.map((m) => [m.sender, m.content.map((c) => c.type)]), [ ["user", ["text"]], ["assistant", ["thinking", "text", "tool_use", "tool_use"]], ["tool", ["tool_result"]], ["tool", ["tool_result"]], ["assistant", ["text"]], ] ); const [user, plan, ok, bad] = body.messages; assert.equal(user.content[0].text, "Create c.txt"); assert.equal(user.timestamp, AT); // Each result names the call it answers: call i of step s lands at step s+1+i. assert.deepEqual( plan.content.filter((c) => c.type === "tool_use").map((c) => c.id), [ok.content[0].id, bad.content[0].id] ); assert.equal(ok.content[0].output, "The command exited with code 0.\n"); assert.equal(ok.content[0].is_error, false); assert.equal(bad.content[0].is_error, true); assert.equal(plan.usage.input_tokens, 3889); assert.equal(plan.usage.cache_read_input_tokens, 768); const sub = await (await fetch(`${BASE}/api/sessions/${ID}/transcript?agent_id=x`)).json(); assert.equal(sub.messages.length, 0); }); });