Skip to content

feat(config): narrate_tool_calls knob for CLI agent transcript - #210

Merged
Desperado merged 2 commits into
mainfrom
feature/narrate-tool-calls-config
Sep 26, 2026
Merged

Desperado merged 2 commits into
mainfrom
feature/narrate-tool-calls-config

Conversation

@Desperado

Copy link
Copy Markdown
Contributor

Summary

  • New calibratable knob so users can dial the CLI agent's mid-flight narration up or down without touching CLAUDE.md.
  • Previous behavior collapsed into 🔧 Bash 🔧 Bash 🔧 Bash chains with only end-summary prose, forcing users to open the diff to see what actually ran.
  • Injected into the same turn-1 preamble slot as `effortDirective` / `outputStyleDirective`, so all four subprocess backends (`cc`, `codex`, `agy`, `opencode`) adhere consistently.

Config

New field on `api.Config`:

```go
NarrateToolCalls string `json:"narrate_tool_calls,omitempty"` // "off" | "brief" (default) | "full"
```

value behavior
`off` no preface; chained tool-call icons acceptable, only end summary
`brief` (default) one-line preface quoting the command or snippet before each non-trivial tool call
`full` preface + quoted key output line after each non-trivial call; snippets always shown for edits

Set via:

```bash
qmax-code config set narrate_tool_calls full
qmax-code config set narrate_tool_calls off
```

Synonyms accepted: `none`/`silent` → `off`, `default` → `brief`, `verbose`/`detailed` → `full`. Empty/unknown → `brief` on read.

Directive snippet

```go
// internal/agent/cc_agent.go
func narrationDirective(mode string) string {
switch mode {
case "off": return "\n\nTOOL NARRATION: OFF — Chain tool calls without prose ..."
case "full": return "\n\nTOOL NARRATION: FULL — Before each non-trivial tool call, ..."
default: return "\n\nTOOL NARRATION: BRIEF — Before each non-trivial tool call, ..."
}
}
```

Threading

  • `NewCCAgent`, `NewCodexAgent`, `NewAgyAgent` gain a `narrateToolCalls string` positional param mirroring `outputVerbose` — 6 production call sites in `main.go`/`internal/repl/repl.go`, ~15 test sites updated.
  • `NewOpenCodeAgent` already receives `*api.Config`, so it reads `cfg.NarrateToolCalls` directly — no new param.
  • Preambles updated in cc/codex/agy: `... + outputStyleDirective(a.outputVerbose) + narrationDirective(a.narrateToolCalls) + ...`.

Tests

  • `TestSetConfigField_NarrateToolCalls` — 10 input forms (canonical, synonyms, mixed case, whitespace), invalid value, clear-to-default round trip.
  • `TestNarrationDirectiveIncludesModeLabel` — asserts each mode's label + BRIEF fallback for bogus input.
  • `TestCCAgentPromptIncludesNarrationDirective` — construction stores normalized value; empty → "brief".

```bash
go build -o qmax-code .
go test ./... # all packages ok (agent 6.878s, api cached, main 10.9s)
```

Test plan

  • `go test ./...` green
  • Manual: `qmax-code config set narrate_tool_calls off` → `/orch` a task → confirm chained tool-call icons with minimal prose.
  • Manual: `qmax-code config set narrate_tool_calls full` → same task → confirm command-quoting before each Bash + output line after.
  • Manual: `qmax-code config show` displays the new field.

Notes

  • Value is read at agent construction time. Changing it mid-session takes effect on the next `/orch` (or subprocess reset) — matches how `OutputVerbose` behaved before its runtime toggle.
  • Follow-up (not this PR): add `SetNarrateToolCalls(mode string)` to the `CLIAgent` interface + a hotkey / `/set` bridge in the REPL for live toggling, mirroring `SetOutputVerbose`.

Users can now calibrate how much the CLI agent (cc/codex/agy/opencode)
prefaces each tool call in the transcript. Prior behavior often
collapsed into `🔧 Bash 🔧 Bash 🔧 Bash` with only end-summary prose,
forcing the user to open the diff to see what happened.

New string field on Config:

    narrate_tool_calls  → "off" | "brief" (default) | "full"

- off   = no preface; chained tool-call icons with only end-summary prose
- brief = one-line preface quoting the command or snippet (default)
- full  = preface + quoted key output line after each non-trivial call

Injected into the turn-1 system prompt via new narrationDirective() sibling
of the existing effortDirective / outputStyleDirective helpers, so all four
subprocess backends adhere consistently. OpenCode reads it from the *Config
already threaded through NewOpenCodeAgent; CC / Codex / Antigravity get a
new positional string param mirroring outputVerbose.

Setter registered under /set narrate_tool_calls off|brief|full with
common synonyms (none, silent, default, verbose, detailed) accepted.
@qualitymaxapp

qualitymaxapp Bot commented Sep 26, 2026 •

Copy link
Copy Markdown

QualityMax Review

Verdict: COMMENT · Confidence: evidence-backed scan

Files eligible: 14 · Files reviewed: 14 · Files with findings: 0 · Findings: 0 · Inline cards: 0

Priority findings

priority location finding
— — No blocking findings

Review gates

gate status
AI diff review completed · eligible 14, reviewed 14 · LLM · served gemini-3.1-flash-lite
SAST completed · eligible 14, reviewed 14 · hybrid · served claude-haiku-4-5-20251001 · requested qwen3.7-plus
Overall review evidence clean
Inline evidence not needed

Important files

file risk note next step
— — No findings —

Review lifecycle

Use the inline cards to inspect evidence and suggested remediation. Re-run the QualityMax review after pushing a fix; unchanged cards are identified by their stable finding marker. Dismiss with a reason through the existing QualityMax/GitHub review feedback flow. 0 prior card(s) are stale/resolved on this head. @qmax Q&A is tracked separately.

Proof legend: VERIFIED independently judged patch · REPRODUCED verified finding · GROUNDED deterministic evidence · MODEL-ONLY model judgment.

QualityMax project results are available in the configured project.

Receipt · commit c8133cdefce5cfb5ae2b3d8859408ab003cc024c · run 2026-09-26T18:47:03+00:00 · model served claude-haiku-4-5-20251001, gemini-3.1-flash-lite · model requested qwen3.7-plus, gemini-3.1-flash-lite · model review recorded — 1501 model output tokens · model source repository ai_review_preferences.preferred_model · re-review 2 · proof counts {}

@qualitymaxapp qualitymaxapp Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QualityMax Review — canonical overview updated; inline findings are attached to this review.

@qualitymaxapp

qualitymaxapp Bot commented Sep 26, 2026 •

Copy link
Copy Markdown

⚠️ QualityMax Pipeline

Gate Result
🔍 AI diff review ✅ Clean · gemini-3.1-flash-lite · completed · 14 eligible / 14 reviewed · gemini-3.1-flash-lite
🔍 SAST completed · 14 eligible / 14 reviewed · claude-haiku-4-5-20251001
🔍 Canonical PR review delivery completed · 0 eligible / 0 reviewed · exact-head review #5326971206 and overview #5843683082 confirmed
🧪 Repo Tests ✅ 842/842 passed (go)

Powered by QualityMax — AI-Powered Test Automation

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Narration may expose sensitive output, off mode semantics are inconsistent, and backend prompt wiring lacks sufficient coverage.

Review effort: Lite
Findings: 1 High severity

Open (1)
What changed in this PR

Adds configurable off/brief/full tool-call narration across CLI agent backends, with config handling and tests.

Changes:

  • Adds narrate_tool_calls normalization, aliases, and config commands.
  • Threads narration directives through CC, Codex, Agy, and OpenCode.
  • Updates constructors and related tests.
File Summary
main.go Passes narration configuration to agents.
internal/​repl/​repl.go Threads configuration through backend switching.
internal/​api/​config.go Defines and normalizes the setting.
internal/​agent/​opencode_agent.go Applies narration configuration.
internal/​agent/​mcp_reconnect_test.go Updates agent construction tests.
internal/​agent/​conversation_test.go Updates backend construction tests.
internal/​agent/​codex_agent.go Adds Codex narration directives.
internal/​agent/​codex_agent_continuity_test.go Updates Codex tests.
internal/​agent/​cc_agent.go Adds CC narration directives.
internal/​agent/​cc_agent_session_test.go Tests narration configuration.
internal/​agent/​agy_agent.go Adds Agy narration directives.
internal/​agent/​agy_agent_test.go Updates Agy tests.
config_command.go Supports setting and displaying the setting.
config_command_test.go Tests configuration handling.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread internal/agent/cc_agent.go Outdated
Updated narration guidelines to include redaction of commands and key outputs.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

@qualitymaxapp qualitymaxapp Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QualityMax Review — canonical overview updated; inline findings are attached to this review.

@Desperado
Desperado merged commit 10b6a72 into main Sep 26, 2026
6 checks passed
@Desperado
Desperado deleted the feature/narrate-tool-calls-config branch September 26, 2026 19:16
Desperado added a commit that referenced this pull request Sep 26, 2026
…210) (#211)

Copilot flagged HIGH-severity credential-exposure risk on PR #210: the
`full` narration directive asked the subprocess agent to echo commands
and output verbatim, which can carry API keys (argv `--token=`), bearer
tokens (`Authorization:` headers), env-var values from a `printenv`
call, connection strings, private keys, etc.

Every mode (off/brief/full — including the "bogus"→brief fallback) now
carries a shared REDACTION clause that:

- names the secret classes to substitute (API keys, bearer/OAuth/session
  tokens, passwords, private keys, Authorization/Cookie header values,
  connection strings, --token=/--api-key=/--password=/--secret= flag
  values, AWS_*/GITHUB_TOKEN/ANTHROPIC_API_KEY/*_KEY/*_TOKEN/*_SECRET
  env-var values, webhook signing secrets),
- specifies the substitution (`<REDACTED>`, not omission),
- forbids quoting `env`/`printenv`/`railway variables` output or `.env*`
  file contents in the narration channel,
- covers `off` mode too because "only narrate on failure" is exactly
  where secrets tend to appear (401 responses, curl -v dumps).

Subprocess agents (Codex CLI, Antigravity, opencode-selected models) do
not inherit qmax-code's own secret-handling rules from CLAUDE.md, so the
guard is spelled out in the injected system prompt.

TestNarrationDirectiveCarriesRedactionClause asserts each mode names the
key secret classes by string — a future edit that thins the directive
without replacing the guard fails loudly.
@Desperado Desperado mentioned this pull request Sep 26, 2026
2 of 3 tasks
Desperado added a commit that referenced this pull request Sep 26, 2026
* release: v1.37.0

Ship the Opus 5.5 picker refresh (#209), the narrate_tool_calls
transcript-verbosity knob (#210), and the narration secret-redaction
hardening (#211).

* release: bump CHANGELOG date to 2026-09-27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants