@astralbeam/sdk 0.5.0 → 0.7.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 +35 -29
- package/dist/client.d.ts +14 -9
- package/dist/client.js +1 -1
- package/dist/{core-BZxnUlwg.js → core-BF1G1dLe.js} +99 -47
- package/dist/core.d.ts +2 -2
- package/dist/core.js +2 -2
- package/dist/{index-8NUgB59m.d.ts → index-CudekMKM.d.ts} +148 -25
- package/dist/react.d.ts +11 -50
- package/dist/react.js +8 -15
- package/dist/server.d.ts +28 -43
- package/dist/server.js +53 -84
- package/dist/widget-PZ-6BF36.js +79 -0
- package/package.json +4 -18
- package/dist/vue.d.ts +0 -4
- package/dist/vue.js +0 -4
- package/dist/widget-DiGFLZyX.js +0 -79
package/README.md
CHANGED
|
@@ -28,34 +28,41 @@ const handle = mountAstralBeamChat(document.getElementById("sidebar"), {})
|
|
|
28
28
|
- The widget fills its container, so give it a parent with a definite height (`min-h-0` in a flex column).
|
|
29
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 `apiUrl` to their own origin.
|
|
30
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
|
|
31
|
+
- No runtime dependencies; `react` and `react-dom` are optional peers used only by `@astralbeam/sdk/react`.
|
|
32
32
|
- Mount it above your router if the transcript should survive page navigation.
|
|
33
33
|
|
|
34
34
|
## Authentication
|
|
35
35
|
|
|
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).
|
|
36
|
+
The widget will not chat until your app mints it a short-lived chat auth token; it never sees your API key. That token is the credential your server signs for AstralBeam, never your app's own session cookie or access token. See [Authentication](https://app.astralbeam.ai/docs/sdk/authentication).
|
|
37
37
|
|
|
38
38
|
```ts
|
|
39
|
-
import {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
39
|
+
import { createChatAuthToken } from "@astralbeam/sdk/server"
|
|
40
|
+
|
|
41
|
+
const apiKey = process.env.ASTRALBEAM_API_KEY // key_<organization>_<key>_abo_<secret>
|
|
42
|
+
|
|
43
|
+
export async function POST(request: Request) {
|
|
44
|
+
if (!apiKey) return Response.json({ error: "Not configured" }, { status: 503 })
|
|
45
|
+
const session = await getApplicationSession(request)
|
|
46
|
+
if (!session) return Response.json({ error: "Unauthenticated" }, { status: 401 })
|
|
47
|
+
const token = await createChatAuthToken({
|
|
48
|
+
apiKey,
|
|
49
|
+
user: {
|
|
50
|
+
id: session.user.id,
|
|
51
|
+
name: session.user.name,
|
|
52
|
+
metadata: { email: session.user.email },
|
|
53
|
+
},
|
|
54
|
+
tenant: {
|
|
55
|
+
id: session.tenant.id,
|
|
56
|
+
name: session.tenant.name,
|
|
57
|
+
metadata: { plan: session.tenant.plan },
|
|
58
|
+
},
|
|
59
|
+
})
|
|
60
|
+
return Response.json({ token }, { headers: { "cache-control": "no-store" } })
|
|
61
|
+
}
|
|
55
62
|
```
|
|
56
63
|
|
|
57
64
|
- Add one endpoint, `/api/astralbeam/token` by default, that authenticates your own session first.
|
|
58
|
-
-
|
|
65
|
+
- Your handler owns the response: answer `cache-control: no-store`, and fail closed with a 401 or 503.
|
|
59
66
|
- Authenticate once, then derive `user` and `tenant` separately from that same application session.
|
|
60
67
|
- Derive `user` and `tenant` from trusted server-side state, never from anything the browser sent.
|
|
61
68
|
- Provide stable tenant-local `user.id` and stable `tenant.id` values; names are optional, and set `user.admin` only from trusted state.
|
|
@@ -64,7 +71,7 @@ export const POST = createAstralBeamTokenRoute({
|
|
|
64
71
|
- Tokens use the API key's organization slug as issuer and the platform audience `astralbeam`; AstralBeam does not require or interpret `sub`.
|
|
65
72
|
- Tokens are signed, not encrypted: never put a secret in them.
|
|
66
73
|
- Lifetimes are 60–600 seconds; the SDK renews in memory before expiry.
|
|
67
|
-
- `
|
|
74
|
+
- `fetchChatAuthToken` says where the chat auth token comes from: `{ url, ...init }`, which the widget calls as `fetch(url, init)` with a standard `RequestInit`, or a function returning `{ token }` (or a promise of it, or `undefined` when it cannot mint one).
|
|
68
75
|
- It defaults to `{ url: "/api/astralbeam/token" }`, posted with the page's cookies, and runs again on every renewal, so a rotating credential stays current.
|
|
69
76
|
|
|
70
77
|
## Options
|
|
@@ -73,9 +80,9 @@ Every option is also a prop on `<AstralBeamChat>`; `handle.update(options)` appl
|
|
|
73
80
|
|
|
74
81
|
| Option | Default | Meaning |
|
|
75
82
|
| ------------------------------------ | ---------------------------------- | ------------------------------------------------------------------ |
|
|
76
|
-
| `agentId` | organization's default | `
|
|
83
|
+
| `agentId` | organization's default | `agent_<uuid>`, copied from the dashboard |
|
|
77
84
|
| `apiUrl` | `https://app.astralbeam.ai/api` | Base URL of the AstralBeam API; the widget calls `/chat` there |
|
|
78
|
-
| `
|
|
85
|
+
| `fetchChatAuthToken` | `{ url: "/api/astralbeam/token" }` | Chat auth token endpoint as `{ url, ...RequestInit }`, or a minter |
|
|
79
86
|
| `title`, `showHeader` | `"AstralBeam"`, `true` | Header text, and whether the header and reset button show |
|
|
80
87
|
| `emptyTitle`, `emptyDescription` | generic copy | Headline and subtitle of the empty transcript |
|
|
81
88
|
| `colorScheme`, `theme` | `"system"`, built-in palette | Light/dark/system, and shadcn token overrides |
|
|
@@ -133,13 +140,12 @@ Each guide is short and self-contained.
|
|
|
133
140
|
|
|
134
141
|
There is no root export. Conversation history is not built yet.
|
|
135
142
|
|
|
136
|
-
| Entry point | Contents
|
|
137
|
-
| ------------------------ |
|
|
138
|
-
| `@astralbeam/sdk/client` | `mountAstralBeamChat`, the vanilla loader
|
|
139
|
-
| `@astralbeam/sdk/core` | `createAstralBeamChat`, the headless session
|
|
140
|
-
| `@astralbeam/sdk/react` | `<AstralBeamChat>`, `useAstralBeamChat`
|
|
141
|
-
| `@astralbeam/sdk/server` | `
|
|
142
|
-
| `@astralbeam/sdk/vue` | Vue components (placeholder) | `vue` |
|
|
143
|
+
| Entry point | Contents | Peer dependency |
|
|
144
|
+
| ------------------------ | -------------------------------------------- | -------------------- |
|
|
145
|
+
| `@astralbeam/sdk/client` | `mountAstralBeamChat`, the vanilla loader | none |
|
|
146
|
+
| `@astralbeam/sdk/core` | `createAstralBeamChat`, the headless session | none |
|
|
147
|
+
| `@astralbeam/sdk/react` | `<AstralBeamChat>`, `useAstralBeamChat` | `react`, `react-dom` |
|
|
148
|
+
| `@astralbeam/sdk/server` | `createChatAuthToken`, the token minter | none |
|
|
143
149
|
|
|
144
150
|
Types resolve under every TypeScript module resolution mode, including the classic `"moduleResolution": "node"` that Ionic, Capacitor, and Create React App templates still ship. TypeScript 5.0 or later is required, because the declarations use `const` type parameters; on TypeScript 4.x the `.d.ts` files fail to parse.
|
|
145
151
|
|
package/dist/client.d.ts
CHANGED
|
@@ -108,14 +108,14 @@ interface AstralBeamChatAuthTokenRequest extends RequestInit {
|
|
|
108
108
|
url: string;
|
|
109
109
|
}
|
|
110
110
|
/**
|
|
111
|
-
* Where the widget's short-lived chat
|
|
111
|
+
* Where the widget's short-lived chat auth token comes from: an endpoint to POST, or a function that
|
|
112
112
|
* mints the token in the host page and returns `{ token }`, optionally as a promise.
|
|
113
113
|
*
|
|
114
114
|
* Either form runs again on every renewal — near expiry and after a token is rejected — so a
|
|
115
115
|
* rotating credential stays current rather than being captured once. A function that returns
|
|
116
116
|
* `undefined`, or throws, fails authentication closed; the composer's retry link asks again.
|
|
117
117
|
*/
|
|
118
|
-
type
|
|
118
|
+
type AstralBeamChatAuthTokenSource = AstralBeamChatAuthTokenRequest | (() => {
|
|
119
119
|
token: string;
|
|
120
120
|
} | undefined | Promise<{
|
|
121
121
|
token: string;
|
|
@@ -130,6 +130,11 @@ interface AstralBeamChatTheme {
|
|
|
130
130
|
light?: AstralBeamChatThemeVariables | undefined;
|
|
131
131
|
dark?: AstralBeamChatThemeVariables | undefined;
|
|
132
132
|
}
|
|
133
|
+
/**
|
|
134
|
+
* Every option of the drop-in chat widget, and the one documented source the React props and the
|
|
135
|
+
* headless core options are derived from. Each is optional and accepts an explicit `undefined`, so
|
|
136
|
+
* a host with `exactOptionalPropertyTypes` can pass a value it does not have yet.
|
|
137
|
+
*/
|
|
133
138
|
interface MountAstralBeamChatOptions {
|
|
134
139
|
/**
|
|
135
140
|
* Public ID of the organization-owned agent. Omit it to use the organization's default agent,
|
|
@@ -155,16 +160,16 @@ interface MountAstralBeamChatOptions {
|
|
|
155
160
|
*/
|
|
156
161
|
apiUrl?: string | undefined;
|
|
157
162
|
/**
|
|
158
|
-
* Where the short-lived chat
|
|
159
|
-
* a function that mints `{ token }` in the host page. Read for every token, so a
|
|
160
|
-
* to the next one, which is minted when the cached token nears expiry. Default
|
|
163
|
+
* Where the short-lived chat auth token comes from: `{ url, ...RequestInit }` for a token
|
|
164
|
+
* endpoint, or a function that mints `{ token }` in the host page. Read for every token, so a
|
|
165
|
+
* change applies to the next one, which is minted when the cached token nears expiry. Default
|
|
161
166
|
* `{ url: "/api/astralbeam/token" }`, posted with the page's cookies.
|
|
162
167
|
*/
|
|
163
|
-
|
|
168
|
+
fetchChatAuthToken?: AstralBeamChatAuthTokenSource | undefined;
|
|
164
169
|
/** Host-defined tools the agent can call, executed in the host page, keyed by tool name. */
|
|
165
170
|
tools?: Record<string, ToolDefinition> | undefined;
|
|
166
171
|
/** Host-defined widgets the agent can render inline in the conversation, keyed by identifier. */
|
|
167
|
-
widgets?: Record<string, WidgetDefinition
|
|
172
|
+
widgets?: Record<string, WidgetDefinition> | undefined;
|
|
168
173
|
/** Host-rendered replacements for parts of the widget's chrome; see `AstralBeamChatSlots`. */
|
|
169
174
|
slots?: AstralBeamChatSlots | undefined;
|
|
170
175
|
/**
|
|
@@ -179,7 +184,7 @@ interface MountAstralBeamChatOptions {
|
|
|
179
184
|
*/
|
|
180
185
|
attachments?: boolean | AstralBeamChatAttachmentOptions | undefined;
|
|
181
186
|
/** Color scheme of the widget. Default `"system"`. */
|
|
182
|
-
colorScheme?: AstralBeamChatColorScheme;
|
|
187
|
+
colorScheme?: AstralBeamChatColorScheme | undefined;
|
|
183
188
|
/** Custom values for the widget's theming CSS variables, per color scheme. */
|
|
184
189
|
theme?: AstralBeamChatTheme | undefined;
|
|
185
190
|
/**
|
|
@@ -227,4 +232,4 @@ declare function defineWidget<const S extends ParametersSchema = JsonSchemaObjec
|
|
|
227
232
|
//#region src/client/index.d.ts
|
|
228
233
|
declare function mountAstralBeamChat(target: HTMLElement, options: MountAstralBeamChatOptions): AstralBeamChatHandle;
|
|
229
234
|
//#endregion
|
|
230
|
-
export { type AstralBeamChatAttachmentOptions, type AstralBeamChatAuthTokenRequest, type
|
|
235
|
+
export { type AstralBeamChatAttachmentOptions, type AstralBeamChatAuthTokenRequest, type AstralBeamChatAuthTokenSource, 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{c as e,t}from"./debug-DyjRg3e0.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.`,apiUrl:i.apiUrl??`https://app.astralbeam.ai/api`,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-
|
|
1
|
+
import{c as e,t}from"./debug-DyjRg3e0.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.`,apiUrl:i.apiUrl??`https://app.astralbeam.ai/api`,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-PZ-6BF36.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)},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};
|
|
@@ -7842,29 +7842,29 @@ function buildHostTools(tools, debug) {
|
|
|
7842
7842
|
const REFRESH_SKEW_MS = 6e4;
|
|
7843
7843
|
const MAX_TOKEN_LENGTH = 16384;
|
|
7844
7844
|
function tokenExpiry(token) {
|
|
7845
|
-
if (token.length > MAX_TOKEN_LENGTH) throw new Error("The
|
|
7845
|
+
if (token.length > MAX_TOKEN_LENGTH) throw new Error("The chat auth token is too large");
|
|
7846
7846
|
const parts = token.split(".");
|
|
7847
|
-
if (parts.length !== 3 || !parts[1]) throw new Error("The
|
|
7847
|
+
if (parts.length !== 3 || !parts[1]) throw new Error("The chat auth token is not a JWT");
|
|
7848
7848
|
const encoded = parts[1].replaceAll("-", "+").replaceAll("_", "/");
|
|
7849
7849
|
const padded = encoded.padEnd(Math.ceil(encoded.length / 4) * 4, "=");
|
|
7850
7850
|
let payload;
|
|
7851
7851
|
try {
|
|
7852
7852
|
payload = JSON.parse(atob(padded));
|
|
7853
7853
|
} catch {
|
|
7854
|
-
throw new Error("The
|
|
7854
|
+
throw new Error("The chat auth token has an invalid payload");
|
|
7855
7855
|
}
|
|
7856
7856
|
const exp = payload?.exp;
|
|
7857
|
-
if (!Number.isInteger(exp) || Number(exp) <= 0) throw new Error("The
|
|
7857
|
+
if (!Number.isInteger(exp) || Number(exp) <= 0) throw new Error("The chat auth token has no valid expiry");
|
|
7858
7858
|
return Number(exp) * 1e3;
|
|
7859
7859
|
}
|
|
7860
7860
|
function bearerToken(headers) {
|
|
7861
7861
|
const authorization = headers.get("authorization");
|
|
7862
7862
|
return authorization?.startsWith("Bearer ") ? authorization.slice(7) : void 0;
|
|
7863
7863
|
}
|
|
7864
|
-
async function
|
|
7865
|
-
const {
|
|
7866
|
-
if (typeof
|
|
7867
|
-
const { url, ...init } =
|
|
7864
|
+
async function requestChatAuthToken(options, signal) {
|
|
7865
|
+
const { fetchChatAuthToken, fetchClient } = options;
|
|
7866
|
+
if (typeof fetchChatAuthToken === "function") return (await fetchChatAuthToken())?.token;
|
|
7867
|
+
const { url, ...init } = fetchChatAuthToken;
|
|
7868
7868
|
const headers = new Headers(init.headers);
|
|
7869
7869
|
if (!headers.has("accept")) headers.set("accept", "application/json");
|
|
7870
7870
|
const response = await fetchClient(url, {
|
|
@@ -7878,12 +7878,12 @@ async function requestChatToken(options, signal) {
|
|
|
7878
7878
|
if (!response.ok) throw new Error(`Authentication endpoint returned HTTP ${response.status}`);
|
|
7879
7879
|
return (await response.json())?.token;
|
|
7880
7880
|
}
|
|
7881
|
-
async function
|
|
7881
|
+
async function loadChatAuthToken(options) {
|
|
7882
7882
|
const { session, onStateChange, debug } = options;
|
|
7883
7883
|
const { signal } = session.abortController;
|
|
7884
|
-
const source = typeof options.
|
|
7884
|
+
const source = typeof options.fetchChatAuthToken === "function" ? "fetchChatAuthToken" : "Authentication endpoint";
|
|
7885
7885
|
try {
|
|
7886
|
-
const token = await
|
|
7886
|
+
const token = await requestChatAuthToken(options, signal);
|
|
7887
7887
|
if (typeof token !== "string" || !token) throw new Error(`${source} did not return a token`);
|
|
7888
7888
|
const expiresAt = tokenExpiry(token);
|
|
7889
7889
|
if (expiresAt <= Date.now()) throw new Error(`${source} returned an expired token`);
|
|
@@ -7906,13 +7906,13 @@ async function fetchChatToken(options) {
|
|
|
7906
7906
|
throw error;
|
|
7907
7907
|
}
|
|
7908
7908
|
}
|
|
7909
|
-
async function
|
|
7909
|
+
async function getValidChatAuthToken(options) {
|
|
7910
7910
|
const { session, force = false, onStateChange } = options;
|
|
7911
7911
|
const now = Date.now();
|
|
7912
7912
|
if (!force && session.cached && session.cached.expiresAt - now > REFRESH_SKEW_MS) return session.cached.value;
|
|
7913
7913
|
if (session.refreshPromise) return await session.refreshPromise;
|
|
7914
7914
|
onStateChange({ status: "loading" });
|
|
7915
|
-
const refresh =
|
|
7915
|
+
const refresh = loadChatAuthToken(options);
|
|
7916
7916
|
session.refreshPromise = refresh;
|
|
7917
7917
|
try {
|
|
7918
7918
|
return await refresh;
|
|
@@ -7922,7 +7922,7 @@ async function getValidChatToken(options) {
|
|
|
7922
7922
|
}
|
|
7923
7923
|
async function initializeChatAuthentication(options) {
|
|
7924
7924
|
if (options.session.abortController.signal.aborted) options.session.abortController = new AbortController();
|
|
7925
|
-
await
|
|
7925
|
+
await getValidChatAuthToken(options);
|
|
7926
7926
|
}
|
|
7927
7927
|
function disposeChatAuthentication({ session }) {
|
|
7928
7928
|
session.abortController.abort();
|
|
@@ -7935,8 +7935,8 @@ async function fetchAuthenticatedChat(options) {
|
|
|
7935
7935
|
const usedToken = bearerToken(new Headers(init?.headers));
|
|
7936
7936
|
const rejectedCurrentToken = !usedToken || session.cached?.value === usedToken;
|
|
7937
7937
|
if (rejectedCurrentToken) session.cached = void 0;
|
|
7938
|
-
debug?.("auth", "chat token was rejected; refreshing once");
|
|
7939
|
-
const token = await
|
|
7938
|
+
debug?.("auth", "chat auth token was rejected; refreshing once");
|
|
7939
|
+
const token = await getValidChatAuthToken({
|
|
7940
7940
|
...options,
|
|
7941
7941
|
force: rejectedCurrentToken
|
|
7942
7942
|
});
|
|
@@ -8076,6 +8076,19 @@ function describeSandboxCommandRun(run) {
|
|
|
8076
8076
|
}
|
|
8077
8077
|
//#endregion
|
|
8078
8078
|
//#region src/core/session.ts
|
|
8079
|
+
const CORE_OPTION_KEYS = Object.keys({
|
|
8080
|
+
agentId: true,
|
|
8081
|
+
apiUrl: true,
|
|
8082
|
+
fetchChatAuthToken: true,
|
|
8083
|
+
tools: true,
|
|
8084
|
+
widgets: true,
|
|
8085
|
+
onRenderWidget: true,
|
|
8086
|
+
streamCallbacks: true,
|
|
8087
|
+
debug: true
|
|
8088
|
+
});
|
|
8089
|
+
function sameAgentTools(current, next) {
|
|
8090
|
+
return current.length === next.length && current.every((tool, index) => tool.name === next[index]?.name && tool.title === next[index]?.title);
|
|
8091
|
+
}
|
|
8079
8092
|
/**
|
|
8080
8093
|
* The headless AstralBeam chat session: authentication, transport, the tool protocol, and
|
|
8081
8094
|
* transcript state, with no markup. The drop-in widget is one consumer; a host that owns its
|
|
@@ -8091,6 +8104,7 @@ function createAstralBeamChat(options) {
|
|
|
8091
8104
|
error: void 0,
|
|
8092
8105
|
auth: { status: "loading" },
|
|
8093
8106
|
capabilities: { attachments: true },
|
|
8107
|
+
agentTools: [],
|
|
8094
8108
|
sandboxStatus: void 0,
|
|
8095
8109
|
sandbox: {
|
|
8096
8110
|
files: [],
|
|
@@ -8105,7 +8119,7 @@ function createAstralBeamChat(options) {
|
|
|
8105
8119
|
for (const listener of listeners) listener();
|
|
8106
8120
|
};
|
|
8107
8121
|
const authentication = {
|
|
8108
|
-
|
|
8122
|
+
fetchChatAuthToken: live.fetchChatAuthToken ?? { url: "/api/astralbeam/token" },
|
|
8109
8123
|
session: {
|
|
8110
8124
|
cached: void 0,
|
|
8111
8125
|
refreshPromise: void 0,
|
|
@@ -8116,15 +8130,20 @@ function createAstralBeamChat(options) {
|
|
|
8116
8130
|
debug
|
|
8117
8131
|
};
|
|
8118
8132
|
initializeChatAuthentication(authentication).catch(() => void 0);
|
|
8133
|
+
let capabilitiesGeneration = 0;
|
|
8119
8134
|
const resolveCapabilities = async () => {
|
|
8135
|
+
const generation = ++capabilitiesGeneration;
|
|
8120
8136
|
try {
|
|
8121
8137
|
const url = new URL(chatApiUrls(live.apiUrl).config, globalThis.location?.href);
|
|
8122
8138
|
if (live.agentId) url.searchParams.set("agentId", live.agentId);
|
|
8123
|
-
const token = await
|
|
8139
|
+
const token = await getValidChatAuthToken(authentication);
|
|
8124
8140
|
const response = await fetch(url, { headers: { authorization: `Bearer ${token}` } });
|
|
8125
8141
|
if (!response.ok) throw new Error(`The config request answered ${response.status}`);
|
|
8126
8142
|
const body = await response.json();
|
|
8127
|
-
|
|
8143
|
+
if (generation !== capabilitiesGeneration) return;
|
|
8144
|
+
const attachments = body.capabilities?.attachments !== false;
|
|
8145
|
+
update({ capabilities: { attachments } });
|
|
8146
|
+
debug?.("mount", "agent capabilities resolved", { attachments });
|
|
8128
8147
|
} catch (error) {
|
|
8129
8148
|
debug?.("error", "agent capabilities could not be resolved; keeping the defaults", error);
|
|
8130
8149
|
}
|
|
@@ -8143,32 +8162,52 @@ function createAstralBeamChat(options) {
|
|
|
8143
8162
|
if (validated == null) throw new Error(`Props for widget "${input.widget}" failed validation`);
|
|
8144
8163
|
renderCleanups.get(toolCallId)?.();
|
|
8145
8164
|
renderCleanups.delete(toolCallId);
|
|
8165
|
+
let registered;
|
|
8166
|
+
const release = () => {
|
|
8167
|
+
if (renderCleanups.get(toolCallId) === registered) renderCleanups.delete(toolCallId);
|
|
8168
|
+
};
|
|
8146
8169
|
const cleanup = live.onRenderWidget?.({
|
|
8147
8170
|
widget: input.widget,
|
|
8148
8171
|
props: validated,
|
|
8149
|
-
toolCallId
|
|
8172
|
+
toolCallId,
|
|
8173
|
+
release
|
|
8150
8174
|
});
|
|
8151
|
-
if (cleanup)
|
|
8175
|
+
if (cleanup) {
|
|
8176
|
+
registered = cleanup;
|
|
8177
|
+
renderCleanups.set(toolCallId, cleanup);
|
|
8178
|
+
}
|
|
8152
8179
|
return {
|
|
8153
8180
|
widget: input.widget,
|
|
8154
8181
|
rendered: live.onRenderWidget !== void 0
|
|
8155
8182
|
};
|
|
8156
8183
|
};
|
|
8157
|
-
const
|
|
8184
|
+
const buildTools = () => buildAgentTools(live.widgets ?? {}, live.tools ?? {}, renderWidget, debug);
|
|
8185
|
+
const declareTools = () => {
|
|
8186
|
+
const tools = buildTools();
|
|
8187
|
+
const agentTools = tools.map((tool) => {
|
|
8188
|
+
const title = tool.metadata?.["title"];
|
|
8189
|
+
return {
|
|
8190
|
+
name: tool.name,
|
|
8191
|
+
title: typeof title === "string" && title.length > 0 ? title : void 0
|
|
8192
|
+
};
|
|
8193
|
+
});
|
|
8194
|
+
if (!sameAgentTools(state.agentTools, agentTools)) update({ agentTools });
|
|
8195
|
+
return tools;
|
|
8196
|
+
};
|
|
8158
8197
|
const forwardedProps = () => ({
|
|
8159
8198
|
...live.agentId ? { agentId: live.agentId } : {},
|
|
8160
8199
|
...live.debug ? { debug: true } : {}
|
|
8161
8200
|
});
|
|
8162
8201
|
const client = new ChatClient({
|
|
8163
8202
|
connection: fetchServerSentEvents(() => chatApiUrls(live.apiUrl).chat, async () => ({
|
|
8164
|
-
headers: { authorization: `Bearer ${await
|
|
8203
|
+
headers: { authorization: `Bearer ${await getValidChatAuthToken(authentication)}` },
|
|
8165
8204
|
fetchClient: (input, init) => fetchAuthenticatedChat({
|
|
8166
8205
|
...authentication,
|
|
8167
8206
|
input,
|
|
8168
8207
|
init
|
|
8169
8208
|
})
|
|
8170
8209
|
})),
|
|
8171
|
-
tools:
|
|
8210
|
+
tools: declareTools(),
|
|
8172
8211
|
forwardedProps: forwardedProps(),
|
|
8173
8212
|
onMessagesChange: (messages) => {
|
|
8174
8213
|
update({
|
|
@@ -8184,30 +8223,40 @@ function createAstralBeamChat(options) {
|
|
|
8184
8223
|
onCustomEvent: (eventType, data) => {
|
|
8185
8224
|
const value = data?.state;
|
|
8186
8225
|
if (eventType === "astralbeam.sandbox.status" && (value === "starting" || value === "ready" || value === "error")) {
|
|
8226
|
+
debug?.("sandbox", `sandbox ${value}`);
|
|
8187
8227
|
update({ sandboxStatus: value });
|
|
8188
8228
|
return;
|
|
8189
8229
|
}
|
|
8190
8230
|
debug?.("stream", `custom event "${eventType}"`, data);
|
|
8191
|
-
}
|
|
8231
|
+
},
|
|
8232
|
+
onChunk: (chunk) => live.streamCallbacks?.onChunk?.(chunk),
|
|
8233
|
+
onResponse: (response) => live.streamCallbacks?.onResponse?.(response),
|
|
8234
|
+
onFinish: (message) => live.streamCallbacks?.onFinish?.(message),
|
|
8235
|
+
onError: (error) => live.streamCallbacks?.onError?.(error)
|
|
8192
8236
|
});
|
|
8193
8237
|
const settleDanglingToolCalls = () => {
|
|
8194
8238
|
for (const message of state.messages) for (const part of message.parts) {
|
|
8195
8239
|
if (part.type !== "tool-call" || isSettledToolCall(part)) continue;
|
|
8196
|
-
if (part.name === "ask_questionnaire")
|
|
8197
|
-
|
|
8198
|
-
|
|
8199
|
-
|
|
8200
|
-
|
|
8201
|
-
|
|
8202
|
-
|
|
8203
|
-
|
|
8204
|
-
|
|
8205
|
-
|
|
8206
|
-
|
|
8207
|
-
|
|
8208
|
-
|
|
8209
|
-
|
|
8210
|
-
|
|
8240
|
+
if (part.name === "ask_questionnaire") {
|
|
8241
|
+
debug?.("questionnaire", "skipping pending questionnaire before send", { id: part.id });
|
|
8242
|
+
client.addToolResult({
|
|
8243
|
+
toolCallId: part.id,
|
|
8244
|
+
tool: part.name,
|
|
8245
|
+
output: {
|
|
8246
|
+
answers: [],
|
|
8247
|
+
skipped: true
|
|
8248
|
+
}
|
|
8249
|
+
});
|
|
8250
|
+
} else {
|
|
8251
|
+
debug?.("tool", `settling unimplemented tool call "${part.name}" as error`, { id: part.id });
|
|
8252
|
+
client.addToolResult({
|
|
8253
|
+
toolCallId: part.id,
|
|
8254
|
+
tool: part.name,
|
|
8255
|
+
output: null,
|
|
8256
|
+
state: "output-error",
|
|
8257
|
+
errorText: `The application hosting this chat has no implementation for "${part.name}"`
|
|
8258
|
+
});
|
|
8259
|
+
}
|
|
8211
8260
|
}
|
|
8212
8261
|
};
|
|
8213
8262
|
return {
|
|
@@ -8224,10 +8273,10 @@ function createAstralBeamChat(options) {
|
|
|
8224
8273
|
...next
|
|
8225
8274
|
};
|
|
8226
8275
|
debug = createDebugLogger(live.debug);
|
|
8227
|
-
authentication.
|
|
8276
|
+
authentication.fetchChatAuthToken = live.fetchChatAuthToken ?? { url: "/api/astralbeam/token" };
|
|
8228
8277
|
authentication.debug = debug;
|
|
8229
8278
|
client.updateOptions({
|
|
8230
|
-
tools:
|
|
8279
|
+
tools: declareTools(),
|
|
8231
8280
|
forwardedProps: forwardedProps()
|
|
8232
8281
|
});
|
|
8233
8282
|
if (live.agentId !== agent || live.apiUrl !== apiUrl) resolveCapabilities();
|
|
@@ -8238,8 +8287,15 @@ function createAstralBeamChat(options) {
|
|
|
8238
8287
|
},
|
|
8239
8288
|
addToolResult: (result) => client.addToolResult(result),
|
|
8240
8289
|
stop: () => client.stop(),
|
|
8290
|
+
retryAuthentication: () => {
|
|
8291
|
+
getValidChatAuthToken({
|
|
8292
|
+
...authentication,
|
|
8293
|
+
force: true
|
|
8294
|
+
}).catch(() => void 0);
|
|
8295
|
+
},
|
|
8241
8296
|
reload: () => client.reload(),
|
|
8242
8297
|
reset: () => {
|
|
8298
|
+
debug?.("status", "conversation reset");
|
|
8243
8299
|
client.clear();
|
|
8244
8300
|
disposeRenders();
|
|
8245
8301
|
update({
|
|
@@ -8266,9 +8322,5 @@ function createAstralBeamChat(options) {
|
|
|
8266
8322
|
function defineTool(tool) {
|
|
8267
8323
|
return tool;
|
|
8268
8324
|
}
|
|
8269
|
-
/** Declares a host widget; a Standard Schema `parameters` types (and validates) `render`'s props. */
|
|
8270
|
-
function defineWidget(widget) {
|
|
8271
|
-
return widget;
|
|
8272
|
-
}
|
|
8273
8325
|
//#endregion
|
|
8274
|
-
export { DEFAULT_COLOR_SCHEME as C, SANDBOX_WRITE_FILE_TOOL as S, SANDBOX_LIST_FILES_TOOL as _, describeSandboxCommandRun as a, SANDBOX_RUN_COMMAND_TOOL as b, readSandboxCommandRun as c, hasPendingToolRun as d, isSettledToolCall as f, RENDER_WIDGET_TOOL as g, ASK_QUESTIONNAIRE_TOOL as h, collectSandboxActivity as i, readSandboxFileWrite as l, buildAgentTools as m,
|
|
8326
|
+
export { DEFAULT_COLOR_SCHEME as C, SANDBOX_WRITE_FILE_TOOL as S, SANDBOX_LIST_FILES_TOOL as _, describeSandboxCommandRun as a, SANDBOX_RUN_COMMAND_TOOL as b, readSandboxCommandRun as c, hasPendingToolRun as d, isSettledToolCall as f, RENDER_WIDGET_TOOL as g, ASK_QUESTIONNAIRE_TOOL as h, collectSandboxActivity as i, readSandboxFileWrite as l, buildAgentTools as m, CORE_OPTION_KEYS as n, isSandboxTool as o, lastPartInProgress as p, createAstralBeamChat as r, readSandboxArtifact as s, defineTool as t, sandboxRefusal as u, SANDBOX_PUBLISH_ARTIFACT_TOOL as v, SANDBOX_STATUS_EVENT as x, SANDBOX_READ_FILE_TOOL as y };
|
package/dist/core.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
export { ASK_QUESTIONNAIRE_TOOL, type AstralBeamChatCore, type AstralBeamChatCoreOptions, type AstralBeamChatState, type ChatAuthenticationState, type InferParameters, type JsonSchemaObject, type ParametersSchema, RENDER_WIDGET_TOOL, type RenderWidgetInput, SANDBOX_LIST_FILES_TOOL, SANDBOX_PUBLISH_ARTIFACT_TOOL, SANDBOX_READ_FILE_TOOL, SANDBOX_RUN_COMMAND_TOOL, SANDBOX_STATUS_EVENT, SANDBOX_WRITE_FILE_TOOL, type SandboxActivity, type SandboxArtifact, type SandboxCommandRun, type SandboxFileWrite, type SandboxStatus, type StandardSchemaV1, type ToolDefinition, type WidgetDeclaration, type WidgetRenderRequest, buildAgentTools, collectSandboxActivity, createAstralBeamChat, defineTool,
|
|
1
|
+
import { A as RenderWidgetInput, B as ToolDefinition, C as AstralBeamChatState, D as ChatAuthenticationState, E as createAstralBeamChat, F as SandboxStatus, I as InferParameters, L as JsonSchemaObject, M as SandboxArtifact, N as SandboxCommandRun, O as WidgetDeclaration, P as SandboxFileWrite, R as ParametersSchema, S as AstralBeamChatCoreOptions, T as WidgetRenderRequest, _ as hasPendingToolRun, a as SANDBOX_PUBLISH_ARTIFACT_TOOL, b as AgentToolInfo, c as SANDBOX_STATUS_EVENT, d as describeSandboxCommandRun, f as isSandboxTool, g as sandboxRefusal, h as readSandboxFileWrite, i as SANDBOX_LIST_FILES_TOOL, j as SandboxActivity, k as buildAgentTools, l as SANDBOX_WRITE_FILE_TOOL, m as readSandboxCommandRun, n as ASK_QUESTIONNAIRE_TOOL, o as SANDBOX_READ_FILE_TOOL, p as readSandboxArtifact, r as RENDER_WIDGET_TOOL, s as SANDBOX_RUN_COMMAND_TOOL, t as defineTool, u as collectSandboxActivity, v as isSettledToolCall, w as ChatStreamCallbacks, x as AstralBeamChatCore, y as lastPartInProgress, z as StandardSchemaV1 } from "./index-CudekMKM.js";
|
|
2
|
+
export { ASK_QUESTIONNAIRE_TOOL, type AgentToolInfo, type AstralBeamChatCore, type AstralBeamChatCoreOptions, type AstralBeamChatState, type ChatAuthenticationState, type ChatStreamCallbacks, type InferParameters, type JsonSchemaObject, type ParametersSchema, RENDER_WIDGET_TOOL, type RenderWidgetInput, SANDBOX_LIST_FILES_TOOL, SANDBOX_PUBLISH_ARTIFACT_TOOL, SANDBOX_READ_FILE_TOOL, SANDBOX_RUN_COMMAND_TOOL, SANDBOX_STATUS_EVENT, SANDBOX_WRITE_FILE_TOOL, type SandboxActivity, type SandboxArtifact, type SandboxCommandRun, type SandboxFileWrite, type SandboxStatus, type StandardSchemaV1, type ToolDefinition, type WidgetDeclaration, type WidgetRenderRequest, buildAgentTools, collectSandboxActivity, createAstralBeamChat, defineTool, describeSandboxCommandRun, hasPendingToolRun, isSandboxTool, isSettledToolCall, lastPartInProgress, readSandboxArtifact, readSandboxCommandRun, readSandboxFileWrite, sandboxRefusal };
|
package/dist/core.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { S as SANDBOX_WRITE_FILE_TOOL, _ as SANDBOX_LIST_FILES_TOOL, a as describeSandboxCommandRun, b as SANDBOX_RUN_COMMAND_TOOL, c as readSandboxCommandRun, d as hasPendingToolRun, f as isSettledToolCall, g as RENDER_WIDGET_TOOL, h as ASK_QUESTIONNAIRE_TOOL, i as collectSandboxActivity, l as readSandboxFileWrite, m as buildAgentTools,
|
|
2
|
-
export { ASK_QUESTIONNAIRE_TOOL, RENDER_WIDGET_TOOL, SANDBOX_LIST_FILES_TOOL, SANDBOX_PUBLISH_ARTIFACT_TOOL, SANDBOX_READ_FILE_TOOL, SANDBOX_RUN_COMMAND_TOOL, SANDBOX_STATUS_EVENT, SANDBOX_WRITE_FILE_TOOL, buildAgentTools, collectSandboxActivity, createAstralBeamChat, defineTool,
|
|
1
|
+
import { S as SANDBOX_WRITE_FILE_TOOL, _ as SANDBOX_LIST_FILES_TOOL, a as describeSandboxCommandRun, b as SANDBOX_RUN_COMMAND_TOOL, c as readSandboxCommandRun, d as hasPendingToolRun, f as isSettledToolCall, g as RENDER_WIDGET_TOOL, h as ASK_QUESTIONNAIRE_TOOL, i as collectSandboxActivity, l as readSandboxFileWrite, m as buildAgentTools, o as isSandboxTool, p as lastPartInProgress, r as createAstralBeamChat, s as readSandboxArtifact, t as defineTool, u as sandboxRefusal, v as SANDBOX_PUBLISH_ARTIFACT_TOOL, x as SANDBOX_STATUS_EVENT, y as SANDBOX_READ_FILE_TOOL } from "./core-BF1G1dLe.js";
|
|
2
|
+
export { ASK_QUESTIONNAIRE_TOOL, RENDER_WIDGET_TOOL, SANDBOX_LIST_FILES_TOOL, SANDBOX_PUBLISH_ARTIFACT_TOOL, SANDBOX_READ_FILE_TOOL, SANDBOX_RUN_COMMAND_TOOL, SANDBOX_STATUS_EVENT, SANDBOX_WRITE_FILE_TOOL, buildAgentTools, collectSandboxActivity, createAstralBeamChat, defineTool, describeSandboxCommandRun, hasPendingToolRun, isSandboxTool, isSettledToolCall, lastPartInProgress, readSandboxArtifact, readSandboxCommandRun, readSandboxFileWrite, sandboxRefusal };
|