@rallycry/conveyor-agent 5.2.0 → 5.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -752,7 +752,7 @@ function aggregateModelUsage(modelUsage) {
752
752
  }
753
753
  return { queryInputTokens, contextWindow, totalInputTokens, totalCacheRead, totalCacheCreation };
754
754
  }
755
- function emitContextUpdate(modelUsage, host, context) {
755
+ function emitContextUpdate(modelUsage, host, context, lastAssistantUsage) {
756
756
  const usage = aggregateModelUsage(modelUsage);
757
757
  let { contextWindow } = usage;
758
758
  const settings = context.agentSettings ?? host.config.agentSettings ?? {};
@@ -761,13 +761,15 @@ function emitContextUpdate(modelUsage, host, context) {
761
761
  contextWindow = 1e6;
762
762
  }
763
763
  if (contextWindow > 0) {
764
+ const currentContextTokens = lastAssistantUsage ? (lastAssistantUsage.input_tokens ?? 0) + (lastAssistantUsage.cache_read_input_tokens ?? 0) + (lastAssistantUsage.cache_creation_input_tokens ?? 0) : usage.queryInputTokens;
764
765
  host.connection.sendEvent({
765
766
  type: "context_update",
766
- contextTokens: usage.queryInputTokens,
767
+ contextTokens: currentContextTokens,
767
768
  contextWindow,
768
769
  inputTokens: usage.totalInputTokens,
769
770
  cacheReadInputTokens: usage.totalCacheRead,
770
- cacheCreationInputTokens: usage.totalCacheCreation
771
+ cacheCreationInputTokens: usage.totalCacheCreation,
772
+ totalTokensUsed: usage.queryInputTokens
771
773
  });
772
774
  }
773
775
  }
@@ -783,7 +785,7 @@ function trackCostSpending(host, context, cumulativeTotal) {
783
785
  });
784
786
  }
785
787
  }
786
- function handleSuccessResult(event, host, context, startTime) {
788
+ function handleSuccessResult(event, host, context, startTime, lastAssistantUsage) {
787
789
  const durationMs = Date.now() - startTime;
788
790
  const summary = event.result || "Task completed.";
789
791
  const retriable = isRetriableMessage(summary);
@@ -794,28 +796,38 @@ function handleSuccessResult(event, host, context, startTime) {
794
796
  }
795
797
  host.connection.sendEvent({ type: "completed", summary, costUsd: cumulativeTotal, durationMs });
796
798
  if (modelUsage && typeof modelUsage === "object") {
797
- emitContextUpdate(modelUsage, host, context);
799
+ emitContextUpdate(modelUsage, host, context, lastAssistantUsage);
798
800
  }
799
801
  trackCostSpending(host, context, cumulativeTotal);
800
802
  return { totalCostUsd: cumulativeTotal, retriable };
801
803
  }
802
804
  function handleErrorResult(event, host) {
803
805
  const errorMsg = event.errors.length > 0 ? event.errors.join(", ") : `Agent stopped: ${event.subtype}`;
806
+ const isStaleSession = errorMsg.includes("No conversation found with session ID");
807
+ if (isStaleSession) {
808
+ return { retriable: false, staleSession: true };
809
+ }
804
810
  const retriable = isRetriableMessage(errorMsg);
805
811
  host.connection.sendEvent({ type: "error", message: errorMsg });
806
812
  return { retriable };
807
813
  }
808
- function handleResultEvent(event, host, context, startTime) {
814
+ function handleResultEvent(event, host, context, startTime, lastAssistantUsage) {
809
815
  const resultSummary = event.subtype === "success" ? event.result : event.errors.join(", ");
810
816
  if (event.subtype === "success") {
811
- const result2 = handleSuccessResult(event, host, context, startTime);
817
+ const result2 = handleSuccessResult(
818
+ event,
819
+ host,
820
+ context,
821
+ startTime,
822
+ lastAssistantUsage
823
+ );
812
824
  return { ...result2, resultSummary };
813
825
  }
814
826
  const result = handleErrorResult(event, host);
815
827
  return { totalCostUsd: 0, ...result, resultSummary };
816
828
  }
817
- async function emitResultEvent(event, host, context, startTime) {
818
- const result = handleResultEvent(event, host, context, startTime);
829
+ async function emitResultEvent(event, host, context, startTime, lastAssistantUsage) {
830
+ const result = handleResultEvent(event, host, context, startTime, lastAssistantUsage);
819
831
  const durationMs = Date.now() - startTime;
820
832
  if (event.subtype === "success") {
821
833
  const successEvent = event;
@@ -826,12 +838,16 @@ async function emitResultEvent(event, host, context, startTime) {
826
838
  costUsd: result.totalCostUsd,
827
839
  durationMs
828
840
  });
829
- } else {
841
+ } else if (!result.staleSession) {
830
842
  const errorEvent = event;
831
843
  const errorMsg = errorEvent.errors.length > 0 ? errorEvent.errors.join(", ") : `Agent stopped: ${errorEvent.subtype}`;
832
844
  await host.callbacks.onEvent({ type: "error", message: errorMsg });
833
845
  }
834
- return { retriable: result.retriable, resultSummary: result.resultSummary };
846
+ return {
847
+ retriable: result.retriable,
848
+ resultSummary: result.resultSummary,
849
+ staleSession: result.staleSession
850
+ };
835
851
  }
836
852
  function handleRateLimitEvent(event, host) {
837
853
  const { rate_limit_info } = event;
@@ -878,6 +894,8 @@ async function processEvents(events, context, host) {
878
894
  let retriable = false;
879
895
  let resultSummary;
880
896
  let rateLimitResetsAt;
897
+ let staleSession;
898
+ let lastAssistantUsage;
881
899
  const turnToolCalls = [];
882
900
  for await (const event of events) {
883
901
  if (host.isStopped()) break;
@@ -899,7 +917,12 @@ async function processEvents(events, context, host) {
899
917
  setTimeout(() => host.connection.sendTypingStart(), 200);
900
918
  isTyping = true;
901
919
  }
902
- await processAssistantEvent(event, host, turnToolCalls);
920
+ const assistantEvent = event;
921
+ await processAssistantEvent(assistantEvent, host, turnToolCalls);
922
+ const msgUsage = assistantEvent.message.usage;
923
+ if (msgUsage) {
924
+ lastAssistantUsage = msgUsage;
925
+ }
903
926
  break;
904
927
  }
905
928
  case "result": {
@@ -911,10 +934,14 @@ async function processEvents(events, context, host) {
911
934
  event,
912
935
  host,
913
936
  context,
914
- startTime
937
+ startTime,
938
+ lastAssistantUsage
915
939
  );
916
940
  retriable = resultInfo.retriable;
917
941
  resultSummary = resultInfo.resultSummary;
942
+ if (resultInfo.staleSession) {
943
+ staleSession = true;
944
+ }
918
945
  break;
919
946
  }
920
947
  case "rate_limit_event": {
@@ -927,7 +954,12 @@ async function processEvents(events, context, host) {
927
954
  if (isTyping) {
928
955
  host.connection.sendTypingStop();
929
956
  }
930
- return { retriable, resultSummary, rateLimitResetsAt };
957
+ return {
958
+ retriable,
959
+ resultSummary,
960
+ rateLimitResetsAt,
961
+ ...staleSession && { staleSession }
962
+ };
931
963
  }
932
964
 
933
965
  // src/execution/query-executor.ts
@@ -1323,7 +1355,7 @@ Your responses are sent directly to the task chat \u2014 the team sees everythin
1323
1355
  );
1324
1356
  if (!isPm || isPmActive) {
1325
1357
  parts.push(
1326
- `Use the create_pull_request tool to open PRs \u2014 do NOT use gh CLI or shell commands for PR creation.`
1358
+ `Use the mcp__conveyor__create_pull_request tool to open PRs \u2014 do NOT use gh CLI or shell commands for PR creation.`
1327
1359
  );
1328
1360
  }
1329
1361
  const modePrompt = buildModePrompt(agentMode, context);
@@ -1394,7 +1426,7 @@ Address the requested changes. Do NOT re-investigate the codebase from scratch o
1394
1426
  );
1395
1427
  } else {
1396
1428
  parts.push(
1397
- `When finished, use the create_pull_request tool to open a PR. Do NOT use gh CLI.`
1429
+ `When finished, use the mcp__conveyor__create_pull_request tool to open a PR. Do NOT use gh CLI.`
1398
1430
  );
1399
1431
  }
1400
1432
  } else {
@@ -1501,12 +1533,12 @@ function buildFreshInstructions(isPm, isAutoMode, context, agentMode) {
1501
1533
  `Your plan has been approved. Begin implementing it now.`,
1502
1534
  `Work on the git branch "${context.githubBranch}". Stay on this branch \u2014 do not checkout or create other branches.`,
1503
1535
  `Start by reading the relevant source files mentioned in the plan, then write code.`,
1504
- `When finished, commit and push your changes, then use the create_pull_request tool to open a PR. Do NOT use gh CLI.`,
1536
+ `When finished, commit and push your changes, then use the mcp__conveyor__create_pull_request tool to open a PR. Do NOT use gh CLI.`,
1505
1537
  `
1506
1538
  CRITICAL: You are in Auto mode. Do NOT report status, ask for confirmation, or go idle without making code changes.`,
1507
1539
  `Your FIRST action must be reading source files from the plan, then immediately writing code.`,
1508
1540
  `Do NOT summarize the plan or say "ready to implement" \u2014 start implementing.`,
1509
- `When all changes are committed and pushed, use create_pull_request to open a PR.`,
1541
+ `When all changes are committed and pushed, use mcp__conveyor__create_pull_request to open a PR.`,
1510
1542
  `If you are genuinely blocked, explain the specific blocker \u2014 do not go idle silently.`
1511
1543
  ];
1512
1544
  }
@@ -1540,14 +1572,14 @@ CRITICAL: You are in Auto mode. Do NOT report status, ask for confirmation, or g
1540
1572
  `Your FIRST action should be reading the relevant source files mentioned in the plan, then writing code. Do NOT run install, build, lint, test, or dev server commands first \u2014 the environment is already set up.`,
1541
1573
  `Work on the git branch "${context.githubBranch}". Stay on this branch for the entire task. Do not checkout or create other branches.`,
1542
1574
  `Your replies are visible to the team in chat \u2014 briefly describe what you're doing when you begin meaningful implementation, and again when the PR is ready.`,
1543
- `When finished, commit your changes, then run \`git fetch origin ${context.githubBranch}\` and \`git push origin ${context.githubBranch}\` (use --force-with-lease if push fails). Then use the create_pull_request tool to open a PR. Do NOT use gh CLI or any other method to create PRs.`
1575
+ `When finished, commit your changes, then run \`git fetch origin ${context.githubBranch}\` and \`git push origin ${context.githubBranch}\` (use --force-with-lease if push fails). Then use the mcp__conveyor__create_pull_request tool to open a PR. Do NOT use gh CLI or any other method to create PRs.`
1544
1576
  ];
1545
1577
  if (isAutoMode) {
1546
1578
  parts.push(
1547
1579
  `
1548
1580
  CRITICAL: You are in Auto mode. Do NOT report status, ask for confirmation, or go idle without making code changes.`,
1549
1581
  `Do NOT summarize the plan or say "ready to implement" \u2014 start implementing immediately.`,
1550
- `When all changes are committed and pushed, you MUST use create_pull_request to open a PR before finishing.`,
1582
+ `When all changes are committed and pushed, you MUST use mcp__conveyor__create_pull_request to open a PR before finishing.`,
1551
1583
  `If you are genuinely blocked, explain the specific blocker \u2014 do not go idle silently.`
1552
1584
  );
1553
1585
  }
@@ -1584,7 +1616,7 @@ Address the requested changes directly. Do NOT re-investigate the codebase from
1584
1616
  );
1585
1617
  } else {
1586
1618
  parts.push(
1587
- `When finished, use the create_pull_request tool to open a PR. Do NOT use gh CLI or any other method to create PRs.`
1619
+ `When finished, use the mcp__conveyor__create_pull_request tool to open a PR. Do NOT use gh CLI or any other method to create PRs.`
1588
1620
  );
1589
1621
  }
1590
1622
  return parts;
@@ -1896,6 +1928,30 @@ function buildGetTaskIncidentsTool(connection) {
1896
1928
  { annotations: { readOnlyHint: true } }
1897
1929
  );
1898
1930
  }
1931
+ function buildCreatePullRequestTool(connection) {
1932
+ return tool(
1933
+ "create_pull_request",
1934
+ "Create a GitHub pull request for this task. Use this instead of gh CLI or git commands to create PRs.",
1935
+ {
1936
+ title: z.string().describe("The PR title"),
1937
+ body: z.string().describe("The PR description/body in markdown")
1938
+ },
1939
+ async ({ title, body }) => {
1940
+ try {
1941
+ const result = await connection.createPR({ title, body });
1942
+ connection.sendEvent({
1943
+ type: "pr_created",
1944
+ url: result.url,
1945
+ number: result.number
1946
+ });
1947
+ return textResult(`Pull request #${result.number} created: ${result.url}`);
1948
+ } catch (error) {
1949
+ const msg = error instanceof Error ? error.message : "Unknown error";
1950
+ return textResult(`Failed to create pull request: ${msg}`);
1951
+ }
1952
+ }
1953
+ );
1954
+ }
1899
1955
  function buildCommonTools(connection, config) {
1900
1956
  return [
1901
1957
  buildReadTaskChatTool(connection),
@@ -1907,7 +1963,8 @@ function buildCommonTools(connection, config) {
1907
1963
  buildListTaskFilesTool(connection),
1908
1964
  buildGetTaskFileTool(connection),
1909
1965
  buildSearchIncidentsTool(connection),
1910
- buildGetTaskIncidentsTool(connection)
1966
+ buildGetTaskIncidentsTool(connection),
1967
+ buildCreatePullRequestTool(connection)
1911
1968
  ];
1912
1969
  }
1913
1970
 
@@ -2075,42 +2132,12 @@ function buildPackTools(connection) {
2075
2132
  ];
2076
2133
  }
2077
2134
 
2078
- // src/tools/task-tools.ts
2135
+ // src/tools/discovery-tools.ts
2079
2136
  import { tool as tool3 } from "@anthropic-ai/claude-agent-sdk";
2080
2137
  import { z as z3 } from "zod";
2081
- function buildTaskTools(connection) {
2082
- return [
2083
- tool3(
2084
- "create_pull_request",
2085
- "Create a GitHub pull request for this task. Use this instead of gh CLI or git commands to create PRs.",
2086
- {
2087
- title: z3.string().describe("The PR title"),
2088
- body: z3.string().describe("The PR description/body in markdown")
2089
- },
2090
- async ({ title, body }) => {
2091
- try {
2092
- const result = await connection.createPR({ title, body });
2093
- connection.sendEvent({
2094
- type: "pr_created",
2095
- url: result.url,
2096
- number: result.number
2097
- });
2098
- return textResult(`Pull request #${result.number} created: ${result.url}`);
2099
- } catch (error) {
2100
- const msg = error instanceof Error ? error.message : "Unknown error";
2101
- return textResult(`Failed to create pull request: ${msg}`);
2102
- }
2103
- }
2104
- )
2105
- ];
2106
- }
2107
-
2108
- // src/tools/discovery-tools.ts
2109
- import { tool as tool4 } from "@anthropic-ai/claude-agent-sdk";
2110
- import { z as z4 } from "zod";
2111
2138
  function buildIconTools(connection) {
2112
2139
  return [
2113
- tool4(
2140
+ tool3(
2114
2141
  "list_icons",
2115
2142
  "List available icons (default library + user-created). Returns icon IDs, names, and whether they're defaults. Call this FIRST before set_task_icon to check for existing matches.",
2116
2143
  {},
@@ -2126,11 +2153,11 @@ function buildIconTools(connection) {
2126
2153
  },
2127
2154
  { annotations: { readOnlyHint: true } }
2128
2155
  ),
2129
- tool4(
2156
+ tool3(
2130
2157
  "set_task_icon",
2131
2158
  "Assign an existing icon to this task by its ID. Use list_icons first to find a matching icon.",
2132
2159
  {
2133
- iconId: z4.string().describe("The icon ID to assign")
2160
+ iconId: z3.string().describe("The icon ID to assign")
2134
2161
  },
2135
2162
  async ({ iconId }) => {
2136
2163
  try {
@@ -2143,14 +2170,14 @@ function buildIconTools(connection) {
2143
2170
  }
2144
2171
  }
2145
2172
  ),
2146
- tool4(
2173
+ tool3(
2147
2174
  "generate_task_icon",
2148
2175
  "Generate a new SVG icon using AI and assign it to this task. Only use if no existing icon from list_icons is a good fit. Provide a concise visual description.",
2149
2176
  {
2150
- prompt: z4.string().describe(
2177
+ prompt: z3.string().describe(
2151
2178
  "Description of the icon to generate (e.g. 'minimal flat gear and wrench icon')"
2152
2179
  ),
2153
- aspectRatio: z4.enum(["auto", "portrait", "landscape", "square"]).optional().describe("Icon aspect ratio, defaults to square")
2180
+ aspectRatio: z3.enum(["auto", "portrait", "landscape", "square"]).optional().describe("Icon aspect ratio, defaults to square")
2154
2181
  },
2155
2182
  async ({ prompt, aspectRatio }) => {
2156
2183
  try {
@@ -2168,10 +2195,10 @@ function buildIconTools(connection) {
2168
2195
  function buildDiscoveryTools(connection, context) {
2169
2196
  const spDescription = buildStoryPointDescription(context?.storyPoints);
2170
2197
  return [
2171
- tool4(
2198
+ tool3(
2172
2199
  "set_story_points",
2173
2200
  "Set the story point estimate for this task. Use after understanding the scope of the work.",
2174
- { value: z4.number().describe(spDescription) },
2201
+ { value: z3.number().describe(spDescription) },
2175
2202
  async ({ value }) => {
2176
2203
  try {
2177
2204
  await Promise.resolve(connection.updateTaskProperties({ storyPointValue: value }));
@@ -2183,11 +2210,11 @@ function buildDiscoveryTools(connection, context) {
2183
2210
  }
2184
2211
  }
2185
2212
  ),
2186
- tool4(
2213
+ tool3(
2187
2214
  "set_task_tags",
2188
2215
  "Assign tags to this task from the project's available tags. Use the tag IDs from the project tags list.",
2189
2216
  {
2190
- tagIds: z4.array(z4.string()).describe("Array of tag IDs to assign")
2217
+ tagIds: z3.array(z3.string()).describe("Array of tag IDs to assign")
2191
2218
  },
2192
2219
  async ({ tagIds }) => {
2193
2220
  try {
@@ -2200,11 +2227,11 @@ function buildDiscoveryTools(connection, context) {
2200
2227
  }
2201
2228
  }
2202
2229
  ),
2203
- tool4(
2230
+ tool3(
2204
2231
  "set_task_title",
2205
2232
  "Update the task title to better reflect the planned work.",
2206
2233
  {
2207
- title: z4.string().describe("The new task title")
2234
+ title: z3.string().describe("The new task title")
2208
2235
  },
2209
2236
  async ({ title }) => {
2210
2237
  try {
@@ -2231,10 +2258,7 @@ function imageBlock(data, mimeType) {
2231
2258
  function getModeTools(agentMode, connection, config, context) {
2232
2259
  switch (agentMode) {
2233
2260
  case "building":
2234
- return context?.isParentTask ? [
2235
- ...buildTaskTools(connection),
2236
- ...buildPmTools(connection, context?.storyPoints, { includePackTools: true })
2237
- ] : buildTaskTools(connection);
2261
+ return context?.isParentTask ? buildPmTools(connection, context?.storyPoints, { includePackTools: true }) : [];
2238
2262
  case "review":
2239
2263
  case "auto":
2240
2264
  case "discovery":
@@ -2243,7 +2267,7 @@ function getModeTools(agentMode, connection, config, context) {
2243
2267
  includePackTools: !!context?.isParentTask
2244
2268
  });
2245
2269
  default:
2246
- return config.mode === "pm" ? buildPmTools(connection, context?.storyPoints, { includePackTools: false }) : buildTaskTools(connection);
2270
+ return config.mode === "pm" ? buildPmTools(connection, context?.storyPoints, { includePackTools: false }) : [];
2247
2271
  }
2248
2272
  }
2249
2273
  function createConveyorMcpServer(connection, config, context, agentMode) {
@@ -2696,16 +2720,15 @@ async function runWithRetry(initialQuery, context, host, options) {
2696
2720
  if (host.isStopped()) return;
2697
2721
  const agentQuery = attempt === 0 ? initialQuery : buildRetryQuery(host, context, options, lastErrorWasImage);
2698
2722
  try {
2699
- const { retriable, resultSummary, modeRestart, rateLimitResetsAt } = await processEvents(
2700
- agentQuery,
2701
- context,
2702
- host
2703
- );
2723
+ const { retriable, resultSummary, modeRestart, rateLimitResetsAt, staleSession } = await processEvents(agentQuery, context, host);
2704
2724
  if (modeRestart || host.isStopped()) return;
2705
2725
  if (rateLimitResetsAt) {
2706
2726
  handleRateLimitPause(host, rateLimitResetsAt);
2707
2727
  return;
2708
2728
  }
2729
+ if (staleSession && context.claudeSessionId) {
2730
+ return handleStaleSession(context, host, options);
2731
+ }
2709
2732
  if (!retriable) return;
2710
2733
  lastErrorWasImage = IMAGE_ERROR_PATTERN2.test(resultSummary ?? "");
2711
2734
  } catch (error) {
@@ -2925,39 +2948,6 @@ async function runSetupSafe(runnerConfig, connection, callbacks, setupLog, _effe
2925
2948
  if (!await checkoutTaskBranch(runnerConfig, connection, callbacks, setupLog)) {
2926
2949
  return { ok: false, deferredStartConfig: null };
2927
2950
  }
2928
- const taskBranch = process.env.CONVEYOR_TASK_BRANCH;
2929
- if (taskBranch) {
2930
- pushSetupLog(setupLog, `[conveyor] Switching to task branch ${taskBranch}...`);
2931
- connection.sendEvent({
2932
- type: "setup_output",
2933
- stream: "stdout",
2934
- data: `Switching to task branch ${taskBranch}...
2935
- `
2936
- });
2937
- try {
2938
- await runSetupCommand(
2939
- `git fetch origin ${taskBranch} && git checkout ${taskBranch}`,
2940
- runnerConfig.workspaceDir,
2941
- (stream, data) => {
2942
- connection.sendEvent({ type: "setup_output", stream, data });
2943
- for (const line of data.split("\n").filter(Boolean)) {
2944
- pushSetupLog(setupLog, `[${stream}] ${line}`);
2945
- }
2946
- }
2947
- );
2948
- pushSetupLog(setupLog, `[conveyor] Switched to ${taskBranch}`);
2949
- } catch (error) {
2950
- const message = `Failed to checkout ${taskBranch}: ${error instanceof Error ? error.message : "unknown error"}`;
2951
- connection.sendEvent({ type: "setup_error", message });
2952
- await callbacks.onEvent({ type: "setup_error", message });
2953
- connection.postChatMessage(
2954
- `Failed to switch to task branch \`${taskBranch}\`.
2955
-
2956
- ${message}`
2957
- );
2958
- return { ok: false, deferredStartConfig: null };
2959
- }
2960
- }
2961
2951
  const config = await loadConveyorConfig(runnerConfig.workspaceDir);
2962
2952
  if (!config) {
2963
2953
  connection.sendEvent({ type: "setup_complete" });
@@ -3295,47 +3285,38 @@ var AgentRunner = class {
3295
3285
  } catch {
3296
3286
  }
3297
3287
  }
3298
- async maybeSendPRNudge() {
3288
+ needsPRNudge() {
3299
3289
  if (!this.config.isAuto || this.stopped) return false;
3300
3290
  const maxNudges = this.taskContext?.agentSettings?.maxPrNudges ?? this.config.agentSettings?.maxPrNudges ?? 3;
3301
3291
  if (this.prNudgeCount >= maxNudges) return false;
3292
+ const status = this.taskContext?.status;
3293
+ return status === "InProgress" && !this.taskContext?.githubPRUrl;
3294
+ }
3295
+ async maybeSendPRNudge() {
3302
3296
  const fresh = await this.connection.fetchTaskContext().catch(() => null);
3303
3297
  if (fresh) this.taskContext = fresh;
3304
- const status = this.taskContext?.status;
3305
- const hasPR = !!this.taskContext?.githubPRUrl;
3306
- if (status === "InProgress" && !hasPR) {
3307
- this.prNudgeCount++;
3308
- const ctx = this.taskContext ?? fresh;
3309
- if (!ctx) return false;
3310
- if (this.prNudgeCount >= maxNudges) {
3311
- this.connection.postChatMessage(
3312
- `Auto-mode agent failed to open a PR after ${maxNudges} nudges. Shutting down.`
3313
- );
3314
- this.stop();
3315
- return true;
3316
- }
3317
- if (this.prNudgeCount === 1) {
3318
- this.connection.postChatMessage(
3319
- "Auto-nudge: Task is still In Progress with no PR. Prompting agent to continue..."
3320
- );
3321
- await this.setState("running");
3322
- await this.runQuerySafe(
3323
- ctx,
3324
- "You are in Auto mode and your task is still In Progress with no pull request. You MUST create a pull request before finishing. Use the create_pull_request tool now to open a PR for your changes. If you are blocked, explain what is preventing you from creating a PR."
3325
- );
3326
- } else {
3327
- this.connection.postChatMessage(
3328
- `Auto-nudge (attempt ${this.prNudgeCount}/${maxNudges}): Task still has no PR. Prompting agent again...`
3329
- );
3330
- await this.setState("running");
3331
- await this.runQuerySafe(
3332
- ctx,
3333
- `This is reminder ${this.prNudgeCount} of ${maxNudges}. You MUST open a pull request using create_pull_request NOW or explain what is blocking you. Do NOT go idle \u2014 either create the PR or describe the specific blocker.`
3334
- );
3335
- }
3298
+ if (!this.needsPRNudge()) return false;
3299
+ this.prNudgeCount++;
3300
+ const ctx = this.taskContext ?? fresh;
3301
+ if (!ctx) return false;
3302
+ const maxNudges = this.taskContext?.agentSettings?.maxPrNudges ?? this.config.agentSettings?.maxPrNudges ?? 3;
3303
+ if (this.prNudgeCount >= maxNudges) {
3304
+ this.connection.postChatMessage(
3305
+ `Auto-mode agent failed to open a PR after ${maxNudges} nudges. Shutting down.`
3306
+ );
3307
+ this.stop();
3336
3308
  return true;
3337
3309
  }
3338
- return false;
3310
+ await this.sendPRNudgeQuery(ctx, maxNudges);
3311
+ return true;
3312
+ }
3313
+ async sendPRNudgeQuery(ctx, maxNudges) {
3314
+ const isFirst = this.prNudgeCount === 1;
3315
+ const chatMsg = isFirst ? "Auto-nudge: Task is still In Progress with no PR. Prompting agent to continue..." : `Auto-nudge (attempt ${this.prNudgeCount}/${maxNudges}): Task still has no PR. Prompting agent again...`;
3316
+ const prompt = isFirst ? "You are in Auto mode and your task is still In Progress with no pull request. You MUST create a pull request before finishing. Use the create_pull_request tool now to open a PR for your changes. If you are blocked, explain what is preventing you from creating a PR." : `This is reminder ${this.prNudgeCount} of ${maxNudges}. You MUST open a pull request using create_pull_request NOW or explain what is blocking you. Do NOT go idle \u2014 either create the PR or describe the specific blocker.`;
3317
+ this.connection.postChatMessage(chatMsg);
3318
+ await this.setState("running");
3319
+ await this.runQuerySafe(ctx, prompt);
3339
3320
  }
3340
3321
  async executeInitialMode() {
3341
3322
  if (!this.taskContext) return;
@@ -3838,7 +3819,7 @@ var ProjectRunner = class {
3838
3819
  projectId: config.projectId
3839
3820
  });
3840
3821
  }
3841
- async checkoutWorkspaceBranch() {
3822
+ checkoutWorkspaceBranch() {
3842
3823
  const workspaceBranch = process.env.CONVEYOR_WORKSPACE_BRANCH;
3843
3824
  if (!workspaceBranch) return;
3844
3825
  try {
@@ -3853,7 +3834,7 @@ var ProjectRunner = class {
3853
3834
  }
3854
3835
  }
3855
3836
  async start() {
3856
- await this.checkoutWorkspaceBranch();
3837
+ this.checkoutWorkspaceBranch();
3857
3838
  await this.connection.connect();
3858
3839
  this.connection.onTaskAssignment((assignment) => {
3859
3840
  this.handleAssignment(assignment);
@@ -4068,4 +4049,4 @@ export {
4068
4049
  ProjectRunner,
4069
4050
  FileCache
4070
4051
  };
4071
- //# sourceMappingURL=chunk-R37YJZWE.js.map
4052
+ //# sourceMappingURL=chunk-DMWUXQ4M.js.map