Files
galaxy/app/src/ai/openai/request_translator_tests.rs
T
Ryan Ward 5ea378a38d Add OpenAI/LiteLLM provider support with settings UI
- Add openai/ provider module with translator, client, convert, request/response translators
- Add shared provider/ types (ConversationMessage, MessageRole, ProviderConfig enum)
- Wire OpenAI-compatible provider dispatch alongside Bedrock in response_stream.rs
- Add ai.openai.* settings (enabled, base_url, api_key, model, models)
- Add OpenAI/LiteLLM settings page with model fetch, picker, and config UI
- Extend model menu items and llms.rs to surface LiteLLM models
- Update WARP.md with OpenAI provider architecture docs
2026-06-17 14:14:40 -05:00

149 lines
4.5 KiB
Rust

use serde_json::json;
use crate::ai::openai::request_translator::sanitize_messages_for_openai;
use crate::ai::provider::types::{ContentPart, ConversationMessage, MessageContent, MessageRole};
#[test]
fn test_removes_orphaned_tool_results() {
let mut messages = vec![
ConversationMessage {
role: MessageRole::User,
content: MessageContent::Text("Hello".to_string()),
},
// This tool result references a tool_use that doesn't exist
ConversationMessage {
role: MessageRole::User,
content: MessageContent::ToolResult {
tool_use_id: "nonexistent_id".to_string(),
content: "some result".to_string(),
is_error: false,
},
},
];
sanitize_messages_for_openai(&mut messages);
assert_eq!(messages.len(), 1);
matches!(&messages[0].content, MessageContent::Text(_));
}
#[test]
fn test_keeps_valid_tool_results() {
let mut messages = vec![
ConversationMessage {
role: MessageRole::Assistant,
content: MessageContent::ToolUse {
tool_use_id: "valid_id".to_string(),
name: "run_shell_command".to_string(),
input: json!({"command": "ls"}),
},
},
ConversationMessage {
role: MessageRole::User,
content: MessageContent::ToolResult {
tool_use_id: "valid_id".to_string(),
content: "file1.txt".to_string(),
is_error: false,
},
},
];
sanitize_messages_for_openai(&mut messages);
assert_eq!(messages.len(), 2);
}
#[test]
fn test_synthesizes_missing_tool_results() {
let mut messages = vec![
ConversationMessage {
role: MessageRole::Assistant,
content: MessageContent::ToolUse {
tool_use_id: "unanswered_id".to_string(),
name: "read_files".to_string(),
input: json!({"files": ["test.rs"]}),
},
},
// No corresponding tool result!
];
sanitize_messages_for_openai(&mut messages);
// Should have synthesized a tool result
assert_eq!(messages.len(), 2);
match &messages[1].content {
MessageContent::ToolResult {
tool_use_id,
is_error,
..
} => {
assert_eq!(tool_use_id, "unanswered_id");
assert!(*is_error);
}
_ => panic!("Expected ToolResult"),
}
}
#[test]
fn test_does_not_require_user_assistant_alternation() {
let mut messages = vec![
ConversationMessage {
role: MessageRole::User,
content: MessageContent::Text("First message".to_string()),
},
ConversationMessage {
role: MessageRole::User,
content: MessageContent::Text("Second message".to_string()),
},
ConversationMessage {
role: MessageRole::Assistant,
content: MessageContent::Text("Response".to_string()),
},
];
sanitize_messages_for_openai(&mut messages);
// Both user messages should remain — OpenAI allows consecutive same-role
assert_eq!(messages.len(), 3);
}
#[test]
fn test_does_not_require_starting_with_user() {
let mut messages = vec![ConversationMessage {
role: MessageRole::Assistant,
content: MessageContent::Text("I start the conversation".to_string()),
}];
sanitize_messages_for_openai(&mut messages);
// Should NOT prepend a user message (unlike Bedrock)
assert_eq!(messages.len(), 1);
assert_eq!(messages[0].role, MessageRole::Assistant);
}
#[test]
fn test_multipart_tool_uses_all_get_results() {
let mut messages = vec![ConversationMessage {
role: MessageRole::Assistant,
content: MessageContent::MultiPart(vec![
ContentPart::ToolUse {
tool_use_id: "id_1".to_string(),
name: "grep".to_string(),
input: json!({"queries": ["test"]}),
},
ContentPart::ToolUse {
tool_use_id: "id_2".to_string(),
name: "file_glob".to_string(),
input: json!({"patterns": ["*.rs"]}),
},
]),
}];
sanitize_messages_for_openai(&mut messages);
// Should synthesize results for both unanswered tool calls
assert_eq!(messages.len(), 3);
assert_eq!(messages[1].role, MessageRole::User);
assert_eq!(messages[2].role, MessageRole::User);
}