Skip to content

Commit d1ba33e

Browse files
committed
feat(ai-agent): tag tool events with agentName for UI scope grouping
1 parent 96799ec commit d1ba33e

10 files changed

Lines changed: 73 additions & 26 deletions

File tree

packages/bubble-core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@bubblelab/bubble-core",
3-
"version": "0.1.298",
3+
"version": "0.1.299",
44
"type": "module",
55
"license": "Apache-2.0",
66
"main": "./dist/index.js",

packages/bubble-core/src/bubbles/service-bubble/ai-agent.ts

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,13 @@ export class AIAgentBubble extends ServiceBubble<
563563
this.beforeToolCallHook = params.beforeToolCall;
564564
this.afterToolCallHook = params.afterToolCall;
565565
this.afterLLMCallHook = params.afterLLMCall;
566-
this.streamingCallback = params.streamingCallback;
566+
// Use explicit param if provided (Salad /ai route), otherwise check
567+
// execution metadata (Pearl flow execution injects it there).
568+
this.streamingCallback =
569+
params.streamingCallback ??
570+
(context?.executionMeta?._agentStreamCallback as
571+
| StreamingCallback
572+
| undefined);
567573
this.factory = new BubbleFactory();
568574
}
569575

@@ -2285,6 +2291,7 @@ export class AIAgentBubble extends ServiceBubble<
22852291
input: toolCall.args,
22862292
callId: toolCall.id!,
22872293
variableId: this.context?.variableId,
2294+
agentName: this.params.name,
22882295
},
22892296
});
22902297

@@ -2304,6 +2311,7 @@ export class AIAgentBubble extends ServiceBubble<
23042311
output: { error: errorContent },
23052312
duration: Date.now() - startTime,
23062313
variableId: this.context?.variableId,
2314+
agentName: this.params.name,
23072315
},
23082316
});
23092317

@@ -2361,6 +2369,7 @@ export class AIAgentBubble extends ServiceBubble<
23612369
input: toolCall.args,
23622370
callId: toolCall.id!,
23632371
variableId: this.context?.variableId,
2372+
agentName: this.params.name,
23642373
},
23652374
});
23662375

@@ -2482,6 +2491,7 @@ export class AIAgentBubble extends ServiceBubble<
24822491
output: toolOutput,
24832492
duration: toolDurationMs,
24842493
variableId: this.context?.variableId,
2494+
agentName: this.params.name,
24852495
},
24862496
});
24872497
} catch (error) {
@@ -2513,6 +2523,7 @@ export class AIAgentBubble extends ServiceBubble<
25132523
output: { error: errorContent },
25142524
duration: Date.now() - startTime,
25152525
variableId: this.context?.variableId,
2526+
agentName: this.params.name,
25162527
},
25172528
});
25182529

@@ -2670,6 +2681,11 @@ export class AIAgentBubble extends ServiceBubble<
26702681
callbacks: [
26712682
{
26722683
handleLLMStart: async (): Promise<void> => {
2684+
// Only for master — subagent llm_start events would flush
2685+
// the frontend's active tools group erroneously.
2686+
if (this.params.name?.startsWith('Capability Agent:')) {
2687+
return;
2688+
}
26732689
await this.streamingCallback?.({
26742690
type: 'llm_start',
26752691
data: {
@@ -2678,9 +2694,26 @@ export class AIAgentBubble extends ServiceBubble<
26782694
},
26792695
});
26802696
},
2697+
handleLLMNewToken: async (token: string): Promise<void> => {
2698+
if (
2699+
token &&
2700+
this.streamingCallback &&
2701+
!this.params.name?.startsWith('Capability Agent:')
2702+
) {
2703+
await this.streamingCallback({
2704+
type: 'token',
2705+
data: { content: token, messageId },
2706+
});
2707+
}
2708+
},
26812709
handleLLMEnd: async (output): Promise<void> => {
26822710
extractedThinking = extractThinking(output);
2683-
if (extractedThinking) {
2711+
// Only emit think/llm_complete for the master agent — subagent
2712+
// events would confuse the frontend timeline (they're internal
2713+
// to the capability's execution).
2714+
const isMaster =
2715+
!this.params.name?.startsWith('Capability Agent:');
2716+
if (extractedThinking && isMaster) {
26842717
await this.streamingCallback?.({
26852718
type: 'think',
26862719
data: {
@@ -2689,19 +2722,21 @@ export class AIAgentBubble extends ServiceBubble<
26892722
},
26902723
});
26912724
}
2692-
const content = formatFinalResponse(
2693-
generationsToMessageContent(output.generations.flat()),
2694-
this.params.model.model
2695-
).response;
2696-
await this.streamingCallback?.({
2697-
type: 'llm_complete',
2698-
data: {
2699-
messageId,
2700-
content: content,
2701-
totalTokens:
2702-
output.llmOutput?.usage_metadata?.total_tokens,
2703-
},
2704-
});
2725+
if (isMaster) {
2726+
const content = formatFinalResponse(
2727+
generationsToMessageContent(output.generations.flat()),
2728+
this.params.model.model
2729+
).response;
2730+
await this.streamingCallback?.({
2731+
type: 'llm_complete',
2732+
data: {
2733+
messageId,
2734+
content: content,
2735+
totalTokens:
2736+
output.llmOutput?.usage_metadata?.total_tokens,
2737+
},
2738+
});
2739+
}
27052740
},
27062741
},
27072742
],

packages/bubble-core/src/bubbles/service-bubble/slack/slack.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2497,6 +2497,12 @@ Comprehensive Slack integration for messaging and workspace management.
24972497
// Resolve channel name to ID if needed
24982498
const resolvedChannel = await this.resolveChannelId(channel);
24992499

2500+
// Detect markdown in text and convert to blocks if no blocks are already provided
2501+
let finalBlocks = blocks;
2502+
if (text && !blocks && containsMarkdown(text)) {
2503+
finalBlocks = markdownToBlocks(text) as unknown as typeof blocks;
2504+
}
2505+
25002506
const body: Record<string, unknown> = {
25012507
channel: resolvedChannel,
25022508
text,
@@ -2507,7 +2513,7 @@ Comprehensive Slack integration for messaging and workspace management.
25072513
if (icon_emoji) body.icon_emoji = icon_emoji;
25082514
if (icon_url) body.icon_url = icon_url;
25092515
if (thread_ts) body.thread_ts = thread_ts;
2510-
if (blocks) body.blocks = blocks;
2516+
if (finalBlocks) body.blocks = finalBlocks;
25112517
if (unfurl_links !== undefined) body.unfurl_links = unfurl_links;
25122518
if (unfurl_media !== undefined) body.unfurl_media = unfurl_media;
25132519

packages/bubble-runtime/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@bubblelab/bubble-runtime",
3-
"version": "0.1.298",
3+
"version": "0.1.299",
44
"type": "module",
55
"license": "Apache-2.0",
66
"main": "./dist/index.js",

packages/bubble-scope-manager/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@bubblelab/ts-scope-manager",
3-
"version": "0.1.298",
3+
"version": "0.1.299",
44
"private": false,
55
"license": "MIT",
66
"type": "commonjs",

packages/bubble-shared-schemas/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@bubblelab/shared-schemas",
3-
"version": "0.1.298",
3+
"version": "0.1.299",
44
"type": "module",
55
"license": "Apache-2.0",
66
"main": "./dist/index.js",

packages/bubble-shared-schemas/src/streaming-events.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ export type StreamingEvent =
107107
input: unknown;
108108
callId: string;
109109
variableId?: number;
110+
/** Name of the agent that emitted the call. Empty/undefined for the
111+
* master agent; "Capability Agent: <id>" for subagents. */
112+
agentName?: string;
110113
};
111114
}
112115
| {
@@ -118,6 +121,9 @@ export type StreamingEvent =
118121
duration: number;
119122
callId: string;
120123
variableId?: number;
124+
/** Name of the agent that emitted the call. Empty/undefined for the
125+
* master agent; "Capability Agent: <id>" for subagents. */
126+
agentName?: string;
121127
};
122128
}
123129
| { type: 'iteration_start'; data: { iteration: number } }

packages/create-bubblelab-app/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "create-bubblelab-app",
3-
"version": "0.1.298",
3+
"version": "0.1.299",
44
"type": "module",
55
"license": "Apache-2.0",
66
"description": "Create BubbleLab AI agent applications with one command",

packages/create-bubblelab-app/templates/basic/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111
"typecheck": "tsc --noEmit"
1212
},
1313
"dependencies": {
14-
"@bubblelab/bubble-core": "^0.1.298",
15-
"@bubblelab/bubble-runtime": "^0.1.298",
16-
"@bubblelab/shared-schemas": "^0.1.298",
14+
"@bubblelab/bubble-core": "^0.1.299",
15+
"@bubblelab/bubble-runtime": "^0.1.299",
16+
"@bubblelab/shared-schemas": "^0.1.299",
1717
"dotenv": "^16.4.5"
1818
},
1919
"devDependencies": {

packages/create-bubblelab-app/templates/reddit-scraper/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
"typecheck": "tsc --noEmit"
1212
},
1313
"dependencies": {
14-
"@bubblelab/bubble-core": "^0.1.298",
15-
"@bubblelab/bubble-runtime": "^0.1.298",
14+
"@bubblelab/bubble-core": "^0.1.299",
15+
"@bubblelab/bubble-runtime": "^0.1.299",
1616
"dotenv": "^16.4.5"
1717
},
1818
"devDependencies": {

0 commit comments

Comments
 (0)