-
Notifications
You must be signed in to change notification settings - Fork 4
fix: use cursor's real --resume flag and never type a resume into a live agent #426
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -589,6 +589,13 @@ const DEFAULT_HALT_IDLE_WITHOUT_DONE_DWELL_MS = 15 * 60_000; | |||||||||||||||||||||||||||||||||
| const DEFAULT_HALT_WEDGED_DWELL_MS = 120_000; | ||||||||||||||||||||||||||||||||||
| const DEFAULT_HALT_WEDGED_SWEEPS = 3; | ||||||||||||||||||||||||||||||||||
| const MAX_AUTO_REVIVE_BACKOFF_MS = 30_000; | ||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||
| * Harness responses that mean "I refused this resume command" -- a wrong flag, | ||||||||||||||||||||||||||||||||||
| * an unknown/expired session, or no such binary. Matched only against the screen | ||||||||||||||||||||||||||||||||||
| * tail that follows our own echoed resume command. | ||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||
| const RESUME_REJECTION_RE = | ||||||||||||||||||||||||||||||||||
| /\b(?:unknown option|unknown argument|unknown flag|unrecognized (?:option|argument)|unexpected argument|command not found|no rollout found|failed to resume|session not found|no such session|invalid session)\b/i; | ||||||||||||||||||||||||||||||||||
| const DONE_QUIESCENCE_MS = 1_500; | ||||||||||||||||||||||||||||||||||
| const SESSION_ID_PATTERN = | ||||||||||||||||||||||||||||||||||
| "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"; | ||||||||||||||||||||||||||||||||||
|
|
@@ -3031,6 +3038,15 @@ export class AgentEngine { | |||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| if (!evidence.ready && !evidence.activeCodex) { | ||||||||||||||||||||||||||||||||||
| this.readyPatternMatches.delete(agent.agent_id); | ||||||||||||||||||||||||||||||||||
| // A harness that rejected the resume command is a FAILED attempt, not a | ||||||||||||||||||||||||||||||||||
| // slow boot. Record it now instead of burning the boot timeout in | ||||||||||||||||||||||||||||||||||
| // silence and then retrying the identical broken command. | ||||||||||||||||||||||||||||||||||
| const rejection = this.detectResumeRejection(agent, screen.text); | ||||||||||||||||||||||||||||||||||
| if (rejection) { | ||||||||||||||||||||||||||||||||||
| const settled = this.stateMgr.updateRecord(agent.agent_id, settlement); | ||||||||||||||||||||||||||||||||||
| this.registry.set(agent.agent_id, settled); | ||||||||||||||||||||||||||||||||||
| return this.recordAutoReviveResumeFailure(settled, rejection); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| const since = Date.parse(agent.updated_at); | ||||||||||||||||||||||||||||||||||
| if ( | ||||||||||||||||||||||||||||||||||
| !Number.isNaN(since) && | ||||||||||||||||||||||||||||||||||
|
|
@@ -3484,7 +3500,7 @@ export class AgentEngine { | |||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| private async dispatchCliExitOutcome( | ||||||||||||||||||||||||||||||||||
| agent: AgentRecord, | ||||||||||||||||||||||||||||||||||
| outcome: "revived" | "unrecoverable", | ||||||||||||||||||||||||||||||||||
| outcome: "revived" | "recovered" | "unrecoverable", | ||||||||||||||||||||||||||||||||||
| ): Promise<{ record: AgentRecord; dispatched: boolean }> { | ||||||||||||||||||||||||||||||||||
| if (!agent.parent_agent_id || agent.revive_notification_sent_at) { | ||||||||||||||||||||||||||||||||||
| return { record: agent, dispatched: false }; | ||||||||||||||||||||||||||||||||||
|
|
@@ -3494,15 +3510,19 @@ export class AgentEngine { | |||||||||||||||||||||||||||||||||
| ? buildRawResumeCommand(agent.cli, agent.repo, agent.cli_session_id) | ||||||||||||||||||||||||||||||||||
| : null; | ||||||||||||||||||||||||||||||||||
| const tag = | ||||||||||||||||||||||||||||||||||
| outcome === "revived" | ||||||||||||||||||||||||||||||||||
| ? "agent_cli_exit_revived" | ||||||||||||||||||||||||||||||||||
| : "agent_cli_exit_unrecoverable"; | ||||||||||||||||||||||||||||||||||
| outcome === "unrecoverable" | ||||||||||||||||||||||||||||||||||
| ? "agent_cli_exit_unrecoverable" | ||||||||||||||||||||||||||||||||||
| : "agent_cli_exit_revived"; | ||||||||||||||||||||||||||||||||||
| const task = | ||||||||||||||||||||||||||||||||||
| outcome === "revived" | ||||||||||||||||||||||||||||||||||
| ? `Agent ${agent.agent_id} revived automatically on attempt ${attempts} ` + | ||||||||||||||||||||||||||||||||||
| `in surface ${agent.surface_id}; verified model ${agent.parsed_model ?? "unknown"}.` | ||||||||||||||||||||||||||||||||||
| : `Agent ${agent.agent_id} CLI exit is unrecoverable after ${attempts} attempts ` + | ||||||||||||||||||||||||||||||||||
| `in surface ${agent.surface_id}. Manual fallback: ${manualResumeCommand ?? "no captured session"}`; | ||||||||||||||||||||||||||||||||||
| : outcome === "recovered" | ||||||||||||||||||||||||||||||||||
| ? `Agent ${agent.agent_id} recovered in surface ${agent.surface_id} without an ` + | ||||||||||||||||||||||||||||||||||
| `engine resume after ${attempts} attempts; the pending auto-resume was ` + | ||||||||||||||||||||||||||||||||||
| `cleared before injection so nothing was typed into the live agent.` | ||||||||||||||||||||||||||||||||||
| : `Agent ${agent.agent_id} CLI exit is unrecoverable after ${attempts} attempts ` + | ||||||||||||||||||||||||||||||||||
| `in surface ${agent.surface_id}. Manual fallback: ${manualResumeCommand ?? "no captured session"}`; | ||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||
| dispatchOnce( | ||||||||||||||||||||||||||||||||||
| agent.parent_agent_id, | ||||||||||||||||||||||||||||||||||
|
|
@@ -3582,8 +3602,187 @@ export class AgentEngine { | |||||||||||||||||||||||||||||||||
| return completed; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||
| * Classify what currently occupies a revive target's surface. Auto-resume may | ||||||||||||||||||||||||||||||||||
| * only type into a bare shell: between the death signal and the injection the | ||||||||||||||||||||||||||||||||||
| * pane can be revived by other means (a human running `--resume` by hand), and | ||||||||||||||||||||||||||||||||||
| * typing then lands the resume command in a working agent's composer as if it | ||||||||||||||||||||||||||||||||||
| * were a user message. Same guard class as the interactive-overlay delivery | ||||||||||||||||||||||||||||||||||
| * refusal. | ||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||
| private async classifyReviveTarget( | ||||||||||||||||||||||||||||||||||
| agent: AgentRecord, | ||||||||||||||||||||||||||||||||||
| knownShellScreenText?: string, | ||||||||||||||||||||||||||||||||||
| ): Promise<"shell" | "live_agent" | "unverified"> { | ||||||||||||||||||||||||||||||||||
| let screenText: string; | ||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||
| screenText = | ||||||||||||||||||||||||||||||||||
| knownShellScreenText ?? (await this.readSweepScreen(agent, {})).text; | ||||||||||||||||||||||||||||||||||
| } catch { | ||||||||||||||||||||||||||||||||||
| return "unverified"; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| const parsed = parseScreen(screenText); | ||||||||||||||||||||||||||||||||||
| if (parsed.control_state === "shell") return "shell"; | ||||||||||||||||||||||||||||||||||
| if ( | ||||||||||||||||||||||||||||||||||
| parsed.control_state === "ready" || | ||||||||||||||||||||||||||||||||||
| parsed.control_state === "busy" || | ||||||||||||||||||||||||||||||||||
| parsed.control_state === "permission_prompt" || | ||||||||||||||||||||||||||||||||||
| parsed.control_state === "interactive_overlay" || | ||||||||||||||||||||||||||||||||||
| screenHasReadyAgentIdentity(agent.cli, screenText, parsed) | ||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||
| return "live_agent"; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| return "unverified"; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||
| * The pane came back without us: clear the pending resume so nothing is typed, | ||||||||||||||||||||||||||||||||||
| * and hand the record back to the ordinary boot-readiness path. | ||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||
| private async markAutoReviveRecovered( | ||||||||||||||||||||||||||||||||||
| agent: AgentRecord, | ||||||||||||||||||||||||||||||||||
| ): Promise<AgentRecord> { | ||||||||||||||||||||||||||||||||||
| let recovered = this.stateMgr.updateRecord(agent.agent_id, { | ||||||||||||||||||||||||||||||||||
| revive_last_outcome: "revived", | ||||||||||||||||||||||||||||||||||
| revive_last_error: null, | ||||||||||||||||||||||||||||||||||
| revive_next_attempt_at: null, | ||||||||||||||||||||||||||||||||||
| revive_completed_at: new Date().toISOString(), | ||||||||||||||||||||||||||||||||||
| revive_observation_source: "screen", | ||||||||||||||||||||||||||||||||||
| revive_observed_at_ms: Date.now(), | ||||||||||||||||||||||||||||||||||
| error: null, | ||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||
| this.registry.set(agent.agent_id, recovered); | ||||||||||||||||||||||||||||||||||
| const notification = await this.dispatchCliExitOutcome( | ||||||||||||||||||||||||||||||||||
| recovered, | ||||||||||||||||||||||||||||||||||
| "recovered", | ||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||
| recovered = notification.record; | ||||||||||||||||||||||||||||||||||
| this.appendAutoReviveCliExitEvent( | ||||||||||||||||||||||||||||||||||
| recovered, | ||||||||||||||||||||||||||||||||||
| "revived", | ||||||||||||||||||||||||||||||||||
| notification.dispatched, | ||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||
| const creating = this.stateMgr.transition( | ||||||||||||||||||||||||||||||||||
| recovered.agent_id, | ||||||||||||||||||||||||||||||||||
| "creating", | ||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||
| error: null, | ||||||||||||||||||||||||||||||||||
| pid: null, | ||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||
| this.registry.set(creating.agent_id, creating); | ||||||||||||||||||||||||||||||||||
| const booting = this.stateMgr.transition(creating.agent_id, "booting", { | ||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Medium
🚀 Reply "fix it for me" or copy this AI Prompt for your agent: |
||||||||||||||||||||||||||||||||||
| error: null, | ||||||||||||||||||||||||||||||||||
| pid: null, | ||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||
| this.registry.set(booting.agent_id, booting); | ||||||||||||||||||||||||||||||||||
| return booting; | ||||||||||||||||||||||||||||||||||
| } catch { | ||||||||||||||||||||||||||||||||||
| return recovered; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||
| * Hold the attempt without consuming one: we could not prove the surface is a | ||||||||||||||||||||||||||||||||||
| * bare shell, and typing on an unproven surface is the failure mode this guard | ||||||||||||||||||||||||||||||||||
| * exists to prevent. | ||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||
| private deferAutoReviveAttempt( | ||||||||||||||||||||||||||||||||||
| agent: AgentRecord, | ||||||||||||||||||||||||||||||||||
| attempt: number, | ||||||||||||||||||||||||||||||||||
| ): AgentRecord { | ||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||
| const deferred = this.stateMgr.updateRecord(agent.agent_id, { | ||||||||||||||||||||||||||||||||||
| revive_next_attempt_at: new Date( | ||||||||||||||||||||||||||||||||||
| Date.now() + this.autoReviveBackoffMs(attempt), | ||||||||||||||||||||||||||||||||||
| ).toISOString(), | ||||||||||||||||||||||||||||||||||
| revive_observation_source: "screen", | ||||||||||||||||||||||||||||||||||
| revive_observed_at_ms: Date.now(), | ||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||
| this.registry.set(agent.agent_id, deferred); | ||||||||||||||||||||||||||||||||||
| return deferred; | ||||||||||||||||||||||||||||||||||
| } catch { | ||||||||||||||||||||||||||||||||||
| return agent; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+3691
to
+3708
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift Bound the deferral so an unverifiable surface still escalates.
If Track consecutive deferrals and escalate at a cap. 🛠️ Suggested direction private deferAutoReviveAttempt(
agent: AgentRecord,
attempt: number,
- ): AgentRecord {
+ ): AgentRecord | Promise<AgentRecord> {
+ const deferrals = (agent.revive_consecutive_observations ?? 0) + 1;
+ if (deferrals > MAX_RESPAWN_ATTEMPTS) {
+ return this.markAutoReviveUnrecoverable(
+ agent,
+ "revive target surface could not be proven to be a bare shell",
+ );
+ }
try {
const deferred = this.stateMgr.updateRecord(agent.agent_id, {
revive_next_attempt_at: new Date(
- Date.now() + this.autoReviveBackoffMs(attempt),
+ Date.now() + this.autoReviveBackoffMs(deferrals),
).toISOString(),Use a dedicated counter field instead of 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||
| * The harness rejected the resume command itself (bad flag, unknown session). | ||||||||||||||||||||||||||||||||||
| * Record the failure and back off; at the cap, escalate as unrecoverable. | ||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||
| private async recordAutoReviveResumeFailure( | ||||||||||||||||||||||||||||||||||
| agent: AgentRecord, | ||||||||||||||||||||||||||||||||||
| reason: string, | ||||||||||||||||||||||||||||||||||
| ): Promise<AgentRecord> { | ||||||||||||||||||||||||||||||||||
| const attempts = agent.revive_attempts ?? 0; | ||||||||||||||||||||||||||||||||||
| let failed: AgentRecord; | ||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||
| failed = | ||||||||||||||||||||||||||||||||||
| agent.state === "error" | ||||||||||||||||||||||||||||||||||
| ? agent | ||||||||||||||||||||||||||||||||||
| : this.stateMgr.transition(agent.agent_id, "error", { | ||||||||||||||||||||||||||||||||||
| error: `Auto-revive attempt ${attempts} failed: ${reason}`, | ||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||
| failed = this.stateMgr.updateRecord(failed.agent_id, { | ||||||||||||||||||||||||||||||||||
| revive_last_outcome: "failed", | ||||||||||||||||||||||||||||||||||
| revive_last_error: reason, | ||||||||||||||||||||||||||||||||||
| revive_next_attempt_at: new Date( | ||||||||||||||||||||||||||||||||||
| Date.now() + this.autoReviveBackoffMs(Math.max(1, attempts)), | ||||||||||||||||||||||||||||||||||
| ).toISOString(), | ||||||||||||||||||||||||||||||||||
| revive_observation_source: "screen", | ||||||||||||||||||||||||||||||||||
| revive_observed_at_ms: Date.now(), | ||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||
| this.registry.set(failed.agent_id, failed); | ||||||||||||||||||||||||||||||||||
| } catch { | ||||||||||||||||||||||||||||||||||
| return agent; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| if (attempts >= MAX_RESPAWN_ATTEMPTS) { | ||||||||||||||||||||||||||||||||||
| return this.markAutoReviveUnrecoverable(failed, reason); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| return failed; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||
| * Detect a resume command the harness refused, by reading only the screen tail | ||||||||||||||||||||||||||||||||||
| * that followed our own echoed command. Returns the offending line, or null. | ||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||
| private detectResumeRejection( | ||||||||||||||||||||||||||||||||||
| agent: AgentRecord, | ||||||||||||||||||||||||||||||||||
| screenText: string, | ||||||||||||||||||||||||||||||||||
| ): string | null { | ||||||||||||||||||||||||||||||||||
| if (agent.revive_last_outcome !== "pending" || !agent.cli_session_id) { | ||||||||||||||||||||||||||||||||||
| return null; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| let resumeCommand: string; | ||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||
| resumeCommand = buildRawResumeCommand( | ||||||||||||||||||||||||||||||||||
| agent.cli, | ||||||||||||||||||||||||||||||||||
| agent.repo, | ||||||||||||||||||||||||||||||||||
| agent.cli_session_id, | ||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||
| } catch { | ||||||||||||||||||||||||||||||||||
| return null; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| const echoed = screenText.lastIndexOf(resumeCommand); | ||||||||||||||||||||||||||||||||||
| if (echoed < 0) return null; | ||||||||||||||||||||||||||||||||||
| const tail = screenText.slice(echoed + resumeCommand.length); | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+3767
to
+3769
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Match the echoed command after whitespace normalization.
Locate the echo on whitespace-stripped text and map the offset back. 🔧 Proposed fix- const echoed = screenText.lastIndexOf(resumeCommand);
- if (echoed < 0) return null;
- const tail = screenText.slice(echoed + resumeCommand.length);
+ const offsets: number[] = [];
+ let compact = "";
+ for (let i = 0; i < screenText.length; i += 1) {
+ const ch = screenText[i]!;
+ if (/\s/.test(ch)) continue;
+ compact += ch;
+ offsets.push(i);
+ }
+ const compactCommand = resumeCommand.replace(/\s+/g, "");
+ const echoed = compact.lastIndexOf(compactCommand);
+ if (echoed < 0) return null;
+ const endIndex = offsets[echoed + compactCommand.length - 1]!;
+ const tail = screenText.slice(endIndex + 1);📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||
| const parsed = parseScreen(tail); | ||||||||||||||||||||||||||||||||||
| // An agent that actually came up is not a rejected resume, whatever else | ||||||||||||||||||||||||||||||||||
| // its own output happens to say. | ||||||||||||||||||||||||||||||||||
| if (screenHasReadyAgentIdentity(agent.cli, tail, parsed)) return null; | ||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||
| tail | ||||||||||||||||||||||||||||||||||
| .split("\n") | ||||||||||||||||||||||||||||||||||
| .map((line) => line.trim()) | ||||||||||||||||||||||||||||||||||
| .filter(Boolean) | ||||||||||||||||||||||||||||||||||
| .find((line) => RESUME_REJECTION_RE.test(line)) ?? null | ||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| private async attemptSameSurfaceAutoRevive( | ||||||||||||||||||||||||||||||||||
| agent: AgentRecord, | ||||||||||||||||||||||||||||||||||
| knownShellScreenText?: string, | ||||||||||||||||||||||||||||||||||
| ): Promise<AgentRecord> { | ||||||||||||||||||||||||||||||||||
| const attempt = (agent.revive_attempts ?? 0) + 1; | ||||||||||||||||||||||||||||||||||
| if (attempt > MAX_RESPAWN_ATTEMPTS) { | ||||||||||||||||||||||||||||||||||
|
|
@@ -3599,6 +3798,13 @@ export class AgentEngine { | |||||||||||||||||||||||||||||||||
| "captured session id is missing", | ||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| const target = await this.classifyReviveTarget(agent, knownShellScreenText); | ||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟠 High
🚀 Reply "fix it for me" or copy this AI Prompt for your agent: |
||||||||||||||||||||||||||||||||||
| if (target === "live_agent") { | ||||||||||||||||||||||||||||||||||
| return this.markAutoReviveRecovered(agent); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| if (target === "unverified") { | ||||||||||||||||||||||||||||||||||
| return this.deferAutoReviveAttempt(agent, attempt); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| const attemptedAt = new Date().toISOString(); | ||||||||||||||||||||||||||||||||||
| let attempted = this.stateMgr.updateRecord(agent.agent_id, { | ||||||||||||||||||||||||||||||||||
| revive_attempts: attempt, | ||||||||||||||||||||||||||||||||||
|
|
@@ -3795,7 +4001,9 @@ export class AgentEngine { | |||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||
| this.registry.set(agent.agent_id, tracked); | ||||||||||||||||||||||||||||||||||
| this.appendAutoReviveCliExitEvent(tracked, "pending", false); | ||||||||||||||||||||||||||||||||||
| return this.attemptSameSurfaceAutoRevive(tracked); | ||||||||||||||||||||||||||||||||||
| // This sweep just proved the surface is a bare shell; reuse that read | ||||||||||||||||||||||||||||||||||
| // rather than paying for (and racing on) a second one. | ||||||||||||||||||||||||||||||||||
| return this.attemptSameSurfaceAutoRevive(tracked, screenText); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| let inboxDispatched = false; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🌐 Web query:
Cursor CLI cursor agent --resume flag documentation💡 Result:
The --resume flag in the Cursor CLI is used to continue an existing chat session by loading its prior context [1][2]. Usage Details: --resume [chatId]: Resumes a specific chat session identified by its unique ID [1][3][4]. If you do not know the ID, you can use the command cursor agent ls to list all past conversations and find the appropriate one [1][3][5]. --resume (without an ID): When used as a standalone command (or as cursor agent resume), it typically resumes the most recent chat session [3][6][4][7]. Additional Resumption Options: --continue: This is an alias for --resume=-1, which continues the most recent session [1][6][4]. /resume: This can be used within the interactive session to open recent chats and select one to resume [8][2]. By using --resume, you avoid the need to re-describe the task or context, as the agent retains the history of the previous conversation [3][2]. This functionality is particularly useful for long-running tasks or sessions that were interrupted [3][6].
Citations:
🏁 Script executed:
Repository: EtanHey/cmuxlayer
Length of output: 10997
🌐 Web query:
site:cursor.com/docs/cli "resume" "chatId" cursor agent💡 Result:
To resume a chat session with the Cursor Agent CLI, you can use several commands depending on your preference or the specific session you wish to restore: * Resume the most recent conversation: Use the command agent resume [1][2][3] or agent --continue (which acts as an alias for --resume=-1) [2][3]. * Resume a specific conversation: Use the command agent --resume="[chat-id]" [2][3]. * Browse and select from recent chats: Use the command agent ls to open a list of previous chat sessions and select one to resume [1][3]. Additionally, when interacting with the agent, you can use the /resume slash command within the interface to open and select recent chats [4][5]. Resuming a conversation restores its full context, allowing you to continue where you left off [3][5]. Subagents also persist their checkpoints when resumed, ensuring that prior work is maintained [5].
Citations:
🏁 Script executed:
Repository: EtanHey/cmuxlayer
Length of output: 18515
🌐 Web query:
Cursor CLI reference parameters exact syntax "--resume" "[chatId]" current💡 Result:
To resume a specific chat session using the Cursor CLI, use the --resume parameter followed by the chat ID [1][2][3]. The exact syntax for the command is: agent --resume [chatId] For example: agent --resume abc12345 Additional details for managing chat sessions in the Cursor CLI: - List available chats: You can find your chat IDs by running agent ls [1][4][3]. - Resume the latest chat: You can use the command agent resume [1][2][3] or the flag --continue (which is an alias for --resume=-1) [1][3]. - Context: The --resume flag loads the prior context associated with the specified thread ID, allowing you to continue an existing conversation [5][6]. Note: Depending on your installation, the command prefix may be cursor-agent [7] or simply agent [3][6]. Always ensure you have the latest version installed if commands are not recognized [3].
Citations:
Validate the target Cursor CLI version before release. Current documentation supports
cursor agent --resume [chatId], but repository tests model older versions that reject--resume.🤖 Prompt for AI Agents