diff --git a/crates/hermesllm/src/apis/openai_responses.rs b/crates/hermesllm/src/apis/openai_responses.rs index a0b9f46a..33dea44a 100644 --- a/crates/hermesllm/src/apis/openai_responses.rs +++ b/crates/hermesllm/src/apis/openai_responses.rs @@ -107,14 +107,35 @@ pub struct ResponsesAPIRequest { pub top_logprobs: Option, } -/// Input parameter - can be a simple string or array of input messages +/// Input parameter - can be a simple string or array of input items #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] pub enum InputParam { /// Simple text input Text(String), - /// Array of input messages - Items(Vec), + /// Array of input items (messages, references, outputs, etc.) + Items(Vec), +} + +/// Input item - can be a message, item reference, function call output, etc. +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum InputItem { + /// Input message (role + content) + Message(InputMessage), + /// Item reference + ItemReference { + #[serde(rename = "type")] + item_type: String, + id: String, + }, + /// Function call output + FunctionCallOutput { + #[serde(rename = "type")] + item_type: String, + call_id: String, + output: String, + }, } /// Input message with role and content @@ -993,8 +1014,8 @@ pub struct ListInputItemsRequest { pub struct ListInputItemsResponse { /// Object type - always "list" pub object: String, - /// Array of input messages - pub data: Vec, + /// Array of input items + pub data: Vec, /// First ID in the list pub first_id: Option, /// Last ID in the list @@ -1024,8 +1045,10 @@ impl ProviderRequest for ResponsesAPIRequest { match &self.input { InputParam::Text(text) => text.clone(), InputParam::Items(items) => { - items.iter().fold(String::new(), |acc, msg| { - let content_text = match &msg.content { + items.iter().fold(String::new(), |acc, item| { + match item { + InputItem::Message(msg) => { + let content_text = match &msg.content { MessageContent::Text(text) => text.clone(), MessageContent::Items(content_items) => { content_items.iter().fold(String::new(), |acc, content| { @@ -1039,6 +1062,10 @@ impl ProviderRequest for ResponsesAPIRequest { } }; acc + " " + &content_text + } + // Skip non-message items (references, outputs, etc.) + _ => acc, + } }) } } @@ -1048,10 +1075,11 @@ impl ProviderRequest for ResponsesAPIRequest { match &self.input { InputParam::Text(text) => Some(text.clone()), InputParam::Items(items) => { - items.iter().rev().find_map(|msg| { - if matches!(msg.role, MessageRole::User) { - // Extract text from content - match &msg.content { + items.iter().rev().find_map(|item| { + match item { + InputItem::Message(msg) if matches!(msg.role, MessageRole::User) => { + // Extract text from content + match &msg.content { MessageContent::Text(text) => Some(text.clone()), MessageContent::Items(content_items) => { content_items.iter().find_map(|content| { @@ -1062,8 +1090,9 @@ impl ProviderRequest for ResponsesAPIRequest { }) } } - } else { - None + } + // Skip non-message items + _ => None, } }) } diff --git a/crates/hermesllm/src/transforms/request/from_openai.rs b/crates/hermesllm/src/transforms/request/from_openai.rs index 9607565f..27366f4d 100644 --- a/crates/hermesllm/src/transforms/request/from_openai.rs +++ b/crates/hermesllm/src/transforms/request/from_openai.rs @@ -14,7 +14,7 @@ use crate::apis::openai::{ }; use crate::apis::openai_responses::{ - ResponsesAPIRequest, InputContent, InputParam, MessageRole, Modality, ReasoningEffort, Tool as ResponsesTool, ToolChoice as ResponsesToolChoice + ResponsesAPIRequest, InputContent, InputItem, InputParam, MessageRole, Modality, ReasoningEffort, Tool as ResponsesTool, ToolChoice as ResponsesToolChoice }; use crate::clients::TransformError; use crate::transforms::lib::ExtractText; @@ -280,9 +280,11 @@ impl TryFrom for ChatCompletionsRequest { }); } - // Convert each input message - for input_msg in items { - let role = match input_msg.role { + // Convert each input item + for item in items { + match item { + InputItem::Message(input_msg) => { + let role = match input_msg.role { MessageRole::User => Role::User, MessageRole::Assistant => Role::Assistant, MessageRole::System => Role::System, @@ -354,6 +356,11 @@ impl TryFrom for ChatCompletionsRequest { tool_call_id: None, tool_calls: None, }); + } + // Skip non-message items (references, outputs) for now + // These would need special handling in chat completions format + _ => {} + } } converted_messages