@lobehub/chat 1.0.11 → 1.0.13

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 (66) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/locales/ar/setting.json +5 -0
  3. package/locales/bg-BG/setting.json +5 -0
  4. package/locales/de-DE/setting.json +5 -0
  5. package/locales/en-US/setting.json +5 -0
  6. package/locales/es-ES/setting.json +5 -0
  7. package/locales/fr-FR/setting.json +5 -0
  8. package/locales/it-IT/setting.json +5 -0
  9. package/locales/ja-JP/setting.json +5 -0
  10. package/locales/ko-KR/setting.json +5 -0
  11. package/locales/nl-NL/setting.json +5 -0
  12. package/locales/pl-PL/setting.json +5 -0
  13. package/locales/pt-BR/setting.json +5 -0
  14. package/locales/ru-RU/setting.json +5 -0
  15. package/locales/tr-TR/setting.json +5 -0
  16. package/locales/vi-VN/setting.json +5 -0
  17. package/locales/zh-CN/setting.json +5 -0
  18. package/locales/zh-TW/setting.json +5 -0
  19. package/package.json +4 -3
  20. package/src/app/(main)/chat/(workspace)/@conversation/default.tsx +1 -1
  21. package/src/app/(main)/chat/settings/features/EditPage.tsx +2 -2
  22. package/src/app/(main)/settings/agent/index.tsx +1 -1
  23. package/src/app/(main)/settings/system-agent/features/AgentMeta.tsx +58 -0
  24. package/src/app/(main)/settings/system-agent/features/Topic.tsx +1 -0
  25. package/src/app/(main)/settings/system-agent/features/Translation.tsx +1 -0
  26. package/src/app/(main)/settings/system-agent/index.tsx +2 -0
  27. package/src/app/(main)/settings/system-agent/page.tsx +1 -1
  28. package/src/const/settings/systemAgent.ts +1 -0
  29. package/src/features/AgentSetting/AgentMeta/AutoGenerateAvatar.tsx +59 -0
  30. package/src/features/AgentSetting/AgentMeta/index.tsx +6 -9
  31. package/src/features/AgentSetting/AgentSettings.tsx +24 -0
  32. package/src/features/AgentSetting/AgentSettingsStore.tsx +14 -0
  33. package/src/features/AgentSetting/StoreUpdater.tsx +10 -5
  34. package/src/features/AgentSetting/hooks/useAgentSettings.ts +31 -0
  35. package/src/features/AgentSetting/index.tsx +3 -26
  36. package/src/features/AgentSetting/store/action.ts +36 -18
  37. package/src/features/ChatInput/useSend.ts +8 -0
  38. package/src/features/Conversation/Error/ErrorJsonViewer.tsx +1 -1
  39. package/src/features/Conversation/Messages/Assistant/ToolCalls/index.tsx +3 -2
  40. package/src/features/Conversation/Messages/Tool/index.tsx +3 -5
  41. package/src/features/Conversation/Messages/components/Arguments.tsx +20 -0
  42. package/src/features/Conversation/Messages/hooks/useYamlArguments.ts +11 -0
  43. package/src/features/ModelSelect/index.tsx +6 -4
  44. package/src/libs/agent-runtime/anthropic/index.test.ts +1 -31
  45. package/src/libs/agent-runtime/anthropic/index.ts +9 -63
  46. package/src/libs/agent-runtime/openai/index.test.ts +7 -7
  47. package/src/libs/agent-runtime/openai/index.ts +0 -6
  48. package/src/libs/agent-runtime/utils/anthropicHelpers.ts +2 -2
  49. package/src/libs/agent-runtime/utils/streams/anthropic.test.ts +102 -28
  50. package/src/libs/agent-runtime/utils/streams/anthropic.ts +29 -12
  51. package/src/libs/agent-runtime/utils/streams/protocol.ts +6 -1
  52. package/src/locales/default/setting.ts +5 -0
  53. package/src/services/message/server.ts +4 -0
  54. package/src/services/message/type.ts +1 -1
  55. package/src/store/agent/slices/chat/initialState.ts +2 -0
  56. package/src/store/chat/slices/message/action.ts +48 -48
  57. package/src/store/chat/slices/message/initialState.ts +2 -0
  58. package/src/store/chat/slices/message/selectors.ts +3 -0
  59. package/src/store/chat/slices/plugin/action.test.ts +15 -15
  60. package/src/store/chat/slices/plugin/action.ts +128 -115
  61. package/src/store/chat/utils/index.ts +19 -0
  62. package/src/store/user/slices/settings/action.ts +8 -2
  63. package/src/store/user/slices/settings/selectors/systemAgent.ts +2 -0
  64. package/src/types/message/index.ts +1 -1
  65. package/src/types/user/settings/systemAgent.ts +3 -0
  66. /package/src/{components/StoreHydration → app/(main)/chat/(workspace)/@conversation/features}/ChatHydration/index.tsx +0 -0
@@ -0,0 +1,31 @@
1
+ import { useMemo } from 'react';
2
+
3
+ import { useStoreApi } from '../store';
4
+ import { PublicAction } from '../store/action';
5
+
6
+ export type AgentSettingsInstance = PublicAction;
7
+
8
+ export const useAgentSettings = (): AgentSettingsInstance => {
9
+ const storeApi = useStoreApi();
10
+
11
+ const {
12
+ autocompleteMeta,
13
+ autocompleteAllMeta,
14
+ autocompleteAgentTitle,
15
+ autocompleteAgentDescription,
16
+ autocompleteAgentTags,
17
+ autoPickEmoji,
18
+ } = storeApi.getState();
19
+
20
+ return useMemo(
21
+ () => ({
22
+ autoPickEmoji,
23
+ autocompleteAgentDescription,
24
+ autocompleteAgentTags,
25
+ autocompleteAgentTitle,
26
+ autocompleteAllMeta,
27
+ autocompleteMeta,
28
+ }),
29
+ [],
30
+ );
31
+ };
@@ -1,26 +1,3 @@
1
- import AgentChat from './AgentChat';
2
- import AgentMeta from './AgentMeta';
3
- import AgentModal from './AgentModal';
4
- import AgentPlugin from './AgentPlugin';
5
- import AgentPrompt from './AgentPrompt';
6
- import AgentTTS from './AgentTTS';
7
- import StoreUpdater, { StoreUpdaterProps } from './StoreUpdater';
8
- import { Provider, createStore } from './store';
9
-
10
- type AgentSettingsProps = StoreUpdaterProps;
11
-
12
- const AgentSettings = (props: AgentSettingsProps) => {
13
- return (
14
- <Provider createStore={createStore}>
15
- <StoreUpdater {...props} />
16
- <AgentPrompt />
17
- <AgentMeta />
18
- <AgentChat />
19
- <AgentModal />
20
- <AgentTTS />
21
- <AgentPlugin />
22
- </Provider>
23
- );
24
- };
25
-
26
- export default AgentSettings;
1
+ export { AgentSettings } from './AgentSettings';
2
+ export { AgentSettingsStore } from './AgentSettingsStore';
3
+ export type { AgentSettingsInstance } from './hooks/useAgentSettings';
@@ -7,9 +7,13 @@ import { chainSummaryDescription } from '@/chains/summaryDescription';
7
7
  import { chainSummaryTags } from '@/chains/summaryTags';
8
8
  import { TraceNameMap, TracePayload, TraceTopicType } from '@/const/trace';
9
9
  import { chatService } from '@/services/chat';
10
+ import { useUserStore } from '@/store/user';
11
+ import { systemAgentSelectors } from '@/store/user/slices/settings/selectors';
10
12
  import { LobeAgentChatConfig, LobeAgentConfig } from '@/types/agent';
11
13
  import { MetaData } from '@/types/meta';
14
+ import { SystemAgentItem } from '@/types/user/settings';
12
15
  import { MessageTextChunk } from '@/utils/fetch';
16
+ import { merge } from '@/utils/merge';
13
17
  import { setNamespace } from '@/utils/storeDebug';
14
18
 
15
19
  import { SessionLoadingState } from '../store/initialState';
@@ -17,15 +21,12 @@ import { State, initialState } from './initialState';
17
21
  import { ConfigDispatch, configReducer } from './reducers/config';
18
22
  import { MetaDataDispatch, metaDataReducer } from './reducers/meta';
19
23
 
20
- /**
21
- * 设置操作
22
- */
23
- export interface Action {
24
+ export interface PublicAction {
24
25
  /**
25
26
  * 自动选择表情
26
27
  * @param id - 表情的 ID
27
28
  */
28
- autoPickEmoji: () => void;
29
+ autoPickEmoji: () => Promise<void>;
29
30
  /**
30
31
  * 自动完成代理描述
31
32
  * @param id - 代理的 ID
@@ -44,20 +45,25 @@ export interface Action {
44
45
  */
45
46
  autocompleteAllMeta: (replace?: boolean) => void;
46
47
  autocompleteMeta: (key: keyof MetaData) => void;
48
+ }
49
+
50
+ export interface Action extends PublicAction {
47
51
  dispatchConfig: (payload: ConfigDispatch) => void;
48
52
  dispatchMeta: (payload: MetaDataDispatch) => void;
49
53
  getCurrentTracePayload: (data: Partial<TracePayload>) => TracePayload;
50
54
 
55
+ internal_getSystemAgentForMeta: () => SystemAgentItem;
51
56
  resetAgentConfig: () => void;
52
- resetAgentMeta: () => void;
53
57
 
58
+ resetAgentMeta: () => void;
54
59
  setAgentConfig: (config: DeepPartial<LobeAgentConfig>) => void;
55
60
  setAgentMeta: (meta: Partial<MetaData>) => void;
56
- setChatConfig: (config: Partial<LobeAgentChatConfig>) => void;
57
61
 
62
+ setChatConfig: (config: Partial<LobeAgentChatConfig>) => void;
58
63
  streamUpdateMetaArray: (key: keyof MetaData) => any;
59
64
  streamUpdateMetaString: (key: keyof MetaData) => any;
60
65
  toggleAgentPlugin: (pluginId: string, state?: boolean) => void;
66
+
61
67
  /**
62
68
  * 更新加载状态
63
69
  * @param key - SessionLoadingState 的键
@@ -77,17 +83,19 @@ export const store: StateCreator<Store, [['zustand/devtools', never]]> = (set, g
77
83
 
78
84
  const systemRole = config.systemRole;
79
85
 
80
- const emoji = await chatService.fetchPresetTaskResult({
86
+ chatService.fetchPresetTaskResult({
87
+ onFinish: async (emoji) => {
88
+ dispatchMeta({ type: 'update', value: { avatar: emoji } });
89
+ },
81
90
  onLoadingChange: (loading) => {
82
91
  get().updateLoadingState('avatar', loading);
83
92
  },
84
- params: chainPickEmoji([meta.title, meta.description, systemRole].filter(Boolean).join(',')),
93
+ params: merge(
94
+ get().internal_getSystemAgentForMeta(),
95
+ chainPickEmoji([meta.title, meta.description, systemRole].filter(Boolean).join(',')),
96
+ ),
85
97
  trace: get().getCurrentTracePayload({ traceName: TraceNameMap.EmojiPicker }),
86
98
  });
87
-
88
- if (emoji) {
89
- dispatchMeta({ type: 'update', value: { avatar: emoji } });
90
- }
91
99
  },
92
100
  autocompleteAgentDescription: async () => {
93
101
  const { dispatchMeta, config, meta, updateLoadingState, streamUpdateMetaString } = get();
@@ -109,7 +117,7 @@ export const store: StateCreator<Store, [['zustand/devtools', never]]> = (set, g
109
117
  updateLoadingState('description', loading);
110
118
  },
111
119
  onMessageHandle: streamUpdateMetaString('description'),
112
- params: chainSummaryDescription(systemRole),
120
+ params: merge(get().internal_getSystemAgentForMeta(), chainSummaryDescription(systemRole)),
113
121
  trace: get().getCurrentTracePayload({ traceName: TraceNameMap.SummaryAgentDescription }),
114
122
  });
115
123
  },
@@ -125,6 +133,7 @@ export const store: StateCreator<Store, [['zustand/devtools', never]]> = (set, g
125
133
  // 替换为 ...
126
134
  dispatchMeta({ type: 'update', value: { tags: ['...'] } });
127
135
 
136
+ // Get current agent for agentMeta
128
137
  chatService.fetchPresetTaskResult({
129
138
  onError: () => {
130
139
  dispatchMeta({ type: 'update', value: { tags: preValue } });
@@ -133,8 +142,9 @@ export const store: StateCreator<Store, [['zustand/devtools', never]]> = (set, g
133
142
  updateLoadingState('tags', loading);
134
143
  },
135
144
  onMessageHandle: streamUpdateMetaArray('tags'),
136
- params: chainSummaryTags(
137
- [meta.title, meta.description, systemRole].filter(Boolean).join(','),
145
+ params: merge(
146
+ get().internal_getSystemAgentForMeta(),
147
+ chainSummaryTags([meta.title, meta.description, systemRole].filter(Boolean).join(',')),
138
148
  ),
139
149
  trace: get().getCurrentTracePayload({ traceName: TraceNameMap.SummaryAgentTags }),
140
150
  });
@@ -159,7 +169,10 @@ export const store: StateCreator<Store, [['zustand/devtools', never]]> = (set, g
159
169
  updateLoadingState('title', loading);
160
170
  },
161
171
  onMessageHandle: streamUpdateMetaString('title'),
162
- params: chainSummaryAgentName([meta.description, systemRole].filter(Boolean).join(',')),
172
+ params: merge(
173
+ get().internal_getSystemAgentForMeta(),
174
+ chainSummaryAgentName([meta.description, systemRole].filter(Boolean).join(',')),
175
+ ),
163
176
  trace: get().getCurrentTracePayload({ traceName: TraceNameMap.SummaryAgentTitle }),
164
177
  });
165
178
  },
@@ -231,6 +244,11 @@ export const store: StateCreator<Store, [['zustand/devtools', never]]> = (set, g
231
244
  topicId: TraceTopicType.AgentSettings,
232
245
  ...data,
233
246
  }),
247
+
248
+ internal_getSystemAgentForMeta: () => {
249
+ return systemAgentSelectors.agentMeta(useUserStore.getState());
250
+ },
251
+
234
252
  resetAgentConfig: () => {
235
253
  get().dispatchConfig({ type: 'reset' });
236
254
  },
@@ -238,13 +256,13 @@ export const store: StateCreator<Store, [['zustand/devtools', never]]> = (set, g
238
256
  resetAgentMeta: () => {
239
257
  get().dispatchMeta({ type: 'reset' });
240
258
  },
241
-
242
259
  setAgentConfig: (config) => {
243
260
  get().dispatchConfig({ config, type: 'update' });
244
261
  },
245
262
  setAgentMeta: (meta) => {
246
263
  get().dispatchMeta({ type: 'update', value: meta });
247
264
  },
265
+
248
266
  setChatConfig: (config) => {
249
267
  get().setAgentConfig({ chatConfig: config });
250
268
  },
@@ -31,5 +31,13 @@ export const useSendMessage = () => {
31
31
 
32
32
  updateInputMessage('');
33
33
  useFileStore.getState().clearImageList();
34
+
35
+ // const hasSystemRole = agentSelectors.hasSystemRole(useAgentStore.getState());
36
+ // const agentSetting = useAgentStore.getState().agentSettingInstance;
37
+
38
+ // // if there is a system role, then we need to use agent setting instance to autocomplete agent meta
39
+ // if (hasSystemRole && !!agentSetting) {
40
+ // agentSetting.autocompleteAllMeta();
41
+ // }
34
42
  }, []);
35
43
  };
@@ -5,7 +5,7 @@ import { Flexbox } from 'react-layout-kit';
5
5
  import { ChatMessageError } from '@/types/message';
6
6
 
7
7
  interface ErrorJSONViewerProps {
8
- error?: ChatMessageError;
8
+ error?: ChatMessageError | null;
9
9
  id: string;
10
10
  }
11
11
 
@@ -1,4 +1,4 @@
1
- import { Avatar, Highlighter, Icon } from '@lobehub/ui';
1
+ import { Avatar, Icon } from '@lobehub/ui';
2
2
  import isEqual from 'fast-deep-equal';
3
3
  import { Loader2, LucideChevronDown, LucideChevronRight, LucideToyBrick } from 'lucide-react';
4
4
  import { CSSProperties, memo, useState } from 'react';
@@ -10,6 +10,7 @@ import { chatSelectors } from '@/store/chat/selectors';
10
10
  import { pluginHelpers, useToolStore } from '@/store/tool';
11
11
  import { toolSelectors } from '@/store/tool/selectors';
12
12
 
13
+ import Arguments from '../../components/Arguments';
13
14
  import { useStyles } from './style';
14
15
 
15
16
  export interface InspectorProps {
@@ -64,7 +65,7 @@ const CallItem = memo<InspectorProps>(
64
65
  </Flexbox>
65
66
  <Icon icon={open ? LucideChevronDown : LucideChevronRight} />
66
67
  </Flexbox>
67
- {(open || loading) && <Highlighter language={'json'}>{requestArgs}</Highlighter>}
68
+ {(open || loading) && <Arguments arguments={requestArgs} />}
68
69
  </Flexbox>
69
70
  );
70
71
  },
@@ -1,4 +1,3 @@
1
- import { Snippet } from '@lobehub/ui';
2
1
  import { memo, useState } from 'react';
3
2
  import { Flexbox } from 'react-layout-kit';
4
3
 
@@ -7,10 +6,11 @@ import { chatSelectors } from '@/store/chat/selectors';
7
6
  import { ChatMessage } from '@/types/message';
8
7
 
9
8
  import PluginRender from '../../Plugins/Render';
9
+ import Arguments from '../components/Arguments';
10
10
  import Inspector from './Inspector';
11
11
 
12
12
  export const ToolMessage = memo<ChatMessage>(({ id, content, plugin }) => {
13
- const loading = useChatStore(chatSelectors.isMessageGenerating(id));
13
+ const loading = useChatStore(chatSelectors.isPluginApiInvoking(id));
14
14
 
15
15
  const [showRender, setShow] = useState(plugin?.type !== 'default');
16
16
 
@@ -35,9 +35,7 @@ export const ToolMessage = memo<ChatMessage>(({ id, content, plugin }) => {
35
35
  type={plugin?.type}
36
36
  />
37
37
  ) : (
38
- <Flexbox>
39
- <Snippet>{plugin?.arguments || ''}</Snippet>
40
- </Flexbox>
38
+ <Arguments arguments={plugin?.arguments} />
41
39
  )}
42
40
  </Flexbox>
43
41
  );
@@ -0,0 +1,20 @@
1
+ import { Highlighter } from '@lobehub/ui';
2
+ import { memo } from 'react';
3
+
4
+ import { useYamlArguments } from '../hooks/useYamlArguments';
5
+
6
+ export interface ArgumentsProps {
7
+ arguments?: string;
8
+ }
9
+
10
+ const Arguments = memo<ArgumentsProps>(({ arguments: args = '' }) => {
11
+ const yaml = useYamlArguments(args);
12
+
13
+ return (
14
+ <Highlighter language={'yaml'} showLanguage={false}>
15
+ {yaml}
16
+ </Highlighter>
17
+ );
18
+ });
19
+
20
+ export default Arguments;
@@ -0,0 +1,11 @@
1
+ import { Allow, parse } from 'partial-json';
2
+ import { stringify } from 'yaml';
3
+
4
+ export const useYamlArguments = (args: string) => {
5
+ try {
6
+ const obj = parse(args, Allow.OBJ);
7
+ return stringify(obj);
8
+ } catch {
9
+ return args;
10
+ }
11
+ };
@@ -10,11 +10,12 @@ import { ModelProviderCard } from '@/types/llm';
10
10
 
11
11
  const useStyles = createStyles(({ css, prefixCls }) => ({
12
12
  select: css`
13
- .${prefixCls}-select-dropdown .${prefixCls}-select-item-option-grouped {
13
+ &.${prefixCls}-select-dropdown .${prefixCls}-select-item-option-grouped {
14
14
  padding-inline-start: 12px;
15
15
  }
16
16
  `,
17
17
  }));
18
+
18
19
  interface ModelOption {
19
20
  label: any;
20
21
  provider: string;
@@ -23,10 +24,11 @@ interface ModelOption {
23
24
 
24
25
  interface ModelSelectProps {
25
26
  onChange?: (props: { model: string; provider: string }) => void;
27
+ showAbility?: boolean;
26
28
  value?: string;
27
29
  }
28
30
 
29
- const ModelSelect = memo<ModelSelectProps>(({ value, onChange }) => {
31
+ const ModelSelect = memo<ModelSelectProps>(({ value, onChange, showAbility = true }) => {
30
32
  const enabledList = useUserStore(modelProviderSelectors.modelProviderListForModelSelect, isEqual);
31
33
 
32
34
  const { styles } = useStyles();
@@ -34,7 +36,7 @@ const ModelSelect = memo<ModelSelectProps>(({ value, onChange }) => {
34
36
  const options = useMemo<SelectProps['options']>(() => {
35
37
  const getChatModels = (provider: ModelProviderCard) =>
36
38
  provider.chatModels.map((model) => ({
37
- label: <ModelItemRender {...model} />,
39
+ label: <ModelItemRender {...model} showInfoTag={showAbility} />,
38
40
  provider: provider.id,
39
41
  value: model.id,
40
42
  }));
@@ -53,11 +55,11 @@ const ModelSelect = memo<ModelSelectProps>(({ value, onChange }) => {
53
55
 
54
56
  return (
55
57
  <Select
56
- className={styles.select}
57
58
  onChange={(model, option) => {
58
59
  onChange?.({ model, provider: (option as unknown as ModelOption).provider });
59
60
  }}
60
61
  options={options}
62
+ popupClassName={styles.select}
61
63
  popupMatchSelectWidth={false}
62
64
  value={value}
63
65
  />
@@ -22,10 +22,6 @@ beforeEach(() => {
22
22
 
23
23
  // 使用 vi.spyOn 来模拟 chat.completions.create 方法
24
24
  vi.spyOn(instance['client'].messages, 'create').mockReturnValue(new ReadableStream() as any);
25
-
26
- vi.spyOn(instance['client'].beta.tools.messages, 'create').mockReturnValue({
27
- content: [],
28
- } as any);
29
25
  });
30
26
 
31
27
  afterEach(() => {
@@ -260,35 +256,9 @@ describe('LobeAnthropicAI', () => {
260
256
  });
261
257
 
262
258
  // Assert
263
- expect(instance['client'].beta.tools.messages.create).toHaveBeenCalled();
259
+ expect(instance['client'].messages.create).toHaveBeenCalled();
264
260
  expect(spyOn).toHaveBeenCalledWith(tools);
265
261
  });
266
-
267
- it('should handle text and tool_use content correctly in transformResponseToStream', async () => {
268
- // Arrange
269
- const mockResponse = {
270
- content: [
271
- { type: 'text', text: 'Hello' },
272
- { type: 'tool_use', id: 'tool1', name: 'tool1', input: 'input1' },
273
- ],
274
- };
275
- // @ts-ignore
276
- vi.spyOn(instance, 'transformResponseToStream').mockReturnValue(new ReadableStream());
277
- vi.spyOn(instance['client'].beta.tools.messages, 'create').mockResolvedValue(
278
- mockResponse as any,
279
- );
280
-
281
- // Act
282
- await instance.chat({
283
- messages: [{ content: 'Hello', role: 'user' }],
284
- model: 'claude-3-haiku-20240307',
285
- temperature: 0,
286
- tools: [{ function: { name: 'tool1', description: 'desc1' }, type: 'function' }],
287
- });
288
-
289
- // Assert
290
- expect(instance['transformResponseToStream']).toHaveBeenCalledWith(mockResponse);
291
- });
292
262
  });
293
263
 
294
264
  describe('Error', () => {
@@ -30,41 +30,20 @@ export class LobeAnthropicAI implements LobeRuntimeAI {
30
30
  async chat(payload: ChatStreamPayload, options?: ChatCompetitionOptions) {
31
31
  try {
32
32
  const anthropicPayload = this.buildAnthropicPayload(payload);
33
-
34
- // if there is no tool, we can use the normal chat API
35
- if (!anthropicPayload.tools || anthropicPayload.tools.length === 0) {
36
- const response = await this.client.messages.create(
37
- { ...anthropicPayload, stream: true },
38
- {
39
- signal: options?.signal,
40
- },
41
- );
42
-
43
- const [prod, debug] = response.tee();
44
-
45
- if (process.env.DEBUG_ANTHROPIC_CHAT_COMPLETION === '1') {
46
- debugStream(debug.toReadableStream()).catch(console.error);
47
- }
48
-
49
- return StreamingResponse(AnthropicStream(prod, options?.callback), {
50
- headers: options?.headers,
51
- });
52
- }
53
-
54
- // or we should call the tool API
55
- const response = await this.client.beta.tools.messages.create(
56
- { ...anthropicPayload, stream: false },
57
- { signal: options?.signal },
33
+ const response = await this.client.messages.create(
34
+ { ...anthropicPayload, stream: true },
35
+ {
36
+ signal: options?.signal,
37
+ },
58
38
  );
59
39
 
40
+ const [prod, debug] = response.tee();
41
+
60
42
  if (process.env.DEBUG_ANTHROPIC_CHAT_COMPLETION === '1') {
61
- console.log('\n[no stream response]\n');
62
- console.log(JSON.stringify(response) + '\n');
43
+ debugStream(debug.toReadableStream()).catch(console.error);
63
44
  }
64
45
 
65
- const stream = this.transformResponseToStream(response);
66
-
67
- return StreamingResponse(AnthropicStream(stream, options?.callback), {
46
+ return StreamingResponse(AnthropicStream(prod, options?.callback), {
68
47
  headers: options?.headers,
69
48
  });
70
49
  } catch (error) {
@@ -118,43 +97,10 @@ export class LobeAnthropicAI implements LobeRuntimeAI {
118
97
  model,
119
98
  system: system_message?.content as string,
120
99
  temperature,
121
- // TODO: Anthropic sdk don't have tools interface currently
122
- // @ts-ignore
123
100
  tools: buildAnthropicTools(tools),
124
101
  top_p,
125
102
  } satisfies Anthropic.MessageCreateParams;
126
103
  }
127
-
128
- private transformResponseToStream = (response: Anthropic.Beta.Tools.ToolsBetaMessage) => {
129
- return new ReadableStream<Anthropic.MessageStreamEvent>({
130
- start(controller) {
131
- response.content.forEach((content) => {
132
- switch (content.type) {
133
- case 'text': {
134
- controller.enqueue({
135
- delta: { text: content.text, type: 'text_delta' },
136
- type: 'content_block_delta',
137
- } as Anthropic.ContentBlockDeltaEvent);
138
- break;
139
- }
140
- case 'tool_use': {
141
- controller.enqueue({
142
- delta: {
143
- tool_use: { id: content.id, input: content.input, name: content.name },
144
- type: 'tool_use',
145
- },
146
- type: 'content_block_delta',
147
- } as any);
148
- }
149
- }
150
- });
151
-
152
- controller.enqueue({ type: 'message_stop' } as Anthropic.MessageStopEvent);
153
-
154
- controller.close();
155
- },
156
- });
157
- };
158
104
  }
159
105
 
160
106
  export default LobeAnthropicAI;
@@ -49,7 +49,7 @@ describe('LobeOpenAI', () => {
49
49
  });
50
50
 
51
51
  describe('Error', () => {
52
- it('should return OpenAIBizError with an openai error response when OpenAI.APIError is thrown', async () => {
52
+ it('should return ProviderBizError with an openai error response when OpenAI.APIError is thrown', async () => {
53
53
  // Arrange
54
54
  const apiError = new OpenAI.APIError(
55
55
  400,
@@ -79,7 +79,7 @@ describe('LobeOpenAI', () => {
79
79
  error: { message: 'Bad Request' },
80
80
  status: 400,
81
81
  },
82
- errorType: 'OpenAIBizError',
82
+ errorType: 'ProviderBizError',
83
83
  provider: 'openai',
84
84
  });
85
85
  }
@@ -89,11 +89,11 @@ describe('LobeOpenAI', () => {
89
89
  try {
90
90
  new LobeOpenAI({});
91
91
  } catch (e) {
92
- expect(e).toEqual({ errorType: 'NoOpenAIAPIKey' });
92
+ expect(e).toEqual({ errorType: 'InvalidProviderAPIKey' });
93
93
  }
94
94
  });
95
95
 
96
- it('should return OpenAIBizError with the cause when OpenAI.APIError is thrown with cause', async () => {
96
+ it('should return ProviderBizError with the cause when OpenAI.APIError is thrown with cause', async () => {
97
97
  // Arrange
98
98
  const errorInfo = {
99
99
  stack: 'abc',
@@ -119,13 +119,13 @@ describe('LobeOpenAI', () => {
119
119
  cause: { message: 'api is undefined' },
120
120
  stack: 'abc',
121
121
  },
122
- errorType: 'OpenAIBizError',
122
+ errorType: 'ProviderBizError',
123
123
  provider: 'openai',
124
124
  });
125
125
  }
126
126
  });
127
127
 
128
- it('should return OpenAIBizError with an cause response with desensitize Url', async () => {
128
+ it('should return ProviderBizError with an cause response with desensitize Url', async () => {
129
129
  // Arrange
130
130
  const errorInfo = {
131
131
  stack: 'abc',
@@ -155,7 +155,7 @@ describe('LobeOpenAI', () => {
155
155
  cause: { message: 'api is undefined' },
156
156
  stack: 'abc',
157
157
  },
158
- errorType: 'OpenAIBizError',
158
+ errorType: 'ProviderBizError',
159
159
  provider: 'openai',
160
160
  });
161
161
  }
@@ -1,4 +1,3 @@
1
- import { AgentRuntimeErrorType } from '../error';
2
1
  import { ModelProvider } from '../types';
3
2
  import { LobeOpenAICompatibleFactory } from '../utils/openaiCompatibleFactory';
4
3
 
@@ -7,10 +6,5 @@ export const LobeOpenAI = LobeOpenAICompatibleFactory({
7
6
  debug: {
8
7
  chatCompletion: () => process.env.DEBUG_OPENAI_CHAT_COMPLETION === '1',
9
8
  },
10
- errorType: {
11
- bizError: AgentRuntimeErrorType.OpenAIBizError,
12
- invalidAPIKey: AgentRuntimeErrorType.NoOpenAIAPIKey,
13
- },
14
-
15
9
  provider: ModelProvider.OpenAI,
16
10
  });
@@ -112,9 +112,9 @@ export const buildAnthropicMessages = (
112
112
 
113
113
  export const buildAnthropicTools = (tools?: OpenAI.ChatCompletionTool[]) =>
114
114
  tools?.map(
115
- (tool): Anthropic.Beta.Tools.Tool => ({
115
+ (tool): Anthropic.Tool => ({
116
116
  description: tool.function.description,
117
- input_schema: tool.function.parameters as Anthropic.Beta.Tools.Tool.InputSchema,
117
+ input_schema: tool.function.parameters as Anthropic.Tool.InputSchema,
118
118
  name: tool.function.name,
119
119
  }),
120
120
  );