mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-08-26 20:27:13 +00:00
feat(agent): add visual event range picker
This commit is contained in:
@@ -758,7 +758,10 @@ test.describe('agent and pipeline save concurrency', () => {
|
||||
test('agent save freezes its payload and keeps later edits dirty', async ({
|
||||
page,
|
||||
}) => {
|
||||
await installLangBotApiMocks(page, { authenticated: true });
|
||||
await installLangBotApiMocks(page, {
|
||||
authenticated: true,
|
||||
withAdapterEvents: true,
|
||||
});
|
||||
const delayedSave = await installDelayedFirstSave(
|
||||
page,
|
||||
'/api/v1/agents/agent-save-race',
|
||||
@@ -770,12 +773,23 @@ test.describe('agent and pipeline save concurrency', () => {
|
||||
const eventPatterns = page.getByLabel('Event Range');
|
||||
await expect(eventPatterns).toBeVisible();
|
||||
|
||||
await eventPatterns.fill('message.received');
|
||||
await eventPatterns.click();
|
||||
await page
|
||||
.getByRole('option')
|
||||
.filter({ hasText: 'message.received' })
|
||||
.click();
|
||||
await page.keyboard.press('Escape');
|
||||
await saveButton.click();
|
||||
await expect.poll(() => delayedSave.payloads.length).toBe(1);
|
||||
await expect(saveButton).toBeDisabled();
|
||||
|
||||
await eventPatterns.fill('group.*');
|
||||
await eventPatterns.click();
|
||||
await page.getByRole('option').filter({ hasText: 'group.*' }).click();
|
||||
await page
|
||||
.getByRole('option')
|
||||
.filter({ hasText: 'message.received' })
|
||||
.click();
|
||||
await page.keyboard.press('Escape');
|
||||
await forceFormSubmit(page, '#agent-form');
|
||||
expect(delayedSave.payloads).toHaveLength(1);
|
||||
await expect(saveButton).toBeDisabled();
|
||||
|
||||
@@ -106,6 +106,7 @@ interface LangBotApiMockState {
|
||||
sessionAnalyses: Record<string, unknown>;
|
||||
sessionMessages: Record<string, unknown[]>;
|
||||
skills: SkillMock[];
|
||||
withAdapterEvents: boolean;
|
||||
withRunnerToolSelector: boolean;
|
||||
workspaces: WorkspaceEntryMock[];
|
||||
}
|
||||
@@ -514,7 +515,7 @@ function makeBot(
|
||||
};
|
||||
}
|
||||
|
||||
function mockAdapters() {
|
||||
function mockAdapters(withAdapterEvents = false) {
|
||||
return [
|
||||
{
|
||||
name: 'playwright-adapter',
|
||||
@@ -528,6 +529,17 @@ function mockAdapters() {
|
||||
},
|
||||
spec: {
|
||||
categories: ['testing'],
|
||||
...(withAdapterEvents
|
||||
? {
|
||||
supported_events: [
|
||||
'message.received',
|
||||
'message.edited',
|
||||
'group.member_joined',
|
||||
'group.member_left',
|
||||
'feedback.received',
|
||||
],
|
||||
}
|
||||
: {}),
|
||||
config: [],
|
||||
},
|
||||
},
|
||||
@@ -621,7 +633,9 @@ async function handleBackendApi(route: Route, state: LangBotApiMockState) {
|
||||
}
|
||||
|
||||
if (path === '/api/v1/platform/adapters') {
|
||||
return fulfillJson(route, { adapters: mockAdapters() });
|
||||
return fulfillJson(route, {
|
||||
adapters: mockAdapters(state.withAdapterEvents),
|
||||
});
|
||||
}
|
||||
|
||||
if (path === '/api/v1/platform/bots') {
|
||||
@@ -1230,6 +1244,7 @@ export async function installLangBotApiMocks(
|
||||
sessionAnalyses?: Record<string, unknown>;
|
||||
sessionMessages?: Record<string, unknown[]>;
|
||||
storage?: JsonRecord;
|
||||
withAdapterEvents?: boolean;
|
||||
withRunnerToolSelector?: boolean;
|
||||
workspaces?: WorkspaceEntryMock[];
|
||||
} = {},
|
||||
@@ -1241,6 +1256,7 @@ export async function installLangBotApiMocks(
|
||||
sessionAnalyses,
|
||||
sessionMessages,
|
||||
storage = {},
|
||||
withAdapterEvents = false,
|
||||
withRunnerToolSelector = false,
|
||||
workspaces = [defaultWorkspaceEntry()],
|
||||
} = options;
|
||||
@@ -1256,6 +1272,7 @@ export async function installLangBotApiMocks(
|
||||
sessionAnalyses: sessionAnalyses || {},
|
||||
sessionMessages: sessionMessages || {},
|
||||
skills: [],
|
||||
withAdapterEvents,
|
||||
withRunnerToolSelector,
|
||||
workspaces,
|
||||
};
|
||||
|
||||
@@ -10,6 +10,7 @@ test.describe('processor detail workbench', () => {
|
||||
}) => {
|
||||
await installLangBotApiMocks(page, {
|
||||
authenticated: true,
|
||||
withAdapterEvents: true,
|
||||
withRunnerToolSelector: true,
|
||||
});
|
||||
|
||||
@@ -45,14 +46,23 @@ test.describe('processor detail workbench', () => {
|
||||
expect(debugBox!.y).toBeGreaterThanOrEqual(0);
|
||||
|
||||
const flow = configPanel.getByRole('tablist');
|
||||
await expect(flow.getByRole('tab').nth(0)).toContainText(
|
||||
await expect(flow.getByRole('tab').nth(0)).toContainText('Runner');
|
||||
await expect(flow.getByRole('tab').nth(1)).toContainText('Local Agent');
|
||||
await expect(flow.getByRole('tab').nth(2)).toContainText(
|
||||
'Bindable Event Range',
|
||||
);
|
||||
await expect(flow.getByRole('tab').nth(1)).toContainText('Runner');
|
||||
await expect(flow.getByRole('tab').nth(2)).toContainText('Local Agent');
|
||||
await expect(flow.getByRole('tab')).toHaveCount(3);
|
||||
await expect(flow.getByText('Management')).toHaveCount(0);
|
||||
|
||||
await page.setViewportSize({ width: 1024, height: 900 });
|
||||
const tabListMetrics = await flow.evaluate((element) => ({
|
||||
clientWidth: element.clientWidth,
|
||||
scrollWidth: element.scrollWidth,
|
||||
}));
|
||||
expect(tabListMetrics.scrollWidth).toBeLessThanOrEqual(
|
||||
tabListMetrics.clientWidth,
|
||||
);
|
||||
|
||||
await expect(
|
||||
page.getByRole('heading', { name: /agent-workbench/ }),
|
||||
).toBeVisible();
|
||||
@@ -83,11 +93,22 @@ test.describe('processor detail workbench', () => {
|
||||
.last(),
|
||||
).toBeVisible();
|
||||
|
||||
await flow.getByRole('tab').nth(0).click();
|
||||
await flow.getByRole('tab').nth(2).click();
|
||||
await expect(
|
||||
configPanel.getByText('Bindable Event Range', { exact: true }).last(),
|
||||
).toBeVisible();
|
||||
await flow.getByRole('tab').nth(2).click();
|
||||
const eventPicker = configPanel.getByRole('combobox', {
|
||||
name: 'Event Range',
|
||||
});
|
||||
await expect(eventPicker).toBeVisible();
|
||||
await expect(configPanel.getByRole('textbox')).toHaveCount(0);
|
||||
await eventPicker.click();
|
||||
await expect(
|
||||
page.getByRole('option').filter({ hasText: 'message.received' }),
|
||||
).toBeVisible();
|
||||
await page.keyboard.press('Escape');
|
||||
|
||||
await flow.getByRole('tab').nth(1).click();
|
||||
await expect(
|
||||
configPanel.getByText('Local Agent', { exact: true }).last(),
|
||||
).toBeVisible();
|
||||
|
||||
Reference in New Issue
Block a user