@@ -671,41 +671,22 @@ export class ImplementSessionManager {
671671 if ( ! this . deps . llm ) {
672672 throw new Error ( "implement_experiments is configured for staged_llm mode, but no LLM client is available." ) ;
673673 }
674- const llmTimeoutMs = getImplementLlmTimeoutMs ( ) ;
675- const timeoutController = new AbortController ( ) ;
676- const timeoutId = setTimeout ( ( ) => timeoutController . abort ( ) , llmTimeoutMs ) ;
677- const llmAbortSignal = abortSignal
678- ? AbortSignal . any ( [ abortSignal , timeoutController . signal ] )
679- : timeoutController . signal ;
680- try {
681- const completion = await this . deps . llm . complete ( attemptPrompt , {
682- systemPrompt : attemptSystemPrompt ,
683- abortSignal : llmAbortSignal ,
684- onProgress : ( event ) => {
685- const text = event . text . trim ( ) ;
686- if ( ! text ) {
687- return ;
688- }
689- emitImplementObservation ( "codex" , event . type === "delta" ? `LLM> ${ text } ` : text , {
690- attempt,
691- threadId : activeThreadId ,
692- publicDir : defaultPublicDir
693- } ) ;
694- }
695- } ) ;
696- result = {
697- threadId : activeThreadId ,
698- finalText : completion . text ,
699- events : [ ]
700- } ;
701- } catch ( error ) {
702- if ( timeoutController . signal . aborted && ! abortSignal ?. aborted ) {
703- throw new Error ( `implement_experiments staged_llm request timed out after ${ llmTimeoutMs } ms` ) ;
704- }
705- throw error ;
706- } finally {
707- clearTimeout ( timeoutId ) ;
708- }
674+ const llmTimeoutMs = getImplementLlmTimeoutMs ( this . deps . config ) ;
675+ const completion = await this . completeStagedLlmRequest ( {
676+ prompt : attemptPrompt ,
677+ systemPrompt : attemptSystemPrompt ,
678+ timeoutMs : llmTimeoutMs ,
679+ abortSignal,
680+ attempt,
681+ threadId : activeThreadId ,
682+ publicDir : defaultPublicDir ,
683+ emitImplementObservation
684+ } ) ;
685+ result = {
686+ threadId : completion . threadId || activeThreadId ,
687+ finalText : completion . text ,
688+ events : [ ]
689+ } ;
709690 }
710691 } catch ( error ) {
711692 const errorMessage = error instanceof Error ? error . message : String ( error ) ;
@@ -1368,9 +1349,7 @@ export class ImplementSessionManager {
13681349 const previousSummary = await runContext . get < string > ( "implement_experiments.last_summary" ) ;
13691350 const previousRunCommand = await runContext . get < string > ( "implement_experiments.run_command" ) ;
13701351 const previousScript = await runContext . get < string > ( "implement_experiments.script" ) ;
1371- const runnerFeedback =
1372- ( await runContext . get < RunVerifierReport > ( "implement_experiments.runner_feedback" ) ) ||
1373- ( await runContext . get < RunVerifierReport > ( "run_experiments.feedback_for_implementer" ) ) ;
1352+ const runnerFeedback = await this . loadApplicableRunnerFeedback ( run , runContext ) ;
13741353 const paperCritique = await runContext . get < {
13751354 overall_decision ?: string ;
13761355 manuscript_type ?: string ;
@@ -1461,6 +1440,33 @@ export class ImplementSessionManager {
14611440 } ;
14621441 }
14631442
1443+ private async loadApplicableRunnerFeedback (
1444+ run : RunRecord ,
1445+ runContext : RunContextMemory
1446+ ) : Promise < RunVerifierReport | undefined > {
1447+ const runnerFeedback =
1448+ ( await runContext . get < RunVerifierReport > ( "implement_experiments.runner_feedback" ) ) ||
1449+ ( await runContext . get < RunVerifierReport > ( "run_experiments.feedback_for_implementer" ) ) ;
1450+ if ( ! runnerFeedback ) {
1451+ return undefined ;
1452+ }
1453+ if ( run . graph . nodeStates . run_experiments ?. status === "failed" ) {
1454+ return runnerFeedback ;
1455+ }
1456+ const feedbackRecordedAt = Date . parse ( runnerFeedback . recorded_at || "" ) ;
1457+ const designUpdatedAt = Date . parse ( run . graph . nodeStates . design_experiments ?. updatedAt || "" ) ;
1458+ if (
1459+ Number . isFinite ( feedbackRecordedAt ) &&
1460+ Number . isFinite ( designUpdatedAt ) &&
1461+ designUpdatedAt > feedbackRecordedAt
1462+ ) {
1463+ await runContext . put ( "implement_experiments.runner_feedback" , null ) ;
1464+ await runContext . put ( "run_experiments.feedback_for_implementer" , null ) ;
1465+ return undefined ;
1466+ }
1467+ return runnerFeedback ;
1468+ }
1469+
14641470 private buildAttemptPrompt ( params : {
14651471 taskSpec : ImplementTaskSpec ;
14661472 searchLocalization : LocalizationResult ;
@@ -1618,6 +1624,64 @@ export class ImplementSessionManager {
16181624 return lines . join ( "\n" ) ;
16191625 }
16201626
1627+ private async completeStagedLlmRequest ( input : {
1628+ prompt : string ;
1629+ systemPrompt : string ;
1630+ timeoutMs : number ;
1631+ abortSignal ?: AbortSignal ;
1632+ attempt : number ;
1633+ threadId ?: string ;
1634+ publicDir : string ;
1635+ emitImplementObservation : (
1636+ stage : ImplementProgressStage ,
1637+ message : string ,
1638+ extras ?: Partial < ImplementProgressStatus >
1639+ ) => void ;
1640+ reasoningEffort ?: string ;
1641+ } ) : Promise < { text : string ; threadId ?: string } > {
1642+ const timeoutController = input . timeoutMs > 0 ? new AbortController ( ) : undefined ;
1643+ const timeoutId = timeoutController
1644+ ? setTimeout ( ( ) => timeoutController . abort ( ) , input . timeoutMs )
1645+ : undefined ;
1646+ const llmAbortSignal = timeoutController
1647+ ? input . abortSignal
1648+ ? AbortSignal . any ( [ input . abortSignal , timeoutController . signal ] )
1649+ : timeoutController . signal
1650+ : input . abortSignal ;
1651+ try {
1652+ const completion = await this . deps . llm ! . complete ( input . prompt , {
1653+ threadId : input . threadId ,
1654+ systemPrompt : input . systemPrompt ,
1655+ reasoningEffort : input . reasoningEffort ,
1656+ abortSignal : llmAbortSignal ,
1657+ onProgress : ( event ) => {
1658+ const text = event . text . trim ( ) ;
1659+ if ( ! text ) {
1660+ return ;
1661+ }
1662+ input . emitImplementObservation ( "codex" , event . type === "delta" ? `LLM> ${ text } ` : text , {
1663+ attempt : input . attempt ,
1664+ threadId : input . threadId ,
1665+ publicDir : input . publicDir
1666+ } ) ;
1667+ }
1668+ } ) ;
1669+ return {
1670+ text : completion . text ,
1671+ threadId : completion . threadId
1672+ } ;
1673+ } catch ( error ) {
1674+ if ( timeoutController ?. signal . aborted && ! input . abortSignal ?. aborted ) {
1675+ throw new Error ( `implement_experiments staged_llm request timed out after ${ input . timeoutMs } ms` ) ;
1676+ }
1677+ throw error ;
1678+ } finally {
1679+ if ( timeoutId ) {
1680+ clearTimeout ( timeoutId ) ;
1681+ }
1682+ }
1683+ }
1684+
16211685 private buildLocalizerInput (
16221686 taskSpec : ImplementTaskSpec ,
16231687 previousAttempt : AttemptRecord | undefined ,
@@ -2964,9 +3028,13 @@ function stripDryRunFlag(command: string | undefined): string | undefined {
29643028 return stripped || undefined ;
29653029}
29663030
2967- function getImplementLlmTimeoutMs ( ) : number {
3031+ export function getImplementLlmTimeoutMs ( config : AppConfig ) : number {
29683032 const parsed = Number . parseInt ( process . env . AUTOLABOS_IMPLEMENT_LLM_TIMEOUT_MS || "" , 10 ) ;
2969- return Number . isFinite ( parsed ) && parsed > 0 ? parsed : 60_000 ;
3033+ if ( Number . isFinite ( parsed ) && parsed > 0 ) {
3034+ return parsed ;
3035+ }
3036+ void config ;
3037+ return 0 ;
29703038}
29713039
29723040function isDryRunMetricsRepairFeedback ( report : RunVerifierReport | undefined ) : boolean {
0 commit comments