From dbaf505d5929daf1fbfe729eb8735af97408b767 Mon Sep 17 00:00:00 2001 From: allocsys <225476909+allocsys@users.noreply.github.com> Date: Wed, 9 Sep 2026 05:19:08 +0330 Subject: [PATCH 1/5] Raise EDITOR_HARD_MAX_STEPS default 30 -> 40 --- config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.js b/config.js index e47be6f..bafbdbe 100644 --- a/config.js +++ b/config.js @@ -343,7 +343,7 @@ export const EDITOR_MAX_FILES_PER_RUN = Number(process.env.EDITOR_MAX_FILES_P export const EDITOR_MAX_WRITES_PER_FILE = Number(process.env.EDITOR_MAX_WRITES_PER_FILE) || 5; export const EDITOR_MAX_VALIDATE_CALLS = Number(process.env.EDITOR_MAX_VALIDATE_CALLS) || 5; export const EDITOR_DEFAULT_STEPS = Number(process.env.EDITOR_DEFAULT_STEPS) || 20; -export const EDITOR_HARD_MAX_STEPS = Number(process.env.EDITOR_HARD_MAX_STEPS) || 30; +export const EDITOR_HARD_MAX_STEPS = Number(process.env.EDITOR_HARD_MAX_STEPS) || 40; export const EDITOR_AGENT_ENABLED = process.env.EDITOR_AGENT_ENABLED !== "false"; // Async delegate_editor -- mirrors the AGENT_WORKER_URL/ From 881231e6a34c4a7c055446a38cc73be13527ecb9 Mon Sep 17 00:00:00 2001 From: allocsys <225476909+allocsys@users.noreply.github.com> Date: Wed, 9 Sep 2026 05:19:14 +0330 Subject: [PATCH 2/5] Raise delegate_agent HARD_MAX_STEPS 30 -> 40 --- connectors/delegate/agent/agent_delegate.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/connectors/delegate/agent/agent_delegate.js b/connectors/delegate/agent/agent_delegate.js index 29e4180..8ad2d0d 100644 --- a/connectors/delegate/agent/agent_delegate.js +++ b/connectors/delegate/agent/agent_delegate.js @@ -55,7 +55,7 @@ import { DEFAULT_OWNER } from "../../../config.js"; import { getDelegateHooks } from "../provider_hooks.js"; import { appendTask, buildAgentPreamble } from "../shared/preamble.js"; -const HARD_MAX_STEPS = 30; +const HARD_MAX_STEPS = 40; export const HISTORY_FULL_DETAIL_STEPS = 3; export const COMPACTION_CHAR_THRESHOLD = 500; From a444de66c2148640a1e53c15d94d6b8cc23ab77d Mon Sep 17 00:00:00 2001 From: allocsys <225476909+allocsys@users.noreply.github.com> Date: Wed, 9 Sep 2026 05:19:39 +0330 Subject: [PATCH 3/5] Update delegate_agent tool description/error text: hard cap 30 -> 40 --- connectors/delegate/agent/agent_tools.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/connectors/delegate/agent/agent_tools.js b/connectors/delegate/agent/agent_tools.js index d9e99ff..709d879 100644 --- a/connectors/delegate/agent/agent_tools.js +++ b/connectors/delegate/agent/agent_tools.js @@ -18,7 +18,7 @@ export function register(server) { "POLLING vs PUSHING (async/QStash mode only -- see below): to just check progress on a resume_run_id, call with NO max_steps -- this is always read-only, even in the rare case where the background worker chain has stalled (you'll get a 'stalled' status instead of a stored answer, never a silent extra step). Only pass max_steps when you actually want to advance the investigation further right now (raising the ceiling on a resumed run, or nudging a stalled one forward) -- an explicit max_steps is what authorizes real work to happen on that call. This distinction only applies when the async worker is configured; in synchronous mode there is no separate poll state at all -- every resume_run_id call continues the loop immediately regardless of max_steps, same as always.", { task: z.string().optional().describe("The investigation task/question, described with enough context (repo names, time ranges, etc.) for Gemini to act without needing to ask you anything back -- it can't. Ignored when resume_run_id resolves to a live checkpoint (the original task from that run is reused). Optional ONLY when resume_run_id is given and its checkpoint is still live; required otherwise -- omitting it on a fresh run (no resume_run_id, or an expired one) returns an error rather than silently proceeding with no task."), - max_steps: z.number().optional().describe("Max tool-use turns Gemini gets before being forced to answer (default 20, hard cap 30 regardless of this value). LEAVE UNSET on a fresh call -- there's no reliable way to size this upfront from the task description alone, and an undersized guess just causes the investigation to hit the cap before it's actually done. Only pass an explicit value when RESUMING a run that already came back reporting it hit its step cap (the failed run's own reported step count, plus its transcript, is real evidence for how many more steps are needed -- use that, not a fresh guess). On a resumed run this is the new ceiling, not additional steps on top of what's already done. IN ASYNC/QSTASH MODE: leave unset to just poll a resume_run_id for status -- omitting max_steps guarantees the call is read-only (never drives a step), even if the background worker chain has stalled; pass it explicitly only when you want this call to actually push the investigation forward. In synchronous mode this distinction doesn't apply -- every resume_run_id call runs synchronously regardless."), + max_steps: z.number().optional().describe("Max tool-use turns Gemini gets before being forced to answer (default 20, hard cap 40 regardless of this value). LEAVE UNSET on a fresh call -- there's no reliable way to size this upfront from the task description alone, and an undersized guess just causes the investigation to hit the cap before it's actually done. Only pass an explicit value when RESUMING a run that already came back reporting it hit its step cap (the failed run's own reported step count, plus its transcript, is real evidence for how many more steps are needed -- use that, not a fresh guess). On a resumed run this is the new ceiling, not additional steps on top of what's already done. IN ASYNC/QSTASH MODE: leave unset to just poll a resume_run_id for status -- omitting max_steps guarantees the call is read-only (never drives a step), even if the background worker chain has stalled; pass it explicitly only when you want this call to actually push the investigation forward. In synchronous mode this distinction doesn't apply -- every resume_run_id call runs synchronously regardless."), log_to_notion: z.boolean().optional().describe("Whether to log the task, step-by-step tool calls, and final answer as a page under the Gemini section of Notion (default: false). Write always targets the fixed Gemini root page. ASYNC CAVEAT: not persisted across calls -- the initial fire-and-forget start call ignores this and returns before logging ever runs, so it must be passed again as true on the resume_run_id call(s) that actually retrieve the final answer, or nothing gets logged."), resume_run_id: z.string().optional().describe("A runId returned from a previous failed/partial delegate_agent call. If its checkpoint is still live (1 hour TTL), continues that run's conversation instead of starting fresh."), show_transcript: z.boolean().optional().describe("Include the full step-by-step tool-call transcript in the response, even on a successful run (default: false). Useful for debugging what Gemini actually called and in what order/grouping -- e.g. checking whether independent calls were batched into the same step. On a failed/partial run the transcript is only included if this flag is explicitly true."), @@ -74,7 +74,7 @@ export function register(server) { // "defined", since max_steps is always defined now post-default. if (maxStepsProvided && (!Number.isInteger(max_steps) || max_steps < 1)) { return { - content: [{ type: "text", text: `Invalid max_steps: ${max_steps}. Must be a positive integer (at least 1); the hard cap is 30 regardless of a larger value.` }], + content: [{ type: "text", text: `Invalid max_steps: ${max_steps}. Must be a positive integer (at least 1); the hard cap is 40 regardless of a larger value.` }], isError: true, }; } From 8a76b034b10db4d1b821fc03bd1237562ea2bc2a Mon Sep 17 00:00:00 2001 From: allocsys <225476909+allocsys@users.noreply.github.com> Date: Wed, 9 Sep 2026 05:19:54 +0330 Subject: [PATCH 4/5] Fix stale README figures for delegate_agent step cap (was already stale at 6/20; now 20/40) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 179947d..738b16c 100644 --- a/README.md +++ b/README.md @@ -179,8 +179,8 @@ any in the first place. (e.g. "why is CI failing on PR #42", "summarize what changed in this repo over the last week") to Gemini (default), GLM, or Groq instead of making 5-10 separate manual tool calls. The model runs its own loop server-side across -GitHub, Cloudflare, and Notion (bounded by `max_steps`, default 6, hard cap -20) and returns one synthesized answer. Falls through an ordered model +GitHub, Cloudflare, and Notion (bounded by `max_steps`, default 20, hard cap +40) and returns one synthesized answer. Falls through an ordered model cascade (`GEMINI_MODEL` → `GEMINI_FALLBACK_MODELS`, `GLM_MODEL` → `GLM_FALLBACK_MODELS` across every key in `OPENROUTER_API_KEYS`, or `GROQ_MODEL` → `GROQ_FALLBACK_MODELS` across every key in `GROQ_API_KEYS`) From dbd78f0812cb0aa886fbbd8d0cc6193e0f16e161 Mon Sep 17 00:00:00 2001 From: allocsys <225476909+allocsys@users.noreply.github.com> Date: Wed, 9 Sep 2026 05:20:07 +0330 Subject: [PATCH 5/5] Update seedRun regression test for new HARD_MAX_STEPS (30 -> 40) --- test/agent-seedrun-max-steps-regression.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/agent-seedrun-max-steps-regression.test.js b/test/agent-seedrun-max-steps-regression.test.js index 7415d93..8c75444 100644 --- a/test/agent-seedrun-max-steps-regression.test.js +++ b/test/agent-seedrun-max-steps-regression.test.js @@ -75,11 +75,11 @@ describe("agent_delegate.js — seedRun pins overallMaxSteps to the caller's req expect(checkpoint.overallMaxSteps).toBe(25); }); - it("max_steps above HARD_MAX_STEPS (30) is clamped down to 30, not passed through raw", async () => { + it("max_steps above HARD_MAX_STEPS (40) is clamped down to 40, not passed through raw", async () => { const runId = await seedRun({ task: "huge task", provider: "gemini", max_steps: 999 }); const checkpoint = await loadCheckpoint(runId); - expect(checkpoint.overallMaxSteps).toBe(30); + expect(checkpoint.overallMaxSteps).toBe(40); }); it("omitting max_steps entirely still falls back to seedRun's own documented default of 20 (this is the ONE place 20 should ever come from)", async () => {