fix(context): expose history tokens and remove leaked state files
Address remaining review feedback: 1) Add HistoryTokens field to ContextUsage/ContextStats, showing history-only token count in /context and frontend UI alongside SummarizeAtTokens so users can see the actual summarization trigger comparison. 2) Remove .codebuddy/github-contribute/ state files accidentally included in the PR.
This commit is contained in:
parent
b6030f054d
commit
7a7e205cc8
15 changed files with 25 additions and 90 deletions
|
|
@ -1,17 +0,0 @@
|
||||||
# GitHub Contribution Config — sipeed/picoclaw
|
|
||||||
|
|
||||||
- run_mode: resume
|
|
||||||
- credential_source: session_override_env
|
|
||||||
- github_username: chengzhichao-xydt
|
|
||||||
- github_token: [session-provided]
|
|
||||||
- auth_mode: env_pat
|
|
||||||
- pat_type: classic
|
|
||||||
- max_open_prs_per_project: 5
|
|
||||||
- max_prs_waiting_for_first_review: 3
|
|
||||||
- tasks_per_batch: 3
|
|
||||||
- pr_recheck_interval_minutes: 20
|
|
||||||
- report_language: zh-CN
|
|
||||||
- report_timezone: Asia/Shanghai (UTC+8)
|
|
||||||
- default_branch_prefix: codex
|
|
||||||
- default_risk_level: low
|
|
||||||
- github_communication_language: en
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
# Handoff — sipeed/picoclaw
|
|
||||||
|
|
||||||
Last updated: 2026-06-05 09:30 UTC+8
|
|
||||||
Run mode: resume (fix round complete)
|
|
||||||
|
|
||||||
## Quick Resume
|
|
||||||
- Repo: sipeed/picoclaw (fork: chengzhichao-xydt/picoclaw)
|
|
||||||
- Upstream main: 5224b9a4
|
|
||||||
- Open PRs: #3001, #2985 — both pushed with review fixes
|
|
||||||
- Both waiting for afjcjsbx re-review
|
|
||||||
- 7 merged PRs this round
|
|
||||||
- Next: monitor CI/review, scan new candidates if desired
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
# Journal — sipeed/picoclaw
|
|
||||||
|
|
||||||
## 2026-06-05 08:58 UTC+8 — Resume + Fix round
|
|
||||||
|
|
||||||
- run_mode=resume, 2 open PRs identified
|
|
||||||
- Initialized repo-local state directory (.codebuddy/github-contribute)
|
|
||||||
- Cleaned up merged local branches
|
|
||||||
|
|
||||||
## 2026-06-05 09:05 UTC+8 — #3001 fix
|
|
||||||
- Added TestShellTool_SchemelessURLDetection to shell_test.go
|
|
||||||
- Covers all 7 web schemes + multi-URL commands
|
|
||||||
- Test PASS, pushed a6735517, commented on PR
|
|
||||||
|
|
||||||
## 2026-06-05 09:25 UTC+8 — #2985 fix
|
|
||||||
- Issue 1: Added comment explaining summarizeAtTokens vs UsedTokens difference
|
|
||||||
- Issue 2: Replaced hardcoded strings with i18n keys (5 locale files)
|
|
||||||
- Issue 3: Added SummarizeAtTokens field to pico_test.go with assertion
|
|
||||||
- Build PASS, pico test PASS, pushed 296a8ae2, commented on PR
|
|
||||||
|
|
||||||
## 2026-06-05 09:30 UTC+8 — State update
|
|
||||||
- Both PRs now in 'wait' — awaiting afjcjsbx re-review
|
|
||||||
- Ready for next batch of candidate scanning
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
# PR Board — sipeed/picoclaw
|
|
||||||
|
|
||||||
## awaiting_maintainer_review (2)
|
|
||||||
|
|
||||||
### #3001 — fix(tools): allow scheme-less URLs in workspace guard
|
|
||||||
- Branch: codex/workspace-guard-schemeless-url
|
|
||||||
- Fix: Added TestShellTool_SchemelessURLDetection (7 schemes + multi-URL)
|
|
||||||
- Pushed: a6735517 | Comment: https://github.com/sipeed/picoclaw/pull/3001#issuecomment-4627308317
|
|
||||||
- Next: wait for afjcjsbx re-review
|
|
||||||
|
|
||||||
### #2985 — fix(context): show both summarize and compress thresholds in /context
|
|
||||||
- Branch: codex/context-show-summarize-threshold
|
|
||||||
- Fix: ① Threshold alignment comment ② i18n (5 locales) ③ Test coverage for summarize_at_tokens
|
|
||||||
- Pushed: 296a8ae2 | Comment: https://github.com/sipeed/picoclaw/pull/2985#issuecomment-4627346564
|
|
||||||
- Next: wait for afjcjsbx re-review
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
# Active Queue — sipeed/picoclaw
|
|
||||||
|
|
||||||
## Active (0)
|
|
||||||
|
|
||||||
## Waiting for maintainer review (2)
|
|
||||||
|
|
||||||
| ID | PR | Title | Status | Action |
|
|
||||||
|----|-----|-------|--------|--------|
|
|
||||||
| T1 | #3001 | fix(tools): allow scheme-less URLs in workspace guard | ✅ fix pushed (unit tests added) | wait |
|
|
||||||
| T2 | #2985 | fix(context): show both summarize and compress thresholds | ✅ fix pushed (3 review issues) | wait |
|
|
||||||
|
|
||||||
## Merged (7)
|
|
||||||
#3000, #2999, #2996, #2995, #2992, #2991, #2986
|
|
||||||
|
|
||||||
## Blocked (0)
|
|
||||||
None
|
|
||||||
|
|
@ -352,6 +352,7 @@ 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,
|
SummarizeAtTokens: usage.SummarizeAtTokens,
|
||||||
UsedPercent: usage.UsedPercent,
|
UsedPercent: usage.UsedPercent,
|
||||||
|
|
|
||||||
|
|
@ -64,12 +64,9 @@ func computeContextUsage(agent *AgentInstance, sessionKey string) *bus.ContextUs
|
||||||
// summarizeAt = soft summarization trigger: matches maybeSummarize's
|
// summarizeAt = soft summarization trigger: matches maybeSummarize's
|
||||||
// threshold (contextWindow * SummarizeTokenPercent / 100).
|
// threshold (contextWindow * SummarizeTokenPercent / 100).
|
||||||
//
|
//
|
||||||
// NOTE: The engine's maybeSummarize compares this threshold against
|
// The engine compares this against history-message tokens ONLY (not
|
||||||
// history-message tokens only (via estimateTokens), while UsedTokens
|
// UsedTokens). HistoryTokens is exposed alongside UsedTokens so the
|
||||||
// (shown in /context) includes system prompt, summary, and tool
|
// UI can show both values and avoid user confusion.
|
||||||
// definitions on top of history tokens. A "Used > SummarizeAt" display
|
|
||||||
// does not necessarily mean summarization will fire — the engine may
|
|
||||||
// still consider the history-token budget to be under threshold.
|
|
||||||
summarizeAt := contextWindow * agent.SummarizeTokenPercent / 100
|
summarizeAt := contextWindow * agent.SummarizeTokenPercent / 100
|
||||||
if summarizeAt <= 0 {
|
if summarizeAt <= 0 {
|
||||||
summarizeAt = compressAt
|
summarizeAt = compressAt
|
||||||
|
|
@ -86,6 +83,7 @@ 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,
|
SummarizeAtTokens: summarizeAt,
|
||||||
UsedPercent: usedPercent,
|
UsedPercent: usedPercent,
|
||||||
|
|
|
||||||
|
|
@ -66,8 +66,9 @@ 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
|
||||||
|
HistoryTokens int `json:"history_tokens"` // history-message tokens only (what maybeSummarize checks)
|
||||||
CompressAtTokens int `json:"compress_at_tokens"` // hard budget compression threshold (contextWindow - maxTokens)
|
CompressAtTokens int `json:"compress_at_tokens"` // hard budget compression threshold (contextWindow - maxTokens)
|
||||||
SummarizeAtTokens int `json:"summarize_at_tokens"` // soft summarization trigger (contextWindow * summarizeTokenPercent / 100)
|
SummarizeAtTokens int `json:"summarize_at_tokens"` // soft summarization trigger (vs history tokens)
|
||||||
UsedPercent int `json:"used_percent"` // 0-100, relative to compressAt
|
UsedPercent int `json:"used_percent"` // 0-100, relative to compressAt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1396,6 +1396,7 @@ 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,
|
"summarize_at_tokens": u.SummarizeAtTokens,
|
||||||
"used_percent": u.UsedPercent,
|
"used_percent": u.UsedPercent,
|
||||||
|
|
|
||||||
|
|
@ -604,6 +604,7 @@ 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,
|
SummarizeAtTokens: 60,
|
||||||
UsedPercent: 10,
|
UsedPercent: 10,
|
||||||
|
|
@ -628,6 +629,9 @@ 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) {
|
if got := rawUsage["summarize_at_tokens"]; got != float64(60) {
|
||||||
t.Fatalf("summarize_at_tokens = %#v, want 60", got)
|
t.Fatalf("summarize_at_tokens = %#v, want 60", got)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,11 +30,12 @@ func formatContextStats(s *ContextStats) string {
|
||||||
}
|
}
|
||||||
usedWindowPercent := s.UsedTokens * 100 / max(s.TotalTokens, 1)
|
usedWindowPercent := s.UsedTokens * 100 / max(s.TotalTokens, 1)
|
||||||
msg := fmt.Sprintf(
|
msg := fmt.Sprintf(
|
||||||
"Context usage \nMessages: %d \nUsed: ~%d / %d tokens (%d%%) \nCompress at: %d tokens \nSummarize 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.SummarizeAtTokens,
|
||||||
s.UsedPercent,
|
s.UsedPercent,
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ type MCPToolInfo struct {
|
||||||
type ContextStats struct {
|
type ContextStats struct {
|
||||||
UsedTokens int
|
UsedTokens int
|
||||||
TotalTokens int // model context window
|
TotalTokens int // model context window
|
||||||
|
HistoryTokens int // history-only tokens (what maybeSummarize checks)
|
||||||
CompressAtTokens int // hard budget compression threshold
|
CompressAtTokens int // hard budget compression threshold
|
||||||
SummarizeAtTokens int // soft summarization trigger
|
SummarizeAtTokens int // soft summarization trigger
|
||||||
UsedPercent int // 0-100
|
UsedPercent int // 0-100
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,14 @@ export function ContextUsageRing({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mt-2 space-y-0.5">
|
<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]">
|
<div className="flex items-center justify-between text-[10px]">
|
||||||
<span className="text-muted-foreground">{t("chat.contextCompressAt")}</span>
|
<span className="text-muted-foreground">{t("chat.contextCompressAt")}</span>
|
||||||
<span className="tabular-nums">
|
<span className="tabular-nums">
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,7 @@ 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,
|
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,
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ 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
|
summarize_at_tokens?: number
|
||||||
used_percent: number
|
used_percent: number
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue