@heroui/agent 1.0.0-beta.1 → 1.0.0-beta.11
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/CHANGELOG.md +60 -0
- package/README.md +195 -72
- package/dist/chunk-AMNE7O54.js +1 -0
- package/dist/chunk-AR424OVX.js +1 -0
- package/dist/chunk-FZXNXBTZ.js +1 -0
- package/dist/chunk-IGSNBYO2.js +1 -0
- package/dist/chunk-KFWXAD55.js +1 -0
- package/dist/chunk-QSLALU5G.js +1 -0
- package/dist/client-tools-manifest-PCUOVUXR.js +1 -0
- package/dist/css/index.css +1 -2
- package/dist/index.d.ts +9 -669
- package/dist/index.js +1 -1
- package/dist/internal/host.d.ts +188 -0
- package/dist/internal/host.js +1 -0
- package/dist/internal/shared.d.ts +67 -0
- package/dist/internal/shared.js +1 -0
- package/dist/next.d.ts +3 -4
- package/dist/next.js +1 -1
- package/dist/persistence-YI6JSYCT.js +1 -0
- package/dist/server.d.ts +23 -2
- package/dist/server.js +1 -1
- package/dist/types-C3g7R0hr.d.ts +592 -0
- package/dist/version-BNdyk3rt.d.ts +5 -0
- package/dist/zod.d.ts +1 -0
- package/dist/zod.js +5 -0
- package/package.json +25 -37
- package/dist/chart-content-BBHQVMP4.js +0 -1
- package/dist/chunk-4JEZZR5J.js +0 -1
- package/dist/chunk-5RHO3S5E.js +0 -2
- package/dist/chunk-64RI74L5.js +0 -1
- package/dist/chunk-6ZJJN322.js +0 -1
- package/dist/chunk-7KCGPNEN.js +0 -1
- package/dist/chunk-BBB5EHDN.js +0 -5
- package/dist/chunk-CLHBM3HQ.js +0 -1
- package/dist/chunk-CR3H7AVI.js +0 -1
- package/dist/chunk-HCLXS4HQ.js +0 -1
- package/dist/chunk-PZJ4NC3J.js +0 -1
- package/dist/chunk-RNNGE7KM.js +0 -1
- package/dist/chunk-S6OIAJSC.js +0 -1
- package/dist/chunk-UHHKMESI.js +0 -1
- package/dist/chunk-USFF5UMB.js +0 -2
- package/dist/component-renderer-XOCP6UFF.js +0 -1
- package/dist/composer-draft-NSKK65F3.js +0 -1
- package/dist/composer-image-draft-KAGTNQR7.js +0 -1
- package/dist/contracts.d.ts +0 -1651
- package/dist/contracts.js +0 -2
- package/dist/embed-runtime-FP77ORXA.js +0 -5
- package/dist/identity-3P8-17km.d.ts +0 -95
- package/dist/interactive-map-surface-WC2LPCR7.js +0 -1
- package/dist/internal/client-tools.js +0 -1
- package/dist/internal/models.js +0 -1
- package/dist/internal/runtime.js +0 -1
- package/dist/internal/theme.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,66 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
- Preserve thrown client-tool messages and distinguish oversized results from invalid JSON. Logs, Runs API responses, exports, and webhook run payloads include bounded tool-error details.
|
|
6
|
+
- Reject reserved client-tool names at mount with an actionable error; stop repeating configuration failures and bound iframe handshake retries with backoff.
|
|
7
|
+
- Stop the exact in-flight turn without requeueing its prompt, including when admission is still pending. Queued follow-ups remain paused.
|
|
8
|
+
- Support pasting images into the composer through the existing attachment validation and upload flow.
|
|
9
|
+
- Keep provider reasoning headings out of progress labels and discard unexpected Chinese text in generated titles while preserving Chinese and Japanese conversations.
|
|
10
|
+
- Return actionable OpenUI validation errors with component signatures so the agent can repair a view using the same data. The partner's original intermittent chart failure has not been reproduced.
|
|
11
|
+
- Overlap independent API admission checks and expose their individual timing spans. Controlled API timing improved; the reported production admission delay still needs its original trace.
|
|
12
|
+
- Fix shared context typing for interfaces while retaining validation of the reserved `page` callback.
|
|
13
|
+
- Hide dictation when iframe microphone policy explicitly blocks it; preserve explicit opt-out.
|
|
14
|
+
- Add launcher `iconSize` and opt-in mobile sheets with configurable height. Existing sizing and full-screen defaults remain unchanged.
|
|
15
|
+
- Export pinned `z` from `@heroui/agent/zod` and align anonymous/sign-in token examples.
|
|
16
|
+
- Add descriptive server-assigned token metadata, snapshotted per run.
|
|
17
|
+
- Hosted dashboard: preserve edited color alpha, explain prop precedence, and configure signed webhooks for selected run events (`run.started`, `run.completed`, `run.failed`, and `run.cancelled`) with delivery status.
|
|
18
|
+
- Automatically pause webhooks after five consecutive exhausted delivery cycles, resume from the dashboard, and retry individual failed events with their original payload and event ID. Preserve attempt history and bound internal queue recovery.
|
|
19
|
+
- Preserve elapsed "Worked for" duration across transcript reloads.
|
|
20
|
+
- Expose available run timing data for diagnosis. Fast tool execution alone does not establish total-response latency; no measured latency improvement is claimed in this release.
|
|
21
|
+
|
|
22
|
+
- Add `locale` to React and vanilla integrations, including `auto` for browser language detection, regional formatting, and optional `translations` for custom copy by language.
|
|
23
|
+
- Select localized agent copy using the SDK override or saved agent default. AI responses follow the user's language.
|
|
24
|
+
|
|
25
|
+
## Unreleased
|
|
26
|
+
|
|
27
|
+
- Move the model catalog, attachment limits and MIME allowlist, and design theme
|
|
28
|
+
list out of the published package and into the hosted runtime. Adding a model,
|
|
29
|
+
attachment type, or theme variant no longer requires a customer npm release.
|
|
30
|
+
Removed exports: `AGENT_MODEL_IDS`, `AGENT_MODEL_OPTIONS`,
|
|
31
|
+
`DEFAULT_AGENT_PICKER_MODEL_ID`, `LEGACY_AGENT_MODEL_IDS`,
|
|
32
|
+
`resolveAgentModelId`, `isAgentModelId`, `getAgentModelTier`,
|
|
33
|
+
`AgentModelOption`, `AgentModelTier`, `AGENT_DESIGN_THEMES`, every
|
|
34
|
+
`HEROUI_AGENT_*ATTACHMENT*` constant, `isHeroUIAgentAttachmentContentType`,
|
|
35
|
+
`resolveHeroUIAgentAttachmentContentType`, and
|
|
36
|
+
`HeroUIAgentAttachmentContentType`.
|
|
37
|
+
- Type `composer.defaultModel` (`AgentModelId`), `composer.attachments`
|
|
38
|
+
(`AgentAttachmentContentType`), and `theme.designTheme` (`AgentDesignTheme`)
|
|
39
|
+
as plain strings. The hosted runtime validates them: retired model ids resolve
|
|
40
|
+
to their replacement, unknown model ids fall back to the hosted default,
|
|
41
|
+
unsupported attachment types are dropped, and unknown design themes render
|
|
42
|
+
`base`.
|
|
43
|
+
- Accept client tool results and page context whose optional fields are
|
|
44
|
+
`undefined`. The bridge previously rejected them as not JSON-serializable
|
|
45
|
+
even though `JSON.stringify` drops them; it now forwards the canonical JSON.
|
|
46
|
+
- Move the visible Agent UI into a cross-origin iframe hosted by HeroUI. This is
|
|
47
|
+
the one-time host-bridge upgrade; UI, renderer, chart, PDF/XLSX, and backend
|
|
48
|
+
changes no longer require another customer npm release.
|
|
49
|
+
- Keep client tools, product context, navigation, mutations, identity, drafts,
|
|
50
|
+
attachments, and the durable message outbox in the customer page behind the
|
|
51
|
+
origin- and session-bound iframe RPC boundary.
|
|
52
|
+
- Replace custom React tool/Markdown renderers and React icon components with
|
|
53
|
+
hosted declarative UI and HeroUI-owned icon identifiers.
|
|
54
|
+
- Keep `@heroui/agent/css` as a compatibility no-op; the iframe ships its own
|
|
55
|
+
hashed, code-split styles and assets.
|
|
56
|
+
- Move the full conversation implementation into the private
|
|
57
|
+
`@heroui/agent-hosted-runtime` workspace package. The published package keeps
|
|
58
|
+
only the host bridge, public types, client tools, and server helper, and
|
|
59
|
+
no longer installs Streamdown as a customer dependency.
|
|
60
|
+
- Move runtime, telemetry, remote configuration, token-claim, and generated UI
|
|
61
|
+
schemas into the private `@heroui/agent-runtime-contracts` workspace
|
|
62
|
+
package. Remove the beta-only public `@heroui/agent/contracts` entry point.
|
|
63
|
+
- Retire `@heroui/agent-client`; its session manager now belongs to the public
|
|
64
|
+
bridge, while conversation targeting and history belong to the hosted runtime.
|
|
5
65
|
- Keep the built-in Agent palette isolated from generic host variables such as
|
|
6
66
|
`--background` and `--foreground`, which may contain framework-specific color
|
|
7
67
|
channels rather than valid CSS colors and previously made panels transparent.
|
package/README.md
CHANGED
|
@@ -2,23 +2,54 @@
|
|
|
2
2
|
|
|
3
3
|
# HeroUI Agents SDK
|
|
4
4
|
|
|
5
|
-
Embed a hosted generative-UI agent in
|
|
5
|
+
Embed a hosted generative-UI agent in any modern website. Use
|
|
6
|
+
[`@heroui/agent`](https://heroui.pro/agents) for typed React integrations, or the CDN loader with
|
|
7
|
+
vanilla JavaScript. The hosted runtime plans answers, runs calculations in a sandbox, and streams
|
|
8
|
+
back charts, tables, and metrics.
|
|
6
9
|
|
|
7
|
-
|
|
10
|
+
The npm package contains only the iframe bridge, public types, client-tool executor, and server
|
|
11
|
+
token helper. The full conversation UI lives in the private `@heroui/agent-hosted-runtime` workspace
|
|
12
|
+
package and is deployed through `agent.heroui.pro`.
|
|
13
|
+
|
|
14
|
+
## React installation
|
|
8
15
|
|
|
9
16
|
```bash
|
|
10
|
-
npm install @heroui/agent@
|
|
17
|
+
npm install @heroui/agent@latest
|
|
11
18
|
```
|
|
12
19
|
|
|
13
|
-
|
|
20
|
+
## React (Vite) usage
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
import {HeroUIAgent} from "@heroui/agent";
|
|
24
|
+
|
|
25
|
+
const agentId = process.env.HEROUI_AGENT_ID;
|
|
14
26
|
|
|
15
|
-
|
|
16
|
-
|
|
27
|
+
export function AppAgent() {
|
|
28
|
+
return (
|
|
29
|
+
<HeroUIAgent
|
|
30
|
+
agentId={agentId!}
|
|
31
|
+
getAuthToken={async (context) => {
|
|
32
|
+
const response = await fetch("/api/heroui-agent/auth-token", {
|
|
33
|
+
method: "POST",
|
|
34
|
+
signal: context.signal,
|
|
35
|
+
headers: {"Content-Type": "application/json"},
|
|
36
|
+
body: JSON.stringify(context),
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
if (!response.ok) throw new Error("Agent authentication failed");
|
|
40
|
+
|
|
41
|
+
return response.json();
|
|
42
|
+
}}
|
|
43
|
+
/>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
17
46
|
```
|
|
18
47
|
|
|
19
|
-
##
|
|
48
|
+
## Next.js usage
|
|
20
49
|
|
|
21
50
|
```tsx
|
|
51
|
+
"use client";
|
|
52
|
+
|
|
22
53
|
import {HeroUIAgent} from "@heroui/agent/next";
|
|
23
54
|
|
|
24
55
|
export function AppAgent() {
|
|
@@ -28,6 +59,7 @@ export function AppAgent() {
|
|
|
28
59
|
getAuthToken={async (context) => {
|
|
29
60
|
const response = await fetch("/api/heroui-agent/auth-token", {
|
|
30
61
|
method: "POST",
|
|
62
|
+
signal: context.signal,
|
|
31
63
|
headers: {"Content-Type": "application/json"},
|
|
32
64
|
body: JSON.stringify(context),
|
|
33
65
|
});
|
|
@@ -48,49 +80,83 @@ import {createAuthToken} from "@heroui/agent/server";
|
|
|
48
80
|
|
|
49
81
|
export async function POST(request: Request) {
|
|
50
82
|
const {anonymousId, agentId} = await request.json();
|
|
83
|
+
const configuredAgentId = process.env.HEROUI_AGENT_ID;
|
|
84
|
+
|
|
85
|
+
if (!configuredAgentId || agentId !== configuredAgentId) {
|
|
86
|
+
return Response.json({error: "Invalid agent"}, {status: 400});
|
|
87
|
+
}
|
|
51
88
|
|
|
52
89
|
return Response.json(
|
|
53
90
|
await createAuthToken({
|
|
91
|
+
anonymousId,
|
|
54
92
|
apiKey: process.env.HEROUI_AGENT_API_KEY!,
|
|
55
93
|
identity: {id: anonymousId, type: "anonymous"},
|
|
56
|
-
agentId,
|
|
94
|
+
agentId: configuredAgentId,
|
|
57
95
|
}),
|
|
58
96
|
);
|
|
59
97
|
}
|
|
60
98
|
```
|
|
61
99
|
|
|
100
|
+
## Vanilla JavaScript
|
|
101
|
+
|
|
102
|
+
No npm package or React dependency is required:
|
|
103
|
+
|
|
104
|
+
```html
|
|
105
|
+
<script src="https://agent.heroui.pro/loader.js" defer></script>
|
|
106
|
+
<script>
|
|
107
|
+
window.addEventListener("heroui-agent:loaded", () => {
|
|
108
|
+
window.agent = window.HeroUIAgent.mount({
|
|
109
|
+
agentId: "your_agent_id",
|
|
110
|
+
getAuthToken: async (context) => {
|
|
111
|
+
const response = await fetch("/api/heroui-agent/auth-token", {
|
|
112
|
+
body: JSON.stringify(context),
|
|
113
|
+
headers: {"Content-Type": "application/json"},
|
|
114
|
+
method: "POST",
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
if (!response.ok) throw new Error("Agent authentication failed");
|
|
118
|
+
|
|
119
|
+
return response.json();
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
</script>
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Vanilla client tools use raw JSON Schema for `parameters`. The returned controller exposes `show`,
|
|
127
|
+
`hide`, `toggle`, `newConversation`, `refreshAuth`, `shutdown`, and `destroy`.
|
|
128
|
+
|
|
62
129
|
## Overview
|
|
63
130
|
|
|
64
131
|
`@heroui/agent` provides a unified SDK for embedding HeroUI Agents into web applications.
|
|
65
132
|
|
|
66
133
|
### Entrypoints
|
|
67
134
|
|
|
68
|
-
| Entrypoint | Description
|
|
69
|
-
| -------------------------------------------- |
|
|
70
|
-
| [`@heroui/agent`](#herouiagent) | React
|
|
71
|
-
| [`@heroui/agent/next`](#herouiagentnext) | Next.js App Router entry
|
|
72
|
-
|
|
|
73
|
-
| [`@heroui/agent/
|
|
74
|
-
| [`@heroui/agent/contracts`](#contracts) | Shared protocol types and schemas | — |
|
|
135
|
+
| Entrypoint | Description | Links |
|
|
136
|
+
| -------------------------------------------- | ---------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
|
|
137
|
+
| [`@heroui/agent`](#herouiagent) | React bridge, hooks, and typed client tools | [npm](https://www.npmjs.com/package/@heroui/agent) • [Docs](https://heroui.pro/docs/agents/installation) |
|
|
138
|
+
| [`@heroui/agent/next`](#herouiagentnext) | Next.js App Router entry | [Docs](https://heroui.pro/docs/agents/installation) |
|
|
139
|
+
| `agent.heroui.pro/loader.js` | Framework-independent browser bridge | [Docs](https://heroui.pro/docs/agents/installation) |
|
|
140
|
+
| [`@heroui/agent/server`](#herouiagentserver) | Framework-independent auth-token server helper | [Docs](https://heroui.pro/docs/agents/identifying-users) |
|
|
75
141
|
|
|
76
142
|
## Package Details
|
|
77
143
|
|
|
78
144
|
### @heroui/agent
|
|
79
145
|
|
|
80
|
-
The
|
|
146
|
+
The typed React bridge for embedding the hosted Agent iframe.
|
|
81
147
|
|
|
82
148
|
#### Features
|
|
83
149
|
|
|
84
150
|
- **Generative UI** — Charts, tables, metrics, and forms streamed from a validated component union
|
|
85
151
|
- **Client tools** — Typed browser functions that run with the signed-in user's session
|
|
86
|
-
- **Dashboard-driven appearance** — Theme, launcher, greeting, and composer without a redeploy
|
|
152
|
+
- **Dashboard-driven appearance** — Theme, launcher, greeting, subtitle, and composer without a redeploy
|
|
87
153
|
- **Anonymous → identified** — Merge guest history when the user signs in
|
|
88
|
-
- **
|
|
154
|
+
- **Shared host core** — React, Next.js, and the CDN loader use the same iframe bridge
|
|
89
155
|
|
|
90
156
|
#### Installation
|
|
91
157
|
|
|
92
158
|
```bash
|
|
93
|
-
npm install @heroui/agent@
|
|
159
|
+
npm install @heroui/agent@latest
|
|
94
160
|
```
|
|
95
161
|
|
|
96
162
|
### @heroui/agent/next
|
|
@@ -109,34 +175,13 @@ Server-only helpers for exchanging a project API key for a short-lived browser c
|
|
|
109
175
|
import {createAuthToken} from "@heroui/agent/server";
|
|
110
176
|
```
|
|
111
177
|
|
|
112
|
-
### Styles
|
|
113
|
-
|
|
114
|
-
```css
|
|
115
|
-
@import "@heroui/agent/css";
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
Optional Pro theme variants (`brutalism`, `glass`, `mouve`) ship from [`@heroui-pro/react`](https://heroui.pro/docs):
|
|
119
|
-
|
|
120
|
-
```tsx
|
|
121
|
-
import "@heroui/agent/css";
|
|
122
|
-
import "@heroui-pro/react/agent-themes/glass";
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
### Contracts
|
|
126
|
-
|
|
127
|
-
Shared protocol version, message types, and schemas used by the SDK and hosted API.
|
|
128
|
-
|
|
129
|
-
```ts
|
|
130
|
-
import {HEROUI_AGENT_PROTOCOL_VERSION} from "@heroui/agent/contracts";
|
|
131
|
-
```
|
|
132
|
-
|
|
133
178
|
## Client Tools
|
|
134
179
|
|
|
135
180
|
Client tools let the agent call into your application — fetch data, change filters, create records:
|
|
136
181
|
|
|
137
182
|
```tsx
|
|
138
183
|
import {HeroUIAgent, createToolHelper} from "@heroui/agent";
|
|
139
|
-
import {z} from "zod";
|
|
184
|
+
import {z} from "@heroui/agent/zod";
|
|
140
185
|
|
|
141
186
|
const tool = createToolHelper<{apiClient: ApiClient}>();
|
|
142
187
|
|
|
@@ -150,60 +195,95 @@ const tools = [
|
|
|
150
195
|
];
|
|
151
196
|
|
|
152
197
|
<HeroUIAgent
|
|
153
|
-
agentId={process.env.
|
|
198
|
+
agentId={process.env.HEROUI_AGENT_ID!}
|
|
154
199
|
getAuthToken={getAuthToken}
|
|
155
200
|
context={{apiClient}}
|
|
156
201
|
tools={tools}
|
|
157
202
|
/>;
|
|
158
203
|
```
|
|
159
204
|
|
|
160
|
-
|
|
205
|
+
Tool manifests, JSON-safe page context, and validated tool results cross the iframe boundary. Tool
|
|
206
|
+
implementations, API clients, routers, state setters, and the rest of `context` stay in the browser.
|
|
207
|
+
|
|
208
|
+
### Image results
|
|
209
|
+
|
|
210
|
+
Any client tool can return a `ClientToolVisualResult` to send an image to the
|
|
211
|
+
model alongside JSON details. This works through the same result contract for
|
|
212
|
+
all agents; no particular tool name or agent ID is required.
|
|
213
|
+
|
|
214
|
+
```ts
|
|
215
|
+
import type {ClientToolVisualResult} from "@heroui/agent";
|
|
216
|
+
|
|
217
|
+
// Return this from your client tool's execute function.
|
|
218
|
+
const result: ClientToolVisualResult = {
|
|
219
|
+
kind: "heroui-agent-visual-result",
|
|
220
|
+
image: {data: imageBase64, mediaType: "image/png"},
|
|
221
|
+
description: "The chart currently visible in the application",
|
|
222
|
+
};
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Use JPEG or PNG base64 without a data-URL prefix, with at most 40,000 base64
|
|
226
|
+
characters. Additional JSON fields accompany the image as text. The complete
|
|
227
|
+
tool result must still fit the existing 64 KiB receipt limit. Use a model that
|
|
228
|
+
supports image input. Ordinary JSON results remain unchanged.
|
|
229
|
+
|
|
230
|
+
Validation failures return `CLIENT_TOOL_INVALID_INPUT` before execution. When
|
|
231
|
+
the schema provides issues, the result includes bounded field paths, error
|
|
232
|
+
codes, expected types, and numeric limits so the model can correct its input.
|
|
233
|
+
Submitted values and arbitrary exception messages are not included.
|
|
161
234
|
|
|
162
|
-
[Learn more](https://heroui.pro/docs/
|
|
235
|
+
[Learn more](https://heroui.pro/docs/agents/api-reference/client-tools)
|
|
163
236
|
|
|
164
237
|
## Documentation
|
|
165
238
|
|
|
166
|
-
- [Installation](https://heroui.pro/docs/
|
|
167
|
-
- [Identifying users](https://heroui.pro/docs/
|
|
168
|
-
- [Configuration](https://heroui.pro/docs/
|
|
169
|
-
- [Client tools](https://heroui.pro/docs/
|
|
170
|
-
- [Appearance](https://heroui.pro/docs/
|
|
171
|
-
- [Configure](https://heroui.pro/docs/
|
|
239
|
+
- [Installation](https://heroui.pro/docs/agents/installation)
|
|
240
|
+
- [Identifying users](https://heroui.pro/docs/agents/identifying-users)
|
|
241
|
+
- [Configuration](https://heroui.pro/docs/agents/api-reference/configuration)
|
|
242
|
+
- [Client tools](https://heroui.pro/docs/agents/api-reference/client-tools)
|
|
243
|
+
- [Appearance](https://heroui.pro/docs/agents/configure/appearance)
|
|
244
|
+
- [Configure](https://heroui.pro/docs/agents/configure)
|
|
172
245
|
|
|
173
246
|
Projects and API keys are managed in the [Agents dashboard](https://heroui.pro/dashboard/agents).
|
|
174
247
|
|
|
175
248
|
## What runs where
|
|
176
249
|
|
|
177
|
-
The
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
|
187
|
-
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
250
|
+
The npm package creates a cross-origin iframe at `agent.heroui.pro` and keeps the customer-product
|
|
251
|
+
trust boundary in the parent page. A versioned `heroui-agent-bridge/v1` handshake exchanges the
|
|
252
|
+
browser credential for a short-lived iframe session bound to both origins. Credentials never appear
|
|
253
|
+
in the iframe URL.
|
|
254
|
+
|
|
255
|
+
| In the customer page | In the hosted iframe and edge runtime |
|
|
256
|
+
| --------------------------------------------- | --------------------------------------------- |
|
|
257
|
+
| Client tool functions and product context | Panel, composer, Markdown, and generated UI |
|
|
258
|
+
| Navigation, mutations, and approval effects | Approval, progress, result, and error cards |
|
|
259
|
+
| Identity, drafts, attachments, durable outbox | Conversation Durable Object and model stream |
|
|
260
|
+
| Outside clicks, page margin, focus, z-index | Server tools, lazy MCP, PDF/XLSX, and sandbox |
|
|
261
|
+
|
|
262
|
+
Add the iframe origin to your Content Security Policy:
|
|
263
|
+
|
|
264
|
+
```http
|
|
265
|
+
Content-Security-Policy: frame-src https://agent.heroui.pro
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
When using the CDN loader, allow the same origin in `script-src`:
|
|
269
|
+
|
|
270
|
+
```http
|
|
271
|
+
Content-Security-Policy: frame-src https://agent.heroui.pro; script-src 'self' https://agent.heroui.pro
|
|
272
|
+
```
|
|
192
273
|
|
|
193
274
|
## Compatibility
|
|
194
275
|
|
|
195
|
-
-
|
|
196
|
-
-
|
|
276
|
+
- Any modern website through `agent.heroui.pro/loader.js`
|
|
277
|
+
- React 19+ only when using `@heroui/agent`
|
|
278
|
+
- Next.js 15+ only when using `@heroui/agent/next`
|
|
197
279
|
- Chrome/Edge 120+, Firefox 121+, Safari 17.2+
|
|
198
|
-
- ESM
|
|
199
|
-
|
|
200
|
-
This SDK speaks protocol version `6`. The hosted API returns `426 Upgrade Required` when a beta SDK is no longer compatible.
|
|
280
|
+
- ESM-only npm entry points; the CDN loader is a classic browser script
|
|
201
281
|
|
|
202
282
|
## Support
|
|
203
283
|
|
|
204
|
-
- [Documentation](https://heroui.pro/docs/
|
|
284
|
+
- [Documentation](https://heroui.pro/docs/agents)
|
|
205
285
|
- [Agents product](https://heroui.pro/agents)
|
|
206
|
-
- [Issues](https://github.com/heroui-inc/heroui-
|
|
286
|
+
- [Issues](https://github.com/heroui-inc/heroui-pro/issues)
|
|
207
287
|
- [Discord](https://discord.gg/9b6yyZKmH4)
|
|
208
288
|
|
|
209
289
|
## License
|
|
@@ -213,3 +293,46 @@ MIT — see [LICENSE](LICENSE).
|
|
|
213
293
|
---
|
|
214
294
|
|
|
215
295
|
Built by [HeroUI](https://www.heroui.com)
|
|
296
|
+
|
|
297
|
+
## Status, recovery, and cancellation
|
|
298
|
+
|
|
299
|
+
Use `onOpenChange(open)` to observe visible panel opens and closes. Preloading
|
|
300
|
+
and `onReady` do not count as opening the panel.
|
|
301
|
+
|
|
302
|
+
Use `onStatusChange(status)` to observe startup, connection, generation, finishing, and recovery.
|
|
303
|
+
`onError(error)` receives a safe `message`, `category`, `phase`, `retryable`, and `diagnosticId`.
|
|
304
|
+
Use the diagnostic ID to correlate failures; keep prompts, form values, files, credentials, and tool
|
|
305
|
+
outputs out of telemetry. The hosted panel supplies recovery actions and preserves conversation drafts.
|
|
306
|
+
|
|
307
|
+
Pass `context.signal` from `getAuthToken` into your authentication fetch. Authentication expires
|
|
308
|
+
after 15 seconds and superseded attempts are cancelled. Client tools receive
|
|
309
|
+
`execution.signal` as their third argument; pass it into cancellable requests and use
|
|
310
|
+
`execution.idempotencyKey` for server mutations. Cancellation after dispatch can leave an unknown
|
|
311
|
+
outcome, so the runtime preserves a receipt and does not automatically repeat the effect.
|
|
312
|
+
|
|
313
|
+
Generated forms submit their validated values as a queued user message without changing the composer
|
|
314
|
+
draft. “Submitted to agent” confirms queue acceptance; action completion is reported separately.
|
|
315
|
+
The selected conversation stays connected while visible. Settled inactive conversations disconnect
|
|
316
|
+
after a grace period; closing the panel leaves active work running.
|
|
317
|
+
|
|
318
|
+
## Language
|
|
319
|
+
|
|
320
|
+
Set the default language in the HeroUI Agents editor. Pass `locale` to override it for a user:
|
|
321
|
+
|
|
322
|
+
```tsx
|
|
323
|
+
<HeroUIAgent agentId={agentId} getAuthToken={getAuthToken} locale="es" />
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
The vanilla integration accepts the same `locale` option. English (`en`) and neutral Latin American Spanish (`es`) are supported. Regional tags such as `es-AR` share Spanish text and use regional number and date formatting. Unsupported locales fall back to English.
|
|
327
|
+
|
|
328
|
+
Set `locale="auto"` (or choose **Auto** in the editor) to use the first supported language in the visitor’s browser preferences, with English as the fallback. Regional formatting is preserved. Auto updates when browser language preferences change.
|
|
329
|
+
|
|
330
|
+
The SDK locale takes precedence over the saved agent locale, then English. With `remoteConfig={false}`, only the SDK locale and English fallback apply. Update the prop when your application's language changes; existing messages stay intact and subsequent submissions capture the new locale.
|
|
331
|
+
|
|
332
|
+
Interface language and response language are separate: the AI follows the user's message, keeps the previous conversational language for ambiguous follow-ups, and otherwise uses the configured locale. Explicit translation requests are honored.
|
|
333
|
+
|
|
334
|
+
Edit English and Spanish greetings, subtitles, placeholders, disclaimers, and suggested prompts in the editor's **Edit and preview** tabs. Explicit SDK copy overrides the selected translation. With `remoteConfig={false}`, pass a `translations` object keyed by base language (`{en: {greeting: "Hello"}, es: {greeting: "Hola"}}`) to provide custom copy for Auto. Missing Spanish copy uses built-in Spanish defaults; untranslated suggested prompts are hidden. Empty values and disabled disclaimers are preserved. Legacy custom copy remains English.
|
|
335
|
+
|
|
336
|
+
### Pasting images
|
|
337
|
+
|
|
338
|
+
Paste an image into the composer with Cmd+V or Ctrl+V. Pasted images use the same accepted file types, size limits, previews, and upload flow as the attachment button. Disabling attachments also disables image paste. Ordinary pasted text remains editable.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{b as te}from"./chunk-QSLALU5G.js";import{c as ee,h as G,i as ne,j as oe,m as re,n as ie,o as B}from"./chunk-FZXNXBTZ.js";function ye(e,t){return e.throwIfAborted(),new Promise((n,o)=>{let s=()=>o(e.reason);e.addEventListener("abort",s,{once:!0});try{t().then(n,o).finally(()=>e.removeEventListener("abort",s))}catch(u){e.removeEventListener("abort",s),o(u)}})}async function V(e,t,n){let o=new AbortController,s=setTimeout(()=>o.abort(new DOMException("Request timed out","TimeoutError")),e),u=n?AbortSignal.any([n,o.signal]):o.signal;try{return await ye(u,()=>t(u))}finally{clearTimeout(s)}}var be={approval:"This approval has expired. Ask the agent to request it again.",authentication:"Could not authenticate. Sign in if needed, then retry.",chunk:"Could not load the conversation. Retry, or reload the panel.",configuration:"Could not load the agent configuration. Try again.",connection:"Connection interrupted. Completed page changes remain applied. Reconnect to continue this chat.",credits:"This agent has reached its usage limit.",deleted:"This conversation was deleted. Start a new conversation.",rate_limit:"Too many requests. Wait a moment before retrying.",unknown:"The request could not be completed. Try again."},ve="Too many conversations are active. Wait a few minutes, then retry this chat.";function X(e,t="connecting"){let n=e&&typeof e=="object"?e:{},o=[e instanceof Error?e.message:"",n.code,n.status].filter(u=>typeof u=="string"||typeof u=="number").join(" ").toLowerCase(),s=t==="authenticating"||/auth|401|sign.in/.test(o)?"authentication":/429|rate.limit|concurrency_limit|too many conversations are active/.test(o)?"rate_limit":/credit|usage.limit|usage_limit|402/.test(o)?"credits":/deleted|conversation_not_found/.test(o)?"deleted":/approval.*expir/.test(o)?"approval":/dynamic.*import|chunk|module.*fetch/.test(o)?"chunk":/config/.test(o)?"configuration":/network|fetch|connect|timeout|timed out/.test(o)?"connection":"unknown";return{category:s,diagnosticId:crypto.randomUUID(),message:/concurrency_limit|too many conversations are active/.test(o)?ve:be[s],phase:t,retryable:!["credits","deleted","approval"].includes(s)}}var Ae=5e3;function ae(e){return`heroui-agent:anonymous:${e}`}function Te(e){return e instanceof Error?e:new Error("Auth token request failed")}var M=class{constructor(t,n){this.agentId=t;this.getAuthToken=n}cached=null;failure=null;generation=0;pending=null;controller=new AbortController;clear(){this.controller.abort(),this.controller=new AbortController,this.generation+=1,this.cached=null,this.failure=null,this.pending=null}reset(){this.clear();try{localStorage.removeItem(ae(this.agentId))}catch{}}async get(){if(this.cached&&this.expiresAt(this.cached)>Date.now()+6e4)return this.cached.token;if(!this.pending&&this.failure&&Date.now()<this.failure.retryAt)throw this.failure.error;let t=this.generation,n=this.pending??this.refresh();this.pending||(this.pending=n);try{let o=await n;return t!==this.generation?this.get():(this.cached=o,this.failure=null,o.token)}catch(o){throw t===this.generation&&(this.failure={error:Te(o),retryAt:Date.now()+Ae}),o}finally{this.pending===n&&(this.pending=null)}}async subjectHash(){let t=await this.get(),n=xe(t),o=typeof n.sub=="string"?n.sub:"anonymous",s=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(`${this.agentId}:${o}`));return Array.from(new Uint8Array(s),u=>u.toString(16).padStart(2,"0")).join("").slice(0,24)}anonymousId(){let t=ae(this.agentId);try{let n=localStorage.getItem(t);if(n)return n;let o=crypto.randomUUID();return localStorage.setItem(t,o),o}catch{return crypto.randomUUID()}}expiresAt(t){return t.expiresAt}async refresh(){let t=await V(15e3,n=>this.getAuthToken({agentId:this.agentId,anonymousId:this.anonymousId(),signal:n}),this.controller.signal);if(!t||typeof t.token!="string"||!t.token.trim()||typeof t.expiresAt!="number"||!Number.isFinite(t.expiresAt)||t.expiresAt<=0)throw new Error("Auth token callback returned invalid data");return{expiresAt:t.expiresAt,token:t.token}}};function xe(e){try{let t=e.split(".")[1];if(!t)return{};let n=t.replace(/-/g,"+").replace(/_/g,"/"),o=n.padEnd(Math.ceil(n.length/4)*4,"=");return JSON.parse(atob(o))}catch{return{}}}var Ee=64*1024,H=class extends Error{constructor(n,o){super(o);this.code=n}};function se(e){let t;try{let n=e??null;if(!B(n))throw new Error("Not a JSON value");t=JSON.stringify(n)}catch{throw new H("CLIENT_TOOL_RESULT_NOT_SERIALIZABLE","The client tool returned a result that is not JSON-serializable. Return plain JSON values; convert Map and Date values explicitly and remove circular references. The tool already ran; do not repeat an action without checking its outcome.")}if(new TextEncoder().encode(t).byteLength>Ee)throw new H("CLIENT_TOOL_RESULT_TOO_LARGE","The client tool result exceeds the 64 KiB limit. Request fewer rows or fields, paginate the data, or use uploadDataSource for a larger dataset. The tool already ran; do not repeat an action without checking its outcome.");return JSON.parse(t)}function le(e){return{bounds:null,closing:!1,dragging:!1,expanded:e.appearance?.panel?.expanded??!1,mounted:!1,open:!1,overlayOpen:!1,ready:!1,resizing:!1,sidebarWidth:null,viewMode:e.appearance?.viewMode??"floating"}}function A(e,t,n,o){return{background:"transparent",border:"0",clipPath:Ie(e,t,n),colorScheme:"normal",height:n&&e.open&&o?`${o.height}px`:"100dvh",inset:n&&e.open&&o?`${o.offsetTop}px 0 auto`:"0",position:"fixed",width:"100vw",zIndex:t.appearance?.zIndex??40}}function de(e){if(!e||typeof e!="object")return null;let t=e;return typeof t.open!="boolean"||typeof t.ready!="boolean"||typeof t.expanded!="boolean"||t.viewMode!=="chat-bar"&&t.viewMode!=="floating"&&t.viewMode!=="sidebar"?null:{bounds:ke(t.bounds),closing:t.closing===!0,dragging:t.dragging===!0,expanded:t.expanded,mounted:t.mounted!==!1,open:t.open,overlayOpen:t.overlayOpen===!0,ready:t.ready,resizing:t.resizing===!0,sidebarWidth:U(t.sidebarWidth)?t.sidebarWidth:null,viewMode:t.viewMode}}function ce(){let e=document.documentElement,t=document.body;return{active:!1,body:t,original:{bodyLeft:t.style.left,bodyOverflow:t.style.overflow,bodyPosition:t.style.position,bodyRight:t.style.right,bodyTop:t.style.top,bodyWidth:t.style.width,rootMarginRight:e.style.marginRight,rootOverflow:e.style.overflow,rootTransition:e.style.transition},root:e,scrollLock:null}}function P(e,t,n,o){let s=t.open||t.closing;if(!s&&!e.active)return;s&&(e.active=!0);let u=s&&(t.viewMode==="chat-bar"?t.expanded:o||t.viewMode==="sidebar"&&t.expanded);pe(e,u);let l=s&&t.viewMode==="sidebar"&&!t.expanded&&!o?Se(t,n):e.original.rootMarginRight;e.root.style.transition=e.original.rootTransition,e.root.style.marginRight=l,s||(e.active=!1)}function ue(e){pe(e,!1),e.root.style.marginRight=e.original.rootMarginRight,e.root.style.transition=e.original.rootTransition,e.active=!1}function Ie(e,t,n){let o=e.open||e.closing;if(o&&(e.overlayOpen||n&&e.viewMode!=="chat-bar"))return"inset(0px)";if(e.bounds)return`inset(${e.bounds.top}px calc(100% - ${e.bounds.right}px) calc(100% - ${e.bounds.bottom}px) ${e.bounds.left}px)`;if(e.viewMode==="chat-bar"){if(e.expanded&&o)return"inset(0px)";let w=o?"calc(100% - min(610px, calc(100dvh - 20px)))":"calc(100% - 114px)",v=o?"calc(50% - min(288px, 50%))":"calc(50% - min(228px, 50%))";return`inset(${w} ${v} 0px ${v})`}let s=t.appearance?.launcher,u=s?.position==="bottom-left",f=(s?.offset?.x??24)+60,l=(s?.offset?.y??24)+60;if(!o)return u?`inset(calc(100% - ${l}px) calc(100% - ${f}px) 0px 0px)`:`inset(calc(100% - ${l}px) 0px 0px calc(100% - ${f}px))`;if(e.viewMode==="sidebar")return`inset(0px 0px 0px calc(100% - (${D(t.appearance?.panel?.initialWidth??420)} + 16px)))`;let g=D(t.appearance?.panel?.initialWidth??440),E=`calc(100% - min(calc(${D(t.appearance?.panel?.initialHeight??"max(420px, 56dvh)")} + 32px), 100dvh))`;return u?`inset(${E} calc(100% - min(calc(${g} + 32px), 100vw)) 0px 0px)`:`inset(${E} 0px 0px calc(100% - min(calc(${g} + 32px), 100vw)))`}function ke(e){if(!e||typeof e!="object")return null;let t=e;return!U(t.top)||!U(t.right)||!U(t.bottom)||!U(t.left)||t.right<t.left||t.bottom<t.top?null:{bottom:t.bottom,left:t.left,right:t.right,top:t.top}}function U(e){return typeof e=="number"&&Number.isFinite(e)&&e>=0&&e<=1e5}function Se(e,t){return e.sidebarWidth===null?D(t.appearance?.panel?.initialWidth??420):`${Math.round(e.sidebarWidth)}px`}function D(e){return typeof e=="number"?`${Math.round(e)}px`:e}function pe(e,t){if(t&&!e.scrollLock){e.scrollLock={x:window.scrollX,y:window.scrollY},e.root.style.overflow="hidden",e.body.style.overflow="hidden",e.body.style.position="fixed",e.body.style.top=`${-e.scrollLock.y}px`,e.body.style.left=`${-e.scrollLock.x}px`,e.body.style.right="0",e.body.style.width="100%";return}if(!t&&e.scrollLock){let{x:n,y:o}=e.scrollLock;e.root.style.overflow=e.original.rootOverflow,e.body.style.overflow=e.original.bodyOverflow,e.body.style.position=e.original.bodyPosition,e.body.style.top=e.original.bodyTop,e.body.style.left=e.original.bodyLeft,e.body.style.right=e.original.bodyRight,e.body.style.width=e.original.bodyWidth,e.scrollLock=null;try{window.scrollTo(n,o)}catch{}}}var Le=16*1024;function et(e,t){let n=e;if(!n?.agentId||typeof n.getAuthToken!="function")throw new Error("HeroUIAgent.mount requires agentId and getAuthToken");G(n.tools??[]);let o=crypto.randomUUID(),s=crypto.randomUUID(),u=(n._api?.baseUrl??te).replace(/\/$/,""),f=Ue(u,n._api?.embedOrigin),l=document.createElement("iframe"),g=new Map,b=[],E=new Set,w=new Map,v=new Set,I=ce(),T=new M(n.agentId,n.getAuthToken),a=le(n),F=null,y=!1,x=!1,k=null,q=!1,S=!1,j=n.preload!==!1,C=()=>{S||T.get().catch(()=>{})},z=new URL("/embed",f);z.searchParams.set("agentId",n.agentId),z.hash=new URLSearchParams({nonce:s,parentOrigin:window.location.origin,sessionId:o}).toString(),l.allow="microphone; clipboard-write",l.referrerPolicy="origin",l.setAttribute("sandbox","allow-downloads allow-forms allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts"),l.src=z.toString(),l.title="HeroUI Agent",Object.assign(l.style,A(a,n,window.innerWidth<640,window.visualViewport?.scale===1?window.visualViewport:void 0)),document.body.append(l);let m=(r,i,d)=>{S||l.contentWindow?.postMessage(re(o,s,r,i,d),f)},fe=(r,i)=>{let d=crypto.randomUUID();return new Promise((c,p)=>{let h=window.setTimeout(()=>{g.delete(d),p(new Error(`HeroUI Agent iframe request timed out: ${r}`))},3e4);g.set(d,{reject:p,resolve:c,timer:h}),m(r,i,d)})},_=new Map,J=0,Y="",N=!1,K=async(r,i=!1)=>{let d=++J;if(N)return;let c;try{c=await He(n,t)}catch(h){if(S||d!==J)return;N=!0;let O={...X(h,"failed"),category:"configuration",message:h instanceof Error?h.message.slice(0,1e3):"Invalid agent configuration",retryable:!1};n.onError?.(O),m("host.init-error",O);return}if(S||d!==J)return;let p=JSON.stringify({props:c.props,tools:c.tools});!i&&p===Y||(Y=p,m(r,{...c,restoreSession:r==="host.init"&&x}))},R=(r,i)=>{if(!a.mounted){b.push({name:r,payload:i}),b.length>32&&b.shift();return}m("host.command",{name:r,payload:i})},W=r=>{r&&C(),r&&!y&&document.activeElement!==l&&(F=document.activeElement),y=r,r||(x=!1),R(r?"show":"hide")},me=()=>{if(a.mounted)for(let r of b.splice(0))m("host.command",r)},he=()=>{x=a.mounted&&y&&!a.closing,a={...a,bounds:null,closing:!1,mounted:!1,open:x,ready:!1},q=!1;for(let r of v)r();Object.assign(l.style,A(a,n,window.innerWidth<640,window.visualViewport?.scale===1?window.visualViewport:void 0)),P(I,a,n,window.innerWidth<640)},Z=r=>{if(r.origin!==f||r.source!==l.contentWindow)return;let i=ie(r.data);if(!(!i||i.sessionId!==o||i.nonce!==s)){if(i.type==="iframe.rpc-result"||i.type==="iframe.rpc-error"){Pe(i,g);return}Me(E,i.requestId)&&we(i)}},we=async r=>{try{if(r.type==="iframe.ready"){(a.mounted||a.ready)&&he(),await K("host.init",!0);return}if(r.type==="iframe.reload"){let i=l.cloneNode(!1),d=new URL(l.src);d.pathname=`/reload/${crypto.randomUUID()}/embed`,i.src=d.href,l.replaceWith(i),l=i;return}if(r.type==="iframe.state"){let i=de(r.payload);if(i){let d=a.mounted,c=a.open||a.closing,p=i;x?i.mounted?(x=!1,i.open||(m("host.command",{name:"show"}),p={...i,bounds:null,closing:!1,open:!0,sidebarWidth:i.sidebarWidth??a.sidebarWidth})):p={...i,bounds:null,closing:!1,open:!0,sidebarWidth:i.sidebarWidth??a.sidebarWidth}:i.open?y=!0:(i.closing||a.open||a.closing)&&(y=!1);let h=p.open||p.closing;if(h&&!c&&document.activeElement!==l&&(F=document.activeElement),!h&&c&&F?.isConnected){let O=F;window.requestAnimationFrame(()=>window.requestAnimationFrame(()=>O.focus({preventScroll:!0})))}h!==c&&n.onOpenChange?.(h),a=p,a.mounted&&!d&&K("host.update"),h&&a.expanded?l.dataset.expanded="true":l.removeAttribute("data-expanded");for(let O of v)O();Object.assign(l.style,A(a,n,window.innerWidth<640,window.visualViewport?.scale===1?window.visualViewport:void 0)),P(I,a,n,window.innerWidth<640),me(),a.ready&&!q&&(q=!0,n.onReady?.())}return}if(r.type==="iframe.error"){n.onError?.(r.payload);return}if(r.type==="iframe.status"){n.onStatusChange?.(r.payload);return}if(r.type==="iframe.tool-cancel"){let i=r.payload;i.idempotencyKey&&_.get(i.idempotencyKey)?.abort();return}if(r.type==="iframe.auth-request"){let i=await T.get(),d=await V(15e3,c=>fetch(`${u}/v1/agents/${encodeURIComponent(n.agentId)}/embed-sessions`,{body:JSON.stringify({iframeOrigin:f,sessionId:o}),cache:"no-store",headers:{Authorization:`Bearer ${i}`,"Content-Type":"application/json"},method:"POST",signal:c}));if(!d.ok)throw new Error("Could not authenticate HeroUI Agent");m("host.rpc-result",{value:await d.json()},r.requestId);return}if(r.type==="iframe.context-request"){let i=_e(await n.context?.page?.()??{},Le,"Agent page context");m("host.rpc-result",{value:i},r.requestId);return}if(r.type==="iframe.tool-execute"){let i=Ce(r.payload),d=n.tools?.find(p=>p.name===i.name);if(!d)throw new Error(`Unknown client tool: ${i.name}`);let c=w.get(i.idempotencyKey);if(!c){let p=new AbortController;_.set(i.idempotencyKey,p),c=Oe(d,i,n,fe,p.signal).finally(()=>_.delete(i.idempotencyKey)),w.set(i.idempotencyKey,c),w.size>2048&&w.delete(w.keys().next().value)}m("host.rpc-result",{value:await c},r.requestId);return}if(r.type==="iframe.feedback"){await n.onFeedback?.(r.payload);return}if(r.type==="iframe.storage"){Re(r.payload);return}if(r.type==="iframe.persistence"){let i=await import("./persistence-YI6JSYCT.js").then(({executeAgentHostPersistence:d})=>d(n.agentId,r.payload));m("host.rpc-result",{value:i},r.requestId)}}catch(i){if(S)return;let d=X(i,r.type==="iframe.auth-request"?"authenticating":"failed"),c=r.type==="iframe.tool-execute",p=c&&i instanceof Error?i.message.slice(0,1e3):d.message;n.onError?.({...d,message:p}),m("host.rpc-error",{error:p,...c?{code:i instanceof H?i.code:"CLIENT_TOOL_EXECUTION_ERROR"}:{}},r.requestId)}},Q=r=>{r.composedPath().includes(l)||a.open&&(a.viewMode==="floating"||a.viewMode==="chat-bar")&&(n.appearance?.shouldCloseOnInteractOutside??!0)&&W(!1)},L=()=>{a={...a,bounds:null},Object.assign(l.style,A(a,n,window.innerWidth<640,window.visualViewport?.scale===1?window.visualViewport:void 0)),P(I,a,n,window.innerWidth<640)},$=()=>{document.visibilityState==="visible"&&(a={...a,bounds:null},Object.assign(l.style,A(a,n,window.innerWidth<640,window.visualViewport?.scale===1?window.visualViewport:void 0)),P(I,a,n,window.innerWidth<640),y&&a.mounted&&m("host.command",{name:"show"}),k!==null&&window.cancelAnimationFrame(k),k=window.requestAnimationFrame(()=>{k=null,Object.assign(l.style,A(a,n,window.innerWidth<640,window.visualViewport?.scale===1?window.visualViewport:void 0))}))};return window.addEventListener("message",Z),window.addEventListener("pointerdown",Q,!0),window.addEventListener("resize",L),window.addEventListener("pageshow",$),window.visualViewport?.addEventListener("resize",L),window.visualViewport?.addEventListener("scroll",L),document.addEventListener("visibilitychange",$),j&&C(),{destroy:()=>{S=!0,T.clear();for(let r of _.values())r.abort();_.clear(),window.removeEventListener("message",Z),window.removeEventListener("pointerdown",Q,!0),window.removeEventListener("resize",L),window.removeEventListener("pageshow",$),window.visualViewport?.removeEventListener("resize",L),window.visualViewport?.removeEventListener("scroll",L),document.removeEventListener("visibilitychange",$),k!==null&&window.cancelAnimationFrame(k);for(let r of g.values())window.clearTimeout(r.timer),r.reject(new Error("HeroUI Agent iframe was removed"));g.clear(),b.length=0,v.clear(),ue(I),l.remove()},hide:()=>W(!1),newConversation:r=>{C(),y=!0,R("newConversation",{prompt:r})},preload:()=>{C(),R("preload")},get ready(){return a.ready},refreshAuth:()=>{T.clear(),R("refreshAuth")},show:()=>W(!0),shutdown:()=>{y=!1,x=!1,T.reset(),R("shutdown")},subscribe:r=>(v.add(r),()=>v.delete(r)),toggle:()=>W(!y),update:r=>{if(r.agentId!==n.agentId)throw new Error("HeroUI Agent agentId cannot change without remounting");G(r.tools??[]);let i=N;N=!1;let d=r.getAuthToken!==n.getAuthToken,c=r.preload!==!1&&(d||!j);j=r.preload!==!1,d&&(T.clear(),T=new M(r.agentId,r.getAuthToken)),n=r,c&&C(),Object.assign(l.style,A(a,n,window.innerWidth<640,window.visualViewport?.scale===1?window.visualViewport:void 0)),P(I,a,n,window.innerWidth<640),(a.mounted||i)&&K(a.mounted?"host.update":"host.init")}}}async function Oe(e,t,n,o,s){let u={conversationId:t.conversationId,idempotencyKey:t.idempotencyKey,signal:s,toolCallId:t.toolCallId,uploadDataSource:async g=>await o("host.upload-data-source",{toolCallId:t.toolCallId,upload:g})},f;try{f=ee(e,t.args)}catch(g){return{code:"CLIENT_TOOL_INVALID_INPUT",...Fe(g),error:`The arguments for ${e.name} do not match its declared schema. Correct the input and try again. No action was performed.`,success:!1}}let l=await e.execute(f,n.context??{},u)??null;return se(l)}async function He(e,t){let{context:n,getAuthToken:o,onError:s,onFeedback:u,onOpenChange:f,onReady:l,onStatusChange:g,tools:b,...E}=e,w=await t(b??[]);return{localStorage:ge(window.localStorage),props:JSON.parse(JSON.stringify(E)),sessionStorage:ge(window.sessionStorage),tools:w}}function Pe(e,t){let n=t.get(e.requestId);if(n)if(t.delete(e.requestId),window.clearTimeout(n.timer),e.type==="iframe.rpc-error"){let o=e.payload;n.reject(new Error(typeof o?.error=="string"?o.error:"Iframe request failed"))}else{let o=e.payload;n.resolve(o?.value)}}function Ce(e){if(!e||typeof e!="object")throw new Error("Invalid client tool request");let t=e;if(typeof t.conversationId!="string"||typeof t.idempotencyKey!="string"||typeof t.name!="string"||typeof t.toolCallId!="string")throw new Error("Invalid client tool request");return t}function _e(e,t,n){if(!B(e))throw new Error(`${n} must be JSON-serializable`);let o=JSON.stringify(e);if(new TextEncoder().encode(o).byteLength>t)throw new Error(`${n} exceeds ${Math.round(t/1024)} KiB`);return JSON.parse(o)}function ge(e){let t={};try{for(let n=0;n<e.length;n+=1){let o=e.key(n);o?.startsWith("heroui-agent:")&&(t[o]=e.getItem(o)??"")}}catch{}return t}function Re(e){if(!e||typeof e!="object")return;let t=e;if(typeof t.key=="string"&&!t.key.startsWith("heroui-agent:"))return;let n=t.storage==="session"?sessionStorage:localStorage;try{if(t.operation==="set"&&typeof t.key=="string"&&typeof t.value=="string")n.setItem(t.key,t.value);else if(t.operation==="remove"&&typeof t.key=="string")n.removeItem(t.key);else if(t.operation==="clear")for(let o=n.length-1;o>=0;o-=1){let s=n.key(o);s?.startsWith("heroui-agent:")&&n.removeItem(s)}}catch{}}function Me(e,t){return e.has(t)?!1:(e.add(t),e.size>2048&&e.delete(e.values().next().value),!0)}function Ue(e,t){if(t){let n=new URL(t);if(n.protocol!=="http:"&&n.protocol!=="https:")throw new Error("HeroUI Agent embed origin must use HTTP or HTTPS");return n.origin}return/^https?:\/\/(?:localhost|127\.0\.0\.1)(?::\d+)?$/i.test(e)?"http://localhost:8793":e.includes("staging")?oe:ne}function Fe(e){if(!e||typeof e!="object"||!("issues"in e)||!Array.isArray(e.issues))return{};let t=e.issues.slice(0,8).flatMap(n=>{if(!n||typeof n!="object")return[];let o=n;return!Array.isArray(o.path)||typeof o.code!="string"?[]:[{code:o.code.slice(0,60),path:o.path.filter(s=>typeof s=="string"||typeof s=="number").join(".").slice(0,200),...typeof o.minimum=="number"&&Number.isFinite(o.minimum)?{minimum:o.minimum}:{},...typeof o.maximum=="number"&&Number.isFinite(o.maximum)?{maximum:o.maximum}:{},...typeof o.expected=="string"?{expected:o.expected.slice(0,100)}:{}}]});return t.length?{issues:t}:{}}export{ye as a,V as b,X as c,M as d,H as e,se as f,et as g};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e={animation:"fadeIn",duration:160,easing:"ease-out",sep:"word",stagger:18};export{e as a};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function T(){return function(e){return e}}function u(t){return!!(t&&typeof t=="object"&&typeof t.safeParse=="function")}function h(t,e){return u(t.parameters)?t.parameters.parse(e):e}function x(t,e){let n=t.get(e);return!n||n.needsApproval?null:n}var d=["readConversationHistory","callMcpTool","composeUI","executeSandbox","generateFile","getUIComponents","readSkill","renderComponent","renderDocument","searchKnowledge","searchMcpTools","searchWeb"],l="mcp_";function p(t){return/^[a-zA-Z][a-zA-Z0-9_-]{0,63}$/.test(t)?d.includes(t)||t.toLowerCase().startsWith(l)?`Client tool name '${t}' is reserved by HeroUI Agent. Rename this tool.`:null:`Client tool name '${t}' must start with a letter and contain only letters, digits, underscores, or hyphens (maximum 64 characters).`}function S(t){let e=new Set;for(let{name:n}of t){let o=p(n);if(o)throw new Error(o);if(e.has(n))throw new Error(`Duplicate client tool name: ${n}`);e.add(n)}}var b="https://agent.heroui.pro",w="https://staging-agent.heroui.pro",k=262144,B=57671680;function C(t,e,n,o,i=crypto.randomUUID()){return{nonce:e,...o===void 0?{}:{payload:o},requestId:i,sessionId:t,type:n}}function _(t){if(!t||typeof t!="object")return null;let e=t;if(typeof e.sessionId!="string"||!a(e.sessionId)||typeof e.nonce!="string"||!a(e.nonce)||typeof e.requestId!="string"||!a(e.requestId)||typeof e.type!="string"||e.type.length===0||!A.has(e.type))return null;let n=e.type==="iframe.persistence"||e.type==="host.upload-data-source"||e.type==="host.rpc-result"?57671680:262144;return m(t)>n||!y(e.type,e.payload)?null:{nonce:e.nonce,...Object.hasOwn(e,"payload")?{payload:e.payload}:{},requestId:e.requestId,sessionId:e.sessionId,type:e.type}}function f(t,e=new Set){if(t===null||typeof t=="string"||typeof t=="boolean")return!0;if(typeof t=="number")return Number.isFinite(t);if(typeof t!="object"||e.has(t))return!1;e.add(t);let n=i=>i===void 0||f(i,e),o=Array.isArray(t)?t.every(n):Object.getPrototypeOf(t)===Object.prototype&&Object.values(t).every(n);return e.delete(t),o}function m(t){return g(t,new Set)}function g(t,e){if(t==null)return 4;if(typeof t=="string")return new TextEncoder().encode(t).byteLength+2;if(typeof t=="boolean"||typeof t=="number")return 8;if(typeof t!="object"||e.has(t))return Number.POSITIVE_INFINITY;if(t instanceof ArrayBuffer||ArrayBuffer.isView(t))return t.byteLength;if(typeof Blob<"u"&&t instanceof Blob)return t.size;e.add(t);let n=2;for(let[o,i]of Object.entries(t))if(n+=g(o,e)+g(i,e),!Number.isFinite(n))break;return e.delete(t),n}function a(t){return t.length>0&&t.length<=128&&/^[A-Za-z0-9._:-]+$/.test(t)}var A=new Set(["host.command","host.init","host.init-error","host.update","host.rpc-result","host.rpc-error","host.upload-data-source","iframe.ready","iframe.reload","iframe.auth-request","iframe.context-request","iframe.feedback","iframe.persistence","iframe.state","iframe.storage","iframe.rpc-result","iframe.rpc-error","iframe.error","iframe.status","iframe.tool-cancel","iframe.tool-execute"]),c=["loading","authenticating","connecting","ready","generating","finishing","reconnecting","failed"],s=t=>!!(t&&typeof t=="object"&&!Array.isArray(t)),r=t=>typeof t=="string";function y(t,e){if(t==="iframe.ready"||t==="iframe.reload"||t==="iframe.auth-request"||t==="iframe.context-request")return e===void 0;if(t==="iframe.status")return c.includes(e);if(!s(e))return!1;switch(t){case"host.init":case"host.update":return s(e.props)&&s(e.localStorage)&&s(e.sessionStorage)&&Object.values(e.localStorage).every(r)&&Object.values(e.sessionStorage).every(r)&&(e.restoreSession===void 0||typeof e.restoreSession=="boolean")&&Array.isArray(e.tools)&&e.tools.every(n=>s(n)&&r(n.name)&&r(n.description)&&s(n.inputSchema));case"host.command":return["show","hide","toggle","preload","refreshAuth","shutdown","newConversation"].includes(e.name);case"host.rpc-error":case"iframe.rpc-error":return r(e.error)&&(e.code===void 0||r(e.code));case"host.rpc-result":case"iframe.rpc-result":return!0;case"host.upload-data-source":return r(e.toolCallId)&&s(e.upload);case"iframe.tool-cancel":return r(e.idempotencyKey);case"iframe.tool-execute":return["name","conversationId","idempotencyKey","toolCallId"].every(n=>r(e[n]));case"host.init-error":case"iframe.error":return["authentication","connection","configuration","chunk","rate_limit","credits","deleted","approval","unknown"].includes(e.category)&&c.includes(e.phase)&&r(e.message)&&r(e.diagnosticId)&&typeof e.retryable=="boolean";case"iframe.state":return["open","ready","expanded","closing","dragging","mounted","overlayOpen","resizing"].every(n=>typeof e[n]=="boolean")&&["chat-bar","floating","sidebar"].includes(e.viewMode);case"iframe.storage":return["local","session"].includes(e.storage)&&(e.operation==="clear"||r(e.key)&&(e.operation==="remove"||e.operation==="set"&&r(e.value)));case"iframe.persistence":return["composer-image-drafts","message-outboxes"].includes(e.store)&&(e.operation==="deletePrefix"?r(e.prefix):["get","put","delete"].includes(e.operation)&&r(e.key));case"iframe.feedback":return r(e.conversationId)&&r(e.messageId)&&["positive","negative"].includes(e.rating)&&Array.isArray(e.reasons)}}export{T as a,u as b,h as c,x as d,d as e,l as f,p as g,S as h,b as i,w as j,k,B as l,C as m,_ as n,f as o,m as p};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{g as S}from"./chunk-AMNE7O54.js";import{b as p}from"./chunk-FZXNXBTZ.js";import{useEffect as O,useLayoutEffect as m,useMemo as b,useRef as f,useState as k,useSyncExternalStore as H}from"react";var i=new Map,h=new Set;function C(){for(let t of h)t()}function R(t){return h.add(t),()=>h.delete(t)}function a(t,n,r){let o=t?i.get(t):[...i.values()][i.size-1];if(!o){console.warn("HeroUI Agent is not mounted yet. Add <HeroUIAgent /> to your layout.");return}n==="newConversation"?o.newConversation(r):o[n]()}function w(t){let n=H(R,()=>(t?i.get(t):[...i.values()].at(-1))?.ready??!1,()=>!1);return b(()=>({hide:()=>a(t,"hide"),newConversation:r=>a(t,"newConversation",r),preload:()=>a(t,"preload"),ready:n,refreshAuth:()=>a(t,"refreshAuth"),show:()=>a(t,"show"),shutdown:()=>a(t,"shutdown"),toggle:()=>a(t,"toggle")}),[t,n])}async function I(t){let{serializeClientTools:n}=await import("./client-tools-manifest-PCUOVUXR.js");return n(t).map(o=>{let s=t.find(l=>l.name===o.name);return{...o,...s?.displayName?{displayName:s.displayName}:{},...s?.icon?{icon:s.icon}:{},...s?.iconColor?{iconColor:s.iconColor}:{}}})}function P(t){let n=f(t),r=f(null),o=f(null);m(()=>{n.current=t}),o.current||(o.current={getAuthToken:e=>n.current.getAuthToken(e),onError:e=>n.current.onError?.(e),onFeedback:e=>n.current.onFeedback?.(e),onOpenChange:e=>n.current.onOpenChange?.(e),onReady:()=>n.current.onReady?.(),onStatusChange:e=>n.current.onStatusChange?.(e)},Object.defineProperties(o.current,{context:{enumerable:!0,get(){return n.current.context}},tools:{enumerable:!0,get(){return n.current.tools}}}));let s=x(t),l=o.current;for(let e of Object.keys(l))e!=="context"&&e!=="getAuthToken"&&e!=="onError"&&e!=="onStatusChange"&&e!=="onFeedback"&&e!=="onReady"&&e!=="onOpenChange"&&e!=="tools"&&!(e in s)&&delete l[e];Object.assign(l,s,{agentId:t.agentId});let u=o.current;m(()=>{let e=S(u,I),c=e.subscribe(C);return r.current=e,i.set(t.agentId,e),C(),()=>{c(),e.destroy(),i.get(t.agentId)===e&&i.delete(t.agentId),r.current===e&&(r.current=null),C()}},[t.agentId]);let[y,g]=k("");O(()=>{let e=t.tools??[];if(!e.some(d=>p(d.parameters))){g("");return}let c=!1;return import("./client-tools-manifest-PCUOVUXR.js").then(({serializeClientTools:d})=>{c||g(JSON.stringify(d(e).map(T=>({inputSchema:T.inputSchema,name:T.name}))))}),()=>{c=!0}},[t.tools]);let A=JSON.stringify({props:x(t),tools:(t.tools??[]).map(e=>({description:e.description,displayName:e.displayName,icon:e.icon,iconColor:e.iconColor,name:e.name,needsApproval:e.needsApproval===!0,parameters:p(e.parameters)?null:e.parameters})),zodToolsSchemasKey:y});return m(()=>{r.current?.update(u)},[A]),null}function x(t){let{context:n,getAuthToken:r,onError:o,onFeedback:s,onOpenChange:l,onReady:u,onStatusChange:y,tools:g,...A}=t;return JSON.parse(JSON.stringify(A))}export{w as a,P as b};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{b as i,g as a,o as m}from"./chunk-FZXNXBTZ.js";import{z as t}from"zod";var c=20,p=16*1024,d=t.object({description:t.string().trim().min(1).max(1e3),inputSchema:t.record(t.string(),t.unknown()),name:t.string().superRefine((e,n)=>{let o=a(e);o&&n.addIssue({code:"custom",message:o})}),needsApproval:t.boolean().optional()}),l=t.array(d).max(c).superRefine((e,n)=>{let o=new Set;for(let r of e)o.has(r.name)&&n.addIssue({code:"custom",message:`Duplicate client tool name: ${r.name}`}),o.add(r.name);new TextEncoder().encode(JSON.stringify(e)).byteLength>p&&n.addIssue({code:"custom",message:"Client tool manifest exceeds 16KB"})});function f(e){let n=i(e.parameters)?t.toJSONSchema(e.parameters):e.parameters;if(!m(n))throw new Error(`Client tool ${e.name} parameters must be a JSON-serializable schema`);return s(n)}function s(e){return Array.isArray(e)?e.map(s):e&&typeof e=="object"?Object.fromEntries(Object.entries(e).map(([n,o])=>[n,s(o)])):e}function h(e){return l.parse(e.map(n=>({description:n.description,inputSchema:f(n),name:n.name,...n.needsApproval?{needsApproval:!0}:{}})))}export{c as a,p as b,d as c,l as d,h as e};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var t="1.0.0-beta.11",o="https://api.heroui.pro";export{t as a,o as b};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as c,b as d,c as e,d as f,e as g}from"./chunk-KFWXAD55.js";import{e as a,f as b}from"./chunk-FZXNXBTZ.js";export{c as MAX_CLIENT_TOOLS,d as MAX_CLIENT_TOOLS_BYTES,a as RESERVED_AGENT_TOOL_NAMES,b as RESERVED_AGENT_TOOL_PREFIX,e as clientToolManifestEntrySchema,f as clientToolsSchema,g as serializeClientTools};
|