diff --git a/src/core/message-parsing/DirectiveStreamingParser.ts b/src/core/message-parsing/DirectiveStreamingParser.ts
index 5486aa9f23..bd5038c0b1 100644
--- a/src/core/message-parsing/DirectiveStreamingParser.ts
+++ b/src/core/message-parsing/DirectiveStreamingParser.ts
@@ -27,11 +27,7 @@ export class DirectiveStreamingParser {
parser.onopentag = (node: sax.Tag) => {
// Check if we're inside a code block (either global or within tool parameters)
- const insideCodeBlock =
- context.codeBlockState === CodeBlockState.INSIDE ||
- (activeHandler &&
- "isInsideParameterCodeBlock" in activeHandler &&
- (activeHandler as any).isInsideParameterCodeBlock())
+ const insideCodeBlock = this.isInsideCodeBlock(context, activeHandler)
// Check if we're inside a tool parameter (but not at the parameter level itself)
const insideToolParameter =
@@ -65,11 +61,7 @@ export class DirectiveStreamingParser {
parser.onclosetag = (tagName: string) => {
// Check if we're inside a code block (either global or within tool parameters)
- const insideCodeBlock =
- context.codeBlockState === CodeBlockState.INSIDE ||
- (activeHandler &&
- "isInsideParameterCodeBlock" in activeHandler &&
- (activeHandler as any).isInsideParameterCodeBlock())
+ const insideCodeBlock = this.isInsideCodeBlock(context, activeHandler)
// Check if we're inside a tool parameter (but not at the parameter level itself)
const insideToolParameter =
@@ -130,6 +122,18 @@ export class DirectiveStreamingParser {
return context.contentBlocks
}
+ /**
+ * Check if we're inside a code block (either global or within tool parameters)
+ */
+ private static isInsideCodeBlock(context: ParseContext, activeHandler: any): boolean {
+ return (
+ context.codeBlockState === CodeBlockState.INSIDE ||
+ (activeHandler &&
+ "isInsideParameterCodeBlock" in activeHandler &&
+ (activeHandler as any).isInsideParameterCodeBlock())
+ )
+ }
+
/**
* Convert SAX node attributes to string representation
*/
diff --git a/src/core/message-parsing/__tests__/directive-streaming-parser.spec.ts b/src/core/message-parsing/__tests__/directive-streaming-parser.spec.ts
index 8ff4131ac3..9c85e36e64 100644
--- a/src/core/message-parsing/__tests__/directive-streaming-parser.spec.ts
+++ b/src/core/message-parsing/__tests__/directive-streaming-parser.spec.ts
@@ -297,4 +297,36 @@ I've provided an example of the XML format for the log_message directive. r.type === "log_message")
expect(logMessages).toHaveLength(0)
})
+
+ test("should correctly identify code block contexts in various scenarios", () => {
+ // Test that the extracted isInsideCodeBlock logic works correctly
+ // by testing scenarios that depend on this logic
+
+ // Test 1: Code block should prevent directive parsing
+ const codeBlockInput = "Text ```\nShould not parse\n``` end"
+ const codeBlockResult = DirectiveStreamingParser.parse(codeBlockInput)
+ expect(codeBlockResult).toHaveLength(1)
+ expect(codeBlockResult[0].type).toBe("text")
+ expect((codeBlockResult[0] as any).content).toContain("")
+
+ // Test 2: Tool parameter code block should prevent directive parsing
+ const toolParamCodeBlockInput =
+ "```\nShould not parse\n```"
+ const toolParamResult = DirectiveStreamingParser.parse(toolParamCodeBlockInput)
+ expect(toolParamResult).toHaveLength(1)
+ expect(toolParamResult[0].type).toBe("tool_use")
+ expect((toolParamResult[0] as any).name).toBe("attempt_completion")
+ expect((toolParamResult[0] as any).params.result).toContain("")
+
+ // Ensure no separate log_message directive was created
+ const logMessages = toolParamResult.filter((r) => r.type === "log_message")
+ expect(logMessages).toHaveLength(0)
+
+ // Test 3: Normal directive parsing outside code blocks should still work
+ const normalInput = "Should parse normallyinfo"
+ const normalResult = DirectiveStreamingParser.parse(normalInput)
+ expect(normalResult).toHaveLength(1)
+ expect(normalResult[0].type).toBe("log_message")
+ expect((normalResult[0] as any).message).toBe("Should parse normally")
+ })
})