| | 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 == ""
|
| | } |