180 lines
5.6 KiB
TypeScript
180 lines
5.6 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
|
|
const jobId = "job_architecture";
|
|
const callId = "llmcall_draft";
|
|
|
|
const run = {
|
|
job_id: jobId,
|
|
case_id: "case_architecture",
|
|
status: "completed",
|
|
current_stage: "final",
|
|
trace_completeness: "complete",
|
|
error_stage: null,
|
|
error_summary: null,
|
|
started_at: "2026-07-16T00:00:00.000Z",
|
|
finished_at: "2026-07-16T00:00:03.000Z",
|
|
updated_at: "2026-07-16T00:00:03.000Z",
|
|
};
|
|
|
|
const call = {
|
|
call_id: callId,
|
|
job_id: jobId,
|
|
sequence: 2,
|
|
task: "article_optimizer",
|
|
workflow_stage: "draft",
|
|
rewrite_round: null,
|
|
provider: "deepseek",
|
|
model: "deepseek-chat",
|
|
status: "validated",
|
|
token_usage: { prompt_tokens: 120, completion_tokens: 80, total_tokens: 200 },
|
|
schema_name: "optimizedArticleSchema",
|
|
schema_valid: true,
|
|
validation_issues: [],
|
|
business_status: null,
|
|
duration_ms: 1600,
|
|
started_at: "2026-07-16T00:00:01.000Z",
|
|
responded_at: "2026-07-16T00:00:02.500Z",
|
|
validated_at: "2026-07-16T00:00:02.600Z",
|
|
failed_at: null,
|
|
error_type: null,
|
|
error_summary: null,
|
|
request_available: true,
|
|
response_available: true,
|
|
};
|
|
|
|
const article = {
|
|
job_id: jobId,
|
|
revision: 1,
|
|
title: "可观测的 GEO 优化稿",
|
|
summary: "展示真实后台调用。",
|
|
body_markdown: "## 优化结果\n正文内容。",
|
|
image_suggestions: [],
|
|
changed_sections: ["title", "body"],
|
|
requires_user_confirmation: [],
|
|
};
|
|
|
|
const qaReport = {
|
|
job_id: jobId,
|
|
revision: 1,
|
|
overall_status: "pass",
|
|
checks: [],
|
|
};
|
|
|
|
test("后台架构标签按需展示完整 LLM 请求与响应", async ({ page }) => {
|
|
const payloadReads = { request: 0, response: 0 };
|
|
const streamEvents = [
|
|
{ type: "job_created", job: { id: jobId } },
|
|
{
|
|
type: "llm_call_started",
|
|
job_id: jobId,
|
|
call_id: callId,
|
|
sequence: 2,
|
|
task: "article_optimizer",
|
|
workflow_stage: "draft",
|
|
rewrite_round: null,
|
|
provider: "deepseek",
|
|
model: "deepseek-chat",
|
|
started_at: call.started_at,
|
|
request_available: true,
|
|
},
|
|
{
|
|
type: "llm_call_responded",
|
|
job_id: jobId,
|
|
call_id: callId,
|
|
duration_ms: call.duration_ms,
|
|
token_usage: call.token_usage,
|
|
responded_at: call.responded_at,
|
|
response_available: true,
|
|
},
|
|
{
|
|
type: "llm_call_validated",
|
|
job_id: jobId,
|
|
call_id: callId,
|
|
schema_name: call.schema_name,
|
|
schema_valid: true,
|
|
validation_issues: [],
|
|
validated_at: call.validated_at,
|
|
},
|
|
{
|
|
type: "final_ready",
|
|
job_id: jobId,
|
|
optimized_article: article,
|
|
qa_report: qaReport,
|
|
export_paths: {
|
|
markdown: `/api/jobs/${jobId}/exports/optimized.md`,
|
|
docx: `/api/jobs/${jobId}/exports/optimized.docx`,
|
|
qa_report: `/api/jobs/${jobId}/exports/qa_report.json`,
|
|
},
|
|
},
|
|
];
|
|
|
|
await page.route("**/api/jobs/optimize-stream", async (route) => {
|
|
await route.fulfill({
|
|
status: 200,
|
|
contentType: "application/x-ndjson; charset=utf-8",
|
|
body: `${streamEvents.map((event) => JSON.stringify(event)).join("\n")}\n`,
|
|
});
|
|
});
|
|
await page.route(`**/api/jobs/${jobId}/llm-trace`, async (route) => {
|
|
await route.fulfill({ json: { run, calls: [call] } });
|
|
});
|
|
await page.route("**/api/llm-traces/latest", async (route) => {
|
|
await route.fulfill({ json: { run, calls: [call] } });
|
|
});
|
|
await page.route(`**/api/jobs/${jobId}/llm-trace/${callId}/request`, async (route) => {
|
|
payloadReads.request += 1;
|
|
await route.fulfill({
|
|
json: {
|
|
model: "deepseek-chat",
|
|
messages: [
|
|
{ role: "system", content: "你是 GEO 文章优化器。" },
|
|
{ role: "user", content: "优化这篇原始文章。" },
|
|
],
|
|
response_format: { type: "json_object" },
|
|
temperature: 0.2,
|
|
},
|
|
});
|
|
});
|
|
await page.route(`**/api/jobs/${jobId}/llm-trace/${callId}/response`, async (route) => {
|
|
payloadReads.response += 1;
|
|
await route.fulfill({
|
|
json: {
|
|
id: "chatcmpl_observer",
|
|
choices: [{ message: { role: "assistant", content: JSON.stringify(article) } }],
|
|
usage: call.token_usage,
|
|
},
|
|
});
|
|
});
|
|
|
|
await page.goto("/");
|
|
await page.getByLabel("访问密钥").fill("local-dev-key");
|
|
await page.getByLabel("文章内容").fill("这是一篇需要优化的原始文章。");
|
|
await page.getByRole("button", { name: "开始优化" }).click();
|
|
await page.getByRole("button", { name: "后台架构" }).click();
|
|
|
|
await expect(page.getByLabel("文章优化后台架构")).toBeVisible();
|
|
await expect(page.locator(".llm-call-list code", { hasText: "article_optimizer" }))
|
|
.toBeVisible();
|
|
await expect(page.locator('[data-node="final"]')).toContainText("已完成");
|
|
|
|
await page.getByRole("tab", { name: "请求" }).click();
|
|
await expect(page.locator(".llm-json-view"))
|
|
.toContainText("开启技术详情后按需读取完整正文。");
|
|
expect(payloadReads.request).toBe(0);
|
|
expect(payloadReads.response).toBe(0);
|
|
|
|
await page.getByLabel("技术详情").check();
|
|
await expect(page.locator(".llm-json-view")).toContainText("messages");
|
|
await expect(page.locator(".llm-json-view")).toContainText("你是 GEO 文章优化器。");
|
|
expect(payloadReads.request).toBe(1);
|
|
|
|
await page.getByRole("tab", { name: "响应" }).click();
|
|
await expect(page.locator(".llm-json-view")).toContainText("choices");
|
|
await expect(page.locator(".llm-json-view")).toContainText("chatcmpl_observer");
|
|
expect(payloadReads.response).toBe(1);
|
|
|
|
await page.getByRole("button", { name: "GEO 文章优化" }).click();
|
|
await expect(page.getByText("优化完成。", { exact: true })).toBeVisible();
|
|
await expect(page.getByRole("link", { name: "optimized.md" })).toBeVisible();
|
|
});
|