@agent-platform/ui 0.0.4 → 0.0.7
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 +5 -0
- package/dist/components/agent/agent-container-state.d.ts +2 -0
- package/dist/components/agent/agent-container-state.js +52 -0
- package/dist/components/agent/agent-container-view.d.ts +3 -0
- package/dist/components/agent/agent-container-view.js +22 -0
- package/dist/components/agent/agent-container-view.test.d.ts +1 -0
- package/dist/components/agent/agent-container-view.test.js +16 -0
- package/dist/components/agent/agent-container.d.ts +1 -1
- package/dist/components/agent/agent-container.js +6 -44
- package/dist/components/agent/agent-greeting.d.ts +1 -1
- package/dist/components/agent/agent-greeting.js +4 -4
- package/dist/components/agent/agent-header.d.ts +1 -1
- package/dist/components/agent/agent-header.js +6 -6
- package/dist/components/agent/agent-home-cards.d.ts +2 -2
- package/dist/components/agent/agent-home-cards.js +8 -6
- package/dist/components/agent/agent-screen.d.ts +1 -1
- package/dist/components/agent/agent-screen.js +5 -2
- package/dist/components/agent/approval-ui-model.d.ts +15 -0
- package/dist/components/agent/approval-ui-model.js +27 -0
- package/dist/components/agent/approval-ui-model.test.d.ts +1 -0
- package/dist/components/agent/approval-ui-model.test.js +39 -0
- package/dist/components/agent/defaults.d.ts +0 -6
- package/dist/components/agent/defaults.js +0 -11
- package/dist/components/agent/index.d.ts +0 -2
- package/dist/components/agent/index.js +0 -1
- package/dist/components/agent/input-mode.d.ts +5 -0
- package/dist/components/agent/input-mode.js +9 -0
- package/dist/components/agent/message/index.d.ts +1 -1
- package/dist/components/agent/message/index.js +1 -1
- package/dist/components/agent/message/message-item.js +3 -9
- package/dist/components/agent/message/message-list.js +6 -11
- package/dist/components/agent/message/message-loading.d.ts +0 -6
- package/dist/components/agent/message/message-loading.js +4 -10
- package/dist/components/agent/message/tool-call-card.js +3 -1
- package/dist/components/agent/message/utils.d.ts +8 -0
- package/dist/components/agent/message/utils.js +21 -0
- package/dist/components/agent/provider/agent-context.d.ts +1 -0
- package/dist/components/agent/provider/agent-context.js +3 -0
- package/dist/components/agent/provider/agent-provider.d.ts +1 -1
- package/dist/components/agent/provider/agent-provider.js +19 -5
- package/dist/components/agent/provider/index.d.ts +1 -1
- package/dist/components/agent/provider/runtime-config.js +14 -5
- package/dist/components/agent/provider/types.d.ts +17 -15
- package/dist/components/agent/provider/use-agent-chat.js +39 -8
- package/dist/components/agent/types.d.ts +28 -3
- package/dist/components/ui/button.d.ts +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/modules/agent/agent.repository.d.ts +58 -0
- package/dist/modules/agent/agent.repository.js +235 -0
- package/dist/modules/agent/agent.repository.test.d.ts +1 -0
- package/dist/modules/agent/agent.repository.test.js +64 -0
- package/dist/modules/agent/domain/chat-state.d.ts +64 -0
- package/dist/modules/agent/domain/chat-state.js +148 -0
- package/dist/modules/agent/domain/chat-state.test.d.ts +1 -0
- package/dist/modules/agent/domain/chat-state.test.js +72 -0
- package/dist/modules/agent/use-agent-chat.d.ts +6 -0
- package/dist/modules/agent/use-agent-chat.js +106 -0
- package/dist/modules/agent/usecases/process-stream.d.ts +26 -0
- package/dist/modules/agent/usecases/process-stream.js +112 -0
- package/dist/modules/agent/usecases/process-stream.test.d.ts +1 -0
- package/dist/modules/agent/usecases/process-stream.test.js +91 -0
- package/dist/modules/agent/usecases/send-message.d.ts +21 -0
- package/dist/modules/agent/usecases/send-message.js +298 -0
- package/dist/modules/agent/usecases/send-message.test.d.ts +1 -0
- package/dist/modules/agent/usecases/send-message.test.js +257 -0
- package/dist/styles/globals.css +10 -64
- package/package.json +3 -5
|
@@ -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,
|
|
10
|
+
export declare function AgentProvider({ children, agentId, onError, authToken, getAuthToken, getAgentHeaders, disableToolApiAuthHeader, toolApprovalLabels, }: AgentProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,26 +1,40 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useMemo } from 'react';
|
|
4
|
+
import { useAgentChat } from '../../../modules/agent/use-agent-chat';
|
|
3
5
|
import { AgentContext } from './agent-context';
|
|
4
6
|
import { resolveAgentRuntimeConfig } from './runtime-config';
|
|
5
|
-
import { useAgentChatInternal } from './use-agent-chat';
|
|
6
7
|
/**
|
|
7
8
|
* エージェントチャット機能を提供する内部Provider
|
|
8
9
|
* 公開APIは AgentScreen / AgentPopupWidget を使用する。
|
|
9
10
|
*/
|
|
10
|
-
export function AgentProvider({ children, agentId,
|
|
11
|
+
export function AgentProvider({ children, agentId, onError, authToken, getAuthToken, getAgentHeaders, disableToolApiAuthHeader, toolApprovalLabels, }) {
|
|
11
12
|
const runtimeConfig = resolveAgentRuntimeConfig();
|
|
12
|
-
const value =
|
|
13
|
+
const value = useAgentChat({
|
|
13
14
|
config: {
|
|
14
15
|
endpoint: runtimeConfig.endpoint,
|
|
15
16
|
agentId,
|
|
16
17
|
apiBaseUrl: runtimeConfig.apiBaseUrl,
|
|
17
|
-
executeClientTool,
|
|
18
18
|
onError,
|
|
19
19
|
authToken,
|
|
20
20
|
getAuthToken,
|
|
21
21
|
getAgentHeaders,
|
|
22
22
|
disableToolApiAuthHeader,
|
|
23
|
+
toolApprovalLabels,
|
|
23
24
|
},
|
|
24
25
|
});
|
|
25
|
-
|
|
26
|
+
const contextValue = useMemo(() => value, [
|
|
27
|
+
value.config,
|
|
28
|
+
value.clearChat,
|
|
29
|
+
value.error,
|
|
30
|
+
value.isLoading,
|
|
31
|
+
value.messages,
|
|
32
|
+
value.pendingToolCalls,
|
|
33
|
+
value.activeApprovalRequest,
|
|
34
|
+
value.approveToolCall,
|
|
35
|
+
value.rejectToolCall,
|
|
36
|
+
value.sendMessage,
|
|
37
|
+
value.threadId,
|
|
38
|
+
]);
|
|
39
|
+
return _jsx(AgentContext.Provider, { value: contextValue, children: children });
|
|
26
40
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { useAgentContext } from './agent-context';
|
|
2
2
|
export type { AgentProviderProps } from './agent-provider';
|
|
3
3
|
export { AgentProvider } from './agent-provider';
|
|
4
|
-
export type { AgentContextValue, AgentMessage, AgentProviderConfig,
|
|
4
|
+
export type { ActiveToolApprovalRequest, AgentContextValue, AgentMessage, AgentProviderConfig, ToolApprovalLabels, AgentStreamEvent, FinishPayload, MessageContentPart, ToolCallData, ToolCallState, ToolCallStatus, ToolResultData, } from './types';
|
|
@@ -1,15 +1,24 @@
|
|
|
1
1
|
const isDevelopment = process.env.NODE_ENV === 'development';
|
|
2
2
|
const PRODUCTION_AGENT_ENDPOINT = 'https://agent-server-prod--agent-platform-dev-8e3ae.asia-east1.hosted.app/api/agent';
|
|
3
3
|
const DEVELOPMENT_AGENT_ENDPOINT = 'http://localhost:3002/api/agent';
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
: 'https://demo-scout-api-prod--agent-platform-dev-8e3ae.asia-east1.hosted.app/api';
|
|
4
|
+
const PRODUCTION_API_BASE_URL = 'https://demo-scout-api-prod--agent-platform-dev-8e3ae.asia-east1.hosted.app/api';
|
|
5
|
+
const DEVELOPMENT_API_BASE_URL = 'http://localhost:3001/api';
|
|
7
6
|
function normalizeUrl(url) {
|
|
8
7
|
return url.replace(/\/$/, '');
|
|
9
8
|
}
|
|
10
9
|
export function resolveAgentRuntimeConfig() {
|
|
10
|
+
const endpoint = process.env.NEXT_PUBLIC_AGENT_ENDPOINT
|
|
11
|
+
? process.env.NEXT_PUBLIC_AGENT_ENDPOINT
|
|
12
|
+
: isDevelopment
|
|
13
|
+
? DEVELOPMENT_AGENT_ENDPOINT
|
|
14
|
+
: PRODUCTION_AGENT_ENDPOINT;
|
|
15
|
+
const apiBaseUrl = process.env.NEXT_PUBLIC_API_URL
|
|
16
|
+
? process.env.NEXT_PUBLIC_API_URL
|
|
17
|
+
: isDevelopment
|
|
18
|
+
? DEVELOPMENT_API_BASE_URL
|
|
19
|
+
: PRODUCTION_API_BASE_URL;
|
|
11
20
|
return {
|
|
12
|
-
endpoint: normalizeUrl(
|
|
13
|
-
apiBaseUrl: normalizeUrl(
|
|
21
|
+
endpoint: normalizeUrl(endpoint),
|
|
22
|
+
apiBaseUrl: normalizeUrl(apiBaseUrl),
|
|
14
23
|
};
|
|
15
24
|
}
|
|
@@ -2,7 +2,7 @@ export type { AgentStreamEvent, ToolCallData, ToolResultData, FinishPayload, Mes
|
|
|
2
2
|
/**
|
|
3
3
|
* ツール実行状態
|
|
4
4
|
*/
|
|
5
|
-
export type ToolCallStatus = 'pending' | 'executing' | 'completed' | 'error';
|
|
5
|
+
export type ToolCallStatus = 'pending' | 'awaiting-approval' | 'executing' | 'completed' | 'error';
|
|
6
6
|
/**
|
|
7
7
|
* ツールコール状態(UI表示用)
|
|
8
8
|
*/
|
|
@@ -12,25 +12,23 @@ export interface ToolCallState {
|
|
|
12
12
|
result?: unknown;
|
|
13
13
|
error?: string;
|
|
14
14
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
15
|
+
export interface ActiveToolApprovalRequest {
|
|
16
|
+
toolCall: import('@agent-platform/server').ToolCallData;
|
|
17
|
+
actionLabel: string;
|
|
18
|
+
riskLevel: 'read' | 'write' | 'destructive';
|
|
19
|
+
}
|
|
20
|
+
export interface ToolApprovalLabels {
|
|
21
|
+
title?: string;
|
|
22
|
+
description?: string;
|
|
23
|
+
approveButton?: string;
|
|
24
|
+
rejectButton?: string;
|
|
25
|
+
}
|
|
22
26
|
export type AgentHeadersProvider = () => Record<string, string> | Promise<Record<string, string>>;
|
|
23
27
|
/**
|
|
24
28
|
* AgentProvider設定
|
|
25
29
|
*/
|
|
26
30
|
export interface AgentProviderConfig {
|
|
27
31
|
agentId?: string;
|
|
28
|
-
/** 通信先URLは packages/ui 内部のruntime-configで解決される */
|
|
29
|
-
/**
|
|
30
|
-
* @deprecated 旧実装との後方互換用。
|
|
31
|
-
* executeOn: 'client' のツールをブラウザ側で実行するコールバック
|
|
32
|
-
*/
|
|
33
|
-
executeClientTool?: ClientToolExecutor;
|
|
34
32
|
onError?: (error: string) => void;
|
|
35
33
|
/** 静的なJWTトークン */
|
|
36
34
|
authToken?: string;
|
|
@@ -40,6 +38,8 @@ export interface AgentProviderConfig {
|
|
|
40
38
|
getAgentHeaders?: AgentHeadersProvider;
|
|
41
39
|
/** trueの場合、Tool APIへのAuthorizationヘッダー付与を無効化する */
|
|
42
40
|
disableToolApiAuthHeader?: boolean;
|
|
41
|
+
/** 承認UI文言の上書き */
|
|
42
|
+
toolApprovalLabels?: ToolApprovalLabels;
|
|
43
43
|
}
|
|
44
44
|
/**
|
|
45
45
|
* Agent通信先を解決済みの内部設定
|
|
@@ -57,8 +57,10 @@ export interface AgentContextValue {
|
|
|
57
57
|
isLoading: boolean;
|
|
58
58
|
error: string | null;
|
|
59
59
|
pendingToolCalls: ToolCallState[];
|
|
60
|
+
activeApprovalRequest: ActiveToolApprovalRequest | null;
|
|
61
|
+
approveToolCall: () => void;
|
|
62
|
+
rejectToolCall: () => void;
|
|
60
63
|
sendMessage: (message: string) => Promise<void>;
|
|
61
|
-
loadThread: (threadId: string) => Promise<void>;
|
|
62
64
|
clearChat: () => void;
|
|
63
65
|
config: ResolvedAgentRuntimeConfig;
|
|
64
66
|
}
|
|
@@ -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 ?
|
|
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] = {
|
|
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((
|
|
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
|
-
|
|
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 ?
|
|
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
|
-
|
|
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
|
|
467
|
+
setError(normalizeErrorMessage(e));
|
|
437
468
|
}
|
|
438
469
|
finally {
|
|
439
470
|
setIsLoading(false);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { ReactNode } from
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { ActiveToolApprovalRequest, ToolApprovalLabels, ToolCallState } from './provider/types';
|
|
2
3
|
export interface AgentHeaderProps {
|
|
3
4
|
historyLabel?: string;
|
|
4
5
|
onHistoryClick?: () => void;
|
|
@@ -31,9 +32,33 @@ export interface AgentInputProps {
|
|
|
31
32
|
isLoading?: boolean;
|
|
32
33
|
className?: string;
|
|
33
34
|
}
|
|
35
|
+
export interface AgentChatStateShape {
|
|
36
|
+
showHeader: boolean;
|
|
37
|
+
effectiveHeaderProps: AgentHeaderProps;
|
|
38
|
+
showGreeting: boolean;
|
|
39
|
+
greetingProps?: AgentGreetingProps;
|
|
40
|
+
showHomeCards: boolean;
|
|
41
|
+
cards?: AgentHomeCardProps[];
|
|
42
|
+
onCardClick?: (cardId: string) => void;
|
|
43
|
+
autoShowMessages: boolean;
|
|
44
|
+
showInput: boolean;
|
|
45
|
+
effectiveInputProps: AgentInputProps;
|
|
46
|
+
className?: string;
|
|
47
|
+
children?: ReactNode;
|
|
48
|
+
messages: import('@agent-platform/server').AgentMessage[];
|
|
49
|
+
pendingToolCalls: ToolCallState[];
|
|
50
|
+
activeApprovalRequest: ActiveToolApprovalRequest | null;
|
|
51
|
+
approveToolCall: () => void;
|
|
52
|
+
rejectToolCall: () => void;
|
|
53
|
+
toolApprovalLabels?: ToolApprovalLabels;
|
|
54
|
+
error: string | null;
|
|
55
|
+
isLoading: boolean;
|
|
56
|
+
mergedToolNameLabels: Record<string, string>;
|
|
57
|
+
hasMessages: boolean;
|
|
58
|
+
}
|
|
34
59
|
export interface AgentContainerProps {
|
|
35
60
|
showHeader?: boolean;
|
|
36
|
-
headerProps?: Omit<AgentHeaderProps,
|
|
61
|
+
headerProps?: Omit<AgentHeaderProps, 'className'>;
|
|
37
62
|
showGreeting?: boolean;
|
|
38
63
|
greetingProps?: AgentGreetingProps;
|
|
39
64
|
showHomeCards?: boolean;
|
|
@@ -50,7 +75,7 @@ export interface AgentContainerProps {
|
|
|
50
75
|
*/
|
|
51
76
|
autoShowMessages?: boolean;
|
|
52
77
|
showInput?: boolean;
|
|
53
|
-
inputProps?: Omit<AgentInputProps,
|
|
78
|
+
inputProps?: Omit<AgentInputProps, 'className'>;
|
|
54
79
|
className?: string;
|
|
55
80
|
children?: ReactNode;
|
|
56
81
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type VariantProps } from 'class-variance-authority';
|
|
2
2
|
import type * as React from 'react';
|
|
3
3
|
declare const buttonVariants: (props?: ({
|
|
4
|
-
variant?: "
|
|
4
|
+
variant?: "destructive" | "link" | "default" | "outline" | "secondary" | "ghost" | 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
7
|
declare function Button({ className, variant, size, asChild, ...props }: React.ComponentProps<'button'> & VariantProps<typeof buttonVariants> & {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { AgentScreen
|
|
2
|
-
export type { AgentScreenProps,
|
|
1
|
+
export { AgentScreen } from './components/agent';
|
|
2
|
+
export type { AgentScreenProps, AgentHomeCardProps } from './components/agent';
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { AgentScreen
|
|
1
|
+
export { AgentScreen } from './components/agent';
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { AgentStreamEvent, ToolCallData } from '../../components/agent/provider/types';
|
|
2
|
+
export interface ToolExecutionResult {
|
|
3
|
+
output: unknown;
|
|
4
|
+
isError?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export interface ContinuePayload {
|
|
7
|
+
threadId: string | null;
|
|
8
|
+
agentId: string;
|
|
9
|
+
toolResults: {
|
|
10
|
+
toolCallId: string;
|
|
11
|
+
result: unknown;
|
|
12
|
+
isError?: boolean;
|
|
13
|
+
}[];
|
|
14
|
+
toolCalls: {
|
|
15
|
+
toolCallId: string;
|
|
16
|
+
toolName: string;
|
|
17
|
+
args: unknown;
|
|
18
|
+
}[];
|
|
19
|
+
}
|
|
20
|
+
export interface SendChatParams {
|
|
21
|
+
endpoint: string;
|
|
22
|
+
threadId: string | null;
|
|
23
|
+
message: string;
|
|
24
|
+
agentId: string;
|
|
25
|
+
headers: Record<string, string>;
|
|
26
|
+
signal?: AbortSignal;
|
|
27
|
+
}
|
|
28
|
+
export interface ContinueChatParams {
|
|
29
|
+
endpoint: string;
|
|
30
|
+
payload: ContinuePayload;
|
|
31
|
+
headers: Record<string, string>;
|
|
32
|
+
signal?: AbortSignal;
|
|
33
|
+
}
|
|
34
|
+
export interface ExecuteToolCallParams {
|
|
35
|
+
toolCall: ToolCallData;
|
|
36
|
+
apiBaseUrl: string;
|
|
37
|
+
authHeaders: Record<string, string>;
|
|
38
|
+
}
|
|
39
|
+
export interface AgentRepository {
|
|
40
|
+
buildAgentHeaders: (getAgentHeaders?: () => Record<string, string> | Promise<Record<string, string>>) => Promise<Record<string, string>>;
|
|
41
|
+
buildToolApiHeaders: () => Promise<Record<string, string>>;
|
|
42
|
+
sendChat: (params: SendChatParams) => Promise<Response>;
|
|
43
|
+
continueChat: (params: ContinueChatParams) => Promise<Response>;
|
|
44
|
+
collectStreamEvents: (response: Response, options?: CollectStreamEventsOptions) => Promise<AgentStreamEvent[]>;
|
|
45
|
+
executeToolCall: (params: ExecuteToolCallParams) => Promise<ToolExecutionResult>;
|
|
46
|
+
parseErrorResponse: (response: Response, fallback: string) => Promise<string>;
|
|
47
|
+
}
|
|
48
|
+
export interface CollectStreamEventsOptions {
|
|
49
|
+
onEvents?: (events: AgentStreamEvent[]) => void;
|
|
50
|
+
}
|
|
51
|
+
interface CreateAgentRepositoryOptions {
|
|
52
|
+
fetchFn?: typeof fetch;
|
|
53
|
+
authToken?: string;
|
|
54
|
+
getAuthToken?: () => string | Promise<string>;
|
|
55
|
+
disableToolApiAuthHeader?: boolean;
|
|
56
|
+
}
|
|
57
|
+
export declare function createAgentRepository(options: CreateAgentRepositoryOptions): AgentRepository;
|
|
58
|
+
export {};
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
function parseSSEBuffer(buffer) {
|
|
2
|
+
const events = [];
|
|
3
|
+
const lines = buffer.split('\n');
|
|
4
|
+
const remaining = lines.pop() || '';
|
|
5
|
+
for (const line of lines) {
|
|
6
|
+
if (!line.startsWith('data: ')) {
|
|
7
|
+
continue;
|
|
8
|
+
}
|
|
9
|
+
const jsonString = line.slice(6);
|
|
10
|
+
if (!jsonString) {
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
const event = JSON.parse(jsonString);
|
|
15
|
+
events.push(event);
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
console.warn('Failed to parse SSE event:', error);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return { events, remaining };
|
|
22
|
+
}
|
|
23
|
+
function isLikelyJwtToken(token) {
|
|
24
|
+
const normalized = token.startsWith('Bearer ') ? token.slice(7) : token;
|
|
25
|
+
return normalized.split('.').length === 3;
|
|
26
|
+
}
|
|
27
|
+
function buildToolEndpointRequest(toolCall, apiBaseUrl) {
|
|
28
|
+
if (!toolCall.apiRequest) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
const { apiRequest, input } = toolCall;
|
|
32
|
+
const inputData = (input ?? {});
|
|
33
|
+
const method = apiRequest.method.toUpperCase();
|
|
34
|
+
let path = apiRequest.path;
|
|
35
|
+
const usedParams = new Set();
|
|
36
|
+
for (const paramName of apiRequest.pathParams) {
|
|
37
|
+
const value = inputData[paramName];
|
|
38
|
+
if (value === undefined) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
path = path.replace(`{${paramName}}`, encodeURIComponent(String(value)));
|
|
42
|
+
usedParams.add(paramName);
|
|
43
|
+
}
|
|
44
|
+
const queryParams = {};
|
|
45
|
+
const bodyData = {};
|
|
46
|
+
for (const key of apiRequest.queryParams) {
|
|
47
|
+
const value = inputData[key];
|
|
48
|
+
if (value === undefined) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
queryParams[key] = String(value);
|
|
52
|
+
usedParams.add(key);
|
|
53
|
+
}
|
|
54
|
+
for (const key of apiRequest.bodyFields) {
|
|
55
|
+
const value = inputData[key];
|
|
56
|
+
if (value === undefined) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
bodyData[key] = value;
|
|
60
|
+
usedParams.add(key);
|
|
61
|
+
}
|
|
62
|
+
for (const [key, value] of Object.entries(inputData)) {
|
|
63
|
+
if (usedParams.has(key) || value === undefined) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (method === 'GET' || method === 'DELETE') {
|
|
67
|
+
queryParams[key] = String(value);
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
bodyData[key] = value;
|
|
71
|
+
}
|
|
72
|
+
const queryString = new URLSearchParams(queryParams).toString();
|
|
73
|
+
return {
|
|
74
|
+
method,
|
|
75
|
+
url: `${apiBaseUrl}${path}${queryString ? `?${queryString}` : ''}`,
|
|
76
|
+
bodyData,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
export function createAgentRepository(options) {
|
|
80
|
+
const { fetchFn = fetch, authToken, getAuthToken, disableToolApiAuthHeader = false, } = options;
|
|
81
|
+
const resolveToken = async () => {
|
|
82
|
+
return getAuthToken ? getAuthToken() : authToken;
|
|
83
|
+
};
|
|
84
|
+
return {
|
|
85
|
+
buildAgentHeaders: async (getAgentHeaders) => {
|
|
86
|
+
const headers = {
|
|
87
|
+
'Content-Type': 'application/json',
|
|
88
|
+
};
|
|
89
|
+
const token = await resolveToken();
|
|
90
|
+
if (token) {
|
|
91
|
+
headers.Authorization = token.startsWith('Bearer ') ? token : `Bearer ${token}`;
|
|
92
|
+
}
|
|
93
|
+
const customHeaders = getAgentHeaders ? await getAgentHeaders() : undefined;
|
|
94
|
+
if (!customHeaders) {
|
|
95
|
+
return headers;
|
|
96
|
+
}
|
|
97
|
+
for (const [key, value] of Object.entries(customHeaders)) {
|
|
98
|
+
if (value) {
|
|
99
|
+
headers[key] = value;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return headers;
|
|
103
|
+
},
|
|
104
|
+
buildToolApiHeaders: async () => {
|
|
105
|
+
const headers = {};
|
|
106
|
+
if (disableToolApiAuthHeader) {
|
|
107
|
+
return headers;
|
|
108
|
+
}
|
|
109
|
+
const token = await resolveToken();
|
|
110
|
+
if (!token) {
|
|
111
|
+
return headers;
|
|
112
|
+
}
|
|
113
|
+
const resolvedToken = token.startsWith('Bearer ') ? token : `Bearer ${token}`;
|
|
114
|
+
if (!isLikelyJwtToken(resolvedToken)) {
|
|
115
|
+
return headers;
|
|
116
|
+
}
|
|
117
|
+
headers.Authorization = resolvedToken;
|
|
118
|
+
return headers;
|
|
119
|
+
},
|
|
120
|
+
sendChat: async ({ endpoint, threadId, message, agentId, headers, signal }) => {
|
|
121
|
+
return fetchFn(`${endpoint}/chat`, {
|
|
122
|
+
method: 'POST',
|
|
123
|
+
headers,
|
|
124
|
+
credentials: 'include',
|
|
125
|
+
body: JSON.stringify({ threadId, message, agentId }),
|
|
126
|
+
signal,
|
|
127
|
+
});
|
|
128
|
+
},
|
|
129
|
+
continueChat: async ({ endpoint, payload, headers, signal }) => {
|
|
130
|
+
return fetchFn(`${endpoint}/chat/tool-result`, {
|
|
131
|
+
method: 'POST',
|
|
132
|
+
headers,
|
|
133
|
+
credentials: 'include',
|
|
134
|
+
body: JSON.stringify(payload),
|
|
135
|
+
signal,
|
|
136
|
+
});
|
|
137
|
+
},
|
|
138
|
+
collectStreamEvents: async (response, options) => {
|
|
139
|
+
const reader = response.body?.getReader();
|
|
140
|
+
if (!reader) {
|
|
141
|
+
return [];
|
|
142
|
+
}
|
|
143
|
+
const decoder = new TextDecoder();
|
|
144
|
+
const events = [];
|
|
145
|
+
let buffer = '';
|
|
146
|
+
try {
|
|
147
|
+
while (true) {
|
|
148
|
+
const { done, value } = await reader.read();
|
|
149
|
+
if (done) {
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
buffer += decoder.decode(value, { stream: true });
|
|
153
|
+
const parsed = parseSSEBuffer(buffer);
|
|
154
|
+
buffer = parsed.remaining;
|
|
155
|
+
events.push(...parsed.events);
|
|
156
|
+
if (parsed.events.length > 0) {
|
|
157
|
+
options?.onEvents?.(parsed.events);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (buffer.startsWith('data: ')) {
|
|
161
|
+
try {
|
|
162
|
+
const event = JSON.parse(buffer.slice(6));
|
|
163
|
+
events.push(event);
|
|
164
|
+
options?.onEvents?.([event]);
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
console.warn('Failed to parse remaining SSE event:', error);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return events;
|
|
171
|
+
}
|
|
172
|
+
finally {
|
|
173
|
+
reader.releaseLock();
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
executeToolCall: async ({ toolCall, apiBaseUrl, authHeaders }) => {
|
|
177
|
+
const request = buildToolEndpointRequest(toolCall, apiBaseUrl);
|
|
178
|
+
if (!request) {
|
|
179
|
+
return { output: 'No API endpoint defined for this tool', isError: true };
|
|
180
|
+
}
|
|
181
|
+
try {
|
|
182
|
+
const fetchOptions = {
|
|
183
|
+
method: request.method,
|
|
184
|
+
headers: {
|
|
185
|
+
'Content-Type': 'application/json',
|
|
186
|
+
...authHeaders,
|
|
187
|
+
},
|
|
188
|
+
credentials: 'include',
|
|
189
|
+
};
|
|
190
|
+
if ((request.method === 'POST' || request.method === 'PUT' || request.method === 'PATCH') &&
|
|
191
|
+
Object.keys(request.bodyData).length > 0) {
|
|
192
|
+
fetchOptions.body = JSON.stringify(request.bodyData);
|
|
193
|
+
}
|
|
194
|
+
const response = await fetchFn(request.url, fetchOptions);
|
|
195
|
+
const text = await response.text();
|
|
196
|
+
let data;
|
|
197
|
+
try {
|
|
198
|
+
data = text ? JSON.parse(text) : null;
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
data = { raw: text, status: response.status };
|
|
202
|
+
}
|
|
203
|
+
if (!response.ok) {
|
|
204
|
+
return { output: data, isError: true };
|
|
205
|
+
}
|
|
206
|
+
return { output: data };
|
|
207
|
+
}
|
|
208
|
+
catch (error) {
|
|
209
|
+
return {
|
|
210
|
+
output: error instanceof Error ? error.message : 'Network error',
|
|
211
|
+
isError: true,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
parseErrorResponse: async (response, fallback) => {
|
|
216
|
+
let errorMessage = fallback;
|
|
217
|
+
try {
|
|
218
|
+
const contentType = response.headers.get('content-type');
|
|
219
|
+
if (contentType?.includes('application/json')) {
|
|
220
|
+
const errorData = await response.json();
|
|
221
|
+
if (typeof errorData?.error === 'string') {
|
|
222
|
+
return errorData.error;
|
|
223
|
+
}
|
|
224
|
+
if (typeof errorData?.message === 'string') {
|
|
225
|
+
return errorData.message;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
catch (error) {
|
|
230
|
+
console.warn('Failed to parse error response:', error);
|
|
231
|
+
}
|
|
232
|
+
return errorMessage;
|
|
233
|
+
},
|
|
234
|
+
};
|
|
235
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|