Skip to content

Commit aa0f29d

Browse files
authored
Fix: Ensure step messages represent input only (#884)
1 parent 7ebf450 commit aa0f29d

28 files changed

Lines changed: 290 additions & 171 deletions

File tree

src/Providers/Anthropic/Handlers/Stream.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,13 @@ protected function handleToolCalls(Request $request, int $depth): Generator
503503

504504
// Add messages to request for next turn
505505
if ($toolResults !== []) {
506+
// Emit step finish after tool calls
507+
$this->state->markStepFinished();
508+
yield new StepFinishEvent(
509+
id: EventID::generate(),
510+
timestamp: time()
511+
);
512+
506513
$request->addMessage(new AssistantMessage(
507514
content: $this->state->currentText(),
508515
toolCalls: $toolCalls,
@@ -515,13 +522,6 @@ protected function handleToolCalls(Request $request, int $depth): Generator
515522
$request->addMessage(new ToolResultMessage($toolResults));
516523
$request->resetToolChoice();
517524

518-
// Emit step finish after tool calls
519-
$this->state->markStepFinished();
520-
yield new StepFinishEvent(
521-
id: EventID::generate(),
522-
timestamp: time()
523-
);
524-
525525
// Continue streaming if within step limit
526526
$depth++;
527527
if ($depth < $request->maxSteps()) {

src/Providers/Anthropic/Handlers/Text.php

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,6 @@ public function handle(): Response
5252

5353
$this->prepareTempResponse();
5454

55-
$responseMessage = new AssistantMessage(
56-
$this->tempResponse->text,
57-
$this->tempResponse->toolCalls,
58-
$this->tempResponse->additionalContent,
59-
);
60-
61-
$this->request->addMessage($responseMessage);
62-
6355
return match ($this->tempResponse->finishReason) {
6456
FinishReason::ToolCalls => $this->handleToolCalls(),
6557
FinishReason::Stop, FinishReason::Length => $this->handleStop(),
@@ -102,18 +94,25 @@ public static function buildHttpRequestPayload(PrismRequest $request): array
10294
protected function handleToolCalls(): Response
10395
{
10496
$toolResults = $this->callTools($this->request->tools(), $this->tempResponse->toolCalls);
105-
$message = new ToolResultMessage($toolResults);
97+
98+
$this->addStep($toolResults);
99+
100+
$this->request->addMessage(new AssistantMessage(
101+
$this->tempResponse->text,
102+
$this->tempResponse->toolCalls,
103+
$this->tempResponse->additionalContent,
104+
));
105+
106+
$toolResultMessage = new ToolResultMessage($toolResults);
106107

107108
// Apply tool result caching if configured
108109
if ($tool_result_cache_type = $this->request->providerOptions('tool_result_cache_type')) {
109-
$message->withProviderOptions(['cacheType' => $tool_result_cache_type]);
110+
$toolResultMessage->withProviderOptions(['cacheType' => $tool_result_cache_type]);
110111
}
111112

112-
$this->request->addMessage($message);
113+
$this->request->addMessage($toolResultMessage);
113114
$this->request->resetToolChoice();
114115

115-
$this->addStep($toolResults);
116-
117116
if ($this->responseBuilder->steps->count() < $this->request->maxSteps()) {
118117
return $this->handle();
119118
}

src/Providers/DeepSeek/Handlers/Stream.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -383,16 +383,16 @@ protected function handleToolCalls(Request $request, string $text, array $toolCa
383383
$toolResults = [];
384384
yield from $this->callToolsAndYieldEvents($request->tools(), $mappedToolCalls, $this->state->messageId(), $toolResults);
385385

386-
$request->addMessage(new AssistantMessage($text, $mappedToolCalls));
387-
$request->addMessage(new ToolResultMessage($toolResults));
388-
$request->resetToolChoice();
389-
390386
$this->state->markStepFinished();
391387
yield new StepFinishEvent(
392388
id: EventID::generate(),
393389
timestamp: time()
394390
);
395391

392+
$request->addMessage(new AssistantMessage($text, $mappedToolCalls));
393+
$request->addMessage(new ToolResultMessage($toolResults));
394+
$request->resetToolChoice();
395+
396396
$this->state->resetTextState();
397397
$this->state->withMessageId(EventID::generate());
398398

src/Providers/DeepSeek/Handlers/Text.php

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,6 @@ public function handle(Request $request): TextResponse
4545

4646
$this->validateResponse($data);
4747

48-
$responseMessage = new AssistantMessage(
49-
data_get($data, 'choices.0.message.content') ?? '',
50-
ToolCallMap::map(data_get($data, 'choices.0.message.tool_calls', [])),
51-
[]
52-
);
53-
54-
$request = $request->addMessage($responseMessage);
55-
5648
return match ($this->mapFinishReason($data)) {
5749
FinishReason::ToolCalls => $this->handleToolCalls($data, $request),
5850
FinishReason::Stop => $this->handleStop($data, $request),
@@ -65,16 +57,20 @@ public function handle(Request $request): TextResponse
6557
*/
6658
protected function handleToolCalls(array $data, Request $request): TextResponse
6759
{
68-
$toolResults = $this->callTools(
69-
$request->tools(),
70-
ToolCallMap::map(data_get($data, 'choices.0.message.tool_calls', []))
71-
);
60+
$toolCalls = ToolCallMap::map(data_get($data, 'choices.0.message.tool_calls', []));
7261

73-
$request = $request->addMessage(new ToolResultMessage($toolResults));
74-
$request->resetToolChoice();
62+
$toolResults = $this->callTools($request->tools(), $toolCalls);
7563

7664
$this->addStep($data, $request, $toolResults);
7765

66+
$request = $request->addMessage(new AssistantMessage(
67+
data_get($data, 'choices.0.message.content') ?? '',
68+
$toolCalls,
69+
[]
70+
));
71+
$request = $request->addMessage(new ToolResultMessage($toolResults));
72+
$request->resetToolChoice();
73+
7874
if ($this->shouldContinue($request)) {
7975
return $this->handle($request);
8076
}

src/Providers/Gemini/Handlers/Stream.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -337,17 +337,17 @@ protected function handleToolCalls(
337337
yield from $this->callToolsAndYieldEvents($request->tools(), $mappedToolCalls, $this->state->messageId(), $toolResults);
338338

339339
if ($toolResults !== []) {
340-
$request->addMessage(new AssistantMessage($this->state->currentText(), $mappedToolCalls));
341-
$request->addMessage(new ToolResultMessage($toolResults));
342-
$request->resetToolChoice();
343-
344340
// Emit step finish after tool calls
345341
$this->state->markStepFinished();
346342
yield new StepFinishEvent(
347343
id: EventID::generate(),
348344
timestamp: time()
349345
);
350346

347+
$request->addMessage(new AssistantMessage($this->state->currentText(), $mappedToolCalls));
348+
$request->addMessage(new ToolResultMessage($toolResults));
349+
$request->resetToolChoice();
350+
351351
$depth++;
352352
if ($depth < $request->maxSteps()) {
353353
$previousUsage = $this->state->usage();

src/Providers/Gemini/Handlers/Text.php

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,6 @@ public function handle(Request $request): TextResponse
5151

5252
$isToolCall = $this->hasToolCalls($data);
5353

54-
$responseMessage = new AssistantMessage(
55-
$this->extractTextContent($data),
56-
$isToolCall ? ToolCallMap::map(data_get($data, 'candidates.0.content.parts', [])) : [],
57-
);
58-
59-
$request->addMessage($responseMessage);
60-
6154
$finishReason = FinishReasonMap::map(
6255
data_get($data, 'candidates.0.finishReason'),
6356
$isToolCall
@@ -147,16 +140,19 @@ protected function handleStop(array $data, Request $request, FinishReason $finis
147140
*/
148141
protected function handleToolCalls(array $data, Request $request): TextResponse
149142
{
150-
$toolResults = $this->callTools(
151-
$request->tools(),
152-
ToolCallMap::map(data_get($data, 'candidates.0.content.parts', []))
153-
);
143+
$toolCalls = ToolCallMap::map(data_get($data, 'candidates.0.content.parts', []));
154144

155-
$request->addMessage(new ToolResultMessage($toolResults));
156-
$request->resetToolChoice();
145+
$toolResults = $this->callTools($request->tools(), $toolCalls);
157146

158147
$this->addStep($data, $request, FinishReason::ToolCalls, $toolResults);
159148

149+
$request->addMessage(new AssistantMessage(
150+
$this->extractTextContent($data),
151+
$toolCalls,
152+
));
153+
$request->addMessage(new ToolResultMessage($toolResults));
154+
$request->resetToolChoice();
155+
160156
if ($this->shouldContinue($request)) {
161157
return $this->handle($request);
162158
}

src/Providers/Groq/Handlers/Stream.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -279,17 +279,17 @@ protected function handleToolCalls(
279279
$toolResults = [];
280280
yield from $this->callToolsAndYieldEvents($request->tools(), $mappedToolCalls, $this->state->messageId(), $toolResults);
281281

282-
$request->addMessage(new AssistantMessage($text, $mappedToolCalls));
283-
$request->addMessage(new ToolResultMessage($toolResults));
284-
$request->resetToolChoice();
285-
286282
// Emit step finish after tool calls
287283
$this->state->markStepFinished();
288284
yield new StepFinishEvent(
289285
id: EventID::generate(),
290286
timestamp: time()
291287
);
292288

289+
$request->addMessage(new AssistantMessage($text, $mappedToolCalls));
290+
$request->addMessage(new ToolResultMessage($toolResults));
291+
$request->resetToolChoice();
292+
293293
// Reset text state for next response
294294
$this->state->resetTextState();
295295
$this->state->withMessageId(EventID::generate());

src/Providers/Groq/Handlers/Text.php

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,6 @@ public function handle(Request $request): TextResponse
4646

4747
$data = $response->json();
4848

49-
$responseMessage = new AssistantMessage(
50-
data_get($data, 'choices.0.message.content') ?? '',
51-
$this->mapToolCalls(data_get($data, 'choices.0.message.tool_calls', []) ?? []),
52-
);
53-
54-
$request->addMessage($responseMessage);
55-
5649
$finishReason = FinishReasonMap::map(data_get($data, 'choices.0.finish_reason', ''));
5750

5851
return match ($finishReason) {
@@ -86,16 +79,19 @@ protected function sendRequest(Request $request): ClientResponse
8679
*/
8780
protected function handleToolCalls(array $data, Request $request, ClientResponse $clientResponse): TextResponse
8881
{
89-
$toolResults = $this->callTools(
90-
$request->tools(),
91-
$this->mapToolCalls(data_get($data, 'choices.0.message.tool_calls', []) ?? []),
92-
);
82+
$toolCalls = $this->mapToolCalls(data_get($data, 'choices.0.message.tool_calls', []) ?? []);
9383

94-
$request->addMessage(new ToolResultMessage($toolResults));
95-
$request->resetToolChoice();
84+
$toolResults = $this->callTools($request->tools(), $toolCalls);
9685

9786
$this->addStep($data, $request, $clientResponse, FinishReason::ToolCalls, $toolResults);
9887

88+
$request->addMessage(new AssistantMessage(
89+
data_get($data, 'choices.0.message.content') ?? '',
90+
$toolCalls,
91+
));
92+
$request->addMessage(new ToolResultMessage($toolResults));
93+
$request->resetToolChoice();
94+
9995
if ($this->shouldContinue($request)) {
10096
return $this->handle($request);
10197
}

src/Providers/Mistral/Handlers/Stream.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -323,16 +323,16 @@ protected function handleToolCalls(
323323
$toolResults = [];
324324
yield from $this->callToolsAndYieldEvents($request->tools(), $mappedToolCalls, $this->state->messageId(), $toolResults);
325325

326-
$request->addMessage(new AssistantMessage($text, $mappedToolCalls));
327-
$request->addMessage(new ToolResultMessage($toolResults));
328-
$request->resetToolChoice();
329-
330326
$this->state->markStepFinished();
331327
yield new StepFinishEvent(
332328
id: EventID::generate(),
333329
timestamp: time()
334330
);
335331

332+
$request->addMessage(new AssistantMessage($text, $mappedToolCalls));
333+
$request->addMessage(new ToolResultMessage($toolResults));
334+
$request->resetToolChoice();
335+
336336
$this->state->resetTextState();
337337
$this->state->withMessageId(EventID::generate());
338338

src/Providers/Mistral/Handlers/Text.php

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,6 @@ public function handle(Request $request): Response
5353

5454
$data = $response->json();
5555

56-
$responseMessage = new AssistantMessage(
57-
$this->extractText(data_get($data, 'choices.0.message', [])),
58-
$this->mapToolCalls(data_get($data, 'choices.0.message.tool_calls', [])),
59-
);
60-
61-
$request->addMessage($responseMessage);
62-
6356
return match ($this->mapFinishReason($data)) {
6457
FinishReason::ToolCalls => $this->handleToolCalls($data, $request, $response),
6558
FinishReason::Stop => $this->handleStop($data, $request, $response),
@@ -72,16 +65,19 @@ public function handle(Request $request): Response
7265
*/
7366
protected function handleToolCalls(array $data, Request $request, ClientResponse $clientResponse): Response
7467
{
75-
$toolResults = $this->callTools(
76-
$request->tools(),
77-
$this->mapToolCalls(data_get($data, 'choices.0.message.tool_calls', [])),
78-
);
68+
$toolCalls = $this->mapToolCalls(data_get($data, 'choices.0.message.tool_calls', []));
7969

80-
$request->addMessage(new ToolResultMessage($toolResults));
81-
$request->resetToolChoice();
70+
$toolResults = $this->callTools($request->tools(), $toolCalls);
8271

8372
$this->addStep($data, $request, $clientResponse, $toolResults);
8473

74+
$request->addMessage(new AssistantMessage(
75+
$this->extractText(data_get($data, 'choices.0.message', [])),
76+
$toolCalls,
77+
));
78+
$request->addMessage(new ToolResultMessage($toolResults));
79+
$request->resetToolChoice();
80+
8581
if ($this->shouldContinue($request)) {
8682
return $this->handle($request);
8783
}

0 commit comments

Comments
 (0)