Tool progress markers (e.g. `⏰ list`) were injected directly into SSE delta.content chunks. OpenAI-compatible frontends (Open WebUI, LobeChat, etc.) store delta.content verbatim as the assistant message and send it back on subsequent requests. After enough turns, the model learns to emit these markers as plain text instead of issuing real tool calls — silently hallucinating tool results without ever running them. Fix: Send tool progress as a custom `event: hermes.tool.progress` SSE event instead of mixing it into delta.content. Per the SSE spec, clients that don't understand a custom event type silently ignore it, so this is backward-compatible. Frontends that want to render progress indicators can listen for the custom event without persisting it to conversation history. The /v1/runs endpoint already uses structured events — this aligns the /v1/chat/completions streaming path with the same principle. Closes #6972
75 KiB
75 KiB