mirror of
https://github.com/aiclientproxy/proxycast.git
synced 2026-09-24 23:10:56 +08:00
feat: ship lime 1.6.1 rollout
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { spawnSync } from "node:child_process";
|
||||
import path from "node:path";
|
||||
import process from "node:process";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const rootDir = path.resolve(__dirname, "..");
|
||||
const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm";
|
||||
|
||||
function runVitest(label, args) {
|
||||
console.log(`\n[smoke:agent-service-skill-entry] > ${label}`);
|
||||
const result = spawnSync(
|
||||
npmCommand,
|
||||
["exec", "--", "vitest", "run", ...args],
|
||||
{
|
||||
cwd: rootDir,
|
||||
stdio: "inherit",
|
||||
env: process.env,
|
||||
},
|
||||
);
|
||||
|
||||
if (result.error) {
|
||||
throw result.error;
|
||||
}
|
||||
|
||||
if (typeof result.status === "number" && result.status !== 0) {
|
||||
const error = new Error(
|
||||
`[smoke:agent-service-skill-entry] ${label} 失败`,
|
||||
);
|
||||
error.exitCode = result.status;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
function main() {
|
||||
runVitest("服务技能入口路由与挂起参数", [
|
||||
"src/components/skills/SkillsWorkspacePage.test.tsx",
|
||||
"src/components/agent/chat/workspace/useWorkspaceServiceSkillEntryActions.test.tsx",
|
||||
"src/components/agent/chat/index.shell-routing.test.tsx",
|
||||
"src/components/AppPageContent.test.tsx",
|
||||
]);
|
||||
|
||||
runVitest("Agent 对话内 A2UI 挂起主链", [
|
||||
"src/components/agent/chat/index.test.tsx",
|
||||
"--hookTimeout=60000",
|
||||
"-t",
|
||||
"AgentChatPage 服务技能 A2UI|AgentChatPage legacy 问卷 A2UI",
|
||||
]);
|
||||
|
||||
console.log("\n[smoke:agent-service-skill-entry] 通过");
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -7,6 +7,7 @@ const DEFAULTS = {
|
||||
invokeUrl: "http://127.0.0.1:3030/invoke",
|
||||
timeoutMs: 60_000,
|
||||
intervalMs: 1_000,
|
||||
invokeTimeoutMs: 20_000,
|
||||
};
|
||||
|
||||
function printHelp() {
|
||||
@@ -24,6 +25,7 @@ Lime Site Adapter Catalog Smoke
|
||||
--invoke-url <url> DevBridge invoke 地址,默认 http://127.0.0.1:3030/invoke
|
||||
--timeout-ms <ms> 等待健康检查超时,默认 60000
|
||||
--interval-ms <ms> 健康检查轮询间隔,默认 1000
|
||||
--invoke-timeout-ms <ms> 单次 invoke 超时,默认 20000
|
||||
-h, --help 显示帮助
|
||||
`);
|
||||
}
|
||||
@@ -53,6 +55,11 @@ function parseArgs(argv) {
|
||||
index += 1;
|
||||
continue;
|
||||
}
|
||||
if (arg === "--invoke-timeout-ms" && argv[index + 1]) {
|
||||
options.invokeTimeoutMs = Number(argv[index + 1]);
|
||||
index += 1;
|
||||
continue;
|
||||
}
|
||||
if (arg === "--help" || arg === "-h") {
|
||||
printHelp();
|
||||
process.exit(0);
|
||||
@@ -65,6 +72,12 @@ function parseArgs(argv) {
|
||||
if (!Number.isFinite(options.intervalMs) || options.intervalMs < 100) {
|
||||
throw new Error("--interval-ms 必须是 >= 100 的数字");
|
||||
}
|
||||
if (
|
||||
!Number.isFinite(options.invokeTimeoutMs) ||
|
||||
options.invokeTimeoutMs < 1_000
|
||||
) {
|
||||
throw new Error("--invoke-timeout-ms 必须是 >= 1000 的数字");
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
@@ -111,14 +124,26 @@ async function waitForHealth(options) {
|
||||
);
|
||||
}
|
||||
|
||||
async function invoke(invokeUrl, cmd, args) {
|
||||
const response = await fetch(invokeUrl, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ cmd, args }),
|
||||
});
|
||||
async function invoke(options, cmd, args) {
|
||||
console.log(`[smoke:site-adapters] invoke ${cmd}`);
|
||||
let response;
|
||||
try {
|
||||
response = await fetch(options.invokeUrl, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ cmd, args }),
|
||||
signal: AbortSignal.timeout(options.invokeTimeoutMs),
|
||||
});
|
||||
} catch (error) {
|
||||
if (error?.name === "TimeoutError") {
|
||||
throw new Error(
|
||||
`[smoke:site-adapters] ${cmd} 超时,${options.invokeTimeoutMs}ms 内未收到 DevBridge 响应`,
|
||||
);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||
@@ -140,7 +165,7 @@ async function main() {
|
||||
const options = parseArgs(process.argv.slice(2));
|
||||
await waitForHealth(options);
|
||||
|
||||
const status = await invoke(options.invokeUrl, "site_get_adapter_catalog_status");
|
||||
const status = await invoke(options, "site_get_adapter_catalog_status");
|
||||
assert(status && typeof status === "object", "site_get_adapter_catalog_status 返回为空");
|
||||
assert(
|
||||
typeof status.adapter_count === "number" && status.adapter_count >= 0,
|
||||
@@ -151,7 +176,7 @@ async function main() {
|
||||
"site_get_adapter_catalog_status 返回了未知 source_kind",
|
||||
);
|
||||
|
||||
const adapters = await invoke(options.invokeUrl, "site_list_adapters");
|
||||
const adapters = await invoke(options, "site_list_adapters");
|
||||
assert(Array.isArray(adapters), "site_list_adapters 返回不是数组");
|
||||
assert(adapters.length > 0, "site_list_adapters 返回为空");
|
||||
|
||||
@@ -165,7 +190,7 @@ async function main() {
|
||||
"site_list_adapters 首项缺少 domain",
|
||||
);
|
||||
|
||||
const recommendations = await invoke(options.invokeUrl, "site_recommend_adapters", {
|
||||
const recommendations = await invoke(options, "site_recommend_adapters", {
|
||||
request: {
|
||||
limit: 3,
|
||||
},
|
||||
@@ -189,7 +214,7 @@ async function main() {
|
||||
);
|
||||
}
|
||||
|
||||
const searchResults = await invoke(options.invokeUrl, "site_search_adapters", {
|
||||
const searchResults = await invoke(options, "site_search_adapters", {
|
||||
request: {
|
||||
query: adapter.name,
|
||||
},
|
||||
|
||||
@@ -132,15 +132,23 @@ function formatCommand(command, args) {
|
||||
return [command, ...args].join(" ");
|
||||
}
|
||||
|
||||
function runCommand(command, args, label) {
|
||||
function runCommand(command, args, label, timeoutMs) {
|
||||
console.log(`\n[verify:gui-smoke] > ${formatCommand(command, args)}`);
|
||||
const result = spawnSync(command, args, {
|
||||
cwd: rootDir,
|
||||
stdio: "inherit",
|
||||
env: process.env,
|
||||
timeout: timeoutMs,
|
||||
});
|
||||
|
||||
if (result.error) {
|
||||
if (result.error.code === "ETIMEDOUT") {
|
||||
const error = new Error(
|
||||
`[verify:gui-smoke] ${label} 超时(>${timeoutMs}ms)`,
|
||||
);
|
||||
error.exitCode = 124;
|
||||
throw error;
|
||||
}
|
||||
throw result.error;
|
||||
}
|
||||
|
||||
@@ -341,6 +349,7 @@ async function main() {
|
||||
String(options.intervalMs),
|
||||
],
|
||||
"bridge:health",
|
||||
options.timeoutMs + 5_000,
|
||||
);
|
||||
|
||||
await waitForAppShell(options);
|
||||
@@ -359,6 +368,7 @@ async function main() {
|
||||
options.sampleProjectName,
|
||||
],
|
||||
"smoke:workspace-ready",
|
||||
options.timeoutMs + 5_000,
|
||||
);
|
||||
|
||||
runCommand(
|
||||
@@ -374,6 +384,7 @@ async function main() {
|
||||
"--headless",
|
||||
],
|
||||
"smoke:browser-runtime",
|
||||
options.timeoutMs + 5_000,
|
||||
);
|
||||
|
||||
runCommand(
|
||||
@@ -388,6 +399,14 @@ async function main() {
|
||||
String(options.intervalMs),
|
||||
],
|
||||
"smoke:site-adapters",
|
||||
options.timeoutMs + 5_000,
|
||||
);
|
||||
|
||||
runCommand(
|
||||
npmCommand,
|
||||
["run", "smoke:agent-service-skill-entry"],
|
||||
"smoke:agent-service-skill-entry",
|
||||
options.timeoutMs + 30_000,
|
||||
);
|
||||
|
||||
console.log("\n[verify:gui-smoke] 通过");
|
||||
|
||||
Reference in New Issue
Block a user