Buckets:
| import type { Message, Part } from "@opencode-ai/sdk/v2/client" | |
| export type SessionContextBreakdownKey = "system" | "user" | "assistant" | "tool" | "other" | |
| export type SessionContextBreakdownSegment = { | |
| key: SessionContextBreakdownKey | |
| tokens: number | |
| width: number | |
| percent: number | |
| } | |
| const estimateTokens = (chars: number) => Math.ceil(chars / 4) | |
| const toPercent = (tokens: number, input: number) => (tokens / input) * 100 | |
| const toPercentLabel = (tokens: number, input: number) => Math.round(toPercent(tokens, input) * 10) / 10 | |
| const charsFromUserPart = (part: Part) => { | |
| if (part.type === "text") return part.text.length | |
| if (part.type === "file") return part.source?.text.value.length ?? 0 | |
| if (part.type === "agent") return part.source?.value.length ?? 0 | |
| return 0 | |
| } | |
| const charsFromAssistantPart = (part: Part) => { | |
| if (part.type === "text") return { assistant: part.text.length, tool: 0 } | |
| if (part.type === "reasoning") return { assistant: part.text.length, tool: 0 } | |
| if (part.type !== "tool") return { assistant: 0, tool: 0 } | |
| const input = Object.keys(part.state.input).length * 16 | |
| if (part.state.status === "pending") return { assistant: 0, tool: input + part.state.raw.length } | |
| if (part.state.status === "completed") return { assistant: 0, tool: input + part.state.output.length } | |
| if (part.state.status === "error") return { assistant: 0, tool: input + part.state.error.length } | |
| return { assistant: 0, tool: input } | |
| } | |
| const build = ( | |
| tokens: { system: number; user: number; assistant: number; tool: number; other: number }, | |
| input: number, | |
| ) => { | |
| return [ | |
| { | |
| key: "system", | |
| tokens: tokens.system, | |
| }, | |
| { | |
| key: "user", | |
| tokens: tokens.user, | |
| }, | |
| { | |
| key: "assistant", | |
| tokens: tokens.assistant, | |
| }, | |
| { | |
| key: "tool", | |
| tokens: tokens.tool, | |
| }, | |
| { | |
| key: "other", | |
| tokens: tokens.other, | |
| }, | |
| ] | |
| .filter((x) => x.tokens > 0) | |
| .map((x) => ({ | |
| key: x.key, | |
| tokens: x.tokens, | |
| width: toPercent(x.tokens, input), | |
| percent: toPercentLabel(x.tokens, input), | |
| })) as SessionContextBreakdownSegment[] | |
| } | |
| export function estimateSessionContextBreakdown(args: { | |
| messages: Message[] | |
| parts: Record<string, Part[] | undefined> | |
| input: number | |
| systemPrompt?: string | |
| }) { | |
| if (!args.input) return [] | |
| const counts = args.messages.reduce( | |
| (acc, msg) => { | |
| const parts = args.parts[msg.id] ?? [] | |
| if (msg.role === "user") { | |
| const user = parts.reduce((sum, part) => sum + charsFromUserPart(part), 0) | |
| return { ...acc, user: acc.user + user } | |
| } | |
| if (msg.role !== "assistant") return acc | |
| const assistant = parts.reduce( | |
| (sum, part) => { | |
| const next = charsFromAssistantPart(part) | |
| return { | |
| assistant: sum.assistant + next.assistant, | |
| tool: sum.tool + next.tool, | |
| } | |
| }, | |
| { assistant: 0, tool: 0 }, | |
| ) | |
| return { | |
| ...acc, | |
| assistant: acc.assistant + assistant.assistant, | |
| tool: acc.tool + assistant.tool, | |
| } | |
| }, | |
| { | |
| system: args.systemPrompt?.length ?? 0, | |
| user: 0, | |
| assistant: 0, | |
| tool: 0, | |
| }, | |
| ) | |
| const tokens = { | |
| system: estimateTokens(counts.system), | |
| user: estimateTokens(counts.user), | |
| assistant: estimateTokens(counts.assistant), | |
| tool: estimateTokens(counts.tool), | |
| } | |
| const estimated = tokens.system + tokens.user + tokens.assistant + tokens.tool | |
| if (estimated <= args.input) { | |
| return build({ ...tokens, other: args.input - estimated }, args.input) | |
| } | |
| const scale = args.input / estimated | |
| const scaled = { | |
| system: Math.floor(tokens.system * scale), | |
| user: Math.floor(tokens.user * scale), | |
| assistant: Math.floor(tokens.assistant * scale), | |
| tool: Math.floor(tokens.tool * scale), | |
| } | |
| const total = scaled.system + scaled.user + scaled.assistant + scaled.tool | |
| return build({ ...scaled, other: Math.max(0, args.input - total) }, args.input) | |
| } | |
Xet Storage Details
- Size:
- 4.02 kB
- Xet hash:
- 6b00a353c70afcb27b924c8b3a56af5963bac8381e8f18d37354d09b3b451b30
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.