fix: redact hook-blocked CLI raw traces

This commit is contained in:
jesse-merhi
2026-05-06 10:49:37 +10:00
committed by clawsweeper
parent d4b8acb117
commit ae922c96f9
2 changed files with 99 additions and 9 deletions

View File

@@ -1690,6 +1690,93 @@ describe("runReplyAgent claude-cli routing", () => {
expect(result).toMatchObject({ text: "ok" });
});
it("does not leak hook-blocked CLI input in raw trace payloads", async () => {
runCliAgentMock.mockResolvedValueOnce({
payloads: [{ text: "The agent cannot read this message.", isError: true }],
meta: {
error: { kind: "hook_block", message: "The agent cannot read this message." },
agentMeta: {
provider: "claude-cli",
model: "opus-4.5",
},
},
});
const typing = createMockTypingController();
const sessionCtx = {
Provider: "webchat",
OriginatingTo: "session:1",
AccountId: "primary",
MessageSid: "msg",
CommandBody: "secret hitl prompt",
RawBody: "secret hitl prompt",
BodyForAgent: "secret hitl prompt",
Body: "secret hitl prompt",
} as unknown as TemplateContext;
const resolvedQueue = { mode: "interrupt" } as unknown as QueueSettings;
const sessionEntry = {
sessionId: "session",
updatedAt: Date.now(),
traceLevel: "raw",
} as SessionEntry;
const followupRun = {
prompt: "secret hitl prompt",
summaryLine: "secret hitl prompt",
enqueuedAt: Date.now(),
run: {
agentId: "main",
sessionId: "session",
sessionKey: "main",
messageProvider: "webchat",
sessionFile: "/tmp/session.jsonl",
workspaceDir: "/tmp",
config: createCliBackendTestConfig(),
skillsSnapshot: {},
traceAuthorized: true,
provider: "claude-cli",
model: "opus-4.5",
thinkLevel: "low",
verboseLevel: "off",
elevatedLevel: "off",
bashElevated: {
enabled: false,
allowed: false,
defaultLevel: "off",
},
timeoutMs: 1_000,
blockReplyBreak: "message_end",
},
} as unknown as FollowupRun;
const result = await runReplyAgent({
commandBody: "secret hitl prompt",
followupRun,
queueKey: "main",
resolvedQueue,
shouldSteer: false,
shouldFollowup: false,
isActive: false,
isStreaming: false,
typing,
sessionCtx,
sessionEntry,
sessionStore: { main: sessionEntry },
defaultModel: "claude-cli/opus-4.5",
resolvedVerboseLevel: "off",
isNewSession: false,
blockStreamingEnabled: false,
resolvedBlockStreamingBreak: "message_end",
shouldInjectGroupIntro: false,
typingMode: "instant",
});
const texts = Array.isArray(result)
? result.map((payload) => payload.text ?? "").join("\n")
: (result?.text ?? "");
expect(texts).toContain("The agent cannot read this message.");
expect(texts).not.toContain("secret hitl prompt");
});
it("uses the selected CLI runtime for canonical Anthropic models", async () => {
runCliAgentMock.mockResolvedValueOnce({
payloads: [{ text: "ok" }],

View File

@@ -1708,14 +1708,17 @@ export async function runReplyAgent(params: {
}
}
const prefixPayloads = [...verboseNotices];
const rawUserText =
runResult.meta?.finalPromptText ??
sessionCtx.CommandBody ??
sessionCtx.RawBody ??
sessionCtx.BodyForAgent ??
sessionCtx.Body;
const rawAssistantText =
runResult.meta?.finalAssistantRawText ?? runResult.meta?.finalAssistantVisibleText;
const isHookBlockedRun = runResult.meta?.error?.kind === "hook_block";
const rawUserText = isHookBlockedRun
? runResult.meta?.finalPromptText
: (runResult.meta?.finalPromptText ??
sessionCtx.CommandBody ??
sessionCtx.RawBody ??
sessionCtx.BodyForAgent ??
sessionCtx.Body);
const rawAssistantText = isHookBlockedRun
? undefined
: (runResult.meta?.finalAssistantRawText ?? runResult.meta?.finalAssistantVisibleText);
const traceAuthorized = followupRun.run.traceAuthorized === true;
const executionTrace = mergeExecutionTrace({
fallbackAttempts,
@@ -1847,7 +1850,7 @@ export async function runReplyAgent(params: {
if (responseUsageLine) {
finalPayloads = appendUsageLine(finalPayloads, responseUsageLine);
}
if (runResult.meta?.error?.kind === "hook_block") {
if (isHookBlockedRun) {
finalPayloads = markBeforeAgentRunBlockedPayloads(finalPayloads);
}