diff --git a/connectors/delegate/agent/agent_tools.js b/connectors/delegate/agent/agent_tools.js index d9e99ff..cf2197b 100644 --- a/connectors/delegate/agent/agent_tools.js +++ b/connectors/delegate/agent/agent_tools.js @@ -14,7 +14,7 @@ export function register(server) { "NOT: web access -> use delegate_research (task param, wide mode) instead. NOT: any write -> read-only by design.\n" + "USE FOR: e.g. 'why is CI failing on PR #42', 'summarize what changed in this repo over the last week' -- cases needing 5-10+ manual cross-system calls otherwise.\n" + "RESUME: failed/partial run -> response includes resume_run_id -> pass back to continue from last completed step instead of restarting.\n" + - "ASYNC, DO NOT POLL REPEATEDLY: a fresh call may return a run_id immediately while work continues server-side. Check status with resume_run_id ONCE, then stop -- space out polls instead of hammering it; polling faster does not finish it faster. If still running, end your turn (do other work, or wait for the user's next message) and resume later. Only a resume_run_id call returns the final answer, so you must check back eventually -- just not repeatedly in the same turn.\n" + + "ASYNC: a fresh call may return a run_id immediately while work continues server-side. If still running, sleep 60 seconds before polling again if you have nothing else to do, then call again with the same resume_run_id. Only a resume_run_id call returns the final answer.\n" + "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."), diff --git a/connectors/delegate/editor/editor_tools.js b/connectors/delegate/editor/editor_tools.js index 71cccdd..c2b84e8 100644 --- a/connectors/delegate/editor/editor_tools.js +++ b/connectors/delegate/editor/editor_tools.js @@ -67,7 +67,7 @@ export function register(server) { "PREREQUISITE: `branch` MUST already exist and MUST NOT be the repo's default branch -- checked live against the GitHub API before any tool call, never trusted from the argument alone. No branch yet -> call create_branch first.\n" + "CANNOT open, approve, or merge pull requests -- this tool has no create_pull_request/merge_pull_request in its own function set, structurally, not just by convention. A human reviews the branch's diff afterward; this tool only gets it ready for that review.\n" + "RESUME: failed/partial run -> response includes resume_run_id -> pass back to continue from the last completed step instead of restarting.\n" + - "ASYNC -- DO NOT HAMMER THIS: a fresh call may return a run_id immediately while the run keeps stepping server-side in the background. Check status with resume_run_id ONCE, then STOP -- go do other work (other tasks, other tool calls, or just respond to the user) and check back later. A single step realistically takes several seconds to tens of seconds end-to-end (QStash delivery plus the step itself), so calling resume_run_id again right away, or more than once in the same turn, does not finish it any faster -- it only burns a call for the same 'still running' answer. Only a resume_run_id call returns the final result, so you do need to check back eventually -- just not immediately, and not repeatedly.\n" + + "ASYNC: a fresh call may return a run_id immediately while the run keeps stepping server-side in the background. If still running, sleep 60 seconds before polling again if you have nothing else to do, then call again with the same resume_run_id. Only a resume_run_id call returns the final result.\n" + "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 or write). Only pass max_steps when you actually want to advance the run 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 (including further commits) 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.", { owner: z.string().optional().describe(`Repository owner. Defaults to "${DEFAULT_OWNER}" if omitted.`), diff --git a/connectors/github/actions.js b/connectors/github/actions.js index 1a5ea88..991cea2 100644 --- a/connectors/github/actions.js +++ b/connectors/github/actions.js @@ -11,7 +11,7 @@ export function register(server) { server.tool( "list_workflow_runs", "List recent GitHub Actions workflow runs for a repository.\n" + - "DO NOT POLL REPEATEDLY: a queued/in-progress run takes real wall-clock time to finish (queue time plus job runtime -- often 30s to several minutes, not instant) -- calling this again immediately in a tight loop to watch a run complete does not make it finish faster, it just burns calls for the same unchanged status. Check once; if the run you care about is still queued/in_progress, space out the next check meaningfully (do other work, or end your turn and check back later) instead of re-calling this right away.", + "If the run you care about is still queued/in_progress, sleep 30 seconds before checking again if you have nothing else to do, then call this again.", { owner: z.string().optional().describe(`Repository owner. Defaults to "${DEFAULT_OWNER}" if omitted.`), repo: z.string().describe("Repository name"), diff --git a/connectors/github/ci_control.js b/connectors/github/ci_control.js index 2bd70d5..23c0fea 100644 --- a/connectors/github/ci_control.js +++ b/connectors/github/ci_control.js @@ -88,7 +88,8 @@ export function register(server) { server.tool( "get_check_runs", "DOES: Individual check/status entries (pass/fail dots) for a commit/branch/tag -- the data behind GitHub's green check / red X.\n" + - "NOT: a list of Actions runs -> use list_workflow_runs for that.", + "NOT: a list of Actions runs -> use list_workflow_runs for that.\n" + + "If checks are still pending, sleep 30 seconds before checking again if you have nothing else to do, then call this again.", { owner: z.string().optional().describe(`Repository owner. Defaults to "${DEFAULT_OWNER}" if omitted.`), repo: z.string().describe("Repository name"), @@ -108,7 +109,8 @@ export function register(server) { server.tool( "get_combined_status", - "DOES: Combined commit status for a ref -- overall pass/fail/pending rollup + each individual status context (the legacy Status API some CI systems/integrations use instead of, or alongside, Actions check-runs).", + "DOES: Combined commit status for a ref -- overall pass/fail/pending rollup + each individual status context (the legacy Status API some CI systems/integrations use instead of, or alongside, Actions check-runs).\n" + + "If the overall state is still pending, sleep 30 seconds before checking again if you have nothing else to do, then call this again.", { owner: z.string().optional().describe(`Repository owner. Defaults to "${DEFAULT_OWNER}" if omitted.`), repo: z.string().describe("Repository name"),