mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-04 23:44:41 +00:00
fix(creation): prevent duplicate workspaces and agents on retries (#4442)
* fix(creation): prevent duplicate workspaces and agents on retries * test(creation): cover plugin hooks across receipt replays * fix(creation): recover draft retries without accepting partial workspaces * refactor(creation): name receipt inputs and tag compatibility gate * fix(file-observer): track files announced by native change events * fix(creation): keep initial prompts in daemon-owned creation requests * fix(creation): reuse connection-owned progress and recovery * test(creation): adapt handoff gates to combined requests * ci(desktop): avoid xz compression for smoke packages * ci(desktop): pass valid RPM compression through FPM config * refactor(creation): give legacy and modern requests one identity owner * fix(creation): log observer failures without interrupting creation
This commit is contained in:
@@ -319,6 +319,36 @@ Example: adding a new enum value
|
||||
// 4. Gate the new emitted value: session.supports(CLIENT_CAPS.newThing) ? "new_value" : "old_value"
|
||||
```
|
||||
|
||||
### Creation ownership
|
||||
|
||||
Creation is owned by the daemon across socket lifetimes. A workspace request can include
|
||||
its initial agent and prompt. Workspace readiness is published before provider startup;
|
||||
the app keeps its existing disk-ready navigation and observes the remaining creation.
|
||||
Callbacks do not advance the workflow. Resource reservations in acknowledgement are
|
||||
identities, not ready workspace records.
|
||||
|
||||
The creation journal (`server/creation/`) owns identity and execution for both legacy and
|
||||
modern creation RPCs. Requesting progress never selects a different journal. Existing
|
||||
agent receipts are imported at this boundary; message delivery receipts remain separate.
|
||||
It keeps cumulative milestones and permanent IDs under an operation kind and idempotency
|
||||
key. Reconnect subscribes to that key; retries
|
||||
join active work or reuse committed stages. A persisted resource alone cannot prove
|
||||
that a provider accepted its initial prompt. Interrupted side effects with no conclusive
|
||||
receipt return an unknown outcome instead of being repeated.
|
||||
|
||||
`packages/client/src/creation/` owns capability selection and legacy orchestration.
|
||||
Callers always pass the initial prompt to agent creation. On an older host, the client
|
||||
adapts keyed creation to the legacy create/send sequence; it cannot continue that
|
||||
sequence after the client process disappears. Explicitly requested IDs or receipts
|
||||
that an old host cannot honor produce an unsupported error. Keep these adapters inside
|
||||
the client package, as an exception to the default no-fallback feature policy.
|
||||
|
||||
Creation executes through the existing Session capabilities. Connection-owned delivery
|
||||
controls observation only: detaching a socket or cleaning up its Session does not cancel
|
||||
accepted creation. Updates require an explicit subscription and go only to that socket;
|
||||
reconnect uses the shared subscription owner. Legacy consumers, including Hub, keep their
|
||||
existing response contract.
|
||||
|
||||
## Agent lifecycle
|
||||
|
||||
The lifecycle states are defined in `shared/agent-lifecycle.ts`:
|
||||
|
||||
@@ -49,6 +49,10 @@ Provider controls remain provider-native; see [providers.md](providers.md).
|
||||
`send_agent_message_request` with a stable `messageId`. Request IDs correlate individual attempts;
|
||||
creation keys and message IDs identify the operation across attempts. A creation key is daemon-wide;
|
||||
a message ID is scoped to its agent. Reusing either with different arguments is a conflict.
|
||||
`workspace.create.request.idempotencyKey` provides the same creation guarantee for directory and
|
||||
worktree workspaces; check `server_info.features.workspaceRequestReceipts` before using it.
|
||||
Workspace creation keys and agent creation keys have separate namespaces. The app keeps these keys
|
||||
for the lifetime of a draft and reuses the first message ID after failures.
|
||||
|
||||
The daemon journals the assigned agent ID before creation. Concurrent retries share one operation,
|
||||
and a retry after a lost acknowledgement or restart returns the durable agent without creating a
|
||||
|
||||
Reference in New Issue
Block a user