Skip to content

feat(agent): add hidden rootly agent AI chat mode (phase 1) - #73

Closed
kwent wants to merge 4 commits into
masterfrom
devin/1793273673-rootly-agent
Closed

kwent wants to merge 4 commits into
masterfrom
devin/1793273673-rootly-agent

Conversation

@kwent

@kwent kwent commented Oct 29, 2026 •

Copy link
Copy Markdown
Member

Why

Phase 1 of the CLI AI agent: chat with Rootly AI from the terminal, using the /v1/ai/chat/stream SSE API through rootly-go's StreamAiChatEvents.

What

  • New hidden rootly agent command (alias chat). Bare rootly and all existing subcommands are unchanged.
  • Interactive (Bubble Tea v2, inline, no alt screen):
    • Streams glamour-rendered markdown with a spinner, status/task line and elapsed time. The renderer and rendered output are cached, so spinner redraws don't re-render the answer.
    • Finished turns go to normal scrollback, including partial output on Ctrl+C (Cancelled.) or on error.
    • Enter sends; Alt/Shift+Enter adds a newline; /new, /help, /exit, /quit.
    • Ctrl+C cancels the stream. Events from a cancelled turn are dropped (turn IDs), so they can't end the next turn. Ctrl+C twice while idle exits.
    • --no-color gives raw markdown and an ASCII colour profile (no colour codes at all).
  • Confirmations: confirmation_required shows the question and JSON preview. y resumes with decision=confirm; n/Esc resumes with cancel (same session_id + checkpoint_id). Expiry is re-checked after the answer, so an expired checkpoint is never resumed in either mode. The resumed text starts on a new paragraph.
  • Print mode: rootly agent -p "q", or a non-TTY stdin (cat log | rootly agent -p "explain" appends stdin after the prompt).
    • The final answer goes to stdout once: glamour on a TTY, raw markdown when piped.
    • Progress goes to stderr, only when stderr is a TTY.
    • Approval: a y/N prompt on a TTY; non-interactive input exits non-zero.
  • internal/api: Client.StreamAiChatEvents reuses the existing auth/transport (API key or OAuth). The --debug transport no longer reads text/event-stream bodies, which previously blocked on the live stream.
  • Friendly errors for 401 (login hint), 403 ai.chat:write (re-login hint) and 429.
  • rootly-go bumped to master (v0.14.1-0.20261029113308-2c148c1fd796), which has the stream API plus the session/current-user endpoints for phase 2. No existing call sites needed changes.

Known server behaviour

Ctrl+C only stops the CLI. The server keeps generating and saves the reply (SseStreamer swallows the disconnect), so a cancelled turn's reply can land in the session after the next turn's. The UI is unaffected.

Risk

Low. The command is hidden, so existing commands are untouched apart from the debug-transport change, which only affects SSE responses.

Rollback

Revert the PR.

Link to Devin session: https://rootly.devinenterprise.com/sessions/28ad93d126254ea18116565e125bb089
Open in Devin Desktop: https://rootly.devinenterprise.com/desktop/session/28ad93d126254ea18116565e125bb089?variant=devin
Requested by: @kwent

devin-ai-integration Bot and others added 2 commits October 29, 2026 11:42
Co-Authored-By: Quentin Rousseau <quentin@rootly.com>
Co-Authored-By: Quentin Rousseau <quentin@rootly.com>
@kwent
kwent requested a review from a team October 29, 2026 11:48
@devin-ai-integration

Copy link
Copy Markdown
Contributor

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

@greptile-apps

greptile-apps Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 4/5

[Medium impact] The PR adds an opt-in AI chat workflow to the CLI.

The PR appears safe to merge, with non-blocking fixes for stale approvals, ignored color settings, and unnecessary rendering work.

Findings

  1. P2 Expired approvals still get sent ▶
  2. P2 Interactive mode ignores color settings ▶
  3. P2 Spinner redraws repeat Markdown work ▶
Fix with agent prompt
### Issue 1
internal/agent/print.go:112-117
Print mode sends a resume request even if the checkpoint expired while the user answered the approval prompt. The TUI also skips the expiry check for `n` and Esc. This submits stale decisions instead of showing that the approval expired.

Check `expired()` immediately before sending either decision, and show the existing expiration message instead.

### Issue 2
internal/cmd/agent/agent.go:47-51
`rootly agent --no-color` still produces colored interactive output. Print mode receives the flag through `PrintOptions`, but the TUI receives no equivalent setting and still creates colored messages and styled Markdown.

Pass the setting into `NewTUIModel` and disable color in both its messages and Markdown output.

### Issue 3
internal/agent/tui.go:451-455
Every streaming redraw creates a new Glamour renderer and renders the entire accumulated answer, even when only the spinner or elapsed time changed. Long answers repeat this work throughout the turn and use more CPU than needed.

Reuse the renderer until the width changes, and cache the rendered answer until its text or width changes.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

Adds hidden rootly agent and chat commands for streamed AI conversations.

  • People can chat with Rootly AI in an interactive terminal screen.
  • Print mode sends a prompt and writes one final chat answer.
  • The API client carries Rootly AI chat as a live event stream.

Reviews (1) · Last reviewed commit: "fix(agent): handle interrupted and resum..." · Reviewed by Greptile

Comment thread internal/agent/print.go
Comment on lines +112 to +117
params = &rootly.StreamAiChatParams{
SessionID: sessionID,
CheckpointID: &checkpointID,
Decision: &decision,
}
continue

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Expired approvals still get sent

Print mode sends a resume request even if the checkpoint expired while the user answered the approval prompt. The TUI also skips the expiry check for n and Esc. This submits stale decisions instead of showing that the approval expired.

Check expired() immediately before sending either decision, and show the existing expiration message instead.

Prompt To Fix With AI
This is a comment left during a code review.
Path: internal/agent/print.go
Line: 112-117

Comment:
**Expired approvals still get sent**

Print mode sends a resume request even if the checkpoint expired while the user answered the approval prompt. The TUI also skips the expiry check for `n` and Esc. This submits stale decisions instead of showing that the approval expired.

Check `expired()` immediately before sending either decision, and show the existing expiration message instead.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Comment thread internal/cmd/agent/agent.go Outdated
Comment on lines +47 to +51
model := aiagent.NewTUIModel(cmd.Context(), client)
program := tea.NewProgram(model,
tea.WithInput(stdin),
tea.WithOutput(cmd.OutOrStdout()),
tea.WithContext(cmd.Context()),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Interactive mode ignores color settings

rootly agent --no-color still produces colored interactive output. Print mode receives the flag through PrintOptions, but the TUI receives no equivalent setting and still creates colored messages and styled Markdown.

Pass the setting into NewTUIModel and disable color in both its messages and Markdown output.

Prompt To Fix With AI
This is a comment left during a code review.
Path: internal/cmd/agent/agent.go
Line: 47-51

Comment:
**Interactive mode ignores color settings**

`rootly agent --no-color` still produces colored interactive output. Print mode receives the flag through `PrintOptions`, but the TUI receives no equivalent setting and still creates colored messages and styled Markdown.

Pass the setting into `NewTUIModel` and disable color in both its messages and Markdown output.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Comment thread internal/agent/tui.go Outdated
Comment on lines +451 to +455
renderer, err := glamour.NewTermRenderer(glamour.WithEnvironmentConfig(), glamour.WithWordWrap(width))
if err != nil {
return markdown
}
rendered, err := renderer.Render(markdown)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Spinner redraws repeat Markdown work

Every streaming redraw creates a new Glamour renderer and renders the entire accumulated answer, even when only the spinner or elapsed time changed. Long answers repeat this work throughout the turn and use more CPU than needed.

Reuse the renderer until the width changes, and cache the rendered answer until its text or width changes.

Prompt To Fix With AI
This is a comment left during a code review.
Path: internal/agent/tui.go
Line: 451-455

Comment:
**Spinner redraws repeat Markdown work**

Every streaming redraw creates a new Glamour renderer and renders the entire accumulated answer, even when only the spinner or elapsed time changed. Long answers repeat this work throughout the turn and use more CPU than needed.

Reuse the renderer until the width changes, and cache the rendered answer until its text or width changes.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

devin-ai-integration Bot and others added 2 commits October 29, 2026 11:57
Co-Authored-By: Quentin Rousseau <quentin@rootly.com>
Co-Authored-By: Quentin Rousseau <quentin@rootly.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor

E2E: local Rootly with a real LLM, run in a terminal. Full run on d305e56, re-checked on 32e17ca, --no-color re-checked on ee730a5.

rootly agent e2e

Tool use + streaming --no-color (no colour codes in the raw capture)
Tool-use streaming No-colour
Approved write (y) → 1 row in the DB Cancelled write (n) → Action cancelled., 0 rows
Approved Cancelled
Print-mode approval, with the resumed text now on its own paragraph Confirmation prompt
Print approved Confirmation

Also verified:

  • follow-up questions keep the session; /help, /new (new session ID in the DB), /exit, /quit; the chat alias; Alt+Enter for a new line; Ctrl+C twice while idle; Ctrl+D.
  • Ctrl+C mid-stream keeps the partial output, and the next question works right away.
  • -p, stdin only, and -p + stdin all exit 0; piped output is raw Markdown with no ANSI codes.
  • bad key and team-disabled both print a friendly error and exit 1; a piped write that needs approval exits non-zero.
  • --debug streams without hanging.
  • rootly --help doesn't list the command, and rootly incidents list still works.

Server behaviour: after Ctrl+C, the server finishes the cancelled turn and saves it. Here it saved the reply at 11:51:17, after the next question's reply (11:50:59) in the same session. The UI showed no interleaving.

Not tested end to end: a confirmation actually expiring (unit tests cover it) and Shift+Enter on its own.

Written by Devin

@devin-ai-integration

Copy link
Copy Markdown
Contributor

Superseded by #74, which now targets master and includes this branch (phases 1 and 2 in one PR, per Quentin). Not merged.

Written by Devin

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant