ghostykit 0.3.2 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,89 @@
1
+ // src/transport/index.ts
2
+ var PilotHttpError = class extends Error {
3
+ constructor(message, status, code, retryAfter) {
4
+ super(message);
5
+ this.name = "PilotHttpError";
6
+ this.status = status;
7
+ this.code = code;
8
+ this.retryAfter = retryAfter;
9
+ }
10
+ };
11
+ async function readSse(body, onMessage) {
12
+ const reader = body.getReader();
13
+ const decoder = new TextDecoder();
14
+ let buffer = "";
15
+ let event = "message";
16
+ let data = [];
17
+ const flush = () => {
18
+ if (data.length) onMessage({ event, data: data.join("\n") });
19
+ event = "message";
20
+ data = [];
21
+ };
22
+ for (; ; ) {
23
+ const { value, done } = await reader.read();
24
+ if (done) break;
25
+ buffer += decoder.decode(value, { stream: true });
26
+ let nl;
27
+ while ((nl = buffer.search(/\r\n|\r|\n/)) >= 0) {
28
+ const line = buffer.slice(0, nl);
29
+ buffer = buffer.slice(nl + (buffer[nl] === "\r" && buffer[nl + 1] === "\n" ? 2 : 1));
30
+ if (line === "") flush();
31
+ else if (line.startsWith(":")) continue;
32
+ else {
33
+ const i = line.indexOf(":");
34
+ const field = i < 0 ? line : line.slice(0, i);
35
+ const val = i < 0 ? "" : line.slice(i + 1).replace(/^ /, "");
36
+ if (field === "event") event = val;
37
+ else if (field === "data") data.push(val);
38
+ }
39
+ }
40
+ }
41
+ flush();
42
+ }
43
+ function createAgUiTransport(opts) {
44
+ const doFetch = (...a) => (opts.fetch ?? fetch)(...a);
45
+ const sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
46
+ const retries = opts.retries ?? 6;
47
+ return {
48
+ async run(input, onEvent, signal) {
49
+ const body = JSON.stringify(input);
50
+ for (let attempt = 0; ; attempt++) {
51
+ const res = await doFetch(opts.url, {
52
+ method: "POST",
53
+ credentials: opts.credentials ?? "same-origin",
54
+ headers: { "content-type": "application/json", accept: "text/event-stream", ...opts.headers },
55
+ body,
56
+ signal
57
+ });
58
+ const retryAfter = Number(res.headers.get("Retry-After")) || void 0;
59
+ if (res.status === 503 && attempt < retries) {
60
+ await sleep((retryAfter ?? 3) * 1e3);
61
+ continue;
62
+ }
63
+ if (!res.ok) {
64
+ const json = await res.json().catch(() => null);
65
+ throw new PilotHttpError(json?.message ?? json?.error ?? `Error ${res.status}`, res.status, json?.error, retryAfter);
66
+ }
67
+ if (!res.body) return;
68
+ const serverDate = Date.parse(res.headers.get("date") ?? "");
69
+ const skew = Number.isNaN(serverDate) ? null : serverDate - Date.now();
70
+ await readSse(res.body, ({ data }) => {
71
+ if (!data) return;
72
+ try {
73
+ const event = JSON.parse(data);
74
+ if (skew !== null && typeof event.timestamp !== "number") event.timestamp = Date.now() + skew;
75
+ onEvent(event);
76
+ } catch {
77
+ }
78
+ });
79
+ return;
80
+ }
81
+ }
82
+ };
83
+ }
84
+
85
+ export {
86
+ PilotHttpError,
87
+ readSse,
88
+ createAgUiTransport
89
+ };
@@ -1,7 +1,6 @@
1
1
  export * from "./types";
2
- export { RESTART_NOTICE, RESUME_TEXT, appendAgentMessages, applyHistory, beginSend, createPilotState, dropLastExchange, expiryMs, lastUserTurn, reconcileWith, reducePilotEvent, resolvePermission, resumeMode, sendAccepted, sendFailed, sendRejectedBusy, stopTurn, } from "./reducer";
3
- export { reconcileTurns } from "./reconcile";
2
+ export { argsDetail, beginSend, createPilotState, dropLastExchange, expiryMs, lastUserTurn, messagesToTurns, reduceAgUiEvent, resolvePermission, sendFailed, stopTurn, toPermission, } from "./reducer";
4
3
  export { isNarration, narrationToMarkdown, splitNarration } from "./narration";
5
4
  export { cleanReplyOption, extractReplyOptions, type ReplyOptions } from "./options";
6
- export { TOOL_VERBS_EN, TOOL_VERBS_ES, groupSteps, isRunning, stepLabel, summarizeTools, toolName, type ToolVerb, type ToolVerbs, } from "./steps";
5
+ export { TOOL_VERBS_EN, TOOL_VERBS_ES, groupSteps, isRunning, stepLabel, summarizeTools, toolName, toolNames, type ToolVerb, type ToolVerbs, } from "./steps";
7
6
  export { applyReferences, cleanUserText, formatDuration, systemNoteOf } from "./text";
@@ -1,10 +1,7 @@
1
1
  import {
2
- RESTART_NOTICE,
3
- RESUME_TEXT,
4
2
  TOOL_VERBS_EN,
5
3
  TOOL_VERBS_ES,
6
- appendAgentMessages,
7
- applyHistory,
4
+ argsDetail,
8
5
  beginSend,
9
6
  cleanReplyOption,
10
7
  createPilotState,
@@ -15,21 +12,19 @@ import {
15
12
  isNarration,
16
13
  isRunning,
17
14
  lastUserTurn,
15
+ messagesToTurns,
18
16
  narrationToMarkdown,
19
- reconcileTurns,
20
- reconcileWith,
21
- reducePilotEvent,
17
+ reduceAgUiEvent,
22
18
  resolvePermission,
23
- resumeMode,
24
- sendAccepted,
25
19
  sendFailed,
26
- sendRejectedBusy,
27
20
  splitNarration,
28
21
  stepLabel,
29
22
  stopTurn,
30
23
  summarizeTools,
31
- toolName
32
- } from "../chunks/chunk-O6FCE4CS.js";
24
+ toPermission,
25
+ toolName,
26
+ toolNames
27
+ } from "../chunks/chunk-JQEB37IY.js";
33
28
  import {
34
29
  applyReferences,
35
30
  cleanUserText,
@@ -37,13 +32,10 @@ import {
37
32
  systemNoteOf
38
33
  } from "../chunks/chunk-6U545WJG.js";
39
34
  export {
40
- RESTART_NOTICE,
41
- RESUME_TEXT,
42
35
  TOOL_VERBS_EN,
43
36
  TOOL_VERBS_ES,
44
- appendAgentMessages,
45
- applyHistory,
46
37
  applyReferences,
38
+ argsDetail,
47
39
  beginSend,
48
40
  cleanReplyOption,
49
41
  cleanUserText,
@@ -56,19 +48,17 @@ export {
56
48
  isNarration,
57
49
  isRunning,
58
50
  lastUserTurn,
51
+ messagesToTurns,
59
52
  narrationToMarkdown,
60
- reconcileTurns,
61
- reconcileWith,
62
- reducePilotEvent,
53
+ reduceAgUiEvent,
63
54
  resolvePermission,
64
- resumeMode,
65
- sendAccepted,
66
55
  sendFailed,
67
- sendRejectedBusy,
68
56
  splitNarration,
69
57
  stepLabel,
70
58
  stopTurn,
71
59
  summarizeTools,
72
60
  systemNoteOf,
73
- toolName
61
+ toPermission,
62
+ toolName,
63
+ toolNames
74
64
  };
@@ -1,54 +1,36 @@
1
- import type { Attachment, PermissionRequest, PilotState, SendResult, Turn } from "./types";
2
- /** El aviso de reinicio del servidor. Se retira solo si el agente sigue mandando algo. */
3
- export declare const RESTART_NOTICE = "El servidor se reinici\u00F3 a media respuesta. Vuelve a enviar el mensaje.";
4
- /** Lo que se ve en el hilo al retomar (el servidor manda al agente la continuación entera). */
5
- export declare const RESUME_TEXT = "Contin\u00FAa donde te quedaste.";
1
+ import type { Interrupt, Message } from "@ag-ui/core";
2
+ import type { Attachment, Decision, PermissionRequest, PilotState, Turn } from "./types";
6
3
  export declare function createPilotState(turns?: Turn[]): PilotState;
4
+ type Ev = {
5
+ type: string;
6
+ [k: string]: any;
7
+ };
8
+ /** Los argumentos de una tool en corto, para el renglón del paso: «job: purge-notifications». */
9
+ export declare function argsDetail(json?: string): string | undefined;
10
+ /** Un `Interrupt` de AG-UI como tarjeta: título, herramienta (por su toolCallId) y vencimiento. */
11
+ export declare function toPermission(i: Interrupt, turns: Turn[], clockOffset?: number): PermissionRequest;
7
12
  /**
8
- * Un evento del stream → estado nuevo. `data` ya viene parseado (JSON); `null` si no traía.
9
- * `now` se inyecta para que el reductor sea puro (tiempos de turno y de página).
13
+ * El hilo guardado (mensajes AG-UI) como turnos: cada mensaje del usuario abre uno; lo que sigue del
14
+ * asistente y de las herramientas se junta en un turno, con sus pasos y su narración.
10
15
  */
11
- export declare function reducePilotEvent(prev: PilotState, name: string, data: unknown, now?: number): PilotState;
12
- /** `expiresAt` (ISO o epoch ms) → epoch ms. */
13
- export declare function expiryMs(v: string | number): number;
14
- /**
15
- * El usuario manda un mensaje. Con turno en vuelo es una CORRECCIÓN: el servidor intenta meterlo
16
- * al turno (steer) y, hasta saber si entró, la burbuja viva se conserva.
17
- */
18
- export declare function beginSend(prev: PilotState, text: string, attachments: Attachment[], now?: number): PilotState;
19
- /** El servidor aceptó el encargo. `inFlight` = había turno en vuelo al mandar. */
20
- export declare function sendAccepted(prev: PilotState, r: SendResult, inFlight: boolean, now?: number): PilotState;
21
- /**
22
- * El servidor ya tiene un turno corriendo (409 `turn_busy`): el mensaje de este cliente NO entró.
23
- * Se quita de la pantalla y se avisa; el transporte se re-engancha al turno que sí corre.
24
- */
25
- export declare function sendRejectedBusy(prev: PilotState, message: string): PilotState;
26
- /** El encargo fue rechazado (sin saldo, sin cuenta…): se DICE, para que no se quede pensando. */
27
- export declare function sendFailed(prev: PilotState, message: string, needsLogin?: boolean): PilotState;
28
- /** Detener el turno en curso (el POST de cancelar lo hace el transporte). */
16
+ export declare function messagesToTurns(messages: Message[]): Turn[];
17
+ /** Un evento AG-UI → estado nuevo. `now` se inyecta para que el reductor sea puro. */
18
+ export declare function reduceAgUiEvent(prev: PilotState, e: Ev, now?: number): PilotState;
19
+ /** El usuario manda un mensaje (o contesta una tarjeta: `text` vacío, sin burbuja). */
20
+ export declare function beginSend(prev: PilotState, text: string, attachments?: Attachment[], now?: number): PilotState;
21
+ /** El servidor no aceptó el encargo (HTTP): se DICE, para que no se quede pensando. */
22
+ export declare function sendFailed(prev: PilotState, message: string): PilotState;
23
+ /** Detener: el cliente cortó la conexión (el servidor corta el run). */
29
24
  export declare function stopTurn(prev: PilotState): PilotState;
30
25
  /** Quita el último intercambio (las respuestas del final y el último mensaje del usuario). */
31
26
  export declare function dropLastExchange(prev: PilotState): PilotState;
32
- /**
33
- * El usuario contestó una tarjeta: sale de las abiertas y queda anotada en la última respuesta
34
- * («Aprobaste: correr la purga»). `resolved: false` = ya no estaba abierta (venció o la contestó otro).
35
- */
36
- export declare function resolvePermission(prev: PilotState, id: string, optionId: string, resolved: boolean, detail?: string,
37
- /** La tarjeta como estaba al contestarla (el stream pudo retirarla mientras tanto). */
38
- asked?: PermissionRequest): PilotState;
39
- /**
40
- * El historial guardado (al montar): el hilo, si la pantalla sigue vacía, y las tarjetas de permiso
41
- * que siguen abiertas (sin duplicar las que el stream ya trajo).
42
- */
43
- export declare function applyHistory(prev: PilotState, turns: Turn[], permissions?: PermissionRequest[]): PilotState;
44
- /** Un mensaje del agente que entró fuera de un turno (el remate de los subagentes). */
45
- export declare function appendAgentMessages(prev: PilotState, texts: string[]): PilotState;
46
- /** La copia del hilo cambió: trae los mensajes que el usuario mandó desde OTRO cliente. Sólo en reposo. */
47
- export declare function reconcileWith(prev: PilotState, fresh: Turn[]): PilotState;
48
- /** El último mensaje del usuario (para reintentar o retomar). */
27
+ /** El último mensaje del usuario (para reintentar). */
49
28
  export declare function lastUserTurn(turns: Turn[]): Turn | null;
50
29
  /**
51
- * «Retomar»: si el agente alcanzó a trabajar (texto o pasos tras el último mensaje), se le pide
52
- * CONTINUAR; si no, es reenviar el mensaje tal cual.
30
+ * El usuario contestó (o dejó vencer) una tarjeta: sale de las abiertas y queda anotada en la última
31
+ * respuesta («Aprobaste: correr la purga»).
53
32
  */
54
- export declare function resumeMode(turns: Turn[]): "continue" | "resend";
33
+ export declare function resolvePermission(prev: PilotState, id: string, status: Decision["status"], asked?: PermissionRequest): PilotState;
34
+ /** `expiresAt` (ISO o epoch ms) → epoch ms. */
35
+ export declare function expiryMs(v: string | number): number;
36
+ export {};
@@ -10,7 +10,15 @@ export interface ToolVerb {
10
10
  export type ToolVerbs = Record<string, ToolVerb>;
11
11
  /** ¿Sigue corriendo? `pending` también: es el instante entre pedirla y arrancarla. */
12
12
  export declare const isRunning: (t: ToolEntry) => boolean;
13
- /** `mcp__servidor__nombre` → `nombre`; cualquier otro título, tal cual. */
13
+ /**
14
+ * Los nombres con los que se puede buscar el verbo/ícono de una herramienta, del más específico al
15
+ * menos: el título tal cual, y sin el prefijo de MCP. Los MCP la nombran `mcp__servidor__tool` (dos
16
+ * guiones bajos) o `mcp_servidor_tool` (uno, visto en EasyBits); como el servidor y la tool también
17
+ * llevan guiones bajos, con uno solo se prueban todos los cortes: `mcp_easy_bits_list_crons` →
18
+ * `easy_bits_list_crons`, `bits_list_crons`, `list_crons`, `crons`.
19
+ */
20
+ export declare function toolNames(t: ToolEntry): string[];
21
+ /** El nombre «corto» de la herramienta (sin el prefijo de MCP de dos guiones bajos). */
14
22
  export declare function toolName(t: ToolEntry): string | null;
15
23
  /** El rótulo de un paso: el verbo de su nombre, o el título que manda el servidor, o su clase. */
16
24
  export declare function stepLabel(t: ToolEntry, verbs: ToolVerbs, fallback?: string): string;
@@ -1,86 +1,28 @@
1
- /** Por dónde va la conexión con el agente antes de que conteste. */
2
- export type ConnectPhase = "waking" | "connecting" | "session";
3
- /** Un modelo que el agente ofrece para la sesión (selector ACP). */
4
- export interface ModelOption {
5
- value: string;
6
- name: string;
7
- }
8
- /**
9
- * Un adjunto listo para el agente: base64 sin prefijo + su MIME, o una URL ya subida.
10
- * Viaja en el cuerpo del POST como `images` (nombre histórico del contrato).
11
- */
1
+ import type { BaseEvent, Interrupt, Message, RunAgentInput } from "@ag-ui/core";
2
+ export type { BaseEvent, Interrupt, Message, RunAgentInput };
3
+ /** Un adjunto del mensaje del usuario (viaja como parte de contenido AG-UI). */
12
4
  export interface Attachment {
13
5
  name?: string;
14
6
  mimeType: string;
15
- /** Base64 sin el prefijo `data:`. Vacío cuando el archivo viaja por `uri`. */
16
- data: string;
17
- /** URL del archivo ya subido (lo que el agente descarga cuando no es imagen ni texto). */
18
- uri?: string;
19
- /** Id del archivo en la app, si la app lo guarda. */
20
- fileId?: string;
7
+ /** Base64 sin el prefijo `data:` (imágenes y texto que caben en el mensaje). */
8
+ data?: string;
9
+ /** URL del archivo ya subido (lo demás). */
10
+ url?: string;
21
11
  }
22
- /** Un paso del agente (una herramienta), según ACP: pending → in_progress → completed | failed. */
12
+ /** Un paso del agente: una llamada a herramienta (TOOL_CALL_*). */
23
13
  export interface ToolEntry {
24
14
  id: string;
15
+ /** El nombre de la herramienta (`toolCallName`): es la llave de los verbos de la app. */
25
16
  title?: string;
26
17
  kind?: string;
18
+ /** `in_progress` mientras corre; `completed` | `failed` con su resultado; `pending` = espera
19
+ * aprobación; `cancelled` = el run se detuvo antes de que terminara. */
27
20
  status?: string;
28
21
  path?: string;
29
- /** Qué hace, en palabras de persona (el comando, el archivo, el prompt de la imagen). */
22
+ /** Los argumentos, en corto («job: purge-notifications»). */
30
23
  detail?: string;
31
- }
32
- /** Lo que el agente ENTREGÓ en el turno (evento `artifact`). `raw` es el payload tal cual. */
33
- export interface Delivery {
34
- kind: "file" | "artifact";
35
- name: string;
36
- fileId?: string;
37
- /** Documento editable de la app (Ghosty: `@ghostystudio/docs`). */
38
- docId?: string;
39
- mime?: string;
40
- size?: number;
41
- /** Captura de pantalla del navegador: se pinta en su tira, no como entrega suelta. */
42
- capture?: boolean;
43
- raw?: Record<string, unknown>;
44
- }
45
- /** Una sección de la página que el turno arma (constructor por secciones). */
46
- export interface PageBuildSection {
47
- id: string;
48
- label: string;
49
- kind: string;
50
- status: "pending" | "building" | "done" | "failed";
51
- html?: string;
52
- }
53
- /** La revisión de la página armada: corriendo, o terminada con sus arreglos. */
54
- export interface PageReview {
55
- status: "running" | "done";
56
- fixes: {
57
- name: string;
58
- sectionId: string;
59
- }[];
60
- skipped: string[];
61
- thumb?: string | null;
62
- seconds?: number;
63
- }
64
- /** Una página que el turno está armando, por `pageId` (eventos `page-plan` … `page-ready`). */
65
- export interface PageBuild {
66
- pageId: string;
67
- title: string;
68
- /** Opaco para Piloto: lo interpreta quien pinta la página (slot `renderDeliveries`). */
69
- theme: unknown;
70
- sections: PageBuildSection[];
71
- startedAt: number;
72
- readyAt?: number;
73
- url?: string | null;
74
- n?: number;
75
- error?: string;
76
- mode?: "build" | "edit";
77
- focus?: {
78
- sectionId: string;
79
- nodeId: string;
80
- };
81
- editLabel?: string;
82
- editSummary?: string;
83
- review?: PageReview;
24
+ /** Los argumentos en JSON tal como llegaron (TOOL_CALL_ARGS). */
25
+ args?: string;
84
26
  }
85
27
  export interface Usage {
86
28
  used: number;
@@ -89,13 +31,17 @@ export interface Usage {
89
31
  input?: number;
90
32
  output?: number;
91
33
  }
34
+ /** Una tarjeta de aprobación ya contestada. */
35
+ export interface Decision {
36
+ id: string;
37
+ title: string;
38
+ status: "approved" | "rejected" | "expired" | "cancelled";
39
+ detail?: string;
40
+ }
92
41
  export interface Turn {
93
42
  role: "user" | "assistant";
94
43
  text: string;
95
- /** Llegó entero fuera de un turno (el remate de los subagentes): se escribe al ritmo. */
96
- arrived?: boolean;
97
- deliveries?: Delivery[];
98
- /** Cuánto tardó, en segundos. Se rellena al cerrar el turno. */
44
+ /** Cuánto tardó, en segundos (sólo los turnos vistos en vivo). */
99
45
  seconds?: number;
100
46
  thought?: string;
101
47
  tools?: ToolEntry[];
@@ -103,48 +49,33 @@ export interface Turn {
103
49
  cuts?: number[];
104
50
  attachments?: Attachment[];
105
51
  usage?: Usage;
106
- /** Lo que el usuario decidió en las tarjetas de permiso de este turno (sólo en vivo). */
52
+ /** Lo que el usuario decidió en las tarjetas de este turno (sólo en vivo). */
107
53
  decisions?: Decision[];
108
- /** Mensaje del usuario que ENTRÓ al turno en vuelo (steer): la respuesta sigue arriba. */
109
- steer?: boolean;
110
- pages?: PageBuild[];
111
- /** El servidor ya está planeando una página (antes de que llegue su plan). */
112
- planning?: boolean;
113
- planningAt?: number;
114
- }
115
- /** Un turno que se cortó por falla del servidor (deploy, caja caída). Lo dice el servidor. */
116
- export interface Interrupted {
117
- reason: string;
118
- turnId?: string;
119
- /** El servidor puede CONTINUAR ese turno (EasyBits: `continueTurnId`). */
120
- canContinue?: boolean;
121
54
  }
122
- /** Una tarjeta de permiso ya contestada. */
123
- export interface Decision {
124
- id: string;
125
- title: string;
126
- status: "approved" | "rejected" | "expired";
127
- /** Lo que devolvió la app al resolverla (p. ej. «ejecutada»). */
128
- detail?: string;
129
- }
130
- /** Una opción de un pedido de permiso, tal cual la manda el agente (ACP). */
55
+ /** Una opción de la tarjeta de aprobación. */
131
56
  export interface PermissionOption {
132
57
  optionId: string;
133
58
  name: string;
134
- /** `allow_once` | `allow_always` | `reject_once` | `reject_always` | otra. */
59
+ /** `allow_once` | `reject_once`. */
135
60
  kind?: string;
136
61
  }
137
- /** El agente pide permiso antes de algo riesgoso: el turno está DETENIDO hasta que alguien conteste. */
62
+ /** Una aprobación pendiente (un `Interrupt` de AG-UI, listo para pintar). */
138
63
  export interface PermissionRequest {
64
+ /** El `id` del interrupt: con él se contesta (`resume[].interruptId`). */
139
65
  id: string;
140
66
  title: string;
141
67
  tool?: string;
68
+ toolCallId?: string;
69
+ reason?: string;
142
70
  options: PermissionOption[];
71
+ /** Hasta cuándo se puede contestar (ISO, reloj del SERVIDOR). */
72
+ expiresAt?: string | number;
143
73
  /**
144
- * Hasta cuándo se puede contestar (ISO o epoch ms). Una tarjeta CON vencimiento no depende del
145
- * turno (EasyBits: la propuesta vive 15 min aunque el turno ya cerró) y sobrevive al `done`.
74
+ * El mismo vencimiento en el reloj de ESTE navegador (epoch ms): `expiresAt` menos la hora del
75
+ * servidor al mandar el evento, más la hora local al recibirlo. Así un reloj local desfasado no
76
+ * adelanta ni atrasa la cuenta regresiva.
146
77
  */
147
- expiresAt?: string | number;
78
+ deadline?: number;
148
79
  }
149
80
  /** Lo que una transición pide hacer FUERA del estado (avisos a la app). */
150
81
  export type PilotEffect = {
@@ -152,85 +83,37 @@ export type PilotEffect = {
152
83
  } | {
153
84
  type: "turn-done";
154
85
  text: string;
155
- turnId?: string;
86
+ runId?: string;
156
87
  seconds?: number;
157
- } | {
158
- type: "turn-interrupted";
159
- reason: string;
160
- turnId?: string;
161
- } | {
162
- type: "needs-login";
88
+ error?: string;
89
+ interrupted?: boolean;
163
90
  } | {
164
91
  type: "title";
165
92
  title?: string;
166
- } | {
167
- type: "disconnected";
168
93
  };
169
94
  export interface PilotState {
170
95
  turns: Turn[];
96
+ /** Hay un run corriendo. */
171
97
  busy: boolean;
172
- connected: boolean;
173
- phase: ConnectPhase;
174
98
  error: string | null;
175
99
  notice: string | null;
176
100
  usage: Usage | null;
177
- models: ModelOption[];
178
- currentModel: string | null;
179
- /** Qué puede el agente. Empieza en `true` para no bloquear mientras se conecta. */
180
- canSeeImages: boolean;
181
- /** El último turno se cortó por falla del servidor: el chat ofrece Retomar. */
182
- interrupted: Interrupted | null;
183
- /** El turno sigue en OTRA instancia del servidor (deploy azul/verde): «sigo trabajando». */
184
- elsewhere: boolean;
185
- /** Permisos abiertos, en el orden en que llegaron. */
101
+ /** Aprobaciones abiertas (del último RUN_FINISHED con outcome interrupt). */
186
102
  permissions: PermissionRequest[];
187
103
  /** Cuándo empezó el turno que ESTE cliente encargó (0 = ninguno). */
188
104
  turnStartedAt: number;
189
- /** Hay una burbuja del asistente recibiendo eventos del turno en curso. */
190
- streaming: boolean;
191
- /** El `turnId` del turno que este cliente encargó (lo devuelve el POST). */
192
- currentTurnId: string | null;
193
- /** Cuántas veces se abrió el stream: >1 = reconexión. */
194
- connections: number;
195
- /** El servidor avisó (`caps.needAccount`) que hace falta cuenta: se avisa al cerrar el turno. */
196
- needAccount: boolean;
197
- /** Cada cuánto promete el servidor su latido (`started.latidoMs`). */
198
- heartbeatMs: number | null;
105
+ runId: string | null;
199
106
  /** Efectos de la ÚLTIMA transición. El hook los ejecuta y los descarta. */
200
107
  effects: PilotEffect[];
201
108
  }
202
- /** Lo que se le pide al transporte al mandar un mensaje. */
203
- export interface SendInput {
204
- text: string;
205
- attachments: Attachment[];
206
- /** Es el primer mensaje del hilo (el servidor lo bautiza al cerrar el turno). */
207
- firstTurn: boolean;
208
- /** «Retomar» un turno cortado: el servidor arma la continuación. */
209
- resume?: boolean;
210
- /** Con `resume`: el turno a continuar, si el servidor lo dijo (`interrupted.turnId`). */
211
- resumeTurnId?: string;
212
- /** Lo que el usuario ve en pantalla, para este turno. */
213
- context?: unknown;
214
- /** Las referencias que viajaron en el texto, también estructuradas. */
215
- references?: Reference[];
216
- }
217
- /** Lo que contesta el servidor al encargo. */
218
- export interface SendResult {
219
- /** El mensaje entró al turno en vuelo (steer). */
220
- injected?: boolean;
221
- /** `queued` = la caja está despertando. */
222
- state?: string;
223
- turnId?: string;
224
- }
225
109
  /**
226
110
  * Una referencia que acompaña al mensaje (una tarjeta del tablero, un elemento señalado).
227
111
  * Con `prompt`, ese renglón va ANTES del mensaje; sin él, las etiquetas van juntas como
228
- * `[#12 Rosa, #7 Javier] ` (el formato del tablero de Ghosty).
112
+ * `[#12 Rosa, #7 Javier] `.
229
113
  */
230
114
  export interface Reference {
231
115
  id: string;
232
116
  label: string;
233
117
  prompt?: string;
234
- /** Texto secundario del chip («el texto señalado»). */
235
118
  hint?: string;
236
119
  }
@@ -1,6 +1,6 @@
1
1
  import { type ReactNode } from "react";
2
2
  import { type ReplyOptions } from "../core/options";
3
- import type { Delivery, Turn, Usage } from "../core/types";
3
+ import type { Turn, Usage } from "../core/types";
4
4
  export declare function UserBubble({ turn }: {
5
5
  turn: Turn;
6
6
  }): import("react").JSX.Element;
@@ -23,10 +23,6 @@ export declare function TurnFooter({ text, seconds, onRetry, showCopy, showDurat
23
23
  showCopy?: boolean;
24
24
  showDuration?: boolean;
25
25
  }): import("react").JSX.Element;
26
- /** Las entregas por defecto: una ficha por archivo (las apps pintan las suyas con `renderDeliveries`). */
27
- export declare function DeliveryChips({ deliveries }: {
28
- deliveries: Delivery[];
29
- }): import("react").JSX.Element | null;
30
26
  export interface AgentBubbleProps {
31
27
  turn: Turn;
32
28
  /** El turno sigue escribiéndose. */
@@ -37,7 +33,7 @@ export interface AgentBubbleProps {
37
33
  showUsage?: boolean;
38
34
  showCopy?: boolean;
39
35
  showDuration?: boolean;
40
- /** Las entregas (y lo que la app quiera bajo la respuesta). Sin esto, fichas simples. */
36
+ /** Lo que la app quiera pintar bajo la respuesta (archivos, tarjetas propias). */
41
37
  renderDeliveries?: (turn: Turn, live: boolean) => ReactNode;
42
38
  }
43
39
  export declare function AgentBubble({ turn, live, onRetry, onOption, showUsage, showCopy, showDuration, renderDeliveries }: AgentBubbleProps): import("react").JSX.Element;
@@ -1,5 +1,10 @@
1
1
  import { type ReactNode } from "react";
2
- import type { Attachment, ModelOption, Reference } from "../core/types";
2
+ import type { Attachment, Reference } from "../core/types";
3
+ /** Un modelo que la app ofrece elegir (AG-UI no lo define: la app lo manda en `forwardedProps`). */
4
+ export interface ModelOption {
5
+ value: string;
6
+ name: string;
7
+ }
3
8
  /** Lo que devuelve la app al subir un archivo: su URL (y su id, si lo guarda). */
4
9
  export interface UploadResult {
5
10
  url: string;
@@ -1,13 +1,12 @@
1
1
  import type { Decision, PermissionOption, PermissionRequest } from "../core/types";
2
- import type { PermissionAnswer } from "./usePilot";
3
2
  /** Las opciones de rechazo van primero y discretas; las de aprobar, al final y en color. */
4
3
  export declare const isRejectOption: (o: PermissionOption) => boolean;
5
4
  export declare function ConfirmCard({ request, onRespond, onSettled, onExpire, }: {
6
5
  request: PermissionRequest;
7
- /** Contesta (el transporte o la ruta de la app). `{resolved:false}` = ya no estaba abierta. */
8
- onRespond: (id: string, optionId: string) => Promise<PermissionAnswer> | PermissionAnswer;
6
+ /** Contesta: `approved` viaja como `payload` del `resume`. */
7
+ onRespond: (id: string, approved: boolean) => void;
9
8
  /** El sello ya se vio: anotar la decisión y retirar la tarjeta. */
10
- onSettled?: (id: string, optionId: string, answer: PermissionAnswer) => void;
9
+ onSettled?: (id: string, status: Decision["status"]) => void;
11
10
  /** Venció sin contestarse. */
12
11
  onExpire?: (id: string) => void;
13
12
  }): import("react").JSX.Element;
@@ -5,7 +5,7 @@ import type { PilotTransport } from "../transport";
5
5
  import { type UploadResult } from "./Composer";
6
6
  import { type MarkdownOptions, type PilotIcon, type PilotTheme } from "./context";
7
7
  import { type PilotStrings } from "./strings";
8
- import { type PermissionHandler, type Pilot, type UsePilotOptions } from "./usePilot";
8
+ import { type Pilot, type UsePilotOptions } from "./usePilot";
9
9
  export interface PilotoFeatures {
10
10
  /** Botones de adjuntar. Default: sí si hay `upload`. */
11
11
  attachments?: boolean;
@@ -15,15 +15,13 @@ export interface PilotoFeatures {
15
15
  copy?: boolean;
16
16
  /** Tokens y costo bajo cada respuesta. Default: sí. */
17
17
  usage?: boolean;
18
- /** Selector de modelo (si el agente ofrece varios). Default: sí. */
19
- models?: boolean;
20
18
  /** Las opciones finales de la última respuesta como botones. Default: sí. */
21
19
  replyOptions?: boolean;
22
20
  /** «· 12 s» junto a la frase de espera. Default: sí. */
23
21
  duration?: boolean;
24
22
  }
25
23
  export interface PilotoSlots {
26
- /** Las entregas de cada respuesta (archivos, páginas, tarjetas propias). */
24
+ /** Lo que la app pinte bajo cada respuesta (archivos, tarjetas propias). */
27
25
  renderDeliveries?: (turn: Turn, live: boolean) => ReactNode;
28
26
  /** Botones propios en la barra del composer. */
29
27
  composerExtras?: ReactNode;
@@ -61,12 +59,7 @@ export interface PilotoProps extends UsePilotOptions {
61
59
  voiceNoteText?: (transcript: string) => string;
62
60
  features?: PilotoFeatures;
63
61
  /**
64
- * Contestar un permiso (p. ej. el POST de aprobación de la app, con su sesión). Default:
65
- * `transport.respondPermission`. Devuelve `{resolved:false}` si ya no estaba abierto.
66
- */
67
- onPermission?: PermissionHandler;
68
- /**
69
- * Una pregunta lista en la caja (sin mandarla) y el foco en ella: al abrir el copiloto desde una
62
+ * Una pregunta lista en la caja (sin mandarla) y el foco en ella: al abrir el piloto desde una
70
63
  * fila («Pídeselo»). Cambiar el texto —o `key`, para repetir el mismo— la vuelve a poner.
71
64
  */
72
65
  draft?: string | {