Skip to content

Agent Behaviour: a real home for character, replacing three hardcoded style heuristics #223

Description

@serge-ivo

Why

An agent's character is configurable nowhere. Three separate failures prove it:

  1. Guardrails is unreachable. topicRestrictions, blockedTerms, responseStyle,
    maxResponseLength, requireCitations are stored per-instance and injected into the prompt
    (agent-do-prompt.ts:86) — and there are zero references to guardrails anywhere in
    store/console/src
    . It has never been editable by anyone.
  2. Style is GUESSED, not declared. agent-think.ts:403:
    const technical = repoChatStyle || hasCodingContext;   // "has repos ⇒ you want jargon"
    plus two hardcoded rules with no opt-out: "Never output step-by-step thinking" and
    "Reply in MAX 2 sentences".
  3. The agent improvised. Asked to be less technical, the FWS Repo Coder wrote
    preference:response_style into Memory — because there was no proper home. Same failure
    shape as it inventing a pipeline named "coding" when it had no tool to start work.

Memory is for subject-matter knowledge. Agent character is not knowledge.

Scope

lib/agent-behaviour.ts — pure, no Env, the single source of truth for the field set. UI, prompt
and tools all derive from it rather than restating it.

  • BEHAVIOUR_FIELDS — declarative schema (id, type, options/range, default, band descriptions).
  • sanitizeBehaviour(raw) — clamps + allowlists; unknown keys dropped.
  • resolveBehaviour(templateDefault, instanceOverride) — creator seeds a default in
    agents.config.behaviour, subscriber overrides in agent_instances.config.behaviour.
  • behaviourPrompt(b) — the load-bearing part. Sliders become language, never numbers.
    technicality: 70 must render as "Assume senior-engineer familiarity; cite real files and
    functions" — not "Technicality: 70/100", which models ignore or overfit. ~4 bands per slider.

Then replace the three heuristics above with the resolved values, keeping today's behaviour as
the default so nothing changes for an agent that has set nothing.

Routes: GET/PUT/DELETE /v1/instances/:id/behaviour. Storage is JSON in existing config columns
— no migration.

Field set

Style — technicality (slider→bands) · verbosity (brief/balanced/thorough) · tone
(casual/neutral/formal) · warmth (matter-of-fact ↔ friendly; orthogonal to formality) · reply language

Reasoning — show its working (overrides the hardcoded no-step-by-step) · hedging (flag
uncertainty ↔ commit) · ask-vs-assume (clarify when ambiguous ↔ assume and proceed)

Formatting — prose/markdown/headings+tables · emoji · code examples (none/on-request/liberal)

Interaction — proactivity (answer only ↔ suggest next steps) · ends-with-a-question · what to
call me · free-text persona (the catch-all)

Guardrails (existing, finally reachable) — stay on topic · never say · cite sources ·
max length

Not in scope

  • Temperature/creativity — dropped. High temperature measurably degrades tool-calling, and the
    benefit is speculative. Not worth a knob that breaks Coders.
  • Rules & Tips stays in Knowledge. Deliberate: standing rules are about the subject matter
    ("always check the migration head"), behaviour is about the agent. Different things, different
    homes.
  • Account-level behaviour defaults. Unlike voice ([docs] Update Coder docs for runner-node picker, engines, and package paths #211), character is legitimately per-agent — a
    Coder should be technical where a Language Buddy should not.

Verification

  • Pure unit tests on behaviourPrompt: every slider band emits prose containing no digits from
    the raw value
    ; empty behaviour reproduces today's prompt byte-for-byte (regression guard on
    the three heuristics).
  • Mutation-check: break the band mapping and the "no numbers in prompt" test must fail.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions