Skip to content

Commit 6f37045

Browse files
committed
fix(coding-agent): seed handoff scope frames with the return chat
1 parent 164acec commit 6f37045

2 files changed

Lines changed: 62 additions & 12 deletions

File tree

‎packages/coding-agent/src/modes/agents-view/agents-view-mode.ts‎

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,37 @@ export function getAgentsViewDepth(scopeRoot: SessionSummary | undefined): numbe
245245
return scopeRoot ? (scopeRoot.rlmDepth ?? 0) + 1 : 0;
246246
}
247247

248+
export function createInitialAgentsViewScopeFrames(
249+
initialScopeKey: AgentsViewScopeKey | undefined,
250+
returnChat: SessionSummary | undefined,
251+
): AgentsViewScopeFrame[] {
252+
if (!initialScopeKey) return [];
253+
return [
254+
{
255+
scope: initialScopeKey,
256+
...(returnChat?.sessionId === initialScopeKey.sessionId ? { returnChat } : {}),
257+
},
258+
];
259+
}
260+
261+
export function createInitialAgentsViewPersistentState(
262+
options: Pick<AgentsViewModeOptions, "initialScopeKey" | "initialSession">,
263+
): AgentsViewPersistentState {
264+
const initialSession = options.initialSession;
265+
return {
266+
...(initialSession
267+
? {
268+
selectedRowIdentity: getSummaryIdentity(initialSession),
269+
selectedSessionKey: getAgentsViewSelectionKey(initialSession),
270+
backSession: initialSession,
271+
}
272+
: {}),
273+
...(options.initialScopeKey
274+
? { scopeFrames: createInitialAgentsViewScopeFrames(options.initialScopeKey, initialSession) }
275+
: {}),
276+
};
277+
}
278+
248279
export function createScopeBackReturnChatOpenResult(
249280
result: Extract<AgentsViewRunResult, { type: "scope_back" }>,
250281
): Extract<AgentsViewRunResult, { type: "open" }> | undefined {
@@ -369,17 +400,7 @@ function isUnknownActiveSessionError(error: unknown): boolean {
369400
}
370401

371402
export async function runAgentsViewMode(options: AgentsViewModeOptions): Promise<void> {
372-
const initialSession = options.initialSession;
373-
const persistentState: AgentsViewPersistentState = {
374-
...(initialSession
375-
? {
376-
selectedRowIdentity: getSummaryIdentity(initialSession),
377-
selectedSessionKey: getAgentsViewSelectionKey(initialSession),
378-
backSession: initialSession,
379-
}
380-
: {}),
381-
...(options.initialScopeKey ? { scopeFrames: [{ scope: options.initialScopeKey }] } : {}),
382-
};
403+
const persistentState = createInitialAgentsViewPersistentState(options);
383404
const promptStashStore = options.promptStashStore ?? new ClientPromptStashStore();
384405

385406
while (true) {
@@ -637,7 +658,11 @@ export class AgentsViewMode implements Component, Focusable {
637658
private readonly persistentState: AgentsViewPersistentState = {},
638659
) {
639660
const initialFrames =
640-
persistentState.scopeFrames ?? (options.initialScopeKey ? [{ scope: options.initialScopeKey }] : []);
661+
persistentState.scopeFrames ??
662+
createInitialAgentsViewScopeFrames(
663+
options.initialScopeKey,
664+
persistentState.backSession ?? options.initialSession,
665+
);
641666
persistentState.scopeFrames = initialFrames;
642667
this.scopeKey = initialFrames.at(-1)?.scope;
643668
this.selectedRowIdentity = persistentState.selectedRowIdentity;

‎packages/coding-agent/test/agents-view-state.test.ts‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import {
1010
createAgentsViewListCommand,
1111
createAgentsViewReplyHeadline,
1212
createAgentsViewResumeConfig,
13+
createInitialAgentsViewPersistentState,
14+
createInitialAgentsViewScopeFrames,
1315
createScopeBackReturnChatOpenResult,
1416
formatAgentsViewRelativeTime,
1517
formatAgentsViewStatusLine,
@@ -1154,6 +1156,29 @@ describe("agents view state", () => {
11541156
const rootScope = { sessionId: "root-session", activeSessionId: "root-active" };
11551157
const childScope = { sessionId: "child-session", activeSessionId: "child-active" };
11561158

1159+
test("seeds handoff scope frames with the matching return chat", () => {
1160+
const chat = makeSummary({ sessionId: "root-session", activeSessionId: "root-active" });
1161+
const persistentState = createInitialAgentsViewPersistentState({
1162+
initialScopeKey: rootScope,
1163+
initialSession: chat,
1164+
});
1165+
const handoffFrame = persistentState.scopeFrames?.at(-1);
1166+
1167+
expect(handoffFrame).toEqual({ scope: rootScope, returnChat: chat });
1168+
expect(createInitialAgentsViewScopeFrames(rootScope, persistentState.backSession)).toEqual([handoffFrame]);
1169+
expect(createInitialAgentsViewScopeFrames(rootScope, makeSummary({ sessionId: "stale-session" }))).toEqual([
1170+
{ scope: rootScope },
1171+
]);
1172+
1173+
const leftResult = resolveAgentsViewLeftResult(chat, [], handoffFrame?.returnChat);
1174+
expect(leftResult?.type).toBe("scope_back");
1175+
if (leftResult?.type !== "scope_back") throw new Error("Expected scoped Left navigation");
1176+
expect(createScopeBackReturnChatOpenResult({ ...leftResult, hasChildren: true })).toMatchObject({
1177+
type: "open",
1178+
summary: { sessionId: "root-session", activeSessionId: "root-active" },
1179+
});
1180+
});
1181+
11571182
test("pushes and pops immutable scope frames with their return chats one level at a time", () => {
11581183
const initial: AgentsViewScopeFrame[] = [];
11591184
const rootChat = makeSummary({ sessionId: "root-session" });

0 commit comments

Comments
 (0)