@@ -343,6 +343,92 @@ describe('runCopilotLifecycle', () => {
343343 )
344344 } )
345345
346+ it ( 'normalizes the initial request body with workspaceId from lifecycle options' , async ( ) => {
347+ let requestBody : Record < string , unknown > | undefined
348+ mockGetEffectiveDecryptedEnv . mockResolvedValueOnce ( { } )
349+ mockRunStreamLoop . mockImplementationOnce (
350+ async ( _fetchUrl : string , fetchOptions : RequestInit ) : Promise < void > => {
351+ requestBody = JSON . parse ( String ( fetchOptions . body ) )
352+ }
353+ )
354+
355+ await runCopilotLifecycle (
356+ { message : 'hello' , messageId : 'stream-1' } ,
357+ {
358+ userId : 'user-1' ,
359+ workspaceId : 'ws-1' ,
360+ chatId : 'chat-1' ,
361+ }
362+ )
363+
364+ expect ( requestBody ) . toEqual (
365+ expect . objectContaining ( {
366+ workspaceId : 'ws-1' ,
367+ } )
368+ )
369+ } )
370+
371+ it ( 'uses the lifecycle workspaceId for async tool resume requests' , async ( ) => {
372+ const requestBodies : Record < string , unknown > [ ] = [ ]
373+ const fetchUrls : string [ ] = [ ]
374+ const executionContext : ExecutionContext = {
375+ userId : 'user-1' ,
376+ workflowId : 'workflow-1' ,
377+ workspaceId : 'ws-1' ,
378+ chatId : 'chat-1' ,
379+ decryptedEnvVars : { } ,
380+ }
381+
382+ mockRunStreamLoop . mockImplementationOnce (
383+ async (
384+ fetchUrl : string ,
385+ fetchOptions : RequestInit ,
386+ context : StreamingContext
387+ ) : Promise < void > => {
388+ fetchUrls . push ( fetchUrl )
389+ requestBodies . push ( JSON . parse ( String ( fetchOptions . body ) ) )
390+ context . toolCalls . set ( 'tool-1' , {
391+ id : 'tool-1' ,
392+ name : 'read' ,
393+ status : MothershipStreamV1ToolOutcome . success ,
394+ result : { success : true , output : { content : 'file contents' } } ,
395+ } )
396+ context . awaitingAsyncContinuation = {
397+ checkpointId : 'ckpt-1' ,
398+ pendingToolCallIds : [ 'tool-1' ] ,
399+ }
400+ }
401+ )
402+ mockRunStreamLoop . mockImplementationOnce (
403+ async ( fetchUrl : string , fetchOptions : RequestInit ) : Promise < void > => {
404+ fetchUrls . push ( fetchUrl )
405+ requestBodies . push ( JSON . parse ( String ( fetchOptions . body ) ) )
406+ }
407+ )
408+
409+ await runCopilotLifecycle (
410+ { message : 'hello' , messageId : 'stream-1' } ,
411+ {
412+ userId : 'user-1' ,
413+ workspaceId : 'ws-1' ,
414+ workflowId : 'workflow-1' ,
415+ chatId : 'chat-1' ,
416+ executionId : 'exec-1' ,
417+ runId : 'run-1' ,
418+ executionContext,
419+ }
420+ )
421+
422+ expect ( fetchUrls [ 1 ] ) . toBe ( 'http://mothership.test/api/tools/resume' )
423+ expect ( requestBodies [ 1 ] ) . toEqual (
424+ expect . objectContaining ( {
425+ checkpointId : 'ckpt-1' ,
426+ userId : 'user-1' ,
427+ workspaceId : 'ws-1' ,
428+ } )
429+ )
430+ } )
431+
346432 it ( 'finalizes as success when a resume fails with a retryable error then the retry succeeds' , async ( ) => {
347433 const executionContext : ExecutionContext = {
348434 userId : 'user-1' ,
0 commit comments