Files
CodeNomad/packages/ui/src/lib/token-utils.ts
2026-03-03 15:07:49 +00:00

67 lines
2.2 KiB
TypeScript

import type { ClientPart } from "../types/message"
/**
* Count the total character content of a message part.
*
* Used by both the xray histogram overlay (message-timeline) and the
* bulk-delete toolbar token pills (message-section) so both surfaces
* derive token estimates from the same logic.
*
* Note: For tool parts we intentionally only count `state.input` and
* `state.output`. We exclude `state.metadata` from token estimation since
* metadata can contain large or verbose diagnostic payloads that are not
* representative of model context.
*/
export function getPartCharCount(part: ClientPart): number {
if (!part) return 0
let count = 0
if (typeof (part as any).text === "string") {
count += (part as any).text.length
}
if (part.type === "tool") {
const state = (part as any).state
// Tool calls may be compacted server-side. When that happens we treat the
// tool payload as effectively absent from context for token estimation.
const compacted = (state as any)?.time?.compacted
if (compacted !== undefined && compacted !== null) {
return 0
}
if (state) {
if (state.input) {
try {
count += JSON.stringify(state.input).length
} catch {}
}
if (state.output) {
if (typeof state.output === "string") {
count += state.output.length
} else {
try {
count += JSON.stringify(state.output).length
} catch {}
}
}
}
}
if (Array.isArray((part as any).content)) {
count += (part as any).content.reduce((acc: number, entry: unknown) => {
if (typeof entry === "string") return acc + entry.length
if (entry && typeof entry === "object") {
let entryCount = (String((entry as any).text || "")).length + (String((entry as any).value || "")).length
if (Array.isArray((entry as any).content)) {
entryCount += (entry as any).content.reduce((innerAcc: number, sub: unknown) => {
if (typeof sub === "string") return innerAcc + sub.length
return innerAcc + (String((sub as any)?.text || "")).length
}, 0)
}
return acc + entryCount
}
return acc
}, 0)
}
return count
}