@hef2024/llmasaservice-ui 0.24.2 → 0.24.4
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.css +256 -62
- package/dist/index.d.mts +158 -115
- package/dist/index.d.ts +158 -115
- package/dist/index.js +3099 -568
- package/dist/index.mjs +3099 -568
- package/index.ts +6 -1
- package/package.json +1 -1
- package/src/AIAgentPanel.tsx +647 -207
- package/src/AIChatPanel.css +286 -37
- package/src/AIChatPanel.tsx +2871 -358
- package/src/AgentPanel.tsx +4 -0
- package/src/ChatPanel.tsx +254 -104
- package/src/hooks/useAgentRegistry.ts +2 -1
- package/src/mcpAuth.ts +36 -0
- package/src/toolArgsParser.ts +346 -0
package/dist/index.mjs
CHANGED
|
@@ -652,6 +652,302 @@ var ThinkingBlock = ({
|
|
|
652
652
|
);
|
|
653
653
|
};
|
|
654
654
|
|
|
655
|
+
// src/mcpAuth.ts
|
|
656
|
+
function normalizeMcpHeaders(value) {
|
|
657
|
+
const normalized = {};
|
|
658
|
+
if (!value) return normalized;
|
|
659
|
+
for (const [key, raw] of Object.entries(value)) {
|
|
660
|
+
if (typeof raw !== "string") continue;
|
|
661
|
+
const trimmedValue = raw.trim();
|
|
662
|
+
if (!trimmedValue) continue;
|
|
663
|
+
normalized[key] = trimmedValue;
|
|
664
|
+
}
|
|
665
|
+
return normalized;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// src/toolArgsParser.ts
|
|
669
|
+
var TOOL_ARGS_CANDIDATE_PARSE_DEPTH = 3;
|
|
670
|
+
var isPlainObject = (value) => {
|
|
671
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
672
|
+
};
|
|
673
|
+
var stripMarkdownCodeFence = (input) => {
|
|
674
|
+
const trimmed = input.trim();
|
|
675
|
+
if (!trimmed.startsWith("```")) return trimmed;
|
|
676
|
+
const withoutStart = trimmed.replace(/^```[a-zA-Z0-9_-]*\s*/u, "");
|
|
677
|
+
return withoutStart.replace(/```$/u, "").trim();
|
|
678
|
+
};
|
|
679
|
+
var stripOuterQuotes = (input) => {
|
|
680
|
+
const trimmed = input.trim();
|
|
681
|
+
if (trimmed.length < 2) return trimmed;
|
|
682
|
+
const first = trimmed[0];
|
|
683
|
+
const last = trimmed[trimmed.length - 1];
|
|
684
|
+
if (first === '"' && last === '"' || first === "'" && last === "'") {
|
|
685
|
+
return trimmed.slice(1, -1).trim();
|
|
686
|
+
}
|
|
687
|
+
return trimmed;
|
|
688
|
+
};
|
|
689
|
+
var normalizeSmartQuotes = (input) => {
|
|
690
|
+
return input.replace(/[“”]/gu, '"').replace(/[‘’]/gu, "'");
|
|
691
|
+
};
|
|
692
|
+
var convertSingleQuotedStrings = (input) => {
|
|
693
|
+
let output = "";
|
|
694
|
+
let inSingle = false;
|
|
695
|
+
let inDouble = false;
|
|
696
|
+
let escaped = false;
|
|
697
|
+
for (let index = 0; index < input.length; index += 1) {
|
|
698
|
+
const char = input[index];
|
|
699
|
+
if (inSingle) {
|
|
700
|
+
if (escaped) {
|
|
701
|
+
output += char === '"' ? '\\"' : char;
|
|
702
|
+
escaped = false;
|
|
703
|
+
continue;
|
|
704
|
+
}
|
|
705
|
+
if (char === "\\") {
|
|
706
|
+
output += "\\";
|
|
707
|
+
escaped = true;
|
|
708
|
+
continue;
|
|
709
|
+
}
|
|
710
|
+
if (char === "'") {
|
|
711
|
+
output += '"';
|
|
712
|
+
inSingle = false;
|
|
713
|
+
continue;
|
|
714
|
+
}
|
|
715
|
+
output += char === '"' ? '\\"' : char;
|
|
716
|
+
continue;
|
|
717
|
+
}
|
|
718
|
+
if (inDouble) {
|
|
719
|
+
output += char;
|
|
720
|
+
if (escaped) {
|
|
721
|
+
escaped = false;
|
|
722
|
+
continue;
|
|
723
|
+
}
|
|
724
|
+
if (char === "\\") {
|
|
725
|
+
escaped = true;
|
|
726
|
+
continue;
|
|
727
|
+
}
|
|
728
|
+
if (char === '"') {
|
|
729
|
+
inDouble = false;
|
|
730
|
+
}
|
|
731
|
+
continue;
|
|
732
|
+
}
|
|
733
|
+
if (char === "'") {
|
|
734
|
+
output += '"';
|
|
735
|
+
inSingle = true;
|
|
736
|
+
continue;
|
|
737
|
+
}
|
|
738
|
+
if (char === '"') {
|
|
739
|
+
output += '"';
|
|
740
|
+
inDouble = true;
|
|
741
|
+
continue;
|
|
742
|
+
}
|
|
743
|
+
output += char;
|
|
744
|
+
}
|
|
745
|
+
return output;
|
|
746
|
+
};
|
|
747
|
+
var quoteBareObjectKeys = (input) => {
|
|
748
|
+
return input.replace(
|
|
749
|
+
/([{,]\s*)([A-Za-z_$][A-Za-z0-9_$-]*)(\s*:)/gu,
|
|
750
|
+
'$1"$2"$3'
|
|
751
|
+
);
|
|
752
|
+
};
|
|
753
|
+
var stripTrailingCommas = (input) => {
|
|
754
|
+
return input.replace(/,\s*([}\]])/gu, "$1");
|
|
755
|
+
};
|
|
756
|
+
var normalizeEscapesOutsideStrings = (input) => {
|
|
757
|
+
let output = "";
|
|
758
|
+
let inDouble = false;
|
|
759
|
+
let inSingle = false;
|
|
760
|
+
let escaped = false;
|
|
761
|
+
for (let index = 0; index < input.length; index += 1) {
|
|
762
|
+
const char = input[index];
|
|
763
|
+
const next = index + 1 < input.length ? input[index + 1] : "";
|
|
764
|
+
if (inDouble || inSingle) {
|
|
765
|
+
output += char;
|
|
766
|
+
if (escaped) {
|
|
767
|
+
escaped = false;
|
|
768
|
+
continue;
|
|
769
|
+
}
|
|
770
|
+
if (char === "\\") {
|
|
771
|
+
escaped = true;
|
|
772
|
+
continue;
|
|
773
|
+
}
|
|
774
|
+
if (inDouble && char === '"') {
|
|
775
|
+
inDouble = false;
|
|
776
|
+
} else if (inSingle && char === "'") {
|
|
777
|
+
inSingle = false;
|
|
778
|
+
}
|
|
779
|
+
continue;
|
|
780
|
+
}
|
|
781
|
+
if (char === '"') {
|
|
782
|
+
inDouble = true;
|
|
783
|
+
output += char;
|
|
784
|
+
continue;
|
|
785
|
+
}
|
|
786
|
+
if (char === "'") {
|
|
787
|
+
inSingle = true;
|
|
788
|
+
output += char;
|
|
789
|
+
continue;
|
|
790
|
+
}
|
|
791
|
+
if (char === "\\") {
|
|
792
|
+
if (next === "n") {
|
|
793
|
+
output += "\n";
|
|
794
|
+
index += 1;
|
|
795
|
+
continue;
|
|
796
|
+
}
|
|
797
|
+
if (next === "r") {
|
|
798
|
+
output += "\r";
|
|
799
|
+
index += 1;
|
|
800
|
+
continue;
|
|
801
|
+
}
|
|
802
|
+
if (next === "t") {
|
|
803
|
+
output += " ";
|
|
804
|
+
index += 1;
|
|
805
|
+
continue;
|
|
806
|
+
}
|
|
807
|
+
if (next === '"') {
|
|
808
|
+
output += '"';
|
|
809
|
+
index += 1;
|
|
810
|
+
continue;
|
|
811
|
+
}
|
|
812
|
+
if (next === "'") {
|
|
813
|
+
output += "'";
|
|
814
|
+
index += 1;
|
|
815
|
+
continue;
|
|
816
|
+
}
|
|
817
|
+
if (next === "\\") {
|
|
818
|
+
output += "\\";
|
|
819
|
+
index += 1;
|
|
820
|
+
continue;
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
output += char;
|
|
824
|
+
}
|
|
825
|
+
return output;
|
|
826
|
+
};
|
|
827
|
+
var normalizeJsLikeJson = (input) => {
|
|
828
|
+
const normalizedQuotes = normalizeSmartQuotes(input);
|
|
829
|
+
const normalizedSingleQuotes = convertSingleQuotedStrings(normalizedQuotes);
|
|
830
|
+
const withQuotedKeys = quoteBareObjectKeys(normalizedSingleQuotes);
|
|
831
|
+
return stripTrailingCommas(withQuotedKeys);
|
|
832
|
+
};
|
|
833
|
+
var extractFirstJsonObject = (input) => {
|
|
834
|
+
const start = input.indexOf("{");
|
|
835
|
+
if (start === -1) return null;
|
|
836
|
+
let depth = 0;
|
|
837
|
+
let inString = false;
|
|
838
|
+
let quoteChar = "";
|
|
839
|
+
let escaped = false;
|
|
840
|
+
for (let index = start; index < input.length; index += 1) {
|
|
841
|
+
const char = input[index];
|
|
842
|
+
if (inString) {
|
|
843
|
+
if (escaped) {
|
|
844
|
+
escaped = false;
|
|
845
|
+
continue;
|
|
846
|
+
}
|
|
847
|
+
if (char === "\\") {
|
|
848
|
+
escaped = true;
|
|
849
|
+
continue;
|
|
850
|
+
}
|
|
851
|
+
if (char === quoteChar) {
|
|
852
|
+
inString = false;
|
|
853
|
+
quoteChar = "";
|
|
854
|
+
}
|
|
855
|
+
continue;
|
|
856
|
+
}
|
|
857
|
+
if (char === '"' || char === "'") {
|
|
858
|
+
inString = true;
|
|
859
|
+
quoteChar = char;
|
|
860
|
+
continue;
|
|
861
|
+
}
|
|
862
|
+
if (char === "{") {
|
|
863
|
+
depth += 1;
|
|
864
|
+
continue;
|
|
865
|
+
}
|
|
866
|
+
if (char === "}") {
|
|
867
|
+
depth -= 1;
|
|
868
|
+
if (depth === 0) {
|
|
869
|
+
return input.slice(start, index + 1);
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
return null;
|
|
874
|
+
};
|
|
875
|
+
var parseMaybeNestedJson = (input) => {
|
|
876
|
+
let current = input;
|
|
877
|
+
for (let depth = 0; depth < TOOL_ARGS_CANDIDATE_PARSE_DEPTH; depth += 1) {
|
|
878
|
+
if (typeof current !== "string") {
|
|
879
|
+
return current;
|
|
880
|
+
}
|
|
881
|
+
const trimmed = current.trim();
|
|
882
|
+
if (!trimmed) {
|
|
883
|
+
return {};
|
|
884
|
+
}
|
|
885
|
+
current = JSON.parse(trimmed);
|
|
886
|
+
}
|
|
887
|
+
return current;
|
|
888
|
+
};
|
|
889
|
+
var addCandidate = (candidates, value) => {
|
|
890
|
+
if (typeof value !== "string") return;
|
|
891
|
+
const trimmed = value.trim();
|
|
892
|
+
if (!trimmed) return;
|
|
893
|
+
candidates.add(trimmed);
|
|
894
|
+
};
|
|
895
|
+
var buildProgressiveQuoteUnescapes = (input, rounds = 4) => {
|
|
896
|
+
const values = [];
|
|
897
|
+
let current = input;
|
|
898
|
+
for (let round = 0; round < rounds; round += 1) {
|
|
899
|
+
const next = current.replace(/\\"/gu, '"');
|
|
900
|
+
if (next === current) {
|
|
901
|
+
break;
|
|
902
|
+
}
|
|
903
|
+
values.push(next);
|
|
904
|
+
current = next;
|
|
905
|
+
}
|
|
906
|
+
return values;
|
|
907
|
+
};
|
|
908
|
+
var parseToolArguments = (rawArgs) => {
|
|
909
|
+
if (isPlainObject(rawArgs)) {
|
|
910
|
+
return rawArgs;
|
|
911
|
+
}
|
|
912
|
+
if (typeof rawArgs !== "string") {
|
|
913
|
+
return {};
|
|
914
|
+
}
|
|
915
|
+
const base = rawArgs.trim();
|
|
916
|
+
if (!base) {
|
|
917
|
+
return {};
|
|
918
|
+
}
|
|
919
|
+
const codeFenceStripped = stripMarkdownCodeFence(base);
|
|
920
|
+
const extracted = extractFirstJsonObject(codeFenceStripped);
|
|
921
|
+
const candidates = /* @__PURE__ */ new Set();
|
|
922
|
+
addCandidate(candidates, base);
|
|
923
|
+
addCandidate(candidates, codeFenceStripped);
|
|
924
|
+
addCandidate(candidates, stripOuterQuotes(codeFenceStripped));
|
|
925
|
+
buildProgressiveQuoteUnescapes(base).forEach((candidate) => addCandidate(candidates, candidate));
|
|
926
|
+
buildProgressiveQuoteUnescapes(codeFenceStripped).forEach(
|
|
927
|
+
(candidate) => addCandidate(candidates, candidate)
|
|
928
|
+
);
|
|
929
|
+
addCandidate(candidates, extracted);
|
|
930
|
+
buildProgressiveQuoteUnescapes(extracted || "").forEach(
|
|
931
|
+
(candidate) => addCandidate(candidates, candidate)
|
|
932
|
+
);
|
|
933
|
+
addCandidate(candidates, normalizeJsLikeJson(codeFenceStripped));
|
|
934
|
+
addCandidate(candidates, extracted ? normalizeJsLikeJson(extracted) : null);
|
|
935
|
+
Array.from(candidates).forEach((candidate) => {
|
|
936
|
+
addCandidate(candidates, normalizeEscapesOutsideStrings(candidate));
|
|
937
|
+
});
|
|
938
|
+
for (const candidate of candidates) {
|
|
939
|
+
try {
|
|
940
|
+
const parsed = parseMaybeNestedJson(candidate);
|
|
941
|
+
if (isPlainObject(parsed)) {
|
|
942
|
+
return parsed;
|
|
943
|
+
}
|
|
944
|
+
} catch (e) {
|
|
945
|
+
continue;
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
return null;
|
|
949
|
+
};
|
|
950
|
+
|
|
655
951
|
// src/ChatPanel.tsx
|
|
656
952
|
var ChatPanel = ({
|
|
657
953
|
project_id,
|
|
@@ -697,7 +993,8 @@ var ChatPanel = ({
|
|
|
697
993
|
customerEmailCaptureMode = "HIDE",
|
|
698
994
|
customerEmailCapturePlaceholder = "Please enter your email...",
|
|
699
995
|
mcpServers,
|
|
700
|
-
progressiveActions = true
|
|
996
|
+
progressiveActions = true,
|
|
997
|
+
resolveMcpAuthHeaders
|
|
701
998
|
}) => {
|
|
702
999
|
var _a;
|
|
703
1000
|
const isEmailAddress = (email) => {
|
|
@@ -1023,6 +1320,44 @@ var ChatPanel = ({
|
|
|
1023
1320
|
const [toolList, setToolList] = useState5([]);
|
|
1024
1321
|
const [toolsLoading, setToolsLoading] = useState5(false);
|
|
1025
1322
|
const [toolsFetchError, setToolsFetchError] = useState5(false);
|
|
1323
|
+
const buildMcpRequestHeaders = useCallback(
|
|
1324
|
+
(_0) => __async(void 0, [_0], function* ({
|
|
1325
|
+
phase,
|
|
1326
|
+
mcpServer,
|
|
1327
|
+
toolName,
|
|
1328
|
+
toolArgs
|
|
1329
|
+
}) {
|
|
1330
|
+
const merged = {};
|
|
1331
|
+
const baseAccessToken = typeof mcpServer.accessToken === "string" ? mcpServer.accessToken.trim() : "";
|
|
1332
|
+
if (baseAccessToken) {
|
|
1333
|
+
merged["x-mcp-access-token"] = baseAccessToken;
|
|
1334
|
+
}
|
|
1335
|
+
if (project_id) {
|
|
1336
|
+
merged["x-project-id"] = project_id;
|
|
1337
|
+
}
|
|
1338
|
+
if (!resolveMcpAuthHeaders) return merged;
|
|
1339
|
+
try {
|
|
1340
|
+
const resolved = yield resolveMcpAuthHeaders({
|
|
1341
|
+
phase,
|
|
1342
|
+
mcpServer,
|
|
1343
|
+
projectId: project_id,
|
|
1344
|
+
customer: currentCustomer,
|
|
1345
|
+
toolName,
|
|
1346
|
+
toolArgs
|
|
1347
|
+
});
|
|
1348
|
+
return __spreadValues(__spreadValues({}, merged), normalizeMcpHeaders(
|
|
1349
|
+
resolved
|
|
1350
|
+
));
|
|
1351
|
+
} catch (error2) {
|
|
1352
|
+
console.error(
|
|
1353
|
+
`Failed to resolve MCP auth headers for ${phase} request:`,
|
|
1354
|
+
error2
|
|
1355
|
+
);
|
|
1356
|
+
return merged;
|
|
1357
|
+
}
|
|
1358
|
+
}),
|
|
1359
|
+
[project_id, currentCustomer, resolveMcpAuthHeaders]
|
|
1360
|
+
);
|
|
1026
1361
|
useEffect6(() => {
|
|
1027
1362
|
const fetchAndSetTools = () => __async(void 0, null, function* () {
|
|
1028
1363
|
if (!mcpServers || mcpServers.length === 0) {
|
|
@@ -1039,7 +1374,13 @@ var ChatPanel = ({
|
|
|
1039
1374
|
m.url
|
|
1040
1375
|
)}`;
|
|
1041
1376
|
try {
|
|
1042
|
-
const
|
|
1377
|
+
const requestHeaders = yield buildMcpRequestHeaders({
|
|
1378
|
+
phase: "list",
|
|
1379
|
+
mcpServer: m
|
|
1380
|
+
});
|
|
1381
|
+
const response2 = yield fetch(urlToFetch, {
|
|
1382
|
+
headers: requestHeaders
|
|
1383
|
+
});
|
|
1043
1384
|
if (!response2.ok) {
|
|
1044
1385
|
console.error(
|
|
1045
1386
|
`Error fetching tools from ${m.url}: ${response2.status} ${response2.statusText}`
|
|
@@ -1055,7 +1396,7 @@ var ChatPanel = ({
|
|
|
1055
1396
|
return toolsFromServer.map((tool) => __spreadProps(__spreadValues({}, tool), {
|
|
1056
1397
|
url: m.url,
|
|
1057
1398
|
accessToken: m.accessToken || "",
|
|
1058
|
-
headers:
|
|
1399
|
+
headers: requestHeaders
|
|
1059
1400
|
}));
|
|
1060
1401
|
} else {
|
|
1061
1402
|
return [];
|
|
@@ -1084,7 +1425,7 @@ var ChatPanel = ({
|
|
|
1084
1425
|
}
|
|
1085
1426
|
});
|
|
1086
1427
|
fetchAndSetTools();
|
|
1087
|
-
}, [mcpServers, publicAPIUrl]);
|
|
1428
|
+
}, [mcpServers, publicAPIUrl, buildMcpRequestHeaders]);
|
|
1088
1429
|
const llmResult = useLLM({
|
|
1089
1430
|
project_id,
|
|
1090
1431
|
customer: currentCustomer,
|
|
@@ -1449,19 +1790,19 @@ var ChatPanel = ({
|
|
|
1449
1790
|
[]
|
|
1450
1791
|
);
|
|
1451
1792
|
const anthropic_toolAction = {
|
|
1452
|
-
pattern: '\\{"type":"tool_use","id":"([^"]+)","name":"([^"]+)","input":(\\{[\\s\\S]
|
|
1793
|
+
pattern: '\\{"type":"tool_use","id":"([^"]+)","name":"([^"]+)","input":(\\{[\\s\\S]*?\\}),"service":"([^"]+)"\\}',
|
|
1453
1794
|
type: "markdown",
|
|
1454
1795
|
markdown: "<br />*Tool use requested: $2*",
|
|
1455
1796
|
actionType: "tool"
|
|
1456
1797
|
};
|
|
1457
1798
|
const openAI_toolAction = {
|
|
1458
|
-
pattern: '\\{"id":"([^"]+)","type":"function","function":\\{"name":"([^"]+)","arguments":"(
|
|
1799
|
+
pattern: '\\{"id":"([^"]+)","type":"function","function":\\{"name":"([^"]+)","arguments":"([\\s\\S]*?)"\\},"service":"([^"]+)"\\}',
|
|
1459
1800
|
type: "markdown",
|
|
1460
1801
|
markdown: "<br />*Tool use requested: $2*",
|
|
1461
1802
|
actionType: "tool"
|
|
1462
1803
|
};
|
|
1463
1804
|
const google_toolAction = {
|
|
1464
|
-
pattern: '^\\{\\s*"(functionCall)"\\s*:\\s*\\{\\s*"name"\\s*:\\s*"([^"]+)"\\s*,\\s*"args"\\s*:\\s*(\\{[\\s\\S]
|
|
1805
|
+
pattern: '^\\{\\s*"(functionCall)"\\s*:\\s*\\{\\s*"name"\\s*:\\s*"([^"]+)"\\s*,\\s*"args"\\s*:\\s*(\\{[\\s\\S]*?\\})\\s*\\}(?:\\s*,\\s*"thoughtSignature"\\s*:\\s*"[^"]*")?\\s*,\\s*"service"\\s*:\\s*"([^"]+)"\\s*\\}$',
|
|
1465
1806
|
type: "markdown",
|
|
1466
1807
|
markdown: "<br />*Tool use requested: $2*",
|
|
1467
1808
|
actionType: "tool"
|
|
@@ -1603,114 +1944,125 @@ var ChatPanel = ({
|
|
|
1603
1944
|
]
|
|
1604
1945
|
}
|
|
1605
1946
|
];
|
|
1606
|
-
const
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1947
|
+
const parsedToolCalls = yield Promise.all(
|
|
1948
|
+
toolsToProcess.map((req, index) => __async(void 0, null, function* () {
|
|
1949
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
1950
|
+
if (!req) return null;
|
|
1951
|
+
let parsedToolCall = null;
|
|
1952
|
+
try {
|
|
1953
|
+
parsedToolCall = JSON.parse(req.match);
|
|
1954
|
+
} catch (error2) {
|
|
1955
|
+
console.error("Failed to parse tool call:", error2);
|
|
1956
|
+
}
|
|
1957
|
+
const toolName = req.groups[1] || req.toolName || (typeof (parsedToolCall == null ? void 0 : parsedToolCall.name) === "string" ? parsedToolCall.name : "") || (typeof ((_a2 = parsedToolCall == null ? void 0 : parsedToolCall.function) == null ? void 0 : _a2.name) === "string" ? parsedToolCall.function.name : "");
|
|
1958
|
+
if (!toolName) return null;
|
|
1959
|
+
const rawCallId = req.groups[0] || (parsedToolCall == null ? void 0 : parsedToolCall.id) || (parsedToolCall == null ? void 0 : parsedToolCall.tool_call_id) || `${toolName}-${index + 1}`;
|
|
1960
|
+
const callId = typeof rawCallId === "string" && rawCallId.trim().length > 0 && rawCallId !== "functionCall" ? rawCallId : `${toolName}-${index + 1}`;
|
|
1961
|
+
let args = {};
|
|
1962
|
+
const rawArgs = (_f = (_e = (_c = (_b = req.groups[2]) != null ? _b : parsedToolCall == null ? void 0 : parsedToolCall.input) != null ? _c : parsedToolCall == null ? void 0 : parsedToolCall.args) != null ? _e : (_d = parsedToolCall == null ? void 0 : parsedToolCall.function) == null ? void 0 : _d.arguments) != null ? _f : "{}";
|
|
1963
|
+
const parsedArgs = parseToolArguments(rawArgs);
|
|
1964
|
+
if (!parsedArgs) {
|
|
1965
|
+
console.error("Failed to parse tool arguments", {
|
|
1966
|
+
toolName,
|
|
1967
|
+
callId,
|
|
1968
|
+
rawArgsPreview: typeof rawArgs === "string" ? rawArgs.slice(0, 500) : JSON.stringify(rawArgs).slice(0, 500)
|
|
1969
|
+
});
|
|
1970
|
+
return null;
|
|
1971
|
+
}
|
|
1972
|
+
args = parsedArgs;
|
|
1973
|
+
const serviceTag = typeof req.groups[3] === "string" && req.groups[3] || typeof (parsedToolCall == null ? void 0 : parsedToolCall.service) === "string" && parsedToolCall.service || "";
|
|
1614
1974
|
return {
|
|
1615
1975
|
req,
|
|
1616
|
-
|
|
1976
|
+
toolName,
|
|
1977
|
+
callId,
|
|
1978
|
+
args,
|
|
1979
|
+
serviceTag
|
|
1617
1980
|
};
|
|
1618
|
-
}
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1981
|
+
}))
|
|
1982
|
+
);
|
|
1983
|
+
const toolCallBatch = parsedToolCalls.filter(Boolean);
|
|
1984
|
+
const finalToolCalls = toolCallBatch.map((toolCall) => ({
|
|
1985
|
+
id: toolCall.callId,
|
|
1986
|
+
type: "tool_use",
|
|
1987
|
+
name: toolCall.toolName,
|
|
1988
|
+
input: toolCall.args,
|
|
1989
|
+
service: toolCall.serviceTag
|
|
1622
1990
|
}));
|
|
1623
|
-
const
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
toolCallsMessage.tool_calls.push(item.parsedToolCall);
|
|
1627
|
-
}
|
|
1628
|
-
});
|
|
1629
|
-
newMessages.push(toolCallsMessage);
|
|
1630
|
-
const finalToolCalls = toolCallsMessage.tool_calls;
|
|
1631
|
-
const toolResponsePromises = parsedToolCalls.map((item) => __async(void 0, null, function* () {
|
|
1632
|
-
var _a2;
|
|
1633
|
-
if (!item || !item.req) return null;
|
|
1634
|
-
const req = item.req;
|
|
1635
|
-
const mcpTool = toolList.find((tool) => tool.name === req.toolName);
|
|
1991
|
+
const toolResponsePromises = toolCallBatch.map((toolCall) => __async(void 0, null, function* () {
|
|
1992
|
+
var _a2, _b, _c;
|
|
1993
|
+
const mcpTool = toolList.find((tool) => tool.name === toolCall.toolName);
|
|
1636
1994
|
if (!mcpTool) {
|
|
1637
|
-
console.error(`Tool ${
|
|
1638
|
-
return
|
|
1995
|
+
console.error(`Tool ${toolCall.toolName} not found in tool list`);
|
|
1996
|
+
return {
|
|
1997
|
+
tool_call_id: toolCall.callId,
|
|
1998
|
+
tool_name: toolCall.toolName,
|
|
1999
|
+
result: `Tool ${toolCall.toolName} not found in current tool list.`,
|
|
2000
|
+
isError: true
|
|
2001
|
+
};
|
|
1639
2002
|
}
|
|
1640
2003
|
try {
|
|
1641
|
-
let args;
|
|
1642
|
-
try {
|
|
1643
|
-
args = JSON.parse(req.groups[2]);
|
|
1644
|
-
} catch (e) {
|
|
1645
|
-
try {
|
|
1646
|
-
args = JSON.parse(req.groups[2].replace(/\\"/g, '"'));
|
|
1647
|
-
} catch (err) {
|
|
1648
|
-
console.error("Failed to parse tool arguments:", err);
|
|
1649
|
-
return null;
|
|
1650
|
-
}
|
|
1651
|
-
}
|
|
1652
2004
|
const body = {
|
|
1653
|
-
tool:
|
|
1654
|
-
args
|
|
2005
|
+
tool: toolCall.toolName,
|
|
2006
|
+
args: toolCall.args
|
|
1655
2007
|
};
|
|
1656
2008
|
const result = yield fetch(
|
|
1657
2009
|
`${publicAPIUrl}/tools/${encodeURIComponent(mcpTool.url)}`,
|
|
1658
2010
|
{
|
|
1659
2011
|
method: "POST",
|
|
1660
|
-
headers: {
|
|
1661
|
-
"Content-Type": "application/json"
|
|
1662
|
-
|
|
1663
|
-
"
|
|
1664
|
-
|
|
2012
|
+
headers: __spreadValues({
|
|
2013
|
+
"Content-Type": "application/json"
|
|
2014
|
+
}, yield buildMcpRequestHeaders({
|
|
2015
|
+
phase: "call",
|
|
2016
|
+
mcpServer: mcpTool,
|
|
2017
|
+
toolName: toolCall.toolName,
|
|
2018
|
+
toolArgs: toolCall.args
|
|
2019
|
+
})),
|
|
1665
2020
|
body: JSON.stringify(body)
|
|
1666
2021
|
}
|
|
1667
2022
|
);
|
|
1668
2023
|
if (!result.ok) {
|
|
1669
2024
|
console.error(
|
|
1670
|
-
`Error calling tool ${
|
|
2025
|
+
`Error calling tool ${toolCall.toolName}: ${result.status} ${result.statusText}`
|
|
1671
2026
|
);
|
|
1672
2027
|
const errorBody = yield result.text();
|
|
1673
2028
|
console.error(`Error body: ${errorBody}`);
|
|
1674
|
-
return
|
|
2029
|
+
return {
|
|
2030
|
+
tool_call_id: toolCall.callId,
|
|
2031
|
+
tool_name: toolCall.toolName,
|
|
2032
|
+
result: `HTTP ${result.status} ${result.statusText}: ${errorBody || "Tool call failed"}`,
|
|
2033
|
+
isError: true
|
|
2034
|
+
};
|
|
1675
2035
|
}
|
|
1676
2036
|
let resultData;
|
|
1677
2037
|
try {
|
|
1678
2038
|
resultData = yield result.json();
|
|
1679
2039
|
} catch (jsonError) {
|
|
1680
2040
|
console.error(
|
|
1681
|
-
`Error parsing JSON response for tool ${
|
|
2041
|
+
`Error parsing JSON response for tool ${toolCall.toolName}:`,
|
|
1682
2042
|
jsonError
|
|
1683
2043
|
);
|
|
1684
|
-
try {
|
|
1685
|
-
const textBody = yield result.text();
|
|
1686
|
-
console.error("Response body (text):", textBody);
|
|
1687
|
-
} catch (textError) {
|
|
1688
|
-
console.error(
|
|
1689
|
-
"Failed to read response body as text either:",
|
|
1690
|
-
textError
|
|
1691
|
-
);
|
|
1692
|
-
}
|
|
1693
|
-
return null;
|
|
1694
|
-
}
|
|
1695
|
-
if (resultData && resultData.content && resultData.content.length > 0) {
|
|
1696
|
-
const textResult = (_a2 = resultData.content[0]) == null ? void 0 : _a2.text;
|
|
1697
2044
|
return {
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
text: textResult
|
|
1703
|
-
}
|
|
1704
|
-
],
|
|
1705
|
-
tool_call_id: req.groups[0]
|
|
2045
|
+
tool_call_id: toolCall.callId,
|
|
2046
|
+
tool_name: toolCall.toolName,
|
|
2047
|
+
result: "Tool returned a non-JSON response.",
|
|
2048
|
+
isError: true
|
|
1706
2049
|
};
|
|
1707
|
-
} else {
|
|
1708
|
-
console.error(`No content returned from tool ${req.toolName}`);
|
|
1709
|
-
return null;
|
|
1710
2050
|
}
|
|
2051
|
+
const textResult = (_c = (_b = (_a2 = resultData == null ? void 0 : resultData.content) == null ? void 0 : _a2[0]) == null ? void 0 : _b.text) != null ? _c : (resultData == null ? void 0 : resultData.result) ? JSON.stringify(resultData.result) : JSON.stringify(resultData);
|
|
2052
|
+
return {
|
|
2053
|
+
tool_call_id: toolCall.callId,
|
|
2054
|
+
tool_name: toolCall.toolName,
|
|
2055
|
+
result: textResult || "",
|
|
2056
|
+
isError: (resultData == null ? void 0 : resultData.isError) === true
|
|
2057
|
+
};
|
|
1711
2058
|
} catch (error2) {
|
|
1712
|
-
console.error(`Error processing tool ${
|
|
1713
|
-
return
|
|
2059
|
+
console.error(`Error processing tool ${toolCall.toolName}:`, error2);
|
|
2060
|
+
return {
|
|
2061
|
+
tool_call_id: toolCall.callId,
|
|
2062
|
+
tool_name: toolCall.toolName,
|
|
2063
|
+
result: error2 instanceof Error ? error2.message : `Unhandled error calling ${toolCall.toolName}`,
|
|
2064
|
+
isError: true
|
|
2065
|
+
};
|
|
1714
2066
|
}
|
|
1715
2067
|
}));
|
|
1716
2068
|
const toolResponses = yield Promise.all(toolResponsePromises);
|
|
@@ -1732,11 +2084,49 @@ var ChatPanel = ({
|
|
|
1732
2084
|
});
|
|
1733
2085
|
});
|
|
1734
2086
|
}
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
2087
|
+
const toReplayText = (value, maxLength = 2e3) => {
|
|
2088
|
+
const raw = typeof value === "string" ? value : (() => {
|
|
2089
|
+
try {
|
|
2090
|
+
return JSON.stringify(value);
|
|
2091
|
+
} catch (_error) {
|
|
2092
|
+
return String(value != null ? value : "");
|
|
2093
|
+
}
|
|
2094
|
+
})();
|
|
2095
|
+
const normalized = String(raw != null ? raw : "").replace(/\s+/g, " ").trim();
|
|
2096
|
+
if (normalized.length <= maxLength) return normalized;
|
|
2097
|
+
return `${normalized.slice(0, maxLength - 3)}...`;
|
|
2098
|
+
};
|
|
2099
|
+
if (toolCallBatch.length > 0) {
|
|
2100
|
+
const replayLines = toolCallBatch.map((toolCall, index) => {
|
|
2101
|
+
var _a2;
|
|
2102
|
+
const matchedResponse = finalToolResponses.find(
|
|
2103
|
+
(response2) => (response2 == null ? void 0 : response2.tool_call_id) === toolCall.callId
|
|
2104
|
+
) || finalToolResponses[index];
|
|
2105
|
+
const status = (matchedResponse == null ? void 0 : matchedResponse.isError) ? "error" : "ok";
|
|
2106
|
+
const resultText = toReplayText((_a2 = matchedResponse == null ? void 0 : matchedResponse.result) != null ? _a2 : "No result returned");
|
|
2107
|
+
return [
|
|
2108
|
+
`Tool: ${toolCall.toolName}`,
|
|
2109
|
+
`Call ID: ${toolCall.callId}`,
|
|
2110
|
+
`Status: ${status}`,
|
|
2111
|
+
`Args: ${toReplayText(toolCall.args, 600)}`,
|
|
2112
|
+
`Result: ${resultText}`
|
|
2113
|
+
].join("\n");
|
|
2114
|
+
});
|
|
2115
|
+
newMessages.push({
|
|
2116
|
+
role: "user",
|
|
2117
|
+
content: [
|
|
2118
|
+
{
|
|
2119
|
+
type: "text",
|
|
2120
|
+
text: [
|
|
2121
|
+
"Tool execution summary for the previous request:",
|
|
2122
|
+
...replayLines,
|
|
2123
|
+
"Continue the same assistant response from exactly where you paused using these tool results.",
|
|
2124
|
+
"If this response is using meta tags, keep the same format (<thinking>, <reasoning>, <searching>) in the continuation."
|
|
2125
|
+
].join("\n\n")
|
|
2126
|
+
}
|
|
2127
|
+
]
|
|
2128
|
+
});
|
|
2129
|
+
}
|
|
1740
2130
|
send(
|
|
1741
2131
|
"",
|
|
1742
2132
|
newMessages,
|
|
@@ -3518,7 +3908,8 @@ var AgentPanel = ({
|
|
|
3518
3908
|
//ragQueryLimit = 10,
|
|
3519
3909
|
//ragRankLimit = 5,
|
|
3520
3910
|
initialHistory = {},
|
|
3521
|
-
hideRagContextInPrompt = true
|
|
3911
|
+
hideRagContextInPrompt = true,
|
|
3912
|
+
resolveMcpAuthHeaders
|
|
3522
3913
|
}) => {
|
|
3523
3914
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u;
|
|
3524
3915
|
const searchParams = new URLSearchParams(location.search);
|
|
@@ -3656,7 +4047,8 @@ var AgentPanel = ({
|
|
|
3656
4047
|
createConversationOnFirstChat: (_s = agentData == null ? void 0 : agentData.createConversationOnFirstChat) != null ? _s : true,
|
|
3657
4048
|
customerEmailCaptureMode: (_t = agentData == null ? void 0 : agentData.customerEmailCaptureMode) != null ? _t : "HIDE",
|
|
3658
4049
|
customerEmailCapturePlaceholder: (_u = agentData == null ? void 0 : agentData.customerEmailCapturePlaceholder) != null ? _u : "Please enter your email...",
|
|
3659
|
-
mcpServers: mcpData
|
|
4050
|
+
mcpServers: mcpData,
|
|
4051
|
+
resolveMcpAuthHeaders
|
|
3660
4052
|
})
|
|
3661
4053
|
));
|
|
3662
4054
|
};
|
|
@@ -3733,18 +4125,731 @@ var ToolInfoModal2 = ({
|
|
|
3733
4125
|
var ToolInfoModal_default2 = ToolInfoModal2;
|
|
3734
4126
|
|
|
3735
4127
|
// src/AIChatPanel.tsx
|
|
4128
|
+
var areToolRequestListsEqual = (a, b) => {
|
|
4129
|
+
if (a.length !== b.length) return false;
|
|
4130
|
+
for (let index = 0; index < a.length; index += 1) {
|
|
4131
|
+
const left = a[index];
|
|
4132
|
+
const right = b[index];
|
|
4133
|
+
if (!left || !right) return false;
|
|
4134
|
+
if (left.callId !== right.callId) return false;
|
|
4135
|
+
if (left.toolName !== right.toolName) return false;
|
|
4136
|
+
if (left.serviceTag !== right.serviceTag) return false;
|
|
4137
|
+
if (left.match !== right.match) return false;
|
|
4138
|
+
if (left.start !== right.start || left.end !== right.end) return false;
|
|
4139
|
+
}
|
|
4140
|
+
return true;
|
|
4141
|
+
};
|
|
4142
|
+
var mergeContinuationResponseText = (baseText, continuationText) => {
|
|
4143
|
+
const base = typeof baseText === "string" ? baseText : "";
|
|
4144
|
+
const continuation = typeof continuationText === "string" ? continuationText : "";
|
|
4145
|
+
if (!base) return continuation;
|
|
4146
|
+
if (!continuation) return base;
|
|
4147
|
+
if (base.includes(continuation)) {
|
|
4148
|
+
return base;
|
|
4149
|
+
}
|
|
4150
|
+
const maxOverlap = Math.min(base.length, continuation.length);
|
|
4151
|
+
for (let overlap = maxOverlap; overlap > 0; overlap -= 1) {
|
|
4152
|
+
if (base.slice(-overlap) === continuation.slice(0, overlap)) {
|
|
4153
|
+
return `${base}${continuation.slice(overlap)}`;
|
|
4154
|
+
}
|
|
4155
|
+
}
|
|
4156
|
+
return `${base}
|
|
4157
|
+
|
|
4158
|
+
${continuation}`;
|
|
4159
|
+
};
|
|
4160
|
+
var INLINE_TOOL_MARKER_PREFIX = "[[AI_TOOL_CALL:";
|
|
4161
|
+
var INLINE_TOOL_MARKER_SUFFIX = "]]";
|
|
4162
|
+
var INLINE_TOOL_MARKER_REGEX = /\[\[AI_TOOL_CALL:([^|\]]+)\|([^\]]+)\]\]/g;
|
|
4163
|
+
var INLINE_THINKING_MARKER_PREFIX = "[[AI_THINK_BLOCK:";
|
|
4164
|
+
var INLINE_THINKING_MARKER_SUFFIX = "]]";
|
|
4165
|
+
var INLINE_THINKING_MARKER_REGEX = /\[\[AI_THINK_BLOCK:([^|\]]+)\|([^\]]+)\]\]/g;
|
|
4166
|
+
var MAX_TOOL_CONTINUATIONS_PER_TURN = 20;
|
|
4167
|
+
var MAX_TOOL_REPLAY_PAYLOAD_CHARS = 75e4;
|
|
4168
|
+
var MAX_TRACE_SUMMARY_CHARS = 1800;
|
|
4169
|
+
var MAX_TRACE_REASONING_BLOCKS = 4;
|
|
4170
|
+
var MAX_TRACE_TOOL_LINES = 6;
|
|
4171
|
+
var MAX_TRACE_ITEM_CHARS = 220;
|
|
4172
|
+
var MAX_TRACE_LINE_CHARS = 420;
|
|
4173
|
+
var hasInlineRuntimeMarkers = (value) => {
|
|
4174
|
+
const source = typeof value === "string" ? value : "";
|
|
4175
|
+
return source.includes(INLINE_TOOL_MARKER_PREFIX) || source.includes(INLINE_THINKING_MARKER_PREFIX);
|
|
4176
|
+
};
|
|
4177
|
+
var toNonEmptyLines = (value) => String(value || "").split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
|
|
4178
|
+
var isBoundarySubsetByLines = (existingLines, incomingLines) => {
|
|
4179
|
+
if (incomingLines.length === 0 || existingLines.length === 0) return false;
|
|
4180
|
+
if (incomingLines.length >= existingLines.length) return false;
|
|
4181
|
+
const prefixMatch = incomingLines.every((line, index) => existingLines[index] === line);
|
|
4182
|
+
if (prefixMatch) return true;
|
|
4183
|
+
const suffixStart = existingLines.length - incomingLines.length;
|
|
4184
|
+
return incomingLines.every((line, index) => existingLines[suffixStart + index] === line);
|
|
4185
|
+
};
|
|
4186
|
+
var shouldPreserveBoundaryDroppedStreamText = (existingContent, incomingContent) => {
|
|
4187
|
+
const existing = String(existingContent || "").trim();
|
|
4188
|
+
const incoming = String(incomingContent || "").trim();
|
|
4189
|
+
if (!existing) return false;
|
|
4190
|
+
if (!incoming) return true;
|
|
4191
|
+
if (incoming === existing) return false;
|
|
4192
|
+
if (!hasInlineRuntimeMarkers(existing)) return false;
|
|
4193
|
+
if (existing.includes(incoming)) {
|
|
4194
|
+
return true;
|
|
4195
|
+
}
|
|
4196
|
+
const existingLines = toNonEmptyLines(existing);
|
|
4197
|
+
const incomingLines = toNonEmptyLines(incoming);
|
|
4198
|
+
return isBoundarySubsetByLines(existingLines, incomingLines);
|
|
4199
|
+
};
|
|
4200
|
+
var isObjectRecord = (value) => !!value && typeof value === "object" && !Array.isArray(value);
|
|
4201
|
+
var stringifyToolArgs = (value) => {
|
|
4202
|
+
if (typeof value === "string") return value;
|
|
4203
|
+
try {
|
|
4204
|
+
return JSON.stringify(value != null ? value : {});
|
|
4205
|
+
} catch (_error) {
|
|
4206
|
+
return "{}";
|
|
4207
|
+
}
|
|
4208
|
+
};
|
|
4209
|
+
var truncateTraceText = (value, maxChars) => {
|
|
4210
|
+
const text = String(value || "").trim();
|
|
4211
|
+
if (!text) return "";
|
|
4212
|
+
if (text.length <= maxChars) return text;
|
|
4213
|
+
return `${text.slice(0, Math.max(0, maxChars - 1)).trimEnd()}\u2026`;
|
|
4214
|
+
};
|
|
4215
|
+
var normalizeTraceText = (value) => {
|
|
4216
|
+
if (value === null || value === void 0) return "";
|
|
4217
|
+
const raw = typeof value === "string" ? value : (() => {
|
|
4218
|
+
try {
|
|
4219
|
+
return JSON.stringify(value);
|
|
4220
|
+
} catch (_error) {
|
|
4221
|
+
return String(value);
|
|
4222
|
+
}
|
|
4223
|
+
})();
|
|
4224
|
+
return String(raw || "").replace(/\s+/g, " ").trim();
|
|
4225
|
+
};
|
|
4226
|
+
var toTraceObjectArray = (value) => {
|
|
4227
|
+
if (!Array.isArray(value)) return [];
|
|
4228
|
+
return value.filter((item) => isObjectRecord(item));
|
|
4229
|
+
};
|
|
4230
|
+
var getTraceStatusLabel = (response) => {
|
|
4231
|
+
if (!response) return "pending";
|
|
4232
|
+
if (response.isError === true || response.error === true) return "error";
|
|
4233
|
+
return "ok";
|
|
4234
|
+
};
|
|
4235
|
+
var buildCompactTraceSummary = ({
|
|
4236
|
+
reasoningBlocks,
|
|
4237
|
+
toolCalls,
|
|
4238
|
+
toolResponses
|
|
4239
|
+
}) => {
|
|
4240
|
+
const sections = [];
|
|
4241
|
+
const normalizedReasoning = (Array.isArray(reasoningBlocks) ? reasoningBlocks : []).filter((block) => !!block && typeof block.content === "string" && block.content.trim().length > 0).slice(-MAX_TRACE_REASONING_BLOCKS).map((block) => {
|
|
4242
|
+
const content = truncateTraceText(normalizeTraceText(block.content), MAX_TRACE_ITEM_CHARS);
|
|
4243
|
+
if (!content) return "";
|
|
4244
|
+
const type = typeof block.type === "string" ? block.type : "thinking";
|
|
4245
|
+
return `- ${type}: ${content}`;
|
|
4246
|
+
}).filter(Boolean);
|
|
4247
|
+
if (normalizedReasoning.length > 0) {
|
|
4248
|
+
sections.push(["reasoning:", ...normalizedReasoning].join("\n"));
|
|
4249
|
+
}
|
|
4250
|
+
const calls = toTraceObjectArray(toolCalls).slice(-MAX_TRACE_TOOL_LINES);
|
|
4251
|
+
const responses = toTraceObjectArray(toolResponses);
|
|
4252
|
+
if (calls.length > 0) {
|
|
4253
|
+
const responsesByCallId = /* @__PURE__ */ new Map();
|
|
4254
|
+
responses.forEach((response) => {
|
|
4255
|
+
const key = typeof response.tool_call_id === "string" ? response.tool_call_id.trim() : "";
|
|
4256
|
+
if (!key || responsesByCallId.has(key)) return;
|
|
4257
|
+
responsesByCallId.set(key, response);
|
|
4258
|
+
});
|
|
4259
|
+
const responseOffset = Math.max(0, responses.length - calls.length);
|
|
4260
|
+
const toolLines = calls.map((call, index) => {
|
|
4261
|
+
var _a, _b, _c, _d, _e, _f;
|
|
4262
|
+
const toolName = typeof call.name === "string" ? call.name.trim() : typeof call.tool_name === "string" ? call.tool_name.trim() : "tool";
|
|
4263
|
+
const callId = typeof call.id === "string" ? call.id.trim() : typeof call.tool_call_id === "string" ? call.tool_call_id.trim() : "";
|
|
4264
|
+
const response = (callId ? responsesByCallId.get(callId) : void 0) || responses[responseOffset + index] || responses[index];
|
|
4265
|
+
const status = getTraceStatusLabel(response);
|
|
4266
|
+
const rawArgs = (_c = (_b = (_a = call.input) != null ? _a : call.args) != null ? _b : call.arguments) != null ? _c : {};
|
|
4267
|
+
const parsedArgs = parseToolArguments(rawArgs);
|
|
4268
|
+
const normalizedArgs = truncateTraceText(
|
|
4269
|
+
normalizeTraceText(parsedArgs != null ? parsedArgs : isObjectRecord(rawArgs) ? rawArgs : rawArgs || {}),
|
|
4270
|
+
MAX_TRACE_ITEM_CHARS
|
|
4271
|
+
);
|
|
4272
|
+
const normalizedResult = truncateTraceText(
|
|
4273
|
+
normalizeTraceText((_f = (_e = (_d = response == null ? void 0 : response.result) != null ? _d : response == null ? void 0 : response.content) != null ? _e : response == null ? void 0 : response.error) != null ? _f : ""),
|
|
4274
|
+
MAX_TRACE_ITEM_CHARS
|
|
4275
|
+
);
|
|
4276
|
+
const base = callId ? `- ${toolName} (${callId}) ${status}` : `- ${toolName} ${status}`;
|
|
4277
|
+
const withArgs = normalizedArgs ? `${base} args=${normalizedArgs}` : base;
|
|
4278
|
+
const withResult = normalizedResult ? `${withArgs} result=${normalizedResult}` : withArgs;
|
|
4279
|
+
return truncateTraceText(withResult, MAX_TRACE_LINE_CHARS);
|
|
4280
|
+
}).filter(Boolean);
|
|
4281
|
+
if (toolLines.length > 0) {
|
|
4282
|
+
sections.push(["tools:", ...toolLines].join("\n"));
|
|
4283
|
+
}
|
|
4284
|
+
}
|
|
4285
|
+
if (sections.length === 0) return "";
|
|
4286
|
+
return truncateTraceText(["TRACE SUMMARY (compact)", ...sections].join("\n"), MAX_TRACE_SUMMARY_CHARS);
|
|
4287
|
+
};
|
|
4288
|
+
var findPreviousNonWhitespaceChar = (text, startIndex) => {
|
|
4289
|
+
for (let index = startIndex; index >= 0; index -= 1) {
|
|
4290
|
+
const char = text[index];
|
|
4291
|
+
if (typeof char !== "string") continue;
|
|
4292
|
+
if (!/\s/.test(char)) {
|
|
4293
|
+
return char;
|
|
4294
|
+
}
|
|
4295
|
+
}
|
|
4296
|
+
return null;
|
|
4297
|
+
};
|
|
4298
|
+
var findNextNonWhitespaceChar = (text, startIndex) => {
|
|
4299
|
+
for (let index = startIndex; index < text.length; index += 1) {
|
|
4300
|
+
const char = text[index];
|
|
4301
|
+
if (typeof char !== "string") continue;
|
|
4302
|
+
if (!/\s/.test(char)) {
|
|
4303
|
+
return char;
|
|
4304
|
+
}
|
|
4305
|
+
}
|
|
4306
|
+
return null;
|
|
4307
|
+
};
|
|
4308
|
+
var isStandaloneToolObjectSegment = (text, openIndex, closeIndex) => {
|
|
4309
|
+
const lineStart = text.lastIndexOf("\n", openIndex - 1) + 1;
|
|
4310
|
+
const lineEndRaw = text.indexOf("\n", closeIndex + 1);
|
|
4311
|
+
const lineEnd = lineEndRaw === -1 ? text.length : lineEndRaw;
|
|
4312
|
+
const linePrefix = text.slice(lineStart, openIndex);
|
|
4313
|
+
const lineSuffix = text.slice(closeIndex + 1, lineEnd);
|
|
4314
|
+
const startsLine = linePrefix.trim().length === 0;
|
|
4315
|
+
const endsLine = lineSuffix.trim().length === 0;
|
|
4316
|
+
const prevChar = findPreviousNonWhitespaceChar(text, openIndex - 1);
|
|
4317
|
+
const nextChar = findNextNonWhitespaceChar(text, closeIndex + 1);
|
|
4318
|
+
const prevDelimited = prevChar !== null && ["{", "}", "[", "]", ","].includes(prevChar);
|
|
4319
|
+
const nextDelimited = nextChar !== null && ["{", "}", "[", "]", ","].includes(nextChar);
|
|
4320
|
+
const prefixWindow = text.slice(Math.max(0, openIndex - 64), openIndex);
|
|
4321
|
+
const hasLabelPrefix = /(?:^|[\r\n])\s*[A-Za-z][A-Za-z0-9 _-]{0,30}:\s*$/.test(prefixWindow);
|
|
4322
|
+
if (hasLabelPrefix) return false;
|
|
4323
|
+
return (startsLine || prevDelimited) && (endsLine || nextDelimited);
|
|
4324
|
+
};
|
|
4325
|
+
var extractTopLevelJsonObjectSegments = (source) => {
|
|
4326
|
+
const text = typeof source === "string" ? source : "";
|
|
4327
|
+
if (!text) return [];
|
|
4328
|
+
const segments = [];
|
|
4329
|
+
let cursor = 0;
|
|
4330
|
+
while (cursor < text.length) {
|
|
4331
|
+
const openIndex = text.indexOf("{", cursor);
|
|
4332
|
+
if (openIndex === -1) break;
|
|
4333
|
+
let depth = 0;
|
|
4334
|
+
let inString = false;
|
|
4335
|
+
let escaped = false;
|
|
4336
|
+
let closeIndex = -1;
|
|
4337
|
+
for (let index = openIndex; index < text.length; index += 1) {
|
|
4338
|
+
const char = text[index];
|
|
4339
|
+
if (inString) {
|
|
4340
|
+
if (escaped) {
|
|
4341
|
+
escaped = false;
|
|
4342
|
+
continue;
|
|
4343
|
+
}
|
|
4344
|
+
if (char === "\\") {
|
|
4345
|
+
escaped = true;
|
|
4346
|
+
continue;
|
|
4347
|
+
}
|
|
4348
|
+
if (char === '"') {
|
|
4349
|
+
inString = false;
|
|
4350
|
+
}
|
|
4351
|
+
continue;
|
|
4352
|
+
}
|
|
4353
|
+
if (char === '"') {
|
|
4354
|
+
inString = true;
|
|
4355
|
+
continue;
|
|
4356
|
+
}
|
|
4357
|
+
if (char === "{") {
|
|
4358
|
+
depth += 1;
|
|
4359
|
+
continue;
|
|
4360
|
+
}
|
|
4361
|
+
if (char === "}") {
|
|
4362
|
+
depth -= 1;
|
|
4363
|
+
if (depth === 0) {
|
|
4364
|
+
closeIndex = index;
|
|
4365
|
+
break;
|
|
4366
|
+
}
|
|
4367
|
+
if (depth < 0) {
|
|
4368
|
+
break;
|
|
4369
|
+
}
|
|
4370
|
+
}
|
|
4371
|
+
}
|
|
4372
|
+
if (closeIndex === -1) {
|
|
4373
|
+
cursor = openIndex + 1;
|
|
4374
|
+
continue;
|
|
4375
|
+
}
|
|
4376
|
+
const raw = text.slice(openIndex, closeIndex + 1);
|
|
4377
|
+
try {
|
|
4378
|
+
const value = JSON.parse(raw);
|
|
4379
|
+
if (isObjectRecord(value) && isStandaloneToolObjectSegment(text, openIndex, closeIndex)) {
|
|
4380
|
+
segments.push({
|
|
4381
|
+
start: openIndex,
|
|
4382
|
+
end: closeIndex + 1,
|
|
4383
|
+
raw,
|
|
4384
|
+
value
|
|
4385
|
+
});
|
|
4386
|
+
}
|
|
4387
|
+
} catch (_error) {
|
|
4388
|
+
}
|
|
4389
|
+
cursor = closeIndex + 1;
|
|
4390
|
+
}
|
|
4391
|
+
return segments;
|
|
4392
|
+
};
|
|
4393
|
+
var resolveToolRequestFromSegment = (segment, fallbackIndex) => {
|
|
4394
|
+
var _a, _b, _c;
|
|
4395
|
+
const record = segment.value;
|
|
4396
|
+
const serviceTag = typeof record.service === "string" ? record.service : "";
|
|
4397
|
+
const rawId = typeof record.id === "string" ? record.id.trim() : "";
|
|
4398
|
+
if (record.type === "tool_use" && typeof record.name === "string") {
|
|
4399
|
+
const toolName = String(record.name).trim();
|
|
4400
|
+
if (!toolName) return null;
|
|
4401
|
+
const callId = rawId || `${toolName}-${fallbackIndex + 1}`;
|
|
4402
|
+
return {
|
|
4403
|
+
match: segment.raw,
|
|
4404
|
+
groups: [callId, toolName, stringifyToolArgs((_a = record.input) != null ? _a : {}), serviceTag],
|
|
4405
|
+
toolName,
|
|
4406
|
+
callId,
|
|
4407
|
+
serviceTag,
|
|
4408
|
+
start: segment.start,
|
|
4409
|
+
end: segment.end
|
|
4410
|
+
};
|
|
4411
|
+
}
|
|
4412
|
+
if (record.type === "function" && isObjectRecord(record.function)) {
|
|
4413
|
+
const functionRecord = record.function;
|
|
4414
|
+
const toolName = typeof functionRecord.name === "string" ? functionRecord.name.trim() : "";
|
|
4415
|
+
if (!toolName) return null;
|
|
4416
|
+
const callId = rawId || `${toolName}-${fallbackIndex + 1}`;
|
|
4417
|
+
return {
|
|
4418
|
+
match: segment.raw,
|
|
4419
|
+
groups: [callId, toolName, stringifyToolArgs((_b = functionRecord.arguments) != null ? _b : {}), serviceTag],
|
|
4420
|
+
toolName,
|
|
4421
|
+
callId,
|
|
4422
|
+
serviceTag,
|
|
4423
|
+
start: segment.start,
|
|
4424
|
+
end: segment.end
|
|
4425
|
+
};
|
|
4426
|
+
}
|
|
4427
|
+
if (isObjectRecord(record.functionCall) && typeof record.functionCall.name === "string") {
|
|
4428
|
+
const functionCall = record.functionCall;
|
|
4429
|
+
const toolName = String(functionCall.name).trim();
|
|
4430
|
+
if (!toolName) return null;
|
|
4431
|
+
const callId = rawId || `${toolName}-${fallbackIndex + 1}`;
|
|
4432
|
+
return {
|
|
4433
|
+
match: segment.raw,
|
|
4434
|
+
groups: [callId, toolName, stringifyToolArgs((_c = functionCall.args) != null ? _c : {}), serviceTag],
|
|
4435
|
+
toolName,
|
|
4436
|
+
callId,
|
|
4437
|
+
serviceTag,
|
|
4438
|
+
start: segment.start,
|
|
4439
|
+
end: segment.end
|
|
4440
|
+
};
|
|
4441
|
+
}
|
|
4442
|
+
return null;
|
|
4443
|
+
};
|
|
4444
|
+
var extractBalancedObjectCandidate = (input) => {
|
|
4445
|
+
const text = typeof input === "string" ? input : "";
|
|
4446
|
+
const start = text.indexOf("{");
|
|
4447
|
+
if (start === -1) return null;
|
|
4448
|
+
let depth = 0;
|
|
4449
|
+
let inString = false;
|
|
4450
|
+
let escaped = false;
|
|
4451
|
+
for (let index = start; index < text.length; index += 1) {
|
|
4452
|
+
const char = text[index];
|
|
4453
|
+
if (inString) {
|
|
4454
|
+
if (escaped) {
|
|
4455
|
+
escaped = false;
|
|
4456
|
+
continue;
|
|
4457
|
+
}
|
|
4458
|
+
if (char === "\\") {
|
|
4459
|
+
escaped = true;
|
|
4460
|
+
continue;
|
|
4461
|
+
}
|
|
4462
|
+
if (char === '"') {
|
|
4463
|
+
inString = false;
|
|
4464
|
+
}
|
|
4465
|
+
continue;
|
|
4466
|
+
}
|
|
4467
|
+
if (char === '"') {
|
|
4468
|
+
inString = true;
|
|
4469
|
+
continue;
|
|
4470
|
+
}
|
|
4471
|
+
if (char === "{") {
|
|
4472
|
+
depth += 1;
|
|
4473
|
+
continue;
|
|
4474
|
+
}
|
|
4475
|
+
if (char === "}") {
|
|
4476
|
+
depth -= 1;
|
|
4477
|
+
if (depth === 0) {
|
|
4478
|
+
return text.slice(start, index + 1);
|
|
4479
|
+
}
|
|
4480
|
+
}
|
|
4481
|
+
}
|
|
4482
|
+
return null;
|
|
4483
|
+
};
|
|
4484
|
+
var extractLineLevelFallbackToolRequests = (source, existing) => {
|
|
4485
|
+
const text = typeof source === "string" ? source : "";
|
|
4486
|
+
if (!text) return [];
|
|
4487
|
+
const takenRanges = existing.map((request) => ({
|
|
4488
|
+
start: request.start,
|
|
4489
|
+
end: request.end
|
|
4490
|
+
}));
|
|
4491
|
+
const overlapsExisting = (start, end) => takenRanges.some((range) => start < range.end && end > range.start);
|
|
4492
|
+
const requests = [];
|
|
4493
|
+
let offset = 0;
|
|
4494
|
+
const lines = text.split("\n");
|
|
4495
|
+
const normalizeStandaloneToolJsonLine = (line) => {
|
|
4496
|
+
const trimmed = line.trim();
|
|
4497
|
+
if (!trimmed) return null;
|
|
4498
|
+
let normalized = trimmed;
|
|
4499
|
+
const first = normalized[0];
|
|
4500
|
+
const last = normalized[normalized.length - 1];
|
|
4501
|
+
const hasSymmetricQuote = normalized.length >= 2 && (first === "'" && last === "'" || first === '"' && last === '"' || first === "`" && last === "`");
|
|
4502
|
+
if (hasSymmetricQuote) {
|
|
4503
|
+
const inner = normalized.slice(1, -1).trim();
|
|
4504
|
+
if (first === '"') {
|
|
4505
|
+
try {
|
|
4506
|
+
const decoded = JSON.parse(normalized);
|
|
4507
|
+
if (typeof decoded === "string") {
|
|
4508
|
+
normalized = decoded.trim();
|
|
4509
|
+
} else {
|
|
4510
|
+
normalized = inner;
|
|
4511
|
+
}
|
|
4512
|
+
} catch (_error) {
|
|
4513
|
+
normalized = inner;
|
|
4514
|
+
}
|
|
4515
|
+
} else {
|
|
4516
|
+
normalized = inner;
|
|
4517
|
+
}
|
|
4518
|
+
}
|
|
4519
|
+
const extractedCandidate = extractBalancedObjectCandidate(normalized);
|
|
4520
|
+
if (extractedCandidate) {
|
|
4521
|
+
normalized = extractedCandidate.trim();
|
|
4522
|
+
}
|
|
4523
|
+
if (!normalized.startsWith("{")) return null;
|
|
4524
|
+
if (!normalized.includes('"type"')) return null;
|
|
4525
|
+
return normalized;
|
|
4526
|
+
};
|
|
4527
|
+
const extractBalancedObjectAfterField = (input, fieldName) => {
|
|
4528
|
+
const fieldRegex = new RegExp(`"${fieldName}"\\s*:\\s*`, "i");
|
|
4529
|
+
const fieldMatch = fieldRegex.exec(input);
|
|
4530
|
+
if (!fieldMatch) return null;
|
|
4531
|
+
const startIndex = input.indexOf("{", fieldMatch.index + fieldMatch[0].length);
|
|
4532
|
+
if (startIndex === -1) return null;
|
|
4533
|
+
let depth = 0;
|
|
4534
|
+
let inString = false;
|
|
4535
|
+
let escaped = false;
|
|
4536
|
+
for (let index = startIndex; index < input.length; index += 1) {
|
|
4537
|
+
const char = input[index];
|
|
4538
|
+
if (inString) {
|
|
4539
|
+
if (escaped) {
|
|
4540
|
+
escaped = false;
|
|
4541
|
+
continue;
|
|
4542
|
+
}
|
|
4543
|
+
if (char === "\\") {
|
|
4544
|
+
escaped = true;
|
|
4545
|
+
continue;
|
|
4546
|
+
}
|
|
4547
|
+
if (char === '"') {
|
|
4548
|
+
inString = false;
|
|
4549
|
+
}
|
|
4550
|
+
continue;
|
|
4551
|
+
}
|
|
4552
|
+
if (char === '"') {
|
|
4553
|
+
inString = true;
|
|
4554
|
+
continue;
|
|
4555
|
+
}
|
|
4556
|
+
if (char === "{") {
|
|
4557
|
+
depth += 1;
|
|
4558
|
+
continue;
|
|
4559
|
+
}
|
|
4560
|
+
if (char === "}") {
|
|
4561
|
+
depth -= 1;
|
|
4562
|
+
if (depth === 0) {
|
|
4563
|
+
return input.slice(startIndex, index + 1);
|
|
4564
|
+
}
|
|
4565
|
+
}
|
|
4566
|
+
}
|
|
4567
|
+
return null;
|
|
4568
|
+
};
|
|
4569
|
+
lines.forEach((line, index) => {
|
|
4570
|
+
var _a, _b, _c, _d, _e, _f;
|
|
4571
|
+
const lineStart = offset;
|
|
4572
|
+
const lineEnd = lineStart + line.length;
|
|
4573
|
+
offset = lineEnd + (index < lines.length - 1 ? 1 : 0);
|
|
4574
|
+
const normalized = normalizeStandaloneToolJsonLine(line);
|
|
4575
|
+
if (!normalized) return;
|
|
4576
|
+
if (!(normalized.includes('"tool_use"') || normalized.includes('"function"'))) return;
|
|
4577
|
+
if (/(^|[\r\n])\s*[A-Za-z][A-Za-z0-9 _-]{0,30}:\s*\{/.test(line)) return;
|
|
4578
|
+
if (overlapsExisting(lineStart, lineEnd)) return;
|
|
4579
|
+
try {
|
|
4580
|
+
const parsedLine = JSON.parse(normalized);
|
|
4581
|
+
if (isObjectRecord(parsedLine)) {
|
|
4582
|
+
const type2 = typeof parsedLine.type === "string" ? parsedLine.type.trim().toLowerCase() : "";
|
|
4583
|
+
if (type2 === "tool_use") {
|
|
4584
|
+
const toolName2 = typeof parsedLine.name === "string" ? parsedLine.name.trim() : "";
|
|
4585
|
+
if (!toolName2) return;
|
|
4586
|
+
const callId2 = typeof parsedLine.id === "string" && parsedLine.id.trim().length > 0 ? parsedLine.id.trim() : `tool-call-${index + 1}`;
|
|
4587
|
+
const serviceTag = typeof parsedLine.service === "string" ? parsedLine.service : "";
|
|
4588
|
+
const parsedArgs2 = parseToolArguments((_a = parsedLine.input) != null ? _a : {});
|
|
4589
|
+
if (!parsedArgs2) return;
|
|
4590
|
+
requests.push({
|
|
4591
|
+
match: line,
|
|
4592
|
+
groups: [callId2, toolName2, stringifyToolArgs(parsedArgs2), serviceTag],
|
|
4593
|
+
toolName: toolName2,
|
|
4594
|
+
callId: callId2,
|
|
4595
|
+
serviceTag,
|
|
4596
|
+
start: lineStart,
|
|
4597
|
+
end: lineEnd
|
|
4598
|
+
});
|
|
4599
|
+
return;
|
|
4600
|
+
}
|
|
4601
|
+
if (type2 === "function" && isObjectRecord(parsedLine.function)) {
|
|
4602
|
+
const functionRecord = parsedLine.function;
|
|
4603
|
+
const toolName2 = typeof functionRecord.name === "string" ? functionRecord.name.trim() : "";
|
|
4604
|
+
if (!toolName2) return;
|
|
4605
|
+
const callId2 = typeof parsedLine.id === "string" && parsedLine.id.trim().length > 0 ? parsedLine.id.trim() : `tool-call-${index + 1}`;
|
|
4606
|
+
const serviceTag = typeof parsedLine.service === "string" ? parsedLine.service : "";
|
|
4607
|
+
const parsedArgs2 = parseToolArguments((_b = functionRecord.arguments) != null ? _b : {});
|
|
4608
|
+
if (!parsedArgs2) return;
|
|
4609
|
+
requests.push({
|
|
4610
|
+
match: line,
|
|
4611
|
+
groups: [callId2, toolName2, stringifyToolArgs(parsedArgs2), serviceTag],
|
|
4612
|
+
toolName: toolName2,
|
|
4613
|
+
callId: callId2,
|
|
4614
|
+
serviceTag,
|
|
4615
|
+
start: lineStart,
|
|
4616
|
+
end: lineEnd
|
|
4617
|
+
});
|
|
4618
|
+
return;
|
|
4619
|
+
}
|
|
4620
|
+
}
|
|
4621
|
+
} catch (_error) {
|
|
4622
|
+
}
|
|
4623
|
+
const typeMatch = normalized.match(/"type"\s*:\s*"([^"]+)"/i);
|
|
4624
|
+
const type = (_c = typeMatch == null ? void 0 : typeMatch[1]) == null ? void 0 : _c.trim().toLowerCase();
|
|
4625
|
+
if (type !== "tool_use" && type !== "function") return;
|
|
4626
|
+
const idMatch = normalized.match(/"id"\s*:\s*"([^"]+)"/i);
|
|
4627
|
+
const callId = ((_d = idMatch == null ? void 0 : idMatch[1]) == null ? void 0 : _d.trim()) || `tool-call-${index + 1}`;
|
|
4628
|
+
let toolName = "";
|
|
4629
|
+
let argsRaw = "{}";
|
|
4630
|
+
if (type === "tool_use") {
|
|
4631
|
+
const nameMatch = normalized.match(/"name"\s*:\s*"([^"]+)"/i);
|
|
4632
|
+
toolName = ((_e = nameMatch == null ? void 0 : nameMatch[1]) == null ? void 0 : _e.trim()) || "";
|
|
4633
|
+
const inputObject = extractBalancedObjectAfterField(normalized, "input");
|
|
4634
|
+
if (inputObject) {
|
|
4635
|
+
argsRaw = inputObject;
|
|
4636
|
+
}
|
|
4637
|
+
} else {
|
|
4638
|
+
const fnNameMatch = normalized.match(/"function"\s*:\s*\{[\s\S]*?"name"\s*:\s*"([^"]+)"/i);
|
|
4639
|
+
toolName = ((_f = fnNameMatch == null ? void 0 : fnNameMatch[1]) == null ? void 0 : _f.trim()) || "";
|
|
4640
|
+
const argumentsObject = extractBalancedObjectAfterField(normalized, "arguments");
|
|
4641
|
+
if (argumentsObject) {
|
|
4642
|
+
argsRaw = argumentsObject;
|
|
4643
|
+
} else {
|
|
4644
|
+
const argsStringMatch = normalized.match(/"arguments"\s*:\s*"([\s\S]*?)"(?:\s*,|\s*})/i);
|
|
4645
|
+
if (argsStringMatch == null ? void 0 : argsStringMatch[1]) {
|
|
4646
|
+
const rawArgs = argsStringMatch[1];
|
|
4647
|
+
try {
|
|
4648
|
+
argsRaw = JSON.parse(`"${rawArgs}"`);
|
|
4649
|
+
} catch (_error) {
|
|
4650
|
+
argsRaw = rawArgs;
|
|
4651
|
+
}
|
|
4652
|
+
}
|
|
4653
|
+
}
|
|
4654
|
+
}
|
|
4655
|
+
if (!toolName) return;
|
|
4656
|
+
const parsedArgs = parseToolArguments(argsRaw);
|
|
4657
|
+
if (!parsedArgs) return;
|
|
4658
|
+
requests.push({
|
|
4659
|
+
match: line,
|
|
4660
|
+
groups: [callId, toolName, stringifyToolArgs(parsedArgs), ""],
|
|
4661
|
+
toolName,
|
|
4662
|
+
callId,
|
|
4663
|
+
serviceTag: "",
|
|
4664
|
+
start: lineStart,
|
|
4665
|
+
end: lineEnd
|
|
4666
|
+
});
|
|
4667
|
+
});
|
|
4668
|
+
return requests;
|
|
4669
|
+
};
|
|
4670
|
+
var stripStandaloneRawToolJsonLines = (source) => {
|
|
4671
|
+
const text = typeof source === "string" ? source : "";
|
|
4672
|
+
if (!text) return text;
|
|
4673
|
+
const normalizeStandaloneToolJsonLine = (line) => {
|
|
4674
|
+
const trimmed = line.trim();
|
|
4675
|
+
if (!trimmed) return null;
|
|
4676
|
+
let normalized = trimmed;
|
|
4677
|
+
const first = normalized[0];
|
|
4678
|
+
const last = normalized[normalized.length - 1];
|
|
4679
|
+
const hasSymmetricQuote = normalized.length >= 2 && (first === "'" && last === "'" || first === '"' && last === '"' || first === "`" && last === "`");
|
|
4680
|
+
if (hasSymmetricQuote) {
|
|
4681
|
+
const inner = normalized.slice(1, -1).trim();
|
|
4682
|
+
if (first === '"') {
|
|
4683
|
+
try {
|
|
4684
|
+
const decoded = JSON.parse(normalized);
|
|
4685
|
+
if (typeof decoded === "string") {
|
|
4686
|
+
normalized = decoded.trim();
|
|
4687
|
+
} else {
|
|
4688
|
+
normalized = inner;
|
|
4689
|
+
}
|
|
4690
|
+
} catch (_error) {
|
|
4691
|
+
normalized = inner;
|
|
4692
|
+
}
|
|
4693
|
+
} else {
|
|
4694
|
+
normalized = inner;
|
|
4695
|
+
}
|
|
4696
|
+
}
|
|
4697
|
+
const extractedCandidate = extractBalancedObjectCandidate(normalized);
|
|
4698
|
+
if (extractedCandidate) {
|
|
4699
|
+
normalized = extractedCandidate.trim();
|
|
4700
|
+
}
|
|
4701
|
+
if (!normalized.startsWith("{") || !normalized.endsWith("}")) return null;
|
|
4702
|
+
return normalized;
|
|
4703
|
+
};
|
|
4704
|
+
const lines = text.split("\n");
|
|
4705
|
+
let removedAny = false;
|
|
4706
|
+
const kept = lines.filter((line) => {
|
|
4707
|
+
const normalized = normalizeStandaloneToolJsonLine(line);
|
|
4708
|
+
if (!normalized) return true;
|
|
4709
|
+
const hasToolType = /"type"\s*:\s*"(tool_use|function)"/i.test(normalized);
|
|
4710
|
+
if (!hasToolType) return true;
|
|
4711
|
+
const hasName = /"name"\s*:\s*"[^"]+"/i.test(normalized);
|
|
4712
|
+
const hasFunctionName = /"function"\s*:\s*\{[\s\S]*?"name"\s*:\s*"[^"]+"/i.test(normalized);
|
|
4713
|
+
if (!hasName && !hasFunctionName) return true;
|
|
4714
|
+
removedAny = true;
|
|
4715
|
+
return false;
|
|
4716
|
+
});
|
|
4717
|
+
if (!removedAny) return text;
|
|
4718
|
+
return kept.join("\n").replace(/\n{3,}/g, "\n\n");
|
|
4719
|
+
};
|
|
4720
|
+
var extractToolRequestMatchesFromText = (rawResponse) => {
|
|
4721
|
+
const requests = [];
|
|
4722
|
+
const segments = extractTopLevelJsonObjectSegments(rawResponse);
|
|
4723
|
+
segments.forEach((segment, segmentIndex) => {
|
|
4724
|
+
const parsed = resolveToolRequestFromSegment(segment, segmentIndex);
|
|
4725
|
+
if (!parsed) return;
|
|
4726
|
+
requests.push(parsed);
|
|
4727
|
+
});
|
|
4728
|
+
const fallbackRequests = extractLineLevelFallbackToolRequests(rawResponse, requests);
|
|
4729
|
+
fallbackRequests.forEach((request) => {
|
|
4730
|
+
requests.push(request);
|
|
4731
|
+
});
|
|
4732
|
+
if (requests.length === 0) return [];
|
|
4733
|
+
requests.sort((a, b) => a.start - b.start);
|
|
4734
|
+
const seenSignatures = /* @__PURE__ */ new Set();
|
|
4735
|
+
const deduped = requests.filter((request) => {
|
|
4736
|
+
const signature = `${String(request.toolName || "").trim().toLowerCase()}::${String(
|
|
4737
|
+
request.callId || ""
|
|
4738
|
+
).trim().toLowerCase()}::${request.start}`;
|
|
4739
|
+
if (seenSignatures.has(signature)) return false;
|
|
4740
|
+
seenSignatures.add(signature);
|
|
4741
|
+
return true;
|
|
4742
|
+
});
|
|
4743
|
+
deduped.sort((a, b) => a.start - b.start);
|
|
4744
|
+
return deduped;
|
|
4745
|
+
};
|
|
4746
|
+
var hashInlineMarkerValue = (value) => {
|
|
4747
|
+
let hash = 5381;
|
|
4748
|
+
const input = String(value || "");
|
|
4749
|
+
for (let index = 0; index < input.length; index += 1) {
|
|
4750
|
+
hash = (hash << 5) + hash ^ input.charCodeAt(index);
|
|
4751
|
+
}
|
|
4752
|
+
return (hash >>> 0).toString(36);
|
|
4753
|
+
};
|
|
4754
|
+
var getThinkingBlockSignature = (type, content) => {
|
|
4755
|
+
const normalizedContent = String(content || "").trim();
|
|
4756
|
+
return `${type}-${hashInlineMarkerValue(normalizedContent)}-${normalizedContent.length}`;
|
|
4757
|
+
};
|
|
4758
|
+
var buildThinkingBlockMarker = (type, signature) => {
|
|
4759
|
+
const normalizedType = String(type || "thinking").trim();
|
|
4760
|
+
const normalizedSignature = String(signature || "").trim() || `${normalizedType}-block`;
|
|
4761
|
+
return `${INLINE_THINKING_MARKER_PREFIX}${encodeURIComponent(normalizedType)}|${encodeURIComponent(
|
|
4762
|
+
normalizedSignature
|
|
4763
|
+
)}${INLINE_THINKING_MARKER_SUFFIX}`;
|
|
4764
|
+
};
|
|
4765
|
+
var buildInlineToolMarker = (toolName, callId) => {
|
|
4766
|
+
const normalizedToolName = String(toolName || "").trim() || "tool";
|
|
4767
|
+
const normalizedCallId = String(callId || "").trim() || `${normalizedToolName}-call`;
|
|
4768
|
+
return `${INLINE_TOOL_MARKER_PREFIX}${encodeURIComponent(normalizedToolName)}|${encodeURIComponent(
|
|
4769
|
+
normalizedCallId
|
|
4770
|
+
)}${INLINE_TOOL_MARKER_SUFFIX}`;
|
|
4771
|
+
};
|
|
4772
|
+
var parseInlineToolMarkers = (text) => {
|
|
4773
|
+
const source = typeof text === "string" ? text : "";
|
|
4774
|
+
if (!source) return { parts: [""], markers: [] };
|
|
4775
|
+
const parts = [];
|
|
4776
|
+
const markers = [];
|
|
4777
|
+
let lastIndex = 0;
|
|
4778
|
+
INLINE_TOOL_MARKER_REGEX.lastIndex = 0;
|
|
4779
|
+
let match;
|
|
4780
|
+
while ((match = INLINE_TOOL_MARKER_REGEX.exec(source)) !== null) {
|
|
4781
|
+
parts.push(source.slice(lastIndex, match.index));
|
|
4782
|
+
const encodedToolName = match[1] || "";
|
|
4783
|
+
const encodedCallId = match[2] || "";
|
|
4784
|
+
let toolName = encodedToolName;
|
|
4785
|
+
let callId = encodedCallId;
|
|
4786
|
+
try {
|
|
4787
|
+
toolName = decodeURIComponent(encodedToolName);
|
|
4788
|
+
} catch (_error) {
|
|
4789
|
+
toolName = encodedToolName;
|
|
4790
|
+
}
|
|
4791
|
+
try {
|
|
4792
|
+
callId = decodeURIComponent(encodedCallId);
|
|
4793
|
+
} catch (_error) {
|
|
4794
|
+
callId = encodedCallId;
|
|
4795
|
+
}
|
|
4796
|
+
markers.push({
|
|
4797
|
+
toolName: String(toolName || "").trim() || "tool",
|
|
4798
|
+
callId: String(callId || "").trim() || "call"
|
|
4799
|
+
});
|
|
4800
|
+
lastIndex = match.index + match[0].length;
|
|
4801
|
+
}
|
|
4802
|
+
parts.push(source.slice(lastIndex));
|
|
4803
|
+
return { parts, markers };
|
|
4804
|
+
};
|
|
4805
|
+
var parseInlineThinkingMarkers = (text) => {
|
|
4806
|
+
const source = typeof text === "string" ? text : "";
|
|
4807
|
+
if (!source) return { parts: [""], markers: [] };
|
|
4808
|
+
const parts = [];
|
|
4809
|
+
const markers = [];
|
|
4810
|
+
let lastIndex = 0;
|
|
4811
|
+
INLINE_THINKING_MARKER_REGEX.lastIndex = 0;
|
|
4812
|
+
let match;
|
|
4813
|
+
while ((match = INLINE_THINKING_MARKER_REGEX.exec(source)) !== null) {
|
|
4814
|
+
parts.push(source.slice(lastIndex, match.index));
|
|
4815
|
+
const encodedType = match[1] || "";
|
|
4816
|
+
const encodedSignature = match[2] || "";
|
|
4817
|
+
let rawType = encodedType;
|
|
4818
|
+
let signature = encodedSignature;
|
|
4819
|
+
try {
|
|
4820
|
+
rawType = decodeURIComponent(encodedType);
|
|
4821
|
+
} catch (_error) {
|
|
4822
|
+
rawType = encodedType;
|
|
4823
|
+
}
|
|
4824
|
+
try {
|
|
4825
|
+
signature = decodeURIComponent(encodedSignature);
|
|
4826
|
+
} catch (_error) {
|
|
4827
|
+
signature = encodedSignature;
|
|
4828
|
+
}
|
|
4829
|
+
const normalizedType = String(rawType || "").trim().toLowerCase();
|
|
4830
|
+
const type = normalizedType === "reasoning" ? "reasoning" : normalizedType === "searching" ? "searching" : "thinking";
|
|
4831
|
+
markers.push({
|
|
4832
|
+
type,
|
|
4833
|
+
signature: String(signature || "").trim()
|
|
4834
|
+
});
|
|
4835
|
+
lastIndex = match.index + match[0].length;
|
|
4836
|
+
}
|
|
4837
|
+
parts.push(source.slice(lastIndex));
|
|
4838
|
+
return { parts, markers };
|
|
4839
|
+
};
|
|
3736
4840
|
var ArrowUpIcon = () => /* @__PURE__ */ React14.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "ai-chat-icon-sm" }, /* @__PURE__ */ React14.createElement("path", { d: "M12 19V5M5 12l7-7 7 7" }));
|
|
3737
4841
|
var StopIcon = () => /* @__PURE__ */ React14.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", className: "ai-chat-icon" }, /* @__PURE__ */ React14.createElement("rect", { x: "6", y: "6", width: "12", height: "12", rx: "2" }));
|
|
3738
4842
|
var ChevronDownIcon = () => /* @__PURE__ */ React14.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "ai-chat-icon-sm" }, /* @__PURE__ */ React14.createElement("path", { d: "m6 9 6 6 6-6" }));
|
|
3739
4843
|
var ChevronUpIcon = () => /* @__PURE__ */ React14.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "ai-chat-icon-sm" }, /* @__PURE__ */ React14.createElement("path", { d: "m18 15-6-6-6 6" }));
|
|
3740
4844
|
var AgentIcon = () => /* @__PURE__ */ React14.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "ai-chat-icon-sm" }, /* @__PURE__ */ React14.createElement("path", { d: "M12 8V4H8" }), /* @__PURE__ */ React14.createElement("rect", { width: "16", height: "12", x: "4", y: "8", rx: "2" }), /* @__PURE__ */ React14.createElement("path", { d: "M2 14h2" }), /* @__PURE__ */ React14.createElement("path", { d: "M20 14h2" }), /* @__PURE__ */ React14.createElement("path", { d: "M15 13v2" }), /* @__PURE__ */ React14.createElement("path", { d: "M9 13v2" }));
|
|
4845
|
+
var ToolIcon = () => /* @__PURE__ */ React14.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "ai-chat-icon-sm" }, /* @__PURE__ */ React14.createElement("path", { d: "M14.7 6.3a4 4 0 0 0-5.4 5.4l-6 6a2 2 0 0 0 2.8 2.8l6-6a4 4 0 0 0 5.4-5.4l-2.1 2.1-3.3-3.3 2.6-1.6Z" }));
|
|
3741
4846
|
var CheckIcon = () => /* @__PURE__ */ React14.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "ai-chat-icon-sm" }, /* @__PURE__ */ React14.createElement("polyline", { points: "20 6 9 17 4 12" }));
|
|
3742
4847
|
var LLMAsAServiceLogo = () => /* @__PURE__ */ React14.createElement("svg", { width: "16", height: "16", viewBox: "0 0 72 72", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ React14.createElement("ellipse", { cx: "14.0868", cy: "59.2146", rx: "7.8261", ry: "7.7854", fill: "#2487D8" }), /* @__PURE__ */ React14.createElement("ellipse", { cx: "24.9013", cy: "43.0776", rx: "6.11858", ry: "6.08676", fill: "#2487D8" }), /* @__PURE__ */ React14.createElement("ellipse", { cx: "45.391", cy: "43.0776", rx: "6.11858", ry: "6.08676", fill: "#2487D8" }), /* @__PURE__ */ React14.createElement("ellipse", { cx: "65.8813", cy: "43.0776", rx: "6.11858", ry: "6.08676", fill: "#2487D8" }), /* @__PURE__ */ React14.createElement("ellipse", { cx: "35.1461", cy: "26.5327", rx: "4.41103", ry: "4.3878", fill: "#2487D8" }), /* @__PURE__ */ React14.createElement("ellipse", { cx: "55.6364", cy: "26.5327", rx: "4.41103", ry: "4.3878", fill: "#2487D8" }), /* @__PURE__ */ React14.createElement("ellipse", { cx: "45.391", cy: "10.3959", rx: "2.70351", ry: "2.68919", fill: "#2487D8" }));
|
|
3743
4848
|
var AlertCircleIcon = () => /* @__PURE__ */ React14.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "ai-chat-icon-sm" }, /* @__PURE__ */ React14.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ React14.createElement("line", { x1: "12", x2: "12", y1: "8", y2: "12" }), /* @__PURE__ */ React14.createElement("line", { x1: "12", x2: "12.01", y1: "16", y2: "16" }));
|
|
3744
4849
|
var CloseIcon = () => /* @__PURE__ */ React14.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "ai-chat-icon-sm" }, /* @__PURE__ */ React14.createElement("line", { x1: "18", x2: "6", y1: "6", y2: "18" }), /* @__PURE__ */ React14.createElement("line", { x1: "6", x2: "18", y1: "6", y2: "18" }));
|
|
3745
4850
|
var ChatInput = React14.memo(({
|
|
3746
4851
|
placeholder,
|
|
3747
|
-
|
|
4852
|
+
isBusy,
|
|
3748
4853
|
onSubmit,
|
|
3749
4854
|
onStop,
|
|
3750
4855
|
agentOptions,
|
|
@@ -3777,14 +4882,14 @@ var ChatInput = React14.memo(({
|
|
|
3777
4882
|
}, []);
|
|
3778
4883
|
const handleSubmit = useCallback2(() => {
|
|
3779
4884
|
const trimmed = inputValue.trim();
|
|
3780
|
-
if (trimmed &&
|
|
4885
|
+
if (trimmed && !isBusy) {
|
|
3781
4886
|
onSubmit(trimmed);
|
|
3782
4887
|
setInputValue("");
|
|
3783
4888
|
if (textareaRef.current) {
|
|
3784
4889
|
textareaRef.current.style.height = "auto";
|
|
3785
4890
|
}
|
|
3786
4891
|
}
|
|
3787
|
-
}, [inputValue,
|
|
4892
|
+
}, [inputValue, isBusy, onSubmit]);
|
|
3788
4893
|
useEffect8(() => {
|
|
3789
4894
|
const handleClickOutside = (event) => {
|
|
3790
4895
|
if (containerRef.current && !containerRef.current.contains(event.target)) {
|
|
@@ -3820,9 +4925,6 @@ var ChatInput = React14.memo(({
|
|
|
3820
4925
|
const hasRawData2 = (section) => {
|
|
3821
4926
|
return typeof section.rawData === "string";
|
|
3822
4927
|
};
|
|
3823
|
-
const hasStructuredData = (section) => {
|
|
3824
|
-
return typeof section.data === "object" && section.data !== null;
|
|
3825
|
-
};
|
|
3826
4928
|
const estimateSectionTokens2 = (section) => {
|
|
3827
4929
|
var _a;
|
|
3828
4930
|
if (typeof section.tokens === "number") {
|
|
@@ -3833,32 +4935,6 @@ var ChatInput = React14.memo(({
|
|
|
3833
4935
|
}
|
|
3834
4936
|
return Math.ceil(JSON.stringify((_a = section.data) != null ? _a : {}).length / 4);
|
|
3835
4937
|
};
|
|
3836
|
-
const detectFormat = (section) => {
|
|
3837
|
-
if (section.format) {
|
|
3838
|
-
return section.format;
|
|
3839
|
-
}
|
|
3840
|
-
if (!hasRawData2(section)) {
|
|
3841
|
-
return "json";
|
|
3842
|
-
}
|
|
3843
|
-
const raw = section.rawData.trim();
|
|
3844
|
-
if (raw.startsWith("{") || raw.startsWith("[")) return "json";
|
|
3845
|
-
if (raw.includes("# ") || raw.includes("```")) return "markdown";
|
|
3846
|
-
return "text";
|
|
3847
|
-
};
|
|
3848
|
-
const formatBadge = (format) => {
|
|
3849
|
-
if (format === "toon") return "TOON";
|
|
3850
|
-
if (format === "markdown") return "MD";
|
|
3851
|
-
if (format === "text") return "TEXT";
|
|
3852
|
-
return "JSON";
|
|
3853
|
-
};
|
|
3854
|
-
const [detailViewModeBySection, setDetailViewModeBySection] = useState7({});
|
|
3855
|
-
const getVisibleDetailMode = (section) => {
|
|
3856
|
-
var _a;
|
|
3857
|
-
if (hasRawData2(section)) {
|
|
3858
|
-
return (_a = detailViewModeBySection[section.id]) != null ? _a : "raw";
|
|
3859
|
-
}
|
|
3860
|
-
return "structured";
|
|
3861
|
-
};
|
|
3862
4938
|
const getStructuredContent = (section) => {
|
|
3863
4939
|
var _a;
|
|
3864
4940
|
return JSON.stringify((_a = section.data) != null ? _a : {}, null, 2);
|
|
@@ -3950,10 +5026,10 @@ var ChatInput = React14.memo(({
|
|
|
3950
5026
|
className: `ai-chat-context-popover__progress-bar ${isOverLimit ? "ai-chat-context-popover__progress-bar--warning" : ""}`,
|
|
3951
5027
|
style: { width: `${Math.min(tokenPercentage, 100)}%` }
|
|
3952
5028
|
}
|
|
3953
|
-
))), /* @__PURE__ */ React14.createElement("div", { className: "ai-chat-context-popover__sections" }, contextSections.map((section) => /* @__PURE__ */ React14.createElement(
|
|
5029
|
+
))), /* @__PURE__ */ React14.createElement("div", { className: "ai-chat-context-popover__sections" }, contextSections.map((section, index) => /* @__PURE__ */ React14.createElement(
|
|
3954
5030
|
"div",
|
|
3955
5031
|
{
|
|
3956
|
-
key: section.id
|
|
5032
|
+
key: `${section.id}-${index}`,
|
|
3957
5033
|
className: `ai-chat-context-popover__section-item ${enableContextDetailView ? "ai-chat-context-popover__section-item--clickable" : ""}`,
|
|
3958
5034
|
onClick: () => {
|
|
3959
5035
|
if (enableContextDetailView) {
|
|
@@ -3964,7 +5040,6 @@ var ChatInput = React14.memo(({
|
|
|
3964
5040
|
},
|
|
3965
5041
|
/* @__PURE__ */ React14.createElement("span", { className: "ai-chat-context-popover__section-icon" }, "\u{1F4C4}"),
|
|
3966
5042
|
/* @__PURE__ */ React14.createElement("span", { className: "ai-chat-context-popover__section-title" }, section.title),
|
|
3967
|
-
/* @__PURE__ */ React14.createElement("span", { className: "ai-chat-context-popover__section-format" }, formatBadge(detectFormat(section))),
|
|
3968
5043
|
/* @__PURE__ */ React14.createElement("span", { className: "ai-chat-context-popover__section-tokens" }, estimateSectionTokens2(section))
|
|
3969
5044
|
))), enableContextDetailView && /* @__PURE__ */ React14.createElement(
|
|
3970
5045
|
"button",
|
|
@@ -4006,15 +5081,13 @@ var ChatInput = React14.memo(({
|
|
|
4006
5081
|
className: `ai-chat-context-popover__progress-bar ${isOverLimit ? "ai-chat-context-popover__progress-bar--warning" : ""}`,
|
|
4007
5082
|
style: { width: `${Math.min(tokenPercentage, 100)}%` }
|
|
4008
5083
|
}
|
|
4009
|
-
))), /* @__PURE__ */ React14.createElement("div", { className: "ai-chat-context-popover__detail-sections" }, contextSections.map((section) => {
|
|
5084
|
+
))), /* @__PURE__ */ React14.createElement("div", { className: "ai-chat-context-popover__detail-sections" }, contextSections.map((section, index) => {
|
|
4010
5085
|
const isRawSection = hasRawData2(section);
|
|
4011
|
-
const hasBothViews = isRawSection && hasStructuredData(section);
|
|
4012
|
-
const visibleMode = getVisibleDetailMode(section);
|
|
4013
5086
|
const isEnabled = !disabledSectionIds.has(section.id);
|
|
4014
5087
|
return /* @__PURE__ */ React14.createElement(
|
|
4015
5088
|
"details",
|
|
4016
5089
|
{
|
|
4017
|
-
key: section.id
|
|
5090
|
+
key: `${section.id}-${index}`,
|
|
4018
5091
|
className: `ai-chat-context-popover__detail-section ${!isEnabled ? "ai-chat-context-popover__detail-section--disabled" : ""}`,
|
|
4019
5092
|
open: expandedSectionId === section.id
|
|
4020
5093
|
},
|
|
@@ -4040,43 +5113,18 @@ var ChatInput = React14.memo(({
|
|
|
4040
5113
|
}
|
|
4041
5114
|
),
|
|
4042
5115
|
/* @__PURE__ */ React14.createElement("span", { className: "ai-chat-context-toggle__slider" })
|
|
4043
|
-
)), /* @__PURE__ */ React14.createElement("span", { className: "ai-chat-context-popover__detail-section-meta" }, /* @__PURE__ */ React14.createElement("code", null, `{{${section.id}}}`), /* @__PURE__ */ React14.createElement("span", null,
|
|
4044
|
-
|
|
4045
|
-
"button",
|
|
4046
|
-
{
|
|
4047
|
-
type: "button",
|
|
4048
|
-
className: `ai-chat-context-popover__detail-view-button ${visibleMode === "raw" ? "active" : ""}`,
|
|
4049
|
-
onClick: (e) => {
|
|
4050
|
-
e.preventDefault();
|
|
4051
|
-
e.stopPropagation();
|
|
4052
|
-
setDetailViewModeBySection((prev) => __spreadProps(__spreadValues({}, prev), { [section.id]: "raw" }));
|
|
4053
|
-
}
|
|
4054
|
-
},
|
|
4055
|
-
"Raw"
|
|
4056
|
-
), /* @__PURE__ */ React14.createElement(
|
|
4057
|
-
"button",
|
|
4058
|
-
{
|
|
4059
|
-
type: "button",
|
|
4060
|
-
className: `ai-chat-context-popover__detail-view-button ${visibleMode === "structured" ? "active" : ""}`,
|
|
4061
|
-
onClick: (e) => {
|
|
4062
|
-
e.preventDefault();
|
|
4063
|
-
e.stopPropagation();
|
|
4064
|
-
setDetailViewModeBySection((prev) => __spreadProps(__spreadValues({}, prev), { [section.id]: "structured" }));
|
|
4065
|
-
}
|
|
4066
|
-
},
|
|
4067
|
-
"Structured"
|
|
4068
|
-
)),
|
|
4069
|
-
/* @__PURE__ */ React14.createElement("pre", { className: "ai-chat-context-popover__detail-content" }, /* @__PURE__ */ React14.createElement("code", null, visibleMode === "raw" && isRawSection ? section.rawData : getStructuredContent(section)))
|
|
5116
|
+
)), /* @__PURE__ */ React14.createElement("span", { className: "ai-chat-context-popover__detail-section-meta" }, /* @__PURE__ */ React14.createElement("code", null, `{{${section.id}}}`), /* @__PURE__ */ React14.createElement("span", null, "~", estimateSectionTokens2(section)))),
|
|
5117
|
+
/* @__PURE__ */ React14.createElement("pre", { className: "ai-chat-context-popover__detail-content" }, /* @__PURE__ */ React14.createElement("code", null, isRawSection ? section.rawData : getStructuredContent(section)))
|
|
4070
5118
|
);
|
|
4071
5119
|
})))
|
|
4072
5120
|
)), /* @__PURE__ */ React14.createElement(
|
|
4073
5121
|
"button",
|
|
4074
5122
|
{
|
|
4075
|
-
className: `ai-chat-send-button ${
|
|
4076
|
-
onClick: () =>
|
|
4077
|
-
disabled:
|
|
5123
|
+
className: `ai-chat-send-button ${!isBusy && !inputValue.trim() ? "ai-chat-send-button--disabled" : ""} ${isBusy ? "ai-chat-send-button--stop" : ""}`,
|
|
5124
|
+
onClick: () => isBusy ? onStop() : handleSubmit(),
|
|
5125
|
+
disabled: !isBusy && !inputValue.trim()
|
|
4078
5126
|
},
|
|
4079
|
-
|
|
5127
|
+
isBusy ? /* @__PURE__ */ React14.createElement(StopIcon, null) : /* @__PURE__ */ React14.createElement(ArrowUpIcon, null)
|
|
4080
5128
|
)),
|
|
4081
5129
|
agentOptions.length > 0 && dropdownOpen && /* @__PURE__ */ React14.createElement("div", { className: "ai-chat-agent-selector__dropdown-inside" }, agentOptions.map((option) => /* @__PURE__ */ React14.createElement(
|
|
4082
5130
|
"button",
|
|
@@ -4133,7 +5181,11 @@ var AIChatPanel = ({
|
|
|
4133
5181
|
initialHistory = {},
|
|
4134
5182
|
hideRagContextInPrompt = true,
|
|
4135
5183
|
createConversationOnFirstChat = true,
|
|
5184
|
+
autoApproveTools = false,
|
|
4136
5185
|
mcpServers = [],
|
|
5186
|
+
resolveMcpAuthHeaders,
|
|
5187
|
+
localToolExecutors,
|
|
5188
|
+
traceContextMode = "standard",
|
|
4137
5189
|
progressiveActions = true,
|
|
4138
5190
|
agentOptions = [],
|
|
4139
5191
|
currentAgentId,
|
|
@@ -4146,6 +5198,7 @@ var AIChatPanel = ({
|
|
|
4146
5198
|
disabledSectionIds: propDisabledSectionIds,
|
|
4147
5199
|
onToggleSection: propOnToggleSection,
|
|
4148
5200
|
onConversationCreated,
|
|
5201
|
+
onBeforeSend,
|
|
4149
5202
|
// UI Customization Props
|
|
4150
5203
|
cssUrl,
|
|
4151
5204
|
markdownClass,
|
|
@@ -4181,6 +5234,8 @@ var AIChatPanel = ({
|
|
|
4181
5234
|
const [collapsedBlocks, setCollapsedBlocks] = useState7(/* @__PURE__ */ new Set());
|
|
4182
5235
|
const hasAutoCollapsedRef = useRef6(false);
|
|
4183
5236
|
const prevBlockCountRef = useRef6(0);
|
|
5237
|
+
const thinkingBlocksByKeyRef = useRef6({});
|
|
5238
|
+
const [thinkingBlocksByKey, setThinkingBlocksByKey] = useState7({});
|
|
4184
5239
|
const [newConversationConfirm, setNewConversationConfirm] = useState7(false);
|
|
4185
5240
|
const [justReset, setJustReset] = useState7(false);
|
|
4186
5241
|
const [copiedCallId, setCopiedCallId] = useState7(null);
|
|
@@ -4200,8 +5255,64 @@ var AIChatPanel = ({
|
|
|
4200
5255
|
const [pendingToolRequests, setPendingToolRequests] = useState7([]);
|
|
4201
5256
|
const [sessionApprovedTools, setSessionApprovedTools] = useState7([]);
|
|
4202
5257
|
const [alwaysApprovedTools, setAlwaysApprovedTools] = useState7([]);
|
|
5258
|
+
const [toolList, setToolList] = useState7([]);
|
|
5259
|
+
const [toolsLoading, setToolsLoading] = useState7(false);
|
|
5260
|
+
const [toolsFetchError, setToolsFetchError] = useState7(false);
|
|
5261
|
+
const [resolvedMcpServers, setResolvedMcpServers] = useState7(mcpServers || []);
|
|
5262
|
+
const [activeToolCalls, setActiveToolCalls] = useState7([]);
|
|
5263
|
+
const normalizeToolName = useCallback2((toolName) => {
|
|
5264
|
+
return String(toolName != null ? toolName : "").trim().toLowerCase();
|
|
5265
|
+
}, []);
|
|
5266
|
+
const getToolCallSignature = useCallback2(
|
|
5267
|
+
(toolName, callId) => {
|
|
5268
|
+
const normalizedToolName = normalizeToolName(toolName);
|
|
5269
|
+
const normalizedCallId = String(callId != null ? callId : "").trim();
|
|
5270
|
+
if (!normalizedToolName || !normalizedCallId) return "";
|
|
5271
|
+
return `${normalizedToolName}::${normalizedCallId}`;
|
|
5272
|
+
},
|
|
5273
|
+
[normalizeToolName]
|
|
5274
|
+
);
|
|
5275
|
+
const alwaysApprovedToolsStorageKey = useMemo2(() => {
|
|
5276
|
+
const customerId = (customer == null ? void 0 : customer.customer_id) || (customer == null ? void 0 : customer.id) || (customer == null ? void 0 : customer.customer_user_email) || "anonymous";
|
|
5277
|
+
const agentIdForScope = currentAgentId || agent || "default";
|
|
5278
|
+
return `llmasaservice-ui:always-approved-tools:${project_id}:${customerId}:${agentIdForScope}`;
|
|
5279
|
+
}, [project_id, customer, currentAgentId, agent]);
|
|
4203
5280
|
const [internalDisabledSectionIds, setInternalDisabledSectionIds] = useState7(/* @__PURE__ */ new Set());
|
|
4204
5281
|
const disabledSectionIds = propDisabledSectionIds != null ? propDisabledSectionIds : internalDisabledSectionIds;
|
|
5282
|
+
useEffect8(() => {
|
|
5283
|
+
if (typeof window === "undefined") return;
|
|
5284
|
+
try {
|
|
5285
|
+
const stored = window.localStorage.getItem(alwaysApprovedToolsStorageKey);
|
|
5286
|
+
if (!stored) return;
|
|
5287
|
+
const parsed = JSON.parse(stored);
|
|
5288
|
+
if (!Array.isArray(parsed)) return;
|
|
5289
|
+
const normalized = Array.from(
|
|
5290
|
+
new Set(
|
|
5291
|
+
parsed.map((value) => normalizeToolName(String(value))).filter((value) => value.length > 0)
|
|
5292
|
+
)
|
|
5293
|
+
);
|
|
5294
|
+
setAlwaysApprovedTools(normalized);
|
|
5295
|
+
} catch (error2) {
|
|
5296
|
+
console.warn("[AIChatPanel] Failed to load always-approved tools from localStorage:", error2);
|
|
5297
|
+
}
|
|
5298
|
+
}, [alwaysApprovedToolsStorageKey, normalizeToolName]);
|
|
5299
|
+
useEffect8(() => {
|
|
5300
|
+
if (typeof window === "undefined") return;
|
|
5301
|
+
try {
|
|
5302
|
+
if (alwaysApprovedTools.length === 0) {
|
|
5303
|
+
window.localStorage.removeItem(alwaysApprovedToolsStorageKey);
|
|
5304
|
+
return;
|
|
5305
|
+
}
|
|
5306
|
+
window.localStorage.setItem(
|
|
5307
|
+
alwaysApprovedToolsStorageKey,
|
|
5308
|
+
JSON.stringify(
|
|
5309
|
+
Array.from(new Set(alwaysApprovedTools.map((value) => normalizeToolName(value)).filter(Boolean)))
|
|
5310
|
+
)
|
|
5311
|
+
);
|
|
5312
|
+
} catch (error2) {
|
|
5313
|
+
console.warn("[AIChatPanel] Failed to persist always-approved tools to localStorage:", error2);
|
|
5314
|
+
}
|
|
5315
|
+
}, [alwaysApprovedToolsStorageKey, alwaysApprovedTools, normalizeToolName]);
|
|
4205
5316
|
useEffect8(() => {
|
|
4206
5317
|
setShowEmailPanel(customerEmailCaptureMode !== "HIDE");
|
|
4207
5318
|
if (customerEmailCaptureMode === "REQUIRED") {
|
|
@@ -4224,6 +5335,14 @@ var AIChatPanel = ({
|
|
|
4224
5335
|
const latestHistoryRef = useRef6(initialHistory);
|
|
4225
5336
|
const initialPromptSentRef = useRef6(false);
|
|
4226
5337
|
const lastFollowOnPromptRef = useRef6("");
|
|
5338
|
+
const handledToolCallSignaturesRef = useRef6(/* @__PURE__ */ new Set());
|
|
5339
|
+
const inFlightToolCallSignaturesRef = useRef6(/* @__PURE__ */ new Set());
|
|
5340
|
+
const toolContinuationCountRef = useRef6(0);
|
|
5341
|
+
const activeStreamAppendBaseRef = useRef6(null);
|
|
5342
|
+
const toolRequestProcessingRef = useRef6(false);
|
|
5343
|
+
const queuedToolRequestsRef = useRef6(null);
|
|
5344
|
+
const suppressAbortHistoryUpdateRef = useRef6(false);
|
|
5345
|
+
const toolReplaySummariesByKeyRef = useRef6({});
|
|
4227
5346
|
useEffect8(() => {
|
|
4228
5347
|
if (!initialHistory) return;
|
|
4229
5348
|
setHistory((prev) => {
|
|
@@ -4242,10 +5361,158 @@ var AIChatPanel = ({
|
|
|
4242
5361
|
return prev;
|
|
4243
5362
|
});
|
|
4244
5363
|
}, [initialHistory]);
|
|
4245
|
-
|
|
5364
|
+
useEffect8(() => {
|
|
5365
|
+
latestHistoryRef.current = history;
|
|
5366
|
+
}, [history]);
|
|
5367
|
+
useEffect8(() => {
|
|
5368
|
+
let cancelled = false;
|
|
5369
|
+
const resolveServers = () => __async(void 0, null, function* () {
|
|
5370
|
+
if (!mcpServers || mcpServers.length === 0) {
|
|
5371
|
+
if (!cancelled) {
|
|
5372
|
+
setResolvedMcpServers((prev) => prev.length === 0 ? prev : []);
|
|
5373
|
+
}
|
|
5374
|
+
return;
|
|
5375
|
+
}
|
|
5376
|
+
if (!resolveMcpAuthHeaders) {
|
|
5377
|
+
if (!cancelled) {
|
|
5378
|
+
setResolvedMcpServers((prev) => {
|
|
5379
|
+
const hasSameServers = prev.length === mcpServers.length && prev.every((server, index) => server === mcpServers[index]);
|
|
5380
|
+
return hasSameServers ? prev : mcpServers;
|
|
5381
|
+
});
|
|
5382
|
+
}
|
|
5383
|
+
return;
|
|
5384
|
+
}
|
|
5385
|
+
try {
|
|
5386
|
+
const enriched = yield Promise.all(
|
|
5387
|
+
mcpServers.map((server) => __async(void 0, null, function* () {
|
|
5388
|
+
const resolved = yield resolveMcpAuthHeaders({
|
|
5389
|
+
phase: "list",
|
|
5390
|
+
mcpServer: server || {},
|
|
5391
|
+
projectId: project_id,
|
|
5392
|
+
customer
|
|
5393
|
+
});
|
|
5394
|
+
return __spreadProps(__spreadValues({}, server || {}), {
|
|
5395
|
+
headers: __spreadValues(__spreadValues({}, typeof (server == null ? void 0 : server.headers) === "object" && (server == null ? void 0 : server.headers) ? server.headers : {}), normalizeMcpHeaders(
|
|
5396
|
+
resolved
|
|
5397
|
+
))
|
|
5398
|
+
});
|
|
5399
|
+
}))
|
|
5400
|
+
);
|
|
5401
|
+
if (!cancelled) setResolvedMcpServers(enriched);
|
|
5402
|
+
} catch (error2) {
|
|
5403
|
+
console.error("[AIChatPanel] Failed to resolve MCP auth headers:", error2);
|
|
5404
|
+
if (!cancelled) setResolvedMcpServers(mcpServers);
|
|
5405
|
+
}
|
|
5406
|
+
});
|
|
5407
|
+
void resolveServers();
|
|
5408
|
+
return () => {
|
|
5409
|
+
cancelled = true;
|
|
5410
|
+
};
|
|
5411
|
+
}, [mcpServers, resolveMcpAuthHeaders, project_id, customer]);
|
|
5412
|
+
const buildMcpRequestHeaders = useCallback2(
|
|
5413
|
+
(_0) => __async(void 0, [_0], function* ({
|
|
5414
|
+
phase,
|
|
5415
|
+
mcpServer,
|
|
5416
|
+
toolName,
|
|
5417
|
+
toolArgs
|
|
5418
|
+
}) {
|
|
5419
|
+
const merged = {};
|
|
5420
|
+
const packScopeIntoAccessToken = (headers) => {
|
|
5421
|
+
const accessToken = typeof headers["x-mcp-access-token"] === "string" ? headers["x-mcp-access-token"].trim() : "";
|
|
5422
|
+
const scopeToken = typeof headers["x-client-id"] === "string" ? headers["x-client-id"].trim() : "";
|
|
5423
|
+
if (!accessToken || !scopeToken) return headers;
|
|
5424
|
+
return __spreadProps(__spreadValues({}, headers), {
|
|
5425
|
+
"x-mcp-access-token": `${accessToken}::scope::${scopeToken}`
|
|
5426
|
+
});
|
|
5427
|
+
};
|
|
5428
|
+
const baseAccessToken = typeof mcpServer.accessToken === "string" ? mcpServer.accessToken.trim() : "";
|
|
5429
|
+
if (baseAccessToken) {
|
|
5430
|
+
merged["x-mcp-access-token"] = baseAccessToken;
|
|
5431
|
+
}
|
|
5432
|
+
if (project_id) {
|
|
5433
|
+
merged["x-project-id"] = project_id;
|
|
5434
|
+
}
|
|
5435
|
+
if (!resolveMcpAuthHeaders) return merged;
|
|
5436
|
+
try {
|
|
5437
|
+
const resolved = yield resolveMcpAuthHeaders({
|
|
5438
|
+
phase,
|
|
5439
|
+
mcpServer,
|
|
5440
|
+
projectId: project_id,
|
|
5441
|
+
customer,
|
|
5442
|
+
toolName,
|
|
5443
|
+
toolArgs
|
|
5444
|
+
});
|
|
5445
|
+
return packScopeIntoAccessToken(__spreadValues(__spreadValues({}, merged), normalizeMcpHeaders(
|
|
5446
|
+
resolved
|
|
5447
|
+
)));
|
|
5448
|
+
} catch (error2) {
|
|
5449
|
+
console.error(
|
|
5450
|
+
`Failed to resolve MCP auth headers for ${phase} request:`,
|
|
5451
|
+
error2
|
|
5452
|
+
);
|
|
5453
|
+
return merged;
|
|
5454
|
+
}
|
|
5455
|
+
}),
|
|
5456
|
+
[project_id, customer, resolveMcpAuthHeaders]
|
|
5457
|
+
);
|
|
5458
|
+
useEffect8(() => {
|
|
5459
|
+
const fetchAndSetTools = () => __async(void 0, null, function* () {
|
|
5460
|
+
if (!resolvedMcpServers || resolvedMcpServers.length === 0) {
|
|
5461
|
+
setToolList((prev) => prev.length === 0 ? prev : []);
|
|
5462
|
+
setToolsLoading((prev) => prev ? false : prev);
|
|
5463
|
+
setToolsFetchError((prev) => prev ? false : prev);
|
|
5464
|
+
return;
|
|
5465
|
+
}
|
|
5466
|
+
setToolsLoading(true);
|
|
5467
|
+
setToolsFetchError(false);
|
|
5468
|
+
try {
|
|
5469
|
+
const fetchPromises = (resolvedMcpServers != null ? resolvedMcpServers : []).map((m) => __async(void 0, null, function* () {
|
|
5470
|
+
const urlToFetch = `${publicAPIUrl}/tools/${encodeURIComponent(m.url)}`;
|
|
5471
|
+
const requestHeaders = yield buildMcpRequestHeaders({
|
|
5472
|
+
phase: "list",
|
|
5473
|
+
mcpServer: m
|
|
5474
|
+
});
|
|
5475
|
+
const response2 = yield fetch(urlToFetch, {
|
|
5476
|
+
headers: requestHeaders
|
|
5477
|
+
});
|
|
5478
|
+
if (!response2.ok) {
|
|
5479
|
+
const errorBody = yield response2.text();
|
|
5480
|
+
throw new Error(
|
|
5481
|
+
`HTTP ${response2.status}: ${response2.statusText} ${errorBody}`
|
|
5482
|
+
);
|
|
5483
|
+
}
|
|
5484
|
+
const toolsFromServer = yield response2.json();
|
|
5485
|
+
if (!Array.isArray(toolsFromServer)) return [];
|
|
5486
|
+
return toolsFromServer.map((tool) => __spreadProps(__spreadValues({}, tool), {
|
|
5487
|
+
url: m.url,
|
|
5488
|
+
accessToken: m.accessToken || "",
|
|
5489
|
+
headers: requestHeaders
|
|
5490
|
+
}));
|
|
5491
|
+
}));
|
|
5492
|
+
const results = yield Promise.all(fetchPromises);
|
|
5493
|
+
const allTools = results.flat();
|
|
5494
|
+
setToolList(allTools);
|
|
5495
|
+
setToolsFetchError(false);
|
|
5496
|
+
} catch (error2) {
|
|
5497
|
+
console.error("[AIChatPanel] Failed to load MCP tools:", error2);
|
|
5498
|
+
setToolList([]);
|
|
5499
|
+
setToolsFetchError(true);
|
|
5500
|
+
} finally {
|
|
5501
|
+
setToolsLoading(false);
|
|
5502
|
+
}
|
|
5503
|
+
});
|
|
5504
|
+
void fetchAndSetTools();
|
|
5505
|
+
}, [resolvedMcpServers, publicAPIUrl, buildMcpRequestHeaders]);
|
|
5506
|
+
const llmResult = useLLM2(__spreadProps(__spreadValues(__spreadValues(__spreadValues({
|
|
4246
5507
|
project_id,
|
|
4247
5508
|
customer
|
|
4248
|
-
}, url && { url }), service && { group_id: service }), agent && { agent }),
|
|
5509
|
+
}, url && { url }), service && { group_id: service }), agent && { agent }), {
|
|
5510
|
+
tools: toolList.map((item) => ({
|
|
5511
|
+
name: item.name,
|
|
5512
|
+
description: item.description,
|
|
5513
|
+
parameters: item.parameters
|
|
5514
|
+
}))
|
|
5515
|
+
}));
|
|
4249
5516
|
const {
|
|
4250
5517
|
send,
|
|
4251
5518
|
response,
|
|
@@ -4255,9 +5522,6 @@ var AIChatPanel = ({
|
|
|
4255
5522
|
setResponse,
|
|
4256
5523
|
error: llmError
|
|
4257
5524
|
} = llmResult;
|
|
4258
|
-
const toolList = llmResult.toolList || [];
|
|
4259
|
-
const toolsLoading = llmResult.toolsLoading || false;
|
|
4260
|
-
const toolsFetchError = llmResult.toolsFetchError || null;
|
|
4261
5525
|
const historyCallbackRef = useRef6(historyChangedCallback);
|
|
4262
5526
|
const responseCompleteCallbackRef = useRef6(responseCompleteCallback);
|
|
4263
5527
|
const responseRef = useRef6(response);
|
|
@@ -4298,18 +5562,26 @@ var AIChatPanel = ({
|
|
|
4298
5562
|
}
|
|
4299
5563
|
}, [propOnToggleSection]);
|
|
4300
5564
|
const ensureConversation = useCallback2(() => {
|
|
4301
|
-
|
|
5565
|
+
const normalizedConversationId = typeof currentConversation === "string" ? currentConversation.trim() : "";
|
|
4302
5566
|
console.log("ensureConversation - called with:", {
|
|
4303
|
-
currentConversation,
|
|
5567
|
+
currentConversation: normalizedConversationId || null,
|
|
4304
5568
|
createConversationOnFirstChat,
|
|
4305
5569
|
project_id,
|
|
4306
5570
|
publicAPIUrl
|
|
4307
5571
|
});
|
|
4308
|
-
if (
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
5572
|
+
if (normalizedConversationId) {
|
|
5573
|
+
console.log("ensureConversation - using existing conversation:", normalizedConversationId);
|
|
5574
|
+
return Promise.resolve(normalizedConversationId);
|
|
5575
|
+
}
|
|
5576
|
+
if (!createConversationOnFirstChat) {
|
|
5577
|
+
return Promise.resolve("");
|
|
5578
|
+
}
|
|
5579
|
+
if (!project_id) {
|
|
5580
|
+
console.error("ensureConversation - Cannot create conversation without project_id");
|
|
5581
|
+
return Promise.resolve("");
|
|
5582
|
+
}
|
|
5583
|
+
const createConversation = () => {
|
|
5584
|
+
var _a2, _b;
|
|
4313
5585
|
const requestBody = {
|
|
4314
5586
|
project_id,
|
|
4315
5587
|
agentId: agent,
|
|
@@ -4335,11 +5607,13 @@ var AIChatPanel = ({
|
|
|
4335
5607
|
}
|
|
4336
5608
|
return res.json();
|
|
4337
5609
|
})).then((newConvo) => {
|
|
5610
|
+
var _a3;
|
|
4338
5611
|
console.log("ensureConversation - API response:", newConvo);
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
5612
|
+
const createdId = typeof (newConvo == null ? void 0 : newConvo.id) === "string" && newConvo.id.trim() || typeof (newConvo == null ? void 0 : newConvo.conversationId) === "string" && newConvo.conversationId.trim() || typeof (newConvo == null ? void 0 : newConvo.conversation_id) === "string" && newConvo.conversation_id.trim() || typeof ((_a3 = newConvo == null ? void 0 : newConvo.conversation) == null ? void 0 : _a3.id) === "string" && newConvo.conversation.id.trim() || "";
|
|
5613
|
+
if (createdId) {
|
|
5614
|
+
console.log("ensureConversation - New conversation ID:", createdId);
|
|
5615
|
+
setCurrentConversation(createdId);
|
|
5616
|
+
return createdId;
|
|
4343
5617
|
}
|
|
4344
5618
|
console.warn("ensureConversation - No ID in response");
|
|
4345
5619
|
return "";
|
|
@@ -4347,9 +5621,8 @@ var AIChatPanel = ({
|
|
|
4347
5621
|
console.error("Error creating new conversation", error2);
|
|
4348
5622
|
return "";
|
|
4349
5623
|
});
|
|
4350
|
-
}
|
|
4351
|
-
|
|
4352
|
-
return Promise.resolve(currentConversation);
|
|
5624
|
+
};
|
|
5625
|
+
return createConversation();
|
|
4353
5626
|
}, [currentConversation, createConversationOnFirstChat, publicAPIUrl, project_id, agent, customer, browserInfo]);
|
|
4354
5627
|
const dataWithExtras = useCallback2(() => {
|
|
4355
5628
|
var _a2, _b, _c, _d, _e, _f, _g, _h;
|
|
@@ -4532,19 +5805,565 @@ var AIChatPanel = ({
|
|
|
4532
5805
|
}
|
|
4533
5806
|
return false;
|
|
4534
5807
|
}, [customerEmailCaptureMode, emailInputSet]);
|
|
4535
|
-
const
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
5808
|
+
const pendingToolRequestsRef = useRef6(pendingToolRequests);
|
|
5809
|
+
const streamIdleRef = useRef6(idle);
|
|
5810
|
+
streamIdleRef.current = idle;
|
|
5811
|
+
const waitForStreamIdle = useCallback2((timeoutMs = 2500) => __async(void 0, null, function* () {
|
|
5812
|
+
const startedAt = Date.now();
|
|
5813
|
+
while (!streamIdleRef.current && Date.now() - startedAt < timeoutMs) {
|
|
5814
|
+
yield new Promise((resolve) => {
|
|
5815
|
+
setTimeout(resolve, 25);
|
|
5816
|
+
});
|
|
4541
5817
|
}
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
const getUniqueToolNames = useCallback2(() => {
|
|
4546
|
-
return Array.from(new Set(pendingToolRequests.map((r) => r.toolName)));
|
|
5818
|
+
}), []);
|
|
5819
|
+
useEffect8(() => {
|
|
5820
|
+
pendingToolRequestsRef.current = pendingToolRequests;
|
|
4547
5821
|
}, [pendingToolRequests]);
|
|
5822
|
+
const processGivenToolRequests = useCallback2(
|
|
5823
|
+
(requests) => __async(void 0, null, function* () {
|
|
5824
|
+
var _a2, _b, _c;
|
|
5825
|
+
const dedupeToolRequests = (input) => {
|
|
5826
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5827
|
+
const deduped = [];
|
|
5828
|
+
for (const request of Array.isArray(input) ? input : []) {
|
|
5829
|
+
if (!request) continue;
|
|
5830
|
+
const signature = getToolCallSignature(request.toolName, request.callId) || request.match;
|
|
5831
|
+
if (!signature || seen.has(signature)) continue;
|
|
5832
|
+
seen.add(signature);
|
|
5833
|
+
deduped.push(request);
|
|
5834
|
+
}
|
|
5835
|
+
return deduped;
|
|
5836
|
+
};
|
|
5837
|
+
if (toolRequestProcessingRef.current) {
|
|
5838
|
+
const queued = dedupeToolRequests([
|
|
5839
|
+
...queuedToolRequestsRef.current || [],
|
|
5840
|
+
...Array.isArray(requests) ? requests : []
|
|
5841
|
+
]);
|
|
5842
|
+
if (queued.length > 0) {
|
|
5843
|
+
queuedToolRequestsRef.current = queued;
|
|
5844
|
+
}
|
|
5845
|
+
return;
|
|
5846
|
+
}
|
|
5847
|
+
toolRequestProcessingRef.current = true;
|
|
5848
|
+
try {
|
|
5849
|
+
let requestsToProcess = requests;
|
|
5850
|
+
if (!requestsToProcess || requestsToProcess.length === 0) {
|
|
5851
|
+
requestsToProcess = pendingToolRequestsRef.current || [];
|
|
5852
|
+
}
|
|
5853
|
+
if (!requestsToProcess || requestsToProcess.length === 0) return;
|
|
5854
|
+
setIsLoading(true);
|
|
5855
|
+
const userPrompt = lastPromptRef.current || lastKeyRef.current || "";
|
|
5856
|
+
const lastPromptKey = lastKeyRef.current;
|
|
5857
|
+
const assistantSeedText = lastPromptKey && ((_a2 = latestHistoryRef.current[lastPromptKey]) == null ? void 0 : _a2.content) ? (_b = latestHistoryRef.current[lastPromptKey]) == null ? void 0 : _b.content : "";
|
|
5858
|
+
const historyForContinuation = latestHistoryRef.current || {};
|
|
5859
|
+
const newMessages = [];
|
|
5860
|
+
Object.entries(historyForContinuation).forEach(([historyPrompt, historyEntry]) => {
|
|
5861
|
+
let promptForHistory = String(historyPrompt || "");
|
|
5862
|
+
const isoTimestampRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z:/;
|
|
5863
|
+
if (isoTimestampRegex.test(promptForHistory)) {
|
|
5864
|
+
const colonIndex = promptForHistory.indexOf(":", 19);
|
|
5865
|
+
promptForHistory = promptForHistory.substring(colonIndex + 1);
|
|
5866
|
+
} else if (/^\d+:/.test(promptForHistory)) {
|
|
5867
|
+
const colonIndex = promptForHistory.indexOf(":");
|
|
5868
|
+
promptForHistory = promptForHistory.substring(colonIndex + 1);
|
|
5869
|
+
}
|
|
5870
|
+
const typedHistoryEntry = historyEntry || { content: "", callId: "" };
|
|
5871
|
+
const assistantBaseContent = typeof typedHistoryEntry.content === "string" ? typedHistoryEntry.content : "";
|
|
5872
|
+
let assistantContextContent = assistantBaseContent;
|
|
5873
|
+
if (traceContextMode === "full") {
|
|
5874
|
+
const traceSummary = buildCompactTraceSummary({
|
|
5875
|
+
reasoningBlocks: thinkingBlocksByKeyRef.current[historyPrompt] || [],
|
|
5876
|
+
toolCalls: typedHistoryEntry.toolCalls,
|
|
5877
|
+
toolResponses: typedHistoryEntry.toolResponses
|
|
5878
|
+
});
|
|
5879
|
+
if (traceSummary) {
|
|
5880
|
+
assistantContextContent = assistantBaseContent ? `${assistantBaseContent}
|
|
5881
|
+
|
|
5882
|
+
${traceSummary}` : traceSummary;
|
|
5883
|
+
}
|
|
5884
|
+
}
|
|
5885
|
+
newMessages.push({
|
|
5886
|
+
role: "user",
|
|
5887
|
+
content: [
|
|
5888
|
+
{
|
|
5889
|
+
type: "text",
|
|
5890
|
+
text: promptForHistory
|
|
5891
|
+
}
|
|
5892
|
+
]
|
|
5893
|
+
});
|
|
5894
|
+
newMessages.push({
|
|
5895
|
+
role: "assistant",
|
|
5896
|
+
content: [
|
|
5897
|
+
{
|
|
5898
|
+
type: "text",
|
|
5899
|
+
text: assistantContextContent
|
|
5900
|
+
}
|
|
5901
|
+
]
|
|
5902
|
+
});
|
|
5903
|
+
});
|
|
5904
|
+
if (newMessages.length === 0 && userPrompt.trim().length > 0) {
|
|
5905
|
+
newMessages.push({
|
|
5906
|
+
role: "user",
|
|
5907
|
+
content: [
|
|
5908
|
+
{
|
|
5909
|
+
type: "text",
|
|
5910
|
+
text: userPrompt
|
|
5911
|
+
}
|
|
5912
|
+
]
|
|
5913
|
+
});
|
|
5914
|
+
if (assistantSeedText.trim().length > 0) {
|
|
5915
|
+
newMessages.push({
|
|
5916
|
+
role: "assistant",
|
|
5917
|
+
content: [
|
|
5918
|
+
{
|
|
5919
|
+
type: "text",
|
|
5920
|
+
text: assistantSeedText
|
|
5921
|
+
}
|
|
5922
|
+
]
|
|
5923
|
+
});
|
|
5924
|
+
}
|
|
5925
|
+
}
|
|
5926
|
+
const parsedToolCalls = yield Promise.all(
|
|
5927
|
+
requestsToProcess.map((req, index) => __async(void 0, null, function* () {
|
|
5928
|
+
var _a3, _b2, _c2, _d, _e, _f;
|
|
5929
|
+
let parsedToolCall = null;
|
|
5930
|
+
try {
|
|
5931
|
+
parsedToolCall = JSON.parse(req.match);
|
|
5932
|
+
} catch (error2) {
|
|
5933
|
+
console.error("[AIChatPanel] Failed to parse tool call payload:", error2);
|
|
5934
|
+
}
|
|
5935
|
+
const toolName = req.groups[1] || req.toolName || (typeof (parsedToolCall == null ? void 0 : parsedToolCall.name) === "string" ? parsedToolCall.name : "") || (typeof ((_a3 = parsedToolCall == null ? void 0 : parsedToolCall.function) == null ? void 0 : _a3.name) === "string" ? parsedToolCall.function.name : "");
|
|
5936
|
+
if (!toolName) return null;
|
|
5937
|
+
const rawCallId = req.callId || req.groups[0] || (parsedToolCall == null ? void 0 : parsedToolCall.id) || (parsedToolCall == null ? void 0 : parsedToolCall.tool_call_id) || `${toolName}-${index + 1}`;
|
|
5938
|
+
const callId = typeof rawCallId === "string" && rawCallId.trim().length > 0 && rawCallId !== "functionCall" ? rawCallId : `${toolName}-${index + 1}`;
|
|
5939
|
+
let args = {};
|
|
5940
|
+
const rawArgs = (_f = (_e = (_c2 = (_b2 = req.groups[2]) != null ? _b2 : parsedToolCall == null ? void 0 : parsedToolCall.input) != null ? _c2 : parsedToolCall == null ? void 0 : parsedToolCall.args) != null ? _e : (_d = parsedToolCall == null ? void 0 : parsedToolCall.function) == null ? void 0 : _d.arguments) != null ? _f : "{}";
|
|
5941
|
+
const parsedArgs = parseToolArguments(rawArgs);
|
|
5942
|
+
if (!parsedArgs) {
|
|
5943
|
+
console.error("[AIChatPanel] Failed to parse tool arguments", {
|
|
5944
|
+
toolName,
|
|
5945
|
+
callId,
|
|
5946
|
+
rawArgsPreview: typeof rawArgs === "string" ? rawArgs.slice(0, 500) : JSON.stringify(rawArgs).slice(0, 500)
|
|
5947
|
+
});
|
|
5948
|
+
return null;
|
|
5949
|
+
}
|
|
5950
|
+
args = parsedArgs;
|
|
5951
|
+
const serviceTag = typeof req.serviceTag === "string" && req.serviceTag || typeof req.groups[3] === "string" && req.groups[3] || typeof (parsedToolCall == null ? void 0 : parsedToolCall.service) === "string" && parsedToolCall.service || "";
|
|
5952
|
+
const callSignature = getToolCallSignature(toolName, callId);
|
|
5953
|
+
if (!callSignature) return null;
|
|
5954
|
+
return {
|
|
5955
|
+
req,
|
|
5956
|
+
toolName,
|
|
5957
|
+
callId,
|
|
5958
|
+
args,
|
|
5959
|
+
serviceTag,
|
|
5960
|
+
callSignature
|
|
5961
|
+
};
|
|
5962
|
+
}))
|
|
5963
|
+
);
|
|
5964
|
+
const toolCallBatch = parsedToolCalls.filter(Boolean);
|
|
5965
|
+
const seenCallSignatures = /* @__PURE__ */ new Set();
|
|
5966
|
+
const callsToRun = [];
|
|
5967
|
+
toolCallBatch.forEach((toolCall) => {
|
|
5968
|
+
if (seenCallSignatures.has(toolCall.callSignature)) return;
|
|
5969
|
+
seenCallSignatures.add(toolCall.callSignature);
|
|
5970
|
+
if (handledToolCallSignaturesRef.current.has(toolCall.callSignature)) return;
|
|
5971
|
+
if (inFlightToolCallSignaturesRef.current.has(toolCall.callSignature)) return;
|
|
5972
|
+
callsToRun.push(toolCall);
|
|
5973
|
+
});
|
|
5974
|
+
if (callsToRun.length === 0) {
|
|
5975
|
+
setPendingToolRequests(
|
|
5976
|
+
(prev) => prev.filter((request) => {
|
|
5977
|
+
const signature = getToolCallSignature(request.toolName, request.callId);
|
|
5978
|
+
if (!signature) return true;
|
|
5979
|
+
return !seenCallSignatures.has(signature);
|
|
5980
|
+
})
|
|
5981
|
+
);
|
|
5982
|
+
setActiveToolCalls([]);
|
|
5983
|
+
setIsLoading(false);
|
|
5984
|
+
return;
|
|
5985
|
+
}
|
|
5986
|
+
const callsToRunSignatures = new Set(callsToRun.map((toolCall) => toolCall.callSignature));
|
|
5987
|
+
setPendingToolRequests(
|
|
5988
|
+
(prev) => prev.filter((request) => {
|
|
5989
|
+
const signature = getToolCallSignature(request.toolName, request.callId);
|
|
5990
|
+
return !signature || !callsToRunSignatures.has(signature);
|
|
5991
|
+
})
|
|
5992
|
+
);
|
|
5993
|
+
callsToRun.forEach((toolCall) => {
|
|
5994
|
+
inFlightToolCallSignaturesRef.current.add(toolCall.callSignature);
|
|
5995
|
+
});
|
|
5996
|
+
setActiveToolCalls(
|
|
5997
|
+
callsToRun.map((toolCall) => ({
|
|
5998
|
+
toolName: toolCall.toolName,
|
|
5999
|
+
callId: toolCall.callId
|
|
6000
|
+
}))
|
|
6001
|
+
);
|
|
6002
|
+
const finalToolCalls = callsToRun.map((toolCall) => ({
|
|
6003
|
+
id: toolCall.callId,
|
|
6004
|
+
type: "tool_use",
|
|
6005
|
+
name: toolCall.toolName,
|
|
6006
|
+
input: toolCall.args,
|
|
6007
|
+
service: toolCall.serviceTag
|
|
6008
|
+
}));
|
|
6009
|
+
let finalToolResponses = [];
|
|
6010
|
+
try {
|
|
6011
|
+
const toolResponses = yield Promise.all(
|
|
6012
|
+
callsToRun.map((toolCall) => __async(void 0, null, function* () {
|
|
6013
|
+
var _a3, _b2, _c2, _d, _e, _f, _g;
|
|
6014
|
+
const mcpTool = toolList.find((tool) => tool.name === toolCall.toolName) || null;
|
|
6015
|
+
const localExecutor = localToolExecutors && typeof localToolExecutors[toolCall.toolName] === "function" ? localToolExecutors[toolCall.toolName] : null;
|
|
6016
|
+
if (localExecutor) {
|
|
6017
|
+
try {
|
|
6018
|
+
const localResult = yield localExecutor(toolCall.args, {
|
|
6019
|
+
toolName: toolCall.toolName,
|
|
6020
|
+
callId: toolCall.callId,
|
|
6021
|
+
serviceTag: toolCall.serviceTag,
|
|
6022
|
+
mcpTool
|
|
6023
|
+
});
|
|
6024
|
+
if (localResult && typeof localResult === "object" && !Array.isArray(localResult)) {
|
|
6025
|
+
const objectResult = localResult;
|
|
6026
|
+
const isError = objectResult.isError === true || objectResult.error === true;
|
|
6027
|
+
const maybeResult = Object.prototype.hasOwnProperty.call(objectResult, "result") ? objectResult.result : localResult;
|
|
6028
|
+
const textResult = typeof maybeResult === "string" ? maybeResult : JSON.stringify(maybeResult != null ? maybeResult : {});
|
|
6029
|
+
return {
|
|
6030
|
+
tool_call_id: toolCall.callId,
|
|
6031
|
+
tool_name: toolCall.toolName,
|
|
6032
|
+
result: textResult || "",
|
|
6033
|
+
isError
|
|
6034
|
+
};
|
|
6035
|
+
}
|
|
6036
|
+
return {
|
|
6037
|
+
tool_call_id: toolCall.callId,
|
|
6038
|
+
tool_name: toolCall.toolName,
|
|
6039
|
+
result: typeof localResult === "string" ? localResult : JSON.stringify(localResult != null ? localResult : {}),
|
|
6040
|
+
isError: false
|
|
6041
|
+
};
|
|
6042
|
+
} catch (error2) {
|
|
6043
|
+
return {
|
|
6044
|
+
tool_call_id: toolCall.callId,
|
|
6045
|
+
tool_name: toolCall.toolName,
|
|
6046
|
+
result: error2 instanceof Error ? error2.message : `Unhandled error calling ${toolCall.toolName}`,
|
|
6047
|
+
isError: true
|
|
6048
|
+
};
|
|
6049
|
+
}
|
|
6050
|
+
}
|
|
6051
|
+
if (!mcpTool) {
|
|
6052
|
+
console.error(`[AIChatPanel] Tool ${toolCall.toolName} not found in tool list`);
|
|
6053
|
+
return {
|
|
6054
|
+
tool_call_id: toolCall.callId,
|
|
6055
|
+
tool_name: toolCall.toolName,
|
|
6056
|
+
result: `Tool ${toolCall.toolName} not found in current tool list.`,
|
|
6057
|
+
isError: true
|
|
6058
|
+
};
|
|
6059
|
+
}
|
|
6060
|
+
const toolUrl = typeof mcpTool.url === "string" ? mcpTool.url : "";
|
|
6061
|
+
if (!toolUrl) {
|
|
6062
|
+
return {
|
|
6063
|
+
tool_call_id: toolCall.callId,
|
|
6064
|
+
tool_name: toolCall.toolName,
|
|
6065
|
+
result: `Tool ${toolCall.toolName} is missing url metadata.`,
|
|
6066
|
+
isError: true
|
|
6067
|
+
};
|
|
6068
|
+
}
|
|
6069
|
+
const body = {
|
|
6070
|
+
tool: toolCall.toolName,
|
|
6071
|
+
args: toolCall.args
|
|
6072
|
+
};
|
|
6073
|
+
try {
|
|
6074
|
+
const result = yield fetch(
|
|
6075
|
+
`${publicAPIUrl}/tools/${encodeURIComponent(toolUrl)}`,
|
|
6076
|
+
{
|
|
6077
|
+
method: "POST",
|
|
6078
|
+
headers: __spreadValues({
|
|
6079
|
+
"Content-Type": "application/json"
|
|
6080
|
+
}, yield buildMcpRequestHeaders({
|
|
6081
|
+
phase: "call",
|
|
6082
|
+
mcpServer: mcpTool,
|
|
6083
|
+
toolName: toolCall.toolName,
|
|
6084
|
+
toolArgs: toolCall.args
|
|
6085
|
+
})),
|
|
6086
|
+
body: JSON.stringify(body)
|
|
6087
|
+
}
|
|
6088
|
+
);
|
|
6089
|
+
if (!result.ok) {
|
|
6090
|
+
const errorBody = yield result.text();
|
|
6091
|
+
console.error(
|
|
6092
|
+
`[AIChatPanel] Tool call failed ${toolCall.toolName}: ${result.status} ${result.statusText} ${errorBody}`
|
|
6093
|
+
);
|
|
6094
|
+
return {
|
|
6095
|
+
tool_call_id: toolCall.callId,
|
|
6096
|
+
tool_name: toolCall.toolName,
|
|
6097
|
+
result: `HTTP ${result.status} ${result.statusText}: ${errorBody || "Tool call failed"}`,
|
|
6098
|
+
isError: true
|
|
6099
|
+
};
|
|
6100
|
+
}
|
|
6101
|
+
let resultData = null;
|
|
6102
|
+
try {
|
|
6103
|
+
resultData = yield result.json();
|
|
6104
|
+
} catch (error2) {
|
|
6105
|
+
console.error("[AIChatPanel] Failed parsing tool call JSON response:", error2);
|
|
6106
|
+
return {
|
|
6107
|
+
tool_call_id: toolCall.callId,
|
|
6108
|
+
tool_name: toolCall.toolName,
|
|
6109
|
+
result: "Tool returned a non-JSON response.",
|
|
6110
|
+
isError: true
|
|
6111
|
+
};
|
|
6112
|
+
}
|
|
6113
|
+
const textResult = (_c2 = (_b2 = (_a3 = resultData == null ? void 0 : resultData.content) == null ? void 0 : _a3[0]) == null ? void 0 : _b2.text) != null ? _c2 : (resultData == null ? void 0 : resultData.result) ? JSON.stringify(resultData.result) : JSON.stringify(resultData);
|
|
6114
|
+
const inferredError = (resultData == null ? void 0 : resultData.isError) === true || (resultData == null ? void 0 : resultData.error) === true || typeof (resultData == null ? void 0 : resultData.error) === "string" || (resultData == null ? void 0 : resultData.status) === "error" || ((_d = resultData == null ? void 0 : resultData.result) == null ? void 0 : _d.isError) === true || ((_e = resultData == null ? void 0 : resultData.result) == null ? void 0 : _e.error) === true || typeof ((_f = resultData == null ? void 0 : resultData.result) == null ? void 0 : _f.error) === "string";
|
|
6115
|
+
const normalizedResultText = typeof textResult === "string" && textResult.trim().length > 0 ? textResult : inferredError && typeof (resultData == null ? void 0 : resultData.error) === "string" ? resultData.error : inferredError && typeof ((_g = resultData == null ? void 0 : resultData.result) == null ? void 0 : _g.error) === "string" ? resultData.result.error : "";
|
|
6116
|
+
return {
|
|
6117
|
+
tool_call_id: toolCall.callId,
|
|
6118
|
+
tool_name: toolCall.toolName,
|
|
6119
|
+
result: normalizedResultText,
|
|
6120
|
+
isError: inferredError
|
|
6121
|
+
};
|
|
6122
|
+
} catch (error2) {
|
|
6123
|
+
console.error(`[AIChatPanel] Error calling tool ${toolCall.toolName}:`, error2);
|
|
6124
|
+
return {
|
|
6125
|
+
tool_call_id: toolCall.callId,
|
|
6126
|
+
tool_name: toolCall.toolName,
|
|
6127
|
+
result: error2 instanceof Error ? error2.message : `Unhandled error calling ${toolCall.toolName}`,
|
|
6128
|
+
isError: true
|
|
6129
|
+
};
|
|
6130
|
+
}
|
|
6131
|
+
}))
|
|
6132
|
+
);
|
|
6133
|
+
finalToolResponses = toolResponses.filter(Boolean);
|
|
6134
|
+
} finally {
|
|
6135
|
+
callsToRun.forEach((toolCall) => {
|
|
6136
|
+
inFlightToolCallSignaturesRef.current.delete(toolCall.callSignature);
|
|
6137
|
+
handledToolCallSignaturesRef.current.add(toolCall.callSignature);
|
|
6138
|
+
});
|
|
6139
|
+
}
|
|
6140
|
+
setActiveToolCalls([]);
|
|
6141
|
+
const currentLastKey = lastKeyRef.current;
|
|
6142
|
+
if (currentLastKey) {
|
|
6143
|
+
setHistory((prev) => {
|
|
6144
|
+
const existingEntry = prev[currentLastKey] || { content: "", callId: "" };
|
|
6145
|
+
return __spreadProps(__spreadValues({}, prev), {
|
|
6146
|
+
[currentLastKey]: __spreadProps(__spreadValues({}, existingEntry), {
|
|
6147
|
+
toolCalls: [...existingEntry.toolCalls || [], ...finalToolCalls],
|
|
6148
|
+
toolResponses: [...existingEntry.toolResponses || [], ...finalToolResponses]
|
|
6149
|
+
})
|
|
6150
|
+
});
|
|
6151
|
+
});
|
|
6152
|
+
}
|
|
6153
|
+
const toReplayText = (value) => {
|
|
6154
|
+
const raw = typeof value === "string" ? value : (() => {
|
|
6155
|
+
try {
|
|
6156
|
+
return JSON.stringify(value);
|
|
6157
|
+
} catch (_error) {
|
|
6158
|
+
return String(value != null ? value : "");
|
|
6159
|
+
}
|
|
6160
|
+
})();
|
|
6161
|
+
return String(raw != null ? raw : "");
|
|
6162
|
+
};
|
|
6163
|
+
const replayEntryKey = lastKeyRef.current || "";
|
|
6164
|
+
const previousReplayEntries = replayEntryKey ? toolReplaySummariesByKeyRef.current[replayEntryKey] || [] : [];
|
|
6165
|
+
const currentReplayEntries = callsToRun.map((toolCall, index) => {
|
|
6166
|
+
var _a3;
|
|
6167
|
+
const matchedResponse = finalToolResponses.find((response2) => (response2 == null ? void 0 : response2.tool_call_id) === toolCall.callId) || finalToolResponses[index];
|
|
6168
|
+
return {
|
|
6169
|
+
toolName: toolCall.toolName,
|
|
6170
|
+
callId: toolCall.callId,
|
|
6171
|
+
status: (matchedResponse == null ? void 0 : matchedResponse.isError) ? "error" : "ok",
|
|
6172
|
+
argsText: toReplayText(toolCall.args),
|
|
6173
|
+
resultText: toReplayText((_a3 = matchedResponse == null ? void 0 : matchedResponse.result) != null ? _a3 : "No result returned")
|
|
6174
|
+
};
|
|
6175
|
+
});
|
|
6176
|
+
const replayEntries = [...previousReplayEntries, ...currentReplayEntries];
|
|
6177
|
+
if (replayEntryKey) {
|
|
6178
|
+
toolReplaySummariesByKeyRef.current[replayEntryKey] = replayEntries;
|
|
6179
|
+
}
|
|
6180
|
+
const replayLines = replayEntries.map(
|
|
6181
|
+
(entry) => [
|
|
6182
|
+
`Tool: ${entry.toolName}`,
|
|
6183
|
+
`Call ID: ${entry.callId}`,
|
|
6184
|
+
`Status: ${entry.status}`,
|
|
6185
|
+
`Args: ${entry.argsText}`,
|
|
6186
|
+
`Result: ${entry.resultText}`
|
|
6187
|
+
].join("\n")
|
|
6188
|
+
);
|
|
6189
|
+
const originalRequest = typeof lastPromptRef.current === "string" && lastPromptRef.current.trim() || typeof userPrompt === "string" && userPrompt.trim() || "";
|
|
6190
|
+
const continuationPromptText = [
|
|
6191
|
+
originalRequest ? `Original request: ${originalRequest}` : "",
|
|
6192
|
+
"Tool execution summary for the previous request:",
|
|
6193
|
+
...replayLines,
|
|
6194
|
+
"Continue the same assistant response from exactly where you paused using these tool results.",
|
|
6195
|
+
"Treat successful mutating tool results above as already completed actions. Do not repeat those same mutating tool calls unless the user explicitly asks to retry.",
|
|
6196
|
+
"If you include meta tags, use only <thinking>, <reasoning>, <searching> for internal process.",
|
|
6197
|
+
"Put the final user-facing answer outside all meta tags."
|
|
6198
|
+
].filter(Boolean).join("\n\n");
|
|
6199
|
+
if (continuationPromptText.length > MAX_TOOL_REPLAY_PAYLOAD_CHARS) {
|
|
6200
|
+
setActiveToolCalls([]);
|
|
6201
|
+
setIsLoading(false);
|
|
6202
|
+
setError({
|
|
6203
|
+
message: "Tool result payload is too large to continue safely in a single turn. Narrow the query or fetch steps in chunks.",
|
|
6204
|
+
code: "TOOL_REPLAY_TOO_LARGE"
|
|
6205
|
+
});
|
|
6206
|
+
return;
|
|
6207
|
+
}
|
|
6208
|
+
newMessages.push({
|
|
6209
|
+
role: "user",
|
|
6210
|
+
content: [
|
|
6211
|
+
{
|
|
6212
|
+
type: "text",
|
|
6213
|
+
text: continuationPromptText
|
|
6214
|
+
}
|
|
6215
|
+
]
|
|
6216
|
+
});
|
|
6217
|
+
if (toolContinuationCountRef.current >= MAX_TOOL_CONTINUATIONS_PER_TURN) {
|
|
6218
|
+
setActiveToolCalls([]);
|
|
6219
|
+
setIsLoading(false);
|
|
6220
|
+
setError({
|
|
6221
|
+
message: "Tool continuation limit reached for this response. Please refine the prompt and retry.",
|
|
6222
|
+
code: "TOOL_CONTINUATION_LIMIT"
|
|
6223
|
+
});
|
|
6224
|
+
return;
|
|
6225
|
+
}
|
|
6226
|
+
toolContinuationCountRef.current += 1;
|
|
6227
|
+
if (!streamIdleRef.current) {
|
|
6228
|
+
yield waitForStreamIdle(1e4);
|
|
6229
|
+
}
|
|
6230
|
+
if (!streamIdleRef.current) {
|
|
6231
|
+
suppressAbortHistoryUpdateRef.current = true;
|
|
6232
|
+
try {
|
|
6233
|
+
stop(lastController);
|
|
6234
|
+
yield waitForStreamIdle(3e3);
|
|
6235
|
+
} finally {
|
|
6236
|
+
suppressAbortHistoryUpdateRef.current = false;
|
|
6237
|
+
}
|
|
6238
|
+
}
|
|
6239
|
+
if (!streamIdleRef.current) {
|
|
6240
|
+
setActiveToolCalls([]);
|
|
6241
|
+
setIsLoading(false);
|
|
6242
|
+
setError({
|
|
6243
|
+
message: "Timed out waiting for the previous stream to settle before tool continuation.",
|
|
6244
|
+
code: "TOOL_CONTINUATION_WAIT_TIMEOUT"
|
|
6245
|
+
});
|
|
6246
|
+
return;
|
|
6247
|
+
}
|
|
6248
|
+
const newController = new AbortController();
|
|
6249
|
+
setLastController(newController);
|
|
6250
|
+
const continuationKey = lastKeyRef.current;
|
|
6251
|
+
if (continuationKey) {
|
|
6252
|
+
const continuationBase = ((_c = latestHistoryRef.current[continuationKey]) == null ? void 0 : _c.content) || "";
|
|
6253
|
+
activeStreamAppendBaseRef.current = continuationBase.trim().length > 0 ? { key: continuationKey, base: continuationBase } : null;
|
|
6254
|
+
} else {
|
|
6255
|
+
activeStreamAppendBaseRef.current = null;
|
|
6256
|
+
}
|
|
6257
|
+
send(
|
|
6258
|
+
"",
|
|
6259
|
+
newMessages,
|
|
6260
|
+
[
|
|
6261
|
+
...dataWithExtras(),
|
|
6262
|
+
{
|
|
6263
|
+
key: "--messages",
|
|
6264
|
+
data: newMessages.length.toString()
|
|
6265
|
+
}
|
|
6266
|
+
],
|
|
6267
|
+
true,
|
|
6268
|
+
true,
|
|
6269
|
+
service,
|
|
6270
|
+
currentConversation,
|
|
6271
|
+
newController,
|
|
6272
|
+
void 0,
|
|
6273
|
+
(errorMsg) => {
|
|
6274
|
+
setActiveToolCalls([]);
|
|
6275
|
+
setIsLoading(false);
|
|
6276
|
+
setError({
|
|
6277
|
+
message: errorMsg,
|
|
6278
|
+
code: "TOOL_ERROR"
|
|
6279
|
+
});
|
|
6280
|
+
}
|
|
6281
|
+
);
|
|
6282
|
+
} finally {
|
|
6283
|
+
toolRequestProcessingRef.current = false;
|
|
6284
|
+
const queued = queuedToolRequestsRef.current;
|
|
6285
|
+
if (queued && queued.length > 0) {
|
|
6286
|
+
queuedToolRequestsRef.current = null;
|
|
6287
|
+
queueMicrotask(() => {
|
|
6288
|
+
void processGivenToolRequests(queued);
|
|
6289
|
+
});
|
|
6290
|
+
}
|
|
6291
|
+
}
|
|
6292
|
+
}),
|
|
6293
|
+
[
|
|
6294
|
+
toolList,
|
|
6295
|
+
localToolExecutors,
|
|
6296
|
+
publicAPIUrl,
|
|
6297
|
+
buildMcpRequestHeaders,
|
|
6298
|
+
dataWithExtras,
|
|
6299
|
+
send,
|
|
6300
|
+
service,
|
|
6301
|
+
currentConversation,
|
|
6302
|
+
setActiveToolCalls,
|
|
6303
|
+
getToolCallSignature,
|
|
6304
|
+
traceContextMode,
|
|
6305
|
+
idle,
|
|
6306
|
+
stop,
|
|
6307
|
+
lastController,
|
|
6308
|
+
waitForStreamIdle
|
|
6309
|
+
]
|
|
6310
|
+
);
|
|
6311
|
+
const handleToolApproval = useCallback2(
|
|
6312
|
+
(toolName, scope) => {
|
|
6313
|
+
const normalizedToolName = normalizeToolName(toolName);
|
|
6314
|
+
if (!normalizedToolName) return;
|
|
6315
|
+
if (scope === "session" || scope === "always") {
|
|
6316
|
+
setSessionApprovedTools((prev) => Array.from(/* @__PURE__ */ new Set([...prev, normalizedToolName])));
|
|
6317
|
+
}
|
|
6318
|
+
if (scope === "always") {
|
|
6319
|
+
setAlwaysApprovedTools((prev) => Array.from(/* @__PURE__ */ new Set([...prev, normalizedToolName])));
|
|
6320
|
+
}
|
|
6321
|
+
const requestsToRun = (pendingToolRequestsRef.current || []).filter(
|
|
6322
|
+
(r) => normalizeToolName(r.toolName) === normalizedToolName
|
|
6323
|
+
);
|
|
6324
|
+
void processGivenToolRequests(requestsToRun);
|
|
6325
|
+
setPendingToolRequests(
|
|
6326
|
+
(prev) => prev.filter((r) => normalizeToolName(r.toolName) !== normalizedToolName)
|
|
6327
|
+
);
|
|
6328
|
+
},
|
|
6329
|
+
[processGivenToolRequests, normalizeToolName]
|
|
6330
|
+
);
|
|
6331
|
+
useEffect8(() => {
|
|
6332
|
+
if (pendingToolRequests.length === 0) return;
|
|
6333
|
+
const configuredAutoApproveTools = Array.isArray(autoApproveTools) ? new Set(
|
|
6334
|
+
autoApproveTools.map((toolName) => normalizeToolName(String(toolName))).filter(Boolean)
|
|
6335
|
+
) : null;
|
|
6336
|
+
const toAuto = pendingToolRequests.filter(
|
|
6337
|
+
(r) => {
|
|
6338
|
+
const normalized = normalizeToolName(r.toolName);
|
|
6339
|
+
if (!normalized) return false;
|
|
6340
|
+
if (autoApproveTools === true) return true;
|
|
6341
|
+
if (configuredAutoApproveTools == null ? void 0 : configuredAutoApproveTools.has(normalized)) return true;
|
|
6342
|
+
return sessionApprovedTools.includes(normalized) || alwaysApprovedTools.includes(normalized);
|
|
6343
|
+
}
|
|
6344
|
+
);
|
|
6345
|
+
if (toAuto.length > 0) {
|
|
6346
|
+
void processGivenToolRequests(toAuto);
|
|
6347
|
+
setPendingToolRequests(
|
|
6348
|
+
(prev) => prev.filter(
|
|
6349
|
+
(r) => {
|
|
6350
|
+
const normalized = normalizeToolName(r.toolName);
|
|
6351
|
+
if (!normalized) return true;
|
|
6352
|
+
if (autoApproveTools === true) return false;
|
|
6353
|
+
if (configuredAutoApproveTools == null ? void 0 : configuredAutoApproveTools.has(normalized)) return false;
|
|
6354
|
+
return !sessionApprovedTools.includes(normalized) && !alwaysApprovedTools.includes(normalized);
|
|
6355
|
+
}
|
|
6356
|
+
)
|
|
6357
|
+
);
|
|
6358
|
+
}
|
|
6359
|
+
}, [
|
|
6360
|
+
autoApproveTools,
|
|
6361
|
+
pendingToolRequests,
|
|
6362
|
+
sessionApprovedTools,
|
|
6363
|
+
alwaysApprovedTools,
|
|
6364
|
+
processGivenToolRequests,
|
|
6365
|
+
normalizeToolName
|
|
6366
|
+
]);
|
|
4548
6367
|
const cleanContentForDisplay = useCallback2((content) => {
|
|
4549
6368
|
let cleaned = content.replace(/\*\*(.*?)\*\*/g, "$1").replace(/\*(.*?)\*/g, "$1").replace(/\n+/g, " ").replace(/\s+/g, " ").trim();
|
|
4550
6369
|
if (cleaned.length > 100) {
|
|
@@ -4553,7 +6372,6 @@ var AIChatPanel = ({
|
|
|
4553
6372
|
return cleaned || "Thinking";
|
|
4554
6373
|
}, []);
|
|
4555
6374
|
const processThinkingTags = useCallback2((text) => {
|
|
4556
|
-
var _a2, _b, _c;
|
|
4557
6375
|
if (!text) {
|
|
4558
6376
|
return {
|
|
4559
6377
|
cleanedText: "",
|
|
@@ -4563,30 +6381,28 @@ var AIChatPanel = ({
|
|
|
4563
6381
|
};
|
|
4564
6382
|
}
|
|
4565
6383
|
const processedText = text.replace(/\u200B/g, "");
|
|
4566
|
-
const
|
|
4567
|
-
const
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
allMatches.push({ content, index: match.index, type: "searching" });
|
|
6384
|
+
const completedBlocks = [];
|
|
6385
|
+
const textWithCompleteMarkers = processedText.replace(
|
|
6386
|
+
/<(thinking|reasoning|searching)>([\s\S]*?)<\/\1>/gi,
|
|
6387
|
+
(_fullMatch, rawType, rawContent, offset) => {
|
|
6388
|
+
const normalizedType = String(rawType || "").trim().toLowerCase();
|
|
6389
|
+
const type = normalizedType === "reasoning" ? "reasoning" : normalizedType === "searching" ? "searching" : "thinking";
|
|
6390
|
+
const content = String(rawContent || "").trim();
|
|
6391
|
+
if (!content) return "\n\n";
|
|
6392
|
+
const signature = getThinkingBlockSignature(type, content);
|
|
6393
|
+
completedBlocks.push({
|
|
6394
|
+
type,
|
|
6395
|
+
content,
|
|
6396
|
+
index: Number(offset || 0),
|
|
6397
|
+
signature
|
|
6398
|
+
});
|
|
6399
|
+
return `
|
|
6400
|
+
|
|
6401
|
+
${buildThinkingBlockMarker(type, signature)}
|
|
6402
|
+
|
|
6403
|
+
`;
|
|
4587
6404
|
}
|
|
4588
|
-
|
|
4589
|
-
const completedBlocks = allMatches.sort((a, b) => a.index - b.index);
|
|
6405
|
+
);
|
|
4590
6406
|
let activeBlock = null;
|
|
4591
6407
|
const tagTypes = ["thinking", "reasoning", "searching"];
|
|
4592
6408
|
let latestIncompletePos = -1;
|
|
@@ -4616,7 +6432,7 @@ var AIChatPanel = ({
|
|
|
4616
6432
|
}
|
|
4617
6433
|
}
|
|
4618
6434
|
}
|
|
4619
|
-
let cleanedText =
|
|
6435
|
+
let cleanedText = textWithCompleteMarkers.replace(/<think(?:i(?:n(?:g)?)?)?$/i, "").replace(/<reas(?:o(?:n(?:i(?:n(?:g)?)?)?)?)?$/i, "").replace(/<sear(?:c(?:h(?:i(?:n(?:g)?)?)?)?)?$/i, "").replace(/<thinking>[\s\S]*$/i, "").replace(/<reasoning>[\s\S]*$/i, "").replace(/<searching>[\s\S]*$/i, "").trim();
|
|
4620
6436
|
let lastThinkingContent = "Thinking";
|
|
4621
6437
|
if (completedBlocks.length > 0) {
|
|
4622
6438
|
const lastBlock = completedBlocks[completedBlocks.length - 1];
|
|
@@ -4628,15 +6444,67 @@ var AIChatPanel = ({
|
|
|
4628
6444
|
}
|
|
4629
6445
|
return { cleanedText, completedBlocks, activeBlock, lastThinkingContent };
|
|
4630
6446
|
}, [cleanContentForDisplay]);
|
|
6447
|
+
const mergeThinkingBlocks = useCallback2(
|
|
6448
|
+
(existing, incoming) => {
|
|
6449
|
+
if (incoming.length === 0) return existing;
|
|
6450
|
+
if (existing.length === 0) return incoming;
|
|
6451
|
+
const incomingSupersetPrefix = incoming.length >= existing.length && existing.every((block, index) => {
|
|
6452
|
+
const next = incoming[index];
|
|
6453
|
+
return !!next && next.type === block.type && next.content === block.content;
|
|
6454
|
+
});
|
|
6455
|
+
if (incomingSupersetPrefix) {
|
|
6456
|
+
return incoming;
|
|
6457
|
+
}
|
|
6458
|
+
const merged = [...existing];
|
|
6459
|
+
const seen = new Set(existing.map((block) => block.signature || `${block.type}::${block.content}`));
|
|
6460
|
+
for (const block of incoming) {
|
|
6461
|
+
const signature = block.signature || `${block.type}::${block.content}`;
|
|
6462
|
+
if (seen.has(signature)) continue;
|
|
6463
|
+
seen.add(signature);
|
|
6464
|
+
merged.push(block);
|
|
6465
|
+
}
|
|
6466
|
+
return merged;
|
|
6467
|
+
},
|
|
6468
|
+
[]
|
|
6469
|
+
);
|
|
6470
|
+
const getThinkingBlockCollapseKey = useCallback2((entryKey, blockKey) => {
|
|
6471
|
+
return `${entryKey}::${blockKey}`;
|
|
6472
|
+
}, []);
|
|
6473
|
+
const getThinkingBlockRenderKey = useCallback2((block, fallbackIndex) => {
|
|
6474
|
+
return String((block == null ? void 0 : block.signature) || "").trim() || `block-${fallbackIndex}`;
|
|
6475
|
+
}, []);
|
|
6476
|
+
const AGENT_SUGGESTION_ACTION = {
|
|
6477
|
+
pattern: "\\[SUGGEST_AGENT:([^|\\]]+)\\|([^|\\]]+)\\|([^\\]]+)\\]",
|
|
6478
|
+
markdown: '<agent-suggestion data-agent-id="$1" data-agent-name="$2" data-reason="$3"></agent-suggestion>'
|
|
6479
|
+
};
|
|
6480
|
+
const extractToolRequests = useCallback2((rawResponse) => {
|
|
6481
|
+
return extractToolRequestMatchesFromText(rawResponse);
|
|
6482
|
+
}, []);
|
|
6483
|
+
const formatToolRequestsForDisplay = useCallback2((rawResponse) => {
|
|
6484
|
+
if (!rawResponse) return rawResponse;
|
|
6485
|
+
const requests = extractToolRequestMatchesFromText(rawResponse);
|
|
6486
|
+
if (requests.length === 0) return stripStandaloneRawToolJsonLines(rawResponse);
|
|
6487
|
+
const output = [];
|
|
6488
|
+
let cursor = 0;
|
|
6489
|
+
requests.forEach((request) => {
|
|
6490
|
+
const start = Math.max(0, Math.min(rawResponse.length, request.start));
|
|
6491
|
+
const end = Math.max(start, Math.min(rawResponse.length, request.end));
|
|
6492
|
+
output.push(rawResponse.slice(cursor, start));
|
|
6493
|
+
output.push(`
|
|
6494
|
+
|
|
6495
|
+
${buildInlineToolMarker(request.toolName, request.callId)}
|
|
6496
|
+
|
|
6497
|
+
`);
|
|
6498
|
+
cursor = end;
|
|
6499
|
+
});
|
|
6500
|
+
output.push(rawResponse.slice(cursor));
|
|
6501
|
+
return stripStandaloneRawToolJsonLines(output.join(""));
|
|
6502
|
+
}, []);
|
|
4631
6503
|
const activeThinkingBlock = useMemo2(() => {
|
|
4632
6504
|
if (!response || justReset) return null;
|
|
4633
6505
|
const { activeBlock } = processThinkingTags(response);
|
|
4634
6506
|
return activeBlock;
|
|
4635
6507
|
}, [response, justReset, processThinkingTags]);
|
|
4636
|
-
const AGENT_SUGGESTION_ACTION = {
|
|
4637
|
-
pattern: "\\[SUGGEST_AGENT:([^|\\]]+)\\|([^|\\]]+)\\|([^\\]]+)\\]",
|
|
4638
|
-
markdown: '<agent-suggestion data-agent-id="$1" data-agent-name="$2" data-reason="$3"></agent-suggestion>'
|
|
4639
|
-
};
|
|
4640
6508
|
const processActions = useCallback2((content) => {
|
|
4641
6509
|
const allActions = [AGENT_SUGGESTION_ACTION, ...actions || []];
|
|
4642
6510
|
let processed = content;
|
|
@@ -4670,6 +6538,38 @@ var AIChatPanel = ({
|
|
|
4670
6538
|
}
|
|
4671
6539
|
return displayPrompt;
|
|
4672
6540
|
}, [hideRagContextInPrompt]);
|
|
6541
|
+
const normalizeHistoryPromptForContext = useCallback2((historyPrompt) => {
|
|
6542
|
+
let promptForHistory = String(historyPrompt || "");
|
|
6543
|
+
const isoTimestampRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z:/;
|
|
6544
|
+
if (isoTimestampRegex.test(promptForHistory)) {
|
|
6545
|
+
const colonIndex = promptForHistory.indexOf(":", 19);
|
|
6546
|
+
promptForHistory = promptForHistory.substring(colonIndex + 1);
|
|
6547
|
+
} else if (/^\d+:/.test(promptForHistory)) {
|
|
6548
|
+
const colonIndex = promptForHistory.indexOf(":");
|
|
6549
|
+
promptForHistory = promptForHistory.substring(colonIndex + 1);
|
|
6550
|
+
}
|
|
6551
|
+
return promptForHistory;
|
|
6552
|
+
}, []);
|
|
6553
|
+
const buildAssistantContextContent = useCallback2(
|
|
6554
|
+
(historyPrompt, historyEntry) => {
|
|
6555
|
+
const assistantBaseContent = typeof (historyEntry == null ? void 0 : historyEntry.content) === "string" ? historyEntry.content : "";
|
|
6556
|
+
if (traceContextMode !== "full") {
|
|
6557
|
+
return assistantBaseContent;
|
|
6558
|
+
}
|
|
6559
|
+
const traceSummary = buildCompactTraceSummary({
|
|
6560
|
+
reasoningBlocks: thinkingBlocksByKeyRef.current[historyPrompt] || [],
|
|
6561
|
+
toolCalls: historyEntry == null ? void 0 : historyEntry.toolCalls,
|
|
6562
|
+
toolResponses: historyEntry == null ? void 0 : historyEntry.toolResponses
|
|
6563
|
+
});
|
|
6564
|
+
if (!traceSummary) {
|
|
6565
|
+
return assistantBaseContent;
|
|
6566
|
+
}
|
|
6567
|
+
return assistantBaseContent ? `${assistantBaseContent}
|
|
6568
|
+
|
|
6569
|
+
${traceSummary}` : traceSummary;
|
|
6570
|
+
},
|
|
6571
|
+
[traceContextMode]
|
|
6572
|
+
);
|
|
4673
6573
|
const interactionClicked = useCallback2((callId, action, emailaddress = "", comment = "") => __async(void 0, null, function* () {
|
|
4674
6574
|
var _a2, _b;
|
|
4675
6575
|
console.log(`[AIChatPanel] Interaction: ${action} for callId: ${callId}`);
|
|
@@ -4752,9 +6652,24 @@ var AIChatPanel = ({
|
|
|
4752
6652
|
lastScrollTimeRef.current = now;
|
|
4753
6653
|
}, []);
|
|
4754
6654
|
const continueChat = useCallback2((promptText) => {
|
|
6655
|
+
handledToolCallSignaturesRef.current = /* @__PURE__ */ new Set();
|
|
6656
|
+
inFlightToolCallSignaturesRef.current = /* @__PURE__ */ new Set();
|
|
6657
|
+
toolContinuationCountRef.current = 0;
|
|
6658
|
+
activeStreamAppendBaseRef.current = null;
|
|
6659
|
+
toolReplaySummariesByKeyRef.current = {};
|
|
6660
|
+
setPendingToolRequests([]);
|
|
6661
|
+
setActiveToolCalls([]);
|
|
6662
|
+
setCollapsedBlocks((prev) => {
|
|
6663
|
+
const next = new Set(prev);
|
|
6664
|
+
Object.entries(thinkingBlocksByKeyRef.current).forEach(([entryKey, blocks]) => {
|
|
6665
|
+
blocks.forEach((block, index) => {
|
|
6666
|
+
next.add(getThinkingBlockCollapseKey(entryKey, getThinkingBlockRenderKey(block, index)));
|
|
6667
|
+
});
|
|
6668
|
+
});
|
|
6669
|
+
return next;
|
|
6670
|
+
});
|
|
4755
6671
|
setThinkingBlocks([]);
|
|
4756
6672
|
setCurrentThinkingIndex(0);
|
|
4757
|
-
setCollapsedBlocks(/* @__PURE__ */ new Set());
|
|
4758
6673
|
hasAutoCollapsedRef.current = false;
|
|
4759
6674
|
prevBlockCountRef.current = 0;
|
|
4760
6675
|
setError(null);
|
|
@@ -4783,6 +6698,7 @@ var AIChatPanel = ({
|
|
|
4783
6698
|
setHistory((prevHistory) => __spreadProps(__spreadValues({}, prevHistory), {
|
|
4784
6699
|
[promptKey]: { content: "", callId: "" }
|
|
4785
6700
|
}));
|
|
6701
|
+
toolReplaySummariesByKeyRef.current[promptKey] = [];
|
|
4786
6702
|
setLastPrompt(promptToSend.trim());
|
|
4787
6703
|
setLastKey(promptKey);
|
|
4788
6704
|
setTimeout(() => {
|
|
@@ -4791,20 +6707,14 @@ var AIChatPanel = ({
|
|
|
4791
6707
|
console.log("AIChatPanel.continueChat - about to call ensureConversation");
|
|
4792
6708
|
ensureConversation().then((convId) => {
|
|
4793
6709
|
console.log("AIChatPanel.continueChat - ensureConversation resolved with:", convId);
|
|
6710
|
+
const historyForCall = latestHistoryRef.current || {};
|
|
4794
6711
|
const messagesAndHistory = [];
|
|
4795
|
-
Object.entries(
|
|
6712
|
+
Object.entries(historyForCall).forEach(([historyPrompt, historyEntry]) => {
|
|
4796
6713
|
if (historyPrompt === promptKey) return;
|
|
4797
|
-
|
|
4798
|
-
const
|
|
4799
|
-
if (isoTimestampRegex.test(historyPrompt)) {
|
|
4800
|
-
const colonIndex = historyPrompt.indexOf(":", 19);
|
|
4801
|
-
promptForHistory = historyPrompt.substring(colonIndex + 1);
|
|
4802
|
-
} else if (/^\d+:/.test(historyPrompt)) {
|
|
4803
|
-
const colonIndex = historyPrompt.indexOf(":");
|
|
4804
|
-
promptForHistory = historyPrompt.substring(colonIndex + 1);
|
|
4805
|
-
}
|
|
6714
|
+
const promptForHistory = normalizeHistoryPromptForContext(historyPrompt);
|
|
6715
|
+
const assistantContextContent = buildAssistantContextContent(historyPrompt, historyEntry);
|
|
4806
6716
|
messagesAndHistory.push({ role: "user", content: promptForHistory });
|
|
4807
|
-
messagesAndHistory.push({ role: "assistant", content:
|
|
6717
|
+
messagesAndHistory.push({ role: "assistant", content: assistantContextContent });
|
|
4808
6718
|
});
|
|
4809
6719
|
let fullPromptToSend = promptToSend.trim();
|
|
4810
6720
|
if (messagesAndHistory.length === 0 && promptTemplate) {
|
|
@@ -4812,6 +6722,19 @@ var AIChatPanel = ({
|
|
|
4812
6722
|
}
|
|
4813
6723
|
const newController = new AbortController();
|
|
4814
6724
|
setLastController(newController);
|
|
6725
|
+
if (onBeforeSend) {
|
|
6726
|
+
void Promise.resolve(
|
|
6727
|
+
onBeforeSend({
|
|
6728
|
+
prompt: promptToSend.trim(),
|
|
6729
|
+
conversationId: convId || null,
|
|
6730
|
+
agentId: agent,
|
|
6731
|
+
service,
|
|
6732
|
+
messages: messagesAndHistory
|
|
6733
|
+
})
|
|
6734
|
+
).catch((error2) => {
|
|
6735
|
+
console.warn("[AIChatPanel] onBeforeSend callback failed:", error2);
|
|
6736
|
+
});
|
|
6737
|
+
}
|
|
4815
6738
|
send(
|
|
4816
6739
|
fullPromptToSend,
|
|
4817
6740
|
messagesAndHistory,
|
|
@@ -4834,14 +6757,21 @@ var AIChatPanel = ({
|
|
|
4834
6757
|
console.log("[AIChatPanel] Error callback triggered:", errorMsg);
|
|
4835
6758
|
const isAbortError = errorMsg.toLowerCase().includes("abort") || errorMsg.toLowerCase().includes("canceled") || errorMsg.toLowerCase().includes("cancelled");
|
|
4836
6759
|
if (isAbortError) {
|
|
6760
|
+
if (suppressAbortHistoryUpdateRef.current) {
|
|
6761
|
+
setIsLoading(false);
|
|
6762
|
+
return;
|
|
6763
|
+
}
|
|
4837
6764
|
console.log("[AIChatPanel] Request was aborted by user");
|
|
4838
6765
|
if (promptKey) {
|
|
4839
|
-
setHistory((prev) =>
|
|
4840
|
-
[promptKey]:
|
|
4841
|
-
|
|
4842
|
-
|
|
4843
|
-
|
|
4844
|
-
|
|
6766
|
+
setHistory((prev) => {
|
|
6767
|
+
const existingEntry = prev[promptKey] || { content: "", callId: "" };
|
|
6768
|
+
return __spreadProps(__spreadValues({}, prev), {
|
|
6769
|
+
[promptKey]: __spreadProps(__spreadValues({}, existingEntry), {
|
|
6770
|
+
content: "Response canceled",
|
|
6771
|
+
callId: lastCallId || existingEntry.callId || ""
|
|
6772
|
+
})
|
|
6773
|
+
});
|
|
6774
|
+
});
|
|
4845
6775
|
}
|
|
4846
6776
|
} else if (errorMsg.includes("413") || errorMsg.toLowerCase().includes("content too large")) {
|
|
4847
6777
|
setError({
|
|
@@ -4849,12 +6779,15 @@ var AIChatPanel = ({
|
|
|
4849
6779
|
code: "413"
|
|
4850
6780
|
});
|
|
4851
6781
|
if (promptKey) {
|
|
4852
|
-
setHistory((prev) =>
|
|
4853
|
-
[promptKey]:
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
|
|
6782
|
+
setHistory((prev) => {
|
|
6783
|
+
const existingEntry = prev[promptKey] || { content: "", callId: "" };
|
|
6784
|
+
return __spreadProps(__spreadValues({}, prev), {
|
|
6785
|
+
[promptKey]: __spreadProps(__spreadValues({}, existingEntry), {
|
|
6786
|
+
content: `Error: ${errorMsg}`,
|
|
6787
|
+
callId: lastCallId || existingEntry.callId || ""
|
|
6788
|
+
})
|
|
6789
|
+
});
|
|
6790
|
+
});
|
|
4858
6791
|
}
|
|
4859
6792
|
} else if (errorMsg.toLowerCase().includes("network error") || errorMsg.toLowerCase().includes("fetch")) {
|
|
4860
6793
|
setError({
|
|
@@ -4862,12 +6795,15 @@ var AIChatPanel = ({
|
|
|
4862
6795
|
code: "NETWORK_ERROR"
|
|
4863
6796
|
});
|
|
4864
6797
|
if (promptKey) {
|
|
4865
|
-
setHistory((prev) =>
|
|
4866
|
-
[promptKey]:
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
6798
|
+
setHistory((prev) => {
|
|
6799
|
+
const existingEntry = prev[promptKey] || { content: "", callId: "" };
|
|
6800
|
+
return __spreadProps(__spreadValues({}, prev), {
|
|
6801
|
+
[promptKey]: __spreadProps(__spreadValues({}, existingEntry), {
|
|
6802
|
+
content: `Error: ${errorMsg}`,
|
|
6803
|
+
callId: lastCallId || existingEntry.callId || ""
|
|
6804
|
+
})
|
|
6805
|
+
});
|
|
6806
|
+
});
|
|
4871
6807
|
}
|
|
4872
6808
|
} else {
|
|
4873
6809
|
setError({
|
|
@@ -4875,12 +6811,15 @@ var AIChatPanel = ({
|
|
|
4875
6811
|
code: "UNKNOWN_ERROR"
|
|
4876
6812
|
});
|
|
4877
6813
|
if (promptKey) {
|
|
4878
|
-
setHistory((prev) =>
|
|
4879
|
-
[promptKey]:
|
|
4880
|
-
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
|
|
6814
|
+
setHistory((prev) => {
|
|
6815
|
+
const existingEntry = prev[promptKey] || { content: "", callId: "" };
|
|
6816
|
+
return __spreadProps(__spreadValues({}, prev), {
|
|
6817
|
+
[promptKey]: __spreadProps(__spreadValues({}, existingEntry), {
|
|
6818
|
+
content: `Error: ${errorMsg}`,
|
|
6819
|
+
callId: lastCallId || existingEntry.callId || ""
|
|
6820
|
+
})
|
|
6821
|
+
});
|
|
6822
|
+
});
|
|
4884
6823
|
}
|
|
4885
6824
|
}
|
|
4886
6825
|
setIsLoading(false);
|
|
@@ -4902,14 +6841,20 @@ var AIChatPanel = ({
|
|
|
4902
6841
|
lastCallId,
|
|
4903
6842
|
processThinkingTags,
|
|
4904
6843
|
clearFollowOnQuestionsNextPrompt,
|
|
4905
|
-
history,
|
|
4906
6844
|
promptTemplate,
|
|
4907
6845
|
send,
|
|
4908
6846
|
service,
|
|
6847
|
+
agent,
|
|
4909
6848
|
ensureConversation,
|
|
6849
|
+
normalizeHistoryPromptForContext,
|
|
6850
|
+
buildAssistantContextContent,
|
|
6851
|
+
traceContextMode,
|
|
4910
6852
|
dataWithExtras,
|
|
4911
6853
|
scrollToBottom,
|
|
4912
6854
|
onConversationCreated,
|
|
6855
|
+
onBeforeSend,
|
|
6856
|
+
getThinkingBlockCollapseKey,
|
|
6857
|
+
getThinkingBlockRenderKey,
|
|
4913
6858
|
setResponse
|
|
4914
6859
|
]);
|
|
4915
6860
|
const handleSuggestionClick = useCallback2((question) => {
|
|
@@ -4937,6 +6882,14 @@ var AIChatPanel = ({
|
|
|
4937
6882
|
setLastKey(null);
|
|
4938
6883
|
setIsLoading(false);
|
|
4939
6884
|
setCurrentConversation(null);
|
|
6885
|
+
thinkingBlocksByKeyRef.current = {};
|
|
6886
|
+
setThinkingBlocksByKey({});
|
|
6887
|
+
handledToolCallSignaturesRef.current = /* @__PURE__ */ new Set();
|
|
6888
|
+
inFlightToolCallSignaturesRef.current = /* @__PURE__ */ new Set();
|
|
6889
|
+
toolContinuationCountRef.current = 0;
|
|
6890
|
+
activeStreamAppendBaseRef.current = null;
|
|
6891
|
+
toolReplaySummariesByKeyRef.current = {};
|
|
6892
|
+
setPendingToolRequests([]);
|
|
4940
6893
|
setFollowOnQuestionsState(followOnQuestions);
|
|
4941
6894
|
setThinkingBlocks([]);
|
|
4942
6895
|
setCurrentThinkingIndex(0);
|
|
@@ -4947,6 +6900,7 @@ var AIChatPanel = ({
|
|
|
4947
6900
|
setLastController(new AbortController());
|
|
4948
6901
|
setUserHasScrolled(false);
|
|
4949
6902
|
setError(null);
|
|
6903
|
+
setActiveToolCalls([]);
|
|
4950
6904
|
setTimeout(() => {
|
|
4951
6905
|
var _a2;
|
|
4952
6906
|
setJustReset(false);
|
|
@@ -4955,43 +6909,85 @@ var AIChatPanel = ({
|
|
|
4955
6909
|
}, [newConversationConfirm, idle, stop, lastController, setResponse, followOnQuestions]);
|
|
4956
6910
|
useEffect8(() => {
|
|
4957
6911
|
if (!response || !lastKey || justReset) return;
|
|
4958
|
-
const
|
|
4959
|
-
|
|
4960
|
-
|
|
6912
|
+
const extractedToolRequests = extractToolRequests(response);
|
|
6913
|
+
const seenToolCallSignatures = /* @__PURE__ */ new Set();
|
|
6914
|
+
const unseenToolRequests = extractedToolRequests.filter((request) => {
|
|
6915
|
+
const callSignature = getToolCallSignature(request.toolName, request.callId);
|
|
6916
|
+
if (!callSignature) return false;
|
|
6917
|
+
if (seenToolCallSignatures.has(callSignature)) return false;
|
|
6918
|
+
seenToolCallSignatures.add(callSignature);
|
|
6919
|
+
if (handledToolCallSignaturesRef.current.has(callSignature)) return false;
|
|
6920
|
+
if (inFlightToolCallSignaturesRef.current.has(callSignature)) return false;
|
|
6921
|
+
return true;
|
|
6922
|
+
});
|
|
6923
|
+
setPendingToolRequests((prev) => {
|
|
6924
|
+
if (areToolRequestListsEqual(prev, unseenToolRequests)) {
|
|
6925
|
+
return prev;
|
|
6926
|
+
}
|
|
6927
|
+
return unseenToolRequests;
|
|
6928
|
+
});
|
|
6929
|
+
const responseWithInlineToolLabels = formatToolRequestsForDisplay(response);
|
|
6930
|
+
const { cleanedText: parsedCleanedText, completedBlocks } = processThinkingTags(responseWithInlineToolLabels);
|
|
6931
|
+
const cleanedText = parsedCleanedText.trim();
|
|
6932
|
+
const existingBlocks = thinkingBlocksByKeyRef.current[lastKey] || [];
|
|
6933
|
+
const mergedBlocks = mergeThinkingBlocks(existingBlocks, completedBlocks);
|
|
6934
|
+
thinkingBlocksByKeyRef.current[lastKey] = mergedBlocks;
|
|
6935
|
+
setThinkingBlocksByKey((prev) => {
|
|
6936
|
+
const existing = prev[lastKey];
|
|
6937
|
+
const isSame = !!existing && existing.length === mergedBlocks.length && existing.every(
|
|
6938
|
+
(block, index) => {
|
|
6939
|
+
var _a2, _b;
|
|
6940
|
+
return block.type === ((_a2 = mergedBlocks[index]) == null ? void 0 : _a2.type) && block.content === ((_b = mergedBlocks[index]) == null ? void 0 : _b.content);
|
|
6941
|
+
}
|
|
6942
|
+
);
|
|
6943
|
+
if (isSame) return prev;
|
|
6944
|
+
return __spreadProps(__spreadValues({}, prev), {
|
|
6945
|
+
[lastKey]: mergedBlocks
|
|
6946
|
+
});
|
|
6947
|
+
});
|
|
6948
|
+
setThinkingBlocks(mergedBlocks);
|
|
6949
|
+
setCurrentThinkingIndex(Math.max(0, mergedBlocks.length - 1));
|
|
6950
|
+
if (mergedBlocks.length > prevBlockCountRef.current) {
|
|
4961
6951
|
setCollapsedBlocks((prev) => {
|
|
4962
6952
|
const next = new Set(prev);
|
|
4963
|
-
for (let i = 0; i <
|
|
4964
|
-
|
|
6953
|
+
for (let i = 0; i < mergedBlocks.length - 1; i++) {
|
|
6954
|
+
const block = mergedBlocks[i];
|
|
6955
|
+
if (!block) continue;
|
|
6956
|
+
next.add(getThinkingBlockCollapseKey(lastKey, getThinkingBlockRenderKey(block, i)));
|
|
4965
6957
|
}
|
|
4966
6958
|
return next;
|
|
4967
6959
|
});
|
|
4968
|
-
prevBlockCountRef.current =
|
|
4969
|
-
}
|
|
4970
|
-
const hasMainContent = cleanedText.trim().length > 0;
|
|
4971
|
-
const hasThinkingContent = completedBlocks.length > 0 || processThinkingTags(response).activeBlock !== null;
|
|
4972
|
-
if (hasMainContent && hasThinkingContent && !hasAutoCollapsedRef.current) {
|
|
4973
|
-
hasAutoCollapsedRef.current = true;
|
|
4974
|
-
setTimeout(() => {
|
|
4975
|
-
setCollapsedBlocks((prev) => {
|
|
4976
|
-
const next = new Set(prev);
|
|
4977
|
-
completedBlocks.forEach((_, index) => next.add(`block-${index}`));
|
|
4978
|
-
next.add("active");
|
|
4979
|
-
return next;
|
|
4980
|
-
});
|
|
4981
|
-
}, 500);
|
|
6960
|
+
prevBlockCountRef.current = mergedBlocks.length;
|
|
4982
6961
|
}
|
|
4983
6962
|
setHistory((prev) => {
|
|
4984
6963
|
const newHistory = __spreadValues({}, prev);
|
|
4985
|
-
newHistory[lastKey]
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
|
|
6964
|
+
const existingEntry = newHistory[lastKey] || { content: "", callId: "" };
|
|
6965
|
+
const appendBase = activeStreamAppendBaseRef.current;
|
|
6966
|
+
const mergedContinuationContent = appendBase && appendBase.key === lastKey ? mergeContinuationResponseText(appendBase.base, cleanedText) : cleanedText;
|
|
6967
|
+
const existingContent = typeof existingEntry.content === "string" ? existingEntry.content : "";
|
|
6968
|
+
const nextContent = appendBase && appendBase.key === lastKey && existingContent.length > mergedContinuationContent.length ? existingContent : shouldPreserveBoundaryDroppedStreamText(existingContent, mergedContinuationContent) ? existingContent : mergedContinuationContent;
|
|
6969
|
+
newHistory[lastKey] = __spreadProps(__spreadValues({}, existingEntry), {
|
|
6970
|
+
content: nextContent,
|
|
6971
|
+
// Store raw content without tool JSON or thinking tags
|
|
6972
|
+
callId: lastCallId || existingEntry.callId || ""
|
|
6973
|
+
});
|
|
4990
6974
|
latestHistoryRef.current = newHistory;
|
|
4991
6975
|
return newHistory;
|
|
4992
6976
|
});
|
|
4993
|
-
}, [
|
|
6977
|
+
}, [
|
|
6978
|
+
response,
|
|
6979
|
+
lastKey,
|
|
6980
|
+
lastCallId,
|
|
6981
|
+
processThinkingTags,
|
|
6982
|
+
justReset,
|
|
6983
|
+
extractToolRequests,
|
|
6984
|
+
getToolCallSignature,
|
|
6985
|
+
getThinkingBlockCollapseKey,
|
|
6986
|
+
getThinkingBlockRenderKey,
|
|
6987
|
+
formatToolRequestsForDisplay
|
|
6988
|
+
]);
|
|
4994
6989
|
useEffect8(() => {
|
|
6990
|
+
var _a2;
|
|
4995
6991
|
const wasStreaming = !prevIdleRef.current;
|
|
4996
6992
|
const isNowIdle = idle;
|
|
4997
6993
|
prevIdleRef.current = idle;
|
|
@@ -5015,6 +7011,12 @@ var AIChatPanel = ({
|
|
|
5015
7011
|
if (!isNowIdle && hasNotifiedCompletionRef.current) {
|
|
5016
7012
|
hasNotifiedCompletionRef.current = false;
|
|
5017
7013
|
prevResponseLengthRef.current = 0;
|
|
7014
|
+
const currentLastKey = lastKeyRef.current;
|
|
7015
|
+
const existingContent = currentLastKey ? ((_a2 = latestHistoryRef.current[currentLastKey]) == null ? void 0 : _a2.content) || "" : "";
|
|
7016
|
+
activeStreamAppendBaseRef.current = currentLastKey && existingContent.trim().length > 0 ? {
|
|
7017
|
+
key: currentLastKey,
|
|
7018
|
+
base: existingContent
|
|
7019
|
+
} : null;
|
|
5018
7020
|
}
|
|
5019
7021
|
}, [idle]);
|
|
5020
7022
|
useEffect8(() => {
|
|
@@ -5035,21 +7037,19 @@ var AIChatPanel = ({
|
|
|
5035
7037
|
scrollToBottom(true);
|
|
5036
7038
|
}
|
|
5037
7039
|
}, [response, idle]);
|
|
5038
|
-
const idleRef = useRef6(idle);
|
|
5039
|
-
idleRef.current = idle;
|
|
5040
7040
|
useEffect8(() => {
|
|
5041
7041
|
const scrollArea = responseAreaRef.current;
|
|
5042
7042
|
if (!scrollArea) return;
|
|
5043
7043
|
const scrollViewport = scrollArea.querySelector(".ai-scroll-area-viewport");
|
|
5044
7044
|
const scrollElement = scrollViewport || scrollArea;
|
|
5045
7045
|
const handleWheel = (e) => {
|
|
5046
|
-
if (
|
|
7046
|
+
if (streamIdleRef.current) return;
|
|
5047
7047
|
if (e.deltaY < 0 && !userHasScrolledRef.current) {
|
|
5048
7048
|
setUserHasScrolled(true);
|
|
5049
7049
|
}
|
|
5050
7050
|
};
|
|
5051
7051
|
const handleScroll = () => {
|
|
5052
|
-
if (
|
|
7052
|
+
if (streamIdleRef.current || !userHasScrolledRef.current) return;
|
|
5053
7053
|
const scrollHeight = scrollElement.scrollHeight;
|
|
5054
7054
|
const currentScrollTop = scrollElement.scrollTop;
|
|
5055
7055
|
const clientHeight = scrollElement.clientHeight;
|
|
@@ -5066,7 +7066,12 @@ var AIChatPanel = ({
|
|
|
5066
7066
|
};
|
|
5067
7067
|
}, []);
|
|
5068
7068
|
useEffect8(() => {
|
|
5069
|
-
setFollowOnQuestionsState(
|
|
7069
|
+
setFollowOnQuestionsState((prev) => {
|
|
7070
|
+
if (prev.length === followOnQuestions.length && prev.every((question, index) => question === followOnQuestions[index])) {
|
|
7071
|
+
return prev;
|
|
7072
|
+
}
|
|
7073
|
+
return followOnQuestions;
|
|
7074
|
+
});
|
|
5070
7075
|
}, [followOnQuestions]);
|
|
5071
7076
|
useEffect8(() => {
|
|
5072
7077
|
const currentlyLoading = isLoading || !idle;
|
|
@@ -5084,10 +7089,11 @@ var AIChatPanel = ({
|
|
|
5084
7089
|
const currentLastKey = lastKeyRef.current;
|
|
5085
7090
|
const currentLastCallId = lastCallIdRef.current;
|
|
5086
7091
|
if (currentLastKey && currentResponse) {
|
|
5087
|
-
currentHistory[currentLastKey]
|
|
7092
|
+
const existingEntry = currentHistory[currentLastKey] || { content: "", callId: "" };
|
|
7093
|
+
currentHistory[currentLastKey] = __spreadProps(__spreadValues({}, existingEntry), {
|
|
5088
7094
|
content: currentResponse + "\n\n(response interrupted)",
|
|
5089
|
-
callId: currentLastCallId || ""
|
|
5090
|
-
};
|
|
7095
|
+
callId: currentLastCallId || existingEntry.callId || ""
|
|
7096
|
+
});
|
|
5091
7097
|
}
|
|
5092
7098
|
if (historyCallbackRef.current && Object.keys(currentHistory).length > 0 && !hasNotifiedCompletionRef.current) {
|
|
5093
7099
|
historyCallbackRef.current(currentHistory);
|
|
@@ -5124,12 +7130,15 @@ var AIChatPanel = ({
|
|
|
5124
7130
|
code: "413"
|
|
5125
7131
|
});
|
|
5126
7132
|
if (lastKey) {
|
|
5127
|
-
setHistory((prev) =>
|
|
5128
|
-
[lastKey]:
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
7133
|
+
setHistory((prev) => {
|
|
7134
|
+
const existingEntry = prev[lastKey] || { content: "", callId: "" };
|
|
7135
|
+
return __spreadProps(__spreadValues({}, prev), {
|
|
7136
|
+
[lastKey]: __spreadProps(__spreadValues({}, existingEntry), {
|
|
7137
|
+
content: `Error: ${errorMessage}`,
|
|
7138
|
+
callId: lastCallId || existingEntry.callId || ""
|
|
7139
|
+
})
|
|
7140
|
+
});
|
|
7141
|
+
});
|
|
5133
7142
|
}
|
|
5134
7143
|
} else if (errorMessage.toLowerCase().includes("network error") || errorMessage.toLowerCase().includes("fetch")) {
|
|
5135
7144
|
setError({
|
|
@@ -5137,12 +7146,15 @@ var AIChatPanel = ({
|
|
|
5137
7146
|
code: "NETWORK_ERROR"
|
|
5138
7147
|
});
|
|
5139
7148
|
if (lastKey) {
|
|
5140
|
-
setHistory((prev) =>
|
|
5141
|
-
[lastKey]:
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
7149
|
+
setHistory((prev) => {
|
|
7150
|
+
const existingEntry = prev[lastKey] || { content: "", callId: "" };
|
|
7151
|
+
return __spreadProps(__spreadValues({}, prev), {
|
|
7152
|
+
[lastKey]: __spreadProps(__spreadValues({}, existingEntry), {
|
|
7153
|
+
content: `Error: ${errorMessage}`,
|
|
7154
|
+
callId: lastCallId || existingEntry.callId || ""
|
|
7155
|
+
})
|
|
7156
|
+
});
|
|
7157
|
+
});
|
|
5146
7158
|
}
|
|
5147
7159
|
} else {
|
|
5148
7160
|
setError({
|
|
@@ -5150,12 +7162,15 @@ var AIChatPanel = ({
|
|
|
5150
7162
|
code: "UNKNOWN_ERROR"
|
|
5151
7163
|
});
|
|
5152
7164
|
if (lastKey) {
|
|
5153
|
-
setHistory((prev) =>
|
|
5154
|
-
[lastKey]:
|
|
5155
|
-
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
7165
|
+
setHistory((prev) => {
|
|
7166
|
+
const existingEntry = prev[lastKey] || { content: "", callId: "" };
|
|
7167
|
+
return __spreadProps(__spreadValues({}, prev), {
|
|
7168
|
+
[lastKey]: __spreadProps(__spreadValues({}, existingEntry), {
|
|
7169
|
+
content: `Error: ${errorMessage}`,
|
|
7170
|
+
callId: lastCallId || existingEntry.callId || ""
|
|
7171
|
+
})
|
|
7172
|
+
});
|
|
7173
|
+
});
|
|
5159
7174
|
}
|
|
5160
7175
|
}
|
|
5161
7176
|
setIsLoading(false);
|
|
@@ -5286,47 +7301,220 @@ var AIChatPanel = ({
|
|
|
5286
7301
|
);
|
|
5287
7302
|
}
|
|
5288
7303
|
}), [CodeBlock, AgentSuggestionCard]);
|
|
5289
|
-
const
|
|
5290
|
-
const
|
|
5291
|
-
|
|
5292
|
-
|
|
5293
|
-
|
|
5294
|
-
|
|
5295
|
-
|
|
5296
|
-
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
|
|
7304
|
+
const toggleThinkingBlockCollapsed = useCallback2((entryKey, blockKey) => {
|
|
7305
|
+
const collapseKey = getThinkingBlockCollapseKey(entryKey, blockKey);
|
|
7306
|
+
setCollapsedBlocks((prev) => {
|
|
7307
|
+
const next = new Set(prev);
|
|
7308
|
+
if (next.has(collapseKey)) {
|
|
7309
|
+
next.delete(collapseKey);
|
|
7310
|
+
} else {
|
|
7311
|
+
next.add(collapseKey);
|
|
7312
|
+
}
|
|
7313
|
+
return next;
|
|
7314
|
+
});
|
|
7315
|
+
}, [getThinkingBlockCollapseKey]);
|
|
7316
|
+
const renderThinkingBlockCard = (entryKey, block, blockKey, renderKey, isStreaming) => {
|
|
7317
|
+
const collapseKey = getThinkingBlockCollapseKey(entryKey, blockKey);
|
|
7318
|
+
return /* @__PURE__ */ React14.createElement(
|
|
7319
|
+
ThinkingBlock,
|
|
7320
|
+
{
|
|
7321
|
+
key: renderKey,
|
|
7322
|
+
type: block.type,
|
|
7323
|
+
content: block.content,
|
|
7324
|
+
isStreaming,
|
|
7325
|
+
isCollapsed: collapsedBlocks.has(collapseKey),
|
|
7326
|
+
onToggleCollapse: () => toggleThinkingBlockCollapsed(entryKey, blockKey)
|
|
7327
|
+
}
|
|
7328
|
+
);
|
|
7329
|
+
};
|
|
7330
|
+
const renderActiveThinkingBlock = (entryKey, activeBlock, keyPrefix) => {
|
|
7331
|
+
if (!activeBlock) return null;
|
|
7332
|
+
return /* @__PURE__ */ React14.createElement("div", { className: "ai-chat-inline-thinking-events" }, renderThinkingBlockCard(entryKey, activeBlock, "active", `${keyPrefix}-active`, true));
|
|
7333
|
+
};
|
|
7334
|
+
const panelClasses = ["ai-chat-panel", theme === "dark" ? "dark-theme" : ""].filter(Boolean).join(" ");
|
|
7335
|
+
const getToolStatusRank = (status) => {
|
|
7336
|
+
switch (status) {
|
|
7337
|
+
case "error":
|
|
7338
|
+
return 4;
|
|
7339
|
+
case "completed":
|
|
7340
|
+
return 3;
|
|
7341
|
+
case "running":
|
|
7342
|
+
return 2;
|
|
7343
|
+
case "pending":
|
|
7344
|
+
default:
|
|
7345
|
+
return 1;
|
|
7346
|
+
}
|
|
7347
|
+
};
|
|
7348
|
+
const formatToolCallId = (callId) => {
|
|
7349
|
+
const normalized = String(callId || "").trim();
|
|
7350
|
+
if (normalized.length <= 22) return normalized;
|
|
7351
|
+
return `${normalized.slice(0, 10)}...${normalized.slice(-8)}`;
|
|
7352
|
+
};
|
|
7353
|
+
const renderMarkdownContent = (content, key) => {
|
|
7354
|
+
if (!content || !content.trim()) return null;
|
|
7355
|
+
if (markdownClass) {
|
|
7356
|
+
return /* @__PURE__ */ React14.createElement("div", { key, className: markdownClass }, /* @__PURE__ */ React14.createElement(
|
|
7357
|
+
ReactMarkdown2,
|
|
7358
|
+
{
|
|
7359
|
+
remarkPlugins: [remarkGfm2],
|
|
7360
|
+
rehypePlugins: [rehypeRaw2],
|
|
7361
|
+
components: markdownComponents
|
|
7362
|
+
},
|
|
7363
|
+
content
|
|
7364
|
+
));
|
|
7365
|
+
}
|
|
7366
|
+
return /* @__PURE__ */ React14.createElement(
|
|
7367
|
+
ReactMarkdown2,
|
|
7368
|
+
{
|
|
7369
|
+
key,
|
|
7370
|
+
remarkPlugins: [remarkGfm2],
|
|
7371
|
+
rehypePlugins: [rehypeRaw2],
|
|
7372
|
+
components: markdownComponents
|
|
7373
|
+
},
|
|
7374
|
+
content
|
|
7375
|
+
);
|
|
7376
|
+
};
|
|
7377
|
+
const renderToolStatusRow = (toolStatusRow, key) => /* @__PURE__ */ React14.createElement(
|
|
7378
|
+
"div",
|
|
7379
|
+
{
|
|
7380
|
+
key,
|
|
7381
|
+
className: `ai-chat-tool-status-row ai-chat-tool-status-row--${toolStatusRow.status}`
|
|
7382
|
+
},
|
|
7383
|
+
/* @__PURE__ */ React14.createElement("div", { className: "ai-chat-tool-status-row__main" }, /* @__PURE__ */ React14.createElement(ToolIcon, null), /* @__PURE__ */ React14.createElement("span", { className: "ai-chat-tool-status-row__label" }, toolStatusRow.statusLabel), /* @__PURE__ */ React14.createElement("span", { className: "ai-chat-tool-status-row__call-id" }, formatToolCallId(toolStatusRow.callId))),
|
|
7384
|
+
toolStatusRow.status === "pending" && /* @__PURE__ */ React14.createElement("div", { className: "ai-chat-tool-status-row__actions" }, /* @__PURE__ */ React14.createElement(
|
|
7385
|
+
Button,
|
|
7386
|
+
{
|
|
7387
|
+
size: "sm",
|
|
7388
|
+
variant: "ghost",
|
|
7389
|
+
className: "ai-chat-tool-status-row__button",
|
|
7390
|
+
onClick: () => handleToolApproval(toolStatusRow.toolName, "once")
|
|
7391
|
+
},
|
|
7392
|
+
"once"
|
|
7393
|
+
), /* @__PURE__ */ React14.createElement(
|
|
7394
|
+
Button,
|
|
7395
|
+
{
|
|
7396
|
+
size: "sm",
|
|
7397
|
+
variant: "ghost",
|
|
7398
|
+
className: "ai-chat-tool-status-row__button",
|
|
7399
|
+
onClick: () => handleToolApproval(toolStatusRow.toolName, "session")
|
|
7400
|
+
},
|
|
7401
|
+
"session"
|
|
7402
|
+
), /* @__PURE__ */ React14.createElement(
|
|
7403
|
+
Button,
|
|
7404
|
+
{
|
|
7405
|
+
size: "sm",
|
|
7406
|
+
variant: "ghost",
|
|
7407
|
+
className: "ai-chat-tool-status-row__button",
|
|
7408
|
+
onClick: () => handleToolApproval(toolStatusRow.toolName, "always")
|
|
7409
|
+
},
|
|
7410
|
+
"always"
|
|
7411
|
+
))
|
|
7412
|
+
);
|
|
7413
|
+
const renderContentWithInlineToolCards = (content, toolStatusRows, thinkingBlocksForEntry, entryKey, keyPrefix) => {
|
|
7414
|
+
const { parts, markers } = parseInlineToolMarkers(content);
|
|
7415
|
+
const thinkingBlocksBySignature = /* @__PURE__ */ new Map();
|
|
7416
|
+
thinkingBlocksForEntry.forEach((block, index) => {
|
|
7417
|
+
const signature = String((block == null ? void 0 : block.signature) || "").trim() || getThinkingBlockRenderKey(block, index);
|
|
7418
|
+
if (!thinkingBlocksBySignature.has(signature)) {
|
|
7419
|
+
thinkingBlocksBySignature.set(signature, __spreadProps(__spreadValues({}, block), {
|
|
7420
|
+
signature
|
|
7421
|
+
}));
|
|
7422
|
+
}
|
|
7423
|
+
});
|
|
7424
|
+
const pendingBySignature = /* @__PURE__ */ new Map();
|
|
7425
|
+
const pendingByCallId = /* @__PURE__ */ new Map();
|
|
7426
|
+
toolStatusRows.forEach((row) => {
|
|
7427
|
+
if (!pendingBySignature.has(row.signature)) {
|
|
7428
|
+
pendingBySignature.set(row.signature, row);
|
|
7429
|
+
}
|
|
7430
|
+
if (!pendingByCallId.has(row.callId)) {
|
|
7431
|
+
pendingByCallId.set(row.callId, row);
|
|
7432
|
+
}
|
|
7433
|
+
});
|
|
7434
|
+
const nodes = [];
|
|
7435
|
+
parts.forEach((part, partIndex) => {
|
|
7436
|
+
const { parts: thinkingParts, markers: thinkingMarkers } = parseInlineThinkingMarkers(part);
|
|
7437
|
+
thinkingParts.forEach((thinkingPart, thinkingIndex) => {
|
|
7438
|
+
const markdownNode = renderMarkdownContent(
|
|
7439
|
+
thinkingPart,
|
|
7440
|
+
`${keyPrefix}-md-${partIndex}-${thinkingIndex}`
|
|
7441
|
+
);
|
|
7442
|
+
if (markdownNode) {
|
|
7443
|
+
nodes.push(markdownNode);
|
|
5300
7444
|
}
|
|
5301
|
-
|
|
7445
|
+
const thinkingMarker = thinkingMarkers[thinkingIndex];
|
|
7446
|
+
if (!thinkingMarker) return;
|
|
7447
|
+
const matchedBlock = thinkingBlocksBySignature.get(thinkingMarker.signature);
|
|
7448
|
+
if (!matchedBlock) return;
|
|
7449
|
+
const blockKey = getThinkingBlockRenderKey(matchedBlock, thinkingIndex);
|
|
7450
|
+
nodes.push(
|
|
7451
|
+
/* @__PURE__ */ React14.createElement(
|
|
7452
|
+
"div",
|
|
7453
|
+
{
|
|
7454
|
+
key: `${keyPrefix}-thinking-${partIndex}-${thinkingIndex}-${blockKey}`,
|
|
7455
|
+
className: "ai-chat-inline-thinking-events"
|
|
7456
|
+
},
|
|
7457
|
+
renderThinkingBlockCard(
|
|
7458
|
+
entryKey,
|
|
7459
|
+
matchedBlock,
|
|
7460
|
+
blockKey,
|
|
7461
|
+
`${keyPrefix}-thinking-card-${partIndex}-${thinkingIndex}-${blockKey}`,
|
|
7462
|
+
false
|
|
7463
|
+
)
|
|
7464
|
+
)
|
|
7465
|
+
);
|
|
5302
7466
|
});
|
|
5303
|
-
|
|
5304
|
-
|
|
5305
|
-
const
|
|
5306
|
-
|
|
5307
|
-
|
|
5308
|
-
|
|
5309
|
-
|
|
5310
|
-
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
|
-
|
|
7467
|
+
const marker = markers[partIndex];
|
|
7468
|
+
if (!marker) return;
|
|
7469
|
+
const markerSignature = getToolCallSignature(marker.toolName, marker.callId);
|
|
7470
|
+
const matchedRow = (markerSignature ? pendingBySignature.get(markerSignature) : void 0) || pendingByCallId.get(marker.callId);
|
|
7471
|
+
const fallbackSignature = markerSignature || getToolCallSignature(marker.toolName, `${marker.callId}-${partIndex + 1}`) || `${marker.toolName}::${marker.callId}::${partIndex}`;
|
|
7472
|
+
const rowToRender = matchedRow || {
|
|
7473
|
+
signature: fallbackSignature,
|
|
7474
|
+
toolName: marker.toolName,
|
|
7475
|
+
callId: marker.callId,
|
|
7476
|
+
status: "running",
|
|
7477
|
+
statusLabel: `tool call ${marker.toolName} running`
|
|
7478
|
+
};
|
|
7479
|
+
if (matchedRow) {
|
|
7480
|
+
pendingBySignature.delete(matchedRow.signature);
|
|
7481
|
+
const pendingByCallIdMatch = pendingByCallId.get(matchedRow.callId);
|
|
7482
|
+
if ((pendingByCallIdMatch == null ? void 0 : pendingByCallIdMatch.signature) === matchedRow.signature) {
|
|
7483
|
+
pendingByCallId.delete(matchedRow.callId);
|
|
5315
7484
|
}
|
|
5316
|
-
);
|
|
5317
|
-
}), activeThinkingBlock && /* @__PURE__ */ React14.createElement(
|
|
5318
|
-
ThinkingBlock,
|
|
5319
|
-
{
|
|
5320
|
-
key: "active-streaming",
|
|
5321
|
-
type: activeThinkingBlock.type,
|
|
5322
|
-
content: activeThinkingBlock.content,
|
|
5323
|
-
isStreaming: true,
|
|
5324
|
-
isCollapsed: collapsedBlocks.has("active"),
|
|
5325
|
-
onToggleCollapse: () => handleToggleCollapse("active")
|
|
5326
7485
|
}
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
|
|
7486
|
+
nodes.push(
|
|
7487
|
+
/* @__PURE__ */ React14.createElement(
|
|
7488
|
+
"div",
|
|
7489
|
+
{
|
|
7490
|
+
key: `${keyPrefix}-inline-${rowToRender.signature}-${partIndex}`,
|
|
7491
|
+
className: "ai-chat-inline-tool-events",
|
|
7492
|
+
role: "status",
|
|
7493
|
+
"aria-live": "polite"
|
|
7494
|
+
},
|
|
7495
|
+
renderToolStatusRow(rowToRender, `${keyPrefix}-row-${rowToRender.signature}-${partIndex}`)
|
|
7496
|
+
)
|
|
7497
|
+
);
|
|
7498
|
+
});
|
|
7499
|
+
const unmatchedRows = Array.from(pendingBySignature.values());
|
|
7500
|
+
if (unmatchedRows.length > 0) {
|
|
7501
|
+
nodes.push(
|
|
7502
|
+
/* @__PURE__ */ React14.createElement(
|
|
7503
|
+
"div",
|
|
7504
|
+
{
|
|
7505
|
+
key: `${keyPrefix}-tail`,
|
|
7506
|
+
className: "ai-chat-inline-tool-events ai-chat-inline-tool-events--tail",
|
|
7507
|
+
role: "status",
|
|
7508
|
+
"aria-live": "polite"
|
|
7509
|
+
},
|
|
7510
|
+
unmatchedRows.map(
|
|
7511
|
+
(row, rowIndex) => renderToolStatusRow(row, `${keyPrefix}-tail-${row.signature}-${rowIndex}`)
|
|
7512
|
+
)
|
|
7513
|
+
)
|
|
7514
|
+
);
|
|
7515
|
+
}
|
|
7516
|
+
return /* @__PURE__ */ React14.createElement(React14.Fragment, null, nodes);
|
|
7517
|
+
};
|
|
5330
7518
|
return /* @__PURE__ */ React14.createElement(
|
|
5331
7519
|
"div",
|
|
5332
7520
|
{
|
|
@@ -5359,47 +7547,114 @@ var AIChatPanel = ({
|
|
|
5359
7547
|
initialMessage
|
|
5360
7548
|
))), Object.entries(history).map(([prompt, entry], index, entries) => {
|
|
5361
7549
|
const isLastEntry = index === entries.length - 1;
|
|
7550
|
+
const isStreamingEntry = isLastEntry && (isLoading || !idle) && !justReset;
|
|
7551
|
+
const continuationAppendBase = isStreamingEntry && activeStreamAppendBaseRef.current && activeStreamAppendBaseRef.current.key === prompt && activeStreamAppendBaseRef.current.base.trim().length > 0 ? activeStreamAppendBaseRef.current : null;
|
|
7552
|
+
const isContinuationStreamingEntry = !!continuationAppendBase;
|
|
5362
7553
|
const isSystemMessage = prompt.startsWith("__system__:");
|
|
5363
7554
|
const { cleanedText } = processThinkingTags(entry.content);
|
|
5364
7555
|
const processedContent = processActions(cleanedText);
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
|
|
7556
|
+
const entryThinkingBlocks = thinkingBlocksByKey[prompt] || [];
|
|
7557
|
+
const statusBySignature = /* @__PURE__ */ new Map();
|
|
7558
|
+
const upsertToolStatus = (row) => {
|
|
7559
|
+
const existing = statusBySignature.get(row.signature);
|
|
7560
|
+
if (!existing || getToolStatusRank(row.status) >= getToolStatusRank(existing.status)) {
|
|
7561
|
+
statusBySignature.set(row.signature, row);
|
|
7562
|
+
}
|
|
7563
|
+
};
|
|
7564
|
+
const entryToolCalls = Array.isArray(entry.toolCalls) ? entry.toolCalls : [];
|
|
7565
|
+
const entryToolResponses = Array.isArray(entry.toolResponses) ? entry.toolResponses : [];
|
|
7566
|
+
entryToolCalls.forEach((toolCall, toolIndex) => {
|
|
7567
|
+
const toolName = String((toolCall == null ? void 0 : toolCall.name) || "").trim() || "tool";
|
|
7568
|
+
const callId = String((toolCall == null ? void 0 : toolCall.id) || "").trim() || `${toolName}-${toolIndex + 1}`;
|
|
7569
|
+
const signature = getToolCallSignature(toolName, callId) || `completed-${prompt}-${toolIndex}-${toolName}-${callId}`;
|
|
7570
|
+
const matchedResponse = entryToolResponses.find((response2) => String((response2 == null ? void 0 : response2.tool_call_id) || "").trim() === callId) || entryToolResponses[toolIndex];
|
|
7571
|
+
const isError = Boolean(matchedResponse == null ? void 0 : matchedResponse.isError);
|
|
7572
|
+
upsertToolStatus({
|
|
7573
|
+
signature,
|
|
7574
|
+
toolName,
|
|
7575
|
+
callId,
|
|
7576
|
+
status: isError ? "error" : "completed",
|
|
7577
|
+
statusLabel: isError ? `tool call ${toolName} errored` : `tool call ${toolName} completed`
|
|
7578
|
+
});
|
|
7579
|
+
});
|
|
7580
|
+
if (isLastEntry && !justReset) {
|
|
7581
|
+
pendingToolRequests.forEach((request, requestIndex) => {
|
|
7582
|
+
const toolName = String((request == null ? void 0 : request.toolName) || "").trim() || "tool";
|
|
7583
|
+
const callId = String((request == null ? void 0 : request.callId) || "").trim() || `${toolName}-pending-${requestIndex + 1}`;
|
|
7584
|
+
const signature = getToolCallSignature(toolName, callId) || `pending-${prompt}-${requestIndex}-${toolName}-${callId}`;
|
|
7585
|
+
upsertToolStatus({
|
|
7586
|
+
signature,
|
|
7587
|
+
toolName,
|
|
7588
|
+
callId,
|
|
7589
|
+
status: "pending",
|
|
7590
|
+
statusLabel: `tool call ${toolName} awaiting approval`
|
|
7591
|
+
});
|
|
7592
|
+
});
|
|
7593
|
+
activeToolCalls.forEach((activeToolCall, activeIndex) => {
|
|
7594
|
+
const toolName = String((activeToolCall == null ? void 0 : activeToolCall.toolName) || "").trim() || "tool";
|
|
7595
|
+
const callId = String((activeToolCall == null ? void 0 : activeToolCall.callId) || "").trim() || `${toolName}-running-${activeIndex + 1}`;
|
|
7596
|
+
const signature = getToolCallSignature(toolName, callId) || `running-${prompt}-${activeIndex}-${toolName}-${callId}`;
|
|
7597
|
+
upsertToolStatus({
|
|
7598
|
+
signature,
|
|
7599
|
+
toolName,
|
|
7600
|
+
callId,
|
|
7601
|
+
status: "running",
|
|
7602
|
+
statusLabel: `tool call ${toolName} running`
|
|
7603
|
+
});
|
|
7604
|
+
});
|
|
7605
|
+
}
|
|
7606
|
+
const entryToolStatusRows = Array.from(statusBySignature.values());
|
|
7607
|
+
const hasInFlightToolStatus = entryToolStatusRows.some(
|
|
7608
|
+
(row) => row.status === "pending" || row.status === "running"
|
|
7609
|
+
);
|
|
7610
|
+
const isActivePromptEntry = !!lastKey && prompt === lastKey;
|
|
7611
|
+
const shouldShowBusyGapThinkingFallback = isActivePromptEntry && !isStreamingEntry && (isLoading || !idle) && !activeThinkingBlock && !hasInFlightToolStatus;
|
|
7612
|
+
return /* @__PURE__ */ React14.createElement("div", { key: prompt, className: "ai-chat-entry" }, !(hideInitialPrompt && index === 0) && !isSystemMessage && /* @__PURE__ */ React14.createElement("div", { className: "ai-chat-message ai-chat-message--user" }, /* @__PURE__ */ React14.createElement("div", { className: "ai-chat-message__content" }, formatPromptForDisplay(prompt))), /* @__PURE__ */ React14.createElement("div", { className: "ai-chat-message ai-chat-message--assistant" }, /* @__PURE__ */ React14.createElement("div", { className: "ai-chat-message__content" }, isStreamingEntry ? (() => {
|
|
7613
|
+
if (isContinuationStreamingEntry) {
|
|
7614
|
+
const continuationResponseWithInlineToolLabels = formatToolRequestsForDisplay(response || "");
|
|
7615
|
+
const { cleanedText: continuationCleanedText } = processThinkingTags(
|
|
7616
|
+
continuationResponseWithInlineToolLabels
|
|
7617
|
+
);
|
|
7618
|
+
const appendBase2 = continuationAppendBase || activeStreamAppendBaseRef.current;
|
|
7619
|
+
const continuationMergedText = appendBase2 && appendBase2.key === prompt ? mergeContinuationResponseText(appendBase2.base, continuationCleanedText.trim()) : continuationCleanedText;
|
|
7620
|
+
const continuationDisplaySource = continuationMergedText.trim().length > 0 ? continuationMergedText : cleanedText;
|
|
7621
|
+
const continuationDisplayContent = processActions(continuationDisplaySource);
|
|
7622
|
+
const hasVisibleContinuationContent = continuationDisplayContent.trim().length > 0;
|
|
7623
|
+
const hasFreshContinuationContent = continuationCleanedText.trim().length > 0;
|
|
7624
|
+
const showThinkingFallback2 = !activeThinkingBlock && !hasFreshContinuationContent && !hasInFlightToolStatus;
|
|
7625
|
+
return /* @__PURE__ */ React14.createElement("div", { className: "ai-chat-streaming" }, renderActiveThinkingBlock(prompt, activeThinkingBlock, `${prompt}-continuation`), hasVisibleContinuationContent ? /* @__PURE__ */ React14.createElement(React14.Fragment, null, renderContentWithInlineToolCards(
|
|
7626
|
+
continuationDisplayContent,
|
|
7627
|
+
entryToolStatusRows,
|
|
7628
|
+
entryThinkingBlocks,
|
|
7629
|
+
prompt,
|
|
7630
|
+
`${prompt}-continuation`
|
|
7631
|
+
), showThinkingFallback2 && /* @__PURE__ */ React14.createElement("div", { className: "ai-chat-loading ai-chat-loading--inline" }, /* @__PURE__ */ React14.createElement("span", null, "Thinking"), /* @__PURE__ */ React14.createElement("span", { className: "ai-chat-loading__dots" }, /* @__PURE__ */ React14.createElement("span", { className: "ai-chat-loading__dot" }), /* @__PURE__ */ React14.createElement("span", { className: "ai-chat-loading__dot" }), /* @__PURE__ */ React14.createElement("span", { className: "ai-chat-loading__dot" })))) : /* @__PURE__ */ React14.createElement("div", { className: "ai-chat-loading" }, /* @__PURE__ */ React14.createElement("span", null, "Continuing response"), /* @__PURE__ */ React14.createElement("span", { className: "ai-chat-loading__dots" }, /* @__PURE__ */ React14.createElement("span", { className: "ai-chat-loading__dot" }), /* @__PURE__ */ React14.createElement("span", { className: "ai-chat-loading__dot" }), /* @__PURE__ */ React14.createElement("span", { className: "ai-chat-loading__dot" }))));
|
|
7632
|
+
}
|
|
7633
|
+
const streamingResponseWithInlineToolLabels = formatToolRequestsForDisplay(response || "");
|
|
7634
|
+
const { cleanedText: streamingCleanedText } = processThinkingTags(streamingResponseWithInlineToolLabels);
|
|
7635
|
+
const appendBase = activeStreamAppendBaseRef.current;
|
|
7636
|
+
const streamingMergedText = appendBase && appendBase.key === prompt ? mergeContinuationResponseText(appendBase.base, streamingCleanedText.trim()) : streamingCleanedText;
|
|
7637
|
+
const streamingContent = processActions(streamingMergedText);
|
|
5368
7638
|
const hasStreamingContent = streamingContent.trim().length > 0;
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
|
|
5372
|
-
|
|
5373
|
-
|
|
5374
|
-
|
|
5375
|
-
|
|
5376
|
-
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
{
|
|
5380
|
-
|
|
5381
|
-
|
|
5382
|
-
|
|
5383
|
-
|
|
5384
|
-
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
|
|
5388
|
-
{
|
|
5389
|
-
remarkPlugins: [remarkGfm2],
|
|
5390
|
-
rehypePlugins: [rehypeRaw2],
|
|
5391
|
-
components: markdownComponents
|
|
5392
|
-
},
|
|
5393
|
-
processedContent
|
|
5394
|
-
)) : /* @__PURE__ */ React14.createElement(
|
|
5395
|
-
ReactMarkdown2,
|
|
5396
|
-
{
|
|
5397
|
-
remarkPlugins: [remarkGfm2],
|
|
5398
|
-
rehypePlugins: [rehypeRaw2],
|
|
5399
|
-
components: markdownComponents
|
|
5400
|
-
},
|
|
5401
|
-
processedContent
|
|
5402
|
-
))), (!isLastEntry || !isLoading) && /* @__PURE__ */ React14.createElement("div", { className: "ai-chat-message__actions" }, /* @__PURE__ */ React14.createElement(
|
|
7639
|
+
const hasFreshStreamingContent = streamingCleanedText.trim().length > 0;
|
|
7640
|
+
const fallbackHistoryContent = processedContent.trim();
|
|
7641
|
+
const streamingDisplayContent = hasStreamingContent ? streamingContent : fallbackHistoryContent;
|
|
7642
|
+
const hasDisplayContent = streamingDisplayContent.trim().length > 0;
|
|
7643
|
+
const showThinkingFallback = !activeThinkingBlock && !hasFreshStreamingContent && !hasInFlightToolStatus;
|
|
7644
|
+
return /* @__PURE__ */ React14.createElement("div", { className: "ai-chat-streaming" }, renderActiveThinkingBlock(prompt, activeThinkingBlock, `${prompt}-streaming`), hasDisplayContent ? /* @__PURE__ */ React14.createElement(React14.Fragment, null, renderContentWithInlineToolCards(
|
|
7645
|
+
streamingDisplayContent,
|
|
7646
|
+
entryToolStatusRows,
|
|
7647
|
+
entryThinkingBlocks,
|
|
7648
|
+
prompt,
|
|
7649
|
+
`${prompt}-streaming`
|
|
7650
|
+
), showThinkingFallback && /* @__PURE__ */ React14.createElement("div", { className: "ai-chat-loading ai-chat-loading--inline" }, /* @__PURE__ */ React14.createElement("span", null, "Thinking"), /* @__PURE__ */ React14.createElement("span", { className: "ai-chat-loading__dots" }, /* @__PURE__ */ React14.createElement("span", { className: "ai-chat-loading__dot" }), /* @__PURE__ */ React14.createElement("span", { className: "ai-chat-loading__dot" }), /* @__PURE__ */ React14.createElement("span", { className: "ai-chat-loading__dot" })))) : /* @__PURE__ */ React14.createElement("div", { className: "ai-chat-loading" }, /* @__PURE__ */ React14.createElement("span", null, activeThinkingBlock ? "Still thinking" : "Thinking"), /* @__PURE__ */ React14.createElement("span", { className: "ai-chat-loading__dots" }, /* @__PURE__ */ React14.createElement("span", { className: "ai-chat-loading__dot" }), /* @__PURE__ */ React14.createElement("span", { className: "ai-chat-loading__dot" }), /* @__PURE__ */ React14.createElement("span", { className: "ai-chat-loading__dot" }))));
|
|
7651
|
+
})() : /* @__PURE__ */ React14.createElement(React14.Fragment, null, renderContentWithInlineToolCards(
|
|
7652
|
+
processedContent,
|
|
7653
|
+
entryToolStatusRows,
|
|
7654
|
+
entryThinkingBlocks,
|
|
7655
|
+
prompt,
|
|
7656
|
+
`${prompt}-final`
|
|
7657
|
+
), shouldShowBusyGapThinkingFallback && /* @__PURE__ */ React14.createElement("div", { className: "ai-chat-loading ai-chat-loading--inline", "aria-live": "polite" }, /* @__PURE__ */ React14.createElement("span", null, "Thinking"), /* @__PURE__ */ React14.createElement("span", { className: "ai-chat-loading__dots" }, /* @__PURE__ */ React14.createElement("span", { className: "ai-chat-loading__dot" }), /* @__PURE__ */ React14.createElement("span", { className: "ai-chat-loading__dot" }), /* @__PURE__ */ React14.createElement("span", { className: "ai-chat-loading__dot" }))))), (!isLastEntry || !isLoading) && /* @__PURE__ */ React14.createElement("div", { className: "ai-chat-message__actions" }, /* @__PURE__ */ React14.createElement(
|
|
5403
7658
|
"button",
|
|
5404
7659
|
{
|
|
5405
7660
|
className: "ai-chat-action-button",
|
|
@@ -5425,7 +7680,7 @@ var AIChatPanel = ({
|
|
|
5425
7680
|
style: (feedbackCallId == null ? void 0 : feedbackCallId.callId) === entry.callId && (feedbackCallId == null ? void 0 : feedbackCallId.type) === "down" ? { color: "#ef4444" } : void 0
|
|
5426
7681
|
},
|
|
5427
7682
|
(feedbackCallId == null ? void 0 : feedbackCallId.callId) === entry.callId && (feedbackCallId == null ? void 0 : feedbackCallId.type) === "down" ? /* @__PURE__ */ React14.createElement("span", { style: { fontSize: "11px", fontWeight: 500 } }, "Thanks!") : /* @__PURE__ */ React14.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "ai-chat-icon-sm" }, /* @__PURE__ */ React14.createElement("path", { d: "M10 15v4a3 3 0 0 0 3 3l4-9V2H5.72a2 2 0 0 0-2 1.7l-1.38 9a2 2 0 0 0 2 2.3zm7-13h2.67A2.31 2.31 0 0 1 22 4v7a2.31 2.31 0 0 1-2.33 2H17" }))
|
|
5428
|
-
),
|
|
7683
|
+
), /* @__PURE__ */ React14.createElement(
|
|
5429
7684
|
"button",
|
|
5430
7685
|
{
|
|
5431
7686
|
className: "ai-chat-action-button",
|
|
@@ -5451,34 +7706,6 @@ var AIChatPanel = ({
|
|
|
5451
7706
|
},
|
|
5452
7707
|
question
|
|
5453
7708
|
))), /* @__PURE__ */ React14.createElement("div", { ref: bottomRef })),
|
|
5454
|
-
pendingToolRequests.length > 0 && /* @__PURE__ */ React14.createElement("div", { className: "ai-chat-approve-tools-panel" }, /* @__PURE__ */ React14.createElement("div", { className: "ai-chat-approve-tools-header" }, "Tool Approval Required"), /* @__PURE__ */ React14.createElement("div", { className: "ai-chat-approve-tools-description" }, "The AI wants to use the following tools:"), getUniqueToolNames().map((toolName) => /* @__PURE__ */ React14.createElement("div", { key: toolName, className: "ai-chat-approve-tool-item" }, /* @__PURE__ */ React14.createElement("div", { className: "ai-chat-approve-tool-name" }, toolName), /* @__PURE__ */ React14.createElement("div", { className: "ai-chat-approve-tools-buttons" }, /* @__PURE__ */ React14.createElement(
|
|
5455
|
-
Button,
|
|
5456
|
-
{
|
|
5457
|
-
size: "sm",
|
|
5458
|
-
variant: "outline",
|
|
5459
|
-
className: "ai-chat-approve-tools-button",
|
|
5460
|
-
onClick: () => handleToolApproval(toolName, "once")
|
|
5461
|
-
},
|
|
5462
|
-
"Once"
|
|
5463
|
-
), /* @__PURE__ */ React14.createElement(
|
|
5464
|
-
Button,
|
|
5465
|
-
{
|
|
5466
|
-
size: "sm",
|
|
5467
|
-
variant: "outline",
|
|
5468
|
-
className: "ai-chat-approve-tools-button",
|
|
5469
|
-
onClick: () => handleToolApproval(toolName, "session")
|
|
5470
|
-
},
|
|
5471
|
-
"This Session"
|
|
5472
|
-
), /* @__PURE__ */ React14.createElement(
|
|
5473
|
-
Button,
|
|
5474
|
-
{
|
|
5475
|
-
size: "sm",
|
|
5476
|
-
variant: "default",
|
|
5477
|
-
className: "ai-chat-approve-tools-button",
|
|
5478
|
-
onClick: () => handleToolApproval(toolName, "always")
|
|
5479
|
-
},
|
|
5480
|
-
"Always"
|
|
5481
|
-
))))),
|
|
5482
7709
|
(showSaveButton || showEmailButton || showCallToAction) && /* @__PURE__ */ React14.createElement("div", { className: "ai-chat-button-container" }, showSaveButton && /* @__PURE__ */ React14.createElement(
|
|
5483
7710
|
Button,
|
|
5484
7711
|
{
|
|
@@ -5614,7 +7841,7 @@ var AIChatPanel = ({
|
|
|
5614
7841
|
ChatInput,
|
|
5615
7842
|
{
|
|
5616
7843
|
placeholder,
|
|
5617
|
-
idle,
|
|
7844
|
+
isBusy: isLoading || !idle,
|
|
5618
7845
|
onSubmit: continueChat,
|
|
5619
7846
|
onStop: handleStop,
|
|
5620
7847
|
agentOptions,
|
|
@@ -5861,13 +8088,14 @@ var SparkleIcon = () => /* @__PURE__ */ React15.createElement("svg", { width: "1
|
|
|
5861
8088
|
var normalizeConversationListPayload = (payload) => {
|
|
5862
8089
|
if (!payload) return [];
|
|
5863
8090
|
const conversations = Array.isArray(payload) ? payload : payload.conversations || [];
|
|
5864
|
-
|
|
8091
|
+
const normalized = conversations.map((conv, index) => {
|
|
5865
8092
|
let title = conv.title && conv.title !== "Conversation" ? conv.title : "";
|
|
5866
8093
|
if (!title) {
|
|
5867
8094
|
title = conv.summary || extractTitleFromConversation(conv);
|
|
5868
8095
|
}
|
|
8096
|
+
const resolvedConversationId = conv.conversationId || conv.id || conv.conversation_id || `conversation-${index}-${Date.now()}`;
|
|
5869
8097
|
return {
|
|
5870
|
-
conversationId:
|
|
8098
|
+
conversationId: resolvedConversationId,
|
|
5871
8099
|
title,
|
|
5872
8100
|
summary: conv.summary,
|
|
5873
8101
|
createdAt: conv.createdAt || conv.created_at || conv.timestamp || (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -5876,6 +8104,20 @@ var normalizeConversationListPayload = (payload) => {
|
|
|
5876
8104
|
messageCount: conv.messageCount || conv.message_count
|
|
5877
8105
|
};
|
|
5878
8106
|
});
|
|
8107
|
+
const dedupedById = /* @__PURE__ */ new Map();
|
|
8108
|
+
for (const conv of normalized) {
|
|
8109
|
+
const existing = dedupedById.get(conv.conversationId);
|
|
8110
|
+
if (!existing) {
|
|
8111
|
+
dedupedById.set(conv.conversationId, conv);
|
|
8112
|
+
continue;
|
|
8113
|
+
}
|
|
8114
|
+
const existingUpdated = new Date(existing.updatedAt).getTime();
|
|
8115
|
+
const incomingUpdated = new Date(conv.updatedAt).getTime();
|
|
8116
|
+
if (incomingUpdated >= existingUpdated) {
|
|
8117
|
+
dedupedById.set(conv.conversationId, conv);
|
|
8118
|
+
}
|
|
8119
|
+
}
|
|
8120
|
+
return Array.from(dedupedById.values());
|
|
5879
8121
|
};
|
|
5880
8122
|
var extractTitleFromConversation = (conv) => {
|
|
5881
8123
|
var _a;
|
|
@@ -5949,6 +8191,248 @@ var groupConversationsByTime = (conversations, showAllGroups = false) => {
|
|
|
5949
8191
|
});
|
|
5950
8192
|
return Object.entries(groups).filter(([_, convs]) => showAllGroups || convs.length > 0).map(([label, conversations2]) => ({ label, conversations: conversations2, count: conversations2.length }));
|
|
5951
8193
|
};
|
|
8194
|
+
var toRecord = (value) => {
|
|
8195
|
+
if (typeof value === "object" && value !== null) {
|
|
8196
|
+
return value;
|
|
8197
|
+
}
|
|
8198
|
+
return null;
|
|
8199
|
+
};
|
|
8200
|
+
var toStringValue = (value) => {
|
|
8201
|
+
if (typeof value === "string") return value;
|
|
8202
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
8203
|
+
return "";
|
|
8204
|
+
};
|
|
8205
|
+
var normalizeContentText = (value) => {
|
|
8206
|
+
if (typeof value === "string") return value;
|
|
8207
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
8208
|
+
if (Array.isArray(value)) {
|
|
8209
|
+
return value.map((item) => normalizeContentText(item)).filter(Boolean).join("\n").trim();
|
|
8210
|
+
}
|
|
8211
|
+
const record = toRecord(value);
|
|
8212
|
+
if (!record) return "";
|
|
8213
|
+
const directText = toStringValue(record.text);
|
|
8214
|
+
if (directText) return directText;
|
|
8215
|
+
const directValue = toStringValue(record.value);
|
|
8216
|
+
if (directValue) return directValue;
|
|
8217
|
+
const directContent = toStringValue(record.content);
|
|
8218
|
+
if (directContent) return directContent;
|
|
8219
|
+
if (Array.isArray(record.content)) {
|
|
8220
|
+
return normalizeContentText(record.content);
|
|
8221
|
+
}
|
|
8222
|
+
if (Array.isArray(record.parts)) {
|
|
8223
|
+
return normalizeContentText(record.parts);
|
|
8224
|
+
}
|
|
8225
|
+
if (record.content && typeof record.content === "object") {
|
|
8226
|
+
return normalizeContentText(record.content);
|
|
8227
|
+
}
|
|
8228
|
+
return "";
|
|
8229
|
+
};
|
|
8230
|
+
var parseCallMessages = (rawMessages) => {
|
|
8231
|
+
var _a, _b;
|
|
8232
|
+
let parsed = rawMessages;
|
|
8233
|
+
if (typeof rawMessages === "string") {
|
|
8234
|
+
try {
|
|
8235
|
+
parsed = JSON.parse(rawMessages);
|
|
8236
|
+
} catch (e) {
|
|
8237
|
+
return [];
|
|
8238
|
+
}
|
|
8239
|
+
}
|
|
8240
|
+
const parsedRecord = toRecord(parsed);
|
|
8241
|
+
if (parsedRecord && Array.isArray(parsedRecord.messages)) {
|
|
8242
|
+
parsed = parsedRecord.messages;
|
|
8243
|
+
}
|
|
8244
|
+
if (!Array.isArray(parsed)) {
|
|
8245
|
+
return [];
|
|
8246
|
+
}
|
|
8247
|
+
const normalized = [];
|
|
8248
|
+
for (const message of parsed) {
|
|
8249
|
+
const messageRecord = toRecord(message);
|
|
8250
|
+
if (!messageRecord) continue;
|
|
8251
|
+
const role = toStringValue(messageRecord.role).toLowerCase().trim();
|
|
8252
|
+
if (!role) continue;
|
|
8253
|
+
const content = normalizeContentText(
|
|
8254
|
+
(_b = (_a = messageRecord.content) != null ? _a : messageRecord.text) != null ? _b : messageRecord.message
|
|
8255
|
+
).trim();
|
|
8256
|
+
if (!content) continue;
|
|
8257
|
+
normalized.push({ role, content });
|
|
8258
|
+
}
|
|
8259
|
+
return normalized;
|
|
8260
|
+
};
|
|
8261
|
+
var shouldSkipTranscriptMessage = (message) => {
|
|
8262
|
+
return message.role === "system" || message.role === "user" && message.content.startsWith("__system__:");
|
|
8263
|
+
};
|
|
8264
|
+
var parseTimestampMs = (value) => {
|
|
8265
|
+
const timestamp = toStringValue(value).trim();
|
|
8266
|
+
if (!timestamp) return null;
|
|
8267
|
+
const parsed = Date.parse(timestamp);
|
|
8268
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
8269
|
+
};
|
|
8270
|
+
var getCallTimestampMs = (call, fallbackIndex) => {
|
|
8271
|
+
const timestampCandidates = [
|
|
8272
|
+
call.createdAt,
|
|
8273
|
+
call.created_at,
|
|
8274
|
+
call.timestamp,
|
|
8275
|
+
call.updatedAt,
|
|
8276
|
+
call.updated_at
|
|
8277
|
+
];
|
|
8278
|
+
for (const candidate of timestampCandidates) {
|
|
8279
|
+
const parsed = parseTimestampMs(candidate);
|
|
8280
|
+
if (parsed !== null) return parsed;
|
|
8281
|
+
}
|
|
8282
|
+
return fallbackIndex;
|
|
8283
|
+
};
|
|
8284
|
+
var getCallId = (call) => {
|
|
8285
|
+
const id = toStringValue(call.id);
|
|
8286
|
+
if (id) return id;
|
|
8287
|
+
return toStringValue(call.callId);
|
|
8288
|
+
};
|
|
8289
|
+
var normalizeCallsPayload = (payload) => {
|
|
8290
|
+
const payloadRecord = toRecord(payload);
|
|
8291
|
+
const calls = Array.isArray(payload) ? payload : payloadRecord && Array.isArray(payloadRecord.calls) ? payloadRecord.calls : [];
|
|
8292
|
+
return calls.map((call) => toRecord(call)).filter((call) => call !== null);
|
|
8293
|
+
};
|
|
8294
|
+
var turnsEqual = (left, right) => {
|
|
8295
|
+
return left.prompt === right.prompt && left.response === right.response;
|
|
8296
|
+
};
|
|
8297
|
+
var getPrefixMatchLength = (existing, incoming) => {
|
|
8298
|
+
const max = Math.min(existing.length, incoming.length);
|
|
8299
|
+
let matched = 0;
|
|
8300
|
+
while (matched < max && turnsEqual(existing[matched], incoming[matched])) {
|
|
8301
|
+
matched += 1;
|
|
8302
|
+
}
|
|
8303
|
+
return matched;
|
|
8304
|
+
};
|
|
8305
|
+
var getSuffixPrefixOverlap = (existing, incoming) => {
|
|
8306
|
+
const max = Math.min(existing.length, incoming.length);
|
|
8307
|
+
for (let overlap = max; overlap > 0; overlap -= 1) {
|
|
8308
|
+
let matches = true;
|
|
8309
|
+
for (let idx = 0; idx < overlap; idx += 1) {
|
|
8310
|
+
const left = existing[existing.length - overlap + idx];
|
|
8311
|
+
const right = incoming[idx];
|
|
8312
|
+
if (!turnsEqual(left, right)) {
|
|
8313
|
+
matches = false;
|
|
8314
|
+
break;
|
|
8315
|
+
}
|
|
8316
|
+
}
|
|
8317
|
+
if (matches) return overlap;
|
|
8318
|
+
}
|
|
8319
|
+
return 0;
|
|
8320
|
+
};
|
|
8321
|
+
var mergeTranscriptTurns = (existing, incoming) => {
|
|
8322
|
+
if (incoming.length === 0) return existing;
|
|
8323
|
+
if (existing.length === 0) return [...incoming];
|
|
8324
|
+
const prefixMatchLength = getPrefixMatchLength(existing, incoming);
|
|
8325
|
+
if (prefixMatchLength > 0) {
|
|
8326
|
+
return [...existing, ...incoming.slice(prefixMatchLength)];
|
|
8327
|
+
}
|
|
8328
|
+
const overlap = getSuffixPrefixOverlap(existing, incoming);
|
|
8329
|
+
if (overlap > 0) {
|
|
8330
|
+
return [...existing, ...incoming.slice(overlap)];
|
|
8331
|
+
}
|
|
8332
|
+
return [...existing, ...incoming];
|
|
8333
|
+
};
|
|
8334
|
+
var buildTurnsFromMessages = (messages, fallbackResponse, callId, timestampMs) => {
|
|
8335
|
+
const turns = [];
|
|
8336
|
+
for (let index = 0; index < messages.length; index += 1) {
|
|
8337
|
+
const message = messages[index];
|
|
8338
|
+
if (!message || message.role !== "user") continue;
|
|
8339
|
+
const prompt = message.content.trim();
|
|
8340
|
+
if (!prompt) continue;
|
|
8341
|
+
let response = "";
|
|
8342
|
+
let reachedNextUser = false;
|
|
8343
|
+
for (let lookAhead = index + 1; lookAhead < messages.length; lookAhead += 1) {
|
|
8344
|
+
const nextMessage = messages[lookAhead];
|
|
8345
|
+
if (!nextMessage) continue;
|
|
8346
|
+
if (nextMessage.role === "assistant") {
|
|
8347
|
+
response = nextMessage.content.trim();
|
|
8348
|
+
index = lookAhead;
|
|
8349
|
+
break;
|
|
8350
|
+
}
|
|
8351
|
+
if (nextMessage.role === "user") {
|
|
8352
|
+
reachedNextUser = true;
|
|
8353
|
+
break;
|
|
8354
|
+
}
|
|
8355
|
+
}
|
|
8356
|
+
if (!response && !reachedNextUser) {
|
|
8357
|
+
response = fallbackResponse;
|
|
8358
|
+
}
|
|
8359
|
+
if (!response) continue;
|
|
8360
|
+
turns.push({
|
|
8361
|
+
prompt,
|
|
8362
|
+
response,
|
|
8363
|
+
callId,
|
|
8364
|
+
timestampMs
|
|
8365
|
+
});
|
|
8366
|
+
}
|
|
8367
|
+
return turns;
|
|
8368
|
+
};
|
|
8369
|
+
var buildTranscriptTurnsFromCalls = (calls) => {
|
|
8370
|
+
const orderedCalls = calls.map((call, index) => ({
|
|
8371
|
+
call,
|
|
8372
|
+
index,
|
|
8373
|
+
timestampMs: getCallTimestampMs(call, index)
|
|
8374
|
+
})).sort((left, right) => {
|
|
8375
|
+
if (left.timestampMs === right.timestampMs) return left.index - right.index;
|
|
8376
|
+
return left.timestampMs - right.timestampMs;
|
|
8377
|
+
});
|
|
8378
|
+
let mergedTurns = [];
|
|
8379
|
+
for (const orderedCall of orderedCalls) {
|
|
8380
|
+
const { call, timestampMs } = orderedCall;
|
|
8381
|
+
const callId = getCallId(call);
|
|
8382
|
+
const fallbackResponse = normalizeContentText(call.response).trim();
|
|
8383
|
+
const parsedMessages = parseCallMessages(call.messages).filter(
|
|
8384
|
+
(message) => !shouldSkipTranscriptMessage(message)
|
|
8385
|
+
);
|
|
8386
|
+
let callTurns = buildTurnsFromMessages(
|
|
8387
|
+
parsedMessages,
|
|
8388
|
+
fallbackResponse,
|
|
8389
|
+
callId,
|
|
8390
|
+
timestampMs
|
|
8391
|
+
);
|
|
8392
|
+
if (callTurns.length === 0) {
|
|
8393
|
+
const fallbackPrompt = normalizeContentText(call.prompt).trim();
|
|
8394
|
+
if (fallbackPrompt && fallbackResponse) {
|
|
8395
|
+
callTurns = [
|
|
8396
|
+
{
|
|
8397
|
+
prompt: fallbackPrompt,
|
|
8398
|
+
response: fallbackResponse,
|
|
8399
|
+
callId,
|
|
8400
|
+
timestampMs
|
|
8401
|
+
}
|
|
8402
|
+
];
|
|
8403
|
+
}
|
|
8404
|
+
}
|
|
8405
|
+
mergedTurns = mergeTranscriptTurns(mergedTurns, callTurns);
|
|
8406
|
+
}
|
|
8407
|
+
return mergedTurns;
|
|
8408
|
+
};
|
|
8409
|
+
var buildHistoryFromTranscriptTurns = (turns) => {
|
|
8410
|
+
const history = {};
|
|
8411
|
+
const keyUsageByPrompt = /* @__PURE__ */ new Map();
|
|
8412
|
+
turns.forEach((turn, index) => {
|
|
8413
|
+
var _a;
|
|
8414
|
+
const prompt = turn.prompt.trim();
|
|
8415
|
+
const response = turn.response.trim();
|
|
8416
|
+
if (!prompt || !response) return;
|
|
8417
|
+
const baseTimestampMs = Number.isFinite(turn.timestampMs) ? turn.timestampMs : index;
|
|
8418
|
+
const keySeed = `${baseTimestampMs}:${prompt}`;
|
|
8419
|
+
const keyUsageCount = (_a = keyUsageByPrompt.get(keySeed)) != null ? _a : 0;
|
|
8420
|
+
keyUsageByPrompt.set(keySeed, keyUsageCount + 1);
|
|
8421
|
+
const uniqueTimestamp = new Date(baseTimestampMs + keyUsageCount).toISOString();
|
|
8422
|
+
const historyKey = `${uniqueTimestamp}:${prompt}`;
|
|
8423
|
+
history[historyKey] = {
|
|
8424
|
+
content: response,
|
|
8425
|
+
callId: turn.callId
|
|
8426
|
+
};
|
|
8427
|
+
});
|
|
8428
|
+
return history;
|
|
8429
|
+
};
|
|
8430
|
+
var truncatePromptForTitle = (prompt) => {
|
|
8431
|
+
if (prompt.length > 60) {
|
|
8432
|
+
return `${prompt.slice(0, 57)}...`;
|
|
8433
|
+
}
|
|
8434
|
+
return prompt;
|
|
8435
|
+
};
|
|
5952
8436
|
var EMPTY_ARRAY = [];
|
|
5953
8437
|
var EMPTY_HISTORY = {};
|
|
5954
8438
|
var ChatPanelWrapper = ({
|
|
@@ -5982,6 +8466,7 @@ var ChatPanelWrapper = ({
|
|
|
5982
8466
|
disabledSectionIds,
|
|
5983
8467
|
onToggleSection,
|
|
5984
8468
|
onConversationCreated,
|
|
8469
|
+
onBeforeSend,
|
|
5985
8470
|
conversationInitialPrompt,
|
|
5986
8471
|
// New props from ChatPanel port
|
|
5987
8472
|
cssUrl,
|
|
@@ -5998,7 +8483,11 @@ var ChatPanelWrapper = ({
|
|
|
5998
8483
|
callToActionEmailAddress,
|
|
5999
8484
|
callToActionEmailSubject,
|
|
6000
8485
|
customerEmailCaptureMode,
|
|
6001
|
-
customerEmailCapturePlaceholder
|
|
8486
|
+
customerEmailCapturePlaceholder,
|
|
8487
|
+
resolveMcpAuthHeaders,
|
|
8488
|
+
localToolExecutors,
|
|
8489
|
+
traceContextMode,
|
|
8490
|
+
autoApproveTools
|
|
6002
8491
|
}) => {
|
|
6003
8492
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
6004
8493
|
const convAgentProfile = getAgent(activeConv.agentId);
|
|
@@ -6022,6 +8511,16 @@ var ChatPanelWrapper = ({
|
|
|
6022
8511
|
},
|
|
6023
8512
|
[onConversationCreated, activeConv.conversationId]
|
|
6024
8513
|
);
|
|
8514
|
+
const beforeSendCallback = useCallback4(
|
|
8515
|
+
(payload) => {
|
|
8516
|
+
if (!onBeforeSend) return;
|
|
8517
|
+
return onBeforeSend(__spreadProps(__spreadValues({}, payload), {
|
|
8518
|
+
conversationId: payload.conversationId || activeConv.conversationId,
|
|
8519
|
+
agentId: payload.agentId || activeConv.agentId
|
|
8520
|
+
}));
|
|
8521
|
+
},
|
|
8522
|
+
[onBeforeSend, activeConv.conversationId, activeConv.agentId]
|
|
8523
|
+
);
|
|
6025
8524
|
const agentStatus = convAgentProfile == null ? void 0 : convAgentProfile.status;
|
|
6026
8525
|
const promptsString = (convAgentMetadata == null ? void 0 : convAgentMetadata.displayFollowOnPrompts) || "";
|
|
6027
8526
|
let effectiveFollowOnQuestions;
|
|
@@ -6085,6 +8584,7 @@ var ChatPanelWrapper = ({
|
|
|
6085
8584
|
disabledSectionIds,
|
|
6086
8585
|
onToggleSection,
|
|
6087
8586
|
onConversationCreated: conversationCreatedCallback,
|
|
8587
|
+
onBeforeSend: beforeSendCallback,
|
|
6088
8588
|
cssUrl,
|
|
6089
8589
|
markdownClass,
|
|
6090
8590
|
width,
|
|
@@ -6099,7 +8599,11 @@ var ChatPanelWrapper = ({
|
|
|
6099
8599
|
callToActionEmailAddress: (_g = callToActionEmailAddress != null ? callToActionEmailAddress : convAgentMetadata.displayCallToActionEmailAddress) != null ? _g : "",
|
|
6100
8600
|
callToActionEmailSubject: (_h = callToActionEmailSubject != null ? callToActionEmailSubject : convAgentMetadata.displayCallToActionEmailSubject) != null ? _h : "Agent CTA submitted",
|
|
6101
8601
|
customerEmailCaptureMode: (_i = customerEmailCaptureMode != null ? customerEmailCaptureMode : convAgentMetadata == null ? void 0 : convAgentMetadata.customerEmailCaptureMode) != null ? _i : "HIDE",
|
|
6102
|
-
customerEmailCapturePlaceholder: (_j = customerEmailCapturePlaceholder != null ? customerEmailCapturePlaceholder : convAgentMetadata == null ? void 0 : convAgentMetadata.customerEmailCapturePlaceholder) != null ? _j : "Please enter your email..."
|
|
8602
|
+
customerEmailCapturePlaceholder: (_j = customerEmailCapturePlaceholder != null ? customerEmailCapturePlaceholder : convAgentMetadata == null ? void 0 : convAgentMetadata.customerEmailCapturePlaceholder) != null ? _j : "Please enter your email...",
|
|
8603
|
+
resolveMcpAuthHeaders,
|
|
8604
|
+
localToolExecutors,
|
|
8605
|
+
traceContextMode,
|
|
8606
|
+
autoApproveTools
|
|
6103
8607
|
}
|
|
6104
8608
|
)
|
|
6105
8609
|
);
|
|
@@ -6150,6 +8654,7 @@ var AIAgentPanel = React15.forwardRef(({
|
|
|
6150
8654
|
enableContextDetailView = false,
|
|
6151
8655
|
onAgentSwitch,
|
|
6152
8656
|
onConversationChange,
|
|
8657
|
+
onBeforeSend,
|
|
6153
8658
|
historyChangedCallback,
|
|
6154
8659
|
responseCompleteCallback,
|
|
6155
8660
|
thumbsUpClick,
|
|
@@ -6181,7 +8686,11 @@ var AIAgentPanel = React15.forwardRef(({
|
|
|
6181
8686
|
callToActionEmailAddress,
|
|
6182
8687
|
callToActionEmailSubject,
|
|
6183
8688
|
customerEmailCaptureMode,
|
|
6184
|
-
customerEmailCapturePlaceholder
|
|
8689
|
+
customerEmailCapturePlaceholder,
|
|
8690
|
+
resolveMcpAuthHeaders,
|
|
8691
|
+
localToolExecutors,
|
|
8692
|
+
traceContextMode = "standard",
|
|
8693
|
+
autoApproveTools
|
|
6185
8694
|
}, ref) => {
|
|
6186
8695
|
var _a, _b, _c, _d;
|
|
6187
8696
|
useEffect10(() => {
|
|
@@ -6201,13 +8710,7 @@ var AIAgentPanel = React15.forwardRef(({
|
|
|
6201
8710
|
const [uncontrolledIsCollapsed, setUncontrolledIsCollapsed] = useState9(collapsible && defaultCollapsed);
|
|
6202
8711
|
const isControlled = controlledIsCollapsed !== void 0;
|
|
6203
8712
|
const isCollapsed = isControlled ? controlledIsCollapsed : uncontrolledIsCollapsed;
|
|
6204
|
-
const [isHistoryCollapsed, setIsHistoryCollapsed] = useState9(
|
|
6205
|
-
if (typeof window !== "undefined") {
|
|
6206
|
-
const saved = localStorage.getItem("ai-agent-panel-history-collapsed");
|
|
6207
|
-
return saved === "true";
|
|
6208
|
-
}
|
|
6209
|
-
return false;
|
|
6210
|
-
});
|
|
8713
|
+
const [isHistoryCollapsed, setIsHistoryCollapsed] = useState9(true);
|
|
6211
8714
|
const [panelWidth, setPanelWidth] = useState9(() => {
|
|
6212
8715
|
if (typeof window !== "undefined") {
|
|
6213
8716
|
const savedWidth = localStorage.getItem("ai-agent-panel-width");
|
|
@@ -6309,8 +8812,12 @@ var AIAgentPanel = React15.forwardRef(({
|
|
|
6309
8812
|
const [conversationsLoading, setConversationsLoading] = useState9(false);
|
|
6310
8813
|
const [conversationsError, setConversationsError] = useState9(null);
|
|
6311
8814
|
const [searchQuery, setSearchQuery] = useState9("");
|
|
8815
|
+
const controlledConversationId = typeof conversation === "string" && conversation.trim() !== "" ? conversation.trim() : null;
|
|
8816
|
+
const isConversationControlled = controlledConversationId !== null;
|
|
6312
8817
|
const [activeConversations, setActiveConversations] = useState9(/* @__PURE__ */ new Map());
|
|
6313
|
-
const [currentConversationId, setCurrentConversationId] = useState9(
|
|
8818
|
+
const [currentConversationId, setCurrentConversationId] = useState9(
|
|
8819
|
+
controlledConversationId
|
|
8820
|
+
);
|
|
6314
8821
|
const [conversationFirstPrompts, setConversationFirstPrompts] = useState9({});
|
|
6315
8822
|
const [loadingPrompts, setLoadingPrompts] = useState9(/* @__PURE__ */ new Set());
|
|
6316
8823
|
const [loadingConversationId, setLoadingConversationId] = useState9(null);
|
|
@@ -6330,6 +8837,7 @@ var AIAgentPanel = React15.forwardRef(({
|
|
|
6330
8837
|
agentList
|
|
6331
8838
|
} = useAgentRegistry(agentIds, { url, localOverrides });
|
|
6332
8839
|
const fetchInProgressRef = useRef7(false);
|
|
8840
|
+
const loadingTranscriptIdsRef = useRef7(/* @__PURE__ */ new Set());
|
|
6333
8841
|
const lastFetchedAgentRef = useRef7(null);
|
|
6334
8842
|
const checkedPromptsRef = useRef7(/* @__PURE__ */ new Set());
|
|
6335
8843
|
const fetchingPromptsRef = useRef7(/* @__PURE__ */ new Set());
|
|
@@ -6338,29 +8846,49 @@ var AIAgentPanel = React15.forwardRef(({
|
|
|
6338
8846
|
activeConversationsRef.current = activeConversations;
|
|
6339
8847
|
const currentConversationIdRef = useRef7(currentConversationId);
|
|
6340
8848
|
currentConversationIdRef.current = currentConversationId;
|
|
6341
|
-
|
|
6342
|
-
|
|
6343
|
-
const
|
|
8849
|
+
const commitConversationSelection = useCallback4(
|
|
8850
|
+
(conversationId, notifyChange) => {
|
|
8851
|
+
const shouldSyncLocalState = !isConversationControlled || !notifyChange || controlledConversationId === conversationId;
|
|
8852
|
+
if (shouldSyncLocalState) {
|
|
8853
|
+
setCurrentConversationId(conversationId);
|
|
8854
|
+
}
|
|
8855
|
+
if (notifyChange && conversationId && onConversationChange) {
|
|
8856
|
+
const shouldNotifyParent = !isConversationControlled || controlledConversationId !== conversationId;
|
|
8857
|
+
if (shouldNotifyParent) {
|
|
8858
|
+
onConversationChange(conversationId);
|
|
8859
|
+
}
|
|
8860
|
+
}
|
|
8861
|
+
},
|
|
8862
|
+
[controlledConversationId, isConversationControlled, onConversationChange]
|
|
8863
|
+
);
|
|
8864
|
+
const createDraftConversation = useCallback4(
|
|
8865
|
+
(agentId, conversationInitialPrompt) => {
|
|
6344
8866
|
const tempId = `new-${Date.now()}`;
|
|
6345
8867
|
setActiveConversations((prev) => {
|
|
6346
8868
|
const next = new Map(prev);
|
|
6347
8869
|
next.set(tempId, {
|
|
6348
8870
|
conversationId: tempId,
|
|
6349
8871
|
stableKey: tempId,
|
|
6350
|
-
agentId
|
|
8872
|
+
agentId,
|
|
6351
8873
|
history: {},
|
|
8874
|
+
transcriptLoaded: true,
|
|
6352
8875
|
isLoading: false,
|
|
6353
8876
|
title: "New conversation",
|
|
6354
|
-
conversationInitialPrompt
|
|
8877
|
+
conversationInitialPrompt
|
|
6355
8878
|
});
|
|
6356
8879
|
return next;
|
|
6357
8880
|
});
|
|
6358
|
-
|
|
6359
|
-
|
|
6360
|
-
|
|
6361
|
-
|
|
8881
|
+
return tempId;
|
|
8882
|
+
},
|
|
8883
|
+
[]
|
|
8884
|
+
);
|
|
8885
|
+
React15.useImperativeHandle(ref, () => ({
|
|
8886
|
+
startNewConversation: (prompt, agent) => {
|
|
8887
|
+
const targetAgent = agent || currentAgentId;
|
|
8888
|
+
const tempId = createDraftConversation(targetAgent, prompt);
|
|
8889
|
+
commitConversationSelection(tempId, true);
|
|
6362
8890
|
}
|
|
6363
|
-
}), [
|
|
8891
|
+
}), [commitConversationSelection, createDraftConversation, currentAgentId]);
|
|
6364
8892
|
const [showContextNotification, setShowContextNotification] = useState9(false);
|
|
6365
8893
|
const prevContextRef = useRef7(null);
|
|
6366
8894
|
const contextNotificationTimeoutRef = useRef7(null);
|
|
@@ -6502,14 +9030,15 @@ var AIAgentPanel = React15.forwardRef(({
|
|
|
6502
9030
|
}
|
|
6503
9031
|
}
|
|
6504
9032
|
}), [apiKey, customerId, getAgent, fetchFirstPrompt]);
|
|
6505
|
-
const loadConversationTranscript = useCallback4((conversationId, agentIdForConversation, title) => __async(void 0, null, function* () {
|
|
9033
|
+
const loadConversationTranscript = useCallback4((conversationId, agentIdForConversation, title, notifyConversationChange = true) => __async(void 0, null, function* () {
|
|
6506
9034
|
var _a2;
|
|
6507
9035
|
const existingActive = activeConversationsRef.current.get(conversationId);
|
|
6508
|
-
if (existingActive) {
|
|
6509
|
-
|
|
6510
|
-
|
|
6511
|
-
|
|
6512
|
-
|
|
9036
|
+
if (existingActive && (existingActive.transcriptLoaded || Object.keys(existingActive.history || {}).length > 0)) {
|
|
9037
|
+
commitConversationSelection(conversationId, notifyConversationChange);
|
|
9038
|
+
return;
|
|
9039
|
+
}
|
|
9040
|
+
if (loadingTranscriptIdsRef.current.has(conversationId)) {
|
|
9041
|
+
commitConversationSelection(conversationId, notifyConversationChange);
|
|
6513
9042
|
return;
|
|
6514
9043
|
}
|
|
6515
9044
|
const agentIdToUse = agentIdForConversation || currentAgentId;
|
|
@@ -6519,6 +9048,8 @@ var AIAgentPanel = React15.forwardRef(({
|
|
|
6519
9048
|
setConversationsError("Missing API key or project ID");
|
|
6520
9049
|
return;
|
|
6521
9050
|
}
|
|
9051
|
+
loadingTranscriptIdsRef.current.add(conversationId);
|
|
9052
|
+
setConversationsError(null);
|
|
6522
9053
|
setLoadingConversationId(conversationId);
|
|
6523
9054
|
try {
|
|
6524
9055
|
console.log("loadConversationTranscript - conversationId:", conversationId);
|
|
@@ -6531,57 +9062,34 @@ var AIAgentPanel = React15.forwardRef(({
|
|
|
6531
9062
|
}
|
|
6532
9063
|
});
|
|
6533
9064
|
if (!response.ok) {
|
|
9065
|
+
if (response.status === 404) {
|
|
9066
|
+
const conversationTitle2 = title || conversationFirstPrompts[conversationId] || "New conversation";
|
|
9067
|
+
setActiveConversations((prev) => {
|
|
9068
|
+
const next = new Map(prev);
|
|
9069
|
+
next.set(conversationId, {
|
|
9070
|
+
conversationId,
|
|
9071
|
+
stableKey: conversationId,
|
|
9072
|
+
agentId: agentIdToUse,
|
|
9073
|
+
history: {},
|
|
9074
|
+
transcriptLoaded: true,
|
|
9075
|
+
isLoading: false,
|
|
9076
|
+
title: conversationTitle2
|
|
9077
|
+
});
|
|
9078
|
+
return next;
|
|
9079
|
+
});
|
|
9080
|
+
commitConversationSelection(conversationId, notifyConversationChange);
|
|
9081
|
+
return;
|
|
9082
|
+
}
|
|
6534
9083
|
throw new Error(`Failed to load conversation (${response.status})`);
|
|
6535
9084
|
}
|
|
6536
9085
|
const payload = yield response.json();
|
|
6537
9086
|
console.log("loadConversationTranscript - API response:", payload);
|
|
6538
|
-
const
|
|
6539
|
-
|
|
6540
|
-
|
|
6541
|
-
|
|
6542
|
-
|
|
6543
|
-
|
|
6544
|
-
if (lastCall.messages) {
|
|
6545
|
-
try {
|
|
6546
|
-
const messages2 = JSON.parse(lastCall.messages);
|
|
6547
|
-
console.log("loadConversationTranscript - parsed messages:", messages2);
|
|
6548
|
-
const relevantMessages = messages2.filter(
|
|
6549
|
-
(msg) => msg.role !== "system" && !(msg.role === "user" && msg.content.startsWith("__system__:"))
|
|
6550
|
-
);
|
|
6551
|
-
console.log("loadConversationTranscript - filtered messages:", relevantMessages);
|
|
6552
|
-
for (let i = 0; i < relevantMessages.length; i++) {
|
|
6553
|
-
const msg = relevantMessages[i];
|
|
6554
|
-
if (!msg) continue;
|
|
6555
|
-
if (msg.role === "user") {
|
|
6556
|
-
if (!firstPrompt) {
|
|
6557
|
-
firstPrompt = msg.content.length > 60 ? msg.content.slice(0, 57) + "..." : msg.content;
|
|
6558
|
-
}
|
|
6559
|
-
const nextMsg = relevantMessages[i + 1];
|
|
6560
|
-
if (nextMsg && nextMsg.role === "assistant") {
|
|
6561
|
-
const historyKey = `${timestamp}:${msg.content}`;
|
|
6562
|
-
history[historyKey] = {
|
|
6563
|
-
content: nextMsg.content,
|
|
6564
|
-
callId
|
|
6565
|
-
};
|
|
6566
|
-
i++;
|
|
6567
|
-
} else {
|
|
6568
|
-
if (lastCall.response) {
|
|
6569
|
-
const historyKey = `${timestamp}:${msg.content}`;
|
|
6570
|
-
history[historyKey] = {
|
|
6571
|
-
content: lastCall.response,
|
|
6572
|
-
callId
|
|
6573
|
-
};
|
|
6574
|
-
}
|
|
6575
|
-
}
|
|
6576
|
-
}
|
|
6577
|
-
}
|
|
6578
|
-
} catch (err) {
|
|
6579
|
-
console.error("loadConversationTranscript - failed to parse messages property:", err);
|
|
6580
|
-
}
|
|
6581
|
-
}
|
|
6582
|
-
}
|
|
6583
|
-
console.log("loadConversationTranscript - created", Object.keys(history).length, "history entries");
|
|
6584
|
-
console.log("loadConversationTranscript - parsed history:", history);
|
|
9087
|
+
const calls = normalizeCallsPayload(payload);
|
|
9088
|
+
const transcriptTurns = buildTranscriptTurnsFromCalls(calls);
|
|
9089
|
+
const history = buildHistoryFromTranscriptTurns(transcriptTurns);
|
|
9090
|
+
const firstPrompt = transcriptTurns.length > 0 ? truncatePromptForTitle(transcriptTurns[0].prompt) : null;
|
|
9091
|
+
console.log("loadConversationTranscript - parsed calls:", calls.length);
|
|
9092
|
+
console.log("loadConversationTranscript - created history entries:", Object.keys(history).length);
|
|
6585
9093
|
if (firstPrompt) {
|
|
6586
9094
|
setConversationFirstPrompts((prev) => __spreadProps(__spreadValues({}, prev), {
|
|
6587
9095
|
[conversationId]: firstPrompt
|
|
@@ -6596,22 +9104,85 @@ var AIAgentPanel = React15.forwardRef(({
|
|
|
6596
9104
|
// Use real ID as stable key when loading from API
|
|
6597
9105
|
agentId: agentIdToUse,
|
|
6598
9106
|
history,
|
|
9107
|
+
transcriptLoaded: true,
|
|
6599
9108
|
isLoading: false,
|
|
6600
9109
|
title: conversationTitle
|
|
6601
9110
|
});
|
|
6602
9111
|
return next;
|
|
6603
9112
|
});
|
|
6604
|
-
|
|
6605
|
-
if (onConversationChange) {
|
|
6606
|
-
onConversationChange(conversationId);
|
|
6607
|
-
}
|
|
6608
|
-
setLoadingConversationId(null);
|
|
9113
|
+
commitConversationSelection(conversationId, notifyConversationChange);
|
|
6609
9114
|
} catch (error) {
|
|
6610
9115
|
console.error("Failed to load conversation:", error);
|
|
6611
9116
|
setConversationsError(error.message || "Failed to load conversation");
|
|
6612
|
-
|
|
9117
|
+
} finally {
|
|
9118
|
+
loadingTranscriptIdsRef.current.delete(conversationId);
|
|
9119
|
+
setLoadingConversationId((prev) => prev === conversationId ? null : prev);
|
|
9120
|
+
}
|
|
9121
|
+
}), [apiKey, commitConversationSelection, conversationFirstPrompts, currentAgentId, getAgent]);
|
|
9122
|
+
useEffect10(() => {
|
|
9123
|
+
if (!isConversationControlled) return;
|
|
9124
|
+
const targetConversationId = controlledConversationId;
|
|
9125
|
+
if (!targetConversationId) {
|
|
9126
|
+
if (currentConversationIdRef.current !== null) {
|
|
9127
|
+
setCurrentConversationId(null);
|
|
9128
|
+
}
|
|
9129
|
+
return;
|
|
9130
|
+
}
|
|
9131
|
+
if (targetConversationId.startsWith("new-")) {
|
|
9132
|
+
setActiveConversations((prev) => {
|
|
9133
|
+
if (prev.has(targetConversationId)) {
|
|
9134
|
+
return prev;
|
|
9135
|
+
}
|
|
9136
|
+
const next = new Map(prev);
|
|
9137
|
+
next.set(targetConversationId, {
|
|
9138
|
+
conversationId: targetConversationId,
|
|
9139
|
+
stableKey: targetConversationId,
|
|
9140
|
+
agentId: currentAgentId,
|
|
9141
|
+
history: {},
|
|
9142
|
+
transcriptLoaded: true,
|
|
9143
|
+
isLoading: false,
|
|
9144
|
+
title: "New conversation"
|
|
9145
|
+
});
|
|
9146
|
+
return next;
|
|
9147
|
+
});
|
|
9148
|
+
if (currentConversationIdRef.current !== targetConversationId) {
|
|
9149
|
+
setCurrentConversationId(targetConversationId);
|
|
9150
|
+
}
|
|
9151
|
+
return;
|
|
9152
|
+
}
|
|
9153
|
+
if (loadingConversationId === targetConversationId) {
|
|
9154
|
+
return;
|
|
9155
|
+
}
|
|
9156
|
+
const existingActive = activeConversationsRef.current.get(targetConversationId);
|
|
9157
|
+
if (existingActive && existingActive.transcriptLoaded && currentConversationIdRef.current === targetConversationId) {
|
|
9158
|
+
return;
|
|
9159
|
+
}
|
|
9160
|
+
const apiConversation = apiConversations.find(
|
|
9161
|
+
(conv) => conv.conversationId === targetConversationId
|
|
9162
|
+
);
|
|
9163
|
+
const targetAgentId = (apiConversation == null ? void 0 : apiConversation.agentId) || (existingActive == null ? void 0 : existingActive.agentId) || currentAgentId;
|
|
9164
|
+
if (!targetAgentId) {
|
|
9165
|
+
return;
|
|
9166
|
+
}
|
|
9167
|
+
if (targetAgentId !== currentAgentId) {
|
|
9168
|
+
setCurrentAgentId(targetAgentId);
|
|
6613
9169
|
}
|
|
6614
|
-
|
|
9170
|
+
const targetTitle = conversationFirstPrompts[targetConversationId] || (apiConversation == null ? void 0 : apiConversation.title) || (existingActive == null ? void 0 : existingActive.title);
|
|
9171
|
+
void loadConversationTranscript(
|
|
9172
|
+
targetConversationId,
|
|
9173
|
+
targetAgentId,
|
|
9174
|
+
targetTitle,
|
|
9175
|
+
false
|
|
9176
|
+
);
|
|
9177
|
+
}, [
|
|
9178
|
+
apiConversations,
|
|
9179
|
+
controlledConversationId,
|
|
9180
|
+
conversationFirstPrompts,
|
|
9181
|
+
currentAgentId,
|
|
9182
|
+
isConversationControlled,
|
|
9183
|
+
loadConversationTranscript,
|
|
9184
|
+
loadingConversationId
|
|
9185
|
+
]);
|
|
6615
9186
|
const handleRefreshConversations = useCallback4(() => {
|
|
6616
9187
|
fetchConversations(currentAgentId);
|
|
6617
9188
|
}, [currentAgentId, fetchConversations]);
|
|
@@ -6628,30 +9199,18 @@ var AIAgentPanel = React15.forwardRef(({
|
|
|
6628
9199
|
}
|
|
6629
9200
|
}, [agentsLoading, currentAgentId, apiKey, fetchConversations, getAgent, showConversationHistory]);
|
|
6630
9201
|
const handleNewConversation = useCallback4(() => {
|
|
6631
|
-
const tempId =
|
|
6632
|
-
|
|
6633
|
-
|
|
6634
|
-
next.set(tempId, {
|
|
6635
|
-
conversationId: tempId,
|
|
6636
|
-
stableKey: tempId,
|
|
6637
|
-
// Stable key never changes even when conversationId updates
|
|
6638
|
-
agentId: currentAgentId,
|
|
6639
|
-
history: {},
|
|
6640
|
-
isLoading: false,
|
|
6641
|
-
title: "New conversation"
|
|
6642
|
-
});
|
|
6643
|
-
return next;
|
|
6644
|
-
});
|
|
6645
|
-
setCurrentConversationId(tempId);
|
|
6646
|
-
}, [currentAgentId]);
|
|
9202
|
+
const tempId = createDraftConversation(currentAgentId);
|
|
9203
|
+
commitConversationSelection(tempId, true);
|
|
9204
|
+
}, [commitConversationSelection, createDraftConversation, currentAgentId]);
|
|
6647
9205
|
useEffect10(() => {
|
|
6648
9206
|
var _a2;
|
|
9207
|
+
if (isConversationControlled) return;
|
|
6649
9208
|
const agentProfile = getAgent(currentAgentId);
|
|
6650
9209
|
const isAgentReady = (_a2 = agentProfile == null ? void 0 : agentProfile.metadata) == null ? void 0 : _a2.projectId;
|
|
6651
9210
|
if (isAgentReady && !agentsLoading && activeConversations.size === 0) {
|
|
6652
9211
|
handleNewConversation();
|
|
6653
9212
|
}
|
|
6654
|
-
}, [currentAgentId, agentsLoading, activeConversations.size, getAgent, handleNewConversation]);
|
|
9213
|
+
}, [currentAgentId, agentsLoading, activeConversations.size, getAgent, handleNewConversation, isConversationControlled]);
|
|
6655
9214
|
const handleCloseConversation = useCallback4((conversationId, e) => {
|
|
6656
9215
|
var _a2;
|
|
6657
9216
|
if (e) {
|
|
@@ -6665,9 +9224,13 @@ var AIAgentPanel = React15.forwardRef(({
|
|
|
6665
9224
|
if (currentConversationIdRef.current === conversationId) {
|
|
6666
9225
|
const remaining = Array.from(activeConversationsRef.current.keys()).filter((id) => id !== conversationId);
|
|
6667
9226
|
const nextId = remaining.length > 0 ? (_a2 = remaining[0]) != null ? _a2 : null : null;
|
|
6668
|
-
|
|
9227
|
+
if (nextId) {
|
|
9228
|
+
commitConversationSelection(nextId, true);
|
|
9229
|
+
} else if (!isConversationControlled) {
|
|
9230
|
+
setCurrentConversationId(null);
|
|
9231
|
+
}
|
|
6669
9232
|
}
|
|
6670
|
-
}, []);
|
|
9233
|
+
}, [commitConversationSelection, isConversationControlled]);
|
|
6671
9234
|
const handleSelectConversation = useCallback4((conversationId) => {
|
|
6672
9235
|
loadConversationTranscript(conversationId);
|
|
6673
9236
|
}, [loadConversationTranscript]);
|
|
@@ -6968,6 +9531,7 @@ var AIAgentPanel = React15.forwardRef(({
|
|
|
6968
9531
|
}
|
|
6969
9532
|
next.set(targetConversationId, __spreadProps(__spreadValues({}, existing), {
|
|
6970
9533
|
history,
|
|
9534
|
+
transcriptLoaded: true,
|
|
6971
9535
|
title
|
|
6972
9536
|
}));
|
|
6973
9537
|
return next;
|
|
@@ -7057,26 +9621,23 @@ var AIAgentPanel = React15.forwardRef(({
|
|
|
7057
9621
|
return prev;
|
|
7058
9622
|
});
|
|
7059
9623
|
if (currentConversationIdRef.current === tempId) {
|
|
7060
|
-
|
|
7061
|
-
if (onConversationChange) {
|
|
7062
|
-
onConversationChange(realId);
|
|
7063
|
-
}
|
|
9624
|
+
commitConversationSelection(realId, true);
|
|
7064
9625
|
}
|
|
7065
|
-
}, [
|
|
9626
|
+
}, [commitConversationSelection]);
|
|
7066
9627
|
const toggleCollapse = useCallback4(() => {
|
|
7067
9628
|
if (!collapsible) return;
|
|
7068
9629
|
const newValue = !isCollapsed;
|
|
9630
|
+
if (!newValue) {
|
|
9631
|
+
setIsHistoryCollapsed(true);
|
|
9632
|
+
setShowSearch(false);
|
|
9633
|
+
}
|
|
7069
9634
|
if (!isControlled) {
|
|
7070
9635
|
setUncontrolledIsCollapsed(newValue);
|
|
7071
9636
|
}
|
|
7072
9637
|
onCollapsedChange == null ? void 0 : onCollapsedChange(newValue);
|
|
7073
9638
|
}, [collapsible, isCollapsed, isControlled, onCollapsedChange]);
|
|
7074
9639
|
const toggleHistoryCollapse = useCallback4(() => {
|
|
7075
|
-
setIsHistoryCollapsed((prev) =>
|
|
7076
|
-
const next = !prev;
|
|
7077
|
-
localStorage.setItem("ai-agent-panel-history-collapsed", String(next));
|
|
7078
|
-
return next;
|
|
7079
|
-
});
|
|
9640
|
+
setIsHistoryCollapsed((prev) => !prev);
|
|
7080
9641
|
}, []);
|
|
7081
9642
|
const panelClasses = [
|
|
7082
9643
|
"ai-agent-panel",
|
|
@@ -7148,27 +9709,11 @@ var AIAgentPanel = React15.forwardRef(({
|
|
|
7148
9709
|
}
|
|
7149
9710
|
onCollapsedChange == null ? void 0 : onCollapsedChange(false);
|
|
7150
9711
|
if (hasActiveConversation && activeConvForAgent) {
|
|
7151
|
-
setCurrentConversationId(activeConvForAgent.conversationId);
|
|
7152
9712
|
setCurrentAgentId(agent.id);
|
|
7153
|
-
|
|
7154
|
-
onConversationChange(activeConvForAgent.conversationId);
|
|
7155
|
-
}
|
|
9713
|
+
commitConversationSelection(activeConvForAgent.conversationId, true);
|
|
7156
9714
|
} else {
|
|
7157
|
-
const tempId =
|
|
7158
|
-
|
|
7159
|
-
const next = new Map(prev);
|
|
7160
|
-
next.set(tempId, {
|
|
7161
|
-
conversationId: tempId,
|
|
7162
|
-
stableKey: tempId,
|
|
7163
|
-
// Stable key never changes
|
|
7164
|
-
agentId: agent.id,
|
|
7165
|
-
history: {},
|
|
7166
|
-
isLoading: false,
|
|
7167
|
-
title: "New conversation"
|
|
7168
|
-
});
|
|
7169
|
-
return next;
|
|
7170
|
-
});
|
|
7171
|
-
setCurrentConversationId(tempId);
|
|
9715
|
+
const tempId = createDraftConversation(agent.id);
|
|
9716
|
+
commitConversationSelection(tempId, true);
|
|
7172
9717
|
setCurrentAgentId(agent.id);
|
|
7173
9718
|
}
|
|
7174
9719
|
},
|
|
@@ -7253,27 +9798,11 @@ var AIAgentPanel = React15.forwardRef(({
|
|
|
7253
9798
|
title: agent.name,
|
|
7254
9799
|
onClick: () => {
|
|
7255
9800
|
if (hasActiveConversation && activeConvForAgent) {
|
|
7256
|
-
setCurrentConversationId(activeConvForAgent.conversationId);
|
|
7257
9801
|
setCurrentAgentId(agent.id);
|
|
7258
|
-
|
|
7259
|
-
onConversationChange(activeConvForAgent.conversationId);
|
|
7260
|
-
}
|
|
9802
|
+
commitConversationSelection(activeConvForAgent.conversationId, true);
|
|
7261
9803
|
} else {
|
|
7262
|
-
const tempId =
|
|
7263
|
-
|
|
7264
|
-
const next = new Map(prev);
|
|
7265
|
-
next.set(tempId, {
|
|
7266
|
-
conversationId: tempId,
|
|
7267
|
-
stableKey: tempId,
|
|
7268
|
-
// Stable key never changes
|
|
7269
|
-
agentId: agent.id,
|
|
7270
|
-
history: {},
|
|
7271
|
-
isLoading: false,
|
|
7272
|
-
title: "New conversation"
|
|
7273
|
-
});
|
|
7274
|
-
return next;
|
|
7275
|
-
});
|
|
7276
|
-
setCurrentConversationId(tempId);
|
|
9804
|
+
const tempId = createDraftConversation(agent.id);
|
|
9805
|
+
commitConversationSelection(tempId, true);
|
|
7277
9806
|
setCurrentAgentId(agent.id);
|
|
7278
9807
|
}
|
|
7279
9808
|
},
|
|
@@ -7326,10 +9855,7 @@ var AIAgentPanel = React15.forwardRef(({
|
|
|
7326
9855
|
key: activeConv.stableKey,
|
|
7327
9856
|
className: `ai-agent-panel__conversation ai-agent-panel__conversation--active-item ${currentConversationId === activeConv.conversationId ? "ai-agent-panel__conversation--current" : ""}`,
|
|
7328
9857
|
onClick: () => {
|
|
7329
|
-
|
|
7330
|
-
if (onConversationChange) {
|
|
7331
|
-
onConversationChange(activeConv.conversationId);
|
|
7332
|
-
}
|
|
9858
|
+
commitConversationSelection(activeConv.conversationId, true);
|
|
7333
9859
|
}
|
|
7334
9860
|
},
|
|
7335
9861
|
/* @__PURE__ */ React15.createElement("div", { className: "ai-agent-panel__conversation-content" }, /* @__PURE__ */ React15.createElement("div", { className: "ai-agent-panel__conversation-title" }, activeConv.isLoading && /* @__PURE__ */ React15.createElement(LoadingDotIcon, null), /* @__PURE__ */ React15.createElement("span", null, activeConv.title))),
|
|
@@ -7350,12 +9876,12 @@ var AIAgentPanel = React15.forwardRef(({
|
|
|
7350
9876
|
},
|
|
7351
9877
|
/* @__PURE__ */ React15.createElement("span", null, group.label, " ", group.count > 0 && `(${group.count})`),
|
|
7352
9878
|
/* @__PURE__ */ React15.createElement("span", { className: "ai-agent-panel__group-chevron" }, expandedSections[group.label] ? "\u25BC" : "\u25B6")
|
|
7353
|
-
), expandedSections[group.label] && group.conversations.length > 0 && group.conversations.map((conv) => {
|
|
9879
|
+
), expandedSections[group.label] && group.conversations.length > 0 && group.conversations.map((conv, convIndex) => {
|
|
7354
9880
|
const isActive = activeConversations.has(conv.conversationId);
|
|
7355
9881
|
return /* @__PURE__ */ React15.createElement(
|
|
7356
9882
|
"div",
|
|
7357
9883
|
{
|
|
7358
|
-
key: conv.conversationId
|
|
9884
|
+
key: `${group.label}-${conv.conversationId}-${convIndex}`,
|
|
7359
9885
|
className: `ai-agent-panel__conversation ${currentConversationId === conv.conversationId ? "ai-agent-panel__conversation--current" : ""} ${isActive ? "ai-agent-panel__conversation--in-active" : ""}`,
|
|
7360
9886
|
onClick: () => handleConversationSelect(conv)
|
|
7361
9887
|
},
|
|
@@ -7365,7 +9891,7 @@ var AIAgentPanel = React15.forwardRef(({
|
|
|
7365
9891
|
/* @__PURE__ */ React15.createElement("div", { className: "ai-agent-panel__chat" }, !showConversationHistory && collapsible && /* @__PURE__ */ React15.createElement("div", { className: "ai-agent-panel__chat-header" }, /* @__PURE__ */ React15.createElement("div", { className: "ai-agent-panel__chat-header-spacer" }), /* @__PURE__ */ React15.createElement(Tooltip, { content: "Collapse Panel", side: position === "right" ? "left" : "right" }, /* @__PURE__ */ React15.createElement(Button, { variant: "ghost", size: "icon", onClick: toggleCollapse }, position === "right" ? /* @__PURE__ */ React15.createElement(ChevronRightIcon, null) : /* @__PURE__ */ React15.createElement(ChevronLeftIcon, null)))), showContextNotification && /* @__PURE__ */ React15.createElement("div", { className: "ai-agent-panel__context-notification" }, /* @__PURE__ */ React15.createElement(SparkleIcon, null), /* @__PURE__ */ React15.createElement("span", null, "Agent now has new context")), activeConversationsList.map((activeConv) => /* @__PURE__ */ React15.createElement(
|
|
7366
9892
|
ChatPanelWrapper,
|
|
7367
9893
|
{
|
|
7368
|
-
key:
|
|
9894
|
+
key: activeConv.stableKey,
|
|
7369
9895
|
activeConv,
|
|
7370
9896
|
currentConversationId,
|
|
7371
9897
|
getAgent,
|
|
@@ -7396,6 +9922,7 @@ var AIAgentPanel = React15.forwardRef(({
|
|
|
7396
9922
|
disabledSectionIds: currentDisabledSections,
|
|
7397
9923
|
onToggleSection: handleContextSectionToggle,
|
|
7398
9924
|
onConversationCreated: handleConversationCreated,
|
|
9925
|
+
onBeforeSend,
|
|
7399
9926
|
conversationInitialPrompt: activeConv.conversationInitialPrompt,
|
|
7400
9927
|
cssUrl,
|
|
7401
9928
|
markdownClass,
|
|
@@ -7411,7 +9938,11 @@ var AIAgentPanel = React15.forwardRef(({
|
|
|
7411
9938
|
callToActionEmailAddress,
|
|
7412
9939
|
callToActionEmailSubject,
|
|
7413
9940
|
customerEmailCaptureMode,
|
|
7414
|
-
customerEmailCapturePlaceholder
|
|
9941
|
+
customerEmailCapturePlaceholder,
|
|
9942
|
+
resolveMcpAuthHeaders,
|
|
9943
|
+
localToolExecutors,
|
|
9944
|
+
traceContextMode,
|
|
9945
|
+
autoApproveTools
|
|
7415
9946
|
}
|
|
7416
9947
|
)), loadingConversationId && /* @__PURE__ */ React15.createElement("div", { className: "ai-agent-panel__conversation-loading-overlay" }, /* @__PURE__ */ React15.createElement("div", { className: "ai-agent-panel__loading-spinner" }), /* @__PURE__ */ React15.createElement("p", null, "Loading conversation...")), currentAgentMetadata && activeConversationsList.length === 0 && !loadingConversationId && /* @__PURE__ */ React15.createElement("div", { className: "ai-agent-panel__empty-chat" }, /* @__PURE__ */ React15.createElement(MessageIcon, null), /* @__PURE__ */ React15.createElement("p", null, "Select a conversation or start a new one"), /* @__PURE__ */ React15.createElement(Button, { variant: "default", size: "sm", onClick: handleNewConversation }, "New Conversation")), agentsLoading && !currentAgentMetadata && /* @__PURE__ */ React15.createElement("div", { className: "ai-agent-panel__loading" }, /* @__PURE__ */ React15.createElement("div", { className: "ai-agent-panel__loading-spinner" }), /* @__PURE__ */ React15.createElement("p", null, "Loading agent..."))),
|
|
7417
9948
|
/* @__PURE__ */ React15.createElement(
|