diff --git a/packages/tui/src/component/devtools-bar.tsx b/packages/tui/src/component/devtools-bar.tsx
index 45c031069c..8fa55144e1 100644
--- a/packages/tui/src/component/devtools-bar.tsx
+++ b/packages/tui/src/component/devtools-bar.tsx
@@ -77,6 +77,7 @@ export function DevToolsBar() {
const runtime = createMemo(() => runtimeStatus(frontendSamples()))
const timing = () => config.data.debug?.timing ?? false
const turnTokens = () => config.data.debug?.turn_tokens ?? false
+ const verboseTurnTokens = () => turnTokens() === "verbose"
const offEscape = keymap.intercept(
"key",
@@ -380,6 +381,16 @@ export function DevToolsBar() {
>
{turnTokens() ? "[x]" : "[ ]"} Turn token usage
+
+ void config.update((draft) => {
+ draft.debug = { ...draft.debug, turn_tokens: verboseTurnTokens() ? true : "verbose" }
+ })
+ }
+ hoverBackground
+ >
+ {verboseTurnTokens() ? "[x]" : "[ ]"} Turn token usage (verbose)
+
{(group) => (
diff --git a/packages/tui/src/component/dialog-config.tsx b/packages/tui/src/component/dialog-config.tsx
index 0cf13f88ac..49d5f93650 100644
--- a/packages/tui/src/component/dialog-config.tsx
+++ b/packages/tui/src/component/dialog-config.tsx
@@ -254,8 +254,8 @@ export const settings: Setting[] = [
category: "Debug",
path: ["debug", "turn_tokens"],
default: false,
- values: [false, true],
- labels: ["off", "on"],
+ values: [false, true, "verbose"],
+ labels: ["off", "on", "verbose"],
keywords: ["tokens", "usage", "debug"],
},
]
diff --git a/packages/tui/src/config/index.tsx b/packages/tui/src/config/index.tsx
index 424e8dbc9a..70e2ed3d30 100644
--- a/packages/tui/src/config/index.tsx
+++ b/packages/tui/src/config/index.tsx
@@ -159,7 +159,9 @@ export const Info = Schema.Struct({
Schema.Struct({
devtools: Schema.optional(Schema.Boolean).annotate({ description: "Show the DevTools debug bar" }),
timing: Schema.optional(Schema.Boolean).annotate({ description: "Show time-to-first-draw diagnostics" }),
- turn_tokens: Schema.optional(Schema.Boolean).annotate({ description: "Show per-turn token usage diagnostics" }),
+ turn_tokens: Schema.optional(Schema.Union([Schema.Boolean, Schema.Literal("verbose")])).annotate({
+ description: "Show per-turn token usage diagnostics, optionally with tool call inputs",
+ }),
}),
).annotate({ description: "Debugging settings" }),
animations: Schema.optional(Schema.Boolean).annotate({ description: "Enable interface animations" }),
diff --git a/packages/tui/src/context/data.tsx b/packages/tui/src/context/data.tsx
index f0e313f921..01a60f57f1 100644
--- a/packages/tui/src/context/data.tsx
+++ b/packages/tui/src/context/data.tsx
@@ -761,6 +761,12 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
})
break
case "session.compaction.ended":
+ setStore(
+ "session",
+ "pending",
+ event.data.sessionID,
+ (store.session.pending[event.data.sessionID] ?? []).filter((item) => item.type !== "compaction"),
+ )
message.update(event.data.sessionID, (draft, index) => {
const position = draft.findLastIndex((item) => item.type === "compaction" && item.status === "running")
const current = draft[position]
diff --git a/packages/tui/src/routes/session/index.tsx b/packages/tui/src/routes/session/index.tsx
index 4b1717b488..917e3a4e83 100644
--- a/packages/tui/src/routes/session/index.tsx
+++ b/packages/tui/src/routes/session/index.tsx
@@ -1104,6 +1104,7 @@ function TurnTokenUsage(props: {
}) {
const config = useConfig()
const { themeV2 } = useTheme()
+ const verbose = () => config.data.debug?.turn_tokens === "verbose"
const steps = createMemo(() => {
let previousCache = props.previousCache
return props.messageIDs.flatMap((messageID) => {
@@ -1123,6 +1124,7 @@ function TurnTokenUsage(props: {
return [
{
finish: message.finish === "tool-calls" ? "tool-call" : (message.finish ?? "unknown"),
+ tools: verbose() ? message.content.filter((part) => part.type === "tool") : [],
newTokens,
cached: message.tokens.cache.read,
total,
@@ -1138,7 +1140,7 @@ function TurnTokenUsage(props: {
total: Math.max("Total".length, ...steps().map((item) => item.total.toLocaleString().length)),
}))
return (
- 0}>
+ 0}>
@@ -1161,7 +1163,7 @@ function TurnTokenUsage(props: {
{(item) => (
-
+
{item.finish.padEnd(columns().step + 2)}
{item.newTokens.toLocaleString().padStart(columns().newTokens)}
@@ -1171,6 +1173,7 @@ function TurnTokenUsage(props: {
{" "}
{item.total.toLocaleString().padStart(columns().total)}
+
! Likely cache bust: {item.reuseDrop?.toLocaleString()} fewer cached tokens than the previous step
@@ -1184,6 +1187,54 @@ function TurnTokenUsage(props: {
)
}
+function TurnTokenToolCalls(props: { tools: SessionMessageAssistantTool[] }) {
+ const { themeV2 } = useTheme()
+ const nameWidth = () => Math.max(0, ...props.tools.map((tool) => tool.name.length)) + 2
+ return (
+ 0}>
+
+
+ {(tool) => (
+
+
+ {tool.name}
+
+
+ {turnTokenToolSummary(tool)}
+
+
+ )}
+
+
+
+ )
+}
+
+function turnTokenToolSummary(tool: SessionMessageAssistantTool) {
+ const data = tool.state.input
+ if (typeof data === "string") return data
+ const primaryKey = ["command", "id", "pattern", "url", "query", "path", "description", "code"].find(
+ (key) => key in data,
+ )
+ const input = Object.entries(data).filter(([, value]) =>
+ ["string", "number", "boolean"].includes(typeof value),
+ )
+ const primary = input.find(([key]) => key === primaryKey)?.[1]
+ const details = input.filter(([key]) => key !== primaryKey).map(([key, value]) => `${key}: ${String(value)}`)
+ return [primary === undefined ? "" : String(primary), ...details].filter(Boolean).join(" ")
+}
+
function BackgroundToolHint(props: { messages: SessionMessageInfo[] }) {
const { themeV2 } = useTheme()
const shortcut = Keymap.useShortcut("session.background")
diff --git a/packages/tui/src/routes/session/rows.ts b/packages/tui/src/routes/session/rows.ts
index 3c20184011..1f8e814793 100644
--- a/packages/tui/src/routes/session/rows.ts
+++ b/packages/tui/src/routes/session/rows.ts
@@ -41,7 +41,7 @@ export function createSessionRows(sessionID: Accessor) {
const config = useConfig()
const [rows, setRows] = createStore([])
const revertBoundary = () => data.session.get(sessionID())?.revert?.messageID
- const turnTokens = () => config.data.debug?.turn_tokens === true
+ const turnTokens = () => Boolean(config.data.debug?.turn_tokens)
function reduce() {
const messages = data.session.message.list(sessionID())