@@ -1518,6 +1518,42 @@ function loadReportIncompleteMessages(items) {
15181518 }
15191519}
15201520
1521+ const DIAGNOSTIC_AGENT_OUTPUT_TYPES = new Set ( [ "noop" , "missing_tool" , "missing_data" , "report_incomplete" ] ) ;
1522+ const TASK_COMPLETE_REGISTRATION_SIGNALS = [ "not registering" , "not registered" , "not recognizing" , "not recognized" , "recognition issue" , "not yet marked" , "haven't marked" , "tool calls are not registering" ] ;
1523+ const TASK_COMPLETE_COMPLETION_SIGNALS = [ "completed successfully" , "safe-output" , "safe output" , "no remaining work" ] ;
1524+ const TASK_COMPLETE_COMPLETION_REGEXPS = [ / \b a n a l y s i s s t e p s ? c o m p l e t e d \b / , / \b a l l s t e p s c o m p l e t e d \b / ] ;
1525+
1526+ /**
1527+ * Determine whether agent output contains at least one real task-level item.
1528+ * @param {Array<any> | undefined } items
1529+ * @returns {boolean }
1530+ */
1531+ function hasTaskLevelAgentOutput ( items ) {
1532+ if ( ! Array . isArray ( items ) ) {
1533+ return false ;
1534+ }
1535+ return items . some ( item => item && typeof item . type === "string" && ! DIAGNOSTIC_AGENT_OUTPUT_TYPES . has ( item . type ) ) ;
1536+ }
1537+
1538+ /**
1539+ * Detect a spurious report_incomplete caused only by task_complete registration/recognition
1540+ * trouble after the agent already finished the real task work.
1541+ * @param {{reason?: string, details?: string} | undefined } item
1542+ * @returns {boolean }
1543+ */
1544+ function isTaskCompleteRegistrationIssue ( item ) {
1545+ if ( ! item ) {
1546+ return false ;
1547+ }
1548+ const text = `${ item . reason || "" } \n${ item . details || "" } ` . toLowerCase ( ) ;
1549+ if ( ! text . includes ( "task_complete" ) ) {
1550+ return false ;
1551+ }
1552+ const hasRegistrationSignal = TASK_COMPLETE_REGISTRATION_SIGNALS . some ( signal => text . includes ( signal ) ) ;
1553+ const hasCompletionSignal = TASK_COMPLETE_COMPLETION_SIGNALS . some ( signal => text . includes ( signal ) ) || TASK_COMPLETE_COMPLETION_REGEXPS . some ( regexp => regexp . test ( text ) ) ;
1554+ return hasRegistrationSignal && hasCompletionSignal ;
1555+ }
1556+
15211557/**
15221558 * Build report_incomplete context string for display in failure issues/comments.
15231559 * This surfaces the agent's structured incompletion signal so maintainers can
@@ -2964,6 +3000,13 @@ async function main() {
29643000 let hasCompletedDespiteJobFailure = false ;
29653001 const { loadAgentOutput } = require ( "./load_agent_output.cjs" ) ;
29663002 const agentOutputResult = loadAgentOutput ( ) ;
3003+ const taskCompleteRegistrationIssueOnlyReportIncomplete =
3004+ agentOutputResult . success &&
3005+ agentOutputResult . items &&
3006+ agentOutputResult . items . some ( item => item . type === "report_incomplete" ) &&
3007+ hasAgentTerminalReasonCompleted ( ) &&
3008+ hasTaskLevelAgentOutput ( agentOutputResult . items ) &&
3009+ agentOutputResult . items . filter ( item => item . type === "report_incomplete" ) . every ( isTaskCompleteRegistrationIssue ) ;
29673010
29683011 if ( agentConclusion === "success" ) {
29693012 if ( ! agentOutputResult . success || ! agentOutputResult . items || agentOutputResult . items . length === 0 ) {
@@ -2987,7 +3030,7 @@ async function main() {
29873030 if ( nonNoopItems . length === 0 ) {
29883031 hasOnlyNoopOutputs = true ;
29893032 core . info ( "Agent failed with exit code 1 but produced only noop outputs - treating as successful no-action (transient AI model error)" ) ;
2990- } else if ( ! nonNoopItems . some ( item => item . type === "report_incomplete" ) ) {
3033+ } else if ( ! nonNoopItems . some ( item => item . type === "report_incomplete" && ! isTaskCompleteRegistrationIssue ( item ) ) ) {
29913034 // The agent produced valid non-noop safe outputs (e.g. create_discussion) but the
29923035 // job exit code is non-zero. If terminal_reason: completed is present in the log,
29933036 // the failure was a transient error after the agent finished its task — do not report
@@ -3008,10 +3051,14 @@ async function main() {
30083051 if ( agentOutputResult . success && agentOutputResult . items && agentOutputResult . items . length > 0 ) {
30093052 const reportIncompleteItems = agentOutputResult . items . filter ( item => item . type === "report_incomplete" ) ;
30103053 if ( reportIncompleteItems . length > 0 ) {
3011- hasReportIncomplete = true ;
3012- core . info ( `Agent emitted ${ reportIncompleteItems . length } report_incomplete signal(s) - activating failure handling` ) ;
3013- for ( const item of reportIncompleteItems ) {
3014- core . info ( ` report_incomplete reason: ${ item . reason } ` ) ;
3054+ if ( taskCompleteRegistrationIssueOnlyReportIncomplete ) {
3055+ core . info ( "Ignoring report_incomplete signal(s) caused only by task_complete registration trouble after successful task-level outputs" ) ;
3056+ } else {
3057+ hasReportIncomplete = true ;
3058+ core . info ( `Agent emitted ${ reportIncompleteItems . length } report_incomplete signal(s) - activating failure handling` ) ;
3059+ for ( const item of reportIncompleteItems ) {
3060+ core . info ( ` report_incomplete reason: ${ item . reason } ` ) ;
3061+ }
30153062 }
30163063 }
30173064 }
0 commit comments