@hsafa/ui-sdk 0.6.0 → 0.6.2

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.
@@ -16,7 +16,7 @@ Create custom UIs for specific tool calls using the `HsafaUI` prop. Your compone
16
16
  ### Usage Example
17
17
 
18
18
  ```tsx
19
- import { HsafaChat, CustomToolUIRenderProps } from '@hsafa/sdk';
19
+ import { HsafaChat, CustomToolUIRenderProps } from '@hsafa/ui-sdk';
20
20
 
21
21
  // Custom UI component for a tool
22
22
  function ChoiceToolUI({ toolName, toolCallId, input, output, status, addToolResult, ...restInputProps }: CustomToolUIRenderProps & any) {
@@ -123,7 +123,7 @@ Add a persistent component above the chat input (e.g., quick actions, status bar
123
123
  ### Usage Example
124
124
 
125
125
  ```tsx
126
- import { HsafaChat } from '@hsafa/sdk';
126
+ import { HsafaChat } from '@hsafa/ui-sdk';
127
127
 
128
128
  function QuickActions() {
129
129
  const handleQuickAction = (action: string) => {
@@ -264,7 +264,7 @@ function App() {
264
264
  Combining all customizations:
265
265
 
266
266
  ```tsx
267
- import { HsafaChat } from '@hsafa/sdk';
267
+ import { HsafaChat } from '@hsafa/ui-sdk';
268
268
  import { ChoiceToolUI } from './components/ChoiceToolUI';
269
269
  import { QuickActions } from './components/QuickActions';
270
270
 
@@ -303,7 +303,6 @@ All types are exported from the SDK:
303
303
  ```tsx
304
304
  import type {
305
305
  CustomToolUIRenderProps,
306
- CustomEditModalRenderProps,
307
306
  Attachment
308
- } from '@hsafa/sdk';
307
+ } from '@hsafa/ui-sdk';
309
308
  ```
@@ -1,5 +1,8 @@
1
1
  # Dynamic Page Schemas Guide
2
2
 
3
+ > Note: the Dynamic Page subsystem referenced in this document is not present in the current `sdk/src` in this repository.
4
+ > This file is kept for historical/reference purposes only.
5
+
3
6
  This guide explains how to use optional Zod schemas and examples with Dynamic Page component types.
4
7
 
5
8
  ## Overview
@@ -37,22 +37,10 @@ const agent = useHsafaAgent({
37
37
  baseUrl?: string,
38
38
  tools?: Record<string, Function | { tool: Function, executeEachToken?: boolean }>,
39
39
  uiComponents?: Record<string, React.ComponentType>,
40
- dynamicPageTypes?: Array<DynamicPageTypeConfig>,
41
40
  onFinish?: (message: any) => void,
42
41
  onError?: (error: Error) => void,
43
42
  onMessagesChange?: (messages: any[]) => void,
44
43
  initialMessages?: any[],
45
- colors?: {
46
- primaryColor?: string,
47
- backgroundColor?: string,
48
- borderColor?: string,
49
- textColor?: string,
50
- accentColor?: string,
51
- mutedTextColor?: string,
52
- inputBackground?: string,
53
- cardBackground?: string,
54
- hoverBackground?: string,
55
- },
56
44
  });
57
45
  ```
58
46
 
@@ -74,7 +62,6 @@ const agent = useHsafaAgent({
74
62
  | `chatId` | `string` | Current chat ID |
75
63
  | `tools` | `object` | All available tools |
76
64
  | `uiComponents` | `object` | All UI components |
77
- | `dynamicPage` | `object \| null` | Dynamic page operations |
78
65
  | `formHostRef` | `React.MutableRefObject` | Form host elements ref |
79
66
  | `formStateRef` | `React.MutableRefObject` | Form state ref |
80
67
  | `cleanupForms()` | `() => void` | Cleanup all forms |
@@ -19,7 +19,7 @@ The Hsafa SDK provides headless hooks that let you build completely custom chat
19
19
  Here's the simplest example of using the headless API:
20
20
 
21
21
  ```tsx
22
- import { useHsafaAgent } from '@hsafa/sdk';
22
+ import { useHsafaAgent } from '@hsafa/ui-sdk';
23
23
 
24
24
  function MyCustomChat() {
25
25
  const agent = useHsafaAgent({
@@ -67,7 +67,7 @@ function MyCustomChat() {
67
67
  The main hook that provides all agent functionality.
68
68
 
69
69
  ```tsx
70
- import { useHsafaAgent } from '@hsafa/sdk';
70
+ import { useHsafaAgent } from '@hsafa/ui-sdk';
71
71
 
72
72
  const agent = useHsafaAgent({
73
73
  agentId: 'my-agent-id',
@@ -85,26 +85,12 @@ const agent = useHsafaAgent({
85
85
  uiComponents: {
86
86
  MyCustomComponent: ({ data }) => <div>{data.message}</div>,
87
87
  },
88
-
89
- // Optional: Enable dynamic pages
90
- dynamicPageTypes: [
91
- {
92
- type: 'product-catalog',
93
- schema: { /* ... */ },
94
- },
95
- ],
96
-
88
+
97
89
  // Optional: Callbacks
98
90
  onFinish: (message) => console.log('Message finished:', message),
99
91
  onError: (error) => console.error('Error:', error),
100
92
  onMessagesChange: (messages) => console.log('Messages updated:', messages),
101
93
 
102
- // Optional: Theme colors for built-in forms
103
- colors: {
104
- primaryColor: '#3b82f6',
105
- backgroundColor: '#ffffff',
106
- textColor: '#000000',
107
- },
108
94
  });
109
95
 
110
96
  // Access the API
@@ -128,7 +114,7 @@ agent.uiComponents // All UI components
128
114
  Handle file uploads for messages.
129
115
 
130
116
  ```tsx
131
- import { useFileUpload } from '@hsafa/sdk';
117
+ import { useFileUpload } from '@hsafa/ui-sdk';
132
118
 
133
119
  function FileUploadExample() {
134
120
  const agent = useHsafaAgent({ agentId: 'my-agent', baseUrl: 'http://localhost:3000' });
@@ -184,7 +170,7 @@ function FileUploadExample() {
184
170
  Persist and manage chat history.
185
171
 
186
172
  ```tsx
187
- import { useHsafaAgent, useChatStorage } from '@hsafa/sdk';
173
+ import { useHsafaAgent, useChatStorage } from '@hsafa/ui-sdk';
188
174
 
189
175
  function ChatWithHistory() {
190
176
  const agent = useHsafaAgent({ agentId: 'my-agent', baseUrl: 'http://localhost:3000' });
@@ -235,7 +221,7 @@ function ChatWithHistory() {
235
221
  Edit messages and regenerate responses.
236
222
 
237
223
  ```tsx
238
- import { useHsafaAgent, useMessageEditor } from '@hsafa/sdk';
224
+ import { useHsafaAgent, useMessageEditor } from '@hsafa/ui-sdk';
239
225
 
240
226
  function EditableChat() {
241
227
  const agent = useHsafaAgent({ agentId: 'my-agent', baseUrl: 'http://localhost:3000' });
@@ -280,7 +266,7 @@ function EditableChat() {
280
266
  Auto-scroll to bottom during streaming.
281
267
 
282
268
  ```tsx
283
- import { useHsafaAgent, useAutoScroll } from '@hsafa/sdk';
269
+ import { useHsafaAgent, useAutoScroll } from '@hsafa/ui-sdk';
284
270
 
285
271
  function AutoScrollChat() {
286
272
  const agent = useHsafaAgent({ agentId: 'my-agent', baseUrl: 'http://localhost:3000' });
@@ -301,7 +287,7 @@ function AutoScrollChat() {
301
287
  ### Minimal Chat Interface
302
288
 
303
289
  ```tsx
304
- import { useHsafaAgent } from '@hsafa/sdk';
290
+ import { useHsafaAgent } from '@hsafa/ui-sdk';
305
291
 
306
292
  function MinimalChat() {
307
293
  const agent = useHsafaAgent({
@@ -406,7 +392,7 @@ import {
406
392
  useChatStorage,
407
393
  useMessageEditor,
408
394
  useAutoScroll
409
- } from '@hsafa/sdk';
395
+ } from '@hsafa/ui-sdk';
410
396
 
411
397
  function FullFeaturedChat() {
412
398
  const [showHistory, setShowHistory] = useState(false);
@@ -629,7 +615,7 @@ function FullFeaturedChat() {
629
615
  ### Custom Tool Example
630
616
 
631
617
  ```tsx
632
- import { useHsafaAgent } from '@hsafa/sdk';
618
+ import { useHsafaAgent } from '@hsafa/ui-sdk';
633
619
 
634
620
  function ChatWithCustomTools() {
635
621
  const agent = useHsafaAgent({
@@ -677,6 +663,4 @@ See individual hook files for complete TypeScript interfaces:
677
663
 
678
664
  ## Next Steps
679
665
 
680
- - Check out the [Dynamic Pages documentation](./DYNAMIC_PAGE_SCHEMAS.md) for building dynamic UIs
681
- - See the [Tool Development Guide](./TOOL_DEVELOPMENT.md) for creating custom tools
682
666
  - Browse the `/examples` folder for more use cases
@@ -58,13 +58,6 @@ function App() {
58
58
  uiComponents: {
59
59
  CustomCard: ({ data }) => <div>{data.text}</div>
60
60
  },
61
-
62
- // Theme colors for built-in forms
63
- colors: {
64
- primaryColor: '#0ea5e9',
65
- backgroundColor: '#0B0B0F',
66
- textColor: '#EDEEF0',
67
- }
68
61
  });
69
62
 
70
63
  const scrollRef = useAutoScroll<HTMLDivElement>(agent.isLoading);
@@ -258,16 +251,9 @@ const agent = useHsafaAgent({
258
251
 
259
252
  **After:**
260
253
  ```tsx
261
- const agent = useHsafaAgent({
262
- colors: {
263
- primaryColor: '#0ea5e9',
264
- backgroundColor: '#0B0B0F',
265
- textColor: '#EDEEF0',
266
- // ... other colors
267
- }
268
- });
269
-
270
- // Then apply these colors in your own styling
254
+ // In headless mode, you control styling directly.
255
+ // If you need theme colors, keep them in your app state/theme system and apply them
256
+ // when rendering your custom UI.
271
257
  ```
272
258
 
273
259
  ### 8. Callbacks
@@ -288,29 +274,6 @@ const agent = useHsafaAgent({
288
274
  });
289
275
  ```
290
276
 
291
- ### 9. Dynamic Pages
292
-
293
- **Before:**
294
- ```tsx
295
- <HsafaChat
296
- dynamicPageTypes={[
297
- { type: 'product-catalog', schema: { /* ... */ } }
298
- ]}
299
- />
300
- ```
301
-
302
- **After:**
303
- ```tsx
304
- const agent = useHsafaAgent({
305
- dynamicPageTypes: [
306
- { type: 'product-catalog', schema: { /* ... */ } }
307
- ]
308
- });
309
-
310
- // Access dynamic page operations:
311
- agent.dynamicPage?.getOperations()
312
- ```
313
-
314
277
  ## Common Patterns
315
278
 
316
279
  ### Pattern 1: Minimal Chat
@@ -0,0 +1,441 @@
1
+ # HSAFA UI SDK — Professional Guide
2
+
3
+ This guide is an **authoritative, implementation-aligned** documentation for `@hsafa/ui-sdk` as it exists in this repository.
4
+
5
+ It is written for:
6
+ - Teams embedding **Hsafa Chat** into existing products
7
+ - Teams building a **fully custom UI** around the agent runtime
8
+ - Teams implementing **tool-driven interfaces** (dashboards, builders, maps)
9
+
10
+ ## Scope and sources
11
+
12
+ - **Package**: `@hsafa/ui-sdk` (see `sdk/package.json`)
13
+ - **Public entry point**: `sdk/src/index.ts`
14
+ - **Type signature reference**: `sdk/dist/index.d.ts` (the built build output)
15
+ - **Real integration examples**: `use-cases/rafed-hack` and `use-cases/ksu-agent`
16
+
17
+ > Important: some legacy or experimental docs in `sdk/docs/` and `sdk/docs/api/` may reference APIs not present in the current source. This guide always prefers the current source/export surface.
18
+
19
+ ---
20
+
21
+ # 1) Mental model
22
+
23
+ ## 1.1 Two integration modes
24
+
25
+ - **UI mode (drop-in chat)**
26
+ - Use `HsafaProvider` + `HsafaChat`
27
+ - You get chat UI, streaming, file upload, history UI, message editing, tool rendering
28
+
29
+ - **Headless mode (custom UI)**
30
+ - Use `useHsafaAgent` (+ optionally `useChatStorage`, `useMessageEditor`, `useFileUpload`, `useAutoScroll`)
31
+ - You build the UI yourself (layout, styling, message rendering)
32
+
33
+ Both modes support:
34
+ - **Server-side tools** (tools executed on your server)
35
+ - **Client-side tools** (tools executed in the browser)
36
+ - **Tool-driven UI rendering** (`HsafaUI` / `uiComponents`)
37
+
38
+ ## 1.2 Data flow overview
39
+
40
+ 1. **User types** a prompt (optionally attaches files).
41
+ 2. Client sends `POST {baseUrl}/api/run/:agentId` using the Vercel AI SDK v5 transport.
42
+ 3. Server streams NDJSON events.
43
+ 4. Client renders:
44
+ - assistant text (Markdown)
45
+ - reasoning (optional)
46
+ - tool calls and tool results
47
+ - custom UI for selected tools (via `HsafaUI`)
48
+ 5. If the assistant requests a **client tool**:
49
+ - the SDK executes it in the browser and sends `addToolResult(...)` back into the chat stream.
50
+
51
+ ---
52
+
53
+ # 2) Installation & setup
54
+
55
+ ## 2.1 Install
56
+
57
+ ```bash
58
+ pnpm add @hsafa/ui-sdk
59
+ # or npm i @hsafa/ui-sdk
60
+ ```
61
+
62
+ Peer dependencies:
63
+ - `react >= 18`
64
+ - `react-dom >= 18`
65
+ - `@tabler/icons-react` (some UI pieces rely on icons)
66
+
67
+ ## 2.2 Styles
68
+
69
+ The package exports CSS:
70
+ - `@hsafa/ui-sdk/index.css`
71
+
72
+ If your host app does not already include the SDK styles, import them once near your app root:
73
+
74
+ ```ts
75
+ import '@hsafa/ui-sdk/index.css';
76
+ ```
77
+
78
+ > Some components also bring their own styles from dependencies (e.g. `@ant-design/x-markdown` theme CSS) internally.
79
+
80
+ ---
81
+
82
+ # 3) Quickstart (pre-built chat UI)
83
+
84
+ ## 3.1 Minimal setup
85
+
86
+ ```tsx
87
+ import { HsafaProvider, HsafaChat } from '@hsafa/ui-sdk';
88
+
89
+ export default function App() {
90
+ return (
91
+ <HsafaProvider baseUrl="http://localhost:3900">
92
+ <HsafaChat agentId="YOUR_AGENT_ID" />
93
+ </HsafaProvider>
94
+ );
95
+ }
96
+ ```
97
+
98
+ ## 3.2 `baseUrl` rules
99
+
100
+ - `baseUrl` can be:
101
+ - `""` (same origin)
102
+ - `"https://your-server.example"`
103
+ - `HsafaChat` and `useHsafaAgent` accept a `baseUrl` prop/config.
104
+ - If omitted, they fall back to the provider’s `baseUrl`.
105
+
106
+ ---
107
+
108
+ # 4) Provider: `HsafaProvider` and `useHsafa`
109
+
110
+ Source: `sdk/src/providers/HsafaProvider.tsx`
111
+
112
+ ## 4.1 Responsibilities
113
+
114
+ - Stores SDK defaults: `baseUrl`, `dir`, `theme`
115
+ - Tracks cross-chat state:
116
+ - `isAnyStreaming` (useful for global UI effects)
117
+ - `isAnyChatOpen` (useful for layout adjustments)
118
+ - Exposes `currentChatId` (set by `HsafaChat` / `useHsafaAgent`)
119
+
120
+ ## 4.2 Practical pattern: layout that reacts to chat open/streaming
121
+
122
+ The SDK ships `ContentContainer` which reads provider state and:
123
+ - animates a border during streaming
124
+ - applies margin when chat is open (so your app content is not covered)
125
+
126
+ Source: `sdk/src/components/ContentContainer.tsx`
127
+
128
+ Common usage (as seen in `use-cases/rafed-hack`):
129
+
130
+ ```tsx
131
+ <HsafaProvider baseUrl={AGENT_BASE_URL}>
132
+ <ContentContainer>
133
+ <YourAppRoutes />
134
+ </ContentContainer>
135
+
136
+ <HsafaChat agentId={AGENT_ID} alwaysOpen />
137
+ </HsafaProvider>
138
+ ```
139
+
140
+ ---
141
+
142
+ # 5) `HsafaChat` (UI component)
143
+
144
+ Source: `sdk/src/components/HsafaChat.tsx`
145
+
146
+ ## 5.1 What `HsafaChat` provides
147
+
148
+ - Streaming chat UI (based on `useHsafaAgent`)
149
+ - Attachments (via `useFileUpload`)
150
+ - Chat history (via `useChatStorage`)
151
+ - Message editing (internally + `useMessageEditor`)
152
+ - Tool visualization + custom tool UIs (`HsafaUI`)
153
+ - RTL + Arabic labels
154
+ - Optional full-page mode (`fullPageChat`)
155
+
156
+ ## 5.2 Key props (most used in real apps)
157
+
158
+ From `sdk/src/types/chat.ts`:
159
+ - `agentId: string` (**required**)
160
+ - `baseUrl?: string` (optional override)
161
+ - `HsafaTools?: Record<string, HsafaTool>` (client-side tools)
162
+ - `HsafaUI?: Record<string, React.ComponentType<any>>` (tool rendering)
163
+ - `onMessagesChange?: (messages, chatId?) => void`
164
+ - `onFinish?: (payload) => void`
165
+ - `templateParams?: Record<string, unknown>`
166
+ - UI configuration:
167
+ - `theme`, `dir`, `lang/language`
168
+ - colors: `primaryColor`, `backgroundColor`, ...
169
+ - `title`, `placeholder`, `emptyStateMessage`
170
+ - `presetPrompts`
171
+ - `fullPageChat`
172
+
173
+ ## 5.3 Example: Arabic RTL “full page” chat (from `use-cases/ksu-agent`)
174
+
175
+ - Uses `dir="rtl"` + `language="ar"`
176
+ - Uses `fullPageChat`
177
+ - Provides `presetPrompts` in Arabic
178
+ - Provides `HsafaUI` to render specialized tool results
179
+
180
+ ---
181
+
182
+ # 6) Headless mode: `useHsafaAgent`
183
+
184
+ Source: `sdk/src/hooks/useHsafaAgent.ts`
185
+
186
+ ## 6.1 When to use headless
187
+
188
+ Choose headless mode when you need:
189
+ - full control over layout and component library
190
+ - custom message presentation (timeline, cards, split panes)
191
+ - deep integration with app state / routing
192
+
193
+ ## 6.2 What it returns
194
+
195
+ `useHsafaAgent(config)` returns an API with:
196
+ - **state**: `messages`, `input`, `status`, `isLoading`, `error`, `chatId`
197
+ - **actions**: `setInput`, `sendMessage`, `stop`, `newChat`, `setMessages`, `setChatId`
198
+ - **tool/UI wiring**: `tools`, `uiComponents`, `onUISuccess`, `onUIError`, `cleanupForms`
199
+
200
+ ## 6.3 The transport: `/api/run/:agentId` and `templateParams`
201
+
202
+ The SDK uses `DefaultChatTransport` (from the `ai` package).
203
+
204
+ `createHsafaTransport(baseUrl, agentId, chatId, templateParams)`:
205
+ - posts to `${baseUrl}/api/run/${agentId}`
206
+ - merges `{ ...templateParams, ...body, chatId }` into the request
207
+
208
+ Practical uses for `templateParams`:
209
+ - pass tenant context
210
+ - pass feature flags
211
+ - pass a document id or workspace id
212
+
213
+ ---
214
+
215
+ # 7) Tools: client-side tool execution
216
+
217
+ ## 7.1 Tool types
218
+
219
+ `HsafaTool` (from `sdk/src/types/chat.ts`):
220
+ - `async (input) => output`
221
+ - or `{ tool: async (input) => output, executeEachToken?: boolean }`
222
+
223
+ ## 7.2 `executeEachToken` (streaming-safe tools)
224
+
225
+ If `executeEachToken: true`, the tool may run multiple times as the model streams partial tool inputs.
226
+
227
+ This is used to power:
228
+ - progressive UI feedback (“building component…”, “tool input streaming…”) as seen in the dashboard builder
229
+ - streaming-friendly “patch/merge” tools
230
+
231
+ **Use-case example** (dashboard builder):
232
+ - `create_component` uses `executeEachToken: true`
233
+ - intermediate calls update `componentsUnderLoading` to show placeholders while the model is still deciding
234
+
235
+ ## 7.3 Designing tools (recommended)
236
+
237
+ - Make tools **idempotent** or **merge-based** when streaming.
238
+ - Validate input strictly and return structured errors.
239
+ - Return **human-readable** `message` + structured `data`.
240
+ - Keep side-effects explicit (avoid hidden mutations).
241
+
242
+ ---
243
+
244
+ # 8) Tool UIs: rendering tool calls with `HsafaUI`
245
+
246
+ ## 8.1 How it works
247
+
248
+ - The assistant emits tool parts such as `tool-<name>` or `tool-call`.
249
+ - `AssistantMassage` checks `HsafaUI[toolName]`.
250
+ - If present, it renders your UI component.
251
+
252
+ Source: `sdk/src/components/hsafa-chat/AssistantMassage.tsx`
253
+
254
+ ## 8.2 Props your tool UI receives
255
+
256
+ Your component receives (at minimum):
257
+ - `toolName: string`
258
+ - `toolCallId: string`
259
+ - `input: any`
260
+ - `output: any`
261
+ - `status?: string` (`input-streaming`, `input-available`, `output-available`, ...)
262
+ - `addToolResult?: (payload) => void`
263
+
264
+ ## 8.3 Error handling and reporting
265
+
266
+ Tool UIs render inside `UIErrorBoundary`:
267
+ - errors are caught and shown to the user
268
+ - `onUIError(toolCallId, toolName, error)` is invoked
269
+ - on successful mount, `onUISuccess(toolCallId, toolName)` is invoked
270
+
271
+ This is important if you want to:
272
+ - notify the agent that the UI rendered (continuation)
273
+ - notify the agent that the UI failed (fallback to text)
274
+
275
+ ---
276
+
277
+ # 9) Attachments: `useFileUpload` and `/api/uploads`
278
+
279
+ ## 9.1 Endpoint
280
+
281
+ The SDK expects:
282
+ - `POST {baseUrl}/api/uploads` returning JSON `{ id, name, url, mimeType, size }`
283
+
284
+ ## 9.2 File size
285
+
286
+ The SDK enforces a max file size (25MB) in the client.
287
+
288
+ ---
289
+
290
+ # 10) Persistence: `useChatStorage`
291
+
292
+ Source: `sdk/src/hooks/useChatStorage.ts` + `sdk/src/utils/chat-storage.ts`
293
+
294
+ - Persists chat index + chat messages in `localStorage`
295
+ - Namespaced by `agentId` using keys with prefix `hsafaChat_${agentId}`
296
+
297
+ This is how `HsafaChat` provides chat history without server-side storage.
298
+
299
+ ---
300
+
301
+ # 11) Editing: `useMessageEditor`
302
+
303
+ Source: `sdk/src/hooks/useMessageEditor.ts`
304
+
305
+ Implements:
306
+ - editing a prior user message
307
+ - truncating subsequent messages
308
+ - resending the edited message to regenerate assistant responses
309
+
310
+ Important constraints:
311
+ - editing is blocked while `isLoading`
312
+ - attachment upload during edit requires `baseUrl` (provider or explicit)
313
+
314
+ ---
315
+
316
+ # 12) Markdown rendering: `XMarkdownRenderer`
317
+
318
+ Source: `sdk/src/components/XMarkdownRenderer.tsx`
319
+
320
+ - Uses `@ant-design/x-markdown`
321
+ - Supports streaming animations
322
+ - RTL fixes are applied so Arabic works well
323
+
324
+ Practical usage:
325
+ - You can use it inside custom message UIs, not only inside the built-in chat.
326
+
327
+ ---
328
+
329
+ # 13) Web-controller tools (built-in)
330
+
331
+ Exported from `sdk/src/components/web-controler/*` and included as built-in tools:
332
+ - `getDomComponents`
333
+ - `controlCursor`
334
+ - `fillActiveInput`
335
+ - `requestInput` (special: renders an inline form)
336
+
337
+ These enable “agent controls the UI” demos and automation-like flows.
338
+
339
+ ---
340
+
341
+ # 14) Patterns from `use-cases/` (real-world techniques)
342
+
343
+ This section summarizes *how you used the SDK* and what to copy.
344
+
345
+ ## 14.1 Pattern: split-screen builder + always-open chat
346
+
347
+ Used in `rafed-hack` pages:
348
+ - left/main pane renders your artifact (presentation, infographic, map, dashboard)
349
+ - the chat is always open and acts as the control plane
350
+
351
+ Benefits:
352
+ - user sees changes immediately
353
+ - tool calls become an “execution log”
354
+
355
+ ## 14.2 Pattern: custom `HsafaUI` for “tool call cards”
356
+
357
+ You create a mapping like:
358
+ - `set_presentation_slides` → shows a status card
359
+ - `imageGenerator` → shows a loading card until `imageUrl` appears
360
+ - `set_map_config` / `update_map_config` / `read_map_config` → shows map config state
361
+
362
+ Benefits:
363
+ - tool calls feel like product UI, not debug logs
364
+ - streaming tool status is translated into user-friendly states
365
+
366
+ ## 14.3 Pattern: robust input parsing
367
+
368
+ In tools (`deckglMapTools.ts`, dashboard tools), you apply:
369
+ - `safeParseJSON` to accept either JSON string or object
370
+ - `asRecord`/guards to avoid runtime crashes
371
+
372
+ This is essential because LLM tool inputs are often:
373
+ - strings
374
+ - partially streamed
375
+ - missing optional fields
376
+
377
+ ## 14.4 Pattern: tool validation + warnings
378
+
379
+ In `deckglMapTools.ts` you:
380
+ - validate layer queries (optional `validate` flag)
381
+ - produce warnings for unsupported style fields
382
+
383
+ This is a professional technique:
384
+ - it helps the model self-correct
385
+ - it helps the user trust results
386
+
387
+ ## 14.5 Pattern: streaming-friendly UX (`executeEachToken`)
388
+
389
+ In `DashboardBuilderTools.tsx`:
390
+ - `create_component.executeEachToken = true`
391
+ - intermediate `toolCallNumber` updates `componentsUnderLoading`
392
+
393
+ This produces “AI is building…” UI without waiting for the final tool output.
394
+
395
+ ---
396
+
397
+ # 15) Troubleshooting
398
+
399
+ ## 15.1 Chat does not stream
400
+
401
+ - Confirm your server endpoint is `POST /api/run/:agentId` and streams NDJSON.
402
+ - Confirm CORS if `baseUrl` is cross-origin.
403
+
404
+ ## 15.2 Uploads fail
405
+
406
+ - Confirm endpoint `POST /api/uploads` exists.
407
+ - Confirm returned JSON includes `url`.
408
+
409
+ ## 15.3 My `HsafaUI` component never renders
410
+
411
+ - Ensure your tool name matches exactly (snake_case vs camelCase matters).
412
+ - Check `AssistantMassage.tsx` tool-name normalization rules.
413
+
414
+ ## 15.4 “Dynamic Pages” docs mismatch
415
+
416
+ Some docs reference a dynamic-page subsystem that is not present in the current `sdk/src`. Treat those docs as historical or planned work.
417
+
418
+ ---
419
+
420
+ # 16) Recommended doc map
421
+
422
+ - Start here:
423
+ - `sdk/docs/handbook/01-Quickstart.md`
424
+ - `sdk/docs/handbook/02-Architecture.md`
425
+ - For headless:
426
+ - `sdk/docs/HEADLESS_QUICK_REFERENCE.md`
427
+ - `sdk/docs/HEADLESS_USAGE.md`
428
+ - For custom tool UIs:
429
+ - `sdk/docs/CUSTOM_UI_EXAMPLES.md`
430
+ - For Markdown:
431
+ - `sdk/docs/XMARKDOWN_USAGE.md`
432
+
433
+ ---
434
+
435
+ # 17) Appendix: current public API surface
436
+
437
+ Always verify the current exported surface here:
438
+ - `sdk/src/index.ts`
439
+ - `sdk/dist/index.d.ts`
440
+
441
+ This avoids drift between code and generated docs.