@@ -74,6 +74,20 @@ type PermissionRequest = {
7474 } > ;
7575} ;
7676
77+ const CRON_CREATE_INSTRUCTION = 'Call cron_create with cron expression' ;
78+
79+ function isCronCreateRequest ( body : Record < string , unknown > ) : boolean {
80+ const messages = body [ 'messages' ] ;
81+ const latestMessage = Array . isArray ( messages ) ? messages . at ( - 1 ) : undefined ;
82+ return (
83+ typeof latestMessage === 'object' &&
84+ latestMessage !== null &&
85+ 'role' in latestMessage &&
86+ latestMessage . role === 'user' &&
87+ JSON . stringify ( latestMessage ) ?. includes ( CRON_CREATE_INSTRUCTION ) === true
88+ ) ;
89+ }
90+
7791/**
7892 * Sets up an ACP test environment with cron support enabled, backed by
7993 * a fake-openai-server for deterministic model responses.
@@ -400,14 +414,8 @@ async function initSession(
400414 const rig = new TestRig ( ) ;
401415 await rig . setup ( 'acp-cron-e2e' ) ;
402416
403- // Only requestIndex 0 is load-bearing: it returns the cron_create
404- // tool call. The CLI makes internal model calls (tool-call
405- // classification, suggestion mode) between user-facing turns, so
406- // later indices do not map 1:1 to the prompts sent below. No
407- // assertion reads scripted response content, so the default reply
408- // suffices for every other turn.
409- const fakeServer = await startFakeOpenAIServer ( ( { requestIndex } ) => {
410- if ( requestIndex === 0 ) {
417+ const fakeServer = await startFakeOpenAIServer ( ( { body } ) => {
418+ if ( isCronCreateRequest ( body ) ) {
411419 return {
412420 toolCalls : [
413421 fakeToolCall ( 'cron_create' , {
@@ -440,14 +448,12 @@ async function initSession(
440448 } ) ) as { stopReason : string } ;
441449 expect ( createResult . stopReason ) . toBe ( 'end_turn' ) ;
442450
443- // Fail fast if the cron_create tool call was not served to the first
444- // user prompt. An internal model call before the first prompt (title
445- // generation, a classifier pass) would shift dispatch and otherwise
446- // surface only as an opaque 75s timeout in Part 3a.
451+ // Fail fast instead of surfacing a missing tool call as an opaque
452+ // 75s timeout in Part 3a.
447453 expect (
448- JSON . stringify ( fakeServer . requests [ 0 ] ?. body [ 'messages' ] ) ,
449- 'requestIndex 0 was not the cron_create prompt — dispatch shifted ' ,
450- ) . toContain ( 'CRONFIRE7742' ) ;
454+ fakeServer . requests . some ( ( { body } ) => isCronCreateRequest ( body ) ) ,
455+ 'fake server did not receive the cron_create prompt' ,
456+ ) . toBe ( true ) ;
451457
452458 // --- Part 2: Session stays responsive while cron is pending ---
453459 const interactiveResult = ( await sendRequest ( 'session/prompt' , {
0 commit comments