Skip to content

Commit 3af5609

Browse files
authored
fix(daemon): preserve runtime usage attribution in diagnostics (#7076)
1 parent 39d97a0 commit 3af5609

2 files changed

Lines changed: 71 additions & 2 deletions

File tree

apps/daemon/src/runtimes/runs.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,8 @@ function summarizeAssistantMessageEvents(events) {
203203
let upstreamErrorCount = 0;
204204
let provider;
205205
let model;
206+
let usageProvider;
207+
let usageModel;
206208
let fallbackOrdinal = 0;
207209
const countErrorClass = (value) => {
208210
if (value === 'rate_limited') rateLimitedCount += 1;
@@ -212,6 +214,15 @@ function summarizeAssistantMessageEvents(events) {
212214
for (const record of events) {
213215
if (record?.event !== 'agent' || !record.data || typeof record.data !== 'object') continue;
214216
const data = record.data;
217+
if (data.type === 'usage') {
218+
if (typeof data.provider === 'string' && data.provider.trim()) {
219+
usageProvider = data.provider.trim();
220+
}
221+
if (typeof data.model === 'string' && data.model.trim()) {
222+
usageModel = data.model.trim();
223+
}
224+
continue;
225+
}
215226
if (data.type !== 'diagnostic') continue;
216227
if (data.name === 'model_retry') {
217228
retryCount += 1;
@@ -282,8 +293,8 @@ function summarizeAssistantMessageEvents(events) {
282293
rateLimitedCount,
283294
timeoutCount,
284295
upstreamErrorCount,
285-
provider,
286-
model,
296+
provider: provider ?? usageProvider,
297+
model: model ?? usageModel,
287298
};
288299
}
289300

apps/daemon/tests/runtimes/runs.test.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)