@probelabs/probe 0.6.0-rc269 → 0.6.0-rc270

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3582,23 +3582,24 @@ Follow these instructions carefully:
3582
3582
  // Continue even if storage fails
3583
3583
  }
3584
3584
 
3585
- // Completion prompt handling - run a follow-up prompt after attempt_completion for validation/review
3586
- // This runs BEFORE mermaid validation and JSON schema validation
3587
- // Skip if we're already in a completion prompt follow-up call or if no completion prompt is configured
3585
+ // Completion prompt handling - inject one more user message into the existing conversation
3586
+ // This continues the SAME agentic session (same tools, same TaskManager, same history)
3587
+ // rather than spawning a recursive this.answer() call which would reset state
3588
3588
  if (completionAttempted && this.completionPrompt && !options._completionPromptProcessed) {
3589
3589
  if (this.debug) {
3590
- console.log('[DEBUG] Running completion prompt for post-completion validation/review...');
3590
+ console.log('[DEBUG] Running completion prompt as continuation of current session...');
3591
3591
  }
3592
3592
 
3593
3593
  try {
3594
- // Record completion prompt start in telemetry
3594
+ const originalResult = finalResult;
3595
+
3595
3596
  if (this.tracer) {
3596
3597
  this.tracer.recordEvent('completion_prompt.started', {
3597
3598
  'completion_prompt.original_result_length': finalResult?.length || 0
3598
3599
  });
3599
3600
  }
3600
3601
 
3601
- // Create the completion prompt with the current result as context
3602
+ // Append completion prompt as a user message to the existing conversation
3602
3603
  const completionPromptMessage = `${this.completionPrompt}
3603
3604
 
3604
3605
  Here is the result to review:
@@ -3606,34 +3607,82 @@ Here is the result to review:
3606
3607
  ${finalResult}
3607
3608
  </result>
3608
3609
 
3609
- After reviewing, provide your final answer using attempt_completion.`;
3610
+ Double-check your response based on the criteria above. If everything looks good, respond with your previous answer exactly as-is using attempt_completion. If something needs to be fixed or is missing, do it now, then respond with the COMPLETE updated answer (everything you did in total, not just the fix) using attempt_completion.`;
3610
3611
 
3611
- // Make a follow-up call with the completion prompt
3612
- // Pass _completionPromptProcessed to prevent infinite loops
3613
- // Save output buffers the recursive answer() must not destroy DSL output() content
3614
- const savedOutputItems = this._outputBuffer ? [...this._outputBuffer.items] : [];
3615
- const savedExtractedBlocks = this._extractedRawBlocks ? [...this._extractedRawBlocks] : [];
3616
- const completionResult = await this.answer(completionPromptMessage, [], {
3617
- ...options,
3618
- _completionPromptProcessed: true
3619
- });
3620
- // Restore output buffers so the parent call can append them to the final result
3621
- if (this._outputBuffer) {
3622
- this._outputBuffer.items = savedOutputItems;
3612
+ currentMessages.push({ role: 'user', content: completionPromptMessage });
3613
+
3614
+ // Reset completion tracking for the follow-up turn
3615
+ completionResult = null;
3616
+ completionAttempted = false;
3617
+
3618
+ // Run one more streamText pass with the same tools and conversation context
3619
+ // Give a small number of extra iterations for the follow-up
3620
+ const completionMaxIterations = 5;
3621
+ const completionStreamOptions = {
3622
+ model: this.provider ? this.provider(this.model) : this.model,
3623
+ messages: this.prepareMessagesWithImages(currentMessages),
3624
+ tools,
3625
+ stopWhen: stepCountIs(completionMaxIterations),
3626
+ maxTokens: maxResponseTokens,
3627
+ temperature: 0.3,
3628
+ onStepFinish: ({ toolResults, text, finishReason, usage }) => {
3629
+ if (usage) {
3630
+ this.tokenCounter.recordUsage(usage);
3631
+ }
3632
+ if (options.onStream && text) {
3633
+ options.onStream(text);
3634
+ }
3635
+ if (this.debug) {
3636
+ console.log(`[DEBUG] Completion prompt step finished (reason: ${finishReason}, tools: ${toolResults?.length || 0})`);
3637
+ }
3638
+ }
3639
+ };
3640
+
3641
+ const providerOpts = this._buildThinkingProviderOptions(maxResponseTokens);
3642
+ if (providerOpts) {
3643
+ completionStreamOptions.providerOptions = providerOpts;
3644
+ }
3645
+
3646
+ const cpResult = await this.streamTextWithRetryAndFallback(completionStreamOptions);
3647
+ const cpFinalText = await cpResult.text;
3648
+ const cpUsage = await cpResult.usage;
3649
+ if (cpUsage) {
3650
+ this.tokenCounter.recordUsage(cpUsage, cpResult.experimental_providerMetadata);
3651
+ }
3652
+
3653
+ // Append follow-up messages to conversation history
3654
+ const cpMessages = await cpResult.response?.messages;
3655
+ if (cpMessages) {
3656
+ for (const msg of cpMessages) {
3657
+ currentMessages.push(msg);
3658
+ }
3623
3659
  }
3624
- this._extractedRawBlocks = savedExtractedBlocks;
3625
3660
 
3626
- // Update finalResult with the result from the completion prompt
3627
- finalResult = completionResult;
3661
+ // Use new completion result if the agent called attempt_completion again,
3662
+ // otherwise keep the original result (the follow-up may have just done side-effects)
3663
+ if (completionResult) {
3664
+ finalResult = completionResult;
3665
+ completionAttempted = true;
3666
+ } else if (cpFinalText && cpFinalText.trim().length > 0) {
3667
+ finalResult = cpFinalText;
3668
+ completionAttempted = true;
3669
+ } else {
3670
+ // Follow-up produced nothing useful — keep the original
3671
+ finalResult = originalResult;
3672
+ completionAttempted = true;
3673
+ if (this.debug) {
3674
+ console.log('[DEBUG] Completion prompt returned empty result, keeping original.');
3675
+ }
3676
+ }
3628
3677
 
3629
3678
  if (this.debug) {
3630
- console.log(`[DEBUG] Completion prompt finished. New result length: ${finalResult?.length || 0}`);
3679
+ console.log(`[DEBUG] Completion prompt finished. Final result length: ${finalResult?.length || 0}`);
3631
3680
  }
3632
3681
 
3633
- // Record completion prompt completion in telemetry
3634
3682
  if (this.tracer) {
3635
3683
  this.tracer.recordEvent('completion_prompt.completed', {
3636
- 'completion_prompt.final_result_length': finalResult?.length || 0
3684
+ 'completion_prompt.final_result_length': finalResult?.length || 0,
3685
+ 'completion_prompt.used_original': finalResult === originalResult
3637
3686
  });
3638
3687
  }
3639
3688
  } catch (error) {
@@ -84554,9 +84554,10 @@ You are working with a workspace. Available paths: ${workspaceDesc}
84554
84554
  }
84555
84555
  if (completionAttempted && this.completionPrompt && !options._completionPromptProcessed) {
84556
84556
  if (this.debug) {
84557
- console.log("[DEBUG] Running completion prompt for post-completion validation/review...");
84557
+ console.log("[DEBUG] Running completion prompt as continuation of current session...");
84558
84558
  }
84559
84559
  try {
84560
+ const originalResult = finalResult;
84560
84561
  if (this.tracer) {
84561
84562
  this.tracer.recordEvent("completion_prompt.started", {
84562
84563
  "completion_prompt.original_result_length": finalResult?.length || 0
@@ -84569,24 +84570,66 @@ Here is the result to review:
84569
84570
  ${finalResult}
84570
84571
  </result>
84571
84572
 
84572
- After reviewing, provide your final answer using attempt_completion.`;
84573
- const savedOutputItems = this._outputBuffer ? [...this._outputBuffer.items] : [];
84574
- const savedExtractedBlocks = this._extractedRawBlocks ? [...this._extractedRawBlocks] : [];
84575
- const completionResult2 = await this.answer(completionPromptMessage, [], {
84576
- ...options,
84577
- _completionPromptProcessed: true
84578
- });
84579
- if (this._outputBuffer) {
84580
- this._outputBuffer.items = savedOutputItems;
84573
+ Double-check your response based on the criteria above. If everything looks good, respond with your previous answer exactly as-is using attempt_completion. If something needs to be fixed or is missing, do it now, then respond with the COMPLETE updated answer (everything you did in total, not just the fix) using attempt_completion.`;
84574
+ currentMessages.push({ role: "user", content: completionPromptMessage });
84575
+ completionResult = null;
84576
+ completionAttempted = false;
84577
+ const completionMaxIterations = 5;
84578
+ const completionStreamOptions = {
84579
+ model: this.provider ? this.provider(this.model) : this.model,
84580
+ messages: this.prepareMessagesWithImages(currentMessages),
84581
+ tools: tools2,
84582
+ stopWhen: stepCountIs(completionMaxIterations),
84583
+ maxTokens: maxResponseTokens,
84584
+ temperature: 0.3,
84585
+ onStepFinish: ({ toolResults, text, finishReason, usage }) => {
84586
+ if (usage) {
84587
+ this.tokenCounter.recordUsage(usage);
84588
+ }
84589
+ if (options.onStream && text) {
84590
+ options.onStream(text);
84591
+ }
84592
+ if (this.debug) {
84593
+ console.log(`[DEBUG] Completion prompt step finished (reason: ${finishReason}, tools: ${toolResults?.length || 0})`);
84594
+ }
84595
+ }
84596
+ };
84597
+ const providerOpts = this._buildThinkingProviderOptions(maxResponseTokens);
84598
+ if (providerOpts) {
84599
+ completionStreamOptions.providerOptions = providerOpts;
84600
+ }
84601
+ const cpResult = await this.streamTextWithRetryAndFallback(completionStreamOptions);
84602
+ const cpFinalText = await cpResult.text;
84603
+ const cpUsage = await cpResult.usage;
84604
+ if (cpUsage) {
84605
+ this.tokenCounter.recordUsage(cpUsage, cpResult.experimental_providerMetadata);
84606
+ }
84607
+ const cpMessages = await cpResult.response?.messages;
84608
+ if (cpMessages) {
84609
+ for (const msg of cpMessages) {
84610
+ currentMessages.push(msg);
84611
+ }
84612
+ }
84613
+ if (completionResult) {
84614
+ finalResult = completionResult;
84615
+ completionAttempted = true;
84616
+ } else if (cpFinalText && cpFinalText.trim().length > 0) {
84617
+ finalResult = cpFinalText;
84618
+ completionAttempted = true;
84619
+ } else {
84620
+ finalResult = originalResult;
84621
+ completionAttempted = true;
84622
+ if (this.debug) {
84623
+ console.log("[DEBUG] Completion prompt returned empty result, keeping original.");
84624
+ }
84581
84625
  }
84582
- this._extractedRawBlocks = savedExtractedBlocks;
84583
- finalResult = completionResult2;
84584
84626
  if (this.debug) {
84585
- console.log(`[DEBUG] Completion prompt finished. New result length: ${finalResult?.length || 0}`);
84627
+ console.log(`[DEBUG] Completion prompt finished. Final result length: ${finalResult?.length || 0}`);
84586
84628
  }
84587
84629
  if (this.tracer) {
84588
84630
  this.tracer.recordEvent("completion_prompt.completed", {
84589
- "completion_prompt.final_result_length": finalResult?.length || 0
84631
+ "completion_prompt.final_result_length": finalResult?.length || 0,
84632
+ "completion_prompt.used_original": finalResult === originalResult
84590
84633
  });
84591
84634
  }
84592
84635
  } catch (error) {
@@ -111502,9 +111502,10 @@ You are working with a workspace. Available paths: ${workspaceDesc}
111502
111502
  }
111503
111503
  if (completionAttempted && this.completionPrompt && !options._completionPromptProcessed) {
111504
111504
  if (this.debug) {
111505
- console.log("[DEBUG] Running completion prompt for post-completion validation/review...");
111505
+ console.log("[DEBUG] Running completion prompt as continuation of current session...");
111506
111506
  }
111507
111507
  try {
111508
+ const originalResult = finalResult;
111508
111509
  if (this.tracer) {
111509
111510
  this.tracer.recordEvent("completion_prompt.started", {
111510
111511
  "completion_prompt.original_result_length": finalResult?.length || 0
@@ -111517,24 +111518,66 @@ Here is the result to review:
111517
111518
  ${finalResult}
111518
111519
  </result>
111519
111520
 
111520
- After reviewing, provide your final answer using attempt_completion.`;
111521
- const savedOutputItems = this._outputBuffer ? [...this._outputBuffer.items] : [];
111522
- const savedExtractedBlocks = this._extractedRawBlocks ? [...this._extractedRawBlocks] : [];
111523
- const completionResult2 = await this.answer(completionPromptMessage, [], {
111524
- ...options,
111525
- _completionPromptProcessed: true
111526
- });
111527
- if (this._outputBuffer) {
111528
- this._outputBuffer.items = savedOutputItems;
111521
+ Double-check your response based on the criteria above. If everything looks good, respond with your previous answer exactly as-is using attempt_completion. If something needs to be fixed or is missing, do it now, then respond with the COMPLETE updated answer (everything you did in total, not just the fix) using attempt_completion.`;
111522
+ currentMessages.push({ role: "user", content: completionPromptMessage });
111523
+ completionResult = null;
111524
+ completionAttempted = false;
111525
+ const completionMaxIterations = 5;
111526
+ const completionStreamOptions = {
111527
+ model: this.provider ? this.provider(this.model) : this.model,
111528
+ messages: this.prepareMessagesWithImages(currentMessages),
111529
+ tools: tools2,
111530
+ stopWhen: (0, import_ai6.stepCountIs)(completionMaxIterations),
111531
+ maxTokens: maxResponseTokens,
111532
+ temperature: 0.3,
111533
+ onStepFinish: ({ toolResults, text, finishReason, usage }) => {
111534
+ if (usage) {
111535
+ this.tokenCounter.recordUsage(usage);
111536
+ }
111537
+ if (options.onStream && text) {
111538
+ options.onStream(text);
111539
+ }
111540
+ if (this.debug) {
111541
+ console.log(`[DEBUG] Completion prompt step finished (reason: ${finishReason}, tools: ${toolResults?.length || 0})`);
111542
+ }
111543
+ }
111544
+ };
111545
+ const providerOpts = this._buildThinkingProviderOptions(maxResponseTokens);
111546
+ if (providerOpts) {
111547
+ completionStreamOptions.providerOptions = providerOpts;
111548
+ }
111549
+ const cpResult = await this.streamTextWithRetryAndFallback(completionStreamOptions);
111550
+ const cpFinalText = await cpResult.text;
111551
+ const cpUsage = await cpResult.usage;
111552
+ if (cpUsage) {
111553
+ this.tokenCounter.recordUsage(cpUsage, cpResult.experimental_providerMetadata);
111554
+ }
111555
+ const cpMessages = await cpResult.response?.messages;
111556
+ if (cpMessages) {
111557
+ for (const msg of cpMessages) {
111558
+ currentMessages.push(msg);
111559
+ }
111560
+ }
111561
+ if (completionResult) {
111562
+ finalResult = completionResult;
111563
+ completionAttempted = true;
111564
+ } else if (cpFinalText && cpFinalText.trim().length > 0) {
111565
+ finalResult = cpFinalText;
111566
+ completionAttempted = true;
111567
+ } else {
111568
+ finalResult = originalResult;
111569
+ completionAttempted = true;
111570
+ if (this.debug) {
111571
+ console.log("[DEBUG] Completion prompt returned empty result, keeping original.");
111572
+ }
111529
111573
  }
111530
- this._extractedRawBlocks = savedExtractedBlocks;
111531
- finalResult = completionResult2;
111532
111574
  if (this.debug) {
111533
- console.log(`[DEBUG] Completion prompt finished. New result length: ${finalResult?.length || 0}`);
111575
+ console.log(`[DEBUG] Completion prompt finished. Final result length: ${finalResult?.length || 0}`);
111534
111576
  }
111535
111577
  if (this.tracer) {
111536
111578
  this.tracer.recordEvent("completion_prompt.completed", {
111537
- "completion_prompt.final_result_length": finalResult?.length || 0
111579
+ "completion_prompt.final_result_length": finalResult?.length || 0,
111580
+ "completion_prompt.used_original": finalResult === originalResult
111538
111581
  });
111539
111582
  }
111540
111583
  } catch (error2) {
package/cjs/index.cjs CHANGED
@@ -108797,9 +108797,10 @@ You are working with a workspace. Available paths: ${workspaceDesc}
108797
108797
  }
108798
108798
  if (completionAttempted && this.completionPrompt && !options._completionPromptProcessed) {
108799
108799
  if (this.debug) {
108800
- console.log("[DEBUG] Running completion prompt for post-completion validation/review...");
108800
+ console.log("[DEBUG] Running completion prompt as continuation of current session...");
108801
108801
  }
108802
108802
  try {
108803
+ const originalResult = finalResult;
108803
108804
  if (this.tracer) {
108804
108805
  this.tracer.recordEvent("completion_prompt.started", {
108805
108806
  "completion_prompt.original_result_length": finalResult?.length || 0
@@ -108812,24 +108813,66 @@ Here is the result to review:
108812
108813
  ${finalResult}
108813
108814
  </result>
108814
108815
 
108815
- After reviewing, provide your final answer using attempt_completion.`;
108816
- const savedOutputItems = this._outputBuffer ? [...this._outputBuffer.items] : [];
108817
- const savedExtractedBlocks = this._extractedRawBlocks ? [...this._extractedRawBlocks] : [];
108818
- const completionResult2 = await this.answer(completionPromptMessage, [], {
108819
- ...options,
108820
- _completionPromptProcessed: true
108821
- });
108822
- if (this._outputBuffer) {
108823
- this._outputBuffer.items = savedOutputItems;
108816
+ Double-check your response based on the criteria above. If everything looks good, respond with your previous answer exactly as-is using attempt_completion. If something needs to be fixed or is missing, do it now, then respond with the COMPLETE updated answer (everything you did in total, not just the fix) using attempt_completion.`;
108817
+ currentMessages.push({ role: "user", content: completionPromptMessage });
108818
+ completionResult = null;
108819
+ completionAttempted = false;
108820
+ const completionMaxIterations = 5;
108821
+ const completionStreamOptions = {
108822
+ model: this.provider ? this.provider(this.model) : this.model,
108823
+ messages: this.prepareMessagesWithImages(currentMessages),
108824
+ tools: tools2,
108825
+ stopWhen: (0, import_ai4.stepCountIs)(completionMaxIterations),
108826
+ maxTokens: maxResponseTokens,
108827
+ temperature: 0.3,
108828
+ onStepFinish: ({ toolResults, text, finishReason, usage }) => {
108829
+ if (usage) {
108830
+ this.tokenCounter.recordUsage(usage);
108831
+ }
108832
+ if (options.onStream && text) {
108833
+ options.onStream(text);
108834
+ }
108835
+ if (this.debug) {
108836
+ console.log(`[DEBUG] Completion prompt step finished (reason: ${finishReason}, tools: ${toolResults?.length || 0})`);
108837
+ }
108838
+ }
108839
+ };
108840
+ const providerOpts = this._buildThinkingProviderOptions(maxResponseTokens);
108841
+ if (providerOpts) {
108842
+ completionStreamOptions.providerOptions = providerOpts;
108843
+ }
108844
+ const cpResult = await this.streamTextWithRetryAndFallback(completionStreamOptions);
108845
+ const cpFinalText = await cpResult.text;
108846
+ const cpUsage = await cpResult.usage;
108847
+ if (cpUsage) {
108848
+ this.tokenCounter.recordUsage(cpUsage, cpResult.experimental_providerMetadata);
108849
+ }
108850
+ const cpMessages = await cpResult.response?.messages;
108851
+ if (cpMessages) {
108852
+ for (const msg of cpMessages) {
108853
+ currentMessages.push(msg);
108854
+ }
108855
+ }
108856
+ if (completionResult) {
108857
+ finalResult = completionResult;
108858
+ completionAttempted = true;
108859
+ } else if (cpFinalText && cpFinalText.trim().length > 0) {
108860
+ finalResult = cpFinalText;
108861
+ completionAttempted = true;
108862
+ } else {
108863
+ finalResult = originalResult;
108864
+ completionAttempted = true;
108865
+ if (this.debug) {
108866
+ console.log("[DEBUG] Completion prompt returned empty result, keeping original.");
108867
+ }
108824
108868
  }
108825
- this._extractedRawBlocks = savedExtractedBlocks;
108826
- finalResult = completionResult2;
108827
108869
  if (this.debug) {
108828
- console.log(`[DEBUG] Completion prompt finished. New result length: ${finalResult?.length || 0}`);
108870
+ console.log(`[DEBUG] Completion prompt finished. Final result length: ${finalResult?.length || 0}`);
108829
108871
  }
108830
108872
  if (this.tracer) {
108831
108873
  this.tracer.recordEvent("completion_prompt.completed", {
108832
- "completion_prompt.final_result_length": finalResult?.length || 0
108874
+ "completion_prompt.final_result_length": finalResult?.length || 0,
108875
+ "completion_prompt.used_original": finalResult === originalResult
108833
108876
  });
108834
108877
  }
108835
108878
  } catch (error2) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@probelabs/probe",
3
- "version": "0.6.0-rc269",
3
+ "version": "0.6.0-rc270",
4
4
  "description": "Node.js wrapper for the probe code search tool",
5
5
  "main": "src/index.js",
6
6
  "module": "src/index.js",
@@ -3582,23 +3582,24 @@ Follow these instructions carefully:
3582
3582
  // Continue even if storage fails
3583
3583
  }
3584
3584
 
3585
- // Completion prompt handling - run a follow-up prompt after attempt_completion for validation/review
3586
- // This runs BEFORE mermaid validation and JSON schema validation
3587
- // Skip if we're already in a completion prompt follow-up call or if no completion prompt is configured
3585
+ // Completion prompt handling - inject one more user message into the existing conversation
3586
+ // This continues the SAME agentic session (same tools, same TaskManager, same history)
3587
+ // rather than spawning a recursive this.answer() call which would reset state
3588
3588
  if (completionAttempted && this.completionPrompt && !options._completionPromptProcessed) {
3589
3589
  if (this.debug) {
3590
- console.log('[DEBUG] Running completion prompt for post-completion validation/review...');
3590
+ console.log('[DEBUG] Running completion prompt as continuation of current session...');
3591
3591
  }
3592
3592
 
3593
3593
  try {
3594
- // Record completion prompt start in telemetry
3594
+ const originalResult = finalResult;
3595
+
3595
3596
  if (this.tracer) {
3596
3597
  this.tracer.recordEvent('completion_prompt.started', {
3597
3598
  'completion_prompt.original_result_length': finalResult?.length || 0
3598
3599
  });
3599
3600
  }
3600
3601
 
3601
- // Create the completion prompt with the current result as context
3602
+ // Append completion prompt as a user message to the existing conversation
3602
3603
  const completionPromptMessage = `${this.completionPrompt}
3603
3604
 
3604
3605
  Here is the result to review:
@@ -3606,34 +3607,82 @@ Here is the result to review:
3606
3607
  ${finalResult}
3607
3608
  </result>
3608
3609
 
3609
- After reviewing, provide your final answer using attempt_completion.`;
3610
+ Double-check your response based on the criteria above. If everything looks good, respond with your previous answer exactly as-is using attempt_completion. If something needs to be fixed or is missing, do it now, then respond with the COMPLETE updated answer (everything you did in total, not just the fix) using attempt_completion.`;
3610
3611
 
3611
- // Make a follow-up call with the completion prompt
3612
- // Pass _completionPromptProcessed to prevent infinite loops
3613
- // Save output buffers the recursive answer() must not destroy DSL output() content
3614
- const savedOutputItems = this._outputBuffer ? [...this._outputBuffer.items] : [];
3615
- const savedExtractedBlocks = this._extractedRawBlocks ? [...this._extractedRawBlocks] : [];
3616
- const completionResult = await this.answer(completionPromptMessage, [], {
3617
- ...options,
3618
- _completionPromptProcessed: true
3619
- });
3620
- // Restore output buffers so the parent call can append them to the final result
3621
- if (this._outputBuffer) {
3622
- this._outputBuffer.items = savedOutputItems;
3612
+ currentMessages.push({ role: 'user', content: completionPromptMessage });
3613
+
3614
+ // Reset completion tracking for the follow-up turn
3615
+ completionResult = null;
3616
+ completionAttempted = false;
3617
+
3618
+ // Run one more streamText pass with the same tools and conversation context
3619
+ // Give a small number of extra iterations for the follow-up
3620
+ const completionMaxIterations = 5;
3621
+ const completionStreamOptions = {
3622
+ model: this.provider ? this.provider(this.model) : this.model,
3623
+ messages: this.prepareMessagesWithImages(currentMessages),
3624
+ tools,
3625
+ stopWhen: stepCountIs(completionMaxIterations),
3626
+ maxTokens: maxResponseTokens,
3627
+ temperature: 0.3,
3628
+ onStepFinish: ({ toolResults, text, finishReason, usage }) => {
3629
+ if (usage) {
3630
+ this.tokenCounter.recordUsage(usage);
3631
+ }
3632
+ if (options.onStream && text) {
3633
+ options.onStream(text);
3634
+ }
3635
+ if (this.debug) {
3636
+ console.log(`[DEBUG] Completion prompt step finished (reason: ${finishReason}, tools: ${toolResults?.length || 0})`);
3637
+ }
3638
+ }
3639
+ };
3640
+
3641
+ const providerOpts = this._buildThinkingProviderOptions(maxResponseTokens);
3642
+ if (providerOpts) {
3643
+ completionStreamOptions.providerOptions = providerOpts;
3644
+ }
3645
+
3646
+ const cpResult = await this.streamTextWithRetryAndFallback(completionStreamOptions);
3647
+ const cpFinalText = await cpResult.text;
3648
+ const cpUsage = await cpResult.usage;
3649
+ if (cpUsage) {
3650
+ this.tokenCounter.recordUsage(cpUsage, cpResult.experimental_providerMetadata);
3651
+ }
3652
+
3653
+ // Append follow-up messages to conversation history
3654
+ const cpMessages = await cpResult.response?.messages;
3655
+ if (cpMessages) {
3656
+ for (const msg of cpMessages) {
3657
+ currentMessages.push(msg);
3658
+ }
3623
3659
  }
3624
- this._extractedRawBlocks = savedExtractedBlocks;
3625
3660
 
3626
- // Update finalResult with the result from the completion prompt
3627
- finalResult = completionResult;
3661
+ // Use new completion result if the agent called attempt_completion again,
3662
+ // otherwise keep the original result (the follow-up may have just done side-effects)
3663
+ if (completionResult) {
3664
+ finalResult = completionResult;
3665
+ completionAttempted = true;
3666
+ } else if (cpFinalText && cpFinalText.trim().length > 0) {
3667
+ finalResult = cpFinalText;
3668
+ completionAttempted = true;
3669
+ } else {
3670
+ // Follow-up produced nothing useful — keep the original
3671
+ finalResult = originalResult;
3672
+ completionAttempted = true;
3673
+ if (this.debug) {
3674
+ console.log('[DEBUG] Completion prompt returned empty result, keeping original.');
3675
+ }
3676
+ }
3628
3677
 
3629
3678
  if (this.debug) {
3630
- console.log(`[DEBUG] Completion prompt finished. New result length: ${finalResult?.length || 0}`);
3679
+ console.log(`[DEBUG] Completion prompt finished. Final result length: ${finalResult?.length || 0}`);
3631
3680
  }
3632
3681
 
3633
- // Record completion prompt completion in telemetry
3634
3682
  if (this.tracer) {
3635
3683
  this.tracer.recordEvent('completion_prompt.completed', {
3636
- 'completion_prompt.final_result_length': finalResult?.length || 0
3684
+ 'completion_prompt.final_result_length': finalResult?.length || 0,
3685
+ 'completion_prompt.used_original': finalResult === originalResult
3637
3686
  });
3638
3687
  }
3639
3688
  } catch (error) {