Skip to content

Per-agent verboseDefault / elevatedDefault rejected by config schema, despite resolver and SDK types supporting them #73680

@kevinheinrichs

Description

@kevinheinrichs

Summary

The runtime treats verboseDefault and elevatedDefault as valid per-agent overrides (resolver, plugin-SDK types, status text, command handlers), but the strict zod entry schema does not declare them, so openclaw config set agents.list.<idx>.verboseDefault on (or elevatedDefault) is rejected with Unrecognized key. Only agents.defaults.* accepts these keys today, which forces a global default even when the operator only wants to change one agent.

thinkingDefault, reasoningDefault, and fastModeDefault are accepted per agent — they are listed in AgentEntrySchema. verboseDefault/elevatedDefault are missing from that same schema, despite the rest of the stack already supporting them.

Environment

  • OpenClaw 2026.4.24 (cbcfdf6)
  • Linux x86_64 (Ubuntu VM)
  • Config edited via openclaw config set

Repro

# index 0 = any agent in agents.list, e.g. main
openclaw config set agents.list.0.verboseDefault on
# Error: Config validation failed: agents.list.0: Unrecognized key: "verboseDefault"

openclaw config set agents.list.0.elevatedDefault on
# Error: Config validation failed: agents.list.0: Unrecognized key: "elevatedDefault"

Same error when setting it in openclaw.json directly and running openclaw config validate.

thinkingDefault works as expected on the same path:

openclaw config set agents.list.0.thinkingDefault high
# OK

agents.defaults.verboseDefault and agents.defaults.elevatedDefault are also accepted and work as documented.

Expected

Either (preferred): allow verboseDefault and elevatedDefault on per-agent entries the same way thinkingDefault, reasoningDefault, and fastModeDefault are allowed, since the rest of the codebase already resolves them per agent.

Or: explicitly document that these are global-only and remove the per-agent resolution paths and SDK types so the surface stays consistent.

Evidence the rest of the stack already expects per-agent values

The strict schema is the only place the per-agent fields are missing. Everywhere else the resolver chain reads entry.verboseDefault / agentCfg.verboseDefault first and only then falls back to agents.defaults.verboseDefault:

  • dist/agent-scope-*.js:
    verboseDefault: entry.verboseDefault ?? agentDefaults?.verboseDefault,
  • dist/directive-handling.levels-*.js:
    currentVerboseLevel: params.sessionEntry?.verboseLevel ?? params.agentCfg?.verboseDefault,
  • dist/agent-command-*.js:
    const resolvedVerboseLevel = verboseOverride ?? persistedVerbose ?? agentCfg?.verboseDefault;
  • dist/get-reply-*.js:
    const resolvedVerboseLevel = directives.verboseLevel ?? targetSessionEntry?.verboseLevel ?? agentCfg?.verboseDefault;
  • dist/dispatch-*.js:
    fallbackLevel: normalizeVerboseLevel(
      sessionStoreEntry.entry?.verboseLevel
        ?? sessionAgentCfg?.verboseDefault
        ?? cfg.agents?.defaults?.verboseDefault
        ?? ""
    ) ?? "off"
  • dist/status-message-*.js:
    const verboseLevel = args.resolvedVerbose
      ?? args.sessionEntry?.verboseLevel
      ?? args.agent?.verboseDefault
      ?? "off";

The Plugin-SDK type definitions also document the per-agent fields:

  • dist/plugin-sdk/src/config/types.agents.d.ts:
    /** Optional per-agent default verbosity level. */
    verboseDefault?: "off" | "on" | "full";
  • dist/plugin-sdk/src/config/zod-schema.agents.d.ts (the published TS schema):
    verboseDefault: z.ZodOptional<z.ZodUnion<readonly [
      z.ZodLiteral<"off">, z.ZodLiteral<"on">, z.ZodLiteral<"full">
    ]>>;
  • dist/plugin-sdk/src/agents/agent-scope-config.d.ts:
    verboseDefault?: AgentDefaultsConfig["verboseDefault"];

Where the runtime schema diverges

dist/zod-schema.agent-runtime-*.js declares AgentEntrySchema as z.object({...}).strict() and only includes thinkingDefault, reasoningDefault, and fastModeDefault. verboseDefault and elevatedDefault are absent:

const AgentEntrySchema = z.object({
  id: z.string(),
  // ...
  thinkingDefault: z.enum(["off","minimal","low","medium","high","xhigh","adaptive","max"]).optional(),
  reasoningDefault: z.enum(["on","off","stream"]).optional(),
  fastModeDefault: z.boolean().optional(),
  // verboseDefault   <-- missing
  // elevatedDefault  <-- missing
  // ...
}).strict();

The defaults schema (AgentDefaultsConfig in zod-schema-*.js) does declare them:

verboseDefault: z.union([
  z.literal("off"), z.literal("on"), z.literal("full")
]).optional(),
elevatedDefault: z.union([
  z.literal("off"), z.literal("on"), z.literal("ask"), z.literal("full")
]).optional(),

openclaw config schema confirms it at runtime — agents.list[] lists thinkingDefault, reasoningDefault, fastModeDefault but not verboseDefault or elevatedDefault.

Documentation

docs.openclaw.ai/gateway/config-agents documents verboseDefault and elevatedDefault only under agents.defaults.*. There is no documented per-agent override for them, even though thinkingDefault is documented as available both at agents.defaults.thinkingDefault and agents.list[].thinkingDefault. The doc lookup at https://docs.openclaw.ai/tools/thinking even references Per-agent default (agents.list[].thinkingDefault in config), which sets the expected pattern.

Suggested fix

Add the two fields to AgentEntrySchema in zod-schema.agent-runtime:

verboseDefault: z.enum(["off", "on", "full"]).optional(),
elevatedDefault: z.enum(["off", "on", "ask", "full"]).optional(),

…and document them under agents.list[] in gateway/config-agents.mdx with the same precedence note used for thinkingDefault (per-agent overrides default, omitted falls back to agents.defaults.*).

Workaround

Set the value globally via agents.defaults.verboseDefault / elevatedDefault. Per-agent toggling currently has to happen via runtime /verbose and /elevated slash commands per session, which doesn't survive new sessions.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions