feat(browser): complete camofox BrowserProvider with tabs, interaction, download capture and control lease

Contracts for browser API and browser.* agent capabilities; adapter implements
close/list/restore sessions, tabs + reconcile, history, click/type/select/scroll/press,
extract, waitForDownload (staged via DownloadSink, sha256), stale-ref guard and
automation/human actor check. testkit mock camofox gains an interactive site
(login redirect, captcha, click-driven page changes, downloads, PNG screenshots).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-09-28 20:17:46 +08:00
1 parent 62290d4477
commit c17d4b90bd
12 files changed
+1832 -101

No files matched your search

+50
View File
@@ -72,6 +72,10 @@ export const CAPABILITY_IDS = [
"site.health_check",
"site.refresh_login",
"site.user_data",
"browser.snapshot",
"browser.navigate",
"browser.interact",
"browser.download",
] as const;
export const KnownCapabilityId = z.enum(CAPABILITY_IDS);
export type KnownCapabilityId = z.infer<typeof KnownCapabilityId>;
@@ -348,6 +352,52 @@ export const CAPABILITY_CATALOG: Record<KnownCapabilityId, CapabilityDescriptor>
true,
false,
),
// C1-E 浏览器能力(REQ §4.4、§4.7.3):经 BrowserProvider 访问用户已有的 camofox-browser;
// 导航限站点域名,凭证由服务端注入,人工接管期间自动化动作被拒;下载产物只进后端暂存核验
"browser.snapshot": d(
"browser.snapshot",
"读取原站页面",
"读取站点浏览器会话当前页面的结构化快照(可访问性文本 + eN 元素引用,凭证已遮蔽);控制权交还或导航后必须重新读取",
"read",
"BrowserSnapshot",
"read",
"low",
true,
false,
),
"browser.navigate": d(
"browser.navigate",
"打开原站页面",
"在站点浏览器会话里打开站点域名内的地址(没有会话时按站点打开);受站点限流、超时与重试预算约束",
"execute",
"BrowserNavigate",
"admin",
"low",
false,
false,
),
"browser.interact": d(
"browser.interact",
"操作原站页面",
"在站点浏览器会话里点击 / 输入 / 选择 / 滚动 / 按键;登录字段用 credential 由服务端注入凭证;验证码或二次认证用 request_human 转人工",
"execute",
"BrowserInteract",
"admin",
"medium",
false,
false,
),
"browser.download": d(
"browser.download",
"捕获原站下载",
"捕获浏览器会话里的种子下载,交后端暂存并核验 infohash、匹配本地资源;提交下载仍用 download.plan / download.submit",
"execute",
"BrowserDownload",
"organize.execute",
"medium",
false,
false,
),
};
function d(