Skip to content

Commit 52e8e1b

Browse files
authored
Merge pull request #1153 from objectstack-ai/copilot/refactor-chatbot-plugin-ai-sdui
2 parents fdd42ec + 85d85fc commit 52e8e1b

File tree

17 files changed

+1535
-194
lines changed

17 files changed

+1535
-194
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Added
1111

12+
- **AI SDUI Chatbot integration** (`@object-ui/plugin-chatbot`): Refactored chatbot plugin to support full AI streaming via `service-ai` backend and `vercel/ai` SDK (`@ai-sdk/react`). New `useObjectChat` composable hook wraps `@ai-sdk/react`'s `useChat` for SSE streaming, tool-calling, and production-grade chat. Auto-detects API mode (when `api` schema field is set) vs legacy local auto-response mode. ChatbotEnhanced component now supports stop, reload, error display, and streaming state indicators. 44 unit tests (19 new hook tests, 10 new streaming tests).
13+
14+
- **New ChatbotSchema fields** (`@object-ui/types`): Extended `ChatbotSchema` with `api`, `conversationId`, `systemPrompt`, `model`, `streamingEnabled`, `headers`, `body`, `maxToolRoundtrips`, and `onError` fields for service-ai integration. Extended `ChatMessage` with `streaming`, `toolInvocations` fields and added `ChatToolInvocation` interface for tool-calling flows.
15+
16+
- **New Storybook stories for AI chatbot** (`@object-ui/components`): Added `AIStreamingMode`, `AIWithSystemPrompt`, and `AIWithToolCalls` stories demonstrating the new AI SDUI chat modes alongside existing local/demo stories.
17+
1218
- **Object Manager visual designer** (`@object-ui/plugin-designer`): Enterprise-grade object management interface for creating, editing, deleting, and configuring meta-object definitions. Uses standard ObjectGrid for the list view and ModalForm for create/edit operations. Features include property editing (name, label, plural label, description, icon, group, sort order, enabled toggle), object relationship display, search/filter, system object protection, confirm dialogs for destructive actions, and read-only mode. 18 unit tests.
1319

1420
- **Field Designer visual designer** (`@object-ui/plugin-designer`): Enterprise-grade field configuration wizard supporting 27 field types with full CRUD operations. Uses standard ObjectGrid for the list view with a specialized FieldEditor panel for advanced type-specific properties. Features include uniqueness constraints, default values, picklist/option set management, read-only, hidden, validation rules (min/max/length/pattern/custom), external ID, history tracking, and database indexing. Type-specific editors for lookup references, formula expressions, and select options. Field type filtering, search, system field protection, and read-only mode. 22 unit tests.

ROADMAP.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
> **Spec Version:** @objectstack/spec v3.3.0
66
> **Client Version:** @objectstack/client v3.3.0
77
> **Target UX Benchmark:** 🎯 Airtable parity
8-
> **Current Priority:** AppShell Navigation · Designer Interaction · **View Config Live Preview Sync ✅** · Dashboard Config Panel · Airtable UX Polish · **Flow Designer ✅** · **App Creation & Editing Flow ✅** · **System Settings & App Management ✅** · **Right-Side Visual Editor Drawer ✅** · **Object Manager & Field Designer ✅**
8+
> **Current Priority:** AppShell Navigation · Designer Interaction · **View Config Live Preview Sync ✅** · Dashboard Config Panel · Airtable UX Polish · **Flow Designer ✅** · **App Creation & Editing Flow ✅** · **System Settings & App Management ✅** · **Right-Side Visual Editor Drawer ✅** · **Object Manager & Field Designer ✅** · **AI SDUI Chatbot (service-ai + vercel/ai) ✅**
99
1010
---
1111

content/docs/plugins/plugin-chatbot.mdx

Lines changed: 96 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,17 @@ const schema = {
170170
autoResponseText?: string,
171171
autoResponseDelay?: number,
172172
onSend?: (content: string, messages: ChatMessage[]) => void,
173-
className?: string
173+
className?: string,
174+
// AI / service-ai integration fields
175+
api?: string,
176+
conversationId?: string,
177+
systemPrompt?: string,
178+
model?: string,
179+
streamingEnabled?: boolean,
180+
headers?: Record<string, string>,
181+
body?: Record<string, unknown>,
182+
maxToolRoundtrips?: number,
183+
onError?: (error: Error) => void,
174184
}
175185
```
176186

@@ -179,11 +189,12 @@ const schema = {
179189
```plaintext
180190
{
181191
id: string,
182-
role: 'user' | 'assistant' | 'system',
192+
role: 'user' | 'assistant' | 'system' | 'tool',
183193
content: string,
184-
timestamp?: string,
185-
avatar?: string,
186-
avatarFallback?: string
194+
timestamp?: string | Date,
195+
metadata?: any,
196+
streaming?: boolean,
197+
toolInvocations?: ChatToolInvocation[],
187198
}
188199
```
189200

@@ -200,11 +211,53 @@ const schema = {
200211
| `assistantAvatarUrl` | string | - | URL for assistant avatar image |
201212
| `assistantAvatarFallback` | string | `'AI'` | Fallback text for assistant avatar |
202213
| `maxHeight` | string | `'500px'` | Maximum chat container height |
203-
| `autoResponse` | boolean | `false` | Enable auto-response (demo mode) |
214+
| `autoResponse` | boolean | `false` | Enable auto-response (demo mode, ignored when `api` is set) |
204215
| `autoResponseText` | string | - | Text for auto-response |
205216
| `autoResponseDelay` | number | `1000` | Delay before auto-response (ms) |
206217
| `onSend` | function | - | Callback when message is sent |
207218
| `className` | string | `''` | Additional Tailwind CSS classes |
219+
| `api` | string | - | Backend SSE endpoint (e.g., `/api/v1/ai/chat`). Enables AI streaming mode |
220+
| `conversationId` | string | - | Multi-turn conversation identifier |
221+
| `systemPrompt` | string | - | System prompt to configure assistant behavior |
222+
| `model` | string | - | AI model identifier (e.g., `gpt-4o`) |
223+
| `streamingEnabled` | boolean | `true` | Enable SSE streaming for AI responses |
224+
| `headers` | object | - | Additional headers for API requests |
225+
| `body` | object | - | Additional body params for API requests |
226+
| `maxToolRoundtrips` | number | `5` | Max tool-calling round-trips per message |
227+
| `onError` | function | - | Error callback for streaming/API errors |
228+
229+
## Operating Modes
230+
231+
The chatbot supports two modes, automatically selected based on the `api` field:
232+
233+
### Local/Demo Mode (default)
234+
235+
When `api` is not set, the chatbot operates in local mode with optional auto-response:
236+
237+
```tsx
238+
const schema = {
239+
type: 'chatbot',
240+
messages: [...],
241+
autoResponse: true,
242+
autoResponseText: 'Thanks!',
243+
autoResponseDelay: 1000,
244+
};
245+
```
246+
247+
### AI Streaming Mode (service-ai)
248+
249+
When `api` is set, the chatbot uses `@ai-sdk/react` for real SSE streaming:
250+
251+
```tsx
252+
const schema = {
253+
type: 'chatbot',
254+
api: '/api/v1/ai/chat',
255+
model: 'gpt-4o',
256+
systemPrompt: 'You are a helpful assistant.',
257+
streamingEnabled: true,
258+
messages: [],
259+
};
260+
```
208261

209262
## Message Roles
210263

@@ -246,6 +299,27 @@ System messages appear centered with muted styling:
246299
}
247300
```
248301

302+
### Tool Messages (AI Mode)
303+
304+
Tool messages represent results from tool invocations during AI streaming. They are generated automatically by the vercel/ai SDK when the backend performs tool calls (e.g., fetching weather, querying a database). The SDK may emit `role: 'tool'` messages as well as populate the assistant message's `toolInvocations` array. In the current chat UI, any non-`user` role (including `tool`) is rendered as an assistant bubble, so if you do not want raw tool messages to appear you should filter them out before rendering and instead rely on the assistant message's `toolInvocations`:
305+
306+
```tsx
307+
{
308+
id: '4',
309+
role: 'assistant',
310+
content: 'The weather in SF is 68°F.',
311+
toolInvocations: [
312+
{
313+
toolCallId: 'tc-1',
314+
toolName: 'getWeather',
315+
args: { city: 'San Francisco' },
316+
result: { temp: 68, condition: 'Sunny' },
317+
state: 'result',
318+
}
319+
]
320+
}
321+
```
322+
249323
## Examples
250324

251325
### Simple AI Chat
@@ -445,8 +519,10 @@ const schema = {
445519
## TypeScript Support
446520

447521
```plaintext
448-
import type { ChatbotSchema, ChatMessage } from '@object-ui/types'
522+
import type { ChatbotSchema, ChatMessage, ChatToolInvocation } from '@object-ui/types'
523+
import { useObjectChat } from '@object-ui/plugin-chatbot'
449524
525+
// Basic messages
450526
const messages: ChatMessage[] = [
451527
{
452528
id: '1',
@@ -455,12 +531,24 @@ const messages: ChatMessage[] = [
455531
}
456532
]
457533
458-
const chatbotSchema: ChatbotSchema = {
534+
// Local/demo mode
535+
const demoSchema: ChatbotSchema = {
459536
type: 'chatbot',
460537
messages,
461538
placeholder: 'Type here...',
462539
showTimestamp: true
463540
}
541+
542+
// AI streaming mode (service-ai)
543+
const aiSchema: ChatbotSchema = {
544+
type: 'chatbot',
545+
messages: [],
546+
api: '/api/v1/ai/chat',
547+
model: 'gpt-4o',
548+
systemPrompt: 'You are a helpful assistant.',
549+
streamingEnabled: true,
550+
conversationId: 'conv-123',
551+
}
464552
```
465553

466554
## Related Documentation

packages/components/src/stories-json/chatbot.stories.tsx

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,3 +246,104 @@ export const StreamingResponse: Story = {
246246
className: 'w-full max-w-2xl'
247247
} as any,
248248
};
249+
250+
// ============================================================================
251+
// AI SDUI Mode Stories (service-ai integration)
252+
// ============================================================================
253+
254+
/**
255+
* AI Streaming Mode - demonstrates schema config for service-ai backend.
256+
* In production, set `api` to your service-ai endpoint.
257+
* Without a real backend, this falls back to local auto-response.
258+
*/
259+
export const AIStreamingMode: Story = {
260+
render: renderStory,
261+
args: {
262+
type: 'chatbot',
263+
messages: [
264+
{
265+
id: 'welcome',
266+
role: 'assistant',
267+
content: 'Hello! I\'m your AI assistant powered by service-ai. Ask me anything!',
268+
}
269+
],
270+
placeholder: 'Ask the AI assistant...',
271+
enableMarkdown: true,
272+
showTimestamp: false,
273+
// AI SDUI fields — in production, set api to your endpoint:
274+
// api: '/api/v1/ai/chat',
275+
// model: 'gpt-4o',
276+
// systemPrompt: 'You are a helpful assistant.',
277+
// streamingEnabled: true,
278+
// Fallback to auto-response for demo:
279+
autoResponse: true,
280+
autoResponseText: 'This is a demo response. In production, connect `api` to your service-ai endpoint for real streaming.',
281+
autoResponseDelay: 800,
282+
className: 'w-full max-w-2xl'
283+
} as any,
284+
};
285+
286+
/**
287+
* AI Chat with system prompt and model config.
288+
*/
289+
export const AIWithSystemPrompt: Story = {
290+
render: renderStory,
291+
args: {
292+
type: 'chatbot',
293+
messages: [
294+
{
295+
id: 'system-1',
296+
role: 'system',
297+
content: 'You are a customer support agent for Acme Inc.',
298+
},
299+
{
300+
id: 'welcome',
301+
role: 'assistant',
302+
content: 'Welcome to Acme Support! How can I help you today?',
303+
}
304+
],
305+
placeholder: 'Describe your issue...',
306+
enableMarkdown: true,
307+
showTimestamp: true,
308+
systemPrompt: 'You are a customer support agent for Acme Inc. Be helpful and professional.',
309+
model: 'gpt-4o',
310+
autoResponse: true,
311+
autoResponseText: 'Thank you for contacting Acme Support. I\'m looking into your request.',
312+
autoResponseDelay: 1200,
313+
className: 'w-full max-w-2xl'
314+
} as any,
315+
};
316+
317+
/**
318+
* AI Chat including tool invocation metadata in messages.
319+
*/
320+
export const AIWithToolCalls: Story = {
321+
render: renderStory,
322+
args: {
323+
type: 'chatbot',
324+
messages: [
325+
{
326+
id: '1',
327+
role: 'user',
328+
content: 'What\'s the weather in San Francisco?',
329+
},
330+
{
331+
id: '2',
332+
role: 'assistant',
333+
content: 'The weather in San Francisco is currently 68°F with partly cloudy skies.',
334+
toolInvocations: [
335+
{
336+
toolCallId: 'tc-1',
337+
toolName: 'getWeather',
338+
args: { city: 'San Francisco' },
339+
result: { temp: 68, condition: 'Partly cloudy' },
340+
state: 'result',
341+
}
342+
],
343+
}
344+
],
345+
placeholder: 'Ask about weather, stocks, or more...',
346+
enableMarkdown: true,
347+
className: 'w-full max-w-2xl'
348+
} as any,
349+
};

0 commit comments

Comments
 (0)