Skip to content

catalog

WhistleCatalogInvoke = (commandId, args, signal) => Promise<WhistleJsonValue>>

Call one advertised command at its backend; resolves to a raw step.

string

WhistleJsonObject

AbortSignal

Promise<WhistleJsonValue>


WhistleCatalogV1 = ReadonlySchemaValue<z.output<typeof WhistleCatalogSchema>>>>

An advertised command catalog decoded by the maintained catalog schema.


WhistleCatalogStepV1 = ReadonlySchemaValue<z.output<typeof WhistleCatalogStepSchema>>>>

A decoded catalog response step derived from its maintained schema.

const whistleCatalogProtocol: "whistle.catalog/v1" = "whistle.catalog/v1"

The one catalog protocol this Whistle understands.


const WhistleCatalogSchema: ZodPipe<ZodObject<{ protocol: ZodLiteral<"whistle.catalog/v1">>; commands: ZodArray<ZodObject<{ id: ZodString; title: ZodString; category: ZodString; description: ZodOptional<ZodString>>; projections: ZodOptional<ZodObject<{ bindings: ZodOptional<ZodObject<…, …>>; agent: ZodOptional<ZodObject<…, …>>; help: ZodOptional<ZodObject<…, …>>; menu: ZodOptional<ZodObject<…, …>>; palette: ZodOptional<ZodObject<…, …>>; slash: ZodOptional<ZodObject<…, …>>; }, $strict>>>>; action: ZodOptional<ZodObject<{ inputSchema: ZodOptional<ZodRecord<…, …>>; outputSchema: ZodOptional<ZodRecord<…, …>>; presentation: ZodOptional<ZodUnion<…>>; }, $strict>>>>; availability: ZodOptional<ZodDiscriminatedUnion<[ZodObject<{ status: …; }, $strict>>, ZodObject<{ status: …; reason: …; }, $strict>>], "status">>>>; }, $strict>>>>; }, $strict>>, ZodTransform<Readonly<{ protocol: "whistle.catalog/v1"; commands: readonly object[]; }>, { protocol: "whistle.catalog/v1"; commands: object[]; }>>

Validate one complete Whistle catalog and its unique command ids.


const parseCatalog: typeof WhistleCatalogSchema.parse

Parse an advertised catalog at the client boundary.


const WhistleCatalogStepSchema: ZodPipe<ZodDiscriminatedUnion<[ZodObject<{ type: ZodLiteral<"done">>; notice: ZodOptional<ZodDiscriminatedUnion<[ZodObject<{ type: ZodLiteral<…>; message: ZodPipe<…, …>; links: ZodOptional<…>; }, $strict>>, ZodObject<{ type: ZodLiteral<…>; message: ZodPipe<…, …>; }, $strict>>, ZodObject<{ type: ZodLiteral<…>; url: ZodURL; code: ZodOptional<…>; message: ZodOptional<…>; }, $strict>>, ZodObject<{ type: ZodLiteral<…>; message: ZodPipe<…, …>; }, $strict>>], "type">>>>; result: ZodOptional<ZodJSONSchema>>; }, $strict>>, ZodObject<{ type: ZodLiteral<"prompt">>; prompt: ZodDiscriminatedUnion<[ZodObject<{ type: ZodLiteral<"choice">>; message: ZodPipe<ZodString, ZodString>>; collapsedGroup: ZodOptional<ZodPipe<…, …>>; options: ZodArray<ZodObject<…, …>>; }, $strict>>, ZodObject<{ type: ZodLiteral<"text">>; message: ZodPipe<ZodString, ZodString>>; placeholder: ZodOptional<ZodPipe<…, …>>; secret: ZodOptional<ZodBoolean>>; }, $strict>>, ZodObject<{ type: ZodLiteral<"confirmation">>; message: ZodPipe<ZodString, ZodString>>; confirmLabel: ZodOptional<ZodPipe<…, …>>; cancelLabel: ZodOptional<ZodPipe<…, …>>; }, $strict>>], "type">>; notice: ZodOptional<ZodDiscriminatedUnion<[ZodObject<{ type: ZodLiteral<…>; message: ZodPipe<…, …>; links: ZodOptional<…>; }, $strict>>, ZodObject<{ type: ZodLiteral<…>; message: ZodPipe<…, …>; }, $strict>>, ZodObject<{ type: ZodLiteral<…>; url: ZodURL; code: ZodOptional<…>; message: ZodOptional<…>; }, $strict>>, ZodObject<{ type: ZodLiteral<…>; message: ZodPipe<…, …>; }, $strict>>], "type">>>>; next: ZodObject<{ arguments: ZodRecord<ZodString, ZodJSONSchema>>; answer: ZodString; }, $strict>>; }, $strict>>], "type">>, ZodTransform<Readonly<{ type: "done"; notice?: { type: "info"; message: string; links?: object[]; } | { type: "progress"; message: string; } | { type: "handoff"; url: string; code?: string; message?: string; } | { type: "success"; message: string; }; result?: JSONType; }> | Readonly<{ type: "prompt"; prompt: { type: "choice"; message: string; collapsedGroup?: string; options: object[]; } | { type: "text"; message: string; placeholder?: string; secret?: boolean; } | { type: "confirmation"; message: string; confirmLabel?: string; cancelLabel?: string; }; notice?: { type: "info"; message: string; links?: object[]; } | { type: "progress"; message: string; } | { type: "handoff"; url: string; code?: string; message?: string; } | { type: "success"; message: string; }; next: { arguments: Record<string, JSONType>>; answer: string; }; }>, { type: "done"; notice?: { type: "info"; message: string; links?: object[]; } | { type: "progress"; message: string; } | { type: "handoff"; url: string; code?: string; message?: string; } | { type: "success"; message: string; }; result?: JSONType; } | { type: "prompt"; prompt: { type: "choice"; message: string; collapsedGroup?: string; options: object[]; } | { type: "text"; message: string; placeholder?: string; secret?: boolean; } | { type: "confirmation"; message: string; confirmLabel?: string; cancelLabel?: string; }; notice?: { type: "info"; message: string; links?: object[]; } | { type: "progress"; message: string; } | { type: "handoff"; url: string; code?: string; message?: string; } | { type: "success"; message: string; }; next: { arguments: Record<string, JSONType>>; answer: string; }; }>>

Validate one response step before it reaches an interaction renderer.


const parseCatalogStep: typeof WhistleCatalogStepSchema.parse

Parse one backend reply before any of it reaches a renderer.

catalogCommands(catalog, invoke): readonly Readonly<{ id: string; title: string; category: string; description?: string; projections?: { bindings?: { order?: number; values: readonly string[]; }; agent?: { keybind?: string; order?: number; }; help?: { order?: number; }; menu?: { order?: number; }; palette?: { order?: number; }; slash?: { aliases: readonly string[]; order?: number; arguments?: { hint: string; words?: readonly …[]; text?: { field: …; arguments: …; requestIdField?: …; }; }; }; }; action?: { inputSchema?: {[key: string]: string | number | boolean | readonly string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | … 4 more … | null)[] | { …; } | null)[] | { …; } | null)[] | { …; } | …[] | {[key: string]: string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | … 4 more … | null)[] | { …; } | null)[] | { …; } | null)[] | { …; } | …; } | null; }; outputSchema?: {[key: string]: string | number | boolean | readonly string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | … 4 more … | null)[] | { …; } | null)[] | { …; } | null)[] | { …; } | …[] | {[key: string]: string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | … 4 more … | null)[] | { …; } | null)[] | { …; } | null)[] | { …; } | …; } | null; }; presentation?: { type: "action"; } | { type: "custom"; data: {[key: string]: string | number | boolean | readonly string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | … 4 more … | null)[] | { …; } | null)[] | { …; } | null)[] | { …; } | …[] | {[key: string]: string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | … 4 more … | null)[] | { …; } | null)[] | { …; } | null)[] | { …; } | …; } | null; }; } | { type: "choice"; options: readonly object[]; } | { type: "form"; submitLabel?: string; } | { type: "confirmation"; message: string; confirmLabel?: string; cancelLabel?: string; }; }; availability?: () => WhistleAvailability; handler: (input) => unknown; }>[]

Turn an advertised catalog into Whistle commands. Each handler runs the backend’s step conversation through the caller’s interaction; an Agent, which has no interaction, can run only commands that finish in one step.

"whistle.catalog/v1" = whistleCatalogProtocol

readonly object[] = ...

WhistleCatalogInvoke

readonly Readonly<{ id: string; title: string; category: string; description?: string; projections?: { bindings?: { order?: number; values: readonly string[]; }; agent?: { keybind?: string; order?: number; }; help?: { order?: number; }; menu?: { order?: number; }; palette?: { order?: number; }; slash?: { aliases: readonly string[]; order?: number; arguments?: { hint: string; words?: readonly …[]; text?: { field: …; arguments: …; requestIdField?: …; }; }; }; }; action?: { inputSchema?: {[key: string]: string | number | boolean | readonly string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | … 4 more … | null)[] | { …; } | null)[] | { …; } | null)[] | { …; } | …[] | {[key: string]: string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | … 4 more … | null)[] | { …; } | null)[] | { …; } | null)[] | { …; } | …; } | null; }; outputSchema?: {[key: string]: string | number | boolean | readonly string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | … 4 more … | null)[] | { …; } | null)[] | { …; } | null)[] | { …; } | …[] | {[key: string]: string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | … 4 more … | null)[] | { …; } | null)[] | { …; } | null)[] | { …; } | …; } | null; }; presentation?: { type: "action"; } | { type: "custom"; data: {[key: string]: string | number | boolean | readonly string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | … 4 more … | null)[] | { …; } | null)[] | { …; } | null)[] | { …; } | …[] | {[key: string]: string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | … 4 more … | null)[] | { …; } | null)[] | { …; } | null)[] | { …; } | …; } | null; }; } | { type: "choice"; options: readonly object[]; } | { type: "form"; submitLabel?: string; } | { type: "confirmation"; message: string; confirmLabel?: string; cancelLabel?: string; }; }; availability?: () => WhistleAvailability; handler: (input) => unknown; }>[]