@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.
Files changed (68) hide show
  1. package/README.md +5 -0
  2. package/dist/components/agent/agent-container-state.d.ts +2 -0
  3. package/dist/components/agent/agent-container-state.js +52 -0
  4. package/dist/components/agent/agent-container-view.d.ts +3 -0
  5. package/dist/components/agent/agent-container-view.js +22 -0
  6. package/dist/components/agent/agent-container-view.test.d.ts +1 -0
  7. package/dist/components/agent/agent-container-view.test.js +16 -0
  8. package/dist/components/agent/agent-container.d.ts +1 -1
  9. package/dist/components/agent/agent-container.js +6 -44
  10. package/dist/components/agent/agent-greeting.d.ts +1 -1
  11. package/dist/components/agent/agent-greeting.js +4 -4
  12. package/dist/components/agent/agent-header.d.ts +1 -1
  13. package/dist/components/agent/agent-header.js +6 -6
  14. package/dist/components/agent/agent-home-cards.d.ts +2 -2
  15. package/dist/components/agent/agent-home-cards.js +8 -6
  16. package/dist/components/agent/agent-screen.d.ts +1 -1
  17. package/dist/components/agent/agent-screen.js +5 -2
  18. package/dist/components/agent/approval-ui-model.d.ts +15 -0
  19. package/dist/components/agent/approval-ui-model.js +27 -0
  20. package/dist/components/agent/approval-ui-model.test.d.ts +1 -0
  21. package/dist/components/agent/approval-ui-model.test.js +39 -0
  22. package/dist/components/agent/defaults.d.ts +0 -6
  23. package/dist/components/agent/defaults.js +0 -11
  24. package/dist/components/agent/index.d.ts +0 -2
  25. package/dist/components/agent/index.js +0 -1
  26. package/dist/components/agent/input-mode.d.ts +5 -0
  27. package/dist/components/agent/input-mode.js +9 -0
  28. package/dist/components/agent/message/index.d.ts +1 -1
  29. package/dist/components/agent/message/index.js +1 -1
  30. package/dist/components/agent/message/message-item.js +3 -9
  31. package/dist/components/agent/message/message-list.js +6 -11
  32. package/dist/components/agent/message/message-loading.d.ts +0 -6
  33. package/dist/components/agent/message/message-loading.js +4 -10
  34. package/dist/components/agent/message/tool-call-card.js +3 -1
  35. package/dist/components/agent/message/utils.d.ts +8 -0
  36. package/dist/components/agent/message/utils.js +21 -0
  37. package/dist/components/agent/provider/agent-context.d.ts +1 -0
  38. package/dist/components/agent/provider/agent-context.js +3 -0
  39. package/dist/components/agent/provider/agent-provider.d.ts +1 -1
  40. package/dist/components/agent/provider/agent-provider.js +19 -5
  41. package/dist/components/agent/provider/index.d.ts +1 -1
  42. package/dist/components/agent/provider/runtime-config.js +14 -5
  43. package/dist/components/agent/provider/types.d.ts +17 -15
  44. package/dist/components/agent/provider/use-agent-chat.js +39 -8
  45. package/dist/components/agent/types.d.ts +28 -3
  46. package/dist/components/ui/button.d.ts +1 -1
  47. package/dist/index.d.ts +2 -2
  48. package/dist/index.js +1 -1
  49. package/dist/modules/agent/agent.repository.d.ts +58 -0
  50. package/dist/modules/agent/agent.repository.js +235 -0
  51. package/dist/modules/agent/agent.repository.test.d.ts +1 -0
  52. package/dist/modules/agent/agent.repository.test.js +64 -0
  53. package/dist/modules/agent/domain/chat-state.d.ts +64 -0
  54. package/dist/modules/agent/domain/chat-state.js +148 -0
  55. package/dist/modules/agent/domain/chat-state.test.d.ts +1 -0
  56. package/dist/modules/agent/domain/chat-state.test.js +72 -0
  57. package/dist/modules/agent/use-agent-chat.d.ts +6 -0
  58. package/dist/modules/agent/use-agent-chat.js +106 -0
  59. package/dist/modules/agent/usecases/process-stream.d.ts +26 -0
  60. package/dist/modules/agent/usecases/process-stream.js +112 -0
  61. package/dist/modules/agent/usecases/process-stream.test.d.ts +1 -0
  62. package/dist/modules/agent/usecases/process-stream.test.js +91 -0
  63. package/dist/modules/agent/usecases/send-message.d.ts +21 -0
  64. package/dist/modules/agent/usecases/send-message.js +298 -0
  65. package/dist/modules/agent/usecases/send-message.test.d.ts +1 -0
  66. package/dist/modules/agent/usecases/send-message.test.js +257 -0
  67. package/dist/styles/globals.css +10 -64
  68. 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, executeClientTool, onError, authToken, getAuthToken, getAgentHeaders, disableToolApiAuthHeader, }: AgentProviderProps): import("react/jsx-runtime").JSX.Element;
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, executeClientTool, onError, authToken, getAuthToken, getAgentHeaders, disableToolApiAuthHeader, }) {
11
+ export function AgentProvider({ children, agentId, onError, authToken, getAuthToken, getAgentHeaders, disableToolApiAuthHeader, toolApprovalLabels, }) {
11
12
  const runtimeConfig = resolveAgentRuntimeConfig();
12
- const value = useAgentChatInternal({
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
- return _jsx(AgentContext.Provider, { value: value, children: children });
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, AgentStreamEvent, ClientToolExecutor, FinishPayload, MessageContentPart, ToolCallData, ToolCallState, ToolCallStatus, ToolResultData, } from './types';
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 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';
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(isDevelopment ? DEVELOPMENT_AGENT_ENDPOINT : PRODUCTION_AGENT_ENDPOINT),
13
- apiBaseUrl: normalizeUrl(FIXED_API_BASE_URL),
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
- export type ClientToolExecutor = (toolCall: import('@agent-platform/server').ToolCallData) => Promise<{
19
- output: unknown;
20
- isError?: boolean;
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 ? String(tr.result) : undefined,
81
+ error: tr.isError ? normalizeErrorMessage(tr.result) : undefined,
59
82
  });
60
83
  }
61
84
  return newMap;
@@ -67,7 +90,12 @@ function handleFinish(assistantMessageId, setMessages) {
67
90
  const idx = updated.findIndex((m) => m.id === assistantMessageId);
68
91
  const existing = idx >= 0 ? updated[idx] : undefined;
69
92
  if (existing) {
70
- updated[idx] = { id: existing.id, role: existing.role, content: existing.content, isStreaming: false };
93
+ updated[idx] = {
94
+ id: existing.id,
95
+ role: existing.role,
96
+ content: existing.content,
97
+ isStreaming: false,
98
+ };
71
99
  }
72
100
  return updated;
73
101
  });
@@ -173,6 +201,7 @@ export function useAgentChatInternal(options) {
173
201
  const buildAgentHeaders = useCallback(async () => {
174
202
  const headers = { 'Content-Type': 'application/json' };
175
203
  const token = getAuthToken ? await getAuthToken() : authToken;
204
+ console.log('[buildAgentHeaders] Building headers for agent request: ', token ? 'with auth' : 'no auth');
176
205
  if (token) {
177
206
  headers['Authorization'] = token.startsWith('Bearer ') ? token : `Bearer ${token}`;
178
207
  }
@@ -186,7 +215,8 @@ export function useAgentChatInternal(options) {
186
215
  }
187
216
  return headers;
188
217
  }, [authToken, getAuthToken, getAgentHeaders]);
189
- const handleError = useCallback((errorMessage) => {
218
+ const handleError = useCallback((errorInput) => {
219
+ const errorMessage = normalizeErrorMessage(errorInput);
190
220
  setError(errorMessage);
191
221
  onError?.(errorMessage);
192
222
  }, [onError]);
@@ -255,7 +285,9 @@ export function useAgentChatInternal(options) {
255
285
  const toolApiHeaders = {};
256
286
  if (!disableToolApiAuthHeader) {
257
287
  const token = getAuthToken ? await getAuthToken() : authToken;
258
- if (token) {
288
+ // Tool APIはcredentials: 'include'でCookie送信されるため、
289
+ // 非JWT(例: ANON_KEY)はAuthorizationヘッダーに載せずCookie認証を優先する。
290
+ if (token && isLikelyJwtToken(token)) {
259
291
  toolApiHeaders['Authorization'] = token.startsWith('Bearer ') ? token : `Bearer ${token}`;
260
292
  }
261
293
  }
@@ -297,7 +329,7 @@ export function useAgentChatInternal(options) {
297
329
  toolCall: tc,
298
330
  status: isError ? 'error' : 'completed',
299
331
  result: result.output,
300
- error: isError ? String(result.output) : undefined,
332
+ error: isError ? normalizeErrorMessage(result.output) : undefined,
301
333
  });
302
334
  return newMap;
303
335
  });
@@ -403,8 +435,7 @@ export function useAgentChatInternal(options) {
403
435
  catch (e) {
404
436
  if (e instanceof Error && e.name === 'AbortError')
405
437
  return;
406
- const errorMessage = e instanceof Error ? e.message : 'Unknown error';
407
- handleError(errorMessage);
438
+ handleError(e);
408
439
  }
409
440
  finally {
410
441
  setIsLoading(false);
@@ -433,7 +464,7 @@ export function useAgentChatInternal(options) {
433
464
  })) || []);
434
465
  }
435
466
  catch (e) {
436
- setError(e instanceof Error ? e.message : 'Unknown error');
467
+ setError(normalizeErrorMessage(e));
437
468
  }
438
469
  finally {
439
470
  setIsLoading(false);
@@ -1,4 +1,5 @@
1
- import type { ReactNode } from "react";
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, "className">;
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, "className">;
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?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | null | undefined;
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, AgentPopupWidget } from './components/agent';
2
- export type { AgentScreenProps, AgentPopupWidgetProps, AgentHomeCardProps, } from './components/agent';
1
+ export { AgentScreen } from './components/agent';
2
+ export type { AgentScreenProps, AgentHomeCardProps } from './components/agent';
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- export { AgentScreen, AgentPopupWidget } from './components/agent';
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 {};