ghostykit 0.4.0 → 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.
- package/dist/chunks/{chunk-HPTM2BCM.js → chunk-JQEB37IY.js} +12 -5
- package/dist/chunks/{chunk-DXFWACUL.js → chunk-TMEHQZWL.js} +5 -1
- package/dist/core/index.js +1 -1
- package/dist/core/reducer.d.ts +1 -1
- package/dist/core/types.d.ts +9 -2
- package/dist/react/index.js +8 -4
- package/dist/transport/index.js +1 -1
- package/package.json +1 -1
|
@@ -36,7 +36,7 @@ function upsertTool(s, id, patch) {
|
|
|
36
36
|
}
|
|
37
37
|
var APPROVE = { optionId: "approve", name: "Aprobar", kind: "allow_once" };
|
|
38
38
|
var REJECT = { optionId: "reject", name: "Rechazar", kind: "reject_once" };
|
|
39
|
-
function toPermission(i, turns) {
|
|
39
|
+
function toPermission(i, turns, clockOffset = 0) {
|
|
40
40
|
const meta = i.metadata ?? {};
|
|
41
41
|
const toolName2 = (typeof meta.tool === "string" ? meta.tool : void 0) ?? turns.flatMap((t) => t.tools ?? []).find((x) => x.id === i.toolCallId)?.title;
|
|
42
42
|
return {
|
|
@@ -46,9 +46,14 @@ function toPermission(i, turns) {
|
|
|
46
46
|
...i.toolCallId ? { toolCallId: i.toolCallId } : {},
|
|
47
47
|
reason: i.reason,
|
|
48
48
|
options: [REJECT, APPROVE],
|
|
49
|
-
...i.expiresAt ? { expiresAt: i.expiresAt } : {}
|
|
49
|
+
...i.expiresAt ? { expiresAt: i.expiresAt, deadline: expiryMs(i.expiresAt) + clockOffset } : {}
|
|
50
50
|
};
|
|
51
51
|
}
|
|
52
|
+
function closeOpenTools(turns, status) {
|
|
53
|
+
return turns.map(
|
|
54
|
+
(t) => t.tools?.some((x) => x.status === "in_progress") ? { ...t, tools: t.tools.map((x) => x.status === "in_progress" ? { ...x, status } : x) } : t
|
|
55
|
+
);
|
|
56
|
+
}
|
|
52
57
|
function textOf(content) {
|
|
53
58
|
if (typeof content === "string") return content;
|
|
54
59
|
if (Array.isArray(content)) return content.map((p) => p && typeof p === "object" && p.type === "text" ? p.text ?? "" : "").join("");
|
|
@@ -175,7 +180,9 @@ function finish(s0, e, now, failed = false) {
|
|
|
175
180
|
let s = { ...s0, busy: false };
|
|
176
181
|
const outcome = e.outcome;
|
|
177
182
|
const interrupted = outcome?.type === "interrupt" && Array.isArray(outcome.interrupts) && outcome.interrupts.length > 0;
|
|
178
|
-
|
|
183
|
+
const clockOffset = typeof e.timestamp === "number" ? now - e.timestamp : 0;
|
|
184
|
+
s.permissions = interrupted ? outcome.interrupts.map((i) => toPermission(i, s.turns, clockOffset)) : [];
|
|
185
|
+
if (outcome?.type === "cancelled" || failed) s = { ...s, turns: closeOpenTools(s.turns, failed ? "failed" : "cancelled") };
|
|
179
186
|
if (interrupted) {
|
|
180
187
|
const waiting = new Set(s.permissions.map((p) => p.toolCallId).filter(Boolean));
|
|
181
188
|
if (waiting.size) {
|
|
@@ -211,7 +218,7 @@ function sendFailed(prev, message) {
|
|
|
211
218
|
return { ...prev, busy: false, turnStartedAt: 0, error: message, effects: [] };
|
|
212
219
|
}
|
|
213
220
|
function stopTurn(prev) {
|
|
214
|
-
return { ...prev, busy: false, turnStartedAt: 0, effects: [] };
|
|
221
|
+
return { ...prev, busy: false, turnStartedAt: 0, turns: closeOpenTools(prev.turns, "cancelled"), effects: [] };
|
|
215
222
|
}
|
|
216
223
|
function dropLastExchange(prev) {
|
|
217
224
|
const turns = [...prev.turns];
|
|
@@ -311,7 +318,7 @@ function cleanReplyOption(t) {
|
|
|
311
318
|
}
|
|
312
319
|
|
|
313
320
|
// src/core/steps.ts
|
|
314
|
-
var isRunning = (t) => t.status !== "completed" && t.status !== "failed";
|
|
321
|
+
var isRunning = (t) => t.status !== "completed" && t.status !== "failed" && t.status !== "cancelled";
|
|
315
322
|
function toolNames(t) {
|
|
316
323
|
const title = t.title ?? "";
|
|
317
324
|
if (!title) return [];
|
|
@@ -65,10 +65,14 @@ function createAgUiTransport(opts) {
|
|
|
65
65
|
throw new PilotHttpError(json?.message ?? json?.error ?? `Error ${res.status}`, res.status, json?.error, retryAfter);
|
|
66
66
|
}
|
|
67
67
|
if (!res.body) return;
|
|
68
|
+
const serverDate = Date.parse(res.headers.get("date") ?? "");
|
|
69
|
+
const skew = Number.isNaN(serverDate) ? null : serverDate - Date.now();
|
|
68
70
|
await readSse(res.body, ({ data }) => {
|
|
69
71
|
if (!data) return;
|
|
70
72
|
try {
|
|
71
|
-
|
|
73
|
+
const event = JSON.parse(data);
|
|
74
|
+
if (skew !== null && typeof event.timestamp !== "number") event.timestamp = Date.now() + skew;
|
|
75
|
+
onEvent(event);
|
|
72
76
|
} catch {
|
|
73
77
|
}
|
|
74
78
|
});
|
package/dist/core/index.js
CHANGED
package/dist/core/reducer.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ type Ev = {
|
|
|
8
8
|
/** Los argumentos de una tool en corto, para el renglón del paso: «job: purge-notifications». */
|
|
9
9
|
export declare function argsDetail(json?: string): string | undefined;
|
|
10
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[]): PermissionRequest;
|
|
11
|
+
export declare function toPermission(i: Interrupt, turns: Turn[], clockOffset?: number): PermissionRequest;
|
|
12
12
|
/**
|
|
13
13
|
* El hilo guardado (mensajes AG-UI) como turnos: cada mensaje del usuario abre uno; lo que sigue del
|
|
14
14
|
* asistente y de las herramientas se junta en un turno, con sus pasos y su narración.
|
package/dist/core/types.d.ts
CHANGED
|
@@ -15,7 +15,8 @@ export interface ToolEntry {
|
|
|
15
15
|
/** El nombre de la herramienta (`toolCallName`): es la llave de los verbos de la app. */
|
|
16
16
|
title?: string;
|
|
17
17
|
kind?: string;
|
|
18
|
-
/** `in_progress` mientras corre; `completed` | `failed` con su resultado; `pending` = espera
|
|
18
|
+
/** `in_progress` mientras corre; `completed` | `failed` con su resultado; `pending` = espera
|
|
19
|
+
* aprobación; `cancelled` = el run se detuvo antes de que terminara. */
|
|
19
20
|
status?: string;
|
|
20
21
|
path?: string;
|
|
21
22
|
/** Los argumentos, en corto («job: purge-notifications»). */
|
|
@@ -67,8 +68,14 @@ export interface PermissionRequest {
|
|
|
67
68
|
toolCallId?: string;
|
|
68
69
|
reason?: string;
|
|
69
70
|
options: PermissionOption[];
|
|
70
|
-
/** Hasta cuándo se puede contestar (ISO). */
|
|
71
|
+
/** Hasta cuándo se puede contestar (ISO, reloj del SERVIDOR). */
|
|
71
72
|
expiresAt?: string | number;
|
|
73
|
+
/**
|
|
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.
|
|
77
|
+
*/
|
|
78
|
+
deadline?: number;
|
|
72
79
|
}
|
|
73
80
|
/** Lo que una transición pide hacer FUERA del estado (avisos a la app). */
|
|
74
81
|
export type PilotEffect = {
|
package/dist/react/index.js
CHANGED
|
@@ -24,12 +24,12 @@ import {
|
|
|
24
24
|
toPermission,
|
|
25
25
|
toolName,
|
|
26
26
|
toolNames
|
|
27
|
-
} from "../chunks/chunk-
|
|
27
|
+
} from "../chunks/chunk-JQEB37IY.js";
|
|
28
28
|
import {
|
|
29
29
|
PilotHttpError,
|
|
30
30
|
createAgUiTransport,
|
|
31
31
|
readSse
|
|
32
|
-
} from "../chunks/chunk-
|
|
32
|
+
} from "../chunks/chunk-TMEHQZWL.js";
|
|
33
33
|
import {
|
|
34
34
|
applyReferences,
|
|
35
35
|
cleanUserText,
|
|
@@ -1009,7 +1009,7 @@ function ConfirmCard({
|
|
|
1009
1009
|
const { strings: t } = usePiloto();
|
|
1010
1010
|
const [pending, setPending] = useState(null);
|
|
1011
1011
|
const [stamp, setStamp] = useState(null);
|
|
1012
|
-
const time = useRemaining(request.expiresAt);
|
|
1012
|
+
const time = useRemaining(request.deadline ?? request.expiresAt);
|
|
1013
1013
|
const expired = time !== null && time.left <= 0;
|
|
1014
1014
|
const urgent = time !== null && !expired && time.left < 6e4;
|
|
1015
1015
|
useEffect(() => {
|
|
@@ -1448,7 +1448,10 @@ function StepLine({ tool, times, live }) {
|
|
|
1448
1448
|
const spins = isRunning(tool) && live;
|
|
1449
1449
|
const label = stepLabel(tool, toolVerbs, t.step);
|
|
1450
1450
|
return /* @__PURE__ */ jsxs3("li", { className: "gs-paso-in flex min-w-0 items-center gap-2 text-[13px] leading-6 text-text-secondary", children: [
|
|
1451
|
-
/* @__PURE__ */ jsx5("span", { className: "flex h-5 w-5 shrink-0 items-center justify-center", "aria-label": spins ? t.running : tool.status === "failed" ? t.failed : t.done, children: spins ? /* @__PURE__ */ jsx5(LoaderCircle, { className: "h-4 w-4 animate-spin text-text-info" }) : tool.status === "
|
|
1451
|
+
/* @__PURE__ */ jsx5("span", { className: "flex h-5 w-5 shrink-0 items-center justify-center", "aria-label": spins ? t.running : tool.status === "failed" ? t.failed : t.done, children: spins ? /* @__PURE__ */ jsx5(LoaderCircle, { className: "h-4 w-4 animate-spin text-text-info" }) : tool.status === "cancelled" ? (
|
|
1452
|
+
// El run se detuvo antes de que terminara.
|
|
1453
|
+
/* @__PURE__ */ jsx5(CircleSlash, { className: "h-4 w-4 text-text-tertiary" })
|
|
1454
|
+
) : tool.status === "pending" ? (
|
|
1452
1455
|
// Espera aprobación (el run se detuvo en un interrupt): ni gira ni está lista.
|
|
1453
1456
|
/* @__PURE__ */ jsx5(Clock, { className: "h-4 w-4 text-text-tertiary" })
|
|
1454
1457
|
) : tool.status === "failed" ? /* @__PURE__ */ jsx5(CircleX, { className: "h-4 w-4 text-text-danger" }) : /* @__PURE__ */ jsx5(CircleCheck, { className: "h-4 w-4 text-text-success" }) }),
|
|
@@ -1470,6 +1473,7 @@ var STATUS = {
|
|
|
1470
1473
|
pending: { Icon: Clock, className: "text-text-tertiary", key: "step" },
|
|
1471
1474
|
in_progress: { Icon: LoaderCircle, className: "animate-spin text-text-info", key: "running" },
|
|
1472
1475
|
completed: { Icon: CircleCheck, className: "text-text-success", key: "done" },
|
|
1476
|
+
cancelled: { Icon: CircleSlash, className: "text-text-tertiary", key: "step" },
|
|
1473
1477
|
failed: { Icon: CircleX, className: "text-text-danger", key: "failed" }
|
|
1474
1478
|
};
|
|
1475
1479
|
function ToolRow({ tool }) {
|
package/dist/transport/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ghostykit",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Ghosty Autopilot \u2014 the autopilot chat for your React app, on AG-UI: works with LangGraph, Mastra, CrewAI or any AG-UI agent. Streaming text, agent steps, human approval cards (interrupt/resume), attachments and voice.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/core/index.js",
|