1import { assert } from "@effect/vitest";
2import type { ProviderReplayTranscript } from "@t3tools/contracts";
3
4import type { OrchestratorV2ScenarioResult } from "../../OrchestratorScenario.ts";
5import {
6 assertAssistantTextIncludes,
7 assertBaseProjection,
8 assertConversationMessageRoles,
9 assertExecutionNodeKinds,
10 assertRuntimeRequestCounts,
11 assertSemanticProjectionIntegrity,
12 assertTurnItemTypes,
13 assertUserMessagesInclude,
14 assertVisibleTurnItemsMirrorLocalTurnItems,
15 projectionFor,
16 WEB_SEARCH_PROMPT,
17} from "../shared.ts";
18
19const CLAUDE_WEB_SEARCH_QUERY = "FIFA World Cup 2026 ticket pricing";
20
21export function assertClaudeWebSearchOutput(
22 result: OrchestratorV2ScenarioResult,
23 transcript: ProviderReplayTranscript,
24) {
25 assertBaseProjection({ result, transcript, runCount: 1, runStatuses: ["completed"] });
26
27 const projection = projectionFor(result, transcript.scenario);
28 assertSemanticProjectionIntegrity(projection);
29 assertVisibleTurnItemsMirrorLocalTurnItems(projection);
30 assertExecutionNodeKinds(projection, ["root_turn", "tool_call", "assistant_message"]);
31 assertConversationMessageRoles(projection, ["user", "assistant"]);
32 assertTurnItemTypes(projection, [
33 "user_message",
34 "dynamic_tool",
35 "web_search",
36 "assistant_message",
37 ]);
38 assertRuntimeRequestCounts(projection, { total: 0 });
39 assertUserMessagesInclude(projection, [WEB_SEARCH_PROMPT]);
40 assertAssistantTextIncludes(projection, "web search fixture complete");
41
42 const toolSearchItems = projection.turnItems.filter(
43 (item) => item.type === "dynamic_tool" && item.toolName === "ToolSearch",
44 );
45 assert.lengthOf(toolSearchItems, 1);
46
47 const webSearchItems = projection.turnItems.filter((item) => item.type === "web_search");
48 assert.lengthOf(webSearchItems, 1);
49 const webSearch = webSearchItems[0];
50 assert.isDefined(webSearch);
51 assert.equal(webSearch.status, "completed");
52 assert.include(webSearch.patterns ?? [], CLAUDE_WEB_SEARCH_QUERY);
53 assert.isAtLeast(webSearch.results?.length ?? 0, 1);
54 assert.isTrue(
55 webSearch.results?.some((entry) => entry.url?.includes("fifa.com")) ?? false,
56 "Claude web search should project structured result URLs",
57 );
58}