chore(ai-builder): Adding telemetry for categorization in the workflow builder (#21486)

This commit is contained in:
Michael Drury
2025-11-03 14:33:08 +00:00
committed by GitHub
parent 9400d845f7
commit 10e08fd685
2 changed files with 85 additions and 0 deletions
@@ -1348,6 +1348,50 @@ describe('AskAssistantBuild', () => {
});
});
it('should track categorization telemetry when categorize_prompt tool completes', async () => {
renderComponent();
// Simulate streaming starts
builderStore.$patch({ streaming: true });
await flushPromises();
// Add categorization tool message
builderStore.toolMessages = [
{
id: faker.string.uuid(),
role: 'assistant' as const,
type: 'tool' as const,
toolName: 'categorize_prompt',
toolCallId: faker.string.uuid(),
status: 'completed',
updates: [
{
type: 'output',
data: {
categorization: {
techniques: ['chatbot', 'notification'],
confidence: 0.85,
},
},
},
],
},
];
// Simulate streaming stops (this triggers trackWorkflowModifications)
builderStore.$patch({ streaming: false });
await flushPromises();
expect(trackMock).toHaveBeenCalledWith('Classifier labels user prompt', {
user_id: undefined,
workflow_id: 'abc123',
classifier_labels: ['chatbot', 'notification'],
confidence: 0.85,
session_id: 'app_session_id',
timestamp: expect.any(String),
});
});
it('should handle multiple canvas generations correctly', async () => {
const originalWorkflow = {
nodes: [],
@@ -34,6 +34,7 @@ const { goToUpgrade } = usePageRedirectionHelper();
// Track processed workflow updates
const processedWorkflowUpdates = ref(new Set<string>());
const trackedTools = ref(new Set<string>());
const trackedCategorizations = ref(new Set<string>());
const workflowUpdated = ref<{ start: string; end: string } | undefined>();
const n8nChatRef = ref<InstanceType<typeof N8nAskAssistantChat>>();
@@ -103,6 +104,7 @@ function onNewWorkflow() {
builderStore.resetBuilderChat();
processedWorkflowUpdates.value.clear();
trackedTools.value.clear();
trackedCategorizations.value.clear();
workflowUpdated.value = undefined;
}
@@ -127,6 +129,44 @@ function dedupeToolNames(toolNames: string[]): string[] {
return [...new Set(toolNames)];
}
function isCategorizationData(
data: unknown,
): data is { techniques: string[]; confidence?: number } {
return (
typeof data === 'object' &&
data !== null &&
'techniques' in data &&
Array.isArray(data.techniques) &&
data.techniques.every((t) => typeof t === 'string')
);
}
function trackWorkflowCategorization() {
// Track categorization telemetry
builderStore.toolMessages.forEach((toolMsg) => {
if (toolMsg.toolName !== 'categorize_prompt') return;
if (toolMsg.status !== 'completed') return;
if (!toolMsg.toolCallId) return;
if (trackedCategorizations.value.has(toolMsg.toolCallId)) return;
const outputUpdate = toolMsg.updates.find((u) => u.type === 'output');
const categorizationData = outputUpdate?.data?.categorization;
if (!isCategorizationData(categorizationData)) return;
trackedCategorizations.value.add(toolMsg.toolCallId);
telemetry.track('Classifier labels user prompt', {
user_id: usersStore.currentUserId ?? undefined,
workflow_id: workflowsStore.workflowId,
classifier_labels: categorizationData.techniques,
confidence: categorizationData.confidence,
session_id: builderStore.trackingSessionId,
timestamp: new Date().toISOString(),
});
});
}
function trackWorkflowModifications() {
if (workflowUpdated.value) {
// Track tool usage for telemetry
@@ -244,6 +284,7 @@ watch(
async (isStreaming) => {
if (!isStreaming) {
trackWorkflowModifications();
trackWorkflowCategorization();
}
if (