Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: runtime bug #252

Closed
wants to merge 19 commits into from
Closed
Show file tree
Hide file tree
Changes from all 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
14 changes: 13 additions & 1 deletion components/useXChat/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { fireEvent, render, waitFakeTimer } from '../../../tests/utils';
import { fireEvent, render, renderHook, waitFakeTimer } from '../../../tests/utils';
import useXAgent, { RequestFn } from '../../useXAgent';
import { MessageStatus, SimpleType, XChatConfig } from '../index';
import useXChat from '../index';
Expand Down Expand Up @@ -217,4 +217,16 @@ describe('useXChat', () => {
expectMessage('light', 'success'),
]);
});

it('should throw an error if onRequest is called without an agent', () => {
const { result } = renderHook(() =>
useXChat({
defaultMessages: [{ message: 'Hello' }],
}),
);

expect(() => result.current?.onRequest('Hello')).toThrow(
'If the onRequest method is used, the agent parameter is required!',
);
});
});
2 changes: 1 addition & 1 deletion components/useXChat/index.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ type useXChat<AgentMessage, ParsedMessage = AgentMessage> = (

| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| agent | Agent generated by useXAgent | XAgent | - | |
| agent | `agent` parameter is required when using the `onRequest` method in an agent generated by `useXAgent`. | XAgent | - | |
| defaultMessages | default messages | { status, message }[] | - | |
| parser | Convert AgentMessage to ParsedMessage for consumption. If not set, AgentMessage will be consumed directly. Supports converting one AgentMessage to multiple ParsedMessages | (message: AgentMessage) => BubbleMessage \| BubbleMessage[] | - | |
| requestFallback | Fallback when request fails, not provided will not be displayed | AgentMessage \| () => AgentMessage | - | |
Expand Down
6 changes: 5 additions & 1 deletion components/useXChat/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ export interface XChatConfig<
AgentMessage extends SimpleType = string,
BubbleMessage extends SimpleType = AgentMessage,
> {
agent: XAgent<AgentMessage>;
/** If the onRequest method is used, the agent parameter is required */
agent?: XAgent<AgentMessage>;

defaultMessages?: DefaultMessageInfo<AgentMessage>[];

Expand Down Expand Up @@ -128,6 +129,9 @@ export default function useXChat<
const getRequestMessages = () => getFilteredMessages(getMessages());

const onRequest = useEvent((message: AgentMessage) => {
if (!agent)
throw new Error('If the onRequest method is used, the agent parameter is required!');

let loadingMsgId: number | string | null = null;

// Add placeholder message
Expand Down
2 changes: 1 addition & 1 deletion components/useXChat/index.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ type useXChat<AgentMessage, ParsedMessage = AgentMessage> = (

| 属性 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| agent | 由 useXAgent 生成的代理器 | XAgent | - | |
| agent |`useXAgent` 生成的代理器, 如果需要使用 `onRequest` 方法, `agent` 参数是必需的 | XAgent | - | |
| defaultMessages | 默认展示信息 | { status, message }[] | - | |
| parser | 将 AgentMessage 转换成消费使用的 ParsedMessage,不设置时则直接消费 AgentMessage。支持将一条 AgentMessage 转换成多条 ParsedMessage | (message: AgentMessage) => BubbleMessage \| BubbleMessage[] | - | |
| requestFallback | 请求失败的兜底信息,不提供则不会展示 | AgentMessage \| () => AgentMessage | - | |
Expand Down
2 changes: 1 addition & 1 deletion components/x-provider/index.en-US.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
category: Components
group:
title: Tool
title: Tools
order: 5
title: XProvider
order: 999
Expand Down
2 changes: 1 addition & 1 deletion components/x-stream/index.en-US.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
category: Components
group:
title: Tool
title: Tools
order: 5
title: XStream
order: 1
Expand Down
7 changes: 6 additions & 1 deletion components/x-stream/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,19 @@ function splitStream() {
});
}

/**
* @link https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#fields
*/
export type SSEFields = 'data' | 'event' | 'id' | 'retry';

/**
* @example
* const sseObject = {
* event: 'delta',
* data: '{ key: "world!" }',
* };
*/
export type SSEOutput = Record<string, any>;
export type SSEOutput = Partial<Record<SSEFields, any>>;

/**
* @description A TransformStream inst that transforms a part string into {@link SSEOutput}
Expand Down
74 changes: 41 additions & 33 deletions docs/react/model-use-openai.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,47 +10,55 @@ Typically, `openai-node` is used in Node.js environments. If you need to use it
## Example of Streaming Requests with `openai-node`

```tsx
import { useXAgent, useXChat, Sender } from '@ant-design/x';
import React from 'react';
import { useXAgent, useXChat, Sender, Bubble } from '@ant-design/x';
import OpenAI from 'openai';

const client = new OpenAI({
apiKey: process.env['OPENAI_API_KEY'],
dangerouslyAllowBrowser: true,
});

// React environment setup
const [agent] = useXAgent({
request: async (info, callbacks) => {
const stream = await client.chat.completions.create({
model: 'gpt-4o',
messages: [{ role: 'user', content: 'Say this is a test' }],
stream: true,
});

for await (const chunk of stream) {
// Trigger the callback
callbacks.onUpdate(chunk.choices[0]?.delta?.content || '');
}
},
});
const Component: React.FC = () => {
const [agent] = useXAgent({
request: async (info, callbacks) => {
const { messages, message } = info;

console.log('message', message);
console.log('messages', messages);

const stream = await client.chat.completions.create({
model: 'gpt-4o',
YumoImer marked this conversation as resolved.
Show resolved Hide resolved
messages: [{ role: 'user', content: message }],
stream: true,
});

for await (const chunk of stream) {
// Trigger the callback
callbacks.onUpdate(chunk.choices[0]?.delta?.content || '');
}
},
YumoImer marked this conversation as resolved.
Show resolved Hide resolved
});

const {
// Used to initiate conversation requests
onRequest,
// Used to bind the view
messages,
} = useXChat({ agent });

const items = messages.map(({ message, id }) => ({
key: id,
content: message,
}));

const {
// Used to initiate conversation requests
onRequest,
// Used to bind the view
messages,
} = useXChat({ agent });

const items = messages.map((message) => ({
content: message,
}));

return (
<div>
<Bubble.List items={items} />
<Sender onSubmit={onRequest} />
</div>
);
return (
<div>
<Bubble.List items={items} />
<Sender onSubmit={onRequest} />
</div>
);
};
```

## use openai API
Expand Down
74 changes: 41 additions & 33 deletions docs/react/model-use-openai.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,47 +10,55 @@ order: 0
## 使用 openai-node 流式调用示例

```tsx
import { useXAgent, useXChat, Sender } from '@ant-design/x';
import React from 'react';
import { useXAgent, useXChat, Sender, Bubble } from '@ant-design/x';
import OpenAI from 'openai';

const client = new OpenAI({
apiKey: process.env['OPENAI_API_KEY'],
dangerouslyAllowBrowser: true,
});

// react env ...
const [agent] = useXAgent({
request: async (info, callbacks) => {
const stream = await client.chat.completions.create({
model: 'gpt-4o',
messages: [{ role: 'user', content: 'Say this is a test' }],
stream: true,
});

for await (const chunk of stream) {
// 调用回调
callbacks.onUpdate(chunk.choices[0]?.delta?.content || '');
}
},
});
const Component: React.FC = () => {
const [agent] = useXAgent({
request: async (info, callbacks) => {
const { messages, message } = info;

console.log('message', message);
console.log('messages', messages);

const stream = await client.chat.completions.create({
model: 'gpt-4o',
messages: [{ role: 'user', content: message }],
stream: true,
});
YumoImer marked this conversation as resolved.
Show resolved Hide resolved

for await (const chunk of stream) {
// 调用回调
callbacks.onUpdate(chunk.choices[0]?.delta?.content || '');
}
},
});

const {
// 用于发起对话请求
onRequest,
// 用于绑定视图
messages,
} = useXChat({ agent });

const items = messages.map(({ message, id }) => ({
key: id,
content: message,
}));

const {
// 用于发起对话请求
onRequest,
// 用于绑定视图
messages,
} = useXChat({ agent });

const items = messages.map((i) => ({
content: message,
}));

return (
<div>
<Bubble.List items={items} />
<Sender onSubmit={onRequest} />
</div>
);
return (
<div>
<Bubble.List items={items} />
<Sender onSubmit={onRequest} />
</div>
);
};
```

## 使用 openai API 调用
Expand Down
Loading