feat(ailogic): add ailogic:config CLI commands#10841
Conversation
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.
- 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.
# Conflicts: # CHANGELOG.md
Add `firebase ailogic:config:get [path]` and `ailogic:config:set <path> <value>` to read and write Firebase AI Logic service configuration from the CLI. - config:get prints the full config (providers, security, monitoring) or a single value by path; it is read-only and reports "not enabled" gracefully rather than forcing API enablement. - config:set updates one setting. Tightening security.auth-only or security.template-only from false to true prompts for confirmation (--force to skip); monitoring.sample-rate-percentage is validated as an integer 1-100. - Developer-facing paths map onto the underlying config resource (trafficFilter.*, telemetryConfig.*), with sample rate stored as a fraction. Supports --json and --non-interactive.
- Bring config commands under the ailogic experiment gate (via cherry-pick of the providers review fixes) and inherit the provider rename + centralized validation. - config:get/config:set: single source of valid paths (fixes get's validate-vs-error mismatch); rename provider id to gemini-agent-platform-api. - config:set: drop the redundant non-interactive guard (confirm() enforces --force), use utils.logSuccess, extract a bool parser, validate the path before the API-enablement flow. - gcp: GLOBAL_LOCATION constant for the config resource; AILOGIC_LOGGING_PREFIX in isAILogicApiEnabled. - Add ailogic-config-get.spec.ts and ailogic-config-set.spec.ts.
- config:set validates the value before the API-enablement flow (fail-fast) and
returns a {path, value} result so --json produces output.
- config:get path traversal uses an isRecord type guard instead of an `as` cast;
provider keys/paths derive from ailogic.PROVIDER_TYPES (no duplicated literals).
- Add tests: monitoring.state=false -> NONE, template-only tightening, nested-path
get, and fail-fast-before-enablement.
Wiz Scan Summary
To detect these findings earlier in the dev lifecycle, try using Wiz Code VS Code Extension. |
There was a problem hiding this comment.
Code Review
This pull request introduces the firebase ailogic CLI command surface to manage Gemini API providers and configure AI Logic settings, including commands to enable, disable, and list providers, as well as get and set configuration values. It also updates the help command to support namespace subcommands and adds cache invalidation for disabled APIs. Feedback on the changes highlights a critical startup crash in src/commands/index.ts when the ailogic experiment is disabled because configuration commands are registered on an uninitialized client.ailogic object. Additionally, suggestions were made to parallelize API enablement checks in listProviders for better performance and to allow case-insensitive boolean parsing in parseBool for improved usability.
- Critical: register ailogic:config commands INSIDE the experiment gate; a rebase had left them outside, which crashed CLI startup for users without the ailogic experiment (client.ailogic was undefined). - parseBool accepts case-insensitive true/false. - listProviders runs its two independent enablement checks in parallel.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #10841 +/- ##
=======================================
Coverage ? 58.32%
=======================================
Files ? 617
Lines ? 40494
Branches ? 8216
=======================================
Hits ? 23618
Misses ? 14911
Partials ? 1965 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
- Remove the unused security-rules layer (generateRulesContent, getSecurityRules, updateSecurityRules, the rules import, and their tests); nothing references it. - Single source for config paths: WRITABLE_CONFIG_PATHS exported from gcp/ailogic, READABLE derived from it; shared assertKnownConfigPath error helper; shared samplingRateToPercent/percentToSamplingRate codec (both directions were hand-coded in each command). - config:get validates the path before any API call and only checks provider enablement when the requested path needs it. - config:set: buildUpdate is now the single per-path decision site (folds in the confirmation message and current-value read), the switch is exhaustive so a new path cannot silently fall into the sample-rate branch, the percentage requires a plain decimal integer (Number() also accepted hex and scientific notation), and the --json result echoes the normalized value. - ensureAILogicApiEnabled reuses isAILogicApiEnabled instead of inlining the check.
- config:set preflights serviceusage.services.get (ensureAILogicApiEnabled reads
enablement state via Service Usage; without it a cold cache surfaced a raw 403
mid-command despite passing requirePermissions).
- Echo a normalized sample-rate value ('007' -> '7') so the success message and
--json output match what was stored.
- ensureAILogicApiEnabled honors --force for its enable confirmation and the
provider selection offers a cancel choice (the Spark-plan retry loop had no
exit besides Ctrl+C).
- Strengthen provider specs: pin each provider to its own API via withArgs (a
swapped destructure passed before) and assert the disable cross-check consults
the other provider's API.
joehan
left a comment
There was a problem hiding this comment.
LGTM overall, with some simple nits
|
|
||
| export const command = new Command("ailogic:config:get [path]") | ||
| .description("read AI Logic configuration") | ||
| .before(requirePermissions, ["firebasevertexai.config.get", "serviceusage.services.get"]) |
There was a problem hiding this comment.
Please add detailed help text explaining how to use this command using the .help() method. Would be particularly nice to explain what values are allowed for [path]
There was a problem hiding this comment.
Done. Added help text listing all the readable paths (built from the path list so it stays in sync) plus an example.
| export const command = new Command("ailogic:config:set <path> <value>") | ||
| .description("set one configuration value") | ||
| .option("-f, --force", "bypass confirmation prompt") | ||
| .before(requirePermissions, [ |
There was a problem hiding this comment.
Please add detailed help text explaining how to use this command using the .help() method. Would be particularly nice to explain what values are allowed for [path]
There was a problem hiding this comment.
Done. Added help text listing each writable path with the values it accepts.
| .description("disable a Gemini API provider service") | ||
| .option("-f, --force", "bypass confirmation prompt") | ||
| .before(requirePermissions, ["serviceusage.services.disable", "firebasevertexai.config.update"]) | ||
| .action(async (providerType: string, options: Options) => { |
There was a problem hiding this comment.
Please add detailed help text explaining how to use this command using the .help() method. Would be particularly nice to explain what values are allowed for providerType
There was a problem hiding this comment.
Done. Added help text listing the valid provider types.
| export const command = new Command("ailogic:providers:enable <providerType>") | ||
| .description("enable a Gemini API provider service") | ||
| .before(requirePermissions, ["serviceusage.services.enable", "firebasevertexai.config.update"]) | ||
| .action(async (providerType: string, options: Options) => { |
There was a problem hiding this comment.
Please add detailed help text explaining how to use this command using the .help() method. Would be particularly nice to explain what values are allowed for
There was a problem hiding this comment.
Done. Added help text listing the valid provider types, noting the Blaze plan requirement for the agent platform.
| @@ -1,3 +1,5 @@ | |||
| - Added `firebase ailogic:providers:*` CLI commands to enable, disable, and list Gemini API providers. | |||
There was a problem hiding this comment.
We can omit the changelog while we are developing behind a flag - we'll add Changelogs for all when we flip the falg
There was a problem hiding this comment.
Done. Removed the changelog entries; will add them back when the flag flips.
|
One other note - please move these PRs over to a branch on the main repo. If you don't have access, go/firebase-github-access |
| } | ||
| } | ||
|
|
||
| /** |
There was a problem hiding this comment.
Remove empty comment blocks - agents love adding these for some reason
There was a problem hiding this comment.
Done. Removed both empty comment blocks. They had been added to silence a jsdoc lint warning, but it is warn-level only, so removing them is harmless.
| * Converts the API's telemetry sampling rate, a fraction in (0,1], to the | ||
| * integer percentage (1-100) the CLI exposes. | ||
| */ | ||
| export function samplingRateToPercent(samplingRate: number): number { |
There was a problem hiding this comment.
Super overkill to make this a function when it is only used once. Same with the inverse function. Also, no need to export functions that are not used elsewhere.
There was a problem hiding this comment.
Done. Removed both functions and inlined the conversions at their single call sites.
- Add detailed .help() text to ailogic:config:get/set and ailogic:providers:enable/disable documenting allowed values - Drop CHANGELOG entries while the feature is behind the experiment flag - Remove empty JSDoc blocks in gcp/ailogic.ts - Inline single-use sampling-rate conversions instead of exporting helpers
- 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
|
FYI: I found and fixed a provider-state inconsistency bug on the providers PR (details in #10778 (comment)). This branch picks the fix up via a merge commit. |
|
Closing in favor of #10850, which moves this to a branch on the main repo as @joehan requested. The branch is identical (all review nits addressed, and it carries the provider-state consistency fix via the providers branch). @christhompsongoogle FYI. Approvals do not carry over, so a fresh stamp on #10850 would be appreciated. |
Description
Adds the
firebase ailogic:config:*commands to read and modify Firebase AI Logic configuration, gated behind theailogicexperiment (same asailogic:providers).ailogic:config:get [path]reads the config. With no path it prints the whole resource; with a path it prints one value. Providers appear as read-only status derived from API enablement.ailogic:config:set <path> <value>writes one setting. Developer-facing paths map to the underlying resource fields:security.auth-only->trafficFilter.firebaseAuthRequiredsecurity.template-only->trafficFilter.templateOnlymonitoring.state->telemetryConfig.mode(ALL/NONE)monitoring.sample-rate-percentage->telemetryConfig.samplingRate(an integer percent 1-100 exposed as the API's (0,1] fraction)Tightening
security.auth-onlyorsecurity.template-onlyfrom false to true prompts for confirmation because existing clients start getting rejected;confirm()enforces--forcein non-interactive mode. Input (path and value) is validated up front, before the API-enablement flow, so bad input fails fast.Depends on #10778 (
ailogic:providers). This branch is rebased on top of that one, so until #10778 merges the diff here also shows the provider commits; once #10778 lands inmainthe diff narrows to the config-only changes automatically. Please review theailogic-config-*and config-relatedgcp/ailogic.tschanges here; the provider files are the already-approved #10778 content.Scenarios Tested
ailogic-config-get.spec.ts,ailogic-config-set.spec.ts, plusgetConfig/updateConfigingcp/ailogic.spec.ts. Covers unknown path, non-boolean and out-of-range values, false->true tightening confirmation, non-interactive-without-force, value/field mapping, nested-path reads, and fail-fast-before-enablement.npm run build,npm run lint, andtsc --noEmitare clean.FIREBASE_CLI_EXPERIMENTS=ailogic.Sample Commands