@@ -155,6 +155,64 @@ describe('chat run service shutdown', () => {
155155 vi . useRealTimers ( ) ;
156156 } ) ;
157157
158+ it ( 'uses runtime usage attribution when the adapter has no message lifecycle' , ( ) => {
159+ const runs = createRuns ( ) ;
160+ const run = runs . create ( {
161+ projectId : 'project-1' ,
162+ conversationId : 'conv-1' ,
163+ agentId : 'deepseek-harness' ,
164+ } ) as any ;
165+ run . model = 'default' ;
166+ runs . emit ( run , 'agent' , {
167+ type : 'usage' ,
168+ provider : 'deepseek-official' ,
169+ model : 'deepseek-v4-flash' ,
170+ usage : { input_tokens : 10 , output_tokens : 2 } ,
171+ } ) ;
172+ runs . finish ( run , 'succeeded' , 0 , null ) ;
173+
174+ const diagnostics = runs . statusBody ( run ) . executionDiagnostics ;
175+ expect ( diagnostics ?. environment ) . toMatchObject ( {
176+ requestedModel : { state : 'available' , value : 'default' } ,
177+ provider : { state : 'available' , value : 'deepseek-official' } ,
178+ resolvedModel : { state : 'available' , value : 'deepseek-v4-flash' } ,
179+ } ) ;
180+ expect ( diagnostics ?. assistantMessages . count ) . toMatchObject ( {
181+ state : 'not_collected' ,
182+ missingReason : 'assistant_message_lifecycle_not_exposed_by_runtime' ,
183+ } ) ;
184+ } ) ;
185+
186+ it ( 'keeps lifecycle attribution ahead of the usage fallback' , ( ) => {
187+ const runs = createRuns ( ) ;
188+ const run = runs . create ( {
189+ projectId : 'project-1' ,
190+ conversationId : 'conv-1' ,
191+ agentId : 'amr' ,
192+ } ) as any ;
193+ runs . emit ( run , 'agent' , {
194+ type : 'usage' ,
195+ provider : 'usage-provider' ,
196+ model : 'usage-model' ,
197+ usage : { input_tokens : 10 , output_tokens : 2 } ,
198+ } ) ;
199+ runs . emit ( run , 'agent' , {
200+ type : 'diagnostic' ,
201+ name : 'assistant_message_lifecycle' ,
202+ phase : 'end' ,
203+ status : 'completed' ,
204+ assistantMessageIndex : 1 ,
205+ provider : 'lifecycle-provider' ,
206+ model : 'lifecycle-model' ,
207+ } ) ;
208+ runs . finish ( run , 'succeeded' , 0 , null ) ;
209+
210+ expect ( runs . statusBody ( run ) . executionDiagnostics ?. environment ) . toMatchObject ( {
211+ provider : { state : 'available' , value : 'lifecycle-provider' } ,
212+ resolvedModel : { state : 'available' , value : 'lifecycle-model' } ,
213+ } ) ;
214+ } ) ;
215+
158216 it ( 'keeps model-step percentiles unavailable until the documented sample minimum' , ( ) => {
159217 const runs = createRuns ( ) ;
160218 const run = runs . create ( { projectId : 'project-1' , conversationId : 'conv-1' , agentId : 'amr' } ) as any ;
0 commit comments