feat: command.execute returns the lifecycle pairing id ({matched, commandId?})
CommandService.execute now returns a CommandExecution — the normalized result plus the commandId minted for its command/run/command/done records — and the wire admission value carries commandId exactly when matched, so the issuing client can correlate its RPC acknowledgment with the flow node the lifecycle events produce. apiproxy api/schema/handler, the connection fixture, and the TUI/plan/goal consumers follow the new shape.
This commit is contained in:
21 files changed
+85
-55
No files matched your search
@@ -921,9 +921,13 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
|
||||
try {
|
||||
// Pure admission: the executor's durable command/run + command/done
|
||||
// pair (broadcast on the mux stream) carries the outcome; the
|
||||
// response only reports whether the line resolved to a handler.
|
||||
const result = await commands.execute(found.agent, line, signal)
|
||||
return ok(request, { matched: result !== undefined })
|
||||
// response reports whether the line resolved to a handler, plus the
|
||||
// minted pairing id so the issuing client can correlate its request
|
||||
// with the flow node the lifecycle events produce.
|
||||
const execution = await commands.execute(found.agent, line, signal)
|
||||
return ok(request, execution === undefined
|
||||
? { matched: false }
|
||||
: { matched: true, commandId: execution.commandId })
|
||||
} catch (error: unknown) {
|
||||
if (signal.aborted) return err(request, { code: 'cancelled', message: 'command execution was aborted', details: {} })
|
||||
return err(request, { code: 'internal', message: `command failed: ${String(error)}`, details: {} })
|
||||
|
||||
@@ -32,7 +32,8 @@ export const commandExecuteRequestSchema = z.object({
|
||||
line: z.string(),
|
||||
}) satisfies z.ZodType<Wire<RequestPayload<'command.execute'>>>
|
||||
|
||||
/** command.execute response value: pure admission — outcomes ride the logged lifecycle events, never this response. */
|
||||
/** command.execute response value: pure admission — outcomes ride the logged lifecycle events; commandId (present exactly when matched) correlates with them. */
|
||||
export const commandExecuteValueSchema = z.object({
|
||||
matched: z.boolean(),
|
||||
commandId: z.string().min(1).optional(),
|
||||
}) satisfies z.ZodType<Wire<ResponseValue<'command.execute'>>>
|
||||
@@ -36,10 +36,12 @@ export interface CommandsApi {
|
||||
* when syntax or name does not resolve (the client falls back to its
|
||||
* default sink). The handler's outcome does NOT ride the response: the host
|
||||
* executor durably logs the lifecycle (`command/run`/`command/done`), which
|
||||
* broadcasts on the mux stream and renders as a persistent flow node. The
|
||||
* signal rides beside the request, never on the wire: the fetch carrier's
|
||||
* request signal cancels the running handler.
|
||||
* broadcasts on the mux stream and renders as a persistent flow node.
|
||||
* `commandId` is present exactly when matched — the minted lifecycle
|
||||
* pairing id, letting the issuing client correlate this acknowledgment
|
||||
* with that flow node. The signal rides beside the request, never on the
|
||||
* wire: the fetch carrier's request signal cancels the running handler.
|
||||
*/
|
||||
execute(request: RpcRequest<{ sessionId: SessionId; line: string }>, signal: AbortSignal):
|
||||
Promise<RpcResponse<{ matched: boolean }>>
|
||||
Promise<RpcResponse<{ matched: boolean; commandId?: string }>>
|
||||
}
|
||||
Reference in New Issue
Block a user