Skip to content

Commit 7dfe1bc

Browse files
SheldonNunestaofeeq-deruabhiaiyer91
authored
Add usage to onDelegationComplete hook (#15825)
Co-authored-by: Taofeeq Oluderu <oluderutaofeeq@gmail.com> Co-authored-by: Abhi Aiyer <abhiaiyer91@gmail.com>
1 parent 04dce6c commit 7dfe1bc

4 files changed

Lines changed: 42 additions & 2 deletions

File tree

.changeset/crisp-moons-jump.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@mastra/core': patch
3+
---
4+
5+
Added sub-agent token usage to `onDelegationComplete` results, so apps can track per-sub-agent token costs

packages/core/src/agent/agent.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4282,7 +4282,13 @@ export class Agent<
42824282
});
42834283
}
42844284

4285-
result = { text: generateResult.text, subAgentThreadId, subAgentResourceId, subAgentToolResults };
4285+
result = {
4286+
text: generateResult.text,
4287+
subAgentThreadId,
4288+
subAgentResourceId,
4289+
subAgentToolResults,
4290+
usage: generateResult.usage,
4291+
};
42864292
} else if (
42874293
(methodType === 'generate' || methodType === 'generateLegacy') &&
42884294
resolvedModelVersion === 'v1'
@@ -4295,7 +4301,21 @@ export class Agent<
42954301
...resolveObservabilityContext(context ?? {}),
42964302
context: filteredContextMessages as unknown as CoreMessage[],
42974303
});
4298-
result = { text: generateResult.text };
4304+
const subAgentToolResultsLegacy = generateResult.toolResults?.map((toolResult: any) => ({
4305+
toolName: toolResult.toolName,
4306+
toolCallId: toolResult.toolCallId,
4307+
result: toolResult.result,
4308+
args: toolResult.args,
4309+
isError: toolResult.isError,
4310+
}));
4311+
4312+
result = {
4313+
text: generateResult.text,
4314+
subAgentThreadId,
4315+
subAgentResourceId,
4316+
subAgentToolResults: subAgentToolResultsLegacy,
4317+
usage: generateResult.usage,
4318+
};
42994319
} else if (
43004320
(methodType === 'stream' || methodType === 'streamLegacy') &&
43014321
supportedLanguageModelSpecifications.includes(resolvedModelVersion)
@@ -4441,11 +4461,13 @@ export class Agent<
44414461
// Use streamResult.text (a delayed promise) which resolves to the
44424462
// output-processor-modified text, rather than the raw accumulated text-deltas.
44434463
const processedText = await streamResult.text;
4464+
const subAgentUsage = await streamResult.usage;
44444465
result = {
44454466
text: processedText,
44464467
subAgentThreadId,
44474468
subAgentResourceId,
44484469
subAgentToolResults,
4470+
usage: subAgentUsage,
44494471
};
44504472
} else {
44514473
if (typeof resolvedAgent.streamLegacy !== 'function') {
@@ -4476,6 +4498,10 @@ export class Agent<
44764498
result = { text: fullText };
44774499
}
44784500

4501+
// Note: `usage` is included in `result` for successful generate, generateLegacy,
4502+
// and stream code paths. The `streamLegacy` path accumulates text only and won't
4503+
// have `usage`. Error/rejected delegation callbacks may also omit it.
4504+
44794505
// Call onDelegationComplete hook if provided
44804506
if (delegation?.onDelegationComplete) {
44814507
try {

packages/core/src/agent/agent.types.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,14 @@ export interface DelegationCompleteContext {
143143
text: string;
144144
subAgentThreadId?: string;
145145
subAgentResourceId?: string;
146+
/** Aggregate token usage from the sub-agent's execution */
147+
usage?: {
148+
inputTokens: number;
149+
outputTokens: number;
150+
totalTokens: number;
151+
reasoningTokens?: number;
152+
cachedInputTokens?: number;
153+
};
146154
};
147155
/** Duration of the delegation in milliseconds */
148156
duration: number;

packages/core/src/agent/subagent.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export type SubAgentGenerateResult = Pick<FullOutput, 'text' | 'finishReason' |
2828
toolResults?: SubAgentToolResult[];
2929
suspendPayload?: unknown;
3030
resumeSchema?: unknown;
31+
usage?: FullOutput['usage'];
3132
};
3233

3334
export type SubAgentStreamResult = {

0 commit comments

Comments
 (0)