Class CollectingStreamWriter

java.lang.Object
com.axelor.ai.chat.stream.StreamWriter
com.axelor.ai.chat.stream.CollectingStreamWriter
All Implemented Interfaces:
AutoCloseable

public class CollectingStreamWriter extends StreamWriter
A StreamWriter that collects text deltas in memory instead of writing SSE. Used by AiServiceImpl for synchronous agent invocations.

It also records how the turn ended, not just what it said. A turn that suspends waiting for a human — a tool needing approval, a client-side tool — finishes cleanly with no Error event, and a caller that only reads the text cannot tell that apart from a real answer. See getSuspendedTools() and isMaxStepsExhausted().

  • Constructor Details

    • CollectingStreamWriter

      public CollectingStreamWriter()
  • Method Details

    • write

      public void write(StreamEvent event) throws IOException
      Description copied from class: StreamWriter
      Serializes the event as data: {json}\n\n and flushes.
      Overrides:
      write in class StreamWriter
      Throws:
      IOException
    • done

      public void done()
      Description copied from class: StreamWriter
      Writes the data: [DONE]\n\n terminator and flushes. Must be the last write.
      Overrides:
      done in class StreamWriter
    • close

      public void close()
      Specified by:
      close in interface AutoCloseable
      Overrides:
      close in class StreamWriter
    • getText

      public String getText()
      Returns the accumulated text from all text deltas.
    • isDone

      public boolean isDone()
    • getError

      public String getError()
      Returns the error message if the stream failed, or null.
    • getSuspendedTools

      public Collection<String> getSuspendedTools()
      The tools the turn is still waiting on, empty when it ended on its own terms. Non-empty means the agentic loop stopped mid-reasoning for a human — the text collected so far is a fragment, not an answer.
    • isMaxStepsExhausted

      public boolean isMaxStepsExhausted()
      Whether the agentic loop stopped because it ran out of steps rather than finishing.