| package stream
|
|
|
| import "strings"
|
|
|
|
|
| var ToolTagPrefixes = []string{
|
| "<function_calls",
|
| "<tool>",
|
| "<tool ",
|
| "<tools>",
|
| "<tools ",
|
| }
|
|
|
|
|
| type TextBuffer struct {
|
| PendingText string
|
| ToolCallDetected bool
|
| }
|
|
|
|
|
| func NewTextBuffer() *TextBuffer {
|
| return &TextBuffer{
|
| PendingText: "",
|
| ToolCallDetected: false,
|
| }
|
| }
|
|
|
|
|
| func (b *TextBuffer) Add(text string) {
|
| b.PendingText += text
|
| }
|
|
|
|
|
| func (b *TextBuffer) FlushSafeText(emitFunc func(string)) {
|
| if b.PendingText == "" || b.ToolCallDetected {
|
| return
|
| }
|
|
|
| safeEndIndex := len(b.PendingText)
|
|
|
|
|
| for _, prefix := range ToolTagPrefixes {
|
| for i := 1; i <= len(prefix); i++ {
|
| partialTag := prefix[:i]
|
| idx := strings.LastIndex(b.PendingText, partialTag)
|
| if idx != -1 && idx+len(partialTag) == len(b.PendingText) {
|
|
|
| if idx < safeEndIndex {
|
| safeEndIndex = idx
|
| }
|
| }
|
| }
|
| }
|
|
|
| if safeEndIndex > 0 {
|
| safeText := b.PendingText[:safeEndIndex]
|
| if safeText != "" {
|
| emitFunc(safeText)
|
| }
|
| b.PendingText = b.PendingText[safeEndIndex:]
|
| }
|
| }
|
|
|
|
|
| func (b *TextBuffer) FlushAll(emitFunc func(string)) {
|
| if b.PendingText != "" {
|
| emitFunc(b.PendingText)
|
| b.PendingText = ""
|
| }
|
| }
|
|
|
|
|
| func (b *TextBuffer) Clear() {
|
| b.PendingText = ""
|
| }
|
|
|
|
|
| func (b *TextBuffer) IsEmpty() bool {
|
| return b.PendingText == ""
|
| } |