@rallycry/conveyor-agent 4.4.0 → 4.5.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.
|
@@ -253,6 +253,10 @@ var ConveyorConnection = class _ConveyorConnection {
|
|
|
253
253
|
if (!this.socket) return;
|
|
254
254
|
this.socket.emit("agentRunner:statusUpdate", { status });
|
|
255
255
|
}
|
|
256
|
+
emitRateLimitPause(resetsAt) {
|
|
257
|
+
if (!this.socket) return;
|
|
258
|
+
this.socket.emit("agentRunner:rateLimitPause", { resetsAt });
|
|
259
|
+
}
|
|
256
260
|
sendHeartbeat() {
|
|
257
261
|
if (!this.socket) return;
|
|
258
262
|
this.socket.emit("agentRunner:heartbeat", {});
|
|
@@ -727,16 +731,19 @@ function handleRateLimitEvent(event, host) {
|
|
|
727
731
|
const { rate_limit_info } = event;
|
|
728
732
|
const status = rate_limit_info.status;
|
|
729
733
|
if (status === "rejected") {
|
|
730
|
-
const resetsAt = rate_limit_info.resetsAt ? new Date(rate_limit_info.resetsAt).toISOString() :
|
|
731
|
-
const
|
|
734
|
+
const resetsAt = rate_limit_info.resetsAt ? new Date(rate_limit_info.resetsAt).toISOString() : void 0;
|
|
735
|
+
const resetsAtDisplay = resetsAt ?? "unknown";
|
|
736
|
+
const message = `Rate limit rejected (type: ${rate_limit_info.rateLimitType ?? "unknown"}, resets at: ${resetsAtDisplay})`;
|
|
732
737
|
host.connection.sendEvent({ type: "error", message });
|
|
733
738
|
void host.callbacks.onEvent({ type: "error", message });
|
|
739
|
+
return resetsAt;
|
|
734
740
|
} else if (status === "allowed_warning") {
|
|
735
741
|
const utilization = rate_limit_info.utilization ? `${Math.round(rate_limit_info.utilization * 100)}%` : "high";
|
|
736
742
|
const message = `Rate limit warning: ${utilization} utilization (type: ${rate_limit_info.rateLimitType ?? "unknown"})`;
|
|
737
743
|
host.connection.sendEvent({ type: "thinking", message });
|
|
738
744
|
void host.callbacks.onEvent({ type: "thinking", message });
|
|
739
745
|
}
|
|
746
|
+
return void 0;
|
|
740
747
|
}
|
|
741
748
|
async function processEvents(events, context, host) {
|
|
742
749
|
const startTime = Date.now();
|
|
@@ -744,6 +751,7 @@ async function processEvents(events, context, host) {
|
|
|
744
751
|
let isTyping = false;
|
|
745
752
|
let retriable = false;
|
|
746
753
|
let resultSummary;
|
|
754
|
+
let rateLimitResetsAt;
|
|
747
755
|
const turnToolCalls = [];
|
|
748
756
|
for await (const event of events) {
|
|
749
757
|
if (host.isStopped()) break;
|
|
@@ -793,7 +801,8 @@ async function processEvents(events, context, host) {
|
|
|
793
801
|
break;
|
|
794
802
|
}
|
|
795
803
|
case "rate_limit_event": {
|
|
796
|
-
handleRateLimitEvent(event, host);
|
|
804
|
+
const resetsAt = handleRateLimitEvent(event, host);
|
|
805
|
+
if (resetsAt) rateLimitResetsAt = resetsAt;
|
|
797
806
|
break;
|
|
798
807
|
}
|
|
799
808
|
}
|
|
@@ -801,7 +810,7 @@ async function processEvents(events, context, host) {
|
|
|
801
810
|
if (isTyping) {
|
|
802
811
|
host.connection.sendTypingStop();
|
|
803
812
|
}
|
|
804
|
-
return { retriable, resultSummary };
|
|
813
|
+
return { retriable, resultSummary, rateLimitResetsAt };
|
|
805
814
|
}
|
|
806
815
|
|
|
807
816
|
// src/execution/query-executor.ts
|
|
@@ -974,16 +983,28 @@ function buildModePrompt(agentMode, context) {
|
|
|
974
983
|
## Mode: Discovery`,
|
|
975
984
|
`You are in Discovery mode \u2014 helping plan and scope this task.`,
|
|
976
985
|
`- You have read-only codebase access (can read files, run git commands, search code)`,
|
|
977
|
-
`- You
|
|
986
|
+
`- You can write plan files in .claude/plans/ only \u2014 no other file writes`,
|
|
978
987
|
`- You can create and manage subtasks`,
|
|
979
|
-
`- You cannot write code or edit files (except .claude/plans/)`,
|
|
980
988
|
`- Goal: collaborate with the user to create a clear plan`,
|
|
981
989
|
`- Proactively fill task properties (SP, tags, icon) as the plan takes shape`,
|
|
982
990
|
``,
|
|
991
|
+
`### Self-Identification Tools`,
|
|
992
|
+
`Use these MCP tools to set your own task properties:`,
|
|
993
|
+
`- \`update_task\` \u2014 save your plan and description`,
|
|
994
|
+
`- \`set_story_points\` \u2014 assign story points`,
|
|
995
|
+
`- \`set_task_title\` \u2014 set an accurate title`,
|
|
996
|
+
`- \`set_task_tags\` \u2014 categorize the work`,
|
|
997
|
+
`- \`set_task_icon\` / \`generate_task_icon\` \u2014 set a task icon (call \`list_icons\` first)`,
|
|
998
|
+
``,
|
|
983
999
|
`### Self-Update vs Subtasks`,
|
|
984
1000
|
`- If the work fits in a single task (1-3 SP), update YOUR OWN plan and properties \u2014 do not create subtasks`,
|
|
985
1001
|
`- Only create subtasks when the work genuinely requires multiple independent pieces (e.g., Pack-tier work, 8+ SP)`,
|
|
986
|
-
|
|
1002
|
+
``,
|
|
1003
|
+
`### Finishing Planning`,
|
|
1004
|
+
`Once your plan is complete and all required properties are set, call the **ExitPlanMode** tool.`,
|
|
1005
|
+
`- Required before ExitPlanMode will succeed: **plan** (via update_task), **story points** (via set_story_points), **title** (via set_task_title)`,
|
|
1006
|
+
`- ExitPlanMode validates these properties and moves the task to Open status`,
|
|
1007
|
+
`- It does NOT start building \u2014 the team controls when to switch to Build mode`
|
|
987
1008
|
];
|
|
988
1009
|
if (context) {
|
|
989
1010
|
parts.push(...buildPropertyInstructions(context));
|
|
@@ -1357,7 +1378,15 @@ ${context.plan}`);
|
|
|
1357
1378
|
}
|
|
1358
1379
|
return parts;
|
|
1359
1380
|
}
|
|
1360
|
-
function buildFreshInstructions(isPm, isAutoMode, context) {
|
|
1381
|
+
function buildFreshInstructions(isPm, isAutoMode, context, agentMode) {
|
|
1382
|
+
if (isPm && agentMode === "building") {
|
|
1383
|
+
return [
|
|
1384
|
+
`Your plan has been approved. Begin implementing it now.`,
|
|
1385
|
+
`Work on the git branch "${context.githubBranch}". Stay on this branch \u2014 do not checkout or create other branches.`,
|
|
1386
|
+
`Start by reading the relevant source files mentioned in the plan, then write code.`,
|
|
1387
|
+
`When finished, commit and push your changes, then use the create_pull_request tool to open a PR. Do NOT use gh CLI.`
|
|
1388
|
+
];
|
|
1389
|
+
}
|
|
1361
1390
|
if (isAutoMode && isPm) {
|
|
1362
1391
|
return [
|
|
1363
1392
|
`You are operating autonomously. Begin planning immediately.`,
|
|
@@ -1432,11 +1461,22 @@ function buildInstructions(mode, context, scenario, agentMode) {
|
|
|
1432
1461
|
## Instructions`];
|
|
1433
1462
|
const isPm = mode === "pm";
|
|
1434
1463
|
if (scenario === "fresh") {
|
|
1435
|
-
parts.push(...buildFreshInstructions(isPm, agentMode === "auto", context));
|
|
1464
|
+
parts.push(...buildFreshInstructions(isPm, agentMode === "auto", context, agentMode));
|
|
1436
1465
|
return parts;
|
|
1437
1466
|
}
|
|
1438
1467
|
if (scenario === "idle_relaunch") {
|
|
1439
|
-
if (isPm) {
|
|
1468
|
+
if (isPm && (agentMode === "building" || agentMode === "review")) {
|
|
1469
|
+
parts.push(
|
|
1470
|
+
`You were relaunched but no new instructions have been given since your last run.`,
|
|
1471
|
+
`Work on the git branch "${context.githubBranch}". Stay on this branch \u2014 do not checkout or create other branches.`,
|
|
1472
|
+
`Run \`git log --oneline -10\` to review what you already committed, then verify the current state is correct.`,
|
|
1473
|
+
`Reply with a brief status update summarizing where things stand (visible in chat).`,
|
|
1474
|
+
`Then wait for further instructions \u2014 do NOT redo work that was already completed.`
|
|
1475
|
+
);
|
|
1476
|
+
if (context.githubPRUrl) {
|
|
1477
|
+
parts.push(`An existing PR is open at ${context.githubPRUrl}. Do not create a new PR.`);
|
|
1478
|
+
}
|
|
1479
|
+
} else if (isPm) {
|
|
1440
1480
|
parts.push(
|
|
1441
1481
|
`You were relaunched but no new instructions have been given since your last run.`,
|
|
1442
1482
|
`You are the project manager for this task.`,
|
|
@@ -2130,6 +2170,12 @@ async function handleExitPlanMode(host, input) {
|
|
|
2130
2170
|
}
|
|
2131
2171
|
await host.connection.triggerIdentification();
|
|
2132
2172
|
host.hasExitedPlanMode = true;
|
|
2173
|
+
if (host.agentMode === "discovery") {
|
|
2174
|
+
host.connection.postChatMessage(
|
|
2175
|
+
"Task identified and moved to Open. Switch to Build mode when ready to start implementation."
|
|
2176
|
+
);
|
|
2177
|
+
return { behavior: "allow", updatedInput: input };
|
|
2178
|
+
}
|
|
2133
2179
|
const newMode = host.isParentTask ? "review" : "building";
|
|
2134
2180
|
host.pendingModeRestart = true;
|
|
2135
2181
|
if (host.onModeTransition) {
|
|
@@ -2169,7 +2215,7 @@ async function handleAskUserQuestion(host, input) {
|
|
|
2169
2215
|
}
|
|
2170
2216
|
function buildCanUseTool(host) {
|
|
2171
2217
|
return async (toolName, input) => {
|
|
2172
|
-
if (toolName === "ExitPlanMode" && host.agentMode === "auto" && !host.hasExitedPlanMode) {
|
|
2218
|
+
if (toolName === "ExitPlanMode" && (host.agentMode === "auto" || host.agentMode === "discovery") && !host.hasExitedPlanMode) {
|
|
2173
2219
|
return await handleExitPlanMode(host, input);
|
|
2174
2220
|
}
|
|
2175
2221
|
if (toolName === "AskUserQuestion") {
|
|
@@ -2235,9 +2281,6 @@ function buildSandboxConfig(host) {
|
|
|
2235
2281
|
}
|
|
2236
2282
|
};
|
|
2237
2283
|
}
|
|
2238
|
-
function isActiveBuildMode(mode, hasExitedPlanMode) {
|
|
2239
|
-
return mode === "building" || mode === "review" || mode === "auto" && hasExitedPlanMode;
|
|
2240
|
-
}
|
|
2241
2284
|
function isReadOnlyMode(mode, hasExitedPlanMode) {
|
|
2242
2285
|
return mode === "discovery" || mode === "help" || mode === "auto" && !hasExitedPlanMode;
|
|
2243
2286
|
}
|
|
@@ -2250,7 +2293,9 @@ function buildDisallowedTools(settings, mode, hasExitedPlanMode) {
|
|
|
2250
2293
|
function buildQueryOptions(host, context) {
|
|
2251
2294
|
const settings = context.agentSettings ?? host.config.agentSettings ?? {};
|
|
2252
2295
|
const mode = host.agentMode;
|
|
2253
|
-
const
|
|
2296
|
+
const isCloud = host.config.mode === "pm";
|
|
2297
|
+
const isReadOnly = isReadOnlyMode(mode, host.hasExitedPlanMode);
|
|
2298
|
+
const needsCanUseTool = isCloud && isReadOnly;
|
|
2254
2299
|
const systemPromptText = buildSystemPrompt(
|
|
2255
2300
|
host.config.mode,
|
|
2256
2301
|
context,
|
|
@@ -2268,8 +2313,8 @@ function buildQueryOptions(host, context) {
|
|
|
2268
2313
|
},
|
|
2269
2314
|
settingSources,
|
|
2270
2315
|
cwd: host.config.workspaceDir,
|
|
2271
|
-
permissionMode:
|
|
2272
|
-
allowDangerouslySkipPermissions: !
|
|
2316
|
+
permissionMode: needsCanUseTool ? "acceptEdits" : "bypassPermissions",
|
|
2317
|
+
allowDangerouslySkipPermissions: !needsCanUseTool,
|
|
2273
2318
|
canUseTool: buildCanUseTool(host),
|
|
2274
2319
|
tools: { type: "preset", preset: "claude_code" },
|
|
2275
2320
|
mcpServers: { conveyor: createConveyorMcpServer(host.connection, host.config, context) },
|
|
@@ -2282,7 +2327,7 @@ function buildQueryOptions(host, context) {
|
|
|
2282
2327
|
disallowedTools: buildDisallowedTools(settings, mode, host.hasExitedPlanMode),
|
|
2283
2328
|
enableFileCheckpointing: settings.enableFileCheckpointing
|
|
2284
2329
|
};
|
|
2285
|
-
if (
|
|
2330
|
+
if (needsCanUseTool) {
|
|
2286
2331
|
baseOptions.sandbox = buildSandboxConfig(host);
|
|
2287
2332
|
}
|
|
2288
2333
|
return baseOptions;
|
|
@@ -2452,12 +2497,23 @@ async function runWithRetry(initialQuery, context, host, options) {
|
|
|
2452
2497
|
if (host.isStopped()) return;
|
|
2453
2498
|
const agentQuery = attempt === 0 ? initialQuery : buildRetryQuery(host, context, options, lastErrorWasImage);
|
|
2454
2499
|
try {
|
|
2455
|
-
const { retriable, resultSummary, modeRestart } = await processEvents(
|
|
2500
|
+
const { retriable, resultSummary, modeRestart, rateLimitResetsAt } = await processEvents(
|
|
2456
2501
|
agentQuery,
|
|
2457
2502
|
context,
|
|
2458
2503
|
host
|
|
2459
2504
|
);
|
|
2460
|
-
if (modeRestart ||
|
|
2505
|
+
if (modeRestart || host.isStopped()) return;
|
|
2506
|
+
if (rateLimitResetsAt) {
|
|
2507
|
+
const resetMs = new Date(rateLimitResetsAt).getTime() - Date.now();
|
|
2508
|
+
if (resetMs > 5 * 6e4) {
|
|
2509
|
+
host.connection.emitRateLimitPause(rateLimitResetsAt);
|
|
2510
|
+
host.connection.postChatMessage(
|
|
2511
|
+
`Rate limited. The task will be automatically re-queued and resume after ${new Date(rateLimitResetsAt).toLocaleString()}.`
|
|
2512
|
+
);
|
|
2513
|
+
return;
|
|
2514
|
+
}
|
|
2515
|
+
}
|
|
2516
|
+
if (!retriable) return;
|
|
2461
2517
|
lastErrorWasImage = IMAGE_ERROR_PATTERN2.test(resultSummary ?? "");
|
|
2462
2518
|
} catch (error) {
|
|
2463
2519
|
if (isStaleOrExitedSession(error, context) && context.claudeSessionId) {
|
|
@@ -2748,13 +2804,8 @@ async function handleAutoModeRestart(state, connection, setState, runQuerySafe,
|
|
|
2748
2804
|
const newMode = state.agentMode;
|
|
2749
2805
|
const isParentTask = !!taskContext.isParentTask;
|
|
2750
2806
|
const newModel = getModelForMode(taskContext, newMode, isParentTask);
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
taskContext.claudeSessionId = resumeSessionId;
|
|
2754
|
-
} else {
|
|
2755
|
-
taskContext.claudeSessionId = null;
|
|
2756
|
-
connection.storeSessionId("");
|
|
2757
|
-
}
|
|
2807
|
+
taskContext.claudeSessionId = null;
|
|
2808
|
+
connection.storeSessionId("");
|
|
2758
2809
|
if (newModel) taskContext.model = newModel;
|
|
2759
2810
|
taskContext.agentMode = newMode;
|
|
2760
2811
|
connection.emitModeTransition({ fromMode: "auto", toMode: newMode ?? "building" });
|
|
@@ -3168,6 +3219,10 @@ var AgentRunner = class {
|
|
|
3168
3219
|
this.connection.postChatMessage(
|
|
3169
3220
|
`Mode switched to **${effectiveMode}**${effectiveMode === "building" ? " \u2014 I now have direct coding access." : ""}`
|
|
3170
3221
|
);
|
|
3222
|
+
if (effectiveMode === "building" && this.taskContext?.status === "Open") {
|
|
3223
|
+
this.connection.updateStatus("InProgress");
|
|
3224
|
+
this.taskContext.status = "InProgress";
|
|
3225
|
+
}
|
|
3171
3226
|
}
|
|
3172
3227
|
stop() {
|
|
3173
3228
|
this.stopped = true;
|
|
@@ -3641,4 +3696,4 @@ export {
|
|
|
3641
3696
|
ProjectRunner,
|
|
3642
3697
|
FileCache
|
|
3643
3698
|
};
|
|
3644
|
-
//# sourceMappingURL=chunk-
|
|
3699
|
+
//# sourceMappingURL=chunk-7Y3RP3ZA.js.map
|