Class NaruThinkingTagParser
Stateful on purpose. A tag can be split across two network packets -- a
chunk may well end mid-way through the literal <thi, and a parser
that assumed a whole tag per chunk would leak that fragment into the answer
as visible text. So this buffers the longest tail that could still turn out to
be the start of a tag, and only emits text once it knows the tail is not a tag.
Not thread-safe: one parser belongs to one response, driven by one transport thread.
Why not a regex
Pattern cannot express "a tag may straddle a chunk boundary" without
being handed the whole stream, which is exactly what defeats incremental
display. The buffering is the feature.
-
Field Summary
Fields -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionchunks()Every chunk this parser has produced, in order.closeTag()Feeds one chunk of stream text.Signals the end of the stream and returns whatever was still buffered.booleanWhether the stream ended with every segment properly closed.booleanWhether the last thinking segment was left open at the end of the stream.markOpenSegmentTruncated(String provider) Re-tags the chunk of the given kind that is still open as truncated.openTag()static voidparseAll(String text, String openTag, String closeTag, String provider, Consumer<NaruStreamChunk> sink) Feeds a whole response's text through the parser and hands each chunk tosink, then flushes.booleanWhether an unterminatedopenTagwas seen.tags()The delimiter pair this parser was built with, for handing to aNaruStreamPipelineor aNaruModelConfig.toString()
-
Field Details
-
DEFAULT_OPEN_TAG
The delimiter pair used by the conventions in the wild.- See Also:
-
DEFAULT_CLOSE_TAG
- See Also:
-
-
Constructor Details
-
NaruThinkingTagParser
public NaruThinkingTagParser() -
NaruThinkingTagParser
-
-
Method Details
-
openTag
-
closeTag
-
extraction
-
tags
The delimiter pair this parser was built with, for handing to aNaruStreamPipelineor aNaruModelConfig. -
sawThinking
public boolean sawThinking()Whether an unterminatedopenTagwas seen. A provider that opened a reasoning block and never closed it is common, and the tail is still thinking -- it just has no closing boundary. -
isTruncated
public boolean isTruncated()Whether the last thinking segment was left open at the end of the stream. -
feed
Feeds one chunk of stream text.- Returns:
- the chunks this input completed, in order; empty when the input was absorbed into the tag-boundary buffer
-
flush
Signals the end of the stream and returns whatever was still buffered.Must be called, or a tag that straddles the final chunk is never emitted and text is silently lost.
-
markOpenSegmentTruncated
Re-tags the chunk of the given kind that is still open as truncated.Called when a generation is interrupted. Mid-stream text was already emitted as non-final, so usually there is nothing buffered here; this exists for the case where the interrupt landed on a chunk boundary and the tail is still ambiguous, and it settles the segment either way.
-
isSegmentComplete
public boolean isSegmentComplete()Whether the stream ended with every segment properly closed.This is the authoritative completion signal, and unlike
NaruStreamChunk.complete()it is meaningful for a stream that was cut short -- a chunk delivered mid-stream cannot know what comes next, but after the stream ends this says definitively whether the reasoning was finished or interrupted. This is what a persisted thinking segment records. -
chunks
Every chunk this parser has produced, in order. -
parseAll
public static void parseAll(String text, String openTag, String closeTag, String provider, Consumer<NaruStreamChunk> sink) Feeds a whole response's text through the parser and hands each chunk tosink, then flushes. The batch counterpart offeed(java.lang.String, java.lang.String). -
toString
-