miniai/test_chat.ts

63 lines
2.9 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 本地端到端æµè¯•ï¼šæ¨¡æŸæµ<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("\ˆ¤å®š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>æˆæ¨¡åžæœªè°ƒç”¨)");