diff --git a/CHANGELOG.md b/CHANGELOG.md
index d5cef71..e602dc3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
# Changelog
+## v2.1.1 (2026-05-19)
+
+- Fixed proxy: map `developer` role to `system` for Chat Completions providers (DeepSeek, Qwen, etc.)
+- Fixed proxy: map `developer` role to `user` for Anthropic providers
+- Forward `instructions` field from Responses API as system message/param
+- Fixes "unknown variant `developer`" error from providers like DeepSeek
+
## v2.1.0 (2026-05-19)
- Added Codex auth status detection (reads `codex login status`)
diff --git a/codex-launcher_2.1.0_all.deb b/codex-launcher_2.1.0_all.deb
deleted file mode 100644
index 7bee63b..0000000
Binary files a/codex-launcher_2.1.0_all.deb and /dev/null differ
diff --git a/codex-launcher_2.1.1_all.deb b/codex-launcher_2.1.1_all.deb
new file mode 100644
index 0000000..56b06c5
Binary files /dev/null and b/codex-launcher_2.1.1_all.deb differ
diff --git a/src/codex-launcher-gui b/src/codex-launcher-gui
index 9170285..ef10be8 100755
--- a/src/codex-launcher-gui
+++ b/src/codex-launcher-gui
@@ -24,6 +24,12 @@ model_catalog_json = ""
"""
CHANGELOG = [
+ ("2.1.1", "2026-05-19", [
+ "Fixed proxy: map 'developer' role to 'system' for Chat Completions providers",
+ "Fixed proxy: map 'developer' role to 'user' for Anthropic providers",
+ "Forward 'instructions' field from Responses API as system message/param",
+ "Fixes DeepSeek and other providers rejecting unknown 'developer' role",
+ ]),
("2.1.0", "2026-05-19", [
"Added Codex auth status detection (codex login status)",
"Added Re-login button to re-authenticate via codex login",
@@ -494,7 +500,7 @@ class LauncherWin(Gtk.Window):
# header row
hdr = Gtk.Box(spacing=8)
vbox.pack_start(hdr, False, False, 0)
- lbl = Gtk.Label(label="Codex Launcher v2.1.0")
+ lbl = Gtk.Label(label="Codex Launcher v2.1.1")
lbl.set_use_markup(True)
hdr.pack_start(lbl, False, False, 0)
changelog_btn = Gtk.Button(label="Changelog")
diff --git a/src/translate-proxy.py b/src/translate-proxy.py
index 5f1d632..adb1e05 100755
--- a/src/translate-proxy.py
+++ b/src/translate-proxy.py
@@ -151,6 +151,8 @@ def oa_input_to_messages(input_data):
t = item.get("type")
if t == "message":
role = item.get("role", "user")
+ if role == "developer":
+ role = "system"
text = ""
for part in item.get("content", []):
pt = part.get("type", "")
@@ -323,6 +325,8 @@ def an_input_to_messages(input_data):
t = item.get("type")
if t == "message":
role = item.get("role", "user")
+ if role == "developer":
+ role = "user"
text = ""
for part in item.get("content", []):
pt = part.get("type", "")
@@ -532,7 +536,11 @@ class Handler(http.server.BaseHTTPRequestHandler):
def _handle_openai_compat(self, body, model, stream):
input_data = body.get("input", "")
- chat_body = {"model": model, "messages": oa_input_to_messages(input_data)}
+ messages = oa_input_to_messages(input_data)
+ instructions = body.get("instructions", "").strip()
+ if instructions:
+ messages.insert(0, {"role": "system", "content": instructions})
+ chat_body = {"model": model, "messages": messages}
for k in ("temperature", "top_p", "max_output_tokens"):
if k in body:
chat_body["max_tokens" if k == "max_output_tokens" else k] = body[k]
@@ -562,6 +570,9 @@ class Handler(http.server.BaseHTTPRequestHandler):
input_data = body.get("input", "")
an_body = {"model": model, "messages": an_input_to_messages(input_data),
"max_tokens": body.get("max_output_tokens", 8192)}
+ instructions = body.get("instructions", "").strip()
+ if instructions:
+ an_body["system"] = instructions
for k in ("temperature", "top_p"):
if k in body:
an_body[k] = body[k]