ghostykit 0.6.4 → 0.7.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/README.md +100 -19
- package/dist/chunks/{chunk-LPPND5ME.js → chunk-7M2B7VKH.js} +31 -146
- package/dist/chunks/{chunk-TMEHQZWL.js → chunk-KG23PQI2.js} +5 -2
- package/dist/chunks/chunk-PNU3LKWG.js +1798 -0
- package/dist/chunks/chunk-UUH37KXA.js +144 -0
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.js +12 -8
- package/dist/core/narration.d.ts +18 -1
- package/dist/core/types.d.ts +7 -0
- package/dist/plugins/index.d.ts +39 -0
- package/dist/plugins/index.js +129 -0
- package/dist/react/Bubble.d.ts +15 -1
- package/dist/react/Composer.d.ts +15 -3
- package/dist/react/Piloto.d.ts +18 -37
- package/dist/react/context.d.ts +6 -1
- package/dist/react/index.d.ts +4 -3
- package/dist/react/index.js +555 -1792
- package/dist/react/plugins.d.ts +249 -0
- package/dist/react/usePilot.d.ts +15 -0
- package/dist/styles.css +572 -548
- package/dist/transport/index.d.ts +3 -1
- package/dist/transport/index.js +1 -1
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -97,34 +97,115 @@ const ref = useRef<PilotoHandle>(null);
|
|
|
97
97
|
draft={{ text: "Why did the monitor fail?", key: row.id }} // prefilled + focused, not sent
|
|
98
98
|
threadId={conversationId} // reopen a stored thread
|
|
99
99
|
context={() => ({ screen: "crons", selected })} // AG-UI `context`, every run
|
|
100
|
-
toolVerbs={{ run_cron: { one: "Ran a cron", many: "Ran %n crons", running: "Running the cron…" } }}
|
|
101
|
-
upload={async (file) => ({ url: await myUpload(file) })}
|
|
102
|
-
transcribe={async (audio) => myWhisper(audio)}
|
|
103
100
|
onTurnDone={({ text }) => refreshMyData()}
|
|
104
|
-
|
|
101
|
+
plugins={PLUGINS} // everything else: see Customize
|
|
105
102
|
/>;
|
|
106
103
|
|
|
107
104
|
ref.current?.addReference({ id: "12", label: "#12 Rosa" }); // "@" a row into the message
|
|
108
105
|
ref.current?.send("Why did this fail?"); // ask on the user's behalf
|
|
109
106
|
```
|
|
110
107
|
|
|
111
|
-
Other
|
|
112
|
-
|
|
113
|
-
`
|
|
114
|
-
pages of a long thread), `forwardedProps` (extra keys for every run, e.g.
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
`turn.custom` (what `renderDeliveries` draws).
|
|
108
|
+
Other props: `features` (`attachments`, `retry`, `copy`, `usage`, `replyOptions`, `duration`,
|
|
109
|
+
`steer`, `narration`: `false` keeps the text written before each tool as part of the answer instead of
|
|
110
|
+
checked progress lines), `references` / `onReferencesChange`, `placeholder`, `avatar`, `initialTurns`, `loadOlder`
|
|
111
|
+
(earlier pages of a long thread), `forwardedProps` (extra keys for every run, e.g.
|
|
112
|
+
`{permissions: "ask"}`), and the callbacks `onTurnStart`, `onTitle`, `onState`, `onEvent` (every raw
|
|
113
|
+
AG-UI event), `onSend`. The agent's shared state (`STATE_SNAPSHOT` + `STATE_DELTA`) is
|
|
114
|
+
`pilot.state.agentState`, and each turn's `CUSTOM` events are `turn.custom`.
|
|
119
115
|
|
|
120
116
|
Subagents (`state.subagents.tasks`) are `pilot.subagents`; `pilot.stopSubagent(id)` stops one, and
|
|
121
|
-
`<Subagents pilot={pilot} />` is a ready-made bar ("2 agents working", one row each, *Stop*)
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
117
|
+
`<Subagents pilot={pilot} />` is a ready-made bar ("2 agents working", one row each, *Stop*). A
|
|
118
|
+
message the server can't take while a run is live (`409 run_active`) waits in `pilot.state.queued`
|
|
119
|
+
and is sent when that run ends. `pilot.refresh()` asks for the thread again (when your own event bus
|
|
120
|
+
says something changed). To read the state outside the chat, call `usePilot(transport)` yourself and
|
|
121
|
+
pass the result as `pilot`. Every piece is exported (`AgentBubble`, `AgentSteps`, `Composer`,
|
|
122
|
+
`ConfirmCard`, `Markdown`, …) if you want to build your own layout.
|
|
123
|
+
|
|
124
|
+
## Customize
|
|
125
|
+
|
|
126
|
+
There is **one** way to customize `<Piloto>`: **plugins**. A plugin is an object with a `name` and
|
|
127
|
+
named extension points. Everything a plugin draws is a React **component**: it is mounted as
|
|
128
|
+
`<View ctx={…} />`, so it can use hooks. Branding is the skin plus `--piloto-*` tokens.
|
|
129
|
+
|
|
130
|
+
```tsx
|
|
131
|
+
import { Piloto, definePlugin } from "ghostykit";
|
|
132
|
+
import { livePage, modelPicker, pilotDevtools } from "ghostykit/plugins";
|
|
133
|
+
|
|
134
|
+
const crm = definePlugin({
|
|
135
|
+
name: "crm",
|
|
136
|
+
requires: { events: ["crm.card"] }, // what it handles, visible at a glance
|
|
137
|
+
tools: { verbs: { find_lead: { one: "Found the lead", many: "Found %n leads", running: "Looking…" } } },
|
|
138
|
+
message: { custom: { "crm.card": ({ entry, ctx }) => <LeadCard lead={entry.value} onOpen={() => ctx.send("Open it")} /> } },
|
|
139
|
+
composer: { actions: ({ ctx }) => <PointButton onPick={(row) => ctx.addReference(row)} /> },
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// Create them ONCE (module scope or useMemo): some plugins keep state.
|
|
143
|
+
const PLUGINS = [crm, modelPicker({ onChange: (model) => api.setModel(model) }), livePage(), pilotDevtools()];
|
|
144
|
+
|
|
145
|
+
<Piloto transport={transport} skin="ghosty" plugins={PLUGINS} />;
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
| Point | What it does | Example |
|
|
149
|
+
|---|---|---|
|
|
150
|
+
| `name` | Unique. Marks everything it draws with `data-plugin="<name>"`. | `"crm"` |
|
|
151
|
+
| `styles` | Whose styles its views use. `"host"` (default): your app's; ghostykit's utilities stay out (`data-piloto-isolate`), so they never override your classes. `"ghostykit"`: for views built from ghostykit components (`<Subagents>`, `ModelPicker`). | `"ghostykit"` |
|
|
152
|
+
| `requires` | `{events, state}` it handles. Derived from `events`/`state`/`message.custom` if missing; in development a mismatch is a warning. | `{ events: ["ghosty.page"] }` |
|
|
153
|
+
| `strings` | Texts over the locale's. | `{ stop: "Para" }` |
|
|
154
|
+
| `markdown.transform` | Rewrites the answer's markdown, with the turn at hand (chained). | `(md, turn) => md.replace(/#(\d+)/g, "[#$1](#folio-$1)")` |
|
|
155
|
+
| `markdown.onLinkClick` | A click on a link; `true` if handled (asked in order). | open in-app |
|
|
156
|
+
| `markdown.components` | How a markdown element is drawn, by tag (gets its props and `ctx`): e.g. a link that is a CTA as a button. | `{ a: ({ href, children, ctx }) => … }` |
|
|
157
|
+
| `markdown.blocks` | Fenced blocks by name (```` ```eb-file ````) taken out of the text and drawn as cards under the answer; one still being written comes with `complete: false`. | `{ "eb-file": FileCard }` |
|
|
158
|
+
| `vars`, `className` | Branding on the root: `--piloto-*` tokens and classes. | `{ "--piloto-radius-bubble": "6px" }` |
|
|
159
|
+
| `tools.verbs` | How each tool is named in the steps. | `{ run_cron: { one, many, running } }` |
|
|
160
|
+
| `tools.icons` | Icon by tool name or `kind`. | `{ run_cron: Clock }` |
|
|
161
|
+
| `tools.render` | A tool's own view, under the steps, by tool name or `kind`. | `{ create_image: ImagePreview }` |
|
|
162
|
+
| `events` | Handlers by AG-UI type, by `CUSTOM` name, or `*`. | `{ "ghosty.ui": (e, ctx) => board.open(e.value) }` |
|
|
163
|
+
| `state` | Called when that key of `agentState` changes. | `{ model: (v, ctx) => … }` |
|
|
164
|
+
| `message.custom` | Draws a `turn.custom` entry by its name (deliveries, CRM cards). | `{ "ghosty.delivery": DeliveryCard }` |
|
|
165
|
+
| `message.assistantBefore` | Before each answer's text, under its steps. | live page progress, "Creating image…" |
|
|
166
|
+
| `message.user` / `message.assistant` | Extras under each user message / answer. | `({ turn, live }) => …` |
|
|
167
|
+
| `message.formatUserText` | How the user's text is shown (chained). | strip app plumbing |
|
|
168
|
+
| `message.beforeSend` | Rewrites the text that goes out (chained). | prepend what was pointed at |
|
|
169
|
+
| `message.avatar` | The agent's avatar next to each answer. | `() => <img src={logo} />` |
|
|
170
|
+
| `composer.actions` | Buttons in the composer bar, between the image button and the clip. | "My files", "Point" |
|
|
171
|
+
| `composer.actionsEnd` | Buttons after the clip. | model picker |
|
|
172
|
+
| `composer.above` | Above the message box. | `<Subagents pilot={ctx.pilot} />` |
|
|
173
|
+
| `composer.below` | Under the message box. | suggestion chips |
|
|
174
|
+
| `composer.attachments` | `upload`, `transcribe`, `voiceNoteText`, and the limits `accept`, `maxFiles`, `maxBytes`. A voice note keeps its audio attached when there is `upload`. | `{ upload, accept: "image/*", maxFiles: 4, maxBytes: 4_000_000 }` |
|
|
175
|
+
| `composer.replace` | `{ when(ctx), view }`: drawn instead of the message box while `when` is true. | trial over (403 + `x-needs-login`) → "Create your account" |
|
|
176
|
+
| `header` | Top right, over the thread. | share button |
|
|
177
|
+
| `sidePanel` | Next to the chat. | live page, subagents |
|
|
178
|
+
| `aboveThread` | Above the messages. | a banner |
|
|
179
|
+
| `empty` | The empty thread (instead of the greeting). | onboarding |
|
|
180
|
+
| `waiting` | While the agent hasn't answered (instead of the waiting phrase). Gets `step`, `since`. | "Creating your image…" |
|
|
181
|
+
| `wrap` | A provider around the whole chat (`{ctx, children}`); the first plugin is outermost. | artifacts panel |
|
|
182
|
+
| `onHttpError` | The server refused a message before answering (`{status, code, message, headers}`; also in `pilot.state.httpError` until the next send). | 429 → upgrade banner |
|
|
183
|
+
| `onTurnStart` / `onTurnDone` | This client started / finished a turn. | open the last delivery |
|
|
184
|
+
|
|
185
|
+
Every view gets `ctx`: `{pilot, agentState, strings, send, addReference, addAttachments, setDraft, focus, plugins}`.
|
|
186
|
+
`addAttachments` takes `File`s (they go through `upload`) or ready `Attachment`s (e.g. from "My files"),
|
|
187
|
+
and they can be sent without text. The `ref` of `<Piloto>` is the same handle (without `plugins`,
|
|
188
|
+
`strings`, `agentState`), so the app never needs a separate `usePilot`: `ref.current.addReference(…)`,
|
|
189
|
+
`ref.current.pilot.reconnect()` (when your own event bus says the thread changed),
|
|
190
|
+
`ref.current.pilot.stop()`. `initialPrompt` sends a message as soon as the thread is open (a question
|
|
191
|
+
in the URL).
|
|
192
|
+
|
|
193
|
+
**Order and precedence**, in the order of the `plugins` list:
|
|
194
|
+
|
|
195
|
+
- **Maps** (`strings`, `tools.verbs`, `tools.icons`, `vars`) are merged, and later plugins win. `markdown.transform`, `formatUserText` and `beforeSend` are chained.
|
|
196
|
+
- **`events` and `state`** call every handler, in order.
|
|
197
|
+
- **Keyed or single views** (`tools.render`, `message.custom`, `markdown.blocks`, `markdown.components`, `message.avatar`, `empty`, `waiting`, `composer.attachments`, `composer.replace`): the first plugin that declares one wins. A clash is a development warning.
|
|
198
|
+
- **Lists** (`header`, `sidePanel`, `aboveThread`, `composer.actions`/`actionsEnd`/`above`/`below`, `message.user`/`assistant`/`assistantBefore`, `wrap`, `onTurnStart`/`onTurnDone`) all apply, in order.
|
|
199
|
+
|
|
200
|
+
In development, ghostykit also warns once about a `CUSTOM` event that nothing handles.
|
|
201
|
+
|
|
202
|
+
**Ready-made plugins** (`ghostykit/plugins`), usable as they are and as templates:
|
|
203
|
+
|
|
204
|
+
| Plugin | What it does |
|
|
205
|
+
|---|---|
|
|
206
|
+
| `modelPicker({ onChange, stateKey? })` | The model picker in the composer bar, from `agentState.model = {current, options}`. Switching is your API (`onChange`). |
|
|
207
|
+
| `livePage({ width? })` | A side panel that follows `CUSTOM ghosty.page` (plan, sections, ready, error) with the link at the end. |
|
|
208
|
+
| `pilotDevtools({ events? })` | Prints the mounted plugins, their points and what they handle; with `events: true`, every event and who handles it. |
|
|
128
209
|
|
|
129
210
|
### Skins and theming
|
|
130
211
|
|
|
@@ -439,7 +439,7 @@ function finish(s0, e, now, failed = false) {
|
|
|
439
439
|
}
|
|
440
440
|
function beginSend(prev, text, attachments = [], now = Date.now()) {
|
|
441
441
|
const turns = text || attachments.length ? [...prev.turns, { role: "user", text, ...attachments.length ? { attachments } : {} }] : prev.turns;
|
|
442
|
-
return { ...prev, turns, busy: true, error: null, notice: null, cutRun: null, turnStartedAt: now, effects: [{ type: "turn-start" }] };
|
|
442
|
+
return { ...prev, turns, busy: true, error: null, notice: null, cutRun: null, httpError: null, turnStartedAt: now, effects: [{ type: "turn-start" }] };
|
|
443
443
|
}
|
|
444
444
|
function beginSteer(prev, text) {
|
|
445
445
|
return { ...prev, turns: [...prev.turns, { role: "user", text }], notice: null, openText: null, effects: [] };
|
|
@@ -540,7 +540,7 @@ function isNarration(chunk) {
|
|
|
540
540
|
const t = chunk.trim();
|
|
541
541
|
return t.length > 0 && t.length <= 300 && !/\n\s*\n/.test(t) && !t.includes("```");
|
|
542
542
|
}
|
|
543
|
-
function splitNarration(text, cuts) {
|
|
543
|
+
function splitNarration(text, cuts, closed = false) {
|
|
544
544
|
if (cuts?.length) {
|
|
545
545
|
const valid = cuts.filter((c) => c > 0 && c <= text.length);
|
|
546
546
|
if (valid.length) {
|
|
@@ -552,7 +552,9 @@ function splitNarration(text, cuts) {
|
|
|
552
552
|
from = c;
|
|
553
553
|
}
|
|
554
554
|
if (chunks.every(isNarration)) {
|
|
555
|
-
|
|
555
|
+
const rest = text.slice(from).replace(/^\s+/, "");
|
|
556
|
+
if (closed && !rest.trim()) return { steps: chunks.slice(0, -1).map((t) => t.replace(/\s*\n\s*/g, " ")), rest: chunks[chunks.length - 1] };
|
|
557
|
+
return { steps: chunks.map((t) => t.replace(/\s*\n\s*/g, " ")), rest };
|
|
556
558
|
}
|
|
557
559
|
}
|
|
558
560
|
return { steps: [], rest: text };
|
|
@@ -576,6 +578,30 @@ function narrationToMarkdown(chunks, answer) {
|
|
|
576
578
|
|
|
577
579
|
${answer.trim()}` : list;
|
|
578
580
|
}
|
|
581
|
+
function extractBlocks(text, langs, cuts) {
|
|
582
|
+
if (!langs.length || !text.includes("```")) return { text, cuts, blocks: [] };
|
|
583
|
+
const want = new Set(langs);
|
|
584
|
+
const blocks = [];
|
|
585
|
+
const removed = [];
|
|
586
|
+
const re = /(^|\n)```([\w.-]+)[^\n]*\n([\s\S]*?)(\n```[ \t]*(?=\n|$)|$)/g;
|
|
587
|
+
for (let m = re.exec(text); m; m = re.exec(text)) {
|
|
588
|
+
if (!want.has(m[2])) continue;
|
|
589
|
+
const start = m.index + m[1].length;
|
|
590
|
+
const end = m.index + m[0].length;
|
|
591
|
+
blocks.push({ lang: m[2], body: m[3], complete: Boolean(m[4]) });
|
|
592
|
+
removed.push([start, end]);
|
|
593
|
+
}
|
|
594
|
+
if (!removed.length) return { text, cuts, blocks };
|
|
595
|
+
let out = "";
|
|
596
|
+
let from = 0;
|
|
597
|
+
for (const [a, b] of removed) {
|
|
598
|
+
out += text.slice(from, a);
|
|
599
|
+
from = b;
|
|
600
|
+
}
|
|
601
|
+
out += text.slice(from);
|
|
602
|
+
const shift = (c) => c - removed.reduce((n, [a, b]) => n + (c >= b ? b - a : c > a ? c - a : 0), 0);
|
|
603
|
+
return { text: out, ...cuts ? { cuts: cuts.map(shift) } : {}, blocks };
|
|
604
|
+
}
|
|
579
605
|
|
|
580
606
|
// src/core/options.ts
|
|
581
607
|
var BULLET = /^\s*(?:[-*•+]|(\d{1,2})[.)])\s+(.+?)\s*$/;
|
|
@@ -606,140 +632,6 @@ function cleanReplyOption(t) {
|
|
|
606
632
|
return s.charAt(0).toLocaleUpperCase() + s.slice(1);
|
|
607
633
|
}
|
|
608
634
|
|
|
609
|
-
// src/core/steps.ts
|
|
610
|
-
var isRunning = (t) => t.status !== "completed" && t.status !== "failed" && t.status !== "cancelled";
|
|
611
|
-
function toolNames(t) {
|
|
612
|
-
const title = t.title ?? "";
|
|
613
|
-
if (!title) return [];
|
|
614
|
-
const out = [title];
|
|
615
|
-
const double = /^mcp__.+?__(.+)$/i.exec(title);
|
|
616
|
-
if (double) out.push(double[1]);
|
|
617
|
-
else if (/^mcp_/i.test(title)) {
|
|
618
|
-
const parts = title.slice(4).split("_");
|
|
619
|
-
for (let i = 0; i < parts.length; i++) out.push(parts.slice(i).join("_"));
|
|
620
|
-
}
|
|
621
|
-
return [...new Set(out)];
|
|
622
|
-
}
|
|
623
|
-
function toolName(t) {
|
|
624
|
-
const names = toolNames(t);
|
|
625
|
-
return /^mcp__/i.test(names[0] ?? "") ? names[1] ?? names[0] : names[0] ?? null;
|
|
626
|
-
}
|
|
627
|
-
function namedVerb(t, verbs) {
|
|
628
|
-
for (const name of toolNames(t)) if (verbs[name]) return { key: name, verb: verbs[name] };
|
|
629
|
-
return null;
|
|
630
|
-
}
|
|
631
|
-
function stepLabel(t, verbs, fallback = "Paso") {
|
|
632
|
-
if (t.label) return t.label;
|
|
633
|
-
const named = namedVerb(t, verbs);
|
|
634
|
-
if (named) return isRunning(t) && named.verb.running ? named.verb.running : named.verb.one;
|
|
635
|
-
return t.title ?? t.kind ?? fallback;
|
|
636
|
-
}
|
|
637
|
-
function summarizeTools(tools, verbs) {
|
|
638
|
-
const groups = /* @__PURE__ */ new Map();
|
|
639
|
-
for (const t of tools) {
|
|
640
|
-
const named = namedVerb(t, verbs);
|
|
641
|
-
const key = named?.key ?? t.kind ?? "other";
|
|
642
|
-
const g = groups.get(key) ?? { n: 0, verb: named?.verb ?? verbs[key] };
|
|
643
|
-
g.n++;
|
|
644
|
-
groups.set(key, g);
|
|
645
|
-
}
|
|
646
|
-
const parts = [];
|
|
647
|
-
for (const [key, { n, verb }] of groups) {
|
|
648
|
-
if (verb) parts.push(n === 1 ? verb.one : verb.many.replace("%n", String(n)));
|
|
649
|
-
else parts.push(`${n} \xD7 ${key.replace(/[_-]/g, " ")}`);
|
|
650
|
-
}
|
|
651
|
-
return parts.join(" \xB7 ");
|
|
652
|
-
}
|
|
653
|
-
function groupSteps(tools, label) {
|
|
654
|
-
const groups = /* @__PURE__ */ new Map();
|
|
655
|
-
for (const t of tools) {
|
|
656
|
-
const k = `${label(t)}\0${t.detail ?? ""}`;
|
|
657
|
-
const g = groups.get(k);
|
|
658
|
-
if (!g) {
|
|
659
|
-
groups.set(k, { tool: t, times: 1 });
|
|
660
|
-
continue;
|
|
661
|
-
}
|
|
662
|
-
g.times++;
|
|
663
|
-
const wins = isRunning(t) || t.status === "failed" || !(isRunning(g.tool) || g.tool.status === "failed");
|
|
664
|
-
if (wins) g.tool = { ...t, id: g.tool.id };
|
|
665
|
-
}
|
|
666
|
-
return [...groups.values()];
|
|
667
|
-
}
|
|
668
|
-
var TOOL_VERBS_ES = {
|
|
669
|
-
read: { one: "Le\xED un archivo", many: "Le\xED %n archivos" },
|
|
670
|
-
read_file: { one: "Le\xED un archivo", many: "Le\xED %n archivos" },
|
|
671
|
-
write: { one: "Escrib\xED un archivo", many: "Escrib\xED %n archivos" },
|
|
672
|
-
write_file: { one: "Escrib\xED un archivo", many: "Escrib\xED %n archivos" },
|
|
673
|
-
edit: { one: "Edit\xE9 un archivo", many: "Edit\xE9 %n archivos" },
|
|
674
|
-
edit_file: { one: "Edit\xE9 un archivo", many: "Edit\xE9 %n archivos" },
|
|
675
|
-
bash: { one: "Corr\xED un comando", many: "Corr\xED %n comandos" },
|
|
676
|
-
shell: { one: "Corr\xED un comando", many: "Corr\xED %n comandos" },
|
|
677
|
-
terminal: { one: "Corr\xED un comando", many: "Corr\xED %n comandos" },
|
|
678
|
-
execute: { one: "Corr\xED un comando", many: "Corr\xED %n comandos" },
|
|
679
|
-
grep: { one: "Busqu\xE9 en el c\xF3digo", many: "Busqu\xE9 en el c\xF3digo" },
|
|
680
|
-
glob: { one: "Busqu\xE9 archivos", many: "Busqu\xE9 archivos" },
|
|
681
|
-
search: { one: "Busqu\xE9", many: "Busqu\xE9 %n veces" },
|
|
682
|
-
tool_search: { one: "Busqu\xE9 una herramienta", many: "Busqu\xE9 %n herramientas" },
|
|
683
|
-
web_search: { one: "Busqu\xE9 en la web", many: "Busqu\xE9 en la web" },
|
|
684
|
-
web_fetch: { one: "Abr\xED una p\xE1gina", many: "Abr\xED %n p\xE1ginas" },
|
|
685
|
-
fetch: { one: "Abr\xED una p\xE1gina", many: "Abr\xED %n p\xE1ginas" },
|
|
686
|
-
site_publish: { one: "Publiqu\xE9 una p\xE1gina", many: "Publiqu\xE9 %n p\xE1ginas" },
|
|
687
|
-
pdf: { one: "Gener\xE9 un PDF", many: "Gener\xE9 %n PDF" },
|
|
688
|
-
connector: { one: "Us\xE9 tu sistema", many: "Us\xE9 tu sistema %n veces" },
|
|
689
|
-
mcp: { one: "Us\xE9 una herramienta", many: "Us\xE9 %n herramientas" },
|
|
690
|
-
browser: { one: "Us\xE9 el navegador", many: "Us\xE9 el navegador" },
|
|
691
|
-
todo: { one: "Anot\xE9 el plan", many: "Anot\xE9 el plan" },
|
|
692
|
-
delete: { one: "Borr\xE9 un archivo", many: "Borr\xE9 %n archivos" },
|
|
693
|
-
move: { one: "Mov\xED un archivo", many: "Mov\xED %n archivos" },
|
|
694
|
-
think: { one: "Lo pens\xE9", many: "Lo pens\xE9" },
|
|
695
|
-
image: { one: "Cre\xE9 una imagen", many: "Cre\xE9 %n im\xE1genes" },
|
|
696
|
-
delegate: { one: "Delegu\xE9 una tarea", many: "Delegu\xE9 %n tareas" },
|
|
697
|
-
collect: { one: "Recog\xED un resultado", many: "Recog\xED %n resultados" },
|
|
698
|
-
status: { one: "Pregunt\xE9 c\xF3mo iba", many: "Pregunt\xE9 %n veces c\xF3mo iba" },
|
|
699
|
-
stop: { one: "Detuve una tarea", many: "Detuve %n tareas" },
|
|
700
|
-
guide: { one: "Le\xED una gu\xEDa", many: "Le\xED %n gu\xEDas" },
|
|
701
|
-
deliver: { one: "Entregu\xE9 un archivo", many: "Entregu\xE9 %n archivos" },
|
|
702
|
-
sheet: { one: "Consult\xE9 una hoja", many: "Consult\xE9 %n hojas" },
|
|
703
|
-
view: { one: "Arm\xE9 una vista", many: "Arm\xE9 %n vistas" }
|
|
704
|
-
};
|
|
705
|
-
var TOOL_VERBS_EN = {
|
|
706
|
-
read: { one: "Read a file", many: "Read %n files" },
|
|
707
|
-
read_file: { one: "Read a file", many: "Read %n files" },
|
|
708
|
-
write: { one: "Wrote a file", many: "Wrote %n files" },
|
|
709
|
-
write_file: { one: "Wrote a file", many: "Wrote %n files" },
|
|
710
|
-
edit: { one: "Edited a file", many: "Edited %n files" },
|
|
711
|
-
edit_file: { one: "Edited a file", many: "Edited %n files" },
|
|
712
|
-
bash: { one: "Ran a command", many: "Ran %n commands" },
|
|
713
|
-
shell: { one: "Ran a command", many: "Ran %n commands" },
|
|
714
|
-
terminal: { one: "Ran a command", many: "Ran %n commands" },
|
|
715
|
-
execute: { one: "Ran a command", many: "Ran %n commands" },
|
|
716
|
-
grep: { one: "Searched the code", many: "Searched the code" },
|
|
717
|
-
glob: { one: "Searched for files", many: "Searched for files" },
|
|
718
|
-
search: { one: "Searched", many: "Searched %n times" },
|
|
719
|
-
tool_search: { one: "Looked for a tool", many: "Looked for %n tools" },
|
|
720
|
-
web_search: { one: "Searched the web", many: "Searched the web" },
|
|
721
|
-
web_fetch: { one: "Opened a page", many: "Opened %n pages" },
|
|
722
|
-
fetch: { one: "Opened a page", many: "Opened %n pages" },
|
|
723
|
-
site_publish: { one: "Published a page", many: "Published %n pages" },
|
|
724
|
-
pdf: { one: "Generated a PDF", many: "Generated %n PDFs" },
|
|
725
|
-
connector: { one: "Used your system", many: "Used your system %n times" },
|
|
726
|
-
mcp: { one: "Used a tool", many: "Used %n tools" },
|
|
727
|
-
browser: { one: "Used the browser", many: "Used the browser" },
|
|
728
|
-
todo: { one: "Wrote down the plan", many: "Wrote down the plan" },
|
|
729
|
-
delete: { one: "Deleted a file", many: "Deleted %n files" },
|
|
730
|
-
move: { one: "Moved a file", many: "Moved %n files" },
|
|
731
|
-
think: { one: "Thought it through", many: "Thought it through" },
|
|
732
|
-
image: { one: "Created an image", many: "Created %n images" },
|
|
733
|
-
delegate: { one: "Delegated a task", many: "Delegated %n tasks" },
|
|
734
|
-
collect: { one: "Collected a result", many: "Collected %n results" },
|
|
735
|
-
status: { one: "Checked how it was going", many: "Checked %n times how it was going" },
|
|
736
|
-
stop: { one: "Stopped a task", many: "Stopped %n tasks" },
|
|
737
|
-
guide: { one: "Read a guide", many: "Read %n guides" },
|
|
738
|
-
deliver: { one: "Delivered a file", many: "Delivered %n files" },
|
|
739
|
-
sheet: { one: "Checked a sheet", many: "Checked %n sheets" },
|
|
740
|
-
view: { one: "Built a view", many: "Built %n views" }
|
|
741
|
-
};
|
|
742
|
-
|
|
743
635
|
export {
|
|
744
636
|
applyJsonPatch,
|
|
745
637
|
createPilotState,
|
|
@@ -763,14 +655,7 @@ export {
|
|
|
763
655
|
isNarration,
|
|
764
656
|
splitNarration,
|
|
765
657
|
narrationToMarkdown,
|
|
658
|
+
extractBlocks,
|
|
766
659
|
extractReplyOptions,
|
|
767
|
-
cleanReplyOption
|
|
768
|
-
isRunning,
|
|
769
|
-
toolNames,
|
|
770
|
-
toolName,
|
|
771
|
-
stepLabel,
|
|
772
|
-
summarizeTools,
|
|
773
|
-
groupSteps,
|
|
774
|
-
TOOL_VERBS_ES,
|
|
775
|
-
TOOL_VERBS_EN
|
|
660
|
+
cleanReplyOption
|
|
776
661
|
};
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
// src/transport/index.ts
|
|
2
2
|
var PilotHttpError = class extends Error {
|
|
3
|
-
constructor(message, status, code, retryAfter) {
|
|
3
|
+
constructor(message, status, code, retryAfter, headers) {
|
|
4
4
|
super(message);
|
|
5
5
|
this.name = "PilotHttpError";
|
|
6
6
|
this.status = status;
|
|
7
7
|
this.code = code;
|
|
8
8
|
this.retryAfter = retryAfter;
|
|
9
|
+
this.headers = headers;
|
|
9
10
|
}
|
|
10
11
|
};
|
|
11
12
|
async function readSse(body, onMessage) {
|
|
@@ -62,7 +63,9 @@ function createAgUiTransport(opts) {
|
|
|
62
63
|
}
|
|
63
64
|
if (!res.ok) {
|
|
64
65
|
const json = await res.json().catch(() => null);
|
|
65
|
-
|
|
66
|
+
const headers = {};
|
|
67
|
+
res.headers?.forEach?.((v, k) => void (headers[k.toLowerCase()] = v));
|
|
68
|
+
throw new PilotHttpError(json?.message ?? json?.error ?? `Error ${res.status}`, res.status, json?.error, retryAfter, headers);
|
|
66
69
|
}
|
|
67
70
|
if (!res.body) return;
|
|
68
71
|
const serverDate = Date.parse(res.headers.get("date") ?? "");
|