@agent-platform/ui 0.0.1
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/README.md +41 -0
- package/dist/components/agent/agent-container.d.ts +3 -0
- package/dist/components/agent/agent-container.js +47 -0
- package/dist/components/agent/agent-greeting.d.ts +3 -0
- package/dist/components/agent/agent-greeting.js +7 -0
- package/dist/components/agent/agent-header.d.ts +3 -0
- package/dist/components/agent/agent-header.js +9 -0
- package/dist/components/agent/agent-home-card.d.ts +3 -0
- package/dist/components/agent/agent-home-card.js +7 -0
- package/dist/components/agent/agent-home-cards.d.ts +9 -0
- package/dist/components/agent/agent-home-cards.js +11 -0
- package/dist/components/agent/agent-input.d.ts +3 -0
- package/dist/components/agent/agent-input.js +50 -0
- package/dist/components/agent/agent-popup-widget.d.ts +15 -0
- package/dist/components/agent/agent-popup-widget.js +49 -0
- package/dist/components/agent/agent-screen.d.ts +5 -0
- package/dist/components/agent/agent-screen.js +7 -0
- package/dist/components/agent/defaults.d.ts +11 -0
- package/dist/components/agent/defaults.js +23 -0
- package/dist/components/agent/index.d.ts +5 -0
- package/dist/components/agent/index.js +2 -0
- package/dist/components/agent/message/index.d.ts +8 -0
- package/dist/components/agent/message/index.js +4 -0
- package/dist/components/agent/message/markdown.d.ts +6 -0
- package/dist/components/agent/message/markdown.js +66 -0
- package/dist/components/agent/message/message-item.d.ts +7 -0
- package/dist/components/agent/message/message-item.js +30 -0
- package/dist/components/agent/message/message-list.d.ts +8 -0
- package/dist/components/agent/message/message-list.js +24 -0
- package/dist/components/agent/message/message-loading.d.ts +10 -0
- package/dist/components/agent/message/message-loading.js +16 -0
- package/dist/components/agent/message/tool-call-card.d.ts +9 -0
- package/dist/components/agent/message/tool-call-card.js +25 -0
- package/dist/components/agent/provider/agent-context.d.ts +3 -0
- package/dist/components/agent/provider/agent-context.js +10 -0
- package/dist/components/agent/provider/agent-provider.d.ts +10 -0
- package/dist/components/agent/provider/agent-provider.js +22 -0
- package/dist/components/agent/provider/index.d.ts +4 -0
- package/dist/components/agent/provider/index.js +2 -0
- package/dist/components/agent/provider/parse-sse-buffer.d.ts +9 -0
- package/dist/components/agent/provider/parse-sse-buffer.js +23 -0
- package/dist/components/agent/provider/types.d.ts +58 -0
- package/dist/components/agent/provider/types.js +1 -0
- package/dist/components/agent/provider/use-agent-chat.d.ts +6 -0
- package/dist/components/agent/provider/use-agent-chat.js +452 -0
- package/dist/components/agent/types.d.ts +56 -0
- package/dist/components/agent/types.js +1 -0
- package/dist/components/index.d.ts +7 -0
- package/dist/components/index.js +9 -0
- package/dist/components/ui/badge.d.ts +9 -0
- package/dist/components/ui/badge.js +24 -0
- package/dist/components/ui/button.d.ts +10 -0
- package/dist/components/ui/button.js +35 -0
- package/dist/components/ui/card.d.ts +9 -0
- package/dist/components/ui/card.js +24 -0
- package/dist/components/ui/input.d.ts +3 -0
- package/dist/components/ui/input.js +6 -0
- package/dist/components/ui/label.d.ts +4 -0
- package/dist/components/ui/label.js +7 -0
- package/dist/components/ui/separator.d.ts +4 -0
- package/dist/components/ui/separator.js +8 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/lib/index.d.ts +1 -0
- package/dist/lib/index.js +1 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/lib/utils.js +5 -0
- package/dist/styles/globals.css +157 -0
- package/package.json +59 -0
package/README.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# @agent-platform/ui
|
|
2
|
+
|
|
3
|
+
Agent Platform の共有 UI コンポーネントライブラリです。
|
|
4
|
+
|
|
5
|
+
## インストール
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @agent-platform/ui
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
```css
|
|
12
|
+
@import "@agent-platform/ui/styles/globals.css";
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## 公開方針(現運用)
|
|
16
|
+
|
|
17
|
+
`@agent-platform/ui` の公開は、ローカル/CI どちらも **`NODE_AUTH_TOKEN` を使う token ベース運用**です。
|
|
18
|
+
|
|
19
|
+
- 必須環境変数: `NODE_AUTH_TOKEN`
|
|
20
|
+
- CI では GitHub Secret `NPM_TOKEN` を `NODE_AUTH_TOKEN` にマップして実行
|
|
21
|
+
- ローカル公開時も同じスクリプトを実行
|
|
22
|
+
|
|
23
|
+
## 公開手順
|
|
24
|
+
|
|
25
|
+
1. 認証付き事前チェック
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pnpm --filter @agent-platform/ui release:check
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
2. 公開
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pnpm --filter @agent-platform/ui publish:public
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
3. 公開ドライラン
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pnpm --filter @agent-platform/ui publish:public:dry-run
|
|
41
|
+
```
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { AgentContainerProps } from './types';
|
|
2
|
+
declare function AgentContainer({ showHeader, headerProps, showGreeting, greetingProps, showHomeCards, cards, onCardClick, toolNameLabels, autoShowMessages, showInput, inputProps, className, children, }: AgentContainerProps): import("react/jsx-runtime").JSX.Element;
|
|
3
|
+
export { AgentContainer };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { cn } from '../../lib/utils';
|
|
4
|
+
import { AgentGreeting } from './agent-greeting';
|
|
5
|
+
import { AgentHeader } from './agent-header';
|
|
6
|
+
import { AgentHomeCards } from './agent-home-cards';
|
|
7
|
+
import { AgentInput } from './agent-input';
|
|
8
|
+
import { DEFAULT_TOOL_NAME_LABELS } from './defaults';
|
|
9
|
+
import { MessageList } from './message';
|
|
10
|
+
import { useAgentContext } from './provider';
|
|
11
|
+
function AgentContainer({ showHeader = true, headerProps, showGreeting = true, greetingProps, showHomeCards = true, cards, onCardClick, toolNameLabels, autoShowMessages = true, showInput = true, inputProps, className, children, }) {
|
|
12
|
+
// AgentProvider配下で使用されている場合のみ有効
|
|
13
|
+
let messages = [];
|
|
14
|
+
let pendingToolCalls = [];
|
|
15
|
+
let error = null;
|
|
16
|
+
let sendMessage;
|
|
17
|
+
let clearChat;
|
|
18
|
+
let isLoading = false;
|
|
19
|
+
try {
|
|
20
|
+
const context = useAgentContext();
|
|
21
|
+
messages = context.messages;
|
|
22
|
+
pendingToolCalls = context.pendingToolCalls;
|
|
23
|
+
error = context.error;
|
|
24
|
+
sendMessage = context.sendMessage;
|
|
25
|
+
clearChat = context.clearChat;
|
|
26
|
+
isLoading = context.isLoading;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
// AgentProvider外で使用されている場合は無視
|
|
30
|
+
}
|
|
31
|
+
// propsのデフォルト値をコンテキストから適用
|
|
32
|
+
const effectiveInputProps = {
|
|
33
|
+
...inputProps,
|
|
34
|
+
onSend: inputProps?.onSend ?? sendMessage,
|
|
35
|
+
isLoading: inputProps?.isLoading ?? isLoading,
|
|
36
|
+
};
|
|
37
|
+
const effectiveHeaderProps = {
|
|
38
|
+
...headerProps,
|
|
39
|
+
onNewChatClick: headerProps?.onNewChatClick ?? clearChat,
|
|
40
|
+
};
|
|
41
|
+
const hasMessages = messages.length > 0;
|
|
42
|
+
const mergedToolNameLabels = { ...DEFAULT_TOOL_NAME_LABELS, ...toolNameLabels };
|
|
43
|
+
// 自動メッセージ表示用コンテンツ
|
|
44
|
+
const autoMessagesContent = autoShowMessages && (hasMessages || isLoading) && (_jsxs("div", { className: "flex-1 overflow-y-auto bg-white", children: [_jsx(MessageList, { messages: messages, pendingToolCalls: pendingToolCalls, toolNameLabels: mergedToolNameLabels, isLoading: isLoading }), error && (_jsx("div", { className: "mx-4 mb-4 rounded-lg bg-red-50 p-3 text-sm text-red-600", children: error }))] }));
|
|
45
|
+
return (_jsxs("div", { "data-slot": "agent-container", className: cn('flex flex-col w-full h-full', className), children: [showHeader && _jsx(AgentHeader, { ...effectiveHeaderProps }), children ? (children) : autoMessagesContent ? (autoMessagesContent) : (_jsxs("div", { className: "flex flex-1 flex-col items-center justify-center gap-6 bg-background px-4 py-4", children: [showGreeting && _jsx(AgentGreeting, { ...greetingProps }), showHomeCards && cards && _jsx(AgentHomeCards, { cards: cards, onCardClick: onCardClick })] })), showInput && _jsx(AgentInput, { ...effectiveInputProps })] }));
|
|
46
|
+
}
|
|
47
|
+
export { AgentContainer };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { cn } from "../../lib/utils";
|
|
4
|
+
function AgentGreeting({ greeting = "こんにちは 👋", subtext = "何かお手伝いできることはありますか?", className, }) {
|
|
5
|
+
return (_jsxs("div", { "data-slot": "agent-greeting", className: cn("flex flex-col items-center gap-1.5 text-center", className), children: [_jsx("p", { className: "text-sm text-muted-foreground", children: greeting }), _jsx("p", { className: "text-lg font-semibold tracking-tight text-balance text-card-foreground", children: subtext })] }));
|
|
6
|
+
}
|
|
7
|
+
export { AgentGreeting };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { AgentHeaderProps } from "./types";
|
|
2
|
+
declare function AgentHeader({ historyLabel, onHistoryClick, onSettingsClick, onNewChatClick, newChatLabel, settingsAriaLabel, className, }: AgentHeaderProps): import("react/jsx-runtime").JSX.Element;
|
|
3
|
+
export { AgentHeader };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { CaretDown, Gear } from "@phosphor-icons/react/dist/ssr";
|
|
4
|
+
import { cn } from "../../lib/utils";
|
|
5
|
+
import { Button } from "../ui/button";
|
|
6
|
+
function AgentHeader({ historyLabel = "履歴", onHistoryClick, onSettingsClick, onNewChatClick, newChatLabel = "新規チャット", settingsAriaLabel = "設定", className, }) {
|
|
7
|
+
return (_jsxs("div", { "data-slot": "agent-header", className: cn("flex w-full items-center justify-between bg-background px-4 py-2", className), children: [_jsxs("div", { className: "flex items-center", children: [_jsx("span", { className: "text-sm font-semibold text-foreground", children: historyLabel }), _jsx(Button, { variant: "ghost", size: "icon-sm", onClick: onHistoryClick, "aria-label": historyLabel, children: _jsx(CaretDown, { className: "size-5" }) })] }), _jsxs("div", { className: "flex items-center gap-1", children: [_jsx(Button, { variant: "ghost", size: "icon-sm", onClick: onSettingsClick, "aria-label": settingsAriaLabel, className: "text-foreground", children: _jsx(Gear, { className: "size-5" }) }), _jsx(Button, { size: "sm", onClick: onNewChatClick, className: "bg-foreground text-background text-xs font-medium hover:bg-foreground/90", children: newChatLabel })] })] }));
|
|
8
|
+
}
|
|
9
|
+
export { AgentHeader };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { cn } from "../../lib/utils";
|
|
4
|
+
function AgentHomeCard({ id, icon, title, description, onClick, className, }) {
|
|
5
|
+
return (_jsxs("button", { type: "button", "data-slot": "agent-home-card", "data-card-id": id, onClick: onClick, className: cn("flex flex-1 flex-col items-start gap-2.5 rounded-lg border border-border bg-card p-3 text-left transition-all hover:border-primary/30 hover:bg-accent focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring", className), children: [_jsx("div", { className: "text-muted-foreground [&_svg]:size-5", children: icon }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("p", { className: "text-sm font-semibold leading-none text-card-foreground", children: title }), _jsx("p", { className: "text-xs leading-relaxed text-muted-foreground", children: description })] })] }));
|
|
6
|
+
}
|
|
7
|
+
export { AgentHomeCard };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { AgentHomeCardProps } from "./types";
|
|
2
|
+
interface AgentHomeCardsProps {
|
|
3
|
+
cards: AgentHomeCardProps[];
|
|
4
|
+
onCardClick?: (cardId: string) => void;
|
|
5
|
+
className?: string;
|
|
6
|
+
}
|
|
7
|
+
declare function AgentHomeCards({ cards, onCardClick, className, }: AgentHomeCardsProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export { AgentHomeCards };
|
|
9
|
+
export type { AgentHomeCardsProps };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { cn } from "../../lib/utils";
|
|
4
|
+
import { AgentHomeCard } from "./agent-home-card";
|
|
5
|
+
function AgentHomeCards({ cards, onCardClick, className, }) {
|
|
6
|
+
return (_jsx("div", { "data-slot": "agent-home-cards", className: cn("flex w-full items-start justify-center gap-4 px-12", className), children: cards.map((card) => (_jsx(AgentHomeCard, { ...card, onClick: () => {
|
|
7
|
+
card.onClick?.();
|
|
8
|
+
onCardClick?.(card.id);
|
|
9
|
+
} }, card.id))) }));
|
|
10
|
+
}
|
|
11
|
+
export { AgentHomeCards };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Paperclip, PaperPlaneTilt } from '@phosphor-icons/react/dist/ssr';
|
|
4
|
+
import { useCallback, useRef, useState } from 'react';
|
|
5
|
+
import { cn } from '../../lib/utils';
|
|
6
|
+
import { Button } from '../ui/button';
|
|
7
|
+
function AgentInput({ value: controlledValue, onChange, onSend, onAttach, placeholder = 'AIに相談してみましょう', disabled = false, isLoading = false, className, }) {
|
|
8
|
+
const [uncontrolledValue, setUncontrolledValue] = useState('');
|
|
9
|
+
const textareaRef = useRef(null);
|
|
10
|
+
const isControlled = controlledValue !== undefined;
|
|
11
|
+
const value = isControlled ? controlledValue : uncontrolledValue;
|
|
12
|
+
const resetTextareaHeight = useCallback(() => {
|
|
13
|
+
if (textareaRef.current) {
|
|
14
|
+
textareaRef.current.style.height = 'auto';
|
|
15
|
+
}
|
|
16
|
+
}, []);
|
|
17
|
+
const adjustTextareaHeight = useCallback(() => {
|
|
18
|
+
const textarea = textareaRef.current;
|
|
19
|
+
if (textarea) {
|
|
20
|
+
textarea.style.height = 'auto';
|
|
21
|
+
textarea.style.height = `${Math.min(textarea.scrollHeight, 160)}px`;
|
|
22
|
+
}
|
|
23
|
+
}, []);
|
|
24
|
+
const handleChange = useCallback((e) => {
|
|
25
|
+
const newValue = e.target.value;
|
|
26
|
+
if (!isControlled) {
|
|
27
|
+
setUncontrolledValue(newValue);
|
|
28
|
+
}
|
|
29
|
+
onChange?.(newValue);
|
|
30
|
+
adjustTextareaHeight();
|
|
31
|
+
}, [isControlled, onChange, adjustTextareaHeight]);
|
|
32
|
+
const handleSend = useCallback(() => {
|
|
33
|
+
if (value.trim() && !disabled && !isLoading) {
|
|
34
|
+
onSend?.(value.trim());
|
|
35
|
+
if (!isControlled) {
|
|
36
|
+
setUncontrolledValue('');
|
|
37
|
+
}
|
|
38
|
+
resetTextareaHeight();
|
|
39
|
+
}
|
|
40
|
+
}, [value, disabled, isLoading, onSend, isControlled, resetTextareaHeight]);
|
|
41
|
+
const handleKeyDown = useCallback((e) => {
|
|
42
|
+
if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {
|
|
43
|
+
e.preventDefault();
|
|
44
|
+
handleSend();
|
|
45
|
+
}
|
|
46
|
+
}, [handleSend]);
|
|
47
|
+
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 px-2.5 py-1.5 transition-colors focus-within:border-primary/40", 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-5" }) }), _jsx("textarea", { ref: textareaRef, value: value, onChange: handleChange, onKeyDown: handleKeyDown, placeholder: placeholder, disabled: disabled, rows: 1, className: "flex-1 resize-none bg-transparent text-sm leading-5 text-foreground placeholder:text-placeholder focus:outline-none disabled:cursor-not-allowed disabled:opacity-50", style: { maxHeight: '160px' } }), _jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", onClick: handleSend, disabled: !canSend, "aria-label": "\u9001\u4FE1 (\u2318+Enter)", className: "mb-0.5 text-muted-foreground hover:text-foreground disabled:opacity-30", children: _jsx(PaperPlaneTilt, { className: "size-5", weight: "fill" }) })] }) }));
|
|
49
|
+
}
|
|
50
|
+
export { AgentInput };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { AgentProviderConfig } from './provider';
|
|
2
|
+
import type { AgentContainerProps } from './types';
|
|
3
|
+
export interface AgentPopupWidgetProps extends AgentProviderConfig {
|
|
4
|
+
containerProps?: AgentContainerProps;
|
|
5
|
+
defaultOpen?: boolean;
|
|
6
|
+
launcherLabel?: string;
|
|
7
|
+
launcherAriaLabel?: string;
|
|
8
|
+
closeLabel?: string;
|
|
9
|
+
className?: string;
|
|
10
|
+
launcherClassName?: string;
|
|
11
|
+
offsetBottom?: number | string;
|
|
12
|
+
offsetRight?: number | string;
|
|
13
|
+
zIndex?: number;
|
|
14
|
+
}
|
|
15
|
+
export declare function AgentPopupWidget({ endpoint, agentId, apiBaseUrl, executeClientTool, onError, authToken, getAuthToken, containerProps, defaultOpen, launcherLabel, launcherAriaLabel, closeLabel, className, launcherClassName, offsetBottom, offsetRight, zIndex, }: AgentPopupWidgetProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
4
|
+
import { Button } from '../ui/button';
|
|
5
|
+
import { cn } from '../../lib/utils';
|
|
6
|
+
import { AgentContainer } from './agent-container';
|
|
7
|
+
import { AgentProvider } from './provider';
|
|
8
|
+
const DEFAULT_OFFSET = '1.5rem';
|
|
9
|
+
const DEFAULT_Z_INDEX = 60;
|
|
10
|
+
function toCssSize(value, fallback) {
|
|
11
|
+
if (typeof value === 'number')
|
|
12
|
+
return `${value}px`;
|
|
13
|
+
if (typeof value === 'string' && value.trim().length > 0)
|
|
14
|
+
return value;
|
|
15
|
+
return fallback;
|
|
16
|
+
}
|
|
17
|
+
export function AgentPopupWidget({ endpoint, agentId, apiBaseUrl, executeClientTool, onError, authToken, getAuthToken, containerProps, defaultOpen = false, launcherLabel = 'AIアシスタント', launcherAriaLabel = 'AIアシスタントを開く', closeLabel = '閉じる', className, launcherClassName, offsetBottom, offsetRight, zIndex = DEFAULT_Z_INDEX, }) {
|
|
18
|
+
const [isOpen, setIsOpen] = useState(defaultOpen);
|
|
19
|
+
const overlayStyle = useMemo(() => ({
|
|
20
|
+
'--agent-popup-right': toCssSize(offsetRight, DEFAULT_OFFSET),
|
|
21
|
+
'--agent-popup-bottom': toCssSize(offsetBottom, DEFAULT_OFFSET),
|
|
22
|
+
'--agent-popup-z-index': String(zIndex),
|
|
23
|
+
}), [offsetBottom, offsetRight, zIndex]);
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (!isOpen)
|
|
26
|
+
return;
|
|
27
|
+
const handleKeyDown = (event) => {
|
|
28
|
+
if (event.key === 'Escape') {
|
|
29
|
+
setIsOpen(false);
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
window.addEventListener('keydown', handleKeyDown);
|
|
33
|
+
return () => window.removeEventListener('keydown', handleKeyDown);
|
|
34
|
+
}, [isOpen]);
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (!isOpen)
|
|
37
|
+
return;
|
|
38
|
+
const originalOverflow = document.body.style.overflow;
|
|
39
|
+
document.body.style.overflow = 'hidden';
|
|
40
|
+
return () => {
|
|
41
|
+
document.body.style.overflow = originalOverflow;
|
|
42
|
+
};
|
|
43
|
+
}, [isOpen]);
|
|
44
|
+
return (_jsx(AgentProvider, { endpoint: endpoint, agentId: agentId, apiBaseUrl: apiBaseUrl, 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) => {
|
|
45
|
+
if (event.key === 'Escape') {
|
|
46
|
+
setIsOpen(false);
|
|
47
|
+
}
|
|
48
|
+
}, children: _jsxs("section", { role: "dialog", "aria-modal": "true", "aria-label": launcherLabel, className: cn('fixed inset-0 flex flex-col overflow-hidden bg-background animate-in fade-in zoom-in-95 duration-200', 'sm:inset-auto sm:right-[var(--agent-popup-right)] sm:bottom-[var(--agent-popup-bottom)] sm:h-[min(70vh,720px)] sm:w-[380px] sm:rounded-2xl sm:border sm:border-border sm:shadow-2xl', className), onClick: (event) => event.stopPropagation(), children: [_jsx(Button, { type: "button", variant: "ghost", size: "icon-xs", "aria-label": closeLabel, className: "absolute top-3 right-3 z-10", onClick: () => setIsOpen(false), children: "\u00D7" }), _jsx(AgentContainer, { ...containerProps, className: cn('h-full bg-background', containerProps?.className) })] }) }))] }) }));
|
|
49
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { AgentProviderConfig } from './provider';
|
|
2
|
+
import type { AgentContainerProps } from './types';
|
|
3
|
+
export interface AgentScreenProps extends AgentProviderConfig, AgentContainerProps {
|
|
4
|
+
}
|
|
5
|
+
export declare function AgentScreen({ endpoint, agentId, apiBaseUrl, executeClientTool, onError, authToken, getAuthToken, ...containerProps }: AgentScreenProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { AgentContainer } from './agent-container';
|
|
4
|
+
import { AgentProvider } from './provider';
|
|
5
|
+
export function AgentScreen({ endpoint, agentId, apiBaseUrl, executeClientTool, onError, authToken, getAuthToken, ...containerProps }) {
|
|
6
|
+
return (_jsx(AgentProvider, { endpoint: endpoint, agentId: agentId, apiBaseUrl: apiBaseUrl, executeClientTool: executeClientTool, onError: onError, authToken: authToken, getAuthToken: getAuthToken, children: _jsx(AgentContainer, { ...containerProps }) }));
|
|
7
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AgentHomeCardProps } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* デフォルトのホームカード定義
|
|
4
|
+
* 消費側でカスタマイズ可能だが、デフォルトとして提供
|
|
5
|
+
*/
|
|
6
|
+
export declare const DEFAULT_HOME_CARDS: Omit<AgentHomeCardProps, 'icon'>[];
|
|
7
|
+
/**
|
|
8
|
+
* デフォルトのツール名ラベル
|
|
9
|
+
* 消費側でマージ/上書き可能
|
|
10
|
+
*/
|
|
11
|
+
export declare const DEFAULT_TOOL_NAME_LABELS: Record<string, string>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* デフォルトのホームカード定義
|
|
3
|
+
* 消費側でカスタマイズ可能だが、デフォルトとして提供
|
|
4
|
+
*/
|
|
5
|
+
export const DEFAULT_HOME_CARDS = [
|
|
6
|
+
{
|
|
7
|
+
id: 'chat',
|
|
8
|
+
title: 'チャットを開始',
|
|
9
|
+
description: 'AIアシスタントと会話を始めましょう',
|
|
10
|
+
},
|
|
11
|
+
];
|
|
12
|
+
/**
|
|
13
|
+
* デフォルトのツール名ラベル
|
|
14
|
+
* 消費側でマージ/上書き可能
|
|
15
|
+
*/
|
|
16
|
+
export const DEFAULT_TOOL_NAME_LABELS = {
|
|
17
|
+
// 汎用ツール名
|
|
18
|
+
search: '検索',
|
|
19
|
+
get: '取得',
|
|
20
|
+
create: '作成',
|
|
21
|
+
update: '更新',
|
|
22
|
+
delete: '削除',
|
|
23
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { AgentScreen } from './agent-screen';
|
|
2
|
+
export type { AgentScreenProps } from './agent-screen';
|
|
3
|
+
export { AgentPopupWidget } from './agent-popup-widget';
|
|
4
|
+
export type { AgentPopupWidgetProps } from './agent-popup-widget';
|
|
5
|
+
export type { AgentHomeCardProps } from './types';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { MessageList } from './message-list';
|
|
2
|
+
export type { MessageListProps } from './message-list';
|
|
3
|
+
export { MessageItem } from './message-item';
|
|
4
|
+
export type { MessageItemProps } from './message-item';
|
|
5
|
+
export { ToolCallCard } from './tool-call-card';
|
|
6
|
+
export type { ToolCallCardProps } from './tool-call-card';
|
|
7
|
+
export { MessageLoading, ThinkingDots } from './message-loading';
|
|
8
|
+
export type { MessageLoadingProps } from './message-loading';
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import ReactMarkdown from 'react-markdown';
|
|
4
|
+
import remarkGfm from 'remark-gfm';
|
|
5
|
+
import { cn } from '../../../lib/utils';
|
|
6
|
+
const listItemPattern = /^\s*(?:[-*+]\s+|\d+[.)]\s+)/;
|
|
7
|
+
const codeFenceStartPattern = /^\s*```/;
|
|
8
|
+
const blockquotePattern = /^\s*>/;
|
|
9
|
+
function isListItemLine(line) {
|
|
10
|
+
return listItemPattern.test(line);
|
|
11
|
+
}
|
|
12
|
+
function isPotentialParagraphLine(line) {
|
|
13
|
+
if (!line.trim())
|
|
14
|
+
return false;
|
|
15
|
+
if (/^(?: {4,}|\t)/.test(line))
|
|
16
|
+
return false;
|
|
17
|
+
const normalizedLine = line.replace(/^[ \u3000]+/, '');
|
|
18
|
+
if (!normalizedLine)
|
|
19
|
+
return false;
|
|
20
|
+
if (isListItemLine(normalizedLine))
|
|
21
|
+
return false;
|
|
22
|
+
if (blockquotePattern.test(normalizedLine))
|
|
23
|
+
return false;
|
|
24
|
+
if (codeFenceStartPattern.test(normalizedLine))
|
|
25
|
+
return false;
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
function normalizeAgentMarkdown(content) {
|
|
29
|
+
const lines = content.replace(/\r\n?/g, '\n').split('\n');
|
|
30
|
+
const normalized = [];
|
|
31
|
+
for (const line of lines) {
|
|
32
|
+
const prevLine = normalized[normalized.length - 1] ?? '';
|
|
33
|
+
if (isListItemLine(prevLine) && isPotentialParagraphLine(line)) {
|
|
34
|
+
normalized.push('');
|
|
35
|
+
}
|
|
36
|
+
normalized.push(line);
|
|
37
|
+
}
|
|
38
|
+
return normalized.join('\n');
|
|
39
|
+
}
|
|
40
|
+
const components = {
|
|
41
|
+
pre: ({ children }) => (_jsx("pre", { className: "bg-background/50 rounded p-2 overflow-x-auto my-1.5 text-xs", children: children })),
|
|
42
|
+
code: ({ children, className }) => {
|
|
43
|
+
if (className) {
|
|
44
|
+
return _jsx("code", { className: cn('text-xs', className), children: children });
|
|
45
|
+
}
|
|
46
|
+
return (_jsx("code", { className: "bg-background/50 px-1 py-0.5 rounded text-xs", children: children }));
|
|
47
|
+
},
|
|
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 }) => (_jsx("ul", { className: "list-disc list-inside pl-1 my-1.5 space-y-0.5", children: children })),
|
|
50
|
+
ol: ({ children }) => (_jsx("ol", { className: "list-decimal list-inside pl-1 my-1.5 space-y-0.5", children: children })),
|
|
51
|
+
li: ({ children }) => _jsx("li", { className: "leading-relaxed", children: children }),
|
|
52
|
+
p: ({ children }) => _jsx("p", { className: "my-1.5 first:mt-0 last:mb-0", children: children }),
|
|
53
|
+
h1: ({ children }) => (_jsx("h1", { className: "text-base font-bold mt-3 mb-1.5 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
|
+
blockquote: ({ children }) => (_jsx("blockquote", { className: "border-l-2 border-border pl-3 my-1.5 text-muted-foreground italic", children: children })),
|
|
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 }) => (_jsx("thead", { className: "bg-muted/50", children: children })),
|
|
59
|
+
th: ({ children }) => (_jsx("th", { className: "border border-border px-2 py-1.5 text-left font-semibold", children: children })),
|
|
60
|
+
td: ({ children }) => (_jsx("td", { className: "border border-border px-2 py-1.5", children: children })),
|
|
61
|
+
hr: () => _jsx("hr", { className: "my-3 border-border" }),
|
|
62
|
+
};
|
|
63
|
+
export function Markdown({ content, className }) {
|
|
64
|
+
const normalizedContent = normalizeAgentMarkdown(content);
|
|
65
|
+
return (_jsx("div", { className: cn('text-sm leading-relaxed', className), children: _jsx(ReactMarkdown, { remarkPlugins: [remarkGfm], components: components, children: normalizedContent }) }));
|
|
66
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { AgentMessage, ToolCallState } from '../provider/types';
|
|
2
|
+
export interface MessageItemProps {
|
|
3
|
+
message: AgentMessage;
|
|
4
|
+
pendingToolCalls: ToolCallState[];
|
|
5
|
+
toolNameLabels?: Record<string, string>;
|
|
6
|
+
}
|
|
7
|
+
export declare function MessageItem({ message, pendingToolCalls, toolNameLabels, }: MessageItemProps): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { cn } from '../../../lib/utils';
|
|
4
|
+
import { Markdown } from './markdown';
|
|
5
|
+
import { ToolCallCard } from './tool-call-card';
|
|
6
|
+
export function MessageItem({ message, pendingToolCalls, toolNameLabels, }) {
|
|
7
|
+
const isUser = message.role === 'user';
|
|
8
|
+
// メッセージからテキストを抽出
|
|
9
|
+
const textContent = message.content
|
|
10
|
+
.filter((c) => c.type === 'text')
|
|
11
|
+
.map((c) => c.text)
|
|
12
|
+
.join('');
|
|
13
|
+
// メッセージからツールコールを抽出
|
|
14
|
+
const toolCalls = message.content
|
|
15
|
+
.filter((c) => c.type === 'tool-call')
|
|
16
|
+
.map((c) => c.toolCall);
|
|
17
|
+
// 空のストリーミング中の assistant メッセージは非表示(MessageLoading が表示されるため)
|
|
18
|
+
if (!isUser && message.isStreaming && !textContent && toolCalls.length === 0) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
return (_jsx("div", { className: cn('flex', isUser ? 'justify-end' : 'justify-start'), children: _jsxs("div", { className: "max-w-xl space-y-1.5", children: [textContent && (_jsx("div", { className: cn('rounded-lg px-3 py-2', isUser
|
|
22
|
+
? 'bg-primary text-primary-foreground'
|
|
23
|
+
: 'border border-border bg-card text-card-foreground'), children: isUser ? (_jsx("div", { className: "whitespace-pre-wrap text-sm leading-relaxed", children: textContent })) : (_jsx(Markdown, { content: textContent })) })), !isUser && toolCalls.length > 0 && (_jsx("div", { className: "ml-2 space-y-1.5 border-l-2 border-border pl-2", children: toolCalls.map((tc) => {
|
|
24
|
+
const toolCallState = pendingToolCalls.find((p) => p.toolCall.toolCallId === tc.toolCallId);
|
|
25
|
+
if (toolCallState) {
|
|
26
|
+
return (_jsx(ToolCallCard, { toolCallState: toolCallState, toolNameLabels: toolNameLabels }, tc.toolCallId));
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
}) }))] }) }));
|
|
30
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AgentMessage, ToolCallState } from '../provider/types';
|
|
2
|
+
export interface MessageListProps {
|
|
3
|
+
messages: AgentMessage[];
|
|
4
|
+
pendingToolCalls: ToolCallState[];
|
|
5
|
+
toolNameLabels?: Record<string, string>;
|
|
6
|
+
isLoading?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function MessageList({ messages, pendingToolCalls, toolNameLabels, isLoading, }: MessageListProps): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useRef } from 'react';
|
|
4
|
+
import { MessageItem } from './message-item';
|
|
5
|
+
import { MessageLoading } from './message-loading';
|
|
6
|
+
export function MessageList({ messages, pendingToolCalls, toolNameLabels, isLoading = false, }) {
|
|
7
|
+
const bottomRef = useRef(null);
|
|
8
|
+
// 新しいメッセージが追加されたら自動スクロール
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
bottomRef.current?.scrollIntoView({ behavior: 'smooth' });
|
|
11
|
+
}, [messages, isLoading]);
|
|
12
|
+
if (messages.length === 0 && !isLoading) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
const lastMessage = messages[messages.length - 1];
|
|
16
|
+
// Check if the last assistant message has actual text content
|
|
17
|
+
const lastAssistantHasContent = lastMessage?.role === 'assistant' &&
|
|
18
|
+
lastMessage.content.some((c) => c.type === 'text' && c.text.length > 0);
|
|
19
|
+
// Show loading indicator when:
|
|
20
|
+
// 1. isLoading is true AND
|
|
21
|
+
// 2. No messages yet OR last message is from user OR last assistant has no content
|
|
22
|
+
const showLoadingIndicator = isLoading && (messages.length === 0 || lastMessage?.role === 'user' || !lastAssistantHasContent);
|
|
23
|
+
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
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface MessageLoadingProps {
|
|
2
|
+
className?: string;
|
|
3
|
+
}
|
|
4
|
+
export declare function MessageLoading({ className }: MessageLoadingProps): import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
/**
|
|
6
|
+
* Compact loading indicator for inline use (e.g., inside MessageItem during streaming)
|
|
7
|
+
*/
|
|
8
|
+
export declare function ThinkingDots({ className }: {
|
|
9
|
+
className?: string;
|
|
10
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
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]" })] }));
|
|
7
|
+
}
|
|
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 items-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-gradient-to-r from-muted via-muted-foreground/10 to-muted bg-[length:200%_100%]" }), _jsx("div", { className: "h-2.5 w-3/4 animate-shimmer rounded bg-gradient-to-r from-muted via-muted-foreground/10 to-muted bg-[length:200%_100%] [animation-delay:100ms]" }), _jsx("div", { className: "h-2.5 w-1/2 animate-shimmer rounded bg-gradient-to-r from-muted via-muted-foreground/10 to-muted bg-[length:200%_100%] [animation-delay:200ms]" })] })] }) }) }));
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Compact loading indicator for inline use (e.g., inside MessageItem during streaming)
|
|
13
|
+
*/
|
|
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, {})] }));
|
|
16
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ToolCallState } from '../provider/types';
|
|
2
|
+
export interface ToolCallCardProps {
|
|
3
|
+
toolCallState: ToolCallState;
|
|
4
|
+
toolNameLabels?: Record<string, string>;
|
|
5
|
+
statusLabels?: Record<string, string>;
|
|
6
|
+
parametersLabel?: string;
|
|
7
|
+
resultLabel?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function ToolCallCard({ toolCallState, toolNameLabels, statusLabels, parametersLabel, resultLabel, }: ToolCallCardProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { CheckCircle, XCircle } from '@phosphor-icons/react/dist/ssr';
|
|
4
|
+
import { cn } from '../../../lib/utils';
|
|
5
|
+
const defaultStatusLabels = {
|
|
6
|
+
pending: '待機中',
|
|
7
|
+
executing: '実行中',
|
|
8
|
+
completed: '完了',
|
|
9
|
+
error: 'エラー',
|
|
10
|
+
};
|
|
11
|
+
const statusColors = {
|
|
12
|
+
pending: 'bg-muted text-muted-foreground',
|
|
13
|
+
executing: 'bg-primary/10 text-primary',
|
|
14
|
+
completed: 'bg-green-100 text-green-600 dark:bg-green-950 dark:text-green-400',
|
|
15
|
+
error: 'bg-destructive/10 text-destructive',
|
|
16
|
+
};
|
|
17
|
+
export function ToolCallCard({ toolCallState, toolNameLabels = {}, statusLabels, parametersLabel = 'パラメータ', resultLabel = '結果を表示', }) {
|
|
18
|
+
const { toolCall, status, result, error } = toolCallState;
|
|
19
|
+
const toolLabel = toolNameLabels[toolCall.toolName] || toolCall.toolName;
|
|
20
|
+
const mergedStatusLabels = statusLabels
|
|
21
|
+
? { ...defaultStatusLabels, ...statusLabels }
|
|
22
|
+
: defaultStatusLabels;
|
|
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 }))] }));
|
|
25
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { createContext, useContext } from 'react';
|
|
3
|
+
export const AgentContext = createContext(null);
|
|
4
|
+
export function useAgentContext() {
|
|
5
|
+
const context = useContext(AgentContext);
|
|
6
|
+
if (!context) {
|
|
7
|
+
throw new Error('useAgentContext must be used within an AgentProvider');
|
|
8
|
+
}
|
|
9
|
+
return context;
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { AgentProviderConfig } from './types';
|
|
3
|
+
export interface AgentProviderProps extends AgentProviderConfig {
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* エージェントチャット機能を提供する内部Provider
|
|
8
|
+
* 公開APIは AgentScreen / AgentPopupWidget を使用する。
|
|
9
|
+
*/
|
|
10
|
+
export declare function AgentProvider({ children, endpoint, agentId, apiBaseUrl, executeClientTool, onError, authToken, getAuthToken, }: AgentProviderProps): import("react/jsx-runtime").JSX.Element;
|