Skip to content

About

通用 Agent Skill + CLI,将网页版 AI 作为外部 Agent,用于调研、评审与方案讨论,帮助降低宿主上下文占用和 API Token 消耗;当前仅支持 ChatGPT 自动化。

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Latest commit

 

History

29 Commits

Folders and files

Repository files navigation

ask-web-ai

通用 Agent Skill + CLI,让宿主 Agent 在当前任务中调用网页版 AI 进行调研、推理、头脑风暴、方案讨论、评审和结果综合;帮助降低上下文与 API Token 消耗,当前仅支持 ChatGPT 自动化。

ask-web-ai 不绑定单一宿主 Agent。凡是能够加载并遵循 Skill、执行本地 CLI,并访问同机 Tabbit Browser Runtime 的宿主,都可以接入这套协作流程。Codex 是当前已文档化的接入示例之一,不是项目的定义。

它把适合独立处理的调研和推理从宿主会话中拆出,以持久、可恢复的 Job 管理提交、等待和结果交付,并复用用户网页账号中已有的模型与产品能力。它不保证端到端总 Token 一定下降,也不假设网页版模型始终优于宿主模型。

当前只有 ChatGPT 具备确定性浏览器操作 Adapter。“确定性”指提交、恢复、完成判定和 selector 行为受明确协议约束,不表示模型回答可重复。Claude、Gemini 和 Kimi 仅在注册表中可发现,尚不会自动操作或提交。

适用场景

ask-web-ai 适合在当前任务中引入网页 AI 的独立研究、推理或判断:

  • 架构与方案评审:独立检查设计假设、接口边界、迁移方案、技术选型和遗漏。
  • 反方审查:寻找反例、失败模式、隐含前提和高风险条件。
  • 调研与事实核对:收集资料、比较观点和验证关键结论;需要事实验证时仍回到原始来源。
  • 头脑风暴与问题探索:生成候选想法、探索替代路径、讨论取舍并推进复杂问题。
  • 复杂决策的第二意见:为明显存在 trade-off 的选择引入另一套分析框架。
  • 文案、API 与设计评审:从不同读者或使用者视角检查 README、设计文档、API 说明和提示词。
  • 跨 turn 的长耗时咨询:让网页任务持久运行,不让当前 Agent 的一次等待窗口决定任务生死。

它不是自治多 Agent 编排平台。ask-web-ai 不自行产生目标或扩大权限;是否咨询、共享什么上下文、如何采纳结果,仍由当前 Agent 或调用方负责。

核心能力

  • start 只负责准备页面、完成一次逻辑提交并返回 operationId,不占住进程等待回答。
  • Prompt 先作为不可变 UTF-8 Payload 落入私有 Prompt Store;inline 输入采用有界 fill 或 pasteText,异常时重新解析输入框并逐字核对草稿;超过内部安全阈值时自动生成一个 .txt 附件和短说明。
  • 上传、写草稿和点击发送是独立 mutation。草稿写好后使用只读检查等待 Send 真正可操作;只有草稿全文及附件状态通过页面可见验证后,才进入一次点击。
  • 发送前遇到 ChatGPT 自动保存的历史草稿时,会先核对页面和草稿指纹、自动清空并验空,再重新填写;每次调用至多成功清空一次。页面已换会话、草稿持续变化或 Send 可能发生时绝不清空。
  • status 只返回有界尾部、结构计数和附件摘要,不随回答长度增长。
  • 生成按钮只作为“可能仍在生成”的 busy 提示,不作为进度证明;回答证据五分钟没有变化时返回可恢复的 stalled,不会关闭页面或重发 Prompt。
  • 回答超过约 20 分钟后进入 long_running 观察预算并降低轮询频率;默认 60 分钟观察期限到达只返回 deadline_exceeded,任务仍保留,可继续延长。
  • operationId 代表同一个问题,每个输入/发送 attempt 使用独立 request-id。输入中断进入 uncertain_input,不会被误判为已经发送;确认是本 Operation 写入的严格前缀后,原 Prompt 的显式 start 可进行一次有界完整替换。一旦点击可能已经派发,永久禁止再次发送 Prompt。
  • Send 只在当前 composer 所属 form 内寻找唯一可操作按钮;新 user turn/assistant turn 才是提交成功的主要证据,Stop 按钮、输入框变空和 click 成功都不能单独证明发送成功。
  • 对属于本次回答的明确生成错误框,可使用独立 mutation 最多点击一次该回答自己的 Retry/Regenerate;不会点击全局、登录、限流、配额、政策、上传、下载或来源不明的 Retry。
  • 登录页返回明确的 needs_login,不会伪装成 timeout 或观察失败。
  • 最终正文先写入私有 Result Store;短文本可 inline,长文本通过绝对文件路径和 SHA-256 清单交付。
  • 图片默认只返回脱敏元数据;显式使用 --artifact-policy download 时优先可验证下载,否则保存并标注渲染截图。
  • result 从 Result Store 交付结果,并优先自动完成本次 Task Space 清理;清理无法确认时返回 delivered,由 ack 作为重试入口。结果交付后即可立即在原会话续问,发布后的结果即使 Runtime 暂时离线也能读取。
  • 默认把当前代码项目映射到一个私人 ChatGPT Project;显示名称使用用户可读的仓库或工作区名称,内部身份与名称分开。Project 与 Conversation 长期保留,浏览器 Task Space 只在一次 Operation 期间存在。
  • 新主题默认在 Project 内创建新 Conversation;--session 或 --continue 才复用指定会话,不根据 Prompt 内容猜历史会话。
  • 同一 Conversation 同时只允许一个写入 Operation,不同 Conversation 可以并行。
  • Operation 先加锁、再认领 Conversation、再持久化 Job;未形成 Job 的认领会精确回滚,不留下空会话占用。
  • 只使用 Tabbit Browser-owned Runtime,不静默切换 Chrome、CDP、MCP 或其他浏览器后端。
  • Task 一旦绑定就必须走唯一的 finish 收尾;保留页面与保留 Runtime Task 分开处理。新 Task 使用 Runtime 的真实上限,撞到上限时直接报告占用数和任务名。
  • Windows 与 macOS 使用同一个 Skill、同一套命令和状态模型。

Provider 状态

Provider 已注册 确定性 Adapter 当前能力
ChatGPT 是 是 文本提问、单附件长 Prompt、持久 Job、长回答文件交付、图片元数据/截图、登录恢复
Claude 是 否 仅可发现;不会猜 selector 或自动提交
Gemini 是 否 仅可发现;不会猜 selector 或自动提交
Kimi 是 否 仅可发现;不会猜 selector 或自动提交

新增 Provider 的实现门槛见 Provider Adapter Authoring。

工作原理

flowchart LR
    A[Host Agent] -->|start| B[ask-web-ai Job Manager]
    B --> C[Provider Adapter]
    C --> D[tabbit-cli]
    D --> E[Persistent Task Space]
    E --> F[ChatGPT]
    A -->|status / result / ack| B
    B <--> G[(Private run ledger)]
    B <--> H[(Private Result Store)]
    B <--> I[(Private Prompt Store)]
    B <--> J[(Workspace / Project / Conversation Registry)]
Loading

一个 Job 的正常生命周期:

start -> prepared -> optional upload -> staging_input -> input_staged -> submitting -> running
                       |                    |                 |
                       v                    v                 v
                uncertain_upload     uncertain_input   uncertain_submission
                                            |
                                            v
                              read-only draft reconciliation
                                            |
                                            v
                              automatic CAS clear -> restage

running <-> stalled
          |
          v
quiescent_unverified -> finalizing -> materializing -> ready
                                                    |       |
                                                    v       v
                                      delivery_blocked   result -> completed
                                                               |
                                                               v
                                                        delivered -> ack -> completed

最重要的边界是:

宿主 Agent 等待结束 != 浏览器 Job 结束 != finish Task Space

结果交付时会优先自动清理对应 Operation 的 Task Space;只有清理无法确认时才进入 delivered,等待 ack 重试。结果交付后,该 Operation 就不再占用 Conversation 写入权;续问无需先关闭旧 Task Space。完整状态机与 result schema 见 docs/spec.md。

Project、Conversation 和 Task Space 不是一回事:

代码仓库 -> ChatGPT Project(长期)
讨论主题 -> Conversation(长期)
一次提问 -> Operation(可恢复)
浏览器页 -> Task Space(交付确认后关闭)

环境要求

  • 能够加载并遵循本地 Skill、执行 Node.js CLI 的宿主 Agent。
  • 已安装并启动 Tabbit Browser,且 tabbit-cli diagnose 能连接 Browser-owned Runtime 并返回 Task inventory。
  • 宿主 Agent 与 Tabbit 位于同一台可访问本机 GUI Browser 的机器;纯云端或隔离沙箱宿主通常无法直接使用。
  • Node.js 运行环境;CI 使用 Node.js 22。
  • 使用 ChatGPT 前,由用户本人在 Tabbit Browser 中完成登录。

登录、CAPTCHA、两步验证、账号选择和 consent 都是人工操作。不要向任何 Agent 提供密码、Cookie 或 token。

安装与宿主接入

宿主需要安装 skills/ask-web-ai/ 目录中的 SKILL.md,执行其中的 scripts/*.mjs,并访问同机的 Tabbit Runtime。不同宿主发现和安装 Skill 的方式可能不同,但调用的是同一套 CLI 和状态协议。

宿主 当前状态 接入要求
Codex 已文档化并实际使用 安装为全局 Skill,允许执行本地 CLI
其他支持本地 Skill 的 Agent 按能力条件可接入 能读取 SKILL.md、执行 CLI、访问同机 Runtime
云端或隔离沙箱 Agent 环境相关 必须具备到本机 Runtime 的安全访问路径

Codex 接入示例

在 Codex 中调用全局 Skill Installer:

使用 $skill-installer 将 https://github.com/pgw10086/ask-web-ai/tree/main/skills/ask-web-ai 安装到 Codex 全局 skills。

安装后新建一个 Codex 任务或重启 Codex,使 Skill 被重新发现。其他宿主应按自身 Skill 发现机制暴露本仓库。Tabbit Browser 与 Runtime 是独立前提,本 Skill 不会自行下载、启动或替换浏览器。

两种使用方式

1. 用户显式委托

用户可以明确要求当前 Agent 发起一次持久化咨询:

使用 ask-web-ai,把下面的问题只提交给 ChatGPT 一次。等待 Job 完成后取回完整回答,把它作为外部意见与你自己的分析一起交付给我:
<你的问题>

2. Agent 内部主动协作

用户不需要在每个任务中明确写“去问 ChatGPT”。当宿主 Agent 的权限和策略允许,并且第二意见确有帮助时,可以把 ask-web-ai 作为任务内部的协作工具:

评审下面的架构方案。你负责最终结论;必要时可以使用 ask-web-ai 获取 ChatGPT 的第二意见。

只共享完成评审所需的最小上下文。比较双方观点后,说明一致点、分歧点以及采纳或不采纳外部意见的理由,再给出最终建议:
<架构方案>

这种主动协作只是当前 Agent 在既定任务范围内选择一个外部咨询工具,不表示 ask-web-ai 获得独立任务所有权、权限扩张或自治规划能力。

两种方式都会执行 start、短 status 轮询和 result;只有 result 返回 delivered 时才需要 ack 重试清理。running、stalled、quiescent_unverified、finalizing 或 materializing 时按照返回的 nextPollMs 再次查询。回答超过当前宿主调用窗口时,应保留 operationId,后续继续同一个 Job,而不是重新提问。

ChatGPT Project 与会话

仓库中的普通咨询默认使用 Project scope。第一次使用时,start 会返回 needs_project_setup,但不会操作浏览器。先查看建议绑定:

SKILL_DIR="${CODEX_HOME:-$HOME/.codex}/skills/ask-web-ai"
node "$SKILL_DIR/scripts/projects.mjs" status --pretty
node "$SKILL_DIR/scripts/projects.mjs" init --pretty

needs_project_setup 表示“当前工作区还没有本地项目绑定”,不是“ChatGPT 上没有这个项目”。这是本次 Project Job 的终止状态:不能因为找不到绑定就把同一个问题改发到临时对话或普通历史。只有用户事先明确要求一次性临时咨询时,才使用 --temporary。

init 先返回 confirmation_required。用户确认名称和创建动作后,才执行一次:

node "$SKILL_DIR/scripts/projects.mjs" init --yes --pretty

创建使用 ChatGPT 可见页面,设置为私人、Project-only memory,不调用网页私有 API,也不上传仓库。已有 Project 可在用户确认后绑定:

node "$SKILL_DIR/scripts/projects.mjs" bind \
  --url '<project-url>' --name '<exact-project-name>' --yes --pretty

默认建议名只用于显示,例如 ask-web-ai;不会再把内部 hash 放进 ChatGPT 侧边栏。若本机已有另一个同名项目,建议名才升级为 owner/repo。真正的绑定依赖本地 LocalProject 身份和准确 Project URL,不依赖名称。

同一 Git common dir 下的 worktree 会自动复用绑定;相同 remote 的另一份 clone、fork 或同名目录不会自动绑定。--workspace '<path>' 表示用户或宿主明确指定的项目范围,也可用于 monorepo 子项目:

node "$SKILL_DIR/scripts/projects.mjs" status --workspace '<actual-project-root>' --pretty
printf '%s' '<question>' | node "$SKILL_DIR/scripts/ask.mjs" \
  start --workspace '<actual-project-root>' --pretty

宿主提供的无 Git 投影目录会返回 workspace_identity_unverified。有可信真实根目录时显式传 --workspace;没有时让用户确认一次,不能根据变形目录名猜测并误绑。Codex 投影目录是其中一个实际例子。

默认每个新问题创建一条 Project Conversation。明确需要持续讨论时再复用:

# 稳定命名的专题会话
printf '%s' '<question>' | node "$SKILL_DIR/scripts/ask.mjs" \
  start --session architecture --pretty

# 继续某次 Operation 所在的会话
printf '%s' '<follow-up>' | node "$SKILL_DIR/scripts/ask.mjs" \
  start --continue '<operation-id>' --pretty

新主题不是直接在 Project 首页等待 composer。Adapter 先进入已绑定 Project,点击 Project 内部的新聊天入口,再确认 Conversation surface 和 composer。续聊则通过可见会话卡片进入目标 Conversation,等历史消息数量稳定后记录基线,再允许提交。这样不会把旧回答当成本轮结果。相同 session 或 conversationRef 已有写入者时返回 conversation_busy,不会发送 Prompt。

若旧版本或异常中断留下“没有对应 Job 的 Conversation 占用”,先预览再确认修复:

node "$SKILL_DIR/scripts/projects.mjs" repair --pretty
node "$SKILL_DIR/scripts/projects.mjs" repair --yes --pretty

修复只处理没有 Run、没有活跃操作锁且已经超过落盘窗口的认领。默认命令不修改数据;已有会话地址、session 或历史操作记录不会因为空占用修复而被删除。

CLI

提交一次并立即返回 Job:

printf '%s' '<question>' | node "$SKILL_DIR/scripts/ask.mjs" \
  start --provider chatgpt --pretty

默认 scope 是当前仓库绑定的 ChatGPT Project。一次性、无需保留上下文的独立调研显式使用 --temporary;需要普通 ChatGPT 历史但不属于 Project 时使用 --persistent。

需要把回答中的图片保存为文件时,在首次 start 增加:

printf '%s' '<question>' | node "$SKILL_DIR/scripts/ask.mjs" \
  start --provider chatgpt --artifact-policy download --pretty

短轮询状态:

node "$SKILL_DIR/scripts/ask.mjs" status '<operation-id>' --pretty

有 nextPollMs 时按该值再次查询:普通等待为 3000 ms,最终化阶段为 2000 ms,长任务约 10000 ms,疑似卡住约 15000 ms。每次 status 都是独立的有界观察,不返回完整正文。

状态为 ready 后读取回答:

node "$SKILL_DIR/scripts/ask.mjs" result '<operation-id>' --pretty

只有 result 返回 delivered 时,才调用 ack 重试清理:

node "$SKILL_DIR/scripts/ask.mjs" ack '<operation-id>' --pretty

明确放弃并清理:

node "$SKILL_DIR/scripts/ask.mjs" cancel '<operation-id>' --pretty

Prompt 只通过 stdin 传入,不进入进程参数。--deadline-ms 设置提交后的 Job 观察期限,默认 60 分钟;期限到达只返回 deadline_exceeded,不会停止生成、清理页面或重发 Prompt。用同一 operationId 和新的 --deadline-ms 可以继续。

发送前遇到非空草稿时,工具默认把它当作 ChatGPT 自动保存的历史未发送内容:记录 Project/Conversation 页面和草稿 SHA-256 指纹,使用独立 mutation 清空并验空,再重新填写、逐字核对,最后才进入独立 Send。这个取舍意味着用户手工留在同一输入框但尚未发送的草稿也会被删除。

一次调用最多成功清空一次。若清空前草稿发生变化,返回可恢复的 input_busy,调用方等待 nextPollMs 后用同一 Prompt 和 operationId 再次执行 start,无需询问用户;若页面已经切换到另一个会话,则返回 draft_conflict 并停止,不能把新页面升级成新的清空目标。已提交或可能已提交的 Job 永远不会清空输入框。--discard-draft 只为旧调用兼容保留,新流程不需要使用。

输入规划按 UTF-8 字节数执行。默认 32 KiB 以内使用 inline 输入,超过后使用一个 .txt 附件;默认 Prompt 总上限为 32 MiB。Inline 文本小于约 8 KiB 时使用有界 fill,多行文本也不例外;更大的 inline 文本才优先 pasteText。若 paste helper 在可能写入后报错,工具会重新解析输入框并读回可见全文,再判断完整、空白、本任务前缀或冲突;空白时才回退到最长 60 秒的 fill。比较保留正文和内部换行,只忽略富文本编辑器不稳定表示的末尾空行。8 KiB 只是输入策略提示,不是 ChatGPT 限制或附件阈值。

旧的 --resume <operation-id> 和 --abandon <operation-id> 仍可用于兼容迁移;新集成应使用显式 Job 子命令。

登录恢复

每个结果都包含 evidence.promptCommitted:

  • false:问题尚未提交。用户登录后,用原 Prompt 和原 operationId 再次执行 start。
  • true:问题已经提交。用户登录后只执行 status,绝不能再次传入 Prompt 或调用 submit。

promptCommitted 是给调用方看的恢复证据,不是唯一保护。即使调用方错误地再次执行 start,Job Manager 也会根据 ledger、Prompt fingerprint 和 mutation receipt 转入只读状态流程,不能强迫第二次 submit。

# 登录发生在提交前
printf '%s' '<same question>' | node "$SKILL_DIR/scripts/ask.mjs" \
  start --operation-id '<operation-id>' --pretty

# 登录发生在提交后
node "$SKILL_DIR/scripts/ask.mjs" status '<operation-id>' --pretty

登录域名只参与只读状态识别,不在该域名执行任何提交 mutation。

Job 状态

状态 含义 下一步
uploading 长 Prompt 附件正在准备或页面仍显示上传中 按 nextPollMs 只读查询
uncertain_input 写草稿阶段中断,Send 尚未开始 只读核对草稿;完整或为空时按原流程继续;确认是本 Operation 写入的严格前缀时,用原 Prompt 和原 operationId 再次执行 start 完整替换一次
input_busy 清空前草稿发生变化,可能有人或页面仍在修改输入框 不发送;等待 nextPollMs 后用原 Prompt 和原 operationId 再次执行 start,无需用户确认
draft_conflict 页面/会话身份变化或无法建立清空所需的页面与指纹前提 不清空、不发送;检查会话绑定或取消该 Job
ready_to_submit 附件/草稿已确认,Send 尚未发生;可能仍在等待按钮可操作 send_not_ready 时按 nextPollMs 查询;可操作后用原 Prompt 和原 operationId 再次执行 start
uncertain_upload 无法证明附件 mutation 的外部状态 只读核对同一 Job;不要重新上传或 Send
running 已提交,回答仍在出现、变化或短暂稳定 按 nextPollMs 再次 status
stalled Provider 可能仍显示忙碌,但五分钟没有可测回答进度;Stop 按钮本身不算进度 保留页面并低频继续同一 Job;不要停止、刷新或重发
quiescent_unverified UI 已安静,但还没有最终化和持久化结果 按 nextPollMs 继续
finalizing / materializing 正在复核页面并把正文/附件写入 Result Store 按 nextPollMs 继续
needs_login 明确识别到登录页或登录控件 人工登录,根据 promptCommitted 恢复
provider_unavailable ChatGPT 会话历史限流弹窗、Project 首页只剩重试或 Project Conversation 暂未就绪 保留同一 Job;恢复 Project surface 后用原 Prompt 和原 operationId 再次执行 start
ready 必需结果已发布并通过大小、哈希和类型校验 调用 result
delivered 回答已返回调用方,但 Task 清理尚未确认 确认收到后调用 ack 重试清理
completed 回答已交付且 Task 清理已确认 无需继续
delivery_blocked 网页可能已完成,但必需结果未安全持久化 禁止 ack;保留页面用于诊断或 cancel
deadline_exceeded Job 观察预算已到,未宣称成功或失败 不代表 ChatGPT 已停止;需要时为同一 Job 设置新期限
uncertain_submission 无法证明提交是否发生 只做 receipt、checkpoint 和页面核对
runtime_unavailable Browser-owned Runtime 暂时不可访问、Task 容量已满,或有界观察结果无法读取 保留同一 Job;有 nextPollMs 时继续,没有时先排查/恢复 Runtime 再显式查询
provider_error Provider 或 Adapter 有确定性错误 根据 error.source、error.code 排查或 cancel
abandoned 用户明确放弃 已进入清理流程

running、stalled 和最终化中间态都不是普通 timeout。stalled 只是“疑似没有进展”,后续可能恢复为 running;evidence.providerBusy 只表示页面仍显示忙碌,不等于进度证明。写草稿不具备 Send 能力,因此它的中断只能进入 uncertain_input。还在 queued/running 或进程退出时留在 staging_input 的写入,只能恢复同一 request-id。终态不确定后,status 只读识别 exact、empty、partial 或 conflict;同一 Prompt 的 start 负责后续 mutation。非空冲突在发送前由独立清空 mutation 处理,清空与 Send 之间必须重新暂存并核对全文;清空回执不确定时先只读对账,页面身份变化时永久停止清空。完整草稿但按钮 disabled 时只返回 ready_to_submit / send_not_ready,不会消耗点击。点击 attempt 只有在页面程序返回 not_dispatched 或 receipt 返回 mutationState: none 时才能更换。

助手回答重试与 Prompt 提交完全分开。Adapter 只有在“目标 user turn 唯一、错误属于紧随其后的 assistant response family、Retry 控件位于该错误范围、错误不属于排除类型”四项同时满足时才点击。点击前后 user turn 数量和身份必须不变;Retry receipt 只要进入 queued、running、interrupted 或已派发状态,就不会再创建第二次助手 Retry。

完成判定

ready 不是“看见停止按钮消失”或“文本暂时没变”。流程必须依次完成:

  • 用有界尾部、结构计数和附件摘要确认本次 assistant turn 有语义进度;
  • Provider 忙碌信号消失,且两次独立观察至少间隔两秒、状态不再变化;
  • 最终化时重新核对 host、登录、当前 turn 错误、忙碌状态和待加载图片;
  • 完整正文在 Browser-owned Runtime 内写入安全 artifact path;
  • Result Store 原子复制必需文件,验证大小、SHA-256、媒体类型并最后发布 manifest。

回答正文和原始 URL 不会写入 ledger。Ledger 只保存有界 observation signature、进度时间和恢复所需的最小状态。结果文件默认保留七天,独立于浏览器 Task Space 生命周期。

长输入、长回答和图片

长输入与长回答是两条独立链路。小于约 8 KiB 的 inline 输入优先使用有界 fill;更大的 inline 输入才使用 Runtime 的任务内 pasteText,并在 helper 报错后读回页面确认实际结果。网站拒绝合成粘贴且输入框为空时使用 60 秒有界 fill。每条路径都会重新解析 composer,并使用同一个严格的编辑器文本比较规则:除已有的换行规范外,只接受目标普通空格在相同位置被富文本编辑器显示为 NBSP;长度、字符或其他空白差异仍会阻止发送。输入阶段绝不会顺带点击 Send。超过 32 KiB inline 安全阈值时,Adapter 才从 Prompt Store 构造标准浏览器 File 并派发到公开 file input;正文不进入浏览器程序源码。

这个生成的 .txt 只包含用户已经要求发送给网页 AI 的 stdin 内容,不代表获准上传 Prompt 中提到的仓库文件或任意本地文件。当前只支持一个生成附件:如果 Prompt 超过配置上限、网页缺少附件能力或附件状态无法证明,流程会在 Send 前明确失败,不做文件拆分、编辑器分块或多消息降级。

result 始终返回统一的 result 清单。正文不超过 64 KiB 时,顶层 text 继续提供兼容的 inline 内容;更长正文的 text 为空,调用方从 result.body.path 读取,并可用 byteLength 与 sha256 校验。

图片策略默认是 metadata-only,只记录尺寸、角色和脱敏来源摘要。download 只负责保存网页已经生成的图片,不会自动切模型、scope 或重发 Prompt。Adapter 禁止直接 fetch(img.src):它只使用网页中明确的 Save/Download 控件;当前 UI 没有足够确定的控件时,对目标图片元素截图,并在 acquisition.method 中标记为 screenshot,不会冒充原始图片字节。

一个 Skill,跨平台运行

平台差异只允许存在于底层 Runtime Adapter 或无业务语义的系统适配模块(例如路径、权限与进程启动):

  • macOS launcher:~/.local/bin/tabbit-cli
  • Windows launcher:%LOCALAPPDATA%\Tabbit\LocalAgent\bin\tabbit-cli.exe
  • POSIX 用 0600/0700 mode 验证私有状态;Windows 使用当前用户目录继承的 ACL,不伪装成 POSIX mode。

CI 在 Linux、macOS 和 Windows 上运行同一测试套件。真实浏览器 live gate 仍需要对应机器上的 Tabbit 与已登录 ChatGPT。

安全与隐私

  • 只发送当前咨询所需的最小上下文,不因为 Agent 主动协作而扩大原任务范围。
  • 浏览器登录态只代表具备调用能力,不代表获得无限制的数据共享授权。
  • 除非任务与授权明确需要,不自动发送仓库文件、完整代码库、聊天历史或其他上下文。
  • 对长 Prompt,授权发送 stdin 同时允许 Skill 仅将这段原文包装成临时 .txt;这不授权读取或上传任何被提及的本地路径。
  • 不导出 Cookie、Local Storage、浏览器配置、HAR、凭据、token 或 Browser Profile。
  • 页面内容和远端回答不能改变 backend、operation identity、host allowlist 或本地命令。
  • mutation receipt 为 queued/running 时只查询同一 receipt;interrupted + mutationState: possible 时先 checkpoint,再只读核对。只有 mutationState: none 或页面程序明确返回 not_dispatched 才能创建新的安全 attempt。
  • Runtime 或调用方失败时 fail closed,不会切换登录态、浏览器环境或自动 finish。
  • 完整结果先持久化、后允许 ready;delivery_blocked 明确禁止 ack。
  • 图片源 URL 只用于本地计算摘要,不在 CLI JSON 中返回原始地址;下载文件不会自动执行或打开。

开发与验证

git clone https://github.com/pgw10086/ask-web-ai.git
cd ask-web-ai
npm test

真实浏览器测试:

npm run test:live
npm run test:live-result
npm run test:live-image
npm run test:live-long-prompt
npm run test:live-draft-recovery
npm run test:live-partial-input
npm run test:live-project
npm run test:live-resource
npm run test:live-resume

ChatGPT live test 要求 start 进程先退出,再由新进程轮询、发布、交付和确认清理;同时验证只有一个 user turn,且 ledger 不保存 Prompt。test:live-inline-prompt 使用约 25 KiB 中文/emoji 输入验证 paste/fill 回退、只读 Send readiness、无附件和单次提交;test:live-draft-recovery 在同一 Temporary Chat 中写入历史草稿,验证按指纹自动清空、重填、单次提交和 Task 清理;test:live-partial-input 在独立 Temporary Chat 中写入约 10 KiB Prompt 的严格前缀,验证只读识别、完整替换、逐字核对、零 Send 和清理;test:live-project 验证同一 Conversation 关闭页面后可重新进入、历史基线不为空、续聊只读取新回答以及单写锁。test:live-long-prompt 使用约 60 KiB 中文/emoji 输入验证单附件、单次提交和 Prompt Store 清理;test:live-result 验证 270 KB Browser-owned UTF-8 文件的逐字节发布;test:live-image 验证真实图片识别、下载/截图 acquisition 和媒体 sniff;Resource gate 验证超过 64 KiB 的即时 Resource stub、同 request-id 正式回执、UTF-8 边界恢复与清理。

已知限制

  • 当前只有 ChatGPT 确定性 Adapter。
  • 支持把超出安全阈值的 stdin 文本包装成一个生成的 .txt;任意用户文件附件、文件拆分、模型选择、Deep Research 控件和通用多轮 API 尚未实现。
  • Provider 文件候选目前只返回元数据;ChatGPT 图片可保存,但原始下载是否可用取决于当前 UI 是否暴露确定性控件,否则使用明确标注的截图回退。
  • 网页 UI 变化可能需要更新 Adapter 并重新执行 live gate。
  • Runtime 无法访问本机 GUI Browser 时,没有其他浏览器后端兜底。
  • 当前不包含常驻后台清理 daemon;新 Job 启动时会顺便回收明确过期的旧 Job,清理无法确认的 Job 仍需 ack 或 cancel。
  • Project 会话列表、Conversation 重命名、rotate、自动换新和交接摘要属于后续版本;当前只通过 --session 与 --continue 显式复用。用户在 ChatGPT 中重命名 Project 不改变绑定,Skill 会继续按准确 URL 使用并刷新本地显示名。

维护入口:SKILL.md · 运行协议 · Project/Conversation 设计 · Runtime 恢复 · Provider Adapter Authoring · README 设计调研

About

通用 Agent Skill + CLI,将网页版 AI 作为外部 Agent,用于调研、评审与方案讨论,帮助降低宿主上下文占用和 API Token 消耗;当前仅支持 ChatGPT 自动化。

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages