@herbertgao/pi-extensions 2026.9.2 → 2026.9.4
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 +4 -2
- package/THIRD_PARTY_NOTICES.md +49 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +3 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +16 -11
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-renderer.ts +20 -6
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +12 -7
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +98 -0
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
- package/node_modules/@herbertgao/sol-pi/LICENSE +19 -0
- package/node_modules/@herbertgao/sol-pi/README.md +159 -0
- package/node_modules/@herbertgao/sol-pi/SECURITY.md +26 -0
- package/node_modules/@herbertgao/sol-pi/THIRD_PARTY_NOTICES.md +19 -0
- package/node_modules/@herbertgao/sol-pi/agents-install.md +150 -0
- package/node_modules/@herbertgao/sol-pi/assets/sol-pi-hero.png +0 -0
- package/node_modules/@herbertgao/sol-pi/docs/compatibility.md +69 -0
- package/node_modules/@herbertgao/sol-pi/docs/configuration.md +75 -0
- package/node_modules/@herbertgao/sol-pi/package.json +76 -0
- package/node_modules/@herbertgao/sol-pi/scripts/check-pi-compat.mjs +32 -0
- package/node_modules/@herbertgao/sol-pi/scripts/check-sol-pi-config.mjs +120 -0
- package/node_modules/@herbertgao/sol-pi/sol-pi.example.json +10 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/config.ts +135 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/file-queue.ts +74 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/index.ts +185 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/then-run.ts +128 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/archive.ts +53 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/candidate.ts +101 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/config.ts +71 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/index.ts +220 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/journal.ts +25 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/provider.ts +164 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/receipt.ts +177 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/index.ts +227 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/ledger.ts +20 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/observation.ts +252 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/economics.ts +237 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/extension.ts +455 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/index.ts +49 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/plan.ts +79 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/state.ts +208 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/tools.ts +100 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/index.ts +42 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/runtime-paths.ts +17 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/tui.ts +71 -0
- package/node_modules/@narumitw/pi-btw/dist/index.ts +12 -2
- package/node_modules/@narumitw/pi-btw/dist/index.ts.map +2 -2
- package/node_modules/@narumitw/pi-btw/package.json +1 -1
- package/node_modules/@narumitw/pi-btw/src/btw.ts +13 -2
- package/node_modules/pi-antigravity/LICENSE +21 -0
- package/node_modules/pi-antigravity/README.md +194 -0
- package/node_modules/pi-antigravity/package.json +67 -0
- package/node_modules/pi-antigravity/src/auth/index.ts +14 -0
- package/node_modules/pi-antigravity/src/auth/oauth.ts +442 -0
- package/node_modules/pi-antigravity/src/client/client.ts +561 -0
- package/node_modules/pi-antigravity/src/client/index.ts +1 -0
- package/node_modules/pi-antigravity/src/diagnostics/diagnostics.ts +96 -0
- package/node_modules/pi-antigravity/src/diagnostics/index.ts +1 -0
- package/node_modules/pi-antigravity/src/image/image.ts +336 -0
- package/node_modules/pi-antigravity/src/image/index.ts +1 -0
- package/node_modules/pi-antigravity/src/index.ts +280 -0
- package/node_modules/pi-antigravity/src/models/discovery.ts +154 -0
- package/node_modules/pi-antigravity/src/models/grouping.ts +424 -0
- package/node_modules/pi-antigravity/src/models/index.ts +3 -0
- package/node_modules/pi-antigravity/src/models/models.ts +500 -0
- package/node_modules/pi-antigravity/src/stream/index.ts +1 -0
- package/node_modules/pi-antigravity/src/stream/stream.ts +1460 -0
- package/node_modules/pi-antigravity/src/types/enums.ts +42 -0
- package/node_modules/pi-antigravity/src/types/index.ts +2 -0
- package/node_modules/pi-antigravity/src/types/types.ts +292 -0
- package/node_modules/pi-antigravity/src/usage/index.ts +1 -0
- package/node_modules/pi-antigravity/src/usage/usage.ts +371 -0
- package/node_modules/pi-antigravity/src/utils/http.ts +91 -0
- package/node_modules/pi-antigravity/src/utils/index.ts +3 -0
- package/node_modules/pi-antigravity/src/utils/security.ts +73 -0
- package/node_modules/pi-antigravity/src/utils/util.ts +132 -0
- package/node_modules/pi-antigravity/tsconfig.json +21 -0
- package/node_modules/pi-lens/CHANGELOG.md +176 -0
- package/node_modules/pi-lens/README.md +13 -8
- package/node_modules/pi-lens/config/dependency-cruiser-eager-allowlist.json +3 -1
- package/node_modules/pi-lens/dist/clients/analysed-root.js +1 -0
- package/node_modules/pi-lens/dist/clients/ast-grep-tool-logger.js +1 -1
- package/node_modules/pi-lens/dist/clients/biome-client.js +13 -2
- package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +2 -0
- package/node_modules/pi-lens/dist/clients/cache-observability.js +122 -1
- package/node_modules/pi-lens/dist/clients/complexity-client.js +5 -0
- package/node_modules/pi-lens/dist/clients/config-diagnostic-codes.js +2 -0
- package/node_modules/pi-lens/dist/clients/config-resolve.js +6 -3
- package/node_modules/pi-lens/dist/clients/config-schema.js +17 -0
- package/node_modules/pi-lens/dist/clients/config-warn.js +2 -2
- package/node_modules/pi-lens/dist/clients/dead-code-client.js +8 -1
- package/node_modules/pi-lens/dist/clients/dependency-checker.js +5 -1
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +38 -15
- package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +5 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/actionlint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +2 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +4 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/dart-analyze.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/dotnet-build.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/fish-indent.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/gleam-check.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/golangci-lint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +3 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ktlint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +19 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/php-lint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/prisma-validate.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +12 -12
- package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/rubocop.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +2 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +12 -11
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +2 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +5 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +2 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +8 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +4 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +2 -1
- package/node_modules/pi-lens/dist/clients/effective-config.js +12 -2
- package/node_modules/pi-lens/dist/clients/extension-log.js +2 -0
- package/node_modules/pi-lens/dist/clients/file-role.js +18 -1
- package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +4 -0
- package/node_modules/pi-lens/dist/clients/formatters.js +54 -188
- package/node_modules/pi-lens/dist/clients/generation-guard.js +4 -0
- package/node_modules/pi-lens/dist/clients/gitleaks-client.js +42 -6
- package/node_modules/pi-lens/dist/clients/govulncheck-client.js +48 -7
- package/node_modules/pi-lens/dist/clients/installer/index.js +196 -52
- package/node_modules/pi-lens/dist/clients/jscpd-client.js +9 -1
- package/node_modules/pi-lens/dist/clients/knip-client.js +9 -2
- package/node_modules/pi-lens/dist/clients/language-profile.js +12 -2
- package/node_modules/pi-lens/dist/clients/latency-logger.js +2 -0
- package/node_modules/pi-lens/dist/clients/lens-config.js +4 -0
- package/node_modules/pi-lens/dist/clients/lsp/config.js +36 -7
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +24 -1
- package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +78 -0
- package/node_modules/pi-lens/dist/clients/lsp/index.js +281 -45
- package/node_modules/pi-lens/dist/clients/lsp/server.js +62 -15
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +37 -4
- package/node_modules/pi-lens/dist/clients/mcp/analyze.js +3 -0
- package/node_modules/pi-lens/dist/clients/mcp/session.js +2 -0
- package/node_modules/pi-lens/dist/clients/opengrep-client.js +2 -0
- package/node_modules/pi-lens/dist/clients/package-manager.js +2 -1
- package/node_modules/pi-lens/dist/clients/php-cs-fixer-config.js +8 -3
- package/node_modules/pi-lens/dist/clients/pipeline.js +3 -2
- package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +38 -10
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +10 -9
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +3 -0
- package/node_modules/pi-lens/dist/clients/read-guard-logger.js +2 -0
- package/node_modules/pi-lens/dist/clients/review-graph-logger.js +2 -0
- package/node_modules/pi-lens/dist/clients/ruff-client.js +18 -9
- package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +9 -0
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +5 -0
- package/node_modules/pi-lens/dist/clients/runtime-session.js +13 -4
- package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +4 -1
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +48 -1
- package/node_modules/pi-lens/dist/clients/security-scan-client.js +2 -2
- package/node_modules/pi-lens/dist/clients/session-event-guard.js +69 -1
- package/node_modules/pi-lens/dist/clients/sg-runner.js +2 -1
- package/node_modules/pi-lens/dist/clients/situational-tool-telemetry.js +108 -0
- package/node_modules/pi-lens/dist/clients/test-runner-client.js +291 -76
- package/node_modules/pi-lens/dist/clients/tool-config.js +199 -0
- package/node_modules/pi-lens/dist/clients/tool-cwd.js +299 -0
- package/node_modules/pi-lens/dist/clients/tool-probe.js +53 -0
- package/node_modules/pi-lens/dist/clients/tool-set-policy.js +42 -0
- package/node_modules/pi-lens/dist/clients/trivy-client.js +9 -1
- package/node_modules/pi-lens/dist/clients/turn-context.js +52 -0
- package/node_modules/pi-lens/dist/clients/widget-state.js +4 -3
- package/node_modules/pi-lens/dist/index.js +21969 -20005
- package/node_modules/pi-lens/dist/mcp/analyze-cli.js +3 -2
- package/node_modules/pi-lens/dist/mcp/server.js +135 -159
- package/node_modules/pi-lens/dist/tools/activate-tools.js +10 -7
- package/node_modules/pi-lens/dist/tools/ast-grep-outline.js +2 -13
- package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +8 -13
- package/node_modules/pi-lens/dist/tools/ast-grep-search.js +83 -39
- package/node_modules/pi-lens/dist/tools/effective-config.js +4 -3
- package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +1 -10
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +353 -85
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +21 -110
- package/node_modules/pi-lens/dist/tools/lsp-navigation.js +20 -44
- package/node_modules/pi-lens/dist/tools/module-report.js +5 -9
- package/node_modules/pi-lens/dist/tools/project-report.js +9 -17
- package/node_modules/pi-lens/dist/tools/render-compact.js +280 -1
- package/node_modules/pi-lens/dist/tools/symbol-search.js +2 -2
- package/node_modules/pi-lens/docs/agent-guide.md +3 -4
- package/node_modules/pi-lens/docs/agent-tools.md +46 -22
- package/node_modules/pi-lens/docs/configuration.md +9 -0
- package/node_modules/pi-lens/docs/environment-variables.md +0 -5
- package/node_modules/pi-lens/docs/features.md +5 -5
- package/node_modules/pi-lens/docs/globalconfig.md +11 -1
- package/node_modules/pi-lens/docs/mcp.md +13 -1
- package/node_modules/pi-lens/docs/pi-lens-fixer.md +71 -0
- package/node_modules/pi-lens/docs/pi-lens-investigator.md +15 -0
- package/node_modules/pi-lens/docs/pi-lens-monitor.md +88 -0
- package/node_modules/pi-lens/docs/pi-lens-reviewer.md +35 -0
- package/node_modules/pi-lens/docs/pi-lens-subagent.md +12 -4
- package/node_modules/pi-lens/docs/public-api-stability.md +1 -0
- package/node_modules/pi-lens/docs/real-harness.md +46 -0
- package/node_modules/pi-lens/docs/release-qa-baseline.md +5 -1
- package/node_modules/pi-lens/docs/servercapabilities.md +1 -6
- package/node_modules/pi-lens/docs/settings.md +37 -2
- package/node_modules/pi-lens/docs/tools_improvement2.md +4 -4
- package/node_modules/pi-lens/docs/tree-sitter_rules_catalog.md +1 -1
- package/node_modules/pi-lens/docs/usage.md +13 -3
- package/node_modules/pi-lens/package.json +10 -1
- package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/sql-injection.yml +7 -3
- package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +8 -6
- package/node_modules/pi-lens/skills/pi-lens-lsp-navigation/SKILL.md +19 -9
- package/node_modules/pi-web-access/CHANGELOG.md +29 -0
- package/node_modules/pi-web-access/README.md +33 -22
- package/node_modules/pi-web-access/abortable.ts +17 -0
- package/node_modules/pi-web-access/crawl4ai.ts +204 -0
- package/node_modules/pi-web-access/credential-source.ts +1 -0
- package/node_modules/pi-web-access/curator-page.ts +20 -2
- package/node_modules/pi-web-access/curator-run.ts +44 -0
- package/node_modules/pi-web-access/curator-server.ts +3 -1
- package/node_modules/pi-web-access/duckduckgo.ts +1 -1
- package/node_modules/pi-web-access/extract.ts +57 -12
- package/node_modules/pi-web-access/fetch-params.ts +1 -1
- package/node_modules/pi-web-access/gemini-search.ts +9 -5
- package/node_modules/pi-web-access/index.ts +25 -18
- package/node_modules/pi-web-access/openai-search.ts +35 -13
- package/node_modules/pi-web-access/package.json +2 -2
- package/node_modules/pi-web-access/page-query.ts +5 -2
- package/node_modules/pi-web-access/query-rewrite.ts +5 -2
- package/node_modules/pi-web-access/serpapi.ts +220 -0
- package/node_modules/pi-web-access/ssrf-protection.ts +5 -1
- package/node_modules/pi-web-access/storage.ts +10 -0
- package/node_modules/pi-web-access/summary-review.ts +34 -21
- package/node_modules/pi-web-access/utils.ts +6 -4
- package/package.json +11 -5
- package/node_modules/pi-lens/dist/tools/ast-dump.js +0 -103
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export enum ThinkingEffort {
|
|
2
|
+
Off = "off",
|
|
3
|
+
Minimal = "minimal",
|
|
4
|
+
Low = "low",
|
|
5
|
+
Medium = "medium",
|
|
6
|
+
High = "high",
|
|
7
|
+
Xhigh = "xhigh",
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export enum ToolChoice {
|
|
11
|
+
Auto = "auto",
|
|
12
|
+
None = "none",
|
|
13
|
+
Any = "any",
|
|
14
|
+
Required = "required",
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export enum GeminiToolCallingMode {
|
|
18
|
+
None = "NONE",
|
|
19
|
+
Any = "ANY",
|
|
20
|
+
Auto = "AUTO",
|
|
21
|
+
Validated = "VALIDATED",
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export enum GeminiRole {
|
|
25
|
+
User = "user",
|
|
26
|
+
Model = "model",
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export enum AntigravityRequestType {
|
|
30
|
+
Agent = "agent",
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export enum AntigravityUserAgent {
|
|
34
|
+
Antigravity = "antigravity",
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export enum StopReason {
|
|
38
|
+
Stop = "stop",
|
|
39
|
+
Length = "length",
|
|
40
|
+
ToolUse = "toolUse",
|
|
41
|
+
Error = "error",
|
|
42
|
+
}
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import type { Server } from "node:http";
|
|
2
|
+
import type {
|
|
3
|
+
OAuthCredentials,
|
|
4
|
+
SimpleStreamOptions,
|
|
5
|
+
TextContent,
|
|
6
|
+
ThinkingContent,
|
|
7
|
+
ToolCall,
|
|
8
|
+
} from "@earendil-works/pi-ai";
|
|
9
|
+
import type {
|
|
10
|
+
AntigravityRequestType,
|
|
11
|
+
AntigravityUserAgent,
|
|
12
|
+
GeminiRole,
|
|
13
|
+
GeminiToolCallingMode,
|
|
14
|
+
ThinkingEffort,
|
|
15
|
+
ToolChoice,
|
|
16
|
+
} from "./enums.js";
|
|
17
|
+
|
|
18
|
+
// OAuth & Auth Types
|
|
19
|
+
export type AntigravityOAuthCredentials = OAuthCredentials & {
|
|
20
|
+
projectId?: string;
|
|
21
|
+
email?: string;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export type AntigravityApiKey = {
|
|
25
|
+
token: string;
|
|
26
|
+
projectId: string;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export type DynamicModelInfo = {
|
|
30
|
+
id: string;
|
|
31
|
+
experiments?: string[];
|
|
32
|
+
apiProvider?: string;
|
|
33
|
+
modelProvider?: string;
|
|
34
|
+
model?: string;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export type CallbackServer = {
|
|
38
|
+
server: Server;
|
|
39
|
+
waitForCode: () => Promise<{ code: string; state: string }>;
|
|
40
|
+
cleanup: () => void;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Model Types
|
|
44
|
+
export type AntigravityRouting = {
|
|
45
|
+
off?: string;
|
|
46
|
+
routing?: Partial<Record<ThinkingEffort, string>>;
|
|
47
|
+
defaultRequestId?: string;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// Stream & API Types
|
|
51
|
+
export const ANTIGRAVITY_API = "antigravity-api" as const;
|
|
52
|
+
export type AntigravityApi = typeof ANTIGRAVITY_API;
|
|
53
|
+
|
|
54
|
+
export type AntigravityStreamOptions = Omit<SimpleStreamOptions, "toolChoice"> & {
|
|
55
|
+
toolChoice?: ToolChoice | `${ToolChoice}`;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export type GeminiTextPart = { text: string; thoughtSignature?: string };
|
|
59
|
+
export type GeminiInlineDataPart = { inlineData: { mimeType: string; data: string } };
|
|
60
|
+
export type GeminiThoughtPart = {
|
|
61
|
+
thought: true;
|
|
62
|
+
text: string;
|
|
63
|
+
thoughtSignature?: string;
|
|
64
|
+
};
|
|
65
|
+
export type GeminiFunctionCallPart = {
|
|
66
|
+
functionCall: {
|
|
67
|
+
name: string;
|
|
68
|
+
args: Record<string, unknown>;
|
|
69
|
+
id?: string;
|
|
70
|
+
};
|
|
71
|
+
thoughtSignature?: string;
|
|
72
|
+
};
|
|
73
|
+
export type GeminiFunctionResponsePart = {
|
|
74
|
+
functionResponse: {
|
|
75
|
+
name: string;
|
|
76
|
+
response: { error: string } | { output: string };
|
|
77
|
+
id?: string;
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
export type GeminiPart =
|
|
81
|
+
| GeminiTextPart
|
|
82
|
+
| GeminiInlineDataPart
|
|
83
|
+
| GeminiThoughtPart
|
|
84
|
+
| GeminiFunctionCallPart
|
|
85
|
+
| GeminiFunctionResponsePart;
|
|
86
|
+
|
|
87
|
+
export type GeminiContent = {
|
|
88
|
+
role: GeminiRole;
|
|
89
|
+
parts: GeminiPart[];
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export type GeminiFunctionDeclaration = {
|
|
93
|
+
name: string;
|
|
94
|
+
description: string;
|
|
95
|
+
parameters?: unknown;
|
|
96
|
+
parametersJsonSchema?: unknown;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export type GeminiToolConfig = {
|
|
100
|
+
functionCallingConfig: {
|
|
101
|
+
mode: GeminiToolCallingMode;
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
export type ThinkingWire = {
|
|
106
|
+
includeThoughts: boolean;
|
|
107
|
+
thinkingBudget: number;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
export type GeminiGenerationConfig = {
|
|
111
|
+
temperature?: number;
|
|
112
|
+
maxOutputTokens?: number;
|
|
113
|
+
thinkingConfig?: ThinkingWire;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
export type GeminiRequestBody = {
|
|
117
|
+
contents: GeminiContent[];
|
|
118
|
+
systemInstruction: {
|
|
119
|
+
role: GeminiRole.User;
|
|
120
|
+
parts: GeminiTextPart[];
|
|
121
|
+
};
|
|
122
|
+
generationConfig?: GeminiGenerationConfig;
|
|
123
|
+
tools?: { functionDeclarations: GeminiFunctionDeclaration[] }[];
|
|
124
|
+
toolConfig?: GeminiToolConfig;
|
|
125
|
+
sessionId?: string;
|
|
126
|
+
labels?: Record<string, string>;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
export type AntigravityGenerateRequest = {
|
|
130
|
+
project: string;
|
|
131
|
+
model: string;
|
|
132
|
+
request: GeminiRequestBody;
|
|
133
|
+
requestType: AntigravityRequestType.Agent;
|
|
134
|
+
userAgent: AntigravityUserAgent.Antigravity;
|
|
135
|
+
requestId: string;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
export type StreamPart = {
|
|
139
|
+
text?: string;
|
|
140
|
+
thought?: boolean;
|
|
141
|
+
thoughtSignature?: string;
|
|
142
|
+
functionCall?: {
|
|
143
|
+
id?: string;
|
|
144
|
+
name?: string;
|
|
145
|
+
args?: Record<string, unknown>;
|
|
146
|
+
};
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
export type StreamUsageMetadata = {
|
|
150
|
+
promptTokenCount?: number;
|
|
151
|
+
cachedContentTokenCount?: number;
|
|
152
|
+
candidatesTokenCount?: number;
|
|
153
|
+
thoughtsTokenCount?: number;
|
|
154
|
+
totalTokenCount?: number;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
export type StreamCandidate = {
|
|
158
|
+
content?: { parts?: StreamPart[] };
|
|
159
|
+
finishReason?: string;
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
export type StreamResponseData = {
|
|
163
|
+
candidates?: StreamCandidate[];
|
|
164
|
+
usageMetadata?: StreamUsageMetadata;
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
export type StreamChunk = StreamResponseData & {
|
|
168
|
+
error?: { message?: string };
|
|
169
|
+
response?: StreamResponseData;
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
export type LooseImageBlock = {
|
|
173
|
+
type: "image";
|
|
174
|
+
data?: string;
|
|
175
|
+
mimeType?: string;
|
|
176
|
+
mediaType?: string;
|
|
177
|
+
source?: { data?: string; mediaType?: string };
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
export type ContentBlock = TextContent | ThinkingContent | ToolCall | LooseImageBlock;
|
|
181
|
+
|
|
182
|
+
export type ActiveTextBlock = TextContent;
|
|
183
|
+
export type ActiveThinkingBlock = ThinkingContent;
|
|
184
|
+
export type ActiveBlock = ActiveTextBlock | ActiveThinkingBlock;
|
|
185
|
+
|
|
186
|
+
// Usage & Quota Types
|
|
187
|
+
export type QuotaBucket = {
|
|
188
|
+
bucketId: string;
|
|
189
|
+
displayName: string;
|
|
190
|
+
window?: string;
|
|
191
|
+
resetTime?: string;
|
|
192
|
+
description?: string;
|
|
193
|
+
remainingFraction: number;
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
export type QuotaGroup = {
|
|
197
|
+
displayName: string;
|
|
198
|
+
description?: string;
|
|
199
|
+
buckets: QuotaBucket[];
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
export type ModelQuotaRow = {
|
|
203
|
+
modelId: string;
|
|
204
|
+
displayName?: string;
|
|
205
|
+
remainingFraction?: number;
|
|
206
|
+
resetTime?: string;
|
|
207
|
+
modelProvider?: string;
|
|
208
|
+
supportsThinking?: boolean;
|
|
209
|
+
supportsImages?: boolean;
|
|
210
|
+
recommended?: boolean;
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
export type TierInfo = {
|
|
214
|
+
id?: string;
|
|
215
|
+
name?: string;
|
|
216
|
+
description?: string;
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
export type AccountUsage = {
|
|
220
|
+
projectId: string;
|
|
221
|
+
endpoint: string;
|
|
222
|
+
email?: string;
|
|
223
|
+
productTier?: TierInfo;
|
|
224
|
+
paidTier?: TierInfo;
|
|
225
|
+
planLabel?: string;
|
|
226
|
+
groups: QuotaGroup[];
|
|
227
|
+
groupDescription?: string;
|
|
228
|
+
/** Set when the (subscription-gated) quota-summary RPC was unavailable, e.g. free-tier SUBSCRIPTION_REQUIRED. */
|
|
229
|
+
quotaSummaryError?: string;
|
|
230
|
+
models: ModelQuotaRow[];
|
|
231
|
+
defaultAgentModelId?: string;
|
|
232
|
+
fetchedAt: number;
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
export type ApiErrorBody = {
|
|
236
|
+
error?: { message?: string };
|
|
237
|
+
raw?: string;
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
export type QuotaBucketRaw = {
|
|
241
|
+
bucketId?: unknown;
|
|
242
|
+
displayName?: unknown;
|
|
243
|
+
window?: unknown;
|
|
244
|
+
resetTime?: unknown;
|
|
245
|
+
description?: unknown;
|
|
246
|
+
remainingFraction?: unknown;
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
export type QuotaGroupRaw = {
|
|
250
|
+
displayName?: unknown;
|
|
251
|
+
description?: unknown;
|
|
252
|
+
buckets?: QuotaBucketRaw[];
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
export type QuotaSummaryRaw = {
|
|
256
|
+
description?: unknown;
|
|
257
|
+
groups?: QuotaGroupRaw[];
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
export type ModelInfoRaw = {
|
|
261
|
+
isInternal?: unknown;
|
|
262
|
+
displayName?: unknown;
|
|
263
|
+
label?: unknown;
|
|
264
|
+
modelName?: unknown;
|
|
265
|
+
model?: unknown;
|
|
266
|
+
modelProvider?: unknown;
|
|
267
|
+
apiProvider?: unknown;
|
|
268
|
+
supportsThinking?: unknown;
|
|
269
|
+
supportsImages?: unknown;
|
|
270
|
+
recommended?: unknown;
|
|
271
|
+
quotaInfo?: {
|
|
272
|
+
remainingFraction?: unknown;
|
|
273
|
+
resetTime?: unknown;
|
|
274
|
+
};
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
export type AvailableModelsRaw = {
|
|
278
|
+
models?: Record<string, ModelInfoRaw>;
|
|
279
|
+
defaultAgentModelId?: unknown;
|
|
280
|
+
defaultAgentModel?: unknown;
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
export type TierRaw = {
|
|
284
|
+
id?: unknown;
|
|
285
|
+
name?: unknown;
|
|
286
|
+
description?: unknown;
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
export type LoadCodeAssistRaw = {
|
|
290
|
+
currentTier?: TierRaw;
|
|
291
|
+
paidTier?: TierRaw;
|
|
292
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./usage.js";
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import {
|
|
3
|
+
antigravityHeaders,
|
|
4
|
+
endpointCandidates,
|
|
5
|
+
extractProjectId,
|
|
6
|
+
fetchAvailableModelsCatalog,
|
|
7
|
+
parseApiKey,
|
|
8
|
+
resolveProjectId,
|
|
9
|
+
} from "../client/client.js";
|
|
10
|
+
import {
|
|
11
|
+
setLastEndpoint,
|
|
12
|
+
setLastError,
|
|
13
|
+
setLastProjectId,
|
|
14
|
+
setLastStatus,
|
|
15
|
+
} from "../diagnostics/diagnostics.js";
|
|
16
|
+
import { isRecord } from "../utils/util.js";
|
|
17
|
+
import { safeError } from "../utils/security.js";
|
|
18
|
+
import { antigravityFetch } from "../utils/http.js";
|
|
19
|
+
import type {
|
|
20
|
+
AccountUsage,
|
|
21
|
+
ApiErrorBody,
|
|
22
|
+
AvailableModelsRaw,
|
|
23
|
+
LoadCodeAssistRaw,
|
|
24
|
+
ModelQuotaRow,
|
|
25
|
+
QuotaBucket,
|
|
26
|
+
QuotaGroup,
|
|
27
|
+
QuotaSummaryRaw,
|
|
28
|
+
TierInfo,
|
|
29
|
+
TierRaw,
|
|
30
|
+
} from "../types/types.js";
|
|
31
|
+
|
|
32
|
+
function clampFraction(value: unknown): number | undefined {
|
|
33
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return undefined;
|
|
34
|
+
if (value < 0) return 0;
|
|
35
|
+
if (value > 1) return 1;
|
|
36
|
+
return value;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function remainingPercent(remaining?: number): number | undefined {
|
|
40
|
+
if (remaining === undefined) return undefined;
|
|
41
|
+
return Math.round(remaining * 1000) / 10;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function progressBar(remaining?: number, width = 20): string {
|
|
45
|
+
if (remaining === undefined) return `[${"?".repeat(width)}]`;
|
|
46
|
+
const filled = Math.max(0, Math.min(width, Math.round(remaining * width)));
|
|
47
|
+
return `[${"#".repeat(filled)}${"-".repeat(width - filled)}]`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function formatReset(resetTime?: string): string {
|
|
51
|
+
if (!resetTime) return "n/a";
|
|
52
|
+
const ts = Date.parse(resetTime);
|
|
53
|
+
if (!Number.isFinite(ts)) return resetTime;
|
|
54
|
+
const delta = ts - Date.now();
|
|
55
|
+
if (delta <= 0) return "now";
|
|
56
|
+
const totalMin = Math.round(delta / 60000);
|
|
57
|
+
const days = Math.floor(totalMin / (60 * 24));
|
|
58
|
+
const hours = Math.floor((totalMin % (60 * 24)) / 60);
|
|
59
|
+
const mins = totalMin % 60;
|
|
60
|
+
if (days > 0) return `${days}d ${hours}h`;
|
|
61
|
+
if (hours > 0) return `${hours}h ${mins}m`;
|
|
62
|
+
return `${mins}m`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function jsonHeaders(token: string): Record<string, string> {
|
|
66
|
+
return {
|
|
67
|
+
...antigravityHeaders(token),
|
|
68
|
+
Accept: "application/json",
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function postJson(
|
|
73
|
+
path: string,
|
|
74
|
+
token: string,
|
|
75
|
+
body: Record<string, unknown>,
|
|
76
|
+
): Promise<{ endpoint: string; status: number; data: unknown }> {
|
|
77
|
+
let lastErrorText = "";
|
|
78
|
+
for (const endpoint of endpointCandidates()) {
|
|
79
|
+
try {
|
|
80
|
+
const res = await antigravityFetch(`${endpoint}${path}`, {
|
|
81
|
+
method: "POST",
|
|
82
|
+
headers: jsonHeaders(token),
|
|
83
|
+
body: JSON.stringify(body),
|
|
84
|
+
});
|
|
85
|
+
setLastEndpoint(endpoint);
|
|
86
|
+
setLastStatus(res.status);
|
|
87
|
+
const text = await res.text();
|
|
88
|
+
let data: unknown;
|
|
89
|
+
try {
|
|
90
|
+
data = JSON.parse(text) as unknown;
|
|
91
|
+
} catch {
|
|
92
|
+
data = { raw: text } satisfies ApiErrorBody;
|
|
93
|
+
}
|
|
94
|
+
if (!res.ok) {
|
|
95
|
+
const errorBody = isRecord(data) ? (data as ApiErrorBody) : undefined;
|
|
96
|
+
lastErrorText =
|
|
97
|
+
typeof errorBody?.error?.message === "string" ? errorBody.error.message : text;
|
|
98
|
+
if (![403, 404, 429, 500, 502, 503, 504].includes(res.status)) {
|
|
99
|
+
throw new Error(`${path} failed (${String(res.status)}): ${lastErrorText.slice(0, 300)}`);
|
|
100
|
+
}
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
return { endpoint, status: res.status, data };
|
|
104
|
+
} catch (error) {
|
|
105
|
+
lastErrorText = safeError(error);
|
|
106
|
+
setLastError(lastErrorText);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
throw new Error(`${path} failed: ${lastErrorText || "no endpoint available"}`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function parseQuotaSummary(data: unknown): { groups: QuotaGroup[]; description?: string } {
|
|
113
|
+
const summary = (isRecord(data) ? data : {}) as QuotaSummaryRaw;
|
|
114
|
+
const groups: QuotaGroup[] = [];
|
|
115
|
+
for (const group of summary.groups || []) {
|
|
116
|
+
const buckets: QuotaBucket[] = [];
|
|
117
|
+
for (const bucket of group.buckets || []) {
|
|
118
|
+
const remaining = clampFraction(bucket.remainingFraction);
|
|
119
|
+
if (remaining === undefined && !bucket.bucketId) continue;
|
|
120
|
+
buckets.push({
|
|
121
|
+
bucketId: String(bucket.bucketId || bucket.displayName || "unknown"),
|
|
122
|
+
displayName: String(bucket.displayName || bucket.bucketId || "Limit"),
|
|
123
|
+
window: bucket.window ? String(bucket.window) : undefined,
|
|
124
|
+
resetTime: bucket.resetTime ? String(bucket.resetTime) : undefined,
|
|
125
|
+
description: bucket.description ? String(bucket.description) : undefined,
|
|
126
|
+
remainingFraction: remaining ?? 0,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
if (!buckets.length && !group.displayName) continue;
|
|
130
|
+
groups.push({
|
|
131
|
+
displayName: String(group.displayName || "Quota group"),
|
|
132
|
+
description: group.description ? String(group.description) : undefined,
|
|
133
|
+
buckets,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
groups,
|
|
138
|
+
description: summary.description ? String(summary.description) : undefined,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function parseModels(data: unknown): {
|
|
143
|
+
models: ModelQuotaRow[];
|
|
144
|
+
defaultAgentModelId?: string;
|
|
145
|
+
} {
|
|
146
|
+
const raw = (isRecord(data) ? data : {}) as AvailableModelsRaw;
|
|
147
|
+
const modelsObj = raw.models && isRecord(raw.models) ? raw.models : {};
|
|
148
|
+
const models: ModelQuotaRow[] = [];
|
|
149
|
+
for (const [modelId, info] of Object.entries(modelsObj)) {
|
|
150
|
+
if (!info || !isRecord(info)) continue;
|
|
151
|
+
if (info.isInternal || String(modelId).startsWith("chat_")) continue;
|
|
152
|
+
const qi = isRecord(info.quotaInfo) ? info.quotaInfo : {};
|
|
153
|
+
models.push({
|
|
154
|
+
modelId,
|
|
155
|
+
displayName:
|
|
156
|
+
typeof info.displayName === "string"
|
|
157
|
+
? info.displayName
|
|
158
|
+
: typeof info.label === "string"
|
|
159
|
+
? info.label
|
|
160
|
+
: typeof info.modelName === "string"
|
|
161
|
+
? info.modelName
|
|
162
|
+
: undefined,
|
|
163
|
+
remainingFraction: clampFraction(qi.remainingFraction),
|
|
164
|
+
resetTime: qi.resetTime ? String(qi.resetTime) : undefined,
|
|
165
|
+
modelProvider:
|
|
166
|
+
typeof info.modelProvider === "string"
|
|
167
|
+
? info.modelProvider
|
|
168
|
+
: typeof info.apiProvider === "string"
|
|
169
|
+
? info.apiProvider
|
|
170
|
+
: undefined,
|
|
171
|
+
supportsThinking: !!info.supportsThinking,
|
|
172
|
+
supportsImages: !!info.supportsImages,
|
|
173
|
+
recommended: !!info.recommended,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
models.sort((a, b) => a.modelId.localeCompare(b.modelId));
|
|
177
|
+
return {
|
|
178
|
+
models,
|
|
179
|
+
defaultAgentModelId:
|
|
180
|
+
raw.defaultAgentModelId || raw.defaultAgentModel
|
|
181
|
+
? String(raw.defaultAgentModelId || raw.defaultAgentModel)
|
|
182
|
+
: undefined,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function parseTier(value: unknown): TierInfo | undefined {
|
|
187
|
+
if (!isRecord(value)) return undefined;
|
|
188
|
+
const tier = value as TierRaw;
|
|
189
|
+
if (!tier.id && !tier.name) return undefined;
|
|
190
|
+
return {
|
|
191
|
+
id: tier.id ? String(tier.id) : undefined,
|
|
192
|
+
name: tier.name ? String(tier.name) : undefined,
|
|
193
|
+
description: tier.description ? String(tier.description) : undefined,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async function loadCodeAssistSafe(token: string) {
|
|
198
|
+
try {
|
|
199
|
+
return await postJson("/v1internal:loadCodeAssist", token, {
|
|
200
|
+
metadata: {
|
|
201
|
+
ideType: "ANTIGRAVITY",
|
|
202
|
+
platform: "PLATFORM_UNSPECIFIED",
|
|
203
|
+
pluginType: "GEMINI",
|
|
204
|
+
},
|
|
205
|
+
});
|
|
206
|
+
} catch {
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* The user-quota-summary RPC is gated behind a paid subscription: free-tier
|
|
213
|
+
* accounts get 403 SUBSCRIPTION_REQUIRED (#3501). It is best-effort diagnostics
|
|
214
|
+
* only — never let it block the rest of the account data (models, tier, project).
|
|
215
|
+
*/
|
|
216
|
+
async function fetchQuotaSummarySafe(token: string): Promise<
|
|
217
|
+
| { ok: true; result: { endpoint: string; status: number; data: unknown } }
|
|
218
|
+
| {
|
|
219
|
+
ok: false;
|
|
220
|
+
error: string;
|
|
221
|
+
}
|
|
222
|
+
> {
|
|
223
|
+
try {
|
|
224
|
+
return { ok: true, result: await postJson("/v1internal:retrieveUserQuotaSummary", token, {}) };
|
|
225
|
+
} catch (error) {
|
|
226
|
+
const msg = safeError(error);
|
|
227
|
+
setLastError(msg);
|
|
228
|
+
return { ok: false, error: msg };
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export async function fetchAccountUsage(apiKeyRaw?: string): Promise<AccountUsage> {
|
|
233
|
+
const creds = parseApiKey(apiKeyRaw);
|
|
234
|
+
const initialProjectId =
|
|
235
|
+
creds.projectId ||
|
|
236
|
+
resolveProjectId({
|
|
237
|
+
token: creds.token,
|
|
238
|
+
credentialProjectId: creds.projectId,
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
// Fetch loadCodeAssist, quota summary, and available models all in parallel
|
|
242
|
+
// to minimize command execution latency.
|
|
243
|
+
const [assistResult, summaryRes, available] = await Promise.all([
|
|
244
|
+
loadCodeAssistSafe(creds.token),
|
|
245
|
+
fetchQuotaSummarySafe(creds.token),
|
|
246
|
+
fetchAvailableModelsCatalog(creds.token, initialProjectId),
|
|
247
|
+
]);
|
|
248
|
+
|
|
249
|
+
// Derive project ID from the loadCodeAssist response or stored project ID.
|
|
250
|
+
const discoveredProject = assistResult ? extractProjectId(assistResult.data) : undefined;
|
|
251
|
+
const projectId = resolveProjectId({
|
|
252
|
+
token: creds.token,
|
|
253
|
+
warmedProject: discoveredProject ?? null,
|
|
254
|
+
credentialProjectId: creds.projectId,
|
|
255
|
+
});
|
|
256
|
+
setLastProjectId(projectId);
|
|
257
|
+
|
|
258
|
+
const summary = summaryRes.ok ? summaryRes.result : null;
|
|
259
|
+
const quotaSummaryError = summaryRes.ok ? undefined : summaryRes.error;
|
|
260
|
+
const { groups, description } = summary
|
|
261
|
+
? parseQuotaSummary(summary.data)
|
|
262
|
+
: { groups: [], description: undefined };
|
|
263
|
+
const { models, defaultAgentModelId } = parseModels(available.data);
|
|
264
|
+
|
|
265
|
+
const assistData = (isRecord(assistResult?.data) ? assistResult.data : {}) as LoadCodeAssistRaw;
|
|
266
|
+
const productTier = parseTier(assistData.currentTier);
|
|
267
|
+
const paidTier = parseTier(assistData.paidTier);
|
|
268
|
+
|
|
269
|
+
// Google returns currentTier=free-tier even for Google AI Pro accounts.
|
|
270
|
+
// The real subscription lives in paidTier (e.g. g1-pro-tier / Google AI Pro).
|
|
271
|
+
const planLabel = paidTier?.name
|
|
272
|
+
? `${paidTier.name}${paidTier.id ? ` (${paidTier.id})` : ""}`
|
|
273
|
+
: productTier?.name
|
|
274
|
+
? `${productTier.name}${productTier.id ? ` (${productTier.id})` : ""}`
|
|
275
|
+
: undefined;
|
|
276
|
+
|
|
277
|
+
return {
|
|
278
|
+
projectId,
|
|
279
|
+
endpoint: summary?.endpoint ?? available.endpoint ?? assistResult?.endpoint,
|
|
280
|
+
productTier,
|
|
281
|
+
paidTier,
|
|
282
|
+
planLabel,
|
|
283
|
+
groups,
|
|
284
|
+
groupDescription: description,
|
|
285
|
+
quotaSummaryError,
|
|
286
|
+
models,
|
|
287
|
+
defaultAgentModelId,
|
|
288
|
+
fetchedAt: Date.now(),
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function quotaErrorNote(msg: string): string {
|
|
293
|
+
if (/SUBSCRIPTION_REQUIRED|#3501|(?:lack|missing).*license/i.test(msg)) {
|
|
294
|
+
return "Aggregate quota summary needs a paid subscription (free-tier can't use that endpoint). Per-model usage is still available via /antigravity.models.";
|
|
295
|
+
}
|
|
296
|
+
return `Aggregate quota summary unavailable: ${msg.slice(0, 160)}`;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
export function formatUsageSummary(usage: AccountUsage): string {
|
|
300
|
+
const lines: string[] = [];
|
|
301
|
+
|
|
302
|
+
if (usage.planLabel) lines.push(usage.planLabel);
|
|
303
|
+
|
|
304
|
+
if (!usage.groups.length) {
|
|
305
|
+
if (usage.quotaSummaryError) {
|
|
306
|
+
lines.push(quotaErrorNote(usage.quotaSummaryError));
|
|
307
|
+
} else {
|
|
308
|
+
lines.push("No quota groups returned.");
|
|
309
|
+
}
|
|
310
|
+
return lines.join("\n");
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
for (const group of usage.groups) {
|
|
314
|
+
if (lines.length) lines.push("");
|
|
315
|
+
lines.push(group.displayName);
|
|
316
|
+
for (const bucket of group.buckets) {
|
|
317
|
+
const rem = remainingPercent(bucket.remainingFraction);
|
|
318
|
+
lines.push(
|
|
319
|
+
` ${progressBar(bucket.remainingFraction)} ${bucket.displayName}: ${rem ?? "?"}% left · resets ${formatReset(bucket.resetTime)}`,
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
return lines.join("\n").trimEnd();
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
export function formatModelsList(usage: AccountUsage, opts?: { all?: boolean }): string {
|
|
328
|
+
const lines: string[] = [];
|
|
329
|
+
lines.push("Antigravity available models");
|
|
330
|
+
lines.push(`project=${usage.projectId}`);
|
|
331
|
+
if (usage.defaultAgentModelId) lines.push(`defaultAgentModel=${usage.defaultAgentModelId}`);
|
|
332
|
+
lines.push("");
|
|
333
|
+
|
|
334
|
+
const rows = opts?.all
|
|
335
|
+
? usage.models
|
|
336
|
+
: usage.models.filter((m) => !/tab_|chat_/i.test(m.modelId));
|
|
337
|
+
|
|
338
|
+
if (!rows.length) {
|
|
339
|
+
lines.push("No models returned.");
|
|
340
|
+
return lines.join("\n");
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const maxId = Math.max(...rows.map((m) => m.modelId.length), 8);
|
|
344
|
+
for (const m of rows) {
|
|
345
|
+
const rem = remainingPercent(m.remainingFraction);
|
|
346
|
+
const flags = [
|
|
347
|
+
m.recommended ? "recommended" : "",
|
|
348
|
+
m.supportsThinking ? "thinking" : "",
|
|
349
|
+
m.supportsImages ? "images" : "",
|
|
350
|
+
]
|
|
351
|
+
.filter(Boolean)
|
|
352
|
+
.join(",");
|
|
353
|
+
const name = m.displayName && m.displayName !== m.modelId ? ` ${m.displayName}` : "";
|
|
354
|
+
lines.push(
|
|
355
|
+
`${m.modelId.padEnd(maxId)} rem ${rem === undefined ? " ?" : String(rem).padStart(5)}% reset ${formatReset(m.resetTime).padEnd(8)}${flags ? ` [${flags}]` : ""}${name}`,
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
lines.push("");
|
|
359
|
+
lines.push("Note: remaining % is pool-shared (not a private per-model budget).");
|
|
360
|
+
return lines.join("\n");
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
export async function resolveApiKeyFromContext(
|
|
364
|
+
ctx: ExtensionCommandContext,
|
|
365
|
+
): Promise<string | undefined> {
|
|
366
|
+
try {
|
|
367
|
+
return await ctx.modelRegistry.getApiKeyForProvider("antigravity");
|
|
368
|
+
} catch {
|
|
369
|
+
return undefined;
|
|
370
|
+
}
|
|
371
|
+
}
|