ghostykit 0.6.2 → 0.6.3
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.
|
@@ -116,7 +116,8 @@ function createPilotState(turns = []) {
|
|
|
116
116
|
effects: []
|
|
117
117
|
};
|
|
118
118
|
}
|
|
119
|
-
var NOT_IN_TURN = /* @__PURE__ */ new Set(["ghosty.title", "ghosty.injected", "ghosty.history", "ghosty.tool", "ghosty.replace", "ghosty.page"]);
|
|
119
|
+
var NOT_IN_TURN = /* @__PURE__ */ new Set(["ghosty.title", "ghosty.injected", "ghosty.history", "ghosty.tool", "ghosty.replace", "ghosty.page", "ghosty.stalled"]);
|
|
120
|
+
var PROGRESS = /* @__PURE__ */ new Set(["TEXT_MESSAGE_START", "TEXT_MESSAGE_CONTENT", "TEXT_MESSAGE_CHUNK", "TOOL_CALL_START", "TOOL_CALL_ARGS", "TOOL_CALL_CHUNK", "TOOL_CALL_RESULT", "REASONING_MESSAGE_CONTENT", "REASONING_MESSAGE_CHUNK", "RUN_STARTED"]);
|
|
120
121
|
function patchAssistant(s, patch) {
|
|
121
122
|
const turns = [...s.turns];
|
|
122
123
|
const last = turns[turns.length - 1];
|
|
@@ -283,7 +284,8 @@ function applySnapshot(s, messages) {
|
|
|
283
284
|
};
|
|
284
285
|
}
|
|
285
286
|
function reduceAgUiEvent(prev, e, now = Date.now()) {
|
|
286
|
-
|
|
287
|
+
let s = prev.effects.length ? { ...prev, effects: [] } : prev;
|
|
288
|
+
if (s.stalled && PROGRESS.has(e.type)) s = { ...s, stalled: null };
|
|
287
289
|
switch (e.type) {
|
|
288
290
|
case "RUN_STARTED":
|
|
289
291
|
return { ...s, busy: true, error: null, step: null, runId: e.runId ?? s.runId };
|
|
@@ -355,6 +357,10 @@ function reduceAgUiEvent(prev, e, now = Date.now()) {
|
|
|
355
357
|
case "CUSTOM":
|
|
356
358
|
if (e.name === "ghosty.title") return { ...s, effects: [{ type: "title", title: e.value?.title }] };
|
|
357
359
|
if (e.name === "ghosty.history") return { ...s, historyNext: toHistory(e.value) };
|
|
360
|
+
if (e.name === "ghosty.stalled") {
|
|
361
|
+
const message = e.value?.message;
|
|
362
|
+
return { ...s, stalled: typeof message === "string" && message ? { message } : {} };
|
|
363
|
+
}
|
|
358
364
|
if (e.name === "ghosty.tool") {
|
|
359
365
|
const v = e.value ?? {};
|
|
360
366
|
if (typeof v.toolCallId !== "string") return s;
|
|
@@ -390,7 +396,7 @@ function toHistory(v) {
|
|
|
390
396
|
return { hasMoreBefore: h.hasMoreBefore === true, ...before !== void 0 ? { before } : {} };
|
|
391
397
|
}
|
|
392
398
|
function finish(s0, e, now, failed = false) {
|
|
393
|
-
let s = { ...s0, busy: false, step: null, openText: null };
|
|
399
|
+
let s = { ...s0, busy: false, step: null, openText: null, stalled: null };
|
|
394
400
|
const outcome = e.outcome;
|
|
395
401
|
const interrupted = outcome?.type === "interrupt" && Array.isArray(outcome.interrupts) && outcome.interrupts.length > 0;
|
|
396
402
|
const clockOffset = typeof e.timestamp === "number" ? now - e.timestamp : 0;
|
|
@@ -414,7 +420,9 @@ function finish(s0, e, now, failed = false) {
|
|
|
414
420
|
const seconds = t0 ? Math.max(1, Math.round((now - t0) / 1e3)) : void 0;
|
|
415
421
|
const turns = [...s.turns];
|
|
416
422
|
const last = turns[turns.length - 1];
|
|
417
|
-
|
|
423
|
+
const tr = e.metadata?.truncated;
|
|
424
|
+
const truncated = tr ? { ...typeof tr.reason === "string" ? { reason: tr.reason } : {} } : void 0;
|
|
425
|
+
if (last?.role === "assistant") turns[turns.length - 1] = { ...last, ...seconds !== void 0 ? { seconds } : {}, ...usage ? { usage } : {}, ...truncated ? { truncated } : {} };
|
|
418
426
|
s = { ...s, turns, turnStartedAt: 0, ...usage ? { usage } : {} };
|
|
419
427
|
if (!t0) return s;
|
|
420
428
|
const effect = {
|
package/dist/core/index.js
CHANGED
package/dist/core/types.d.ts
CHANGED
|
@@ -95,6 +95,10 @@ export interface Turn {
|
|
|
95
95
|
usage?: Usage;
|
|
96
96
|
/** Lo que el usuario decidió en las tarjetas de este turno (sólo en vivo). */
|
|
97
97
|
decisions?: Decision[];
|
|
98
|
+
/** El servidor recortó la respuesta (`RUN_FINISHED.metadata.truncated`); `reason` si la dio. */
|
|
99
|
+
truncated?: {
|
|
100
|
+
reason?: string;
|
|
101
|
+
};
|
|
98
102
|
/** Los `CUSTOM` del turno (p. ej. `ghosty.delivery`), para `renderDeliveries`. Del snapshot salen
|
|
99
103
|
* del campo `custom` de cada mensaje del asistente. */
|
|
100
104
|
custom?: CustomEntry[];
|
|
@@ -171,6 +175,10 @@ export interface PilotState {
|
|
|
171
175
|
runId: string;
|
|
172
176
|
reason?: string;
|
|
173
177
|
} | null;
|
|
178
|
+
/** El agente se atoró y el servidor sigue intentando (`CUSTOM ghosty.stalled`); se quita con lo siguiente que llegue. */
|
|
179
|
+
stalled?: {
|
|
180
|
+
message?: string;
|
|
181
|
+
} | null;
|
|
174
182
|
/** Mensajes en espera de que termine el run vivo (steer rechazado). */
|
|
175
183
|
queued: QueuedMessage[];
|
|
176
184
|
/** Lo que estaba en espera cuando la persona detuvo: regresa a la caja (`n` cambia en cada vez). */
|
package/dist/react/index.js
CHANGED
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
toPermission,
|
|
32
32
|
toolName,
|
|
33
33
|
toolNames
|
|
34
|
-
} from "../chunks/chunk-
|
|
34
|
+
} from "../chunks/chunk-LFFJLMDO.js";
|
|
35
35
|
import {
|
|
36
36
|
PilotHttpError,
|
|
37
37
|
createAgUiTransport,
|
|
@@ -896,6 +896,9 @@ var STRINGS_ES = {
|
|
|
896
896
|
loadingOlder: "Cargando\u2026",
|
|
897
897
|
continueRun: "Continuar",
|
|
898
898
|
runCut: "La respuesta se cort\xF3 antes de terminar.",
|
|
899
|
+
stalled: "Se ator\xF3, sigo intentando\u2026",
|
|
900
|
+
truncated: "La respuesta qued\xF3 incompleta.",
|
|
901
|
+
attachmentFailed: (name, reason) => reason ? `No pude leer ${name}: ${reason}` : `No pude leer ${name}`,
|
|
899
902
|
queued: "Se manda cuando termine",
|
|
900
903
|
subagentsWorking: (n) => n === 1 ? "1 agente trabajando" : `${n} agentes trabajando`,
|
|
901
904
|
subagentsDone: (n) => n === 1 ? "1 agente termin\xF3" : `${n} agentes terminaron`,
|
|
@@ -971,6 +974,9 @@ var STRINGS_EN = {
|
|
|
971
974
|
loadingOlder: "Loading\u2026",
|
|
972
975
|
continueRun: "Continue",
|
|
973
976
|
runCut: "The answer was cut off before it finished.",
|
|
977
|
+
stalled: "Got stuck, still trying\u2026",
|
|
978
|
+
truncated: "The answer is incomplete.",
|
|
979
|
+
attachmentFailed: (name, reason) => reason ? `Couldn't read ${name}: ${reason}` : `Couldn't read ${name}`,
|
|
974
980
|
queued: "Sends when this finishes",
|
|
975
981
|
subagentsWorking: (n) => n === 1 ? "1 agent working" : `${n} agents working`,
|
|
976
982
|
subagentsDone: (n) => n === 1 ? "1 agent finished" : `${n} agents finished`,
|
|
@@ -2388,7 +2394,7 @@ function usePilot(transport, opts = {}) {
|
|
|
2388
2394
|
ctrl.current?.abort();
|
|
2389
2395
|
const c = new AbortController();
|
|
2390
2396
|
ctrl.current = c;
|
|
2391
|
-
const steering =
|
|
2397
|
+
const steering = input.forwardedProps?.steer !== void 0 && input.forwardedProps?.steer !== false;
|
|
2392
2398
|
const userMsg = input.messages[0];
|
|
2393
2399
|
if (!steering && (input.messages.length || input.resume?.length || input.forwardedProps?.continueRun)) liveRun.current = input.runId;
|
|
2394
2400
|
optsRef.current.onSend?.(input);
|
|
@@ -2410,6 +2416,18 @@ function usePilot(transport, opts = {}) {
|
|
|
2410
2416
|
} catch (err) {
|
|
2411
2417
|
if (c.signal.aborted) return;
|
|
2412
2418
|
const code = err instanceof PilotHttpError ? err.code : void 0;
|
|
2419
|
+
if (code === "run_not_live" && steering && userMsg) {
|
|
2420
|
+
const { text } = fromUserMessage(userMsg.content);
|
|
2421
|
+
let s = ref.current;
|
|
2422
|
+
for (let i = s.turns.length - 1; i >= 0; i--) {
|
|
2423
|
+
if (s.turns[i].role === "user" && s.turns[i].text === text) {
|
|
2424
|
+
s = { ...s, turns: [...s.turns.slice(0, i), ...s.turns.slice(i + 1)] };
|
|
2425
|
+
break;
|
|
2426
|
+
}
|
|
2427
|
+
}
|
|
2428
|
+
commit({ ...s, busy: false, turnStartedAt: 0, effects: [] });
|
|
2429
|
+
return sendNew(text, []);
|
|
2430
|
+
}
|
|
2413
2431
|
if (code === "nothing_to_continue") {
|
|
2414
2432
|
liveRun.current = null;
|
|
2415
2433
|
commit({ ...ref.current, busy: false, turnStartedAt: 0, cutRun: null, effects: [] });
|
|
@@ -2461,8 +2479,8 @@ function usePilot(transport, opts = {}) {
|
|
|
2461
2479
|
async (text, attachments = [], _extra = {}) => {
|
|
2462
2480
|
if (!transportRef.current) return;
|
|
2463
2481
|
if (ref.current.busy) {
|
|
2464
|
-
const live = liveRun.current ?? ref.current.runId;
|
|
2465
|
-
if (!steerOn() || !
|
|
2482
|
+
const live = liveRun.current ?? ref.current.runId ?? true;
|
|
2483
|
+
if (!steerOn() || !text.trim() || attachments.length) return;
|
|
2466
2484
|
commit(beginSteer(ref.current, text));
|
|
2467
2485
|
await runNow({ messages: [userMessage(text, [])], forwardedProps: { steer: live } });
|
|
2468
2486
|
return;
|
|
@@ -2864,20 +2882,24 @@ var Piloto = forwardRef3(function Piloto2(props, handle) {
|
|
|
2864
2882
|
turns.map((turn, i) => {
|
|
2865
2883
|
const isLast = i === turns.length - 1;
|
|
2866
2884
|
const live = busy && isLast;
|
|
2867
|
-
return /* @__PURE__ */
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2885
|
+
return /* @__PURE__ */ jsxs8("div", { "data-turn": i - olderCount, children: [
|
|
2886
|
+
turn.role === "user" ? /* @__PURE__ */ jsx10(UserBubble, { turn }) : /* @__PURE__ */ jsx10(
|
|
2887
|
+
AgentBubble,
|
|
2888
|
+
{
|
|
2889
|
+
turn,
|
|
2890
|
+
live,
|
|
2891
|
+
onRetry: isLast && features.retry !== false ? pilot.retry : void 0,
|
|
2892
|
+
onOption: isLast && !busy && features.replyOptions !== false ? (text) => send(text) : void 0,
|
|
2893
|
+
showUsage: features.usage !== false,
|
|
2894
|
+
showCopy: features.copy !== false,
|
|
2895
|
+
showDuration: features.duration !== false,
|
|
2896
|
+
renderDeliveries: slots.renderDeliveries
|
|
2897
|
+
}
|
|
2898
|
+
),
|
|
2899
|
+
turn.role === "assistant" && /* @__PURE__ */ jsx10(TurnNotes, { turn })
|
|
2900
|
+
] }, i - olderCount);
|
|
2880
2901
|
}),
|
|
2902
|
+
busy && state.stalled && /* @__PURE__ */ jsx10("p", { className: "text-sm text-text-tertiary", children: state.stalled.message ?? t.stalled }),
|
|
2881
2903
|
state.queued.map((q, i) => (
|
|
2882
2904
|
// Esperan a que termine el run vivo (el servidor no los dejó entrar): salen solos.
|
|
2883
2905
|
/* @__PURE__ */ jsxs8("div", { "data-queued": true, className: "flex flex-col items-end gap-1 opacity-60", children: [
|
|
@@ -2926,6 +2948,15 @@ var Piloto = forwardRef3(function Piloto2(props, handle) {
|
|
|
2926
2948
|
] })
|
|
2927
2949
|
] })) }) });
|
|
2928
2950
|
});
|
|
2951
|
+
function TurnNotes({ turn }) {
|
|
2952
|
+
const { strings: t } = usePiloto();
|
|
2953
|
+
const failed = (turn.custom ?? []).filter((c) => c.name === "ghosty.attachments_failed").flatMap((c) => (c.value?.files ?? []).filter((f) => f?.name));
|
|
2954
|
+
if (!failed.length && !turn.truncated) return null;
|
|
2955
|
+
return /* @__PURE__ */ jsxs8("div", { "data-turn-notes": true, className: "mt-1 flex flex-col gap-0.5 text-xs text-text-tertiary", children: [
|
|
2956
|
+
failed.map((f, i) => /* @__PURE__ */ jsx10("p", { children: t.attachmentFailed(f.name, f.reason) }, i)),
|
|
2957
|
+
turn.truncated && /* @__PURE__ */ jsx10("p", { children: turn.truncated.reason ?? t.truncated })
|
|
2958
|
+
] });
|
|
2959
|
+
}
|
|
2929
2960
|
|
|
2930
2961
|
// src/react/Subagents.tsx
|
|
2931
2962
|
import { useState as useState10 } from "react";
|
package/dist/react/strings.d.ts
CHANGED
|
@@ -62,6 +62,12 @@ export interface PilotStrings {
|
|
|
62
62
|
continueRun: string;
|
|
63
63
|
/** La franja, si el servidor no dio razón. */
|
|
64
64
|
runCut: string;
|
|
65
|
+
/** `ghosty.stalled` sin mensaje propio. */
|
|
66
|
+
stalled: string;
|
|
67
|
+
/** Bajo una respuesta recortada por el servidor. */
|
|
68
|
+
truncated: string;
|
|
69
|
+
/** Un adjunto que el agente no pudo leer: nombre y razón. */
|
|
70
|
+
attachmentFailed: (name: string, reason?: string) => string;
|
|
65
71
|
/** Bajo un mensaje que espera a que termine el run vivo. */
|
|
66
72
|
queued: string;
|
|
67
73
|
/** «2 agentes trabajando». */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ghostykit",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.3",
|
|
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",
|