fix: OCR keywords leaking into LLM prompt + streaming preview issues (#74)
- Strip consumed OCR option keywords (縦書き, figures, etc.) from message content after PDF processing so they don't get interpreted as LLM instructions - Apply StripThinkBlocks to streaming preview to hide <think> tags - Clear orphan draft on SendDraft failure to prevent stale preview bubbles Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
fc6714b52b
commit
fc6baf3402
3 changed files with 41 additions and 2 deletions
|
|
@ -256,7 +256,7 @@ func (al *AgentLoop) setupStreamingHook(opts processOptions, task *activeTask) (
|
||||||
go func() {
|
go func() {
|
||||||
defer close(streamDone)
|
defer close(streamDone)
|
||||||
for up := range streamCh {
|
for up := range streamCh {
|
||||||
display := buildStreamingDisplay(up.accumulated, up.reasoning)
|
display := buildStreamingDisplay(utils.StripThinkBlocks(up.accumulated), up.reasoning)
|
||||||
outMsg := bus.OutboundMessage{
|
outMsg := bus.OutboundMessage{
|
||||||
Channel: opts.Channel,
|
Channel: opts.Channel,
|
||||||
ChatID: opts.ChatID,
|
ChatID: opts.ChatID,
|
||||||
|
|
|
||||||
|
|
@ -471,6 +471,38 @@ func detectReadingOrder(content string, cfgDefault string) string {
|
||||||
return "auto"
|
return "auto"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// stripConsumedOCRKeywords removes OCR option keywords from the message
|
||||||
|
// content after they have been consumed by PDF processing, so the LLM
|
||||||
|
// does not interpret them as user instructions.
|
||||||
|
func stripConsumedOCRKeywords(content string, withFigures bool, readingOrder string) string {
|
||||||
|
lower := strings.ToLower(content)
|
||||||
|
if withFigures {
|
||||||
|
for _, kw := range figureKeywords {
|
||||||
|
if idx := strings.Index(lower, kw); idx >= 0 {
|
||||||
|
content = content[:idx] + content[idx+len(kw):]
|
||||||
|
lower = lower[:idx] + lower[idx+len(kw):]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if readingOrder != "auto" {
|
||||||
|
for _, kw := range readingOrderKeywords {
|
||||||
|
if kw.order != readingOrder {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if idx := strings.Index(lower, kw.keyword); idx >= 0 {
|
||||||
|
content = content[:idx] + content[idx+len(kw.keyword):]
|
||||||
|
lower = lower[:idx] + lower[idx+len(kw.keyword):]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Normalize runs of whitespace left by removal.
|
||||||
|
for strings.Contains(content, " ") {
|
||||||
|
content = strings.ReplaceAll(content, " ", " ")
|
||||||
|
}
|
||||||
|
content = strings.TrimSpace(content)
|
||||||
|
return content
|
||||||
|
}
|
||||||
|
|
||||||
const pdfHintMessage = "PDF OCR in progress. " +
|
const pdfHintMessage = "PDF OCR in progress. " +
|
||||||
"Tip: include \"figures\" or \"\u56f3\u7248\" to extract images. " +
|
"Tip: include \"figures\" or \"\u56f3\u7248\" to extract images. " +
|
||||||
"Add \"\u7e26\u66f8\u304d\" or \"\u6a2a\u66f8\u304d\" to set reading order."
|
"Add \"\u7e26\u66f8\u304d\" or \"\u6a2a\u66f8\u304d\" to set reading order."
|
||||||
|
|
@ -495,9 +527,14 @@ func (al *AgentLoop) processPDFsInMessages(
|
||||||
cfgRO = ocrCfg.ReadingOrder
|
cfgRO = ocrCfg.ReadingOrder
|
||||||
}
|
}
|
||||||
readingOrder := detectReadingOrder(m.Content, cfgRO)
|
readingOrder := detectReadingOrder(m.Content, cfgRO)
|
||||||
result[i].Content = al.replacePDFTags(
|
newContent := al.replacePDFTags(
|
||||||
ctx, m.Content, ocrCfg, channel, chatID, withFigures, readingOrder,
|
ctx, m.Content, ocrCfg, channel, chatID, withFigures, readingOrder,
|
||||||
)
|
)
|
||||||
|
// PDF was actually processed (content changed) → strip consumed keywords
|
||||||
|
if newContent != m.Content {
|
||||||
|
newContent = stripConsumedOCRKeywords(newContent, withFigures, readingOrder)
|
||||||
|
}
|
||||||
|
result[i].Content = newContent
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
|
||||||
|
|
@ -184,6 +184,8 @@ func (m *Manager) preSend(ctx context.Context, name string, msg bus.OutboundMess
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
// Clear orphan draft on failure to prevent stale streaming preview.
|
||||||
|
_ = drafter.SendDraft(ctx, msg.ChatID, entry.draftID, "")
|
||||||
}
|
}
|
||||||
m.statusEditTimes.Delete(key)
|
m.statusEditTimes.Delete(key)
|
||||||
// Draft update failed → fall through to placeholder path.
|
// Draft update failed → fall through to placeholder path.
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue