From 345911533b7a7527e833fb9b4e33960f46400dfc Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Mon, 7 Sep 2026 21:38:13 +0200 Subject: [PATCH] refactor(creation): name receipt inputs and tag compatibility gate --- packages/client/src/daemon-client.ts | 2 +- packages/protocol/src/messages.ts | 1 + .../src/server/request-receipts/index.ts | 46 +++++++++++-------- 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/packages/client/src/daemon-client.ts b/packages/client/src/daemon-client.ts index 38c4c20c1b..eb040bee25 100644 --- a/packages/client/src/daemon-client.ts +++ b/packages/client/src/daemon-client.ts @@ -4338,7 +4338,7 @@ export class DaemonClient { }, requestId?: string, ): Promise { - // COMPAT(workspaceRequestReceipts): added in v0.7.3; remove gate after 2027-03-07. + // COMPAT(workspaceRequestReceipts): added in v0.8.0; remove gate after 2027-03-07. if ( input.idempotencyKey !== undefined && !this.lastServerInfoMessage?.features?.workspaceRequestReceipts diff --git a/packages/protocol/src/messages.ts b/packages/protocol/src/messages.ts index 8e54cba18d..d22834849a 100644 --- a/packages/protocol/src/messages.ts +++ b/packages/protocol/src/messages.ts @@ -3481,6 +3481,7 @@ export const ServerInfoStatusPayloadSchema = z .object({ // COMPAT(agentRequestReceipts): added in v0.8.0; remove gate after 2027-03-05. agentRequestReceipts: z.boolean().optional(), + // COMPAT(workspaceRequestReceipts): added in v0.8.0; remove gate after 2027-03-07. workspaceRequestReceipts: z.boolean().optional(), // COMPAT(hubAgentRpc): added in v0.8.0; remove gate after 2027-03-05. hubAgentRpc: z.boolean().optional(), diff --git a/packages/server/src/server/request-receipts/index.ts b/packages/server/src/server/request-receipts/index.ts index 32948c7bcc..4f457710c9 100644 --- a/packages/server/src/server/request-receipts/index.ts +++ b/packages/server/src/server/request-receipts/index.ts @@ -17,18 +17,36 @@ type Receipt = z.infer & { resource: { kind: "agent" | "workspace"; id: string }; }; +interface CreateAgentInput { + key: string; + request: unknown; + findAgent: (agentId: string) => Promise; + create: (agentId: string) => Promise; +} + +interface CreateWorkspaceInput { + key: string; + request: unknown; + workspaceId: string; + findWorkspace: (workspaceId: string) => Promise; + create: (workspaceId: string) => Promise; +} + +interface SendMessageInput { + agentId: string; + messageId: string; + request: unknown; + send: () => Promise; + prepare?: () => Promise; +} + /** One daemon-owned request journal, shared by all of its socket sessions. */ export class RequestReceipts { private readonly pending = new Map>(); constructor(private readonly directory: string) {} - createAgent(input: { - key: string; - request: unknown; - findAgent: (agentId: string) => Promise; - create: (agentId: string) => Promise; - }): Promise { + createAgent(input: CreateAgentInput): Promise { return this.execute(["create", input.key], input.request, { resource: { kind: "agent", id: randomUUID() }, recover: input.findAgent, @@ -37,13 +55,7 @@ export class RequestReceipts { }); } - createWorkspace(input: { - key: string; - request: unknown; - workspaceId: string; - findWorkspace: (workspaceId: string) => Promise; - create: (workspaceId: string) => Promise; - }): Promise { + createWorkspace(input: CreateWorkspaceInput): Promise { return this.execute(["create-workspace", input.key], input.request, { resource: { kind: "workspace", id: input.workspaceId }, // A registry entry can survive failed provisioning and checkout rollback. @@ -54,13 +66,7 @@ export class RequestReceipts { }); } - async sendMessage(input: { - agentId: string; - messageId: string; - request: unknown; - send: () => Promise; - prepare?: () => Promise; - }): Promise { + async sendMessage(input: SendMessageInput): Promise { await this.execute(["send", input.agentId, input.messageId], input.request, { resource: { kind: "agent", id: input.agentId }, // A provider call can take effect before the daemon records its outcome.