Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
727 changes: 637 additions & 90 deletions packages/x-sdk/src/x-chat/__test__/providers.test.ts

Large diffs are not rendered by default.

53 changes: 34 additions & 19 deletions packages/x-sdk/src/x-chat/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ enum MessageStatusEnum {

export type MessageStatus = `${MessageStatusEnum}`;

type RequestPlaceholderFn<Message extends SimpleType> = (
message: Message,
type RequestPlaceholderFn<Input, Message> = (
requestParams: Partial<Input>,
info: { messages: Message[] },
) => Message;

type RequestFallbackFn<Message extends SimpleType> = (
message: Message,
info: { error: Error; messages: Message[] },
type RequestFallbackFn<Input, Message extends SimpleType> = (
requestParams: Partial<Input>,
info: { error: Error; messages: Message[]; message: Message },
) => Message | Promise<Message>;

export type RequestParams<Message> = {
Expand All @@ -45,8 +45,8 @@ export interface XChatConfig<
defaultMessages?: DefaultMessageInfo<ChatMessage>[];
/** Convert agent message to bubble usage message type */
parser?: (message: ChatMessage) => BubbleMessage | BubbleMessage[];
requestPlaceholder?: ChatMessage | RequestPlaceholderFn<ChatMessage>;
requestFallback?: ChatMessage | RequestFallbackFn<ChatMessage>;
requestPlaceholder?: ChatMessage | RequestPlaceholderFn<Input, ChatMessage>;
requestFallback?: ChatMessage | RequestFallbackFn<Input, ChatMessage>;
}

export interface MessageInfo<Message extends SimpleType> {
Expand Down Expand Up @@ -76,6 +76,8 @@ function toArray<T>(item: T | T[]): T[] {
return Array.isArray(item) ? item : [item];
}

const IsRequestingMap = new Map<string, boolean>();

export default function useXChat<
ChatMessage extends SimpleType = string,
ParsedMessage extends SimpleType = ChatMessage,
Expand Down Expand Up @@ -169,7 +171,9 @@ export default function useXChat<
}
const { updatingId, reload } = opts || {};
let loadingMsgId: number | string | null | undefined = null;
const message = provider.transformLocalMessage(requestParams);
const messages = (provider.transformLocalMessage(requestParams) as ChatMessage[]).map(
(message) => createMessage(message, 'local', opts?.extra),
);
if (reload) {
loadingMsgId = updatingId;
setMessages((ori: MessageInfo<ChatMessage>[]) => {
Expand All @@ -178,9 +182,12 @@ export default function useXChat<
let placeholderMsg: ChatMessage;
if (typeof requestPlaceholder === 'function') {
// typescript has bug that not get real return type when use `typeof function` check
placeholderMsg = (requestPlaceholder as RequestPlaceholderFn<ChatMessage>)(message, {
messages: getFilteredMessages(nextMessages),
});
placeholderMsg = (requestPlaceholder as RequestPlaceholderFn<Input, ChatMessage>)(
requestParams,
{
messages: getFilteredMessages(nextMessages),
},
);
} else {
placeholderMsg = requestPlaceholder;
}
Expand All @@ -199,14 +206,17 @@ export default function useXChat<
} else {
// Add placeholder message
setMessages((ori: MessageInfo<ChatMessage>[]) => {
let nextMessages = [...ori, createMessage(message, 'local', opts?.extra)];
let nextMessages = [...ori, ...messages];
if (requestPlaceholder) {
let placeholderMsg: ChatMessage;
if (typeof requestPlaceholder === 'function') {
// typescript has bug that not get real return type when use `typeof function` check
placeholderMsg = (requestPlaceholder as RequestPlaceholderFn<ChatMessage>)(message, {
messages: getFilteredMessages(nextMessages),
});
placeholderMsg = (requestPlaceholder as RequestPlaceholderFn<Input, ChatMessage>)(
requestParams,
{
messages: getFilteredMessages(nextMessages),
},
);
} else {
placeholderMsg = requestPlaceholder;
}
Expand Down Expand Up @@ -288,10 +298,12 @@ export default function useXChat<
},
onSuccess: (chunks: Output[], headers: Headers) => {
setIsRequesting(false);
conversationKey && IsRequestingMap.delete(conversationKey);
updateMessage('success', undefined as Output, chunks, headers);
},
onError: async (error: Error) => {
setIsRequesting(false);
conversationKey && IsRequestingMap.delete(conversationKey);
if (requestFallback) {
let fallbackMsg: ChatMessage;
// Update as error
Expand All @@ -300,11 +312,12 @@ export default function useXChat<
const messages = getRequestMessages();
const msg = getMessages().find(
(info) => info.id === loadingMsgId || info.id === updatingMsgId,
);
fallbackMsg = await (requestFallback as RequestFallbackFn<ChatMessage>)(
msg?.message || message,
) as MessageInfo<ChatMessage>;
fallbackMsg = await (requestFallback as RequestFallbackFn<Input, ChatMessage>)(
requestParams,
{
error,
message: msg.message as ChatMessage,
messages,
},
);
Expand Down Expand Up @@ -334,7 +347,9 @@ export default function useXChat<
}
},
});

setIsRequesting(true);
conversationKey && IsRequestingMap.set(conversationKey, true);
provider.request.run(provider.transformParams(requestParams, provider.request.options));
};

Expand Down Expand Up @@ -375,7 +390,7 @@ export default function useXChat<
}
requestHandlerRef.current?.abort();
},
isRequesting,
isRequesting: conversationKey ? IsRequestingMap?.get(conversationKey) || false : isRequesting,
onReload,
} as const;
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export default abstract class AbstractChatProvider<ChatMessage, Input, Output> {
* 将onRequest传入的参数转换为本地(用户发送)的ChatMessage,用于消息渲染
* @param requestParams onRequest传入的参数
*/
abstract transformLocalMessage(requestParams: Partial<Input>): ChatMessage;
abstract transformLocalMessage(requestParams: Partial<Input>): ChatMessage | ChatMessage[];

/**
* 可在更新返回数据时对messages做转换,同时会更新到messages
Expand Down
5 changes: 2 additions & 3 deletions packages/x-sdk/src/x-chat/providers/DeepSeekChatProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,8 @@ export default class DeepSeekChatProvider<
} as unknown as Input;
}

transformLocalMessage(requestParams: Partial<Input>): ChatMessage {
const lastMessage = requestParams?.messages?.[requestParams?.messages?.length - 1];
return lastMessage as unknown as ChatMessage;
transformLocalMessage(requestParams: Partial<Input>): ChatMessage[] {
return (requestParams?.messages || []) as ChatMessage[];
}

transformMessage(info: TransformMessage<ChatMessage, Output>): ChatMessage {
Expand Down
5 changes: 2 additions & 3 deletions packages/x-sdk/src/x-chat/providers/OpenAIChatProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,8 @@ export default class OpenAIChatProvider<
} as unknown as Input;
}

transformLocalMessage(requestParams: Partial<Input>): ChatMessage {
const lastMessage = requestParams?.messages?.[requestParams?.messages?.length - 1];
return lastMessage as unknown as ChatMessage;
transformLocalMessage(requestParams: Partial<Input>): ChatMessage[] {
return (requestParams?.messages || []) as ChatMessage[];
}

transformMessage(info: TransformMessage<ChatMessage, Output>): ChatMessage {
Expand Down
3 changes: 1 addition & 2 deletions packages/x/docs/playground/copilot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -259,8 +259,7 @@ const Copilot = (props: CopilotProps) => {
role: 'assistant',
};
},
requestFallback: (message, info) => {
console.log(message, info);
requestFallback: (_, { message }) => {
return message;
},
});
Expand Down
6 changes: 3 additions & 3 deletions packages/x/docs/playground/independent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -533,10 +533,10 @@ const Independent: React.FC = () => {
role: 'assistant',
};
},
requestFallback: (e) => {
requestFallback: (_, { message }) => {
return {
...e,
content: e.content || locale.requestFailedPleaseTryAgain,
...message,
content: message.content || locale.requestFailedPleaseTryAgain,
};
},
});
Expand Down
6 changes: 3 additions & 3 deletions packages/x/docs/playground/ultramodern.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -287,10 +287,10 @@ const App = () => {
role: 'assistant',
};
},
requestFallback: (e) => {
requestFallback: (_, { message }) => {
return {
...e,
content: e.content || locale.requestFailedPleaseTryAgain,
...message,
content: message.content || locale.requestFailedPleaseTryAgain,
};
},
});
Expand Down
6 changes: 3 additions & 3 deletions packages/x/docs/x-sdk/demos/x-conversations/with-x-chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,10 @@ export default () => {
role: 'assistant',
};
},
requestFallback: (e) => {
requestFallback: (_, { error, message }) => {
return {
...e,
content: e.content,
role: message?.role,
content: error.message,
};
},
});
Expand Down
4 changes: 2 additions & 2 deletions packages/x/docs/x-sdk/use-x-chat.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ type useXChat<
| provider | Data provider used to convert data and requests of different structures into formats that useXChat can consume. The platform includes built-in `DefaultChatProvider` and `OpenAIChatProvider`, and you can also implement your own Provider by inheriting `AbstractChatProvider`. See: [Chat Provider Documentation](/x-sdks/chat-provider-en) | AbstractChatProvider\<ChatMessage, Input, Output\> | - | - |
| defaultMessages | Default display messages | { message: ChatMessage, status: MessageStatus }[] | - | - |
| parser | Converts ChatMessage into ParsedMessage for consumption. When not set, ChatMessage is consumed directly. Supports converting one ChatMessage into multiple ParsedMessages | (message: ChatMessage) => BubbleMessage \| BubbleMessage[] | - | - |
| requestFallback | Fallback message for failed requests. When not provided, no message will be displayed | ChatMessage \| () => ChatMessage | - | - |
| requestPlaceholder | Placeholder message during requests. When not provided, no message will be displayed | ChatMessage \| () => ChatMessage | - | - |
| requestFallback | Fallback message for failed requests. When not provided, no message will be displayed | ChatMessage \| (requestParams: Partial\<Input\>,info: { error: Error; messages: ChatMessage[], message: ChatMessage }) => ChatMessage\|Promise\<ChatMessage\> | - | - |
| requestPlaceholder | Placeholder message during requests. When not provided, no message will be displayed | ChatMessage \| (requestParams: Partial\<Input\>, info: { error: Error; messages: ChatMessage[], message: ChatMessage }) => ChatMessage \|Promise<\Message\> | - | - |

### XChatConfigReturnType

Expand Down
4 changes: 2 additions & 2 deletions packages/x/docs/x-sdk/use-x-chat.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ type useXChat<
| provider | 数据提供方,用于将不同结构的数据及请求转换为useXChat能消费的格式,平台内置了`DefaultChatProvider`和`OpenAIChatProvider`,你也可以通过继承`AbstractChatProvider`实现自己的Provider。详见:[Chat Provider文档](/x-sdks/chat-provider-cn) | AbstractChatProvider\<ChatMessage, Input, Output\> | - | - |
| defaultMessages | 默认展示信息 | { message: ChatMessage ,status: MessageStatus}[] | - | - |
| parser | 将 ChatMessage 转换成消费使用的 ParsedMessage,不设置时则直接消费 ChatMessage。支持将一条 ChatMessage 转换成多条 ParsedMessage | (message: ChatMessage) => BubbleMessage \| BubbleMessage[] | - | - |
| requestFallback | 请求失败的兜底信息,不提供则不会展示 | ChatMessage \| () => ChatMessage | - | - |
| requestPlaceholder | 请求中的占位信息,不提供则不会展示 | ChatMessage \| () => ChatMessage | - | - |
| requestFallback | 请求失败的兜底信息,不提供则不会展示 | ChatMessage \| (requestParams: Partial\<Input\>,info: { error: Error; messages: ChatMessage[], message: ChatMessage }) => ChatMessage\|Promise\<ChatMessage\> | - | - |
| requestPlaceholder | 请求中的占位信息,不提供则不会展示 | ChatMessage \| (requestParams: Partial\<Input\>, info: { error: Error; messages: ChatMessage[], message: ChatMessage }) => ChatMessage \|Promise<\Message\>| - | - |

### XChatConfigReturnType

Expand Down
Loading