Multi-Agent Tenant Upgrade
by @maverick-software
Multi-agent UX for OpenClaw Control UI — agent selector, per-agent sessions, session history viewer with search, agent-filtered Sessions tab with friendly na...
clawhub install multi-agent-tenant-upgrade📖 About This Skill
name: agent-chat-ux version: 1.5.2 author: Charles Sears description: "Multi-agent UX for OpenClaw Control UI — agent selector, per-agent sessions, session history viewer with search, agent-filtered Sessions tab with friendly names, Create Agent wizard, emoji picker, backend agent CRUD, and auth mode badge."
agent-chat-ux
name: agent-chat-ux version: 1.5.2 author: Charles Sears description: Multi-agent UX for OpenClaw Control UI — agent selector, per-agent sessions, session history viewer with search, agent-filtered Sessions tab with friendly names, Create Agent wizard, emoji picker, and backend agent CRUD.
⚠️ Security & Transparency Notes
Before applying this skill's patches, be aware of the following:
Credential Access (agents.wizard)
The AI Wizard backend (agents.wizard RPC) calls the configured model provider API directly via HTTP. To do this it needs an API key. It resolves credentials in this exact order:
1. Default config auth — uses it if the resolved mode is api-key (most common)
2. Auth profile store — searches for the first api_key-type profile matching the provider. Reads only provider and type fields to find it; does not log or return values.
3. Environment variable — ANTHROPIC_API_KEY or OPENAI_API_KEY as a last resort
> If you don't want the wizard reading your auth store, set ANTHROPIC_API_KEY in your environment and ensure your default auth profile is already api-key mode — step 2 is skipped entirely in that case.
External API Calls
agents.wizard makes a single HTTP POST to:
https://api.anthropic.com/v1/messages (Anthropic models)https://api.openai.com/v1/chat/completions (OpenAI-compatible models)No other outbound calls. The call carries your user-supplied description and nothing else from your system.
Patch Scope
These patches modify only agent-related files:
| Patch | File modified | What it changes |
|---|---|---|
| schema-agents.txt | src/gateway/protocol/schema/agents-models-skills.ts | Adds emoji optional param to AgentsUpdateParamsSchema |
| server-agents.txt | src/gateway/server-methods/agents.ts | Adds agents.wizard RPC; fixes agents.update to write - Emoji: (not - Avatar:) so emoji edits persist correctly |
| app-main.txt | ui/src/ui/app.ts | Adds 19 @state() fields: 10 for Create Agent/Wizard + 9 for edit agent, delete agent |
| app-render.txt | ui/src/ui/app-render.ts | Wires create/wizard props + edit agent save handler (sends emoji param, not avatar; evicts identity cache after save) |
| app-render-helpers.txt | ui/src/ui/app-render.helpers.ts | Agent selector dropdown in chat header (uses resolveAgentEmoji() for correct emoji), per-agent session filter, + New Session button |
| agents-view.txt | ui/src/ui/views/agents.ts | Create Agent panel (manual + wizard modes, 103-emoji picker); Edit agent inline form (name/emoji/workspace); Delete agent with confirmation; always-editable Overview |
| agents-utils.txt | ui/src/ui/views/agents-utils.ts | buildModelOptionsMulti() for multi-select fallback dropdown |
| agents-panels-cron.txt | ui/src/ui/views/agents-panels-status-files.ts | Cron Jobs tab Scheduler card now shows agent-specific job count and next-wake (not global gateway stats) |
Each patch is scoped to a single concern. If any patch file modifies more than the files listed above, stop — you have an outdated copy.
LLM Output Validation
Wizard model output is parsed as JSON and validated before use:
name (string), emoji (string), soul (string)name is capped at 100 characters, emoji at 10soul must be ≥ 20 charactersSource Code Modification
This skill applies git apply patches against ~/openclaw and requires a UI + gateway rebuild. Changes are persistent. Always backup before patching:
cd ~/openclaw && git stash # or git branch backup/pre-agent-ux
What This Skill Adds
1. Agent Selector Dropdown in Chat Header
When multiple agents are configured, a dropdown appears left of the session dropdown in the chat header. Selecting an agent switches to that agent's most recent session (or falls back to a fresh webchat key for that agent). The session dropdown automatically filters to show only sessions belonging to the selected agent.2. Per-Agent Session Filtering (Sorted Newest First)
Sessions are now scoped to the active agent and sorted newest-first. No more mixing other agents' cron jobs and subagent sessions into the current chat's session picker.3. + New Session Button in Chat Header
A+ icon button sits right of the session dropdown, allowing new sessions to be started without typing /new.4. Create Agent Panel (Manual + AI Wizard)
The Agents tab gains a + Create Agent button that expands a panel with two modes:Manual mode:
AI Wizard mode:
After creation, the agents list and config form are both refreshed automatically — no "not found in config" error, no manual reload needed.
5. Emoji Picker Dropdown
The emoji field in Create Agent and Edit Agent forms is a dropdown with 103 curated emojis grouped into 5 categories (Tech & AI, People & Roles, Animals, Nature & Elements, Objects & Symbols), each showing the emoji and its name. A large live preview shows the selected emoji next to the dropdown.6. Edit Agent Inline (Agents Overview)
The Agents Overview card now shows editable inputs directly — no toggle needed:- Emoji: in IDENTITY.md (last-wins override of creation value); identity cache is evicted after save so changes appear immediatelyemoji param of agents.update (not avatar) so the correct IDENTITY.md key is written7. Delete Agent
8. Agent-Specific Cron Stats
The Scheduler card on the Cron Jobs tab previously showed global gateway stats (total job count, global next wake). Now:nextRunAtMs across this agent's jobs (n/a if no jobs)Jobs: 0 / Next wake: n/a.9. Agents Tab — Model Selector Cleanup
using the same full model catalog as the primary selector10. Backend — agents.create / agents.update / agents.delete / agents.wizard
New RPC handlers wired into the gateway:| Method | Description |
|--------|-------------|
| agents.create | Provisions a new agent entry in config + scaffolds workspace (SOUL.md, AGENTS.md, USER.md) |
| agents.update | Patches agent config (name, workspace, model, identity, etc.) |
| agents.delete | Removes agent from config |
| agents.wizard | Calls the configured LLM to generate name, emoji, and SOUL.md from a plain-text description |
Auth fix in agents.wizard: Raw HTTP calls to the model API require an api_key token, not an OAuth/bearer token. The wizard now falls back to an explicit api_key profile (or ANTHROPIC_API_KEY env var) when the default resolved auth mode is oauth or token.
11. Session History Viewer (v1.4.0)
A modal overlay accessible from the Sessions tab that displays full conversation history for any session:12. Sessions Tab Overhaul (v1.4.0)
The Sessions tab now provides a unified multi-agent experience:agents.list)agent:main:cron:cc63fdb3-...identity.name → name → id fallback chaingrid-template-columns with proportional widths; headers align precisely with data13. Backend — sessions.history RPC (v1.4.0)
New RPC handler that reads full JSONL transcript files:| Param | Type | Description |
|-------|------|-------------|
| key | string | Session key |
| limit | number | Max messages (default 200, max 500) |
| offset | number | Pagination offset |
| search | string | Full-text search filter |
| rolesFilter | string[] | Filter by role(s) |
Returns {key, sessionId, agentId, total, offset, items[{role, text, timestamp}]}.
14. Auth Mode Badge on Every Assistant Message (v1.5.0 / v1.5.1)
A small pill badge appears on every assistant message group showing which auth method was used:| Badge | Color | Meaning |
|-------|-------|---------|
| OAuth | Green | Claude Max OAuth setup token (sk-ant-oat01-*) |
| API | Indigo | Direct Anthropic API key |
| Fallback | Orange | OpenAI or other fallback provider |
How it works:
1. After each final chat event, the UI calls auth.status RPC
2. The RPC reads lastGood from auth-profiles.json and returns {profileId, mode}
3. chatAuthMode state is updated and passed as fallbackAuthMode to all message groups
4. Messages with a specific _authProfileId (from the run pipeline) use that; all others fall back to chatAuthMode
5. renderAuthBadge() handles both profileId strings (e.g. anthropic:manual) and __mode:oauth shorthand
This ensures every assistant message shows a badge, including tool-use messages and messages from autonomous loops.
"Up to Date" pill: The gateway version header now shows "Up to Date" in a styled pill matching the Version and Health pills (green dot + rounded backdrop).
15. Pipedream Tab Refreshes on Agent Switch (v1.5.0)
Previously, switching agents while on the Pipedream sub-tab kept showing the previous agent's data. NowonSelectAgent reloads Pipedream (and Zapier) state when their respective sub-tabs are active. Same fix applied to Zapier tab.16. OAuth-First Auth Priority Enforcement (v1.5.1)
The auth profile candidate list is now sorted sotoken/oauth type profiles always come before api_key profiles, regardless of the order returned by resolveAuthProfileOrder. This guarantees OAuth is tried first for Anthropic even if the profile resolution system silently skips it.// In pi-embedded-runner/run.ts — applied after resolveAuthProfileOrder()
const sortedProfileOrder = [...profileOrder].sort((a, b) => {
const typeA = authStore.profiles[a]?.type ?? "api_key";
const typeB = authStore.profiles[b]?.type ?? "api_key";
const rank = (t: string) => (t === "token" || t === "oauth" ? 0 : 1);
return rank(typeA) - rank(typeB);
});
Files Changed
| File | Change |
|------|--------|
| src/gateway/protocol/schema/agents-models-skills.ts | Adds emoji optional param to AgentsUpdateParamsSchema |
| src/gateway/server-methods/agents.ts | agents.wizard RPC; agents.update emoji fix (writes - Emoji: not - Avatar:) |
| ui/src/ui/app-render.helpers.ts | Agent dropdown in chat (with resolveAgentEmoji()), per-agent session filter, + New Session button |
| ui/src/ui/views/agents.ts | Create Agent panel, 103-emoji picker, edit/delete agent UI, always-editable Overview |
| ui/src/ui/views/agents-utils.ts | buildModelOptionsMulti() for multi-select fallback model dropdown |
| ui/src/ui/views/agents-panels-status-files.ts | Cron Jobs tab Scheduler card: agent-specific job count + next wake |
| ui/src/ui/app-render.ts | Create/wizard props wiring + edit agent save handler (emoji param, cache eviction) + session history modal wiring + agent filter for Sessions tab + agent identity name resolution (identity.name fallback chain) + History button agent pre-selection |
| ui/src/ui/app.ts | 19 @state() fields: create/wizard (10) + edit/delete agent (9) + session history modal (8) + sessions agent filter (1) |
| ui/src/ui/app-view-state.ts | Session history modal + sessions agent filter type definitions |
| ui/src/ui/views/sessions.ts | Overhauled: friendly names, agent identity column, agent filter dropdown, CSS grid layout, History button, Label column removed |
| ui/src/ui/views/sessions-history-modal.ts | New file: Session history modal component |
| src/gateway/protocol/schema/sessions.ts | SessionsHistoryParamsSchema |
| src/gateway/protocol/schema/types.ts | SessionsHistoryParams type export |
| src/gateway/protocol/index.ts | validateSessionsHistoryParams + re-exports |
| src/gateway/server-methods/sessions.ts | sessions.history RPC handler |
| src/agents/pi-embedded-runner/run.ts | Calls updateAgentRunContext with authProfileId; sorts profile candidates so token/oauth always first |
| src/gateway/server-chat.ts | Includes authProfileId from run context in final chat event payload |
| src/gateway/server-methods-list.ts | Registers auth.status as a known RPC method |
| src/gateway/server-methods/sessions.ts | auth.status RPC: reads lastGood from auth-profiles store |
| src/infra/agent-events.ts | Adds authProfileId?: string to AgentRunContext; exports updateAgentRunContext() |
| ui/src/styles/chat/grouped.css | Auth badge styles for per-message display (OAuth/API/fallback) |
| ui/src/styles/chat/layout.css | .chat-auth-badge styles for chat controls bar badge |
| ui/src/ui/app-gateway.ts | Calls auth.status after each final chat event; updates chatAuthMode state |
| ui/src/ui/app-render.helpers.ts | Agent dropdown, per-agent session filter, + New Session; auth badge in controls bar removed in v1.5.1 (moved to per-message) |
| ui/src/ui/app-view-state.ts | Adds chatAuthMode field |
| ui/src/ui/app.ts | Adds @state() chatAuthMode |
| ui/src/ui/chat/grouped-render.ts | renderAuthBadge() for per-message badge; accepts fallbackAuthMode opt; handles __mode:oauth shorthand |
| ui/src/ui/controllers/chat.ts | Annotates final messages with _authProfileId from payload |
| ui/src/ui/types/chat-types.ts | Adds authProfileId?: string to MessageGroup type |
| ui/src/ui/views/chat.ts | groupMessages() propagates _authProfileId; ChatProps adds chatAuthMode; passes fallbackAuthMode to renderMessageGroup |
| ui/src/ui/app-render.ts | onSelectAgent reloads Pipedream/Zapier state when sub-tabs active; passes chatAuthMode to chat props; "Up to Date" styled as pill |
| ui/src/ui/app-chat.ts | Removed CHAT_SESSIONS_ACTIVE_MINUTES time filter (was 120min, now 0 = show all sessions in chat dropdown) |
UI Design & Styling Reference
This section documents the UI design decisions for anyone installing or extending this skill.
Sessions Tab Layout
Uses CSS grid (display: grid) instead of the default OpenClaw .table flex layout for precise column alignment:.sessions-grid {
grid-template-columns: 2fr 1.2fr 0.6fr 0.8fr 1fr 0.8fr 0.8fr auto;
/* Session | Agent | Kind | Updated | Tokens | Thinking | Reasoning | Actions */
}
var(--text-muted) color, bottom borderdisplay: contents for grid participation, subtle bottom border, hover highlight at 2% white opacityvar(--accent, #6366f1)), raw key below in 11px muted monospace at 50% opacitymax-width: 100px to prevent overflowSession History Modal
Dark overlay modal with the following structure:┌──────────────────────────────────────────────────┐
│ Session History [✕] │
│ [Agent ▼] [Session ▼] │
│ [🔍 Search...] [All] [User] [Asst] [Sys] [Tool]│
│ ─────────────────────────────────────────────── │
│ 👤 User · Feb 23, 10:23 AM │
│ Hello, can you help me? │
│ ─────────────────────────────────────────────── │
│ 🤖 Assistant · Feb 23, 10:23 AM │
│ Of course! What do you need? │
│ ─────────────────────────────────────────────── │
│ [Load More ↓] Showing 100 of 342 │
└──────────────────────────────────────────────────┘
Key CSS variables used:
var(--bg-card, #1a1a2e) — modal backgroundvar(--border, #333) — bordersvar(--accent, #6366f1) — user role color, active chipvar(--text, #e0e0e0) — message textvar(--border-subtle, rgba(255,255,255,0.06)) — message separatorsRole colors:
| Role | Color |
|------|-------|
| User | var(--accent, #6366f1) (indigo) |
| Assistant | #10b981 (emerald) |
| System | #f59e0b (amber) |
| Tool | #8b5cf6 (violet) |
Role icons: 👤 User, 🤖 Assistant, ⚙️ System, 🔧 Tool, 💬 Other
Session Name Resolution
The friendly name fallback chain: 1.row.label (user-set label)
2. row.displayName (server-computed, e.g. "discord:#bot-chat")
3. Smart key parsing:
- *:main → "Main Session"
- *:cron:*:run:* → "Cron Run"
- *:cron:* → "Cron Job"
- *:subagent:* → "Subagent"
- *:openai:* → "OpenAI Session"
- *::direct: → "Channel · id"
- *::group:* → "Channel Group"
4. Raw key as fallbackAgent Identity Resolution
For the Agent column and dropdowns: 1.agent.identity.name (from IDENTITY.md — e.g. "Assistant")
2. agent.name (from config — e.g. "main")
3. agent.id (raw identifier)Emoji: agent.identity.emoji with "🤖" as fallback.
Chat Dropdown
The session dropdown in the chat header shows all sessions for the selected agent (no time filter). Previously limited to sessions active within 120 minutes, which hid older Discord channels and other sessions.Installation
This skill requires patching OpenClaw source files and a UI + gateway rebuild.
Prerequisites
~/openclaw (fork or local clone)pnpm installed (npm install -g pnpm)Step 1: Apply patches
cd ~/openclawgit apply ~/.openclaw/workspace/skills/agent-chat-ux/references/schema-agents.txt
git apply ~/.openclaw/workspace/skills/agent-chat-ux/references/agents-view.txt
git apply ~/.openclaw/workspace/skills/agent-chat-ux/references/agents-utils.txt
git apply ~/.openclaw/workspace/skills/agent-chat-ux/references/agents-panels-cron.txt
git apply ~/.openclaw/workspace/skills/agent-chat-ux/references/app-render-helpers.txt
git apply ~/.openclaw/workspace/skills/agent-chat-ux/references/app-render.txt
git apply ~/.openclaw/workspace/skills/agent-chat-ux/references/app-main.txt
git apply ~/.openclaw/workspace/skills/agent-chat-ux/references/server-agents.txt
If any patch fails due to upstream drift, apply manually using the patch file as a line-by-line reference.
Step 1b: Apply v1.4.0 patches (Session History + Sessions Tab Overhaul)
cd ~/openclawBackend: sessions.history RPC
git apply ~/.openclaw/workspace/skills/agent-chat-ux/references/v1.4.0/patch-01-sessions-history-rpc.txtSessions tab: friendly names, agent column, agent filter
git apply ~/.openclaw/workspace/skills/agent-chat-ux/references/v1.4.0/patch-02-sessions-tab-overhaul.txtApp state + render wiring for history modal
git apply ~/.openclaw/workspace/skills/agent-chat-ux/references/v1.4.0/patch-03-app-wiring.txtNew file: session history modal component
cp ~/.openclaw/workspace/skills/agent-chat-ux/references/v1.4.0/patch-04-sessions-history-modal.ts \
ui/src/ui/views/sessions-history-modal.tsChat dropdown: show all sessions (remove 120min active filter)
git apply ~/.openclaw/workspace/skills/agent-chat-ux/references/v1.4.0/patch-05-chat-sessions-all.txt
Step 1c: Apply v1.5.0 patches (Auth badge + Pipedream agent switch fix)
cd ~/openclawAuth badge (auth.status RPC + per-message badge on all assistant groups)
Also includes: OAuth-first sort, "Up to Date" pill styling
git apply ~/.openclaw/workspace/skills/agent-chat-ux/references/v1.5.0/patch-auth-badge.txtPipedream/Zapier tab refresh on agent switch + chatAuthMode wiring to chat view
git apply ~/.openclaw/workspace/skills/agent-chat-ux/references/v1.5.0/patch-pipedream-agent-switch.txt
Step 2: Rebuild UI
cd ~/openclaw
pnpm ui:build
Step 3: Rebuild gateway (for backend agent methods)
cd ~/openclaw
pnpm build
Step 4: Restart gateway
openclaw gateway restart
Step 5: Verify
1. Open Control UI at http://localhost:18789
2. Chat tab — agent dropdown appears left of session dropdown (if >1 agent configured); + button appears right of session dropdown
3. Agents tab — "+ Create Agent" button with Manual and AI Wizard modes
4. Agents → Overview → Model Selection — fallback is now a multi-select dropdown
5. Create an agent with the AI Wizard — should generate cleanly and appear in the list with no "not found" error
6. Agents → Overview — Name, Emoji, Workspace are editable directly; Save button at bottom activates on any change
7. Change an agent's emoji — after Save it should persist (not revert to the original creation emoji)
8. Agents → Cron Jobs — agents with no cron jobs show Jobs: 0 / Next wake: n/a (not the global gateway count)
9. Sessions tab — sessions show friendly names (e.g. "Main Session") with agent emoji+name column; agent filter dropdown works
10. Sessions tab → History button — opens modal with conversation history, search, and role filter chips
11. History modal → Agent filter — changing agent filters the session dropdown; selecting a session loads its messages
12. Chat dropdown — session dropdown shows ALL sessions for the selected agent (including older Discord channels, OpenAI sessions, etc. — not just recent ones)
Usage
Chat: Switching Agents & Sessions
+ button: starts a new session for the current agent (same as /new)Agents: Create Agent
1. Click + Create Agent 2. Manual: enter name, workspace, pick emoji → "Create Agent" 3. AI Wizard: describe the agent → "Generate Agent" → review preview → "✅ Create This Agent"Agents: Fallback Models
In Model Selection:Ctrl/⌘ + click for multiple); these are retried in order when the primary model fails (rate limit, context overflow, etc.)Sessions: Viewing History
1. Go to Sessions tab 2. Optionally filter by agent using the Agent dropdown 3. Click History on any session row 4. The modal opens with the full conversation 5. Search — type to search across all messages (300ms debounce) 6. Role chips — click All/User/Assistant/System/Tool to filter by role 7. Load More — pagination loads 100 messages at a timeSessions: Agent-Filtered View
The Sessions tab now shows:Architecture Notes
Session Key Format
agent:: — the agent selector reads parseAgentSessionKey(state.sessionKey).agentId to determine the active agent and filters the session list accordingly.Config Refresh After Creation
Afteragents.create succeeds, the UI calls both agents.list (to update the sidebar) and loadConfig (to refresh configForm). Without the loadConfig call, selecting the new agent would show "not found in config" because the config form was stale.Wizard Auth Resolution
agents.wizard makes a direct HTTP call to the model provider API. Raw HTTP calls require an api_key type credential — not an OAuth bearer token. The resolution order is:
1. Default resolveApiKeyForProvider result (used if mode is api-key)
2. First api_key-type profile in the auth store for the provider
3. ANTHROPIC_API_KEY / OPENAI_API_KEY env var directlyThis mirrors the same pattern used in enhanced-loop-hook.ts.
Model Fallbacks
Stored asmodel.fallbacks[] in the agent config. The runtime tries them via runWithModelFallback() when the primary model returns an error.Changelog
1.5.1 (2026-02-28)
chatAuthMode passed as fallbackAuthMode to every message group rendererrenderAuthBadge() updated to handle __mode: shorthand in addition to raw profile IDstoken/oauth profiles always precede api_key, regardless of resolution order quirkspatch-auth-badge.txt and patch-pipedream-agent-switch.txt in references/v1.5.0/ to include all v1.5.1 changes1.5.0 (2026-02-28)
auth.status RPC reading lastGood from auth-profiles storeauth.status RPC — reads lastGood from loadAuthProfileStore() and returns {profileId, mode} (oauth | api | fallback | unknown)chatAuthMode UI state — updates after each final chat event; drives the badge color/labelreferences/v1.5.0/1.4.0 (2026-02-23)
sessions.history RPC — reads full JSONL transcripts with search, role filtering, and offset/limit paginationagent:main:main, agent:main:cron:cc63fdb3-...)grid-template-columns with proportional widthsidentity.name → config name → agent id fallback chain (shows "Assistant" not "Main Agent")CHAT_SESSIONS_ACTIVE_MINUTES 120min time filter that was hiding older Discord channels and API sessions)references/v1.4.0/1.3.0 (2026-02-19)
agents-panels-cron.txt patch — Scheduler card on Cron Jobs tab now shows agent-specific job count and next-wake (n/a when no jobs assigned)agents.update now accepts an emoji param and writes - Emoji: to IDENTITY.md; previously wrote - Avatar: which was always overridden by the creation-time - Emoji: lineschema-agents.txt) — AgentsUpdateParamsSchema now includes optional emoji fieldresolveAgentEmoji() to correctly pick up IDENTITY.md emoji (not just agent.identity.emoji)1.2.1 (2026-02-19)
app-render.txt that referenced state not defined by this skill's app-main.txt patch — applying the previous patch would have caused TypeScript errors and runtime crashesapp-render.txtas any casts in agent create handlers with typed assertions ({ ok?: boolean; error?: string } | null)1.2.0 (2026-02-19)
.metadata.json now explicitly declares ANTHROPIC_API_KEY/OPENAI_API_KEY as optional env vars with auth resolution order documentedapp-main.txt that belonged to an unrelated featureagents.wizard JSON parsing now performs structural validation before accepting model output — rejects non-object, missing fields, empty strings, truncated contentname capped to 100 chars, emoji to 10 chars on output to prevent oversized valuescapabilities block documenting auth_profile_read, external_api_calls, and source_code_patch with mitigations1.1.0 (2026-02-18)
x-api-key; now falls back to api_key profile or env varloadConfig now called after agents.create in both Manual and Wizard paths⚠️ Known Gotchas
Model Dropdown Shows Only 1–3 Models
This manifests in two distinct failure modes that often alternate. Both are fixed permanently in v1.5.2 source patches. Understanding both helps if you're on an unpatched install.
#### Mode A — Allowlist Trap (agents.defaults.models non-empty)
Symptom: Dropdown shows a handful of models from one provider (e.g. 2 Claude variants) even though many providers have API keys configured. openclaw models list --all shows 750+ models fine.
Root cause: agents.defaults.models in openclaw.json acts as a strict allowlist inside buildAllowedModelSet() in the models.list RPC handler. Any wizard, openclaw models set , or onboarding command writes a single entry there — after that, only that one provider's model is shown. The key is never auto-cleared.
Temporary fix (unpatched installs):
python3 -c "
import json, re
path = '/home/charl/.openclaw/openclaw.json' # adjust path if needed
raw = open(path).read()
strip JS comments, fix trailing commas, then parse
clean = re.sub(r'//.*\n', '\n', raw)
clean = re.sub(r',\s*([}\]])', r'\1', clean)
cfg = json.loads(clean)
cfg.setdefault('agents', {}).setdefault('defaults', {})['models'] = {}
open(path, 'w').write(json.dumps(cfg, indent=2))
print('done')
"
systemctl --user restart openclaw-gateway
Permanent fix (source patch — v1.5.2):
Remove buildAllowedModelSet from the models.list handler entirely. agents.defaults.models controls routing/defaults, not what appears in the UI dropdown. File: src/gateway/server-methods/models.ts.
- const cfg = loadConfig();
const { allowedCatalog } = buildAllowedModelSet({
cfg,
catalog,
defaultProvider: DEFAULT_PROVIDER,
});
const models = allowedCatalog.length > 0 ? allowedCatalog : catalog;
+ // Always return the full catalog — agents.defaults.models is for routing,
+ // not for filtering what's visible in the UI dropdown.
+ const models = await context.loadGatewayModelCatalog();
respond(true, { models }, undefined);
#### Mode B — Empty Catalog on First Gateway Boot
Symptom: Dropdown shows nothing (or only the currently-selected model as a static fallback). Happens right after a fresh systemctl restart. After a second restart it usually works. The models.list RPC takes 1000+ ms and returns { models: [] }.
Root cause: Three interacting issues:
1. loadModelCatalog() is lazy — not called until the first models.list RPC. If the gateway was busy at startup (e.g. rebuilding the Control UI, which happens on first install), the dynamic import() of the Pi SDK module may contend with other startup I/O and resolve to an empty registry.
2. When models.length === 0, modelCatalogPromise is reset to null — so every subsequent call retries, but the error is only logged once (then hasLoggedModelCatalogError suppresses all future failures). This makes the root cause invisible in logs.
3. The loadGatewayModelCatalog() wrapper had no retry — it returned [] as-is.
Permanent fix (source patches — v1.5.2):
src/gateway/server-model-catalog.ts — retry once on empty + pre-warm at startup:
export async function loadGatewayModelCatalog(): Promise {
const result = await loadModelCatalog({ config: loadConfig() });
if (result.length === 0) {
// Bust cache and retry once — handles transient startup race.
return await loadModelCatalog({ config: loadConfig(), useCache: false });
}
return result;
}export function warmModelCatalogInBackground(): void {
loadGatewayModelCatalog().catch(() => {});
}
src/agents/model-catalog.ts — reset error-log gate on each new attempt so failures stay visible:
modelCatalogPromise = null;
+ hasLoggedModelCatalogError = false; // allow next attempt to log
src/gateway/server.impl.ts — call warmModelCatalogInBackground() at gateway startup (after sidecars):
import { loadGatewayModelCatalog, warmModelCatalogInBackground } from "./server-model-catalog.js";
// ...inside startGateway(), after startGatewaySidecars():
warmModelCatalogInBackground();
#### Diagnostic Commands
# How many models does the CLI see?
openclaw models list --all | wc -l # should be 750+What does the live RPC return? (needs wscat or the gateway WS client)
Quickest check — look at the gateway log for models.list response time:
< 100ms = hitting cache (good); > 500ms = fresh load (may be empty)
journalctl --user -u openclaw-gateway --no-pager | grep "models.list"Is the allowlist populated?
python3 -c "
import json, re
raw = open('/home/charl/.openclaw/openclaw.json').read()
clean = re.sub(r'//.*\n', '\n', raw)
clean = re.sub(r',\s*([}\]])', r'\1', clean)
cfg = json.loads(clean)
print('models allowlist:', cfg.get('agents',{}).get('defaults',{}).get('models',{}))
"
1.5.2 (2026-03-08)
buildAllowedModelSet from models.list handler — the dropdown now always shows the full Pi SDK catalog regardless of agents.defaults.models. Adds warmModelCatalogInBackground() called at gateway startup to pre-warm the catalog and prevent the empty-on-first-boot race. Adds retry in loadGatewayModelCatalog() when the first load returns empty. Resets hasLoggedModelCatalogError on each fresh attempt so failures are always logged.1.0.0 (2026-02-18)
+) in chat headeragents.create / agents.update / agents.delete / agents.wizard backend methods💡 Examples
Chat: Switching Agents & Sessions
+ button: starts a new session for the current agent (same as /new)Agents: Create Agent
1. Click + Create Agent 2. Manual: enter name, workspace, pick emoji → "Create Agent" 3. AI Wizard: describe the agent → "Generate Agent" → review preview → "✅ Create This Agent"Agents: Fallback Models
In Model Selection:Ctrl/⌘ + click for multiple); these are retried in order when the primary model fails (rate limit, context overflow, etc.)Sessions: Viewing History
1. Go to Sessions tab 2. Optionally filter by agent using the Agent dropdown 3. Click History on any session row 4. The modal opens with the full conversation 5. Search — type to search across all messages (300ms debounce) 6. Role chips — click All/User/Assistant/System/Tool to filter by role 7. Load More — pagination loads 100 messages at a timeSessions: Agent-Filtered View
The Sessions tab now shows:⚙️ Configuration
~/openclaw (fork or local clone)pnpm installed (npm install -g pnpm)Step 1: Apply patches
cd ~/openclawgit apply ~/.openclaw/workspace/skills/agent-chat-ux/references/schema-agents.txt
git apply ~/.openclaw/workspace/skills/agent-chat-ux/references/agents-view.txt
git apply ~/.openclaw/workspace/skills/agent-chat-ux/references/agents-utils.txt
git apply ~/.openclaw/workspace/skills/agent-chat-ux/references/agents-panels-cron.txt
git apply ~/.openclaw/workspace/skills/agent-chat-ux/references/app-render-helpers.txt
git apply ~/.openclaw/workspace/skills/agent-chat-ux/references/app-render.txt
git apply ~/.openclaw/workspace/skills/agent-chat-ux/references/app-main.txt
git apply ~/.openclaw/workspace/skills/agent-chat-ux/references/server-agents.txt
If any patch fails due to upstream drift, apply manually using the patch file as a line-by-line reference.
Step 1b: Apply v1.4.0 patches (Session History + Sessions Tab Overhaul)
cd ~/openclawBackend: sessions.history RPC
git apply ~/.openclaw/workspace/skills/agent-chat-ux/references/v1.4.0/patch-01-sessions-history-rpc.txtSessions tab: friendly names, agent column, agent filter
git apply ~/.openclaw/workspace/skills/agent-chat-ux/references/v1.4.0/patch-02-sessions-tab-overhaul.txtApp state + render wiring for history modal
git apply ~/.openclaw/workspace/skills/agent-chat-ux/references/v1.4.0/patch-03-app-wiring.txtNew file: session history modal component
cp ~/.openclaw/workspace/skills/agent-chat-ux/references/v1.4.0/patch-04-sessions-history-modal.ts \
ui/src/ui/views/sessions-history-modal.tsChat dropdown: show all sessions (remove 120min active filter)
git apply ~/.openclaw/workspace/skills/agent-chat-ux/references/v1.4.0/patch-05-chat-sessions-all.txt
Step 1c: Apply v1.5.0 patches (Auth badge + Pipedream agent switch fix)
cd ~/openclawAuth badge (auth.status RPC + per-message badge on all assistant groups)
Also includes: OAuth-first sort, "Up to Date" pill styling
git apply ~/.openclaw/workspace/skills/agent-chat-ux/references/v1.5.0/patch-auth-badge.txtPipedream/Zapier tab refresh on agent switch + chatAuthMode wiring to chat view
git apply ~/.openclaw/workspace/skills/agent-chat-ux/references/v1.5.0/patch-pipedream-agent-switch.txt
Step 2: Rebuild UI
cd ~/openclaw
pnpm ui:build
Step 3: Rebuild gateway (for backend agent methods)
cd ~/openclaw
pnpm build
Step 4: Restart gateway
openclaw gateway restart
Step 5: Verify
1. Open Control UI at http://localhost:18789
2. Chat tab — agent dropdown appears left of session dropdown (if >1 agent configured); + button appears right of session dropdown
3. Agents tab — "+ Create Agent" button with Manual and AI Wizard modes
4. Agents → Overview → Model Selection — fallback is now a multi-select dropdown
5. Create an agent with the AI Wizard — should generate cleanly and appear in the list with no "not found" error
6. Agents → Overview — Name, Emoji, Workspace are editable directly; Save button at bottom activates on any change
7. Change an agent's emoji — after Save it should persist (not revert to the original creation emoji)
8. Agents → Cron Jobs — agents with no cron jobs show Jobs: 0 / Next wake: n/a (not the global gateway count)
9. Sessions tab — sessions show friendly names (e.g. "Main Session") with agent emoji+name column; agent filter dropdown works
10. Sessions tab → History button — opens modal with conversation history, search, and role filter chips
11. History modal → Agent filter — changing agent filters the session dropdown; selecting a session loads its messages
12. Chat dropdown — session dropdown shows ALL sessions for the selected agent (including older Discord channels, OpenAI sessions, etc. — not just recent ones)