138 lines
4.9 KiB
TypeScript
138 lines
4.9 KiB
TypeScript
import { expect, test } from '@playwright/test'
|
|
|
|
function resolveAdminKey(): string | undefined {
|
|
return process.env.E2E_ADMIN_KEY || process.env.ADMIN_CONSOLE_KEY
|
|
}
|
|
|
|
function hasLiveModelKey(): boolean {
|
|
return Boolean(
|
|
process.env.AGENT_OS_MODEL_API_KEY || process.env.BIGMODEL_API_KEY || process.env.ZHIPU_API_KEY
|
|
)
|
|
}
|
|
|
|
test.describe('Agent OS Live E2E', () => {
|
|
test.skip(!resolveAdminKey(), 'E2E_ADMIN_KEY or ADMIN_CONSOLE_KEY is required')
|
|
test.skip(!hasLiveModelKey(), 'Live model API key is required for this suite')
|
|
|
|
test('runs model planning and policy approval loop with audit records', async ({
|
|
request,
|
|
page,
|
|
}) => {
|
|
const adminKey = resolveAdminKey()!
|
|
|
|
const tokenResponse = await request.post('/api/admin/auth/token', {
|
|
data: {
|
|
adminKey,
|
|
operator: 'playwright-e2e',
|
|
},
|
|
})
|
|
expect(tokenResponse.ok()).toBeTruthy()
|
|
const tokenPayload = await tokenResponse.json()
|
|
expect(tokenPayload.success).toBe(true)
|
|
const bearerToken = tokenPayload.token as string
|
|
|
|
const headers = {
|
|
Authorization: `Bearer ${bearerToken}`,
|
|
'Content-Type': 'application/json',
|
|
}
|
|
|
|
const firstRunResponse = await request.post('/api/agent/goals', {
|
|
headers,
|
|
data: {
|
|
goal: 'Please discover AI agent projects from trending signals and summarize with RAG retrieval.',
|
|
preferredAgentId: 'agent.discovery.scout',
|
|
},
|
|
})
|
|
expect(firstRunResponse.ok()).toBeTruthy()
|
|
const firstRun = await firstRunResponse.json()
|
|
|
|
expect(firstRun.success).toBe(true)
|
|
expect(firstRun.planning?.source).toBe('model')
|
|
expect(Array.isArray(firstRun.tasks)).toBe(true)
|
|
expect(firstRun.tasks.length).toBeGreaterThan(0)
|
|
expect(Array.isArray(firstRun.toolCalls)).toBe(true)
|
|
expect(firstRun.toolCalls.length).toBeGreaterThan(0)
|
|
|
|
const runId = firstRun.run?.id as string
|
|
expect(typeof runId).toBe('string')
|
|
|
|
const runDetailResponse = await request.get(`/api/agent/runs/${runId}`, { headers })
|
|
expect(runDetailResponse.ok()).toBeTruthy()
|
|
const runDetail = await runDetailResponse.json()
|
|
expect(runDetail.success).toBe(true)
|
|
expect(runDetail.run?.id).toBe(runId)
|
|
expect(runDetail.tasks.length).toBeGreaterThan(0)
|
|
|
|
const proposalResponse = await request.post('/api/admin/policies/proposals', {
|
|
headers,
|
|
data: {
|
|
title: 'Deny MCP browser for discovery scout',
|
|
description: 'Policy proposal created by live e2e to validate approval effectiveness.',
|
|
targetType: 'agent',
|
|
targetId: 'agent.discovery.scout',
|
|
changes: {
|
|
policyOverrides: {
|
|
'mcp.agent_browser.read': 'deny',
|
|
},
|
|
},
|
|
},
|
|
})
|
|
expect(proposalResponse.ok()).toBeTruthy()
|
|
const proposalPayload = await proposalResponse.json()
|
|
expect(proposalPayload.success).toBe(true)
|
|
const approvalId = proposalPayload.approvalTicket?.id as string
|
|
expect(typeof approvalId).toBe('string')
|
|
|
|
const approveResponse = await request.post(`/api/admin/approvals/${approvalId}/decision`, {
|
|
headers,
|
|
data: {
|
|
decision: 'approved',
|
|
comment: 'approved by playwright e2e',
|
|
},
|
|
})
|
|
expect(approveResponse.ok()).toBeTruthy()
|
|
const approvePayload = await approveResponse.json()
|
|
expect(approvePayload.success).toBe(true)
|
|
expect(approvePayload.approvalTicket?.status).toBe('approved')
|
|
|
|
const secondRunResponse = await request.post('/api/agent/goals', {
|
|
headers,
|
|
data: {
|
|
goal: 'Use web_read capability to read website https://example.com and extract key points.',
|
|
preferredAgentId: 'agent.discovery.scout',
|
|
},
|
|
})
|
|
expect(secondRunResponse.ok()).toBeTruthy()
|
|
const secondRun = await secondRunResponse.json()
|
|
expect(secondRun.success).toBe(true)
|
|
|
|
const webReadCalls = secondRun.toolCalls.filter(
|
|
(call: { resourceId: string }) =>
|
|
call.resourceId === 'mcp.agent_browser.read' ||
|
|
call.resourceId === 'tool.web.read' ||
|
|
call.resourceId === 'tool.web.search'
|
|
)
|
|
expect(webReadCalls.length).toBeGreaterThan(0)
|
|
expect(webReadCalls.some((call: { resourceId: string }) => call.resourceId === 'tool.web.read')).toBe(
|
|
true
|
|
)
|
|
|
|
const allReasons: string[] = secondRun.toolCalls.flatMap((call: { reasons?: string[] }) =>
|
|
Array.isArray(call.reasons) ? call.reasons : []
|
|
)
|
|
expect(allReasons.some((reason) => reason.startsWith('fallback_low_trust:'))).toBe(true)
|
|
|
|
const secondRunId = secondRun.run?.id as string
|
|
const logResponse = await request.get(`/api/admin/logs/tool-calls?runId=${secondRunId}`, {
|
|
headers,
|
|
})
|
|
expect(logResponse.ok()).toBeTruthy()
|
|
const logPayload = await logResponse.json()
|
|
expect(logPayload.success).toBe(true)
|
|
expect(logPayload.toolCalls.length).toBeGreaterThan(0)
|
|
|
|
await page.goto('/en/admin/chat')
|
|
await expect(page.getByText('Agent Gateway Chat Console')).toBeVisible()
|
|
})
|
|
})
|