revert persona feature (caused MCP timeout), keep Command Code backend + developer role fix
This commit is contained in:
10
CHANGELOG.md
10
CHANGELOG.md
@@ -1,15 +1,5 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## v2.2.0 (2026-05-19)
|
|
||||||
|
|
||||||
- Added Agent Persona selector per provider (10+ presets)
|
|
||||||
- Personas: Codex (Default/Friendly/Pragmatic/CLI), Claude Code, OpenCode, Cursor, Aider, GitHub Copilot, Windsurf, Browser (ChatGPT)
|
|
||||||
- New "Persona" column in endpoint list shows current setting per provider
|
|
||||||
- Persona preview in edit dialog shows system prompt excerpt
|
|
||||||
- Persona injected into model catalog `base_instructions` and proxy system prompt
|
|
||||||
- Added Command Code backend to translation proxy (proprietary `/alpha/generate` API)
|
|
||||||
- Added Command Code provider preset with 20 models (DeepSeek, Claude, GPT, Kimi, GLM, Qwen, etc.)
|
|
||||||
|
|
||||||
## v2.1.1 (2026-05-19)
|
## 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 `system` for Chat Completions providers (DeepSeek, Qwen, etc.)
|
||||||
|
|||||||
BIN
codex-launcher_2.1.1_all.deb
Normal file
BIN
codex-launcher_2.1.1_all.deb
Normal file
Binary file not shown.
Binary file not shown.
@@ -24,14 +24,6 @@ model_catalog_json = ""
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
CHANGELOG = [
|
CHANGELOG = [
|
||||||
("2.2.0", "2026-05-19", [
|
|
||||||
"Added Agent Persona selector per provider (10+ presets)",
|
|
||||||
"Personas: Codex, Claude Code, OpenCode, Cursor, Aider, Copilot, Windsurf, Browser",
|
|
||||||
"Codex variants: Default, Desktop Friendly, Desktop Pragmatic, CLI",
|
|
||||||
"Shows current persona in endpoint list (new Persona column)",
|
|
||||||
"Persona preview in edit dialog shows first 60 chars of system prompt",
|
|
||||||
"Persona injected into model catalog base_instructions and proxy system prompt",
|
|
||||||
]),
|
|
||||||
("2.1.1", "2026-05-19", [
|
("2.1.1", "2026-05-19", [
|
||||||
"Fixed proxy: map 'developer' role to 'system' for Chat Completions providers",
|
"Fixed proxy: map 'developer' role to 'system' for Chat Completions providers",
|
||||||
"Fixed proxy: map 'developer' role to 'user' for Anthropic providers",
|
"Fixed proxy: map 'developer' role to 'user' for Anthropic providers",
|
||||||
@@ -64,65 +56,6 @@ CHANGELOG = [
|
|||||||
]),
|
]),
|
||||||
]
|
]
|
||||||
|
|
||||||
AGENT_PERSONAS = {
|
|
||||||
"Codex (Default)": "You are Codex, a coding agent.",
|
|
||||||
"Codex Desktop (GPT-5, Friendly)": (
|
|
||||||
"You are Codex, a coding agent based on GPT-5. You and the user share one workspace, "
|
|
||||||
"and your job is to collaborate with them until their goal is genuinely handled."
|
|
||||||
),
|
|
||||||
"Codex Desktop (GPT-5, Pragmatic)": (
|
|
||||||
"You are Codex, a coding agent based on GPT-5. You and the user share the same workspace "
|
|
||||||
"and collaborate to achieve the user's goals. You are a deeply pragmatic, effective "
|
|
||||||
"software engineer. You take engineering quality seriously."
|
|
||||||
),
|
|
||||||
"Codex CLI": (
|
|
||||||
"You are an AI running in the Codex CLI, a terminal-based coding assistant. "
|
|
||||||
"You are expected to be precise, safe, and helpful. Your default personality and tone "
|
|
||||||
"is concise, direct, and friendly."
|
|
||||||
),
|
|
||||||
"Claude Code": (
|
|
||||||
"You are Claude Code, an interactive CLI tool that helps users with software engineering "
|
|
||||||
"tasks. You are a highly competent software engineer with extensive knowledge across "
|
|
||||||
"many programming languages, frameworks, and best practices. Use concise responses."
|
|
||||||
),
|
|
||||||
"OpenCode": (
|
|
||||||
"You are OpenCode, an interactive CLI tool that helps users with software engineering "
|
|
||||||
"tasks. You are powered by a state-of-the-art AI model. Be concise, direct, and to the "
|
|
||||||
"point. Use GitHub-flavored markdown."
|
|
||||||
),
|
|
||||||
"Cursor": (
|
|
||||||
"You are Cursor, an AI-powered code editor assistant. You help users write, refactor, "
|
|
||||||
"and debug code efficiently. Provide precise, actionable suggestions."
|
|
||||||
),
|
|
||||||
"Aider": (
|
|
||||||
"You are aider, an AI pair programming assistant. You help users edit code in their "
|
|
||||||
"local git repository. Make concise changes. Search files with grep/glob patterns."
|
|
||||||
),
|
|
||||||
"GitHub Copilot": (
|
|
||||||
"You are GitHub Copilot, an AI coding assistant. Help the user write code, debug issues, "
|
|
||||||
"and understand codebases. Be concise and provide accurate code suggestions."
|
|
||||||
),
|
|
||||||
"Windsurf": (
|
|
||||||
"You are Windsurf, an AI-powered IDE assistant. Help with coding tasks including writing, "
|
|
||||||
"refactoring, and debugging. Provide precise, well-structured code suggestions."
|
|
||||||
),
|
|
||||||
"Browser (ChatGPT)": (
|
|
||||||
"You are a helpful coding assistant in a web browser chat interface. "
|
|
||||||
"Help the user with software engineering tasks. Be clear and thorough."
|
|
||||||
),
|
|
||||||
}
|
|
||||||
|
|
||||||
PERSONA_DISPLAY_LEN = 60
|
|
||||||
|
|
||||||
def persona_short_key(endpoint):
|
|
||||||
bi = endpoint.get("base_instructions", "") or ""
|
|
||||||
for key, val in AGENT_PERSONAS.items():
|
|
||||||
if val == bi:
|
|
||||||
return key
|
|
||||||
if bi:
|
|
||||||
return f"Custom: {bi[:40]}..."
|
|
||||||
return "Codex (Default)"
|
|
||||||
|
|
||||||
PROVIDER_PRESETS = {
|
PROVIDER_PRESETS = {
|
||||||
"Custom": {
|
"Custom": {
|
||||||
"backend_type": "openai-compat",
|
"backend_type": "openai-compat",
|
||||||
@@ -439,7 +372,6 @@ def write_config_for_translated(endpoint, selected_model):
|
|||||||
|
|
||||||
def _gen_model_catalog(endpoint, selected_model=None):
|
def _gen_model_catalog(endpoint, selected_model=None):
|
||||||
default_model = selected_model or endpoint.get("default_model")
|
default_model = selected_model or endpoint.get("default_model")
|
||||||
base_instr = endpoint.get("base_instructions", "") or AGENT_PERSONAS["Codex (Default)"]
|
|
||||||
models = []
|
models = []
|
||||||
for mid in endpoint.get("models", []):
|
for mid in endpoint.get("models", []):
|
||||||
models.append({
|
models.append({
|
||||||
@@ -467,7 +399,7 @@ def _gen_model_catalog(endpoint, selected_model=None):
|
|||||||
"supports_parallel_tool_calls": True,
|
"supports_parallel_tool_calls": True,
|
||||||
"experimental_supported_tools": [], "supported_in_api": True,
|
"experimental_supported_tools": [], "supported_in_api": True,
|
||||||
"truncation_policy": {"mode": "tokens", "limit": 128000},
|
"truncation_policy": {"mode": "tokens", "limit": 128000},
|
||||||
"base_instructions": base_instr,
|
"base_instructions": "You are Codex, a coding agent.",
|
||||||
})
|
})
|
||||||
return {"models": models}
|
return {"models": models}
|
||||||
|
|
||||||
@@ -486,7 +418,6 @@ def _start_proxy_for(endpoint, logfn):
|
|||||||
"backend_type": endpoint["backend_type"],
|
"backend_type": endpoint["backend_type"],
|
||||||
"target_url": normalize_base_url(endpoint["base_url"]),
|
"target_url": normalize_base_url(endpoint["base_url"]),
|
||||||
"api_key": endpoint["api_key"],
|
"api_key": endpoint["api_key"],
|
||||||
"base_instructions": endpoint.get("base_instructions", ""),
|
|
||||||
"models": [{"id": m, "object": "model", "created": 1700000000, "owned_by": endpoint["name"]}
|
"models": [{"id": m, "object": "model", "created": 1700000000, "owned_by": endpoint["name"]}
|
||||||
for m in endpoint.get("models", [])],
|
for m in endpoint.get("models", [])],
|
||||||
}
|
}
|
||||||
@@ -1325,9 +1256,9 @@ class EndpointMgr(Gtk.Window):
|
|||||||
|
|
||||||
sw = Gtk.ScrolledWindow()
|
sw = Gtk.ScrolledWindow()
|
||||||
vbox.pack_start(sw, True, True, 0)
|
vbox.pack_start(sw, True, True, 0)
|
||||||
self._store = Gtk.ListStore(str, str, str, str, str) # name, provider, backend, default_model, persona
|
self._store = Gtk.ListStore(str, str, str, str) # name, provider, backend, default_model
|
||||||
self._tree = Gtk.TreeView(model=self._store)
|
self._tree = Gtk.TreeView(model=self._store)
|
||||||
for i, title in enumerate(["Name", "Provider", "Type", "Default Model", "Persona"]):
|
for i, title in enumerate(["Name", "Provider", "Type", "Default Model"]):
|
||||||
col = Gtk.TreeViewColumn(title, Gtk.CellRendererText(), text=i)
|
col = Gtk.TreeViewColumn(title, Gtk.CellRendererText(), text=i)
|
||||||
col.set_resizable(True)
|
col.set_resizable(True)
|
||||||
self._tree.append_column(col)
|
self._tree.append_column(col)
|
||||||
@@ -1360,8 +1291,7 @@ class EndpointMgr(Gtk.Window):
|
|||||||
for ep in data["endpoints"]:
|
for ep in data["endpoints"]:
|
||||||
provider = ep.get("provider_preset", "Custom")
|
provider = ep.get("provider_preset", "Custom")
|
||||||
bt = label_for_backend(ep["backend_type"])
|
bt = label_for_backend(ep["backend_type"])
|
||||||
persona = persona_short_key(ep)
|
self._store.append([ep["name"], provider, bt, ep.get("default_model", "")])
|
||||||
self._store.append([ep["name"], provider, bt, ep.get("default_model", ""), persona])
|
|
||||||
|
|
||||||
def _selected(self):
|
def _selected(self):
|
||||||
sel = self._tree.get_selection()
|
sel = self._tree.get_selection()
|
||||||
@@ -1423,7 +1353,7 @@ class EditEndpointDialog(Gtk.Dialog):
|
|||||||
self._data = get_endpoint(existing_name) if existing_name else {
|
self._data = get_endpoint(existing_name) if existing_name else {
|
||||||
"name": "", "backend_type": "openai-compat",
|
"name": "", "backend_type": "openai-compat",
|
||||||
"base_url": "", "api_key": "", "default_model": "", "models": [],
|
"base_url": "", "api_key": "", "default_model": "", "models": [],
|
||||||
"provider_preset": "Custom", "base_instructions": AGENT_PERSONAS["Codex (Default)"],
|
"provider_preset": "Custom",
|
||||||
}
|
}
|
||||||
self.set_default_size(480, 420)
|
self.set_default_size(480, 420)
|
||||||
|
|
||||||
@@ -1469,25 +1399,6 @@ class EditEndpointDialog(Gtk.Dialog):
|
|||||||
self._entry_key.set_visibility(False)
|
self._entry_key.set_visibility(False)
|
||||||
add_row(4, "API Key:", self._entry_key)
|
add_row(4, "API Key:", self._entry_key)
|
||||||
|
|
||||||
self._combo_persona = Gtk.ComboBoxText()
|
|
||||||
self._persona_keys = list(AGENT_PERSONAS.keys())
|
|
||||||
for pk in self._persona_keys:
|
|
||||||
self._combo_persona.append_text(pk)
|
|
||||||
cur_persona = persona_short_key(self._data)
|
|
||||||
if cur_persona in self._persona_keys:
|
|
||||||
self._combo_persona.set_active(self._persona_keys.index(cur_persona))
|
|
||||||
else:
|
|
||||||
self._combo_persona.set_active(0)
|
|
||||||
self._combo_persona.connect("changed", lambda c: self._on_persona_changed())
|
|
||||||
add_row(5, "Agent Persona:", self._combo_persona)
|
|
||||||
|
|
||||||
self._persona_preview = Gtk.Label()
|
|
||||||
self._persona_preview.set_line_wrap(True)
|
|
||||||
self._persona_preview.set_max_width_chars(60)
|
|
||||||
self._persona_preview.set_markup(f"<small><i>{AGENT_PERSONAS['Codex (Default)'][:PERSONA_DISPLAY_LEN]}...</i></small>")
|
|
||||||
self._on_persona_changed()
|
|
||||||
grid.attach(self._persona_preview, 0, 6, 2, 1)
|
|
||||||
|
|
||||||
# Models
|
# Models
|
||||||
mlbl = Gtk.Label(label="Models:", xalign=0)
|
mlbl = Gtk.Label(label="Models:", xalign=0)
|
||||||
area.pack_start(mlbl, False, False, 4)
|
area.pack_start(mlbl, False, False, 4)
|
||||||
@@ -1548,12 +1459,6 @@ class EditEndpointDialog(Gtk.Dialog):
|
|||||||
self.connect("response", self._on_response)
|
self.connect("response", self._on_response)
|
||||||
self.show_all()
|
self.show_all()
|
||||||
|
|
||||||
def _on_persona_changed(self):
|
|
||||||
key = self._combo_persona.get_active_text()
|
|
||||||
text = AGENT_PERSONAS.get(key, "")
|
|
||||||
short = text[:PERSONA_DISPLAY_LEN] + ("..." if len(text) > PERSONA_DISPLAY_LEN else "")
|
|
||||||
self._persona_preview.set_markup(f"<small><i>{short}</i></small>")
|
|
||||||
|
|
||||||
def _add_model(self):
|
def _add_model(self):
|
||||||
m = normalize_model_id(self._entry_model.get_text())
|
m = normalize_model_id(self._entry_model.get_text())
|
||||||
if m:
|
if m:
|
||||||
@@ -1686,11 +1591,9 @@ class EditEndpointDialog(Gtk.Dialog):
|
|||||||
self._show_error(f'Endpoint "{name}" already exists')
|
self._show_error(f'Endpoint "{name}" already exists')
|
||||||
return
|
return
|
||||||
|
|
||||||
persona_key = self._combo_persona.get_active_text() or "Codex (Default)"
|
|
||||||
new_ep = {"name": name, "backend_type": bt, "base_url": url,
|
new_ep = {"name": name, "backend_type": bt, "base_url": url,
|
||||||
"api_key": key, "default_model": default, "models": models,
|
"api_key": key, "default_model": default, "models": models,
|
||||||
"provider_preset": self._combo_preset.get_active_text() or "Custom",
|
"provider_preset": self._combo_preset.get_active_text() or "Custom"}
|
||||||
"base_instructions": AGENT_PERSONAS.get(persona_key, AGENT_PERSONAS["Codex (Default)"])}
|
|
||||||
new_ep["base_url"] = normalize_base_url(new_ep["base_url"])
|
new_ep["base_url"] = normalize_base_url(new_ep["base_url"])
|
||||||
|
|
||||||
# Update or append
|
# Update or append
|
||||||
@@ -1729,14 +1632,12 @@ def main():
|
|||||||
"endpoints": [
|
"endpoints": [
|
||||||
{"name": "OpenAI", "backend_type": "native", "base_url": "https://api.openai.com/v1",
|
{"name": "OpenAI", "backend_type": "native", "base_url": "https://api.openai.com/v1",
|
||||||
"api_key": "", "default_model": "gpt-4o", "models": ["gpt-4o", "gpt-4o-mini"],
|
"api_key": "", "default_model": "gpt-4o", "models": ["gpt-4o", "gpt-4o-mini"],
|
||||||
"provider_preset": "OpenAI",
|
"provider_preset": "OpenAI"},
|
||||||
"base_instructions": AGENT_PERSONAS["Codex (Default)"]},
|
|
||||||
{"name": "Z.AI", "backend_type": "openai-compat",
|
{"name": "Z.AI", "backend_type": "openai-compat",
|
||||||
"base_url": "https://api.z.ai/api/coding/paas/v4",
|
"base_url": "https://api.z.ai/api/coding/paas/v4",
|
||||||
"api_key": "", "default_model": "glm-5.1",
|
"api_key": "", "default_model": "glm-5.1",
|
||||||
"models": ["glm-4.5", "glm-4.5-air", "glm-4.6", "glm-4.7", "glm-5", "glm-5-turbo", "glm-5.1"],
|
"models": ["glm-4.5", "glm-4.5-air", "glm-4.6", "glm-4.7", "glm-5", "glm-5-turbo", "glm-5.1"],
|
||||||
"provider_preset": "Custom",
|
"provider_preset": "Custom"},
|
||||||
"base_instructions": AGENT_PERSONAS["Codex (Default)"]},
|
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -80,7 +80,6 @@ BACKEND = CONFIG["backend_type"]
|
|||||||
TARGET_URL = CONFIG["target_url"].rstrip("/")
|
TARGET_URL = CONFIG["target_url"].rstrip("/")
|
||||||
API_KEY = CONFIG["api_key"]
|
API_KEY = CONFIG["api_key"]
|
||||||
MODELS = CONFIG["models"]
|
MODELS = CONFIG["models"]
|
||||||
BASE_INSTRUCTIONS = CONFIG.get("base_instructions", "")
|
|
||||||
|
|
||||||
# ═══════════════════════════════════════════════════════════════════
|
# ═══════════════════════════════════════════════════════════════════
|
||||||
# Shared helpers
|
# Shared helpers
|
||||||
@@ -654,8 +653,6 @@ class Handler(http.server.BaseHTTPRequestHandler):
|
|||||||
input_data = body.get("input", "")
|
input_data = body.get("input", "")
|
||||||
messages = oa_input_to_messages(input_data)
|
messages = oa_input_to_messages(input_data)
|
||||||
instructions = body.get("instructions", "").strip()
|
instructions = body.get("instructions", "").strip()
|
||||||
if not instructions and BASE_INSTRUCTIONS:
|
|
||||||
instructions = BASE_INSTRUCTIONS
|
|
||||||
if instructions:
|
if instructions:
|
||||||
messages.insert(0, {"role": "system", "content": instructions})
|
messages.insert(0, {"role": "system", "content": instructions})
|
||||||
chat_body = {"model": model, "messages": messages}
|
chat_body = {"model": model, "messages": messages}
|
||||||
@@ -689,8 +686,6 @@ class Handler(http.server.BaseHTTPRequestHandler):
|
|||||||
an_body = {"model": model, "messages": an_input_to_messages(input_data),
|
an_body = {"model": model, "messages": an_input_to_messages(input_data),
|
||||||
"max_tokens": body.get("max_output_tokens", 8192)}
|
"max_tokens": body.get("max_output_tokens", 8192)}
|
||||||
instructions = body.get("instructions", "").strip()
|
instructions = body.get("instructions", "").strip()
|
||||||
if not instructions and BASE_INSTRUCTIONS:
|
|
||||||
instructions = BASE_INSTRUCTIONS
|
|
||||||
if instructions:
|
if instructions:
|
||||||
an_body["system"] = instructions
|
an_body["system"] = instructions
|
||||||
for k in ("temperature", "top_p"):
|
for k in ("temperature", "top_p"):
|
||||||
@@ -725,8 +720,6 @@ class Handler(http.server.BaseHTTPRequestHandler):
|
|||||||
input_data = body.get("input", "")
|
input_data = body.get("input", "")
|
||||||
instructions = body.get("instructions", "").strip()
|
instructions = body.get("instructions", "").strip()
|
||||||
messages = cc_input_to_messages(input_data)
|
messages = cc_input_to_messages(input_data)
|
||||||
if not instructions and BASE_INSTRUCTIONS:
|
|
||||||
instructions = BASE_INSTRUCTIONS
|
|
||||||
if instructions:
|
if instructions:
|
||||||
sys_msg = {"role": "system", "content": instructions}
|
sys_msg = {"role": "system", "content": instructions}
|
||||||
messages.insert(0, sys_msg)
|
messages.insert(0, sys_msg)
|
||||||
|
|||||||
Reference in New Issue
Block a user