fix: OpenRouter header format, pipx install, code exec output truncation, and model config UI improvements

- Change X-OpenRouter-Categories from YAML list to comma-separated string - Add pipx to base Python installation - Truncate long lines in code execution output to 500 chars (250 from each end) before prompt detection - Reorder model config UI sections and simplify plugin config button handler - Remove border/padding from model summary grid and adjust mobile responsive styles

frdel committed Mar 19, 2026 at 16:28 UTC a7bfc7798bf1788ed74bb35b800778ea46b9c94d
4 files changed +65 -57
conf/model_providers.yaml
+1 -3
@@ -124,9 +124,7 @@ chat:
124 extra_headers:
125 "HTTP-Referer": "https://agent-zero.ai/"
126 "X-Title": "Agent Zero"
127 - "X-OpenRouter-Categories":
128 - - personal-agent
129 - - cloud-agent
127 + "X-OpenRouter-Categories": "personal-agent,cloud-agent"
128 sambanova:
129 name: Sambanova
130 litellm_provider: sambanova
docker/base/fs/ins/install_python.sh
+1 -1
@@ -55,7 +55,7 @@ pyenv install 3.12.4
55 source /opt/venv-a0/bin/activate
56
57 # upgrade pip and install static packages
58 -pip install --no-cache-dir --upgrade pip
58 +pip install --no-cache-dir --upgrade pip pipx
59
60 # Install some packages in specific variants
61 pip install --no-cache-dir \
plugins/_code_execution/tools/code_execution_tool.py
+3 -1
@@ -265,8 +265,10 @@ class CodeExecution(Tool):
265 )
266 last_lines.reverse()
267 for idx, line in enumerate(last_lines):
268 + line = line.strip()
269 + line = line if len(line) <= 500 else line[:250] + line[-250:]
270 for pat in prompt_patterns:
269 - if pat.search(line.strip()):
271 + if pat.search(line):
272 PrintStyle.info(
273 "Detected shell prompt, returning output early."
274 )
plugins/_model_config/webui/models-summary.html
+60 -52
@@ -1,4 +1,5 @@
1 <html>
2 +
3 <head>
4 <title>Model Configuration</title>
5 </head>
@@ -9,79 +10,77 @@
10 </script>
11
12 <div x-data>
12 - <template x-if="$store.modelConfig">
13 - <div>
14 - <div class="section-title">Model Configuration</div>
15 - <div class="section-description">
16 - Model settings are managed through the Model Configuration plugin, supporting per-project and per-agent overrides.
17 - </div>
18 -
19 - <div style="display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px;">
20 - <button class="btn btn-field" @click="(async () => {
21 - const pluginMeta = { name: '_model_config', always_enabled: true, per_project_config: true, per_agent_config: true, has_config_screen: true };
22 - if ($store.pluginToggle?.open) await $store.pluginToggle.open(pluginMeta);
23 - await $store.pluginSettingsPrototype.open('_model_config', { perProjectConfig: true, perAgentConfig: true });
24 - openModal('components/plugins/plugin-settings.html');
25 - })()">
26 - Configure Models
27 - </button>
28 - <button class="btn btn-field" @click="openModal('/plugins/_model_config/webui/api-keys.html')">
29 - Manage API Keys
30 - </button>
31 - </div>
32 -
33 - <!-- Read-only model config summary -->
34 - <div x-data="{ loading: true, models: [] }"
35 - x-init="
13 + <template x-if="$store.modelConfig">
14 + <div>
15 + <div class="section-title">Model Configuration</div>
16 + <div class="section-description">
17 + AI models can be configured globally, per project, per agent and using quick-switch presets as well.
18 + </div>
19 +
20 + <!-- Read-only model config summary -->
21 + <div x-data="{ loading: true, models: [] }" x-init="
22 models = await $store.modelConfig.loadModelsSummary().catch(() => []);
23 loading = false;
38 - "
39 - class="model-summary">
40 - <div class="model-summary-header">
41 - <div class="field-title">Current Models</div>
42 - <div class="field-description">Active model configuration resolved from global, project, and agent profile scopes.</div>
43 - </div>
44 - <div x-show="loading" style="text-align:center; padding:12px;">
45 - <span class="material-symbols-outlined spinning" style="font-size:18px;">progress_activity</span>
46 - </div>
47 - <template x-if="!loading && models.length">
48 - <div class="model-summary-grid">
49 - <template x-for="m in models" :key="m.title">
50 - <div class="model-summary-row">
51 - <span class="material-symbols-outlined model-summary-icon" x-text="m.icon"></span>
52 - <span class="model-summary-label" x-text="m.title"></span>
53 - <span class="model-summary-value">
54 - <span x-text="m.provider" style="opacity:0.6;"></span>
55 - <span style="opacity:0.3; margin:0 4px;">/</span>
56 - <span x-text="m.name"></span>
57 - </span>
24 + " class="model-summary">
25 + <div class="model-summary-header">
26 + <div class="field-title">Current Models</div>
27 + <div class="field-description">Active model configuration resolved from global, project, and agent profile
28 + scopes.</div>
29 + </div>
30 + <div x-show="loading" style="text-align:center; padding:12px;">
31 + <span class="material-symbols-outlined spinning" style="font-size:18px;">progress_activity</span>
32 + </div>
33 + <template x-if="!loading && models.length">
34 + <div class="model-summary-grid">
35 + <template x-for="m in models" :key="m.title">
36 + <div class="model-summary-row">
37 + <span class="material-symbols-outlined model-summary-icon" x-text="m.icon"></span>
38 + <span class="model-summary-label" x-text="m.title"></span>
39 + <span class="model-summary-value">
40 + <span x-text="m.provider" style="opacity:0.6;"></span>
41 + <span style="opacity:0.3; margin:0 4px;">/</span>
42 + <span x-text="m.name"></span>
43 + </span>
44 + </div>
45 + </template>
46 </div>
47 </template>
48 </div>
61 - </template>
62 - </div>
63 - </div>
64 - </template>
49 +
50 + <div style="display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px;">
51 + <button class="btn btn-field" @click="$store.pluginListStore.openPluginConfig('_model_config')">
52 + Configure Models
53 + </button>
54 + <button class="btn btn-field" @click="openModal('/plugins/_model_config/webui/api-keys.html')">
55 + Manage API Keys
56 + </button>
57 + </div>
58 +
59 + </div>
60 + </template>
61 </div>
62
63 <style>
64 .model-summary {
65 margin-top: 14px;
66 }
67 +
68 .model-summary-header {
69 margin-bottom: 8px;
70 }
71 +
72 .model-summary-grid {
73 display: flex;
74 flex-direction: column;
75 background: var(--color-input);
78 - border: 1px solid var(--color-border);
79 - border-radius: 8px;
80 - padding: 0.75em 1em;
76 + /* border: 1px solid var(--color-border);
77 + border-radius: 8px; */
78 + /* padding: 0.75em 1em; */
79 max-width: 100%;
80 overflow: hidden;
81 box-sizing: border-box;
82 }
83 +
84 .model-summary-row {
85 display: flex;
86 align-items: center;
@@ -90,20 +89,24 @@
89 font-size: 0.82rem;
90 min-width: 0;
91 }
92 +
93 .model-summary-row:not(:last-child) {
94 border-bottom: 1px solid var(--color-border);
95 }
96 +
97 .model-summary-icon {
98 font-size: 16px;
99 opacity: 0.45;
100 flex-shrink: 0;
101 }
102 +
103 .model-summary-label {
104 width: 80px;
105 flex-shrink: 0;
106 font-weight: 500;
107 opacity: 0.7;
108 }
109 +
110 .model-summary-value {
111 flex: 1;
112 min-width: 0;
@@ -111,18 +114,22 @@
114 text-overflow: ellipsis;
115 white-space: nowrap;
116 }
117 +
118 @media (max-width: 600px) {
119 .model-summary-grid {
120 padding: 0.5em 0.5em;
121 }
122 +
123 .model-summary-row {
124 flex-wrap: wrap;
125 padding: 8px 8px;
126 gap: 4px;
127 }
128 +
129 .model-summary-label {
130 width: auto;
131 }
132 +
133 .model-summary-value {
134 width: 100%;
135 flex-basis: 100%;
@@ -134,4 +141,5 @@
141 }
142 </style>
143 </body>
137 -</html>
144 +
145 +</html>
\ No newline at end of file