@truefoundry/trueforge-ui 0.3.0-rc.0 → 0.3.0-rc.1
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/CHANGELOG.md +48 -0
- package/README.md +14 -6
- package/dist/AgentCodeSnippets-NZOFJE57.js +74 -0
- package/dist/AgentCodeSnippets-NZOFJE57.js.map +1 -0
- package/dist/AgentMetricChart-JPU3MFQ2.js +15 -0
- package/dist/AgentOverview-EEBHJC32.js +167 -0
- package/dist/AgentOverview-EEBHJC32.js.map +1 -0
- package/dist/AgentSessionEventTimeline-26Z6IB3B.js +79 -0
- package/dist/AgentSessionEventTimeline-26Z6IB3B.js.map +1 -0
- package/dist/AgentSessionEventTimelineChart-CGCU7WBK.js +504 -0
- package/dist/AgentSessionEventTimelineChart-CGCU7WBK.js.map +1 -0
- package/dist/AgentSessions-3MPDZASK.js +275 -0
- package/dist/AgentSessions-3MPDZASK.js.map +1 -0
- package/dist/{ConnectorSettings-FXQ5B7TN.js → ConnectorSettings-MXFRWWR6.js} +8 -6
- package/dist/{ConnectorSettings-FXQ5B7TN.js.map → ConnectorSettings-MXFRWWR6.js.map} +1 -1
- package/dist/{DockLayout-LBNQJZNF.js → DockLayout-LM4AFMFY.js} +11 -10
- package/dist/{DockLayout-LBNQJZNF.js.map → DockLayout-LM4AFMFY.js.map} +1 -1
- package/dist/DrawerLayout-JR3O6RRB.js +184 -0
- package/dist/DrawerLayout-JR3O6RRB.js.map +1 -0
- package/dist/{ModelSettings-4L4LOQJA.js → ModelSettings-G7IFNC2Y.js} +8 -6
- package/dist/{ModelSettings-4L4LOQJA.js.map → ModelSettings-G7IFNC2Y.js.map} +1 -1
- package/dist/OpenUiFenceBlock-2TV5TQ6P.js +9 -0
- package/dist/OpenUiFenceBlock-2TV5TQ6P.js.map +1 -0
- package/dist/{SandboxSettings-Z4ZG6ZX4.js → SandboxSettings-NXAANMAX.js} +8 -6
- package/dist/{SandboxSettings-Z4ZG6ZX4.js.map → SandboxSettings-NXAANMAX.js.map} +1 -1
- package/dist/SchedulesPage-KKLUDO6B.js +15 -0
- package/dist/SchedulesPage-KKLUDO6B.js.map +1 -0
- package/dist/{SettingsBuilder-WF7ZWKQW.js → SettingsBuilder-L34IQ56S.js} +26 -22
- package/dist/SettingsBuilder-L34IQ56S.js.map +1 -0
- package/dist/{ShellRouteSync-T4WLY57Q.js → ShellRouteSync-CEBETGEJ.js} +95 -22
- package/dist/ShellRouteSync-CEBETGEJ.js.map +1 -0
- package/dist/SidebarLayout-A2HJPPHS.js +308 -0
- package/dist/SidebarLayout-A2HJPPHS.js.map +1 -0
- package/dist/{SkillSettings-3EPPC3IT.js → SkillSettings-FGGMSUNO.js} +8 -6
- package/dist/{SkillSettings-3EPPC3IT.js.map → SkillSettings-FGGMSUNO.js.map} +1 -1
- package/dist/{TrueForgeUIWithRouter-NZ4FGPE4.js → TrueForgeUIWithRouter-MZVJWJMB.js} +14 -10
- package/dist/{TrueForgeUIWithRouter-NZ4FGPE4.js.map → TrueForgeUIWithRouter-MZVJWJMB.js.map} +1 -1
- package/dist/{WidgetLayout-3QZ357FL.js → WidgetLayout-6QM45OQQ.js} +17 -13
- package/dist/WidgetLayout-6QM45OQQ.js.map +1 -0
- package/dist/chunk-2XPPBEYF.js +74 -0
- package/dist/chunk-2XPPBEYF.js.map +1 -0
- package/dist/chunk-6O6FWUDW.js +1376 -0
- package/dist/chunk-6O6FWUDW.js.map +1 -0
- package/dist/chunk-7Z2C2K7F.js +578 -0
- package/dist/chunk-7Z2C2K7F.js.map +1 -0
- package/dist/{chunk-WREC7D54.js → chunk-CYHJDKFB.js} +115 -32
- package/dist/chunk-CYHJDKFB.js.map +1 -0
- package/dist/chunk-DJUFS2BW.js +27 -0
- package/dist/chunk-DJUFS2BW.js.map +1 -0
- package/dist/chunk-DMMZSZTN.js +252 -0
- package/dist/chunk-DMMZSZTN.js.map +1 -0
- package/dist/chunk-FJW36PD7.js +180 -0
- package/dist/chunk-FJW36PD7.js.map +1 -0
- package/dist/chunk-M62XY4NC.js +555 -0
- package/dist/chunk-M62XY4NC.js.map +1 -0
- package/dist/{chunk-B52K63AW.js → chunk-MPNSO7E6.js} +2 -2
- package/dist/{chunk-CFLVPV5M.js → chunk-QC42MLAK.js} +7 -2
- package/dist/chunk-QC42MLAK.js.map +1 -0
- package/dist/chunk-RDXBMTP5.js +32 -0
- package/dist/chunk-RDXBMTP5.js.map +1 -0
- package/dist/chunk-SFZNIO6U.js +18 -0
- package/dist/chunk-SFZNIO6U.js.map +1 -0
- package/dist/chunk-U7KURWW3.js +840 -0
- package/dist/chunk-U7KURWW3.js.map +1 -0
- package/dist/chunk-WVE3F724.js +200 -0
- package/dist/chunk-WVE3F724.js.map +1 -0
- package/dist/{chunk-FJ5RSSMA.js → chunk-XAU7QFG3.js} +178 -36
- package/dist/chunk-XAU7QFG3.js.map +1 -0
- package/dist/chunk-Y6S4OVVQ.js +16 -0
- package/dist/chunk-Y6S4OVVQ.js.map +1 -0
- package/dist/chunk-ZKNUMH2M.js +119 -0
- package/dist/chunk-ZKNUMH2M.js.map +1 -0
- package/dist/chunk-ZTMKFZQ3.js +13214 -0
- package/dist/chunk-ZTMKFZQ3.js.map +1 -0
- package/dist/{createTrueFoundryServer-B72bU-J7.d.ts → createTrueFoundryServer-CmZnBh_l.d.ts} +15 -4
- package/dist/index.d.ts +1002 -22
- package/dist/index.js +689 -67
- package/dist/index.js.map +1 -1
- package/dist/plugins/trueforge-agent-server-adapter/index.d.ts +552 -8
- package/dist/plugins/trueforge-agent-server-adapter/index.js +503 -188
- package/dist/plugins/trueforge-agent-server-adapter/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +8 -7
- package/dist/DrawerLayout-Q6UK4VMI.js +0 -159
- package/dist/DrawerLayout-Q6UK4VMI.js.map +0 -1
- package/dist/OpenUiFenceBlock-6UIIAVBX.js +0 -9
- package/dist/SettingsBuilder-WF7ZWKQW.js.map +0 -1
- package/dist/ShellRouteSync-T4WLY57Q.js.map +0 -1
- package/dist/SidebarLayout-3WZ3CVON.js +0 -256
- package/dist/SidebarLayout-3WZ3CVON.js.map +0 -1
- package/dist/WidgetLayout-3QZ357FL.js.map +0 -1
- package/dist/chunk-36KOSC2J.js +0 -567
- package/dist/chunk-36KOSC2J.js.map +0 -1
- package/dist/chunk-3S6KHO7H.js +0 -2121
- package/dist/chunk-3S6KHO7H.js.map +0 -1
- package/dist/chunk-7L63OK3O.js +0 -91
- package/dist/chunk-7L63OK3O.js.map +0 -1
- package/dist/chunk-CFLVPV5M.js.map +0 -1
- package/dist/chunk-FJ5RSSMA.js.map +0 -1
- package/dist/chunk-OSV3HI5M.js +0 -6891
- package/dist/chunk-OSV3HI5M.js.map +0 -1
- package/dist/chunk-WQULF5AT.js +0 -460
- package/dist/chunk-WQULF5AT.js.map +0 -1
- package/dist/chunk-WREC7D54.js.map +0 -1
- package/dist/chunk-YIWUG6MC.js +0 -101
- package/dist/chunk-YIWUG6MC.js.map +0 -1
- package/dist/chunk-ZXOADNF3.js +0 -75
- package/dist/chunk-ZXOADNF3.js.map +0 -1
- /package/dist/{OpenUiFenceBlock-6UIIAVBX.js.map → AgentMetricChart-JPU3MFQ2.js.map} +0 -0
- /package/dist/{chunk-B52K63AW.js.map → chunk-MPNSO7E6.js.map} +0 -0
package/dist/chunk-3S6KHO7H.js
DELETED
|
@@ -1,2121 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ComposerBusyProvider,
|
|
3
|
-
useComposerBusyState,
|
|
4
|
-
useOptionalCustomActionRenderers
|
|
5
|
-
} from "./chunk-BSIPI3KV.js";
|
|
6
|
-
import {
|
|
7
|
-
useAui,
|
|
8
|
-
useAuiState
|
|
9
|
-
} from "./chunk-M6MHLVSO.js";
|
|
10
|
-
import {
|
|
11
|
-
ASK_USER_CUSTOM_OPTION,
|
|
12
|
-
BottomSheet,
|
|
13
|
-
Button,
|
|
14
|
-
SearchInput_default,
|
|
15
|
-
SlotsProvider,
|
|
16
|
-
USER_MESSAGE_ATTACHMENT_PREVIEW_REM,
|
|
17
|
-
canReuseMutableShell,
|
|
18
|
-
preloadMarkdownOpenUI,
|
|
19
|
-
readThreadAgentName,
|
|
20
|
-
threadListIndicesByRecency,
|
|
21
|
-
threadListItemIsMutable,
|
|
22
|
-
useIsMobile,
|
|
23
|
-
useMCPAuth,
|
|
24
|
-
useSearchAgentsList,
|
|
25
|
-
useSlot,
|
|
26
|
-
useSlotIsDefault,
|
|
27
|
-
useToasterOptional
|
|
28
|
-
} from "./chunk-OSV3HI5M.js";
|
|
29
|
-
import {
|
|
30
|
-
DraftCatalogProvider,
|
|
31
|
-
Icon,
|
|
32
|
-
auiButtonClass,
|
|
33
|
-
useCompactLayout,
|
|
34
|
-
useDraftCatalog
|
|
35
|
-
} from "./chunk-FJ5RSSMA.js";
|
|
36
|
-
import {
|
|
37
|
-
libraryAgentId,
|
|
38
|
-
useOptionalCatalogServer,
|
|
39
|
-
useOptionalServer,
|
|
40
|
-
useOptionalShellMode
|
|
41
|
-
} from "./chunk-WQULF5AT.js";
|
|
42
|
-
import {
|
|
43
|
-
cn
|
|
44
|
-
} from "./chunk-36KOSC2J.js";
|
|
45
|
-
|
|
46
|
-
// src/containers/AgentStepsContainer.tsx
|
|
47
|
-
import { useEffect, useRef, useState } from "react";
|
|
48
|
-
import { jsx } from "react/jsx-runtime";
|
|
49
|
-
function AgentStepsContainer({
|
|
50
|
-
children,
|
|
51
|
-
toolCount,
|
|
52
|
-
thinkingCount,
|
|
53
|
-
hasFinal
|
|
54
|
-
}) {
|
|
55
|
-
const AgentStepsCard = useSlot("AgentStepsCard");
|
|
56
|
-
const [expanded, setExpanded] = useState(true);
|
|
57
|
-
const collapsedByFinal = useRef(false);
|
|
58
|
-
useEffect(() => {
|
|
59
|
-
if (hasFinal && !collapsedByFinal.current) {
|
|
60
|
-
collapsedByFinal.current = true;
|
|
61
|
-
setExpanded(false);
|
|
62
|
-
}
|
|
63
|
-
}, [hasFinal]);
|
|
64
|
-
return /* @__PURE__ */ jsx(
|
|
65
|
-
AgentStepsCard,
|
|
66
|
-
{
|
|
67
|
-
toolCount,
|
|
68
|
-
thinkingCount,
|
|
69
|
-
expanded,
|
|
70
|
-
onToggle: () => setExpanded((prev) => !prev),
|
|
71
|
-
children
|
|
72
|
-
}
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// src/containers/AskUserContainer.tsx
|
|
77
|
-
import { useThreadIsRunning } from "@assistant-ui/core/react";
|
|
78
|
-
import { useTrueFoundryToolResponses } from "@truefoundry/assistant-ui-runtime";
|
|
79
|
-
import { useCallback, useEffect as useEffect2, useMemo, useState as useState2 } from "react";
|
|
80
|
-
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
81
|
-
var EMPTY_ANSWER = { radioValue: "", custom: "" };
|
|
82
|
-
function AskUserContainer() {
|
|
83
|
-
const AskUserPrompt = useSlot("AskUserPrompt");
|
|
84
|
-
const { pending, respond } = useTrueFoundryToolResponses();
|
|
85
|
-
const isRunning = useThreadIsRunning();
|
|
86
|
-
const item = pending[0];
|
|
87
|
-
const questions = useMemo(
|
|
88
|
-
() => item == null ? [] : [
|
|
89
|
-
{
|
|
90
|
-
id: item.toolCallId,
|
|
91
|
-
question: item.question ?? "Answer required",
|
|
92
|
-
options: item.options ?? []
|
|
93
|
-
}
|
|
94
|
-
],
|
|
95
|
-
[item]
|
|
96
|
-
);
|
|
97
|
-
const [currentQuestionIndex, setCurrentQuestionIndex] = useState2(0);
|
|
98
|
-
const [answers, setAnswers] = useState2({});
|
|
99
|
-
useEffect2(() => {
|
|
100
|
-
setCurrentQuestionIndex(0);
|
|
101
|
-
setAnswers({});
|
|
102
|
-
}, [item?.toolCallId]);
|
|
103
|
-
const safeIndex = Math.min(currentQuestionIndex, Math.max(questions.length - 1, 0));
|
|
104
|
-
const currentQuestion = questions[safeIndex];
|
|
105
|
-
const currentAnswer = currentQuestion == null ? EMPTY_ANSWER : answers[currentQuestion.id] ?? EMPTY_ANSWER;
|
|
106
|
-
const getResponseForQuestion = useCallback(
|
|
107
|
-
(questionId) => {
|
|
108
|
-
const answer = answers[questionId] ?? EMPTY_ANSWER;
|
|
109
|
-
return answer.radioValue === ASK_USER_CUSTOM_OPTION ? answer.custom.trim() : answer.radioValue.trim();
|
|
110
|
-
},
|
|
111
|
-
[answers]
|
|
112
|
-
);
|
|
113
|
-
const allQuestionsAnswered = useMemo(
|
|
114
|
-
() => questions.every((question) => getResponseForQuestion(question.id)),
|
|
115
|
-
[getResponseForQuestion, questions]
|
|
116
|
-
);
|
|
117
|
-
const selectedResponse = currentAnswer.radioValue === ASK_USER_CUSTOM_OPTION ? currentAnswer.custom.trim() : currentAnswer.radioValue.trim();
|
|
118
|
-
const isSubmitDisabled = isRunning || currentQuestion == null || selectedResponse.length === 0;
|
|
119
|
-
const isSubmitAllDisabled = isSubmitDisabled || !allQuestionsAnswered;
|
|
120
|
-
const onCurrentAnswerChange = useCallback((questionId, update) => {
|
|
121
|
-
setAnswers((previous) => ({
|
|
122
|
-
...previous,
|
|
123
|
-
[questionId]: {
|
|
124
|
-
...previous[questionId] ?? EMPTY_ANSWER,
|
|
125
|
-
...update
|
|
126
|
-
}
|
|
127
|
-
}));
|
|
128
|
-
}, []);
|
|
129
|
-
const onSubmit = useCallback(() => {
|
|
130
|
-
if (item == null || !allQuestionsAnswered) return;
|
|
131
|
-
const content = getResponseForQuestion(item.toolCallId);
|
|
132
|
-
if (!content) return;
|
|
133
|
-
respond({ toolCallId: item.toolCallId, content });
|
|
134
|
-
}, [allQuestionsAnswered, getResponseForQuestion, item, respond]);
|
|
135
|
-
if (item == null || currentQuestion == null) return null;
|
|
136
|
-
return /* @__PURE__ */ jsx2(
|
|
137
|
-
AskUserPrompt,
|
|
138
|
-
{
|
|
139
|
-
questions,
|
|
140
|
-
readOnly: isRunning,
|
|
141
|
-
currentQuestion,
|
|
142
|
-
currentQuestionIndex: safeIndex,
|
|
143
|
-
currentAnswer,
|
|
144
|
-
totalQuestions: questions.length,
|
|
145
|
-
isMultiQuestion: questions.length > 1,
|
|
146
|
-
isLastQuestion: safeIndex === questions.length - 1,
|
|
147
|
-
allQuestionsAnswered,
|
|
148
|
-
isSubmitDisabled,
|
|
149
|
-
isSubmitAllDisabled,
|
|
150
|
-
onCurrentQuestionIndexChange: setCurrentQuestionIndex,
|
|
151
|
-
onCurrentAnswerChange,
|
|
152
|
-
onSubmit
|
|
153
|
-
}
|
|
154
|
-
);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// src/utils/computeAgentStepsSplit.ts
|
|
158
|
-
function computeAgentStepsSplit(parts, isRunning) {
|
|
159
|
-
const finalTexts = [];
|
|
160
|
-
let cutIdx = parts.length;
|
|
161
|
-
for (let i = parts.length - 1; i >= 0; i--) {
|
|
162
|
-
const part = parts[i];
|
|
163
|
-
if (!part) continue;
|
|
164
|
-
if (part.type === "text") {
|
|
165
|
-
const text = part.text ?? "";
|
|
166
|
-
const trimmed = text.trim();
|
|
167
|
-
if (trimmed) {
|
|
168
|
-
finalTexts.unshift({ index: i, content: text });
|
|
169
|
-
cutIdx = i;
|
|
170
|
-
} else {
|
|
171
|
-
cutIdx = i;
|
|
172
|
-
}
|
|
173
|
-
} else {
|
|
174
|
-
break;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
const trailingChars = finalTexts.reduce((sum, t) => sum + t.content.length, 0);
|
|
178
|
-
const hasAgentStepsBeforeCut = parts.slice(0, cutIdx).some((p) => p.type === "tool-call" || p.type === "reasoning");
|
|
179
|
-
const finalConfirmed = finalTexts.length > 0 && (!isRunning || trailingChars >= 500 || !hasAgentStepsBeforeCut);
|
|
180
|
-
const actualCutIndex = finalConfirmed ? cutIdx : parts.length;
|
|
181
|
-
let toolCount = 0;
|
|
182
|
-
let thinkingCount = 0;
|
|
183
|
-
for (let i = 0; i < actualCutIndex; i++) {
|
|
184
|
-
const part = parts[i];
|
|
185
|
-
if (!part) continue;
|
|
186
|
-
if (part.type === "tool-call") {
|
|
187
|
-
toolCount++;
|
|
188
|
-
} else if (part.type === "reasoning") {
|
|
189
|
-
thinkingCount++;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
return {
|
|
193
|
-
cutIndex: actualCutIndex,
|
|
194
|
-
hasFinal: finalConfirmed,
|
|
195
|
-
toolCount,
|
|
196
|
-
thinkingCount
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// src/containers/AssistantTextContainer.tsx
|
|
201
|
-
import {
|
|
202
|
-
useAuiState as useAuiState2,
|
|
203
|
-
useSmooth
|
|
204
|
-
} from "@assistant-ui/react";
|
|
205
|
-
import { useTrueFoundryDownloadSandboxFile } from "@truefoundry/assistant-ui-runtime";
|
|
206
|
-
import { useCallback as useCallback2, useMemo as useMemo2, useRef as useRef3 } from "react";
|
|
207
|
-
|
|
208
|
-
// src/hooks/useThrottledMarkdownText.ts
|
|
209
|
-
import { useEffect as useEffect3, useRef as useRef2, useState as useState3 } from "react";
|
|
210
|
-
var MARKDOWN_SMOOTH_BACKLOG_CHARS = 4 * 1024;
|
|
211
|
-
var LARGE_MARKDOWN_THROTTLE_MS = 100;
|
|
212
|
-
function useThrottledMarkdownText(text, {
|
|
213
|
-
isComplete,
|
|
214
|
-
enabled,
|
|
215
|
-
throttleMs = LARGE_MARKDOWN_THROTTLE_MS
|
|
216
|
-
}) {
|
|
217
|
-
const [committed, setCommitted] = useState3(text);
|
|
218
|
-
const lastCommittedRef = useRef2(text);
|
|
219
|
-
const lastCommitAtRef = useRef2(Date.now());
|
|
220
|
-
const pendingRef = useRef2(text);
|
|
221
|
-
const wasEnabledRef = useRef2(enabled);
|
|
222
|
-
useEffect3(() => {
|
|
223
|
-
pendingRef.current = text;
|
|
224
|
-
const commit = (value) => {
|
|
225
|
-
if (value.length < lastCommittedRef.current.length && value !== lastCommittedRef.current) {
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
lastCommittedRef.current = value;
|
|
229
|
-
lastCommitAtRef.current = Date.now();
|
|
230
|
-
setCommitted(value);
|
|
231
|
-
};
|
|
232
|
-
if (!enabled) {
|
|
233
|
-
wasEnabledRef.current = false;
|
|
234
|
-
lastCommittedRef.current = text;
|
|
235
|
-
lastCommitAtRef.current = Date.now();
|
|
236
|
-
setCommitted(text);
|
|
237
|
-
return;
|
|
238
|
-
}
|
|
239
|
-
if (!wasEnabledRef.current) {
|
|
240
|
-
wasEnabledRef.current = true;
|
|
241
|
-
commit(text);
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
if (lastCommittedRef.current === text) return;
|
|
245
|
-
if (isComplete) {
|
|
246
|
-
commit(text);
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
|
-
const elapsed = Date.now() - lastCommitAtRef.current;
|
|
250
|
-
if (elapsed >= throttleMs) {
|
|
251
|
-
commit(text);
|
|
252
|
-
return;
|
|
253
|
-
}
|
|
254
|
-
const id = setTimeout(() => {
|
|
255
|
-
commit(pendingRef.current);
|
|
256
|
-
}, throttleMs - elapsed);
|
|
257
|
-
return () => clearTimeout(id);
|
|
258
|
-
}, [text, isComplete, enabled, throttleMs]);
|
|
259
|
-
return enabled ? committed : text;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
// src/containers/AssistantTextContainer.tsx
|
|
263
|
-
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
264
|
-
function filenameFromPath(path) {
|
|
265
|
-
return path.split("/").pop() || "download";
|
|
266
|
-
}
|
|
267
|
-
function triggerBrowserDownload(blob, filename) {
|
|
268
|
-
if (typeof document === "undefined") return;
|
|
269
|
-
const url = URL.createObjectURL(blob);
|
|
270
|
-
const anchor = document.createElement("a");
|
|
271
|
-
anchor.href = url;
|
|
272
|
-
anchor.download = filename;
|
|
273
|
-
anchor.click();
|
|
274
|
-
URL.revokeObjectURL(url);
|
|
275
|
-
}
|
|
276
|
-
function AssistantTextContainer() {
|
|
277
|
-
const Markdown = useSlot("Markdown");
|
|
278
|
-
const toaster = useToasterOptional();
|
|
279
|
-
const downloadSandboxFile = useTrueFoundryDownloadSandboxFile();
|
|
280
|
-
const downloadRef = useRef3({ downloadSandboxFile, toaster });
|
|
281
|
-
downloadRef.current = { downloadSandboxFile, toaster };
|
|
282
|
-
const partState = useAuiState2((s) => s.part);
|
|
283
|
-
const pacedModeRef = useRef3(false);
|
|
284
|
-
const smoothedPart = useSmooth(
|
|
285
|
-
partState,
|
|
286
|
-
pacedModeRef.current ? false : {
|
|
287
|
-
drainMs: 150,
|
|
288
|
-
maxCharIntervalMs: 4,
|
|
289
|
-
maxCharsPerFrame: 128,
|
|
290
|
-
minCommitMs: 48
|
|
291
|
-
}
|
|
292
|
-
);
|
|
293
|
-
const networkComplete = partState.status?.type !== "running";
|
|
294
|
-
const smoothLag = partState.text.length - smoothedPart.text.length;
|
|
295
|
-
if (!pacedModeRef.current && !networkComplete && smoothLag >= MARKDOWN_SMOOTH_BACKLOG_CHARS) {
|
|
296
|
-
pacedModeRef.current = true;
|
|
297
|
-
}
|
|
298
|
-
const usePacedMode = pacedModeRef.current;
|
|
299
|
-
const pacedText = useThrottledMarkdownText(partState.text, {
|
|
300
|
-
enabled: usePacedMode,
|
|
301
|
-
isComplete: networkComplete
|
|
302
|
-
});
|
|
303
|
-
const text = usePacedMode ? pacedText : smoothedPart.text;
|
|
304
|
-
const isStreaming = usePacedMode ? !networkComplete || text !== partState.text : smoothedPart.status?.type === "running";
|
|
305
|
-
const handleDownloadArtifact = useCallback2(async (path) => {
|
|
306
|
-
const { downloadSandboxFile: downloadSandboxFile2, toaster: toaster2 } = downloadRef.current;
|
|
307
|
-
try {
|
|
308
|
-
triggerBrowserDownload(await downloadSandboxFile2(path), filenameFromPath(path));
|
|
309
|
-
} catch (error) {
|
|
310
|
-
if (toaster2 != null) {
|
|
311
|
-
toaster2.showError(error);
|
|
312
|
-
} else {
|
|
313
|
-
console.error("Failed to download sandbox artifact", error);
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
}, []);
|
|
317
|
-
return useMemo2(
|
|
318
|
-
() => /* @__PURE__ */ jsx3(Markdown, { content: text, isStreaming, onDownloadArtifact: handleDownloadArtifact }),
|
|
319
|
-
[Markdown, text, isStreaming, handleDownloadArtifact]
|
|
320
|
-
);
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
// src/containers/ReasoningContainer.tsx
|
|
324
|
-
import { useAuiState as useAuiState3 } from "@assistant-ui/react";
|
|
325
|
-
import { useCallback as useCallback3, useRef as useRef4, useState as useState4 } from "react";
|
|
326
|
-
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
327
|
-
function ReasoningContainer({ group }) {
|
|
328
|
-
const ReasoningCard = useSlot("ReasoningCard");
|
|
329
|
-
const content = useAuiState3(
|
|
330
|
-
(s) => group.indices.map((i) => s.message.parts[i]).filter((p) => p != null && p.type === "reasoning").map((p) => p.text ?? "").join("")
|
|
331
|
-
);
|
|
332
|
-
const streaming = useAuiState3((s) => {
|
|
333
|
-
if (s.message.status?.type !== "running") return false;
|
|
334
|
-
const lastIndex = s.message.parts.length - 1;
|
|
335
|
-
if (lastIndex < 0) return false;
|
|
336
|
-
if (s.message.parts[lastIndex]?.type !== "reasoning") return false;
|
|
337
|
-
const lastGroupIndex = group.indices[group.indices.length - 1];
|
|
338
|
-
return lastGroupIndex !== void 0 && lastIndex >= group.indices[0] && lastIndex <= lastGroupIndex;
|
|
339
|
-
});
|
|
340
|
-
const [expanded, setExpanded] = useState4(streaming);
|
|
341
|
-
const [prevStreaming, setPrevStreaming] = useState4(streaming);
|
|
342
|
-
const [isMultiLine, setIsMultiLine] = useState4(false);
|
|
343
|
-
const observerRef = useRef4(null);
|
|
344
|
-
if (streaming !== prevStreaming) {
|
|
345
|
-
setPrevStreaming(streaming);
|
|
346
|
-
if (streaming) setExpanded(true);
|
|
347
|
-
}
|
|
348
|
-
const contentRef = useCallback3(
|
|
349
|
-
(node) => {
|
|
350
|
-
observerRef.current?.disconnect();
|
|
351
|
-
observerRef.current = null;
|
|
352
|
-
if (node == null || streaming) return;
|
|
353
|
-
const check = () => {
|
|
354
|
-
const lineHeight = Number.parseFloat(getComputedStyle(node).lineHeight) || 24;
|
|
355
|
-
setIsMultiLine(node.scrollHeight > lineHeight * 1.5);
|
|
356
|
-
};
|
|
357
|
-
check();
|
|
358
|
-
observerRef.current = new ResizeObserver(check);
|
|
359
|
-
observerRef.current.observe(node);
|
|
360
|
-
},
|
|
361
|
-
[streaming]
|
|
362
|
-
);
|
|
363
|
-
const reasoningTimeText = null;
|
|
364
|
-
const previewText = content.replace(/\s+/g, " ").trim();
|
|
365
|
-
const isShortText = !streaming && content.length > 0 && !isMultiLine;
|
|
366
|
-
const headingText = "Reasoning";
|
|
367
|
-
return /* @__PURE__ */ jsx4(
|
|
368
|
-
ReasoningCard,
|
|
369
|
-
{
|
|
370
|
-
content,
|
|
371
|
-
isStreaming: streaming,
|
|
372
|
-
expanded,
|
|
373
|
-
isMultiLine,
|
|
374
|
-
reasoningTimeText,
|
|
375
|
-
previewText,
|
|
376
|
-
headingText,
|
|
377
|
-
contentRef: isShortText ? contentRef : void 0,
|
|
378
|
-
onToggle: () => setExpanded((prev) => !prev)
|
|
379
|
-
}
|
|
380
|
-
);
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
// src/containers/ToolApprovalContainer.tsx
|
|
384
|
-
import { useCallback as useCallback4, useMemo as useMemo3, useState as useState5 } from "react";
|
|
385
|
-
|
|
386
|
-
// src/utils/toolCallParsing.ts
|
|
387
|
-
import { parse as parsePartialJson } from "partial-json";
|
|
388
|
-
var SUB_AGENT_TOOL_NAME = "create_sub_agent";
|
|
389
|
-
var ASK_USER_TOOL_NAME = "ask_user_question";
|
|
390
|
-
var SANDBOX_TOOL_NAMES = /* @__PURE__ */ new Set(["exec", "sandbox_exec"]);
|
|
391
|
-
var MCP_META_TOOLS = /* @__PURE__ */ new Set(["call_tool", "list_tools", "get_tool_info"]);
|
|
392
|
-
var APPROVAL_OPTION_DEFAULT_LABELS = {
|
|
393
|
-
"allow-once": "Allow",
|
|
394
|
-
"allow-always": "Always allow",
|
|
395
|
-
"reject-once": "Deny",
|
|
396
|
-
"reject-always": "Always deny"
|
|
397
|
-
};
|
|
398
|
-
var isAllowKind = (kind) => kind === "allow-once" || kind === "allow-always";
|
|
399
|
-
function parseJsonIncrementally(content) {
|
|
400
|
-
try {
|
|
401
|
-
return { success: true, value: JSON.parse(content), isPartial: false };
|
|
402
|
-
} catch {
|
|
403
|
-
const trimmed = content.trim();
|
|
404
|
-
if (trimmed[0] !== "{" && trimmed[0] !== "[") return { success: false };
|
|
405
|
-
try {
|
|
406
|
-
return { success: true, value: parsePartialJson(content), isPartial: true };
|
|
407
|
-
} catch {
|
|
408
|
-
return { success: false };
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
function isUnknownRecord(value) {
|
|
413
|
-
return value != null && typeof value === "object" && !Array.isArray(value);
|
|
414
|
-
}
|
|
415
|
-
function parseAskUserQuestionArgs(argsText) {
|
|
416
|
-
if (!argsText) return {};
|
|
417
|
-
try {
|
|
418
|
-
const parsed = JSON.parse(argsText);
|
|
419
|
-
if (parsed == null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
420
|
-
return {};
|
|
421
|
-
}
|
|
422
|
-
const record = parsed;
|
|
423
|
-
const question = typeof record.question === "string" ? record.question : void 0;
|
|
424
|
-
const options = Array.isArray(record.options) ? record.options.filter((item) => typeof item === "string") : void 0;
|
|
425
|
-
return { question, options };
|
|
426
|
-
} catch {
|
|
427
|
-
return {};
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
function getAskUserAnswerResult(result) {
|
|
431
|
-
if (result === void 0 || result === null) return void 0;
|
|
432
|
-
if (typeof result === "string") {
|
|
433
|
-
const trimmed = result.trim();
|
|
434
|
-
return trimmed.length > 0 ? trimmed : void 0;
|
|
435
|
-
}
|
|
436
|
-
if (typeof result === "object" && "content" in result) {
|
|
437
|
-
const content = result.content;
|
|
438
|
-
if (typeof content === "string" && content.trim()) {
|
|
439
|
-
return content.trim();
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
return void 0;
|
|
443
|
-
}
|
|
444
|
-
function hasPendingAskUserResponse(part) {
|
|
445
|
-
return part.interrupt != null && part.result === void 0;
|
|
446
|
-
}
|
|
447
|
-
function hasPendingToolApproval(approval) {
|
|
448
|
-
return approval != null && approval.approved === void 0 && approval.resolution === void 0;
|
|
449
|
-
}
|
|
450
|
-
function buildApprovalOptions(options) {
|
|
451
|
-
const declared = options?.filter((o) => Object.hasOwn(APPROVAL_OPTION_DEFAULT_LABELS, o.kind));
|
|
452
|
-
if (declared && declared.length > 0) {
|
|
453
|
-
const allow = declared.filter((o) => isAllowKind(o.kind));
|
|
454
|
-
const reject = declared.filter((o) => !isAllowKind(o.kind));
|
|
455
|
-
const mapped = [...allow, ...reject].map((o) => ({
|
|
456
|
-
id: o.id,
|
|
457
|
-
label: o.label ?? APPROVAL_OPTION_DEFAULT_LABELS[o.kind] ?? o.id,
|
|
458
|
-
isAllow: isAllowKind(o.kind),
|
|
459
|
-
grants: o.grants,
|
|
460
|
-
confirm: o.confirm != null ? typeof o.confirm === "object" ? o.confirm : {} : void 0
|
|
461
|
-
}));
|
|
462
|
-
if (reject.length === 0) {
|
|
463
|
-
mapped.push({ id: "__deny", label: "Deny", isAllow: false, confirm: {} });
|
|
464
|
-
}
|
|
465
|
-
return mapped;
|
|
466
|
-
}
|
|
467
|
-
return [
|
|
468
|
-
{ id: "__allow", label: "Allow", isAllow: true },
|
|
469
|
-
{ id: "__deny", label: "Deny", isAllow: false, confirm: {} }
|
|
470
|
-
];
|
|
471
|
-
}
|
|
472
|
-
function formatDuration(ms) {
|
|
473
|
-
if (ms < 1e3) return "<1s";
|
|
474
|
-
const seconds = ms / 1e3;
|
|
475
|
-
if (seconds < 10) return `${(Math.floor(seconds * 10) / 10).toFixed(1)}s`;
|
|
476
|
-
if (seconds < 60) return `${Math.floor(seconds)}s`;
|
|
477
|
-
return `${Math.floor(seconds / 60)}m ${Math.floor(seconds % 60)}s`;
|
|
478
|
-
}
|
|
479
|
-
function toStatus(statusType) {
|
|
480
|
-
if (statusType === "complete") return "success";
|
|
481
|
-
if (statusType === "incomplete") return "error";
|
|
482
|
-
return "running";
|
|
483
|
-
}
|
|
484
|
-
function parseSandboxArgs(argsText) {
|
|
485
|
-
if (!argsText) return {};
|
|
486
|
-
const parsed = parseJsonIncrementally(argsText);
|
|
487
|
-
if (!parsed.success || !isUnknownRecord(parsed.value)) return { argsJson: argsText };
|
|
488
|
-
return {
|
|
489
|
-
command: typeof parsed.value.command === "string" ? parsed.value.command : void 0,
|
|
490
|
-
intent: typeof parsed.value.intent === "string" ? parsed.value.intent : void 0,
|
|
491
|
-
argsJson: parsed.isPartial ? argsText : JSON.stringify(parsed.value, null, 2)
|
|
492
|
-
};
|
|
493
|
-
}
|
|
494
|
-
function parseSandboxResult(result) {
|
|
495
|
-
if (result === void 0) return {};
|
|
496
|
-
const parsed = parseJsonIncrementally(result);
|
|
497
|
-
if (!parsed.success || !isUnknownRecord(parsed.value)) return { resultText: result };
|
|
498
|
-
const response = isUnknownRecord(parsed.value.response) ? parsed.value.response : void 0;
|
|
499
|
-
const exitCode = typeof response?.exitCode === "number" ? response.exitCode : null;
|
|
500
|
-
const resultText = typeof response?.result === "string" ? response.result : void 0;
|
|
501
|
-
return {
|
|
502
|
-
exitCode,
|
|
503
|
-
resultText,
|
|
504
|
-
resultJson: parsed.isPartial ? result : JSON.stringify(parsed.value, null, 2)
|
|
505
|
-
};
|
|
506
|
-
}
|
|
507
|
-
function parseMcpToolArgs(argsText) {
|
|
508
|
-
if (!argsText) return {};
|
|
509
|
-
try {
|
|
510
|
-
const parsed = JSON.parse(argsText);
|
|
511
|
-
return {
|
|
512
|
-
mcpServer: parsed.mcp_server,
|
|
513
|
-
innerToolName: parsed.tool_name,
|
|
514
|
-
input: parsed.input
|
|
515
|
-
};
|
|
516
|
-
} catch {
|
|
517
|
-
return {};
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
function getJsonDisplayValue(content) {
|
|
521
|
-
if (!content?.trim()) return { value: "", isJson: false };
|
|
522
|
-
const trimmed = content.trim();
|
|
523
|
-
if (trimmed[0] !== "{" && trimmed[0] !== "[") {
|
|
524
|
-
return { value: content, isJson: false };
|
|
525
|
-
}
|
|
526
|
-
try {
|
|
527
|
-
const parsed = JSON.parse(content);
|
|
528
|
-
return { value: JSON.stringify(parsed, null, 2), isJson: true };
|
|
529
|
-
} catch {
|
|
530
|
-
return { value: content, isJson: false };
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
function getToolResultContent(content) {
|
|
534
|
-
try {
|
|
535
|
-
if (!content) return { isJson: false, data: "" };
|
|
536
|
-
const parsedResult = typeof content === "string" && content.trim().startsWith("{") ? JSON.parse(content) : content;
|
|
537
|
-
if (typeof parsedResult === "object" && parsedResult != null && Array.isArray(parsedResult.content)) {
|
|
538
|
-
const text = parsedResult.content[0]?.text || "";
|
|
539
|
-
const display2 = getJsonDisplayValue(typeof text === "string" ? text : JSON.stringify(text));
|
|
540
|
-
return { data: display2.value, isJson: display2.isJson };
|
|
541
|
-
}
|
|
542
|
-
const display = getJsonDisplayValue(typeof parsedResult === "string" ? parsedResult : JSON.stringify(parsedResult));
|
|
543
|
-
return { data: display.value, isJson: display.isJson };
|
|
544
|
-
} catch {
|
|
545
|
-
return { data: String(content), isJson: false };
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
function resolveSubAgentMeta(part) {
|
|
549
|
-
const artifactSubAgent = part.artifact?.subAgents?.[0];
|
|
550
|
-
const firstNested = part.messages?.[0];
|
|
551
|
-
const subAgent = firstNested?.metadata?.custom?.subAgent;
|
|
552
|
-
return {
|
|
553
|
-
agentName: subAgent?.title ?? subAgent?.name ?? artifactSubAgent?.title ?? artifactSubAgent?.agentInfo?.name ?? part.toolName,
|
|
554
|
-
instruction: subAgent?.input ?? artifactSubAgent?.agentInfo?.input ?? "",
|
|
555
|
-
stepCount: part.messages?.length ?? 0
|
|
556
|
-
};
|
|
557
|
-
}
|
|
558
|
-
function mcpDisplayName(toolName, mcpServer, innerToolName) {
|
|
559
|
-
if (toolName === "call_tool" && innerToolName) {
|
|
560
|
-
return mcpServer ? `call_tool: ${innerToolName} (${mcpServer})` : `call_tool: ${innerToolName}`;
|
|
561
|
-
}
|
|
562
|
-
if (toolName === "get_tool_info" && innerToolName && mcpServer) {
|
|
563
|
-
return `get_tool_info: ${innerToolName} (${mcpServer})`;
|
|
564
|
-
}
|
|
565
|
-
return toolName;
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
// src/containers/ToolApprovalContainer.tsx
|
|
569
|
-
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
570
|
-
function ToolApprovalContainer({
|
|
571
|
-
toolName = "",
|
|
572
|
-
argsText,
|
|
573
|
-
options,
|
|
574
|
-
onSelectOption
|
|
575
|
-
}) {
|
|
576
|
-
const ToolApprovalBar = useSlot("ToolApprovalBar");
|
|
577
|
-
const { mcpServer, innerToolName } = parseMcpToolArgs(argsText);
|
|
578
|
-
const displayToolName = innerToolName && mcpServer ? `${innerToolName} (${mcpServer})` : toolName;
|
|
579
|
-
const [selectedDenyOptionId, setSelectedDenyOptionId] = useState5(null);
|
|
580
|
-
const [denialReason, setDenialReason] = useState5("");
|
|
581
|
-
const [showReasonError, setShowReasonError] = useState5(false);
|
|
582
|
-
const approveOptions = useMemo3(
|
|
583
|
-
() => options.filter((option) => option.isAllow).map((option, index) => ({
|
|
584
|
-
...option,
|
|
585
|
-
variant: index === 0 ? "primary" : "secondary",
|
|
586
|
-
requiresReason: false
|
|
587
|
-
})),
|
|
588
|
-
[options]
|
|
589
|
-
);
|
|
590
|
-
const denyOptions = useMemo3(
|
|
591
|
-
() => options.filter((option) => !option.isAllow).map((option) => ({
|
|
592
|
-
...option,
|
|
593
|
-
variant: "secondary",
|
|
594
|
-
requiresReason: option.confirm != null
|
|
595
|
-
})),
|
|
596
|
-
[options]
|
|
597
|
-
);
|
|
598
|
-
const selectedDenyOption = denyOptions.find((option) => option.id === selectedDenyOptionId);
|
|
599
|
-
const onDenyOptionChange = useCallback4((optionId) => {
|
|
600
|
-
setSelectedDenyOptionId(optionId);
|
|
601
|
-
setDenialReason("");
|
|
602
|
-
setShowReasonError(false);
|
|
603
|
-
}, []);
|
|
604
|
-
const onDenialReasonChange = useCallback4((reason) => {
|
|
605
|
-
setDenialReason(reason);
|
|
606
|
-
setShowReasonError(false);
|
|
607
|
-
}, []);
|
|
608
|
-
const onReasonSubmit = useCallback4(() => {
|
|
609
|
-
const reason = denialReason.trim();
|
|
610
|
-
if (!reason) {
|
|
611
|
-
setShowReasonError(true);
|
|
612
|
-
return;
|
|
613
|
-
}
|
|
614
|
-
if (selectedDenyOptionId) {
|
|
615
|
-
onSelectOption(selectedDenyOptionId, reason);
|
|
616
|
-
onDenyOptionChange(null);
|
|
617
|
-
}
|
|
618
|
-
}, [denialReason, onDenyOptionChange, onSelectOption, selectedDenyOptionId]);
|
|
619
|
-
return /* @__PURE__ */ jsx5(
|
|
620
|
-
ToolApprovalBar,
|
|
621
|
-
{
|
|
622
|
-
toolName: displayToolName,
|
|
623
|
-
approveOptions: approveOptions.length > 0 ? approveOptions : void 0,
|
|
624
|
-
denyOptions: denyOptions.length > 0 ? denyOptions : void 0,
|
|
625
|
-
selectedDenyOption,
|
|
626
|
-
denialReason,
|
|
627
|
-
showReasonError,
|
|
628
|
-
onSelect: onSelectOption,
|
|
629
|
-
onDenyOptionChange,
|
|
630
|
-
onDenialReasonChange,
|
|
631
|
-
onReasonSubmit
|
|
632
|
-
}
|
|
633
|
-
);
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
// src/containers/ToolCallContentBlockContainer.tsx
|
|
637
|
-
import { useCallback as useCallback5, useEffect as useEffect4, useRef as useRef5, useState as useState6 } from "react";
|
|
638
|
-
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
639
|
-
function ToolCallContentBlockContainer(props) {
|
|
640
|
-
const ToolCallContentBlock = useSlot("ToolCallContentBlock");
|
|
641
|
-
const { isJson, onContentHeightChange: notifyContentHeightChange, resizable } = props;
|
|
642
|
-
const [fullscreen, setFullscreen] = useState6(false);
|
|
643
|
-
const [contentHeightRem, setContentHeightRem] = useState6();
|
|
644
|
-
const observerRef = useRef5(null);
|
|
645
|
-
const contentNodeRef = useRef5(null);
|
|
646
|
-
const hasMeasuredRef = useRef5(false);
|
|
647
|
-
const contentRef = useCallback5(
|
|
648
|
-
(node) => {
|
|
649
|
-
observerRef.current?.disconnect();
|
|
650
|
-
observerRef.current = null;
|
|
651
|
-
contentNodeRef.current = node;
|
|
652
|
-
hasMeasuredRef.current = false;
|
|
653
|
-
if (node == null) return;
|
|
654
|
-
setContentHeightRem(void 0);
|
|
655
|
-
if (!resizable) return;
|
|
656
|
-
const updateHeight = () => {
|
|
657
|
-
if (!hasMeasuredRef.current && isJson !== false) return;
|
|
658
|
-
const renderedHeight = node.getBoundingClientRect().height;
|
|
659
|
-
const height = hasMeasuredRef.current && renderedHeight > 0 ? renderedHeight : node.scrollHeight;
|
|
660
|
-
hasMeasuredRef.current = true;
|
|
661
|
-
setContentHeightRem(height / 16);
|
|
662
|
-
};
|
|
663
|
-
updateHeight();
|
|
664
|
-
observerRef.current = new ResizeObserver(updateHeight);
|
|
665
|
-
observerRef.current.observe(node);
|
|
666
|
-
},
|
|
667
|
-
[isJson, resizable]
|
|
668
|
-
);
|
|
669
|
-
const onContentHeightChange = useCallback5(
|
|
670
|
-
(height) => {
|
|
671
|
-
const node = contentNodeRef.current;
|
|
672
|
-
if (node == null) return;
|
|
673
|
-
const renderedHeight = node.getBoundingClientRect().height;
|
|
674
|
-
hasMeasuredRef.current = true;
|
|
675
|
-
setContentHeightRem((renderedHeight > 0 ? renderedHeight : Math.max(height, node.scrollHeight)) / 16);
|
|
676
|
-
notifyContentHeightChange?.(height);
|
|
677
|
-
},
|
|
678
|
-
[notifyContentHeightChange]
|
|
679
|
-
);
|
|
680
|
-
useEffect4(
|
|
681
|
-
() => () => {
|
|
682
|
-
observerRef.current?.disconnect();
|
|
683
|
-
},
|
|
684
|
-
[]
|
|
685
|
-
);
|
|
686
|
-
return /* @__PURE__ */ jsx6(
|
|
687
|
-
ToolCallContentBlock,
|
|
688
|
-
{
|
|
689
|
-
...props,
|
|
690
|
-
fullscreen,
|
|
691
|
-
onFullscreenChange: setFullscreen,
|
|
692
|
-
contentHeightRem,
|
|
693
|
-
contentRef,
|
|
694
|
-
onContentHeightChange
|
|
695
|
-
}
|
|
696
|
-
);
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
// src/containers/ToolCallContainer.tsx
|
|
700
|
-
import {
|
|
701
|
-
MessagePartPrimitive,
|
|
702
|
-
MessagePrimitive,
|
|
703
|
-
useToolCallElapsed
|
|
704
|
-
} from "@assistant-ui/react";
|
|
705
|
-
import { useTrueFoundryRespondToToolApproval } from "@truefoundry/assistant-ui-runtime";
|
|
706
|
-
import { useState as useState8 } from "react";
|
|
707
|
-
|
|
708
|
-
// src/containers/nestedApprovalBridge.ts
|
|
709
|
-
import { createContext, useContext } from "react";
|
|
710
|
-
var NestedApprovalBridgeContext = createContext(false);
|
|
711
|
-
function useNestedApprovalBridge() {
|
|
712
|
-
return useContext(NestedApprovalBridgeContext);
|
|
713
|
-
}
|
|
714
|
-
|
|
715
|
-
// src/containers/SandboxToolCallContainer.tsx
|
|
716
|
-
import { useMemo as useMemo4, useState as useState7 } from "react";
|
|
717
|
-
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
718
|
-
function SandboxToolCallContainer(props) {
|
|
719
|
-
const SandboxToolCallCard = useSlot("SandboxToolCallCard");
|
|
720
|
-
const [viewMode, setViewMode] = useState7("terminal");
|
|
721
|
-
const hasContent = useMemo4(() => {
|
|
722
|
-
if (viewMode === "code") return Boolean(props.argsJson || props.resultJson);
|
|
723
|
-
return Boolean(props.command || props.resultText || props.resultJson);
|
|
724
|
-
}, [props.argsJson, props.command, props.resultJson, props.resultText, viewMode]);
|
|
725
|
-
return /* @__PURE__ */ jsx7(SandboxToolCallCard, { ...props, viewMode, hasContent, onViewModeChange: setViewMode });
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
// src/containers/ToolCallContainer.tsx
|
|
729
|
-
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
730
|
-
function NestedSubAgentAssistantMessage() {
|
|
731
|
-
const AssistantMessageBubble = useSlot("AssistantMessageBubble");
|
|
732
|
-
return /* @__PURE__ */ jsx8("div", { className: "mb-3 min-w-0", children: /* @__PURE__ */ jsx8(MessagePrimitive.Root, { "data-role": "assistant", children: /* @__PURE__ */ jsx8(AssistantMessageBubble, { children: /* @__PURE__ */ jsx8(
|
|
733
|
-
MessagePrimitive.Parts,
|
|
734
|
-
{
|
|
735
|
-
components: {
|
|
736
|
-
Text: AssistantTextContainer,
|
|
737
|
-
Reasoning: AssistantTextContainer,
|
|
738
|
-
tools: { Fallback: ToolCallContainer }
|
|
739
|
-
}
|
|
740
|
-
}
|
|
741
|
-
) }) }) });
|
|
742
|
-
}
|
|
743
|
-
function ToolApprovalSlot({ part }) {
|
|
744
|
-
const isNestedReadonly = useNestedApprovalBridge();
|
|
745
|
-
const respondToNestedApproval = useTrueFoundryRespondToToolApproval();
|
|
746
|
-
const respond = (response) => {
|
|
747
|
-
if (!isNestedReadonly) {
|
|
748
|
-
part.respondToApproval(response);
|
|
749
|
-
return;
|
|
750
|
-
}
|
|
751
|
-
if (part.approval == null) return;
|
|
752
|
-
let approved;
|
|
753
|
-
let optionId;
|
|
754
|
-
if ("approved" in response) {
|
|
755
|
-
approved = response.approved;
|
|
756
|
-
} else if ("optionId" in response) {
|
|
757
|
-
const option = buildApprovalOptions(part.approval.options).find((o) => o.id === response.optionId);
|
|
758
|
-
if (option == null) return;
|
|
759
|
-
approved = option.isAllow;
|
|
760
|
-
optionId = response.optionId;
|
|
761
|
-
}
|
|
762
|
-
if (approved === void 0) return;
|
|
763
|
-
respondToNestedApproval({
|
|
764
|
-
approvalId: part.approval.id,
|
|
765
|
-
approved,
|
|
766
|
-
...optionId != null && optionId !== "__allow" && optionId !== "__deny" ? { optionId } : {},
|
|
767
|
-
..."reason" in response && response.reason != null ? { reason: response.reason } : {}
|
|
768
|
-
});
|
|
769
|
-
};
|
|
770
|
-
const onSelectOption = (optionId, reason) => {
|
|
771
|
-
if (optionId === "__allow") return respond({ approved: true });
|
|
772
|
-
if (optionId === "__deny") return respond({ approved: false, reason });
|
|
773
|
-
return respond({ optionId, reason });
|
|
774
|
-
};
|
|
775
|
-
return /* @__PURE__ */ jsx8(
|
|
776
|
-
ToolApprovalContainer,
|
|
777
|
-
{
|
|
778
|
-
toolName: part.toolName,
|
|
779
|
-
argsText: part.argsText,
|
|
780
|
-
options: buildApprovalOptions(part.approval?.options),
|
|
781
|
-
onSelectOption
|
|
782
|
-
}
|
|
783
|
-
);
|
|
784
|
-
}
|
|
785
|
-
function RequestResponseSlots({
|
|
786
|
-
request,
|
|
787
|
-
response
|
|
788
|
-
}) {
|
|
789
|
-
return {
|
|
790
|
-
requestSlot: request.value ? /* @__PURE__ */ jsx8(
|
|
791
|
-
ToolCallContentBlockContainer,
|
|
792
|
-
{
|
|
793
|
-
title: "Request",
|
|
794
|
-
content: request.value,
|
|
795
|
-
isJson: request.isJson,
|
|
796
|
-
maxHeight: "10.5rem"
|
|
797
|
-
}
|
|
798
|
-
) : response.data ? /* @__PURE__ */ jsx8(ToolCallContentBlockContainer, { title: "Request", content: "{}", isJson: true, maxHeight: "10.5rem" }) : void 0,
|
|
799
|
-
responseSlot: response.data ? /* @__PURE__ */ jsx8(ToolCallContentBlockContainer, { title: "Response", content: response.data, isJson: response.isJson, resizable: true }) : void 0
|
|
800
|
-
};
|
|
801
|
-
}
|
|
802
|
-
var ToolCallContainer = (part) => {
|
|
803
|
-
const ToolCallCard = useSlot("ToolCallCard");
|
|
804
|
-
const SubAgentCard = useSlot("SubAgentCard");
|
|
805
|
-
const AskUserPrompt = useSlot("AskUserPrompt");
|
|
806
|
-
const elapsedMs = useToolCallElapsed();
|
|
807
|
-
const isRequiresAction = part.status?.type === "requires-action";
|
|
808
|
-
const isSubAgent = part.toolName === SUB_AGENT_TOOL_NAME;
|
|
809
|
-
const isSandbox = SANDBOX_TOOL_NAMES.has(part.toolName);
|
|
810
|
-
const [expanded, setExpanded] = useState8(isRequiresAction);
|
|
811
|
-
const [prevRequiresAction, setPrevRequiresAction] = useState8(isRequiresAction);
|
|
812
|
-
if (isRequiresAction !== prevRequiresAction) {
|
|
813
|
-
setPrevRequiresAction(isRequiresAction);
|
|
814
|
-
if (isRequiresAction) setExpanded(true);
|
|
815
|
-
}
|
|
816
|
-
const showApproval = isRequiresAction && hasPendingToolApproval(part.approval);
|
|
817
|
-
const durationText = elapsedMs === void 0 ? void 0 : formatDuration(elapsedMs);
|
|
818
|
-
const status = toStatus(part.status?.type);
|
|
819
|
-
const onToggle = () => setExpanded((prev) => !prev);
|
|
820
|
-
if (part.toolName === ASK_USER_TOOL_NAME) {
|
|
821
|
-
if (hasPendingAskUserResponse(part)) {
|
|
822
|
-
return null;
|
|
823
|
-
}
|
|
824
|
-
const answer = getAskUserAnswerResult(part.result);
|
|
825
|
-
if (answer == null) {
|
|
826
|
-
return null;
|
|
827
|
-
}
|
|
828
|
-
const { question, options = [] } = parseAskUserQuestionArgs(part.argsText);
|
|
829
|
-
const isCustom = options.length > 0 && !options.includes(answer);
|
|
830
|
-
return /* @__PURE__ */ jsx8(
|
|
831
|
-
AskUserPrompt,
|
|
832
|
-
{
|
|
833
|
-
questions: [],
|
|
834
|
-
answeredQuestions: [
|
|
835
|
-
{
|
|
836
|
-
id: part.toolCallId,
|
|
837
|
-
question: question ?? "Question",
|
|
838
|
-
options,
|
|
839
|
-
answer,
|
|
840
|
-
isCustom
|
|
841
|
-
}
|
|
842
|
-
],
|
|
843
|
-
onSubmit: () => {
|
|
844
|
-
},
|
|
845
|
-
readOnly: true
|
|
846
|
-
}
|
|
847
|
-
);
|
|
848
|
-
}
|
|
849
|
-
if (isSubAgent) {
|
|
850
|
-
const { agentName, instruction, stepCount } = resolveSubAgentMeta(part);
|
|
851
|
-
return /* @__PURE__ */ jsx8("div", { "data-slot": "tool-call-card", "data-variant": "sub-agent", className: "w-full", children: /* @__PURE__ */ jsx8(
|
|
852
|
-
SubAgentCard,
|
|
853
|
-
{
|
|
854
|
-
status,
|
|
855
|
-
expanded,
|
|
856
|
-
onToggle,
|
|
857
|
-
durationText,
|
|
858
|
-
agentName,
|
|
859
|
-
instruction,
|
|
860
|
-
stepCount,
|
|
861
|
-
children: /* @__PURE__ */ jsx8(NestedApprovalBridgeContext.Provider, { value: true, children: /* @__PURE__ */ jsx8(
|
|
862
|
-
MessagePartPrimitive.Messages,
|
|
863
|
-
{
|
|
864
|
-
components: {
|
|
865
|
-
AssistantMessage: NestedSubAgentAssistantMessage,
|
|
866
|
-
UserMessage: () => null
|
|
867
|
-
}
|
|
868
|
-
}
|
|
869
|
-
) })
|
|
870
|
-
}
|
|
871
|
-
) });
|
|
872
|
-
}
|
|
873
|
-
const resultString = part.result === void 0 ? void 0 : typeof part.result === "string" ? part.result : JSON.stringify(part.result, null, 2);
|
|
874
|
-
if (isSandbox) {
|
|
875
|
-
const { command, intent, argsJson } = parseSandboxArgs(part.argsText);
|
|
876
|
-
const { exitCode, resultText, resultJson } = parseSandboxResult(resultString);
|
|
877
|
-
return /* @__PURE__ */ jsx8(
|
|
878
|
-
SandboxToolCallContainer,
|
|
879
|
-
{
|
|
880
|
-
name: part.toolName,
|
|
881
|
-
intent,
|
|
882
|
-
status,
|
|
883
|
-
expanded,
|
|
884
|
-
onToggle,
|
|
885
|
-
durationText,
|
|
886
|
-
command,
|
|
887
|
-
exitCode,
|
|
888
|
-
argsJson,
|
|
889
|
-
resultText,
|
|
890
|
-
resultJson
|
|
891
|
-
}
|
|
892
|
-
);
|
|
893
|
-
}
|
|
894
|
-
if (MCP_META_TOOLS.has(part.toolName)) {
|
|
895
|
-
const { mcpServer, innerToolName, input } = parseMcpToolArgs(part.argsText);
|
|
896
|
-
const argsDisplay2 = getJsonDisplayValue(part.argsText);
|
|
897
|
-
const resultDisplay2 = getToolResultContent(part.result);
|
|
898
|
-
if (part.toolName === "list_tools" && mcpServer) {
|
|
899
|
-
const slots3 = RequestResponseSlots({
|
|
900
|
-
request: argsDisplay2,
|
|
901
|
-
response: resultDisplay2
|
|
902
|
-
});
|
|
903
|
-
return /* @__PURE__ */ jsx8(
|
|
904
|
-
ToolCallCard,
|
|
905
|
-
{
|
|
906
|
-
toolName: `Listing tools \xB7 ${mcpServer}`,
|
|
907
|
-
icon: "mcp-server",
|
|
908
|
-
expanded,
|
|
909
|
-
onToggle,
|
|
910
|
-
awaiting: status === "running",
|
|
911
|
-
awaitingText: durationText ?? "Awaiting Response\u2026",
|
|
912
|
-
showResponseLine: status !== "running" && !!resultDisplay2.data,
|
|
913
|
-
mcpServerName: mcpServer,
|
|
914
|
-
...slots3
|
|
915
|
-
}
|
|
916
|
-
);
|
|
917
|
-
}
|
|
918
|
-
const inputDisplay = input !== void 0 ? getJsonDisplayValue(JSON.stringify(input, null, 2)) : argsDisplay2;
|
|
919
|
-
const slots2 = RequestResponseSlots({
|
|
920
|
-
request: inputDisplay,
|
|
921
|
-
response: resultDisplay2
|
|
922
|
-
});
|
|
923
|
-
return /* @__PURE__ */ jsx8(
|
|
924
|
-
ToolCallCard,
|
|
925
|
-
{
|
|
926
|
-
toolName: mcpDisplayName(part.toolName, mcpServer, innerToolName),
|
|
927
|
-
icon: "mcp-server",
|
|
928
|
-
expanded,
|
|
929
|
-
onToggle,
|
|
930
|
-
awaiting: status === "running",
|
|
931
|
-
awaitingText: durationText ?? "Awaiting Response\u2026",
|
|
932
|
-
showResponseLine: status !== "running" && resultDisplay2.data !== void 0,
|
|
933
|
-
mcpServerName: mcpServer,
|
|
934
|
-
...slots2,
|
|
935
|
-
approvalSlot: showApproval ? /* @__PURE__ */ jsx8(ToolApprovalSlot, { part }) : void 0
|
|
936
|
-
}
|
|
937
|
-
);
|
|
938
|
-
}
|
|
939
|
-
const argsDisplay = getJsonDisplayValue(part.argsText);
|
|
940
|
-
const resultDisplay = getToolResultContent(part.result);
|
|
941
|
-
const slots = RequestResponseSlots({
|
|
942
|
-
request: argsDisplay,
|
|
943
|
-
response: resultDisplay
|
|
944
|
-
});
|
|
945
|
-
return /* @__PURE__ */ jsx8(
|
|
946
|
-
ToolCallCard,
|
|
947
|
-
{
|
|
948
|
-
toolName: part.toolName,
|
|
949
|
-
expanded,
|
|
950
|
-
onToggle,
|
|
951
|
-
awaiting: status === "running",
|
|
952
|
-
awaitingText: durationText ?? "Awaiting Response\u2026",
|
|
953
|
-
showResponseLine: status !== "running" && resultDisplay.data !== void 0,
|
|
954
|
-
...slots,
|
|
955
|
-
approvalSlot: showApproval ? /* @__PURE__ */ jsx8(ToolApprovalSlot, { part }) : void 0
|
|
956
|
-
}
|
|
957
|
-
);
|
|
958
|
-
};
|
|
959
|
-
|
|
960
|
-
// src/containers/AssistantMessageContainer.tsx
|
|
961
|
-
import { useActionBarCopy, useMessageError, useThreadIsRunning as useThreadIsRunning2 } from "@assistant-ui/core/react";
|
|
962
|
-
import { MessagePrimitive as MessagePrimitive2, useAuiState as useAuiState5 } from "@assistant-ui/react";
|
|
963
|
-
import { useTrueFoundryResumeUnavailable } from "@truefoundry/assistant-ui-runtime";
|
|
964
|
-
|
|
965
|
-
// src/containers/MessageImageContainer.tsx
|
|
966
|
-
import { useAuiState as useAuiState4 } from "@assistant-ui/react";
|
|
967
|
-
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
968
|
-
function MessageImageContainer() {
|
|
969
|
-
const AttachmentCard = useSlot("AttachmentCard");
|
|
970
|
-
const AttachmentPreviewDialog = useSlot("AttachmentPreviewDialog");
|
|
971
|
-
const image = useAuiState4((s) => s.part.type === "image" ? s.part.image : "");
|
|
972
|
-
const filename = useAuiState4((s) => s.part.type === "image" ? s.part.filename : void 0);
|
|
973
|
-
if (!image) {
|
|
974
|
-
return null;
|
|
975
|
-
}
|
|
976
|
-
const card = /* @__PURE__ */ jsx9(
|
|
977
|
-
AttachmentCard,
|
|
978
|
-
{
|
|
979
|
-
name: filename ?? "image",
|
|
980
|
-
previewSrc: image,
|
|
981
|
-
isImage: true,
|
|
982
|
-
size: "preview",
|
|
983
|
-
previewRem: USER_MESSAGE_ATTACHMENT_PREVIEW_REM
|
|
984
|
-
}
|
|
985
|
-
);
|
|
986
|
-
return /* @__PURE__ */ jsx9(AttachmentPreviewDialog, { previewSrc: image, children: /* @__PURE__ */ jsx9("div", { className: "aui-message-image", children: card }) });
|
|
987
|
-
}
|
|
988
|
-
|
|
989
|
-
// src/containers/AssistantMessageContainer.tsx
|
|
990
|
-
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
991
|
-
function AssistantLeafPartContainer({ part }) {
|
|
992
|
-
switch (part.type) {
|
|
993
|
-
case "text":
|
|
994
|
-
case "reasoning":
|
|
995
|
-
return /* @__PURE__ */ jsx10(AssistantTextContainer, {});
|
|
996
|
-
case "image":
|
|
997
|
-
return /* @__PURE__ */ jsx10(MessageImageContainer, {});
|
|
998
|
-
case "tool-call":
|
|
999
|
-
return /* @__PURE__ */ jsx10(ToolCallContainer, { ...part });
|
|
1000
|
-
default:
|
|
1001
|
-
return null;
|
|
1002
|
-
}
|
|
1003
|
-
}
|
|
1004
|
-
function AssistantMessageContainer() {
|
|
1005
|
-
const AssistantMessageBubble = useSlot("AssistantMessageBubble");
|
|
1006
|
-
const MessageActionBar = useSlot("MessageActionBar");
|
|
1007
|
-
const MessageErrorBanner = useSlot("MessageErrorBanner");
|
|
1008
|
-
const MessageIndicator = useSlot("MessageIndicator");
|
|
1009
|
-
const isThreadRunning = useThreadIsRunning2();
|
|
1010
|
-
const resumeUnavailable = useTrueFoundryResumeUnavailable();
|
|
1011
|
-
const error = useMessageError();
|
|
1012
|
-
const createdAt = useAuiState5((s) => s.message.createdAt);
|
|
1013
|
-
const isMessageRunning = useAuiState5((s) => s.message.status?.type === "running");
|
|
1014
|
-
const { copy, isCopied } = useActionBarCopy({
|
|
1015
|
-
copyToClipboard: (text) => navigator.clipboard.writeText(text)
|
|
1016
|
-
});
|
|
1017
|
-
const parts = useAuiState5((s) => s.message.parts);
|
|
1018
|
-
const { cutIndex, hasFinal, toolCount, thinkingCount } = computeAgentStepsSplit(parts, isMessageRunning);
|
|
1019
|
-
const groupBy = (part, _context) => {
|
|
1020
|
-
const index = parts.findIndex((p) => p === part);
|
|
1021
|
-
if (index === -1) return null;
|
|
1022
|
-
if (part.type === "text" && index >= cutIndex) {
|
|
1023
|
-
return null;
|
|
1024
|
-
}
|
|
1025
|
-
if (index < cutIndex) {
|
|
1026
|
-
if (part.type === "reasoning") {
|
|
1027
|
-
return ["group-agentSteps", "group-reasoning"];
|
|
1028
|
-
}
|
|
1029
|
-
return ["group-agentSteps"];
|
|
1030
|
-
}
|
|
1031
|
-
return null;
|
|
1032
|
-
};
|
|
1033
|
-
return /* @__PURE__ */ jsx10(MessagePrimitive2.Root, { "data-role": "assistant", children: /* @__PURE__ */ jsx10(
|
|
1034
|
-
AssistantMessageBubble,
|
|
1035
|
-
{
|
|
1036
|
-
error: error !== void 0 ? /* @__PURE__ */ jsx10(MessageErrorBanner, { message: String(error) }) : void 0,
|
|
1037
|
-
actionBar: !isThreadRunning ? /* @__PURE__ */ jsx10(MessageActionBar, { isCopied, onCopy: copy, createdAt }) : void 0,
|
|
1038
|
-
children: /* @__PURE__ */ jsx10(MessagePrimitive2.GroupedParts, { groupBy, children: ({ part, children }) => {
|
|
1039
|
-
switch (part.type) {
|
|
1040
|
-
case "group-agentSteps":
|
|
1041
|
-
return /* @__PURE__ */ jsx10(AgentStepsContainer, { toolCount, thinkingCount, hasFinal, children });
|
|
1042
|
-
case "group-reasoning":
|
|
1043
|
-
return /* @__PURE__ */ jsx10(ReasoningContainer, { group: part });
|
|
1044
|
-
case "text": {
|
|
1045
|
-
const index = parts.findIndex((p) => p === part);
|
|
1046
|
-
if (index >= 0 && index < cutIndex) {
|
|
1047
|
-
return /* @__PURE__ */ jsx10("div", { className: "mb-2 ml-[1.75rem] text-xs text-text-secondary [&_.markdown-body]:text-inherit", children: /* @__PURE__ */ jsx10(AssistantTextContainer, {}) });
|
|
1048
|
-
}
|
|
1049
|
-
return /* @__PURE__ */ jsx10(AssistantTextContainer, {});
|
|
1050
|
-
}
|
|
1051
|
-
case "reasoning":
|
|
1052
|
-
case "tool-call":
|
|
1053
|
-
case "image":
|
|
1054
|
-
case "data":
|
|
1055
|
-
return /* @__PURE__ */ jsx10(AssistantLeafPartContainer, { part });
|
|
1056
|
-
case "indicator":
|
|
1057
|
-
return resumeUnavailable ? null : /* @__PURE__ */ jsx10(MessageIndicator, {});
|
|
1058
|
-
default:
|
|
1059
|
-
return null;
|
|
1060
|
-
}
|
|
1061
|
-
} })
|
|
1062
|
-
}
|
|
1063
|
-
) });
|
|
1064
|
-
}
|
|
1065
|
-
|
|
1066
|
-
// src/containers/AttachmentsContainer.tsx
|
|
1067
|
-
import { ComposerPrimitive, MessagePrimitive as MessagePrimitive3, useAui as useAui2, useAuiState as useAuiState7 } from "@assistant-ui/react";
|
|
1068
|
-
|
|
1069
|
-
// src/containers/useAttachmentPreviewSrc.ts
|
|
1070
|
-
import { useAuiState as useAuiState6 } from "@assistant-ui/react";
|
|
1071
|
-
import { useEffect as useEffect5, useState as useState9 } from "react";
|
|
1072
|
-
function isImageAttachment(type, contentType) {
|
|
1073
|
-
return type === "image" || (contentType?.startsWith("image/") ?? false);
|
|
1074
|
-
}
|
|
1075
|
-
function useFileObjectUrl(file) {
|
|
1076
|
-
const [src, setSrc] = useState9(void 0);
|
|
1077
|
-
useEffect5(() => {
|
|
1078
|
-
if (!file) {
|
|
1079
|
-
setSrc(void 0);
|
|
1080
|
-
return;
|
|
1081
|
-
}
|
|
1082
|
-
const objectUrl = URL.createObjectURL(file);
|
|
1083
|
-
setSrc(objectUrl);
|
|
1084
|
-
return () => URL.revokeObjectURL(objectUrl);
|
|
1085
|
-
}, [file]);
|
|
1086
|
-
return src;
|
|
1087
|
-
}
|
|
1088
|
-
function useAttachmentPreviewSrc() {
|
|
1089
|
-
const type = useAuiState6((s) => s.attachment.type);
|
|
1090
|
-
const contentType = useAuiState6((s) => s.attachment.contentType);
|
|
1091
|
-
const file = useAuiState6((s) => "file" in s.attachment ? s.attachment.file : void 0);
|
|
1092
|
-
const contentSrc = useAuiState6((s) => {
|
|
1093
|
-
if (!isImageAttachment(s.attachment.type, s.attachment.contentType)) return void 0;
|
|
1094
|
-
const imagePart = s.attachment.content?.find((part) => part.type === "image");
|
|
1095
|
-
if (imagePart?.type === "image" && imagePart.image) return imagePart.image;
|
|
1096
|
-
return void 0;
|
|
1097
|
-
});
|
|
1098
|
-
const image = isImageAttachment(type, contentType);
|
|
1099
|
-
const fileSrc = useFileObjectUrl(image ? file : void 0);
|
|
1100
|
-
if (!image) return void 0;
|
|
1101
|
-
return fileSrc ?? contentSrc;
|
|
1102
|
-
}
|
|
1103
|
-
|
|
1104
|
-
// src/containers/AttachmentsContainer.tsx
|
|
1105
|
-
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
1106
|
-
function ComposerAttachmentItem() {
|
|
1107
|
-
const AttachmentPreviewDialog = useSlot("AttachmentPreviewDialog");
|
|
1108
|
-
const AttachmentCard = useSlot("AttachmentCard");
|
|
1109
|
-
const aui = useAui2();
|
|
1110
|
-
const name = useAuiState7((s) => s.attachment.name);
|
|
1111
|
-
const contentType = useAuiState7((s) => s.attachment.contentType);
|
|
1112
|
-
const type = useAuiState7((s) => s.attachment.type);
|
|
1113
|
-
const isImage = isImageAttachment(type, contentType);
|
|
1114
|
-
const previewSrc = useAttachmentPreviewSrc();
|
|
1115
|
-
return /* @__PURE__ */ jsx11(AttachmentPreviewDialog, { previewSrc, children: /* @__PURE__ */ jsx11(
|
|
1116
|
-
AttachmentCard,
|
|
1117
|
-
{
|
|
1118
|
-
name,
|
|
1119
|
-
contentType,
|
|
1120
|
-
previewSrc,
|
|
1121
|
-
isImage,
|
|
1122
|
-
size: "chip",
|
|
1123
|
-
onRemove: () => void aui.attachment().remove()
|
|
1124
|
-
}
|
|
1125
|
-
) });
|
|
1126
|
-
}
|
|
1127
|
-
function MessageAttachmentItem() {
|
|
1128
|
-
const AttachmentPreviewDialog = useSlot("AttachmentPreviewDialog");
|
|
1129
|
-
const AttachmentCard = useSlot("AttachmentCard");
|
|
1130
|
-
const name = useAuiState7((s) => s.attachment.name);
|
|
1131
|
-
const contentType = useAuiState7((s) => s.attachment.contentType);
|
|
1132
|
-
const type = useAuiState7((s) => s.attachment.type);
|
|
1133
|
-
const isImage = isImageAttachment(type, contentType);
|
|
1134
|
-
const previewSrc = useAttachmentPreviewSrc();
|
|
1135
|
-
const card = /* @__PURE__ */ jsx11(
|
|
1136
|
-
AttachmentCard,
|
|
1137
|
-
{
|
|
1138
|
-
name,
|
|
1139
|
-
contentType,
|
|
1140
|
-
previewSrc,
|
|
1141
|
-
isImage,
|
|
1142
|
-
size: isImage ? "preview" : "chip",
|
|
1143
|
-
previewRem: USER_MESSAGE_ATTACHMENT_PREVIEW_REM
|
|
1144
|
-
}
|
|
1145
|
-
);
|
|
1146
|
-
if (isImage && previewSrc) {
|
|
1147
|
-
return /* @__PURE__ */ jsx11(AttachmentPreviewDialog, { previewSrc, children: card });
|
|
1148
|
-
}
|
|
1149
|
-
return card;
|
|
1150
|
-
}
|
|
1151
|
-
function ComposerAttachmentsContainer() {
|
|
1152
|
-
return /* @__PURE__ */ jsx11("div", { className: "aui-composer-attachments flex w-full flex-row flex-wrap items-center gap-2 empty:hidden", children: /* @__PURE__ */ jsx11(ComposerPrimitive.Attachments, { children: () => /* @__PURE__ */ jsx11(ComposerAttachmentItem, {}) }) });
|
|
1153
|
-
}
|
|
1154
|
-
function MessageAttachmentsContainer() {
|
|
1155
|
-
return /* @__PURE__ */ jsx11("div", { className: "aui-user-message-attachments-end col-span-full col-start-1 row-start-1 flex w-full flex-row justify-end gap-2", children: /* @__PURE__ */ jsx11(MessagePrimitive3.Attachments, { children: () => /* @__PURE__ */ jsx11(MessageAttachmentItem, {}) }) });
|
|
1156
|
-
}
|
|
1157
|
-
function ComposerAttachmentPickerContainer() {
|
|
1158
|
-
const AttachmentPickerButton = useSlot("AttachmentPickerButton");
|
|
1159
|
-
return /* @__PURE__ */ jsx11(ComposerPrimitive.AddAttachment, { asChild: true, children: /* @__PURE__ */ jsx11(AttachmentPickerButton, {}) });
|
|
1160
|
-
}
|
|
1161
|
-
|
|
1162
|
-
// src/hooks/useComposerPauseView.ts
|
|
1163
|
-
import { useAuiState as useAuiState8 } from "@assistant-ui/react";
|
|
1164
|
-
import { useTrueFoundryToolResponses as useTrueFoundryToolResponses2 } from "@truefoundry/assistant-ui-runtime";
|
|
1165
|
-
function threadHasPendingMcpAuth(s) {
|
|
1166
|
-
const messages = s.thread.messages;
|
|
1167
|
-
const last = messages[messages.length - 1];
|
|
1168
|
-
if (last?.role !== "assistant") return false;
|
|
1169
|
-
if (last.status?.type !== "requires-action") return false;
|
|
1170
|
-
return last.metadata?.custom?.pendingMcpAuth === true;
|
|
1171
|
-
}
|
|
1172
|
-
function useComposerPauseView() {
|
|
1173
|
-
const mcpPending = useAuiState8(threadHasPendingMcpAuth);
|
|
1174
|
-
const { pending: toolResponsesPending } = useTrueFoundryToolResponses2();
|
|
1175
|
-
const customActionRenderers = useOptionalCustomActionRenderers();
|
|
1176
|
-
if (mcpPending) {
|
|
1177
|
-
return { kind: "mcp" };
|
|
1178
|
-
}
|
|
1179
|
-
const firstPending = toolResponsesPending[0];
|
|
1180
|
-
if (firstPending != null) {
|
|
1181
|
-
const toolName = firstPending.toolName;
|
|
1182
|
-
if (toolName != null && customActionRenderers?.[toolName] != null) {
|
|
1183
|
-
return { kind: "custom", toolName };
|
|
1184
|
-
}
|
|
1185
|
-
return { kind: "ask-user" };
|
|
1186
|
-
}
|
|
1187
|
-
return { kind: "compose" };
|
|
1188
|
-
}
|
|
1189
|
-
|
|
1190
|
-
// src/containers/CustomActionContainer.tsx
|
|
1191
|
-
import { useThreadIsRunning as useThreadIsRunning3 } from "@assistant-ui/core/react";
|
|
1192
|
-
import { useTrueFoundryToolResponses as useTrueFoundryToolResponses3 } from "@truefoundry/assistant-ui-runtime";
|
|
1193
|
-
import { useCallback as useCallback6 } from "react";
|
|
1194
|
-
import { jsx as jsx12 } from "react/jsx-runtime";
|
|
1195
|
-
function CustomActionContainer() {
|
|
1196
|
-
const renderers = useOptionalCustomActionRenderers();
|
|
1197
|
-
const { pending, respond } = useTrueFoundryToolResponses3();
|
|
1198
|
-
const isRunning = useThreadIsRunning3();
|
|
1199
|
-
const item = pending[0];
|
|
1200
|
-
const onSubmit = useCallback6(
|
|
1201
|
-
(content) => {
|
|
1202
|
-
if (item == null) return;
|
|
1203
|
-
const trimmed = content.trim();
|
|
1204
|
-
if (!trimmed) return;
|
|
1205
|
-
respond({ toolCallId: item.toolCallId, content: trimmed });
|
|
1206
|
-
},
|
|
1207
|
-
[item, respond]
|
|
1208
|
-
);
|
|
1209
|
-
if (item == null || item.toolName == null) return null;
|
|
1210
|
-
const Renderer = renderers?.[item.toolName];
|
|
1211
|
-
if (Renderer == null) return null;
|
|
1212
|
-
return /* @__PURE__ */ jsx12(Renderer, { args: item.args ?? {}, disabled: isRunning, onSubmit });
|
|
1213
|
-
}
|
|
1214
|
-
|
|
1215
|
-
// src/containers/McpAuthContainer.tsx
|
|
1216
|
-
import { useThreadIsRunning as useThreadIsRunning4 } from "@assistant-ui/core/react";
|
|
1217
|
-
import { useTrueFoundryMcpAuth } from "@truefoundry/assistant-ui-runtime";
|
|
1218
|
-
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
1219
|
-
function CatalogMcpAuthPrompt({ servers, onContinue, readOnly }) {
|
|
1220
|
-
const McpAuthPrompt = useSlot("McpAuthPrompt");
|
|
1221
|
-
const { handleAuthorize } = useMCPAuth();
|
|
1222
|
-
const { refreshConnectors } = useDraftCatalog();
|
|
1223
|
-
const handleConnect = (serverId) => {
|
|
1224
|
-
void handleAuthorize(serverId, (isSuccess) => {
|
|
1225
|
-
if (isSuccess) {
|
|
1226
|
-
void refreshConnectors();
|
|
1227
|
-
}
|
|
1228
|
-
});
|
|
1229
|
-
};
|
|
1230
|
-
return /* @__PURE__ */ jsx13(McpAuthPrompt, { servers, onConnect: handleConnect, onContinue, readOnly });
|
|
1231
|
-
}
|
|
1232
|
-
function McpAuthContainer() {
|
|
1233
|
-
const McpAuthPrompt = useSlot("McpAuthPrompt");
|
|
1234
|
-
const { pending, resume } = useTrueFoundryMcpAuth();
|
|
1235
|
-
const isRunning = useThreadIsRunning4();
|
|
1236
|
-
const catalog = useOptionalCatalogServer();
|
|
1237
|
-
if (!pending) return null;
|
|
1238
|
-
if (catalog) {
|
|
1239
|
-
return /* @__PURE__ */ jsx13(CatalogMcpAuthPrompt, { servers: pending.mcpServers, onContinue: () => void resume(), readOnly: isRunning });
|
|
1240
|
-
}
|
|
1241
|
-
const handleConnect = (serverId) => {
|
|
1242
|
-
const server = pending.mcpServers.find((s) => s.id === serverId);
|
|
1243
|
-
if (server?.authUrl) {
|
|
1244
|
-
window.open(server.authUrl, "_blank", "noopener,noreferrer");
|
|
1245
|
-
}
|
|
1246
|
-
};
|
|
1247
|
-
return /* @__PURE__ */ jsx13(
|
|
1248
|
-
McpAuthPrompt,
|
|
1249
|
-
{
|
|
1250
|
-
servers: pending.mcpServers,
|
|
1251
|
-
onConnect: handleConnect,
|
|
1252
|
-
onContinue: () => void resume(),
|
|
1253
|
-
readOnly: isRunning
|
|
1254
|
-
}
|
|
1255
|
-
);
|
|
1256
|
-
}
|
|
1257
|
-
|
|
1258
|
-
// src/containers/ComposerContainer.tsx
|
|
1259
|
-
import { ComposerPrimitive as ComposerPrimitive2, useAui as useAui3, useAuiState as useAuiState9 } from "@assistant-ui/react";
|
|
1260
|
-
import { useTrueFoundryAgentSpec, useTrueFoundryCancel } from "@truefoundry/assistant-ui-runtime";
|
|
1261
|
-
import { useRef as useRef6 } from "react";
|
|
1262
|
-
import { Fragment, jsx as jsx14, jsxs } from "react/jsx-runtime";
|
|
1263
|
-
function ComposerBody({ placeholder }) {
|
|
1264
|
-
const ComposerShell = useSlot("ComposerShell");
|
|
1265
|
-
const aui = useAui3();
|
|
1266
|
-
const shell = useOptionalShellMode();
|
|
1267
|
-
const hasText = useAuiState9((s) => s.composer.text.trim().length > 0);
|
|
1268
|
-
const { agentSpec } = useTrueFoundryAgentSpec();
|
|
1269
|
-
const requiresModel = shell == null || shell.mode.status === "active" && shell.mode.isMutable;
|
|
1270
|
-
const hasModel = Boolean(agentSpec?.model?.name?.trim());
|
|
1271
|
-
const { isBusy, send, resetBusy } = useComposerBusyState();
|
|
1272
|
-
const cancel = useTrueFoundryCancel();
|
|
1273
|
-
const fileInputRef = useRef6(null);
|
|
1274
|
-
const canSubmit = !isBusy && hasText && (!requiresModel || hasModel);
|
|
1275
|
-
const submit = () => {
|
|
1276
|
-
if (!canSubmit) return;
|
|
1277
|
-
send(() => aui.composer().send());
|
|
1278
|
-
};
|
|
1279
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1280
|
-
/* @__PURE__ */ jsx14(
|
|
1281
|
-
"input",
|
|
1282
|
-
{
|
|
1283
|
-
ref: fileInputRef,
|
|
1284
|
-
type: "file",
|
|
1285
|
-
multiple: true,
|
|
1286
|
-
hidden: true,
|
|
1287
|
-
onChange: (event) => {
|
|
1288
|
-
const files = event.target.files;
|
|
1289
|
-
if (files) {
|
|
1290
|
-
for (const file of files) {
|
|
1291
|
-
void aui.composer().addAttachment(file);
|
|
1292
|
-
}
|
|
1293
|
-
}
|
|
1294
|
-
event.target.value = "";
|
|
1295
|
-
}
|
|
1296
|
-
}
|
|
1297
|
-
),
|
|
1298
|
-
/* @__PURE__ */ jsx14(
|
|
1299
|
-
ComposerPrimitive2.AttachmentDropzone,
|
|
1300
|
-
{
|
|
1301
|
-
disabled: isBusy,
|
|
1302
|
-
"data-slot": "aui_composer-attachment-dropzone",
|
|
1303
|
-
className: "w-full rounded-[var(--composer-radius,1.5rem)] transition-[box-shadow] data-[dragging=true]:ring-focus-ring/20 data-[dragging=true]:ring-3",
|
|
1304
|
-
children: /* @__PURE__ */ jsx14(
|
|
1305
|
-
ComposerPrimitive2.Root,
|
|
1306
|
-
{
|
|
1307
|
-
"data-slot": "aui_composer-root",
|
|
1308
|
-
className: "w-full",
|
|
1309
|
-
onSubmit: (event) => {
|
|
1310
|
-
event.preventDefault();
|
|
1311
|
-
submit();
|
|
1312
|
-
},
|
|
1313
|
-
children: /* @__PURE__ */ jsx14(
|
|
1314
|
-
ComposerShell,
|
|
1315
|
-
{
|
|
1316
|
-
attachments: /* @__PURE__ */ jsx14(ComposerAttachmentsContainer, {}),
|
|
1317
|
-
input: /* @__PURE__ */ jsx14(
|
|
1318
|
-
ComposerPrimitive2.Input,
|
|
1319
|
-
{
|
|
1320
|
-
"data-slot": "aui_composer-input",
|
|
1321
|
-
placeholder,
|
|
1322
|
-
disabled: isBusy,
|
|
1323
|
-
submitMode: "enter",
|
|
1324
|
-
"aria-label": "Message input",
|
|
1325
|
-
className: "text-text-primary placeholder:text-text-secondary/80 max-h-[10lh] min-h-10 w-full resize-none overflow-y-auto rounded-lg border-none bg-transparent px-1 py-1 text-base leading-normal shadow-none outline-none disabled:cursor-not-allowed"
|
|
1326
|
-
}
|
|
1327
|
-
),
|
|
1328
|
-
disabled: isBusy,
|
|
1329
|
-
canSubmit,
|
|
1330
|
-
isRunning: isBusy,
|
|
1331
|
-
onSubmit: submit,
|
|
1332
|
-
onCancel: () => {
|
|
1333
|
-
resetBusy();
|
|
1334
|
-
void cancel();
|
|
1335
|
-
},
|
|
1336
|
-
onAttach: () => fileInputRef.current?.click()
|
|
1337
|
-
}
|
|
1338
|
-
)
|
|
1339
|
-
}
|
|
1340
|
-
)
|
|
1341
|
-
}
|
|
1342
|
-
)
|
|
1343
|
-
] });
|
|
1344
|
-
}
|
|
1345
|
-
function ComposerContainer({
|
|
1346
|
-
placeholder = "Ask anything... (Shift+Enter for new line)"
|
|
1347
|
-
}) {
|
|
1348
|
-
const pauseView = useComposerPauseView();
|
|
1349
|
-
const shell = useOptionalShellMode();
|
|
1350
|
-
const parentLeftSection = useSlot("ComposerLeftSection");
|
|
1351
|
-
const parentRightSection = useSlot("ComposerRightSection");
|
|
1352
|
-
const usesDefaultLeftSection = useSlotIsDefault("ComposerLeftSection");
|
|
1353
|
-
const usesDefaultRightSection = useSlotIsDefault("ComposerRightSection");
|
|
1354
|
-
const DraftComposerLeftSection = useSlot("DraftComposerLeftSection");
|
|
1355
|
-
const DraftComposerRightSection = useSlot("DraftComposerRightSection");
|
|
1356
|
-
const canMutateSpec = shell?.mode.status === "active" && shell.mode.isMutable;
|
|
1357
|
-
if (pauseView.kind === "mcp") {
|
|
1358
|
-
return /* @__PURE__ */ jsx14(McpAuthContainer, {});
|
|
1359
|
-
}
|
|
1360
|
-
if (pauseView.kind === "custom") {
|
|
1361
|
-
return /* @__PURE__ */ jsx14(CustomActionContainer, {});
|
|
1362
|
-
}
|
|
1363
|
-
if (pauseView.kind === "ask-user") {
|
|
1364
|
-
return /* @__PURE__ */ jsx14(AskUserContainer, {});
|
|
1365
|
-
}
|
|
1366
|
-
if (canMutateSpec) {
|
|
1367
|
-
return /* @__PURE__ */ jsx14(DraftCatalogProvider, { children: /* @__PURE__ */ jsx14(
|
|
1368
|
-
SlotsProvider,
|
|
1369
|
-
{
|
|
1370
|
-
overrides: {
|
|
1371
|
-
ComposerLeftSection: usesDefaultLeftSection ? DraftComposerLeftSection : parentLeftSection,
|
|
1372
|
-
ComposerRightSection: usesDefaultRightSection ? DraftComposerRightSection : parentRightSection
|
|
1373
|
-
},
|
|
1374
|
-
children: /* @__PURE__ */ jsx14(ComposerBody, { placeholder })
|
|
1375
|
-
}
|
|
1376
|
-
) });
|
|
1377
|
-
}
|
|
1378
|
-
return /* @__PURE__ */ jsx14(ComposerBody, { placeholder });
|
|
1379
|
-
}
|
|
1380
|
-
|
|
1381
|
-
// src/containers/HistoryLoaderContainer.tsx
|
|
1382
|
-
import { useTrueFoundryHistoryPagination } from "@truefoundry/assistant-ui-runtime";
|
|
1383
|
-
import { useCallback as useCallback7, useEffect as useEffect6, useRef as useRef7, useState as useState10 } from "react";
|
|
1384
|
-
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
1385
|
-
var TOP_THRESHOLD_PX = 200;
|
|
1386
|
-
var VIEWPORT_SELECTOR = '[data-slot="aui_thread-viewport"]';
|
|
1387
|
-
function HistoryLoaderContainer() {
|
|
1388
|
-
const HistoryLoader = useSlot("HistoryLoader");
|
|
1389
|
-
const { hasOlderHistory, isLoadingOlderHistory, loadOlderHistory } = useTrueFoundryHistoryPagination();
|
|
1390
|
-
const [sentinel, setSentinel] = useState10(null);
|
|
1391
|
-
const inflightRef = useRef7(false);
|
|
1392
|
-
const maybeLoadOlder = useCallback7(async () => {
|
|
1393
|
-
if (inflightRef.current) return;
|
|
1394
|
-
inflightRef.current = true;
|
|
1395
|
-
const viewport = sentinel?.closest(VIEWPORT_SELECTOR) ?? null;
|
|
1396
|
-
const prevScrollHeight = viewport?.scrollHeight ?? 0;
|
|
1397
|
-
const prevScrollTop = viewport?.scrollTop ?? 0;
|
|
1398
|
-
try {
|
|
1399
|
-
await loadOlderHistory();
|
|
1400
|
-
requestAnimationFrame(() => {
|
|
1401
|
-
if (viewport == null) return;
|
|
1402
|
-
const delta = viewport.scrollHeight - prevScrollHeight;
|
|
1403
|
-
if (delta > 0) {
|
|
1404
|
-
viewport.scrollTo({ top: prevScrollTop + delta, behavior: "instant" });
|
|
1405
|
-
}
|
|
1406
|
-
});
|
|
1407
|
-
} catch {
|
|
1408
|
-
} finally {
|
|
1409
|
-
inflightRef.current = false;
|
|
1410
|
-
}
|
|
1411
|
-
}, [sentinel, loadOlderHistory]);
|
|
1412
|
-
useEffect6(() => {
|
|
1413
|
-
if (sentinel == null || !hasOlderHistory) return;
|
|
1414
|
-
const viewport = sentinel.closest(VIEWPORT_SELECTOR);
|
|
1415
|
-
const observer = new IntersectionObserver(
|
|
1416
|
-
(entries) => {
|
|
1417
|
-
if (entries.some((entry) => entry.isIntersecting)) {
|
|
1418
|
-
void maybeLoadOlder();
|
|
1419
|
-
}
|
|
1420
|
-
},
|
|
1421
|
-
{ root: viewport, rootMargin: `${TOP_THRESHOLD_PX}px 0px 0px 0px` }
|
|
1422
|
-
);
|
|
1423
|
-
observer.observe(sentinel);
|
|
1424
|
-
return () => observer.disconnect();
|
|
1425
|
-
}, [sentinel, hasOlderHistory, maybeLoadOlder]);
|
|
1426
|
-
if (!hasOlderHistory) return null;
|
|
1427
|
-
return /* @__PURE__ */ jsx15(HistoryLoader, { ref: setSentinel, isLoading: isLoadingOlderHistory });
|
|
1428
|
-
}
|
|
1429
|
-
|
|
1430
|
-
// src/containers/ResumeUnavailableContainer.tsx
|
|
1431
|
-
import { useTrueFoundryResumeUnavailable as useTrueFoundryResumeUnavailable2 } from "@truefoundry/assistant-ui-runtime";
|
|
1432
|
-
import { jsx as jsx16 } from "react/jsx-runtime";
|
|
1433
|
-
function ResumeUnavailableContainer() {
|
|
1434
|
-
const ResumeUnavailable = useSlot("ResumeUnavailable");
|
|
1435
|
-
const resumeUnavailable = useTrueFoundryResumeUnavailable2();
|
|
1436
|
-
if (!resumeUnavailable) return null;
|
|
1437
|
-
return /* @__PURE__ */ jsx16(ResumeUnavailable, {});
|
|
1438
|
-
}
|
|
1439
|
-
|
|
1440
|
-
// src/containers/UserEditComposerContainer.tsx
|
|
1441
|
-
import { useComposerCancel, useComposerSend, useThreadIsRunning as useThreadIsRunning5 } from "@assistant-ui/core/react";
|
|
1442
|
-
import { ComposerPrimitive as ComposerPrimitive3, MessagePrimitive as MessagePrimitive4, useAuiState as useAuiState10 } from "@assistant-ui/react";
|
|
1443
|
-
import { jsx as jsx17, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1444
|
-
function ReadOnlyMessageAttachments() {
|
|
1445
|
-
const hasAttachments = useAuiState10((s) => (s.message.attachments?.length ?? 0) > 0);
|
|
1446
|
-
if (!hasAttachments) {
|
|
1447
|
-
return null;
|
|
1448
|
-
}
|
|
1449
|
-
return /* @__PURE__ */ jsx17("div", { className: "pointer-events-none mb-2 opacity-90", children: /* @__PURE__ */ jsx17(MessageAttachmentsContainer, {}) });
|
|
1450
|
-
}
|
|
1451
|
-
function UserEditComposerContainer() {
|
|
1452
|
-
const UserMessageEdit = useSlot("UserMessageEdit");
|
|
1453
|
-
const MessageTimestamp = useSlot("MessageTimestamp");
|
|
1454
|
-
const isRunning = useThreadIsRunning5();
|
|
1455
|
-
const createdAt = useAuiState10((s) => s.message.createdAt);
|
|
1456
|
-
const { cancel, disabled: cancelDisabled } = useComposerCancel();
|
|
1457
|
-
const { disabled: sendDisabled } = useComposerSend();
|
|
1458
|
-
return /* @__PURE__ */ jsx17(MessagePrimitive4.Root, { "data-role": "user", children: /* @__PURE__ */ jsx17(
|
|
1459
|
-
ComposerPrimitive3.Root,
|
|
1460
|
-
{
|
|
1461
|
-
"data-slot": "aui_user-edit-composer-root",
|
|
1462
|
-
className: "fade-in slide-in-from-bottom-1 animate-in flex w-full justify-end px-2 duration-150",
|
|
1463
|
-
children: /* @__PURE__ */ jsx17(
|
|
1464
|
-
UserMessageEdit,
|
|
1465
|
-
{
|
|
1466
|
-
timestamp: /* @__PURE__ */ jsx17(MessageTimestamp, { createdAt }),
|
|
1467
|
-
attachments: /* @__PURE__ */ jsx17(ReadOnlyMessageAttachments, {}),
|
|
1468
|
-
input: /* @__PURE__ */ jsx17("div", { className: "mt-1 rounded border border-border bg-secondary-bg p-2 text-text-primary", children: /* @__PURE__ */ jsx17(
|
|
1469
|
-
ComposerPrimitive3.Input,
|
|
1470
|
-
{
|
|
1471
|
-
"data-slot": "aui_user-edit-input",
|
|
1472
|
-
disabled: isRunning,
|
|
1473
|
-
submitMode: "enter",
|
|
1474
|
-
"aria-label": "Edit message",
|
|
1475
|
-
className: "max-h-32 min-h-10 w-full resize-none border-none bg-transparent p-0 text-base leading-[1.34] outline-none focus:shadow-none"
|
|
1476
|
-
}
|
|
1477
|
-
) }),
|
|
1478
|
-
footer: /* @__PURE__ */ jsxs2("div", { className: "flex items-center justify-end gap-2", children: [
|
|
1479
|
-
/* @__PURE__ */ jsx17(Button, { variant: "secondary", type: "button", disabled: cancelDisabled, onClick: cancel, children: "Cancel" }),
|
|
1480
|
-
/* @__PURE__ */ jsx17(ComposerPrimitive3.Send, { asChild: true, children: /* @__PURE__ */ jsx17(Button, { type: "submit", disabled: sendDisabled || isRunning, children: "Save & Rerun" }) })
|
|
1481
|
-
] })
|
|
1482
|
-
}
|
|
1483
|
-
)
|
|
1484
|
-
}
|
|
1485
|
-
) });
|
|
1486
|
-
}
|
|
1487
|
-
|
|
1488
|
-
// src/containers/UserMessageContainer.tsx
|
|
1489
|
-
import { useActionBarCopy as useActionBarCopy2, useActionBarEdit, useThreadIsRunning as useThreadIsRunning6 } from "@assistant-ui/core/react";
|
|
1490
|
-
import { MessagePrimitive as MessagePrimitive5, useAui as useAui4, useAuiState as useAuiState11 } from "@assistant-ui/react";
|
|
1491
|
-
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
1492
|
-
function UserMessageContainer() {
|
|
1493
|
-
const UserMessageBubble = useSlot("UserMessageBubble");
|
|
1494
|
-
const UserMessageActionBar = useSlot("UserMessageActionBar");
|
|
1495
|
-
const isRunning = useThreadIsRunning6();
|
|
1496
|
-
const aui = useAui4();
|
|
1497
|
-
const createdAt = useAuiState11((s) => s.message.createdAt);
|
|
1498
|
-
const text = useAuiState11(
|
|
1499
|
-
(s) => s.message.content.filter((part) => part.type === "text").map((part) => part.text).join("\n")
|
|
1500
|
-
);
|
|
1501
|
-
const { edit, disabled: editDisabled } = useActionBarEdit();
|
|
1502
|
-
const { copy, isCopied } = useActionBarCopy2({
|
|
1503
|
-
copyToClipboard: (value) => navigator.clipboard.writeText(value)
|
|
1504
|
-
});
|
|
1505
|
-
return /* @__PURE__ */ jsx18(MessagePrimitive5.Root, { "data-role": "user", children: /* @__PURE__ */ jsx18(
|
|
1506
|
-
UserMessageBubble,
|
|
1507
|
-
{
|
|
1508
|
-
text,
|
|
1509
|
-
attachments: /* @__PURE__ */ jsx18(MessageAttachmentsContainer, {}),
|
|
1510
|
-
editAction: !isRunning ? /* @__PURE__ */ jsx18(
|
|
1511
|
-
UserMessageActionBar,
|
|
1512
|
-
{
|
|
1513
|
-
isCopied,
|
|
1514
|
-
editDisabled,
|
|
1515
|
-
createdAt,
|
|
1516
|
-
onCopy: copy,
|
|
1517
|
-
onEdit: edit,
|
|
1518
|
-
onRetry: () => {
|
|
1519
|
-
aui.message().composer().beginEdit();
|
|
1520
|
-
aui.message().composer().send({ startRun: true });
|
|
1521
|
-
}
|
|
1522
|
-
}
|
|
1523
|
-
) : void 0
|
|
1524
|
-
}
|
|
1525
|
-
) });
|
|
1526
|
-
}
|
|
1527
|
-
|
|
1528
|
-
// src/containers/ThreadContainer.tsx
|
|
1529
|
-
import { ThreadPrimitive, useAuiState as useAuiState12 } from "@assistant-ui/react";
|
|
1530
|
-
import { useEffect as useEffect8 } from "react";
|
|
1531
|
-
|
|
1532
|
-
// src/hooks/useSyncSessionTitle.ts
|
|
1533
|
-
import { useThreadIsRunning as useThreadIsRunning7 } from "@assistant-ui/core/react";
|
|
1534
|
-
import { useEffect as useEffect7, useRef as useRef8 } from "react";
|
|
1535
|
-
function useSyncSessionTitle() {
|
|
1536
|
-
const server = useOptionalServer();
|
|
1537
|
-
const aui = useAui();
|
|
1538
|
-
const remoteId = useAuiState((s) => s.threadListItem.remoteId);
|
|
1539
|
-
const title = useAuiState((s) => s.threadListItem.title);
|
|
1540
|
-
const isRunning = useThreadIsRunning7();
|
|
1541
|
-
const wasRunningRef = useRef8(false);
|
|
1542
|
-
const syncedRemoteIdRef = useRef8(void 0);
|
|
1543
|
-
useEffect7(() => {
|
|
1544
|
-
syncedRemoteIdRef.current = void 0;
|
|
1545
|
-
}, [remoteId]);
|
|
1546
|
-
useEffect7(() => {
|
|
1547
|
-
const finishedTurn = wasRunningRef.current && !isRunning;
|
|
1548
|
-
wasRunningRef.current = isRunning;
|
|
1549
|
-
if (!finishedTurn || server == null || remoteId == null) {
|
|
1550
|
-
return;
|
|
1551
|
-
}
|
|
1552
|
-
if (syncedRemoteIdRef.current === remoteId) {
|
|
1553
|
-
return;
|
|
1554
|
-
}
|
|
1555
|
-
if (title != null && title.trim() !== "") {
|
|
1556
|
-
syncedRemoteIdRef.current = remoteId;
|
|
1557
|
-
return;
|
|
1558
|
-
}
|
|
1559
|
-
let cancelled = false;
|
|
1560
|
-
void server.getSession({ sessionId: remoteId }).then((session) => {
|
|
1561
|
-
if (cancelled) return;
|
|
1562
|
-
const nextTitle = typeof session.title === "string" ? session.title.trim() : "";
|
|
1563
|
-
if (nextTitle.length === 0) return;
|
|
1564
|
-
syncedRemoteIdRef.current = remoteId;
|
|
1565
|
-
return aui.threadListItem().rename(nextTitle);
|
|
1566
|
-
}).catch(() => void 0);
|
|
1567
|
-
return () => {
|
|
1568
|
-
cancelled = true;
|
|
1569
|
-
};
|
|
1570
|
-
}, [aui, isRunning, remoteId, server, title]);
|
|
1571
|
-
}
|
|
1572
|
-
|
|
1573
|
-
// src/utils/isNewChatView.ts
|
|
1574
|
-
var isNewChatView = (s) => s.thread.messages.length === 0 && (!s.thread.isLoading || s.threads.isLoading) && s.threadListItem.remoteId == null;
|
|
1575
|
-
|
|
1576
|
-
// src/containers/ThreadContainer.tsx
|
|
1577
|
-
import { Fragment as Fragment2, jsx as jsx19, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1578
|
-
function AnimatedMessageShell({ children }) {
|
|
1579
|
-
return /* @__PURE__ */ jsx19("div", { className: "animate-in fade-in slide-in-from-bottom-1 fill-mode-both duration-200", children });
|
|
1580
|
-
}
|
|
1581
|
-
function ThreadMessage({ isEditing }) {
|
|
1582
|
-
const role = useAuiState12((s) => s.message.role);
|
|
1583
|
-
if (role === "user") {
|
|
1584
|
-
if (isEditing) {
|
|
1585
|
-
return /* @__PURE__ */ jsx19(UserEditComposerContainer, {});
|
|
1586
|
-
}
|
|
1587
|
-
return /* @__PURE__ */ jsx19(UserMessageContainer, {});
|
|
1588
|
-
}
|
|
1589
|
-
return /* @__PURE__ */ jsx19(AssistantMessageContainer, {});
|
|
1590
|
-
}
|
|
1591
|
-
function ThreadContainer({ composer }) {
|
|
1592
|
-
useEffect8(() => {
|
|
1593
|
-
void preloadMarkdownOpenUI();
|
|
1594
|
-
}, []);
|
|
1595
|
-
useSyncSessionTitle();
|
|
1596
|
-
const shell = useOptionalShellMode();
|
|
1597
|
-
const WelcomeScreen = useSlot("WelcomeScreen");
|
|
1598
|
-
const MessageListSkeleton = useSlot("MessageListSkeleton");
|
|
1599
|
-
const ScrollToBottomButton = useSlot("ScrollToBottomButton");
|
|
1600
|
-
const MessageGroup = useSlot("MessageGroup");
|
|
1601
|
-
const ThreadComposerAreaShell = useSlot("ThreadComposerAreaShell");
|
|
1602
|
-
const ThreadRootShell = useSlot("ThreadRootShell");
|
|
1603
|
-
const ThreadViewportShell = useSlot("ThreadViewportShell");
|
|
1604
|
-
const isEmpty = useAuiState12(isNewChatView);
|
|
1605
|
-
const isLoading = useAuiState12((s) => s.thread.isLoading);
|
|
1606
|
-
const welcomeHeading = shell?.mode.status === "active" ? shell.mode.agentName : void 0;
|
|
1607
|
-
return /* @__PURE__ */ jsx19(ComposerBusyProvider, { children: /* @__PURE__ */ jsx19(ThreadPrimitive.Root, { asChild: true, children: /* @__PURE__ */ jsxs3(ThreadRootShell, { children: [
|
|
1608
|
-
/* @__PURE__ */ jsx19(ThreadPrimitive.Viewport, { asChild: true, autoScroll: true, children: /* @__PURE__ */ jsxs3(ThreadViewportShell, { isEmpty, children: [
|
|
1609
|
-
isEmpty && /* @__PURE__ */ jsx19(WelcomeScreen, { heading: welcomeHeading }),
|
|
1610
|
-
isEmpty && !isLoading && composer,
|
|
1611
|
-
isLoading ? /* @__PURE__ */ jsx19(MessageListSkeleton, {}) : !isEmpty && /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
1612
|
-
/* @__PURE__ */ jsx19(HistoryLoaderContainer, {}),
|
|
1613
|
-
/* @__PURE__ */ jsxs3(MessageGroup, { children: [
|
|
1614
|
-
/* @__PURE__ */ jsx19(ThreadPrimitive.Messages, { children: ({ message }) => /* @__PURE__ */ jsx19(AnimatedMessageShell, { children: /* @__PURE__ */ jsx19(ThreadMessage, { isEditing: message.role === "user" && message.composer.isEditing }) }) }),
|
|
1615
|
-
/* @__PURE__ */ jsx19(ResumeUnavailableContainer, {})
|
|
1616
|
-
] })
|
|
1617
|
-
] })
|
|
1618
|
-
] }) }),
|
|
1619
|
-
!isLoading && !isEmpty && /* @__PURE__ */ jsxs3(ThreadComposerAreaShell, { isEmpty, children: [
|
|
1620
|
-
/* @__PURE__ */ jsx19(ThreadPrimitive.ScrollToBottom, { asChild: true, children: /* @__PURE__ */ jsx19(ScrollToBottomButton, {}) }),
|
|
1621
|
-
composer
|
|
1622
|
-
] })
|
|
1623
|
-
] }) }) });
|
|
1624
|
-
}
|
|
1625
|
-
|
|
1626
|
-
// src/containers/Thread.tsx
|
|
1627
|
-
import { jsx as jsx20 } from "react/jsx-runtime";
|
|
1628
|
-
function Thread() {
|
|
1629
|
-
return /* @__PURE__ */ jsx20(ThreadContainer, { composer: /* @__PURE__ */ jsx20(ComposerContainer, {}) });
|
|
1630
|
-
}
|
|
1631
|
-
|
|
1632
|
-
// src/containers/ThreadListContainer.tsx
|
|
1633
|
-
import {
|
|
1634
|
-
ThreadListItemByIndexProvider,
|
|
1635
|
-
ThreadListItemMorePrimitive,
|
|
1636
|
-
ThreadListItemPrimitive,
|
|
1637
|
-
ThreadListPrimitive,
|
|
1638
|
-
useAui as useAui5,
|
|
1639
|
-
useAuiState as useAuiState13
|
|
1640
|
-
} from "@assistant-ui/react";
|
|
1641
|
-
import { useCallback as useCallback8, useEffect as useEffect11, useMemo as useMemo5, useRef as useRef11, useState as useState13 } from "react";
|
|
1642
|
-
|
|
1643
|
-
// src/atoms/AgentHistoryFilterButton.tsx
|
|
1644
|
-
import { useEffect as useEffect10, useId as useId2, useLayoutEffect, useRef as useRef10, useState as useState12 } from "react";
|
|
1645
|
-
import { createPortal } from "react-dom";
|
|
1646
|
-
|
|
1647
|
-
// src/atoms/primitives/DropdownMenu.tsx
|
|
1648
|
-
import React, { useEffect as useEffect9, useId, useRef as useRef9, useState as useState11 } from "react";
|
|
1649
|
-
import { jsx as jsx21, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1650
|
-
function DropdownMenuItem({ className, ...props }) {
|
|
1651
|
-
return /* @__PURE__ */ jsx21(
|
|
1652
|
-
"button",
|
|
1653
|
-
{
|
|
1654
|
-
role: "menuitem",
|
|
1655
|
-
type: "button",
|
|
1656
|
-
className: cn(
|
|
1657
|
-
"flex w-full cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none",
|
|
1658
|
-
"transition-colors hover:bg-ghost-button-hover",
|
|
1659
|
-
"focus:bg-dropdown-selected-item-bg focus:text-dropdown-selected-item-text",
|
|
1660
|
-
"aria-selected:bg-dropdown-selected-item-bg aria-selected:text-dropdown-selected-item-text",
|
|
1661
|
-
"disabled:pointer-events-none disabled:opacity-50",
|
|
1662
|
-
className
|
|
1663
|
-
),
|
|
1664
|
-
...props
|
|
1665
|
-
}
|
|
1666
|
-
);
|
|
1667
|
-
}
|
|
1668
|
-
|
|
1669
|
-
// src/atoms/AgentHistoryFilterButton.tsx
|
|
1670
|
-
import { Fragment as Fragment3, jsx as jsx22, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1671
|
-
function themePortalRoot(from) {
|
|
1672
|
-
return from?.closest(".aui-theme-root") ?? document.body;
|
|
1673
|
-
}
|
|
1674
|
-
function AgentHistoryFilterButton() {
|
|
1675
|
-
const shell = useOptionalShellMode();
|
|
1676
|
-
const server = useOptionalServer();
|
|
1677
|
-
const isMobile = useIsMobile();
|
|
1678
|
-
const compact = useCompactLayout();
|
|
1679
|
-
const useSheet = isMobile || compact;
|
|
1680
|
-
const [open, setOpen] = useState12(false);
|
|
1681
|
-
const [query, setQuery] = useState12("");
|
|
1682
|
-
const [menuPos, setMenuPos] = useState12(null);
|
|
1683
|
-
const buttonRef = useRef10(null);
|
|
1684
|
-
const menuRef = useRef10(null);
|
|
1685
|
-
const menuId = useId2();
|
|
1686
|
-
const enabled = shell?.isLibraryEnabled === true && server != null;
|
|
1687
|
-
const selected = shell?.historyAgentFilter ?? null;
|
|
1688
|
-
useEffect10(() => {
|
|
1689
|
-
if (!open) setQuery("");
|
|
1690
|
-
}, [open]);
|
|
1691
|
-
const { agents, isInitialLoading, isSearching, loadingMore, hasMore, listRef, sentinelRef } = useSearchAgentsList({
|
|
1692
|
-
enabled: open && enabled,
|
|
1693
|
-
query
|
|
1694
|
-
});
|
|
1695
|
-
useLayoutEffect(() => {
|
|
1696
|
-
if (!open || useSheet) {
|
|
1697
|
-
setMenuPos(null);
|
|
1698
|
-
return;
|
|
1699
|
-
}
|
|
1700
|
-
const update = () => {
|
|
1701
|
-
const rect = buttonRef.current?.getBoundingClientRect();
|
|
1702
|
-
if (!rect) return;
|
|
1703
|
-
setMenuPos({ top: rect.top, left: rect.right + 4 });
|
|
1704
|
-
};
|
|
1705
|
-
update();
|
|
1706
|
-
window.addEventListener("resize", update);
|
|
1707
|
-
window.addEventListener("scroll", update, true);
|
|
1708
|
-
return () => {
|
|
1709
|
-
window.removeEventListener("resize", update);
|
|
1710
|
-
window.removeEventListener("scroll", update, true);
|
|
1711
|
-
};
|
|
1712
|
-
}, [open, useSheet]);
|
|
1713
|
-
useEffect10(() => {
|
|
1714
|
-
if (!open || useSheet) return;
|
|
1715
|
-
const handler = (e) => {
|
|
1716
|
-
const target = e.target;
|
|
1717
|
-
if (buttonRef.current?.contains(target) || menuRef.current?.contains(target)) return;
|
|
1718
|
-
setOpen(false);
|
|
1719
|
-
};
|
|
1720
|
-
document.addEventListener("mousedown", handler);
|
|
1721
|
-
return () => document.removeEventListener("mousedown", handler);
|
|
1722
|
-
}, [open, useSheet]);
|
|
1723
|
-
if (!enabled) return null;
|
|
1724
|
-
const pick = (agentId) => {
|
|
1725
|
-
shell?.setHistoryAgentFilter(agentId);
|
|
1726
|
-
setOpen(false);
|
|
1727
|
-
};
|
|
1728
|
-
const filterBody = /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
1729
|
-
/* @__PURE__ */ jsxs5("div", { className: "p-1", onMouseDown: (e) => e.stopPropagation(), children: [
|
|
1730
|
-
/* @__PURE__ */ jsx22(SearchInput_default, { query, setQuery, placeholder: "Search agents" }),
|
|
1731
|
-
isSearching ? /* @__PURE__ */ jsx22("p", { className: "text-text-secondary px-1 pt-1 text-[11px]", role: "status", children: "Searching\u2026" }) : null
|
|
1732
|
-
] }),
|
|
1733
|
-
/* @__PURE__ */ jsxs5(
|
|
1734
|
-
"div",
|
|
1735
|
-
{
|
|
1736
|
-
ref: listRef,
|
|
1737
|
-
className: cn("mt-1 overflow-y-auto", useSheet ? "min-h-0 flex-1 px-1 pb-2" : "min-h-48 max-h-64"),
|
|
1738
|
-
children: [
|
|
1739
|
-
query.trim() === "" ? /* @__PURE__ */ jsxs5(
|
|
1740
|
-
DropdownMenuItem,
|
|
1741
|
-
{
|
|
1742
|
-
className: cn(
|
|
1743
|
-
"justify-between",
|
|
1744
|
-
selected == null && "bg-dropdown-selected-item-bg text-dropdown-selected-item-text"
|
|
1745
|
-
),
|
|
1746
|
-
onClick: () => pick(null),
|
|
1747
|
-
children: [
|
|
1748
|
-
"All chats",
|
|
1749
|
-
selected == null ? /* @__PURE__ */ jsx22(Icon, { name: "check", className: "size-3.5 shrink-0" }) : null
|
|
1750
|
-
]
|
|
1751
|
-
}
|
|
1752
|
-
) : null,
|
|
1753
|
-
isInitialLoading ? /* @__PURE__ */ jsx22("p", { className: "px-2 py-3 text-center text-xs text-text-secondary", children: "Loading\u2026" }) : agents.length === 0 ? /* @__PURE__ */ jsx22("p", { className: "text-text-secondary px-2 py-6 text-center text-xs", role: "status", children: query.trim() ? `No agents match "${query.trim()}".` : "No agents yet." }) : /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
1754
|
-
agents.map((agent) => {
|
|
1755
|
-
const id = libraryAgentId(agent);
|
|
1756
|
-
const active = selected === id;
|
|
1757
|
-
return /* @__PURE__ */ jsxs5(
|
|
1758
|
-
DropdownMenuItem,
|
|
1759
|
-
{
|
|
1760
|
-
className: cn(
|
|
1761
|
-
"justify-between gap-2 text-left",
|
|
1762
|
-
active && "bg-dropdown-selected-item-bg text-dropdown-selected-item-text"
|
|
1763
|
-
),
|
|
1764
|
-
onClick: () => pick(id),
|
|
1765
|
-
children: [
|
|
1766
|
-
/* @__PURE__ */ jsx22("span", { className: "min-w-0 truncate", children: agent.name }),
|
|
1767
|
-
active ? /* @__PURE__ */ jsx22(Icon, { name: "check", className: "size-3.5 shrink-0" }) : null
|
|
1768
|
-
]
|
|
1769
|
-
},
|
|
1770
|
-
id
|
|
1771
|
-
);
|
|
1772
|
-
}),
|
|
1773
|
-
hasMore ? /* @__PURE__ */ jsx22("div", { ref: sentinelRef, className: "flex h-6 shrink-0 items-center justify-center", "aria-hidden": true, children: loadingMore ? /* @__PURE__ */ jsx22("span", { className: "text-text-secondary text-[11px]", role: "status", children: "Loading more\u2026" }) : null }) : null
|
|
1774
|
-
] })
|
|
1775
|
-
]
|
|
1776
|
-
}
|
|
1777
|
-
)
|
|
1778
|
-
] });
|
|
1779
|
-
return /* @__PURE__ */ jsxs5("div", { className: "relative shrink-0", children: [
|
|
1780
|
-
/* @__PURE__ */ jsxs5(
|
|
1781
|
-
"button",
|
|
1782
|
-
{
|
|
1783
|
-
ref: buttonRef,
|
|
1784
|
-
type: "button",
|
|
1785
|
-
"aria-label": selected != null ? `Filter chat history by agent (${selected})` : "Filter chat history by agent",
|
|
1786
|
-
"aria-haspopup": useSheet ? "dialog" : "menu",
|
|
1787
|
-
"aria-expanded": open,
|
|
1788
|
-
"aria-controls": open ? menuId : void 0,
|
|
1789
|
-
title: "Filter by agent",
|
|
1790
|
-
className: auiButtonClass({
|
|
1791
|
-
variant: "ghost",
|
|
1792
|
-
size: "icon",
|
|
1793
|
-
className: cn(
|
|
1794
|
-
"relative size-7 shrink-0 text-text-secondary hover:bg-ghost-button-hover hover:text-ghost-button-text",
|
|
1795
|
-
selected != null && "text-text-primary"
|
|
1796
|
-
)
|
|
1797
|
-
}),
|
|
1798
|
-
onClick: () => setOpen((v) => !v),
|
|
1799
|
-
children: [
|
|
1800
|
-
/* @__PURE__ */ jsx22(Icon, { name: "funnel", className: "size-3.5" }),
|
|
1801
|
-
selected != null ? /* @__PURE__ */ jsx22(
|
|
1802
|
-
"span",
|
|
1803
|
-
{
|
|
1804
|
-
className: "bg-primary-button-bg absolute top-1 right-1 size-1.5 rounded-full",
|
|
1805
|
-
"aria-hidden": true,
|
|
1806
|
-
"data-testid": "history-filter-active-dot"
|
|
1807
|
-
}
|
|
1808
|
-
) : null
|
|
1809
|
-
]
|
|
1810
|
-
}
|
|
1811
|
-
),
|
|
1812
|
-
useSheet && open ? /* @__PURE__ */ jsx22(BottomSheet, { open: true, onOpenChange: setOpen, id: menuId, "aria-label": "Filter agents", children: /* @__PURE__ */ jsx22("div", { className: "flex min-h-0 flex-1 flex-col p-2", role: "menu", children: filterBody }) }) : null,
|
|
1813
|
-
!useSheet && open && menuPos != null ? createPortal(
|
|
1814
|
-
/* @__PURE__ */ jsx22(
|
|
1815
|
-
"div",
|
|
1816
|
-
{
|
|
1817
|
-
ref: menuRef,
|
|
1818
|
-
id: menuId,
|
|
1819
|
-
role: "menu",
|
|
1820
|
-
"aria-label": "Filter agents",
|
|
1821
|
-
style: { top: menuPos.top, left: menuPos.left },
|
|
1822
|
-
className: "font-sans-flex fixed z-50 w-56 rounded-md border border-border bg-card-bg p-1 text-text-primary shadow-md",
|
|
1823
|
-
children: filterBody
|
|
1824
|
-
}
|
|
1825
|
-
),
|
|
1826
|
-
themePortalRoot(buttonRef.current)
|
|
1827
|
-
) : null
|
|
1828
|
-
] });
|
|
1829
|
-
}
|
|
1830
|
-
|
|
1831
|
-
// src/containers/ThreadListContainer.tsx
|
|
1832
|
-
import { Fragment as Fragment4, jsx as jsx23, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1833
|
-
var deleteItemClass = "flex w-full cursor-pointer select-none items-center gap-2 rounded-md px-2 py-1.5 text-sm font-medium text-failure-bg outline-none transition-colors hover:bg-failure-bg/12 hover:text-failure-bg focus:bg-failure-bg/12 focus:text-failure-bg data-[highlighted]:bg-failure-bg/12 data-[highlighted]:text-failure-bg";
|
|
1834
|
-
function ThreadListItemDeleteMenu() {
|
|
1835
|
-
const compact = useCompactLayout();
|
|
1836
|
-
const isMobile = useIsMobile();
|
|
1837
|
-
const [sheetOpen, setSheetOpen] = useState13(false);
|
|
1838
|
-
const [portalContainer, setPortalContainer] = useState13();
|
|
1839
|
-
const useSheet = isMobile || compact;
|
|
1840
|
-
const setTriggerElement = useCallback8((element) => {
|
|
1841
|
-
const themeRoot = element?.closest(".aui-theme-root");
|
|
1842
|
-
setPortalContainer(themeRoot instanceof HTMLElement ? themeRoot : void 0);
|
|
1843
|
-
}, []);
|
|
1844
|
-
const moreButtonClass = auiButtonClass({
|
|
1845
|
-
variant: "ghost",
|
|
1846
|
-
size: "icon",
|
|
1847
|
-
className: "size-7 shrink-0 text-text-secondary hover:bg-transparent hover:text-text-primary"
|
|
1848
|
-
});
|
|
1849
|
-
if (useSheet) {
|
|
1850
|
-
return /* @__PURE__ */ jsxs6(Fragment4, { children: [
|
|
1851
|
-
/* @__PURE__ */ jsx23(
|
|
1852
|
-
"button",
|
|
1853
|
-
{
|
|
1854
|
-
type: "button",
|
|
1855
|
-
"aria-label": "Session actions",
|
|
1856
|
-
title: "Session actions",
|
|
1857
|
-
"aria-haspopup": "dialog",
|
|
1858
|
-
"aria-expanded": sheetOpen,
|
|
1859
|
-
className: moreButtonClass,
|
|
1860
|
-
onClick: () => setSheetOpen(true),
|
|
1861
|
-
children: /* @__PURE__ */ jsx23(Icon, { name: "ellipsis", className: "size-3.5" })
|
|
1862
|
-
}
|
|
1863
|
-
),
|
|
1864
|
-
sheetOpen ? /* @__PURE__ */ jsx23(BottomSheet, { open: true, onOpenChange: setSheetOpen, "aria-label": "Session actions", children: /* @__PURE__ */ jsx23("div", { className: "flex flex-col gap-1 p-2", role: "menu", children: /* @__PURE__ */ jsxs6(ThreadListItemPrimitive.Delete, { className: deleteItemClass, onClick: () => setSheetOpen(false), children: [
|
|
1865
|
-
/* @__PURE__ */ jsx23(Icon, { name: "trash", className: "size-3.5" }),
|
|
1866
|
-
"Delete"
|
|
1867
|
-
] }) }) }) : null
|
|
1868
|
-
] });
|
|
1869
|
-
}
|
|
1870
|
-
return /* @__PURE__ */ jsxs6(ThreadListItemMorePrimitive.Root, { sharedFocusGroup: true, children: [
|
|
1871
|
-
/* @__PURE__ */ jsx23(
|
|
1872
|
-
ThreadListItemMorePrimitive.Trigger,
|
|
1873
|
-
{
|
|
1874
|
-
ref: setTriggerElement,
|
|
1875
|
-
"aria-label": "Session actions",
|
|
1876
|
-
title: "Session actions",
|
|
1877
|
-
className: moreButtonClass,
|
|
1878
|
-
children: /* @__PURE__ */ jsx23(Icon, { name: "ellipsis", className: "size-3.5" })
|
|
1879
|
-
}
|
|
1880
|
-
),
|
|
1881
|
-
/* @__PURE__ */ jsx23(
|
|
1882
|
-
ThreadListItemMorePrimitive.Content,
|
|
1883
|
-
{
|
|
1884
|
-
portalProps: { container: portalContainer },
|
|
1885
|
-
align: "end",
|
|
1886
|
-
sideOffset: 4,
|
|
1887
|
-
className: "font-sans-flex z-50 min-w-[8rem] rounded-md border border-border bg-card-bg p-1 text-text-primary shadow-md",
|
|
1888
|
-
children: /* @__PURE__ */ jsx23(ThreadListItemPrimitive.Delete, { asChild: true, children: /* @__PURE__ */ jsxs6(ThreadListItemMorePrimitive.Item, { className: deleteItemClass, children: [
|
|
1889
|
-
/* @__PURE__ */ jsx23(Icon, { name: "trash", className: "size-3.5" }),
|
|
1890
|
-
"Delete"
|
|
1891
|
-
] }) })
|
|
1892
|
-
}
|
|
1893
|
-
)
|
|
1894
|
-
] });
|
|
1895
|
-
}
|
|
1896
|
-
function ThreadListItemRow({
|
|
1897
|
-
onThreadOpen,
|
|
1898
|
-
canDeleteSession
|
|
1899
|
-
}) {
|
|
1900
|
-
const aui = useAui5();
|
|
1901
|
-
const shell = useOptionalShellMode();
|
|
1902
|
-
const ThreadListRow = useSlot("ThreadListRow");
|
|
1903
|
-
const id = useAuiState13((s) => s.threadListItem.id);
|
|
1904
|
-
const remoteId = useAuiState13((s) => s.threadListItem.remoteId);
|
|
1905
|
-
const title = useAuiState13((s) => s.threadListItem.title);
|
|
1906
|
-
const lastMessageAt = useAuiState13((s) => s.threadListItem.lastMessageAt);
|
|
1907
|
-
const custom = useAuiState13((s) => s.threadListItem.custom);
|
|
1908
|
-
const mainThreadId = useAuiState13((s) => s.threads.mainThreadId);
|
|
1909
|
-
const agentName = readThreadAgentName(custom);
|
|
1910
|
-
const showDelete = canDeleteSession && remoteId != null;
|
|
1911
|
-
return /* @__PURE__ */ jsx23(ThreadListItemPrimitive.Root, { className: "min-w-0", children: /* @__PURE__ */ jsx23(
|
|
1912
|
-
ThreadListRow,
|
|
1913
|
-
{
|
|
1914
|
-
title: title ?? "New Chat",
|
|
1915
|
-
active: id === mainThreadId,
|
|
1916
|
-
agentName,
|
|
1917
|
-
lastMessageAt,
|
|
1918
|
-
onSelect: () => {
|
|
1919
|
-
onThreadOpen?.();
|
|
1920
|
-
shell?.setSettingsOpen(false);
|
|
1921
|
-
const sessionMutable = threadListItemIsMutable(custom);
|
|
1922
|
-
const sameImmutable = !sessionMutable && shell?.mode.status === "active" && !shell.mode.isMutable && (agentName == null ? shell.mode.agentName == null && shell.mode.agentId == null : shell.mode.agentName === agentName || shell.mode.agentId === agentName);
|
|
1923
|
-
const sameMutable = canReuseMutableShell({
|
|
1924
|
-
sessionMutable,
|
|
1925
|
-
shellMutable: shell?.mode.status === "active" && shell.mode.isMutable,
|
|
1926
|
-
...shell?.mode.status === "active" && shell.mode.isMutable ? { shellAgentName: shell.mode.agentName, shellAgentId: shell.mode.agentId } : {},
|
|
1927
|
-
remoteId,
|
|
1928
|
-
pendingSessionId: shell?.pendingSessionId
|
|
1929
|
-
});
|
|
1930
|
-
if ((sameImmutable || sameMutable) && remoteId != null) {
|
|
1931
|
-
void Promise.resolve(aui.threads().switchToThread(id)).catch(() => void 0);
|
|
1932
|
-
return;
|
|
1933
|
-
}
|
|
1934
|
-
if (remoteId != null) {
|
|
1935
|
-
shell?.openHistorySession({
|
|
1936
|
-
sessionId: remoteId,
|
|
1937
|
-
isMutable: sessionMutable,
|
|
1938
|
-
...agentName != null ? { agentName } : {}
|
|
1939
|
-
});
|
|
1940
|
-
return;
|
|
1941
|
-
}
|
|
1942
|
-
void Promise.resolve(aui.threads().switchToThread(id)).catch(() => void 0);
|
|
1943
|
-
},
|
|
1944
|
-
actions: showDelete ? /* @__PURE__ */ jsx23(ThreadListItemDeleteMenu, {}) : void 0
|
|
1945
|
-
}
|
|
1946
|
-
) });
|
|
1947
|
-
}
|
|
1948
|
-
function useThreadListIndicesByRecency() {
|
|
1949
|
-
const threadIds = useAuiState13((s) => s.threads.threadIds);
|
|
1950
|
-
const threadItems = useAuiState13((s) => s.threads.threadItems);
|
|
1951
|
-
return useMemo5(() => threadListIndicesByRecency({ threadIds, threadItems }), [threadIds, threadItems]);
|
|
1952
|
-
}
|
|
1953
|
-
function ThreadListItemsByRecency({
|
|
1954
|
-
onThreadOpen,
|
|
1955
|
-
canDeleteSession
|
|
1956
|
-
}) {
|
|
1957
|
-
const indices = useThreadListIndicesByRecency();
|
|
1958
|
-
const threadIds = useAuiState13((s) => s.threads.threadIds);
|
|
1959
|
-
return /* @__PURE__ */ jsx23(Fragment4, { children: indices.map((index) => {
|
|
1960
|
-
const key = threadIds[index] ?? String(index);
|
|
1961
|
-
return /* @__PURE__ */ jsx23(ThreadListItemByIndexProvider, { index, archived: false, children: /* @__PURE__ */ jsx23(ThreadListItemRow, { onThreadOpen, canDeleteSession }) }, key);
|
|
1962
|
-
}) });
|
|
1963
|
-
}
|
|
1964
|
-
var THREAD_LIST_VIEWPORT_SLOT = "aui_thread-list-viewport";
|
|
1965
|
-
var LOAD_MORE_BOTTOM_PX = 80;
|
|
1966
|
-
function ChatHistorySection({ children, viewportRef }) {
|
|
1967
|
-
const [expanded, setExpanded] = useState13(true);
|
|
1968
|
-
const shell = useOptionalShellMode();
|
|
1969
|
-
const showFilter = shell?.isLibraryEnabled === true;
|
|
1970
|
-
return /* @__PURE__ */ jsxs6("div", { className: "flex min-h-0 flex-1 flex-col", children: [
|
|
1971
|
-
/* @__PURE__ */ jsxs6("div", { className: "flex shrink-0 items-center gap-1 px-1 py-1", children: [
|
|
1972
|
-
/* @__PURE__ */ jsxs6(
|
|
1973
|
-
"button",
|
|
1974
|
-
{
|
|
1975
|
-
type: "button",
|
|
1976
|
-
"aria-expanded": expanded,
|
|
1977
|
-
className: "flex min-w-0 flex-1 items-center gap-1 rounded-md px-1.5 py-1 text-left text-sm font-medium text-text-secondary hover:bg-ghost-button-hover hover:text-text-primary",
|
|
1978
|
-
onClick: () => setExpanded((v) => !v),
|
|
1979
|
-
children: [
|
|
1980
|
-
/* @__PURE__ */ jsx23("span", { className: "truncate", children: "Chat History" }),
|
|
1981
|
-
/* @__PURE__ */ jsx23(
|
|
1982
|
-
Icon,
|
|
1983
|
-
{
|
|
1984
|
-
name: "chevron-down",
|
|
1985
|
-
className: cn("size-3.5 shrink-0 transition-transform", !expanded && "-rotate-90")
|
|
1986
|
-
}
|
|
1987
|
-
)
|
|
1988
|
-
]
|
|
1989
|
-
}
|
|
1990
|
-
),
|
|
1991
|
-
showFilter ? /* @__PURE__ */ jsx23(AgentHistoryFilterButton, {}) : null
|
|
1992
|
-
] }),
|
|
1993
|
-
expanded ? /* @__PURE__ */ jsx23(
|
|
1994
|
-
"div",
|
|
1995
|
-
{
|
|
1996
|
-
ref: viewportRef,
|
|
1997
|
-
"data-slot": THREAD_LIST_VIEWPORT_SLOT,
|
|
1998
|
-
className: "flex min-h-0 flex-1 flex-col gap-0.5 overflow-y-auto",
|
|
1999
|
-
children
|
|
2000
|
-
}
|
|
2001
|
-
) : null
|
|
2002
|
-
] });
|
|
2003
|
-
}
|
|
2004
|
-
function ThreadListContainer({ onThreadOpen } = {}) {
|
|
2005
|
-
const aui = useAui5();
|
|
2006
|
-
const server = useOptionalServer();
|
|
2007
|
-
const isLoading = useAuiState13((s) => s.threads.isLoading);
|
|
2008
|
-
const isLoadingMore = useAuiState13((s) => s.threads.isLoadingMore);
|
|
2009
|
-
const hasMore = useAuiState13((s) => s.threads.hasMore);
|
|
2010
|
-
const threadIds = useAuiState13((s) => s.threads.threadIds);
|
|
2011
|
-
const shell = useOptionalShellMode();
|
|
2012
|
-
const ThreadListShell = useSlot("ThreadListShell");
|
|
2013
|
-
const ThreadListNewButton = useSlot("ThreadListNewButton");
|
|
2014
|
-
const AgentsLibraryButton = useSlot("AgentsLibraryButton");
|
|
2015
|
-
const ThreadListRowSkeleton = useSlot("ThreadListRowSkeleton");
|
|
2016
|
-
const ThreadListEmptyState = useSlot("ThreadListEmptyState");
|
|
2017
|
-
const viewportRef = useRef11(null);
|
|
2018
|
-
const hasMoreRef = useRef11(hasMore);
|
|
2019
|
-
const auiRef = useRef11(aui);
|
|
2020
|
-
hasMoreRef.current = hasMore;
|
|
2021
|
-
auiRef.current = aui;
|
|
2022
|
-
const showNewChat = shell?.isNewChatEnabled !== false;
|
|
2023
|
-
const isIdle = shell?.mode.status === "idle";
|
|
2024
|
-
const canDeleteSession = typeof server?.deleteSession === "function";
|
|
2025
|
-
useEffect11(() => {
|
|
2026
|
-
if (isIdle || isLoading || isLoadingMore) return;
|
|
2027
|
-
const viewport = viewportRef.current;
|
|
2028
|
-
if (!viewport) return;
|
|
2029
|
-
let cancelled = false;
|
|
2030
|
-
const tryLoadMore = () => {
|
|
2031
|
-
if (cancelled || !hasMoreRef.current) return;
|
|
2032
|
-
if (viewport.clientHeight <= 0) return;
|
|
2033
|
-
const remaining = viewport.scrollHeight - viewport.scrollTop - viewport.clientHeight;
|
|
2034
|
-
if (viewport.scrollHeight > viewport.clientHeight && remaining > LOAD_MORE_BOTTOM_PX) return;
|
|
2035
|
-
void auiRef.current.threads().loadMore();
|
|
2036
|
-
};
|
|
2037
|
-
viewport.addEventListener("scroll", tryLoadMore, { passive: true });
|
|
2038
|
-
const resizeObserver = typeof ResizeObserver === "undefined" ? void 0 : new ResizeObserver(() => tryLoadMore());
|
|
2039
|
-
if (resizeObserver) {
|
|
2040
|
-
resizeObserver.observe(viewport);
|
|
2041
|
-
} else {
|
|
2042
|
-
window.addEventListener("resize", tryLoadMore);
|
|
2043
|
-
}
|
|
2044
|
-
tryLoadMore();
|
|
2045
|
-
return () => {
|
|
2046
|
-
cancelled = true;
|
|
2047
|
-
viewport.removeEventListener("scroll", tryLoadMore);
|
|
2048
|
-
resizeObserver?.disconnect();
|
|
2049
|
-
if (!resizeObserver) {
|
|
2050
|
-
window.removeEventListener("resize", tryLoadMore);
|
|
2051
|
-
}
|
|
2052
|
-
};
|
|
2053
|
-
}, [hasMore, isIdle, isLoading, isLoadingMore, threadIds.length]);
|
|
2054
|
-
const handleNewChat = () => {
|
|
2055
|
-
onThreadOpen?.();
|
|
2056
|
-
if (shell?.isComposerEnabled) {
|
|
2057
|
-
shell.openDraft();
|
|
2058
|
-
return;
|
|
2059
|
-
}
|
|
2060
|
-
shell?.setSettingsOpen(false);
|
|
2061
|
-
void Promise.resolve(aui.threads().switchToNewThread()).catch(() => void 0);
|
|
2062
|
-
};
|
|
2063
|
-
let listBody;
|
|
2064
|
-
if (isIdle) {
|
|
2065
|
-
listBody = /* @__PURE__ */ jsx23(ThreadListEmptyState, {});
|
|
2066
|
-
} else if (isLoading) {
|
|
2067
|
-
listBody = /* @__PURE__ */ jsx23(ThreadListRowSkeleton, {});
|
|
2068
|
-
} else if (threadIds.length === 0) {
|
|
2069
|
-
listBody = /* @__PURE__ */ jsx23(ThreadListEmptyState, {});
|
|
2070
|
-
} else {
|
|
2071
|
-
listBody = /* @__PURE__ */ jsx23(ThreadListPrimitive.Root, { className: "flex min-h-0 flex-col gap-0.5", children: /* @__PURE__ */ jsx23(ThreadListItemsByRecency, { onThreadOpen, canDeleteSession }) });
|
|
2072
|
-
}
|
|
2073
|
-
return /* @__PURE__ */ jsx23(
|
|
2074
|
-
ThreadListShell,
|
|
2075
|
-
{
|
|
2076
|
-
header: /* @__PURE__ */ jsxs6("div", { className: "flex flex-col gap-1", children: [
|
|
2077
|
-
showNewChat ? /* @__PURE__ */ jsx23(ThreadListNewButton, { onClick: handleNewChat }) : null,
|
|
2078
|
-
/* @__PURE__ */ jsx23(
|
|
2079
|
-
AgentsLibraryButton,
|
|
2080
|
-
{
|
|
2081
|
-
onSelectAgent: () => {
|
|
2082
|
-
onThreadOpen?.();
|
|
2083
|
-
}
|
|
2084
|
-
}
|
|
2085
|
-
)
|
|
2086
|
-
] }),
|
|
2087
|
-
children: /* @__PURE__ */ jsxs6(ChatHistorySection, { viewportRef, children: [
|
|
2088
|
-
listBody,
|
|
2089
|
-
!isIdle && hasMore ? /* @__PURE__ */ jsx23("div", { className: "h-4 shrink-0", "aria-hidden": true }) : null
|
|
2090
|
-
] })
|
|
2091
|
-
}
|
|
2092
|
-
);
|
|
2093
|
-
}
|
|
2094
|
-
|
|
2095
|
-
export {
|
|
2096
|
-
AgentStepsContainer,
|
|
2097
|
-
AskUserContainer,
|
|
2098
|
-
computeAgentStepsSplit,
|
|
2099
|
-
AssistantTextContainer,
|
|
2100
|
-
ReasoningContainer,
|
|
2101
|
-
ToolApprovalContainer,
|
|
2102
|
-
ToolCallContentBlockContainer,
|
|
2103
|
-
ToolCallContainer,
|
|
2104
|
-
AssistantMessageContainer,
|
|
2105
|
-
ComposerAttachmentsContainer,
|
|
2106
|
-
MessageAttachmentsContainer,
|
|
2107
|
-
ComposerAttachmentPickerContainer,
|
|
2108
|
-
threadHasPendingMcpAuth,
|
|
2109
|
-
useComposerPauseView,
|
|
2110
|
-
CustomActionContainer,
|
|
2111
|
-
McpAuthContainer,
|
|
2112
|
-
ComposerContainer,
|
|
2113
|
-
HistoryLoaderContainer,
|
|
2114
|
-
ResumeUnavailableContainer,
|
|
2115
|
-
UserEditComposerContainer,
|
|
2116
|
-
UserMessageContainer,
|
|
2117
|
-
ThreadContainer,
|
|
2118
|
-
Thread,
|
|
2119
|
-
ThreadListContainer
|
|
2120
|
-
};
|
|
2121
|
-
//# sourceMappingURL=chunk-3S6KHO7H.js.map
|