|
| 1 | +import { describe, expect, test } from "vite-plus/test"; |
| 2 | +import { parseStdoutJson, runCli } from "./helpers.ts"; |
| 3 | + |
| 4 | +interface ContentPart { |
| 5 | + type: string; |
| 6 | + text?: string; |
| 7 | + image_url?: { url: string }; |
| 8 | +} |
| 9 | + |
| 10 | +interface DryRunBody { |
| 11 | + endpoint?: string; |
| 12 | + request?: { |
| 13 | + input?: { |
| 14 | + messages?: Array<{ role: string; content: string | ContentPart[] }>; |
| 15 | + }; |
| 16 | + parameters?: { |
| 17 | + agent_options?: { |
| 18 | + agent_id?: string; |
| 19 | + }; |
| 20 | + }; |
| 21 | + stream?: boolean; |
| 22 | + }; |
| 23 | +} |
| 24 | + |
| 25 | +describe("e2e: knowledge chat", () => { |
| 26 | + test("knowledge chat --help 正常退出", async () => { |
| 27 | + const { stderr, exitCode } = await runCli(["knowledge", "chat", "--help"]); |
| 28 | + expect(exitCode, stderr).toBe(0); |
| 29 | + expect(stderr).toMatch(/--message/i); |
| 30 | + expect(stderr).toMatch(/--agent-id/i); |
| 31 | + expect(stderr).toMatch(/--workspace-id/i); |
| 32 | + }); |
| 33 | + |
| 34 | + test("缺少 --message 时打印帮助并退出 (0)", async () => { |
| 35 | + const { stderr, exitCode } = await runCli([ |
| 36 | + "knowledge", |
| 37 | + "chat", |
| 38 | + "--agent-id", |
| 39 | + "aid_test", |
| 40 | + "--non-interactive", |
| 41 | + ]); |
| 42 | + expect(exitCode).toBe(0); |
| 43 | + expect(stderr).toMatch(/--message|Usage:/i); |
| 44 | + }); |
| 45 | + |
| 46 | + test("缺少 --agent-id 时打印帮助并退出 (0)", async () => { |
| 47 | + const { stderr, exitCode } = await runCli([ |
| 48 | + "knowledge", |
| 49 | + "chat", |
| 50 | + "--message", |
| 51 | + "Hello", |
| 52 | + "--non-interactive", |
| 53 | + ]); |
| 54 | + expect(exitCode).toBe(0); |
| 55 | + expect(stderr).toMatch(/--agent-id|Usage:/i); |
| 56 | + }); |
| 57 | + |
| 58 | + test("缺少 --workspace-id 时非零退出并提示", async () => { |
| 59 | + const { stderr, exitCode } = await runCli( |
| 60 | + [ |
| 61 | + "knowledge", |
| 62 | + "chat", |
| 63 | + "--message", |
| 64 | + "Hello", |
| 65 | + "--agent-id", |
| 66 | + "aid_test", |
| 67 | + "--non-interactive", |
| 68 | + "--output", |
| 69 | + "json", |
| 70 | + ], |
| 71 | + { BAILIAN_WORKSPACE_ID: "" }, |
| 72 | + ); |
| 73 | + expect(exitCode).not.toBe(0); |
| 74 | + expect(stderr).toMatch(/workspace.*required/i); |
| 75 | + }); |
| 76 | + |
| 77 | + test("--dry-run 输出 endpoint 和 request body", async () => { |
| 78 | + const { stdout, stderr, exitCode } = await runCli([ |
| 79 | + "knowledge", |
| 80 | + "chat", |
| 81 | + "--dry-run", |
| 82 | + "--message", |
| 83 | + "什么是RAG", |
| 84 | + "--agent-id", |
| 85 | + "aid_test", |
| 86 | + "--workspace-id", |
| 87 | + "ws_test", |
| 88 | + "--non-interactive", |
| 89 | + "--output", |
| 90 | + "json", |
| 91 | + ]); |
| 92 | + expect(exitCode, stderr).toBe(0); |
| 93 | + const data = parseStdoutJson<DryRunBody>(stdout); |
| 94 | + expect(data.endpoint).toMatch(/ws_test\.cn-beijing\.maas\.aliyuncs\.com/); |
| 95 | + expect(data.endpoint).toMatch(/api\/v2\/apps\/knowledge\/chat/); |
| 96 | + expect(data.request?.input?.messages?.[0]?.role).toBe("user"); |
| 97 | + expect(data.request?.input?.messages?.[0]?.content).toBe("什么是RAG"); |
| 98 | + expect(data.request?.parameters?.agent_options?.agent_id).toBe("aid_test"); |
| 99 | + }); |
| 100 | + |
| 101 | + test("--dry-run 多轮消息解析 role:content 前缀", async () => { |
| 102 | + const { stdout, stderr, exitCode } = await runCli([ |
| 103 | + "knowledge", |
| 104 | + "chat", |
| 105 | + "--dry-run", |
| 106 | + "--message", |
| 107 | + "user:什么是RAG", |
| 108 | + "--message", |
| 109 | + "assistant:RAG是检索增强生成", |
| 110 | + "--message", |
| 111 | + "它怎么工作", |
| 112 | + "--agent-id", |
| 113 | + "aid_test", |
| 114 | + "--workspace-id", |
| 115 | + "ws_test", |
| 116 | + "--non-interactive", |
| 117 | + "--output", |
| 118 | + "json", |
| 119 | + ]); |
| 120 | + expect(exitCode, stderr).toBe(0); |
| 121 | + const data = parseStdoutJson<DryRunBody>(stdout); |
| 122 | + const msgs = data.request?.input?.messages ?? []; |
| 123 | + expect(msgs).toHaveLength(3); |
| 124 | + expect(msgs[0]?.role).toBe("user"); |
| 125 | + expect(msgs[0]?.content).toBe("什么是RAG"); |
| 126 | + expect(msgs[1]?.role).toBe("assistant"); |
| 127 | + expect(msgs[1]?.content).toBe("RAG是检索增强生成"); |
| 128 | + expect(msgs[2]?.role).toBe("user"); |
| 129 | + expect(msgs[2]?.content).toBe("它怎么工作"); |
| 130 | + }); |
| 131 | + |
| 132 | + test("--dry-run + --image 输出多模态 content 数组", async () => { |
| 133 | + const { stdout, stderr, exitCode } = await runCli([ |
| 134 | + "knowledge", |
| 135 | + "chat", |
| 136 | + "--dry-run", |
| 137 | + "--message", |
| 138 | + "描述这张图", |
| 139 | + "--agent-id", |
| 140 | + "aid_test", |
| 141 | + "--workspace-id", |
| 142 | + "ws_test", |
| 143 | + "--image", |
| 144 | + "https://example.com/img.jpg", |
| 145 | + "--non-interactive", |
| 146 | + "--output", |
| 147 | + "json", |
| 148 | + ]); |
| 149 | + expect(exitCode, stderr).toBe(0); |
| 150 | + const data = parseStdoutJson<DryRunBody>(stdout); |
| 151 | + const lastMsg = data.request?.input?.messages?.[0]; |
| 152 | + expect(lastMsg?.role).toBe("user"); |
| 153 | + expect(Array.isArray(lastMsg?.content)).toBe(true); |
| 154 | + const parts = lastMsg?.content as ContentPart[]; |
| 155 | + expect(parts[0]).toEqual({ type: "text", text: "描述这张图" }); |
| 156 | + expect(parts[1]).toEqual({ |
| 157 | + type: "image_url", |
| 158 | + image_url: { url: "https://example.com/img.jpg" }, |
| 159 | + }); |
| 160 | + }); |
| 161 | + |
| 162 | + test("--dry-run + --image 无 --message 自动创建空 user message", async () => { |
| 163 | + const { stdout, stderr, exitCode } = await runCli([ |
| 164 | + "knowledge", |
| 165 | + "chat", |
| 166 | + "--dry-run", |
| 167 | + "--agent-id", |
| 168 | + "aid_test", |
| 169 | + "--workspace-id", |
| 170 | + "ws_test", |
| 171 | + "--image", |
| 172 | + "https://example.com/a.png", |
| 173 | + "--image", |
| 174 | + "https://example.com/b.png", |
| 175 | + "--non-interactive", |
| 176 | + "--output", |
| 177 | + "json", |
| 178 | + ]); |
| 179 | + expect(exitCode, stderr).toBe(0); |
| 180 | + const data = parseStdoutJson<DryRunBody>(stdout); |
| 181 | + const lastMsg = data.request?.input?.messages?.[0]; |
| 182 | + expect(lastMsg?.role).toBe("user"); |
| 183 | + const parts = lastMsg?.content as ContentPart[]; |
| 184 | + expect(parts[0]).toEqual({ type: "text", text: "" }); |
| 185 | + expect(parts[1]).toEqual({ |
| 186 | + type: "image_url", |
| 187 | + image_url: { url: "https://example.com/a.png" }, |
| 188 | + }); |
| 189 | + expect(parts[2]).toEqual({ |
| 190 | + type: "image_url", |
| 191 | + image_url: { url: "https://example.com/b.png" }, |
| 192 | + }); |
| 193 | + }); |
| 194 | +}); |
0 commit comments