63 lines
2.9 KiB
TypeScript
63 lines
2.9 KiB
TypeScript
// 本地端到端测试:模拟æµ<C3A6>览å™?fetch æµ<C3A6>å¼<C3A5>读å<C2BB>– /api/chatï¼?// é<>‡åˆ°å®¡æ‰¹è‡ªåŠ¨æ‰¹å‡†ï¼ˆå¤šè½®ï¼‰ï¼ŒéªŒè¯<C3A8>“列å‡?D ç›˜æ ¹ç›®å½•â€<C3A2>能返回文件列表ã€?
|
||
const dec = new TextDecoder();
|
||
|
||
async function readStream(url: string, body: any): Promise<{ text: string; approval: any }> {
|
||
const resp = await fetch(url, {
|
||
method: "POST",
|
||
headers: { "Content-Type": "application/json" },
|
||
body: JSON.stringify(body),
|
||
});
|
||
if (resp.status !== 200) { console.log(" HTTP 错误", resp.status); return { text: "", approval: null }; }
|
||
const reader = resp.body!.getReader();
|
||
let buf = "", out = "", approval: any = null;
|
||
while (true) {
|
||
const { done, value } = await reader.read();
|
||
if (done) break;
|
||
buf += dec.decode(value, { stream: true });
|
||
const lines = buf.split("\n");
|
||
buf = lines.pop() || "";
|
||
for (const line of lines) {
|
||
const t = line.trim();
|
||
if (!t.startsWith("data:")) continue;
|
||
const d = t.slice(5).trim();
|
||
let ev: any; try { ev = JSON.parse(d); } catch { continue; }
|
||
if (ev.type === "token") out += ev.content;
|
||
else if (ev.type === "approval_required") { console.log(" [需审批]", ev.tool, "�, ev.command); approval = ev; }
|
||
else if (ev.type === "error") console.log(" [错误]", ev.content);
|
||
else if (ev.type === "done") console.log(" [完æˆ<EFBFBD>]");
|
||
}
|
||
}
|
||
return { text: out, approval };
|
||
}
|
||
|
||
async function chat(messages: any[]): Promise<string> {
|
||
let url = "http://127.0.0.1:3100/api/chat";
|
||
let body: any = { messages };
|
||
let total = "";
|
||
let guard = 0;
|
||
while (guard++ < 6) {
|
||
const { text, approval } = await readStream(url, body);
|
||
total += text;
|
||
if (!approval) break;
|
||
// 自动批准,继ç»ï¼ˆå®¡æ‰¹æŽ¥å<C2A5>£å¤<C3A5>用对è¯<C3A8>æµ<C3A6>)
|
||
url = "http://127.0.0.1:3100/api/approve";
|
||
body = { approved: true, tool_call_id: approval.tool_call_id };
|
||
}
|
||
return total;
|
||
}
|
||
|
||
console.log("=== 测试1:列å‡?D ç›˜æ ¹ç›®å½•ï¼ˆè‡ªåŠ¨æ‰¹å‡†ï¼‰===");
|
||
const r1 = await chat([{ role: "user", content: "列出 D ç›˜æ ¹ç›®å½•çš„æ‰€æœ‰æ–‡ä»? }]);
|
||
console.log("最终回å¤?å‰?00å?:\n", r1.slice(0, 500));
|
||
console.log("\n判定1:", !r1.includes("路径越æ<EFBFBD>ƒ") && r1.length > 40 ? "PASS âœ? : "FAIL â<>?);
|
||
|
||
console.log("\n=== 测试2:用 list_directory 直接列出(å…<EFBFBD>审批ï¼?==");
|
||
const r2 = await chat([{ role: "user", content: "请用 list_directory 工具列出 d:\\ æ ¹ç›®å½•ä¸‹çš„å†…å®? }]);
|
||
console.log("最终回å¤?å‰?00å?:\n", r2.slice(0, 500));
|
||
console.log("\n判定2:", !r2.includes("路径越æ<C5A0>ƒ") && r2.length > 40 ? "PASS âœ? : "FAIL â<EFBFBD>?);
|
||
|
||
console.log("\n=== 测试3:黑å<E28098><C3A5>å<EFBFBD>•拦截验è¯<C3A8> ===");
|
||
const r3 = await chat([{ role: "user", content: "读å<C2BB>– C:\\Windows\\system32\\config\\SAM 文件内容" }]);
|
||
console.log("最终回å¤?å‰?00å?:\n", r3.slice(0, 300));
|
||
console.log("\n判定3(应被拦截):", r3.includes("路径越æ<C5A0>ƒ") ? "PASS âœ?黑å<E28098><C3A5>å<EFBFBD>?è¶Šæ<C5A0>ƒç”Ÿæ•ˆ" : "说明 SAM 被å…<C3A5>è®?å<>¯èƒ½åœ¨å·¥ä½œåŒºå¤–被拒ç»<C3A7>或模型未调用)");
|