Class: Silas::AgentSdk::StreamParser
- Inherits:
-
Object
- Object
- Silas::AgentSdk::StreamParser
- Defined in:
- lib/silas/agent_sdk/stream_parser.rb
Overview
Tolerant NDJSON parser for claude -p --output-format stream-json. The
event schema is under-documented and shifts between versions, so unknown
lines/types must never raise. Yields Silas::Event objects; accumulates the
terminal Result (final text, tool_use blocks, usage, session_id).
Instance Attribute Summary collapse
-
#blocks ⇒ Object
readonly
Returns the value of attribute blocks.
-
#final_text ⇒ Object
readonly
Returns the value of attribute final_text.
-
#session_id ⇒ Object
readonly
Returns the value of attribute session_id.
-
#stop_reason ⇒ Object
readonly
Returns the value of attribute stop_reason.
-
#tool_calls ⇒ Object
readonly
Returns the value of attribute tool_calls.
-
#usage ⇒ Object
readonly
Returns the value of attribute usage.
Instance Method Summary collapse
- #ingest(line) ⇒ Object
-
#initialize ⇒ StreamParser
constructor
A new instance of StreamParser.
-
#to_result ⇒ Object
tool_calls stays [] on the Result: in the engine-owned path Claude Code already executed the tools (through our MCP endpoint), so the framework loop must not try to run them again.
Constructor Details
#initialize ⇒ StreamParser
Returns a new instance of StreamParser.
12 13 14 15 16 17 18 19 |
# File 'lib/silas/agent_sdk/stream_parser.rb', line 12 def initialize @blocks = [] @tool_calls = [] @final_text = nil @usage = nil @session_id = nil @stop_reason = nil end |
Instance Attribute Details
#blocks ⇒ Object (readonly)
Returns the value of attribute blocks.
10 11 12 |
# File 'lib/silas/agent_sdk/stream_parser.rb', line 10 def blocks @blocks end |
#final_text ⇒ Object (readonly)
Returns the value of attribute final_text.
10 11 12 |
# File 'lib/silas/agent_sdk/stream_parser.rb', line 10 def final_text @final_text end |
#session_id ⇒ Object (readonly)
Returns the value of attribute session_id.
10 11 12 |
# File 'lib/silas/agent_sdk/stream_parser.rb', line 10 def session_id @session_id end |
#stop_reason ⇒ Object (readonly)
Returns the value of attribute stop_reason.
10 11 12 |
# File 'lib/silas/agent_sdk/stream_parser.rb', line 10 def stop_reason @stop_reason end |
#tool_calls ⇒ Object (readonly)
Returns the value of attribute tool_calls.
10 11 12 |
# File 'lib/silas/agent_sdk/stream_parser.rb', line 10 def tool_calls @tool_calls end |
#usage ⇒ Object (readonly)
Returns the value of attribute usage.
10 11 12 |
# File 'lib/silas/agent_sdk/stream_parser.rb', line 10 def usage @usage end |
Instance Method Details
#ingest(line) ⇒ Object
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/silas/agent_sdk/stream_parser.rb', line 21 def ingest(line) line = line.to_s.strip return if line.empty? event = JSON.parse(line) @session_id ||= event["session_id"] if event["session_id"] case event["type"] when "system" @session_id ||= event["session_id"] yield Event.new(type: :"system.#{event['subtype']}", payload: symbolize(event)) when "assistant" ingest_assistant(event) { |e| yield e } when "user" yield Event.new(type: :tool_result, payload: symbolize(event)) when "result" @final_text = event["result"] @stop_reason = event["subtype"] @usage = extract_usage(event) # The result text usually repeats the last assistant text — only add a # block if it isn't already captured. if @final_text && @blocks.none? { |b| b["type"] == "text" && b["text"] == @final_text } @blocks << { "type" => "text", "text" => @final_text } end yield Event.new(type: :result, payload: symbolize(event)) else yield Event.new(type: :unknown, payload: symbolize(event)) end rescue JSON::ParserError # A non-JSON line (banner, warning) — ignore. end |
#to_result ⇒ Object
tool_calls stays [] on the Result: in the engine-owned path Claude Code already executed the tools (through our MCP endpoint), so the framework loop must not try to run them again.
56 57 58 |
# File 'lib/silas/agent_sdk/stream_parser.rb', line 56 def to_result Engines::Result.new(blocks: @blocks, tool_calls: [], stop_reason: @stop_reason || "end_turn", usage: @usage) end |