The shell tool was only reading once when data was available, which caused
data loss when the child process produced more output than the 4KB buffer.
Fixed by reading in a loop until EOF is reached in both the POLLHUP and
POLLIN handlers.
Resolved merge conflicts:
- CMakeLists.txt: Added both rebase_engine/utility and base64_util sources
- src/harness.cpp: Combined Content type with proper error handling
- src/main.cpp: Merged includes, test flags, and CLI parsing
- Renamed conflicting flags: -B→-Z (build_rebase), -T→-W (edit_prompt), -b→-K (base64_decode)
- tests/CMakeLists.txt: Added all test targets from both branches
- src/rebase_engine.cpp: Fixed to use get_content_string() for Content variant type
- Updated test files to use new flag names (-Z, -W, -K)
The print_history function (used by -p flag) now properly displays multimodal
content by:
- Displaying text content parts from ContentPart arrays
- Indicating presence of image_url content parts with [Image] marker
- Rendering mixed content types in a human-readable format
All 35 tests pass.
Change the required parameter name from 'filePath' to 'path' in the
read_multi_modal tool's JSON schema to match the property definition
and the ReadFileToolParams struct field name.
- Add test_tool_read_multi_modal.sh with tests for:
- Successfully reading a PNG image file
- Error handling for non-existent files
- Reading a JPG file (different MIME type)
- Fix json_types.hpp to properly serialize std::optional and std::variant
types by adding serialize_to_json() helper function that dispatches to
the correct serialization method.
- Register new test in tests/CMakeLists.txt
Add helper functions to run_test.sh:
- dr_history_role: Get message role from chat history
- dr_content_type: Get content type (string/array)
- dr_content_part_type: Get content part type
- dr_content_part_text: Get text from content part
- dr_content_part_image_url: Get image URL from content part
- dr_content_part_image_detail: Get image detail from content part
- dr_content_parts_count: Get content parts count
- dr_content_text: Get text content for text-only messages
Update test_multimodal_message.sh to use the new helpers instead of raw jq
Add a new overload to Harness::chat that takes a std::string as the user
message and a vector<std::string> const& as image paths. The method reads
the image files and converts them to data URIs internally, then constructs
the multimodal message.
This moves all the multimodal message construction logic from main.cpp
into Harness, simplifying main.cpp.
Issue 156 requires verifying that chat files containing multimodal messages
can be serialized to disk and deserialized correctly when resuming a session.
This commit adds test_multimodal_roundtrip.sh which validates:
- Chat file with multimodal message contains content as array of ContentPart objects
- Chat file with text-only message contains content as string
- Resuming with -F correctly deserializes multimodal messages
- Resuming with -F correctly deserializes text-only messages
- Round-trip serialization preserves all ContentPart data
- Image data URIs are preserved in the chat file
- Mixed content types (multimodal and text-only) in same history
When -i flags are present, construct a multimodal message by combining
the text prompt and encoded images into a vector of ContentPart. The text
becomes a text content part and each image becomes an image_url content part.
Changes:
- Added overloaded chat(const Message&) method to Harness class
- Modified Harness::chat(const std::string&) to delegate to new method
- Updated main.cpp to construct multimodal message when images are present
- Added integration test test_multimodal_message.sh
Acceptance criteria met:
- When -i is used, Message::content is a vector<ContentPart>
- Text prompt is included as a text ContentPart
- Each image is included as an image_url ContentPart
- Backward compatible: when -i is not used, content is a plain string
- Works with -m, -d, -t, and -M flags
- Integration test verifies correct multimodal format in chat.json
- Add ImageUrl struct with url and detail fields
- Extend ContentPart with optional text and image_url fields
- Add std::optional serialization/deserialization support
- Custom to_json for ContentPart that only serializes relevant fields
- Custom json_to<ContentPart> for proper deserialization
- Add test_image_url.sh with comprehensive tests
- All 30 tests pass
- Added read_image_as_data_uri() function to base64_util for reading,
validating, and base64-encoding image files
- Added -i CLI flag to accept image file paths (multiple allowed)
- Added -I debug flag for testing image file reading
- Image files are validated at startup with clear error messages for
missing or unreadable files
- Updated help text and README.md documentation
- Added test_image_flag.sh with tests for PNG, JPEG, GIF formats,
error cases, and multiple -i flags
- Add ContentPart struct with type and text fields
- Change Message::content from std::string to std::variant<std::string, std::vector<ContentPart>>
- Add has_json_to partial specialization for std::variant
- Add helper methods get_content_string() and content_empty() to Message
- Add operator<< and append_to_variant_content() for variant content handling
- Update harness.cpp and ollama_client.cpp to use new variant content API
- All 28 existing tests pass without modification
- Add base64_encode() function to encode binary data to base64 string
- Add base64_decode() function to decode base64 string to binary data
- Add get_mime_type_from_extension() for MIME type detection based on file extension
- Add generate_data_uri() for data URI prefix generation
- Add test flags -B (encode), -b (decode), -T (mime type), -U (data URI)
- Add comprehensive tests in test_base64_encode.sh
- No new dependencies added
- Add #include <variant> header
- Add json_type_for_type() helper for type-based disambiguation
- Add to_json for std::variant that serializes active alternative
- Add variant_try_helper_impl for recursive variant deserialization
- Add json_to_impl specialization for std::variant
- Add TestVariantType (std::variant<std::string, std::vector<FunctionCall>>)
for testing variant serialization
- Register TestVariantType in json_dispatch_map for -R debug flag
- Add compile-time static_assert for TestVariantType
- Add test_json_variant.sh test suite
- Add test to CMakeLists.txt
- Update ollama_client.cpp to use std::expected pattern for parse_json_safely
- Add missing 'index' field to tool_calls in add_message_field helper
- Add missing 'index' field to test_edit_history_assistant_with_tool_calls test data
- Create api_response() helper function as single point for generating
complete API response JSON structure
- Refactor tool_call(), tool_call_raw(), be_done(), reasoning_step(),
and reasoning_content_step() to use the shared api_response() function
- Export api_response function for use in test scripts
The create_state function now accepts role/content pairs as arguments
and generates the JSON internally using jq for proper escaping. This
centralizes all JSON blob generation in run_test.sh, eliminating the
need for test files to manually construct JSON arrays.
Centralize history JSON blob generation by moving the create_state
function from test_editor.sh to run_test.sh. This ensures all history
JSON generation happens in only one spot (run_test.sh).
- Added create_state function to run_test.sh with export
- Removed duplicate create_state definition from test_editor.sh
- Changed Client::chat return type from ChatResponse to Message
- Updated OllamaClient and DebugClient to extract message from response
- Simplified Harness to work directly with Message
- ChatResponse is still parsed internally for Usage info logging
The add_message_field function now constructs tool call JSON internally
from simple parameters (id, name, arguments) instead of accepting raw
JSON strings. This makes the test helper functions more robust and
easier to use.
Changed:
- add_message_field: tool_call field now takes id, name, args and builds JSON
- create_message_json: updated to handle tool_call's 3-parameter syntax
- create_messages_json: updated to handle tool_call's 3-parameter syntax
- is_message_field: changed tool_calls to tool_call
- Updated all test files that used the old tool_calls raw JSON syntax
The file was split into 12 individual test files in a previous
commit, but the original combined file was not deleted. This
commit removes the now-obsolete test_rebase_content.sh file.
Updated all 12 test_rebase_content_* test files to use the
create_messages_json helper function from run_test.sh instead of
manually creating JSON strings, following the pattern established
by test_rebase_apply_* tests.
This complies with CONTRIBUTING.md which states:
'If you do any json handling in the test files your changes will be rejected'
All 83 tests pass.
Each test in tests/test_rebase_content.sh is now its own test script:
- test_rebase_content_basic_messages.sh
- test_rebase_content_multiline_content.sh
- test_rebase_content_tool_call_display.sh
- test_rebase_content_tool_message.sh
- test_rebase_content_empty_message.sh
- test_rebase_content_header_comments.sh
- test_rebase_content_multiple_tool_calls.sh
- test_rebase_content_message_indices.sh
- test_rebase_content_scissors_line.sh
- test_rebase_content_special_characters.sh
- test_rebase_content_unicode_characters.sh
- test_rebase_content_very_long_content.sh
All 83 tests pass.
- Consolidated dr_* functions into dr_field helper
- Refactored create_chat_file to use create_history_json
- Refactored create_rebase_lines to use create_rebase_line
- Created add_message_field helper for message field handling
- Created is_message_field helper for field name checking
- Refactored create_messages_json to use create_message_json
- Added local variable declarations for better scoping
Replace hardcoded /tmp/drharness_output.txt with $TEST_TEMP_DIR/drharness_output.txt
in all test files. Tests should only write to subfiles/directories of the working
directory (which is already a temp directory created by run_test.sh).
Add helper functions to run_test.sh for creating rebase lines and history
messages:
- create_rebase_line: creates a single rebase line JSON object
- create_rebase_lines: creates a JSON array of rebase lines
- create_message_json: creates a message JSON with optional fields
- create_messages_json: creates a JSON array of messages
Update test_rebase_apply.sh to use these helper functions instead of
manually constructing JSON strings, which violates CONTRIBUTING.md.
Split the monolithic test_edit_prompt.sh into 6 individual test files:
- test_edit_prompt_with_context.sh
- test_edit_prompt_first_message.sh
- test_edit_prompt_separator_placement.sh
- test_edit_prompt_multiline_context.sh
- test_edit_prompt_tool_role.sh
- test_edit_prompt_middle_message.sh
Each test is now its own script that can be run independently.
Add create_history_json() helper function to run_test.sh and use it in
test_edit_prompt.sh to avoid manual JSON string construction. This follows
CONTRIBUTING.md guidelines that prohibit JSON handling in test files.