Add live steering injection into running chains
Let the user inject a message into a running chain instead of only being
able to abort it. While a chain streams, typing + Enter sends the text to
a new /api/chat/steer endpoint; it is drained at the next iteration
boundary, wrapped with a hint so the model actively classifies it
("complements the task -> keep working" vs. "changes course -> adjust"),
and stored as a Type="steer" user message so it survives reload.
Shared infrastructure (provider-agnostic):
- SteeringQueue: out-of-band queue keyed by sessionId, mirrored from
StreamingTracker (Enqueue/Drain/Clear).
- Program.cs registers it as a singleton and passes it to AnthropicService.
- ChatEndpoint: POST /api/chat/steer enqueues only while IsStreaming,
Clear() in the finally.
- ChatService.BuildHistoryFromDb groups Type="steer" so no two
consecutive user turns are produced on re-chat.
- Frontend api.js/chat.js/bubbles.js/history.js + chat.css render the
optimistic steer bubble and the steer_injected SSE event; Enter during
a stream sends a steer instead of being blocked.
Anthropic API path:
- Drain point B (tool boundary, merged into the tool_result user turn)
and C (turn end -> inject + continue instead of finalize).
Claude CLI path (kill-and-restart):
- The agentic loop runs inside the claude child, so true mid-turn inject
is impossible. On a pending steer the child is killed at the next tool
boundary, progress is rebuilt from the DB as a <work_in_progress>
transcript, and the CLI is restarted with the steer appended.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
a58f279eaa
commit
f2fd493e5f
12 files changed
+555
-132
No files matched your search
@@ -43,11 +43,12 @@ public partial class AnthropicService
|
||||
private readonly ServerSettingsService _settings;
|
||||
private readonly VectorSearchService _vectorSearch;
|
||||
private readonly EmbeddingBackgroundService _embeddingBg;
|
||||
private readonly SteeringQueue _steeringQueue;
|
||||
private ChatService _chatService;
|
||||
private TelegramService _telegramService;
|
||||
private ClaudeCliService _cliService;
|
||||
|
||||
public AnthropicService(IHttpClientFactory httpFactory, ToolService toolService, DatabaseService db, MemoryService memoryService = null, ServerSettingsService settings = null, VectorSearchService vectorSearch = null, EmbeddingBackgroundService embeddingBg = null)
|
||||
public AnthropicService(IHttpClientFactory httpFactory, ToolService toolService, DatabaseService db, MemoryService memoryService = null, ServerSettingsService settings = null, VectorSearchService vectorSearch = null, EmbeddingBackgroundService embeddingBg = null, SteeringQueue steeringQueue = null)
|
||||
{
|
||||
_httpFactory = httpFactory;
|
||||
_toolService = toolService;
|
||||
@@ -56,6 +57,7 @@ public partial class AnthropicService
|
||||
_settings = settings;
|
||||
_vectorSearch = vectorSearch;
|
||||
_embeddingBg = embeddingBg;
|
||||
_steeringQueue = steeringQueue;
|
||||
}
|
||||
|
||||
public void SetCliService(ClaudeCliService cliService)
|
||||
|
||||
Reference in new issue
Block a user