11// Helper functions extracted from streamChatResponse.ts to reduce file size
22
3+ import type { ToolStatus } from "core/index.js" ;
34import { ContinueError , ContinueErrorReason } from "core/util/errors.js" ;
45import { ChatCompletionToolMessageParam } from "openai/resources/chat/completions.mjs" ;
56
@@ -27,6 +28,10 @@ import { logger } from "../util/logger.js";
2728
2829import { StreamCallbacks } from "./streamChatResponse.types.js" ;
2930
31+ export interface ToolResultWithStatus extends ChatCompletionToolMessageParam {
32+ status : ToolStatus ;
33+ }
34+
3035// Helper function to handle permission denied
3136export function handlePermissionDenied (
3237 toolCall : PreprocessedToolCall ,
@@ -389,15 +394,15 @@ export async function preprocessStreamedToolCalls(
389394 * Executes preprocessed tool calls, handling permissions and results
390395 * @param preprocessedCalls - The preprocessed tool calls ready for execution
391396 * @param callbacks - Optional callbacks for notifying of events
392- * @returns - Chat history entries with tool results
397+ * @returns - Chat history entries with tool results and status information
393398 */
394399export async function executeStreamedToolCalls (
395400 preprocessedCalls : PreprocessedToolCall [ ] ,
396401 callbacks ?: StreamCallbacks ,
397402 isHeadless ?: boolean ,
398403) : Promise < {
399404 hasRejection : boolean ;
400- chatHistoryEntries : ChatCompletionToolMessageParam [ ] ;
405+ chatHistoryEntries : ToolResultWithStatus [ ] ;
401406} > {
402407 // Strategy: queue permissions (preserve order), then run approved tools in parallel.
403408 // If any permission is rejected, cancel the remaining tools in this batch.
@@ -408,7 +413,7 @@ export async function executeStreamedToolCalls(
408413 call,
409414 } ) ) ;
410415
411- const entriesByIndex = new Map < number , ChatCompletionToolMessageParam > ( ) ;
416+ const entriesByIndex = new Map < number , ToolResultWithStatus > ( ) ;
412417 const execPromises : Promise < void > [ ] = [ ] ;
413418
414419 let hasRejection = false ;
@@ -439,17 +444,18 @@ export async function executeStreamedToolCalls(
439444 ) ;
440445
441446 if ( ! permissionResult . approved ) {
442- // Permission denied: record and mark rejection
447+ // Permission denied: create entry with canceled status
443448 const denialReason = permissionResult . denialReason || "user" ;
444449 const deniedMessage =
445450 denialReason === "policy"
446451 ? `Command blocked by security policy`
447452 : `Permission denied by user` ;
448453
449- const deniedEntry : ChatCompletionToolMessageParam = {
454+ const deniedEntry : ToolResultWithStatus = {
450455 role : "tool" ,
451456 tool_call_id : call . id ,
452457 content : deniedMessage ,
458+ status : "canceled" ,
453459 } ;
454460 entriesByIndex . set ( index , deniedEntry ) ;
455461 callbacks ?. onToolResult ?.(
@@ -484,10 +490,11 @@ export async function executeStreamedToolCalls(
484490 arguments : call . arguments ,
485491 } ) ;
486492 const toolResult = await executeToolCall ( call ) ;
487- const entry : ChatCompletionToolMessageParam = {
493+ const entry : ToolResultWithStatus = {
488494 role : "tool" ,
489495 tool_call_id : call . id ,
490496 content : toolResult ,
497+ status : "done" ,
491498 } ;
492499 entriesByIndex . set ( index , entry ) ;
493500 callbacks ?. onToolResult ?.( toolResult , call . name , "done" ) ;
@@ -511,6 +518,7 @@ export async function executeStreamedToolCalls(
511518 role : "tool" ,
512519 tool_call_id : call . id ,
513520 content : errorMessage ,
521+ status : "errored" ,
514522 } ) ;
515523 callbacks ?. onToolError ?.( errorMessage , call . name ) ;
516524 // Immediate service update for UI feedback
@@ -536,6 +544,7 @@ export async function executeStreamedToolCalls(
536544 role : "tool" ,
537545 tool_call_id : call . id ,
538546 content : errorMessage ,
547+ status : "errored" ,
539548 } ) ;
540549 callbacks ?. onToolError ?.( errorMessage , call . name ) ;
541550 // Treat permission errors like execution errors but do not stop the batch
@@ -552,9 +561,9 @@ export async function executeStreamedToolCalls(
552561 await Promise . all ( execPromises ) ;
553562
554563 // Assemble final entries in original order
555- const chatHistoryEntries : ChatCompletionToolMessageParam [ ] = preprocessedCalls
564+ const chatHistoryEntries : ToolResultWithStatus [ ] = preprocessedCalls
556565 . map ( ( _ , index ) => entriesByIndex . get ( index ) )
557- . filter ( ( e ) : e is ChatCompletionToolMessageParam => ! ! e ) ;
566+ . filter ( ( e ) : e is ToolResultWithStatus => ! ! e ) ;
558567
559568 return {
560569 hasRejection,
0 commit comments