@dudousxd/nestjs-agent-react 0.8.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -0
- package/dist/index.cjs +668 -187
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +251 -2
- package/dist/index.d.ts +251 -2
- package/dist/index.js +576 -110
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,6 +1,65 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
3
|
|
|
4
|
+
// src/reasoning/timing.ts
|
|
5
|
+
import { useEffect, useRef, useState } from "react";
|
|
6
|
+
var REASONING_METADATA_KEY = "agent";
|
|
7
|
+
function reasoningDurationMetadata(reasoningMs) {
|
|
8
|
+
return {
|
|
9
|
+
[REASONING_METADATA_KEY]: {
|
|
10
|
+
reasoningMs
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
__name(reasoningDurationMetadata, "reasoningDurationMetadata");
|
|
15
|
+
function readReasoningMs(part) {
|
|
16
|
+
const metadata = part.providerMetadata;
|
|
17
|
+
if (typeof metadata !== "object" || metadata === null) return null;
|
|
18
|
+
const scoped = metadata[REASONING_METADATA_KEY];
|
|
19
|
+
if (typeof scoped !== "object" || scoped === null) return null;
|
|
20
|
+
const value = scoped.reasoningMs;
|
|
21
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
|
|
22
|
+
}
|
|
23
|
+
__name(readReasoningMs, "readReasoningMs");
|
|
24
|
+
function useElapsed(running, options = {}) {
|
|
25
|
+
const { intervalMs = 1e3 } = options;
|
|
26
|
+
const nowRef = useRef(options.now ?? Date.now);
|
|
27
|
+
nowRef.current = options.now ?? Date.now;
|
|
28
|
+
const startedAt = useRef(null);
|
|
29
|
+
const [elapsed, setElapsed] = useState(0);
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
if (!running) {
|
|
32
|
+
if (startedAt.current !== null) {
|
|
33
|
+
setElapsed(nowRef.current() - startedAt.current);
|
|
34
|
+
startedAt.current = null;
|
|
35
|
+
}
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
startedAt.current = nowRef.current();
|
|
39
|
+
setElapsed(0);
|
|
40
|
+
const timer = setInterval(() => {
|
|
41
|
+
if (startedAt.current !== null) setElapsed(nowRef.current() - startedAt.current);
|
|
42
|
+
}, intervalMs);
|
|
43
|
+
return () => clearInterval(timer);
|
|
44
|
+
}, [
|
|
45
|
+
running,
|
|
46
|
+
intervalMs
|
|
47
|
+
]);
|
|
48
|
+
return elapsed;
|
|
49
|
+
}
|
|
50
|
+
__name(useElapsed, "useElapsed");
|
|
51
|
+
function formatElapsed(ms) {
|
|
52
|
+
if (!Number.isFinite(ms) || ms < 1e3) return "<1s";
|
|
53
|
+
const totalSeconds = Math.floor(ms / 1e3);
|
|
54
|
+
const hours = Math.floor(totalSeconds / 3600);
|
|
55
|
+
const minutes = Math.floor(totalSeconds % 3600 / 60);
|
|
56
|
+
const seconds = totalSeconds % 60;
|
|
57
|
+
if (hours > 0) return minutes > 0 ? `${hours}h ${minutes}m` : `${hours}h`;
|
|
58
|
+
if (minutes > 0) return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;
|
|
59
|
+
return `${seconds}s`;
|
|
60
|
+
}
|
|
61
|
+
__name(formatElapsed, "formatElapsed");
|
|
62
|
+
|
|
4
63
|
// src/agent-chat-transport.ts
|
|
5
64
|
var HEADER_RUN_ID = "x-agent-run-id";
|
|
6
65
|
var HEADER_THREAD_ID = "x-agent-thread-id";
|
|
@@ -158,6 +217,7 @@ var AgentChatTransport = class {
|
|
|
158
217
|
let stepIndex = 0;
|
|
159
218
|
let textId = null;
|
|
160
219
|
let reasoningId = null;
|
|
220
|
+
let reasoningStartedAt = 0;
|
|
161
221
|
let textSeq = 0;
|
|
162
222
|
let reasoningSeq = 0;
|
|
163
223
|
const announced = /* @__PURE__ */ new Set();
|
|
@@ -194,7 +254,7 @@ var AgentChatTransport = class {
|
|
|
194
254
|
if (!stepOpen) openStep();
|
|
195
255
|
}
|
|
196
256
|
__name(ensureStep, "ensureStep");
|
|
197
|
-
function closeRuns() {
|
|
257
|
+
function closeRuns(reasoningMs) {
|
|
198
258
|
if (textId !== null) {
|
|
199
259
|
controller.enqueue({
|
|
200
260
|
type: "text-end",
|
|
@@ -205,15 +265,16 @@ var AgentChatTransport = class {
|
|
|
205
265
|
if (reasoningId !== null) {
|
|
206
266
|
controller.enqueue({
|
|
207
267
|
type: "reasoning-end",
|
|
208
|
-
id: reasoningId
|
|
268
|
+
id: reasoningId,
|
|
269
|
+
providerMetadata: reasoningDurationMetadata(reasoningMs ?? Math.max(0, Date.now() - reasoningStartedAt))
|
|
209
270
|
});
|
|
210
271
|
reasoningId = null;
|
|
211
272
|
}
|
|
212
273
|
}
|
|
213
274
|
__name(closeRuns, "closeRuns");
|
|
214
|
-
function closeStep() {
|
|
275
|
+
function closeStep(reasoningMs) {
|
|
215
276
|
if (!stepOpen) return;
|
|
216
|
-
closeRuns();
|
|
277
|
+
closeRuns(reasoningMs);
|
|
217
278
|
controller.enqueue({
|
|
218
279
|
type: "finish-step"
|
|
219
280
|
});
|
|
@@ -252,7 +313,7 @@ var AgentChatTransport = class {
|
|
|
252
313
|
openStep();
|
|
253
314
|
break;
|
|
254
315
|
case "step-finish":
|
|
255
|
-
closeStep();
|
|
316
|
+
closeStep(event.reasoningMs);
|
|
256
317
|
if (event.costUsd !== void 0) {
|
|
257
318
|
controller.enqueue({
|
|
258
319
|
type: "message-metadata",
|
|
@@ -283,6 +344,7 @@ var AgentChatTransport = class {
|
|
|
283
344
|
if (reasoningId === null) {
|
|
284
345
|
reasoningId = reasoningSeq === 0 ? `rsn-${stepIndex}` : `rsn-${stepIndex}.${reasoningSeq}`;
|
|
285
346
|
reasoningSeq += 1;
|
|
347
|
+
reasoningStartedAt = Date.now();
|
|
286
348
|
controller.enqueue({
|
|
287
349
|
type: "reasoning-start",
|
|
288
350
|
id: reasoningId
|
|
@@ -617,6 +679,15 @@ var AgentClient = class {
|
|
|
617
679
|
const query = threadId === void 0 ? "" : `?threadId=${encodeURIComponent(threadId)}`;
|
|
618
680
|
return this.request("GET", `/agent/skills${query}`);
|
|
619
681
|
}
|
|
682
|
+
/**
|
|
683
|
+
* The tools this caller can reach through `agent` (the default agent when omitted), each with the
|
|
684
|
+
* server-declared `presentation` a chat narrates it by — the same list the model is offered.
|
|
685
|
+
* Prefer {@link useToolCatalog}, which fetches it once and shares it.
|
|
686
|
+
*/
|
|
687
|
+
listTools(agent) {
|
|
688
|
+
const query = agent === void 0 ? "" : `?agent=${encodeURIComponent(agent)}`;
|
|
689
|
+
return this.request("GET", `/agent/tools${query}`);
|
|
690
|
+
}
|
|
620
691
|
getThread(id) {
|
|
621
692
|
return this.request("GET", `/agent/threads/${encodeURIComponent(id)}`);
|
|
622
693
|
}
|
|
@@ -730,10 +801,10 @@ var AgentClient = class {
|
|
|
730
801
|
};
|
|
731
802
|
|
|
732
803
|
// src/components/chat-input.tsx
|
|
733
|
-
import React2, { useEffect as
|
|
804
|
+
import React2, { useEffect as useEffect3, useState as useState3 } from "react";
|
|
734
805
|
|
|
735
806
|
// src/components/use-speech-recognition.ts
|
|
736
|
-
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
807
|
+
import { useCallback, useEffect as useEffect2, useMemo, useRef as useRef2, useState as useState2 } from "react";
|
|
737
808
|
function getRecognitionCtor() {
|
|
738
809
|
if (typeof window === "undefined") return null;
|
|
739
810
|
const scope = window;
|
|
@@ -741,15 +812,15 @@ function getRecognitionCtor() {
|
|
|
741
812
|
}
|
|
742
813
|
__name(getRecognitionCtor, "getRecognitionCtor");
|
|
743
814
|
function useSpeechRecognition({ lang = "en-US", onFinalTranscript, onInterimTranscript }) {
|
|
744
|
-
const recognitionRef =
|
|
745
|
-
const [isListening, setIsListening] =
|
|
815
|
+
const recognitionRef = useRef2(null);
|
|
816
|
+
const [isListening, setIsListening] = useState2(false);
|
|
746
817
|
const ctor = useMemo(() => getRecognitionCtor(), []);
|
|
747
818
|
const isSupported = ctor !== null;
|
|
748
|
-
const finalRef =
|
|
749
|
-
const interimRef =
|
|
819
|
+
const finalRef = useRef2(onFinalTranscript);
|
|
820
|
+
const interimRef = useRef2(onInterimTranscript);
|
|
750
821
|
finalRef.current = onFinalTranscript;
|
|
751
822
|
interimRef.current = onInterimTranscript;
|
|
752
|
-
|
|
823
|
+
useEffect2(() => {
|
|
753
824
|
if (!ctor) return;
|
|
754
825
|
const recognition = new ctor();
|
|
755
826
|
recognition.lang = lang;
|
|
@@ -817,8 +888,8 @@ __name(useSpeechRecognition, "useSpeechRecognition");
|
|
|
817
888
|
|
|
818
889
|
// src/components/chat-input.tsx
|
|
819
890
|
function ChatInput({ onSubmit, disabled, placeholder, rows = 2, enableSpeech = true, speechLang = "en-US", sendLabel = "Send", onStop, isStreaming = false, stopLabel = "Stop generating", className, textareaClassName, sendButtonClassName, micButtonClassName, stopButtonClassName, renderMic }) {
|
|
820
|
-
const [value, setValue] =
|
|
821
|
-
const [interim, setInterim] =
|
|
891
|
+
const [value, setValue] = useState3("");
|
|
892
|
+
const [interim, setInterim] = useState3("");
|
|
822
893
|
const speech = useSpeechRecognition({
|
|
823
894
|
lang: speechLang,
|
|
824
895
|
onFinalTranscript: /* @__PURE__ */ __name((text) => {
|
|
@@ -829,7 +900,7 @@ function ChatInput({ onSubmit, disabled, placeholder, rows = 2, enableSpeech = t
|
|
|
829
900
|
}, "onFinalTranscript"),
|
|
830
901
|
onInterimTranscript: /* @__PURE__ */ __name((text) => setInterim(text), "onInterimTranscript")
|
|
831
902
|
});
|
|
832
|
-
|
|
903
|
+
useEffect3(() => {
|
|
833
904
|
if (!speech.isListening) setInterim("");
|
|
834
905
|
}, [
|
|
835
906
|
speech.isListening
|
|
@@ -896,10 +967,283 @@ __name(ChatInput, "ChatInput");
|
|
|
896
967
|
import React3 from "react";
|
|
897
968
|
|
|
898
969
|
// src/transcript/use-chat-transcript.ts
|
|
899
|
-
import { useCallback as useCallback3, useEffect as
|
|
970
|
+
import { useCallback as useCallback3, useEffect as useEffect5, useRef as useRef4, useState as useState5 } from "react";
|
|
971
|
+
|
|
972
|
+
// src/transcript/model.ts
|
|
973
|
+
import { getToolName as getToolName2, isDataUIPart, isFileUIPart, isReasoningUIPart, isTextUIPart, isToolUIPart } from "ai";
|
|
974
|
+
|
|
975
|
+
// src/presentation/tool-activity.ts
|
|
976
|
+
import { getToolName } from "ai";
|
|
977
|
+
|
|
978
|
+
// src/presentation/phrasing.ts
|
|
979
|
+
function toolCatalogFrom(entries) {
|
|
980
|
+
const catalog = {};
|
|
981
|
+
for (const entry of entries) {
|
|
982
|
+
if (entry.presentation !== void 0) catalog[entry.name] = entry.presentation;
|
|
983
|
+
}
|
|
984
|
+
return catalog;
|
|
985
|
+
}
|
|
986
|
+
__name(toolCatalogFrom, "toolCatalogFrom");
|
|
987
|
+
function readPath(value, path) {
|
|
988
|
+
return path.split(".").reduce((current, key) => {
|
|
989
|
+
if (current === null || typeof current !== "object") return void 0;
|
|
990
|
+
return current[key];
|
|
991
|
+
}, value);
|
|
992
|
+
}
|
|
993
|
+
__name(readPath, "readPath");
|
|
994
|
+
function renderValue(value) {
|
|
995
|
+
if (value === null || value === void 0) return "";
|
|
996
|
+
if (typeof value === "string") return value;
|
|
997
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
998
|
+
if (Array.isArray(value)) return value.map(renderValue).filter(Boolean).join(", ");
|
|
999
|
+
return "";
|
|
1000
|
+
}
|
|
1001
|
+
__name(renderValue, "renderValue");
|
|
1002
|
+
function fillTemplate(template, context) {
|
|
1003
|
+
return template.replace(/(\s*)\{([\w.]+)\}/g, (_match, space, path) => {
|
|
1004
|
+
const rendered = renderValue(readPath(context, path));
|
|
1005
|
+
return rendered === "" ? "" : `${space}${rendered}`;
|
|
1006
|
+
}).replace(/\s{2,}/g, " ").trim();
|
|
1007
|
+
}
|
|
1008
|
+
__name(fillTemplate, "fillTemplate");
|
|
1009
|
+
function phraseFor(presentation, input, isSettled2, fallback = {
|
|
1010
|
+
running: "Working",
|
|
1011
|
+
done: "Done"
|
|
1012
|
+
}) {
|
|
1013
|
+
if (presentation === void 0) return isSettled2 ? fallback.done : fallback.running;
|
|
1014
|
+
const filled = fillTemplate(isSettled2 ? presentation.done : presentation.running, input);
|
|
1015
|
+
return filled === "" ? presentation.label : filled;
|
|
1016
|
+
}
|
|
1017
|
+
__name(phraseFor, "phraseFor");
|
|
1018
|
+
|
|
1019
|
+
// src/presentation/result-view.ts
|
|
1020
|
+
function isRecord(value) {
|
|
1021
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1022
|
+
}
|
|
1023
|
+
__name(isRecord, "isRecord");
|
|
1024
|
+
function toText(value) {
|
|
1025
|
+
if (value === null || value === void 0) return "\u2014";
|
|
1026
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
1027
|
+
return String(value);
|
|
1028
|
+
}
|
|
1029
|
+
if (Array.isArray(value)) return value.map(toText).join(", ");
|
|
1030
|
+
return "\u2014";
|
|
1031
|
+
}
|
|
1032
|
+
__name(toText, "toText");
|
|
1033
|
+
function inferResultView(output) {
|
|
1034
|
+
if (!isRecord(output)) return void 0;
|
|
1035
|
+
for (const [key, value] of Object.entries(output)) {
|
|
1036
|
+
if (!Array.isArray(value) || value.length === 0) continue;
|
|
1037
|
+
if (value.every((entry) => typeof entry === "string")) {
|
|
1038
|
+
return {
|
|
1039
|
+
kind: "log",
|
|
1040
|
+
lines: key
|
|
1041
|
+
};
|
|
1042
|
+
}
|
|
1043
|
+
if (value.every(isRecord)) {
|
|
1044
|
+
const first = value[0];
|
|
1045
|
+
return {
|
|
1046
|
+
kind: "table",
|
|
1047
|
+
rows: key,
|
|
1048
|
+
columns: Object.keys(first).filter((column) => !isRecord(first[column])).map((column) => ({
|
|
1049
|
+
path: column,
|
|
1050
|
+
label: column
|
|
1051
|
+
}))
|
|
1052
|
+
};
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
const fields = Object.entries(output).filter(([, value]) => [
|
|
1056
|
+
"string",
|
|
1057
|
+
"number",
|
|
1058
|
+
"boolean"
|
|
1059
|
+
].includes(typeof value)).map(([key]) => ({
|
|
1060
|
+
path: key,
|
|
1061
|
+
label: key
|
|
1062
|
+
}));
|
|
1063
|
+
return fields.length > 0 ? {
|
|
1064
|
+
kind: "metrics",
|
|
1065
|
+
fields
|
|
1066
|
+
} : void 0;
|
|
1067
|
+
}
|
|
1068
|
+
__name(inferResultView, "inferResultView");
|
|
1069
|
+
function resolveResultView(output, view, options = {}) {
|
|
1070
|
+
const resolved = view ?? (options.infer === true ? inferResultView(output) : void 0);
|
|
1071
|
+
if (resolved === void 0 || resolved.kind === "elsewhere") return null;
|
|
1072
|
+
switch (resolved.kind) {
|
|
1073
|
+
case "note": {
|
|
1074
|
+
const text = fillTemplate(resolved.text, output);
|
|
1075
|
+
return text === "" ? null : {
|
|
1076
|
+
kind: "note",
|
|
1077
|
+
text
|
|
1078
|
+
};
|
|
1079
|
+
}
|
|
1080
|
+
case "metrics": {
|
|
1081
|
+
const readings = resolved.fields.map((field) => ({
|
|
1082
|
+
field,
|
|
1083
|
+
value: readPath(output, field.path)
|
|
1084
|
+
})).filter((entry) => entry.value !== void 0 && entry.value !== null).map(({ field, value }) => ({
|
|
1085
|
+
label: field.label,
|
|
1086
|
+
value: toText(value),
|
|
1087
|
+
unit: field.unit ?? null
|
|
1088
|
+
}));
|
|
1089
|
+
return readings.length === 0 ? null : {
|
|
1090
|
+
kind: "metrics",
|
|
1091
|
+
readings
|
|
1092
|
+
};
|
|
1093
|
+
}
|
|
1094
|
+
case "log": {
|
|
1095
|
+
const lines = readPath(output, resolved.lines);
|
|
1096
|
+
if (!Array.isArray(lines) || lines.length === 0) return null;
|
|
1097
|
+
return {
|
|
1098
|
+
kind: "log",
|
|
1099
|
+
lines: lines.map(toText)
|
|
1100
|
+
};
|
|
1101
|
+
}
|
|
1102
|
+
case "table": {
|
|
1103
|
+
const rows = readPath(output, resolved.rows);
|
|
1104
|
+
if (!Array.isArray(rows)) return null;
|
|
1105
|
+
return {
|
|
1106
|
+
kind: "table",
|
|
1107
|
+
columns: resolved.columns,
|
|
1108
|
+
rows: rows.map((row) => resolved.columns.map((column) => toText(readPath(row, column.path)))),
|
|
1109
|
+
empty: rows.length === 0 ? resolved.empty ?? null : null
|
|
1110
|
+
};
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
__name(resolveResultView, "resolveResultView");
|
|
1115
|
+
|
|
1116
|
+
// src/presentation/tool-activity.ts
|
|
1117
|
+
function isActionCall(part) {
|
|
1118
|
+
const metadata = part.toolMetadata;
|
|
1119
|
+
return typeof metadata === "object" && metadata !== null && metadata.toolKind === "action";
|
|
1120
|
+
}
|
|
1121
|
+
__name(isActionCall, "isActionCall");
|
|
1122
|
+
function toolCallState(part) {
|
|
1123
|
+
const output = "output" in part ? part.output : void 0;
|
|
1124
|
+
const errorText = "errorText" in part ? part.errorText : void 0;
|
|
1125
|
+
const outputError = output !== null && typeof output === "object" && "error" in output ? String(output.error) : void 0;
|
|
1126
|
+
const isDenied = part.state === "output-denied";
|
|
1127
|
+
const isFailed = part.state === "output-error" || outputError !== void 0 && !isDenied;
|
|
1128
|
+
const isSettled2 = part.state === "output-available" || part.state === "output-error" || isDenied;
|
|
1129
|
+
const isAwaiting = part.state === "approval-requested" || part.state === "input-available" && isActionCall(part);
|
|
1130
|
+
const status = isDenied ? "denied" : isFailed ? "failed" : isSettled2 ? "done" : isAwaiting ? "awaiting-approval" : "running";
|
|
1131
|
+
return {
|
|
1132
|
+
status,
|
|
1133
|
+
isSettled: isSettled2,
|
|
1134
|
+
isFailed,
|
|
1135
|
+
isDenied,
|
|
1136
|
+
output,
|
|
1137
|
+
error: errorText ?? outputError ?? null
|
|
1138
|
+
};
|
|
1139
|
+
}
|
|
1140
|
+
__name(toolCallState, "toolCallState");
|
|
1141
|
+
function correctedCallIds(parts) {
|
|
1142
|
+
const corrected = /* @__PURE__ */ new Set();
|
|
1143
|
+
const lastSuccessByTool = /* @__PURE__ */ new Map();
|
|
1144
|
+
parts.forEach((part, index) => {
|
|
1145
|
+
if (part.state === "output-available" && !toolCallState(part).isFailed) {
|
|
1146
|
+
lastSuccessByTool.set(getToolName(part), index);
|
|
1147
|
+
}
|
|
1148
|
+
});
|
|
1149
|
+
parts.forEach((part, index) => {
|
|
1150
|
+
const successAt = lastSuccessByTool.get(getToolName(part));
|
|
1151
|
+
if (successAt !== void 0 && index < successAt && toolCallState(part).isFailed) {
|
|
1152
|
+
corrected.add(part.toolCallId);
|
|
1153
|
+
}
|
|
1154
|
+
});
|
|
1155
|
+
return corrected;
|
|
1156
|
+
}
|
|
1157
|
+
__name(correctedCallIds, "correctedCallIds");
|
|
1158
|
+
function describeToolCall(part, catalog, options = {}) {
|
|
1159
|
+
const presentation = catalog?.[getToolName(part)];
|
|
1160
|
+
const state = toolCallState(part);
|
|
1161
|
+
const input = part.input;
|
|
1162
|
+
const confirm = presentation?.confirm;
|
|
1163
|
+
return {
|
|
1164
|
+
status: state.status,
|
|
1165
|
+
phrase: phraseFor(presentation, input, state.isSettled, options.fallback),
|
|
1166
|
+
label: presentation?.label ?? null,
|
|
1167
|
+
icon: presentation?.icon ?? null,
|
|
1168
|
+
tone: presentation?.tone ?? "neutral",
|
|
1169
|
+
detail: presentation?.detail ?? null,
|
|
1170
|
+
confirm: confirm === void 0 ? null : {
|
|
1171
|
+
title: fillTemplate(confirm.title, input),
|
|
1172
|
+
verb: confirm.verb,
|
|
1173
|
+
detail: confirm.detail !== void 0 ? fillTemplate(confirm.detail, input) : null
|
|
1174
|
+
},
|
|
1175
|
+
result: state.status === "done" ? resolveResultView(state.output, presentation?.result, {
|
|
1176
|
+
...options.inferResult !== void 0 ? {
|
|
1177
|
+
infer: options.inferResult
|
|
1178
|
+
} : {}
|
|
1179
|
+
}) : null,
|
|
1180
|
+
error: state.error,
|
|
1181
|
+
presentation: presentation ?? null
|
|
1182
|
+
};
|
|
1183
|
+
}
|
|
1184
|
+
__name(describeToolCall, "describeToolCall");
|
|
1185
|
+
var STATUS_WEIGHT = {
|
|
1186
|
+
running: 4,
|
|
1187
|
+
"awaiting-approval": 3,
|
|
1188
|
+
failed: 2,
|
|
1189
|
+
denied: 1,
|
|
1190
|
+
done: 0
|
|
1191
|
+
};
|
|
1192
|
+
function descendants(call) {
|
|
1193
|
+
return call.children.flatMap((child) => [
|
|
1194
|
+
child,
|
|
1195
|
+
...descendants(child)
|
|
1196
|
+
]);
|
|
1197
|
+
}
|
|
1198
|
+
__name(descendants, "descendants");
|
|
1199
|
+
function leaves(call) {
|
|
1200
|
+
return call.children.length === 0 ? [
|
|
1201
|
+
call
|
|
1202
|
+
] : call.children.flatMap(leaves);
|
|
1203
|
+
}
|
|
1204
|
+
__name(leaves, "leaves");
|
|
1205
|
+
function groupToolActivity(calls, options = {}) {
|
|
1206
|
+
const expanded = options.expandNested === true ? calls.flatMap(leaves) : [
|
|
1207
|
+
...calls
|
|
1208
|
+
];
|
|
1209
|
+
const corrected = options.hideCorrected === true ? correctedCallIds(expanded.map((call) => call.part)) : /* @__PURE__ */ new Set();
|
|
1210
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1211
|
+
for (const call of expanded) {
|
|
1212
|
+
if (corrected.has(call.toolCallId)) continue;
|
|
1213
|
+
const presentation = options.catalog?.[call.name];
|
|
1214
|
+
const key = options.keyOf?.(call, presentation) ?? presentation?.label ?? call.name;
|
|
1215
|
+
const status = toolCallState(call.part).status;
|
|
1216
|
+
const phrase = phraseFor(presentation, call.part.input, status !== "running" && status !== "awaiting-approval", options.fallback);
|
|
1217
|
+
const inner = options.expandNested === true ? 0 : descendants(call).length;
|
|
1218
|
+
const existing = groups.get(key);
|
|
1219
|
+
if (existing === void 0) {
|
|
1220
|
+
groups.set(key, {
|
|
1221
|
+
key,
|
|
1222
|
+
label: presentation?.label ?? null,
|
|
1223
|
+
icon: presentation?.icon ?? null,
|
|
1224
|
+
status,
|
|
1225
|
+
count: 1,
|
|
1226
|
+
phrase,
|
|
1227
|
+
calls: [
|
|
1228
|
+
call
|
|
1229
|
+
],
|
|
1230
|
+
innerCount: inner
|
|
1231
|
+
});
|
|
1232
|
+
continue;
|
|
1233
|
+
}
|
|
1234
|
+
existing.count += 1;
|
|
1235
|
+
existing.calls.push(call);
|
|
1236
|
+
existing.phrase = phrase;
|
|
1237
|
+
existing.innerCount += inner;
|
|
1238
|
+
if (STATUS_WEIGHT[status] > STATUS_WEIGHT[existing.status]) existing.status = status;
|
|
1239
|
+
}
|
|
1240
|
+
return [
|
|
1241
|
+
...groups.values()
|
|
1242
|
+
];
|
|
1243
|
+
}
|
|
1244
|
+
__name(groupToolActivity, "groupToolActivity");
|
|
900
1245
|
|
|
901
1246
|
// src/transcript/model.ts
|
|
902
|
-
import { getToolName, isDataUIPart, isFileUIPart, isReasoningUIPart, isTextUIPart, isToolUIPart } from "ai";
|
|
903
1247
|
function buildTranscriptBlocks(message, options) {
|
|
904
1248
|
const blocks = [];
|
|
905
1249
|
let toolBuffer = [];
|
|
@@ -916,13 +1260,19 @@ function buildTranscriptBlocks(message, options) {
|
|
|
916
1260
|
if (toolBuffer.length === 0) {
|
|
917
1261
|
return;
|
|
918
1262
|
}
|
|
919
|
-
const calls = toolBuffer.map((part) => buildToolCall(part, options.approval, approvals.get(part.toolCallId) ?? null));
|
|
1263
|
+
const calls = toolBuffer.map((part) => buildToolCall(part, options.approval, approvals.get(part.toolCallId) ?? null, options.toolCatalog));
|
|
1264
|
+
const roots = nestToolCalls(calls);
|
|
920
1265
|
blocks.push({
|
|
921
1266
|
kind: "tools",
|
|
922
1267
|
key: `${message.id}-tools-${toolCounter++}`,
|
|
923
1268
|
parts: toolBuffer,
|
|
924
1269
|
calls,
|
|
925
|
-
roots
|
|
1270
|
+
roots,
|
|
1271
|
+
activity: groupToolActivity(roots, {
|
|
1272
|
+
...options.toolCatalog !== void 0 ? {
|
|
1273
|
+
catalog: options.toolCatalog
|
|
1274
|
+
} : {}
|
|
1275
|
+
})
|
|
926
1276
|
});
|
|
927
1277
|
toolBuffer = [];
|
|
928
1278
|
}
|
|
@@ -1017,6 +1367,7 @@ function buildTranscriptBlocks(message, options) {
|
|
|
1017
1367
|
key,
|
|
1018
1368
|
text: part.text,
|
|
1019
1369
|
isStreaming,
|
|
1370
|
+
durationMs: readReasoningMs(part),
|
|
1020
1371
|
isOpen: options.isReasoningOpen(key, isStreaming),
|
|
1021
1372
|
toggle: /* @__PURE__ */ __name((open) => options.toggleReasoning(key, open), "toggle")
|
|
1022
1373
|
});
|
|
@@ -1070,7 +1421,7 @@ function isSettled(state) {
|
|
|
1070
1421
|
__name(isSettled, "isSettled");
|
|
1071
1422
|
function toolKind(part) {
|
|
1072
1423
|
const metadata = part.toolMetadata;
|
|
1073
|
-
return
|
|
1424
|
+
return isRecord2(metadata) && typeof metadata.toolKind === "string" ? metadata.toolKind : void 0;
|
|
1074
1425
|
}
|
|
1075
1426
|
__name(toolKind, "toolKind");
|
|
1076
1427
|
function isAwaitingApproval(part) {
|
|
@@ -1085,7 +1436,7 @@ function isAwaitingApproval(part) {
|
|
|
1085
1436
|
__name(isAwaitingApproval, "isAwaitingApproval");
|
|
1086
1437
|
function toolParentId(part) {
|
|
1087
1438
|
const metadata = part.toolMetadata;
|
|
1088
|
-
return
|
|
1439
|
+
return isRecord2(metadata) && typeof metadata.parentId === "string" ? metadata.parentId : null;
|
|
1089
1440
|
}
|
|
1090
1441
|
__name(toolParentId, "toolParentId");
|
|
1091
1442
|
function nestToolCalls(calls) {
|
|
@@ -1118,18 +1469,19 @@ function isAncestor(call, candidate, byId) {
|
|
|
1118
1469
|
return false;
|
|
1119
1470
|
}
|
|
1120
1471
|
__name(isAncestor, "isAncestor");
|
|
1121
|
-
function buildToolCall(part, options, approval) {
|
|
1472
|
+
function buildToolCall(part, options, approval, catalog) {
|
|
1122
1473
|
const toolCallId = part.toolCallId;
|
|
1123
1474
|
const awaiting = isAwaitingApproval(part);
|
|
1124
1475
|
const sending = awaiting ? options?.submitting(toolCallId) ?? null : null;
|
|
1125
1476
|
return {
|
|
1126
1477
|
part,
|
|
1127
1478
|
toolCallId,
|
|
1128
|
-
name:
|
|
1479
|
+
name: getToolName2(part),
|
|
1129
1480
|
toolKind: toolKind(part) ?? null,
|
|
1130
1481
|
parentId: toolParentId(part),
|
|
1131
1482
|
children: [],
|
|
1132
1483
|
approval,
|
|
1484
|
+
description: describeToolCall(part, catalog),
|
|
1133
1485
|
isAwaitingApproval: awaiting,
|
|
1134
1486
|
approve: {
|
|
1135
1487
|
available: awaiting && options?.canApprove === true,
|
|
@@ -1147,17 +1499,17 @@ function buildToolCall(part, options, approval) {
|
|
|
1147
1499
|
__name(buildToolCall, "buildToolCall");
|
|
1148
1500
|
function readElicitationRequest(part) {
|
|
1149
1501
|
const input = part.input;
|
|
1150
|
-
if (!
|
|
1502
|
+
if (!isRecord2(input) || !Array.isArray(input.questions) || input.questions.length === 0) {
|
|
1151
1503
|
return null;
|
|
1152
1504
|
}
|
|
1153
1505
|
const questions = [];
|
|
1154
1506
|
for (const candidate of input.questions) {
|
|
1155
|
-
if (!
|
|
1507
|
+
if (!isRecord2(candidate) || typeof candidate.id !== "string" || typeof candidate.prompt !== "string" || !Array.isArray(candidate.options) || candidate.options.length === 0) {
|
|
1156
1508
|
return null;
|
|
1157
1509
|
}
|
|
1158
1510
|
const options = [];
|
|
1159
1511
|
for (const option of candidate.options) {
|
|
1160
|
-
if (!
|
|
1512
|
+
if (!isRecord2(option) || typeof option.value !== "string" || typeof option.label !== "string") {
|
|
1161
1513
|
return null;
|
|
1162
1514
|
}
|
|
1163
1515
|
options.push({
|
|
@@ -1182,7 +1534,7 @@ function readElicitationRequest(part) {
|
|
|
1182
1534
|
__name(readElicitationRequest, "readElicitationRequest");
|
|
1183
1535
|
function readElicitationOutcome(part) {
|
|
1184
1536
|
const output = part.output;
|
|
1185
|
-
if (!
|
|
1537
|
+
if (!isRecord2(output) || !isRecord2(output.answers) || typeof output.skipped !== "boolean") {
|
|
1186
1538
|
return null;
|
|
1187
1539
|
}
|
|
1188
1540
|
const answers = {};
|
|
@@ -1269,7 +1621,7 @@ function readApprovals(parts) {
|
|
|
1269
1621
|
continue;
|
|
1270
1622
|
}
|
|
1271
1623
|
const data = part.data;
|
|
1272
|
-
if (!
|
|
1624
|
+
if (!isRecord2(data) || typeof data.id !== "string" || typeof data.approver !== "string") {
|
|
1273
1625
|
continue;
|
|
1274
1626
|
}
|
|
1275
1627
|
out.set(data.id, {
|
|
@@ -1283,7 +1635,7 @@ function readApprovals(parts) {
|
|
|
1283
1635
|
__name(readApprovals, "readApprovals");
|
|
1284
1636
|
function readUiComponent(part) {
|
|
1285
1637
|
const data = part.data;
|
|
1286
|
-
if (!
|
|
1638
|
+
if (!isRecord2(data) || typeof data.component !== "string") {
|
|
1287
1639
|
return null;
|
|
1288
1640
|
}
|
|
1289
1641
|
const id = typeof data.id === "string" ? data.id : part.id;
|
|
@@ -1293,18 +1645,18 @@ function readUiComponent(part) {
|
|
|
1293
1645
|
return {
|
|
1294
1646
|
id,
|
|
1295
1647
|
component: data.component,
|
|
1296
|
-
props:
|
|
1648
|
+
props: isRecord2(data.props) ? data.props : {},
|
|
1297
1649
|
version: typeof data.version === "number" ? data.version : null
|
|
1298
1650
|
};
|
|
1299
1651
|
}
|
|
1300
1652
|
__name(readUiComponent, "readUiComponent");
|
|
1301
|
-
function
|
|
1653
|
+
function isRecord2(value) {
|
|
1302
1654
|
return typeof value === "object" && value !== null;
|
|
1303
1655
|
}
|
|
1304
|
-
__name(
|
|
1656
|
+
__name(isRecord2, "isRecord");
|
|
1305
1657
|
function readQuery(part) {
|
|
1306
1658
|
const input = part.input;
|
|
1307
|
-
if (!
|
|
1659
|
+
if (!isRecord2(input) || typeof input.query !== "string") {
|
|
1308
1660
|
return null;
|
|
1309
1661
|
}
|
|
1310
1662
|
return input.query;
|
|
@@ -1312,12 +1664,12 @@ function readQuery(part) {
|
|
|
1312
1664
|
__name(readQuery, "readQuery");
|
|
1313
1665
|
function readPassages(part) {
|
|
1314
1666
|
const output = part.output;
|
|
1315
|
-
if (!
|
|
1667
|
+
if (!isRecord2(output) || !Array.isArray(output.passages) || output.passages.length === 0) {
|
|
1316
1668
|
return null;
|
|
1317
1669
|
}
|
|
1318
1670
|
const passages = [];
|
|
1319
1671
|
for (const candidate of output.passages) {
|
|
1320
|
-
if (!
|
|
1672
|
+
if (!isRecord2(candidate) || typeof candidate.id !== "string" || typeof candidate.text !== "string") {
|
|
1321
1673
|
return null;
|
|
1322
1674
|
}
|
|
1323
1675
|
passages.push({
|
|
@@ -1327,7 +1679,7 @@ function readPassages(part) {
|
|
|
1327
1679
|
...typeof candidate.source === "string" ? {
|
|
1328
1680
|
source: candidate.source
|
|
1329
1681
|
} : {},
|
|
1330
|
-
...
|
|
1682
|
+
...isRecord2(candidate.metadata) ? {
|
|
1331
1683
|
metadata: candidate.metadata
|
|
1332
1684
|
} : {}
|
|
1333
1685
|
});
|
|
@@ -1429,10 +1781,10 @@ function formatCostUsd(cost) {
|
|
|
1429
1781
|
__name(formatCostUsd, "formatCostUsd");
|
|
1430
1782
|
|
|
1431
1783
|
// src/transcript/use-stick-to-bottom.ts
|
|
1432
|
-
import { useCallback as useCallback2, useEffect as
|
|
1784
|
+
import { useCallback as useCallback2, useEffect as useEffect4, useRef as useRef3, useState as useState4 } from "react";
|
|
1433
1785
|
function useStickToBottom({ contentKey, threshold = 32 }) {
|
|
1434
|
-
const containerRef =
|
|
1435
|
-
const [isAtBottom, setIsAtBottom] =
|
|
1786
|
+
const containerRef = useRef3(null);
|
|
1787
|
+
const [isAtBottom, setIsAtBottom] = useState4(true);
|
|
1436
1788
|
const measure = useCallback2(() => {
|
|
1437
1789
|
const element = containerRef.current;
|
|
1438
1790
|
if (!element) {
|
|
@@ -1459,7 +1811,7 @@ function useStickToBottom({ contentKey, threshold = 32 }) {
|
|
|
1459
1811
|
}, [
|
|
1460
1812
|
measure
|
|
1461
1813
|
]);
|
|
1462
|
-
|
|
1814
|
+
useEffect4(() => {
|
|
1463
1815
|
if (isAtBottom) {
|
|
1464
1816
|
scrollToBottom();
|
|
1465
1817
|
}
|
|
@@ -1490,14 +1842,14 @@ var DEFAULT_LOAD_EARLIER_STEP = 50;
|
|
|
1490
1842
|
var DEFAULT_COPY_RESET_MS = 1500;
|
|
1491
1843
|
function useChatTranscript(options) {
|
|
1492
1844
|
const { messages, status, initialVisibleCount = DEFAULT_VISIBLE_COUNT, loadEarlierStep = DEFAULT_LOAD_EARLIER_STEP, followUps, stickToBottomThreshold } = options;
|
|
1493
|
-
const latest =
|
|
1845
|
+
const latest = useRef4(options);
|
|
1494
1846
|
latest.current = options;
|
|
1495
|
-
const [visibleCount, setVisibleCount] =
|
|
1496
|
-
const [stopRequested, setStopRequested] =
|
|
1847
|
+
const [visibleCount, setVisibleCount] = useState5(initialVisibleCount);
|
|
1848
|
+
const [stopRequested, setStopRequested] = useState5(false);
|
|
1497
1849
|
const isStreaming = status === "streaming";
|
|
1498
1850
|
const isBusy = status === "submitted" || isStreaming;
|
|
1499
1851
|
const isEmpty = messages.length === 0;
|
|
1500
|
-
|
|
1852
|
+
useEffect5(() => {
|
|
1501
1853
|
if (!isBusy) {
|
|
1502
1854
|
setStopRequested(false);
|
|
1503
1855
|
}
|
|
@@ -1559,7 +1911,7 @@ function useChatTranscript(options) {
|
|
|
1559
1911
|
__name(useChatTranscript, "useChatTranscript");
|
|
1560
1912
|
function useTranscriptItem(options) {
|
|
1561
1913
|
const { message, isStreaming = false } = options;
|
|
1562
|
-
const messagesRef =
|
|
1914
|
+
const messagesRef = useRef4([
|
|
1563
1915
|
message
|
|
1564
1916
|
]);
|
|
1565
1917
|
if (messagesRef.current[0] !== message) {
|
|
@@ -1577,13 +1929,13 @@ function useTranscriptItem(options) {
|
|
|
1577
1929
|
}
|
|
1578
1930
|
__name(useTranscriptItem, "useTranscriptItem");
|
|
1579
1931
|
function useTranscriptItems({ messages, visibleStart, streamingMessageId, options }) {
|
|
1580
|
-
const [drafts, setDrafts] =
|
|
1581
|
-
const [copied, setCopied] =
|
|
1582
|
-
const [openReasoning, setOpenReasoning] =
|
|
1583
|
-
const [picks, setPicks] =
|
|
1584
|
-
const [settling, setSettling] =
|
|
1585
|
-
const [settleErrors, setSettleErrors] =
|
|
1586
|
-
const latest =
|
|
1932
|
+
const [drafts, setDrafts] = useState5(() => /* @__PURE__ */ new Map());
|
|
1933
|
+
const [copied, setCopied] = useState5(() => /* @__PURE__ */ new Set());
|
|
1934
|
+
const [openReasoning, setOpenReasoning] = useState5(() => /* @__PURE__ */ new Map());
|
|
1935
|
+
const [picks, setPicks] = useState5(() => /* @__PURE__ */ new Map());
|
|
1936
|
+
const [settling, setSettling] = useState5(() => /* @__PURE__ */ new Map());
|
|
1937
|
+
const [settleErrors, setSettleErrors] = useState5(() => /* @__PURE__ */ new Map());
|
|
1938
|
+
const latest = useRef4({
|
|
1587
1939
|
options,
|
|
1588
1940
|
drafts,
|
|
1589
1941
|
picks,
|
|
@@ -1595,15 +1947,15 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
|
|
|
1595
1947
|
picks,
|
|
1596
1948
|
messages
|
|
1597
1949
|
};
|
|
1598
|
-
const copyTimers =
|
|
1599
|
-
|
|
1950
|
+
const copyTimers = useRef4(/* @__PURE__ */ new Map());
|
|
1951
|
+
useEffect5(() => () => {
|
|
1600
1952
|
for (const timer of copyTimers.current.values()) {
|
|
1601
1953
|
clearTimeout(timer);
|
|
1602
1954
|
}
|
|
1603
1955
|
copyTimers.current.clear();
|
|
1604
1956
|
}, []);
|
|
1605
|
-
const callbackCache =
|
|
1606
|
-
const reasoningToggleCache =
|
|
1957
|
+
const callbackCache = useRef4(/* @__PURE__ */ new Map());
|
|
1958
|
+
const reasoningToggleCache = useRef4(/* @__PURE__ */ new Map());
|
|
1607
1959
|
const toggleReasoning = useCallback3((key, open) => {
|
|
1608
1960
|
setOpenReasoning((current) => {
|
|
1609
1961
|
const next = new Map(current);
|
|
@@ -1794,6 +2146,9 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
|
|
|
1794
2146
|
...options.sources !== void 0 ? {
|
|
1795
2147
|
sources: options.sources
|
|
1796
2148
|
} : {},
|
|
2149
|
+
...options.toolCatalog !== void 0 ? {
|
|
2150
|
+
toolCatalog: options.toolCatalog
|
|
2151
|
+
} : {},
|
|
1797
2152
|
...options.onAnswer !== void 0 ? {
|
|
1798
2153
|
elicitation: {
|
|
1799
2154
|
picked: /* @__PURE__ */ __name((toolCallId, questionId) => picks.get(pickKey(toolCallId, questionId)), "picked"),
|
|
@@ -2332,18 +2687,18 @@ function toItem(entry) {
|
|
|
2332
2687
|
__name(toItem, "toItem");
|
|
2333
2688
|
|
|
2334
2689
|
// src/composer/use-composer-autocomplete.ts
|
|
2335
|
-
import { useCallback as useCallback4, useEffect as
|
|
2690
|
+
import { useCallback as useCallback4, useEffect as useEffect6, useId, useLayoutEffect, useMemo as useMemo2, useRef as useRef5, useState as useState6 } from "react";
|
|
2336
2691
|
function useComposerAutocomplete(options) {
|
|
2337
2692
|
const { value, sources, acceptOnTab = true } = options;
|
|
2338
|
-
const latest =
|
|
2693
|
+
const latest = useRef5(options);
|
|
2339
2694
|
latest.current = options;
|
|
2340
|
-
const inputRef =
|
|
2341
|
-
const [caret, setCaret] =
|
|
2342
|
-
const [items, setItems] =
|
|
2343
|
-
const [isLoading, setLoading] =
|
|
2344
|
-
const [error, setError] =
|
|
2345
|
-
const [activeIndex, setActiveIndex] =
|
|
2346
|
-
const [dismissedIndex, setDismissedIndex] =
|
|
2695
|
+
const inputRef = useRef5(null);
|
|
2696
|
+
const [caret, setCaret] = useState6(value.length);
|
|
2697
|
+
const [items, setItems] = useState6([]);
|
|
2698
|
+
const [isLoading, setLoading] = useState6(false);
|
|
2699
|
+
const [error, setError] = useState6(null);
|
|
2700
|
+
const [activeIndex, setActiveIndex] = useState6(0);
|
|
2701
|
+
const [dismissedIndex, setDismissedIndex] = useState6(null);
|
|
2347
2702
|
const safeCaret = Math.min(caret, value.length);
|
|
2348
2703
|
const match = useMemo2(() => findActiveTrigger(value, safeCaret, sources), [
|
|
2349
2704
|
value,
|
|
@@ -2351,16 +2706,16 @@ function useComposerAutocomplete(options) {
|
|
|
2351
2706
|
sources
|
|
2352
2707
|
]);
|
|
2353
2708
|
const isActive = match !== null && dismissedIndex !== match.index;
|
|
2354
|
-
const matchRef =
|
|
2709
|
+
const matchRef = useRef5(match);
|
|
2355
2710
|
matchRef.current = match;
|
|
2356
|
-
const caretRef =
|
|
2711
|
+
const caretRef = useRef5(safeCaret);
|
|
2357
2712
|
caretRef.current = safeCaret;
|
|
2358
|
-
const itemsRef =
|
|
2713
|
+
const itemsRef = useRef5(items);
|
|
2359
2714
|
itemsRef.current = items;
|
|
2360
|
-
const activeIndexRef =
|
|
2715
|
+
const activeIndexRef = useRef5(activeIndex);
|
|
2361
2716
|
activeIndexRef.current = activeIndex;
|
|
2362
2717
|
const requestKey = isActive && match ? `${match.source.id}\0${match.query}` : null;
|
|
2363
|
-
|
|
2718
|
+
useEffect6(() => {
|
|
2364
2719
|
const current = matchRef.current;
|
|
2365
2720
|
if (requestKey === null || current === null) {
|
|
2366
2721
|
setItems([]);
|
|
@@ -2425,7 +2780,7 @@ function useComposerAutocomplete(options) {
|
|
|
2425
2780
|
const current = matchRef.current;
|
|
2426
2781
|
if (current) setDismissedIndex(current.index);
|
|
2427
2782
|
}, []);
|
|
2428
|
-
const pendingCaret =
|
|
2783
|
+
const pendingCaret = useRef5(null);
|
|
2429
2784
|
const accept = useCallback4((item) => {
|
|
2430
2785
|
const current = matchRef.current;
|
|
2431
2786
|
if (!current) return;
|
|
@@ -2569,6 +2924,78 @@ function isPromise(value) {
|
|
|
2569
2924
|
}
|
|
2570
2925
|
__name(isPromise, "isPromise");
|
|
2571
2926
|
|
|
2927
|
+
// src/presentation/use-tool-catalog.ts
|
|
2928
|
+
import { useCallback as useCallback5, useEffect as useEffect7, useMemo as useMemo3, useState as useState7 } from "react";
|
|
2929
|
+
var shared = /* @__PURE__ */ new WeakMap();
|
|
2930
|
+
function load(client, agent) {
|
|
2931
|
+
let byAgent = shared.get(client);
|
|
2932
|
+
if (byAgent === void 0) {
|
|
2933
|
+
byAgent = /* @__PURE__ */ new Map();
|
|
2934
|
+
shared.set(client, byAgent);
|
|
2935
|
+
}
|
|
2936
|
+
const key = agent ?? "";
|
|
2937
|
+
const cached = byAgent.get(key);
|
|
2938
|
+
if (cached !== void 0) return cached;
|
|
2939
|
+
const request = client.listTools(agent).catch((error) => {
|
|
2940
|
+
byAgent.delete(key);
|
|
2941
|
+
throw error;
|
|
2942
|
+
});
|
|
2943
|
+
byAgent.set(key, request);
|
|
2944
|
+
return request;
|
|
2945
|
+
}
|
|
2946
|
+
__name(load, "load");
|
|
2947
|
+
function useToolCatalog(options) {
|
|
2948
|
+
const { client, agent, enabled = true } = options;
|
|
2949
|
+
const [entries, setEntries] = useState7([]);
|
|
2950
|
+
const [isLoading, setLoading] = useState7(enabled);
|
|
2951
|
+
const [error, setError] = useState7(null);
|
|
2952
|
+
const [generation, setGeneration] = useState7(0);
|
|
2953
|
+
useEffect7(() => {
|
|
2954
|
+
if (!enabled) {
|
|
2955
|
+
setLoading(false);
|
|
2956
|
+
return;
|
|
2957
|
+
}
|
|
2958
|
+
let cancelled = false;
|
|
2959
|
+
setLoading(true);
|
|
2960
|
+
load(client, agent).then((loaded) => {
|
|
2961
|
+
if (cancelled) return;
|
|
2962
|
+
setEntries(loaded);
|
|
2963
|
+
setError(null);
|
|
2964
|
+
setLoading(false);
|
|
2965
|
+
}, (failure) => {
|
|
2966
|
+
if (cancelled) return;
|
|
2967
|
+
setError(failure instanceof Error ? failure : new Error(String(failure)));
|
|
2968
|
+
setLoading(false);
|
|
2969
|
+
});
|
|
2970
|
+
return () => {
|
|
2971
|
+
cancelled = true;
|
|
2972
|
+
};
|
|
2973
|
+
}, [
|
|
2974
|
+
client,
|
|
2975
|
+
agent,
|
|
2976
|
+
enabled,
|
|
2977
|
+
generation
|
|
2978
|
+
]);
|
|
2979
|
+
const refresh = useCallback5(() => {
|
|
2980
|
+
shared.get(client)?.delete(agent ?? "");
|
|
2981
|
+
setGeneration((current) => current + 1);
|
|
2982
|
+
}, [
|
|
2983
|
+
client,
|
|
2984
|
+
agent
|
|
2985
|
+
]);
|
|
2986
|
+
const catalog = useMemo3(() => toolCatalogFrom(entries), [
|
|
2987
|
+
entries
|
|
2988
|
+
]);
|
|
2989
|
+
return {
|
|
2990
|
+
catalog,
|
|
2991
|
+
entries,
|
|
2992
|
+
isLoading,
|
|
2993
|
+
error,
|
|
2994
|
+
refresh
|
|
2995
|
+
};
|
|
2996
|
+
}
|
|
2997
|
+
__name(useToolCatalog, "useToolCatalog");
|
|
2998
|
+
|
|
2572
2999
|
// src/stored-message-to-ui-message.ts
|
|
2573
3000
|
import { DEFAULT_REFUSAL_REASON } from "@dudousxd/nestjs-agent-core";
|
|
2574
3001
|
function isRefusal(result) {
|
|
@@ -2590,6 +3017,16 @@ function refusalReason(result) {
|
|
|
2590
3017
|
__name(refusalReason, "refusalReason");
|
|
2591
3018
|
function storedMessageToUiMessage(message) {
|
|
2592
3019
|
const parts = [];
|
|
3020
|
+
if (message.reasoning) {
|
|
3021
|
+
parts.push({
|
|
3022
|
+
type: "reasoning",
|
|
3023
|
+
text: message.reasoning,
|
|
3024
|
+
state: "done",
|
|
3025
|
+
...message.reasoningMs !== void 0 ? {
|
|
3026
|
+
providerMetadata: reasoningDurationMetadata(message.reasoningMs)
|
|
3027
|
+
} : {}
|
|
3028
|
+
});
|
|
3029
|
+
}
|
|
2593
3030
|
if (message.content) {
|
|
2594
3031
|
parts.push({
|
|
2595
3032
|
type: "text",
|
|
@@ -2604,6 +3041,20 @@ function storedMessageToUiMessage(message) {
|
|
|
2604
3041
|
url: attachment.url
|
|
2605
3042
|
});
|
|
2606
3043
|
}
|
|
3044
|
+
for (const component of message.ui ?? []) {
|
|
3045
|
+
parts.push({
|
|
3046
|
+
type: "data-ui",
|
|
3047
|
+
id: component.id,
|
|
3048
|
+
data: {
|
|
3049
|
+
id: component.id,
|
|
3050
|
+
component: component.component,
|
|
3051
|
+
props: component.props,
|
|
3052
|
+
...component.version !== void 0 ? {
|
|
3053
|
+
version: component.version
|
|
3054
|
+
} : {}
|
|
3055
|
+
}
|
|
3056
|
+
});
|
|
3057
|
+
}
|
|
2607
3058
|
for (const call of message.toolCalls ?? []) {
|
|
2608
3059
|
const result = message.toolResults?.find((candidate) => candidate.id === call.id);
|
|
2609
3060
|
const toolKind2 = call.kind;
|
|
@@ -2706,20 +3157,20 @@ __name(sumUsage, "sumUsage");
|
|
|
2706
3157
|
|
|
2707
3158
|
// src/use-agent-chat.ts
|
|
2708
3159
|
import { useChat } from "@ai-sdk/react";
|
|
2709
|
-
import { useCallback as
|
|
3160
|
+
import { useCallback as useCallback6, useEffect as useEffect8, useMemo as useMemo4, useRef as useRef6, useState as useState8 } from "react";
|
|
2710
3161
|
function useAgentChat(options) {
|
|
2711
|
-
const latest =
|
|
3162
|
+
const latest = useRef6(options);
|
|
2712
3163
|
latest.current = options;
|
|
2713
|
-
const [runId, setRunId] =
|
|
2714
|
-
const runIdRef =
|
|
3164
|
+
const [runId, setRunId] = useState8(options.resumeRunId);
|
|
3165
|
+
const runIdRef = useRef6(runId);
|
|
2715
3166
|
runIdRef.current = runId;
|
|
2716
|
-
const settlingRunIdRef =
|
|
2717
|
-
const autoResumeRunIdRef =
|
|
2718
|
-
const [autoResume, setAutoResume] =
|
|
2719
|
-
const [activeRunId, setActiveRunId] =
|
|
2720
|
-
const regenerateNext =
|
|
2721
|
-
const createdThreadId =
|
|
2722
|
-
const client =
|
|
3167
|
+
const settlingRunIdRef = useRef6(void 0);
|
|
3168
|
+
const autoResumeRunIdRef = useRef6(void 0);
|
|
3169
|
+
const [autoResume, setAutoResume] = useState8(false);
|
|
3170
|
+
const [activeRunId, setActiveRunId] = useState8(null);
|
|
3171
|
+
const regenerateNext = useRef6(false);
|
|
3172
|
+
const createdThreadId = useRef6(void 0);
|
|
3173
|
+
const client = useMemo4(() => {
|
|
2723
3174
|
if (options.client) return options.client;
|
|
2724
3175
|
return new AgentClient({
|
|
2725
3176
|
...options.baseUrl !== void 0 ? {
|
|
@@ -2734,7 +3185,7 @@ function useAgentChat(options) {
|
|
|
2734
3185
|
getHeaders: /* @__PURE__ */ __name(async () => mergeHeaders(latest.current), "getHeaders")
|
|
2735
3186
|
});
|
|
2736
3187
|
}, []);
|
|
2737
|
-
|
|
3188
|
+
useEffect8(() => {
|
|
2738
3189
|
if (!options.resume || options.threadId === void 0) return;
|
|
2739
3190
|
let cancelled = false;
|
|
2740
3191
|
const threadId = options.threadId;
|
|
@@ -2754,7 +3205,7 @@ function useAgentChat(options) {
|
|
|
2754
3205
|
options.resume,
|
|
2755
3206
|
options.threadId
|
|
2756
3207
|
]);
|
|
2757
|
-
const transport =
|
|
3208
|
+
const transport = useMemo4(() => {
|
|
2758
3209
|
function onMeta(meta) {
|
|
2759
3210
|
settlingRunIdRef.current = meta.runId;
|
|
2760
3211
|
setRunId(meta.runId);
|
|
@@ -2803,7 +3254,7 @@ function useAgentChat(options) {
|
|
|
2803
3254
|
}, "onAttemptStart")
|
|
2804
3255
|
});
|
|
2805
3256
|
}, []);
|
|
2806
|
-
const backgroundRef =
|
|
3257
|
+
const backgroundRef = useRef6(() => Promise.resolve());
|
|
2807
3258
|
const chat = useChat({
|
|
2808
3259
|
transport,
|
|
2809
3260
|
resume: options.resumeRunId !== void 0 || autoResume,
|
|
@@ -2834,13 +3285,13 @@ function useAgentChat(options) {
|
|
|
2834
3285
|
}
|
|
2835
3286
|
}, "onFinish")
|
|
2836
3287
|
});
|
|
2837
|
-
const chatRef =
|
|
3288
|
+
const chatRef = useRef6(chat);
|
|
2838
3289
|
chatRef.current = chat;
|
|
2839
|
-
const turnInFlight =
|
|
2840
|
-
const isTurnInFlight =
|
|
3290
|
+
const turnInFlight = useRef6(false);
|
|
3291
|
+
const isTurnInFlight = useCallback6(() => turnInFlight.current || transport.isAttemptLive, [
|
|
2841
3292
|
transport
|
|
2842
3293
|
]);
|
|
2843
|
-
const sendMessage =
|
|
3294
|
+
const sendMessage = useCallback6(async (...args) => {
|
|
2844
3295
|
if (isTurnInFlight()) return;
|
|
2845
3296
|
turnInFlight.current = true;
|
|
2846
3297
|
try {
|
|
@@ -2851,15 +3302,15 @@ function useAgentChat(options) {
|
|
|
2851
3302
|
}, [
|
|
2852
3303
|
isTurnInFlight
|
|
2853
3304
|
]);
|
|
2854
|
-
const addToolResult =
|
|
3305
|
+
const addToolResult = useCallback6(({ tool, toolCallId, output }) => chatRef.current.addToolResult({
|
|
2855
3306
|
tool,
|
|
2856
3307
|
toolCallId,
|
|
2857
3308
|
output
|
|
2858
3309
|
}), []);
|
|
2859
|
-
const [threads, setThreads] =
|
|
2860
|
-
const [quota, setQuota] =
|
|
2861
|
-
const [backgroundRuns, setBackgroundRuns] =
|
|
2862
|
-
const refreshBackground =
|
|
3310
|
+
const [threads, setThreads] = useState8([]);
|
|
3311
|
+
const [quota, setQuota] = useState8(null);
|
|
3312
|
+
const [backgroundRuns, setBackgroundRuns] = useState8([]);
|
|
3313
|
+
const refreshBackground = useCallback6(async () => {
|
|
2863
3314
|
const threadId = latest.current.threadId ?? createdThreadId.current;
|
|
2864
3315
|
if (threadId === void 0) {
|
|
2865
3316
|
return;
|
|
@@ -2884,7 +3335,7 @@ function useAgentChat(options) {
|
|
|
2884
3335
|
]);
|
|
2885
3336
|
backgroundRef.current = refreshBackground;
|
|
2886
3337
|
const isWorking = backgroundRuns.some((run) => run.status === "running");
|
|
2887
|
-
|
|
3338
|
+
useEffect8(() => {
|
|
2888
3339
|
if (options.background !== true || options.threadId === void 0) {
|
|
2889
3340
|
return;
|
|
2890
3341
|
}
|
|
@@ -2894,7 +3345,7 @@ function useAgentChat(options) {
|
|
|
2894
3345
|
options.threadId,
|
|
2895
3346
|
refreshBackground
|
|
2896
3347
|
]);
|
|
2897
|
-
|
|
3348
|
+
useEffect8(() => {
|
|
2898
3349
|
const every = latest.current.backgroundPollMs ?? 5e3;
|
|
2899
3350
|
if (latest.current.background !== true || !isWorking || every <= 0) {
|
|
2900
3351
|
return;
|
|
@@ -2905,26 +3356,26 @@ function useAgentChat(options) {
|
|
|
2905
3356
|
isWorking,
|
|
2906
3357
|
refreshBackground
|
|
2907
3358
|
]);
|
|
2908
|
-
const loadThreads =
|
|
3359
|
+
const loadThreads = useCallback6(async () => {
|
|
2909
3360
|
const list = await client.listThreads();
|
|
2910
3361
|
setThreads(list);
|
|
2911
3362
|
return list;
|
|
2912
3363
|
}, [
|
|
2913
3364
|
client
|
|
2914
3365
|
]);
|
|
2915
|
-
const loadThread =
|
|
3366
|
+
const loadThread = useCallback6((id) => client.getThread(id), [
|
|
2916
3367
|
client
|
|
2917
3368
|
]);
|
|
2918
|
-
const deleteThread =
|
|
3369
|
+
const deleteThread = useCallback6(async (id) => {
|
|
2919
3370
|
await client.deleteThread(id);
|
|
2920
3371
|
setThreads((current) => current.filter((thread) => thread.id !== id));
|
|
2921
3372
|
}, [
|
|
2922
3373
|
client
|
|
2923
3374
|
]);
|
|
2924
|
-
const forkThread =
|
|
3375
|
+
const forkThread = useCallback6((threadId, messageId) => client.forkFromMessage(threadId, messageId), [
|
|
2925
3376
|
client
|
|
2926
3377
|
]);
|
|
2927
|
-
const renameThread =
|
|
3378
|
+
const renameThread = useCallback6(async (id, title) => {
|
|
2928
3379
|
await client.renameThread(id, title);
|
|
2929
3380
|
setThreads((current) => current.map((thread) => thread.id === id ? {
|
|
2930
3381
|
...thread,
|
|
@@ -2933,24 +3384,24 @@ function useAgentChat(options) {
|
|
|
2933
3384
|
}, [
|
|
2934
3385
|
client
|
|
2935
3386
|
]);
|
|
2936
|
-
const promoteThread =
|
|
3387
|
+
const promoteThread = useCallback6(async (id) => {
|
|
2937
3388
|
await client.promoteThread(id);
|
|
2938
3389
|
await loadThreads();
|
|
2939
3390
|
}, [
|
|
2940
3391
|
client,
|
|
2941
3392
|
loadThreads
|
|
2942
3393
|
]);
|
|
2943
|
-
const truncateFromMessage =
|
|
3394
|
+
const truncateFromMessage = useCallback6((threadId, messageId) => client.truncateFromMessage(threadId, messageId).then(() => void 0), [
|
|
2944
3395
|
client
|
|
2945
3396
|
]);
|
|
2946
|
-
const loadQuota =
|
|
3397
|
+
const loadQuota = useCallback6(async () => {
|
|
2947
3398
|
const today = await client.getQuotaToday();
|
|
2948
3399
|
setQuota(today);
|
|
2949
3400
|
return today;
|
|
2950
3401
|
}, [
|
|
2951
3402
|
client
|
|
2952
3403
|
]);
|
|
2953
|
-
const cancel =
|
|
3404
|
+
const cancel = useCallback6(async () => {
|
|
2954
3405
|
chatRef.current.stop();
|
|
2955
3406
|
const activeRunId2 = runIdRef.current;
|
|
2956
3407
|
if (activeRunId2) {
|
|
@@ -2962,14 +3413,14 @@ function useAgentChat(options) {
|
|
|
2962
3413
|
}, [
|
|
2963
3414
|
client
|
|
2964
3415
|
]);
|
|
2965
|
-
const approve =
|
|
3416
|
+
const approve = useCallback6(async ({ toolCallId }) => {
|
|
2966
3417
|
await client.approveToolCall({
|
|
2967
3418
|
toolCallId
|
|
2968
3419
|
});
|
|
2969
3420
|
}, [
|
|
2970
3421
|
client
|
|
2971
3422
|
]);
|
|
2972
|
-
const reject =
|
|
3423
|
+
const reject = useCallback6(async ({ toolCallId, reason }) => {
|
|
2973
3424
|
await client.rejectToolCall({
|
|
2974
3425
|
toolCallId,
|
|
2975
3426
|
...reason !== void 0 ? {
|
|
@@ -2979,7 +3430,7 @@ function useAgentChat(options) {
|
|
|
2979
3430
|
}, [
|
|
2980
3431
|
client
|
|
2981
3432
|
]);
|
|
2982
|
-
const answer =
|
|
3433
|
+
const answer = useCallback6(async ({ toolCallId, answers }) => {
|
|
2983
3434
|
await client.answerToolCall({
|
|
2984
3435
|
toolCallId,
|
|
2985
3436
|
...answers !== void 0 ? {
|
|
@@ -2989,14 +3440,14 @@ function useAgentChat(options) {
|
|
|
2989
3440
|
}, [
|
|
2990
3441
|
client
|
|
2991
3442
|
]);
|
|
2992
|
-
const skip =
|
|
3443
|
+
const skip = useCallback6(async ({ toolCallId }) => {
|
|
2993
3444
|
await client.skipToolCall({
|
|
2994
3445
|
toolCallId
|
|
2995
3446
|
});
|
|
2996
3447
|
}, [
|
|
2997
3448
|
client
|
|
2998
3449
|
]);
|
|
2999
|
-
const regenerate =
|
|
3450
|
+
const regenerate = useCallback6(() => {
|
|
3000
3451
|
if (isTurnInFlight()) return;
|
|
3001
3452
|
regenerateNext.current = true;
|
|
3002
3453
|
turnInFlight.current = true;
|
|
@@ -3061,22 +3512,37 @@ export {
|
|
|
3061
3512
|
applyCompletion,
|
|
3062
3513
|
backgroundRunsFromThread,
|
|
3063
3514
|
buildTranscriptBlocks,
|
|
3515
|
+
correctedCallIds,
|
|
3064
3516
|
createSkillsSource,
|
|
3065
3517
|
describeTimestamp,
|
|
3518
|
+
describeToolCall,
|
|
3066
3519
|
describeUsage,
|
|
3067
3520
|
extractMessageText,
|
|
3521
|
+
fillTemplate,
|
|
3068
3522
|
filterAutocompleteItems,
|
|
3069
3523
|
findActiveTrigger,
|
|
3524
|
+
formatElapsed,
|
|
3070
3525
|
formatRelativeTime,
|
|
3526
|
+
groupToolActivity,
|
|
3527
|
+
inferResultView,
|
|
3528
|
+
isActionCall,
|
|
3071
3529
|
loadStoredSpeechLang,
|
|
3072
3530
|
persistSpeechLang,
|
|
3531
|
+
phraseFor,
|
|
3532
|
+
readPath,
|
|
3533
|
+
readReasoningMs,
|
|
3534
|
+
resolveResultView,
|
|
3073
3535
|
storedMessageToUiMessage,
|
|
3074
3536
|
storedThreadToUiMessages,
|
|
3537
|
+
toolCallState,
|
|
3538
|
+
toolCatalogFrom,
|
|
3075
3539
|
useAgentChat,
|
|
3076
3540
|
useChatTranscript,
|
|
3077
3541
|
useComposerAutocomplete,
|
|
3542
|
+
useElapsed,
|
|
3078
3543
|
useSpeechRecognition,
|
|
3079
3544
|
useStickToBottom,
|
|
3545
|
+
useToolCatalog,
|
|
3080
3546
|
useTranscriptItem
|
|
3081
3547
|
};
|
|
3082
3548
|
//# sourceMappingURL=index.js.map
|