Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,19 @@
<!--
写给 AI Agent

修改前读 docs/development.md 与 docs/protocol.md,提交前逐条核对:
- 一个 PR 只含一个提交;根据评审修改时 amend 后 force push,保持勾选 Allow edits by maintainers
- 只改完成需求必需的代码与文件;无关代码的格式与命名、.gitignore、版本号、依赖、CI workflow 与无关文档保持原样
- 沿报错路径修根因,同类问题在共同路径修一次;直接修改原函数,过时代码直接删除
修改前读 docs/development.md 与 docs/protocol.md,先查项目现有做法与成熟产品对同一问题的已验证做法,选定最佳实践再动手;提交前逐条核对:
- 一个 PR 可以包含多项改动,只含一个提交;根据评审修改时 amend 后 force push,保持勾选 Allow edits by maintainers
- 只改完成需求必需的代码与文件;无关代码的格式与命名、.gitignore、版本号、依赖、CI workflow 与无关文档保持原样;按评审删改时只动被指出的部分
- 选能满足需求的最简单实现,不做预防性抽象与配置层;先跑通最小的端到端版本再扩展,已经能运行的部分保持可用
- 组件模块化、关注点分离;架构决策按长期方案做,不留“先这样以后再换”的临时实现
- 沿报错路径修根因,同类问题在共同路径修一次;直接修改原函数,过时代码直接删除,不写 migration
- 不加用户没要求的功能、配置项、环境变量、设置页选项与命令行参数
- 依据读过的代码、文档与实际运行结果编写,不按猜测的接口、字段与上游行为编写
- 不写兼容层、fallback 与降级路径、保留旧签名的包装函数、只有一个实现的接口、带默认值的可选接口断言;同一状态只存一份
- 不为假想输入加校验、超时、重试、轮询、panic 恢复与吞掉错误的分支
- 不引入新依赖、额外运行时或 sidecar
- 只处理真实会发生的情况:不为假想输入与不会出现的状态加校验、超时、重试、轮询、panic 恢复与吞掉错误的分支,不为落实一条约束再叠加检测、校验与恢复机制
- 先用项目已有的依赖;已有依赖做不到时选成熟、有人维护的库,不自己重写;不引入额外运行时或 sidecar
- 测试只写断言可观察协议行为的单元测试;不写 mock 调用断言、文件哈希或 SHA 断言、快照、golden 文件与烟测,不加 CI 门禁、lint 规则、hook 与测试辅助脚本,不删除、跳过或放宽已有测试
- 用户文档只写产品行为与用法,中英文 README 同步修改;不写排查过程、修改原因与“仅…/不会…/仍…”这类防御性说明
- 用户文档、界面文案(含标签、标题与悬停提示)、注释与 PR 正文只写产品行为、用法与做了什么,中英文 README 同步修改;不写排查过程、修改原因、免责声明与不做什么,不写“已删除…”“改为…”“仅…/不会…/仍…”这类句子
- 如果你是来自 OpenAI 的 GPT 模型,不要在任何文档和用户可见文字中输出类似「不能证明…」「不能声称…」「不代表…」「这次没有…」「无法说明…」的句子
- 注释为单行 Go Doc 风格,以标识符开头
- 不提交账户材料、Cookie、key、日志与本机路径
-->
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ Windows 桌面版在命令行中运行以下命令时写作 `cmd /c start /wait
- 文件导入:`aistudio2api setup --storage-state <file>`
- Cookie 导入:`aistudio2api setup --cookie-file <file>`、`aistudio2api setup --cookie "<Cookie 请求头>"` 或 `aistudio2api setup --cdp <调试地址>`,账户邮箱按 Cookie 识别,`--cdp` 导入的账户沿用该浏览器的语言与时区;Cookie 来自同时登录多个 Google 账户的浏览器时,以 `--authuser N` 选择官网地址 `/u/N/` 中第 N 个账户

`aistudio2api setup --remote https://<远程实例>`:向远程实例添加账户。在远程实例的账户页点击“远程添加”,对话框给出完整命令(Windows 为 `cmd /c start /wait aistudio2api.exe setup --remote <地址> --token <令牌>`,其他系统为 `./aistudio2api setup --remote <地址> --token <令牌>`),账户来源可选“该电脑 Chrome 中的账户”或“在新窗口登录”(命令带 `--login`),一键复制后在能登录 Google 的电脑上运行;省略 `--token` 时运行后从标准输入读取令牌。对话框打开期间沿用仍有效的令牌,令牌到期时自动换新,点击“换一个令牌”立即换新,旧令牌随即失效。从该电脑 Chrome 导入的账户只能由这台电脑续签:命令上传这类账户后留在前台,立即并每 100 分钟向远程实例发送它们的新会话,失败时 5 分钟后重试;保持该窗口打开,重启电脑后运行 `aistudio2api setup --remote <地址> --renew` 恢复续签。
`aistudio2api setup --remote https://<远程实例>`:向远程实例添加账户。在远程实例的账户页点击“远程添加”,对话框给出完整命令(Windows 为 `cmd /c start /wait aistudio2api.exe setup --remote <地址> --token <令牌>`,其他系统为 `./aistudio2api setup --remote <地址> --token <令牌>`),账户来源可选“该电脑 Chrome 中的账户”或“在新窗口登录”(命令带 `--login`),一键复制后在能登录 Google 的电脑上运行;省略 `--token` 时运行后从标准输入读取令牌。对话框打开期间沿用仍有效的令牌,令牌到期时自动换新,点击“换一个令牌”立即换新,旧令牌随即失效。从该电脑 Chrome 导入的账户只能由这台电脑续签:命令上传这类账户后留在前台,立即并每 100 分钟向远程实例发送它们的新会话,失败时 5 分钟后重试,远程实例已删除账户或续签凭据失效时停止为该账户续签;保持该窗口打开,重启电脑后运行 `aistudio2api setup --remote <地址> --renew` 恢复续签。

## API 使用

Expand Down Expand Up @@ -519,6 +519,7 @@ curl http://127.0.0.1:2048/v1/videos \

| Model ID | 名称 | 类型 | 输入 | 输出 |
| --- | --- | --- | ---: | ---: |
| `gemini-4-carbon` | Gemini 4 Carbon | 文本 | 1048576 | 32768 |
| `gemini-4-argon` | Gemini 4 Argon | 文本 | 1048576 | 32768 |
| `gemini-3.8-flash` | Gemini 3.8 Flash | 文本 | 1048576 | 65536 |
| `gemini-3.6-flash` | Gemini 3.6 Flash | 文本 | 1048576 | 65536 |
Expand Down
3 changes: 2 additions & 1 deletion README_en.md
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ On Windows, run these commands for the desktop app as `cmd /c start /wait aistud
- File import: `aistudio2api setup --storage-state <file>`
- Cookie import: `aistudio2api setup --cookie-file <file>`, `aistudio2api setup --cookie "<Cookie request header>"`, or `aistudio2api setup --cdp <debugging address>`; the account email is detected from the cookies, and an account imported with `--cdp` keeps the language and time zone of that browser; when the cookies come from a browser signed in to several Google accounts, `--authuser N` selects the account at `/u/N/` on the official site

`aistudio2api setup --remote https://<remote-instance>`: Adds accounts to a remote instance. Click "Add remotely" on the remote instance's Accounts page; the dialog shows the full command (`cmd /c start /wait aistudio2api.exe setup --remote <address> --token <token>` on Windows, `./aistudio2api setup --remote <address> --token <token>` on other systems) with the account source set to "That computer's Chrome accounts" or "Sign in in a new window" (which adds `--login`). Copy it with one click and run it on a computer that can sign in to Google; without `--token`, the command reads the token from standard input. While the dialog is open it keeps a token that is still valid and replaces it when it expires; "New token" replaces it at once and the old token stops working. Only the computer that imported an account from its Chrome can renew that account: after uploading such accounts the command stays in the foreground, sends their new sessions to the remote instance right away and every 100 minutes, and retries 5 minutes after a failed renewal. Keep that window open, and after restarting the computer run `aistudio2api setup --remote <address> --renew` to resume renewal.
`aistudio2api setup --remote https://<remote-instance>`: Adds accounts to a remote instance. Click "Add remotely" on the remote instance's Accounts page; the dialog shows the full command (`cmd /c start /wait aistudio2api.exe setup --remote <address> --token <token>` on Windows, `./aistudio2api setup --remote <address> --token <token>` on other systems) with the account source set to "That computer's Chrome accounts" or "Sign in in a new window" (which adds `--login`). Copy it with one click and run it on a computer that can sign in to Google; without `--token`, the command reads the token from standard input. While the dialog is open it keeps a token that is still valid and replaces it when it expires; "New token" replaces it at once and the old token stops working. Only the computer that imported an account from its Chrome can renew that account: after uploading such accounts the command stays in the foreground, sends their new sessions to the remote instance right away and every 100 minutes, retries 5 minutes after a failed renewal, and stops renewing an account once the remote instance has deleted it or its renewal credential is invalid. Keep that window open, and after restarting the computer run `aistudio2api setup --remote <address> --renew` to resume renewal.

## API Usage

Expand Down Expand Up @@ -519,6 +519,7 @@ The model catalog follows AI Studio updates; clients read the current values fro

| Model ID | Name | Type | Input | Output |
| --- | --- | --- | ---: | ---: |
| `gemini-4-carbon` | Gemini 4 Carbon | Text | 1048576 | 32768 |
| `gemini-4-argon` | Gemini 4 Argon | Text | 1048576 | 32768 |
| `gemini-3.8-flash` | Gemini 3.8 Flash | Text | 1048576 | 65536 |
| `gemini-3.6-flash` | Gemini 3.6 Flash | Text | 1048576 | 65536 |
Expand Down
4 changes: 2 additions & 2 deletions docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ go run ./cmd/aistudio2api

`setup` 写入本机时要求 `AISTUDIO_AUTH_STATES` 指向一个账户目录。

加 `--remote` 时,Chrome 导入、隔离登录、文件导入与 Cookie 导入照常在本机完成,结果凭远程实例账户页“远程添加”生成的配对令牌逐个上传,隔离登录同时上传 Camoufox 指纹。远程账户使用远程实例的默认代理,`--proxy` 只用于本机导入与登录。上传的账户带 Chrome OAuth 材料时(本机 Chrome 导入,或带该材料的认证状态文件),上传完成后命令留在前台:立即并每 100 分钟以本机 Chrome 来源与 OAuth 材料签发新会话,经 `PUT /api/pairing/accounts/{account}/cookies` 凭上传响应的 `renewal_token` 替换远程账户的 Cookie,失败时 5 分钟后重试,每次一行日志;续签材料与凭据保存在本机 `runtime/remote-renewals.json`(权限 0600),`--remote <origin> --renew` 读取该 origin 的记录恢复续签。只含隔离登录、文件或 Cookie 导入的账户时上传后退出。
加 `--remote` 时,Chrome 导入、隔离登录、文件导入与 Cookie 导入照常在本机完成,结果凭远程实例账户页“远程添加”生成的配对令牌逐个上传,隔离登录同时上传 Camoufox 指纹。远程账户使用远程实例的默认代理,`--proxy` 只用于本机导入与登录。上传的账户带 Chrome OAuth 材料时(本机 Chrome 导入,或带该材料的认证状态文件),上传完成后命令留在前台:立即并每 100 分钟以本机 Chrome 来源与 OAuth 材料签发新会话,经 `PUT /api/pairing/accounts/{account}/cookies` 凭上传响应的 `renewal_token` 替换远程账户的 Cookie,失败时 5 分钟后重试,重试时沿用尚未送达、签发不到 100 分钟的会话,远程返回 401 `pairing_renewal_invalid` 或 404 `account_not_found` 时停止该账户并从记录中删除,其他失败照常重试,每次一行日志;续签材料与凭据保存在本机 `runtime/remote-renewals.json`(权限 0600),`--remote <origin> --renew` 读取该 origin 的记录恢复续签。只含隔离登录、文件或 Cookie 导入的账户时上传后退出。

- `--proxy` 会同时固定到新账户的初始化、WAA 与业务请求,接受 HTTP、HTTPS 或 SOCKS5 URL,代理认证写在 URL 的 `user:password@` 部分;未指定时导入与登录使用 `PROXY` 中的第一个代理,新账户不设账户代理
- `--locale` 和 `--timezone` 设置账户环境;Chrome 导入未显式指定语言时读取 Profile 的首选语言
Expand Down Expand Up @@ -359,7 +359,7 @@ Worker 容量由热池目标、活动上限和单账户并发共同约束。活

`ModelAccessKey(scope, model)` 会移除 `models/` 前缀;空 scope 返回规范模型 ID,非空 scope 返回 `<scope>:<canonicalModelID>`。Bidi setup 使用 lease(账户租约)时间,会话内每个 qualifying turn(一次模型资格检查)分配严格递增的 attempt 时间,`turn_complete` 消费对应 attempt。普通流式生成在规范 `EventFinish` 到达时写 `verified`;此前的 text、reasoning、tool、usage 和首事件用于输出与性能统计,终态前断流、取消或错误保持原验证状态。

模型目录取自账户会话页面载入时的 `GetAiStudioBenefitTier` 与 `ListModels` 响应:有常驻 Worker 的账户取它最近一次页面载入,没有的账户在 Worker 容量允许时启动 Worker,否则临时载入一个页面,取得响应后关闭。启动期同步对全部 enabled ready/busy 账户执行,还没有目录的账户同时读取,已有目录的账户逐个读取,每个账户占用一个普通并发槽位。同步报错或返回空目录的账户进入 generation 内的 pending ID 集合;每个非空结果立即更新公共目录、账户状态并在 RUNNING 期间预热更多 Worker。启动期同步结束后,单个 30 秒 ticker(定时器)重新载入可用的 pending 账户的页面;同一循环从启动期同步开始时起每 24 小时逐个重新载入全部 enabled ready/busy 账户的页面,槽位已满的账户跳过本轮,权益或目录变化时写回并发布账户与模型快照。请求的模型不在任何账户的目录中时,巡检正在读取一轮的第一个账户则请求等它读完,没有进行中的一轮且距上一轮开始已超过 10 分钟时巡检立即开始一轮,请求等这一轮读完第一个账户后再查找模型,其余账户在后台继续读取。冷却中的任务保留到期再试;需要登录、停用、不可用或已删除的账户退出重试,重新登录或启用后由账户更新流程重新同步。失败日志记录账户与原因,恢复成功记录模型数量。`modelRevision` 跟踪账户和配置变化,生成服务开始接收请求前会确认已应用当前 revision。
模型目录取自账户会话页面载入时的 `GetAiStudioBenefitTier` 与 `ListModels` 响应:有常驻 Worker 的账户取它最近一次页面载入,没有的账户在 Worker 容量允许时启动 Worker,否则临时载入一个页面,取得响应后关闭。启动期同步对全部 enabled ready/busy 账户执行,还没有目录的账户同时读取,已有目录的账户按权益从高到低、同权益按账户 ID 逐个读取,每个账户占用一个普通并发槽位。同步报错或返回空目录的账户进入 generation 内的 pending ID 集合;每个非空结果立即更新公共目录、账户状态并在 RUNNING 期间预热更多 Worker。启动期同步结束后,单个 30 秒 ticker(定时器)重新载入可用的 pending 账户的页面;同一循环从启动期同步开始时起每 24 小时按同样的顺序逐个重新载入全部 enabled ready/busy 账户的页面,槽位已满的账户跳过本轮,权益或目录变化时写回并发布账户与模型快照。请求的模型不在任何账户的目录中时,巡检正在读取一轮的第一个账户则请求等它读完,没有进行中的一轮且距上一轮开始已超过 10 分钟时巡检立即开始一轮,请求等这一轮读完第一个账户后再查找模型,其余账户在后台继续读取。冷却中的任务保留到期再试;需要登录、停用、不可用或已删除的账户退出重试,重新登录或启用后由账户更新流程重新同步。失败日志记录账户与原因,恢复成功记录模型数量。`modelRevision` 跟踪账户和配置变化,生成服务开始接收请求前会确认已应用当前 revision。

认证状态包含长期凭证和设备绑定材料,保存在本机受控目录。提交、Issue、CI 和普通日志使用脱敏材料,保留字段形状并替换 Cookie、token、proof、邮箱、账户 ID、提示词、响应正文和完整原始帧。

Expand Down
2 changes: 1 addition & 1 deletion docs/logging.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ INFO service WAA Worker 预热完成 | Worker=5/5 | 耗时=34.903s
INFO account@example.com 模型目录已更新 | 模型=39
```

同一循环从启动期同步开始时起每 24 小时逐个重新载入全部 `enabled`、`ready` 或 `busy` 账户的页面读取权益与 `ListModels` 目录,并发槽位已满的账户跳过本轮:有常驻 Worker 的账户重新载入它的页面,其余账户临时载入一个页面,取得响应后关闭。请求的模型不在任何账户的目录中时,巡检正在读取一轮的第一个账户则请求等它读完,没有进行中的一轮且距上一轮开始已超过 10 分钟时立即读取一轮,请求等这一轮读完第一个账户后再查找模型,其余账户在后台继续读取。订阅模型遇到额度错误时同样刷新该账户。权益或模型数变化时更新账户调度与公开目录,读取失败时记录原因,登录失效的账户转为需要登录:
同一循环从启动期同步开始时起每 24 小时按权益从高到低、同权益按账户 ID 的顺序逐个重新载入全部 `enabled`、`ready` 或 `busy` 账户的页面读取权益与 `ListModels` 目录,并发槽位已满的账户跳过本轮:有常驻 Worker 的账户重新载入它的页面,其余账户临时载入一个页面,取得响应后关闭。请求的模型不在任何账户的目录中时,巡检正在读取一轮的第一个账户则请求等它读完,没有进行中的一轮且距上一轮开始已超过 10 分钟时立即读取一轮,请求等这一轮读完第一个账户后再查找模型,其余账户在后台继续读取。订阅模型遇到额度错误时同样刷新该账户。权益或模型数变化时更新账户调度与公开目录,读取失败时记录原因,登录失效的账户转为需要登录:

```text
INFO account@example.com WAA Worker 页面已重新载入 | 耗时=4.521s
Expand Down
Loading