Skip to content

Commit 8e0ae47

Browse files
committed
fix(webapp): drop Keep digging once the turn has already kept digging
1 parent 4593776 commit 8e0ae47

5 files changed

Lines changed: 42 additions & 2 deletions

File tree

apps/webapp/app/components/dashboard-agent/DashboardAgentMessages.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { stripModelImages } from "./model-markdown";
2222
import { reportBlockFromToolPart } from "./report-block-adapter";
2323
import { shouldShowLiveTurnError } from "./turn-error";
2424
import type { ResolvedUri } from "./ReportView";
25+
import { answerContinuesAfter } from "./view-actions";
2526
import { ViewBlocks } from "./view-catalog";
2627

2728
export type { TurnActivity };
@@ -240,6 +241,7 @@ const DashboardAgentTurn = memo(function DashboardAgentTurn({
240241
onIntent={onIntent}
241242
resolveUri={resolveUri}
242243
pagePaths={pagePaths}
244+
answered={answerContinuesAfter(parts as never, i)}
243245
/>
244246
</ChatCardSlot>
245247
);

apps/webapp/app/components/dashboard-agent/InvestigationCard.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,11 +139,14 @@ export function InvestigationCard({
139139
defaultExpanded = false,
140140
resolveUri,
141141
onIntent,
142+
answered = false,
142143
}: {
143144
block: InvestigationBlock;
144145
defaultExpanded?: boolean;
145146
resolveUri?: ResolveUri;
146147
onIntent?: (intent: AgentIntent) => void;
148+
/** The turn kept answering after this card, so "keep digging" has nothing to ask for. */
149+
answered?: boolean;
147150
}) {
148151
const [expanded, setExpanded] = useState(defaultExpanded);
149152
const investigation = block.investigation;
@@ -237,7 +240,12 @@ export function InvestigationCard({
237240
) : null}
238241
</div>
239242

240-
<InvestigationActions actions={block.capabilities?.actions ?? []} onIntent={onIntent} />
243+
<InvestigationActions
244+
actions={(block.capabilities?.actions ?? []).filter(
245+
(action) => !answered || action.kind !== "ask_follow_up"
246+
)}
247+
onIntent={onIntent}
248+
/>
241249
</AgentCardBody>
242250
</AgentCard>
243251
);

apps/webapp/app/components/dashboard-agent/view-actions.test.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { ActionsBlockAction } from "@internal/dashboard-agent-contracts";
22
import { readFileSync } from "node:fs";
33
import { describe, expect, it } from "vitest";
4-
import { renderableActions } from "./view-actions";
4+
import { answerContinuesAfter, renderableActions } from "./view-actions";
55

66
const askAction: ActionsBlockAction = {
77
label: "Investigate it",
@@ -32,6 +32,21 @@ describe("renderableActions", () => {
3232
});
3333
});
3434

35+
describe("keep digging, only while there is digging left", () => {
36+
const card = { type: "data-view" };
37+
const text = (t: string) => ({ type: "text", text: t });
38+
39+
it("sees the answer the turn went on to give", () => {
40+
expect(answerContinuesAfter([card, text("so here is why")] as never, 0)).toBe(true);
41+
});
42+
43+
it("leaves a card the turn ended on", () => {
44+
expect(answerContinuesAfter([text("looking"), card] as never, 1)).toBe(false);
45+
// An empty trailing text part is not an answer.
46+
expect(answerContinuesAfter([card, text(" ")] as never, 0)).toBe(false);
47+
});
48+
});
49+
3550
describe("ActionsBlock", () => {
3651
const source = readFileSync(new URL("./ActionsBlock.tsx", import.meta.url), "utf8");
3752

apps/webapp/app/components/dashboard-agent/view-actions.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,14 @@ export function renderableActions<T extends CardAction>(actions: T[]): T[] {
1414
return intent.kind !== "navigate" || isTriggerUri(intent.target);
1515
});
1616
}
17+
18+
/**
19+
* "Keep digging" asks the agent to carry on — which is pointless once it already has.
20+
* A turn that renders an inconclusive card and then keeps answering leaves the button
21+
* offering work that is already done.
22+
*/
23+
export function answerContinuesAfter(parts: { type: string; text?: string }[], index: number) {
24+
return parts
25+
.slice(index + 1)
26+
.some((part) => part.type === "text" && (part.text ?? "").trim().length > 0);
27+
}

apps/webapp/app/components/dashboard-agent/view-catalog.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,14 @@ export function ViewBlocks({
1313
onIntent,
1414
resolveUri,
1515
pagePaths,
16+
answered = false,
1617
}: {
1718
blocks: ViewBlock[];
1819
onIntent?: (intent: AgentIntent) => void;
1920
resolveUri?: (uri: string) => ResolvedUri | null;
2021
pagePaths?: Record<string, string>;
22+
/** The turn kept answering after this card, so "keep digging" has nothing to ask for. */
23+
answered?: boolean;
2124
}) {
2225
if (!Array.isArray(blocks)) return null;
2326
return (
@@ -41,6 +44,7 @@ export function ViewBlocks({
4144
block={block}
4245
resolveUri={resolveUri}
4346
onIntent={onIntent}
47+
answered={answered}
4448
/>
4549
);
4650
case "report":

0 commit comments

Comments
 (0)