@astralbeam/sdk 0.0.5 → 0.1.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 CHANGED
@@ -1,171 +1,135 @@
1
1
  # @astralbeam/sdk
2
2
 
3
- Frontend SDK for [AstralBeam](https://astralbeam.ai): drop-in, fully-customizable agent UI with managed chat streaming, conversation history, and observability.
4
-
5
- > Work in progress: the chat streams from a real agent endpoint (an AstralBeam webapp exposing `/api/chat`), with optional host-backed authentication, streaming messages, tool calls executed in the host page, in-chat questionnaires, and host-rendered widgets. Conversation history is not built yet.
6
-
7
- ## Installation
3
+ A drop-in agent chat sidebar for your web app, from [AstralBeam](https://astralbeam.ai), with a headless core underneath when you want to own the UI. The widget renders in a shadow root so its styles never mix with yours, and it streams from an AstralBeam chat endpoint.
8
4
 
9
5
  ```sh
10
6
  npm install @astralbeam/sdk
11
7
  ```
12
8
 
13
- ## Usage
9
+ ## Quick start
14
10
 
15
- ### Vanilla (any web app)
11
+ One component in React, one function everywhere else. Full setup, including the required token endpoint, is in [Getting started](https://app.astralbeam.ai/docs/sdk/getting-started).
16
12
 
17
- `@astralbeam/sdk/client` is a tiny framework-agnostic loader with no dependencies of its own; the React-based chat widget is bundled into a lazily loaded chunk, so the host page does not need React.
13
+ ```tsx
14
+ import { AstralBeamChat } from "@astralbeam/sdk/react"
15
+
16
+ export function Sidebar() {
17
+ return <AstralBeamChat />
18
+ }
19
+ ```
18
20
 
19
21
  ```ts
20
22
  import { mountAstralBeamChat } from "@astralbeam/sdk/client"
21
23
 
22
- const sidebar = document.getElementById("sidebar")
23
- const handle = mountAstralBeamChat(sidebar, {
24
- title: "Dashboard assistant", // name in the widget header (default "AstralBeam")
25
- showHeader: true, // header with the title and the reset button (default true)
26
- chatEndpoint: "https://myapp.example/api/chat", // AstralBeam chat endpoint (default "/api/chat")
27
- authEndpoint: "/api/astralbeam/token", // host endpoint minting the chat token (required today)
28
- systemPrompt: "You are the assistant of an infrastructure dashboard.",
29
- colorScheme: "system", // "light" | "dark" | "system" (default)
30
- theme: {
31
- // custom values for the widget's theming CSS variables (all optional)
32
- light: { "--primary": "#b4762a", "--radius": "0px" },
33
- dark: { "--primary": "#d99a45" },
34
- },
35
- attachments: { maxFiles: 3 }, // file attachments in the composer (on by default; false to hide)
36
- debug: false, // log every SDK and endpoint action to the consoles (default false)
37
- tools: {
38
- restart_service: {
39
- metadata: { title: "Restart a service" }, // transcript label; defaults to the tool's name
40
- description: "Restart one of the host app's services by name",
41
- parameters: {
42
- type: "object",
43
- properties: { service: { type: "string" } },
44
- required: ["service"],
45
- },
46
- execute: async ({ service }) => await restartService(String(service)),
47
- },
48
- },
49
- widgets: {
50
- systemStatus: {
51
- description: "Shows the current status of the host app's systems",
52
- parameters: {
53
- type: "object",
54
- properties: { degraded: { type: "boolean" } },
55
- },
56
- render: (props, container) => {
57
- container.textContent = props.degraded ? "Degraded performance" : "All systems operational"
58
- },
59
- },
60
- },
61
- })
62
- // later: handle.update({ colorScheme: "dark", widgets: nextWidgets }), handle.unmount()
24
+ const handle = mountAstralBeamChat(document.getElementById("sidebar"), {})
25
+ // handle.update({ colorScheme: "dark" }) — handle.unmount()
63
26
  ```
64
27
 
65
- The chat widget renders inside a shadow root on the mount target, so its styles never leak into (or absorb from) the host page. It streams the conversation from the `chatEndpoint` (an AstralBeam webapp's `/api/chat`), forwarding the optional `systemPrompt` for the endpoint to append to the agent's instructions. When `authEndpoint` is present, the widget obtains a short-lived bearer token before enabling its composer and renews it in memory as needed. The AstralBeam endpoint currently answers unauthenticated runs with `401`, so `authEndpoint` is required in practice. The `title` option names the assistant in the widget's header, and `showHeader: false` hides that header — title and reset button both — giving the transcript the widget's full height. Assistant replies are rendered as Markdown (headings, lists, tables, links, and fenced code) with [TanStack Markdown](https://tanstack.com/markdown), using its streaming profile so a partial reply stays stable as it arrives; raw HTML in a reply is escaped and executable link protocols are dropped. The `colorScheme` option picks the widget's color scheme — `"system"` (the default) follows the OS `prefers-color-scheme` setting live. The `theme` option overrides the widget's theming CSS variables — the [shadcn/ui tokens](https://ui.shadcn.com/docs/theming) such as `--background`, `--primary`, `--radius`, and the `--font-sans`/`--font-heading`/`--font-mono` font stacks — per color scheme: mirroring shadcn's `:root`/`.dark` split, `theme.light` is the base applied in both schemes and `theme.dark` overrides it when the resolved scheme is dark.
66
-
67
- ### Attachments
28
+ - The widget fills its container, so give it a parent with a definite height (`min-h-0` in a flex column).
29
+ - Two origins by design: chat streams to the hosted cloud by default, while the token comes from your own app's endpoint. Self-hosted deployments set `chatEndpoint` to their own origin.
30
+ - `@astralbeam/sdk/client` ships no React; the chat loads as a lazy chunk with its own bundled copy.
31
+ - `react` and `react-dom` are optional peer dependencies used only by `@astralbeam/sdk/react`.
32
+ - Mount it above your router if the transcript should survive page navigation.
68
33
 
69
- The composer takes files by default: through the paperclip button, by dropping them on the composer, or by pasting them (a pasted screenshot lands as an image). Each file appears as a chip above the input, removable before the message is sent and shown again with the message in the transcript, where clicking one downloads the file. Images and PDFs go to the model as-is; a text file (`.md`, `.csv`, `.json`, source files, ...) is read as text by the endpoint, which labels it with its filename. A file the widget cannot send keeps its chip and says why, and one the endpoint cannot use is explained to the agent in the conversation rather than failing the run — so the assistant can tell the user. Files are sent inline with the message, and stay in the conversation's context for the rest of the run.
34
+ ## Authentication
70
35
 
71
- Set `attachments: false` to hide the feature entirely, or pass an options object to narrow it:
36
+ The widget will not chat until your app mints it a short-lived token; it never sees your API key. See [Authentication](https://app.astralbeam.ai/docs/sdk/authentication).
72
37
 
73
- | Option | Default | Meaning |
74
- | --------------- | ------------------------------------------ | ---------------------------------------------------------------------------- |
75
- | `enabled` | `true` | `false` is the same as `attachments: false` |
76
- | `maxFiles` | `5` | Files per message |
77
- | `maxFileBytes` | per kind: 5 MB image, 10 MB PDF, 1 MB text | Ceiling for one file; the per-kind caps still apply, so the smaller one wins |
78
- | `maxTotalBytes` | 20 MB | Ceiling for all files on one message |
79
- | `accept` | everything supported | MIME types or `type/*` patterns, e.g. `["image/*"]` for images only |
38
+ ```ts
39
+ import { createAstralBeamTokenRoute } from "@astralbeam/sdk/server"
80
40
 
81
- The endpoint enforces the same size and type limits independently, so narrowing them in the widget is a UI affordance rather than a security boundary.
41
+ export const POST = createAstralBeamTokenRoute({
42
+ apiKey: () => process.env.ASTRALBEAM_API_KEY, // key_<organization>_<key>_abo_<secret>
43
+ tenantUser: async (request) => {
44
+ const session = await getApplicationSession(request)
45
+ return session && { id: session.user.id, name: session.user.name }
46
+ },
47
+ })
48
+ ```
82
49
 
83
- `handle.update(options)` replaces any subset of the mount options in place, keeping the transcript, the chat session, and live widget renders: rename the assistant, retheme it alongside the host app, revise the `systemPrompt`, retune or disable `attachments`, register or drop `tools` and `widgets`, or turn `debug` on mid-conversation. Newly declared tools and widgets reach the agent on its next run. `chatEndpoint` and `authEndpoint` are fixed at mount because they construct the transport. Dropping a widget disposes any render of it still in the transcript, which falls back to a summary marker.
50
+ - Add one endpoint, `/api/astralbeam/token` by default, that authenticates your own session first.
51
+ - The factory owns the method check, the unconfigured 503, the unauthenticated 401, and `no-store`.
52
+ - Derive `tenantUser` from trusted server-side state, never from anything the browser sent.
53
+ - Tokens are signed, not encrypted: never put a secret in them.
54
+ - Lifetimes are 60–600 seconds; the SDK renews in memory before expiry.
84
55
 
85
- With `debug: true` (also available as a prop on `<AstralBeamChat>`), every SDK action — mounting, theming, sends, streamed messages and reasoning, tool calls and their host-side executions, widget renders, questionnaire answers, errors — is logged to the browser console with UTC timestamps and full payloads, and the endpoint is asked to log its side of the same run to the server console, so a conversation can be followed end to end.
56
+ ## Options
86
57
 
87
- The agent acts on the host app through **tools** and **widgets**, both keyed by name and declared to the agent with a `description` and a `parameters` schema — either a plain JSON Schema object as above or any [Standard Schema](https://standardschema.dev) validator (Zod, Valibot, ArkType, ...), with no validator dependency required. A Standard Schema is also enforced client-side, validating the agent-chosen input before host code runs; with a plain JSON Schema, treat the input as untrusted. A tool's `execute` runs in the host page and its resolved value streams back to the agent as the tool result. Every tool call becomes one line in the transcript that expands to show the call's input and output as JSON; a tool's `metadata`, forwarded verbatim to the tool definition, labels that line with its `title` in place of the registry name. A widget's `render` draws host UI into the conversation: the SDK creates a light-DOM child of the mount target, calls `render(props, container)` on it, and projects it into the transcript through a named `<slot>`; `render` may return a cleanup function.
58
+ Every option is also a prop on `<AstralBeamChat>`; `handle.update(options)` applies any subset in place. `agentId`, `chatEndpoint`, and `authEndpoint` are fixed at mount. Details in [Configuration](https://app.astralbeam.ai/docs/sdk/configuration).
88
59
 
89
- Widget renders pick up the host page's typography and custom properties automatically. That needs help, because slotted content inherits through the [flattened tree](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_scoping), whose parent for a render is the `<slot>` inside the chat's shadow root — so a render would otherwise inherit the chat's own font and colors, and resolve `var(--card)` against the chat's token of that name instead of yours. The SDK writes one rule into the chat's shadow root giving every widget slot the page's computed value for each inherited CSS property, plus every custom property declared in the page's stylesheets, and re-reads it when a theme class changes on an ancestor. Your own selectors match a render normally and override the mirrored values, so styling a widget is ordinary CSS with no slot-specific rules. Two limits: properties are read from the mount target's parent, so rules targeting the mount target itself are not picked up, and tokens declared only in a cross-origin stylesheet cannot be read.
60
+ | Option | Default | Meaning |
61
+ | ------------------------------------ | ------------------------------------ | --------------------------------------------------------------- |
62
+ | `agentId` | organization's default | `agt_<organization>_<agent>` from the dashboard |
63
+ | `chatEndpoint` | `https://app.astralbeam.ai/api/chat` | The AstralBeam chat endpoint the widget streams from |
64
+ | `authEndpoint` | `/api/astralbeam/token` | Your token endpoint |
65
+ | `title`, `showHeader` | `"AstralBeam"`, `true` | Header text, and whether the header and reset button show |
66
+ | `emptyTitle`, `emptyDescription` | generic copy | Headline and subtitle of the empty transcript |
67
+ | `colorScheme`, `theme` | `"system"`, built-in palette | Light/dark/system, and shadcn token overrides |
68
+ | `attachments` | `true` | `false` hides the feature, or pass limits |
69
+ | `tools`, `widgets` | none | What the agent can do and draw in your app |
70
+ | `sandboxPanel` | `false` | Collected sandbox panel: files with downloads, command log |
71
+ | `header`, `empty`, `composerActions` | widget's own chrome | Host-rendered replacements (React props; `slots` on the handle) |
72
+ | `debug` | `false` | Log every SDK action in the browser and on the server |
90
73
 
91
- ### Authentication
74
+ A `ref` on `<AstralBeamChat>` (and the vanilla handle) exposes `reset()` and `stop()` for hosts that draw their own controls.
92
75
 
93
- Supply `authEndpoint`; the AstralBeam endpoint serves signed-in users only for now and rejects a run with no token, so a widget without it can stream nothing. The host endpoint must authenticate the application's existing session, load the active user and tenant from trusted server-side state, and return `{ "token": "..." }`. The SDK calls it with `POST`, `credentials: "include"`, and `cache: "no-store"`, keeps the token only in memory, refreshes it within one minute of expiry, and retries one rejected chat request with a fresh token. A configured endpoint fails closed: its loading or error state disables the composer instead of falling back to guest chat.
76
+ ## Tools and widgets
94
77
 
95
- Use the server entry to mint the token without exposing the signing secret to browser code:
78
+ A tool does something: its `execute` runs in your page. A widget shows something: its `render` draws your UI into the conversation. Both are declared with a `description` and a `parameters` schema. See [Tools and widgets](https://app.astralbeam.ai/docs/sdk/tools-and-widgets).
96
79
 
97
- ```ts
98
- import { createAstralBeamChatToken } from "@astralbeam/sdk/server"
99
-
100
- export async function POST(request: Request) {
101
- const session = await requireApplicationSession(request)
102
- const token = await createAstralBeamChatToken({
103
- secret: process.env.ASTRALBEAM_CHAT_AUTH_SECRET!,
104
- user: {
105
- id: session.user.id,
106
- name: session.user.name,
107
- email: session.user.email,
108
- avatarUrl: session.user.avatarUrl,
109
- },
110
- tenant: {
111
- id: session.tenant.id,
112
- name: session.tenant.name,
113
- logoUrl: session.tenant.logoUrl,
114
- },
115
- })
116
- return Response.json({ token }, { headers: { "cache-control": "no-store" } })
80
+ ```tsx
81
+ tools: {
82
+ restart_service: {
83
+ metadata: { title: "Restart a service" },
84
+ description: "Restart one of the host app's services by name",
85
+ parameters: { type: "object", properties: { service: { type: "string" } }, required: ["service"] },
86
+ execute: async ({ service }) => await restartService(String(service)),
87
+ },
88
+ },
89
+ widgets: {
90
+ systemStatus: {
91
+ description: "Shows the current status of the host app's systems",
92
+ parameters: { type: "object", properties: { degraded: { type: "boolean" } } },
93
+ render: ({ degraded }) => <StatusCard degraded={Boolean(degraded)} />,
94
+ },
117
95
  }
118
96
  ```
119
97
 
120
- The default lifetime is five minutes and the helper rejects lifetimes above ten minutes, weak secrets, missing IDs, and invalid profile URLs. User and tenant IDs are required; names, email, avatar, and logo are optional display metadata. Tokens use the temporary global issuer and key ID while AstralBeam has no application accounts. Because every integrator temporarily shares the verifier secret, these tokens must not authorize persisted tenant data, billing, or server-side actions until per-application keys are introduced.
121
-
122
- ### React
123
-
124
- `@astralbeam/sdk/react` wraps the vanilla client in an `<AstralBeamChat>` component. It requires the `react` and `react-dom` peer dependencies (already present in any React app):
125
-
126
- ```sh
127
- npm install @astralbeam/sdk react react-dom
128
- ```
129
-
130
- Render `<AstralBeamChat>` wherever the chat sidebar should appear; it fills its container's height, mounts the chat widget on mount, and unmounts it on cleanup. The `title`, `showHeader`, `chatEndpoint`, `authEndpoint`, `systemPrompt`, and `tools` props work like the vanilla options (tool `execute` calls always reach the latest prop value, so they can close over current component state). The `colorScheme` prop (`"light" | "dark" | "system"`, default `"system"`) picks the color scheme, the `theme` prop overrides the widget's theming CSS variables per scheme, and the `attachments` prop configures or disables composer attachments — all like the vanilla options. Every prop except the fixed `chatEndpoint` and `authEndpoint` applies immediately on change — the wrapper forwards them to `handle.update` from an effect. Register widgets through the `widgets` prop — the same tool-definition shape as the vanilla client, except `render` returns JSX instead of drawing into a container. The agent reads each `description` and `parameters` to decide when to render a widget and with which props. Rendered widgets live in your app's React tree and are projected into the chat through slots, so state, context, and event handlers keep working:
98
+ - Schemas are plain JSON Schema, or any [Standard Schema](https://standardschema.dev) validator (Zod, Valibot, ArkType).
99
+ - Only a Standard Schema validates input in the browser; with plain JSON Schema, treat input as untrusted.
100
+ - `defineTool` and `defineWidget` type `execute`/`render` input from a Standard Schema's output.
101
+ - In React, `render` returns JSX in your own tree, so state, context, and handlers keep working.
102
+ - New tools and widgets reach the agent on its next run.
131
103
 
132
- ```tsx
133
- import { AstralBeamChat } from "@astralbeam/sdk/react"
104
+ ## Documentation
134
105
 
135
- export function Sidebar() {
136
- return (
137
- <AstralBeamChat
138
- widgets={{
139
- systemStatus: {
140
- description: "Shows the current status of the host app's systems",
141
- parameters: {
142
- type: "object",
143
- properties: { degraded: { type: "boolean" } },
144
- },
145
- render: ({ degraded }) => <StatusCard degraded={Boolean(degraded)} />,
146
- },
147
- }}
148
- />
149
- )
150
- }
151
- ```
106
+ Each guide is short and self-contained.
152
107
 
153
- The chat widget itself loads as a separate lazy chunk with its own bundled React copy and renders in a shadow root, so it neither depends on nor conflicts with your app's React version or styles. Only the thin `<AstralBeamChat>` wrapper and your widget `render` functions run on your app's React.
108
+ - [Getting started](https://app.astralbeam.ai/docs/sdk/getting-started) install, mount, layout requirements.
109
+ - [Authentication](https://app.astralbeam.ai/docs/sdk/authentication) — the token endpoint and its security rules.
110
+ - [Configuration](https://app.astralbeam.ai/docs/sdk/configuration) — every option, and what `update` can change.
111
+ - [Theming](https://app.astralbeam.ai/docs/sdk/theming) — color schemes, CSS tokens, the shadow-root boundary.
112
+ - [Tools and widgets](https://app.astralbeam.ai/docs/sdk/tools-and-widgets) — schemas, live state, rendering into the transcript.
113
+ - [Attachments](https://app.astralbeam.ai/docs/sdk/attachments) — file kinds, limits, what the endpoint enforces.
114
+ - [Sandbox](https://app.astralbeam.ai/docs/sdk/sandbox) — steps, the opt-in panel, downloads, inline images.
115
+ - [Headless](https://app.astralbeam.ai/docs/sdk/headless) — own the whole chat UI on the same session.
116
+ - [Security model](https://app.astralbeam.ai/docs/sdk/security) — who grants, who enforces, what the client can change.
154
117
 
155
118
  ## Entry points
156
119
 
157
- - `@astralbeam/sdk/client` framework-agnostic browser client
158
- - `@astralbeam/sdk/server` — server-side token helpers
159
- - `@astralbeam/sdk/react` — React components (e.g. `<AstralBeamChat />`), requires the `react` and `react-dom` peer dependencies
160
- - `@astralbeam/sdk/vue` — Vue components, requires the `vue` peer dependency (placeholder)
161
-
162
- ## Examples
120
+ There is no root export. Conversation history is not built yet.
163
121
 
164
- [`examples/todos`](../examples/todos) is a minimal TanStack Start todos app that embeds the chat sidebar from the built package, authenticates a fixed demo identity through a server route, points the chat at a locally running webapp's `/api/chat`, and registers a todo-specific system prompt, `get_todos`/`create_todo`/`update_todo`/`delete_todo` tools, and a `todoCard` widget the agent renders into the conversation once per todo it shows — with no Tailwind or shadcn/ui of its own, to demonstrate the shadow-root style boundary.
122
+ | Entry point | Contents | Peer dependency |
123
+ | ------------------------ | --------------------------------------------------------- | -------------------- |
124
+ | `@astralbeam/sdk/client` | `mountAstralBeamChat`, the vanilla loader | none |
125
+ | `@astralbeam/sdk/core` | `createAstralBeamChat`, the headless session | none |
126
+ | `@astralbeam/sdk/react` | `<AstralBeamChat>`, `useAstralBeamChat` | `react`, `react-dom` |
127
+ | `@astralbeam/sdk/server` | `createAstralBeamChatToken`, `createAstralBeamTokenRoute` | none |
128
+ | `@astralbeam/sdk/vue` | Vue components (placeholder) | `vue` |
165
129
 
166
- ## Architecture
130
+ ## Example
167
131
 
168
- [ARCHITECTURE.md](./ARCHITECTURE.md) explains how the SDK is put together: the entry-point layout, the embedded-React chat widget, the shadow-root and slot boundary between chat and host, and the two-pass build.
132
+ [`examples/todos`](../examples/todos) embeds the sidebar in a minimal TanStack Start app: a demo token route, host tools over live React state, and a `todoCard` widget. It uses no Tailwind or shadcn/ui of its own, to show the shadow-root boundary.
169
133
 
170
134
  ## License
171
135
 
package/dist/client.d.ts CHANGED
@@ -1,11 +1,20 @@
1
- //#region src/lib/client-types.d.ts
2
- interface StandardSchemaV1 {
1
+ //#region src/lib/types.d.ts
2
+ interface StandardSchemaV1<Input = unknown, Output = Input> {
3
3
  readonly "~standard": {
4
4
  readonly version: 1;
5
5
  readonly vendor: string;
6
- readonly validate: (value: unknown) => unknown;
6
+ readonly validate: (value: unknown) => unknown; /** Type-level only; the spec keeps it undefined at runtime. */
7
+ readonly types?: {
8
+ readonly input: Input;
9
+ readonly output: Output;
10
+ } | undefined;
7
11
  };
8
12
  }
13
+ /**
14
+ * Input type `defineTool`/`defineWidget` derive from a `parameters` schema: a Standard Schema's
15
+ * validated output, or untyped props for a plain JSON Schema, which nothing validates in the browser.
16
+ */
17
+ type InferParameters<S extends ParametersSchema> = S extends StandardSchemaV1<any, infer O> ? O : Record<string, unknown>;
9
18
  /** A plain JSON Schema object, the same shape tool definitions use for their parameters. */
10
19
  interface JsonSchemaObject {
11
20
  type: "object";
@@ -71,6 +80,20 @@ interface AstralBeamChatAttachmentOptions {
71
80
  */
72
81
  accept?: readonly string[] | undefined;
73
82
  }
83
+ /**
84
+ * Draws host content into `container`, a light-DOM element the widget projects into the
85
+ * named area. May return a cleanup, called when the slot is replaced and on unmount.
86
+ */
87
+ type AstralBeamChatSlotRenderer = (container: HTMLElement) => (() => void) | void;
88
+ /** Host-rendered replacements for the widget's own chrome; each renders in the host page's style. */
89
+ interface AstralBeamChatSlots {
90
+ /** Replaces the header's content (title and reset button); `showHeader: false` still hides the row. */
91
+ header?: AstralBeamChatSlotRenderer | undefined;
92
+ /** Replaces the empty-transcript state (icon, headline, and subtitle). */
93
+ empty?: AstralBeamChatSlotRenderer | undefined;
94
+ /** Extra controls at the end of the composer's button row, next to send. */
95
+ composerActions?: AstralBeamChatSlotRenderer | undefined;
96
+ }
74
97
  /** Color scheme of the chat widget; `"system"` follows the OS `prefers-color-scheme` setting. */
75
98
  type AstralBeamChatColorScheme = "light" | "dark" | "system";
76
99
  /** Overrides for the widget's theming CSS variables, keyed by custom-property name (`"--primary"`). */
@@ -86,6 +109,11 @@ interface AstralBeamChatTheme {
86
109
  dark?: AstralBeamChatThemeVariables | undefined;
87
110
  }
88
111
  interface MountAstralBeamChatOptions {
112
+ /**
113
+ * Public ID of the organization-owned agent, fixed for this mounted chat. Omit it to use the
114
+ * organization's default agent, which the dashboard's agents page selects.
115
+ */
116
+ agentId?: string | undefined;
89
117
  /** Name shown in the widget's header. Default `"AstralBeam"`. */
90
118
  title?: string | undefined;
91
119
  /**
@@ -93,16 +121,30 @@ interface MountAstralBeamChatOptions {
93
121
  * and gives the transcript the full height. Default `true`.
94
122
  */
95
123
  showHeader?: boolean | undefined;
96
- /** URL of the AstralBeam chat endpoint the widget streams from. Fixed at mount. Default `"/api/chat"`. */
124
+ /** Headline shown on the empty transcript. Default `"Ask the assistant"`. */
125
+ emptyTitle?: string | undefined;
126
+ /** Subtitle shown under the empty transcript's headline. Default describes the app's tools and widgets. */
127
+ emptyDescription?: string | undefined;
128
+ /**
129
+ * URL of the AstralBeam chat endpoint the widget streams from. Fixed at mount. Default
130
+ * `"https://app.astralbeam.ai/api/chat"`, the hosted cloud; self-hosted deployments must set
131
+ * their own origin.
132
+ */
97
133
  chatEndpoint?: string | undefined;
98
- /** Application endpoint that mints a short-lived chat JWT. Fixed at mount; omit for guest chat. */
134
+ /** Application endpoint that mints a short-lived chat JWT. Fixed at mount. Default `"/api/astralbeam/token"`. */
99
135
  authEndpoint?: string | undefined;
100
- /** Host-specific instructions the endpoint appends to the agent's system prompt. */
101
- systemPrompt?: string | undefined;
102
136
  /** Host-defined tools the agent can call, executed in the host page, keyed by tool name. */
103
137
  tools?: Record<string, ToolDefinition> | undefined;
104
138
  /** Host-defined widgets the agent can render inline in the conversation, keyed by identifier. */
105
139
  widgets?: Record<string, WidgetDefinition>;
140
+ /** Host-rendered replacements for parts of the widget's chrome; see `AstralBeamChatSlots`. */
141
+ slots?: AstralBeamChatSlots | undefined;
142
+ /**
143
+ * Shows the collected sandbox panel (every file the agent wrote, with downloads, and the full
144
+ * command log) above the composer once the sandbox has done work. Off by default: the
145
+ * transcript already shows each step where it happened. Default `false`.
146
+ */
147
+ sandboxPanel?: boolean | undefined;
106
148
  /**
107
149
  * File attachments in the composer, on by default. `false` turns them off; an options object
108
150
  * narrows the limits and accepted types.
@@ -119,11 +161,10 @@ interface MountAstralBeamChatOptions {
119
161
  debug?: boolean | undefined;
120
162
  }
121
163
  /**
122
- * Mount options the handle can change afterwards. `chatEndpoint` is excluded on purpose: the
123
- * streaming connection is constructed once, so a new endpoint would mean a new client and a
124
- * discarded transcript.
164
+ * Mount options the handle can change afterwards. The agent and transport endpoints are fixed:
165
+ * changing any of them would mean a new client and a discarded transcript.
125
166
  */
126
- type AstralBeamChatUpdate = Partial<Omit<MountAstralBeamChatOptions, "chatEndpoint" | "authEndpoint">>;
167
+ type AstralBeamChatUpdate = Partial<Omit<MountAstralBeamChatOptions, "agentId" | "chatEndpoint" | "authEndpoint">>;
127
168
  interface AstralBeamChatHandle {
128
169
  unmount: () => void;
129
170
  /**
@@ -131,9 +172,30 @@ interface AstralBeamChatHandle {
131
172
  * transcript, the chat session, and live widget renders. Only the keys given are replaced.
132
173
  */
133
174
  update: (options: AstralBeamChatUpdate) => void;
175
+ /** Clears the conversation: transcript, drafts, attachments, and live widget renders. */
176
+ reset: () => void;
177
+ /** Stops the in-flight generation, if any; the transcript keeps what already streamed. */
178
+ stop: () => void;
179
+ }
180
+ //#endregion
181
+ //#region src/lib/define.d.ts
182
+ interface TypedToolDefinition<S extends ParametersSchema = JsonSchemaObject> {
183
+ description: string;
184
+ metadata?: Record<string, unknown> | undefined;
185
+ parameters?: S;
186
+ execute: (input: InferParameters<S>) => unknown | Promise<unknown>;
187
+ }
188
+ interface TypedWidgetDefinition<S extends ParametersSchema = JsonSchemaObject> {
189
+ description: string;
190
+ parameters?: S;
191
+ render: (props: InferParameters<S>, container: HTMLElement) => (() => void) | void;
134
192
  }
193
+ /** Declares a host tool; a Standard Schema `parameters` types (and validates) `execute`'s input. */
194
+ declare function defineTool<const S extends ParametersSchema = JsonSchemaObject>(tool: TypedToolDefinition<S>): ToolDefinition;
195
+ /** Declares a host widget; a Standard Schema `parameters` types (and validates) `render`'s props. */
196
+ declare function defineWidget<const S extends ParametersSchema = JsonSchemaObject>(widget: TypedWidgetDefinition<S>): WidgetDefinition;
135
197
  //#endregion
136
- //#region src/client.d.ts
137
- declare function mountAstralBeamChat(target: HTMLElement, options?: MountAstralBeamChatOptions): AstralBeamChatHandle;
198
+ //#region src/client/index.d.ts
199
+ declare function mountAstralBeamChat(target: HTMLElement, options: MountAstralBeamChatOptions): AstralBeamChatHandle;
138
200
  //#endregion
139
- export { type AstralBeamChatAttachmentOptions, type AstralBeamChatColorScheme, type AstralBeamChatHandle, type AstralBeamChatTheme, type AstralBeamChatThemeVariables, type AstralBeamChatUpdate, type JsonSchemaObject, type MountAstralBeamChatOptions, type ParametersSchema, type StandardSchemaV1, type ToolDefinition, type WidgetDefinition, mountAstralBeamChat };
201
+ export { type AstralBeamChatAttachmentOptions, type AstralBeamChatColorScheme, type AstralBeamChatHandle, type AstralBeamChatSlotRenderer, type AstralBeamChatSlots, type AstralBeamChatTheme, type AstralBeamChatThemeVariables, type AstralBeamChatUpdate, type InferParameters, type JsonSchemaObject, type MountAstralBeamChatOptions, type ParametersSchema, type StandardSchemaV1, type ToolDefinition, type TypedToolDefinition, type TypedWidgetDefinition, type WidgetDefinition, defineTool, defineWidget, mountAstralBeamChat };
package/dist/client.js CHANGED
@@ -1 +1 @@
1
- import{a as e,t}from"./client-utils-DyEcBInP.js";function n(n,r={}){let i={...r},a=t(i.debug);a?.(`mount`,`mounting chat widget`,{title:i.title??`AstralBeam`,showHeader:i.showHeader??!0,chatEndpoint:i.chatEndpoint??`/api/chat`,authentication:i.authEndpoint?`configured`:`guest`,colorScheme:i.colorScheme??`system`,theme:i.theme,systemPrompt:i.systemPrompt,tools:Object.keys(i.tools??{}),widgets:Object.keys(i.widgets??{}),attachments:i.attachments??!0});let o=n.shadowRoot??n.attachShadow({mode:`open`}),s=document.createElement(`div`);s.className=e,s.style.height=`100%`,o.append(s);let c=matchMedia(`(prefers-color-scheme: dark)`),l=new Set,u=e=>{for(let e of l)s.style.removeProperty(e);l.clear();let t={...i.theme?.light,...e?i.theme?.dark:void 0};for(let[e,n]of Object.entries(t))e.startsWith(`--`)&&(s.style.setProperty(e,n),l.add(e))},d=()=>{let e=i.colorScheme??`system`,t=e===`dark`||e===`system`&&c.matches;s.classList.toggle(`dark`,t),u(t),a?.(`theme`,`color scheme "${e}" resolved to ${t?`dark`:`light`}`,{themeVariables:[...l]})};d(),c.addEventListener(`change`,d);let f=!1,p;return import(`./chat-BlacYOz8.js`).then(({renderChat:e})=>{a?.(`mount`,`chat chunk loaded`),f||(p=e(o,s,i))}),{update:e=>{i={...i,...e},a=t(i.debug),a?.(`mount`,`options updated`,{changed:Object.keys(e)}),d(),p?.update(i)},unmount:()=>{a?.(`mount`,`unmounting chat widget`),f=!0,c.removeEventListener(`change`,d),p?.dispose(),p=void 0,s.remove()}}}export{n as mountAstralBeamChat};
1
+ import{c as e,t}from"./debug-DBysy3en.js";function n(e){return e}function r(e){return e}function i(n,r){let i={...r},a=t(i.debug);a?.(`mount`,`mounting chat widget`,{agentId:i.agentId??`(organization default)`,title:i.title??`AstralBeam`,showHeader:i.showHeader??!0,emptyTitle:i.emptyTitle??`Ask the assistant`,emptyDescription:i.emptyDescription??`It can answer questions and act through this app's own tools and widgets.`,chatEndpoint:i.chatEndpoint??`https://app.astralbeam.ai/api/chat`,authentication:`configured`,colorScheme:i.colorScheme??`system`,theme:i.theme,tools:Object.keys(i.tools??{}),widgets:Object.keys(i.widgets??{}),attachments:i.attachments??!0});let o=n.shadowRoot??n.attachShadow({mode:`open`}),s=document.createElement(`div`);s.className=e,s.style.height=`100%`,o.append(s);let c=matchMedia(`(prefers-color-scheme: dark)`),l=new Set,u=e=>{for(let e of l)s.style.removeProperty(e);l.clear();let t={...i.theme?.light,...e?i.theme?.dark:void 0};for(let[e,n]of Object.entries(t))e.startsWith(`--`)&&(s.style.setProperty(e,n),l.add(e))},d=()=>{let e=i.colorScheme??`system`,t=e===`dark`||e===`system`&&c.matches;s.classList.toggle(`dark`,t),u(t),a?.(`theme`,`color scheme "${e}" resolved to ${t?`dark`:`light`}`,{themeVariables:[...l]})};d(),c.addEventListener(`change`,d);let f=!1,p;return import(`./widget-C7XKsfTv.js`).then(({renderChat:e})=>{a?.(`mount`,`chat chunk loaded`),f||(p=e(o,s,i))}),{update:e=>{if(Object.hasOwn(e,`agentId`)||Object.hasOwn(e,`chatEndpoint`)||Object.hasOwn(e,`authEndpoint`))throw Error(`agentId, chatEndpoint, and authEndpoint are fixed at mount`);i={...i,...e},a=t(i.debug),a?.(`mount`,`options updated`,{changed:Object.keys(e)}),d(),p?.update(i)},reset:()=>p?.reset(),stop:()=>p?.stop(),unmount:()=>{a?.(`mount`,`unmounting chat widget`),f=!0,c.removeEventListener(`change`,d),p?.dispose(),p=void 0,s.remove()}}}export{n as defineTool,r as defineWidget,i as mountAstralBeamChat};