ghostykit 0.6.1 → 0.6.2

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.
@@ -408,6 +408,8 @@ function finish(s0, e, now, failed = false) {
408
408
  { used: 0, size: 0, cost: 0 }
409
409
  ) : null;
410
410
  const usage = tokens || costUsd !== void 0 ? { ...tokens ?? { used: 0, size: 0, cost: 0 }, ...costUsd !== void 0 ? { cost: costUsd } : {} } : null;
411
+ const cut = e.metadata?.interrupted;
412
+ s = { ...s, cutRun: cut && typeof cut.runId === "string" ? { runId: cut.runId, ...typeof cut.reason === "string" && cut.reason ? { reason: cut.reason } : {} } : null };
411
413
  const t0 = s.turnStartedAt;
412
414
  const seconds = t0 ? Math.max(1, Math.round((now - t0) / 1e3)) : void 0;
413
415
  const turns = [...s.turns];
@@ -427,7 +429,7 @@ function finish(s0, e, now, failed = false) {
427
429
  }
428
430
  function beginSend(prev, text, attachments = [], now = Date.now()) {
429
431
  const turns = text || attachments.length ? [...prev.turns, { role: "user", text, ...attachments.length ? { attachments } : {} }] : prev.turns;
430
- return { ...prev, turns, busy: true, error: null, notice: null, turnStartedAt: now, effects: [{ type: "turn-start" }] };
432
+ return { ...prev, turns, busy: true, error: null, notice: null, cutRun: null, turnStartedAt: now, effects: [{ type: "turn-start" }] };
431
433
  }
432
434
  function beginSteer(prev, text) {
433
435
  return { ...prev, turns: [...prev.turns, { role: "user", text }], notice: null, openText: null, effects: [] };
@@ -31,7 +31,7 @@ import {
31
31
  toPermission,
32
32
  toolName,
33
33
  toolNames
34
- } from "../chunks/chunk-T5PZC5NA.js";
34
+ } from "../chunks/chunk-ZJ34IR2Z.js";
35
35
  import {
36
36
  applyReferences,
37
37
  cleanUserText,
@@ -163,6 +163,14 @@ export interface PilotState {
163
163
  olderCount: number;
164
164
  /** El `ghosty.history` que acompaña al snapshot que viene. */
165
165
  historyNext?: HistoryPage | null;
166
+ /**
167
+ * El último run se cortó del lado del servidor (deploy, caja caída): `RUN_FINISHED.metadata.interrupted`.
168
+ * `reason` ya viene en palabras de persona. Se ofrece «Continuar».
169
+ */
170
+ cutRun?: {
171
+ runId: string;
172
+ reason?: string;
173
+ } | null;
166
174
  /** Mensajes en espera de que termine el run vivo (steer rechazado). */
167
175
  queued: QueuedMessage[];
168
176
  /** Lo que estaba en espera cuando la persona detuvo: regresa a la caja (`n` cambia en cada vez). */
@@ -31,7 +31,7 @@ import {
31
31
  toPermission,
32
32
  toolName,
33
33
  toolNames
34
- } from "../chunks/chunk-T5PZC5NA.js";
34
+ } from "../chunks/chunk-ZJ34IR2Z.js";
35
35
  import {
36
36
  PilotHttpError,
37
37
  createAgUiTransport,
@@ -894,6 +894,8 @@ var STRINGS_ES = {
894
894
  steps: { waking: "Despertando al agente\u2026", session: "Preparando la sesi\xF3n\u2026", compacting: "Resumiendo la conversaci\xF3n\u2026" },
895
895
  loadOlder: "Cargar mensajes anteriores",
896
896
  loadingOlder: "Cargando\u2026",
897
+ continueRun: "Continuar",
898
+ runCut: "La respuesta se cort\xF3 antes de terminar.",
897
899
  queued: "Se manda cuando termine",
898
900
  subagentsWorking: (n) => n === 1 ? "1 agente trabajando" : `${n} agentes trabajando`,
899
901
  subagentsDone: (n) => n === 1 ? "1 agente termin\xF3" : `${n} agentes terminaron`,
@@ -967,6 +969,8 @@ var STRINGS_EN = {
967
969
  steps: { waking: "Waking the agent\u2026", session: "Starting the session\u2026", compacting: "Compacting the conversation\u2026" },
968
970
  loadOlder: "Load earlier messages",
969
971
  loadingOlder: "Loading\u2026",
972
+ continueRun: "Continue",
973
+ runCut: "The answer was cut off before it finished.",
970
974
  queued: "Sends when this finishes",
971
975
  subagentsWorking: (n) => n === 1 ? "1 agent working" : `${n} agents working`,
972
976
  subagentsDone: (n) => n === 1 ? "1 agent finished" : `${n} agents finished`,
@@ -2386,7 +2390,7 @@ function usePilot(transport, opts = {}) {
2386
2390
  ctrl.current = c;
2387
2391
  const steering = typeof input.forwardedProps?.steer === "string";
2388
2392
  const userMsg = input.messages[0];
2389
- if (!steering && (input.messages.length || input.resume?.length)) liveRun.current = input.runId;
2393
+ if (!steering && (input.messages.length || input.resume?.length || input.forwardedProps?.continueRun)) liveRun.current = input.runId;
2390
2394
  optsRef.current.onSend?.(input);
2391
2395
  let ended = false;
2392
2396
  try {
@@ -2406,6 +2410,11 @@ function usePilot(transport, opts = {}) {
2406
2410
  } catch (err) {
2407
2411
  if (c.signal.aborted) return;
2408
2412
  const code = err instanceof PilotHttpError ? err.code : void 0;
2413
+ if (code === "nothing_to_continue") {
2414
+ liveRun.current = null;
2415
+ commit({ ...ref.current, busy: false, turnStartedAt: 0, cutRun: null, effects: [] });
2416
+ return;
2417
+ }
2409
2418
  if ((code === "run_active" || code === "interrupt_pending") && !reopening) {
2410
2419
  if (userMsg) {
2411
2420
  const { text, attachments } = fromUserMessage(userMsg.content);
@@ -2571,10 +2580,16 @@ function usePilot(transport, opts = {}) {
2571
2580
  // eslint-disable-next-line react-hooks/exhaustive-deps
2572
2581
  [commit, runNow]
2573
2582
  );
2583
+ const continueRun = useCallback2(async () => {
2584
+ const cut = ref.current.cutRun;
2585
+ if (!cut || ref.current.busy || !transportRef.current) return;
2586
+ commit(beginSend(ref.current, "", []));
2587
+ await runNow({ messages: [], forwardedProps: { continueRun: cut.runId } });
2588
+ }, [commit, runNow]);
2574
2589
  const refresh = useCallback2(() => runNow({ messages: [] }, true), [runNow]);
2575
2590
  const canSteer = Boolean(transport) && (opts.steer ?? state.agentState.caps?.steer === true);
2576
2591
  const subagents = useMemo3(() => subagentsOf(state.agentState), [state.agentState]);
2577
- return { state, threadId, send, stop, retry, respondPermission, recordDecision, expirePermission, canSteer, loadOlder, loadingOlder, subagents, stopSubagent, refresh };
2592
+ return { state, threadId, send, stop, retry, respondPermission, recordDecision, expirePermission, canSteer, loadOlder, loadingOlder, subagents, stopSubagent, refresh, continueRun };
2578
2593
  }
2579
2594
 
2580
2595
  // src/react/Piloto.tsx
@@ -2893,6 +2908,19 @@ var Piloto = forwardRef3(function Piloto2(props, handle) {
2893
2908
  children: /* @__PURE__ */ jsx10(ArrowDown, { className: "h-4 w-4" })
2894
2909
  }
2895
2910
  ),
2911
+ state.cutRun && !busy && // El servidor cortó la respuesta (deploy, caja caída): la persona decide si sigue.
2912
+ /* @__PURE__ */ jsxs8("div", { "data-cut-run": true, role: "status", className: "mb-2 flex items-center gap-3 rounded-2xl border border-border-primary bg-background-secondary px-3 py-2 text-sm text-text-secondary", children: [
2913
+ /* @__PURE__ */ jsx10("span", { className: "min-w-0 flex-1", children: state.cutRun.reason ?? t.runCut }),
2914
+ /* @__PURE__ */ jsx10(
2915
+ "button",
2916
+ {
2917
+ type: "button",
2918
+ onClick: () => void pilot.continueRun(),
2919
+ className: "shrink-0 rounded-full bg-brand-500 px-3 py-1 text-sm font-medium text-white transition hover:bg-brand-600",
2920
+ children: t.continueRun
2921
+ }
2922
+ )
2923
+ ] }),
2896
2924
  aboveComposer,
2897
2925
  composer
2898
2926
  ] })
@@ -58,6 +58,10 @@ export interface PilotStrings {
58
58
  steps: Record<string, string>;
59
59
  loadOlder: string;
60
60
  loadingOlder: string;
61
+ /** El botón de la franja de un run cortado por el servidor (mismo rótulo en iOS y Android). */
62
+ continueRun: string;
63
+ /** La franja, si el servidor no dio razón. */
64
+ runCut: string;
61
65
  /** Bajo un mensaje que espera a que termine el run vivo. */
62
66
  queued: string;
63
67
  /** «2 agentes trabajando». */
@@ -82,6 +82,8 @@ export interface Pilot {
82
82
  * por fuera que algo cambió (p. ej. el bus `/me/events` avisa que un subagente terminó).
83
83
  */
84
84
  refresh: () => Promise<void>;
85
+ /** Continúa el run que el servidor cortó (`state.cutRun`): `forwardedProps.continueRun`. */
86
+ continueRun: () => Promise<void>;
85
87
  }
86
88
  /** El contexto de la app como `context` de AG-UI: `[{description, value}]`, `value` siempre texto. */
87
89
  export declare function toAgUiContext(ctx: unknown): RunAgentInput["context"];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ghostykit",
3
- "version": "0.6.1",
3
+ "version": "0.6.2",
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",