前端 SDK 使用指南
前端 SDK 是把 Asgard Bot Provider 接到瀏覽器中的工具, 負責聊天 UI 渲染與 SSE 串流連線。本指南介紹 SDK 套件選擇、基本使用、常見配置, 並指向更完整的線上互動範例。
本頁假設你已經決定要採用哪一種「整合模式 (Pattern)」 — Direct Connect / Workflow Auth / Backend Relay — 因為不同模式下 SDK 的配置方式會不一樣。
如果你對 Pattern 還不熟悉, 請先閱讀 總覽與選型, 選定後再回到本頁。
前端 SDK 是什麼
Asgard 提供兩個 npm 套件, 合稱「前端 Javascript SDK」:
| 套件 | 用途 |
|---|---|
@asgard-js/core | 與前端 UI 框架無關的核心連線層 — 處理 SSE 串流、Conversation 狀態、檔案上傳 |
@asgard-js/react | 在 core 之上提供現成的 React 聊天 UI 元件 |
依你選擇的整合模式 (Pattern) 對應使用:
- Direct Connect 與 Workflow Auth: SDK 直連 Asgard Edge Server
- Backend Relay: SDK 改打你的後端, 你的後端再轉發 Edge Server
- Hosted Embed: 不需要安裝 SDK(Asgard 托管的前端已內建)
本頁討論的「前端 Javascript SDK」是跑在使用者瀏覽器中的套件。Asgard 另外提供的「後端 Node.js SDK」(@asgard-js/nodejs)是跑在你的伺服器的套件, 兩者用途、套件名稱、執行位置都不同。詳見 後端 SDK 使用指南。
套件選型: core vs react
用 React → 選 @asgard-js/react
最常見的選擇, 你會得到一個現成可用的 <Chatbot /> 元件, 包含對話視窗、訊息渲染、輸入框、上傳介面等完整 UI。也可以做大量客製化。
用其他框架(Vue / Svelte / Vanilla JS)→ 選 @asgard-js/core
你自己渲染 UI, SDK 只負責提供 AsgardServiceClient / Channel / Conversation 等抽象, 讓你能呼叫 SSE、管理對話狀態、上傳檔案。
用 React 但要完全自己渲染 UI → 也可以選 @asgard-js/core
如果預設的 <Chatbot /> UI 不符合你的設計需求, 且 Custom Renderer 也不夠, 你可以只用 core 套件並自行用 React 包裝 UI。Headless 範例 展示這個用法。
安裝
# React 開發者(推薦)
npm install @asgard-js/core @asgard-js/react
# 其他框架
npm install @asgard-js/core
uuid「基本使用」範例用 uuid 產生 customChannelId,請一併安裝 npm install uuid。如果不想多裝套件, 也可以改用瀏覽器內建的 crypto.randomUUID(), 或任何能保證唯一的字串。
CSS 樣式引入(react 套件)
@asgard-js/react 的預設樣式需要單獨引入一次:
import '@asgard-js/react/style';
基本使用(React)
Direct Connect 模式
import { Chatbot } from '@asgard-js/react';
import '@asgard-js/react/style';
import { v4 as uuidv4 } from 'uuid';
import { useRef } from 'react';
export default function App() {
const channelIdRef = useRef(uuidv4());
return (
<Chatbot
title="我的 AI 助理"
config={{
botProviderEndpoint: 'https://api.asgard-ai.com/ns/your-namespace/bot-provider/your-bot',
apiKey: 'your-api-key',
}}
customChannelId={channelIdRef.current}
/>
);
}
Backend Relay 模式
把 botProviderEndpoint 改為指向你的後端, 不需要 apiKey:
<Chatbot
title="我的 AI 助理"
config={{
botProviderEndpoint: 'https://your-backend.com/api/chat', // 你的後端
}}
customChannelId={channelIdRef.current}
customHeaders={{
Authorization: `Bearer ${accessToken}`, // 依照你後端的驗證需求帶上適當的 headers
}}
/>
你的後端必須對應實作 SDK 預期的 endpoint 介面, 詳見 Backend Relay。
重要 Props 速查
Chatbot 元件 — 連線設定 (config)
| Prop | 型別 | 說明 |
|---|---|---|
botProviderEndpoint | string | 必填。Bot Provider 的 endpoint URL, SSE / Blob 等子路徑會自動推導 |
apiKey | string | 可選。Bot Provider API Key。Backend Relay 下不需要 |
customHeaders | Record<string,string> | 可選。隨請求一起送出的 HTTP header(例:Authorization: Bearer xxx) |
transformSsePayload | (payload) => payload | 可選。送出 SSE 請求前的 payload 改寫 hook |
debugMode | boolean | 可選。開發時觀察 deprecation warnings |
Chatbot 元件 — UI / 行為
| Prop | 型別 | 說明 |
|---|---|---|
customChannelId | string | 必填。對話識別, 詳見 Conversation History |
initMessages | ConversationMessage[] | 可選。預先注入的歷史訊息。必須搭配 autoResetChannel={false},否則 mount 時 channel reset 會清掉預載訊息 |
autoResetChannel | boolean | 預設 true。設為 false 時 mount 不發送 RESET_CHANNEL,initMessages 帶入的歷史才能被保留 |
title | string | 視窗標題 |
avatar | string | Bot 頭像 URL |
inputPlaceholder | string | 輸入框提示 |
botTypingPlaceholder | string | Bot 思考中提示文字 |
fullScreen | boolean | 是否全螢幕版型 |
theme | object | 主題樣式(顏色、邊框等) |
enableUpload | boolean | 啟用圖片上傳 |
enableDocumentUpload | boolean | 啟用文件上傳 |
enableExport | boolean | 啟用對話匯出 |
authState | 'loading'|'needApiKey'|'authenticated'|'invalidApiKey'|'error' | 動態 Auth 狀態 |
onApiKeySubmit | (key: string) => void | 使用者輸入 API Key 時的 callback |
Chatbot 元件 — 客製化渲染
| Prop | 型別 | 說明 |
|---|---|---|
renderHeader | () => ReactNode | 完全取代預設標題列。在 renderer 內部可用 useAsgardContext() 取得 resetChannel、isResetting、title、avatar 等狀態。詳見 互動範例 |
renderMenu | () => ReactNode | 在 body 與 footer 之間插入自訂選單區塊。詳見 互動範例 |
renderFooter | () => ReactNode | 完全取代預設輸入列(含 textarea、送出鈕、上傳等)。在 renderer 內部可用 useAsgardContext() 取得 sendMessage、isConnecting、pendingInputValue 等。詳見 互動範例 |
footerEndActions | ReactNode[] | 在預設 footer 右側追加按鈕,不替換整個 footer。詳見 互動範例 |
renderFooter vs footerEndActions只想在輸入框旁邊加一個按鈕 → 用 footerEndActions(保留原有 textarea 與送出鈕)。
需要完全自訂輸入區域的外觀與行為 → 用 renderFooter(自行負責送訊息邏輯)。
Chatbot 元件 — 事件 Hooks
| Prop | 觸發時機 |
|---|---|
onBeforeSendMessage | 訊息送出前(可修改 payload) |
onSseMessage | 收到每一個 SSE 事件 |
onSseError | SSE 串流發生錯誤 |
onReset | Channel 被重置 |
onClose | 視窗關閉 |
完整 Props 參考:Props Reference 互動範例
Chatbot Ref: 從外部觸發行為
把 ref 傳給 <Chatbot> 後, 可從外部觸發送訊息、設定輸入值:
import { Chatbot, ChatbotRef } from '@asgard-js/react';
import { useRef } from 'react';
const ref = useRef<ChatbotRef>(null);
// 從外部送訊息
ref.current?.serviceContext?.sendMessage?.({
text: '從外部送一句話',
blobIds: [],
});
// 設定輸入框值
ref.current?.setInputValue?.('預填的內容');
詳見 Chatbot Ref 互動範例。
@asgard-js/core 直接使用
不透過 React 元件, 而直接用底層 API:
import { AsgardServiceClient, Channel, Conversation } from '@asgard-js/core';
const client = new AsgardServiceClient({
botProviderEndpoint: 'https://api.asgard-ai.com/ns/your-namespace/bot-provider/your-bot',
apiKey: 'your-api-key',
});
const conversation = new Conversation({ messages: new Map() });
const channel = await Channel.reset({
client,
customChannelId: 'channel-123',
conversation,
statesObserver: (states) => {
console.log('Connection status:', states.isConnecting);
console.log('Messages:', Array.from(states.conversation.messages.values()));
},
});
await channel.sendMessage({ text: 'Hello!' });
完整 API 文件見 Core API 互動範例。
進階主題快速導覽
以下功能在 SDK Demo 有完整互動範例:
| 主題 | 連結 |
|---|---|
| 第一個範例(Quick Start) | 互動範例 |
| 預載對話歷史(initMessages) | 互動範例 |
| 嵌入與 Floating Widget 版型 | 互動範例 |
| 自訂標題列(renderHeader) | 互動範例 |
| 自訂輸入列(renderFooter) | 互動範例 |
| 自動重置 Channel | 互動範例 |
| 訊息送出前攔截 | 互動範例 |
| 動態 Payload 注入 | 互動範例 |
| Custom Renderer 客製化渲染 | 互動範例 |
| Markdown 渲染 | 互動範例 |
| Render Menu(自訂選單) | 互動範例 |
| Sizing 與版型 | 互動範例 |
| 主題 / Theme | 互動範例 |
| 訊息範本(Template Messages) | 互動範例 |
| 訊息操作(複製、轉發等) | 互動範例 |
| 工具呼叫處理 | 互動範例 |
| 工具呼叫使用者同意 | 互動範例 |
| HTTP Error 處理 | 互動範例 |
| Headless 模式 | 互動範例 |
| Footer 客製按鈕 | 互動範例 |
版本相容性與升級
- 套件採 semver, 小版號(
0.X.Y)變動可能有 breaking change, 升級前務必看 CHANGELOG @asgard-js/core與@asgard-js/react版本建議保持一致- React peer dependency:
react >= 18(請參考最新 README)
常見問題
Q. 我需要設定 CORS 嗎?
Direct Connect / Workflow Auth 下, Asgard Edge Server 已為一般網域開放 CORS。若有疑問或自有特殊需求, 請洽 Asgard。
Backend Relay 下, 你的後端與前端跨域時, CORS 由你的後端負責設定。
Q. SSE 在 mobile 上會被中斷怎麼辦?
行動裝置背景切換時瀏覽器可能關閉長連線。可開啟 maintainConnectionWhenClosed 嘗試保持連線, 或在 onSseError 中實作重連策略。
Q. 如何在 SSR 框架(Next.js)使用?
<Chatbot> 是純客戶端元件, 需要在客戶端載入。在 Next.js App Router 下加 'use client', 或在 Pages Router 下用 dynamic import 並設 ssr: false。
App Router:
'use client';
import dynamic from 'next/dynamic';
import '@asgard-js/react/style';
const Chatbot = dynamic(
() => import('@asgard-js/react').then((m) => m.Chatbot),
{ ssr: false },
);
Pages Router:
import dynamic from 'next/dynamic';
import '@asgard-js/react/style';
const Chatbot = dynamic(
() => import('@asgard-js/react').then((m) => m.Chatbot),
{ ssr: false },
);
在 Next.js App Router 開發模式下,你可能會看到這樣的 console error:
Only plain objects can be passed to Client Components from Server Components. Set objects are not supported.
這是 Next.js dev overlay 偵測到 SDK 內部狀態物件所觸發的警告,不影響 chatbot 的實際功能,production build 不會出現。如需消除此訊息,可改用 dynamic import 載入元件:
import dynamic from 'next/dynamic';
const AsgardChatbot = dynamic(() => import('./AsgardChatbot'), { ssr: false });
Q. 想把訊息渲染成圖表、卡片、表格等自訂樣式(Custom Renderer)?
@asgard-js/react 支援註冊自訂 Renderer, 把特定型別或內容的訊息以你自己的 React 元件呈現, 而非預設的文字 / Markdown 樣式。完整用法與 API 請參考 Custom Renderer 互動範例。
Q. 想完全自訂 UI(只用 SDK 的資料層)?
用 @asgard-js/core 自己組裝 UI。或者用 @asgard-js/react 的 Headless 模式, 參考 Headless 模式互動範例。
Q. 在固定尺寸的浮動 Widget 容器中使用 renderFooter 時,Footer 被裁切掉了?
浮動 Widget 版型是指把 <Chatbot> 包在一個固定尺寸的 div 裡,而不使用全螢幕模式,例如:
<div style={{ width: 400, height: 600, position: 'fixed', bottom: 24, right: 24 }}>
<Chatbot fullScreen={false} renderFooter={...} ... />
</div>
在這個版型下,SDK 內部的容器使用 display: grid,其高度由 header + body + footer 的內容加總決定,CSS 的 height: 100% 無法正確繼承外層的固定高度(原因是 CSS cascade layer 的交互作用),導致 renderFooter 渲染的 footer 超出外層容器而被裁切。
解法: 在元件掛載後,透過 useEffect 以 inline style + !important 強制指定 SDK 內部容器的高度:
import { useRef, useEffect } from 'react';
import { Chatbot } from '@asgard-js/react';
export default function FloatingWidget() {
const wrapperRef = useRef<HTMLDivElement>(null);
const isOpen = true; // 替換為你控制開關的 state
const isFullscreen = false; // 固定尺寸版型一律 false
useEffect(() => {
if (!isOpen || isFullscreen) return;
const container = wrapperRef.current?.querySelector<HTMLElement>('[class*="_chatbot_container"]');
container?.style.setProperty('height', '100%', 'important');
}, [isOpen, isFullscreen]);
return (
<div
ref={wrapperRef}
style={{ width: 400, height: 600, position: 'fixed', bottom: 24, right: 24 }}
>
<Chatbot
fullScreen={false}
renderFooter={({ sendMessage }) => (
<button onClick={() => sendMessage({ text: '快捷訊息', blobIds: [] })}>送出</button>
)}
{/* 其他 props */}
/>
</div>
);
}
[class*="_chatbot_container"] 是 SDK 內部 CSS Module 的 class 選擇器,未來版本若 class 名稱變動可能需要更新。此 workaround 僅在非全螢幕(fullScreen={false})且外層容器為固定尺寸時才需要套用。
延伸閱讀
- 完整模式深探: Hosted Embed / Direct Connect / Workflow Auth / Backend Relay
- 後端 SDK(Backend Relay 用): 後端 SDK 使用指南
- 完整互動範例(線上 demo): SDK Demo
- GitHub Repo: asgard-js-sdk