← Back to PRs

#20954: feat: per-agent model allowlist

by coletebou open 2026-02-19 13:44 View on GitHub →
docs channel: bluebubbles channel: telegram gateway agents size: XL
## Summary - Adds `models` field to `agents.list[]` entries that, when present, **replaces** the global `agents.defaults.models` allowlist for that agent - Agents without per-agent `models` continue using the global catalog (no breaking change) - Scopes `/model` switching, `/models` listing, Telegram model picker buttons, and session override validation to the agent's allowlist - Fixes global defaults/fallbacks leaking into agent-scoped model lists ## Changes **Type + schema:** - `AgentConfig.models` type in `types.agents.ts` - Zod validation in `zod-schema.agent-runtime.ts` **Core threading:** - `agentModels` param added to `buildAllowedModelSet()`, `buildModelAliasIndex()`, `buildConfiguredAllowlistKeys()`, `getModelRefStatus()`, `resolveAllowedModelRef()` - `resolveAgentConfig()` passes through `entry.models` - `createModelSelectionState()` considers agent-level models for allowlist detection **Call sites:** - `getReplyFromConfig()` resolves agent models and passes through the full reply pipeline - `resolveReplyDirectives()` uses agent models for alias resolution - `buildModelsProviderData()` skips global default/fallback injection when agent allowlist is active - Telegram callback handler resolves agent route before building model picker data **Docs:** - `models.md`: new "Per-agent model allowlist" subsection - `multi-agent.md`: new section with config example - `configuration-reference.md`: `models` field reference ## Config example ```json { "id": "karl-brett", "model": { "primary": "openrouter/minimax/minimax-m2.5" }, "models": { "openrouter/minimax/minimax-m2.5": { "alias": "MiniMax M2.5" }, "openrouter/moonshotai/kimi-k2.5": { "alias": "Kimi K2.5" }, "openrouter/z-ai/glm-5": { "alias": "GLM 5" } } } ``` ## Test plan - [ ] `npx tsc --noEmit` passes (only pre-existing test file errors) - [ ] Agent with per-agent `models` only sees those models in `/models` and Telegram picker - [ ] Agent without per-agent `models` sees full global catalog - [ ] Global defaults/fallbacks do not leak into agent-scoped model lists - [ ] `/model <ref>` rejects models not in the agent's allowlist - [ ] Session model override resets correctly when model is not in agent allowlist ✨ Per aspera ad astra — Nebulatio <!-- greptile_comment --> <h3>Greptile Summary</h3> Adds per-agent model allowlists via `agents.list[].models`, scoping `/model`, `/models`, and Telegram pickers to each agent's catalog. **Key changes:** - New `models` field in `AgentConfig` type and Zod schema - Core model selection functions updated to accept optional `agentModels` parameter - Agent-scoped allowlists replace global defaults (no merge) - Model validation, alias resolution, and command handlers thread `agentModels` through the reply pipeline - Telegram callback handler resolves agent route before building picker data - Global defaults/fallbacks correctly excluded when agent allowlist is active **Issues found:** - `openclaw agent` CLI command (line 394 in `src/commands/agent.ts`) checks global `agentCfg?.models` instead of resolving per-agent models for `sessionAgentId`, causing agent allowlists to be ignored - `sessions_model` tool (`src/agents/tools/session-status-tool.ts:141-151`) doesn't pass agent models to validation, allowing agents to bypass their allowlists via tool calls **Unrelated changes bundled in this PR:** - BlueBubbles extension: surfaces inbound message IDs via system events - Three new skills added: findmy, group-manager, sonos-cloud <h3>Confidence Score: 3/5</h3> - This PR has critical logic gaps that allow per-agent model allowlists to be bypassed - The core implementation is solid: types, schema validation, reply pipeline threading, and Telegram integration all correctly handle per-agent models. However, two critical code paths bypass the feature: the `openclaw agent` CLI command and the `sessions_model` tool both fail to resolve and pass agent models, allowing users to select disallowed models. These gaps undermine the security/policy enforcement aspect of per-agent allowlists. The PR also bundles unrelated changes (BlueBubbles, skills) which should be separate commits. - Pay close attention to `src/commands/agent.ts` and `src/agents/tools/session-status-tool.ts` - both have logic bugs that bypass per-agent model allowlists <sub>Last reviewed commit: 8c9c9b3</sub> <!-- greptile_other_comments_section --> <!-- /greptile_comment -->

Most Similar PRs