@@ -76,8 +76,8 @@ pub enum IrisTaskResult {
7676 StreamingComplete { task_type : TaskType } ,
7777 /// Semantic blame result
7878 SemanticBlame ( SemanticBlameResult ) ,
79- /// Error from the task
80- Error ( String ) ,
79+ /// Error from the task (includes which task failed)
80+ Error { task_type : TaskType , error : String } ,
8181}
8282
8383/// Type of content update triggered by chat
@@ -648,8 +648,6 @@ impl StudioApp {
648648 /// Check for completed Iris task results
649649 /// Convert async Iris results to events and push to queue
650650 fn check_iris_results ( & mut self ) {
651- use super :: state:: Modal ;
652-
653651 while let Ok ( result) = self . iris_result_rx . try_recv ( ) {
654652 let event = match result {
655653 IrisTaskResult :: CommitMessages ( messages) => StudioEvent :: AgentComplete {
@@ -709,13 +707,6 @@ impl StudioApp {
709707 IrisTaskResult :: ToolStatus { tool_name, message } => {
710708 // Tool status updates - move current tool to history, set new current
711709 let tool_desc = format ! ( "{} - {}" , tool_name, message) ;
712- if let Some ( Modal :: Chat ( chat) ) = & mut self . state . modal {
713- // Move previous tool to history (bounded)
714- if let Some ( prev) = chat. current_tool . take ( ) {
715- chat. add_tool_to_history ( prev) ;
716- }
717- chat. current_tool = Some ( tool_desc. clone ( ) ) ;
718- }
719710 if let Some ( prev) = self . state . chat_state . current_tool . take ( ) {
720711 self . state . chat_state . add_tool_to_history ( prev) ;
721712 }
@@ -738,31 +729,8 @@ impl StudioApp {
738729 StudioEvent :: StreamingComplete { task_type }
739730 }
740731
741- IrisTaskResult :: Error ( err) => {
742- // Determine which task failed based on what's currently generating
743- let task_type = if self . state . modes . commit . generating {
744- TaskType :: Commit
745- } else if self . state . modes . review . generating {
746- TaskType :: Review
747- } else if self . state . modes . pr . generating {
748- TaskType :: PR
749- } else if self . state . modes . changelog . generating {
750- TaskType :: Changelog
751- } else if self . state . modes . release_notes . generating {
752- TaskType :: ReleaseNotes
753- } else if matches ! ( & self . state. modal, Some ( Modal :: Chat ( c) ) if c. is_responding) {
754- TaskType :: Chat
755- } else if self . state . modes . explore . blame_loading {
756- TaskType :: SemanticBlame
757- } else {
758- // Default to commit if we can't determine
759- TaskType :: Commit
760- } ;
761-
762- StudioEvent :: AgentError {
763- task_type,
764- error : err,
765- }
732+ IrisTaskResult :: Error { task_type, error } => {
733+ StudioEvent :: AgentError { task_type, error }
766734 }
767735 } ;
768736
@@ -774,7 +742,7 @@ impl StudioApp {
774742 use crate :: agents:: StructuredResponse ;
775743 use crate :: agents:: status:: IRIS_STATUS ;
776744 use crate :: agents:: tools:: { ContentUpdate , create_content_update_channel} ;
777- use crate :: studio:: state:: { ChatMessage , ChatRole , Modal } ;
745+ use crate :: studio:: state:: { ChatMessage , ChatRole } ;
778746 use std:: sync:: Arc ;
779747 use std:: sync:: atomic:: { AtomicBool , Ordering } ;
780748
@@ -795,12 +763,9 @@ impl StudioApp {
795763 let tx_updates = self . iris_result_tx . clone ( ) ;
796764 let mode = context. mode ;
797765
798- // Extract conversation history from chat modal (convert VecDeque → Vec)
799- let chat_history: Vec < ChatMessage > = if let Some ( Modal :: Chat ( chat) ) = & self . state . modal {
800- chat. messages . iter ( ) . cloned ( ) . collect ( )
801- } else {
802- Vec :: new ( )
803- } ;
766+ // Extract conversation history (convert VecDeque → Vec)
767+ let chat_history: Vec < ChatMessage > =
768+ self . state . chat_state . messages . iter ( ) . cloned ( ) . collect ( ) ;
804769
805770 // Use context content if provided, otherwise extract from state
806771 let current_content = context
@@ -1036,9 +1001,10 @@ Simply call the appropriate tool with the new content. Do NOT echo back the full
10361001
10371002 let Some ( agent) = self . agent_service . clone ( ) else {
10381003 let tx = self . iris_result_tx . clone ( ) ;
1039- let _ = tx. send ( IrisTaskResult :: Error (
1040- "Agent service not available" . to_string ( ) ,
1041- ) ) ;
1004+ let _ = tx. send ( IrisTaskResult :: Error {
1005+ task_type : TaskType :: Review ,
1006+ error : "Agent service not available" . to_string ( ) ,
1007+ } ) ;
10421008 return ;
10431009 } ;
10441010
@@ -1050,7 +1016,10 @@ Simply call the appropriate tool with the new content. Do NOT echo back the full
10501016 let context = match TaskContext :: for_review ( None , Some ( from_ref) , Some ( to_ref) , false ) {
10511017 Ok ( ctx) => ctx,
10521018 Err ( e) => {
1053- let _ = tx. send ( IrisTaskResult :: Error ( format ! ( "Context error: {}" , e) ) ) ;
1019+ let _ = tx. send ( IrisTaskResult :: Error {
1020+ task_type : TaskType :: Review ,
1021+ error : format ! ( "Context error: {}" , e) ,
1022+ } ) ;
10541023 return ;
10551024 }
10561025 } ;
@@ -1086,7 +1055,10 @@ Simply call the appropriate tool with the new content. Do NOT echo back the full
10861055 let _ = tx. send ( IrisTaskResult :: ReviewContent ( review_text) ) ;
10871056 }
10881057 Err ( e) => {
1089- let _ = tx. send ( IrisTaskResult :: Error ( format ! ( "Review error: {}" , e) ) ) ;
1058+ let _ = tx. send ( IrisTaskResult :: Error {
1059+ task_type : TaskType :: Review ,
1060+ error : format ! ( "Review error: {}" , e) ,
1061+ } ) ;
10901062 }
10911063 }
10921064 } ) ;
@@ -1098,9 +1070,10 @@ Simply call the appropriate tool with the new content. Do NOT echo back the full
10981070
10991071 let Some ( agent) = self . agent_service . clone ( ) else {
11001072 let tx = self . iris_result_tx . clone ( ) ;
1101- let _ = tx. send ( IrisTaskResult :: Error (
1102- "Agent service not available" . to_string ( ) ,
1103- ) ) ;
1073+ let _ = tx. send ( IrisTaskResult :: Error {
1074+ task_type : TaskType :: PR ,
1075+ error : "Agent service not available" . to_string ( ) ,
1076+ } ) ;
11041077 return ;
11051078 } ;
11061079
@@ -1137,7 +1110,10 @@ Simply call the appropriate tool with the new content. Do NOT echo back the full
11371110 let _ = tx. send ( IrisTaskResult :: PRContent ( pr_text) ) ;
11381111 }
11391112 Err ( e) => {
1140- let _ = tx. send ( IrisTaskResult :: Error ( format ! ( "PR error: {}" , e) ) ) ;
1113+ let _ = tx. send ( IrisTaskResult :: Error {
1114+ task_type : TaskType :: PR ,
1115+ error : format ! ( "PR error: {}" , e) ,
1116+ } ) ;
11411117 }
11421118 }
11431119 } ) ;
@@ -1149,9 +1125,10 @@ Simply call the appropriate tool with the new content. Do NOT echo back the full
11491125
11501126 let Some ( agent) = self . agent_service . clone ( ) else {
11511127 let tx = self . iris_result_tx . clone ( ) ;
1152- let _ = tx. send ( IrisTaskResult :: Error (
1153- "Agent service not available" . to_string ( ) ,
1154- ) ) ;
1128+ let _ = tx. send ( IrisTaskResult :: Error {
1129+ task_type : TaskType :: Changelog ,
1130+ error : "Agent service not available" . to_string ( ) ,
1131+ } ) ;
11551132 return ;
11561133 } ;
11571134
@@ -1191,7 +1168,10 @@ Simply call the appropriate tool with the new content. Do NOT echo back the full
11911168 let _ = tx. send ( IrisTaskResult :: ChangelogContent ( changelog_text) ) ;
11921169 }
11931170 Err ( e) => {
1194- let _ = tx. send ( IrisTaskResult :: Error ( format ! ( "Changelog error: {}" , e) ) ) ;
1171+ let _ = tx. send ( IrisTaskResult :: Error {
1172+ task_type : TaskType :: Changelog ,
1173+ error : format ! ( "Changelog error: {}" , e) ,
1174+ } ) ;
11951175 }
11961176 }
11971177 } ) ;
@@ -1203,9 +1183,10 @@ Simply call the appropriate tool with the new content. Do NOT echo back the full
12031183
12041184 let Some ( agent) = self . agent_service . clone ( ) else {
12051185 let tx = self . iris_result_tx . clone ( ) ;
1206- let _ = tx. send ( IrisTaskResult :: Error (
1207- "Agent service not available" . to_string ( ) ,
1208- ) ) ;
1186+ let _ = tx. send ( IrisTaskResult :: Error {
1187+ task_type : TaskType :: ReleaseNotes ,
1188+ error : "Agent service not available" . to_string ( ) ,
1189+ } ) ;
12091190 return ;
12101191 } ;
12111192
@@ -1245,7 +1226,10 @@ Simply call the appropriate tool with the new content. Do NOT echo back the full
12451226 let _ = tx. send ( IrisTaskResult :: ReleaseNotesContent ( release_notes_text) ) ;
12461227 }
12471228 Err ( e) => {
1248- let _ = tx. send ( IrisTaskResult :: Error ( format ! ( "Release notes error: {}" , e) ) ) ;
1229+ let _ = tx. send ( IrisTaskResult :: Error {
1230+ task_type : TaskType :: ReleaseNotes ,
1231+ error : format ! ( "Release notes error: {}" , e) ,
1232+ } ) ;
12491233 }
12501234 }
12511235 } ) ;
@@ -1567,9 +1551,10 @@ Simply call the appropriate tool with the new content. Do NOT echo back the full
15671551
15681552 let Some ( agent) = self . agent_service . clone ( ) else {
15691553 let tx = self . iris_result_tx . clone ( ) ;
1570- let _ = tx. send ( IrisTaskResult :: Error (
1571- "Agent service not available" . to_string ( ) ,
1572- ) ) ;
1554+ let _ = tx. send ( IrisTaskResult :: Error {
1555+ task_type : TaskType :: Commit ,
1556+ error : "Agent service not available" . to_string ( ) ,
1557+ } ) ;
15731558 return ;
15741559 } ;
15751560
@@ -1597,14 +1582,18 @@ Simply call the appropriate tool with the new content. Do NOT echo back the full
15971582 let _ = tx. send ( IrisTaskResult :: CommitMessages ( vec ! [ msg] ) ) ;
15981583 }
15991584 _ => {
1600- let _ = tx. send ( IrisTaskResult :: Error (
1601- "Unexpected response type from agent" . to_string ( ) ,
1602- ) ) ;
1585+ let _ = tx. send ( IrisTaskResult :: Error {
1586+ task_type : TaskType :: Commit ,
1587+ error : "Unexpected response type from agent" . to_string ( ) ,
1588+ } ) ;
16031589 }
16041590 }
16051591 }
16061592 Err ( e) => {
1607- let _ = tx. send ( IrisTaskResult :: Error ( format ! ( "Agent error: {}" , e) ) ) ;
1593+ let _ = tx. send ( IrisTaskResult :: Error {
1594+ task_type : TaskType :: Commit ,
1595+ error : format ! ( "Agent error: {}" , e) ,
1596+ } ) ;
16081597 }
16091598 }
16101599 } ) ;
@@ -1617,9 +1606,10 @@ Simply call the appropriate tool with the new content. Do NOT echo back the full
16171606
16181607 let Some ( repo) = & self . state . repo else {
16191608 let tx = self . iris_result_tx . clone ( ) ;
1620- let _ = tx. send ( IrisTaskResult :: Error (
1621- "Repository not available" . to_string ( ) ,
1622- ) ) ;
1609+ let _ = tx. send ( IrisTaskResult :: Error {
1610+ task_type : TaskType :: SemanticBlame ,
1611+ error : "Repository not available" . to_string ( ) ,
1612+ } ) ;
16231613 return ;
16241614 } ;
16251615
@@ -1629,15 +1619,21 @@ Simply call the appropriate tool with the new content. Do NOT echo back the full
16291619 let lines: Vec < & str > = content. lines ( ) . collect ( ) ;
16301620 if start_line == 0 || start_line > lines. len ( ) {
16311621 let tx = self . iris_result_tx . clone ( ) ;
1632- let _ = tx. send ( IrisTaskResult :: Error ( "Invalid line range" . to_string ( ) ) ) ;
1622+ let _ = tx. send ( IrisTaskResult :: Error {
1623+ task_type : TaskType :: SemanticBlame ,
1624+ error : "Invalid line range" . to_string ( ) ,
1625+ } ) ;
16331626 return ;
16341627 }
16351628 let end = end_line. min ( lines. len ( ) ) ;
16361629 lines[ ( start_line - 1 ) ..end] . join ( "\n " )
16371630 }
16381631 Err ( e) => {
16391632 let tx = self . iris_result_tx . clone ( ) ;
1640- let _ = tx. send ( IrisTaskResult :: Error ( format ! ( "Could not read file: {}" , e) ) ) ;
1633+ let _ = tx. send ( IrisTaskResult :: Error {
1634+ task_type : TaskType :: SemanticBlame ,
1635+ error : format ! ( "Could not read file: {}" , e) ,
1636+ } ) ;
16411637 return ;
16421638 }
16431639 } ;
@@ -1666,12 +1662,18 @@ Simply call the appropriate tool with the new content. Do NOT echo back the full
16661662 Ok ( output) => {
16671663 let err = String :: from_utf8_lossy ( & output. stderr ) ;
16681664 let tx = self . iris_result_tx . clone ( ) ;
1669- let _ = tx. send ( IrisTaskResult :: Error ( format ! ( "Git blame failed: {}" , err) ) ) ;
1665+ let _ = tx. send ( IrisTaskResult :: Error {
1666+ task_type : TaskType :: SemanticBlame ,
1667+ error : format ! ( "Git blame failed: {}" , err) ,
1668+ } ) ;
16701669 return ;
16711670 }
16721671 Err ( e) => {
16731672 let tx = self . iris_result_tx . clone ( ) ;
1674- let _ = tx. send ( IrisTaskResult :: Error ( format ! ( "Could not run git: {}" , e) ) ) ;
1673+ let _ = tx. send ( IrisTaskResult :: Error {
1674+ task_type : TaskType :: SemanticBlame ,
1675+ error : format ! ( "Could not run git: {}" , e) ,
1676+ } ) ;
16751677 return ;
16761678 }
16771679 } ;
@@ -1697,9 +1699,10 @@ Simply call the appropriate tool with the new content. Do NOT echo back the full
16971699
16981700 let Some ( agent) = self . agent_service . clone ( ) else {
16991701 let tx = self . iris_result_tx . clone ( ) ;
1700- let _ = tx. send ( IrisTaskResult :: Error (
1701- "Agent service not available" . to_string ( ) ,
1702- ) ) ;
1702+ let _ = tx. send ( IrisTaskResult :: Error {
1703+ task_type : TaskType :: SemanticBlame ,
1704+ error : "Agent service not available" . to_string ( ) ,
1705+ } ) ;
17031706 return ;
17041707 } ;
17051708
@@ -1739,16 +1742,17 @@ Simply call the appropriate tool with the new content. Do NOT echo back the full
17391742 let _ = tx. send ( IrisTaskResult :: SemanticBlame ( result) ) ;
17401743 }
17411744 _ => {
1742- let _ = tx. send ( IrisTaskResult :: Error (
1743- "Unexpected response type from agent" . to_string ( ) ,
1744- ) ) ;
1745+ let _ = tx. send ( IrisTaskResult :: Error {
1746+ task_type : TaskType :: SemanticBlame ,
1747+ error : "Unexpected response type from agent" . to_string ( ) ,
1748+ } ) ;
17451749 }
17461750 } ,
17471751 Err ( e) => {
1748- let _ = tx. send ( IrisTaskResult :: Error ( format ! (
1749- "Semantic blame error: {}" ,
1750- e
1751- ) ) ) ;
1752+ let _ = tx. send ( IrisTaskResult :: Error {
1753+ task_type : TaskType :: SemanticBlame ,
1754+ error : format ! ( "Semantic blame error: {}" , e ) ,
1755+ } ) ;
17521756 }
17531757 }
17541758 } ) ;
0 commit comments