-
Notifications
You must be signed in to change notification settings - Fork 1.2k
feat: add firebase ailogic:providers CLI commands #10778
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
79fbcdc
feat: add firebase ailogic:providers CLI commands
marb2000 f314b73
Merge branch 'main' into feat/ailogic-providers
marb2000 6621514
Merge branch 'main' into feat/ailogic-providers
marb2000 f93655f
Merge branch 'main' into feat/ailogic-providers
marb2000 dc501fe
fix(ailogic): address PR review feedback
marb2000 089c274
Merge remote-tracking branch 'origin/main' into feat/ailogic-providers
marb2000 4273fe0
style: format CHANGELOG.md with prettier
marb2000 5187f7a
fix(ailogic): keep provider state consistent with the AI Logic API
marb2000 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| - Added `firebase ailogic:providers:*` CLI commands to enable, disable, and list Gemini API providers. | ||
| - Add `MCP-Protocol-Version`, `Mcp-Method`, and `Mcp-Name` HTTP headers to `OneMcpServer` requests per the MCP 0728 standard release candidate (https://blog.modelcontextprotocol.io/posts/2026-07-28-release-candidate/ and https://modelcontextprotocol.io/seps/2243-http-standardization). | ||
| - Fixes Storage Emulator to support JSON uploads larger than 100KB without hanging or throwing 413 error (#8355) | ||
| - Add `extdeprecationwarnings` experiment to display phased deprecation notices and guidance across `ext:*` CLI commands. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| import { Command } from "../command"; | ||
| import { requirePermissions } from "../requirePermissions"; | ||
| import { needProjectId } from "../projectUtils"; | ||
| import * as ailogic from "../gcp/ailogic"; | ||
| import * as clc from "colorette"; | ||
| import { logger } from "../logger"; | ||
| import { FirebaseError } from "../error"; | ||
| import { confirm } from "../prompt"; | ||
|
|
||
| import { Options } from "../options"; | ||
|
|
||
| export const command = new Command("ailogic:providers:disable <providerType>") | ||
| .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) => { | ||
| const projectId = needProjectId(options); | ||
| const provider = ailogic.parseProviderType(providerType); | ||
| // confirm() aborts (throws) in non-interactive mode unless --force is set, so a | ||
| // separate non-interactive guard is unnecessary here. | ||
| const confirmed = await confirm({ | ||
| message: `You are about to disable ${clc.bold(provider)}. This will stop running apps from invoking it. Are you sure?`, | ||
| force: options.force, | ||
| nonInteractive: options.nonInteractive, | ||
| }); | ||
| if (!confirmed) { | ||
| throw new FirebaseError("Command aborted.", { exit: 1 }); | ||
| } | ||
| await ailogic.disableProvider(projectId, provider); | ||
| logger.info(clc.green(`Successfully disabled provider: ${clc.bold(provider)}`)); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| import { Command } from "../command"; | ||
| import { requirePermissions } from "../requirePermissions"; | ||
| import { needProjectId } from "../projectUtils"; | ||
| import * as ailogic from "../gcp/ailogic"; | ||
| import * as clc from "colorette"; | ||
| import { logger } from "../logger"; | ||
|
|
||
| import { Options } from "../options"; | ||
|
|
||
| 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) => { | ||
| const projectId = needProjectId(options); | ||
| const provider = ailogic.parseProviderType(providerType); | ||
| await ailogic.enableProvider(projectId, provider); | ||
| logger.info(clc.green(`Successfully enabled provider: ${clc.bold(provider)}`)); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| import { Command } from "../command"; | ||
| import { requirePermissions } from "../requirePermissions"; | ||
| import { needProjectId } from "../projectUtils"; | ||
| import * as ailogic from "../gcp/ailogic"; | ||
| import * as clc from "colorette"; | ||
| import { logger } from "../logger"; | ||
| import * as Table from "cli-table3"; | ||
|
|
||
| import { Options } from "../options"; | ||
|
|
||
| export const command = new Command("ailogic:providers:list") | ||
| .description("list which Gemini API providers are enabled") | ||
| .before(requirePermissions, ["serviceusage.services.get"]) | ||
| .action(async (options: Options) => { | ||
| const projectId = needProjectId(options); | ||
| const enabledProviders = await ailogic.listProviders(projectId); | ||
|
|
||
| if (enabledProviders.length === 0) { | ||
| logger.info(clc.bold("No Gemini API providers are enabled.")); | ||
| return enabledProviders; | ||
| } | ||
|
|
||
| const tableHead = ["Provider", "Status"]; | ||
| const table = new Table({ head: tableHead, style: { head: ["green"] } }); | ||
|
|
||
| // Show every possible provider, indicating whether it is enabled or disabled. | ||
| for (const provider of ailogic.PROVIDER_TYPES) { | ||
| const isEnabled = enabledProviders.includes(provider); | ||
| table.push([clc.bold(provider), isEnabled ? clc.green("Enabled") : clc.red("Disabled")]); | ||
| } | ||
|
|
||
| logger.info(table.toString()); | ||
| return enabledProviders; | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| import * as sinon from "sinon"; | ||
| import { expect } from "chai"; | ||
| import { command as helpCommand } from "./help"; | ||
| import { logger } from "../logger"; | ||
|
|
||
| describe("help command namespace listing", () => { | ||
| let loggerStub: sinon.SinonStub; | ||
|
|
||
| beforeEach(() => { | ||
| loggerStub = sinon.stub(logger, "info"); | ||
| }); | ||
|
|
||
| afterEach(() => { | ||
| sinon.restore(); | ||
| }); | ||
|
|
||
| it("should show help for namespace subcommands", async () => { | ||
| const mockEnableCommand = { | ||
| name: () => "ailogic:providers:enable", | ||
| description: () => "enable a provider", | ||
| outputHelp: sinon.stub(), | ||
| }; | ||
| const mockDisableCommand = { | ||
| name: () => "ailogic:providers:disable", | ||
| description: () => "disable a provider", | ||
| outputHelp: sinon.stub(), | ||
| }; | ||
|
|
||
| const mockClient = { | ||
| cli: { | ||
| commands: [mockEnableCommand, mockDisableCommand], | ||
| outputHelp: sinon.stub(), | ||
| }, | ||
| getCommand: sinon.stub().returns(undefined), | ||
| ailogic: { | ||
| providers: {}, | ||
| }, | ||
| }; | ||
|
|
||
| // Run help command action with mock context | ||
| // `actionFn` is a private member of Command; cast through `unknown` to invoke it | ||
| // directly with a mocked command context. The target type is fully specified (no `any`). | ||
| const actionFn = ( | ||
| helpCommand as unknown as { | ||
| actionFn: (this: { client: typeof mockClient }, commandName: string) => Promise<void>; | ||
| } | ||
| ).actionFn; | ||
| await actionFn.call({ client: mockClient }, "ailogic:providers"); | ||
|
|
||
| // It should log the subcommands and descriptions | ||
| expect(loggerStub).to.have.been.called; | ||
| const allArgs = loggerStub.args.map((a) => a.join(" ")).join("\n"); | ||
| expect(allArgs).to.include("Commands under ailogic:providers:"); | ||
| expect(allArgs).to.include("ailogic:providers:enable"); | ||
| expect(allArgs).to.include("enable a provider"); | ||
| expect(allArgs).to.include("ailogic:providers:disable"); | ||
| expect(allArgs).to.include("disable a provider"); | ||
| }); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.