mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-27 21:08:00 +00:00
Co-authored-by: Steven Enamakel <enamakel@tinyhumans.ai>
This commit is contained in:
co-authored by
Steven Enamakel
parent
e4666f9be4
commit
eb80d249c6
@@ -245,10 +245,18 @@ pub(crate) fn build_responses_prompt(
|
||||
continue;
|
||||
}
|
||||
|
||||
// Key the content-part kind on the NORMALIZED role, not the raw one.
|
||||
// `normalize_responses_role` folds `tool` (and any non-user role) into
|
||||
// `assistant`; the Responses API only accepts `output_text`/`refusal`
|
||||
// for assistant items, so the kind must track the same normalized value.
|
||||
// Reading `message.role` here instead let a `tool` turn become an
|
||||
// assistant item carrying `input_text`, which OpenAI rejects with
|
||||
// "Invalid value: 'input_text'" (Sentry TAURI-RUST-8FQ / GH #3624).
|
||||
let role = normalize_responses_role(&message.role);
|
||||
input.push(ResponsesInput {
|
||||
role: normalize_responses_role(&message.role).to_string(),
|
||||
role: role.to_string(),
|
||||
content: vec![ResponsesContentPart {
|
||||
kind: if message.role == "assistant" {
|
||||
kind: if role == "assistant" {
|
||||
"output_text".to_string()
|
||||
} else {
|
||||
"input_text".to_string()
|
||||
|
||||
@@ -862,14 +862,47 @@ fn build_responses_prompt_preserves_multi_turn_history() {
|
||||
assert_eq!(input[1].role, "assistant");
|
||||
assert_eq!(input[1].content[0].kind, "output_text");
|
||||
assert_eq!(input[1].content[0].text, "ack 1");
|
||||
// A `tool` turn normalizes to the `assistant` role, so its content part
|
||||
// MUST be `output_text` — the Responses API rejects `input_text` on an
|
||||
// assistant item (Sentry TAURI-RUST-8FQ / GH #3624).
|
||||
assert_eq!(input[2].role, "assistant");
|
||||
assert_eq!(input[2].content[0].kind, "input_text");
|
||||
assert_eq!(input[2].content[0].kind, "output_text");
|
||||
assert_eq!(input[2].content[0].text, "{\"result\":\"ok\"}");
|
||||
assert_eq!(input[3].role, "user");
|
||||
assert_eq!(input[3].content[0].kind, "input_text");
|
||||
assert_eq!(input[3].content[0].text, "step 2");
|
||||
}
|
||||
|
||||
/// Regression for Sentry TAURI-RUST-8FQ / GH #3624: the Responses API only
|
||||
/// accepts `output_text`/`refusal` for assistant items. `normalize_responses_role`
|
||||
/// folds `tool` into `assistant`, so the content kind must follow the normalized
|
||||
/// role — never the raw one. No assistant-role item may carry `input_text`.
|
||||
#[test]
|
||||
fn build_responses_prompt_tool_role_uses_output_text() {
|
||||
let messages = vec![
|
||||
ChatMessage::assistant("calling a tool"),
|
||||
ChatMessage::tool("{\"result\":\"ok\"}"),
|
||||
ChatMessage::user("thanks"),
|
||||
];
|
||||
|
||||
let (_instructions, input) = build_responses_prompt(&messages);
|
||||
|
||||
// The tool turn folds to assistant and must carry output_text.
|
||||
assert_eq!(input[1].role, "assistant");
|
||||
assert_eq!(input[1].content[0].kind, "output_text");
|
||||
|
||||
// Invariant: an assistant-role item never carries input_text.
|
||||
for item in &input {
|
||||
if item.role == "assistant" {
|
||||
assert_eq!(
|
||||
item.content[0].kind, "output_text",
|
||||
"assistant-role item must use output_text, got {}",
|
||||
item.content[0].kind
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn chat_via_responses_requires_non_system_message() {
|
||||
let provider = make_provider("custom", "https://api.example.com", Some("test-key"));
|
||||
|
||||
Reference in New Issue
Block a user