pi-ui-extend 1.0.41 → 1.0.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -13
- package/dist/app/app.d.ts +13 -0
- package/dist/app/app.js +158 -8
- package/dist/app/cli/install.js +2 -2
- package/dist/app/commands/command-controller.d.ts +4 -0
- package/dist/app/commands/command-controller.js +11 -0
- package/dist/app/commands/command-git-actions.d.ts +25 -0
- package/dist/app/commands/command-git-actions.js +381 -0
- package/dist/app/commands/command-host.d.ts +4 -0
- package/dist/app/commands/command-host.js +5 -2
- package/dist/app/commands/command-model-actions.d.ts +1 -0
- package/dist/app/commands/command-model-actions.js +57 -35
- package/dist/app/commands/command-navigation-actions.d.ts +1 -0
- package/dist/app/commands/command-navigation-actions.js +16 -3
- package/dist/app/commands/command-registry.d.ts +2 -0
- package/dist/app/commands/command-registry.js +15 -1
- package/dist/app/commands/command-session-actions.js +9 -3
- package/dist/app/commands/reload-context-inventory.d.ts +11 -0
- package/dist/app/commands/reload-context-inventory.js +70 -0
- package/dist/app/extensions/extension-actions-controller.d.ts +1 -0
- package/dist/app/extensions/extension-actions-controller.js +6 -0
- package/dist/app/extensions/subagent-catalog-state.d.ts +9 -0
- package/dist/app/extensions/subagent-catalog-state.js +23 -0
- package/dist/app/input/autocomplete-controller.js +61 -34
- package/dist/app/input/input-action-controller.d.ts +2 -0
- package/dist/app/input/input-action-controller.js +8 -1
- package/dist/app/input/input-controller.d.ts +2 -1
- package/dist/app/input/input-controller.js +7 -2
- package/dist/app/input/prompt-enhancer-controller.js +53 -35
- package/dist/app/input/voice-controller.d.ts +41 -45
- package/dist/app/input/voice-controller.js +351 -419
- package/dist/app/model/model-usage-controller.js +17 -7
- package/dist/app/model/model-usage-status.d.ts +4 -1
- package/dist/app/model/model-usage-status.js +270 -46
- package/dist/app/popup/menu-items-controller.d.ts +13 -3
- package/dist/app/popup/menu-items-controller.js +37 -21
- package/dist/app/popup/popup-action-controller.d.ts +12 -2
- package/dist/app/popup/popup-action-controller.js +77 -24
- package/dist/app/popup/popup-menu-controller.d.ts +36 -14
- package/dist/app/popup/popup-menu-controller.js +239 -69
- package/dist/app/rendering/dcp-stats.d.ts +9 -4
- package/dist/app/rendering/dcp-stats.js +40 -425
- package/dist/app/rendering/editor-panels.js +10 -4
- package/dist/app/rendering/popup-menu-renderer.d.ts +3 -5
- package/dist/app/rendering/popup-menu-renderer.js +42 -37
- package/dist/app/rendering/render-controller.js +23 -2
- package/dist/app/rendering/status-line-renderer.d.ts +5 -0
- package/dist/app/rendering/status-line-renderer.js +41 -5
- package/dist/app/rendering/tab-line-renderer.js +26 -20
- package/dist/app/runtime.d.ts +12 -1
- package/dist/app/runtime.js +120 -12
- package/dist/app/screen/mouse-controller.d.ts +2 -0
- package/dist/app/screen/mouse-controller.js +17 -7
- package/dist/app/screen/status-controller.d.ts +4 -0
- package/dist/app/screen/status-controller.js +5 -0
- package/dist/app/session/lazy-session-manager.js +34 -0
- package/dist/app/session/session-event-controller.d.ts +1 -0
- package/dist/app/session/session-event-controller.js +10 -1
- package/dist/app/session/session-history.d.ts +1 -0
- package/dist/app/session/session-history.js +12 -1
- package/dist/app/session/session-lifecycle-controller.d.ts +7 -1
- package/dist/app/session/session-lifecycle-controller.js +16 -1
- package/dist/app/session/tabs-controller.d.ts +26 -1
- package/dist/app/session/tabs-controller.js +454 -147
- package/dist/app/subagents/subagents-files.js +60 -1
- package/dist/app/subagents/subagents-model.d.ts +1 -0
- package/dist/app/subagents/subagents-model.js +18 -2
- package/dist/app/subagents/subagents-widget-controller.d.ts +1 -0
- package/dist/app/subagents/subagents-widget-controller.js +6 -0
- package/dist/app/types.d.ts +16 -1
- package/dist/app/workspace/workspace-actions-controller.js +10 -2
- package/dist/app/workspace/workspace-undo.d.ts +1 -0
- package/dist/app/workspace/workspace-undo.js +1 -0
- package/dist/bundled-extensions/question/index.js +9 -1
- package/dist/bundled-extensions/question/remote.d.ts +4 -0
- package/dist/bundled-extensions/question/remote.js +33 -0
- package/dist/bundled-extensions/telegram-connector/bot.d.ts +43 -0
- package/dist/bundled-extensions/telegram-connector/bot.js +166 -0
- package/dist/bundled-extensions/telegram-connector/config.d.ts +8 -0
- package/dist/bundled-extensions/telegram-connector/config.js +87 -0
- package/dist/bundled-extensions/telegram-connector/coordinator.d.ts +66 -0
- package/dist/bundled-extensions/telegram-connector/coordinator.js +413 -0
- package/dist/bundled-extensions/telegram-connector/index.d.ts +3 -0
- package/dist/bundled-extensions/telegram-connector/index.js +195 -0
- package/dist/bundled-extensions/terminal-bell/index.d.ts +0 -8
- package/dist/bundled-extensions/terminal-bell/index.js +0 -76
- package/dist/bundled-extensions/workspace-undo/index.d.ts +26 -0
- package/dist/bundled-extensions/workspace-undo/index.js +191 -0
- package/dist/config.d.ts +21 -2
- package/dist/config.js +159 -32
- package/dist/default-pix-config.js +25 -5
- package/dist/schemas/index.d.ts +1 -0
- package/dist/schemas/index.js +1 -0
- package/dist/schemas/pi-tools-suite-schema.d.ts +88 -62
- package/dist/schemas/pi-tools-suite-schema.js +54 -83
- package/dist/schemas/pix-schema.d.ts +19 -2
- package/dist/schemas/pix-schema.js +47 -5
- package/dist/schemas/tasks-schema.d.ts +18 -0
- package/dist/schemas/tasks-schema.js +41 -0
- package/docs/concurrency.md +9 -1
- package/docs/desktop-mvp.md +22 -6
- package/docs/desktop-task-manager.md +148 -84
- package/docs/release.md +30 -6
- package/external/pi-tools-suite/README.md +197 -84
- package/external/pi-tools-suite/docs/evals.md +1 -1
- package/external/pi-tools-suite/docs/session-recovery.md +47 -14
- package/external/pi-tools-suite/docs/subagent-model-pools.md +48 -30
- package/external/pi-tools-suite/docs/ui-qa-subagent.md +440 -0
- package/external/pi-tools-suite/package.json +6 -1
- package/external/pi-tools-suite/src/antigravity-auth/auth-store.ts +2 -1
- package/external/pi-tools-suite/src/antigravity-auth/constants.ts +9 -3
- package/external/pi-tools-suite/src/antigravity-auth/headers.ts +41 -3
- package/external/pi-tools-suite/src/antigravity-auth/models.ts +94 -21
- package/external/pi-tools-suite/src/antigravity-auth/oauth.ts +5 -17
- package/external/pi-tools-suite/src/antigravity-auth/payload.ts +72 -7
- package/external/pi-tools-suite/src/antigravity-auth/stream.ts +13 -1
- package/external/pi-tools-suite/src/async-subagents/agents/frontier-review.md +23 -0
- package/external/pi-tools-suite/src/async-subagents/agents/implement.md +1 -1
- package/external/pi-tools-suite/src/async-subagents/agents/presets.jsonc +16 -0
- package/external/pi-tools-suite/src/async-subagents/agents/research.md +5 -3
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/browser.mjs +346 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/desktop.mjs +1038 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/tui.mjs +759 -0
- package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/scripts/browser-qa-runner.mjs +32 -23
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/chrome-devtools/chrome-devtools-provider.mjs +895 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/linux/linux-atspi.py +494 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/macos/macos-accessibility.swift +1085 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/native-terminal/bridge-client.mjs +50 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/native-terminal/native-terminal-host.mjs +501 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/windows/windows-uia.ps1 +454 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-auth.md +114 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-chrome-devtools.md +91 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-playwright.md +145 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser.md +82 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-linux.md +26 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-macos.md +29 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-windows.md +23 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop.md +54 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui-native-terminal.md +59 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui-pty.md +37 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui.md +60 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/scripts/ui-qa-runner.mjs +535 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa.md +75 -0
- package/external/pi-tools-suite/src/async-subagents/commands.ts +15 -71
- package/external/pi-tools-suite/src/async-subagents/core/activity.ts +33 -0
- package/external/pi-tools-suite/src/async-subagents/core/agent-catalog.ts +5 -4
- package/external/pi-tools-suite/src/async-subagents/core/agent-strategy.ts +1 -1
- package/external/pi-tools-suite/src/async-subagents/core/agents-dir.ts +8 -5
- package/external/pi-tools-suite/src/async-subagents/core/browser-qa.ts +16 -2
- package/external/pi-tools-suite/src/async-subagents/core/config.ts +160 -327
- package/external/pi-tools-suite/src/async-subagents/core/model-selection.ts +2 -1
- package/external/pi-tools-suite/src/async-subagents/core/registry.ts +158 -33
- package/external/pi-tools-suite/src/async-subagents/core/routing.ts +21 -5
- package/external/pi-tools-suite/src/async-subagents/core/spawn.ts +40 -26
- package/external/pi-tools-suite/src/async-subagents/core/state.ts +40 -0
- package/external/pi-tools-suite/src/async-subagents/core/types.ts +7 -0
- package/external/pi-tools-suite/src/async-subagents/core/ultrawork-auto.ts +51 -45
- package/external/pi-tools-suite/src/async-subagents/index.ts +69 -5
- package/external/pi-tools-suite/src/async-subagents/lib.ts +16 -9
- package/external/pi-tools-suite/src/async-subagents/tools/spawn.ts +8 -5
- package/external/pi-tools-suite/src/async-subagents/tools/subagents.ts +5 -4
- package/external/pi-tools-suite/src/async-subagents/types.ts +1 -0
- package/external/pi-tools-suite/src/coding-discipline/index.ts +90 -59
- package/external/pi-tools-suite/src/config.ts +55 -1
- package/external/pi-tools-suite/src/context-gateway/accounting-log.ts +282 -0
- package/external/pi-tools-suite/src/context-gateway/config.ts +77 -3
- package/external/pi-tools-suite/src/context-gateway/efficiency.ts +414 -0
- package/external/pi-tools-suite/src/context-gateway/enforcement.ts +222 -0
- package/external/pi-tools-suite/src/context-gateway/index.ts +206 -19
- package/external/pi-tools-suite/src/context-gateway/storeless-capabilities.ts +7 -7
- package/external/pi-tools-suite/src/context-gateway/telemetry.ts +101 -28
- package/external/pi-tools-suite/src/context-gateway/types.ts +16 -3
- package/external/pi-tools-suite/src/context-inventory.ts +99 -0
- package/external/pi-tools-suite/src/dcp/auto-compress-budget.ts +39 -4
- package/external/pi-tools-suite/src/dcp/auto-compress.ts +128 -49
- package/external/pi-tools-suite/src/dcp/commands.ts +32 -156
- package/external/pi-tools-suite/src/dcp/compress-tool.ts +177 -46
- package/external/pi-tools-suite/src/dcp/compression-blocks.ts +6 -58
- package/external/pi-tools-suite/src/dcp/compression-preview.ts +9 -0
- package/external/pi-tools-suite/src/dcp/compression-progress.ts +22 -0
- package/external/pi-tools-suite/src/dcp/config.ts +114 -17
- package/external/pi-tools-suite/src/dcp/conversation-index.ts +36 -9
- package/external/pi-tools-suite/src/dcp/diagnostics.ts +41 -0
- package/external/pi-tools-suite/src/dcp/fresh-tool-results.ts +38 -0
- package/external/pi-tools-suite/src/dcp/index.ts +338 -66
- package/external/pi-tools-suite/src/dcp/journal.ts +126 -4
- package/external/pi-tools-suite/src/dcp/progress-controller.ts +2 -1
- package/external/pi-tools-suite/src/dcp/prompts.ts +83 -192
- package/external/pi-tools-suite/src/dcp/protected-continuity.ts +175 -0
- package/external/pi-tools-suite/src/dcp/pruner-candidates.ts +93 -3
- package/external/pi-tools-suite/src/dcp/pruner-message-ids.ts +6 -10
- package/external/pi-tools-suite/src/dcp/pruner-nudge.ts +36 -33
- package/external/pi-tools-suite/src/dcp/pruner-tools.ts +6 -3
- package/external/pi-tools-suite/src/dcp/pruner.ts +1 -0
- package/external/pi-tools-suite/src/dcp/routine-pressure.ts +86 -0
- package/external/pi-tools-suite/src/dcp/state.ts +9 -0
- package/external/pi-tools-suite/src/dcp/statistics.d.ts +8 -0
- package/external/pi-tools-suite/src/dcp/statistics.js +156 -0
- package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +78 -22
- package/external/pi-tools-suite/src/index.ts +7 -1
- package/external/pi-tools-suite/src/lib/project.ts +36 -1
- package/external/pi-tools-suite/src/model-tools/index.ts +10 -7
- package/external/pi-tools-suite/src/repo-discovery/index.ts +304 -4
- package/external/pi-tools-suite/src/resource-registry/index.ts +2551 -0
- package/external/pi-tools-suite/src/session-recovery/index.ts +17 -0
- package/external/pi-tools-suite/src/shell-command-policy.ts +219 -0
- package/external/pi-tools-suite/src/todo/index.ts +21 -0
- package/external/pi-tools-suite/src/todo/todo.ts +19 -1
- package/external/pi-tools-suite/src/tool-descriptions.ts +47 -19
- package/package.json +10 -9
- package/schemas/pi-tools-suite.json +466 -287
- package/schemas/pix.json +129 -11
- package/schemas/tasks.json +131 -0
- package/skills/simplify/SKILL.md +33 -5
- package/docs/desktop-markdown-media.md +0 -77
- package/external/pi-tools-suite/docs/browser-qa-subagent.md +0 -177
- package/external/pi-tools-suite/docs/dcp-emergency-current-turn.md +0 -102
- package/external/pi-tools-suite/src/async-subagents/agents/browser-qa.md +0 -598
- package/external/pi-tools-suite/src/async-subagents/async-subagents.sample.jsonc +0 -54
- package/external/pi-tools-suite/src/skill-installer/index.ts +0 -333
- package/skills/playwright-cli/SKILL.md +0 -420
- package/skills/playwright-cli/references/element-attributes.md +0 -23
- package/skills/playwright-cli/references/playwright-tests.md +0 -50
- package/skills/playwright-cli/references/request-mocking.md +0 -87
- package/skills/playwright-cli/references/running-code.md +0 -241
- package/skills/playwright-cli/references/session-management.md +0 -273
- package/skills/playwright-cli/references/spec-driven-testing.md +0 -311
- package/skills/playwright-cli/references/storage-state.md +0 -290
- package/skills/playwright-cli/references/test-generation.md +0 -142
- package/skills/playwright-cli/references/tracing.md +0 -154
- package/skills/playwright-cli/references/video-recording.md +0 -147
- package/skills/spec-lite/SKILL.md +0 -140
- /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/examples/qa-auth.example.jsonc +0 -0
- /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/examples/qa-flow.example.jsonc +0 -0
- /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/vendor/fflate.LICENSE +0 -0
- /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/vendor/fflate.mjs +0 -0
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { MODEL_USAGE_POLL_INTERVAL_MS, MODEL_USAGE_STATUS_TICK_MS } from "../constants.js";
|
|
2
2
|
import { formatModelUsageStatusLabel, modelUsageDescriptor, queryModelUsageStatus, } from "./model-usage-status.js";
|
|
3
|
+
function descriptorCacheKey(descriptor) {
|
|
4
|
+
if (!descriptor)
|
|
5
|
+
return undefined;
|
|
6
|
+
if (descriptor.kind !== "google-antigravity")
|
|
7
|
+
return descriptor.modelKey;
|
|
8
|
+
return `${descriptor.modelKey}\0${(descriptor.quotaModelCandidates ?? [descriptor.quotaModelKey]).join("|")}`;
|
|
9
|
+
}
|
|
3
10
|
export class AppModelUsageController {
|
|
4
11
|
host;
|
|
5
12
|
queryUsageStatus;
|
|
@@ -38,18 +45,20 @@ export class AppModelUsageController {
|
|
|
38
45
|
refreshNow() {
|
|
39
46
|
const session = this.host.runtimeSession();
|
|
40
47
|
this.syncActiveModel(session);
|
|
41
|
-
const descriptor = modelUsageDescriptor(session?.model);
|
|
48
|
+
const descriptor = modelUsageDescriptor(session?.model, session?.thinkingLevel);
|
|
42
49
|
if (!descriptor)
|
|
43
50
|
return { kind: "unsupported" };
|
|
44
51
|
const promise = this.refresh(true, descriptor);
|
|
45
52
|
return promise ? { kind: "started", promise } : { kind: "in-flight" };
|
|
46
53
|
}
|
|
47
54
|
tick(force = false) {
|
|
48
|
-
this.
|
|
49
|
-
|
|
55
|
+
const session = this.host.runtimeSession();
|
|
56
|
+
this.syncActiveModel(session);
|
|
57
|
+
const descriptor = modelUsageDescriptor(session?.model, session?.thinkingLevel);
|
|
50
58
|
if (!descriptor)
|
|
51
59
|
return;
|
|
52
|
-
const
|
|
60
|
+
const cacheKey = descriptorCacheKey(descriptor);
|
|
61
|
+
const lastAttemptAt = this.lastAttemptAt.get(cacheKey) ?? 0;
|
|
53
62
|
if (force || Date.now() - lastAttemptAt >= MODEL_USAGE_POLL_INTERVAL_MS) {
|
|
54
63
|
this.refresh(force, descriptor);
|
|
55
64
|
return;
|
|
@@ -58,10 +67,11 @@ export class AppModelUsageController {
|
|
|
58
67
|
this.host.render();
|
|
59
68
|
}
|
|
60
69
|
refresh(force = false, activeDescriptor) {
|
|
61
|
-
const
|
|
70
|
+
const session = this.host.runtimeSession();
|
|
71
|
+
const descriptor = activeDescriptor ?? modelUsageDescriptor(session?.model, session?.thinkingLevel);
|
|
62
72
|
if (!descriptor)
|
|
63
73
|
return undefined;
|
|
64
|
-
const modelKey = descriptor
|
|
74
|
+
const modelKey = descriptorCacheKey(descriptor);
|
|
65
75
|
if (this.inFlightModelKeys.has(modelKey))
|
|
66
76
|
return undefined;
|
|
67
77
|
const lastAttemptAt = this.lastAttemptAt.get(modelKey) ?? 0;
|
|
@@ -86,7 +96,7 @@ export class AppModelUsageController {
|
|
|
86
96
|
});
|
|
87
97
|
}
|
|
88
98
|
syncActiveModel(session) {
|
|
89
|
-
const nextModelKey = modelUsageDescriptor(session?.model)
|
|
99
|
+
const nextModelKey = descriptorCacheKey(modelUsageDescriptor(session?.model, session?.thinkingLevel));
|
|
90
100
|
if (nextModelKey === this.activeModelKey)
|
|
91
101
|
return false;
|
|
92
102
|
this.activeModelKey = nextModelKey;
|
|
@@ -7,6 +7,7 @@ export type ModelUsageDescriptor = BaseModelUsageDescriptor & ({
|
|
|
7
7
|
} | {
|
|
8
8
|
readonly kind: "google-antigravity";
|
|
9
9
|
readonly quotaModelKey: string;
|
|
10
|
+
readonly quotaModelCandidates?: readonly string[];
|
|
10
11
|
readonly account?: AntigravityQuotaAccount;
|
|
11
12
|
readonly accounts?: readonly AntigravityQuotaAccount[];
|
|
12
13
|
});
|
|
@@ -96,6 +97,7 @@ type AntigravityQuotaAccount = {
|
|
|
96
97
|
readonly cachedQuota?: AntigravityCachedQuota;
|
|
97
98
|
readonly cachedQuotaUpdatedAt?: number;
|
|
98
99
|
readonly projectId: string;
|
|
100
|
+
readonly managedProjectId?: string;
|
|
99
101
|
readonly accountIndex?: number;
|
|
100
102
|
readonly accountCount?: number;
|
|
101
103
|
readonly cacheKey: string;
|
|
@@ -107,8 +109,9 @@ type GoogleQuotaResponse = {
|
|
|
107
109
|
resetTime?: string;
|
|
108
110
|
};
|
|
109
111
|
}>;
|
|
112
|
+
readonly source?: "cached";
|
|
110
113
|
};
|
|
111
|
-
export declare function modelUsageDescriptor(model: SessionModel | undefined): ModelUsageDescriptor | undefined;
|
|
114
|
+
export declare function modelUsageDescriptor(model: SessionModel | undefined, thinkingLevel?: string): ModelUsageDescriptor | undefined;
|
|
112
115
|
export declare function queryModelUsageStatus(descriptor: ModelUsageDescriptor): Promise<ModelUsageStatus | undefined>;
|
|
113
116
|
export declare function queryAccountUsageReport(now?: number): Promise<AccountUsageReport>;
|
|
114
117
|
export declare function formatAccountUsageReport(report: AccountUsageReport, now?: number): string;
|
|
@@ -2,31 +2,46 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
5
|
-
import { ModelRuntime, readStoredCredential } from "@earendil-works/pi-coding-agent";
|
|
5
|
+
import { getAgentDir, ModelRuntime, readStoredCredential } from "@earendil-works/pi-coding-agent";
|
|
6
6
|
import { formatCompactProgressBar } from "../../context-progress-bar.js";
|
|
7
7
|
import { APP_ICONS } from "../icons.js";
|
|
8
8
|
const OPENAI_USAGE_URL = "https://chatgpt.com/backend-api/wham/usage";
|
|
9
9
|
const ZAI_QUOTA_URL = "https://api.z.ai/api/monitor/usage/quota/limit";
|
|
10
10
|
const ZHIPU_QUOTA_URL = "https://bigmodel.cn/api/monitor/usage/quota/limit";
|
|
11
|
-
const
|
|
11
|
+
const GOOGLE_ANTIGRAVITY_ENDPOINT_DAILY = "https://daily-cloudcode-pa.googleapis.com";
|
|
12
|
+
const GOOGLE_ANTIGRAVITY_ENDPOINT_PROD = "https://cloudcode-pa.googleapis.com";
|
|
13
|
+
const GOOGLE_ANTIGRAVITY_ENDPOINTS = [GOOGLE_ANTIGRAVITY_ENDPOINT_DAILY, GOOGLE_ANTIGRAVITY_ENDPOINT_PROD];
|
|
12
14
|
const GOOGLE_TOKEN_REFRESH_URL = "https://oauth2.googleapis.com/token";
|
|
13
|
-
const
|
|
15
|
+
const GOOGLE_ANTIGRAVITY_CLI_VERSION = "1.1.24";
|
|
16
|
+
const GOOGLE_ANTIGRAVITY_CLI_CHANGE_LIST = "974782877";
|
|
14
17
|
const REQUEST_TIMEOUT_MS = 10_000;
|
|
15
18
|
const DAY_SECONDS = 86_400;
|
|
16
19
|
const HOUR_SECONDS = 3_600;
|
|
17
20
|
const MODEL_USAGE_WARNING_MIN_USED_PERCENT = 5;
|
|
18
21
|
const MODEL_USAGE_WARNING_MIN_ELAPSED_SECONDS = 6 * HOUR_SECONDS;
|
|
19
|
-
const PI_AUTH_PATH = join(homedir(), ".pi", "agent", "auth.json");
|
|
20
22
|
const DEFAULT_ANTIGRAVITY_PROJECT_ID = "rising-fact-p41fc";
|
|
23
|
+
function normalizeGoogleAntigravityPlatform(platform = process.platform) {
|
|
24
|
+
return platform === "win32" ? "windows" : platform || "unknown";
|
|
25
|
+
}
|
|
26
|
+
function normalizeGoogleAntigravityArch(arch = process.arch) {
|
|
27
|
+
if (arch === "x64")
|
|
28
|
+
return "amd64";
|
|
29
|
+
if (arch === "ia32")
|
|
30
|
+
return "386";
|
|
31
|
+
return arch || "unknown";
|
|
32
|
+
}
|
|
33
|
+
function buildGoogleAntigravityUserAgent() {
|
|
34
|
+
return `antigravity/cli/${GOOGLE_ANTIGRAVITY_CLI_VERSION} (aidev_client; os_type=${normalizeGoogleAntigravityPlatform()}; arch=${normalizeGoogleAntigravityArch()}; cl=${GOOGLE_ANTIGRAVITY_CLI_CHANGE_LIST}; auth_method=consumer)`;
|
|
35
|
+
}
|
|
21
36
|
function getPiAuthPath() {
|
|
22
37
|
return process.env.NODE_ENV === "test" && process.env.PI_TOOLS_SUITE_TEST_AUTH_PATH
|
|
23
38
|
? process.env.PI_TOOLS_SUITE_TEST_AUTH_PATH
|
|
24
|
-
:
|
|
39
|
+
: join(getAgentDir(), "auth.json");
|
|
25
40
|
}
|
|
26
41
|
const OPENAI_QUOTA_PROVIDERS = new Set(["openai", "openai-codex"]);
|
|
27
42
|
const ZHIPU_QUOTA_PROVIDERS = new Set(["zai", "zhipuai-coding-plan"]);
|
|
28
43
|
const ANTIGRAVITY_QUOTA_PROVIDERS = new Set(["antigravity", "google-antigravity"]);
|
|
29
|
-
export function modelUsageDescriptor(model) {
|
|
44
|
+
export function modelUsageDescriptor(model, thinkingLevel) {
|
|
30
45
|
if (!model)
|
|
31
46
|
return undefined;
|
|
32
47
|
const provider = model.provider.toLowerCase();
|
|
@@ -40,10 +55,12 @@ export function modelUsageDescriptor(model) {
|
|
|
40
55
|
const quotaModelKey = resolveAntigravityQuotaModelKey(model);
|
|
41
56
|
if (!quotaModelKey)
|
|
42
57
|
return undefined;
|
|
58
|
+
const quotaModelCandidates = antigravityQuotaModelCandidates(quotaModelKey, thinkingLevel);
|
|
43
59
|
return {
|
|
44
60
|
kind: "google-antigravity",
|
|
45
61
|
modelKey: `${model.provider}/${model.id}`,
|
|
46
62
|
quotaModelKey,
|
|
63
|
+
...(quotaModelCandidates.length > 1 ? { quotaModelCandidates } : {}),
|
|
47
64
|
};
|
|
48
65
|
}
|
|
49
66
|
return undefined;
|
|
@@ -395,8 +412,14 @@ export function resolveAntigravityQuotaModelKey(model) {
|
|
|
395
412
|
if (normalized.includes("claude") && normalized.includes("opus") && normalized.includes("thinking")) {
|
|
396
413
|
return "claude-opus-4-6-thinking";
|
|
397
414
|
}
|
|
415
|
+
// Sonnet thinking rides the base claude-sonnet-4-6 quota bucket.
|
|
398
416
|
if (normalized.includes("claude") && normalized.includes("sonnet"))
|
|
399
417
|
return "claude-sonnet-4-6";
|
|
418
|
+
// Versioned flash generations get their own buckets; keep them ahead of the
|
|
419
|
+
// legacy gemini-3-flash alias so 3.5-3.8 don't collapse into it.
|
|
420
|
+
const versionedFlash = normalized.match(/gemini-3\.([5-8])-flash/u) ?? normalized.match(/\bg3\.([5-8])-flash\b/u);
|
|
421
|
+
if (versionedFlash)
|
|
422
|
+
return `gemini-3.${versionedFlash[1]}-flash`;
|
|
400
423
|
if (normalized.includes("gemini-2.5-flash") || /\bg2[.-]?5-flash\b/u.test(normalized))
|
|
401
424
|
return "gemini-2.5-flash";
|
|
402
425
|
if (normalized.includes("gemini-3-flash") || /\bg3-flash\b/u.test(normalized))
|
|
@@ -407,10 +430,37 @@ export function resolveAntigravityQuotaModelKey(model) {
|
|
|
407
430
|
return "gemini-3.1-pro-low";
|
|
408
431
|
if (/\bg3(?:-pro)?\b/u.test(normalized))
|
|
409
432
|
return "gemini-3.1-pro-low";
|
|
433
|
+
// GPT-OSS has no Google-side quota bucket; callers treat undefined as "no
|
|
434
|
+
// quota status for this model".
|
|
410
435
|
return undefined;
|
|
411
436
|
}
|
|
437
|
+
function antigravityQuotaModelCandidates(quotaModelKey, thinkingLevel) {
|
|
438
|
+
const candidates = [quotaModelKey];
|
|
439
|
+
const level = thinkingLevel?.toLowerCase();
|
|
440
|
+
const tier = level === "high" || level === "xhigh" || level === "max"
|
|
441
|
+
? "high"
|
|
442
|
+
: level === undefined || level === "medium"
|
|
443
|
+
? "medium"
|
|
444
|
+
: "low";
|
|
445
|
+
const versionedFlash = quotaModelKey.match(/^gemini-3\.([5-8])-flash$/u);
|
|
446
|
+
if (versionedFlash) {
|
|
447
|
+
if (versionedFlash[1] === "5") {
|
|
448
|
+
candidates.push(tier === "high"
|
|
449
|
+
? "gemini-3-flash-agent"
|
|
450
|
+
: tier === "medium"
|
|
451
|
+
? "gemini-3.5-flash-low"
|
|
452
|
+
: "gemini-3.5-flash-extra-low");
|
|
453
|
+
}
|
|
454
|
+
else {
|
|
455
|
+
candidates.push(`${quotaModelKey}-${tier}`);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
if (quotaModelKey === "gemini-3.1-pro-low" && tier === "high")
|
|
459
|
+
candidates.push("gemini-pro-agent");
|
|
460
|
+
return candidates;
|
|
461
|
+
}
|
|
412
462
|
export function googleAntigravityUsageStatusFromResponse(data, descriptor, now = Date.now()) {
|
|
413
|
-
const window = googleAntigravityWindowFromResponse(data, descriptor.quotaModelKey, now);
|
|
463
|
+
const window = googleAntigravityWindowFromResponse(data, descriptor.quotaModelKey, now, descriptor.quotaModelCandidates);
|
|
414
464
|
if (!window)
|
|
415
465
|
return undefined;
|
|
416
466
|
const weekly = window.windowSeconds >= DAY_SECONDS ? window : undefined;
|
|
@@ -424,8 +474,13 @@ export function googleAntigravityUsageStatusFromResponse(data, descriptor, now =
|
|
|
424
474
|
...(hourly ? { hourly } : {}),
|
|
425
475
|
};
|
|
426
476
|
}
|
|
427
|
-
function googleAntigravityWindowFromResponse(data, quotaModelKey, now) {
|
|
428
|
-
const quotaInfo =
|
|
477
|
+
function googleAntigravityWindowFromResponse(data, quotaModelKey, now, quotaModelCandidates = [quotaModelKey]) {
|
|
478
|
+
const quotaInfo = quotaModelCandidates
|
|
479
|
+
.map((candidate) => data.models[candidate]?.quotaInfo)
|
|
480
|
+
.find((candidate) => candidate !== undefined)
|
|
481
|
+
?? (data.source === "cached" && /^gemini-3\.[5-8]-flash$/u.test(quotaModelKey)
|
|
482
|
+
? data.models["gemini-3-flash"]?.quotaInfo
|
|
483
|
+
: undefined);
|
|
429
484
|
if (!quotaInfo)
|
|
430
485
|
return undefined;
|
|
431
486
|
const resetAt = parseResetTime(quotaInfo.resetTime, now);
|
|
@@ -435,31 +490,112 @@ function googleAntigravityWindowFromResponse(data, quotaModelKey, now) {
|
|
|
435
490
|
windowSeconds: Math.max(0, Math.round((resetAt - now) / 1000)),
|
|
436
491
|
};
|
|
437
492
|
}
|
|
493
|
+
function googleAntigravityQuotaPoolForModel(quotaModelKey) {
|
|
494
|
+
return quotaModelKey.toLowerCase().includes("claude") ? "non-gemini" : "gemini";
|
|
495
|
+
}
|
|
496
|
+
function googleAntigravityQuotaPoolForBucket(bucketId) {
|
|
497
|
+
if (!bucketId)
|
|
498
|
+
return undefined;
|
|
499
|
+
if (bucketId.startsWith("gemini-"))
|
|
500
|
+
return "gemini";
|
|
501
|
+
if (bucketId.startsWith("3p-"))
|
|
502
|
+
return "non-gemini";
|
|
503
|
+
return undefined;
|
|
504
|
+
}
|
|
505
|
+
function googleAntigravityWindowFromSummaryBucket(bucket, now, windowSeconds) {
|
|
506
|
+
const remainingFraction = Number.isFinite(bucket.remainingFraction) ? bucket.remainingFraction : 0;
|
|
507
|
+
return {
|
|
508
|
+
remainingPercent: clampPercent(Math.round(remainingFraction * 100)),
|
|
509
|
+
resetAt: parseResetTime(bucket.resetTime, now),
|
|
510
|
+
windowSeconds,
|
|
511
|
+
hasKnownWindowDuration: true,
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
function mostConstrainedGoogleQuotaBucket(buckets) {
|
|
515
|
+
return buckets.reduce((best, bucket) => {
|
|
516
|
+
if (!best)
|
|
517
|
+
return bucket;
|
|
518
|
+
const bestRemaining = Number.isFinite(best.remainingFraction) ? best.remainingFraction : 0;
|
|
519
|
+
const nextRemaining = Number.isFinite(bucket.remainingFraction) ? bucket.remainingFraction : 0;
|
|
520
|
+
return nextRemaining < bestRemaining ? bucket : best;
|
|
521
|
+
}, undefined);
|
|
522
|
+
}
|
|
523
|
+
function googleAntigravityWindowsFromQuotaSummary(data, pool, now) {
|
|
524
|
+
const buckets = (data.groups ?? [])
|
|
525
|
+
.flatMap((group) => group.buckets ?? [])
|
|
526
|
+
.filter((bucket) => googleAntigravityQuotaPoolForBucket(bucket.bucketId) === pool);
|
|
527
|
+
const hourlyBucket = mostConstrainedGoogleQuotaBucket(buckets.filter((bucket) => bucket.window === "5h"));
|
|
528
|
+
const weeklyBucket = mostConstrainedGoogleQuotaBucket(buckets.filter((bucket) => bucket.window === "weekly"));
|
|
529
|
+
return {
|
|
530
|
+
...(hourlyBucket ? { hourly: googleAntigravityWindowFromSummaryBucket(hourlyBucket, now, 5 * HOUR_SECONDS) } : {}),
|
|
531
|
+
...(weeklyBucket ? { weekly: googleAntigravityWindowFromSummaryBucket(weeklyBucket, now, 7 * DAY_SECONDS) } : {}),
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
function aggregateGoogleAntigravityWindows(windows) {
|
|
535
|
+
if (windows.length === 0)
|
|
536
|
+
return undefined;
|
|
537
|
+
const hasKnownWindowDuration = windows.every((window) => window.hasKnownWindowDuration === true);
|
|
538
|
+
return {
|
|
539
|
+
remainingPercent: clampPercent(Math.round(windows.reduce((sum, window) => sum + window.remainingPercent, 0) / windows.length)),
|
|
540
|
+
resetAt: Math.min(...windows.map((window) => window.resetAt)),
|
|
541
|
+
windowSeconds: hasKnownWindowDuration
|
|
542
|
+
? windows[0]?.windowSeconds ?? 0
|
|
543
|
+
: Math.min(...windows.map((window) => window.windowSeconds)),
|
|
544
|
+
...(hasKnownWindowDuration ? { hasKnownWindowDuration: true } : {}),
|
|
545
|
+
};
|
|
546
|
+
}
|
|
438
547
|
async function queryGoogleAntigravityModelUsage(descriptor) {
|
|
439
548
|
const now = Date.now();
|
|
440
|
-
const accounts = await readAllAntigravityQuotaAccounts();
|
|
549
|
+
const accounts = await readAllAntigravityQuotaAccounts(descriptor.modelKey);
|
|
441
550
|
if (accounts.length === 0)
|
|
442
551
|
return undefined;
|
|
443
|
-
const
|
|
552
|
+
const pool = googleAntigravityQuotaPoolForModel(descriptor.quotaModelKey);
|
|
553
|
+
const accountWindows = (await Promise.all(accounts.map(async (account) => {
|
|
554
|
+
try {
|
|
555
|
+
const summary = await fetchGoogleAntigravityQuotaSummaryForAccount(account);
|
|
556
|
+
const summaryWindows = googleAntigravityWindowsFromQuotaSummary(summary, pool, now);
|
|
557
|
+
if (summaryWindows.hourly || summaryWindows.weekly)
|
|
558
|
+
return summaryWindows;
|
|
559
|
+
}
|
|
560
|
+
catch {
|
|
561
|
+
// Current Antigravity exposes retrieveUserQuotaSummary, but older or
|
|
562
|
+
// partially rolled-out backends may not. Fall through to the legacy
|
|
563
|
+
// per-model quota response before consulting cached provider data.
|
|
564
|
+
}
|
|
444
565
|
try {
|
|
445
566
|
const response = await fetchGoogleAntigravityQuotaForAccount(account, now);
|
|
446
|
-
|
|
567
|
+
const liveWindow = googleAntigravityWindowFromResponse(response, descriptor.quotaModelKey, now, descriptor.quotaModelCandidates);
|
|
568
|
+
if (liveWindow)
|
|
569
|
+
return { legacy: liveWindow };
|
|
570
|
+
// Google may successfully return fetchAvailableModels while omitting
|
|
571
|
+
// the quotaInfo bucket for a current versioned Flash route. Antigravity
|
|
572
|
+
// stores the last provider-observed aggregate buckets on each account;
|
|
573
|
+
// use that cached shared Flash quota when live data has no matching key.
|
|
574
|
+
const cachedResponse = googleQuotaResponseFromCachedQuota(account.cachedQuota, account.cachedQuotaUpdatedAt, now);
|
|
575
|
+
const cachedWindow = cachedResponse
|
|
576
|
+
? googleAntigravityWindowFromResponse(cachedResponse, descriptor.quotaModelKey, now, descriptor.quotaModelCandidates)
|
|
577
|
+
: undefined;
|
|
578
|
+
if (!cachedWindow)
|
|
579
|
+
return undefined;
|
|
580
|
+
return { legacy: cachedWindow };
|
|
447
581
|
}
|
|
448
582
|
catch {
|
|
449
583
|
return undefined;
|
|
450
584
|
}
|
|
451
|
-
}))).filter((
|
|
452
|
-
if (
|
|
585
|
+
}))).filter((windows) => windows !== undefined);
|
|
586
|
+
if (accountWindows.length === 0)
|
|
587
|
+
return undefined;
|
|
588
|
+
let hourly = aggregateGoogleAntigravityWindows(accountWindows.map((windows) => windows.hourly).filter((window) => window !== undefined));
|
|
589
|
+
let weekly = aggregateGoogleAntigravityWindows(accountWindows.map((windows) => windows.weekly).filter((window) => window !== undefined));
|
|
590
|
+
const legacy = aggregateGoogleAntigravityWindows(accountWindows.map((windows) => windows.legacy).filter((window) => window !== undefined));
|
|
591
|
+
if (!hourly && !weekly && legacy) {
|
|
592
|
+
if (legacy.windowSeconds >= DAY_SECONDS)
|
|
593
|
+
weekly = legacy;
|
|
594
|
+
else
|
|
595
|
+
hourly = legacy;
|
|
596
|
+
}
|
|
597
|
+
if (!hourly && !weekly)
|
|
453
598
|
return undefined;
|
|
454
|
-
const resetAt = Math.min(...windows.map((window) => window.resetAt));
|
|
455
|
-
const windowSeconds = Math.max(0, Math.round((resetAt - now) / 1000));
|
|
456
|
-
const aggregateWindow = {
|
|
457
|
-
remainingPercent: clampPercent(Math.round(windows.reduce((sum, window) => sum + window.remainingPercent, 0) / windows.length)),
|
|
458
|
-
resetAt,
|
|
459
|
-
windowSeconds,
|
|
460
|
-
};
|
|
461
|
-
const weekly = aggregateWindow.windowSeconds >= DAY_SECONDS ? aggregateWindow : undefined;
|
|
462
|
-
const hourly = weekly ? undefined : aggregateWindow;
|
|
463
599
|
return {
|
|
464
600
|
modelKey: descriptor.modelKey,
|
|
465
601
|
provider: "google-antigravity",
|
|
@@ -474,6 +610,10 @@ const GOOGLE_ACCOUNT_QUOTA_WINDOWS = [
|
|
|
474
610
|
{ label: "Claude Sonnet", quotaModelKey: "claude-sonnet-4-6" },
|
|
475
611
|
{ label: "G2.5 Flash", quotaModelKey: "gemini-2.5-flash" },
|
|
476
612
|
{ label: "G3 Flash", quotaModelKey: "gemini-3-flash" },
|
|
613
|
+
{ label: "G3.5 Flash", quotaModelKey: "gemini-3.5-flash" },
|
|
614
|
+
{ label: "G3.6 Flash", quotaModelKey: "gemini-3.6-flash" },
|
|
615
|
+
{ label: "G3.7 Flash", quotaModelKey: "gemini-3.7-flash" },
|
|
616
|
+
{ label: "G3.8 Flash", quotaModelKey: "gemini-3.8-flash" },
|
|
477
617
|
{ label: "G3 Pro", quotaModelKey: "gemini-3.1-pro-low" },
|
|
478
618
|
];
|
|
479
619
|
async function queryGoogleAntigravityAccountUsage(now) {
|
|
@@ -500,8 +640,10 @@ async function queryGoogleAntigravityAccountUsage(now) {
|
|
|
500
640
|
}));
|
|
501
641
|
return results;
|
|
502
642
|
}
|
|
503
|
-
async function readAllAntigravityQuotaAccounts() {
|
|
504
|
-
const
|
|
643
|
+
async function readAllAntigravityQuotaAccounts(modelKey = "antigravity/") {
|
|
644
|
+
const auth = await readPiAuth();
|
|
645
|
+
const provider = modelKey.slice(0, modelKey.indexOf("/")).toLowerCase();
|
|
646
|
+
const credential = auth[provider] ?? auth.antigravity;
|
|
505
647
|
if (!credential)
|
|
506
648
|
return [];
|
|
507
649
|
const credentialClient = getGoogleOAuthClientCredentials(credential);
|
|
@@ -513,6 +655,7 @@ async function readAllAntigravityQuotaAccounts() {
|
|
|
513
655
|
...(credential.email ? { fallbackEmail: credential.email } : {}),
|
|
514
656
|
...(credentialClient ? { clientCredentials: credentialClient } : {}),
|
|
515
657
|
...(accountIndex === activeIndex && activeAccess ? { accessToken: activeAccess.accessToken } : {}),
|
|
658
|
+
...(accountIndex === activeIndex && activeAccess?.projectId ? { accessProjectId: activeAccess.projectId } : {}),
|
|
516
659
|
accountIndex,
|
|
517
660
|
accountCount: accounts.length,
|
|
518
661
|
})).filter((account) => account !== undefined);
|
|
@@ -523,6 +666,7 @@ async function readAllAntigravityQuotaAccounts() {
|
|
|
523
666
|
...(credential.email ? { fallbackEmail: credential.email } : {}),
|
|
524
667
|
...(credentialClient ? { clientCredentials: credentialClient } : {}),
|
|
525
668
|
...(fallbackAccess ? { accessToken: fallbackAccess.accessToken } : {}),
|
|
669
|
+
...(fallbackAccess?.projectId ? { accessProjectId: fallbackAccess.projectId } : {}),
|
|
526
670
|
}) : undefined;
|
|
527
671
|
return account ? [account] : [];
|
|
528
672
|
}
|
|
@@ -556,7 +700,10 @@ function getGoogleOAuthClientCredentials(...sources) {
|
|
|
556
700
|
if (clientId)
|
|
557
701
|
return { clientId, ...(clientSecret ? { clientSecret } : {}) };
|
|
558
702
|
}
|
|
559
|
-
|
|
703
|
+
const clientId = process.env.PI_ANTIGRAVITY_GOOGLE_CLIENT_ID?.trim();
|
|
704
|
+
const clientSecret = process.env.PI_ANTIGRAVITY_GOOGLE_CLIENT_SECRET?.trim();
|
|
705
|
+
if (clientId)
|
|
706
|
+
return { clientId, ...(clientSecret ? { clientSecret } : {}) };
|
|
560
707
|
}
|
|
561
708
|
function storedAntigravityAccounts(credential) {
|
|
562
709
|
return Array.isArray(credential.accounts)
|
|
@@ -585,11 +732,12 @@ function antigravityQuotaAccount(account, options = {}) {
|
|
|
585
732
|
if (!refreshToken)
|
|
586
733
|
return undefined;
|
|
587
734
|
const email = account.email || options.fallbackEmail;
|
|
588
|
-
const projectId = account.projectId || account.managedProjectId || DEFAULT_ANTIGRAVITY_PROJECT_ID;
|
|
735
|
+
const projectId = options.accessProjectId || account.projectId || account.managedProjectId || DEFAULT_ANTIGRAVITY_PROJECT_ID;
|
|
589
736
|
const clientCredentials = getGoogleOAuthClientCredentials(account, options.clientCredentials);
|
|
590
737
|
return {
|
|
591
738
|
refreshToken,
|
|
592
739
|
projectId,
|
|
740
|
+
...(account.managedProjectId ? { managedProjectId: account.managedProjectId } : {}),
|
|
593
741
|
cacheKey: email ? email.toLowerCase() : shortHash(refreshToken),
|
|
594
742
|
...(options.accessToken ? { accessToken: options.accessToken } : {}),
|
|
595
743
|
...(clientCredentials ? { clientId: clientCredentials.clientId } : {}),
|
|
@@ -608,7 +756,7 @@ function googleQuotaResponseFromCachedQuota(cachedQuota, cachedQuotaUpdatedAt, n
|
|
|
608
756
|
addCachedQuotaModels(models, cachedQuota.claude, ["claude-opus-4-6-thinking", "claude-sonnet-4-6"], cachedQuotaUpdatedAt, now);
|
|
609
757
|
addCachedQuotaModels(models, cachedQuota["gemini-flash"], ["gemini-2.5-flash", "gemini-3-flash"], cachedQuotaUpdatedAt, now);
|
|
610
758
|
addCachedQuotaModels(models, cachedQuota["gemini-pro"], ["gemini-3.1-pro-low"], cachedQuotaUpdatedAt, now);
|
|
611
|
-
return Object.keys(models).length > 0 ? { models } : undefined;
|
|
759
|
+
return Object.keys(models).length > 0 ? { models, source: "cached" } : undefined;
|
|
612
760
|
}
|
|
613
761
|
function addCachedQuotaModels(models, quota, quotaModelKeys, cachedQuotaUpdatedAt, now) {
|
|
614
762
|
if (!quota)
|
|
@@ -669,15 +817,44 @@ function shortHash(value) {
|
|
|
669
817
|
return createHash("sha256").update(value).digest("hex").slice(0, 12);
|
|
670
818
|
}
|
|
671
819
|
async function fetchGoogleAntigravityQuotaForAccount(account, now = Date.now()) {
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
820
|
+
let liveError;
|
|
821
|
+
try {
|
|
822
|
+
return await fetchWithGoogleAntigravityAccountAccess(account, (accessToken) => fetchGoogleAntigravityQuota(accessToken, account.projectId));
|
|
823
|
+
}
|
|
824
|
+
catch (error) {
|
|
825
|
+
liveError = error;
|
|
677
826
|
}
|
|
678
827
|
const cachedResponse = googleQuotaResponseFromCachedQuota(account.cachedQuota, account.cachedQuotaUpdatedAt, now);
|
|
679
828
|
if (cachedResponse)
|
|
680
829
|
return cachedResponse;
|
|
830
|
+
if (liveError)
|
|
831
|
+
throw liveError;
|
|
832
|
+
throw new Error("Missing Google OAuth client credentials, cannot query live Antigravity quota.");
|
|
833
|
+
}
|
|
834
|
+
async function fetchGoogleAntigravityQuotaSummaryForAccount(account) {
|
|
835
|
+
return await fetchWithGoogleAntigravityAccountAccess(account, (accessToken) => fetchGoogleAntigravityQuotaSummary(accessToken, account));
|
|
836
|
+
}
|
|
837
|
+
async function fetchWithGoogleAntigravityAccountAccess(account, fetcher) {
|
|
838
|
+
let lastError;
|
|
839
|
+
if (account.accessToken) {
|
|
840
|
+
try {
|
|
841
|
+
return await fetcher(account.accessToken);
|
|
842
|
+
}
|
|
843
|
+
catch (error) {
|
|
844
|
+
lastError = error;
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
if (account.clientId) {
|
|
848
|
+
try {
|
|
849
|
+
const { accessToken } = await refreshGoogleAntigravityAccessToken(account);
|
|
850
|
+
return await fetcher(accessToken);
|
|
851
|
+
}
|
|
852
|
+
catch (error) {
|
|
853
|
+
lastError = error;
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
if (lastError)
|
|
857
|
+
throw lastError;
|
|
681
858
|
throw new Error("Missing Google OAuth client credentials, cannot query live Antigravity quota.");
|
|
682
859
|
}
|
|
683
860
|
async function refreshGoogleAntigravityAccessToken(account) {
|
|
@@ -704,21 +881,68 @@ async function refreshGoogleAntigravityAccessToken(account) {
|
|
|
704
881
|
throw new Error("Google token refresh did not return an access token.");
|
|
705
882
|
return { accessToken: data.access_token };
|
|
706
883
|
}
|
|
884
|
+
function googleAntigravityQuotaHeaders(accessToken) {
|
|
885
|
+
return {
|
|
886
|
+
"User-Agent": buildGoogleAntigravityUserAgent(),
|
|
887
|
+
Authorization: `Bearer ${accessToken}`,
|
|
888
|
+
"Content-Type": "application/json",
|
|
889
|
+
"Accept-Encoding": "gzip",
|
|
890
|
+
};
|
|
891
|
+
}
|
|
892
|
+
async function fetchGoogleAntigravityQuotaSummary(accessToken, account) {
|
|
893
|
+
const errors = [];
|
|
894
|
+
const primaryProjectId = account.managedProjectId || account.projectId;
|
|
895
|
+
let primaryGot403 = false;
|
|
896
|
+
const tryProject = async (projectId) => {
|
|
897
|
+
for (const endpoint of GOOGLE_ANTIGRAVITY_ENDPOINTS) {
|
|
898
|
+
const response = await fetchWithTimeout(`${endpoint}/v1internal:retrieveUserQuotaSummary`, {
|
|
899
|
+
method: "POST",
|
|
900
|
+
headers: googleAntigravityQuotaHeaders(accessToken),
|
|
901
|
+
body: JSON.stringify({ project: projectId }),
|
|
902
|
+
});
|
|
903
|
+
if (response.ok)
|
|
904
|
+
return response.json();
|
|
905
|
+
if (response.status === 403)
|
|
906
|
+
primaryGot403 = true;
|
|
907
|
+
const errorText = await response.text().catch(() => "");
|
|
908
|
+
errors.push(`retrieveUserQuotaSummary ${response.status} at ${endpoint}${errorText ? `: ${errorText.slice(0, 200)}` : ""}`);
|
|
909
|
+
}
|
|
910
|
+
return undefined;
|
|
911
|
+
};
|
|
912
|
+
const primary = await tryProject(primaryProjectId);
|
|
913
|
+
if (primary)
|
|
914
|
+
return primary;
|
|
915
|
+
if (primaryGot403 && account.managedProjectId && account.projectId !== account.managedProjectId) {
|
|
916
|
+
const fallback = await tryProject(account.projectId);
|
|
917
|
+
if (fallback)
|
|
918
|
+
return fallback;
|
|
919
|
+
}
|
|
920
|
+
throw new Error(errors.join("; ") || "Google Antigravity quota summary request failed");
|
|
921
|
+
}
|
|
707
922
|
async function fetchGoogleAntigravityQuota(accessToken, projectId) {
|
|
708
|
-
const
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
923
|
+
const errors = [];
|
|
924
|
+
for (const endpoint of GOOGLE_ANTIGRAVITY_ENDPOINTS) {
|
|
925
|
+
const url = `${endpoint}/v1internal:fetchAvailableModels`;
|
|
926
|
+
const response = await fetchWithTimeout(url, {
|
|
927
|
+
method: "POST",
|
|
928
|
+
headers: googleAntigravityQuotaHeaders(accessToken),
|
|
929
|
+
body: JSON.stringify({ project: projectId }),
|
|
930
|
+
});
|
|
931
|
+
if (response.ok)
|
|
932
|
+
return response.json();
|
|
933
|
+
if (response.status === 403 && projectId) {
|
|
934
|
+
const retry = await fetchWithTimeout(url, {
|
|
935
|
+
method: "POST",
|
|
936
|
+
headers: googleAntigravityQuotaHeaders(accessToken),
|
|
937
|
+
body: JSON.stringify({}),
|
|
938
|
+
});
|
|
939
|
+
if (retry.ok)
|
|
940
|
+
return retry.json();
|
|
941
|
+
}
|
|
942
|
+
const errorText = await response.text().catch(() => "");
|
|
943
|
+
errors.push(`fetchAvailableModels ${response.status} at ${endpoint}${errorText ? `: ${errorText.slice(0, 200)}` : ""}`);
|
|
720
944
|
}
|
|
721
|
-
|
|
945
|
+
throw new Error(errors.join("; ") || "Google Antigravity quota request failed");
|
|
722
946
|
}
|
|
723
947
|
function parseResetTime(value, now) {
|
|
724
948
|
if (!value)
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import type { AgentSessionRuntime, SessionInfo } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import type { PopupMenuItem } from "../../ui.js";
|
|
3
|
-
import type { Entry, ModelMenuValue, QueueMessageMenuValue, ResumeMenuValue, SessionModel, SlashCommand, ThinkingMenuValue, UserMessageJumpMenuValue, UserMessageMenuValue } from "../types.js";
|
|
3
|
+
import type { Entry, ModelMenuValue, QueueMessageMenuValue, ResumeMenuValue, SessionModel, SlashCommand, ThinkingLevel, ThinkingMenuValue, UserMessageJumpMenuValue, UserMessageMenuValue } from "../types.js";
|
|
4
4
|
export type AppMenuItemsControllerHost = {
|
|
5
5
|
runtime(): AgentSessionRuntime | undefined;
|
|
6
|
+
draftModelState?(): {
|
|
7
|
+
models: readonly SessionModel[];
|
|
8
|
+
modelRef?: string;
|
|
9
|
+
thinkingLevel?: ThinkingLevel;
|
|
10
|
+
} | undefined;
|
|
11
|
+
visibleModels(): readonly string[] | undefined;
|
|
6
12
|
getBuiltinSlashCommands(): readonly SlashCommand[];
|
|
7
13
|
getEntries(): readonly Entry[];
|
|
8
14
|
getResumeSessions(): readonly SessionInfo[];
|
|
15
|
+
getOpenSessionPaths?(): readonly string[];
|
|
9
16
|
};
|
|
10
17
|
export declare class AppMenuItemsController {
|
|
11
18
|
private readonly host;
|
|
@@ -18,17 +25,20 @@ export declare class AppMenuItemsController {
|
|
|
18
25
|
getSlashCommandMatches(query: string, limit?: number): import("../../fuzzy.js").FuzzyMatch<SlashCommand>[];
|
|
19
26
|
getSlashCommandMenuItems(query: string): PopupMenuItem<SlashCommand>[];
|
|
20
27
|
modelRef(model: SessionModel): string;
|
|
21
|
-
getModelMenuItems(query: string): PopupMenuItem<ModelMenuValue>[];
|
|
28
|
+
getModelMenuItems(query: string, includeHidden?: boolean): PopupMenuItem<ModelMenuValue>[];
|
|
22
29
|
getThinkingMenuItems(query: string): PopupMenuItem<ThinkingMenuValue>[];
|
|
23
30
|
getUserMessageMenuItems(): PopupMenuItem<UserMessageMenuValue>[];
|
|
24
31
|
getUserMessageJumpMenuItems(query: string): PopupMenuItem<UserMessageJumpMenuValue>[];
|
|
25
32
|
isUserMessageJumpLoading(): boolean;
|
|
26
33
|
refreshUserMessageJumpMenuItems(): Promise<void>;
|
|
27
34
|
getQueueMessageMenuItems(): PopupMenuItem<QueueMessageMenuValue>[];
|
|
28
|
-
getResumeMenuItems(query: string, limit?: number
|
|
35
|
+
getResumeMenuItems(query: string, limit?: number, options?: {
|
|
36
|
+
draft?: boolean;
|
|
37
|
+
}): PopupMenuItem<ResumeMenuValue>[];
|
|
29
38
|
private getResumeMenuItemsLoader;
|
|
30
39
|
private getAllSlashCommands;
|
|
31
40
|
private isCurrentModel;
|
|
41
|
+
private isVisibleModel;
|
|
32
42
|
private getModelMenuModels;
|
|
33
43
|
private thinkingLevelDescription;
|
|
34
44
|
}
|