Skip to content

feat: add firebase ailogic:providers CLI commands#10778

Closed
marb2000 wants to merge 8 commits into
firebase:mainfrom
marb2000:feat/ailogic-providers
Closed

feat: add firebase ailogic:providers CLI commands#10778
marb2000 wants to merge 8 commits into
firebase:mainfrom
marb2000:feat/ailogic-providers

Conversation

@marb2000

@marb2000 marb2000 commented Jul 8, 2026

Copy link
Copy Markdown
Member

Description

Adds the firebase ailogic:providers:* command group to manage the Gemini API providers for Firebase AI Logic from the CLI, so developers and CI pipelines can enable, disable, and inspect providers without using the Firebase Console.

  • ailogic:providers:enable <providerType> — enables the Firebase AI Logic API (firebasevertexai.googleapis.com) if needed, then the selected provider's underlying API. gemini-developer-api enables generativelanguage.googleapis.com; agent-platform-gemini-api requires the Blaze (pay-as-you-go) plan and enables aiplatform.googleapis.com.
  • ailogic:providers:disable <providerType> — prompts for confirmation (skippable with --force) and turns off the proxy when no providers remain enabled.
  • ailogic:providers:list — reports which providers are enabled.

Supporting changes:

  • A shared interactive enablement flow (ensureAILogicApiEnabled) used when the API isn't yet enabled, which checks the serviceusage.services.enable permission up front so callers get a clear error before any prompts.
  • firebase help <namespace> now lists the subcommands under a prefix (e.g. firebase help ailogic:providers) for discoverability.
  • ensureApiEnabled.uncacheEnabledAPI to keep the local API-enablement cache consistent after enabling/disabling an API.

All commands live under the fixed global location (no --location flag), support --json output, and reject client-breaking actions in --non-interactive mode unless --force is passed. Permissions map to the firebasevertexai and serviceusage IAM permissions.

This is the first of a series of scoped PRs bringing Firebase AI Logic management (providers, configuration, prompt templates, triggers) to the CLI.

Scenarios Tested

  • providers:enable gemini-developer-api on a project with the API disabled — enables the AI Logic API and generativelanguage.googleapis.com.
  • providers:enable agent-platform-gemini-api on a Blaze project succeeds; on a Spark project it fails with an upgrade link and does not change the plan.
  • providers:disable — confirmation prompt shown; --force and --non-interactive paths covered; proxy is disabled only when no providers remain.
  • providers:list — reflects enablement state with and without billing.
  • Interactive enablement flow — re-prompts on a Spark billing failure; fails up front when the caller lacks serviceusage.services.enable.
  • firebase help ailogic:providers — lists the namespace subcommands.
  • Unit tests added in src/gcp/ailogic.spec.ts, src/gcp/serviceusage.spec.ts, and src/commands/help.spec.ts. npm test (lint + compile + mocha) passes.

Sample Commands

firebase ailogic:providers:enable gemini-developer-api
firebase ailogic:providers:list
firebase ailogic:providers:list --json
firebase ailogic:providers:disable gemini-developer-api --force
firebase help ailogic:providers

@wiz-9635d3485b

wiz-9635d3485b Bot commented Jul 8, 2026

Copy link
Copy Markdown

Wiz Scan Summary

Scanner Findings
Vulnerability Finding Vulnerabilities -
Data Finding Sensitive Data -
Secret Finding Secrets -
IaC Misconfiguration IaC Misconfigurations -
SAST Finding SAST Findings 1 Low
Software Management Finding Software Management Findings -
Total 1 Low

View scan details in Wiz

To detect these findings earlier in the dev lifecycle, try using Wiz Code VS Code Extension.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the firebase ailogic:providers:* CLI commands (enable, disable, and list) to manage Gemini API providers, along with updates to the help command to list namespace subcommands. Feedback on these changes suggests removing the ensureAILogicApiEnabled check from the disable and list commands to prevent unnecessary enablement prompts, and removing a redundant billing check in listProviders that could cause permission issues. Additionally, the reviewer recommends simplifying the associated unit tests and replacing an any cast in help.spec.ts with a type-safe alternative to adhere to the repository's style guide.

Comment thread src/commands/ailogic-providers-disable.ts Outdated
Comment thread src/commands/ailogic-providers-list.ts Outdated
Comment thread src/gcp/ailogic.ts
Comment thread src/gcp/ailogic.spec.ts Outdated
Comment thread src/commands/help.spec.ts Outdated
Add `firebase ailogic:providers:{enable,disable,list}` to manage the
Gemini API providers (Gemini Developer API and Agent Platform Gemini API)
for Firebase AI Logic from the CLI.

- providers:enable enables the Firebase AI Logic API and the selected
  provider's underlying API; agent-platform-gemini-api requires the Blaze
  (pay-as-you-go) plan.
- providers:disable prompts for confirmation (--force to skip) and turns
  off the proxy when no providers remain enabled.
- providers:list reports which providers are enabled.
- Adds a shared interactive enablement flow (used when the API is not yet
  enabled) that checks enable permission up front before prompting.
- Adds `firebase help <namespace>` listing of subcommands under a prefix
  so ailogic commands are discoverable.

Requires the firebasevertexai and serviceusage IAM permissions; commands
support --json and --non-interactive.
@marb2000
marb2000 force-pushed the feat/ailogic-providers branch from 2efdcd1 to 79fbcdc Compare July 8, 2026 16:42
@marb2000

marb2000 commented Jul 8, 2026

Copy link
Copy Markdown
Member Author

Thanks for the review! Addressed all the feedback:

  • providers:disable / providers:list: removed the ensureAILogicApiEnabled call so these commands no longer force or prompt for API enablement — list now just reports providers as disabled and disable is a no-op prompt-free path when the API is already off.
  • listProviders billing check: removed. Since aiplatform.googleapis.com can't be enabled without billing, an enabled Vertex API already implies the agent-platform provider is available; this also avoids failures for callers without billing-viewer permission.
  • Unit tests: consolidated the two listProviders list tests into one now that billing state is irrelevant.
  • help.spec.ts any cast: replaced. Note the exact suggested cast doesn't compile (TS2352) because actionFn is a private member of Command and the types don't structurally overlap, so I used as unknown as { actionFn: ... } with a fully-specified target type — no any.

@marb2000
marb2000 force-pushed the feat/ailogic-providers branch from abc2d66 to 6621514 Compare July 8, 2026 22:52
@codecov-commenter

codecov-commenter commented Jul 8, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 54.91803% with 55 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (main@16fb909). Learn more about missing BASE report.

Files with missing lines Patch % Lines
src/gcp/ailogic.ts 54.16% 29 Missing and 4 partials ⚠️
src/commands/help.ts 59.25% 6 Missing and 5 partials ⚠️
src/commands/index.ts 0.00% 5 Missing and 1 partial ⚠️
src/ensureApiEnabled.ts 20.00% 4 Missing ⚠️
src/gcp/serviceusage.ts 91.66% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main   #10778   +/-   ##
=======================================
  Coverage        ?   58.20%           
=======================================
  Files           ?      615           
  Lines           ?    40386           
  Branches        ?     8192           
=======================================
  Hits            ?    23508           
  Misses          ?    14920           
  Partials        ?     1958           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

.before(requirePermissions, ["serviceusage.services.disable", "firebasevertexai.config.update"])
.action(async (providerType: string, options: Options) => {
const projectId = needProjectId(options);
if (providerType !== "gemini-developer-api" && providerType !== "agent-platform-gemini-api") {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be more symmetric to use "gemini-developer-api" and "gemini-agent-platform-api"

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in dc501fe. Renamed agent-platform-gemini-api to gemini-agent-platform-api everywhere, so both provider ids share the gemini- prefix. It's a CLI-facing value only (never sent to a backend), so the rename is safe.

throw new FirebaseError(
`Disabling provider ${clc.bold(providerType)} requires confirmation.\n\n` +
`To proceed in non-interactive mode, rerun with --force:\n\n` +
` firebase ailogic:providers:disable ${providerType} --force`,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Singular "provider" would be better, since this is an action on a single provider.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kept the namespace plural (ailogic:providers:*) to stay consistent with the existing CLI conventions like appdistribution:groups, firestore:databases, and database:instances, and because providers:list acts on all of them. Happy to switch if you feel strongly.

.before(requirePermissions, ["serviceusage.services.disable", "firebasevertexai.config.update"])
.action(async (providerType: string, options: Options) => {
const projectId = needProjectId(options);
if (providerType !== "gemini-developer-api" && providerType !== "agent-platform-gemini-api") {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-use ailogic.ProviderType here instead of copying

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in dc501fe. Added ailogic.parseProviderType() (plus isProviderType() and PROVIDER_TYPES) in gcp/ailogic.ts, and both commands now call it instead of copying the union.

`Invalid provider type: ${clc.bold(providerType)}. Must be 'gemini-developer-api' or 'agent-platform-gemini-api'.`,
);
}
if (options.nonInteractive && !options.force) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to disallow non-interactive without also adding --force. Generally I think one or the other would be acceptable, but if this is particularly dangerous we could do both

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the bespoke guard in dc501fe. confirm() already aborts in non-interactive mode unless --force is passed, so the behavior is now handled by the standard path with no duplicated check.

.before(requirePermissions, ["serviceusage.services.enable", "firebasevertexai.config.update"])
.action(async (providerType: string, options: Options) => {
const projectId = needProjectId(options);
if (providerType !== "gemini-developer-api" && providerType !== "agent-platform-gemini-api") {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-use ailogic.ProviderType here

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in dc501fe, same ailogic.parseProviderType() helper.

Comment thread src/commands/help.ts
matched = false;
break;
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This block is a little vague in its intent. Needs a comment to describe what the goal is here. The block below this too

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in dc501fe. Added comments to both blocks: the first walks the nested client command tree to resolve a namespace (for example ailogic:providers), and the second lists every registered command under that prefix.

Comment thread src/commands/index.ts Outdated
}
client.ailogic = {};
client.ailogic.providers = {};
client.ailogic.providers.enable = loadCommand("ailogic-providers-enable");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will need to add an experiment flag here (see "internaltesting" above as an example) until this is API council approved, since the API could change in the near term

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in dc501fe. Added an ailogic experiment and gated registration behind experiments.isEnabled("ailogic"), modeled on internaltesting. Enable it with FIREBASE_CLI_EXPERIMENTS=ailogic until the API is council-approved.

Comment thread src/gcp/ailogic.ts Outdated
"firebasevertexai.googleapis.com",
prefix,
);
ensureApiEnabled.uncacheEnabledAPI(projectId, "firebasevertexai.googleapis.com");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we call this inside the disableServiceAndPoll rather than calling it afterwards each time? Similarly to the other 4 callsites

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in dc501fe. Moved uncacheEnabledAPI into serviceusage.disableServiceAndPoll and removed the per-callsite calls (ailogic is its only caller). Added a test in serviceusage.spec.ts covering it.

Comment thread src/gcp/serviceusage.ts Outdated
export async function disableServiceAndPoll(
projectId: string,
service: string,
prefix: string,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename to logging prefix

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in dc501fe. Renamed the param to loggingPrefix.

Comment thread src/gcp/ailogic.ts Outdated
projectId: string,
providerType: ProviderType,
): Promise<void> {
const prefix = "ailogic";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: rename AILOGIC_LOGGING_PREFIX and move to top of the class

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in dc501fe. Added an exported AILOGIC_LOGGING_PREFIX constant at the top of the module and replaced the repeated "ailogic" literals with it.

- Rename provider id agent-platform-gemini-api -> gemini-agent-platform-api
  for symmetry with gemini-developer-api (paulb777).
- Centralize provider-type validation in ailogic.parseProviderType/isProviderType
  and reuse it in the enable/disable commands instead of copying the union
  (christhompsongoogle).
- Add AILOGIC_LOGGING_PREFIX constant; replace the repeated 'ailogic' literals.
- Move enablement-cache invalidation into serviceusage.disableServiceAndPoll and
  drop the per-callsite uncache calls; rename its 'prefix' param to loggingPrefix.
- Drop the redundant non-interactive guard in disable; confirm() already enforces
  --force in non-interactive mode.
- Gate the ailogic commands behind a new 'ailogic' experiment until API-council
  approval.
- Document the help.ts namespace-listing blocks.
- Update/extend unit tests accordingly.
- listProviders now reports a provider as enabled only when the Firebase
  AI Logic API (firebasevertexai.googleapis.com) is also enabled, so
  providers:list can no longer disagree with other ailogic commands about
  whether AI Logic is enabled on the project
- enableProvider enables the AI Logic API before the provider's service
  API, so a partial failure cannot land in that inconsistent state
@marb2000
marb2000 force-pushed the feat/ailogic-providers branch from 677ea38 to 5187f7a Compare July 27, 2026 04:49
@marb2000

Copy link
Copy Markdown
Member Author

While working on the config PR I found an inconsistency bug in the provider commands and fixed it here (commit 5187f7a).

Enabling a provider turns on both the provider's service API and the Firebase AI Logic API (firebasevertexai.googleapis.com), but providers:list derived provider status purely from the provider service APIs. So a project with generativelanguage.googleapis.com enabled but the AI Logic API off (enabled outside the CLI, or a partial enable failure) would report the provider as enabled while the AI Logic commands report AI Logic as disabled on the same project.

Two changes:

  • listProviders now also requires the AI Logic API to be enabled, otherwise it reports no providers.
  • enableProvider enables the AI Logic API first, so a partial failure can no longer land in that inconsistent state.

Added tests for both.

@marb2000

Copy link
Copy Markdown
Member Author

Closing in favor of #10849, which moves this to a branch on the main repo as @joehan requested. The branch is identical (all review feedback addressed, plus the provider-state consistency fix). @christhompsongoogle FYI. Review approvals unfortunately do not carry over, so a fresh stamp on #10849 would be appreciated.

@marb2000 marb2000 closed this Jul 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants