@athenaintel/react 0.60.1 → 0.61.0
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 +157 -5
- package/dist/agent-ui/AgentTarget.cjs +11 -0
- package/dist/agent-ui/AgentTarget.cjs.map +1 -0
- package/dist/agent-ui/AgentTarget.d.ts +17 -0
- package/dist/agent-ui/AgentTarget.js +11 -0
- package/dist/agent-ui/AgentTarget.js.map +1 -0
- package/dist/agent-ui/AgentUiLayer.cjs +387 -0
- package/dist/agent-ui/AgentUiLayer.cjs.map +1 -0
- package/dist/agent-ui/AgentUiLayer.d.ts +40 -0
- package/dist/agent-ui/AgentUiLayer.js +387 -0
- package/dist/agent-ui/AgentUiLayer.js.map +1 -0
- package/dist/agent-ui/contract.cjs +104 -0
- package/dist/agent-ui/contract.cjs.map +1 -0
- package/dist/agent-ui/contract.d.ts +113 -0
- package/dist/agent-ui/contract.js +104 -0
- package/dist/agent-ui/contract.js.map +1 -0
- package/dist/agent-ui/driver.cjs +335 -0
- package/dist/agent-ui/driver.cjs.map +1 -0
- package/dist/agent-ui/driver.d.ts +66 -0
- package/dist/agent-ui/driver.js +335 -0
- package/dist/agent-ui/driver.js.map +1 -0
- package/dist/agent-ui/index.cjs +33 -0
- package/dist/agent-ui/index.cjs.map +1 -0
- package/dist/agent-ui/index.d.ts +19 -0
- package/dist/agent-ui/index.js +33 -0
- package/dist/agent-ui/index.js.map +1 -0
- package/dist/agent-ui/pace.cjs +121 -0
- package/dist/agent-ui/pace.cjs.map +1 -0
- package/dist/agent-ui/pace.d.ts +66 -0
- package/dist/agent-ui/pace.js +121 -0
- package/dist/agent-ui/pace.js.map +1 -0
- package/dist/agent-ui/screen.cjs +471 -0
- package/dist/agent-ui/screen.cjs.map +1 -0
- package/dist/agent-ui/screen.d.ts +97 -0
- package/dist/agent-ui/screen.js +471 -0
- package/dist/agent-ui/screen.js.map +1 -0
- package/dist/agent-ui/secret-fields.cjs +50 -0
- package/dist/agent-ui/secret-fields.cjs.map +1 -0
- package/dist/agent-ui/secret-fields.d.ts +15 -0
- package/dist/agent-ui/secret-fields.js +50 -0
- package/dist/agent-ui/secret-fields.js.map +1 -0
- package/dist/agent-ui/stage.cjs +196 -0
- package/dist/agent-ui/stage.cjs.map +1 -0
- package/dist/agent-ui/stage.d.ts +110 -0
- package/dist/agent-ui/stage.js +196 -0
- package/dist/agent-ui/stage.js.map +1 -0
- package/dist/agent-ui/tools.cjs +448 -0
- package/dist/agent-ui/tools.cjs.map +1 -0
- package/dist/agent-ui/tools.d.ts +103 -0
- package/dist/agent-ui/tools.js +448 -0
- package/dist/agent-ui/tools.js.map +1 -0
- package/dist/agent-ui/use-agent-target.cjs +63 -0
- package/dist/agent-ui/use-agent-target.cjs.map +1 -0
- package/dist/agent-ui/use-agent-target.d.ts +27 -0
- package/dist/agent-ui/use-agent-target.js +63 -0
- package/dist/agent-ui/use-agent-target.js.map +1 -0
- package/dist/agent-ui/use-agent-ui.cjs +15 -0
- package/dist/agent-ui/use-agent-ui.cjs.map +1 -0
- package/dist/agent-ui/use-agent-ui.d.ts +24 -0
- package/dist/agent-ui/use-agent-ui.js +15 -0
- package/dist/agent-ui/use-agent-ui.js.map +1 -0
- package/dist/chat/AthenaChat.cjs +17 -4
- package/dist/chat/AthenaChat.cjs.map +1 -1
- package/dist/chat/AthenaChat.d.ts +13 -0
- package/dist/chat/AthenaChat.js +17 -4
- package/dist/chat/AthenaChat.js.map +1 -1
- package/dist/chat/StatewireClientToolBridge.cjs +17 -12
- package/dist/chat/StatewireClientToolBridge.cjs.map +1 -1
- package/dist/chat/StatewireClientToolBridge.d.ts +4 -2
- package/dist/chat/StatewireClientToolBridge.js +17 -12
- package/dist/chat/StatewireClientToolBridge.js.map +1 -1
- package/dist/chat/StatewireClientToolConsentCard.cjs +3 -2
- package/dist/chat/StatewireClientToolConsentCard.cjs.map +1 -1
- package/dist/chat/StatewireClientToolConsentCard.d.ts +2 -1
- package/dist/chat/StatewireClientToolConsentCard.js +3 -2
- package/dist/chat/StatewireClientToolConsentCard.js.map +1 -1
- package/dist/chat/chat-voice-controls.cjs +5 -2
- package/dist/chat/chat-voice-controls.cjs.map +1 -1
- package/dist/chat/chat-voice-controls.d.ts +6 -1
- package/dist/chat/chat-voice-controls.js +6 -3
- package/dist/chat/chat-voice-controls.js.map +1 -1
- package/dist/chat/client-tool-write-consent.cjs +16 -5
- package/dist/chat/client-tool-write-consent.cjs.map +1 -1
- package/dist/chat/client-tool-write-consent.d.ts +12 -4
- package/dist/chat/client-tool-write-consent.js +16 -5
- package/dist/chat/client-tool-write-consent.js.map +1 -1
- package/dist/chat-ui/messages/message-components.cjs +1 -1
- package/dist/chat-ui/messages/message-components.cjs.map +1 -1
- package/dist/chat-ui/messages/message-components.d.ts +2 -2
- package/dist/chat-ui/messages/message-components.js +1 -1
- package/dist/chat-ui/messages/message-components.js.map +1 -1
- package/dist/index.cjs +7 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/provider/AthenaProvider.cjs +37 -8
- package/dist/provider/AthenaProvider.cjs.map +1 -1
- package/dist/provider/AthenaProvider.d.ts +18 -1
- package/dist/provider/AthenaProvider.js +33 -4
- package/dist/provider/AthenaProvider.js.map +1 -1
- package/dist/react/package.json.cjs +1 -1
- package/dist/react/package.json.js +1 -1
- package/dist/styles.css +1 -1
- package/package.json +6 -1
package/README.md
CHANGED
|
@@ -318,6 +318,13 @@ function AddMenu() {
|
|
|
318
318
|
- `useAthenaComposerActions()` is `null` outside a composer slot. Both default
|
|
319
319
|
to `true`: a host that sets neither sees no change.
|
|
320
320
|
|
|
321
|
+
### A welcome of your own
|
|
322
|
+
|
|
323
|
+
`welcomeContent` replaces the greeting (`welcomeMessage`, `welcomeSubtext`) in
|
|
324
|
+
the empty thread with what the host renders, in the same place: Athena Desktop
|
|
325
|
+
draws one centred line there whose project name opens its project menu. Absent,
|
|
326
|
+
the greeting shows as before.
|
|
327
|
+
|
|
321
328
|
### Composer slash commands
|
|
322
329
|
|
|
323
330
|
`AthenaChat`'s `composer.slashCommands` (and `TiptapComposer`'s
|
|
@@ -1172,7 +1179,8 @@ const frontendTools = {
|
|
|
1172
1179
|
|
|
1173
1180
|
Before the tool's first call in a conversation runs, `AthenaChat` shows a card
|
|
1174
1181
|
above the composer ("The agent wants to save a note on this record.") with
|
|
1175
|
-
**Allow** and **Decline**. Allow covers the rest of
|
|
1182
|
+
**Allow** and **Decline**. Allow covers that tool for the rest of the
|
|
1183
|
+
conversation, and no other: a second marked tool asks for itself. Decline
|
|
1176
1184
|
answers the agent with an error for the waiting calls, and a later call asks
|
|
1177
1185
|
again. Calls to unmarked tools in the same turn still run. The answer is the
|
|
1178
1186
|
person's own: nothing is remembered across a reload, and someone else signing
|
|
@@ -1180,13 +1188,17 @@ in to the same mounted chat is asked for themselves. The mark also reaches
|
|
|
1180
1188
|
Athena (`requires_write`), which then never answers the call for the person
|
|
1181
1189
|
while their tab is away.
|
|
1182
1190
|
|
|
1191
|
+
- The card names who is asking with the name you gave the agent
|
|
1192
|
+
(`agentUi={{ agentName }}`), else "The agent".
|
|
1183
1193
|
- A host with its own chat mounts `StatewireClientToolConsentCard` (also in
|
|
1184
|
-
`@athenaintel/react/chat-ui/statewire`; `agentName`
|
|
1185
|
-
draws its own on `useClientToolWriteConsent()`:
|
|
1186
|
-
`request` holding the waiting tools (`name`,
|
|
1194
|
+
`@athenaintel/react/chat-ui/statewire`; its `agentName` prop overrides the
|
|
1195
|
+
name), or draws its own on `useClientToolWriteConsent()`:
|
|
1196
|
+
`{ request, allow, decline }`, `request` holding the waiting tools (`name`,
|
|
1197
|
+
`summary`) and that `agentName`, or `null`.
|
|
1187
1198
|
- To ask in a dialog of your own instead, pass `confirmClientToolWrites` on
|
|
1188
1199
|
`<AthenaProvider>`: it receives the same request plus a `signal`, and
|
|
1189
|
-
resolves `true` (allow the conversation) or `false`
|
|
1200
|
+
resolves `true` (allow those tools for the conversation) or `false`
|
|
1201
|
+
(decline). The signal
|
|
1190
1202
|
aborts when the question has no call left to answer: close the dialog then
|
|
1191
1203
|
(its promise need not settle, and a late answer is ignored). A confirmer
|
|
1192
1204
|
that throws counts as a decline.
|
|
@@ -1213,6 +1225,129 @@ execute: async (args, { abortSignal }) => {
|
|
|
1213
1225
|
},
|
|
1214
1226
|
```
|
|
1215
1227
|
|
|
1228
|
+
## Agent-drivable UI
|
|
1229
|
+
|
|
1230
|
+
An app can let its agent work on the screen the person has open: read what is
|
|
1231
|
+
there, point at something, walk the person through steps and, when asked,
|
|
1232
|
+
operate a control. Everything the agent does is shown on the page as it
|
|
1233
|
+
happens: it scrolls there, outlines the element, says what it is doing and
|
|
1234
|
+
types character by character, so the person can follow and learn. Ask "how do
|
|
1235
|
+
I filter this list?" and the agent shows it on the list itself.
|
|
1236
|
+
|
|
1237
|
+
The app decides what the agent can see and touch. Nothing is discovered: an
|
|
1238
|
+
element the app did not mark does not exist for the agent.
|
|
1239
|
+
|
|
1240
|
+
```tsx
|
|
1241
|
+
import { AthenaProvider, agentRegion, agentTarget } from '@athenaintel/react';
|
|
1242
|
+
|
|
1243
|
+
<AthenaProvider agentUi={{ agentName: 'Jichard' }} appId={publicAppId}>
|
|
1244
|
+
<div {...agentRegion({ id: 'filters', label: 'Search and filters' })}>
|
|
1245
|
+
<input
|
|
1246
|
+
aria-label="Search investors"
|
|
1247
|
+
{...agentTarget({ id: 'search', description: 'Narrows the table as it is typed into.' })}
|
|
1248
|
+
/>
|
|
1249
|
+
<button {...agentTarget({ id: 'filters.clear' })}>Clear filters</button>
|
|
1250
|
+
</div>
|
|
1251
|
+
{rows.map((row) => (
|
|
1252
|
+
<a key={row.id} href={row.href} {...agentTarget({ id: 'investor.open', key: row.id, label: row.name })}>
|
|
1253
|
+
{row.name}
|
|
1254
|
+
</a>
|
|
1255
|
+
))}
|
|
1256
|
+
<AthenaChat />
|
|
1257
|
+
</AthenaProvider>
|
|
1258
|
+
```
|
|
1259
|
+
|
|
1260
|
+
**Marking targets.** A target is a few `data-agent-*` attributes on the
|
|
1261
|
+
element itself, so any component that passes `data-*` props to its DOM node
|
|
1262
|
+
works, a plain web component included. `agentTarget(options)` writes them:
|
|
1263
|
+
|
|
1264
|
+
| Option | What it says |
|
|
1265
|
+
|--------|--------------|
|
|
1266
|
+
| `id` | What the agent names the target by: lowercase words joined by `.`, `-` or `_`, stable across renders (`filters.stage`). An id that is not one leaves the element unmarked and logs why. |
|
|
1267
|
+
| `key` | Which one, when several targets share an id (a row's key). The agent names it `investor.open[asset_1]`. |
|
|
1268
|
+
| `label` | What a person calls it. Defaults to the element's accessible name (`aria-label`, its `<label>`, its placeholder, its text). |
|
|
1269
|
+
| `description` | One line for the agent on what it is for. |
|
|
1270
|
+
| `actions` | What the agent may do to it: `click`, `type`, `select`, `toggle`, `clear`. Defaults to what the element allows by nature (a button is clicked, a text field typed into). `[]`: it may only be pointed at. |
|
|
1271
|
+
| `danger` | Acting on it changes or destroys something: the person confirms every time, and only the actions you list are allowed. |
|
|
1272
|
+
| `sensitive` | Its value is never read back to the agent and never typed by it, and its own text never names it. Password, one-time-code and card fields are treated this way without being marked. |
|
|
1273
|
+
|
|
1274
|
+
`agentRegion({ id, label })` names a part of the screen; its targets are
|
|
1275
|
+
grouped under it. For a control that clicks and keystrokes cannot drive (a
|
|
1276
|
+
custom select, a date picker), `useAgentTarget` takes `handlers` that replace
|
|
1277
|
+
the tool's own input, and `<AgentTarget>` marks the element inside it without
|
|
1278
|
+
touching that element's component:
|
|
1279
|
+
|
|
1280
|
+
```tsx
|
|
1281
|
+
import { AgentTarget, useAgentTarget } from '@athenaintel/react';
|
|
1282
|
+
|
|
1283
|
+
const stage = useAgentTarget({
|
|
1284
|
+
id: 'filters.stage',
|
|
1285
|
+
label: 'Stage filter',
|
|
1286
|
+
handlers: { select: ({ option }) => setStage(option), options: () => STAGES, value: () => stage },
|
|
1287
|
+
});
|
|
1288
|
+
<StagePicker {...stage} />
|
|
1289
|
+
|
|
1290
|
+
<AgentTarget id="deal.save" label="Save deal">
|
|
1291
|
+
<Button onClick={save}>Save</Button>
|
|
1292
|
+
</AgentTarget>
|
|
1293
|
+
```
|
|
1294
|
+
|
|
1295
|
+
**What the agent gets.** A fixed handful of tools that name targets by id,
|
|
1296
|
+
declared with every message like any `frontendTools` entry (so `appId` must
|
|
1297
|
+
be a recognised one):
|
|
1298
|
+
|
|
1299
|
+
| Tool | What it does | Changes something |
|
|
1300
|
+
|------|--------------|-------------------|
|
|
1301
|
+
| `read_screen` | Lists the targets on screen: id, role, label, value, state and allowed actions, grouped by region. `region` and `query` narrow it; a long table lists its first 25 rows and counts the rest. | no |
|
|
1302
|
+
| `point_at` | Scrolls to a target, outlines it and shows a note beside it for a few seconds (5 by default, 30 at most). `spotlight` dims the rest of the page. | no |
|
|
1303
|
+
| `show_steps` | A walkthrough of up to 12 steps, each a target and a sentence or two. It advances by itself; the person can pause, go back, skip ahead or close it. | no |
|
|
1304
|
+
| `act_on` | Operates one target: scrolls there, outlines it, moves a cursor onto it, then clicks, types, chooses an option, flips a switch or clears a field, through the element's own events, so your handlers, validation and undo run as they do for a person. | yes |
|
|
1305
|
+
| `go_to` | Opens one of the pages you list. Declared only when you pass `routes` and `navigate`. | no |
|
|
1306
|
+
|
|
1307
|
+
Your own tools stay the way to do a whole job (set these filters, open that
|
|
1308
|
+
record): they take one call and say what changed. The screen tools are for
|
|
1309
|
+
showing, and for the controls no tool of yours covers.
|
|
1310
|
+
|
|
1311
|
+
**Asking first, and stopping.** `act_on` is marked `requiresWriteConsent`, so
|
|
1312
|
+
the chat's consent card asks before the agent first acts in a conversation
|
|
1313
|
+
(see [Frontend tools that ask first, and stop](#frontend-tools-that-ask-first-and-stop)).
|
|
1314
|
+
A `danger` target is asked about on the page itself, every time. The agent
|
|
1315
|
+
acts on the one element it named, as that element is at the moment of acting:
|
|
1316
|
+
several rows sharing an id must be named by key, and an element that changed
|
|
1317
|
+
while the person read the question (another row, disabled, now a password
|
|
1318
|
+
field) is refused. What a keyboard could not do, it does not do: a read-only
|
|
1319
|
+
field is not typed into, nor a field past its `maxlength`. The person's own
|
|
1320
|
+
click, keypress or scroll stops an action in flight and holds back whatever
|
|
1321
|
+
else the agent asked for in the same turn, as does stopping the run; Escape
|
|
1322
|
+
closes whatever the agent is showing, and the keyboard goes back to where it
|
|
1323
|
+
was. With `prefers-reduced-motion` the same steps play without motion: scrolls
|
|
1324
|
+
jump, the cursor lands in place and typed text arrives whole.
|
|
1325
|
+
|
|
1326
|
+
**Options** (`agentUi={{ … }}`; `true` takes the defaults):
|
|
1327
|
+
|
|
1328
|
+
| Option | Default | Purpose |
|
|
1329
|
+
|--------|---------|---------|
|
|
1330
|
+
| `agentName` | `"The agent"` | Who the overlay says is acting, and who the chat's consent card says is asking. |
|
|
1331
|
+
| `speed` | `"normal"` | `"quick"` halves the waits; `"instant"` removes them. |
|
|
1332
|
+
| `allowActing` | `true` | `false` declares no `act_on`: the agent looks and points only (a read-only or "ask" mode). |
|
|
1333
|
+
| `actConsent` | `"host"` | `"overlay"` asks on the page (once per visit) instead of through the chat's consent card. |
|
|
1334
|
+
| `routes`, `navigate` | none | The pages `go_to` may open, and how to open one. |
|
|
1335
|
+
| `describePage` | none | Facts about the page on screen that `read_screen` passes on (its name, the record open). |
|
|
1336
|
+
| `classNames` | none | Restyle the overlay's pieces: `mark`, `caption`, `cursor`, `tour`, `question`. |
|
|
1337
|
+
|
|
1338
|
+
The overlay uses the SDK's own tokens (`primary`, `popover`, `border`), so it
|
|
1339
|
+
follows your theme. To wire the pieces yourself, or draw your own overlay, use
|
|
1340
|
+
`@athenaintel/react/agent-ui`: `useAgentUi(options)` returns `{ agentUi, tools }`
|
|
1341
|
+
(spread `tools` into `frontendTools`), `<AgentUiLayer agentUi={agentUi} />`
|
|
1342
|
+
draws the stage, and `agentUi.stage` (`getState`, `subscribe`) is everything
|
|
1343
|
+
the overlay shows, for a layer of your own.
|
|
1344
|
+
|
|
1345
|
+
**What it does not do.** It works inside one document: a target in an iframe
|
|
1346
|
+
is not seen. A row a virtualized list has not rendered is not on the screen.
|
|
1347
|
+
Nothing is discovered without a mark. None of it is a permission boundary:
|
|
1348
|
+
the tools run in the person's tab as the signed-in person, and your backend's
|
|
1349
|
+
checks, or Athena's, decide what any click may do.
|
|
1350
|
+
|
|
1216
1351
|
## Chat voice in AthenaChat
|
|
1217
1352
|
|
|
1218
1353
|
`AthenaChat` includes realtime voice alongside dictation where the deployment
|
|
@@ -1246,6 +1381,12 @@ or a typed send. A host's own "Continue on…" control offers to send the
|
|
|
1246
1381
|
conversation in voice mode only while `useChatVoiceEnabled({ enabled })` is
|
|
1247
1382
|
true: the same workspace gate the composer's voice control uses.
|
|
1248
1383
|
|
|
1384
|
+
A host can fold voice into Send, as ChatGPT's composer does, with
|
|
1385
|
+
`composer={{ voiceInSend: true }}`: while the draft is empty and no run or call
|
|
1386
|
+
is live, one ink circle with a waveform starts the call; once the person types,
|
|
1387
|
+
Send takes its place. A call that is connecting or live keeps its own cancel or
|
|
1388
|
+
mute beside Send or Stop. Default `false`: voice and Send side by side.
|
|
1389
|
+
|
|
1249
1390
|
Use `<AthenaChat voice={false} />` to omit realtime voice in a host that cannot
|
|
1250
1391
|
support it, or `voice={{ model: 'gemini-3.8-live' }}` to request a host-offered
|
|
1251
1392
|
voice model. A custom `livekit` adapter and `onDiagnostic` observer are accepted
|
|
@@ -1409,6 +1550,17 @@ Both use the same bearer / API key as session creation. The full recipe
|
|
|
1409
1550
|
template skill `voice-session-guide.md`. `createAthenaVoiceSession` is also
|
|
1410
1551
|
exported if you hold the bridge state yourself.
|
|
1411
1552
|
|
|
1553
|
+
## What's new in 0.61.0
|
|
1554
|
+
|
|
1555
|
+
**An app can let its agent work on the screen the person has open.** With `agentUi` on `<AthenaProvider>`, the agent reads the controls your app marks (`agentTarget`, `useAgentTarget`, `<AgentTarget>`), points at one, walks the person through steps on the page, and operates a control once the person allows it. Everything it does is drawn on the page: an outline, a note, a cursor. Nothing unmarked exists for the agent, and password-like fields are never read or typed into. See [Agent-drivable UI](#agent-drivable-ui); the rest of the module is `@athenaintel/react/agent-ui`.
|
|
1556
|
+
|
|
1557
|
+
**A yes to one frontend tool is no longer a yes to another.** A tool marked `requiresWriteConsent` is asked about once per conversation, by itself. In 0.60.1, one Allow covered every marked tool for the rest of that conversation.
|
|
1558
|
+
|
|
1559
|
+
Also in this release:
|
|
1560
|
+
- The consent card names the agent when the app names it (`agentUi={{ agentName }}`), and the request a host's own consent UI receives carries that `agentName`.
|
|
1561
|
+
- `AthenaChat` takes `welcomeContent`, the host's own empty-state welcome in place of the greeting, and `composer={{ voiceInSend: true }}`, one button for voice and Send.
|
|
1562
|
+
- The composer's border darkens a step while it holds focus, in place of the focus ring.
|
|
1563
|
+
|
|
1412
1564
|
## What's new in 0.60.1
|
|
1413
1565
|
|
|
1414
1566
|
**The `@` menu's asset icons draw in apps a computer serves.** In those apps, Marathon's `/_athena/auth` mints `appUrl` as the app's own origin, which serves no Athena icons. So 0.60.0 asked the app itself for the SVGs, and every row fell back to its type's Lucide icon. The icons, mailbox logos, chips and drive cards now load from the deployment's frontend there (`staging-app.athenaintel.com`, `app.athenaintel.com`), the same frontend "Open in Athena" links go to (`assetIconAppUrl`, on `athenaLinkAppUrl`).
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
4
|
+
const radixUi = require("radix-ui");
|
|
5
|
+
const useAgentTarget = require("./use-agent-target.cjs");
|
|
6
|
+
function AgentTarget({ children, ...options }) {
|
|
7
|
+
const props = useAgentTarget.useAgentTarget(options);
|
|
8
|
+
return /* @__PURE__ */ jsxRuntime.jsx(radixUi.Slot.Root, { ...props, children });
|
|
9
|
+
}
|
|
10
|
+
exports.AgentTarget = AgentTarget;
|
|
11
|
+
//# sourceMappingURL=AgentTarget.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AgentTarget.cjs","sources":["../../src/agent-ui/AgentTarget.tsx"],"sourcesContent":["'use client';\n\nimport { Slot } from 'radix-ui';\nimport type { ReactNode } from 'react';\nimport { type UseAgentTargetOptions, useAgentTarget } from './use-agent-target';\n\nexport interface AgentTargetProps extends UseAgentTargetOptions {\n /** The one element that becomes the target. It must pass `data-*` props to its DOM node. */\n children: ReactNode;\n}\n\n/**\n * Make the element inside an agent target, without touching the element's own\n * component: its markup, styles and behaviour stay exactly as they are.\n *\n * ```tsx\n * <AgentTarget id=\"deal.save\" label=\"Save deal\">\n * <Button onClick={save}>Save</Button>\n * </AgentTarget>\n * ```\n */\nexport function AgentTarget({ children, ...options }: AgentTargetProps) {\n const props = useAgentTarget(options);\n return <Slot.Root {...props}>{children}</Slot.Root>;\n}\n"],"names":["useAgentTarget","Slot"],"mappings":";;;;;AAqBO,SAAS,YAAY,EAAE,UAAU,GAAG,WAA6B;AACtE,QAAM,QAAQA,eAAAA,eAAe,OAAO;AACpC,wCAAQC,QAAAA,KAAK,MAAL,EAAW,GAAG,OAAQ,UAAS;AACzC;;"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import { type UseAgentTargetOptions } from './use-agent-target';
|
|
3
|
+
export interface AgentTargetProps extends UseAgentTargetOptions {
|
|
4
|
+
/** The one element that becomes the target. It must pass `data-*` props to its DOM node. */
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Make the element inside an agent target, without touching the element's own
|
|
9
|
+
* component: its markup, styles and behaviour stay exactly as they are.
|
|
10
|
+
*
|
|
11
|
+
* ```tsx
|
|
12
|
+
* <AgentTarget id="deal.save" label="Save deal">
|
|
13
|
+
* <Button onClick={save}>Save</Button>
|
|
14
|
+
* </AgentTarget>
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export declare function AgentTarget({ children, ...options }: AgentTargetProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Slot } from "radix-ui";
|
|
3
|
+
import { useAgentTarget } from "./use-agent-target.js";
|
|
4
|
+
function AgentTarget({ children, ...options }) {
|
|
5
|
+
const props = useAgentTarget(options);
|
|
6
|
+
return /* @__PURE__ */ jsx(Slot.Root, { ...props, children });
|
|
7
|
+
}
|
|
8
|
+
export {
|
|
9
|
+
AgentTarget
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=AgentTarget.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AgentTarget.js","sources":["../../src/agent-ui/AgentTarget.tsx"],"sourcesContent":["'use client';\n\nimport { Slot } from 'radix-ui';\nimport type { ReactNode } from 'react';\nimport { type UseAgentTargetOptions, useAgentTarget } from './use-agent-target';\n\nexport interface AgentTargetProps extends UseAgentTargetOptions {\n /** The one element that becomes the target. It must pass `data-*` props to its DOM node. */\n children: ReactNode;\n}\n\n/**\n * Make the element inside an agent target, without touching the element's own\n * component: its markup, styles and behaviour stay exactly as they are.\n *\n * ```tsx\n * <AgentTarget id=\"deal.save\" label=\"Save deal\">\n * <Button onClick={save}>Save</Button>\n * </AgentTarget>\n * ```\n */\nexport function AgentTarget({ children, ...options }: AgentTargetProps) {\n const props = useAgentTarget(options);\n return <Slot.Root {...props}>{children}</Slot.Root>;\n}\n"],"names":[],"mappings":";;;AAqBO,SAAS,YAAY,EAAE,UAAU,GAAG,WAA6B;AACtE,QAAM,QAAQ,eAAe,OAAO;AACpC,6BAAQ,KAAK,MAAL,EAAW,GAAG,OAAQ,UAAS;AACzC;"}
|
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
4
|
+
const lucideReact = require("lucide-react");
|
|
5
|
+
const require$$0 = require("react");
|
|
6
|
+
const reactDom = require("react-dom");
|
|
7
|
+
const lib_ownerDocument = require("../lib/owner-document.cjs");
|
|
8
|
+
const themeStyleContext = require("../provider/theme-style-context.cjs");
|
|
9
|
+
const contract = require("./contract.cjs");
|
|
10
|
+
const cnfast = require("cnfast");
|
|
11
|
+
const MARK_INSET_PX = 4;
|
|
12
|
+
const CARD_GAP_PX = 10;
|
|
13
|
+
const CARD_WIDTH_PX = 320;
|
|
14
|
+
const CARD_ROOM_PX = 150;
|
|
15
|
+
const EDGE_PX = 8;
|
|
16
|
+
function useElementBox(element) {
|
|
17
|
+
const [box, setBox] = require$$0.useState(null);
|
|
18
|
+
require$$0.useEffect(() => {
|
|
19
|
+
const view = element == null ? void 0 : element.ownerDocument.defaultView;
|
|
20
|
+
if (!element || !view) {
|
|
21
|
+
setBox(null);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
let frame = 0;
|
|
25
|
+
let last = "";
|
|
26
|
+
const read = () => {
|
|
27
|
+
const rect = element.isConnected ? element.getBoundingClientRect() : null;
|
|
28
|
+
const next = rect ? { top: rect.top, left: rect.left, width: rect.width, height: rect.height } : null;
|
|
29
|
+
const signature = next ? [next.top, next.left, next.width, next.height].map(Math.round).join(":") : "gone";
|
|
30
|
+
if (signature !== last) {
|
|
31
|
+
last = signature;
|
|
32
|
+
setBox(next);
|
|
33
|
+
}
|
|
34
|
+
frame = view.requestAnimationFrame(read);
|
|
35
|
+
};
|
|
36
|
+
read();
|
|
37
|
+
return () => view.cancelAnimationFrame(frame);
|
|
38
|
+
}, [element]);
|
|
39
|
+
return box;
|
|
40
|
+
}
|
|
41
|
+
function viewportOf(doc) {
|
|
42
|
+
const view = doc == null ? void 0 : doc.defaultView;
|
|
43
|
+
return { width: (view == null ? void 0 : view.innerWidth) ?? 1024, height: (view == null ? void 0 : view.innerHeight) ?? 768 };
|
|
44
|
+
}
|
|
45
|
+
function cardPosition({ box, viewport }) {
|
|
46
|
+
const width = Math.min(CARD_WIDTH_PX, viewport.width - EDGE_PX * 2);
|
|
47
|
+
if (!box) {
|
|
48
|
+
return { left: Math.max(EDGE_PX, (viewport.width - width) / 2), bottom: 24, width };
|
|
49
|
+
}
|
|
50
|
+
const left = Math.min(Math.max(box.left, EDGE_PX), Math.max(EDGE_PX, viewport.width - width - EDGE_PX));
|
|
51
|
+
const below = box.top + box.height + MARK_INSET_PX + CARD_GAP_PX;
|
|
52
|
+
if (below + CARD_ROOM_PX <= viewport.height || box.top < CARD_ROOM_PX) {
|
|
53
|
+
return { left, top: Math.min(below, Math.max(EDGE_PX, viewport.height - CARD_ROOM_PX)), width };
|
|
54
|
+
}
|
|
55
|
+
return { left, bottom: viewport.height - box.top + MARK_INSET_PX + CARD_GAP_PX, width };
|
|
56
|
+
}
|
|
57
|
+
const TONE_CLASS = {
|
|
58
|
+
point: "border-primary ring-primary/25",
|
|
59
|
+
act: "border-primary ring-primary/25 border-dashed",
|
|
60
|
+
ask: "border-amber-500 ring-amber-500/25"
|
|
61
|
+
};
|
|
62
|
+
function Mark({
|
|
63
|
+
box,
|
|
64
|
+
tone,
|
|
65
|
+
spotlight,
|
|
66
|
+
leaving,
|
|
67
|
+
className
|
|
68
|
+
}) {
|
|
69
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
70
|
+
"div",
|
|
71
|
+
{
|
|
72
|
+
"data-testid": "agent-ui-mark",
|
|
73
|
+
"data-tone": tone,
|
|
74
|
+
className: cnfast.cn(
|
|
75
|
+
"pointer-events-none fixed rounded-lg border-2 ring-4 transition-opacity duration-500 motion-reduce:transition-none",
|
|
76
|
+
TONE_CLASS[tone],
|
|
77
|
+
spotlight && "shadow-[0_0_0_100vmax_rgb(0_0_0/0.45)]",
|
|
78
|
+
leaving ? "opacity-0" : "opacity-100",
|
|
79
|
+
className
|
|
80
|
+
),
|
|
81
|
+
style: {
|
|
82
|
+
top: box.top - MARK_INSET_PX,
|
|
83
|
+
left: box.left - MARK_INSET_PX,
|
|
84
|
+
width: box.width + MARK_INSET_PX * 2,
|
|
85
|
+
height: box.height + MARK_INSET_PX * 2
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
function Card({
|
|
91
|
+
box,
|
|
92
|
+
viewport,
|
|
93
|
+
fit = false,
|
|
94
|
+
className,
|
|
95
|
+
children,
|
|
96
|
+
...props
|
|
97
|
+
}) {
|
|
98
|
+
const { width, ...position } = cardPosition({ box, viewport });
|
|
99
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
100
|
+
"div",
|
|
101
|
+
{
|
|
102
|
+
...props,
|
|
103
|
+
className: cnfast.cn(
|
|
104
|
+
"pointer-events-auto fixed rounded-xl border border-border bg-popover px-3.5 py-3 text-popover-foreground text-sm shadow-lg",
|
|
105
|
+
className
|
|
106
|
+
),
|
|
107
|
+
style: fit ? { ...position, maxWidth: width } : { ...position, width },
|
|
108
|
+
children
|
|
109
|
+
}
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
function Cursor({
|
|
113
|
+
box,
|
|
114
|
+
presses,
|
|
115
|
+
glideMs,
|
|
116
|
+
className
|
|
117
|
+
}) {
|
|
118
|
+
const x = box.left + box.width / 2;
|
|
119
|
+
const y = box.top + box.height / 2;
|
|
120
|
+
const [arrived, setArrived] = require$$0.useState(false);
|
|
121
|
+
require$$0.useEffect(() => {
|
|
122
|
+
const frame = requestAnimationFrame(() => setArrived(true));
|
|
123
|
+
return () => cancelAnimationFrame(frame);
|
|
124
|
+
}, []);
|
|
125
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
126
|
+
"div",
|
|
127
|
+
{
|
|
128
|
+
"data-testid": "agent-ui-cursor",
|
|
129
|
+
className: cnfast.cn("pointer-events-none fixed top-0 left-0 motion-reduce:transition-none", className),
|
|
130
|
+
style: {
|
|
131
|
+
transform: `translate(${arrived ? x : x + 48}px, ${arrived ? y : y + 48}px)`,
|
|
132
|
+
transitionProperty: "transform",
|
|
133
|
+
transitionTimingFunction: "ease-out",
|
|
134
|
+
transitionDuration: `${glideMs}ms`
|
|
135
|
+
},
|
|
136
|
+
children: [
|
|
137
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.MousePointer2Icon, { className: "size-5 fill-primary text-primary-foreground drop-shadow" }),
|
|
138
|
+
presses > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
139
|
+
"span",
|
|
140
|
+
{
|
|
141
|
+
"data-testid": "agent-ui-press",
|
|
142
|
+
className: "-top-2 -left-2 absolute size-6 animate-ping rounded-full bg-primary/50 [animation-iteration-count:1]"
|
|
143
|
+
},
|
|
144
|
+
presses
|
|
145
|
+
) : null
|
|
146
|
+
]
|
|
147
|
+
}
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
function TourCard({
|
|
151
|
+
tour,
|
|
152
|
+
stage,
|
|
153
|
+
box,
|
|
154
|
+
viewport,
|
|
155
|
+
className
|
|
156
|
+
}) {
|
|
157
|
+
const step = tour.steps[tour.index];
|
|
158
|
+
const last = tour.index >= tour.steps.length - 1;
|
|
159
|
+
const progressRef = require$$0.useRef(null);
|
|
160
|
+
const advancing = tour.playing && !tour.searching;
|
|
161
|
+
const durationMs = (step == null ? void 0 : step.durationMs) ?? 0;
|
|
162
|
+
require$$0.useEffect(() => {
|
|
163
|
+
const bar = progressRef.current;
|
|
164
|
+
if (!bar || typeof bar.animate !== "function") return;
|
|
165
|
+
if (!advancing) return;
|
|
166
|
+
const animation = bar.animate([{ width: "0%" }, { width: "100%" }], {
|
|
167
|
+
duration: durationMs,
|
|
168
|
+
fill: "forwards",
|
|
169
|
+
easing: "linear"
|
|
170
|
+
});
|
|
171
|
+
return () => animation.cancel();
|
|
172
|
+
}, [advancing, durationMs, tour.index]);
|
|
173
|
+
if (!step) return null;
|
|
174
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
175
|
+
Card,
|
|
176
|
+
{
|
|
177
|
+
box,
|
|
178
|
+
viewport,
|
|
179
|
+
className,
|
|
180
|
+
role: "dialog",
|
|
181
|
+
"aria-label": tour.title ?? "Walkthrough",
|
|
182
|
+
"data-testid": "agent-ui-tour",
|
|
183
|
+
children: [
|
|
184
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-3", children: [
|
|
185
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "min-w-0 truncate text-muted-foreground text-xs", children: [
|
|
186
|
+
tour.title ? `${tour.title} · ` : "",
|
|
187
|
+
"Step ",
|
|
188
|
+
tour.index + 1,
|
|
189
|
+
" of ",
|
|
190
|
+
tour.steps.length
|
|
191
|
+
] }),
|
|
192
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
193
|
+
"button",
|
|
194
|
+
{
|
|
195
|
+
type: "button",
|
|
196
|
+
"aria-label": "Close the walkthrough",
|
|
197
|
+
onClick: () => stage.endTour(),
|
|
198
|
+
className: "shrink-0 rounded-md p-1 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
|
|
199
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XIcon, { className: "size-3.5" })
|
|
200
|
+
}
|
|
201
|
+
)
|
|
202
|
+
] }),
|
|
203
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "break-words pt-1.5 leading-snug", "data-testid": "agent-ui-tour-text", children: step.text }),
|
|
204
|
+
!tour.searching && !tour.element ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pt-1 text-muted-foreground text-xs", children: "This one is not on the page you have open." }) : null,
|
|
205
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2.5 h-0.5 overflow-hidden rounded-full bg-muted", children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: progressRef, className: "h-full w-0 bg-primary" }) }),
|
|
206
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 pt-2", children: [
|
|
207
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
208
|
+
"button",
|
|
209
|
+
{
|
|
210
|
+
type: "button",
|
|
211
|
+
"aria-label": "Previous step",
|
|
212
|
+
disabled: tour.index === 0,
|
|
213
|
+
onClick: () => stage.tourBack(),
|
|
214
|
+
className: "rounded-md p-1.5 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground disabled:opacity-40",
|
|
215
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeftIcon, { className: "size-4" })
|
|
216
|
+
}
|
|
217
|
+
),
|
|
218
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
219
|
+
"button",
|
|
220
|
+
{
|
|
221
|
+
type: "button",
|
|
222
|
+
"aria-label": tour.playing ? "Pause the walkthrough" : "Play the walkthrough",
|
|
223
|
+
onClick: () => stage.tourTogglePlaying(),
|
|
224
|
+
className: "rounded-md p-1.5 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
|
|
225
|
+
children: tour.playing ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PauseIcon, { className: "size-4" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PlayIcon, { className: "size-4" })
|
|
226
|
+
}
|
|
227
|
+
),
|
|
228
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
229
|
+
"button",
|
|
230
|
+
{
|
|
231
|
+
type: "button",
|
|
232
|
+
onClick: () => stage.tourNext(),
|
|
233
|
+
className: "ml-auto flex items-center gap-1 rounded-md bg-primary px-2.5 py-1 font-medium text-primary-foreground text-xs transition-colors hover:bg-primary/90",
|
|
234
|
+
children: [
|
|
235
|
+
last ? "Done" : "Next",
|
|
236
|
+
last ? null : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRightIcon, { className: "size-3.5" })
|
|
237
|
+
]
|
|
238
|
+
}
|
|
239
|
+
)
|
|
240
|
+
] })
|
|
241
|
+
]
|
|
242
|
+
}
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
function QuestionCard({
|
|
246
|
+
question,
|
|
247
|
+
stage,
|
|
248
|
+
box,
|
|
249
|
+
viewport,
|
|
250
|
+
className
|
|
251
|
+
}) {
|
|
252
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
253
|
+
Card,
|
|
254
|
+
{
|
|
255
|
+
box,
|
|
256
|
+
viewport,
|
|
257
|
+
className,
|
|
258
|
+
role: "alertdialog",
|
|
259
|
+
"aria-label": question.title,
|
|
260
|
+
"data-testid": "agent-ui-question",
|
|
261
|
+
children: [
|
|
262
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "break-words font-semibold leading-snug", children: question.title }),
|
|
263
|
+
question.body ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "break-words pt-1 text-muted-foreground leading-snug", children: question.body }) : null,
|
|
264
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2 pt-2.5", children: [
|
|
265
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
266
|
+
"button",
|
|
267
|
+
{
|
|
268
|
+
type: "button",
|
|
269
|
+
onClick: () => stage.answer(true),
|
|
270
|
+
className: "rounded-md bg-primary px-2.5 py-1 font-medium text-primary-foreground text-xs transition-colors hover:bg-primary/90",
|
|
271
|
+
children: question.allowLabel
|
|
272
|
+
}
|
|
273
|
+
),
|
|
274
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
275
|
+
"button",
|
|
276
|
+
{
|
|
277
|
+
type: "button",
|
|
278
|
+
onClick: () => stage.answer(false),
|
|
279
|
+
className: "rounded-md border border-border px-2.5 py-1 font-medium text-xs transition-colors hover:bg-muted",
|
|
280
|
+
children: question.declineLabel
|
|
281
|
+
}
|
|
282
|
+
)
|
|
283
|
+
] })
|
|
284
|
+
]
|
|
285
|
+
}
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
function AgentUiLayer({ agentUi, classNames }) {
|
|
289
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
290
|
+
const { stage } = agentUi;
|
|
291
|
+
const state = require$$0.useSyncExternalStore(stage.subscribe, stage.getState, stage.getState);
|
|
292
|
+
const ownerDocument = lib_ownerDocument.useOwnerDocument();
|
|
293
|
+
const portalContainer = lib_ownerDocument.usePortalContainer();
|
|
294
|
+
const themeStyle = themeStyleContext.useAthenaThemeStyle();
|
|
295
|
+
const tourElement = ((_a = state.tour) == null ? void 0 : _a.element) ?? null;
|
|
296
|
+
const markedElement = state.tour ? tourElement : ((_b = state.mark) == null ? void 0 : _b.element) ?? null;
|
|
297
|
+
const markBox = useElementBox(markedElement);
|
|
298
|
+
const cursorBox = useElementBox(((_c = state.cursor) == null ? void 0 : _c.element) ?? null);
|
|
299
|
+
const questionBox = useElementBox(((_d = state.question) == null ? void 0 : _d.element) ?? null);
|
|
300
|
+
const showing = state.tour !== null || state.mark !== null;
|
|
301
|
+
require$$0.useEffect(() => {
|
|
302
|
+
if (!showing || !ownerDocument) return;
|
|
303
|
+
const onKeyDown = (event) => {
|
|
304
|
+
if (event.key !== "Escape") return;
|
|
305
|
+
stage.endTour();
|
|
306
|
+
stage.clearMark();
|
|
307
|
+
};
|
|
308
|
+
ownerDocument.addEventListener("keydown", onKeyDown);
|
|
309
|
+
return () => ownerDocument.removeEventListener("keydown", onKeyDown);
|
|
310
|
+
}, [ownerDocument, showing, stage]);
|
|
311
|
+
const container = portalContainer ?? (ownerDocument == null ? void 0 : ownerDocument.body);
|
|
312
|
+
if (!container) return null;
|
|
313
|
+
const idle = !state.mark && !state.cursor && !state.tour && !state.question;
|
|
314
|
+
if (idle) return null;
|
|
315
|
+
const viewport = viewportOf(ownerDocument);
|
|
316
|
+
const caption = state.tour ? null : ((_e = state.mark) == null ? void 0 : _e.caption) ?? null;
|
|
317
|
+
return reactDom.createPortal(
|
|
318
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
319
|
+
"div",
|
|
320
|
+
{
|
|
321
|
+
...{ [contract.AGENT_ATTR.layer]: "" },
|
|
322
|
+
className: "athena-sdk athena-sdk-chrome pointer-events-none fixed inset-0 z-[2147483000]",
|
|
323
|
+
style: themeStyle,
|
|
324
|
+
children: [
|
|
325
|
+
markBox && (state.tour || state.mark) ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
326
|
+
Mark,
|
|
327
|
+
{
|
|
328
|
+
box: markBox,
|
|
329
|
+
tone: state.tour ? "point" : ((_f = state.mark) == null ? void 0 : _f.tone) ?? "point",
|
|
330
|
+
spotlight: state.tour ? false : ((_g = state.mark) == null ? void 0 : _g.spotlight) ?? false,
|
|
331
|
+
leaving: state.tour ? false : ((_h = state.mark) == null ? void 0 : _h.leaving) ?? false,
|
|
332
|
+
className: classNames == null ? void 0 : classNames.mark
|
|
333
|
+
}
|
|
334
|
+
) : null,
|
|
335
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { "aria-live": "polite", children: caption && markBox && !state.question ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
336
|
+
Card,
|
|
337
|
+
{
|
|
338
|
+
box: markBox,
|
|
339
|
+
viewport,
|
|
340
|
+
fit: true,
|
|
341
|
+
className: cnfast.cn(
|
|
342
|
+
"pointer-events-none transition-opacity duration-500 motion-reduce:transition-none",
|
|
343
|
+
((_i = state.mark) == null ? void 0 : _i.leaving) ? "opacity-0" : "opacity-100",
|
|
344
|
+
classNames == null ? void 0 : classNames.caption
|
|
345
|
+
),
|
|
346
|
+
"data-testid": "agent-ui-caption",
|
|
347
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "break-words leading-snug", children: caption })
|
|
348
|
+
}
|
|
349
|
+
) : null }),
|
|
350
|
+
state.tour ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
351
|
+
TourCard,
|
|
352
|
+
{
|
|
353
|
+
tour: state.tour,
|
|
354
|
+
stage,
|
|
355
|
+
box: markBox,
|
|
356
|
+
viewport,
|
|
357
|
+
className: classNames == null ? void 0 : classNames.tour
|
|
358
|
+
}
|
|
359
|
+
) : null,
|
|
360
|
+
state.question ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
361
|
+
QuestionCard,
|
|
362
|
+
{
|
|
363
|
+
question: state.question,
|
|
364
|
+
stage,
|
|
365
|
+
box: questionBox,
|
|
366
|
+
viewport,
|
|
367
|
+
className: classNames == null ? void 0 : classNames.question
|
|
368
|
+
}
|
|
369
|
+
) : null,
|
|
370
|
+
state.cursor && cursorBox ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
371
|
+
Cursor,
|
|
372
|
+
{
|
|
373
|
+
box: cursorBox,
|
|
374
|
+
presses: state.cursor.presses,
|
|
375
|
+
glideMs: agentUi.pace().cursorGlideMs,
|
|
376
|
+
className: classNames == null ? void 0 : classNames.cursor
|
|
377
|
+
}
|
|
378
|
+
) : null
|
|
379
|
+
]
|
|
380
|
+
}
|
|
381
|
+
),
|
|
382
|
+
container
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
exports.AgentUiLayer = AgentUiLayer;
|
|
386
|
+
exports.cardPosition = cardPosition;
|
|
387
|
+
//# sourceMappingURL=AgentUiLayer.cjs.map
|