@@ -35,6 +35,31 @@ interface StreamingContext {
3535 model : string ;
3636}
3737
38+ /**
39+ * Check if a tool result indicates success (for tools that return { success: boolean })
40+ */
41+ function hasSuccessResult ( result : unknown ) : boolean {
42+ return (
43+ typeof result === "object" &&
44+ result !== null &&
45+ "success" in result &&
46+ result . success === true
47+ ) ;
48+ }
49+
50+ /**
51+ * Check if a tool result indicates failure (for tools that return { success: boolean })
52+ */
53+ function hasFailureResult ( result : unknown ) : boolean {
54+ return (
55+ typeof result === "object" &&
56+ result !== null &&
57+ "success" in result &&
58+ result . success === false
59+ ) ;
60+ }
61+
62+
3863export class StreamingMessageAggregator {
3964 private messages = new Map < string , CmuxMessage > ( ) ;
4065 private activeStreams = new Map < string , StreamingContext > ( ) ;
@@ -488,13 +513,7 @@ export class StreamingMessageAggregator {
488513 ( toolPart as DynamicToolPartAvailable ) . output = data . result ;
489514
490515 // Update TODO state if this was a successful todo_write
491- if (
492- data . toolName === "todo_write" &&
493- typeof data . result === "object" &&
494- data . result !== null &&
495- "success" in data . result &&
496- data . result . success
497- ) {
516+ if ( data . toolName === "todo_write" && hasSuccessResult ( data . result ) ) {
498517 const args = toolPart . input as { todos : TodoItem [ ] } ;
499518 // Only update if todos actually changed (prevents flickering from reference changes)
500519 if ( ! this . todosEqual ( this . currentTodos , args . todos ) ) {
@@ -503,13 +522,7 @@ export class StreamingMessageAggregator {
503522 }
504523
505524 // Update agent status if this was a successful status_set
506- if (
507- data . toolName === "status_set" &&
508- typeof data . result === "object" &&
509- data . result !== null &&
510- "success" in data . result &&
511- data . result . success
512- ) {
525+ if ( data . toolName === "status_set" && hasSuccessResult ( data . result ) ) {
513526 const args = toolPart . input as { emoji : string ; message : string } ;
514527 this . agentStatus = { emoji : args . emoji , message : args . message } ;
515528 }
@@ -773,12 +786,7 @@ export class StreamingMessageAggregator {
773786 let status : "pending" | "executing" | "completed" | "failed" | "interrupted" ;
774787 if ( part . state === "output-available" ) {
775788 // Check if result indicates failure (for tools that return { success: boolean })
776- const isFailed =
777- typeof part . output === "object" &&
778- part . output !== null &&
779- "success" in part . output &&
780- part . output . success === false ;
781- status = isFailed ? "failed" : "completed" ;
789+ status = hasFailureResult ( part . output ) ? "failed" : "completed" ;
782790 } else if ( part . state === "input-available" && message . metadata ?. partial ) {
783791 status = "interrupted" ;
784792 } else if ( part . state === "input-available" ) {
0 commit comments