8000 feat(collector): support --codex-5h flag in quota-warmup task by InfinityPacer · Pull Request #75 · InfinityPacer/meterleaf · GitHub
[go: up one dir, main page]

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
6 changes: 3 additions & 3 deletions docs/collector.md
Original file line number Diff line number Diff line change
Expand Up @@ -398,12 +398,12 @@ Antigravity(各实例的 Gemini 与 Claude/GPT 池)和 Codex 的 7 天周窗
- **Antigravity 第三方池**(`3p_weekly`):优先调用 `gpt-oss-120b-medium`(失败时回退 `claude-sonnet-5-5-low`),随后执行 `agy -p /usage` 刷新缓存。
- **Codex**(`seven-day`):在临时目录下调用 `codex exec`(指定 `openai` 通道、`gpt-6-luna`、`low` 推理档位且关闭 MCP),产生的会话记录由下一轮采集器同步自动读取新周期额度。

默认只预热 7 天周窗口;需要连同 5 小时窗口一起预热时,在命令末尾加上 `--include-5h`(或设置环境变量 `METERLEAF_WARMUP_5H=1`)。每个已成功预热的旧周期在 `tasks/quota-warmup/state.json` 里记录,只触发一次;如果当轮失败,下一轮任务(5 分钟后)会自动重试。
默认只预热 7 天周窗口;传入 `--codex-5h`(或 `METERLEAF_WARMUP_CODEX_5H=1`)时一并预热 Codex 的 5 小时窗口,传入 `--include-5h`(或 `METERLEAF_WARMUP_5H=1`)时预热全部来源的 5 小时窗口。每个已成功预热的旧周期在 `tasks/quota-warmup/state.json` 里记录,只触发一次;如果当轮失败,下一轮任务(5 分钟后)会自动重试。

```sh
install -m 755 scripts/quota-warmup.ts ~/.local/bin/meterleaf-quota-warmup
~/.bun/bin/bun ~/.local/bin/meterleaf-quota-warmup --dry-run
meterleaf-collector tasks add quota-warmup --every 5 --timeout 120 -- "$HOME/.bun/bin/bun" "$HOME/.local/bin/meterleaf-quota-warmup"
~/.bun/bin/bun ~/.local/bin/meterleaf-quota-warmup --dry-run --codex-5h
meterleaf-collector tasks add quota-warmup --every 5 --timeout 120 -- "$HOME/.bun/bin/bun" "$HOME/.local/bin/meterleaf-quota-warmup" --codex-5h
meterleaf-collector tasks run quota-warmup
```

Expand Down
25 changes: 19 additions & 6 deletions scripts/quota-warmup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
* 仅靠本地额度缓存与会话文件判断窗口是否已到期,平时不发起任何探测请求。
*
* 默认只预热周窗口(`gemini_weekly`、`3p_weekly`、`codex:seven-day`);
* 传入 `--include-5h`(或环境变量 `METERLEAF_WARMUP_5H=1`)时一并预热 5 小时窗口。
* 传入 `--codex-5h`(或环境变量 `METERLEAF_WARMUP_CODEX_5H=1`)时开启 Codex 5 小时窗口预热,
* 传入 `--include-5h`(或环境变量 `METERLEAF_WARMUP_5H=1`)时一并开启所有 5 小时窗口预热。
*
* 用法: bun scripts/quota-warmup.ts [--dry-run] [--include-5h]
* 用法: bun scripts/quota-warmup.ts [--dry-run] [--codex-5h] [--include-5h]
*/
import {
accessSync,
Expand Down Expand Up @@ -683,6 +684,7 @@ export function readLatestCodexLimits(
export interface WarmupOptions {
dryRun?: boolean;
include5h?: boolean;
includeCodex5h?: boolean;
now?: () => Date;
pickPrompt?: (prompts: readonly string[]) => string;
runner?: CommandRunner;
Expand All @@ -697,6 +699,11 @@ export async function runWarmup(
const include5h =
options.include5h ??
(env.METERLEAF_WARMUP_5H === "1" || env.METERLEAF_WARMUP_5H === "true");
const includeCodex5h =
include5h ||
(options.includeCodex5h ??
(env.METERLEAF_WARMUP_CODEX_5H === "1" ||
env.METERLEAF_WARMUP_CODEX_5H === "true"));
const pickPrompt =
options.pickPrompt ??
((prompts) => prompts[Math.floor(Math.random() * prompts.length)]!);
Expand Down Expand Up @@ -773,7 +780,7 @@ export async function runWarmup(
if (weekly && weekly.resetEpoch <= nowSec) {
candidates.push({ window: "seven-day", resetEpoch: weekly.resetEpoch });
}
if (include5h) {
if (includeCodex5h) {
const fiveHour = codexLimits.windows.get("five-hour");
if (fiveHour && fiveHour.resetEpoch <= nowSec) {
candidates.push({
Expand Down Expand Up @@ -1073,17 +1080,23 @@ async function warmupCodexTarget(
if (import.meta.main) {
const args = process.argv.slice(2);
const unknown = args.filter(
(arg) => arg !== "--dry-run" && arg !== "--include-5h",
(arg) =>
arg !== "--dry-run" && arg !== "--include-5h" && arg !== "--codex-5h",
);
if (unknown.length > 0) {
console.error(
"用法: bun scripts/quota-warmup.ts [--dry-run] [--include-5h]",
"用法: bun scripts/quota-warmup.ts [--dry-run] [--codex-5h] [--include-5h]",
);
process.exit(2);
}
const dryRun = args.includes("--dry-run");
const include5h = args.includes("--include-5h") ? true : undefined;
const report = await runWarmup(process.env, { dryRun, include5h });
const includeCodex5h = args.includes("--codex-5h") ? true : undefined;
const report = await runWarmup(process.env, {
dryRun,
include5h,
includeCodex5h,
});
let failed = false;
for (const action of report.actions) {
const scope = action.profileName
Expand Down
21 changes: 19 additions & 2 deletions tests/quota-warmup.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ describe("quota-warmup task script", () => {
expect(secondReport.skippedHandled).toContain("codex:default");
});

test("supports optional 5h warmup when --include-5h / METERLEAF_WARMUP_5H=1 is enabled, and falls back to secondary 3p model on failure", async () => {
test("supports --codex-5h for Codex 5h without enabling Agy 5h, and --include-5h with 3p model fallback", async () => {
const sb = createSandbox();
const nowSec = 1_800_000_000;

Expand All @@ -290,20 +290,37 @@ describe("quota-warmup task script", () => {
].join("\n") + "\n",
);

// codex: 仅 five-hour 到期,seven-day 未到期
writeCodexRollout(join(sb.codexSessions, "rollout-1.jsonl"), {
timestamp: new Date((nowSec - 10) * 1000).toISOString(),
fiveHourReset: nowSec - 20,
sevenDayReset: nowSec + 86400,
});

const attemptedModels: string[] = [];
const runner: CommandRunner = async (argv) => {
const modelIdx = argv.indexOf("--model");
if (modelIdx !== -1) {
const model = argv[modelIdx + 1]!;
attemptedModels.push(model);
// 模拟主模型 gpt-oss-120b-medium 报错退出,测试自动回退到 claude-sonnet-5-5-low
if (model === "gpt-oss-120b-medium") {
return { exitCode: 1, stdout: "", logText: "" };
}
}
return { exitCode: 0, stdout: "{}", logText: "" };
};

// 仅开启 includeCodex5h 时,只预热 codex:five-hour,不触发 phronara 的 3p_5h
const codexOnly = await runWarmup(sb.env, {
includeCodex5h: true,
now: () => new Date(nowSec * 1000),
runner,
});
expect(codexOnly.actions.map((a) => [a.key, a.windows])).toEqual([
["codex:default", ["five-hour"]],
]);

// 开启 METERLEAF_WARMUP_5H=1 时,phronara 的 3p_5h 也触发并从 gpt-oss-120b-medium 回退到 claude-sonnet-5-5-low
const report = await runWarmup(
{ ...sb.env, METERLEAF_WARMUP_5H: "1" },
{
Expand Down
Loading
0