@reverbia/sdk 1.0.0-next.20251202090922 → 1.0.0-next.20251202095402
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/dist/react/index.cjs +466 -89
- package/dist/react/index.d.mts +149 -24
- package/dist/react/index.d.ts +149 -24
- package/dist/react/index.mjs +462 -88
- package/package.json +1 -1
package/dist/react/index.mjs
CHANGED
|
@@ -818,6 +818,218 @@ var createClientConfig = (config) => ({
|
|
|
818
818
|
// src/client/client.gen.ts
|
|
819
819
|
var client = createClient(createClientConfig(createConfig()));
|
|
820
820
|
|
|
821
|
+
// src/lib/chat/constants.ts
|
|
822
|
+
var DEFAULT_LOCAL_CHAT_MODEL = "onnx-community/Qwen2.5-0.5B-Instruct";
|
|
823
|
+
|
|
824
|
+
// src/lib/chat/pipeline.ts
|
|
825
|
+
var sharedPipeline = null;
|
|
826
|
+
var currentModel = null;
|
|
827
|
+
var currentDevice = null;
|
|
828
|
+
async function getTextGenerationPipeline(options) {
|
|
829
|
+
const { model, device = "wasm", dtype = "q4" } = options;
|
|
830
|
+
if (sharedPipeline && currentModel === model && currentDevice === device) {
|
|
831
|
+
return sharedPipeline;
|
|
832
|
+
}
|
|
833
|
+
const { pipeline, env } = await import("./transformers.node-BSHUG7OY.mjs");
|
|
834
|
+
env.allowLocalModels = false;
|
|
835
|
+
if (env.backends?.onnx) {
|
|
836
|
+
env.backends.onnx.logLevel = "fatal";
|
|
837
|
+
}
|
|
838
|
+
console.log(`[Pipeline] Loading model: ${model} on ${device}...`);
|
|
839
|
+
sharedPipeline = await pipeline("text-generation", model, {
|
|
840
|
+
dtype,
|
|
841
|
+
device
|
|
842
|
+
});
|
|
843
|
+
currentModel = model;
|
|
844
|
+
currentDevice = device;
|
|
845
|
+
console.log(`[Pipeline] Model loaded: ${model}`);
|
|
846
|
+
return sharedPipeline;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
// src/lib/chat/generation.ts
|
|
850
|
+
async function generateLocalChatCompletion(messages, options = {}) {
|
|
851
|
+
const {
|
|
852
|
+
model = DEFAULT_LOCAL_CHAT_MODEL,
|
|
853
|
+
temperature = 0.7,
|
|
854
|
+
max_tokens = 1024,
|
|
855
|
+
top_p = 0.9,
|
|
856
|
+
onToken,
|
|
857
|
+
signal
|
|
858
|
+
} = options;
|
|
859
|
+
const { TextStreamer } = await import("./transformers.node-BSHUG7OY.mjs");
|
|
860
|
+
const chatPipeline = await getTextGenerationPipeline({
|
|
861
|
+
model,
|
|
862
|
+
device: "wasm",
|
|
863
|
+
dtype: "q4"
|
|
864
|
+
});
|
|
865
|
+
class CallbackStreamer extends TextStreamer {
|
|
866
|
+
constructor(tokenizer, cb) {
|
|
867
|
+
super(tokenizer, {
|
|
868
|
+
skip_prompt: true,
|
|
869
|
+
skip_special_tokens: true
|
|
870
|
+
});
|
|
871
|
+
this.cb = cb;
|
|
872
|
+
}
|
|
873
|
+
on_finalized_text(text) {
|
|
874
|
+
if (signal?.aborted) {
|
|
875
|
+
throw new Error("AbortError");
|
|
876
|
+
}
|
|
877
|
+
this.cb(text);
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
const streamer = onToken ? new CallbackStreamer(chatPipeline.tokenizer, onToken) : void 0;
|
|
881
|
+
const output = await chatPipeline(messages, {
|
|
882
|
+
max_new_tokens: max_tokens,
|
|
883
|
+
temperature,
|
|
884
|
+
top_p,
|
|
885
|
+
streamer,
|
|
886
|
+
return_full_text: false
|
|
887
|
+
});
|
|
888
|
+
return output;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
// src/lib/tools/selector.ts
|
|
892
|
+
var DEFAULT_TOOL_SELECTOR_MODEL = "Xenova/LaMini-GPT-124M";
|
|
893
|
+
function buildToolSelectionPrompt(userMessage, tools) {
|
|
894
|
+
const toolList = tools.map((t) => `${t.name} (${t.description})`).join("\n");
|
|
895
|
+
return `Pick the best tool for the task. Reply with ONLY the tool name.
|
|
896
|
+
|
|
897
|
+
Available tools:
|
|
898
|
+
${toolList}
|
|
899
|
+
none (no tool needed)
|
|
900
|
+
|
|
901
|
+
Task: "${userMessage}"
|
|
902
|
+
|
|
903
|
+
Best tool:`;
|
|
904
|
+
}
|
|
905
|
+
function extractParams(userMessage, tool) {
|
|
906
|
+
const params = {};
|
|
907
|
+
if (!tool.parameters) return params;
|
|
908
|
+
for (const param of tool.parameters) {
|
|
909
|
+
if (param.name === "expression" || param.name === "query") {
|
|
910
|
+
params[param.name] = userMessage;
|
|
911
|
+
} else if (param.name === "location" || param.name === "city") {
|
|
912
|
+
const words = userMessage.split(/\s+/);
|
|
913
|
+
const capitalizedWords = words.filter(
|
|
914
|
+
(w) => w.length > 1 && w[0] === w[0].toUpperCase()
|
|
915
|
+
);
|
|
916
|
+
params[param.name] = capitalizedWords.length > 0 ? capitalizedWords.join(" ") : userMessage;
|
|
917
|
+
} else if (param.name === "text" || param.name === "input") {
|
|
918
|
+
params[param.name] = userMessage;
|
|
919
|
+
} else {
|
|
920
|
+
params[param.name] = userMessage;
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
return params;
|
|
924
|
+
}
|
|
925
|
+
function parseToolSelectionResponse(response, tools, userMessage) {
|
|
926
|
+
console.log("[Tool Selector] Raw response:", response);
|
|
927
|
+
const cleaned = response.toLowerCase().trim().split(/[\s\n,.]+/)[0].replace(/[^a-z0-9_-]/g, "");
|
|
928
|
+
console.log("[Tool Selector] Parsed tool name:", cleaned);
|
|
929
|
+
if (cleaned === "none" || cleaned === "null" || cleaned === "") {
|
|
930
|
+
console.log("[Tool Selector] No tool selected");
|
|
931
|
+
return { toolSelected: false };
|
|
932
|
+
}
|
|
933
|
+
const selectedTool = tools.find((t) => t.name.toLowerCase() === cleaned);
|
|
934
|
+
if (!selectedTool) {
|
|
935
|
+
const fuzzyTool = tools.find(
|
|
936
|
+
(t) => t.name.toLowerCase().includes(cleaned) || cleaned.includes(t.name.toLowerCase())
|
|
937
|
+
);
|
|
938
|
+
if (fuzzyTool) {
|
|
939
|
+
console.log(`[Tool Selector] Fuzzy matched tool: ${fuzzyTool.name}`);
|
|
940
|
+
const params2 = extractParams(userMessage, fuzzyTool);
|
|
941
|
+
return {
|
|
942
|
+
toolSelected: true,
|
|
943
|
+
toolName: fuzzyTool.name,
|
|
944
|
+
parameters: params2,
|
|
945
|
+
confidence: 0.6
|
|
946
|
+
};
|
|
947
|
+
}
|
|
948
|
+
console.warn(`[Tool Selector] Unknown tool: ${cleaned}`);
|
|
949
|
+
return { toolSelected: false };
|
|
950
|
+
}
|
|
951
|
+
const params = extractParams(userMessage, selectedTool);
|
|
952
|
+
console.log(`[Tool Selector] Selected tool: ${selectedTool.name}`, params);
|
|
953
|
+
return {
|
|
954
|
+
toolSelected: true,
|
|
955
|
+
toolName: selectedTool.name,
|
|
956
|
+
parameters: params,
|
|
957
|
+
confidence: 0.9
|
|
958
|
+
};
|
|
959
|
+
}
|
|
960
|
+
async function selectTool(userMessage, tools, options = {}) {
|
|
961
|
+
const {
|
|
962
|
+
model = DEFAULT_TOOL_SELECTOR_MODEL,
|
|
963
|
+
signal,
|
|
964
|
+
device = "wasm"
|
|
965
|
+
} = options;
|
|
966
|
+
if (!tools.length) {
|
|
967
|
+
return { toolSelected: false };
|
|
968
|
+
}
|
|
969
|
+
console.log(
|
|
970
|
+
`[Tool Selector] analyzing message: "${userMessage}" with model ${model}`
|
|
971
|
+
);
|
|
972
|
+
try {
|
|
973
|
+
const selectorPipeline = await getTextGenerationPipeline({
|
|
974
|
+
model,
|
|
975
|
+
device,
|
|
976
|
+
dtype: "q4"
|
|
977
|
+
// Aggressive quantization for speed
|
|
978
|
+
});
|
|
979
|
+
const prompt = buildToolSelectionPrompt(userMessage, tools);
|
|
980
|
+
const output = await selectorPipeline(prompt, {
|
|
981
|
+
max_new_tokens: 4,
|
|
982
|
+
// Just need the tool name
|
|
983
|
+
temperature: 0,
|
|
984
|
+
// Deterministic
|
|
985
|
+
do_sample: false,
|
|
986
|
+
return_full_text: false
|
|
987
|
+
});
|
|
988
|
+
if (signal?.aborted) {
|
|
989
|
+
return { toolSelected: false };
|
|
990
|
+
}
|
|
991
|
+
const generatedText = output?.[0]?.generated_text || output?.generated_text || "";
|
|
992
|
+
return parseToolSelectionResponse(generatedText, tools, userMessage);
|
|
993
|
+
} catch (error) {
|
|
994
|
+
console.error("[Tool Selector] Error:", error);
|
|
995
|
+
return { toolSelected: false };
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
var preloadPromise = null;
|
|
999
|
+
async function preloadToolSelectorModel(options = {}) {
|
|
1000
|
+
if (preloadPromise) {
|
|
1001
|
+
return preloadPromise;
|
|
1002
|
+
}
|
|
1003
|
+
const { model = DEFAULT_TOOL_SELECTOR_MODEL, device = "wasm" } = options;
|
|
1004
|
+
console.log(`[Tool Selector] Preloading model: ${model}`);
|
|
1005
|
+
preloadPromise = getTextGenerationPipeline({
|
|
1006
|
+
model,
|
|
1007
|
+
device,
|
|
1008
|
+
dtype: "q4"
|
|
1009
|
+
}).then(() => {
|
|
1010
|
+
console.log(`[Tool Selector] Model preloaded: ${model}`);
|
|
1011
|
+
}).catch((error) => {
|
|
1012
|
+
console.warn("[Tool Selector] Failed to preload model:", error);
|
|
1013
|
+
preloadPromise = null;
|
|
1014
|
+
});
|
|
1015
|
+
return preloadPromise;
|
|
1016
|
+
}
|
|
1017
|
+
async function executeTool(tool, params) {
|
|
1018
|
+
try {
|
|
1019
|
+
console.log(
|
|
1020
|
+
`[Tool Selector] Executing tool ${tool.name} with params:`,
|
|
1021
|
+
params
|
|
1022
|
+
);
|
|
1023
|
+
const result = await tool.execute(params);
|
|
1024
|
+
console.log(`[Tool Selector] Tool ${tool.name} execution result:`, result);
|
|
1025
|
+
return { success: true, result };
|
|
1026
|
+
} catch (error) {
|
|
1027
|
+
const errorMessage = error instanceof Error ? error.message : "Tool execution failed";
|
|
1028
|
+
console.error(`[Tool Selector] Tool ${tool.name} failed:`, errorMessage);
|
|
1029
|
+
return { success: false, error: errorMessage };
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
|
|
821
1033
|
// src/react/useChat.ts
|
|
822
1034
|
function useChat(options) {
|
|
823
1035
|
const {
|
|
@@ -825,9 +1037,15 @@ function useChat(options) {
|
|
|
825
1037
|
baseUrl = BASE_URL,
|
|
826
1038
|
onData: globalOnData,
|
|
827
1039
|
onFinish,
|
|
828
|
-
onError
|
|
1040
|
+
onError,
|
|
1041
|
+
chatProvider = "api",
|
|
1042
|
+
localModel = DEFAULT_LOCAL_CHAT_MODEL,
|
|
1043
|
+
tools,
|
|
1044
|
+
toolSelectorModel = DEFAULT_TOOL_SELECTOR_MODEL,
|
|
1045
|
+
onToolExecution
|
|
829
1046
|
} = options || {};
|
|
830
1047
|
const [isLoading, setIsLoading] = useState(false);
|
|
1048
|
+
const [isSelectingTool, setIsSelectingTool] = useState(false);
|
|
831
1049
|
const abortControllerRef = useRef(null);
|
|
832
1050
|
const stop = useCallback(() => {
|
|
833
1051
|
if (abortControllerRef.current) {
|
|
@@ -843,120 +1061,257 @@ function useChat(options) {
|
|
|
843
1061
|
}
|
|
844
1062
|
};
|
|
845
1063
|
}, []);
|
|
1064
|
+
useEffect(() => {
|
|
1065
|
+
if (tools && tools.length > 0) {
|
|
1066
|
+
preloadToolSelectorModel({ model: toolSelectorModel });
|
|
1067
|
+
}
|
|
1068
|
+
}, [tools, toolSelectorModel]);
|
|
846
1069
|
const sendMessage = useCallback(
|
|
847
1070
|
async ({
|
|
848
1071
|
messages,
|
|
849
1072
|
model,
|
|
850
|
-
onData
|
|
1073
|
+
onData,
|
|
1074
|
+
runTools = true
|
|
851
1075
|
}) => {
|
|
852
1076
|
if (!messages?.length) {
|
|
853
1077
|
const errorMsg = "messages are required to call sendMessage.";
|
|
854
1078
|
if (onError) onError(new Error(errorMsg));
|
|
855
1079
|
return { data: null, error: errorMsg };
|
|
856
1080
|
}
|
|
857
|
-
if (!model) {
|
|
858
|
-
const errorMsg = "model is required to call sendMessage.";
|
|
859
|
-
if (onError) onError(new Error(errorMsg));
|
|
860
|
-
return { data: null, error: errorMsg };
|
|
861
|
-
}
|
|
862
|
-
if (!getToken) {
|
|
863
|
-
const errorMsg = "Token getter function is required.";
|
|
864
|
-
if (onError) onError(new Error(errorMsg));
|
|
865
|
-
return { data: null, error: errorMsg };
|
|
866
|
-
}
|
|
867
1081
|
if (abortControllerRef.current) {
|
|
868
1082
|
abortControllerRef.current.abort();
|
|
869
1083
|
}
|
|
870
1084
|
const abortController = new AbortController();
|
|
871
1085
|
abortControllerRef.current = abortController;
|
|
872
1086
|
setIsLoading(true);
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
1087
|
+
let toolExecutionResult;
|
|
1088
|
+
let messagesWithToolContext = messages;
|
|
1089
|
+
if (runTools && tools && tools.length > 0) {
|
|
1090
|
+
const lastUserMessage = [...messages].reverse().find((m) => m.role === "user");
|
|
1091
|
+
if (lastUserMessage?.content) {
|
|
1092
|
+
setIsSelectingTool(true);
|
|
1093
|
+
try {
|
|
1094
|
+
const selectionResult = await selectTool(
|
|
1095
|
+
lastUserMessage.content,
|
|
1096
|
+
tools,
|
|
1097
|
+
{
|
|
1098
|
+
model: toolSelectorModel,
|
|
1099
|
+
signal: abortController.signal
|
|
1100
|
+
}
|
|
1101
|
+
);
|
|
1102
|
+
if (selectionResult.toolSelected && selectionResult.toolName) {
|
|
1103
|
+
const selectedTool = tools.find(
|
|
1104
|
+
(t) => t.name === selectionResult.toolName
|
|
1105
|
+
);
|
|
1106
|
+
if (selectedTool) {
|
|
1107
|
+
const execResult = await executeTool(
|
|
1108
|
+
selectedTool,
|
|
1109
|
+
selectionResult.parameters || {}
|
|
1110
|
+
);
|
|
1111
|
+
toolExecutionResult = {
|
|
1112
|
+
toolName: selectionResult.toolName,
|
|
1113
|
+
success: execResult.success,
|
|
1114
|
+
result: execResult.result,
|
|
1115
|
+
error: execResult.error
|
|
1116
|
+
};
|
|
1117
|
+
if (onToolExecution) {
|
|
1118
|
+
onToolExecution(toolExecutionResult);
|
|
1119
|
+
}
|
|
1120
|
+
if (toolExecutionResult.success && toolExecutionResult.result !== void 0) {
|
|
1121
|
+
const toolResultContext = {
|
|
1122
|
+
role: "system",
|
|
1123
|
+
content: `Tool "${toolExecutionResult.toolName}" was executed with the following result:
|
|
1124
|
+
${JSON.stringify(
|
|
1125
|
+
toolExecutionResult.result,
|
|
1126
|
+
null,
|
|
1127
|
+
2
|
|
1128
|
+
)}
|
|
1129
|
+
|
|
1130
|
+
Use this information to respond to the user's request.`
|
|
1131
|
+
};
|
|
1132
|
+
messagesWithToolContext = [...messages, toolResultContext];
|
|
1133
|
+
} else if (toolExecutionResult.error) {
|
|
1134
|
+
const toolErrorContext = {
|
|
1135
|
+
role: "system",
|
|
1136
|
+
content: `Tool "${toolExecutionResult.toolName}" was executed but encountered an error: ${toolExecutionResult.error}
|
|
1137
|
+
|
|
1138
|
+
Please inform the user about this issue and try to help them alternatively.`
|
|
1139
|
+
};
|
|
1140
|
+
messagesWithToolContext = [...messages, toolErrorContext];
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
} catch (err) {
|
|
1145
|
+
console.warn("Tool selection error:", err);
|
|
1146
|
+
} finally {
|
|
1147
|
+
setIsSelectingTool(false);
|
|
903
1148
|
}
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
try {
|
|
1152
|
+
if (chatProvider === "local") {
|
|
1153
|
+
let accumulatedContent = "";
|
|
1154
|
+
const usedModel = localModel;
|
|
1155
|
+
const formattedMessages = messagesWithToolContext.map((m) => ({
|
|
1156
|
+
role: m.role || "user",
|
|
1157
|
+
content: m.content || ""
|
|
1158
|
+
}));
|
|
1159
|
+
await generateLocalChatCompletion(formattedMessages, {
|
|
1160
|
+
model: usedModel,
|
|
1161
|
+
signal: abortController.signal,
|
|
1162
|
+
onToken: (token) => {
|
|
1163
|
+
accumulatedContent += token;
|
|
1164
|
+
if (onData) onData(token);
|
|
1165
|
+
if (globalOnData) globalOnData(token);
|
|
908
1166
|
}
|
|
909
|
-
|
|
910
|
-
|
|
1167
|
+
});
|
|
1168
|
+
const completion = {
|
|
1169
|
+
id: `local-${Date.now()}`,
|
|
1170
|
+
model: usedModel,
|
|
1171
|
+
choices: [
|
|
1172
|
+
{
|
|
1173
|
+
index: 0,
|
|
1174
|
+
message: {
|
|
1175
|
+
role: "assistant",
|
|
1176
|
+
content: accumulatedContent
|
|
1177
|
+
},
|
|
1178
|
+
finish_reason: "stop"
|
|
1179
|
+
}
|
|
1180
|
+
],
|
|
1181
|
+
usage: {
|
|
1182
|
+
prompt_tokens: 0,
|
|
1183
|
+
// Not easily available from simple pipeline usage
|
|
1184
|
+
completion_tokens: 0,
|
|
1185
|
+
total_tokens: 0
|
|
911
1186
|
}
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
1187
|
+
};
|
|
1188
|
+
setIsLoading(false);
|
|
1189
|
+
if (onFinish) {
|
|
1190
|
+
onFinish(completion);
|
|
1191
|
+
}
|
|
1192
|
+
return {
|
|
1193
|
+
data: completion,
|
|
1194
|
+
error: null,
|
|
1195
|
+
toolExecution: toolExecutionResult
|
|
1196
|
+
};
|
|
1197
|
+
} else {
|
|
1198
|
+
if (!model) {
|
|
1199
|
+
const errorMsg = "model is required to call sendMessage.";
|
|
1200
|
+
if (onError) onError(new Error(errorMsg));
|
|
1201
|
+
return {
|
|
1202
|
+
data: null,
|
|
1203
|
+
error: errorMsg,
|
|
1204
|
+
toolExecution: toolExecutionResult
|
|
1205
|
+
};
|
|
1206
|
+
}
|
|
1207
|
+
if (!getToken) {
|
|
1208
|
+
const errorMsg = "Token getter function is required.";
|
|
1209
|
+
if (onError) onError(new Error(errorMsg));
|
|
1210
|
+
return {
|
|
1211
|
+
data: null,
|
|
1212
|
+
error: errorMsg,
|
|
1213
|
+
toolExecution: toolExecutionResult
|
|
1214
|
+
};
|
|
1215
|
+
}
|
|
1216
|
+
const token = await getToken();
|
|
1217
|
+
if (!token) {
|
|
1218
|
+
const errorMsg = "No access token available.";
|
|
1219
|
+
setIsLoading(false);
|
|
1220
|
+
if (onError) onError(new Error(errorMsg));
|
|
1221
|
+
return {
|
|
1222
|
+
data: null,
|
|
1223
|
+
error: errorMsg,
|
|
1224
|
+
toolExecution: toolExecutionResult
|
|
1225
|
+
};
|
|
1226
|
+
}
|
|
1227
|
+
const sseResult = await client.sse.post({
|
|
1228
|
+
baseUrl,
|
|
1229
|
+
url: "/api/v1/chat/completions",
|
|
1230
|
+
body: {
|
|
1231
|
+
messages: messagesWithToolContext,
|
|
1232
|
+
model,
|
|
1233
|
+
stream: true
|
|
1234
|
+
},
|
|
1235
|
+
headers: {
|
|
1236
|
+
"Content-Type": "application/json",
|
|
1237
|
+
Authorization: `Bearer ${token}`
|
|
1238
|
+
},
|
|
1239
|
+
signal: abortController.signal
|
|
1240
|
+
});
|
|
1241
|
+
let accumulatedContent = "";
|
|
1242
|
+
let completionId = "";
|
|
1243
|
+
let completionModel = "";
|
|
1244
|
+
let accumulatedUsage = {};
|
|
1245
|
+
let finishReason;
|
|
1246
|
+
for await (const chunk of sseResult.stream) {
|
|
1247
|
+
if (typeof chunk === "string" && (chunk.trim() === "[DONE]" || chunk.includes("[DONE]"))) {
|
|
1248
|
+
continue;
|
|
917
1249
|
}
|
|
918
|
-
if (
|
|
919
|
-
const
|
|
920
|
-
if (
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
1250
|
+
if (chunk && typeof chunk === "object") {
|
|
1251
|
+
const chunkData = chunk;
|
|
1252
|
+
if (chunkData.id && !completionId) {
|
|
1253
|
+
completionId = chunkData.id;
|
|
1254
|
+
}
|
|
1255
|
+
if (chunkData.model && !completionModel) {
|
|
1256
|
+
completionModel = chunkData.model;
|
|
1257
|
+
}
|
|
1258
|
+
if (chunkData.usage) {
|
|
1259
|
+
accumulatedUsage = {
|
|
1260
|
+
...accumulatedUsage,
|
|
1261
|
+
...chunkData.usage
|
|
1262
|
+
};
|
|
1263
|
+
}
|
|
1264
|
+
if (chunkData.choices && Array.isArray(chunkData.choices) && chunkData.choices.length > 0) {
|
|
1265
|
+
const choice = chunkData.choices[0];
|
|
1266
|
+
if (choice.delta?.content) {
|
|
1267
|
+
const content = choice.delta.content;
|
|
1268
|
+
accumulatedContent += content;
|
|
1269
|
+
if (onData) {
|
|
1270
|
+
onData(content);
|
|
1271
|
+
}
|
|
1272
|
+
if (globalOnData) {
|
|
1273
|
+
globalOnData(content);
|
|
1274
|
+
}
|
|
925
1275
|
}
|
|
926
|
-
if (
|
|
927
|
-
|
|
1276
|
+
if (choice.finish_reason) {
|
|
1277
|
+
finishReason = choice.finish_reason;
|
|
928
1278
|
}
|
|
929
1279
|
}
|
|
930
|
-
if (choice.finish_reason) {
|
|
931
|
-
finishReason = choice.finish_reason;
|
|
932
|
-
}
|
|
933
1280
|
}
|
|
934
1281
|
}
|
|
1282
|
+
const completion = {
|
|
1283
|
+
id: completionId,
|
|
1284
|
+
model: completionModel,
|
|
1285
|
+
choices: [
|
|
1286
|
+
{
|
|
1287
|
+
index: 0,
|
|
1288
|
+
message: {
|
|
1289
|
+
role: "assistant",
|
|
1290
|
+
content: accumulatedContent
|
|
1291
|
+
},
|
|
1292
|
+
finish_reason: finishReason
|
|
1293
|
+
}
|
|
1294
|
+
],
|
|
1295
|
+
usage: Object.keys(accumulatedUsage).length > 0 ? accumulatedUsage : void 0
|
|
1296
|
+
};
|
|
1297
|
+
setIsLoading(false);
|
|
1298
|
+
if (onFinish) {
|
|
1299
|
+
onFinish(completion);
|
|
1300
|
+
}
|
|
1301
|
+
return {
|
|
1302
|
+
data: completion,
|
|
1303
|
+
error: null,
|
|
1304
|
+
toolExecution: toolExecutionResult
|
|
1305
|
+
};
|
|
935
1306
|
}
|
|
936
|
-
const completion = {
|
|
937
|
-
id: completionId,
|
|
938
|
-
model: completionModel,
|
|
939
|
-
choices: [
|
|
940
|
-
{
|
|
941
|
-
index: 0,
|
|
942
|
-
message: {
|
|
943
|
-
role: "assistant",
|
|
944
|
-
content: accumulatedContent
|
|
945
|
-
},
|
|
946
|
-
finish_reason: finishReason
|
|
947
|
-
}
|
|
948
|
-
],
|
|
949
|
-
usage: Object.keys(accumulatedUsage).length > 0 ? accumulatedUsage : void 0
|
|
950
|
-
};
|
|
951
|
-
setIsLoading(false);
|
|
952
|
-
if (onFinish) {
|
|
953
|
-
onFinish(completion);
|
|
954
|
-
}
|
|
955
|
-
return { data: completion, error: null };
|
|
956
1307
|
} catch (err) {
|
|
957
1308
|
if (err instanceof Error && err.name === "AbortError") {
|
|
958
1309
|
setIsLoading(false);
|
|
959
|
-
return {
|
|
1310
|
+
return {
|
|
1311
|
+
data: null,
|
|
1312
|
+
error: "Request aborted",
|
|
1313
|
+
toolExecution: toolExecutionResult
|
|
1314
|
+
};
|
|
960
1315
|
}
|
|
961
1316
|
const errorMsg = err instanceof Error ? err.message : "Failed to send message.";
|
|
962
1317
|
const errorObj = err instanceof Error ? err : new Error(errorMsg);
|
|
@@ -964,17 +1319,33 @@ function useChat(options) {
|
|
|
964
1319
|
if (onError) {
|
|
965
1320
|
onError(errorObj);
|
|
966
1321
|
}
|
|
967
|
-
return {
|
|
1322
|
+
return {
|
|
1323
|
+
data: null,
|
|
1324
|
+
error: errorMsg,
|
|
1325
|
+
toolExecution: toolExecutionResult
|
|
1326
|
+
};
|
|
968
1327
|
} finally {
|
|
969
1328
|
if (abortControllerRef.current === abortController) {
|
|
970
1329
|
abortControllerRef.current = null;
|
|
971
1330
|
}
|
|
972
1331
|
}
|
|
973
1332
|
},
|
|
974
|
-
[
|
|
1333
|
+
[
|
|
1334
|
+
getToken,
|
|
1335
|
+
baseUrl,
|
|
1336
|
+
globalOnData,
|
|
1337
|
+
onFinish,
|
|
1338
|
+
onError,
|
|
1339
|
+
chatProvider,
|
|
1340
|
+
localModel,
|
|
1341
|
+
tools,
|
|
1342
|
+
toolSelectorModel,
|
|
1343
|
+
onToolExecution
|
|
1344
|
+
]
|
|
975
1345
|
);
|
|
976
1346
|
return {
|
|
977
1347
|
isLoading,
|
|
1348
|
+
isSelectingTool,
|
|
978
1349
|
sendMessage,
|
|
979
1350
|
stop
|
|
980
1351
|
};
|
|
@@ -1896,12 +2267,15 @@ var extractConversationContext = (messages, maxMessages = 3) => {
|
|
|
1896
2267
|
return userMessages.trim();
|
|
1897
2268
|
};
|
|
1898
2269
|
export {
|
|
2270
|
+
DEFAULT_TOOL_SELECTOR_MODEL,
|
|
1899
2271
|
createMemoryContextSystemMessage,
|
|
1900
2272
|
decryptData,
|
|
1901
2273
|
decryptDataBytes,
|
|
1902
2274
|
encryptData,
|
|
2275
|
+
executeTool,
|
|
1903
2276
|
extractConversationContext,
|
|
1904
2277
|
formatMemoriesForChat,
|
|
2278
|
+
selectTool,
|
|
1905
2279
|
useChat,
|
|
1906
2280
|
useEncryption,
|
|
1907
2281
|
useMemory,
|