@agent-platform/ui 0.0.4 → 0.0.6

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.
@@ -1,16 +1,16 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { cn } from '../../../lib/utils';
4
- /** Reusable bouncing dots animation */
5
- function BouncingDots() {
6
- return (_jsxs("span", { className: "flex gap-1", "aria-hidden": "true", children: [_jsx("span", { className: "h-1.5 w-1.5 animate-bounce rounded-full bg-muted-foreground [animation-delay:0ms]" }), _jsx("span", { className: "h-1.5 w-1.5 animate-bounce rounded-full bg-muted-foreground [animation-delay:150ms]" }), _jsx("span", { className: "h-1.5 w-1.5 animate-bounce rounded-full bg-muted-foreground [animation-delay:300ms]" })] }));
4
+ /** Reusable loading dots animation */
5
+ function LoadingDots() {
6
+ return (_jsxs("span", { className: "flex gap-0.5", "aria-hidden": "true", children: [_jsx("span", { className: "h-0.5 w-0.5 animate-dot-fade rounded-full bg-muted-foreground/50 [animation-delay:0ms]" }), _jsx("span", { className: "h-0.5 w-0.5 animate-dot-fade rounded-full bg-muted-foreground/50 [animation-delay:150ms]" }), _jsx("span", { className: "h-0.5 w-0.5 animate-dot-fade rounded-full bg-muted-foreground/50 [animation-delay:300ms]" })] }));
7
7
  }
8
8
  export function MessageLoading({ className }) {
9
- return (_jsx("div", { className: cn('flex justify-start', className), role: "status", "aria-label": "AI\u5FDC\u7B54\u3092\u5F85\u6A5F\u4E2D", children: _jsx("div", { className: "max-w-xl", children: _jsxs("div", { className: "rounded-lg border border-border bg-card px-3 py-2", children: [_jsxs("div", { className: "flex it ems-center gap-2", children: [_jsxs("div", { className: "relative flex items-center justify-center", children: [_jsx("div", { className: "absolute h-4 w-4 animate-ping rounded-full bg-primary/20" }), _jsx("div", { className: "relative h-2 w-2 animate-pulse rounded-full bg-primary" })] }), _jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: "text-xs text-muted-foreground", children: "\u8003\u3048\u4E2D" }), _jsx(BouncingDots, {})] })] }), _jsxs("div", { className: "mt-2 space-y-1.5", "aria-hidden": "true", children: [_jsx("div", { className: "h-2.5 w-full animate-shimmer rounded bg-linear-to-r from-muted via-muted-foreground/10 to-muted bg-size-[200%_100%]" }), _jsx("div", { className: "h-2.5 w-3/4 animate-shimmer rounded bg-linear-to-r from-muted via-muted-foreground/10 to-muted bg-size-[200%_100%] [animation-delay:100ms]" }), _jsx("div", { className: "h-2.5 w-1/2 animate-shimmer rounded bg-linear-to-r from-muted via-muted-foreground/10 to-muted bg-size-[200%_100%] [animation-delay:200ms]" })] })] }) }) }));
9
+ return (_jsx("output", { className: cn('flex justify-start', className), "aria-label": "AI\u5FDC\u7B54\u3092\u5F85\u6A5F\u4E2D", children: _jsx("div", { className: "max-w-xl", children: _jsx("div", { className: "rounded-lg border border-border bg-card px-3 py-2", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-sm text-muted-foreground", children: "\u8003\u3048\u4E2D" }), _jsx(LoadingDots, {})] }) }) }) }));
10
10
  }
11
11
  /**
12
12
  * Compact loading indicator for inline use (e.g., inside MessageItem during streaming)
13
13
  */
14
14
  export function ThinkingDots({ className }) {
15
- return (_jsxs("div", { className: cn('flex items-center gap-2', className), role: "status", "aria-label": "\u8003\u3048\u4E2D", children: [_jsx("div", { className: "h-2 w-2 animate-pulse rounded-full bg-primary" }), _jsx(BouncingDots, {})] }));
15
+ return (_jsx("output", { className: cn('flex items-center gap-2', className), "aria-label": "\u8003\u3048\u4E2D", children: _jsx(LoadingDots, {}) }));
16
16
  }
@@ -21,5 +21,5 @@ export function ToolCallCard({ toolCallState, toolNameLabels = {}, statusLabels,
21
21
  ? { ...defaultStatusLabels, ...statusLabels }
22
22
  : defaultStatusLabels;
23
23
  const statusLabel = mergedStatusLabels[status];
24
- return (_jsxs("div", { className: "rounded-md border border-border bg-card p-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-xs font-medium text-foreground", children: toolLabel }), _jsx("span", { className: cn('rounded-full px-1.5 py-0.5 text-[10px]', statusColors[status]), children: statusLabel })] }), status === 'executing' && (_jsx("div", { className: "h-4 w-4 animate-spin rounded-full border-2 border-primary border-t-transparent" })), status === 'completed' && (_jsx(CheckCircle, { className: "size-4 text-green-600", weight: "fill" })), status === 'error' && (_jsx(XCircle, { className: "size-4 text-destructive", weight: "fill" }))] }), _jsxs("details", { className: "mt-2", children: [_jsx("summary", { className: "cursor-pointer text-xs text-muted-foreground", children: parametersLabel }), _jsx("pre", { className: "mt-1 overflow-x-auto rounded bg-muted p-2 text-xs text-muted-foreground", children: JSON.stringify(toolCall.input, null, 2) })] }), status === 'completed' && result !== undefined && (_jsxs("details", { className: "mt-2", children: [_jsx("summary", { className: "cursor-pointer text-xs text-green-600 dark:text-green-400", children: resultLabel }), _jsx("pre", { className: "mt-1 max-h-40 overflow-auto rounded bg-green-50 p-2 text-xs text-muted-foreground dark:bg-green-950", children: typeof result === 'string' ? result : JSON.stringify(result, null, 2) })] })), status === 'error' && error && (_jsx("div", { className: "mt-2 rounded bg-destructive/10 p-2 text-xs text-destructive", children: error }))] }));
24
+ return (_jsxs("div", { className: "rounded-md border border-border bg-card p-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-xs font-medium text-foreground", children: toolLabel }), _jsx("span", { className: cn('rounded-full px-1.5 py-0.5 text-[10px]', statusColors[status]), children: statusLabel })] }), status === 'executing' && (_jsx("div", { className: "h-4 w-4 animate-spin rounded-full border-2 border-primary border-t-transparent" })), status === 'completed' && _jsx(CheckCircle, { className: "size-4 text-green-600", weight: "fill" }), status === 'error' && _jsx(XCircle, { className: "size-4 text-destructive", weight: "fill" })] }), _jsxs("details", { className: "mt-2", children: [_jsx("summary", { className: "cursor-pointer text-xs text-muted-foreground", children: parametersLabel }), _jsx("pre", { className: "mt-1 overflow-x-auto rounded bg-muted p-2 text-xs text-muted-foreground", children: JSON.stringify(toolCall.input, null, 2) })] }), status === 'completed' && result !== undefined && (_jsxs("details", { className: "mt-2", children: [_jsx("summary", { className: "cursor-pointer text-xs text-green-800 dark:text-green-400", children: resultLabel }), _jsx("pre", { className: "mt-1 max-h-40 overflow-auto rounded bg-green-50 p-2 text-xs text-muted-foreground dark:bg-green-950", children: typeof result === 'string' ? result : JSON.stringify(result, null, 2) })] })), status === 'error' && error && (_jsx("div", { className: "mt-2 rounded bg-destructive/10 p-2 text-xs text-destructive", children: error }))] }));
25
25
  }
@@ -3,6 +3,29 @@ import { useCallback, useRef, useState } from 'react';
3
3
  import { parseSSEBuffer } from './parse-sse-buffer';
4
4
  /** クライアントツール自動継続の最大回数 */
5
5
  const MAX_CONTINUE_ROUNDS = 10;
6
+ function isLikelyJwtToken(token) {
7
+ const normalized = token.startsWith('Bearer ') ? token.slice(7) : token;
8
+ return normalized.split('.').length === 3;
9
+ }
10
+ function normalizeErrorMessage(error) {
11
+ if (typeof error === 'string' && error.trim().length > 0)
12
+ return error;
13
+ if (typeof error === 'object' &&
14
+ error !== null &&
15
+ 'message' in error &&
16
+ typeof error.message === 'string') {
17
+ return error.message;
18
+ }
19
+ if (error !== undefined) {
20
+ try {
21
+ return JSON.stringify(error);
22
+ }
23
+ catch {
24
+ return String(error);
25
+ }
26
+ }
27
+ return 'Unknown error';
28
+ }
6
29
  // --- イベントハンドラ ---
7
30
  function handleTextDelta(text, accumulatedText, toolCalls, assistantMessageId, setMessages) {
8
31
  const newText = accumulatedText + text;
@@ -55,7 +78,7 @@ function handleToolResult(tr, serverResolvedToolIds, setPendingToolCalls) {
55
78
  ...state,
56
79
  status: tr.isError ? 'error' : 'completed',
57
80
  result: tr.result,
58
- error: tr.isError ? String(tr.result) : undefined,
81
+ error: tr.isError ? normalizeErrorMessage(tr.result) : undefined,
59
82
  });
60
83
  }
61
84
  return newMap;
@@ -67,7 +90,12 @@ function handleFinish(assistantMessageId, setMessages) {
67
90
  const idx = updated.findIndex((m) => m.id === assistantMessageId);
68
91
  const existing = idx >= 0 ? updated[idx] : undefined;
69
92
  if (existing) {
70
- updated[idx] = { id: existing.id, role: existing.role, content: existing.content, isStreaming: false };
93
+ updated[idx] = {
94
+ id: existing.id,
95
+ role: existing.role,
96
+ content: existing.content,
97
+ isStreaming: false,
98
+ };
71
99
  }
72
100
  return updated;
73
101
  });
@@ -173,6 +201,7 @@ export function useAgentChatInternal(options) {
173
201
  const buildAgentHeaders = useCallback(async () => {
174
202
  const headers = { 'Content-Type': 'application/json' };
175
203
  const token = getAuthToken ? await getAuthToken() : authToken;
204
+ console.log('[buildAgentHeaders] Building headers for agent request: ', token ? 'with auth' : 'no auth');
176
205
  if (token) {
177
206
  headers['Authorization'] = token.startsWith('Bearer ') ? token : `Bearer ${token}`;
178
207
  }
@@ -186,7 +215,8 @@ export function useAgentChatInternal(options) {
186
215
  }
187
216
  return headers;
188
217
  }, [authToken, getAuthToken, getAgentHeaders]);
189
- const handleError = useCallback((errorMessage) => {
218
+ const handleError = useCallback((errorInput) => {
219
+ const errorMessage = normalizeErrorMessage(errorInput);
190
220
  setError(errorMessage);
191
221
  onError?.(errorMessage);
192
222
  }, [onError]);
@@ -255,7 +285,9 @@ export function useAgentChatInternal(options) {
255
285
  const toolApiHeaders = {};
256
286
  if (!disableToolApiAuthHeader) {
257
287
  const token = getAuthToken ? await getAuthToken() : authToken;
258
- if (token) {
288
+ // Tool APIはcredentials: 'include'でCookie送信されるため、
289
+ // 非JWT(例: ANON_KEY)はAuthorizationヘッダーに載せずCookie認証を優先する。
290
+ if (token && isLikelyJwtToken(token)) {
259
291
  toolApiHeaders['Authorization'] = token.startsWith('Bearer ') ? token : `Bearer ${token}`;
260
292
  }
261
293
  }
@@ -297,7 +329,7 @@ export function useAgentChatInternal(options) {
297
329
  toolCall: tc,
298
330
  status: isError ? 'error' : 'completed',
299
331
  result: result.output,
300
- error: isError ? String(result.output) : undefined,
332
+ error: isError ? normalizeErrorMessage(result.output) : undefined,
301
333
  });
302
334
  return newMap;
303
335
  });
@@ -403,8 +435,7 @@ export function useAgentChatInternal(options) {
403
435
  catch (e) {
404
436
  if (e instanceof Error && e.name === 'AbortError')
405
437
  return;
406
- const errorMessage = e instanceof Error ? e.message : 'Unknown error';
407
- handleError(errorMessage);
438
+ handleError(e);
408
439
  }
409
440
  finally {
410
441
  setIsLoading(false);
@@ -433,7 +464,7 @@ export function useAgentChatInternal(options) {
433
464
  })) || []);
434
465
  }
435
466
  catch (e) {
436
- setError(e instanceof Error ? e.message : 'Unknown error');
467
+ setError(normalizeErrorMessage(e));
437
468
  }
438
469
  finally {
439
470
  setIsLoading(false);
@@ -132,23 +132,25 @@
132
132
 
133
133
  /* Custom animations for agent loading states */
134
134
  @layer utilities {
135
- @keyframes shimmer {
136
- 0% {
137
- background-position: 200% 0;
138
- }
135
+ @keyframes dot-fade {
136
+ 0%,
137
+ 80%,
139
138
  100% {
140
- background-position: -200% 0;
139
+ opacity: 0.35;
140
+ }
141
+ 40% {
142
+ opacity: 1;
141
143
  }
142
144
  }
143
145
 
144
- .animate-shimmer {
145
- animation: shimmer 2s ease-in-out infinite;
146
+ .animate-dot-fade {
147
+ animation: dot-fade 1.2s ease-in-out infinite;
146
148
  }
147
149
  }
148
150
 
149
151
  /* Respect reduced motion preferences */
150
152
  @media (prefers-reduced-motion: reduce) {
151
- .animate-shimmer,
153
+ .animate-dot-fade,
152
154
  .animate-ping,
153
155
  .animate-pulse,
154
156
  .animate-bounce {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-platform/ui",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "sideEffects": false,