Files
orca/src/shared/native-chat-context-usage.ts
T
Brennan Benson bb44f74d00 Keep native chat /clear in the same conversation (#26579)
* Keep clear in the same chat and reset its provider context

* Derive clear pauses only from journal membership and cover older rewind clients

* Point queued command rewind test at the structured hook

* Group queue consume errors and rewind replay assertions
2026-10-08 16:00:29 -07:00

56 lines
2.1 KiB
TypeScript

// Context usage a chat surface can derive from the transcript alone: the prompt
// the model read on the last request that reported usage, against the window of
// the model that served it.
import { contextTokensFromUsage } from './agent-session-context-usage'
import type { NativeChatMessage } from './native-chat-types'
import { isNativeChatContextClear } from './agent-session-context-clear'
export type NativeChatContextUsage = {
usedTokens: number
/** Null when the serving model's window is not known. */
windowTokens: number | null
/** Rounded and never clamped: an over-limit turn reads above 100. Null with the window. */
percentage: number | null
}
/** Resolves a model's context window, or null when the host does not know it. */
export type NativeChatContextWindowLookup = (message: NativeChatMessage) => number | null
/** True for the transcript row an agent writes when it compacts the conversation. */
export function isNativeChatCompactionBoundary(message: NativeChatMessage): boolean {
return (
message.role === 'system' &&
message.blocks.some((block) => block.type === 'text' && block.presentation === 'compaction')
)
}
/** The newest usage-bearing response decides; a compaction after it means the
* context it measured is gone, so nothing is known until the next response. */
export function deriveNativeChatContextUsage(
messages: readonly NativeChatMessage[],
windowFor: NativeChatContextWindowLookup
): NativeChatContextUsage | null {
for (let index = messages.length - 1; index >= 0; index -= 1) {
const message = messages[index]!
if (isNativeChatCompactionBoundary(message) || isNativeChatContextClear(message)) {
return null
}
if (message.role !== 'assistant' || !message.usage) {
continue
}
const usedTokens = contextTokensFromUsage(message.usage)
if (usedTokens <= 0) {
return null
}
const window = windowFor(message)
const windowTokens = window !== null && window > 0 ? window : null
return {
usedTokens,
windowTokens,
percentage: windowTokens === null ? null : Math.round((usedTokens / windowTokens) * 100)
}
}
return null
}