Merge pull request #2985 from chengzhichao-xydt/codex/context-show-summarize-threshold
fix(context): show both summarize and compress thresholds in /context
This commit is contained in:
commit
b10f9cdf18
15 changed files with 99 additions and 28 deletions
|
|
@ -352,7 +352,9 @@ func (al *AgentLoop) buildCommandsRuntime(
|
||||||
return &commands.ContextStats{
|
return &commands.ContextStats{
|
||||||
UsedTokens: usage.UsedTokens,
|
UsedTokens: usage.UsedTokens,
|
||||||
TotalTokens: usage.TotalTokens,
|
TotalTokens: usage.TotalTokens,
|
||||||
|
HistoryTokens: usage.HistoryTokens,
|
||||||
CompressAtTokens: usage.CompressAtTokens,
|
CompressAtTokens: usage.CompressAtTokens,
|
||||||
|
SummarizeAtTokens: usage.SummarizeAtTokens,
|
||||||
UsedPercent: usage.UsedPercent,
|
UsedPercent: usage.UsedPercent,
|
||||||
MessageCount: len(history),
|
MessageCount: len(history),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,17 @@ func computeContextUsage(agent *AgentInstance, sessionKey string) *bus.ContextUs
|
||||||
// proactive trigger (msgTokens + toolTokens + maxTokens > contextWindow).
|
// proactive trigger (msgTokens + toolTokens + maxTokens > contextWindow).
|
||||||
compressAt := effectiveWindow
|
compressAt := effectiveWindow
|
||||||
|
|
||||||
|
// summarizeAt = soft summarization trigger: matches maybeSummarize's
|
||||||
|
// threshold (contextWindow * SummarizeTokenPercent / 100).
|
||||||
|
//
|
||||||
|
// The engine compares this against history-message tokens ONLY (not
|
||||||
|
// UsedTokens). HistoryTokens is exposed alongside UsedTokens so the
|
||||||
|
// UI can show both values and avoid user confusion.
|
||||||
|
summarizeAt := contextWindow * agent.SummarizeTokenPercent / 100
|
||||||
|
if summarizeAt <= 0 {
|
||||||
|
summarizeAt = compressAt
|
||||||
|
}
|
||||||
|
|
||||||
usedPercent := 0
|
usedPercent := 0
|
||||||
if compressAt > 0 {
|
if compressAt > 0 {
|
||||||
usedPercent = usedTokens * 100 / compressAt
|
usedPercent = usedTokens * 100 / compressAt
|
||||||
|
|
@ -72,7 +83,9 @@ func computeContextUsage(agent *AgentInstance, sessionKey string) *bus.ContextUs
|
||||||
return &bus.ContextUsage{
|
return &bus.ContextUsage{
|
||||||
UsedTokens: usedTokens,
|
UsedTokens: usedTokens,
|
||||||
TotalTokens: contextWindow,
|
TotalTokens: contextWindow,
|
||||||
|
HistoryTokens: historyTokens,
|
||||||
CompressAtTokens: compressAt,
|
CompressAtTokens: compressAt,
|
||||||
|
SummarizeAtTokens: summarizeAt,
|
||||||
UsedPercent: usedPercent,
|
UsedPercent: usedPercent,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,8 +66,10 @@ type OutboundScope struct {
|
||||||
type ContextUsage struct {
|
type ContextUsage struct {
|
||||||
UsedTokens int `json:"used_tokens"`
|
UsedTokens int `json:"used_tokens"`
|
||||||
TotalTokens int `json:"total_tokens"` // model context window
|
TotalTokens int `json:"total_tokens"` // model context window
|
||||||
CompressAtTokens int `json:"compress_at_tokens"` // threshold that triggers compression
|
HistoryTokens int `json:"history_tokens"` // history-message tokens only (what maybeSummarize checks)
|
||||||
UsedPercent int `json:"used_percent"` // 0-100
|
CompressAtTokens int `json:"compress_at_tokens"` // hard budget compression threshold (contextWindow - maxTokens)
|
||||||
|
SummarizeAtTokens int `json:"summarize_at_tokens"` // soft summarization trigger (vs history tokens)
|
||||||
|
UsedPercent int `json:"used_percent"` // 0-100, relative to compressAt
|
||||||
}
|
}
|
||||||
|
|
||||||
type OutboundMessage struct {
|
type OutboundMessage struct {
|
||||||
|
|
|
||||||
|
|
@ -1396,7 +1396,9 @@ func setContextUsagePayload(payload map[string]any, u *bus.ContextUsage) {
|
||||||
payload["context_usage"] = map[string]any{
|
payload["context_usage"] = map[string]any{
|
||||||
"used_tokens": u.UsedTokens,
|
"used_tokens": u.UsedTokens,
|
||||||
"total_tokens": u.TotalTokens,
|
"total_tokens": u.TotalTokens,
|
||||||
|
"history_tokens": u.HistoryTokens,
|
||||||
"compress_at_tokens": u.CompressAtTokens,
|
"compress_at_tokens": u.CompressAtTokens,
|
||||||
|
"summarize_at_tokens": u.SummarizeAtTokens,
|
||||||
"used_percent": u.UsedPercent,
|
"used_percent": u.UsedPercent,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -604,7 +604,9 @@ func TestBeginStream_FinalizeIncludesContextUsage(t *testing.T) {
|
||||||
if err := contextStreamer.FinalizeWithContext(context.Background(), "final", &bus.ContextUsage{
|
if err := contextStreamer.FinalizeWithContext(context.Background(), "final", &bus.ContextUsage{
|
||||||
UsedTokens: 10,
|
UsedTokens: 10,
|
||||||
TotalTokens: 100,
|
TotalTokens: 100,
|
||||||
|
HistoryTokens: 5,
|
||||||
CompressAtTokens: 80,
|
CompressAtTokens: 80,
|
||||||
|
SummarizeAtTokens: 60,
|
||||||
UsedPercent: 10,
|
UsedPercent: 10,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
t.Fatalf("FinalizeWithContext() error = %v", err)
|
t.Fatalf("FinalizeWithContext() error = %v", err)
|
||||||
|
|
@ -627,6 +629,12 @@ func TestBeginStream_FinalizeIncludesContextUsage(t *testing.T) {
|
||||||
if got := rawUsage["used_tokens"]; got != float64(10) {
|
if got := rawUsage["used_tokens"]; got != float64(10) {
|
||||||
t.Fatalf("used_tokens = %#v, want 10", got)
|
t.Fatalf("used_tokens = %#v, want 10", got)
|
||||||
}
|
}
|
||||||
|
if got := rawUsage["history_tokens"]; got != float64(5) {
|
||||||
|
t.Fatalf("history_tokens = %#v, want 5", got)
|
||||||
|
}
|
||||||
|
if got := rawUsage["summarize_at_tokens"]; got != float64(60) {
|
||||||
|
t.Fatalf("summarize_at_tokens = %#v, want 60", got)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateAndAddConnection_RespectsMaxConnectionsConcurrently(t *testing.T) {
|
func TestCreateAndAddConnection_RespectsMaxConnectionsConcurrently(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -29,14 +29,17 @@ func formatContextStats(s *ContextStats) string {
|
||||||
remaining = 0
|
remaining = 0
|
||||||
}
|
}
|
||||||
usedWindowPercent := s.UsedTokens * 100 / max(s.TotalTokens, 1)
|
usedWindowPercent := s.UsedTokens * 100 / max(s.TotalTokens, 1)
|
||||||
return fmt.Sprintf(
|
msg := fmt.Sprintf(
|
||||||
"Context usage \nMessages: %d \nUsed: ~%d / %d tokens (%d%%) \nCompress at: %d tokens \nCompression progress: %d%% \nRemaining: ~%d tokens",
|
"Context usage \nMessages: %d \nUsed: ~%d / %d tokens (%d%%) \nHistory: ~%d tokens \nCompress at: %d tokens \nSummarize at: %d tokens \nCompression progress: %d%% \nRemaining: ~%d tokens",
|
||||||
s.MessageCount,
|
s.MessageCount,
|
||||||
s.UsedTokens,
|
s.UsedTokens,
|
||||||
s.TotalTokens,
|
s.TotalTokens,
|
||||||
usedWindowPercent,
|
usedWindowPercent,
|
||||||
|
s.HistoryTokens,
|
||||||
s.CompressAtTokens,
|
s.CompressAtTokens,
|
||||||
|
s.SummarizeAtTokens,
|
||||||
s.UsedPercent,
|
s.UsedPercent,
|
||||||
remaining,
|
remaining,
|
||||||
)
|
)
|
||||||
|
return msg
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,9 @@ type MCPToolInfo struct {
|
||||||
type ContextStats struct {
|
type ContextStats struct {
|
||||||
UsedTokens int
|
UsedTokens int
|
||||||
TotalTokens int // model context window
|
TotalTokens int // model context window
|
||||||
CompressAtTokens int // compression threshold
|
HistoryTokens int // history-only tokens (what maybeSummarize checks)
|
||||||
|
CompressAtTokens int // hard budget compression threshold
|
||||||
|
SummarizeAtTokens int // soft summarization trigger
|
||||||
UsedPercent int // 0-100
|
UsedPercent int // 0-100
|
||||||
MessageCount int
|
MessageCount int
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -145,6 +145,31 @@ export function ContextUsageRing({
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-2 space-y-0.5">
|
||||||
|
{usage.history_tokens != null && usage.history_tokens > 0 && (
|
||||||
|
<div className="flex items-center justify-between text-[10px]">
|
||||||
|
<span className="text-muted-foreground">History</span>
|
||||||
|
<span className="tabular-nums">
|
||||||
|
{formatTokens(usage.history_tokens)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="flex items-center justify-between text-[10px]">
|
||||||
|
<span className="text-muted-foreground">{t("chat.contextCompressAt")}</span>
|
||||||
|
<span className="tabular-nums">
|
||||||
|
{formatTokens(usage.compress_at_tokens)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{usage.summarize_at_tokens != null && usage.summarize_at_tokens > 0 && (
|
||||||
|
<div className="flex items-center justify-between text-[10px]">
|
||||||
|
<span className="text-muted-foreground">{t("chat.contextSummarizeAt")}</span>
|
||||||
|
<span className="tabular-nums">
|
||||||
|
{formatTokens(usage.summarize_at_tokens)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={handleDetail}
|
onClick={handleDetail}
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,9 @@ function parseContextUsage(
|
||||||
return {
|
return {
|
||||||
used_tokens: used,
|
used_tokens: used,
|
||||||
total_tokens: total,
|
total_tokens: total,
|
||||||
|
history_tokens: obj.history_tokens != null ? Number(obj.history_tokens) : undefined,
|
||||||
compress_at_tokens: Number(obj.compress_at_tokens) || 0,
|
compress_at_tokens: Number(obj.compress_at_tokens) || 0,
|
||||||
|
summarize_at_tokens: obj.summarize_at_tokens != null ? Number(obj.summarize_at_tokens) : undefined,
|
||||||
used_percent: Number(obj.used_percent) || 0,
|
used_percent: Number(obj.used_percent) || 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,8 @@
|
||||||
"sendHint": "পাঠাতে Enter চাপুন\nনতুন লাইনের জন্য Shift + Enter",
|
"sendHint": "পাঠাতে Enter চাপুন\nনতুন লাইনের জন্য Shift + Enter",
|
||||||
"contextTitle": "প্রসঙ্গ",
|
"contextTitle": "প্রসঙ্গ",
|
||||||
"contextDetail": "বিস্তারিত দেখুন",
|
"contextDetail": "বিস্তারিত দেখুন",
|
||||||
|
"contextCompressAt": "Compress at",
|
||||||
|
"contextSummarizeAt": "Summarize at",
|
||||||
"attachImage": "ছবি যোগ করুন",
|
"attachImage": "ছবি যোগ করুন",
|
||||||
"removeImage": "ছবি সরান",
|
"removeImage": "ছবি সরান",
|
||||||
"uploadedImage": "আপলোড করা ছবি",
|
"uploadedImage": "আপলোড করা ছবি",
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,8 @@
|
||||||
"sendHint": "Enter pro odeslání\nShift + Enter pro nový řádek",
|
"sendHint": "Enter pro odeslání\nShift + Enter pro nový řádek",
|
||||||
"contextTitle": "Kontext",
|
"contextTitle": "Kontext",
|
||||||
"contextDetail": "Zobrazit detail",
|
"contextDetail": "Zobrazit detail",
|
||||||
|
"contextCompressAt": "Komprimovat při",
|
||||||
|
"contextSummarizeAt": "Shrnout při",
|
||||||
"attachImage": "Přidat obrázky",
|
"attachImage": "Přidat obrázky",
|
||||||
"dropImagesActive": "Uvolněním přidáte obrázky",
|
"dropImagesActive": "Uvolněním přidáte obrázky",
|
||||||
"removeImage": "Odebrat obrázek",
|
"removeImage": "Odebrat obrázek",
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,8 @@
|
||||||
"sendHint": "Press Enter to send\nShift + Enter for a new line",
|
"sendHint": "Press Enter to send\nShift + Enter for a new line",
|
||||||
"contextTitle": "Context",
|
"contextTitle": "Context",
|
||||||
"contextDetail": "View Details",
|
"contextDetail": "View Details",
|
||||||
|
"contextCompressAt": "Compress at",
|
||||||
|
"contextSummarizeAt": "Summarize at",
|
||||||
"attachImage": "Add images",
|
"attachImage": "Add images",
|
||||||
"dropImagesActive": "Release to add images",
|
"dropImagesActive": "Release to add images",
|
||||||
"removeImage": "Remove image",
|
"removeImage": "Remove image",
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,8 @@
|
||||||
"sendHint": "Pressione Enter para enviar\nShift + Enter para nova linha",
|
"sendHint": "Pressione Enter para enviar\nShift + Enter para nova linha",
|
||||||
"contextTitle": "Contexto",
|
"contextTitle": "Contexto",
|
||||||
"contextDetail": "Ver Detalhes",
|
"contextDetail": "Ver Detalhes",
|
||||||
|
"contextCompressAt": "Comprimir em",
|
||||||
|
"contextSummarizeAt": "Resumir em",
|
||||||
"attachImage": "Adicionar imagens",
|
"attachImage": "Adicionar imagens",
|
||||||
"dropImagesActive": "Solte para adicionar imagens",
|
"dropImagesActive": "Solte para adicionar imagens",
|
||||||
"removeImage": "Remover imagem",
|
"removeImage": "Remover imagem",
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,8 @@
|
||||||
"sendHint": "按 Enter 发送\nShift + Enter 换行",
|
"sendHint": "按 Enter 发送\nShift + Enter 换行",
|
||||||
"contextTitle": "上下文",
|
"contextTitle": "上下文",
|
||||||
"contextDetail": "查看详情",
|
"contextDetail": "查看详情",
|
||||||
|
"contextCompressAt": "压缩阈值",
|
||||||
|
"contextSummarizeAt": "摘要阈值",
|
||||||
"attachImage": "添加图片",
|
"attachImage": "添加图片",
|
||||||
"dropImagesActive": "松开以添加图片",
|
"dropImagesActive": "松开以添加图片",
|
||||||
"removeImage": "移除图片",
|
"removeImage": "移除图片",
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,9 @@ export interface ChatMessage {
|
||||||
export interface ContextUsage {
|
export interface ContextUsage {
|
||||||
used_tokens: number
|
used_tokens: number
|
||||||
total_tokens: number
|
total_tokens: number
|
||||||
|
history_tokens?: number
|
||||||
compress_at_tokens: number
|
compress_at_tokens: number
|
||||||
|
summarize_at_tokens?: number
|
||||||
used_percent: number
|
used_percent: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue