@agent-platform/ui 0.0.2 → 0.0.4
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/components/agent/agent-input.js +2 -1
- package/dist/components/agent/agent-popup-widget.d.ts +1 -1
- package/dist/components/agent/agent-popup-widget.js +3 -3
- package/dist/components/agent/agent-screen.d.ts +1 -1
- package/dist/components/agent/agent-screen.js +2 -2
- package/dist/components/agent/index.d.ts +3 -3
- package/dist/components/agent/index.js +1 -1
- package/dist/components/agent/message/markdown.js +9 -9
- package/dist/components/agent/message/message-item.d.ts +1 -1
- package/dist/components/agent/message/message-item.js +1 -1
- package/dist/components/agent/message/message-list.js +3 -2
- package/dist/components/agent/message/message-loading.js +1 -1
- package/dist/components/agent/provider/agent-provider.d.ts +1 -1
- package/dist/components/agent/provider/agent-provider.js +3 -1
- package/dist/components/agent/provider/runtime-config.js +11 -4
- package/dist/components/agent/provider/types.d.ts +6 -0
- package/dist/components/agent/provider/use-agent-chat.js +24 -14
- package/dist/components/ui/badge.d.ts +1 -1
- package/dist/components/ui/button.d.ts +4 -4
- package/dist/components/ui/button.js +20 -20
- package/dist/components/ui/textarea.d.ts +3 -0
- package/dist/components/ui/textarea.js +6 -0
- package/package.json +1 -1
|
@@ -4,6 +4,7 @@ import { Paperclip, PaperPlaneTilt } from '@phosphor-icons/react/dist/ssr';
|
|
|
4
4
|
import { useCallback, useRef, useState } from 'react';
|
|
5
5
|
import { cn } from '../../lib/utils';
|
|
6
6
|
import { Button } from '../ui/button';
|
|
7
|
+
import { Textarea } from '../ui/textarea';
|
|
7
8
|
function AgentInput({ value: controlledValue, onChange, onSend, onAttach, placeholder = 'AIに相談してみましょう', disabled = false, isLoading = false, className, }) {
|
|
8
9
|
const [uncontrolledValue, setUncontrolledValue] = useState('');
|
|
9
10
|
const textareaRef = useRef(null);
|
|
@@ -45,6 +46,6 @@ function AgentInput({ value: controlledValue, onChange, onSend, onAttach, placeh
|
|
|
45
46
|
}
|
|
46
47
|
}, [handleSend]);
|
|
47
48
|
const canSend = value.trim().length > 0 && !disabled && !isLoading;
|
|
48
|
-
return (_jsx("div", { "data-slot": "agent-input", className: cn('w-full border-t border-border bg-muted px-3 pb-3 pt-2', className), children: _jsxs("div", { className: "flex items-end gap-2 rounded-lg border border-border bg-background
|
|
49
|
+
return (_jsx("div", { "data-slot": "agent-input", className: cn('w-full border-t border-border bg-muted px-3 pb-3 pt-2', className), children: _jsxs("div", { className: "flex items-end gap-1 p-2 rounded-lg border border-border bg-background transition-colors", children: [_jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", onClick: onAttach, disabled: disabled, "aria-label": "\u30D5\u30A1\u30A4\u30EB\u3092\u6DFB\u4ED8", className: "mb-0.5 text-muted-foreground hover:text-foreground", children: _jsx(Paperclip, { className: "size-4", weight: "bold" }) }), _jsx(Textarea, { ref: textareaRef, value: value, onChange: handleChange, onKeyDown: handleKeyDown, placeholder: placeholder, disabled: disabled, rows: 1, className: "border-none p-1 resize-none min-h-8 focus-visible:ring-0 focus-visible:border-0 bg-transparent" }), _jsx(Button, { type: "button", size: "icon-sm", onClick: handleSend, disabled: !canSend, "aria-label": "\u9001\u4FE1 (\u2318+Enter)", children: _jsx(PaperPlaneTilt, { className: "size-5", weight: "fill" }) })] }) }));
|
|
49
50
|
}
|
|
50
51
|
export { AgentInput };
|
|
@@ -12,4 +12,4 @@ export interface AgentPopupWidgetProps extends AgentProviderConfig {
|
|
|
12
12
|
offsetRight?: number | string;
|
|
13
13
|
zIndex?: number;
|
|
14
14
|
}
|
|
15
|
-
export declare function AgentPopupWidget({ agentId, executeClientTool, onError, authToken, getAuthToken, containerProps, defaultOpen, launcherLabel, launcherAriaLabel, closeLabel, className, launcherClassName, offsetBottom, offsetRight, zIndex, }: AgentPopupWidgetProps): import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
export declare function AgentPopupWidget({ agentId, executeClientTool, onError, authToken, getAuthToken, getAgentHeaders, disableToolApiAuthHeader, containerProps, defaultOpen, launcherLabel, launcherAriaLabel, closeLabel, className, launcherClassName, offsetBottom, offsetRight, zIndex, }: AgentPopupWidgetProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useEffect, useMemo, useState } from 'react';
|
|
4
|
-
import { Button } from '../ui/button';
|
|
5
4
|
import { cn } from '../../lib/utils';
|
|
5
|
+
import { Button } from '../ui/button';
|
|
6
6
|
import { AgentContainer } from './agent-container';
|
|
7
7
|
import { AgentProvider } from './provider';
|
|
8
8
|
const DEFAULT_OFFSET = '1.5rem';
|
|
@@ -14,7 +14,7 @@ function toCssSize(value, fallback) {
|
|
|
14
14
|
return value;
|
|
15
15
|
return fallback;
|
|
16
16
|
}
|
|
17
|
-
export function AgentPopupWidget({ agentId, executeClientTool, onError, authToken, getAuthToken, containerProps, defaultOpen = false, launcherLabel = 'AIアシスタント', launcherAriaLabel = 'AIアシスタントを開く', closeLabel = '閉じる', className, launcherClassName, offsetBottom, offsetRight, zIndex = DEFAULT_Z_INDEX, }) {
|
|
17
|
+
export function AgentPopupWidget({ agentId, executeClientTool, onError, authToken, getAuthToken, getAgentHeaders, disableToolApiAuthHeader, containerProps, defaultOpen = false, launcherLabel = 'AIアシスタント', launcherAriaLabel = 'AIアシスタントを開く', closeLabel = '閉じる', className, launcherClassName, offsetBottom, offsetRight, zIndex = DEFAULT_Z_INDEX, }) {
|
|
18
18
|
const [isOpen, setIsOpen] = useState(defaultOpen);
|
|
19
19
|
const overlayStyle = useMemo(() => ({
|
|
20
20
|
'--agent-popup-right': toCssSize(offsetRight, DEFAULT_OFFSET),
|
|
@@ -41,7 +41,7 @@ export function AgentPopupWidget({ agentId, executeClientTool, onError, authToke
|
|
|
41
41
|
document.body.style.overflow = originalOverflow;
|
|
42
42
|
};
|
|
43
43
|
}, [isOpen]);
|
|
44
|
-
return (_jsx(AgentProvider, { agentId: agentId, executeClientTool: executeClientTool, onError: onError, authToken: authToken, getAuthToken: getAuthToken, children: _jsxs("div", { "data-slot": "agent-popup-widget", style: overlayStyle, children: [!isOpen && (_jsx(Button, { type: "button", "aria-label": launcherAriaLabel, onClick: () => setIsOpen(true), className: cn('fixed right-[var(--agent-popup-right)] bottom-[var(--agent-popup-bottom)] z-[var(--agent-popup-z-index)] h-12 rounded-full px-5 shadow-lg', launcherClassName), children: launcherLabel })), isOpen && (_jsx("div", { className: "fixed inset-0 z-[var(--agent-popup-z-index)] bg-black/45 animate-in fade-in duration-200", onClick: () => setIsOpen(false), onKeyDown: (event) => {
|
|
44
|
+
return (_jsx(AgentProvider, { agentId: agentId, executeClientTool: executeClientTool, onError: onError, authToken: authToken, getAuthToken: getAuthToken, getAgentHeaders: getAgentHeaders, disableToolApiAuthHeader: disableToolApiAuthHeader, children: _jsxs("div", { "data-slot": "agent-popup-widget", style: overlayStyle, children: [!isOpen && (_jsx(Button, { type: "button", "aria-label": launcherAriaLabel, onClick: () => setIsOpen(true), className: cn('fixed right-[var(--agent-popup-right)] bottom-[var(--agent-popup-bottom)] z-[var(--agent-popup-z-index)] h-12 rounded-full px-5 shadow-lg', launcherClassName), children: launcherLabel })), isOpen && (_jsx("div", { className: "fixed inset-0 z-[var(--agent-popup-z-index)] bg-black/45 animate-in fade-in duration-200", onClick: () => setIsOpen(false), onKeyDown: (event) => {
|
|
45
45
|
if (event.key === 'Escape') {
|
|
46
46
|
setIsOpen(false);
|
|
47
47
|
}
|
|
@@ -2,4 +2,4 @@ import type { AgentProviderConfig } from './provider';
|
|
|
2
2
|
import type { AgentContainerProps } from './types';
|
|
3
3
|
export interface AgentScreenProps extends AgentProviderConfig, AgentContainerProps {
|
|
4
4
|
}
|
|
5
|
-
export declare function AgentScreen({ agentId, executeClientTool, onError, authToken, getAuthToken, ...containerProps }: AgentScreenProps): import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
export declare function AgentScreen({ agentId, executeClientTool, onError, authToken, getAuthToken, getAgentHeaders, disableToolApiAuthHeader, ...containerProps }: AgentScreenProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import { AgentContainer } from './agent-container';
|
|
4
4
|
import { AgentProvider } from './provider';
|
|
5
|
-
export function AgentScreen({ agentId, executeClientTool, onError, authToken, getAuthToken, ...containerProps }) {
|
|
6
|
-
return (_jsx(AgentProvider, { agentId: agentId, executeClientTool: executeClientTool, onError: onError, authToken: authToken, getAuthToken: getAuthToken, children: _jsx(AgentContainer, { ...containerProps }) }));
|
|
5
|
+
export function AgentScreen({ agentId, executeClientTool, onError, authToken, getAuthToken, getAgentHeaders, disableToolApiAuthHeader, ...containerProps }) {
|
|
6
|
+
return (_jsx(AgentProvider, { agentId: agentId, executeClientTool: executeClientTool, onError: onError, authToken: authToken, getAuthToken: getAuthToken, getAgentHeaders: getAgentHeaders, disableToolApiAuthHeader: disableToolApiAuthHeader, children: _jsx(AgentContainer, { ...containerProps }) }));
|
|
7
7
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { AgentScreen } from './agent-screen';
|
|
2
|
-
export type { AgentScreenProps } from './agent-screen';
|
|
3
|
-
export { AgentPopupWidget } from './agent-popup-widget';
|
|
4
1
|
export type { AgentPopupWidgetProps } from './agent-popup-widget';
|
|
2
|
+
export { AgentPopupWidget } from './agent-popup-widget';
|
|
3
|
+
export type { AgentScreenProps } from './agent-screen';
|
|
4
|
+
export { AgentScreen } from './agent-screen';
|
|
5
5
|
export type { AgentHomeCardProps } from './types';
|
|
@@ -43,21 +43,21 @@ const components = {
|
|
|
43
43
|
if (className) {
|
|
44
44
|
return _jsx("code", { className: cn('text-xs', className), children: children });
|
|
45
45
|
}
|
|
46
|
-
return
|
|
46
|
+
return _jsx("code", { className: "bg-background/50 px-1 py-0.5 rounded text-xs", children: children });
|
|
47
47
|
},
|
|
48
48
|
a: ({ href, children }) => (_jsx("a", { href: href, target: "_blank", rel: "noopener noreferrer", className: "text-primary underline hover:text-primary/80", children: children })),
|
|
49
|
-
ul: ({ children }) =>
|
|
50
|
-
ol: ({ children }) =>
|
|
49
|
+
ul: ({ children }) => _jsx("ul", { className: "list-disc list-inside pl-3 my-1", children: children }),
|
|
50
|
+
ol: ({ children }) => _jsx("ol", { className: "list-decimal list-inside pl-3 my-1", children: children }),
|
|
51
51
|
li: ({ children }) => _jsx("li", { className: "leading-relaxed", children: children }),
|
|
52
|
-
p: ({ children }) => _jsx("p", { className: "
|
|
53
|
-
h1: ({ children }) =>
|
|
54
|
-
h2: ({ children }) =>
|
|
55
|
-
h3: ({ children }) =>
|
|
52
|
+
p: ({ children }) => _jsx("p", { className: "first:mt-0 last:mb-0", children: children }),
|
|
53
|
+
h1: ({ children }) => _jsx("h1", { className: "text-base font-bold mt-3 mb-1 first:mt-0", children: children }),
|
|
54
|
+
h2: ({ children }) => _jsx("h2", { className: "text-sm font-bold mt-2.5 mb-1 first:mt-0", children: children }),
|
|
55
|
+
h3: ({ children }) => _jsx("h3", { className: "text-sm font-semibold mt-2 mb-1 first:mt-0", children: children }),
|
|
56
56
|
blockquote: ({ children }) => (_jsx("blockquote", { className: "border-l-2 border-border pl-3 my-1.5 text-muted-foreground italic", children: children })),
|
|
57
57
|
table: ({ children }) => (_jsx("div", { className: "overflow-x-auto my-1.5", children: _jsx("table", { className: "min-w-full border-collapse border border-border text-xs", children: children }) })),
|
|
58
|
-
thead: ({ children }) =>
|
|
58
|
+
thead: ({ children }) => _jsx("thead", { className: "bg-muted/50", children: children }),
|
|
59
59
|
th: ({ children }) => (_jsx("th", { className: "border border-border px-2 py-1.5 text-left font-semibold", children: children })),
|
|
60
|
-
td: ({ children }) =>
|
|
60
|
+
td: ({ children }) => _jsx("td", { className: "border border-border px-2 py-1.5", children: children }),
|
|
61
61
|
hr: () => _jsx("hr", { className: "my-3 border-border" }),
|
|
62
62
|
};
|
|
63
63
|
export function Markdown({ content, className }) {
|
|
@@ -4,4 +4,4 @@ export interface MessageItemProps {
|
|
|
4
4
|
pendingToolCalls: ToolCallState[];
|
|
5
5
|
toolNameLabels?: Record<string, string>;
|
|
6
6
|
}
|
|
7
|
-
export declare function MessageItem({ message, pendingToolCalls, toolNameLabels
|
|
7
|
+
export declare function MessageItem({ message, pendingToolCalls, toolNameLabels }: MessageItemProps): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -3,7 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { cn } from '../../../lib/utils';
|
|
4
4
|
import { Markdown } from './markdown';
|
|
5
5
|
import { ToolCallCard } from './tool-call-card';
|
|
6
|
-
export function MessageItem({ message, pendingToolCalls, toolNameLabels
|
|
6
|
+
export function MessageItem({ message, pendingToolCalls, toolNameLabels }) {
|
|
7
7
|
const isUser = message.role === 'user';
|
|
8
8
|
// メッセージからテキストを抽出
|
|
9
9
|
const textContent = message.content
|
|
@@ -8,7 +8,7 @@ export function MessageList({ messages, pendingToolCalls, toolNameLabels, isLoad
|
|
|
8
8
|
// 新しいメッセージが追加されたら自動スクロール
|
|
9
9
|
useEffect(() => {
|
|
10
10
|
bottomRef.current?.scrollIntoView({ behavior: 'smooth' });
|
|
11
|
-
}, [
|
|
11
|
+
}, []);
|
|
12
12
|
if (messages.length === 0 && !isLoading) {
|
|
13
13
|
return null;
|
|
14
14
|
}
|
|
@@ -19,6 +19,7 @@ export function MessageList({ messages, pendingToolCalls, toolNameLabels, isLoad
|
|
|
19
19
|
// Show loading indicator when:
|
|
20
20
|
// 1. isLoading is true AND
|
|
21
21
|
// 2. No messages yet OR last message is from user OR last assistant has no content
|
|
22
|
-
const showLoadingIndicator = isLoading &&
|
|
22
|
+
const showLoadingIndicator = isLoading &&
|
|
23
|
+
(messages.length === 0 || lastMessage?.role === 'user' || !lastAssistantHasContent);
|
|
23
24
|
return (_jsxs("div", { className: "flex flex-col gap-3 p-3", children: [messages.map((message) => (_jsx(MessageItem, { message: message, pendingToolCalls: pendingToolCalls, toolNameLabels: toolNameLabels }, message.id))), showLoadingIndicator && _jsx(MessageLoading, {}), _jsx("div", { ref: bottomRef })] }));
|
|
24
25
|
}
|
|
@@ -6,7 +6,7 @@ function BouncingDots() {
|
|
|
6
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]" })] }));
|
|
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
|
|
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]" })] })] }) }) }));
|
|
10
10
|
}
|
|
11
11
|
/**
|
|
12
12
|
* Compact loading indicator for inline use (e.g., inside MessageItem during streaming)
|
|
@@ -7,4 +7,4 @@ export interface AgentProviderProps extends AgentProviderConfig {
|
|
|
7
7
|
* エージェントチャット機能を提供する内部Provider
|
|
8
8
|
* 公開APIは AgentScreen / AgentPopupWidget を使用する。
|
|
9
9
|
*/
|
|
10
|
-
export declare function AgentProvider({ children, agentId, executeClientTool, onError, authToken, getAuthToken, }: AgentProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export declare function AgentProvider({ children, agentId, executeClientTool, onError, authToken, getAuthToken, getAgentHeaders, disableToolApiAuthHeader, }: AgentProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -7,7 +7,7 @@ import { useAgentChatInternal } from './use-agent-chat';
|
|
|
7
7
|
* エージェントチャット機能を提供する内部Provider
|
|
8
8
|
* 公開APIは AgentScreen / AgentPopupWidget を使用する。
|
|
9
9
|
*/
|
|
10
|
-
export function AgentProvider({ children, agentId, executeClientTool, onError, authToken, getAuthToken, }) {
|
|
10
|
+
export function AgentProvider({ children, agentId, executeClientTool, onError, authToken, getAuthToken, getAgentHeaders, disableToolApiAuthHeader, }) {
|
|
11
11
|
const runtimeConfig = resolveAgentRuntimeConfig();
|
|
12
12
|
const value = useAgentChatInternal({
|
|
13
13
|
config: {
|
|
@@ -18,6 +18,8 @@ export function AgentProvider({ children, agentId, executeClientTool, onError, a
|
|
|
18
18
|
onError,
|
|
19
19
|
authToken,
|
|
20
20
|
getAuthToken,
|
|
21
|
+
getAgentHeaders,
|
|
22
|
+
disableToolApiAuthHeader,
|
|
21
23
|
},
|
|
22
24
|
});
|
|
23
25
|
return _jsx(AgentContext.Provider, { value: value, children: children });
|
|
@@ -1,8 +1,15 @@
|
|
|
1
|
-
const
|
|
2
|
-
const
|
|
1
|
+
const isDevelopment = process.env.NODE_ENV === 'development';
|
|
2
|
+
const PRODUCTION_AGENT_ENDPOINT = 'https://agent-server-prod--agent-platform-dev-8e3ae.asia-east1.hosted.app/api/agent';
|
|
3
|
+
const DEVELOPMENT_AGENT_ENDPOINT = 'http://localhost:3002/api/agent';
|
|
4
|
+
const FIXED_API_BASE_URL = isDevelopment
|
|
5
|
+
? 'http://localhost:3001/api'
|
|
6
|
+
: 'https://demo-scout-api-prod--agent-platform-dev-8e3ae.asia-east1.hosted.app/api';
|
|
7
|
+
function normalizeUrl(url) {
|
|
8
|
+
return url.replace(/\/$/, '');
|
|
9
|
+
}
|
|
3
10
|
export function resolveAgentRuntimeConfig() {
|
|
4
11
|
return {
|
|
5
|
-
endpoint:
|
|
6
|
-
apiBaseUrl: FIXED_API_BASE_URL,
|
|
12
|
+
endpoint: normalizeUrl(isDevelopment ? DEVELOPMENT_AGENT_ENDPOINT : PRODUCTION_AGENT_ENDPOINT),
|
|
13
|
+
apiBaseUrl: normalizeUrl(FIXED_API_BASE_URL),
|
|
7
14
|
};
|
|
8
15
|
}
|
|
@@ -19,11 +19,13 @@ export type ClientToolExecutor = (toolCall: import('@agent-platform/server').Too
|
|
|
19
19
|
output: unknown;
|
|
20
20
|
isError?: boolean;
|
|
21
21
|
}>;
|
|
22
|
+
export type AgentHeadersProvider = () => Record<string, string> | Promise<Record<string, string>>;
|
|
22
23
|
/**
|
|
23
24
|
* AgentProvider設定
|
|
24
25
|
*/
|
|
25
26
|
export interface AgentProviderConfig {
|
|
26
27
|
agentId?: string;
|
|
28
|
+
/** 通信先URLは packages/ui 内部のruntime-configで解決される */
|
|
27
29
|
/**
|
|
28
30
|
* @deprecated 旧実装との後方互換用。
|
|
29
31
|
* executeOn: 'client' のツールをブラウザ側で実行するコールバック
|
|
@@ -34,6 +36,10 @@ export interface AgentProviderConfig {
|
|
|
34
36
|
authToken?: string;
|
|
35
37
|
/** 動的にトークンを取得する関数(authTokenより優先) */
|
|
36
38
|
getAuthToken?: () => string | Promise<string>;
|
|
39
|
+
/** Agent Server リクエストにのみ追加するヘッダー */
|
|
40
|
+
getAgentHeaders?: AgentHeadersProvider;
|
|
41
|
+
/** trueの場合、Tool APIへのAuthorizationヘッダー付与を無効化する */
|
|
42
|
+
disableToolApiAuthHeader?: boolean;
|
|
37
43
|
}
|
|
38
44
|
/**
|
|
39
45
|
* Agent通信先を解決済みの内部設定
|
|
@@ -163,21 +163,29 @@ async function executeApiEndpoint(toolCall, apiBaseUrl, authHeaders) {
|
|
|
163
163
|
}
|
|
164
164
|
export function useAgentChatInternal(options) {
|
|
165
165
|
const { config } = options;
|
|
166
|
-
const { endpoint, agentId = 'assistant', apiBaseUrl, executeClientTool, onError, authToken, getAuthToken } = config;
|
|
166
|
+
const { endpoint, agentId = 'assistant', apiBaseUrl, executeClientTool, onError, authToken, getAuthToken, getAgentHeaders, disableToolApiAuthHeader = false, } = config;
|
|
167
167
|
const [messages, setMessages] = useState([]);
|
|
168
168
|
const [threadId, setThreadId] = useState(null);
|
|
169
169
|
const [isLoading, setIsLoading] = useState(false);
|
|
170
170
|
const [error, setError] = useState(null);
|
|
171
171
|
const [pendingToolCalls, setPendingToolCalls] = useState(new Map());
|
|
172
172
|
const abortControllerRef = useRef(null);
|
|
173
|
-
const
|
|
173
|
+
const buildAgentHeaders = useCallback(async () => {
|
|
174
174
|
const headers = { 'Content-Type': 'application/json' };
|
|
175
175
|
const token = getAuthToken ? await getAuthToken() : authToken;
|
|
176
176
|
if (token) {
|
|
177
177
|
headers['Authorization'] = token.startsWith('Bearer ') ? token : `Bearer ${token}`;
|
|
178
178
|
}
|
|
179
|
+
const customHeaders = getAgentHeaders ? await getAgentHeaders() : undefined;
|
|
180
|
+
if (customHeaders) {
|
|
181
|
+
for (const [key, value] of Object.entries(customHeaders)) {
|
|
182
|
+
if (value) {
|
|
183
|
+
headers[key] = value;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
179
187
|
return headers;
|
|
180
|
-
}, [authToken, getAuthToken]);
|
|
188
|
+
}, [authToken, getAuthToken, getAgentHeaders]);
|
|
181
189
|
const handleError = useCallback((errorMessage) => {
|
|
182
190
|
setError(errorMessage);
|
|
183
191
|
onError?.(errorMessage);
|
|
@@ -244,10 +252,12 @@ export function useAgentChatInternal(options) {
|
|
|
244
252
|
console.log('[processStream] apiEndpoint:', JSON.stringify(tc.apiEndpoint, null, 2));
|
|
245
253
|
}
|
|
246
254
|
// 認証ヘッダーを構築
|
|
247
|
-
const
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
255
|
+
const toolApiHeaders = {};
|
|
256
|
+
if (!disableToolApiAuthHeader) {
|
|
257
|
+
const token = getAuthToken ? await getAuthToken() : authToken;
|
|
258
|
+
if (token) {
|
|
259
|
+
toolApiHeaders['Authorization'] = token.startsWith('Bearer ') ? token : `Bearer ${token}`;
|
|
260
|
+
}
|
|
251
261
|
}
|
|
252
262
|
for (const tc of unresolvedCalls) {
|
|
253
263
|
// apiBaseUrlとapiEndpointがある場合は自動実行
|
|
@@ -271,7 +281,7 @@ export function useAgentChatInternal(options) {
|
|
|
271
281
|
let result;
|
|
272
282
|
if (canAutoExecute) {
|
|
273
283
|
// 新しい自動実行パス
|
|
274
|
-
result = await executeApiEndpoint(tc, apiBaseUrl,
|
|
284
|
+
result = await executeApiEndpoint(tc, apiBaseUrl, toolApiHeaders);
|
|
275
285
|
}
|
|
276
286
|
else if (canLegacyExecute) {
|
|
277
287
|
// 従来のexecuteClientToolを使用(後方互換性)
|
|
@@ -304,7 +314,7 @@ export function useAgentChatInternal(options) {
|
|
|
304
314
|
}
|
|
305
315
|
}
|
|
306
316
|
return { clientToolResults, clientToolCalls: executedClientToolCalls };
|
|
307
|
-
}, [apiBaseUrl, executeClientTool, authToken, getAuthToken, handleError]);
|
|
317
|
+
}, [apiBaseUrl, executeClientTool, authToken, getAuthToken, disableToolApiAuthHeader, handleError]);
|
|
308
318
|
const sendMessage = useCallback(async (message) => {
|
|
309
319
|
if (!message.trim() || isLoading)
|
|
310
320
|
return;
|
|
@@ -327,7 +337,7 @@ export function useAgentChatInternal(options) {
|
|
|
327
337
|
setMessages((prev) => [...prev, assistantMessage]);
|
|
328
338
|
try {
|
|
329
339
|
abortControllerRef.current = new AbortController();
|
|
330
|
-
const headers = await
|
|
340
|
+
const headers = await buildAgentHeaders();
|
|
331
341
|
const response = await fetch(`${endpoint}/chat`, {
|
|
332
342
|
method: 'POST',
|
|
333
343
|
headers,
|
|
@@ -364,7 +374,7 @@ export function useAgentChatInternal(options) {
|
|
|
364
374
|
...prev,
|
|
365
375
|
{ id: continueMessageId, role: 'assistant', content: [], isStreaming: true },
|
|
366
376
|
]);
|
|
367
|
-
const continueHeaders = await
|
|
377
|
+
const continueHeaders = await buildAgentHeaders();
|
|
368
378
|
const continueResponse = await fetch(`${endpoint}/chat/continue`, {
|
|
369
379
|
method: 'POST',
|
|
370
380
|
headers: continueHeaders,
|
|
@@ -400,12 +410,12 @@ export function useAgentChatInternal(options) {
|
|
|
400
410
|
setIsLoading(false);
|
|
401
411
|
abortControllerRef.current = null;
|
|
402
412
|
}
|
|
403
|
-
}, [isLoading, threadId, endpoint, agentId, processStream, handleError,
|
|
413
|
+
}, [isLoading, threadId, endpoint, agentId, processStream, handleError, buildAgentHeaders]);
|
|
404
414
|
const loadThread = useCallback(async (loadThreadId) => {
|
|
405
415
|
setIsLoading(true);
|
|
406
416
|
setError(null);
|
|
407
417
|
try {
|
|
408
|
-
const threadHeaders = await
|
|
418
|
+
const threadHeaders = await buildAgentHeaders();
|
|
409
419
|
const response = await fetch(`${endpoint}/threads/${loadThreadId}/messages`, {
|
|
410
420
|
headers: threadHeaders,
|
|
411
421
|
credentials: 'include',
|
|
@@ -428,7 +438,7 @@ export function useAgentChatInternal(options) {
|
|
|
428
438
|
finally {
|
|
429
439
|
setIsLoading(false);
|
|
430
440
|
}
|
|
431
|
-
}, [endpoint,
|
|
441
|
+
}, [endpoint, buildAgentHeaders]);
|
|
432
442
|
const clearChat = useCallback(() => {
|
|
433
443
|
if (abortControllerRef.current) {
|
|
434
444
|
abortControllerRef.current.abort();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { type VariantProps } from "class-variance-authority";
|
|
3
3
|
declare const badgeVariants: (props?: ({
|
|
4
|
-
variant?: "
|
|
4
|
+
variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | null | undefined;
|
|
5
5
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
6
6
|
declare function Badge({ className, variant, asChild, ...props }: React.ComponentProps<"span"> & VariantProps<typeof badgeVariants> & {
|
|
7
7
|
asChild?: boolean;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import { type VariantProps } from 'class-variance-authority';
|
|
2
|
+
import type * as React from 'react';
|
|
3
3
|
declare const buttonVariants: (props?: ({
|
|
4
|
-
variant?: "
|
|
4
|
+
variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | null | undefined;
|
|
5
5
|
size?: "default" | "xs" | "sm" | "lg" | "icon" | "icon-xs" | "icon-sm" | "icon-lg" | null | undefined;
|
|
6
6
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
7
|
-
declare function Button({ className, variant, size, asChild, ...props }: React.ComponentProps<
|
|
7
|
+
declare function Button({ className, variant, size, asChild, ...props }: React.ComponentProps<'button'> & VariantProps<typeof buttonVariants> & {
|
|
8
8
|
asChild?: boolean;
|
|
9
9
|
}): import("react/jsx-runtime").JSX.Element;
|
|
10
10
|
export { Button, buttonVariants };
|
|
@@ -1,35 +1,35 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { cva } from
|
|
3
|
-
import { Slot } from
|
|
4
|
-
import { cn } from
|
|
2
|
+
import { cva } from 'class-variance-authority';
|
|
3
|
+
import { Slot } from 'radix-ui';
|
|
4
|
+
import { cn } from '../../lib/utils';
|
|
5
5
|
const buttonVariants = cva("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", {
|
|
6
6
|
variants: {
|
|
7
7
|
variant: {
|
|
8
|
-
default:
|
|
9
|
-
destructive:
|
|
10
|
-
outline:
|
|
11
|
-
secondary:
|
|
12
|
-
ghost:
|
|
13
|
-
link:
|
|
8
|
+
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
|
|
9
|
+
destructive: 'bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
|
|
10
|
+
outline: 'border bg-background hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50',
|
|
11
|
+
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
|
12
|
+
ghost: 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
|
|
13
|
+
link: 'text-primary underline-offset-4 hover:underline',
|
|
14
14
|
},
|
|
15
15
|
size: {
|
|
16
|
-
default:
|
|
16
|
+
default: 'h-10 px-4 py-2 has-[>svg]:px-3',
|
|
17
17
|
xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
|
|
18
|
-
sm:
|
|
19
|
-
lg:
|
|
20
|
-
icon:
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
sm: 'h-9 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5',
|
|
19
|
+
lg: 'h-11 rounded-md px-6 has-[>svg]:px-4',
|
|
20
|
+
icon: 'size-10',
|
|
21
|
+
'icon-xs': "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3",
|
|
22
|
+
'icon-sm': "size-8 rounded-md [&_svg:not([class*='size-'])]:size-4",
|
|
23
|
+
'icon-lg': "size-10 rounded-md [&_svg:not([class*='size-'])]:size-5",
|
|
24
24
|
},
|
|
25
25
|
},
|
|
26
26
|
defaultVariants: {
|
|
27
|
-
variant:
|
|
28
|
-
size:
|
|
27
|
+
variant: 'default',
|
|
28
|
+
size: 'default',
|
|
29
29
|
},
|
|
30
30
|
});
|
|
31
|
-
function Button({ className, variant =
|
|
32
|
-
const Comp = asChild ? Slot.Root :
|
|
31
|
+
function Button({ className, variant = 'default', size = 'default', asChild = false, ...props }) {
|
|
32
|
+
const Comp = asChild ? Slot.Root : 'button';
|
|
33
33
|
return (_jsx(Comp, { "data-slot": "button", "data-variant": variant, "data-size": size, className: cn(buttonVariants({ variant, size, className })), ...props }));
|
|
34
34
|
}
|
|
35
35
|
export { Button, buttonVariants };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from '@/lib/utils';
|
|
3
|
+
function Textarea({ className, ...props }) {
|
|
4
|
+
return (_jsx("textarea", { "data-slot": "textarea", className: cn('border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm', className), ...props }));
|
|
5
|
+
}
|
|
6
|
+
export { Textarea };
|