跳至主要内容

前端 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/reactcore 之上提供現成的 React 聊天 UI 元件

依你選擇的整合模式 (Pattern) 對應使用:

前端 Javascript SDK ≠ 後端 Node.js SDK

本頁討論的「前端 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
下方 React 範例會用到 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型別說明
botProviderEndpointstring必填。Bot Provider 的 endpoint URL, SSE / Blob 等子路徑會自動推導
apiKeystring可選。Bot Provider API Key。Backend Relay 下不需要
customHeadersRecord<string,string>可選。隨請求一起送出的 HTTP header(例:Authorization: Bearer xxx)
transformSsePayload(payload) => payload可選。送出 SSE 請求前的 payload 改寫 hook
debugModeboolean可選。開發時觀察 deprecation warnings

Chatbot 元件 — UI / 行為

Prop型別說明
customChannelIdstring必填。對話識別, 詳見 Conversation History
initMessagesConversationMessage[]可選。預先注入的歷史訊息。必須搭配 autoResetChannel={false},否則 mount 時 channel reset 會清掉預載訊息
autoResetChannelboolean預設 true。設為 false 時 mount 不發送 RESET_CHANNEL,initMessages 帶入的歷史才能被保留
titlestring視窗標題
avatarstringBot 頭像 URL
inputPlaceholderstring輸入框提示
botTypingPlaceholderstringBot 思考中提示文字
fullScreenboolean是否全螢幕版型
themeobject主題樣式(顏色、邊框等)
enableUploadboolean啟用圖片上傳
enableDocumentUploadboolean啟用文件上傳
enableExportboolean啟用對話匯出
authState'loading'|'needApiKey'|'authenticated'|'invalidApiKey'|'error'動態 Auth 狀態
onApiKeySubmit(key: string) => void使用者輸入 API Key 時的 callback

Chatbot 元件 — 客製化渲染

Prop型別說明
renderHeader() => ReactNode完全取代預設標題列。在 renderer 內部可用 useAsgardContext() 取得 resetChannelisResettingtitleavatar 等狀態。詳見 互動範例
renderMenu() => ReactNode在 body 與 footer 之間插入自訂選單區塊。詳見 互動範例
renderFooter() => ReactNode完全取代預設輸入列(含 textarea、送出鈕、上傳等)。在 renderer 內部可用 useAsgardContext() 取得 sendMessageisConnectingpendingInputValue 等。詳見 互動範例
footerEndActionsReactNode[]在預設 footer 右側追加按鈕,不替換整個 footer。詳見 互動範例
renderFooter vs footerEndActions

只想在輸入框旁邊加一個按鈕 → 用 footerEndActions(保留原有 textarea 與送出鈕)。 需要完全自訂輸入區域的外觀與行為 → 用 renderFooter(自行負責送訊息邏輯)。

Chatbot 元件 — 事件 Hooks

Prop觸發時機
onBeforeSendMessage訊息送出前(可修改 payload)
onSseMessage收到每一個 SSE 事件
onSseErrorSSE 串流發生錯誤
onResetChannel 被重置
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 warning

在 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})且外層容器為固定尺寸時才需要套用。


延伸閱讀