mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 17:30:31 +00:00
Show context compaction as a work item
This commit is contained in:
parent
49c7fc94fd
commit
1430990309
7 changed files with 73 additions and 7 deletions
|
|
@ -167,6 +167,7 @@ function turnActivitySummary(items: readonly DisplayItem[]): string {
|
|||
countMatchingLabel(items, (item) => item.kind === "tool" && !isSteeringActivityDisplayItem(item), "tool"),
|
||||
countLabel(items, "hook", "hook"),
|
||||
countLabel(items, "reasoning", "thought", "thought notes"),
|
||||
countLabel(items, "contextCompaction", "context compaction"),
|
||||
countLabel(items, "approvalResult", "approval"),
|
||||
countLabel(items, "userInputResult", "input"),
|
||||
countLabel(items, "reviewResult", "review"),
|
||||
|
|
|
|||
|
|
@ -393,10 +393,9 @@ function reviewModeDisplayItem(item: ReviewModeItem, turnId?: string): DisplayIt
|
|||
function contextCompactionDisplayItem(item: ContextCompactionItem, turnId?: string): DisplayItem {
|
||||
return {
|
||||
id: item.id,
|
||||
kind: "tool",
|
||||
kind: "contextCompaction",
|
||||
role: "tool",
|
||||
text: "Context compaction",
|
||||
toolLabel: "contextCompaction",
|
||||
...definedProp("turnId", turnId),
|
||||
itemId: item.id,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ export type DisplayKind =
|
|||
| "agent"
|
||||
| "hook"
|
||||
| "reasoning"
|
||||
| "contextCompaction"
|
||||
| "system"
|
||||
| "goal"
|
||||
| "approvalResult"
|
||||
|
|
@ -162,6 +163,11 @@ export interface ReasoningDisplayItem extends ToolDisplayBase {
|
|||
kind: "reasoning";
|
||||
}
|
||||
|
||||
export interface ContextCompactionDisplayItem extends DisplayBase {
|
||||
kind: "contextCompaction";
|
||||
role: "tool";
|
||||
}
|
||||
|
||||
export interface TaskProgressStep {
|
||||
step: string;
|
||||
status: "pending" | "inProgress" | "completed";
|
||||
|
|
@ -218,6 +224,7 @@ export type DisplayItem =
|
|||
| ToolCallDisplayItem
|
||||
| HookDisplayItem
|
||||
| ReasoningDisplayItem
|
||||
| ContextCompactionDisplayItem
|
||||
| TaskProgressDisplayItem
|
||||
| AgentDisplayItem
|
||||
| ApprovalResultDisplayItem
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ function isRenderableToolResultItem(item: DisplayItem): item is ToolResultDispla
|
|||
}
|
||||
|
||||
function isRenderableWorkItem(item: DisplayItem): item is WorkItemDisplayItem {
|
||||
return item.kind === "taskProgress" || item.kind === "agent" || item.kind === "reasoning";
|
||||
return item.kind === "taskProgress" || item.kind === "agent" || item.kind === "reasoning" || item.kind === "contextCompaction";
|
||||
}
|
||||
|
||||
function displayItemNode(item: DisplayItem, context: MessageStreamContext): UiNode {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import type {
|
|||
AgentDisplayItem,
|
||||
AgentRunSummary,
|
||||
AgentRunSummaryAgent,
|
||||
ContextCompactionDisplayItem,
|
||||
DisplayItem,
|
||||
ReasoningDisplayItem,
|
||||
TaskProgressDisplayItem,
|
||||
|
|
@ -19,7 +20,7 @@ import { shortThreadId, truncate } from "../../../utils";
|
|||
const AGENT_ROW_MESSAGE_PREVIEW_LIMIT = 120;
|
||||
const AGENT_ACTIVITY_PROMPT_PREVIEW_LIMIT = 96;
|
||||
|
||||
export type WorkItemDisplayItem = TaskProgressDisplayItem | AgentDisplayItem | ReasoningDisplayItem;
|
||||
export type WorkItemDisplayItem = TaskProgressDisplayItem | AgentDisplayItem | ReasoningDisplayItem | ContextCompactionDisplayItem;
|
||||
|
||||
export interface WorkItemContext {
|
||||
turnLifecycle: ChatTurnLifecycleState;
|
||||
|
|
@ -43,6 +44,7 @@ export function agentRunSummaryNode(summary: AgentRunSummary): UiNode {
|
|||
export function workItemNode(item: WorkItemDisplayItem, context: WorkItemContext): UiNode {
|
||||
if (item.kind === "taskProgress") return <TaskProgressItem item={item} />;
|
||||
if (item.kind === "agent") return <AgentItem item={item} context={context} />;
|
||||
if (item.kind === "contextCompaction") return <ContextCompactionItem item={item} context={context} />;
|
||||
return <ReasoningItem item={item} context={context} />;
|
||||
}
|
||||
|
||||
|
|
@ -75,6 +77,15 @@ function TaskProgressItem({ item }: { item: TaskProgressDisplayItem }): UiNode {
|
|||
);
|
||||
}
|
||||
|
||||
function ContextCompactionItem({ item, context }: { item: ContextCompactionDisplayItem; context: WorkItemContext }): UiNode {
|
||||
const active = workItemsActiveTurnId(context) === item.turnId;
|
||||
return (
|
||||
<WorkMessage label="context" className="codex-panel__context-compaction" state={active ? "running" : "completed"}>
|
||||
<div className="codex-panel__tool-summary">{active ? "Compacting context..." : "Context compacted"}</div>
|
||||
</WorkMessage>
|
||||
);
|
||||
}
|
||||
|
||||
function AgentItem({ item, context }: { item: AgentDisplayItem; context: WorkItemContext }): UiNode {
|
||||
const detailsKey = `${item.id}:agent-details`;
|
||||
const [detailsOpen, setDetailsOpen] = useState(context.openDetails.has(detailsKey));
|
||||
|
|
|
|||
|
|
@ -813,13 +813,12 @@ describe("thread item conversion preserves app-server semantics", () => {
|
|||
});
|
||||
});
|
||||
|
||||
it("preserves context compaction items as short tool items", () => {
|
||||
it("preserves context compaction items as short work items", () => {
|
||||
const item: ThreadItem = { type: "contextCompaction", id: "compact-1" };
|
||||
|
||||
expect(displayItemFromThreadItem(item, "t1")).toMatchObject({
|
||||
kind: "tool",
|
||||
kind: "contextCompaction",
|
||||
text: "Context compaction",
|
||||
toolLabel: "contextCompaction",
|
||||
turnId: "t1",
|
||||
itemId: "compact-1",
|
||||
});
|
||||
|
|
|
|||
|
|
@ -961,6 +961,55 @@ describe("work log renderer decisions", () => {
|
|||
unmountUiRootInAct(parent);
|
||||
});
|
||||
|
||||
it("renders context compaction as a one-line work item while running and after completion", () => {
|
||||
const runningParent = document.createElement("div");
|
||||
const item: DisplayItem = { id: "compact-1", kind: "contextCompaction", role: "tool", text: "Context compaction", turnId: "turn" };
|
||||
|
||||
renderMessageStreamBlocksInAct(
|
||||
runningParent,
|
||||
messageStreamBlocks({
|
||||
activeThreadId: "thread",
|
||||
turnLifecycle: runningTurnLifecycle("turn"),
|
||||
historyCursor: null,
|
||||
loadingHistory: false,
|
||||
displayItems: [item],
|
||||
openDetails: new Set(),
|
||||
loadOlderTurns: vi.fn(),
|
||||
renderMarkdown: (element, text) => element.createDiv({ text }),
|
||||
}),
|
||||
);
|
||||
|
||||
const running = expectPresent(
|
||||
runningParent.querySelector<HTMLElement>('[data-codex-panel-block-key="item:compact-1"] .codex-panel__context-compaction'),
|
||||
);
|
||||
expect(running.querySelector(".codex-panel__message-role")?.textContent).toBe("context");
|
||||
expect(running.querySelector(".codex-panel__tool-summary")?.textContent).toBe("Compacting context...");
|
||||
expect(running.classList.contains("codex-panel__execution--running")).toBe(true);
|
||||
unmountUiRootInAct(runningParent);
|
||||
|
||||
const completedParent = document.createElement("div");
|
||||
renderMessageStreamBlocksInAct(
|
||||
completedParent,
|
||||
messageStreamBlocks({
|
||||
activeThreadId: "thread",
|
||||
turnLifecycle: idleTurnLifecycle(),
|
||||
historyCursor: null,
|
||||
loadingHistory: false,
|
||||
displayItems: [item],
|
||||
openDetails: new Set(),
|
||||
loadOlderTurns: vi.fn(),
|
||||
renderMarkdown: (element, text) => element.createDiv({ text }),
|
||||
}),
|
||||
);
|
||||
|
||||
const completed = expectPresent(
|
||||
completedParent.querySelector<HTMLElement>('[data-codex-panel-block-key="item:compact-1"] .codex-panel__context-compaction'),
|
||||
);
|
||||
expect(completed.querySelector(".codex-panel__tool-summary")?.textContent).toBe("Context compacted");
|
||||
expect(completed.classList.contains("codex-panel__execution--completed")).toBe(true);
|
||||
unmountUiRootInAct(completedParent);
|
||||
});
|
||||
|
||||
it("hides the live agent summary once all subagents are complete", () => {
|
||||
const blocks = messageStreamBlocks({
|
||||
activeThreadId: "thread",
|
||||
|
|
|
|||
Loading…
Reference in a new issue