Skip to content

Commit 4fdddf1

Browse files
committed
fix(orchestrator): send sliced messages in delta mode (not just tool results)
**Problem:** Previous fix removed hasToolResults check from slicing but left it in message selection logic. This caused "at least one message required" error because SAM sent ONLY tool results (no conversation messages) when statefulMarker existed. **Root Cause:** Two separate checks for hasToolResults: 1. Line 4284: Message slicing (FIXED in previous commit) 2. Line 4320: Message selection for delta mode (NOT FIXED - this commit) When statefulMarker existed without hasToolResults, messages were sliced correctly but then ONLY internalMessages (tool results) were sent, no messagesToSend! **Solution:** 1. Removed hasToolResults check from message selection (line 4320) 2. When statefulMarker exists, send BOTH: - Sliced conversation messages (messagesToSend) - Internal messages (tool calls + results) 3. This creates complete delta: new conversation context + tool results **Testing:** ✅ Build: PASS Next: Test with Claude conversation **Related:** Previous commit 29a4941
1 parent 29a4941 commit 4fdddf1

1 file changed

Lines changed: 24 additions & 7 deletions

File tree

Sources/APIFramework/AgentOrchestrator.swift

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4310,19 +4310,36 @@ public class AgentOrchestrator: ObservableObject, IterationController {
43104310

43114311
logger.debug("DEBUG_DUPLICATION: Adding \(messagesToSend.count) conversation messages to request")
43124312

4313-
/// When statefulMarker exists AND we have internal messages, send ONLY internalMessages (delta-only mode)
4313+
/// When statefulMarker exists, send delta (sliced messages + tool results)
43144314
/// This prevents duplicate assistant messages that cause Claude 400 errors
4315-
/// ROOT CAUSE: Assistant responses are in BOTH conversation.messages AND internalMessages
4316-
/// Our approach: internalMessages IS the delta (tool calls + results from previous iteration)
4315+
/// CRITICAL FIX: Always use delta mode when statefulMarker exists (not just when hasToolResults)
4316+
/// ROOT CAUSE: Sending full history + statefulMarker causes Claude to loop (sees own responses)
4317+
/// Our approach: Sliced messagesToSend + internalMessages IS the complete delta
43174318
/// Do NOT inject "Please continue" into messages array
43184319
/// GitHub Copilot API: "Please continue" is query param only, NOT a synthetic message
43194320
var currentMarker = statefulMarker /// Make mutable copy
4320-
if let marker = currentMarker, hasToolResults {
4321-
/// Delta-only mode: Server has full history up to marker, only send new tool execution context
4321+
if let marker = currentMarker {
4322+
/// Delta-only mode: Server has full history up to marker, only send new context
43224323
/// The stateful marker tells the API to continue from the previous response
4323-
/// We send ONLY the tool results (delta), not the full conversation history
4324+
/// We send ONLY the delta: sliced conversation messages + tool results
4325+
4326+
/// Add sliced conversation messages (already filtered by statefulMarkerMessageCount)
4327+
for (index, historyMessage) in messagesToSend.enumerated() {
4328+
let role = historyMessage.isFromUser ? "user" : "assistant"
4329+
var cleanContent = historyMessage.content
4330+
4331+
/// Clean tool call markers from assistant messages
4332+
if role == "assistant" {
4333+
cleanContent = cleanToolCallMarkers(from: cleanContent)
4334+
}
4335+
4336+
messages.append(OpenAIChatMessage(role: role, content: cleanContent))
4337+
logger.debug("DELTA_MESSAGE: Message \(index): role=\(role), content=\(cleanContent.safePrefix(50))")
4338+
}
4339+
4340+
/// Add internal messages (tool calls + results from current iteration)
43244341
messages.append(contentsOf: messagesToAppend)
4325-
logger.debug("STATEFUL_MARKER_DELTA_MODE: Sending \(internalMessages.count) internal messages (delta-only mode, no synthetic user message)")
4342+
logger.debug("STATEFUL_MARKER_DELTA_MODE: Sending \(messagesToSend.count) conversation + \(internalMessages.count) internal messages (delta-only mode)")
43264343

43274344
/// CRITICAL: Enforce 16KB payload limit (vscode-copilot-chat pattern)
43284345
/// Even with cached large tool results, accumulated deltas can exceed limit

0 commit comments

Comments
 (0)