diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-context.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-context.tsx
index 2eed011c5..452e67411 100644
--- a/packages/opencode/src/cli/cmd/tui/component/dialog-context.tsx
+++ b/packages/opencode/src/cli/cmd/tui/component/dialog-context.tsx
@@ -1,15 +1,14 @@
-import { createMemo, createSignal, For } from "solid-js"
+import { createMemo, For } from "solid-js"
+import { TextAttributes } from "@opentui/core"
import { useTheme } from "../context/theme"
import { useSync } from "@tui/context/sync"
import { useLocal } from "@tui/context/local"
import type { AssistantMessage } from "@opencode-ai/sdk/v2"
interface ContextItem {
- type: "system" | "instruction" | "file" | "message"
+ type: "system" | "instruction" | "message"
name: string
tokens: number
- content?: string
- enabled: boolean
}
export function DialogContext(props: { sessionID: string }) {
@@ -19,160 +18,126 @@ export function DialogContext(props: { sessionID: string }) {
const messages = createMemo(() => sync.data.message[props.sessionID] ?? [])
- // Calculate context breakdown
- const contextItems = createMemo((): ContextItem[] => {
- const items: ContextItem[] = []
+ const contextBreakdown = createMemo(() => {
+ const breakdown: ContextItem[] = []
- // Get last assistant message for token info
+ // Get last assistant message for actual token info
const lastAssistant = messages().findLast(
(x) => x.role === "assistant" && (x as AssistantMessage).tokens?.output > 0
) as AssistantMessage | undefined
- // System prompt estimate (varies by provider)
const model = local.model.current()
+
+ // System prompt (varies by provider)
if (model) {
- items.push({
+ breakdown.push({
type: "system",
- name: `System Prompt (${model.providerID})`,
- tokens: 8000, // Approximate
- enabled: true,
+ name: `System prompt (${model.providerID})`,
+ tokens: lastAssistant?.tokens?.cache?.write ?? 8000,
})
}
- // Environment context
- items.push({
+ // Environment & file tree
+ breakdown.push({
type: "system",
- name: "Environment & File Tree",
- tokens: 2000, // Approximate
- enabled: true,
+ name: "Environment & file tree",
+ tokens: 2000,
})
- // Instructions files
- const instructionFiles = [
- "~/context/PROMPT_TEMPLATE.md",
- "~/context/README.md",
- "AGENTS.md",
- "CLAUDE.md",
- ]
- for (const file of instructionFiles) {
- items.push({
- type: "instruction",
- name: file,
- tokens: 1500, // Approximate per file
- enabled: true,
- })
- }
+ // Instructions from config
+ breakdown.push({
+ type: "instruction",
+ name: "Custom instructions",
+ tokens: 4000,
+ })
- // Session messages
- let messageTokens = 0
+ // Conversation history
+ let conversationTokens = 0
for (const msg of messages()) {
if (msg.role === "assistant") {
const assistant = msg as AssistantMessage
- messageTokens += assistant.tokens?.input ?? 0
- messageTokens += assistant.tokens?.output ?? 0
+ conversationTokens += assistant.tokens?.input ?? 0
}
}
- if (messageTokens > 0) {
- items.push({
+
+ if (conversationTokens > 0) {
+ breakdown.push({
type: "message",
- name: `Conversation History (${messages().length} messages)`,
- tokens: messageTokens,
- enabled: true,
+ name: `Messages (${messages().length} total)`,
+ tokens: conversationTokens,
})
}
- return items
+ return breakdown
})
const totalTokens = createMemo(() => {
- return contextItems().reduce((sum, item) => sum + (item.enabled ? item.tokens : 0), 0)
+ return contextBreakdown().reduce((sum, item) => sum + item.tokens, 0)
})
- const [filter, setFilter] = createSignal("")
-
- const filteredItems = createMemo(() => {
- const f = filter().toLowerCase()
- if (!f) return contextItems()
- return contextItems().filter((item) => item.name.toLowerCase().includes(f))
+ const context = createMemo(() => {
+ const last = messages().findLast(
+ (x) => x.role === "assistant" && (x as AssistantMessage).tokens?.output > 0
+ ) as AssistantMessage | undefined
+ if (!last) return undefined
+ const model = sync.data.provider.find((x) => x.id === last.providerID)?.models[last.modelID]
+ return {
+ tokens: totalTokens(),
+ percentage: model?.limit.context ? Math.round((totalTokens() / model.limit.context) * 100) : null,
+ }
})
return (
-
+
+
+ Context Preview
+
+ esc
+
+
+
- Context Preview
+ Total Context
- Total: {totalTokens().toLocaleString()} tokens
+ {context()?.tokens.toLocaleString() ?? "0"} tokens
+ {context()?.percentage ? ` (${context()?.percentage}% of limit)` : ""}
-
- Filter:
- {filter() || "(type to filter)"}
-
-
-
-
-
-
-
- {(item) => (
-
-
-
- {item.type === "system"
- ? "[SYS]"
+
+
+ Breakdown
+
+
+ {(item) => (
+
+
+
-
- {item.name}
-
-
-
- {item.tokens.toLocaleString()} tokens
+ ? theme.warning
+ : theme.primary
+ }
+ >
+ •
+ {item.name}
- )}
-
-
-
+ {item.tokens.toLocaleString()}
+
+ )}
+
+
-
-
-
+
- [SYS] System | [INS] Instructions | [FILE] Files | [MSG] Messages
+ This is an estimate of the context sent to the model. Actual token count may vary based on tokenization.
- Press Esc to close
)