package im
import "strings"
// ThinkBlockStyle controls how ... blocks are rendered.
type ThinkBlockStyle struct {
// ThinkingHeader is shown when the think block is still in-progress (no closing tag yet).
ThinkingHeader string // e.g. "> π **ζθδΈ...**\n" or "π _ζθδΈ..._\n"
// ThoughtHeader is shown before the think block content.
ThoughtHeader string // e.g. "> π **ζθθΏη¨**\n" or "π *ζθθΏη¨*\n"
// LinePrefix is prepended to each line of think content.
LinePrefix string // e.g. "> " or "> _"
// LineSuffix is appended to each line of think content (before newline).
LineSuffix string // e.g. "" or "_"
// Separator is inserted between the think block and the rest of the content.
Separator string // e.g. "\n---\n\n" or "\n"
}
// MarkdownThinkStyle renders think blocks as markdown blockquotes.
// Used by DingTalk and Feishu.
var MarkdownThinkStyle = ThinkBlockStyle{
ThinkingHeader: "> π **ζθδΈ...**\n",
ThoughtHeader: "> π **ζθθΏη¨**\n",
LinePrefix: "> ",
LineSuffix: "",
Separator: "\n---\n\n",
}
// TelegramThinkStyle renders think blocks as blockquotes for Telegram.
// Uses the same blockquote format as other platforms for reliable rendering
// during streaming (where incomplete markdown can cause API failures).
var TelegramThinkStyle = ThinkBlockStyle{
ThinkingHeader: "> π *ζθδΈ...*\n",
ThoughtHeader: "> π *ζθθΏη¨*\n",
LinePrefix: "> ",
LineSuffix: "",
Separator: "\n---\n\n",
}
// TransformThinkBlocks converts ... blocks using the given style.
// Handles both complete blocks and in-progress blocks (where has not
// yet arrived during streaming).
func TransformThinkBlocks(content string, style ThinkBlockStyle) string {
const (
openTag = ""
closeTag = ""
)
openIdx := strings.Index(content, openTag)
if openIdx < 0 {
return content
}
before := content[:openIdx]
after := content[openIdx+len(openTag):]
closeIdx := strings.Index(after, closeTag)
thinkClosed := closeIdx >= 0
var thinkContent, rest string
if thinkClosed {
thinkContent = after[:closeIdx]
rest = after[closeIdx+len(closeTag):]
} else {
thinkContent = after
}
thinkContent = strings.TrimSpace(thinkContent)
var result strings.Builder
result.WriteString(before)
if thinkContent == "" {
if !thinkClosed {
result.WriteString(style.ThinkingHeader)
return result.String()
}
result.WriteString(strings.TrimLeft(rest, "\n"))
return result.String()
}
result.WriteString(style.ThoughtHeader)
for _, line := range strings.Split(thinkContent, "\n") {
result.WriteString(style.LinePrefix)
result.WriteString(line)
result.WriteString(style.LineSuffix)
result.WriteString("\n")
}
if thinkClosed {
rest = strings.TrimLeft(rest, "\n")
if rest != "" {
result.WriteString(style.Separator)
result.WriteString(rest)
}
}
return result.String()
}