From dd8e22ce734f2d930f0a6c0973d8ae2e59283617 Mon Sep 17 00:00:00 2001 From: Steven Enamakel Date: Sun, 20 Sep 2026 13:25:03 +0300 Subject: [PATCH 1/2] fix: preserve literal image marker text Co-authored-by: Medulla --- .../claude_code/input_builder_tests.rs | 17 +++++++++++++++++ .../src/providers/claude_code/mod.rs | 11 ++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/crates/tinyagents-harness/src/providers/claude_code/input_builder_tests.rs b/crates/tinyagents-harness/src/providers/claude_code/input_builder_tests.rs index 0f7669a26..56ce0f106 100644 --- a/crates/tinyagents-harness/src/providers/claude_code/input_builder_tests.rs +++ b/crates/tinyagents-harness/src/providers/claude_code/input_builder_tests.rs @@ -161,6 +161,23 @@ fn image_blocks_preserve_text_order() { assert_eq!(content[4]["text"], " after"); } +#[test] +fn literal_native_image_marker_stays_text() { + let s = String::from_utf8(build_stdin( + &[ChatMessage::user( + "literal [OH_IMAGE:data:image/png;base64,QUJD] then [OH_IMAGE_LITERAL:data:image/png;base64,REVG]", + )], + true, + )) + .unwrap(); + let row: Value = serde_json::from_str(s.lines().next().unwrap()).unwrap(); + let content = row["message"]["content"].as_array().unwrap(); + assert_eq!(content[0]["text"], "literal "); + assert_eq!(content[1]["type"], "image"); + assert_eq!(content[2]["text"], " then "); + assert_eq!(content[3]["text"], "[OH_IMAGE:data:image/png;base64,REVG]"); +} + #[test] fn literal_file_marker_is_not_read() { let s = String::from_utf8(build_stdin( diff --git a/crates/tinyagents-harness/src/providers/claude_code/mod.rs b/crates/tinyagents-harness/src/providers/claude_code/mod.rs index 615a6982b..639b3f0f3 100644 --- a/crates/tinyagents-harness/src/providers/claude_code/mod.rs +++ b/crates/tinyagents-harness/src/providers/claude_code/mod.rs @@ -369,14 +369,19 @@ fn response_format_instruction(format: Option<&ResponseFormat>) -> Option]` marker `input_builder` later rehydrates, +/// blocks pass through (with internal image-looking text escaped), +/// JSON/extension blocks are stringified, an image becomes an +/// `[OH_IMAGE:]` marker `input_builder` later rehydrates, /// and redacted-thinking blocks are dropped (nothing to show). fn render_content(content: &[ContentBlock]) -> String { content .iter() .filter_map(|block| match block { - ContentBlock::Text(text) => Some(text.clone()), + // `[OH_IMAGE:…]` is an internal transport marker. User-authored + // text that happens to contain that spelling must remain prose, + // rather than becoming an unintended native attachment when the + // input builder rehydrates image markers below. + ContentBlock::Text(text) => Some(text.replace("[OH_IMAGE:", "[OH_IMAGE_LITERAL:")), ContentBlock::Image(image) => Some(format!("[OH_IMAGE:{}]", image.url)), ContentBlock::Json(value) | ContentBlock::ProviderExtension(value) => { Some(value.to_string()) From 933aae1901d37743f506b5ad535670d34adea103 Mon Sep 17 00:00:00 2001 From: Steven Enamakel Date: Tue, 22 Sep 2026 05:14:27 +0300 Subject: [PATCH 2/2] test: update dependency boundary line numbers The line numbers in the dependency boundary test for the Claude Code input builder tests have been updated to reflect recent changes in the source file. A new entry for line 242 has been added to the known debt list, ensuring the test remains accurate with the current codebase. Auto-committed-on: dragonfly Co-authored-by: Medulla --- .../tests/dependency_boundary.rs | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/crates/tinyagents-integration-tests/tests/dependency_boundary.rs b/crates/tinyagents-integration-tests/tests/dependency_boundary.rs index 2f6595322..77e23425e 100644 --- a/crates/tinyagents-integration-tests/tests/dependency_boundary.rs +++ b/crates/tinyagents-integration-tests/tests/dependency_boundary.rs @@ -99,15 +99,15 @@ const KNOWN_GENERIC_CLAUDE_CODE_CHAT_MESSAGE_DEBT: &[(&str, usize)] = &[ ), ( "crates/tinyagents-harness/src/providers/claude_code/input_builder_tests.rs", - 178, + 184, ), ( "crates/tinyagents-harness/src/providers/claude_code/input_builder_tests.rs", - 179, + 195, ), ( "crates/tinyagents-harness/src/providers/claude_code/input_builder_tests.rs", - 180, + 196, ), ( "crates/tinyagents-harness/src/providers/claude_code/input_builder_tests.rs", @@ -115,23 +115,27 @@ const KNOWN_GENERIC_CLAUDE_CODE_CHAT_MESSAGE_DEBT: &[(&str, usize)] = &[ ), ( "crates/tinyagents-harness/src/providers/claude_code/input_builder_tests.rs", - 198, + 214, ), ( "crates/tinyagents-harness/src/providers/claude_code/input_builder_tests.rs", - 199, + 215, ), ( "crates/tinyagents-harness/src/providers/claude_code/input_builder_tests.rs", - 200, + 216, ), ( "crates/tinyagents-harness/src/providers/claude_code/input_builder_tests.rs", - 210, + 217, ), ( "crates/tinyagents-harness/src/providers/claude_code/input_builder_tests.rs", - 225, + 227, + ), + ( + "crates/tinyagents-harness/src/providers/claude_code/input_builder_tests.rs", + 242, ), ( "crates/tinyagents-harness/src/providers/claude_code/mod.rs",