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
This commit is contained in:
2026-06-15 21:37:43 +00:00
committed by Jacob Gamble
parent 0772fd5fe8
commit 3fc1a2b286
2 changed files with 81 additions and 13 deletions
+68
View File
@@ -170,6 +170,74 @@ function create_state() {
}
export -f create_state
# Get message role from chat history at given index
function dr_history_role() {
local chat_file="$1"
local index="$2"
jq -r --argjson i "$index" '.history[$i].role' "$chat_file"
}
export -f dr_history_role
# Get content type (string/array) from message at given history index
function dr_content_type() {
local chat_file="$1"
local index="$2"
jq -r --argjson i "$index" '.history[$i].content | type' "$chat_file"
}
export -f dr_content_type
# Get content part type at given history and content part indices
function dr_content_part_type() {
local chat_file="$1"
local history_idx="$2"
local part_idx="$3"
jq -r --argjson h "$history_idx" --argjson p "$part_idx" '.history[$h].content[$p].type' "$chat_file"
}
export -f dr_content_part_type
# Get text content from a content part at given history and content part indices
function dr_content_part_text() {
local chat_file="$1"
local history_idx="$2"
local part_idx="$3"
jq -r --argjson h "$history_idx" --argjson p "$part_idx" '.history[$h].content[$p].text' "$chat_file"
}
export -f dr_content_part_text
# Get image URL from a content part at given history and content part indices
function dr_content_part_image_url() {
local chat_file="$1"
local history_idx="$2"
local part_idx="$3"
jq -r --argjson h "$history_idx" --argjson p "$part_idx" '.history[$h].content[$p].image_url.url' "$chat_file"
}
export -f dr_content_part_image_url
# Get image detail from a content part at given history and content part indices
function dr_content_part_image_detail() {
local chat_file="$1"
local history_idx="$2"
local part_idx="$3"
jq -r --argjson h "$history_idx" --argjson p "$part_idx" '.history[$h].content[$p].image_url.detail' "$chat_file"
}
export -f dr_content_part_image_detail
# Get content parts count from message at given history index
function dr_content_parts_count() {
local chat_file="$1"
local index="$2"
jq --argjson i "$index" '.history[$i].content | length' "$chat_file"
}
export -f dr_content_parts_count
# Get content from message at given history index (for text-only messages)
function dr_content_text() {
local chat_file="$1"
local index="$2"
jq -r --argjson i "$index" '.history[$i].content' "$chat_file"
}
export -f dr_content_text
# Resolve paths relative to this script
SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
PROJECT_ROOT=$(cd "${SCRIPT_DIR}/.." && pwd)
+13 -13
View File
@@ -13,49 +13,49 @@ echo "$(be_done "Response")" | "${DRHARNESS}" \
-m "describe this image" 2>/dev/null
# Verify the first message (index 0) is a user message with multimodal content
ROLE=$(jq -r '.history[0].role' "${TEST_TEMP_DIR}/chat.json")
ROLE=$(dr_history_role "${TEST_TEMP_DIR}/chat.json" 0)
if [ "$ROLE" != "user" ]; then
echo "FAIL: Expected first message role to be 'user', got '${ROLE}'"
exit 1
fi
# Verify content is an array (multimodal format)
CONTENT_TYPE=$(jq -r '.history[0].content | type' "${TEST_TEMP_DIR}/chat.json")
CONTENT_TYPE=$(dr_content_type "${TEST_TEMP_DIR}/chat.json" 0)
if [ "$CONTENT_TYPE" != "array" ]; then
echo "FAIL: Expected content to be an array for multimodal message, got '${CONTENT_TYPE}'"
exit 1
fi
# Verify first content part is text type
TEXT_TYPE=$(jq -r '.history[0].content[0].type' "${TEST_TEMP_DIR}/chat.json")
TEXT_TYPE=$(dr_content_part_type "${TEST_TEMP_DIR}/chat.json" 0 0)
if [ "$TEXT_TYPE" != "text" ]; then
echo "FAIL: Expected first content part type to be 'text', got '${TEXT_TYPE}'"
exit 1
fi
# Verify text content matches the prompt
TEXT_CONTENT=$(jq -r '.history[0].content[0].text' "${TEST_TEMP_DIR}/chat.json")
TEXT_CONTENT=$(dr_content_part_text "${TEST_TEMP_DIR}/chat.json" 0 0)
if [ "$TEXT_CONTENT" != "describe this image" ]; then
echo "FAIL: Expected text content to be 'describe this image', got '${TEXT_CONTENT}'"
exit 1
fi
# Verify second content part is image_url type
IMAGE_TYPE=$(jq -r '.history[0].content[1].type' "${TEST_TEMP_DIR}/chat.json")
IMAGE_TYPE=$(dr_content_part_type "${TEST_TEMP_DIR}/chat.json" 0 1)
if [ "$IMAGE_TYPE" != "image_url" ]; then
echo "FAIL: Expected second content part type to be 'image_url', got '${IMAGE_TYPE}'"
exit 1
fi
# Verify image_url has a valid data URI
IMAGE_URL=$(jq -r '.history[0].content[1].image_url.url' "${TEST_TEMP_DIR}/chat.json")
IMAGE_URL=$(dr_content_part_image_url "${TEST_TEMP_DIR}/chat.json" 0 1)
if ! echo "$IMAGE_URL" | grep -q "^data:image/png;base64,"; then
echo "FAIL: Expected image URL to be a PNG data URI, got '${IMAGE_URL}'"
exit 1
fi
# Verify image detail is "auto"
IMAGE_DETAIL=$(jq -r '.history[0].content[1].image_url.detail' "${TEST_TEMP_DIR}/chat.json")
IMAGE_DETAIL=$(dr_content_part_image_detail "${TEST_TEMP_DIR}/chat.json" 0 1)
if [ "$IMAGE_DETAIL" != "auto" ]; then
echo "FAIL: Expected image detail to be 'auto', got '${IMAGE_DETAIL}'"
exit 1
@@ -73,14 +73,14 @@ echo "$(be_done "Response 2")" | "${DRHARNESS}" \
-m "compare images" 2>/dev/null
# Verify content array has 3 parts (1 text + 2 images)
CONTENT_LENGTH=$(jq '.history[0].content | length' "${TEST_TEMP_DIR}/chat2.json")
CONTENT_LENGTH=$(dr_content_parts_count "${TEST_TEMP_DIR}/chat2.json" 0)
if [ "$CONTENT_LENGTH" != "3" ]; then
echo "FAIL: Expected 3 content parts (1 text + 2 images), got '${CONTENT_LENGTH}'"
exit 1
fi
# Verify third content part is also image_url
THIRD_TYPE=$(jq -r '.history[0].content[2].type' "${TEST_TEMP_DIR}/chat2.json")
THIRD_TYPE=$(dr_content_part_type "${TEST_TEMP_DIR}/chat2.json" 0 2)
if [ "$THIRD_TYPE" != "image_url" ]; then
echo "FAIL: Expected third content part type to be 'image_url', got '${THIRD_TYPE}'"
exit 1
@@ -94,13 +94,13 @@ echo "$(be_done "Response 3")" | "${DRHARNESS}" \
-m "text only prompt" 2>/dev/null
# Verify content is a string (not an array) when no images
BACKWARD_TYPE=$(jq -r '.history[0].content | type' "${TEST_TEMP_DIR}/chat3.json")
BACKWARD_TYPE=$(dr_content_type "${TEST_TEMP_DIR}/chat3.json" 0)
if [ "$BACKWARD_TYPE" != "string" ]; then
echo "FAIL: Expected content to be a string for text-only message, got '${BACKWARD_TYPE}'"
exit 1
fi
BACKWARD_CONTENT=$(jq -r '.history[0].content' "${TEST_TEMP_DIR}/chat3.json")
BACKWARD_CONTENT=$(dr_content_text "${TEST_TEMP_DIR}/chat3.json" 0)
if [ "$BACKWARD_CONTENT" != "text only prompt" ]; then
echo "FAIL: Expected text content to be 'text only prompt', got '${BACKWARD_CONTENT}'"
exit 1
@@ -116,7 +116,7 @@ echo "$(be_done "Response with tool filter")" | "${DRHARNESS}" \
-m "read and describe" 2>/dev/null
# Verify multimodal format still works with tool filter
TOOL_FILTER_TYPE=$(jq -r '.history[0].content | type' "${TEST_TEMP_DIR}/chat4.json")
TOOL_FILTER_TYPE=$(dr_content_type "${TEST_TEMP_DIR}/chat4.json" 0)
if [ "$TOOL_FILTER_TYPE" != "array" ]; then
echo "FAIL: Expected multimodal content array with -t flag, got '${TOOL_FILTER_TYPE}'"
exit 1
@@ -132,7 +132,7 @@ echo "$(be_done "Response with model override")" | "${DRHARNESS}" \
-m "test model override" 2>/dev/null
# Verify multimodal format still works with model override
MODEL_OVERRIDE_TYPE=$(jq -r '.history[0].content | type' "${TEST_TEMP_DIR}/chat5.json")
MODEL_OVERRIDE_TYPE=$(dr_content_type "${TEST_TEMP_DIR}/chat5.json" 0)
if [ "$MODEL_OVERRIDE_TYPE" != "array" ]; then
echo "FAIL: Expected multimodal content array with -M flag, got '${MODEL_OVERRIDE_TYPE}'"
exit 1