@browser-ai/web-llm 2.1.4 → 2.1.5
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/index.js +198 -191
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +198 -191
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -889,7 +889,182 @@ function extractArgumentsDelta(content, state) {
|
|
|
889
889
|
return delta;
|
|
890
890
|
}
|
|
891
891
|
|
|
892
|
-
// src/
|
|
892
|
+
// ../shared/src/streaming/stream-processor.ts
|
|
893
|
+
function generateToolCallId2() {
|
|
894
|
+
return `call_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
|
|
895
|
+
}
|
|
896
|
+
async function processToolCallStream(chunks, emitTextDelta, controller, options) {
|
|
897
|
+
const fenceDetector = new ToolCallFenceDetector();
|
|
898
|
+
let currentToolCallId = null;
|
|
899
|
+
let toolInputStartEmitted = false;
|
|
900
|
+
let accumulatedFenceContent = "";
|
|
901
|
+
let argumentsStreamState = createArgumentsStreamState();
|
|
902
|
+
let insideFence = false;
|
|
903
|
+
let toolCallDetected = false;
|
|
904
|
+
let toolCalls = [];
|
|
905
|
+
let trailingText = "";
|
|
906
|
+
const resetFenceState = () => {
|
|
907
|
+
currentToolCallId = null;
|
|
908
|
+
toolInputStartEmitted = false;
|
|
909
|
+
accumulatedFenceContent = "";
|
|
910
|
+
argumentsStreamState = createArgumentsStreamState();
|
|
911
|
+
insideFence = false;
|
|
912
|
+
};
|
|
913
|
+
for await (const chunk of chunks) {
|
|
914
|
+
if (toolCallDetected) {
|
|
915
|
+
continue;
|
|
916
|
+
}
|
|
917
|
+
fenceDetector.addChunk(chunk);
|
|
918
|
+
while (fenceDetector.hasContent()) {
|
|
919
|
+
const wasInsideFence = insideFence;
|
|
920
|
+
const result = fenceDetector.detectStreamingFence();
|
|
921
|
+
insideFence = result.inFence;
|
|
922
|
+
let madeProgress = false;
|
|
923
|
+
if (!wasInsideFence && result.inFence) {
|
|
924
|
+
if (result.safeContent) {
|
|
925
|
+
emitTextDelta(result.safeContent);
|
|
926
|
+
madeProgress = true;
|
|
927
|
+
}
|
|
928
|
+
currentToolCallId = generateToolCallId2();
|
|
929
|
+
toolInputStartEmitted = false;
|
|
930
|
+
accumulatedFenceContent = "";
|
|
931
|
+
argumentsStreamState = createArgumentsStreamState();
|
|
932
|
+
insideFence = true;
|
|
933
|
+
continue;
|
|
934
|
+
}
|
|
935
|
+
if (result.completeFence) {
|
|
936
|
+
madeProgress = true;
|
|
937
|
+
if (result.safeContent) {
|
|
938
|
+
accumulatedFenceContent += result.safeContent;
|
|
939
|
+
}
|
|
940
|
+
if (toolInputStartEmitted && currentToolCallId) {
|
|
941
|
+
const delta = extractArgumentsDelta(
|
|
942
|
+
accumulatedFenceContent,
|
|
943
|
+
argumentsStreamState
|
|
944
|
+
);
|
|
945
|
+
if (delta.length > 0) {
|
|
946
|
+
controller.enqueue({
|
|
947
|
+
type: "tool-input-delta",
|
|
948
|
+
id: currentToolCallId,
|
|
949
|
+
delta
|
|
950
|
+
});
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
const parsed = parseJsonFunctionCalls(result.completeFence);
|
|
954
|
+
const selectedToolCalls = parsed.toolCalls.slice(0, 1);
|
|
955
|
+
if (selectedToolCalls.length === 0) {
|
|
956
|
+
emitTextDelta(result.completeFence);
|
|
957
|
+
if (result.textAfterFence) {
|
|
958
|
+
emitTextDelta(result.textAfterFence);
|
|
959
|
+
}
|
|
960
|
+
resetFenceState();
|
|
961
|
+
continue;
|
|
962
|
+
}
|
|
963
|
+
if (currentToolCallId) {
|
|
964
|
+
selectedToolCalls[0].toolCallId = currentToolCallId;
|
|
965
|
+
}
|
|
966
|
+
for (const [index, call] of selectedToolCalls.entries()) {
|
|
967
|
+
const toolCallId = index === 0 && currentToolCallId ? currentToolCallId : call.toolCallId;
|
|
968
|
+
const toolName = call.toolName;
|
|
969
|
+
const argsJson = JSON.stringify(call.args ?? {});
|
|
970
|
+
if (toolCallId === currentToolCallId) {
|
|
971
|
+
if (!toolInputStartEmitted) {
|
|
972
|
+
controller.enqueue({
|
|
973
|
+
type: "tool-input-start",
|
|
974
|
+
id: toolCallId,
|
|
975
|
+
toolName
|
|
976
|
+
});
|
|
977
|
+
toolInputStartEmitted = true;
|
|
978
|
+
}
|
|
979
|
+
const delta = extractArgumentsDelta(
|
|
980
|
+
accumulatedFenceContent,
|
|
981
|
+
argumentsStreamState
|
|
982
|
+
);
|
|
983
|
+
if (delta.length > 0) {
|
|
984
|
+
controller.enqueue({
|
|
985
|
+
type: "tool-input-delta",
|
|
986
|
+
id: toolCallId,
|
|
987
|
+
delta
|
|
988
|
+
});
|
|
989
|
+
}
|
|
990
|
+
} else {
|
|
991
|
+
controller.enqueue({
|
|
992
|
+
type: "tool-input-start",
|
|
993
|
+
id: toolCallId,
|
|
994
|
+
toolName
|
|
995
|
+
});
|
|
996
|
+
if (argsJson.length > 0) {
|
|
997
|
+
controller.enqueue({
|
|
998
|
+
type: "tool-input-delta",
|
|
999
|
+
id: toolCallId,
|
|
1000
|
+
delta: argsJson
|
|
1001
|
+
});
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
controller.enqueue({ type: "tool-input-end", id: toolCallId });
|
|
1005
|
+
controller.enqueue({
|
|
1006
|
+
type: "tool-call",
|
|
1007
|
+
toolCallId,
|
|
1008
|
+
toolName,
|
|
1009
|
+
input: argsJson,
|
|
1010
|
+
providerExecuted: false
|
|
1011
|
+
});
|
|
1012
|
+
}
|
|
1013
|
+
trailingText = result.textAfterFence ?? "";
|
|
1014
|
+
toolCalls = selectedToolCalls;
|
|
1015
|
+
toolCallDetected = true;
|
|
1016
|
+
resetFenceState();
|
|
1017
|
+
break;
|
|
1018
|
+
}
|
|
1019
|
+
if (insideFence) {
|
|
1020
|
+
if (result.safeContent) {
|
|
1021
|
+
accumulatedFenceContent += result.safeContent;
|
|
1022
|
+
madeProgress = true;
|
|
1023
|
+
const toolName = extractToolName(accumulatedFenceContent);
|
|
1024
|
+
if (toolName && !toolInputStartEmitted && currentToolCallId) {
|
|
1025
|
+
controller.enqueue({
|
|
1026
|
+
type: "tool-input-start",
|
|
1027
|
+
id: currentToolCallId,
|
|
1028
|
+
toolName
|
|
1029
|
+
});
|
|
1030
|
+
toolInputStartEmitted = true;
|
|
1031
|
+
}
|
|
1032
|
+
if (toolInputStartEmitted && currentToolCallId) {
|
|
1033
|
+
const delta = extractArgumentsDelta(
|
|
1034
|
+
accumulatedFenceContent,
|
|
1035
|
+
argumentsStreamState
|
|
1036
|
+
);
|
|
1037
|
+
if (delta.length > 0) {
|
|
1038
|
+
controller.enqueue({
|
|
1039
|
+
type: "tool-input-delta",
|
|
1040
|
+
id: currentToolCallId,
|
|
1041
|
+
delta
|
|
1042
|
+
});
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
continue;
|
|
1047
|
+
}
|
|
1048
|
+
if (!insideFence && result.safeContent) {
|
|
1049
|
+
emitTextDelta(result.safeContent);
|
|
1050
|
+
madeProgress = true;
|
|
1051
|
+
}
|
|
1052
|
+
if (!madeProgress) {
|
|
1053
|
+
break;
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
if (toolCallDetected && options?.stopEarlyOnToolCall) {
|
|
1057
|
+
break;
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
if (!toolCallDetected && fenceDetector.hasContent()) {
|
|
1061
|
+
emitTextDelta(fenceDetector.getBuffer());
|
|
1062
|
+
fenceDetector.clearBuffer();
|
|
1063
|
+
}
|
|
1064
|
+
return { toolCallDetected, toolCalls, trailingText };
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
// src/utils/convert-to-webllm-messages.tsx
|
|
893
1068
|
function convertToolResultOutput(output) {
|
|
894
1069
|
switch (output.type) {
|
|
895
1070
|
case "text":
|
|
@@ -1028,7 +1203,7 @@ function convertToWebLLMMessages(prompt) {
|
|
|
1028
1203
|
return messages;
|
|
1029
1204
|
}
|
|
1030
1205
|
|
|
1031
|
-
// src/web-llm-language-model.ts
|
|
1206
|
+
// src/chat/web-llm-language-model.ts
|
|
1032
1207
|
var import_web_llm = require("@mlc-ai/web-llm");
|
|
1033
1208
|
|
|
1034
1209
|
// src/utils/prompt-utils.ts
|
|
@@ -1088,7 +1263,7 @@ function doesBrowserSupportWebLLM() {
|
|
|
1088
1263
|
return checkWebGPU();
|
|
1089
1264
|
}
|
|
1090
1265
|
|
|
1091
|
-
// src/web-llm-language-model.ts
|
|
1266
|
+
// src/chat/web-llm-language-model.ts
|
|
1092
1267
|
var WebLLMLanguageModel = class {
|
|
1093
1268
|
constructor(modelId, options = {}) {
|
|
1094
1269
|
this.specificationVersion = "v3";
|
|
@@ -1532,195 +1707,27 @@ var WebLLMLanguageModel = class {
|
|
|
1532
1707
|
...options.abortSignal && !useWorker && { signal: options.abortSignal }
|
|
1533
1708
|
};
|
|
1534
1709
|
const response = await engine.chat.completions.create(streamingRequest);
|
|
1535
|
-
|
|
1536
|
-
let
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
if (!choice) continue;
|
|
1545
|
-
if (choice.delta.content) {
|
|
1546
|
-
const delta = choice.delta.content;
|
|
1547
|
-
accumulatedText += delta;
|
|
1548
|
-
fenceDetector.addChunk(delta);
|
|
1549
|
-
while (fenceDetector.hasContent()) {
|
|
1550
|
-
const wasInsideFence = insideFence;
|
|
1551
|
-
const result = fenceDetector.detectStreamingFence();
|
|
1552
|
-
insideFence = result.inFence;
|
|
1553
|
-
let madeProgress = false;
|
|
1554
|
-
if (!wasInsideFence && result.inFence) {
|
|
1555
|
-
if (result.safeContent) {
|
|
1556
|
-
emitTextDelta(result.safeContent);
|
|
1557
|
-
madeProgress = true;
|
|
1558
|
-
}
|
|
1559
|
-
currentToolCallId = `call_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
|
|
1560
|
-
toolInputStartEmitted = false;
|
|
1561
|
-
accumulatedFenceContent = "";
|
|
1562
|
-
argumentsStreamState = createArgumentsStreamState();
|
|
1563
|
-
insideFence = true;
|
|
1564
|
-
continue;
|
|
1565
|
-
}
|
|
1566
|
-
if (result.completeFence) {
|
|
1567
|
-
madeProgress = true;
|
|
1568
|
-
if (result.safeContent) {
|
|
1569
|
-
accumulatedFenceContent += result.safeContent;
|
|
1570
|
-
}
|
|
1571
|
-
if (toolInputStartEmitted && currentToolCallId) {
|
|
1572
|
-
const delta2 = extractArgumentsDelta(
|
|
1573
|
-
accumulatedFenceContent,
|
|
1574
|
-
argumentsStreamState
|
|
1575
|
-
);
|
|
1576
|
-
if (delta2.length > 0) {
|
|
1577
|
-
controller.enqueue({
|
|
1578
|
-
type: "tool-input-delta",
|
|
1579
|
-
id: currentToolCallId,
|
|
1580
|
-
delta: delta2
|
|
1581
|
-
});
|
|
1582
|
-
}
|
|
1583
|
-
}
|
|
1584
|
-
const parsed = parseJsonFunctionCalls(result.completeFence);
|
|
1585
|
-
const parsedToolCalls = parsed.toolCalls;
|
|
1586
|
-
const selectedToolCalls = parsedToolCalls.slice(0, 1);
|
|
1587
|
-
if (selectedToolCalls.length === 0) {
|
|
1588
|
-
emitTextDelta(result.completeFence);
|
|
1589
|
-
if (result.textAfterFence) {
|
|
1590
|
-
emitTextDelta(result.textAfterFence);
|
|
1591
|
-
}
|
|
1592
|
-
currentToolCallId = null;
|
|
1593
|
-
toolInputStartEmitted = false;
|
|
1594
|
-
accumulatedFenceContent = "";
|
|
1595
|
-
argumentsStreamState = createArgumentsStreamState();
|
|
1596
|
-
insideFence = false;
|
|
1597
|
-
continue;
|
|
1598
|
-
}
|
|
1599
|
-
if (selectedToolCalls.length > 0 && currentToolCallId) {
|
|
1600
|
-
selectedToolCalls[0].toolCallId = currentToolCallId;
|
|
1601
|
-
}
|
|
1602
|
-
for (const [index, call] of selectedToolCalls.entries()) {
|
|
1603
|
-
const toolCallId = index === 0 && currentToolCallId ? currentToolCallId : call.toolCallId;
|
|
1604
|
-
const toolName = call.toolName;
|
|
1605
|
-
const argsJson = JSON.stringify(call.args ?? {});
|
|
1606
|
-
if (toolCallId === currentToolCallId) {
|
|
1607
|
-
if (!toolInputStartEmitted) {
|
|
1608
|
-
controller.enqueue({
|
|
1609
|
-
type: "tool-input-start",
|
|
1610
|
-
id: toolCallId,
|
|
1611
|
-
toolName
|
|
1612
|
-
});
|
|
1613
|
-
toolInputStartEmitted = true;
|
|
1614
|
-
}
|
|
1615
|
-
const delta2 = extractArgumentsDelta(
|
|
1616
|
-
accumulatedFenceContent,
|
|
1617
|
-
argumentsStreamState
|
|
1618
|
-
);
|
|
1619
|
-
if (delta2.length > 0) {
|
|
1620
|
-
controller.enqueue({
|
|
1621
|
-
type: "tool-input-delta",
|
|
1622
|
-
id: toolCallId,
|
|
1623
|
-
delta: delta2
|
|
1624
|
-
});
|
|
1625
|
-
}
|
|
1626
|
-
} else {
|
|
1627
|
-
controller.enqueue({
|
|
1628
|
-
type: "tool-input-start",
|
|
1629
|
-
id: toolCallId,
|
|
1630
|
-
toolName
|
|
1631
|
-
});
|
|
1632
|
-
if (argsJson.length > 0) {
|
|
1633
|
-
controller.enqueue({
|
|
1634
|
-
type: "tool-input-delta",
|
|
1635
|
-
id: toolCallId,
|
|
1636
|
-
delta: argsJson
|
|
1637
|
-
});
|
|
1638
|
-
}
|
|
1639
|
-
}
|
|
1640
|
-
controller.enqueue({
|
|
1641
|
-
type: "tool-input-end",
|
|
1642
|
-
id: toolCallId
|
|
1643
|
-
});
|
|
1644
|
-
controller.enqueue({
|
|
1645
|
-
type: "tool-call",
|
|
1646
|
-
toolCallId,
|
|
1647
|
-
toolName,
|
|
1648
|
-
input: argsJson,
|
|
1649
|
-
providerExecuted: false
|
|
1650
|
-
});
|
|
1651
|
-
}
|
|
1652
|
-
if (result.textAfterFence) {
|
|
1653
|
-
emitTextDelta(result.textAfterFence);
|
|
1654
|
-
}
|
|
1655
|
-
madeProgress = true;
|
|
1656
|
-
currentToolCallId = null;
|
|
1657
|
-
toolInputStartEmitted = false;
|
|
1658
|
-
accumulatedFenceContent = "";
|
|
1659
|
-
argumentsStreamState = createArgumentsStreamState();
|
|
1660
|
-
insideFence = false;
|
|
1661
|
-
continue;
|
|
1662
|
-
}
|
|
1663
|
-
if (insideFence) {
|
|
1664
|
-
if (result.safeContent) {
|
|
1665
|
-
accumulatedFenceContent += result.safeContent;
|
|
1666
|
-
madeProgress = true;
|
|
1667
|
-
const toolName = extractToolName(accumulatedFenceContent);
|
|
1668
|
-
if (toolName && !toolInputStartEmitted && currentToolCallId) {
|
|
1669
|
-
controller.enqueue({
|
|
1670
|
-
type: "tool-input-start",
|
|
1671
|
-
id: currentToolCallId,
|
|
1672
|
-
toolName
|
|
1673
|
-
});
|
|
1674
|
-
toolInputStartEmitted = true;
|
|
1675
|
-
}
|
|
1676
|
-
if (toolInputStartEmitted && currentToolCallId) {
|
|
1677
|
-
const delta2 = extractArgumentsDelta(
|
|
1678
|
-
accumulatedFenceContent,
|
|
1679
|
-
argumentsStreamState
|
|
1680
|
-
);
|
|
1681
|
-
if (delta2.length > 0) {
|
|
1682
|
-
controller.enqueue({
|
|
1683
|
-
type: "tool-input-delta",
|
|
1684
|
-
id: currentToolCallId,
|
|
1685
|
-
delta: delta2
|
|
1686
|
-
});
|
|
1687
|
-
}
|
|
1688
|
-
}
|
|
1689
|
-
}
|
|
1690
|
-
continue;
|
|
1691
|
-
}
|
|
1692
|
-
if (!insideFence && result.safeContent) {
|
|
1693
|
-
emitTextDelta(result.safeContent);
|
|
1694
|
-
madeProgress = true;
|
|
1695
|
-
}
|
|
1696
|
-
if (!madeProgress) {
|
|
1697
|
-
break;
|
|
1698
|
-
}
|
|
1699
|
-
}
|
|
1710
|
+
let lastUsage;
|
|
1711
|
+
let isAbort = false;
|
|
1712
|
+
const chunks = (async function* () {
|
|
1713
|
+
for await (const chunk of response) {
|
|
1714
|
+
const choice = chunk.choices[0];
|
|
1715
|
+
if (!choice) continue;
|
|
1716
|
+
if (choice.delta.content) yield choice.delta.content;
|
|
1717
|
+
if (chunk.usage) lastUsage = chunk.usage;
|
|
1718
|
+
if (choice.finish_reason === "abort") isAbort = true;
|
|
1700
1719
|
}
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
};
|
|
1710
|
-
if (choice.finish_reason === "abort") {
|
|
1711
|
-
finishReason = { unified: "other", raw: "abort" };
|
|
1712
|
-
} else {
|
|
1713
|
-
const { toolCalls } = parseJsonFunctionCalls(accumulatedText);
|
|
1714
|
-
if (toolCalls.length > 0) {
|
|
1715
|
-
finishReason = { unified: "tool-calls", raw: "tool-calls" };
|
|
1716
|
-
}
|
|
1717
|
-
}
|
|
1718
|
-
finishStream(finishReason, chunk.usage);
|
|
1719
|
-
}
|
|
1720
|
-
}
|
|
1721
|
-
if (!finished) {
|
|
1722
|
-
finishStream({ unified: "stop", raw: "stop" });
|
|
1720
|
+
})();
|
|
1721
|
+
const result = await processToolCallStream(
|
|
1722
|
+
chunks,
|
|
1723
|
+
emitTextDelta,
|
|
1724
|
+
controller
|
|
1725
|
+
);
|
|
1726
|
+
if (result.trailingText) {
|
|
1727
|
+
emitTextDelta(result.trailingText);
|
|
1723
1728
|
}
|
|
1729
|
+
const finishReason = isAbort ? { unified: "other", raw: "abort" } : result.toolCallDetected ? { unified: "tool-calls", raw: "tool-calls" } : { unified: "stop", raw: "stop" };
|
|
1730
|
+
finishStream(finishReason, lastUsage);
|
|
1724
1731
|
} catch (error) {
|
|
1725
1732
|
controller.error(error);
|
|
1726
1733
|
} finally {
|
|
@@ -1740,7 +1747,7 @@ var WebLLMLanguageModel = class {
|
|
|
1740
1747
|
}
|
|
1741
1748
|
};
|
|
1742
1749
|
|
|
1743
|
-
// src/web-llm-embedding-model.ts
|
|
1750
|
+
// src/embedding/web-llm-embedding-model.ts
|
|
1744
1751
|
var import_web_llm2 = require("@mlc-ai/web-llm");
|
|
1745
1752
|
var WebLLMEmbeddingModel = class {
|
|
1746
1753
|
constructor(modelId, options = {}) {
|