diff --git a/.github/workflows/gemini-cli-bot-brain.yml b/.github/workflows/gemini-cli-bot-brain.yml index 9390f34a7c..1971f0905b 100644 --- a/.github/workflows/gemini-cli-bot-brain.yml +++ b/.github/workflows/gemini-cli-bot-brain.yml @@ -76,6 +76,7 @@ jobs: env: GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}' GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' + GEMINI_MODEL: 'gemini-3-flash-preview' run: 'npm run brain' - name: 'Stash Brain Outputs' diff --git a/package.json b/package.json index b818ff00da..a39d30381e 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "format": "prettier --experimental-cli --write .", "typecheck": "npm run typecheck --workspaces --if-present && tsc -b evals/tsconfig.json integration-tests/tsconfig.json memory-tests/tsconfig.json", "metrics": "tsx tools/gemini-cli-bot/metrics/index.ts", - "brain": "node bundle/gemini.js tools/gemini-cli-bot/investigations/metrics_analysis.md && node bundle/gemini.js tools/gemini-cli-bot/critique/policy_evaluation.md", + "brain": "node bundle/gemini.js --policy tools/gemini-cli-bot/ci-policy.toml tools/gemini-cli-bot/investigations/metrics_analysis.md && node bundle/gemini.js --policy tools/gemini-cli-bot/ci-policy.toml tools/gemini-cli-bot/critique/policy_evaluation.md", "preflight": "npm run clean && npm ci && npm run format && npm run build && npm run lint:ci && npm run typecheck && npm run test:ci", "prepare": "husky && npm run bundle", "prepare:package": "node scripts/prepare-package.js", diff --git a/packages/core/src/agents/local-executor.ts b/packages/core/src/agents/local-executor.ts index 478521cd9e..e682cbfacb 100644 --- a/packages/core/src/agents/local-executor.ts +++ b/packages/core/src/agents/local-executor.ts @@ -7,6 +7,7 @@ import { type AgentLoopContext } from '../config/agent-loop-context.js'; import { reportError } from '../utils/errorReporting.js'; import { GeminiChat, StreamEventType } from '../core/geminiChat.js'; +import { setMaxListeners } from 'node:events'; import { type Content, type Part, @@ -84,11 +85,13 @@ import { ACTIVATE_SKILL_TOOL_NAME, UPDATE_TOPIC_TOOL_NAME, } from '../tools/definitions/base-declarations.js'; +import { AGENT_TOOL_NAME } from '../tools/tool-names.js'; /** A callback function to report on agent activity. */ export type ActivityCallback = (activity: SubagentActivityEvent) => void; const GRACE_PERIOD_MS = 60 * 1000; // 1 min +const MAX_SUBAGENT_DEPTH = 3; /** The possible outcomes of a single agent turn. */ type AgentTurnResult = @@ -130,6 +133,7 @@ export class LocalAgentExecutor { config: this.context.config, promptId: this.agentId, parentSessionId: this.context.parentSessionId || this.context.promptId, // Always preserve the main agent session ID + depth: (this.context.depth ?? 0) + 1, geminiClient: this.context.geminiClient, sandboxManager: this.context.sandboxManager, toolRegistry: this.toolRegistry, @@ -185,8 +189,12 @@ export class LocalAgentExecutor { const registerToolInstance = (tool: AnyDeclarativeTool) => { // Check if the tool is an agent tool to prevent recursion. - // We do not allow agents to call other agents. - if (tool.kind === Kind.Agent) { + // We allow a limited amount of nesting for coordinator agents. + if ( + tool.kind === Kind.Agent && + (tool.name !== AGENT_TOOL_NAME || + (context.depth ?? 0) >= MAX_SUBAGENT_DEPTH) + ) { return; } @@ -573,6 +581,14 @@ export class LocalAgentExecutor { }; // Combine the external signal with the internal timeout signal. + // We increase the limit on the parent signal to accommodate multiple concurrent subagents. + if (signal instanceof EventTarget) { + try { + setMaxListeners(100, signal); + } catch { + // Ignore if not supported in the environment + } + } const combinedSignal = AbortSignal.any([signal, deadlineTimer.signal]); logAgentStart( diff --git a/tools/gemini-cli-bot/ci-policy.toml b/tools/gemini-cli-bot/ci-policy.toml new file mode 100644 index 0000000000..e0a0fd133e --- /dev/null +++ b/tools/gemini-cli-bot/ci-policy.toml @@ -0,0 +1,16 @@ +# Custom CI Policy for Gemini CLI Bot +# This policy guarantees permission for shell commands and file writing in the bot's CI environment. + +[[rule]] +toolName = ["run_shell_command", "write_file"] +decision = "allow" +# Max priority to ensure it overrides all default and workspace rules. +priority = 999 +# Explicitly target the headless environment to match the specificity of default denial rules. +interactive = false + +[[rule]] +toolName = "invoke_agent" +decision = "deny" +priority = 999 +interactive = false diff --git a/tools/gemini-cli-bot/investigations/metrics_analysis.md b/tools/gemini-cli-bot/investigations/metrics_analysis.md index ab36b8426a..f74d970f09 100644 --- a/tools/gemini-cli-bot/investigations/metrics_analysis.md +++ b/tools/gemini-cli-bot/investigations/metrics_analysis.md @@ -81,3 +81,10 @@ Before proposing an intervention, accurately identify the blocker: cause. Ensure proposed actions align with the Repo Policy Priorities and include concepts like graceful closures and terminal escalations to prevent spam. + +### 6. Execution Constraints + +- **Do NOT use the `invoke_agent` tool.** +- **Do NOT delegate tasks to subagents (like the `generalist`).** +- You must execute all steps, script writing, and data gathering directly within + this main session.