Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions src/four-opencode-token-budget-guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,22 @@ export const FourTokenBudgetGuardPlugin: Plugin = async (_ctx) => {
if (!part || part.type !== "text" || typeof part.text !== "string") return;

const sessionID = props.sessionID ?? "unknown";
currentSessionID = sessionID;
// Only switch if new session is genuinely new (no tokens yet)
if (sessionID !== currentSessionID) {
const existingTokens = sessionTokens.get(sessionID);
if (existingTokens === 0) {
// New session — start fresh
currentSessionID = sessionID;
}
// else: keep tracking old session (compaction created new ID but tokens belong to old)
}
const tokensApprox = estimateTokens(part.text);
const cumulative = sessionTokens.add(sessionID, tokensApprox);
const msgRole = "text-part";

// Publish to plugin bus (P4d) — fire-and-forget on every token update
busPublisher.publish(currentSessionID, tokensApprox, sessionTokens, config).catch(() => {});
// Use the EVENT's sessionID, not currentSessionID (avoids drift when event has new ID)
busPublisher.publish(sessionID, tokensApprox, sessionTokens, config).catch(() => {});

if (cumulative >= config.softLimit) {
const isHard = cumulative >= config.hardLimit;
Expand Down
8 changes: 2 additions & 6 deletions src/session-cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,14 @@ export class SessionTokenCache {
get(sessionID: string): number {
const entry = this.map.get(sessionID);
if (!entry) return 0;
if (Date.now() - entry.lastAccess > this.ttlMs) {
this.map.delete(sessionID);
return 0;
}
entry.lastAccess = Date.now();
// Don't update lastAccess here — get() is read-only
return entry.tokens;
}

add(sessionID: string, delta: number): number {
this.evictStale();
// Read own state BEFORE LRU eviction so we don't self-evict
const prev = this.get(sessionID); // touches lastAccess via get()
const prev = this.get(sessionID); // touches lastAccess (get is read-only)
// If we just added a new session, may need to evict
this.evictOldestIfFull();
const next = prev + delta;
Expand Down
1 change: 0 additions & 1 deletion src/tui.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ function TokenMeterView() {
<TokenMeter
tokens={tokens()}
softLimit={limit()}
colors={{ green: "#4caf50", orange: "#ff9800", red: "#f44336" }}
/>
)}
</box>
Expand Down
Loading