11import { createLogger } from '@sim/logger'
2+ import { toError } from '@sim/utils/errors'
23import { interruptibleSleep } from '@sim/utils/helpers'
34import { generateId } from '@sim/utils/id'
45import { filterUndefined , isPlainRecord , isRecordLike } from '@sim/utils/object'
@@ -261,6 +262,19 @@ function copilotRunLifecycle(context: ExecutionContext) {
261262/** How often a run past its wait is re-read for its log before it is answered running. */
262263const RUN_LOG_POLL_MS = 1000
263264
265+ /** Whether the run's log exists; a lookup that fails counts as not yet, so the call keeps waiting. */
266+ async function runIsReadable ( executionId : string , workflowId : string ) : Promise < boolean > {
267+ try {
268+ return ( await getWorkflowExecutionLogStatus ( executionId , workflowId ) ) !== undefined
269+ } catch ( error ) {
270+ logger . warn ( 'Could not read a workflow tool run past its wait; still waiting on it' , {
271+ executionId,
272+ error : toError ( error ) . message ,
273+ } )
274+ return false
275+ }
276+ }
277+
264278/**
265279 * Runs a workflow tool's run and answers with its result. When the call names a wait the run
266280 * outlasts (`workflowRunWaitMs`), it answers the run still running by the execution id it gave
@@ -284,7 +298,7 @@ async function answerWithinWait(
284298 let result = await Promise . race ( [ settled , waited ( waitMs ) ] )
285299 // Answered running only once the run is readable by its id; one still starting up (or in
286300 // preflight) is waited on until its log exists or it settles.
287- while ( ! result && ! ( await getWorkflowExecutionLogStatus ( executionId , workflowId ) ) ) {
301+ while ( ! result && ! ( await runIsReadable ( executionId , workflowId ) ) ) {
288302 result = await Promise . race ( [ settled , waited ( RUN_LOG_POLL_MS ) ] )
289303 }
290304 if ( result ) return result
0 commit comments