@tailor-platform/app-shell 1.19.0 → 1.20.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/dist/app-shell-core.css +2 -2
- package/dist/app-shell.d.ts +807 -130
- package/dist/app-shell.js +12419 -10930
- package/dist/{appshell-DQTz-QwK.js → appshell-B4QkQvXF.js} +377 -360
- package/dist/fonts/inter.css +7 -7
- package/dist/fonts/noto-sans-jp.css +116 -116
- package/dist/testing.d.ts +119 -89
- package/dist/testing.js +1 -1
- package/dist/vite-plugin.d.ts +119 -89
- package/package.json +10 -8
- package/skills/app-shell-patterns/SKILL.md +4 -3
- package/skills/app-shell-patterns/references/api/create-ai-gateway-client.md +32 -2
- package/skills/app-shell-patterns/references/api/define-module.md +5 -5
- package/skills/app-shell-patterns/references/api/router/use-params.md +2 -2
- package/skills/app-shell-patterns/references/api/use-ai-chat.md +46 -8
- package/skills/app-shell-patterns/references/api/use-app-shell-config.md +4 -4
- package/skills/app-shell-patterns/references/api/use-app-shell-data.md +5 -5
- package/skills/app-shell-patterns/references/api/use-app-shell.md +2 -2
- package/skills/app-shell-patterns/references/api/use-auth.md +3 -3
- package/skills/app-shell-patterns/references/api/use-route-error.md +12 -12
- package/skills/app-shell-patterns/references/components/action-panel.md +4 -2
- package/skills/app-shell-patterns/references/components/activity-card.md +3 -3
- package/skills/app-shell-patterns/references/components/ai-chat.md +37 -3
- package/skills/app-shell-patterns/references/components/app-shell.md +6 -5
- package/skills/app-shell-patterns/references/components/card.md +2 -2
- package/skills/app-shell-patterns/references/components/data-table.md +87 -31
- package/skills/app-shell-patterns/references/components/date-picker.md +2 -2
- package/skills/app-shell-patterns/references/components/default-sidebar.md +2 -2
- package/skills/app-shell-patterns/references/components/dialog.md +8 -0
- package/skills/app-shell-patterns/references/components/filter-rail.md +10 -3
- package/skills/app-shell-patterns/references/components/form.md +5 -5
- package/skills/app-shell-patterns/references/components/global-header-layout.md +31 -8
- package/skills/app-shell-patterns/references/components/layout.md +24 -17
- package/skills/app-shell-patterns/references/components/select.md +8 -0
- package/skills/app-shell-patterns/references/components/sidebar-group.md +9 -7
- package/skills/app-shell-patterns/references/components/sidebar-layout.md +74 -11
- package/skills/app-shell-patterns/references/components/sidebar-section.md +8 -8
- package/skills/app-shell-patterns/references/components/tabs.md +32 -2
- package/skills/app-shell-patterns/references/components/tree.md +342 -0
- package/skills/app-shell-patterns/references/components/with-guard.md +5 -5
- package/skills/app-shell-patterns/references/concepts/authentication.md +1 -1
- package/skills/app-shell-patterns/references/concepts/routing-navigation.md +3 -3
- package/skills/app-shell-patterns/references/concepts/styling-theming.md +13 -13
- package/skills/app-shell-patterns/references/migrations.md +20 -0
- package/skills/app-shell-patterns/references/pages/document-detail.md +8 -12
- package/skills/app-shell-patterns/references/patterns/interaction-multi-select.md +1 -1
|
@@ -182,7 +182,7 @@ function ProductEdit() {
|
|
|
182
182
|
|
|
183
183
|
return (
|
|
184
184
|
<form>
|
|
185
|
-
<h1>Edit Product {id}</h1>
|
|
185
|
+
<Text.h1>Edit Product {id}</Text.h1>
|
|
186
186
|
{/* form fields */}
|
|
187
187
|
</form>
|
|
188
188
|
);
|
|
@@ -203,7 +203,7 @@ function DeleteConfirmation() {
|
|
|
203
203
|
|
|
204
204
|
return (
|
|
205
205
|
<div>
|
|
206
|
-
<p>Delete product {id}?</p>
|
|
206
|
+
<Text.p>Delete product {id}?</Text.p>
|
|
207
207
|
<button onClick={handleDelete}>Confirm</button>
|
|
208
208
|
</div>
|
|
209
209
|
);
|
|
@@ -1,19 +1,24 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: useAIChat
|
|
3
|
-
description:
|
|
3
|
+
description: AI Gateway chat hook with optional local tools
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
<!-- GENERATED by docs-kit from docs-src/hooks/use-ai-chat.docs.outline.md — do not edit by hand. -->
|
|
7
7
|
|
|
8
8
|
# useAIChat
|
|
9
9
|
|
|
10
|
-
React hook for
|
|
10
|
+
React hook for AI Gateway chat on top of `createAIGatewayClient`, with optional local tool support.
|
|
11
11
|
|
|
12
12
|
## Signature
|
|
13
13
|
|
|
14
14
|
```typescript
|
|
15
|
-
const useAIChat: (config: {
|
|
15
|
+
const useAIChat: (config: {
|
|
16
|
+
client: AIGatewayClient;
|
|
17
|
+
model: string;
|
|
18
|
+
tools?: Record<string, AILocalTool>;
|
|
19
|
+
}) => {
|
|
16
20
|
messages: AIChatMessage[];
|
|
21
|
+
toolCalls: { id: string; name: string }[];
|
|
17
22
|
status: "ready" | "submitted" | "streaming" | "error";
|
|
18
23
|
error?: Error;
|
|
19
24
|
sendMessage: (message: string) => Promise<boolean>;
|
|
@@ -33,10 +38,17 @@ interface AIChatMessage {
|
|
|
33
38
|
}
|
|
34
39
|
```
|
|
35
40
|
|
|
41
|
+
### `toolCalls`
|
|
42
|
+
|
|
43
|
+
- **Type:** `{ id: string; name: string }[]`
|
|
44
|
+
- **Description:** Tool calls requested by the model in the active flow, including earlier tool rounds of the current request. This transient list is cleared when the response finishes, is stopped, or fails; it is never added to `messages` or conversation history.
|
|
45
|
+
|
|
46
|
+
Calls become available before local tool execution. They record requested tool names, not successful execution. Arguments and results remain internal.
|
|
47
|
+
|
|
36
48
|
### `status`
|
|
37
49
|
|
|
38
50
|
- **Type:** `"ready" | "submitted" | "streaming" | "error"`
|
|
39
|
-
- **Description:** Current request state
|
|
51
|
+
- **Description:** Current request state. `submitted` covers waiting for the first text, local tool execution, and waiting for the model's next reply after a tool result. `streaming` begins when text arrives. `AIChat.Conversation` automatically shows a waiting indicator while `submitted`.
|
|
40
52
|
|
|
41
53
|
### `error`
|
|
42
54
|
|
|
@@ -54,10 +66,20 @@ interface AIChatMessage {
|
|
|
54
66
|
- **Type:** `() => void`
|
|
55
67
|
- **Description:** Aborts the current request if one is in progress
|
|
56
68
|
|
|
69
|
+
### `tools`
|
|
70
|
+
|
|
71
|
+
Register local tools under a single object using `defineAIChatTool(...)`. Their schemas must implement both [Standard Schema](https://standardschema.dev/) validation and Standard JSON Schema generation (for example, Zod 4). Provider-native tools are not supported.
|
|
72
|
+
|
|
57
73
|
## Usage
|
|
58
74
|
|
|
59
75
|
```tsx
|
|
60
|
-
import {
|
|
76
|
+
import {
|
|
77
|
+
createAuthClient,
|
|
78
|
+
createAIGatewayClient,
|
|
79
|
+
defineAIChatTool,
|
|
80
|
+
useAIChat,
|
|
81
|
+
} from "@tailor-platform/app-shell";
|
|
82
|
+
import { z } from "zod/v4";
|
|
61
83
|
|
|
62
84
|
const authClient = createAuthClient({
|
|
63
85
|
clientId: "your-client-id",
|
|
@@ -69,10 +91,23 @@ const aiClient = createAIGatewayClient({
|
|
|
69
91
|
authClient,
|
|
70
92
|
});
|
|
71
93
|
|
|
94
|
+
const lookupCustomer = defineAIChatTool({
|
|
95
|
+
description: "Look up a customer in the current workspace",
|
|
96
|
+
schema: z.object({
|
|
97
|
+
customerId: z.string(),
|
|
98
|
+
}),
|
|
99
|
+
async execute({ customerId }) {
|
|
100
|
+
return { customerId, name: "Acme Corp" };
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
|
|
72
104
|
export function ChatScreen() {
|
|
73
|
-
const { messages, sendMessage, status, stop, error } = useAIChat({
|
|
105
|
+
const { messages, toolCalls, sendMessage, status, stop, error } = useAIChat({
|
|
74
106
|
client: aiClient,
|
|
75
107
|
model: "gpt-5-mini",
|
|
108
|
+
tools: {
|
|
109
|
+
lookupCustomer,
|
|
110
|
+
},
|
|
76
111
|
});
|
|
77
112
|
|
|
78
113
|
return (
|
|
@@ -82,6 +117,9 @@ export function ChatScreen() {
|
|
|
82
117
|
{message.role}: {message.content}
|
|
83
118
|
</div>
|
|
84
119
|
))}
|
|
120
|
+
{toolCalls.map((call) => (
|
|
121
|
+
<div key={call.id}>Tool call: {call.name}</div>
|
|
122
|
+
))}
|
|
85
123
|
|
|
86
124
|
<button
|
|
87
125
|
onClick={() => void sendMessage("Hello")}
|
|
@@ -101,9 +139,9 @@ export function ChatScreen() {
|
|
|
101
139
|
## Notes
|
|
102
140
|
|
|
103
141
|
- AppShell chooses the appropriate AI Gateway transport automatically
|
|
104
|
-
-
|
|
142
|
+
- Public messages stay user/assistant text-first; tool calls and results never become conversation messages
|
|
105
143
|
- System prompts and custom history shaping should use the low-level client directly
|
|
106
|
-
- `stop()` keeps
|
|
144
|
+
- `stop()` keeps already-streamed assistant text, clears the active `toolCalls`, and ignores late events from the stopped request
|
|
107
145
|
|
|
108
146
|
## Related
|
|
109
147
|
|
|
@@ -56,15 +56,15 @@ const useAppShellConfig: () => {
|
|
|
56
56
|
### Display App Info
|
|
57
57
|
|
|
58
58
|
```typescript
|
|
59
|
-
import { useAppShellConfig } from "@tailor-platform/app-shell";
|
|
59
|
+
import { Text, useAppShellConfig } from "@tailor-platform/app-shell";
|
|
60
60
|
|
|
61
61
|
function AppInfo() {
|
|
62
62
|
const { title, configurations } = useAppShellConfig();
|
|
63
63
|
|
|
64
64
|
return (
|
|
65
65
|
<div>
|
|
66
|
-
<h2>{title}</h2>
|
|
67
|
-
<p>Base: {configurations.basePath}</p>
|
|
66
|
+
<Text.h2>{title}</Text.h2>
|
|
67
|
+
<Text.p>Base: {configurations.basePath}</Text.p>
|
|
68
68
|
</div>
|
|
69
69
|
);
|
|
70
70
|
}
|
|
@@ -96,7 +96,7 @@ function SettingsMenu() {
|
|
|
96
96
|
|
|
97
97
|
return (
|
|
98
98
|
<div>
|
|
99
|
-
<h3>Settings</h3>
|
|
99
|
+
<Text.h3>Settings</Text.h3>
|
|
100
100
|
{configurations.settingsResources.map((resource) => (
|
|
101
101
|
<button key={resource.path}>{resource.path}</button>
|
|
102
102
|
))}
|
|
@@ -28,15 +28,15 @@ const useAppShellData: () => {
|
|
|
28
28
|
### Basic Access
|
|
29
29
|
|
|
30
30
|
```typescript
|
|
31
|
-
import { useAppShellData } from "@tailor-platform/app-shell";
|
|
31
|
+
import { Text, useAppShellData } from "@tailor-platform/app-shell";
|
|
32
32
|
|
|
33
33
|
function UserProfile() {
|
|
34
34
|
const { contextData } = useAppShellData();
|
|
35
35
|
|
|
36
36
|
return (
|
|
37
37
|
<div>
|
|
38
|
-
<p>Welcome, {contextData.currentUser?.name}</p>
|
|
39
|
-
<p>Role: {contextData.currentUser?.role}</p>
|
|
38
|
+
<Text.p>Welcome, {contextData.currentUser?.name}</Text.p>
|
|
39
|
+
<Text.p>Role: {contextData.currentUser?.role}</Text.p>
|
|
40
40
|
</div>
|
|
41
41
|
);
|
|
42
42
|
}
|
|
@@ -54,8 +54,8 @@ function UserInfo() {
|
|
|
54
54
|
|
|
55
55
|
return (
|
|
56
56
|
<div>
|
|
57
|
-
<h2>{contextData.currentUser.name}</h2>
|
|
58
|
-
<p>{contextData.currentUser.email}</p>
|
|
57
|
+
<Text.h2>{contextData.currentUser.name}</Text.h2>
|
|
58
|
+
<Text.p>{contextData.currentUser.email}</Text.p>
|
|
59
59
|
</div>
|
|
60
60
|
);
|
|
61
61
|
}
|
|
@@ -120,8 +120,8 @@ function UserInfo() {
|
|
|
120
120
|
|
|
121
121
|
return (
|
|
122
122
|
<div>
|
|
123
|
-
<h2>{contextData.currentUser.name}</h2>
|
|
124
|
-
<p>{contextData.currentUser.email}</p>
|
|
123
|
+
<Text.h2>{contextData.currentUser.name}</Text.h2>
|
|
124
|
+
<Text.p>{contextData.currentUser.email}</Text.p>
|
|
125
125
|
</div>
|
|
126
126
|
);
|
|
127
127
|
}
|
|
@@ -59,7 +59,7 @@ const useAuth: () => {
|
|
|
59
59
|
### Basic Authentication Flow
|
|
60
60
|
|
|
61
61
|
```typescript
|
|
62
|
-
import { useAuth } from "@tailor-platform/app-shell";
|
|
62
|
+
import { Text, useAuth } from "@tailor-platform/app-shell";
|
|
63
63
|
|
|
64
64
|
function MyComponent() {
|
|
65
65
|
const { isAuthenticated, isReady, login, logout } = useAuth();
|
|
@@ -74,7 +74,7 @@ function MyComponent() {
|
|
|
74
74
|
|
|
75
75
|
return (
|
|
76
76
|
<div>
|
|
77
|
-
<p>You are logged in!</p>
|
|
77
|
+
<Text.p>You are logged in!</Text.p>
|
|
78
78
|
<button onClick={logout}>Log Out</button>
|
|
79
79
|
</div>
|
|
80
80
|
);
|
|
@@ -108,7 +108,7 @@ function AuthStatus() {
|
|
|
108
108
|
if (error) {
|
|
109
109
|
return (
|
|
110
110
|
<div>
|
|
111
|
-
<p>Authentication failed: {error}</p>
|
|
111
|
+
<Text.p>Authentication failed: {error}</Text.p>
|
|
112
112
|
<button onClick={login}>Retry</button>
|
|
113
113
|
</div>
|
|
114
114
|
);
|
|
@@ -26,7 +26,7 @@ const useRouteError: () => unknown;
|
|
|
26
26
|
### Basic Error Boundary
|
|
27
27
|
|
|
28
28
|
```typescript
|
|
29
|
-
import { useRouteError } from "@tailor-platform/app-shell";
|
|
29
|
+
import { Text, useRouteError } from "@tailor-platform/app-shell";
|
|
30
30
|
|
|
31
31
|
function ErrorBoundary() {
|
|
32
32
|
const error = useRouteError();
|
|
@@ -37,8 +37,8 @@ function ErrorBoundary() {
|
|
|
37
37
|
|
|
38
38
|
return (
|
|
39
39
|
<div>
|
|
40
|
-
<h1>Something went wrong</h1>
|
|
41
|
-
<p>{message}</p>
|
|
40
|
+
<Text.h1>Something went wrong</Text.h1>
|
|
41
|
+
<Text.p>{message}</Text.p>
|
|
42
42
|
<button onClick={() => window.location.reload()}>
|
|
43
43
|
Try Again
|
|
44
44
|
</button>
|
|
@@ -79,7 +79,7 @@ const productsModule = defineModule({
|
|
|
79
79
|
### Advanced Error Handling
|
|
80
80
|
|
|
81
81
|
```typescript
|
|
82
|
-
import { isRouteErrorResponse, useRouteError } from "@tailor-platform/app-shell";
|
|
82
|
+
import { isRouteErrorResponse, Text, useRouteError } from "@tailor-platform/app-shell";
|
|
83
83
|
|
|
84
84
|
function ErrorBoundary() {
|
|
85
85
|
const error = useRouteError();
|
|
@@ -88,8 +88,8 @@ function ErrorBoundary() {
|
|
|
88
88
|
if (isRouteErrorResponse(error)) {
|
|
89
89
|
return (
|
|
90
90
|
<div>
|
|
91
|
-
<h1>{error.status} {error.statusText}</h1>
|
|
92
|
-
<p>{error.data}</p>
|
|
91
|
+
<Text.h1>{error.status} {error.statusText}</Text.h1>
|
|
92
|
+
<Text.p>{error.data}</Text.p>
|
|
93
93
|
</div>
|
|
94
94
|
);
|
|
95
95
|
}
|
|
@@ -98,8 +98,8 @@ function ErrorBoundary() {
|
|
|
98
98
|
if (error instanceof Error) {
|
|
99
99
|
return (
|
|
100
100
|
<div>
|
|
101
|
-
<h1>Error</h1>
|
|
102
|
-
<p>{error.message}</p>
|
|
101
|
+
<Text.h1>Error</Text.h1>
|
|
102
|
+
<Text.p>{error.message}</Text.p>
|
|
103
103
|
<pre>{error.stack}</pre>
|
|
104
104
|
</div>
|
|
105
105
|
);
|
|
@@ -108,8 +108,8 @@ function ErrorBoundary() {
|
|
|
108
108
|
// Handle unknown errors
|
|
109
109
|
return (
|
|
110
110
|
<div>
|
|
111
|
-
<h1>Unknown Error</h1>
|
|
112
|
-
<p>Something went wrong</p>
|
|
111
|
+
<Text.h1>Unknown Error</Text.h1>
|
|
112
|
+
<Text.p>Something went wrong</Text.p>
|
|
113
113
|
</div>
|
|
114
114
|
);
|
|
115
115
|
}
|
|
@@ -129,8 +129,8 @@ function ErrorBoundary() {
|
|
|
129
129
|
|
|
130
130
|
return (
|
|
131
131
|
<div>
|
|
132
|
-
<h1>Error</h1>
|
|
133
|
-
<p>We've been notified and will fix this soon.</p>
|
|
132
|
+
<Text.h1>Error</Text.h1>
|
|
133
|
+
<Text.p>We've been notified and will fix this soon.</Text.p>
|
|
134
134
|
</div>
|
|
135
135
|
);
|
|
136
136
|
}
|
|
@@ -94,8 +94,10 @@ function CustomEmptyContent() {
|
|
|
94
94
|
actions={[]}
|
|
95
95
|
emptyContent={
|
|
96
96
|
<div>
|
|
97
|
-
<p>利用可能な操作はありません</p>
|
|
98
|
-
<p
|
|
97
|
+
<Text.p className="text-muted-foreground">利用可能な操作はありません</Text.p>
|
|
98
|
+
<Text.p className="text-muted-foreground">
|
|
99
|
+
ステータスが変わると、操作が表示されます。
|
|
100
|
+
</Text.p>
|
|
99
101
|
</div>
|
|
100
102
|
}
|
|
101
103
|
/>
|
|
@@ -105,7 +105,7 @@ import { ActivityCard, type ActivityCardBaseItem } from "@tailor-platform/app-sh
|
|
|
105
105
|
### Example
|
|
106
106
|
|
|
107
107
|
```tsx
|
|
108
|
-
import { ActivityCard, type ActivityCardBaseItem } from "@tailor-platform/app-shell";
|
|
108
|
+
import { ActivityCard, Text, type ActivityCardBaseItem } from "@tailor-platform/app-shell";
|
|
109
109
|
|
|
110
110
|
interface MyItem extends ActivityCardBaseItem {
|
|
111
111
|
kind: "approval" | "update";
|
|
@@ -123,11 +123,11 @@ const items: MyItem[] = [
|
|
|
123
123
|
{(item) =>
|
|
124
124
|
item.kind === "approval" ? (
|
|
125
125
|
<ActivityCard.Item indicator={<ApprovedIcon />}>
|
|
126
|
-
<p>{item.label}</p>
|
|
126
|
+
<Text.p>{item.label}</Text.p>
|
|
127
127
|
</ActivityCard.Item>
|
|
128
128
|
) : (
|
|
129
129
|
<ActivityCard.Item>
|
|
130
|
-
<p>{item.message}</p>
|
|
130
|
+
<Text.p>{item.message}</Text.p>
|
|
131
131
|
</ActivityCard.Item>
|
|
132
132
|
)
|
|
133
133
|
}
|
|
@@ -84,6 +84,17 @@ Other props spread onto the root `<div>`.
|
|
|
84
84
|
|
|
85
85
|
Other props spread onto the region's outer `<div>`.
|
|
86
86
|
|
|
87
|
+
While the root's `status` is `"submitted"`, the conversation automatically appends a [`Spinner`](./spinner.md) and localized “Thinking…” status at the end. This covers the initial reply wait, tool execution, and the next reply wait after a tool result. The indicator disappears when text starts streaming, or when the request finishes, fails, or is stopped. It participates in the conversation's normal auto-scroll behavior; no separate loader state is needed.
|
|
88
|
+
|
|
89
|
+
### `AIChat.ToolCall`
|
|
90
|
+
|
|
91
|
+
A compact label for one model-requested tool call. Each label occupies its own row, so multiple calls stack vertically. It does not imply execution success, render tool arguments/results, or manage history.
|
|
92
|
+
|
|
93
|
+
| Prop | Type | Default | Description |
|
|
94
|
+
| ----------- | ------------------------------ | -------- | ------------------------------------------------ |
|
|
95
|
+
| `call` | `{ id: string; name: string }` | required | A `toolCalls` element returned by `useAIChat()`. |
|
|
96
|
+
| `className` | `string` | - | Merged onto the outer row, not the badge. |
|
|
97
|
+
|
|
87
98
|
### `AIChat.Composer`
|
|
88
99
|
|
|
89
100
|
| Prop | Type | Default | Description |
|
|
@@ -112,17 +123,18 @@ Most props stay inside their region. These `AIChat.Composer` props land on **ano
|
|
|
112
123
|
|
|
113
124
|
`onValueChange` is wrapped rather than forwarded — it is called from the `Textarea`'s `onChange`, and again with `""` after a submit. `defaultValue` seeds the composer's own state and is never forwarded. Nothing on `AIChat`, `AIChat.Header`, or `AIChat.Conversation` reaches another AppShell component.
|
|
114
125
|
|
|
115
|
-
|
|
126
|
+
Four attached parts wrap an AppShell component. They expose only the props the part's job needs rather than inheriting the wrapped component's surface, so its visual treatment is fixed and not yours to change:
|
|
116
127
|
|
|
117
128
|
| Part | Wraps | Accepts | Fixed |
|
|
118
129
|
| ----------------------------------- | ---------------------------------------------------------- | ------------------------------------------------------------- | ---------------------------------- |
|
|
119
130
|
| `AIChat.Suggestion` | [`Button`](./button.md) | `suggestion`, `onSelect`, `className`, `disabled`, `children` | `variant="secondary"`, `size="sm"` |
|
|
120
131
|
| `AIChat.Action` | [`Button`](./button.md) inside a [`Tooltip`](./tooltip.md) | `label`, `onClick`, `className`, `disabled`, `children` | `variant="ghost"`, `size="icon"` |
|
|
121
132
|
| `AIChat.ChainOfThoughtSearchResult` | [`Badge`](./badge.md) | `className`, `children`, `variant` | — |
|
|
133
|
+
| `AIChat.ToolCall` | [`Badge`](./badge.md) | `call`, `className` | `variant="neutral"` |
|
|
122
134
|
|
|
123
135
|
`variant` stays open on `ChainOfThoughtSearchResult` because conveying status is what a `Badge` is for. `AIChat.Action`'s `label` becomes both the accessible name and the tooltip text.
|
|
124
136
|
|
|
125
|
-
|
|
137
|
+
`ToolCall` applies `className` to its outer row, not the inner badge. For `Suggestion`, `Action`, and `ChainOfThoughtSearchResult`, `className` is merged with `cn()`, which is not configured for AppShell's internal prefix, so it cannot reliably override a base utility from the wrapped component. Add properties the component doesn't set, and reach for the wrapped component's own props or variants to change ones it does — see [Styling AppShell components](../concepts/styling-theming.md#styling-appshell-components).
|
|
126
138
|
|
|
127
139
|
## Filling the page
|
|
128
140
|
|
|
@@ -261,6 +273,28 @@ Structured step timeline for agentic turns — the discrete plan being executed,
|
|
|
261
273
|
|
|
262
274
|
`status` is `"complete" | "active" | "pending"`.
|
|
263
275
|
|
|
276
|
+
### Tool calls during the active flow
|
|
277
|
+
|
|
278
|
+
`useAIChat()` returns a transient `toolCalls` list separately from `messages`. Render it with `AIChat.ToolCall` after the message history inside `AIChat.Conversation`:
|
|
279
|
+
|
|
280
|
+
```tsx
|
|
281
|
+
{
|
|
282
|
+
toolCalls.length > 0 ? (
|
|
283
|
+
<AIChat.Message from="assistant">
|
|
284
|
+
{toolCalls.map((call) => (
|
|
285
|
+
<AIChat.ToolCall key={call.id} call={call} />
|
|
286
|
+
))}
|
|
287
|
+
</AIChat.Message>
|
|
288
|
+
) : null;
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Each call renders on its own row, in the order supplied. Labels are localized automatically.
|
|
293
|
+
|
|
294
|
+
The list clears when the response finishes, is stopped, or fails. It does not create tool messages or persist in the conversation log.
|
|
295
|
+
|
|
296
|
+
These names record model requests, not execution success. Tool arguments and results stay internal. Do not infer a `ToolHeader` success or running state from name-only metadata.
|
|
297
|
+
|
|
264
298
|
### Tool
|
|
265
299
|
|
|
266
300
|
Collapsible tool-call card. Maps 1:1 to the AI SDK's tool-part lifecycle, so a streaming loop can update a call in place as parts arrive.
|
|
@@ -279,7 +313,7 @@ Collapsible tool-call card. Maps 1:1 to the AI SDK's tool-part lifecycle, so a s
|
|
|
279
313
|
|
|
280
314
|
### Sources
|
|
281
315
|
|
|
282
|
-
Compact "Used N sources" citation trigger under a grounded answer.
|
|
316
|
+
Compact "Used N sources" citation trigger under a grounded answer. Supply source data from your application; `useAIChat()` does not return citation metadata.
|
|
283
317
|
|
|
284
318
|
```tsx
|
|
285
319
|
<AIChat.Sources>
|
|
@@ -232,14 +232,14 @@ Access the configured timezone in components using [`useTimeZone`](../api/use-ti
|
|
|
232
232
|
- **Description:** Global error boundary component applied to all routes
|
|
233
233
|
|
|
234
234
|
```tsx
|
|
235
|
-
import { useRouteError } from "@tailor-platform/app-shell";
|
|
235
|
+
import { Text, useRouteError } from "@tailor-platform/app-shell";
|
|
236
236
|
|
|
237
237
|
const GlobalErrorBoundary = () => {
|
|
238
238
|
const error = useRouteError() as Error;
|
|
239
239
|
return (
|
|
240
240
|
<div className="p-8">
|
|
241
|
-
<h1 className="
|
|
242
|
-
<p className="text-
|
|
241
|
+
<Text.h1 className="mb-4">Something went wrong</Text.h1>
|
|
242
|
+
<Text.p className="text-danger-text">{error.message}</Text.p>
|
|
243
243
|
</div>
|
|
244
244
|
);
|
|
245
245
|
};
|
|
@@ -432,6 +432,7 @@ import {
|
|
|
432
432
|
SidebarLayout,
|
|
433
433
|
defineModule,
|
|
434
434
|
defineResource,
|
|
435
|
+
Text,
|
|
435
436
|
useRouteError,
|
|
436
437
|
} from "@tailor-platform/app-shell";
|
|
437
438
|
import { Building } from "lucide-react";
|
|
@@ -450,8 +451,8 @@ const ErrorBoundary = () => {
|
|
|
450
451
|
const error = useRouteError() as Error;
|
|
451
452
|
return (
|
|
452
453
|
<div className="p-8">
|
|
453
|
-
<h1
|
|
454
|
-
<p>{error.message}</p>
|
|
454
|
+
<Text.h1>Error</Text.h1>
|
|
455
|
+
<Text.p>{error.message}</Text.p>
|
|
455
456
|
</div>
|
|
456
457
|
);
|
|
457
458
|
};
|
|
@@ -25,7 +25,7 @@ function BasicUsage() {
|
|
|
25
25
|
<Card.Root>
|
|
26
26
|
<Card.Header title="Order Details" description="Summary of order #1234" />
|
|
27
27
|
<Card.Content>
|
|
28
|
-
<p>Content goes here</p>
|
|
28
|
+
<Text.p>Content goes here</Text.p>
|
|
29
29
|
</Card.Content>
|
|
30
30
|
</Card.Root>
|
|
31
31
|
);
|
|
@@ -154,7 +154,7 @@ For a scrollable list, put the overflow on `Card.Content`. Rows supply their own
|
|
|
154
154
|
```tsx
|
|
155
155
|
<Card.Root>
|
|
156
156
|
<Card.Content>
|
|
157
|
-
<p>No header needed for this card.</p>
|
|
157
|
+
<Text.p>No header needed for this card.</Text.p>
|
|
158
158
|
</Card.Content>
|
|
159
159
|
</Card.Root>
|
|
160
160
|
```
|