From 40327977903613fee5d033efd31c6e01416a2bf0 Mon Sep 17 00:00:00 2001 From: Mutasem Aldmour <4711238+mutdmour@users.noreply.github.com> Date: Fri, 9 Oct 2026 14:12:33 +0000 Subject: [PATCH] fix(editor): Show the renamed agent name in the assistant artifact tab (#40770) Co-authored-by: Claude Opus 5.5 --- .../__tests__/useResourceRegistry.test.ts | 36 +++++++++++++++++-- .../ai/instanceAi/useResourceRegistry.ts | 21 ++++++++--- 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/packages/frontend/editor-ui/src/features/ai/instanceAi/__tests__/useResourceRegistry.test.ts b/packages/frontend/editor-ui/src/features/ai/instanceAi/__tests__/useResourceRegistry.test.ts index a9a87fd1861..a815a75aa01 100644 --- a/packages/frontend/editor-ui/src/features/ai/instanceAi/__tests__/useResourceRegistry.test.ts +++ b/packages/frontend/editor-ui/src/features/ai/instanceAi/__tests__/useResourceRegistry.test.ts @@ -1019,11 +1019,11 @@ describe('useResourceRegistry', () => { }); }); - test('event-derived names win over metadata: unnamed spawn, then named tool result, then metadata enrichment', async () => { + test('event-derived names win over a metadata name that an earlier event carried', async () => { const { messages, producedArtifacts } = setup(undefined, () => ({ agentId: 'agent-1', projectId: 'project-1', - name: 'Stale Metadata Name', + name: 'Support Agent', })); messages.value = [ @@ -1032,6 +1032,12 @@ describe('useResourceRegistry', () => { targetResource: { type: 'agent', id: 'agent-1', projectId: 'project-1' }, toolCalls: [ makeToolCall({ + toolCallId: 'tc-1', + toolName: 'build-agent', + result: { ok: true, agentId: 'agent-1', agentName: 'Support Agent' }, + }), + makeToolCall({ + toolCallId: 'tc-2', toolName: 'build-agent', result: { ok: true, agentId: 'agent-1', agentName: 'Support Bot' }, }), @@ -1048,6 +1054,32 @@ describe('useResourceRegistry', () => { projectId: 'project-1', }); }); + + test('a name the user saved in the agent builder wins over the event-derived name', async () => { + const target = ref({ agentId: 'agent-1', projectId: 'project-1', name: 'Support Bot' }); + const { messages, producedArtifacts } = setup(undefined, () => target.value); + + messages.value = [ + makeMessage({ + agentTree: makeAgentNode({ + targetResource: { type: 'agent', id: 'agent-1', projectId: 'project-1' }, + toolCalls: [ + makeToolCall({ + toolName: 'build-agent', + result: { ok: true, agentId: 'agent-1', agentName: 'Support Bot' }, + }), + ], + }), + }), + ]; + await nextTick(); + expect(producedArtifacts.get('agent-1')?.name).toBe('Support Bot'); + + target.value = { ...target.value, name: 'Helpdesk Bot' }; + await nextTick(); + + expect(producedArtifacts.get('agent-1')?.name).toBe('Helpdesk Bot'); + }); }); describe('list results do not populate producedArtifacts', () => { diff --git a/packages/frontend/editor-ui/src/features/ai/instanceAi/useResourceRegistry.ts b/packages/frontend/editor-ui/src/features/ai/instanceAi/useResourceRegistry.ts index 25bbbb33c57..f741833002c 100644 --- a/packages/frontend/editor-ui/src/features/ai/instanceAi/useResourceRegistry.ts +++ b/packages/frontend/editor-ui/src/features/ai/instanceAi/useResourceRegistry.ts @@ -58,6 +58,8 @@ interface Collections { origins: Map; /** Origin the current collection phase stamps on resources it records for the first time. */ intake: ArtifactOrigin; + /** Every name recorded for each agent id, to tell a stale metadata name from a user rename. */ + agentNames: Map>; } /** @@ -116,6 +118,11 @@ function recordProduced( } : entry; col.produced.set(entry.id, merged); + if (merged.type === 'agent') { + const names = col.agentNames.get(merged.id) ?? new Set(); + names.add(merged.name); + col.agentNames.set(merged.id, names); + } if (!col.origins.has(entry.id)) col.origins.set(entry.id, col.intake); if (existing && existing.name.toLowerCase() !== merged.name.toLowerCase()) { col.byName.delete(existing.name.toLowerCase()); @@ -442,17 +449,22 @@ function enrichAgentFromBuilderTarget( if (!target) return; const existing = col.produced.get(target.agentId); if (existing && existing.type !== 'agent') return; - // Event-derived names are canonical; the persisted metadata name only fills - // in when no run event carried one (e.g. historical threads whose events - // aren't loaded). The 'Untitled' placeholder is not a real name. + // The metadata name lags behind the events during a run, so a name that an + // earlier event carried is stale. A name no event carried is a rename the + // user saved in the agent builder, which only the metadata records. The + // 'Untitled' placeholder is not a real name. const eventName = existing && !existing.pending && existing.name !== 'Untitled' ? existing.name : undefined; + const isUserRename = + target.name !== undefined && + eventName !== undefined && + !col.agentNames.get(target.agentId)?.has(target.name); recordProduced( col, { type: 'agent', id: target.agentId, - name: eventName ?? target.name ?? 'Untitled', + name: (isUserRename ? target.name : eventName) ?? target.name ?? 'Untitled', projectId: target.projectId, }, { linkable: existing !== undefined }, @@ -607,6 +619,7 @@ export function useResourceRegistry( linkableByName: new Map(), origins: new Map(), intake: 'attached', + agentNames: new Map>(), }; // Messages run in order, and within one turn the user's attachments