fix: context overflow compaction and subagent announce improvements (#11664) (thanks @tyler6204)

* initial commit

* feat: implement deriveSessionTotalTokens function and update usage tests

* Added deriveSessionTotalTokens function to calculate total tokens based on usage and context tokens.
* Updated usage tests to include cases for derived session total tokens.
* Refactored session usage calculations in multiple files to utilize the new function for improved accuracy.

* fix: restore overflow truncation fallback + changelog/test hardening (#11551) (thanks @tyler6204)
This commit is contained in:
Tyler Yust
2026-02-07 20:02:32 -08:00
committed by GitHub
parent 8fae55e8e0
commit 191da1feb5
31 changed files with 889 additions and 178 deletions

View File

@@ -564,27 +564,51 @@
/* Compaction indicator */
.compaction-indicator {
align-self: center;
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 13px;
padding: 10px 12px;
line-height: 1.2;
padding: 6px 14px;
margin-bottom: 8px;
border-radius: 999px;
border: 1px solid var(--border);
background: var(--panel-strong);
color: var(--text);
white-space: nowrap;
user-select: none;
animation: fade-in 0.2s var(--ease-out);
}
.compaction-indicator svg {
width: 16px;
height: 16px;
stroke: currentColor;
fill: none;
stroke-width: 1.5px;
stroke-linecap: round;
stroke-linejoin: round;
flex-shrink: 0;
}
.compaction-indicator--active {
animation: compaction-pulse 1.5s ease-in-out infinite;
color: var(--info);
border-color: rgba(59, 130, 246, 0.35);
}
.compaction-indicator--active svg {
animation: compaction-spin 1s linear infinite;
}
.compaction-indicator--complete {
animation: fade-in 0.2s var(--ease-out);
color: var(--ok);
border-color: rgba(34, 197, 94, 0.35);
}
@keyframes compaction-pulse {
0%,
100% {
opacity: 0.7;
}
50% {
opacity: 1;
@keyframes compaction-spin {
to {
transform: rotate(360deg);
}
}

View File

@@ -49,6 +49,68 @@ function createProps(overrides: Partial<ChatProps> = {}): ChatProps {
}
describe("chat view", () => {
it("renders compacting indicator as a badge", () => {
const container = document.createElement("div");
render(
renderChat(
createProps({
compactionStatus: {
active: true,
startedAt: Date.now(),
completedAt: null,
},
}),
),
container,
);
const indicator = container.querySelector(".compaction-indicator--active");
expect(indicator).not.toBeNull();
expect(indicator?.textContent).toContain("Compacting context...");
});
it("renders completion indicator shortly after compaction", () => {
const container = document.createElement("div");
const nowSpy = vi.spyOn(Date, "now").mockReturnValue(1_000);
render(
renderChat(
createProps({
compactionStatus: {
active: false,
startedAt: 900,
completedAt: 900,
},
}),
),
container,
);
const indicator = container.querySelector(".compaction-indicator--complete");
expect(indicator).not.toBeNull();
expect(indicator?.textContent).toContain("Context compacted");
nowSpy.mockRestore();
});
it("hides stale compaction completion indicator", () => {
const container = document.createElement("div");
const nowSpy = vi.spyOn(Date, "now").mockReturnValue(10_000);
render(
renderChat(
createProps({
compactionStatus: {
active: false,
startedAt: 0,
completedAt: 0,
},
}),
),
container,
);
expect(container.querySelector(".compaction-indicator")).toBeNull();
nowSpy.mockRestore();
});
it("shows a stop button when aborting is available", () => {
const container = document.createElement("div");
const onAbort = vi.fn();

View File

@@ -85,7 +85,7 @@ function renderCompactionIndicator(status: CompactionIndicatorStatus | null | un
// Show "compacting..." while active
if (status.active) {
return html`
<div class="callout info compaction-indicator compaction-indicator--active">
<div class="compaction-indicator compaction-indicator--active" role="status" aria-live="polite">
${icons.loader} Compacting context...
</div>
`;
@@ -96,7 +96,7 @@ function renderCompactionIndicator(status: CompactionIndicatorStatus | null | un
const elapsed = Date.now() - status.completedAt;
if (elapsed < COMPACTION_TOAST_DURATION_MS) {
return html`
<div class="callout success compaction-indicator compaction-indicator--complete">
<div class="compaction-indicator compaction-indicator--complete" role="status" aria-live="polite">
${icons.check} Context compacted
</div>
`;
@@ -268,8 +268,6 @@ export function renderChat(props: ChatProps) {
${props.error ? html`<div class="callout danger">${props.error}</div>` : nothing}
${renderCompactionIndicator(props.compactionStatus)}
${
props.focusMode
? html`
@@ -353,6 +351,8 @@ export function renderChat(props: ChatProps) {
: nothing
}
${renderCompactionIndicator(props.compactionStatus)}
${
props.showNewMessages
? html`