mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-10 14:10:37 -07:00
feat(cli): enable skill activation via slash commands (#21758)
Co-authored-by: matt korwel <matt.korwel@gmail.com>
This commit is contained in:
@@ -12,6 +12,11 @@ export interface ToolActionReturn {
|
||||
type: 'tool';
|
||||
toolName: string;
|
||||
toolArgs: Record<string, unknown>;
|
||||
/**
|
||||
* Optional content to be submitted as a prompt to the Gemini model
|
||||
* after the tool call completes.
|
||||
*/
|
||||
postSubmitPrompt?: PartListUnion;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -164,6 +164,43 @@ describe('policy.ts', () => {
|
||||
const result = await checkPolicy(toolCall, mockConfig);
|
||||
expect(result.decision).toBe(PolicyDecision.ASK_USER);
|
||||
});
|
||||
|
||||
it('should return ALLOW if decision is ASK_USER and request is client-initiated', async () => {
|
||||
const mockPolicyEngine = {
|
||||
check: vi.fn().mockResolvedValue({ decision: PolicyDecision.ASK_USER }),
|
||||
} as unknown as Mocked<PolicyEngine>;
|
||||
|
||||
const mockConfig = {
|
||||
getPolicyEngine: vi.fn().mockReturnValue(mockPolicyEngine),
|
||||
isInteractive: vi.fn().mockReturnValue(true),
|
||||
} as unknown as Mocked<Config>;
|
||||
|
||||
const toolCall = {
|
||||
request: { name: 'test-tool', args: {}, isClientInitiated: true },
|
||||
tool: { name: 'test-tool' },
|
||||
} as ValidatingToolCall;
|
||||
|
||||
const result = await checkPolicy(toolCall, mockConfig);
|
||||
expect(result.decision).toBe(PolicyDecision.ALLOW);
|
||||
});
|
||||
|
||||
it('should still return DENY if request is client-initiated but policy says DENY', async () => {
|
||||
const mockPolicyEngine = {
|
||||
check: vi.fn().mockResolvedValue({ decision: PolicyDecision.DENY }),
|
||||
} as unknown as Mocked<PolicyEngine>;
|
||||
|
||||
const mockConfig = {
|
||||
getPolicyEngine: vi.fn().mockReturnValue(mockPolicyEngine),
|
||||
} as unknown as Mocked<Config>;
|
||||
|
||||
const toolCall = {
|
||||
request: { name: 'test-tool', args: {}, isClientInitiated: true },
|
||||
tool: { name: 'test-tool' },
|
||||
} as ValidatingToolCall;
|
||||
|
||||
const result = await checkPolicy(toolCall, mockConfig);
|
||||
expect(result.decision).toBe(PolicyDecision.DENY);
|
||||
});
|
||||
});
|
||||
|
||||
describe('updatePolicy', () => {
|
||||
|
||||
@@ -69,6 +69,19 @@ export async function checkPolicy(
|
||||
|
||||
const { decision } = result;
|
||||
|
||||
// If the tool call was initiated by the client (e.g. via a slash command),
|
||||
// we treat it as implicitly confirmed by the user and bypass the
|
||||
// confirmation prompt if the policy engine's decision is 'ASK_USER'.
|
||||
if (
|
||||
decision === PolicyDecision.ASK_USER &&
|
||||
toolCall.request.isClientInitiated
|
||||
) {
|
||||
return {
|
||||
decision: PolicyDecision.ALLOW,
|
||||
rule: result.rule,
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the full check result including the rule that matched.
|
||||
* This is necessary to access metadata like custom deny messages.
|
||||
|
||||
Reference in New Issue
Block a user