125 Commits

Author SHA1 Message Date
darthrubik 95c415f06a Adding failing test for hanging background processes 2026-08-12 15:48:31 -05:00
darthrubik 6c1906679d Merge remote-tracking branch 'origin/master' into feature/save-model-between-chats 2026-08-12 15:41:23 -05:00
hal9000 3bc2b61b5a Speed up ctrlc test by using shorter sleep (1s instead of 5s) 2026-08-06 21:20:46 +00:00
hal9000 64d8e5bb49 Add test for ctrlc cancellation after tool execution
Test verifies that sending SIGINT during tool execution stops processing
after that tool completes and prevents subsequent tool calls from running.
Conversation state is preserved in the chat file.
2026-08-06 21:17:03 +00:00
hal9000 bbc4f5acf0 Add unit test for ctrlc feature on shell tool (issue 193)
Test verifies that when SIGINT (Ctrl+C) is sent to drharness during
shell command execution, the tool returns the expected
'[user requested halt of program]' message.
2026-08-05 23:49:07 +00:00
hal9000 02975ddfd4 Fix: Use helper functions in test_harness_config.sh
- Added dr_config_base_url and dr_config_model helper functions to run_test.sh
- Updated test_harness_config.sh to use be_done() and helper functions instead of inline JSON
2026-08-04 20:20:10 +00:00
hal9000 3e99b37683 Move base_url and model into HarnessConfig (issue 186)
- Added base_url and model fields to HarnessConfig in json_types.hpp
- Removed base_url and model from OllamaConfig in ollama_client.hpp
- Updated OllamaClient constructor to accept base_url and model as separate parameters
- Updated main.cpp to use HarnessConfig for base_url and model
- Updated agent_tool.cpp to use new OllamaClient constructor
- Added test_harness_config.sh to verify the new config fields
- Updated README.md to document the config fields
2026-08-04 15:13:37 -05:00
darthrubik 815eeeec44 Rename flag that was used in other branch 2026-07-23 16:59:50 -05:00
darthrubik d655a9d953 Merge remote-tracking branch 'origin/master' into feature/rebase 2026-07-23 16:59:40 -05:00
hal9000 48a3f15999 Add -P flag to read prompt from file
Implement issue 185: Create a new flag -P that reads the prompt from a
file instead of the command line.

Changes:
- Add -P flag parsing in main.cpp
- Read prompt content from specified file
- Update help message
- Update README.md documentation
- Add test_prompt_file.sh with tests for basic, multi-line, and error cases
2026-07-22 14:04:04 +00:00
hal9000 4b3a277a15 Implement issue 180: Add unit tests for encoding (commit 11484fe)
- Add test_encoding.sh with 11 tests for UTF-8 encoding validation and conversion
- Add -8 debug flag to test ensure_utf8 function with hex-encoded input
- Fix bug in ensure_utf8: check null terminator at loop start to prevent
  undefined behavior when reading past the end of the string
- Tests cover:
  - Valid ASCII passthrough
  - Valid UTF-8 2-byte, 3-byte, and 4-byte sequences
  - Latin-1 byte conversion (0xe9 -> c3a9)
  - Multiple Latin-1 bytes (café)
  - Isolated continuation byte conversion (0x80 -> c280)
  - Mixed valid/invalid bytes
  - Empty string handling
  - Integration test: read_file with non-UTF8 content
2026-07-10 15:50:01 -05:00
darthrubik e877eca085 Add failing test for tool calls 2026-06-18 15:14:13 -05:00
hal9000 da919f9f6e Merge origin/master into work branch (issue #169)
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)
2026-06-15 22:52:29 +00:00
hal9000 030e3f7656 Implement issue 167: Handle multimodal content in print_history pretty-print mode
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.
2026-06-15 17:31:12 -05:00
hal9000 2824b89643 Implement issue 161: Add unit tests for read_multi_modal tool
- 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
2026-06-15 22:02:58 +00:00
hal9000 3fc1a2b286 Implement issue 160: Replace raw jq parsing with helper functions in test_multimodal_message.sh
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
2026-06-15 16:50:06 -05:00
hal9000 716bfdcd8b Add test for multimodal chat file persistence round-trip
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
2026-06-12 07:17:11 -05:00
hal9000 7d374a4172 Implement multimodal message construction for -i flag (#155)
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
2026-06-12 07:17:11 -05:00
hal9000 0ca0305ebf feat: Add ImageUrl struct and image_url support to ContentPart (#152)
- 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
2026-06-12 07:17:08 -05:00
hal9000 068557b06c Implement issue 154: CLI -i flag with image file reading
- 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
2026-06-12 07:16:40 -05:00
hal9000 ce40d1fe9d Issue 153: Add base64 encoding utility
- 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
2026-06-12 07:16:40 -05:00
hal9000 ffcc907a99 Add std::variant JSON serialization infrastructure (issue 150)
- 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
2026-06-11 21:13:10 +00:00
darthrubik f0293d548f Cache tool response json instead of generating 1001 times 2026-06-04 17:36:23 -05:00
darthrubik fee692d262 Fix compilation errors and test failures after merge (issue #140)
- 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
2026-06-04 16:09:09 -05:00
darthrubik ea8582644e Merge branch 'master' into feature/rebase (issue #140) 2026-06-04 16:07:42 -05:00
darthrubik 2cdb06cffe Fixup tool calling 2026-06-04 15:23:32 -05:00
darthrubik a06aa531f6 Refactor (partially broken) to stream 2026-06-03 17:12:36 -05:00
darthrubik 4ee514efb1 Refactor to put json message generation in one place 2026-06-03 17:10:40 -05:00
darthrubik 06d1551af0 Refactor run_test.sh to generate API response JSON in one spot (issue #138)
- 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
2026-06-03 17:02:25 -05:00
darthrubik 718bd5dca7 Refactor run_test.sh to generate history json blobs in only one spot (issue 137)
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.
2026-06-03 17:00:10 -05:00
darthrubik c5420a0757 issue 136: Move create_state function to run_test.sh
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
2026-06-03 16:56:40 -05:00
darthrubik d81c75a9a3 Fix issue 134: add_message_field no longer accepts raw JSON for tool_calls
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
2026-06-03 07:53:39 -05:00
darthrubik 0a734ec2ba Split test_rebase_parser.sh into individual test files (issue #133)
Each of the 17 tests from test_rebase_parser.sh is now in its own
test file, following the project convention of one test per script.
2026-06-03 07:49:25 -05:00
darthrubik 8cb6f5aa0b Delete old combined test_rebase_content.sh (issue 132)
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.
2026-06-03 07:43:28 -05:00
darthrubik 5f88196c54 Use create_messages_json helper instead of manual JSON (issue 132)
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.
2026-06-03 07:41:24 -05:00
darthrubik a96246bcd3 Split test_rebase_content.sh into 12 individual test scripts (issue 132)
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.
2026-06-03 07:38:10 -05:00
darthrubik 65aededace test: remove combined test_rebase_apply.sh (issue #131)
The tests have been split into individual test files and registered
in CMakeLists.txt. Removing the combined test file as it is no
longer needed.
2026-06-03 07:33:20 -05:00
darthrubik 949682a176 Split test_rebase_apply.sh into individual test files (issue 131)
- test_rebase_apply_pick_preserves.sh
- test_rebase_apply_drop_removes.sh
- test_rebase_apply_edit_updates_role.sh
- test_rebase_apply_edit_preserves_fields.sh
- test_rebase_apply_implicit_pick.sh
- test_rebase_apply_mixed_commands.sh
- test_rebase_apply_empty_lines_preserves.sh
- test_rebase_apply_lenient_orphaned_results.sh
- test_rebase_apply_edit_preserves_tool_calls.sh
- test_rebase_apply_deleting_lines_drops.sh
- test_rebase_apply_all_lines_deleted_keeps.sh

Removed the combined test_rebase_apply.sh file and updated CMakeLists.txt
to include the 11 new individual test files.
2026-06-03 07:02:15 -05:00
darthrubik e65616bfea Remove redundant code from run_test.sh (#130)
- 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
2026-06-02 17:19:21 -05:00
darthrubik 41b49aeeae Fix issue 129: Use TEST_TEMP_DIR instead of /tmp for test output files
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).
2026-06-02 17:09:32 -05:00
darthrubik cec6c72ecd fix(issue 128): replace manual JSON creation with helper functions
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.
2026-06-02 16:33:50 -05:00
darthrubik 511b53ca18 Break test_edit_prompt.sh into multiple tests (issue 127)
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.
2026-06-02 16:27:23 -05:00
darthrubik 15098d7515 Fix issue 126: Replace manual JSON history creation in test_edit_prompt.sh
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.
2026-06-02 16:21:54 -05:00
darthrubik 4393a5dba2 Remove old test_edit_history_flag.sh (issue 125) 2026-06-02 16:17:20 -05:00
darthrubik aa04ad0902 Split test_edit_history_flag.sh into individual test scripts (issue 125) 2026-06-02 16:16:42 -05:00
darthrubik 0366d3db57 Issue 124: Break test_edit_history.sh into multiple test scripts
Split the monolithic test_edit_history.sh file into 21 individual
test scripts, each containing a single test. This follows the
project's testing guideline of having no more than one test per script.

Each test file contains its own helper functions (run_drharness,
get_output, reset_editor_state) and runs independently.

Updated CMakeLists.txt to register all 21 new test targets and
removed the old test_edit_history target.
2026-06-02 16:12:23 -05:00
darthrubik 69bd732ce7 Fix: Drop messages when lines are deleted from rebase editor (issue 120)
- Modified parse_rebase_file to skip header comments before '-- >8 --'
- Modified apply_rebase to drop messages whose indices are not mentioned
  in the parsed commands (implicit drop)
- Special case: if no commands are parsed (all lines deleted), keep all messages
- Updated test_implicit_pick to reflect new behavior
- Added test_deleting_lines_drops_messages and test_all_lines_deleted_keeps_all
- Updated test_delete_line_equals_drop to reflect new behavior
2026-06-01 19:33:46 -05:00
darthrubik 211f42a87e Implement issue 119: Exit on first parse error instead of aggregating all errors
- Removed the errors vector from parse_rebase_file()
- Changed all error handling to return std::unexpected() immediately
- Removed the error aggregation code at the end of the function
- Updated test to verify first error is returned (not all errors)
2026-06-01 18:22:13 -05:00
darthrubik 5351f4f72a Refactor: Extract read_harness_state_or_exit() helper function
This refactors the duplicated code for deserializing HarnessState from a file
into a reusable helper function. The same pattern was used in two places:
1. In the edit_history block
2. In the main flow when loading existing chat files

The helper function handles:
- Opening the file
- Reading file content
- Parsing JSON
- Converting to HarnessState
- Error reporting

This reduces code duplication and makes future modifications easier.
2026-06-01 18:14:41 -05:00
darthrubik 7fe1656c7d Add edge case tests for history editing feature (issue 114)
- Add test for editing a message and removing all content (empty content)
- Add test for multiple consecutive edits to the same message (changes stack)
- Add test for editing messages with special characters
- Add test for very long message content
- Add test for editing assistant messages with tool_calls
- Add test for dropping all messages (empty history result)
- Add test for unicode characters in message content
- Add test for whitespace variations in rebase file
- Add test for comments and empty lines mixed with commands
- Add test for special characters and unicode in rebase content display
- Fix apply_rebase to preserve original content when only role is changed
- Add content_edited flag to RebaseLine to track explicit edits
2026-05-30 19:49:05 -05:00