Skip to content

feat(context): nudge the agent to offer follow-up suggestions when relevant - #597

Merged
iamwhatever merged 1 commit into
mainfrom
feat/followup-nudge
Jul 27, 2026
Merged

feat(context): nudge the agent to offer follow-up suggestions when relevant#597
iamwhatever merged 1 commit into
mainfrom
feat/followup-nudge

Conversation

@kyleseaman

Copy link
Copy Markdown
Collaborator

Problem

PR #461 shipped the suggest_followup MCP tool and the follow-up card UI, but nothing prompted the agent to actually use it. Usage rode entirely on the tool's own description — and because MCP Tool Search is enabled by default, that spec is not injected into every turn's context, so in practice the agent would seldom surface the tool. The feature was fully wired and inert.

Why it matters

An end-of-turn follow-up surface that the agent never reaches for is dead weight. The user asked for the agent to offer follow-ups "when relevant, not on every turn" — which needs an explicit, situational nudge, since the tool cannot rely on being in context.

Fix (symptom → root cause → change)

  • Symptom: agent never calls suggest_followup.
  • Root cause: no prompt-level pointer to the tool; Tool Search keeps its spec out of most turns.
  • Change: inject a short reminder into the per-turn interactive block in context.py — the same place the [OPTIONS:] reminder is appended. It is:
    • Gated to dashboard sessions (session_key starts with dashboard: / dashboard_). The tool rejects Slack, cron, and subagent contexts (no card surface), so prompting them for it would be pure noise and guaranteed 4xx.
    • Framed as situational, not per-turn: "prefer silence when there is no real next step," don't repeat an acted-on card, and never use it to ask a clarifying question. This satisfies "when relevant, not every turn."
    • Distinct from [OPTIONS:]: those are inline choices for the current conversation; a follow-up card is a concrete next task handed off (optionally to a new worktree).

This is a fast-follow to #461 (merged in da39b088); the tool and its user-facing doc already exist on main, so the nudge references a real tool.

Tests

test/test_context.py:

  • test_followup_nudge_only_in_dashboard_sessions — the nudge appears for a dashboard: session and is absent for None / cron: / subagent: / slack: keys. Revert-verified: neutering the dashboard gate fails it.
  • test_followup_nudge_requires_interactive — a non-interactive turn gets neither the [OPTIONS:] reminder nor the nudge.

Manual verification

N/A — the behavior is a deterministic prompt-string injection fully covered by the two gating unit tests. Full backend suite green (18331 passed; the 3 test_dashboard_origin failures are pre-existing KIROCREW_PORT host-env cases unrelated to this change), mypy clean across 487 files, isort/flake8 clean.

Screenshots

N/A — no UI change. The follow-up card surface itself shipped with screenshots in #461; this PR only changes when the agent is prompted to raise one.

…levant

PR #461 shipped the suggest_followup MCP tool and its follow-up card, but
nothing prompted the agent to reach for it — usage rode entirely on the tool's
own description, and with MCP Tool Search enabled that spec is not in every
turn's context, so the tool would rarely be surfaced.

Inject a situational, dashboard-only reminder into the per-turn interactive
block (the same place the [OPTIONS:] reminder lives). It is gated to
dashboard: / dashboard_ session keys because the tool rejects Slack, cron, and
subagent contexts, and it is framed as optional and turn-end — not per-turn —
so it raises awareness without becoming noise.
@github-actions github-actions Bot added the readiness: checking Automated validation is still running label Jul 27, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Opus 5 Review — ✅ no blocking findings

Reviewed e98a675c7bac8f19e6d8c57ae2520f2048430f11 — this comment is updated in place on each push.

No findings.

Verdict recorded via the action's structured output for commit e98a675c7bac8f19e6d8c57ae2520f2048430f11.

False positive or not applicable? A repository writer can comment:
/ai-review override fable e98a675c7bac8f19e6d8c57ae2520f2048430f11: <one-sentence reason>

@github-actions

github-actions Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Arbiter — ✅ no blocking findings

Arbiter found no unresolved long-term items that require action before merging e98a675c7bac8f19e6d8c57ae2520f2048430f11.

Second-order review for e98a675c7bac8f19e6d8c57ae2520f2048430f11; this comment is updated in place on each push.

Review details

Arbiter-Verdict: PASS

No sub-threshold finding meets the long-term-impact bar.

Both line-level reviewers (Opus 5, GPT 5.6) reported no findings at all, so there is nothing to weigh from them. The design reviewer passed the PR and raised a single suggestion: surface eligibility for follow-up cards is now encoded in two places — the tool's own context rejection and the dashboard:/dashboard_ prefix check added in context.py. That is classic duplication/drift risk: it only bites if follow-up cards later ship to a new surface, at which point the nudge silently stays dashboard-only. The failure mode is a missing prompt hint (the tool still works and is discoverable via Tool Search), it is fully reversible in a one-file later change, and this diff creates no persisted-data, wire-format, or API commitment. It is neither a one-way door nor concrete harm, so it does not clear the blocking bar.

Suggested follow-ups (open as issues — non-blocking)

  • Extract a shared "supports follow-up cards" predicate used by both the suggest_followup tool's context gate and the nudge condition in context.py (currently a dashboard:/dashboard_ prefix check), so if follow-up cards ever ship to another surface the nudge follows automatically instead of silently remaining dashboard-only. Safe to wait: the worst case today is a missing optional hint, not a functional or data regression; fix belongs alongside the tool's own surface gate.

[ARBITER-REVIEWED] e98a675

False positive or not applicable? A repository writer can comment:
/ai-review override arbiter e98a675c7bac8f19e6d8c57ae2520f2048430f11: <one-sentence reason>

For a broader accepted-risk deferral, apply defer-longterm and explain why.

@github-actions

Copy link
Copy Markdown
Contributor

GPT 5.6 Review — ✅ no blocking findings

GPT 5.6 completed its review of e98a675c7bac8f19e6d8c57ae2520f2048430f11 and found no blocking issues.

This comment is updated in place on each push.

Review details

No findings.
[GPT-REVIEWED] e98a675

False positive or not applicable? A repository writer can comment:
/ai-review override gpt e98a675c7bac8f19e6d8c57ae2520f2048430f11: <one-sentence reason>

@github-actions

Copy link
Copy Markdown
Contributor

Design Review (Fable 5) — ✅ PASS

Advisory design-level review of e98a675c7bac8f19e6d8c57ae2520f2048430f11 — updated in place on each push; does not block merge.

The PR's own commit relative to its fork point touches only context.py, the follow-up doc, and test_context.py — the wecom/config hunks in the raw range diff are unrelated main commits from the shallow-clone fork point, not part of this change.

Design-Verdict: PASS

Real gap (wired-but-inert tool under Tool Search), fixed at the existing per-turn interactive seam, gated and tested; proportionate and reversible.

Suggestions

  • Surface eligibility now lives in two places: the tool's own context rejection and the dashboard:/dashboard_ prefix check in context.py ("Gated to dashboard sessions because the tool rejects Slack/cron/subagent contexts"). If follow-up cards ever ship to another surface, the nudge silently stays dashboard-only — a shared "supports follow-up cards" predicate next to the tool's gate would keep them from drifting.

[DESIGN-REVIEWED] e98a675

@github-actions github-actions Bot added readiness: passed Eligible automated validation passed for the current revision and removed readiness: checking Automated validation is still running labels Jul 27, 2026
@bolichen97

Copy link
Copy Markdown
Collaborator

Placement looks right to me — I'd keep it in context.py rather than moving it into the system prompt. Tracing the three injection layers:

Why not prompt.md:

  1. It's transport-agnostic; the tool isn't. prompt.md is kiro-cli's real system prompt via file:// (agent.py:1342, agent.py:1377) for every session — dashboard, Slack, cron, subagent. Since suggest_followup hard-rejects non-dashboard sessions (mcp_core.py:5334), gating it there means adding a {{FOLLOWUP_BLOCK}} template alongside {{WIDGET_BLOCK}} (context.py:1056-1090) — more machinery for a weaker signal than this PR gets for free from the session_key already in hand.

  2. prompt.md is user-overridable, so it's a silent-inert vector. ~/.kiro/crew/prompt.md wins over the bundled copy (agent.py:500-503) and nothing regenerates it. Anyone with a customized prompt would never get the nudge — reintroducing the exact failure class this PR fixes.

  3. Repo precedent agrees. [OPTIONS:] — the closest analogue — appears nowhere in prompt.md; it lives in _CRITICAL_RULES (context.py:622-630) plus the per-turn reminder at context.py:1813-1818. This PR appends to that second site, which is consistent.

One thing worth watching: the nudge is injected on every interactive dashboard turn, while its own text argues for restraint ("situational, NOT per-turn... prefer silence"). Repeating a suggestion affordance every turn is a fairly reliable way to get a model to over-fire it. Not a blocker — but if cards start appearing on trivial turns, the per-turn injection is the knob to pull, not the wording. _CRITICAL_RULES (once per session) is the cheaper fallback, at the cost of being compaction-droppable.

Complementary follow-up: the stated root cause is discoverability — Tool Search keeps the spec out of context. prompt.md:19-24 exists for exactly that ("These MCP tools are provided by KiroCrew..." — cron_add, spawn_run, learn_add, task_run). A plain capability line there would attack the root cause directly for ~40 tokens, and is transport-safe since it's a capability statement rather than a behavioral mandate (the tool self-rejects elsewhere, so a Slack session that reads it simply never calls it):

- `suggest_followup` — offer up to 3 concrete next-step cards below the composer at the end of a turn (dashboard sessions only). Each item's `prompt` must be a complete standalone handoff.

Additive to this PR, not a replacement for it.

@iamwhatever
iamwhatever merged commit aabae24 into main Jul 27, 2026
40 checks passed
@iamwhatever
iamwhatever deleted the feat/followup-nudge branch July 27, 2026 22:36
@github-actions github-actions Bot removed the readiness: passed Eligible automated validation passed for the current revision label Jul 27, 2026
encomjp pushed a commit to encomjp/kirocrew-customapi that referenced this pull request Aug 22, 2026
…levant (kirodotdev#597)

PR kirodotdev#461 shipped the suggest_followup MCP tool and its follow-up card, but
nothing prompted the agent to reach for it — usage rode entirely on the tool's
own description, and with MCP Tool Search enabled that spec is not in every
turn's context, so the tool would rarely be surfaced.

Inject a situational, dashboard-only reminder into the per-turn interactive
block (the same place the [OPTIONS:] reminder lives). It is gated to
dashboard: / dashboard_ session keys because the tool rejects Slack, cron, and
subagent contexts, and it is framed as optional and turn-end — not per-turn —
so it raises awareness without becoming noise.

Co-authored-by: Kyle Seaman <kseam@dev-dsk-kseam-1b-55230d27.us-east-1.amazon.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants