@@ -43,6 +43,22 @@ describe("agy request metadata", () => {
4343 expect ( other . session . numericSessionId ) . toBe ( first . session . numericSessionId )
4444 } )
4545
46+ it ( "records a fresh execution ID only for known sessions" , ( ) => {
47+ const sessions = new AgyRequestSessionStore ( "file:///workspace" , { now : ( ) => 100 } )
48+ const session = sessions . beginRequest ( "session-a" ) . session
49+
50+ sessions . completeExecution ( "missing" )
51+ expect ( session . lastExecutionId ) . toBeUndefined ( )
52+
53+ sessions . completeExecution ( "session-a" )
54+ const firstExecutionId = session . lastExecutionId
55+ expect ( firstExecutionId ) . toMatch ( / ^ [ 0 - 9 a - f - ] { 36 } $ / )
56+
57+ sessions . completeExecution ( "session-a" )
58+ expect ( session . lastExecutionId ) . toMatch ( / ^ [ 0 - 9 a - f - ] { 36 } $ / )
59+ expect ( session . lastExecutionId ) . not . toBe ( firstExecutionId )
60+ } )
61+
4662 it ( "creates stable session IDs with independently generated conversation and trajectory IDs" , ( ) => {
4763 expect ( createAgyRequestSessionContext ( "file:///workspace" , {
4864 conversationId : "conversation-id" ,
@@ -78,7 +94,7 @@ describe("agy request metadata", () => {
7894 ] )
7995 } )
8096
81- it ( "derives last_step_index from the number of content parts " , ( ) => {
97+ it ( "supports part- and content-based step counting " , ( ) => {
8298 const payload = {
8399 contents : [
84100 { role : "user" , parts : [ { text : "prompt" } ] } ,
@@ -94,7 +110,8 @@ describe("agy request metadata", () => {
94110 }
95111
96112 expect ( countAgyRequestSteps ( payload ) ) . toBe ( 4 )
97- expect ( countAgyRequestSteps ( { contents : [ ] } ) ) . toBe ( 1 )
113+ expect ( countAgyRequestSteps ( payload , "contents" ) ) . toBe ( 3 )
114+ expect ( countAgyRequestSteps ( { contents : [ ] } , "contents" ) ) . toBe ( 1 )
98115 expect ( countAgyRequestSteps ( { } ) ) . toBe ( 1 )
99116 } )
100117
@@ -132,6 +149,40 @@ describe("agy request metadata", () => {
132149 } )
133150 } )
134151
152+ it ( "matches the captured execution-aware step sequence" , ( ) => {
153+ const session = createAgyRequestSessionContext ( "" , {
154+ conversationId : "conversation-id" ,
155+ trajectoryId : "trajectory-id" ,
156+ } )
157+ const sequence = [
158+ { contents : 1 , step : 1 , executionId : undefined } ,
159+ { contents : 4 , step : 5 , executionId : "execution-1" } ,
160+ { contents : 7 , step : 8 , executionId : "execution-2" } ,
161+ { contents : 9 , step : 10 , executionId : "execution-2" } ,
162+ { contents : 12 , step : 13 , executionId : "execution-3" } ,
163+ { contents : 15 , step : 16 , executionId : "execution-4" } ,
164+ ]
165+
166+ for ( const [ index , item ] of sequence . entries ( ) ) {
167+ session . lastExecutionId = item . executionId
168+ const metadata = buildAgyAgentRequestMetadata (
169+ session ,
170+ { contents : Array . from ( { length : item . contents } , ( ) => ( { role : "user" , parts : [ ] } ) ) } ,
171+ "claude-opus-4-6-thinking" ,
172+ index + 1 ,
173+ { stepCountMode : "contents" } ,
174+ )
175+
176+ expect ( metadata . lastStepIndex ) . toBe ( item . step )
177+ expect ( metadata . requestId . endsWith ( `/${ item . step + 1 } ` ) ) . toBe ( true )
178+ if ( item . executionId ) {
179+ expect ( metadata . labels . last_execution_id ) . toBe ( item . executionId )
180+ } else {
181+ expect ( metadata . labels ) . not . toHaveProperty ( "last_execution_id" )
182+ }
183+ }
184+ } )
185+
135186 it ( "matches every captured agy model enum fixture" , ( ) => {
136187 for ( const fixture of MODEL_METADATA_FIXTURES ) {
137188 for ( const [ model , expected ] of Object . entries ( fixture . models ) ) {
0 commit comments