@chatbotkit/react 1.6.0 → 1.8.0
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 +198 -9
- package/dist/cjs/actions/complete.cjs +178 -0
- package/dist/cjs/actions/complete.d.ts +38 -0
- package/dist/cjs/components/ConversationManager.cjs +26 -0
- package/dist/cjs/components/ConversationManager.d.ts +5 -0
- package/dist/cjs/hooks/useConversationManager.cjs +99 -114
- package/dist/cjs/hooks/useConversationManager.d.ts +13 -52
- package/dist/cjs/hooks/useConversationManagerRemote.cjs +83 -0
- package/dist/cjs/hooks/useConversationManagerRemote.d.ts +20 -0
- package/dist/cjs/hooks/useConversationManagerState.cjs +32 -0
- package/dist/cjs/hooks/useConversationManagerState.d.ts +10 -0
- package/dist/cjs/hooks/useConversationManagerStateReducer.cjs +112 -0
- package/dist/cjs/hooks/useConversationManagerStateReducer.d.ts +42 -0
- package/dist/cjs/index.cjs +4 -1
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/utils/it.cjs +9 -0
- package/dist/cjs/utils/it.d.ts +1 -0
- package/dist/cjs/utils/stream.cjs +2 -2
- package/dist/cjs/utils/stream.d.ts +6 -7
- package/dist/esm/actions/complete.d.ts +38 -0
- package/dist/esm/actions/complete.js +173 -0
- package/dist/esm/components/AutoScroller.js +1 -1
- package/dist/esm/components/ConversationManager.d.ts +5 -0
- package/dist/esm/components/ConversationManager.js +21 -0
- package/dist/esm/hooks/useConversationManager.d.ts +13 -52
- package/dist/esm/hooks/useConversationManager.js +99 -114
- package/dist/esm/hooks/useConversationManagerRemote.d.ts +20 -0
- package/dist/esm/hooks/useConversationManagerRemote.js +78 -0
- package/dist/esm/hooks/useConversationManagerState.d.ts +10 -0
- package/dist/esm/hooks/useConversationManagerState.js +27 -0
- package/dist/esm/hooks/useConversationManagerStateReducer.d.ts +42 -0
- package/dist/esm/hooks/useConversationManagerStateReducer.js +105 -0
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/utils/it.d.ts +1 -0
- package/dist/esm/utils/it.js +5 -0
- package/dist/esm/utils/stream.d.ts +6 -7
- package/dist/esm/utils/stream.js +2 -2
- package/dist/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/tsconfig.esm.tsbuildinfo +1 -1
- package/package.json +122 -2
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
export function stream(source:
|
|
2
|
-
export function consume(source:
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
};
|
|
1
|
+
export function stream(source: StreamSource): StreamResult;
|
|
2
|
+
export function consume(source: ConsumeSource): ConsumeResult;
|
|
3
|
+
export type StreamSource = any;
|
|
4
|
+
export type StreamResult = any;
|
|
5
|
+
export type ConsumeSource = any;
|
|
6
|
+
export type ConsumeResult = any;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export function streamComplete(options: Options): import('../utils/stream.js').StreamResult;
|
|
2
|
+
export default complete;
|
|
3
|
+
export type ReactElement = import('react').ReactElement;
|
|
4
|
+
export type ReactNode = import('react').ReactNode;
|
|
5
|
+
export type BasicParametersSchema = Record<string, any>;
|
|
6
|
+
export type ValidatingParametersSchema = {
|
|
7
|
+
schema: BasicParametersSchema;
|
|
8
|
+
validate(value: any): Promise<{
|
|
9
|
+
valid: boolean;
|
|
10
|
+
error?: Error;
|
|
11
|
+
}>;
|
|
12
|
+
};
|
|
13
|
+
export type InputMessage = {
|
|
14
|
+
type: 'bot' | 'user' | 'context' | 'instruction' | 'backstory' | 'activity';
|
|
15
|
+
text: string;
|
|
16
|
+
meta?: Record<string, any>;
|
|
17
|
+
};
|
|
18
|
+
export type RenderFunction = () => AsyncGenerator<ReactNode> | ReactNode | Promise<ReactNode>;
|
|
19
|
+
export type HandlerArgs = any;
|
|
20
|
+
export type HandlerResult = string | ReactElement | {
|
|
21
|
+
text?: string;
|
|
22
|
+
children?: ReactNode;
|
|
23
|
+
render: RenderFunction;
|
|
24
|
+
result?: any;
|
|
25
|
+
};
|
|
26
|
+
export type InputFunction = {
|
|
27
|
+
name: string;
|
|
28
|
+
description: string;
|
|
29
|
+
parameters: BasicParametersSchema | ValidatingParametersSchema;
|
|
30
|
+
handler?: ((args: HandlerArgs) => Promise<HandlerResult>) | undefined;
|
|
31
|
+
};
|
|
32
|
+
export type Options = Omit<import('@chatbotkit/sdk/conversation/v1.js').ConversationCompleteRequest, 'messages' | 'functions'> & {
|
|
33
|
+
client: import('@chatbotkit/sdk').ConversationClient;
|
|
34
|
+
messages: InputMessage[];
|
|
35
|
+
functions?: (InputFunction | (() => InputFunction))[];
|
|
36
|
+
maxRecusion?: number;
|
|
37
|
+
};
|
|
38
|
+
declare function complete({ client, messages, functions, maxRecusion, ...options }: Options): any;
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { isValidElement } from 'react';
|
|
3
|
+
import { isAsyncGenerator } from '../utils/it.js';
|
|
4
|
+
import { stream } from '../utils/stream.js';
|
|
5
|
+
import { getRandomId } from '../utils/string.js';
|
|
6
|
+
async function* complete({ client, messages, functions, maxRecusion = 3, ...options }) {
|
|
7
|
+
if (maxRecusion <= 0) {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
messages = messages.slice(0);
|
|
11
|
+
const functionDefinitions = functions?.map((fn) => {
|
|
12
|
+
if (typeof fn === 'function') {
|
|
13
|
+
return fn();
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
return fn;
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
let it;
|
|
20
|
+
if (!it) {
|
|
21
|
+
const lastMessage = messages[messages.length - 1];
|
|
22
|
+
if (lastMessage) {
|
|
23
|
+
if (lastMessage.type === 'activity') {
|
|
24
|
+
if (lastMessage.meta?.activity?.type === 'request') {
|
|
25
|
+
messages.pop();
|
|
26
|
+
it = [{ type: 'message', data: lastMessage }];
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (!it) {
|
|
32
|
+
it = client
|
|
33
|
+
.complete(null, {
|
|
34
|
+
...options,
|
|
35
|
+
messages: messages.map(({ type, text, meta }) => {
|
|
36
|
+
return {
|
|
37
|
+
type,
|
|
38
|
+
text,
|
|
39
|
+
meta,
|
|
40
|
+
};
|
|
41
|
+
}),
|
|
42
|
+
functions: functionDefinitions?.map(({ name, description, parameters }) => {
|
|
43
|
+
return {
|
|
44
|
+
name,
|
|
45
|
+
description,
|
|
46
|
+
parameters: parameters.schema ? parameters.schema : parameters,
|
|
47
|
+
};
|
|
48
|
+
}),
|
|
49
|
+
})
|
|
50
|
+
.stream();
|
|
51
|
+
}
|
|
52
|
+
if (!it) {
|
|
53
|
+
throw new Error('No stream iterator');
|
|
54
|
+
}
|
|
55
|
+
for await (const item of it) {
|
|
56
|
+
yield item;
|
|
57
|
+
const { type, data } = item;
|
|
58
|
+
if (type === 'message') {
|
|
59
|
+
const message = data;
|
|
60
|
+
messages.push(message);
|
|
61
|
+
if (message.meta?.activity?.type === 'request') {
|
|
62
|
+
const name = message.meta.activity.function?.name;
|
|
63
|
+
const args = message.meta.activity.function?.arguments;
|
|
64
|
+
const fn = functionDefinitions?.find((fn) => fn.name === name);
|
|
65
|
+
if (fn && typeof fn.handler === 'function') {
|
|
66
|
+
if (fn.parameters.validate) {
|
|
67
|
+
const { valid, error } = await fn.parameters.validate(args);
|
|
68
|
+
if (!valid) {
|
|
69
|
+
throw error || new Error('Invalid arguments');
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const output = await fn.handler(args);
|
|
73
|
+
let text;
|
|
74
|
+
let children;
|
|
75
|
+
let result;
|
|
76
|
+
let render;
|
|
77
|
+
if (typeof output === 'string') {
|
|
78
|
+
text = undefined;
|
|
79
|
+
children = undefined;
|
|
80
|
+
render = undefined;
|
|
81
|
+
result = output;
|
|
82
|
+
}
|
|
83
|
+
else if (isValidElement(output)) {
|
|
84
|
+
text = '';
|
|
85
|
+
children = output;
|
|
86
|
+
render = undefined;
|
|
87
|
+
result = undefined;
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
if (typeof output?.text === 'string') {
|
|
91
|
+
text = output.text;
|
|
92
|
+
}
|
|
93
|
+
if (isValidElement(output?.children)) {
|
|
94
|
+
children = output.children;
|
|
95
|
+
}
|
|
96
|
+
if (typeof output?.render === 'function') {
|
|
97
|
+
render = output.render;
|
|
98
|
+
}
|
|
99
|
+
if (output?.result) {
|
|
100
|
+
result = output.result;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (text || children) {
|
|
104
|
+
yield {
|
|
105
|
+
type: 'message',
|
|
106
|
+
data: {
|
|
107
|
+
type: 'bot',
|
|
108
|
+
text: text ? text : '',
|
|
109
|
+
children: children ? _jsx(_Fragment, { children: children }) : undefined,
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
else if (text || render) {
|
|
114
|
+
const result = await render?.();
|
|
115
|
+
if (isAsyncGenerator(result)) {
|
|
116
|
+
const id = getRandomId('tmp-');
|
|
117
|
+
for await (const item of (result)) {
|
|
118
|
+
yield {
|
|
119
|
+
type: 'message',
|
|
120
|
+
data: {
|
|
121
|
+
id: id,
|
|
122
|
+
type: 'bot',
|
|
123
|
+
text: text ? text : '',
|
|
124
|
+
children: item,
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
yield {
|
|
131
|
+
type: 'message',
|
|
132
|
+
data: {
|
|
133
|
+
type: 'bot',
|
|
134
|
+
text: text ? text : '',
|
|
135
|
+
children: _jsx(_Fragment, { children: result }),
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (result) {
|
|
141
|
+
const activityMessage = {
|
|
142
|
+
type: 'activity',
|
|
143
|
+
text: '',
|
|
144
|
+
meta: {
|
|
145
|
+
activity: {
|
|
146
|
+
type: 'response',
|
|
147
|
+
function: {
|
|
148
|
+
name,
|
|
149
|
+
arguments: args,
|
|
150
|
+
result: JSON.stringify(result),
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
yield { type: 'message', data: activityMessage };
|
|
156
|
+
messages.push(activityMessage);
|
|
157
|
+
yield* complete({
|
|
158
|
+
...options,
|
|
159
|
+
client,
|
|
160
|
+
messages,
|
|
161
|
+
functions,
|
|
162
|
+
maxRecusion: maxRecusion - 1,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
export function streamComplete(options) {
|
|
171
|
+
return stream(complete(options));
|
|
172
|
+
}
|
|
173
|
+
export default complete;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import React, {
|
|
2
|
+
import React, { useEffect, useRef } from 'react';
|
|
3
3
|
function AutoScrollAnchor() {
|
|
4
4
|
return _jsx("div", { className: "auto-scroll-anchor", style: { height: '1px' } });
|
|
5
5
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export function ConversationManager({ children, ...options }: import('../hooks/useConversationManager.js').UseConversationManagerOptions & {
|
|
2
|
+
children: import('react').ReactNode;
|
|
3
|
+
}): import('react').ReactElement;
|
|
4
|
+
export const ConversationContext: import("react").Context<import("../hooks/useConversationManager.js").UseConversationManagerResult>;
|
|
5
|
+
export default ConversationManager;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createContext } from 'react';
|
|
3
|
+
import useConversationManager from '../hooks/useConversationManager.js';
|
|
4
|
+
export const ConversationContext = createContext(({
|
|
5
|
+
message: null,
|
|
6
|
+
messages: [],
|
|
7
|
+
thinking: false,
|
|
8
|
+
typing: false,
|
|
9
|
+
text: '',
|
|
10
|
+
setText: () => { },
|
|
11
|
+
error: null,
|
|
12
|
+
setError: () => { },
|
|
13
|
+
submit: () => { },
|
|
14
|
+
trigger: () => { },
|
|
15
|
+
request: () => { },
|
|
16
|
+
}));
|
|
17
|
+
export function ConversationManager({ children, ...options }) {
|
|
18
|
+
const manager = useConversationManager(options);
|
|
19
|
+
return (_jsx(ConversationContext.Provider, { value: manager, children: children }));
|
|
20
|
+
}
|
|
21
|
+
export default ConversationManager;
|
|
@@ -1,57 +1,18 @@
|
|
|
1
|
-
export function useConversationManager(
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
Model?: string | undefined;
|
|
9
|
-
datasetId?: string | undefined;
|
|
10
|
-
skillsetId?: string | undefined;
|
|
11
|
-
}): {
|
|
12
|
-
token: string | undefined;
|
|
13
|
-
setToken: import("react").Dispatch<import("react").SetStateAction<string | undefined>>;
|
|
14
|
-
conversationId: string | undefined;
|
|
15
|
-
setConversationId: import("react").Dispatch<import("react").SetStateAction<string | undefined>>;
|
|
16
|
-
backstory: string | undefined;
|
|
17
|
-
setBackstory: import("react").Dispatch<import("react").SetStateAction<string | undefined>>;
|
|
18
|
-
model: any;
|
|
19
|
-
setModel: import("react").Dispatch<any>;
|
|
20
|
-
datasetId: string | undefined;
|
|
21
|
-
setDatasetId: import("react").Dispatch<import("react").SetStateAction<string | undefined>>;
|
|
22
|
-
skillsetId: string | undefined;
|
|
23
|
-
setSkillsetId: import("react").Dispatch<import("react").SetStateAction<string | undefined>>;
|
|
24
|
-
text: string;
|
|
25
|
-
setText: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
1
|
+
export function useConversationManager({ ...conversationManagerRemoteOptions }: UseConversationManagerOptions): UseConversationManagerResult;
|
|
2
|
+
export default useConversationManager;
|
|
3
|
+
export type Message = import('@chatbotkit/sdk/conversation/v1').Message;
|
|
4
|
+
export type UseConversationManagerRemoteOptions = import('./useConversationManagerRemote.js').UseConversationManagerRemoteOptions;
|
|
5
|
+
export type UseConversationManagerOptions = UseConversationManagerRemoteOptions & {};
|
|
6
|
+
export type UseConversationManagerResult = {
|
|
7
|
+
message: Message | null;
|
|
26
8
|
messages: Message[];
|
|
27
|
-
setMessages: import("react").Dispatch<import("react").SetStateAction<Message[]>>;
|
|
28
9
|
thinking: boolean;
|
|
29
|
-
setThinking: import("react").Dispatch<import("react").SetStateAction<boolean>>;
|
|
30
10
|
typing: boolean;
|
|
31
|
-
setTyping: import("react").Dispatch<import("react").SetStateAction<boolean>>;
|
|
32
|
-
error: any;
|
|
33
|
-
setError: import("react").Dispatch<any>;
|
|
34
|
-
submit: () => Promise<void>;
|
|
35
|
-
};
|
|
36
|
-
export default useConversationManager;
|
|
37
|
-
export type ModelConfig = {
|
|
38
|
-
maxTokens?: number;
|
|
39
|
-
temperature?: number;
|
|
40
|
-
frequencyPenalty?: number;
|
|
41
|
-
presencePenalty?: number;
|
|
42
|
-
seed?: number;
|
|
43
|
-
interactionMaxMessages?: number;
|
|
44
|
-
region?: 'us' | 'eu';
|
|
45
|
-
};
|
|
46
|
-
export type Model = string | {
|
|
47
|
-
name: string;
|
|
48
|
-
config?: ModelConfig;
|
|
49
|
-
};
|
|
50
|
-
export type Message = {
|
|
51
|
-
id: string;
|
|
52
|
-
type: 'bot' | 'user';
|
|
53
11
|
text: string;
|
|
12
|
+
setText: (text: string) => void;
|
|
13
|
+
error: any;
|
|
14
|
+
setError: (error: any) => void;
|
|
15
|
+
submit: () => void;
|
|
16
|
+
trigger: (name: string) => void;
|
|
17
|
+
request: (name: string, args: any) => void;
|
|
54
18
|
};
|
|
55
|
-
export type EndpointURL = string;
|
|
56
|
-
export type EndpointFunction = (conversationId: any, request: any) => AsyncGenerator<any>;
|
|
57
|
-
import { ConversationClient } from '@chatbotkit/sdk';
|
|
@@ -1,138 +1,123 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const { client: _client, endpoint, token: _token, conversationId: _conversationId, backstory: _backstory, model: _model, datasetId: _datasetId, skillsetId: _skillsetId, ...rest } = options;
|
|
8
|
-
const [token, setToken] = useState(_token);
|
|
9
|
-
const [conversationId, setConversationId] = useState(_conversationId);
|
|
10
|
-
const [backstory, setBackstory] = useState(_backstory);
|
|
11
|
-
const [model, setModel] = useState(_model);
|
|
12
|
-
const [datasetId, setDatasetId] = useState(_datasetId);
|
|
13
|
-
const [skillsetId, setSkillsetId] = useState(_skillsetId);
|
|
14
|
-
const client = useMemo(() => {
|
|
15
|
-
if (typeof endpoint === 'function') {
|
|
16
|
-
return {
|
|
17
|
-
complete(conversationId, options) {
|
|
18
|
-
return {
|
|
19
|
-
async *stream() {
|
|
20
|
-
yield* consume(endpoint(conversationId, options));
|
|
21
|
-
},
|
|
22
|
-
};
|
|
23
|
-
},
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
const options = { ...rest, secret: token || '' };
|
|
27
|
-
let thisClient = _client || new ConversationClient(options);
|
|
28
|
-
const extension = {};
|
|
29
|
-
if (typeof endpoint === 'string') {
|
|
30
|
-
extension.url = new URL(globalThis.window?.location?.origin || 'about:blank');
|
|
31
|
-
extension.endpoints = {
|
|
32
|
-
'/api/v1/conversation/complete': endpoint,
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
if (token) {
|
|
36
|
-
extension.secret = token;
|
|
37
|
-
}
|
|
38
|
-
if (Object.keys(extension).length === 0) {
|
|
39
|
-
return thisClient;
|
|
40
|
-
}
|
|
41
|
-
else {
|
|
42
|
-
return cloneAndExtend(thisClient, extension);
|
|
43
|
-
}
|
|
44
|
-
}, [_client, endpoint, token]);
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import useConversationManagerRemote from './useConversationManagerRemote.js';
|
|
3
|
+
import { useConversationManagerState } from './useConversationManagerState.js';
|
|
4
|
+
export function useConversationManager({ ...conversationManagerRemoteOptions }) {
|
|
5
|
+
const remote = useConversationManagerRemote(conversationManagerRemoteOptions);
|
|
6
|
+
const [{ thinking, typing, message, messages, }, { setThinking, setTyping, appendText, appendMessage, },] = useConversationManagerState();
|
|
45
7
|
const [text, setText] = useState((''));
|
|
46
|
-
const [messages, setMessages] = useState(([]));
|
|
47
|
-
const [thinking, setThinking] = useState(false);
|
|
48
|
-
const [typing, setTyping] = useState(false);
|
|
49
8
|
const [error, setError] = useState((null));
|
|
50
|
-
async function
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
9
|
+
async function stream(newMessages) {
|
|
10
|
+
const allMessages = [
|
|
11
|
+
...messages.map(({ type, text, meta }) => {
|
|
12
|
+
return {
|
|
13
|
+
type,
|
|
14
|
+
text,
|
|
15
|
+
meta,
|
|
16
|
+
};
|
|
17
|
+
}),
|
|
18
|
+
...(newMessages?.map(({ type, text, meta }) => {
|
|
19
|
+
return {
|
|
20
|
+
type,
|
|
21
|
+
text,
|
|
22
|
+
meta,
|
|
23
|
+
};
|
|
24
|
+
}) || []),
|
|
25
|
+
].slice(-100);
|
|
65
26
|
try {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
catch (e) {
|
|
80
|
-
setThinking(false);
|
|
81
|
-
setError(e);
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
const botMessage = {
|
|
85
|
-
id: getRandomId('message-'),
|
|
86
|
-
type: 'bot',
|
|
87
|
-
text: '',
|
|
88
|
-
};
|
|
89
|
-
let alreadyStreaming = false;
|
|
90
|
-
try {
|
|
91
|
-
for await (const event of it.stream()) {
|
|
92
|
-
if (event.type === 'token') {
|
|
93
|
-
if (!alreadyStreaming) {
|
|
94
|
-
alreadyStreaming = true;
|
|
95
|
-
newMessages = [...newMessages, botMessage];
|
|
96
|
-
setMessages(newMessages);
|
|
97
|
-
setThinking(false);
|
|
98
|
-
setTyping(true);
|
|
27
|
+
setThinking(true);
|
|
28
|
+
setError(null);
|
|
29
|
+
for await (const item of remote(allMessages)) {
|
|
30
|
+
switch (item.type) {
|
|
31
|
+
case 'token': {
|
|
32
|
+
appendText(item.data.token);
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
case 'message': {
|
|
36
|
+
appendMessage(item.data);
|
|
37
|
+
break;
|
|
99
38
|
}
|
|
100
|
-
botMessage.text += event.data.token;
|
|
101
|
-
setMessages([...newMessages]);
|
|
102
39
|
}
|
|
103
40
|
}
|
|
104
41
|
}
|
|
105
42
|
catch (e) {
|
|
106
43
|
setError(e);
|
|
44
|
+
if (typeof process !== 'undefined' &&
|
|
45
|
+
process.env.NODE_ENV === 'development') {
|
|
46
|
+
console.error(e);
|
|
47
|
+
}
|
|
107
48
|
}
|
|
108
49
|
finally {
|
|
50
|
+
setThinking(false);
|
|
109
51
|
setTyping(false);
|
|
110
52
|
}
|
|
111
53
|
}
|
|
54
|
+
async function submit(thisText) {
|
|
55
|
+
if (thinking || typing) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (!thisText) {
|
|
59
|
+
if (!text) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
thisText = text;
|
|
63
|
+
setText('');
|
|
64
|
+
}
|
|
65
|
+
const userMessage = {
|
|
66
|
+
type: 'user',
|
|
67
|
+
text: thisText,
|
|
68
|
+
};
|
|
69
|
+
appendMessage(userMessage);
|
|
70
|
+
await stream([userMessage]);
|
|
71
|
+
}
|
|
72
|
+
async function trigger(name) {
|
|
73
|
+
if (thinking || typing) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const activityMessage = {
|
|
77
|
+
type: 'activity',
|
|
78
|
+
text: '',
|
|
79
|
+
meta: {
|
|
80
|
+
activity: {
|
|
81
|
+
type: 'trigger',
|
|
82
|
+
function: {
|
|
83
|
+
name: name,
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
await stream([activityMessage]);
|
|
89
|
+
}
|
|
90
|
+
async function request(name, args) {
|
|
91
|
+
if (thinking || typing) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const activityMessage = {
|
|
95
|
+
type: 'activity',
|
|
96
|
+
text: '',
|
|
97
|
+
meta: {
|
|
98
|
+
activity: {
|
|
99
|
+
type: 'request',
|
|
100
|
+
function: {
|
|
101
|
+
name: name,
|
|
102
|
+
arguments: args,
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
await stream([activityMessage]);
|
|
108
|
+
}
|
|
112
109
|
return {
|
|
113
|
-
|
|
114
|
-
setToken,
|
|
115
|
-
conversationId,
|
|
116
|
-
setConversationId,
|
|
117
|
-
backstory,
|
|
118
|
-
setBackstory,
|
|
119
|
-
model,
|
|
120
|
-
setModel,
|
|
121
|
-
datasetId,
|
|
122
|
-
setDatasetId,
|
|
123
|
-
skillsetId,
|
|
124
|
-
setSkillsetId,
|
|
125
|
-
text,
|
|
126
|
-
setText,
|
|
110
|
+
message,
|
|
127
111
|
messages,
|
|
128
|
-
setMessages,
|
|
129
112
|
thinking,
|
|
130
|
-
setThinking,
|
|
131
113
|
typing,
|
|
132
|
-
|
|
114
|
+
text,
|
|
115
|
+
setText,
|
|
133
116
|
error,
|
|
134
117
|
setError,
|
|
135
118
|
submit,
|
|
119
|
+
trigger,
|
|
120
|
+
request,
|
|
136
121
|
};
|
|
137
122
|
}
|
|
138
123
|
export default useConversationManager;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export function useConversationManagerRemote({ client: _client, endpoint, conversationId, token, backstory, model, datasetId, skillsetId, privacy, moderation, ...rest }: UseConversationManagerRemoteOptions): UseConversationManagerRemoteResult;
|
|
2
|
+
export default useConversationManagerRemote;
|
|
3
|
+
export type Message = import('@chatbotkit/sdk/conversation/v1').Message;
|
|
4
|
+
export type Model = import('@chatbotkit/sdk/model/v1').Model;
|
|
5
|
+
export type EndpointURL = string;
|
|
6
|
+
export type EndpointFunction = (options: any) => AsyncGenerator<any>;
|
|
7
|
+
export type UseConversationManagerRemoteOptions = {
|
|
8
|
+
client?: ConversationClient;
|
|
9
|
+
endpoint?: EndpointURL | EndpointFunction;
|
|
10
|
+
conversationId?: string;
|
|
11
|
+
token?: string;
|
|
12
|
+
backstory?: string;
|
|
13
|
+
model?: Model;
|
|
14
|
+
datasetId?: string;
|
|
15
|
+
skillsetId?: string;
|
|
16
|
+
privacy?: boolean;
|
|
17
|
+
moderation?: boolean;
|
|
18
|
+
};
|
|
19
|
+
export type UseConversationManagerRemoteResult = (messages: Message[]) => AsyncGenerator<any, void, any>;
|
|
20
|
+
import { ConversationClient } from '@chatbotkit/sdk';
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { cloneAndExtend } from '../utils/object.js';
|
|
3
|
+
import { consume } from '../utils/stream.js';
|
|
4
|
+
import { ConversationClient } from '@chatbotkit/sdk';
|
|
5
|
+
export function useConversationManagerRemote({ client: _client, endpoint, conversationId, token, backstory, model, datasetId, skillsetId, privacy, moderation, ...rest }) {
|
|
6
|
+
const client = useMemo(() => {
|
|
7
|
+
if (typeof endpoint === 'function') {
|
|
8
|
+
return {
|
|
9
|
+
complete(conversationId, options) {
|
|
10
|
+
return {
|
|
11
|
+
async *stream() {
|
|
12
|
+
yield* consume(endpoint(options));
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
const options = { ...rest, secret: token || '' };
|
|
19
|
+
let thisClient = _client || new ConversationClient(options);
|
|
20
|
+
const extension = {};
|
|
21
|
+
if (typeof endpoint === 'string') {
|
|
22
|
+
extension.url = new URL(globalThis.window?.location?.origin || 'about:blank');
|
|
23
|
+
extension.endpoints = {
|
|
24
|
+
'/api/v1/conversation/complete': endpoint,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
if (token) {
|
|
28
|
+
extension.secret = token;
|
|
29
|
+
}
|
|
30
|
+
if (Object.keys(extension).length === 0) {
|
|
31
|
+
return thisClient;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
return cloneAndExtend(thisClient, extension);
|
|
35
|
+
}
|
|
36
|
+
}, [_client, endpoint, token]);
|
|
37
|
+
const remote = useMemo(() => {
|
|
38
|
+
if (conversationId) {
|
|
39
|
+
return (async function* (messages) {
|
|
40
|
+
const lastUserMessage = [...messages]
|
|
41
|
+
.reverse()
|
|
42
|
+
.find((message) => message.type === 'user');
|
|
43
|
+
if (!lastUserMessage) {
|
|
44
|
+
throw new Error('No user message found');
|
|
45
|
+
}
|
|
46
|
+
yield* client
|
|
47
|
+
.complete(conversationId, { text: lastUserMessage.text })
|
|
48
|
+
.stream();
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
return (async function* (messages) {
|
|
53
|
+
yield* client
|
|
54
|
+
.complete(null, {
|
|
55
|
+
backstory: backstory,
|
|
56
|
+
model: model,
|
|
57
|
+
datasetId: datasetId,
|
|
58
|
+
skillsetId: skillsetId,
|
|
59
|
+
privacy: privacy,
|
|
60
|
+
moderation: moderation,
|
|
61
|
+
messages: messages,
|
|
62
|
+
})
|
|
63
|
+
.stream();
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}, [
|
|
67
|
+
client,
|
|
68
|
+
conversationId,
|
|
69
|
+
backstory,
|
|
70
|
+
model,
|
|
71
|
+
datasetId,
|
|
72
|
+
skillsetId,
|
|
73
|
+
privacy,
|
|
74
|
+
moderation,
|
|
75
|
+
]);
|
|
76
|
+
return remote;
|
|
77
|
+
}
|
|
78
|
+
export default useConversationManagerRemote;
|