executePrompt runs the actual agent request and returns any error.
(messageParts []st.MessagePart)
| 220 | |
| 221 | // executePrompt runs the actual agent request and returns any error. |
| 222 | func (c *ACPConversation) executePrompt(messageParts []st.MessagePart) error { |
| 223 | // Drain any stale signal before sending the prompt. |
| 224 | select { |
| 225 | case <-c.chunkReceived: |
| 226 | default: |
| 227 | } |
| 228 | |
| 229 | var err error |
| 230 | for _, part := range messageParts { |
| 231 | if c.ctx.Err() != nil { |
| 232 | err = c.ctx.Err() |
| 233 | break |
| 234 | } |
| 235 | if partErr := part.Do(c.agentIO); partErr != nil { |
| 236 | err = partErr |
| 237 | break |
| 238 | } |
| 239 | } |
| 240 | |
| 241 | // The ACP SDK dispatches SessionUpdate notifications as goroutines, so |
| 242 | // the chunk may arrive after conn.Prompt() returns. Wait up to 100ms. |
| 243 | timer := c.clock.NewTimer(100 * time.Millisecond) |
| 244 | select { |
| 245 | case <-c.chunkReceived: |
| 246 | case <-timer.C: |
| 247 | } |
| 248 | timer.Stop() |
| 249 | |
| 250 | c.mu.Lock() |
| 251 | c.prompting = false |
| 252 | |
| 253 | if err != nil { |
| 254 | c.logger.Error("ACPConversation message failed", "error", err) |
| 255 | // Remove the agent's streaming message on error (may be empty or partial) |
| 256 | if len(c.messages) > 0 && c.messages[len(c.messages)-1].Role == st.ConversationRoleAgent { |
| 257 | c.messages = c.messages[:len(c.messages)-1] |
| 258 | } |
| 259 | messages := slices.Clone(c.messages) |
| 260 | status := c.statusLocked() |
| 261 | screen := c.streamingResponse.String() |
| 262 | c.mu.Unlock() |
| 263 | |
| 264 | c.emitter.EmitMessages(messages) |
| 265 | c.emitter.EmitStatus(status) |
| 266 | c.emitter.EmitScreen(screen) |
| 267 | return err |
| 268 | } |
| 269 | |
| 270 | // Final response should already be in the last message via streaming |
| 271 | // but ensure it's finalized |
| 272 | response := c.streamingResponse.String() |
| 273 | if len(c.messages) > 0 && c.messages[len(c.messages)-1].Role == st.ConversationRoleAgent { |
| 274 | // Intentionally not trimming space here. |
| 275 | c.messages[len(c.messages)-1].Message = response |
| 276 | } |
| 277 | messages := slices.Clone(c.messages) |
| 278 | status := c.statusLocked() |
| 279 | screen := c.streamingResponse.String() |
no test coverage detected