Class: AgentsControl::Transcript
- Inherits:
-
Object
- Object
- AgentsControl::Transcript
- Defined in:
- lib/agents_control/transcript.rb
Overview
The tail of a conversation with an agent.
Read from the JSONL file whose path the agent sends with every hook. This beats scraping text off the screen for three reasons: it works the same for a terminal tab and for a VS Code session, which has no screen at all; it gives structure instead of ANSI noise; and it isn't limited to what fit in the visible area.
Constant Summary collapse
- TAIL_BYTES =
The file grows without bound, and only the end matters. Read from the end in blocks, so a multi-megabyte history never has to be pulled fully into memory.
256 * 1024
- PROJECTS =
File.("~/.claude/projects")
Class Method Summary collapse
-
.for_cwd(cwd, root: PROJECTS) ⇒ Object
The transcript of a tab the hooks never sent anything about.
- .slug(cwd) ⇒ Object
Instance Method Summary collapse
- #exists? ⇒ Boolean
-
#initialize(path) ⇒ Transcript
constructor
A new instance of Transcript.
-
#last(count = 6) ⇒ Object
The last N messages as [text:].
-
#render(count = 6) ⇒ Object
Ready-to-send text, in full — splitting across multiple Telegram messages, if needed, is the caller's job (Router#say_chunked).
Constructor Details
#initialize(path) ⇒ Transcript
Returns a new instance of Transcript.
45 46 47 |
# File 'lib/agents_control/transcript.rb', line 45 def initialize(path) @path = path end |
Class Method Details
.for_cwd(cwd, root: PROJECTS) ⇒ Object
The transcript of a tab the hooks never sent anything about.
Claude Code lays out histories in directories named after the
working path, with / and _ replaced by -. If that scheme
ever changes, this method just returns an empty transcript
instead of breaking its caller.
28 29 30 31 32 33 |
# File 'lib/agents_control/transcript.rb', line 28 def for_cwd(cwd, root: PROJECTS) return new(nil) if cwd.to_s.empty? directory = File.join(root, slug(cwd)) new(newest_in(directory)) end |
.slug(cwd) ⇒ Object
35 |
# File 'lib/agents_control/transcript.rb', line 35 def slug(cwd) = cwd.to_s.tr("/_", "--") |
Instance Method Details
#exists? ⇒ Boolean
49 |
# File 'lib/agents_control/transcript.rb', line 49 def exists? = @path && File.exist?(@path) |
#last(count = 6) ⇒ Object
The last N messages as [text:].
52 53 54 55 56 57 |
# File 'lib/agents_control/transcript.rb', line 52 def last(count = 6) return [] unless exists? = parse(tail) .last(count) end |
#render(count = 6) ⇒ Object
Ready-to-send text, in full — splitting across multiple Telegram messages, if needed, is the caller's job (Router#say_chunked).
61 62 63 64 65 66 |
# File 'lib/agents_control/transcript.rb', line 61 def render(count = 6) entries = last(count) return "The conversation is empty." if entries.empty? entries.map { |entry| "#{prefix(entry[:role])} #{entry[:text]}" }.join("\n\n") end |