Skip to content
This repository was archived by the owner on Aug 6, 2026. It is now read-only.

fix(code): never lose a local task's initial prompt - #3396

Closed
frankh wants to merge 1 commit into
mainfrom
posthog-code/persist-initial-prompt
Closed

fix(code): never lose a local task's initial prompt#3396
frankh wants to merge 1 commit into
mainfrom
posthog-code/persist-initial-prompt

Conversation

@frankh

@frankh frankh commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Problem

When creating a local task, the initial prompt was only ever held in memory. If the agent hadn't produced its first response yet and the user looked away — the app was backgrounded, reloaded, crashed, or a transient connect/sendPrompt failure silently exhausted its retries — the prompt was lost and the task never started.

Root cause (packages/core/src/sessions/sessionService.ts):

  • createNewLocalSession stored the prompt only on the in-memory zustand session and delivered it via sendPrompt; the session store has no persistence.
  • client.createTaskRun was called with no options, so the deliverable prompt never reached the server either.
  • On reload the store is wiped; task.latest_run.id still exists, so the resume path (routeLocalConnectresume-existingreconnectToLocalSession) never re-sent the prompt.

Fix

Persist the prompt durably in the workspace-server task_metadata SQLite table, keyed by task id, and wire re-send/clear into the local session flow:

  • Schema: nullable pendingInitialPrompt column on task_metadata + migration 0017.
  • workspace-server / host-router: repo getter + patch field, WorkspaceMetadataService set/get/clear passthroughs, Zod schemas, and one-line tRPC forwards.
  • core sessionService:
    • Write the prompt (JSON ContentBlock[]) right after the task run is created, before spawning the agent — never aborting creation on a persistence failure.
    • On resume, resendPendingPromptIfNeeded re-sends the stored prompt unless the replayed log already contains the session/prompt echo (the agent's "received it" signal, preventing double-send).
    • Clear the durable copy on the prompt echo in handleSessionEvent, independent of in-memory state.
    • clearSessionError falls back to the durable copy so Retry and the silent auto-retry path recover after a reload.

Cloud tasks are unaffected — they self-fetch their prompt server-side and never enter createNewLocalSession.

Testing

  • pnpm typecheck (core, workspace-server, host-router): clean.
  • Biome lint on all three packages: clean, zero noRestrictedImports.
  • Full suites pass (2380 tests), including new task-metadata-repository.test.ts (round-trip / clear / non-clobbering) and initialPromptPersistence.test.ts (echo-detection, resend-once, clear-on-echo, durable retry fallback).

Created with PostHog Code

@trunk-io

trunk-io Bot commented Jul 13, 2026

Copy link
Copy Markdown

Merging to main in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here

@greptile-apps

greptile-apps Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Reviews (1): Last reviewed commit: "fix(code): never lose a local task's ini..." | Re-trigger Greptile

Comment on lines 708 to +716
auth,
logResult,
);
if (reconnected) {
await this.resendPendingPromptIfNeeded(
taskId,
convertStoredEntriesToEvents(logResult.rawEntries),
);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Prompt Echo Race Resends

When reconnectToLocalSession subscribes to live events before this replay check runs, a delayed live session/prompt echo can start clearing the durable prompt while resendPendingPromptIfNeeded still sees the old replayed log without that echo. Because the clear is fire-and-forget, the durable read can still return the prompt and send it again, causing the local task to process the initial prompt twice.

The initial prompt for a local task was only held in memory, so if the
agent hadn't produced its first response yet and the user looked away
(app backgrounded, reloaded, crashed, or a transient connect failure
exhausted its silent retries), the prompt was lost and the task never
started.

Persist the prompt durably in the workspace-server task_metadata table
keyed by task id the moment the task run is created, re-send it on
resume when the agent hasn't consumed it (detected via the session/prompt
echo in the replayed log), and clear it once consumed. clearSessionError
now falls back to the durable copy so Retry and auto-retry recover after
a reload wiped the in-memory session.

Cloud tasks are unaffected — they self-fetch their prompt server-side.

Generated-By: PostHog Code
Task-Id: a4d03ce4-bd03-46db-8893-8a110e54e865
@frankh
frankh force-pushed the posthog-code/persist-initial-prompt branch from f4d9f22 to e4d21d3 Compare July 14, 2026 15:49
@github-actions

Copy link
Copy Markdown

React Doctor found no issues in the changed files. 🎉

Reviewed by React Doctor for commit e4d21d3.

@github-actions

Copy link
Copy Markdown

This PR has had no activity for 7 days and has been marked stale. We are moving to the monorepo and tightening PR staleness in preparation, so it will be closed in 7 days if no further activity occurs.

@github-actions github-actions Bot added the stale No recent changes to PR label Jul 22, 2026
@charlesvien

Copy link
Copy Markdown
Member

Closing stale PRs ahead of Friday's monorepo migration. If this is a mistake, rebase and reopen for review.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

stale No recent changes to PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants