feat(queue): queue a message with everything the composer had attached
Queueing captured only the text and files. Context chips (inline comments, terminal selections, browser annotations, PR comments and checks, quotes, linked issue/PR/Linear references, pending synthetic parts) stayed in the composer and only left with the next manual send, so a queued message the server delivered went out without them and the chips rode an unrelated message later. A queued message now carries what the composer would have sent: the text with its agent mention stripped and file mentions resolved into attachments, the attached context as structured parts, and the skill instruction derived from the text. The server delivers those parts in the composer's order, the VS Code auto-send does the same, and editing a queued message puts the chips and linked references back. A failed queue restores the composer completely. Snapshots and broadcasts omit the captured context like attachment payloads; a take returns it. Claude-Session: https://claude.ai/code/session_01HB9wdLQoZX2vfyDjwv6Rso
This commit is contained in:
@@ -284,7 +284,7 @@ Rules:
|
||||
2. If an action targets a session by ID, resolve the **session's own directory**. Do not assume the current directory is correct.
|
||||
3. `session-ui-store.ts` should delegate to `session-actions.ts` for these mutations instead of duplicating SDK calls.
|
||||
4. Sending after a revert commits the new branch optimistically: remove the reverted tail and marker before inserting the new message, and restore both if the send is rejected.
|
||||
5. Composer and queued sends carry their captured runtime, directory, and session through asynchronous preparation. A runtime change cancels the send instead of re-resolving it against the new runtime. Outside VS Code the queue itself is server-owned (`packages/web/server/lib/message-queue/`): the UI hands the server the captured send configuration at queue time and the server delivers on idle; the composer only sends a queued message itself after taking it back from the server (`takeForSend`). See the `messageQueueStore.ts` section in `stores/DOCUMENTATION.md`.
|
||||
5. Composer and queued sends carry their captured runtime, directory, and session through asynchronous preparation. A runtime change cancels the send instead of re-resolving it against the new runtime. Outside VS Code the queue itself is server-owned (`packages/web/server/lib/message-queue/`): the UI hands the server the captured send configuration, resolved text, attachments, and attached context at queue time and the server delivers on idle; the composer only sends a queued message itself after taking it back from the server (`takeForSend`). See the `messageQueueStore.ts` section in `stores/DOCUMENTATION.md`.
|
||||
6. After session creation, the directory returned by the server is authoritative over the requested draft directory. The server may canonicalize a worktree path, and the first prompt must use the same directory identity as the created session.
|
||||
7. Regular new-chat drafts that inherit the persisted current/last directory must not create a session against a confirmed-missing path. Fall back to the active project only when OpenCode reports the directory missing; keep explicit worktree targets, in-flight worktree creation, and unknown/offline probes unchanged, and do not persist the fallback until session creation succeeds. A concurrent draft rewrite to that same active-project fallback must not abort session creation.
|
||||
8. A prompt send that fails **after** the request left the client is ambiguous, never a definite failure: the server may already be answering it. Transports tag those errors (`markAmbiguousTransportFailure` in `@/lib/relay/transport-error`; the relay tunnel tags every stream that dies with a request in flight), and `isAmbiguousSendFailure` reads the tag before falling back to status/text heuristics. An ambiguous failure waits for the connection to return, refetches recent messages, and confirms the optimistic message in place instead of rolling it back — rolling it back lets the message queue re-send a prompt the engine is already running, producing two independent AI responses for one user message.
|
||||
|
||||
@@ -29,8 +29,8 @@ describe('cleanupPersistedSessionState', () => {
|
||||
// way a server snapshot would, and expect only the projection to go.
|
||||
useMessageQueueStore.setState({
|
||||
queuedMessages: {
|
||||
[getMessageQueueKey(deleted)]: [{ id: 'q-delete', content: 'delete', createdAt: 1 }],
|
||||
[getMessageQueueKey(retained)]: [{ id: 'q-retain', content: 'retain', createdAt: 1 }],
|
||||
[getMessageQueueKey(deleted)]: [{ id: 'q-delete', content: 'delete', text: 'delete', createdAt: 1 }],
|
||||
[getMessageQueueKey(retained)]: [{ id: 'q-retain', content: 'retain', text: 'retain', createdAt: 1 }],
|
||||
},
|
||||
});
|
||||
useTodosPersistStore.getState().setSessionTodos('/repo-a', 'session-1', [todo]);
|
||||
|
||||
Reference in New Issue
Block a user