Skip to content
9 changes: 9 additions & 0 deletions apps/server/scripts/record-claude-agent-sdk-replay-fixture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ import {
import { CLAUDE_BACKGROUND_MONITOR_WAKE_PROMPT } from "../src/orchestration-v2/testkit/fixtures/claude_background_monitor_wake/input.ts";
import { CLAUDE_NESTED_BACKGROUND_SUBAGENT_WAKE_PROMPT } from "../src/orchestration-v2/testkit/fixtures/claude_nested_background_subagent_wake/input.ts";
import { CLAUDE_NESTED_SUBAGENT_MODEL_PROMPT } from "../src/orchestration-v2/testkit/fixtures/claude_nested_subagent_model/input.ts";
import { CLAUDE_MCP_TOOL_PRESENTATION_PROMPT } from "../src/orchestration-v2/testkit/fixtures/claude_mcp_tool_presentation/input.ts";
import { CLAUDE_BACKGROUND_TASK_INTERRUPT_PROMPT } from "../src/orchestration-v2/testkit/fixtures/claude_background_task_interrupt/input.ts";
import { CLAUDE_BACKGROUND_WAKE_BEFORE_QUEUED_PROMPT_LAUNCH_PROMPT } from "../src/orchestration-v2/testkit/fixtures/claude_background_wake_before_queued_prompt/input.ts";
import {
Expand Down Expand Up @@ -253,6 +254,14 @@ const CLAUDE_RECORDINGS = {
queryMode: "streaming",
enableTools: true,
},
// Needs the claude.ai Firecrawl connector on the recording account. Claude
// Code describes MCP tool uses in an undeclared `tool_use_meta` field.
claude_mcp_tool_presentation: {
prompts: [CLAUDE_MCP_TOOL_PRESENTATION_PROMPT],
defaultTranscriptFile: "fixtures/claude_mcp_tool_presentation/claude_transcript.ndjson",
queryMode: "streaming",
enableTools: true,
},
subagent: {
prompts: [SUBAGENT_PROMPT],
defaultTranscriptFile: "fixtures/subagent/claude_transcript.ndjson",
Expand Down
437 changes: 368 additions & 69 deletions apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.test.ts

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,11 @@ interface ClaudeQuerySetModelFrame {
readonly model: string;
}

interface ClaudeQuerySetPermissionModeFrame {
readonly type: "query.set_permission_mode";
readonly mode: string;
}

interface ClaudeQueryInterruptFrame {
readonly type: "query.interrupt";
}
Expand Down Expand Up @@ -239,6 +244,7 @@ type ClaudeOutboundFrame =
| ClaudeQueryOpenFrame
| ClaudePromptOfferFrame
| ClaudeQuerySetModelFrame
| ClaudeQuerySetPermissionModeFrame
| ClaudeQueryInterruptFrame
| ClaudePermissionResponseFrame
| ClaudeSessionForkFrame
Expand Down Expand Up @@ -811,6 +817,13 @@ function makeReplayQueryRunner(
model,
});
}),
setPermissionMode: (mode) =>
replayEffect(() => {
assertNextOutboundFrame({
type: "query.set_permission_mode",
mode,
});
}),
interrupt: replayEffect(() => {
assertNextOutboundFrame({ type: "query.interrupt" });
}),
Expand Down Expand Up @@ -1116,6 +1129,11 @@ function sanitizeSdkMessageForReplay(input: {
session_id: message.session_id,
};
}
// Like init's slash_commands, the recording account's commands and skills
// are local configuration, not protocol.
if (message.type === "system" && message.subtype === "commands_changed") {
return { ...message, commands: [] };
}
if (message.type === "rate_limit_event") {
return {
...message,
Expand Down
Loading
Loading