@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.mjs
CHANGED
|
@@ -858,7 +858,182 @@ function extractArgumentsDelta(content, state) {
|
|
|
858
858
|
return delta;
|
|
859
859
|
}
|
|
860
860
|
|
|
861
|
-
// src/
|
|
861
|
+
// ../shared/src/streaming/stream-processor.ts
|
|
862
|
+
function generateToolCallId2() {
|
|
863
|
+
return `call_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
|
|
864
|
+
}
|
|
865
|
+
async function processToolCallStream(chunks, emitTextDelta, controller, options) {
|
|
866
|
+
const fenceDetector = new ToolCallFenceDetector();
|
|
867
|
+
let currentToolCallId = null;
|
|
868
|
+
let toolInputStartEmitted = false;
|
|
869
|
+
let accumulatedFenceContent = "";
|
|
870
|
+
let argumentsStreamState = createArgumentsStreamState();
|
|
871
|
+
let insideFence = false;
|
|
872
|
+
let toolCallDetected = false;
|
|
873
|
+
let toolCalls = [];
|
|
874
|
+
let trailingText = "";
|
|
875
|
+
const resetFenceState = () => {
|
|
876
|
+
currentToolCallId = null;
|
|
877
|
+
toolInputStartEmitted = false;
|
|
878
|
+
accumulatedFenceContent = "";
|
|
879
|
+
argumentsStreamState = createArgumentsStreamState();
|
|
880
|
+
insideFence = false;
|
|
881
|
+
};
|
|
882
|
+
for await (const chunk of chunks) {
|
|
883
|
+
if (toolCallDetected) {
|
|
884
|
+
continue;
|
|
885
|
+
}
|
|
886
|
+
fenceDetector.addChunk(chunk);
|
|
887
|
+
while (fenceDetector.hasContent()) {
|
|
888
|
+
const wasInsideFence = insideFence;
|
|
889
|
+
const result = fenceDetector.detectStreamingFence();
|
|
890
|
+
insideFence = result.inFence;
|
|
891
|
+
let madeProgress = false;
|
|
892
|
+
if (!wasInsideFence && result.inFence) {
|
|
893
|
+
if (result.safeContent) {
|
|
894
|
+
emitTextDelta(result.safeContent);
|
|
895
|
+
madeProgress = true;
|
|
896
|
+
}
|
|
897
|
+
currentToolCallId = generateToolCallId2();
|
|
898
|
+
toolInputStartEmitted = false;
|
|
899
|
+
accumulatedFenceContent = "";
|
|
900
|
+
argumentsStreamState = createArgumentsStreamState();
|
|
901
|
+
insideFence = true;
|
|
902
|
+
continue;
|
|
903
|
+
}
|
|
904
|
+
if (result.completeFence) {
|
|
905
|
+
madeProgress = true;
|
|
906
|
+
if (result.safeContent) {
|
|
907
|
+
accumulatedFenceContent += result.safeContent;
|
|
908
|
+
}
|
|
909
|
+
if (toolInputStartEmitted && currentToolCallId) {
|
|
910
|
+
const delta = extractArgumentsDelta(
|
|
911
|
+
accumulatedFenceContent,
|
|
912
|
+
argumentsStreamState
|
|
913
|
+
);
|
|
914
|
+
if (delta.length > 0) {
|
|
915
|
+
controller.enqueue({
|
|
916
|
+
type: "tool-input-delta",
|
|
917
|
+
id: currentToolCallId,
|
|
918
|
+
delta
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
const parsed = parseJsonFunctionCalls(result.completeFence);
|
|
923
|
+
const selectedToolCalls = parsed.toolCalls.slice(0, 1);
|
|
924
|
+
if (selectedToolCalls.length === 0) {
|
|
925
|
+
emitTextDelta(result.completeFence);
|
|
926
|
+
if (result.textAfterFence) {
|
|
927
|
+
emitTextDelta(result.textAfterFence);
|
|
928
|
+
}
|
|
929
|
+
resetFenceState();
|
|
930
|
+
continue;
|
|
931
|
+
}
|
|
932
|
+
if (currentToolCallId) {
|
|
933
|
+
selectedToolCalls[0].toolCallId = currentToolCallId;
|
|
934
|
+
}
|
|
935
|
+
for (const [index, call] of selectedToolCalls.entries()) {
|
|
936
|
+
const toolCallId = index === 0 && currentToolCallId ? currentToolCallId : call.toolCallId;
|
|
937
|
+
const toolName = call.toolName;
|
|
938
|
+
const argsJson = JSON.stringify(call.args ?? {});
|
|
939
|
+
if (toolCallId === currentToolCallId) {
|
|
940
|
+
if (!toolInputStartEmitted) {
|
|
941
|
+
controller.enqueue({
|
|
942
|
+
type: "tool-input-start",
|
|
943
|
+
id: toolCallId,
|
|
944
|
+
toolName
|
|
945
|
+
});
|
|
946
|
+
toolInputStartEmitted = true;
|
|
947
|
+
}
|
|
948
|
+
const delta = extractArgumentsDelta(
|
|
949
|
+
accumulatedFenceContent,
|
|
950
|
+
argumentsStreamState
|
|
951
|
+
);
|
|
952
|
+
if (delta.length > 0) {
|
|
953
|
+
controller.enqueue({
|
|
954
|
+
type: "tool-input-delta",
|
|
955
|
+
id: toolCallId,
|
|
956
|
+
delta
|
|
957
|
+
});
|
|
958
|
+
}
|
|
959
|
+
} else {
|
|
960
|
+
controller.enqueue({
|
|
961
|
+
type: "tool-input-start",
|
|
962
|
+
id: toolCallId,
|
|
963
|
+
toolName
|
|
964
|
+
});
|
|
965
|
+
if (argsJson.length > 0) {
|
|
966
|
+
controller.enqueue({
|
|
967
|
+
type: "tool-input-delta",
|
|
968
|
+
id: toolCallId,
|
|
969
|
+
delta: argsJson
|
|
970
|
+
});
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
controller.enqueue({ type: "tool-input-end", id: toolCallId });
|
|
974
|
+
controller.enqueue({
|
|
975
|
+
type: "tool-call",
|
|
976
|
+
toolCallId,
|
|
977
|
+
toolName,
|
|
978
|
+
input: argsJson,
|
|
979
|
+
providerExecuted: false
|
|
980
|
+
});
|
|
981
|
+
}
|
|
982
|
+
trailingText = result.textAfterFence ?? "";
|
|
983
|
+
toolCalls = selectedToolCalls;
|
|
984
|
+
toolCallDetected = true;
|
|
985
|
+
resetFenceState();
|
|
986
|
+
break;
|
|
987
|
+
}
|
|
988
|
+
if (insideFence) {
|
|
989
|
+
if (result.safeContent) {
|
|
990
|
+
accumulatedFenceContent += result.safeContent;
|
|
991
|
+
madeProgress = true;
|
|
992
|
+
const toolName = extractToolName(accumulatedFenceContent);
|
|
993
|
+
if (toolName && !toolInputStartEmitted && currentToolCallId) {
|
|
994
|
+
controller.enqueue({
|
|
995
|
+
type: "tool-input-start",
|
|
996
|
+
id: currentToolCallId,
|
|
997
|
+
toolName
|
|
998
|
+
});
|
|
999
|
+
toolInputStartEmitted = true;
|
|
1000
|
+
}
|
|
1001
|
+
if (toolInputStartEmitted && currentToolCallId) {
|
|
1002
|
+
const delta = extractArgumentsDelta(
|
|
1003
|
+
accumulatedFenceContent,
|
|
1004
|
+
argumentsStreamState
|
|
1005
|
+
);
|
|
1006
|
+
if (delta.length > 0) {
|
|
1007
|
+
controller.enqueue({
|
|
1008
|
+
type: "tool-input-delta",
|
|
1009
|
+
id: currentToolCallId,
|
|
1010
|
+
delta
|
|
1011
|
+
});
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
continue;
|
|
1016
|
+
}
|
|
1017
|
+
if (!insideFence && result.safeContent) {
|
|
1018
|
+
emitTextDelta(result.safeContent);
|
|
1019
|
+
madeProgress = true;
|
|
1020
|
+
}
|
|
1021
|
+
if (!madeProgress) {
|
|
1022
|
+
break;
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
if (toolCallDetected && options?.stopEarlyOnToolCall) {
|
|
1026
|
+
break;
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
if (!toolCallDetected && fenceDetector.hasContent()) {
|
|
1030
|
+
emitTextDelta(fenceDetector.getBuffer());
|
|
1031
|
+
fenceDetector.clearBuffer();
|
|
1032
|
+
}
|
|
1033
|
+
return { toolCallDetected, toolCalls, trailingText };
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
// src/utils/convert-to-webllm-messages.tsx
|
|
862
1037
|
function convertToolResultOutput(output) {
|
|
863
1038
|
switch (output.type) {
|
|
864
1039
|
case "text":
|
|
@@ -997,7 +1172,7 @@ function convertToWebLLMMessages(prompt) {
|
|
|
997
1172
|
return messages;
|
|
998
1173
|
}
|
|
999
1174
|
|
|
1000
|
-
// src/web-llm-language-model.ts
|
|
1175
|
+
// src/chat/web-llm-language-model.ts
|
|
1001
1176
|
import {
|
|
1002
1177
|
CreateWebWorkerMLCEngine,
|
|
1003
1178
|
MLCEngine
|
|
@@ -1060,7 +1235,7 @@ function doesBrowserSupportWebLLM() {
|
|
|
1060
1235
|
return checkWebGPU();
|
|
1061
1236
|
}
|
|
1062
1237
|
|
|
1063
|
-
// src/web-llm-language-model.ts
|
|
1238
|
+
// src/chat/web-llm-language-model.ts
|
|
1064
1239
|
var WebLLMLanguageModel = class {
|
|
1065
1240
|
constructor(modelId, options = {}) {
|
|
1066
1241
|
this.specificationVersion = "v3";
|
|
@@ -1504,195 +1679,27 @@ var WebLLMLanguageModel = class {
|
|
|
1504
1679
|
...options.abortSignal && !useWorker && { signal: options.abortSignal }
|
|
1505
1680
|
};
|
|
1506
1681
|
const response = await engine.chat.completions.create(streamingRequest);
|
|
1507
|
-
|
|
1508
|
-
let
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
if (!choice) continue;
|
|
1517
|
-
if (choice.delta.content) {
|
|
1518
|
-
const delta = choice.delta.content;
|
|
1519
|
-
accumulatedText += delta;
|
|
1520
|
-
fenceDetector.addChunk(delta);
|
|
1521
|
-
while (fenceDetector.hasContent()) {
|
|
1522
|
-
const wasInsideFence = insideFence;
|
|
1523
|
-
const result = fenceDetector.detectStreamingFence();
|
|
1524
|
-
insideFence = result.inFence;
|
|
1525
|
-
let madeProgress = false;
|
|
1526
|
-
if (!wasInsideFence && result.inFence) {
|
|
1527
|
-
if (result.safeContent) {
|
|
1528
|
-
emitTextDelta(result.safeContent);
|
|
1529
|
-
madeProgress = true;
|
|
1530
|
-
}
|
|
1531
|
-
currentToolCallId = `call_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
|
|
1532
|
-
toolInputStartEmitted = false;
|
|
1533
|
-
accumulatedFenceContent = "";
|
|
1534
|
-
argumentsStreamState = createArgumentsStreamState();
|
|
1535
|
-
insideFence = true;
|
|
1536
|
-
continue;
|
|
1537
|
-
}
|
|
1538
|
-
if (result.completeFence) {
|
|
1539
|
-
madeProgress = true;
|
|
1540
|
-
if (result.safeContent) {
|
|
1541
|
-
accumulatedFenceContent += result.safeContent;
|
|
1542
|
-
}
|
|
1543
|
-
if (toolInputStartEmitted && currentToolCallId) {
|
|
1544
|
-
const delta2 = extractArgumentsDelta(
|
|
1545
|
-
accumulatedFenceContent,
|
|
1546
|
-
argumentsStreamState
|
|
1547
|
-
);
|
|
1548
|
-
if (delta2.length > 0) {
|
|
1549
|
-
controller.enqueue({
|
|
1550
|
-
type: "tool-input-delta",
|
|
1551
|
-
id: currentToolCallId,
|
|
1552
|
-
delta: delta2
|
|
1553
|
-
});
|
|
1554
|
-
}
|
|
1555
|
-
}
|
|
1556
|
-
const parsed = parseJsonFunctionCalls(result.completeFence);
|
|
1557
|
-
const parsedToolCalls = parsed.toolCalls;
|
|
1558
|
-
const selectedToolCalls = parsedToolCalls.slice(0, 1);
|
|
1559
|
-
if (selectedToolCalls.length === 0) {
|
|
1560
|
-
emitTextDelta(result.completeFence);
|
|
1561
|
-
if (result.textAfterFence) {
|
|
1562
|
-
emitTextDelta(result.textAfterFence);
|
|
1563
|
-
}
|
|
1564
|
-
currentToolCallId = null;
|
|
1565
|
-
toolInputStartEmitted = false;
|
|
1566
|
-
accumulatedFenceContent = "";
|
|
1567
|
-
argumentsStreamState = createArgumentsStreamState();
|
|
1568
|
-
insideFence = false;
|
|
1569
|
-
continue;
|
|
1570
|
-
}
|
|
1571
|
-
if (selectedToolCalls.length > 0 && currentToolCallId) {
|
|
1572
|
-
selectedToolCalls[0].toolCallId = currentToolCallId;
|
|
1573
|
-
}
|
|
1574
|
-
for (const [index, call] of selectedToolCalls.entries()) {
|
|
1575
|
-
const toolCallId = index === 0 && currentToolCallId ? currentToolCallId : call.toolCallId;
|
|
1576
|
-
const toolName = call.toolName;
|
|
1577
|
-
const argsJson = JSON.stringify(call.args ?? {});
|
|
1578
|
-
if (toolCallId === currentToolCallId) {
|
|
1579
|
-
if (!toolInputStartEmitted) {
|
|
1580
|
-
controller.enqueue({
|
|
1581
|
-
type: "tool-input-start",
|
|
1582
|
-
id: toolCallId,
|
|
1583
|
-
toolName
|
|
1584
|
-
});
|
|
1585
|
-
toolInputStartEmitted = true;
|
|
1586
|
-
}
|
|
1587
|
-
const delta2 = extractArgumentsDelta(
|
|
1588
|
-
accumulatedFenceContent,
|
|
1589
|
-
argumentsStreamState
|
|
1590
|
-
);
|
|
1591
|
-
if (delta2.length > 0) {
|
|
1592
|
-
controller.enqueue({
|
|
1593
|
-
type: "tool-input-delta",
|
|
1594
|
-
id: toolCallId,
|
|
1595
|
-
delta: delta2
|
|
1596
|
-
});
|
|
1597
|
-
}
|
|
1598
|
-
} else {
|
|
1599
|
-
controller.enqueue({
|
|
1600
|
-
type: "tool-input-start",
|
|
1601
|
-
id: toolCallId,
|
|
1602
|
-
toolName
|
|
1603
|
-
});
|
|
1604
|
-
if (argsJson.length > 0) {
|
|
1605
|
-
controller.enqueue({
|
|
1606
|
-
type: "tool-input-delta",
|
|
1607
|
-
id: toolCallId,
|
|
1608
|
-
delta: argsJson
|
|
1609
|
-
});
|
|
1610
|
-
}
|
|
1611
|
-
}
|
|
1612
|
-
controller.enqueue({
|
|
1613
|
-
type: "tool-input-end",
|
|
1614
|
-
id: toolCallId
|
|
1615
|
-
});
|
|
1616
|
-
controller.enqueue({
|
|
1617
|
-
type: "tool-call",
|
|
1618
|
-
toolCallId,
|
|
1619
|
-
toolName,
|
|
1620
|
-
input: argsJson,
|
|
1621
|
-
providerExecuted: false
|
|
1622
|
-
});
|
|
1623
|
-
}
|
|
1624
|
-
if (result.textAfterFence) {
|
|
1625
|
-
emitTextDelta(result.textAfterFence);
|
|
1626
|
-
}
|
|
1627
|
-
madeProgress = true;
|
|
1628
|
-
currentToolCallId = null;
|
|
1629
|
-
toolInputStartEmitted = false;
|
|
1630
|
-
accumulatedFenceContent = "";
|
|
1631
|
-
argumentsStreamState = createArgumentsStreamState();
|
|
1632
|
-
insideFence = false;
|
|
1633
|
-
continue;
|
|
1634
|
-
}
|
|
1635
|
-
if (insideFence) {
|
|
1636
|
-
if (result.safeContent) {
|
|
1637
|
-
accumulatedFenceContent += result.safeContent;
|
|
1638
|
-
madeProgress = true;
|
|
1639
|
-
const toolName = extractToolName(accumulatedFenceContent);
|
|
1640
|
-
if (toolName && !toolInputStartEmitted && currentToolCallId) {
|
|
1641
|
-
controller.enqueue({
|
|
1642
|
-
type: "tool-input-start",
|
|
1643
|
-
id: currentToolCallId,
|
|
1644
|
-
toolName
|
|
1645
|
-
});
|
|
1646
|
-
toolInputStartEmitted = true;
|
|
1647
|
-
}
|
|
1648
|
-
if (toolInputStartEmitted && currentToolCallId) {
|
|
1649
|
-
const delta2 = extractArgumentsDelta(
|
|
1650
|
-
accumulatedFenceContent,
|
|
1651
|
-
argumentsStreamState
|
|
1652
|
-
);
|
|
1653
|
-
if (delta2.length > 0) {
|
|
1654
|
-
controller.enqueue({
|
|
1655
|
-
type: "tool-input-delta",
|
|
1656
|
-
id: currentToolCallId,
|
|
1657
|
-
delta: delta2
|
|
1658
|
-
});
|
|
1659
|
-
}
|
|
1660
|
-
}
|
|
1661
|
-
}
|
|
1662
|
-
continue;
|
|
1663
|
-
}
|
|
1664
|
-
if (!insideFence && result.safeContent) {
|
|
1665
|
-
emitTextDelta(result.safeContent);
|
|
1666
|
-
madeProgress = true;
|
|
1667
|
-
}
|
|
1668
|
-
if (!madeProgress) {
|
|
1669
|
-
break;
|
|
1670
|
-
}
|
|
1671
|
-
}
|
|
1682
|
+
let lastUsage;
|
|
1683
|
+
let isAbort = false;
|
|
1684
|
+
const chunks = (async function* () {
|
|
1685
|
+
for await (const chunk of response) {
|
|
1686
|
+
const choice = chunk.choices[0];
|
|
1687
|
+
if (!choice) continue;
|
|
1688
|
+
if (choice.delta.content) yield choice.delta.content;
|
|
1689
|
+
if (chunk.usage) lastUsage = chunk.usage;
|
|
1690
|
+
if (choice.finish_reason === "abort") isAbort = true;
|
|
1672
1691
|
}
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
};
|
|
1682
|
-
if (choice.finish_reason === "abort") {
|
|
1683
|
-
finishReason = { unified: "other", raw: "abort" };
|
|
1684
|
-
} else {
|
|
1685
|
-
const { toolCalls } = parseJsonFunctionCalls(accumulatedText);
|
|
1686
|
-
if (toolCalls.length > 0) {
|
|
1687
|
-
finishReason = { unified: "tool-calls", raw: "tool-calls" };
|
|
1688
|
-
}
|
|
1689
|
-
}
|
|
1690
|
-
finishStream(finishReason, chunk.usage);
|
|
1691
|
-
}
|
|
1692
|
-
}
|
|
1693
|
-
if (!finished) {
|
|
1694
|
-
finishStream({ unified: "stop", raw: "stop" });
|
|
1692
|
+
})();
|
|
1693
|
+
const result = await processToolCallStream(
|
|
1694
|
+
chunks,
|
|
1695
|
+
emitTextDelta,
|
|
1696
|
+
controller
|
|
1697
|
+
);
|
|
1698
|
+
if (result.trailingText) {
|
|
1699
|
+
emitTextDelta(result.trailingText);
|
|
1695
1700
|
}
|
|
1701
|
+
const finishReason = isAbort ? { unified: "other", raw: "abort" } : result.toolCallDetected ? { unified: "tool-calls", raw: "tool-calls" } : { unified: "stop", raw: "stop" };
|
|
1702
|
+
finishStream(finishReason, lastUsage);
|
|
1696
1703
|
} catch (error) {
|
|
1697
1704
|
controller.error(error);
|
|
1698
1705
|
} finally {
|
|
@@ -1712,7 +1719,7 @@ var WebLLMLanguageModel = class {
|
|
|
1712
1719
|
}
|
|
1713
1720
|
};
|
|
1714
1721
|
|
|
1715
|
-
// src/web-llm-embedding-model.ts
|
|
1722
|
+
// src/embedding/web-llm-embedding-model.ts
|
|
1716
1723
|
import {
|
|
1717
1724
|
CreateWebWorkerMLCEngine as CreateWebWorkerMLCEngine2,
|
|
1718
1725
|
MLCEngine as MLCEngine2
|