feat: Simplify builder tool calls (no-changelog) (#18798)

This commit is contained in:
Mutasem Aldmour
2025-08-28 10:14:03 +02:00
committed by GitHub
parent ff56c95605
commit d244b99484
36 changed files with 2190 additions and 391 deletions

View File

@@ -269,7 +269,7 @@ describe('useBuilderMessages', () => {
expect(result.messages[2].id).toBe('batch-id-2');
});
it('should show running tools message when tools are in progress', () => {
it('should show thinking message when tools are in progress', () => {
const currentMessages: ChatUI.AssistantMessage[] = [];
const newMessages: ChatRequest.MessageResponse[] = [
{
@@ -289,11 +289,11 @@ describe('useBuilderMessages', () => {
);
expect(result.messages).toHaveLength(1);
expect(result.thinkingMessage).toBe('aiAssistant.thinkingSteps.runningTools');
expect(result.thinkingMessage).toBe(undefined);
expect(result.shouldClearThinking).toBe(false);
});
it('should show processing message when tools are completed but no text response yet', () => {
it('should show thinking message when tools are completed but no text response yet', () => {
const currentMessages: ChatUI.AssistantMessage[] = [];
const newMessages: ChatRequest.MessageResponse[] = [
{
@@ -316,7 +316,7 @@ describe('useBuilderMessages', () => {
);
expect(result.messages).toHaveLength(1);
expect(result.thinkingMessage).toBe('aiAssistant.thinkingSteps.processingResults');
expect(result.thinkingMessage).toBe('aiAssistant.thinkingSteps.thinking');
expect(result.shouldClearThinking).toBe(false);
});
@@ -389,11 +389,11 @@ describe('useBuilderMessages', () => {
);
expect(result.messages).toHaveLength(2);
// Should show "aiAssistant.thinkingSteps.runningTools" for the new running tool, not "aiAssistant.thinkingSteps.processingResults"
expect(result.thinkingMessage).toBe('aiAssistant.thinkingSteps.runningTools');
// Should not show thinking message as new tool is running
expect(result.thinkingMessage).toBe(undefined);
});
it('should show processing message when second tool completes', () => {
it('should show thinking message when second tool completes', () => {
// Both tools completed
const currentMessages: ChatUI.AssistantMessage[] = [
{
@@ -426,7 +426,7 @@ describe('useBuilderMessages', () => {
);
expect(result.messages).toHaveLength(2);
expect(result.thinkingMessage).toBe('aiAssistant.thinkingSteps.processingResults');
expect(result.thinkingMessage).toBe('aiAssistant.thinkingSteps.thinking');
});
it('should keep showing running tools message when parallel tools complete one by one', () => {
@@ -473,8 +473,8 @@ describe('useBuilderMessages', () => {
);
expect(result.messages).toHaveLength(2);
// Should still show "aiAssistant.thinkingSteps.runningTools" because call-456 is still running
expect(result.thinkingMessage).toBe('aiAssistant.thinkingSteps.runningTools');
// Should not show thinking because call-456 is still running
expect(result.thinkingMessage).toBe(undefined);
// Verify first tool is now completed
const firstTool = result.messages.find(
@@ -489,7 +489,7 @@ describe('useBuilderMessages', () => {
expect(secondTool.status).toBe('running');
});
it('should show processing results when all parallel tools complete', () => {
it('should show thinking message when all parallel tools complete', () => {
// One tool already completed, one still running
const currentMessages: ChatUI.AssistantMessage[] = [
{
@@ -533,11 +533,11 @@ describe('useBuilderMessages', () => {
);
expect(result.messages).toHaveLength(2);
// Should now show "aiAssistant.thinkingSteps.processingResults" because all tools are completed
expect(result.thinkingMessage).toBe('aiAssistant.thinkingSteps.processingResults');
// Should now show thinking because all tools are completed but no text response yet
expect(result.thinkingMessage).toBe('aiAssistant.thinkingSteps.thinking');
});
it('should keep processing message when workflow-updated arrives after tools complete', () => {
it('should keep thinking message when workflow-updated arrives after tools complete', () => {
// Tool completed
const currentMessages: ChatUI.AssistantMessage[] = [
{
@@ -568,13 +568,13 @@ describe('useBuilderMessages', () => {
);
expect(result.messages).toHaveLength(2);
// Should still show "aiAssistant.thinkingSteps.processingResults" because workflow-updated is not a text response
expect(result.thinkingMessage).toBe('aiAssistant.thinkingSteps.processingResults');
// Should still show thinking because workflow-updated is not a text response
expect(result.thinkingMessage).toBe('aiAssistant.thinkingSteps.thinking');
// Should NOT clear thinking for workflow updates
expect(result.shouldClearThinking).toBe(false);
});
it('should clear processing message only when text arrives after workflow-updated', () => {
it('should clear thinking message only when text arrives after workflow-updated', () => {
// Tool completed and workflow updated
const currentMessages: ChatUI.AssistantMessage[] = [
{
@@ -1263,7 +1263,7 @@ describe('useBuilderMessages', () => {
];
let result = builderMessages.processAssistantMessages(currentMessages, batch1, 'batch-1');
expect(result.thinkingMessage).toBe('aiAssistant.thinkingSteps.runningTools');
expect(result.thinkingMessage).toBe(undefined);
currentMessages = result.messages;
// Second batch: tool completes
@@ -1279,7 +1279,7 @@ describe('useBuilderMessages', () => {
];
result = builderMessages.processAssistantMessages(currentMessages, batch2, 'batch-2');
expect(result.thinkingMessage).toBe('aiAssistant.thinkingSteps.processingResults');
expect(result.thinkingMessage).toBe('aiAssistant.thinkingSteps.thinking');
currentMessages = result.messages;
// Third batch: workflow updated
@@ -1292,7 +1292,7 @@ describe('useBuilderMessages', () => {
];
result = builderMessages.processAssistantMessages(currentMessages, batch3, 'batch-3');
expect(result.thinkingMessage).toBe('aiAssistant.thinkingSteps.processingResults');
expect(result.thinkingMessage).toBe('aiAssistant.thinkingSteps.thinking');
currentMessages = result.messages;
// Fourth batch: final text response

View File

@@ -169,6 +169,8 @@ export function useBuilderMessages() {
type: 'tool',
toolName: msg.toolName,
toolCallId: msg.toolCallId,
displayTitle: msg.displayTitle,
customDisplayTitle: msg.customDisplayTitle,
status: msg.status,
updates: msg.updates || [],
read: false,
@@ -237,10 +239,8 @@ export function useBuilderMessages() {
function determineThinkingMessage(messages: ChatUI.AssistantMessage[]): string | undefined {
const { hasAnyRunningTools, isStillThinking } = getThinkingState(messages);
if (hasAnyRunningTools) {
return locale.baseText('aiAssistant.thinkingSteps.runningTools');
} else if (isStillThinking) {
return locale.baseText('aiAssistant.thinkingSteps.processingResults');
if (!hasAnyRunningTools && isStillThinking) {
return locale.baseText('aiAssistant.thinkingSteps.thinking');
}
return undefined;
@@ -364,6 +364,8 @@ export function useBuilderMessages() {
type: 'tool',
toolName: message.toolName,
toolCallId: message.toolCallId,
displayTitle: message.displayTitle,
customDisplayTitle: message.customDisplayTitle,
status: message.status,
updates: message.updates || [],
read: false,

View File

@@ -257,8 +257,8 @@ describe('AI Builder store', () => {
],
});
// Should show "aiAssistant.thinkingSteps.runningTools"
expect(builderStore.assistantThinkingMessage).toBe('aiAssistant.thinkingSteps.runningTools');
// Should show "aiAssistant.thinkingSteps.thinking"
expect(builderStore.assistantThinkingMessage).toBe('aiAssistant.thinkingSteps.thinking');
// Second tool starts (different toolCallId)
onMessageCallback({
@@ -274,8 +274,8 @@ describe('AI Builder store', () => {
],
});
// Still showing "aiAssistant.thinkingSteps.runningTools" with multiple tools
expect(builderStore.assistantThinkingMessage).toBe('aiAssistant.thinkingSteps.runningTools');
// Still showing "aiAssistant.thinkingSteps.thinking" with multiple tools
expect(builderStore.assistantThinkingMessage).toBe('aiAssistant.thinkingSteps.thinking');
// First tool completes
onMessageCallback({
@@ -291,8 +291,8 @@ describe('AI Builder store', () => {
],
});
// Still "aiAssistant.thinkingSteps.runningTools" because second tool is still running
expect(builderStore.assistantThinkingMessage).toBe('aiAssistant.thinkingSteps.runningTools');
// Still "aiAssistant.thinkingSteps.thinking" because second tool is still running
expect(builderStore.assistantThinkingMessage).toBe('aiAssistant.thinkingSteps.thinking');
// Second tool completes
onMessageCallback({
@@ -308,19 +308,15 @@ describe('AI Builder store', () => {
],
});
// Now should show "aiAssistant.thinkingSteps.processingResults" because all tools completed
expect(builderStore.assistantThinkingMessage).toBe(
'aiAssistant.thinkingSteps.processingResults',
);
// Now should show "aiAssistant.thinkingSteps.thinking" because all tools completed
expect(builderStore.assistantThinkingMessage).toBe('aiAssistant.thinkingSteps.thinking');
// Call onDone to stop streaming
onDoneCallback();
// Message should persist after streaming ends
expect(builderStore.streaming).toBe(false);
expect(builderStore.assistantThinkingMessage).toBe(
'aiAssistant.thinkingSteps.processingResults',
);
expect(builderStore.assistantThinkingMessage).toBe('aiAssistant.thinkingSteps.thinking');
vi.useRealTimers();
});
@@ -360,18 +356,14 @@ describe('AI Builder store', () => {
builderStore.sendChatMessage({ text: 'Add a node' });
// Should show "aiAssistant.thinkingSteps.processingResults" when tool completes
// Should show "aiAssistant.thinkingSteps.thinking" when tool completes
await vi.waitFor(() =>
expect(builderStore.assistantThinkingMessage).toBe(
'aiAssistant.thinkingSteps.processingResults',
),
expect(builderStore.assistantThinkingMessage).toBe('aiAssistant.thinkingSteps.thinking'),
);
// Should still show "aiAssistant.thinkingSteps.processingResults" after workflow-updated
// Should still show "aiAssistant.thinkingSteps.thinking" after workflow-updated
await vi.waitFor(() => expect(builderStore.chatMessages).toHaveLength(3)); // user + tool + workflow
expect(builderStore.assistantThinkingMessage).toBe(
'aiAssistant.thinkingSteps.processingResults',
);
expect(builderStore.assistantThinkingMessage).toBe('aiAssistant.thinkingSteps.thinking');
// Verify streaming has ended
expect(builderStore.streaming).toBe(false);