From ffd90ce7fb605a13a7d027f7b1c4dc8e1af1d88a Mon Sep 17 00:00:00 2001 From: Gahow Wang Date: Sun, 31 May 2026 00:56:39 +0800 Subject: [PATCH] server: emit harmony developer instructions block for gpt-oss Route caller-supplied system messages into a harmony 'developer' instructions block (<|start|>developer<|message|># Instructions...), keeping the fixed system/meta block for the channel declaration. Harmony puts user instructions on the developer role, not system. Co-Authored-By: Claude Opus 4.8 --- crates/xserv-server/src/api.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/crates/xserv-server/src/api.rs b/crates/xserv-server/src/api.rs index 00e3557..6a17d33 100644 --- a/crates/xserv-server/src/api.rs +++ b/crates/xserv-server/src/api.rs @@ -350,10 +350,23 @@ fn build_prompt(messages: &[Message], model_type: &str) -> String { fn build_prompt_gpt_oss(messages: &[Message]) -> String { let mut prompt = String::new(); - // System prompt + // System (meta) block: channel declaration required by harmony. prompt.push_str("<|start|>system<|message|>"); prompt.push_str("You are a helpful assistant.\n\n# Valid channels: analysis, commentary, final. Channel must be included for every message."); prompt.push_str("<|end|>"); + // Caller-supplied system prompt(s) go in a developer instructions block + // (harmony puts user instructions on the `developer` role, not `system`). + let dev_instructions: String = messages + .iter() + .filter(|m| m.role == "system") + .map(|m| m.content.as_str()) + .collect::>() + .join("\n\n"); + if !dev_instructions.is_empty() { + prompt.push_str("<|start|>developer<|message|># Instructions\n\n"); + prompt.push_str(&dev_instructions); + prompt.push_str("<|end|>"); + } for msg in messages { match msg.role.as_str() { "user" => {