Files
LangBot/web/tests/e2e/pipeline-monitoring-turns.spec.ts
T

196 lines
4.9 KiB
TypeScript

import { expect, test } from '@playwright/test';
import { installLangBotApiMocks } from './fixtures/langbot-api';
const bot = {
id: 'bot-pipeline-monitoring',
name: 'Pipeline Bot',
};
const pipeline = {
id: 'pipeline-monitoring',
name: 'Pipeline Under Test',
};
function at(minute: number) {
return `2026-07-02T10:${String(minute).padStart(2, '0')}:00Z`;
}
function message(
id: string,
role: 'user' | 'assistant',
minute: number,
content: string,
sessionId = 'session-pipeline-agent',
) {
return {
id,
timestamp: at(minute),
bot_id: bot.id,
bot_name: bot.name,
pipeline_id: pipeline.id,
pipeline_name: pipeline.name,
message_content: content,
session_id: sessionId,
status: 'success',
level: 'info',
platform: role === 'user' ? 'person' : 'bot',
user_id: 'pipeline-user',
user_name: 'Pipeline User',
runner_name: 'local-agent',
variables: '{}',
role,
};
}
function llmCall(
id: string,
minute: number,
messageId: string,
input: number,
output: number,
duration: number,
) {
return {
id,
timestamp: at(minute),
model_name: 'gpt-5.5',
input_tokens: input,
output_tokens: output,
total_tokens: input + output,
duration,
cost: 0,
status: 'success',
bot_id: bot.id,
bot_name: bot.name,
pipeline_id: pipeline.id,
pipeline_name: pipeline.name,
session_id: 'session-pipeline-agent',
message_id: messageId,
};
}
function toolCall(id: string, minute: number, messageId: string, name: string) {
return {
id,
timestamp: at(minute),
tool_name: name,
tool_source: 'native',
duration: 120,
status: 'success',
bot_id: bot.id,
bot_name: bot.name,
pipeline_id: pipeline.id,
pipeline_name: pipeline.name,
session_id: 'session-pipeline-agent',
message_id: messageId,
arguments: JSON.stringify({ query: name }),
result: JSON.stringify({ ok: true }),
};
}
function monitoringData() {
const messages = [
message(
'single-user',
'user',
1,
'Pipeline single user message without reply',
'session-pipeline-single',
),
message('agent-user', 'user', 10, 'Pipeline needs a deployment plan'),
message(
'agent-assistant-1',
'assistant',
11,
'Pipeline agent step 1: inspect repository',
),
message(
'agent-assistant-2',
'assistant',
12,
'Pipeline agent step 2: run tests',
),
message(
'agent-assistant-3',
'assistant',
13,
'Pipeline final answer: deployment ready',
),
];
const llmCalls = [
llmCall('pipeline-call-1', 10, 'agent-user', 100, 40, 180),
llmCall('pipeline-call-2', 11, 'agent-user', 140, 50, 220),
];
const toolCalls = [
toolCall('pipeline-tool-1', 11, 'agent-user', 'repo_search'),
toolCall('pipeline-tool-2', 12, 'agent-user', 'run_tests'),
];
return {
overview: {
total_messages: messages.length,
llm_calls: llmCalls.length,
embedding_calls: 0,
model_calls: llmCalls.length,
success_rate: 100,
active_sessions: 2,
},
messages,
llmCalls,
toolCalls,
embeddingCalls: [],
sessions: [],
errors: [],
totalCount: {
messages: messages.length,
llmCalls: llmCalls.length,
toolCalls: toolCalls.length,
embeddingCalls: 0,
sessions: 0,
errors: 0,
},
};
}
test.describe('pipeline monitoring conversation turns', () => {
test('uses conversation turns and folded tool calls in the pipeline dashboard', async ({
page,
}) => {
await installLangBotApiMocks(page, {
authenticated: true,
monitoringData: monitoringData(),
});
await page.goto(`/home/pipelines?id=${pipeline.id}`);
await page.getByRole('tab', { name: 'Dashboard' }).click();
await expect(page.getByText('2 conversation turns')).toBeVisible();
await expect(
page.getByText('Pipeline single user message without reply'),
).toBeVisible();
await expect(
page.getByText('Pipeline needs a deployment plan'),
).toBeVisible();
await expect(
page.getByText('Pipeline agent step 1: inspect repository'),
).toBeVisible();
await expect(page.getByText('Assistant +2')).toBeVisible();
await expect(page.getByText('2 tools')).toBeVisible();
const agentTurn = page
.locator('div[role="button"]')
.filter({ hasText: 'Pipeline needs a deployment plan' });
await expect(agentTurn).toHaveCount(1);
await agentTurn.click();
await expect(page.getByText('Tool Calls (2)')).toBeVisible();
await expect(page.getByText('#1 repo_search')).toBeVisible();
await expect(page.getByText('#2 run_tests')).toBeVisible();
await expect(page.getByText('Arguments')).toHaveCount(0);
await page.getByText('#1 repo_search').click();
await expect(page.getByText('Arguments')).toBeVisible();
await expect(page.getByText('Result')).toBeVisible();
});
});