@flanksource/clicky-ui 0.3.16 → 0.3.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/data/DataTable.cjs +30 -10
- package/dist/data/DataTable.cjs.map +1 -1
- package/dist/data/DataTable.d.ts +2 -0
- package/dist/data/DataTable.d.ts.map +1 -1
- package/dist/data/DataTable.js +30 -10
- package/dist/data/DataTable.js.map +1 -1
- package/dist/data/ServerTimingBadge.cjs +64 -0
- package/dist/data/ServerTimingBadge.cjs.map +1 -0
- package/dist/data/ServerTimingBadge.d.ts +9 -0
- package/dist/data/ServerTimingBadge.d.ts.map +1 -0
- package/dist/data/ServerTimingBadge.js +64 -0
- package/dist/data/ServerTimingBadge.js.map +1 -0
- package/dist/data/ai/ChatWindow.cjs +9 -1
- package/dist/data/ai/ChatWindow.cjs.map +1 -1
- package/dist/data/ai/ChatWindow.d.ts.map +1 -1
- package/dist/data/ai/ChatWindow.js +9 -1
- package/dist/data/ai/ChatWindow.js.map +1 -1
- package/dist/data/ai/ChatWindow.thread-status.cjs +14 -0
- package/dist/data/ai/ChatWindow.thread-status.cjs.map +1 -0
- package/dist/data/ai/ChatWindow.thread-status.d.ts +5 -0
- package/dist/data/ai/ChatWindow.thread-status.d.ts.map +1 -0
- package/dist/data/ai/ChatWindow.thread-status.js +14 -0
- package/dist/data/ai/ChatWindow.thread-status.js.map +1 -0
- package/dist/data/ai/ChatWindow.thread.cjs +68 -0
- package/dist/data/ai/ChatWindow.thread.cjs.map +1 -0
- package/dist/data/ai/ChatWindow.thread.d.ts +16 -0
- package/dist/data/ai/ChatWindow.thread.d.ts.map +1 -0
- package/dist/data/ai/ChatWindow.thread.js +68 -0
- package/dist/data/ai/ChatWindow.thread.js.map +1 -0
- package/dist/data/ai/PromptRunEditor/index.cjs +100 -88
- package/dist/data/ai/PromptRunEditor/index.cjs.map +1 -1
- package/dist/data/ai/PromptRunEditor/index.d.ts +5 -9
- package/dist/data/ai/PromptRunEditor/index.d.ts.map +1 -1
- package/dist/data/ai/PromptRunEditor/index.js +103 -91
- package/dist/data/ai/PromptRunEditor/index.js.map +1 -1
- package/dist/data/ai/PromptRunEditor/model.cjs +47 -0
- package/dist/data/ai/PromptRunEditor/model.cjs.map +1 -0
- package/dist/data/ai/PromptRunEditor/model.d.ts +17 -0
- package/dist/data/ai/PromptRunEditor/model.d.ts.map +1 -0
- package/dist/data/ai/PromptRunEditor/model.js +47 -0
- package/dist/data/ai/PromptRunEditor/model.js.map +1 -0
- package/dist/data/ai/RuntimeBar.cjs +104 -32
- package/dist/data/ai/RuntimeBar.cjs.map +1 -1
- package/dist/data/ai/RuntimeBar.d.ts +4 -11
- package/dist/data/ai/RuntimeBar.d.ts.map +1 -1
- package/dist/data/ai/RuntimeBar.js +107 -35
- package/dist/data/ai/RuntimeBar.js.map +1 -1
- package/dist/data/ai/RuntimeBar.model.cjs +14 -0
- package/dist/data/ai/RuntimeBar.model.cjs.map +1 -0
- package/dist/data/ai/RuntimeBar.model.d.ts +10 -0
- package/dist/data/ai/RuntimeBar.model.d.ts.map +1 -0
- package/dist/data/ai/RuntimeBar.model.js +14 -0
- package/dist/data/ai/RuntimeBar.model.js.map +1 -0
- package/dist/data/ai/RuntimeBarCombo.cjs +359 -0
- package/dist/data/ai/RuntimeBarCombo.cjs.map +1 -0
- package/dist/data/ai/RuntimeBarCombo.d.ts +22 -0
- package/dist/data/ai/RuntimeBarCombo.d.ts.map +1 -0
- package/dist/data/ai/RuntimeBarCombo.js +359 -0
- package/dist/data/ai/RuntimeBarCombo.js.map +1 -0
- package/dist/data/ai/SessionViewer.header.cjs +17 -9
- package/dist/data/ai/SessionViewer.header.cjs.map +1 -1
- package/dist/data/ai/SessionViewer.header.d.ts.map +1 -1
- package/dist/data/ai/SessionViewer.header.js +17 -9
- package/dist/data/ai/SessionViewer.header.js.map +1 -1
- package/dist/data/ai/SessionViewer.model.cjs +2 -0
- package/dist/data/ai/SessionViewer.model.cjs.map +1 -1
- package/dist/data/ai/SessionViewer.model.d.ts +4 -0
- package/dist/data/ai/SessionViewer.model.d.ts.map +1 -1
- package/dist/data/ai/SessionViewer.model.js +2 -0
- package/dist/data/ai/SessionViewer.model.js.map +1 -1
- package/dist/data/ai/SessionViewer.unified.d.ts +1 -0
- package/dist/data/ai/SessionViewer.unified.d.ts.map +1 -1
- package/dist/data/ai/SpecRuntimeEditor/fields.js +1 -1
- package/dist/data/ai/ThreadPicker.cjs.map +1 -1
- package/dist/data/ai/ThreadPicker.d.ts +2 -0
- package/dist/data/ai/ThreadPicker.d.ts.map +1 -1
- package/dist/data/ai/ThreadPicker.js.map +1 -1
- package/dist/data/ai/index.d.ts +1 -0
- package/dist/data/ai/index.d.ts.map +1 -1
- package/dist/data/ai/model-capabilities.cjs +12 -1
- package/dist/data/ai/model-capabilities.cjs.map +1 -1
- package/dist/data/ai/model-capabilities.d.ts +2 -6
- package/dist/data/ai/model-capabilities.d.ts.map +1 -1
- package/dist/data/ai/model-capabilities.js +12 -1
- package/dist/data/ai/model-capabilities.js.map +1 -1
- package/dist/data/ai/runtime-mode.cjs +10 -1
- package/dist/data/ai/runtime-mode.cjs.map +1 -1
- package/dist/data/ai/runtime-mode.d.ts +1 -0
- package/dist/data/ai/runtime-mode.d.ts.map +1 -1
- package/dist/data/ai/runtime-mode.js +11 -2
- package/dist/data/ai/runtime-mode.js.map +1 -1
- package/dist/data/chat/Chat.cjs +90 -21
- package/dist/data/chat/Chat.cjs.map +1 -1
- package/dist/data/chat/Chat.d.ts +4 -1
- package/dist/data/chat/Chat.d.ts.map +1 -1
- package/dist/data/chat/Chat.js +90 -21
- package/dist/data/chat/Chat.js.map +1 -1
- package/dist/data/chat/ContextMeter.cjs +144 -73
- package/dist/data/chat/ContextMeter.cjs.map +1 -1
- package/dist/data/chat/ContextMeter.d.ts +8 -3
- package/dist/data/chat/ContextMeter.d.ts.map +1 -1
- package/dist/data/chat/ContextMeter.js +144 -73
- package/dist/data/chat/ContextMeter.js.map +1 -1
- package/dist/data/chat/approval.cjs +21 -0
- package/dist/data/chat/approval.cjs.map +1 -0
- package/dist/data/chat/approval.d.ts +11 -0
- package/dist/data/chat/approval.d.ts.map +1 -0
- package/dist/data/chat/approval.js +21 -0
- package/dist/data/chat/approval.js.map +1 -0
- package/dist/data/chat/types.cjs.map +1 -1
- package/dist/data/chat/types.d.ts +12 -0
- package/dist/data/chat/types.d.ts.map +1 -1
- package/dist/data/chat/types.js.map +1 -1
- package/dist/data/server-timing.cjs +120 -0
- package/dist/data/server-timing.cjs.map +1 -0
- package/dist/data/server-timing.d.ts +11 -0
- package/dist/data/server-timing.d.ts.map +1 -0
- package/dist/data/server-timing.js +120 -0
- package/dist/data/server-timing.js.map +1 -0
- package/dist/data/version-info.cjs +3 -3
- package/dist/data/version-info.js +3 -3
- package/dist/data.cjs +7 -0
- package/dist/data.cjs.map +1 -1
- package/dist/data.d.ts +2 -0
- package/dist/data.d.ts.map +1 -1
- package/dist/data.js +7 -0
- package/dist/data.js.map +1 -1
- package/dist/index.cjs +7 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/layout/AppShell.cjs +1 -1
- package/dist/layout/AppShell.cjs.map +1 -1
- package/dist/layout/AppShell.js +1 -1
- package/dist/layout/AppShell.js.map +1 -1
- package/dist/overlay/HoverCard.cjs.map +1 -1
- package/dist/overlay/HoverCard.d.ts +2 -2
- package/dist/overlay/HoverCard.d.ts.map +1 -1
- package/dist/overlay/HoverCard.js.map +1 -1
- package/dist/rpc/OperationCatalog.cjs +28 -51
- package/dist/rpc/OperationCatalog.cjs.map +1 -1
- package/dist/rpc/OperationCatalog.d.ts +1 -6
- package/dist/rpc/OperationCatalog.d.ts.map +1 -1
- package/dist/rpc/OperationCatalog.js +29 -52
- package/dist/rpc/OperationCatalog.js.map +1 -1
- package/dist/rpc/OperationResultView.cjs +42 -0
- package/dist/rpc/OperationResultView.cjs.map +1 -1
- package/dist/rpc/OperationResultView.d.ts +2 -1
- package/dist/rpc/OperationResultView.d.ts.map +1 -1
- package/dist/rpc/OperationResultView.js +42 -0
- package/dist/rpc/OperationResultView.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/tailwind-preset.cjs +4 -0
- package/dist/tailwind-preset.cjs.map +1 -1
- package/dist/tailwind-preset.d.ts.map +1 -1
- package/dist/tailwind-preset.js +4 -0
- package/dist/tailwind-preset.js.map +1 -1
- package/package.json +1 -1
package/dist/data/chat/Chat.cjs
CHANGED
|
@@ -13,6 +13,7 @@ const providerIcons = require("./provider-icons.cjs");
|
|
|
13
13
|
const ContextMeter = require("./ContextMeter.cjs");
|
|
14
14
|
const effortIcons = require("./effort-icons.cjs");
|
|
15
15
|
const models = require("./models.cjs");
|
|
16
|
+
const approval = require("./approval.cjs");
|
|
16
17
|
const attachmentUpload = require("./attachment-upload.cjs");
|
|
17
18
|
function Chat({
|
|
18
19
|
api = "/api/chat",
|
|
@@ -35,6 +36,7 @@ function Chat({
|
|
|
35
36
|
attachmentUpload: attachmentUpload$1,
|
|
36
37
|
attachmentLimits,
|
|
37
38
|
threadId,
|
|
39
|
+
approvalApi = null,
|
|
38
40
|
renderToolResult,
|
|
39
41
|
body,
|
|
40
42
|
transport,
|
|
@@ -45,10 +47,16 @@ function Chat({
|
|
|
45
47
|
emptyState,
|
|
46
48
|
className
|
|
47
49
|
}) {
|
|
50
|
+
var _a;
|
|
48
51
|
const [models$1, setModels] = react.useState(modelsProp ?? []);
|
|
49
|
-
const [model, setModel] = react.useState(
|
|
50
|
-
|
|
52
|
+
const [model, setModel] = react.useState(
|
|
53
|
+
controlledModel ?? defaultModel
|
|
54
|
+
);
|
|
55
|
+
const [effort, setEffort] = react.useState(
|
|
56
|
+
controlledEffort ?? defaultReasoningEffort
|
|
57
|
+
);
|
|
51
58
|
const [usage, setUsage] = react.useState(null);
|
|
59
|
+
const [approvalError, setApprovalError] = react.useState();
|
|
52
60
|
const lastDefaultModel = react.useRef(defaultModel);
|
|
53
61
|
const sentInitialPromptId = react.useRef(null);
|
|
54
62
|
react.useEffect(() => {
|
|
@@ -59,11 +67,15 @@ function Chat({
|
|
|
59
67
|
react.useEffect(() => {
|
|
60
68
|
if (modelsProp || !modelsApi) return;
|
|
61
69
|
let cancelled = false;
|
|
62
|
-
fetch(modelsApi).then(
|
|
70
|
+
fetch(modelsApi).then(
|
|
71
|
+
(r) => r.ok ? r.json() : Promise.reject(new Error(`models ${r.status}`))
|
|
72
|
+
).then((data) => {
|
|
63
73
|
if (cancelled) return;
|
|
64
74
|
setModels(data);
|
|
65
75
|
setModel((m) => m ?? controlledModel ?? models.defaultChatModelId(data));
|
|
66
|
-
}).catch(
|
|
76
|
+
}).catch(
|
|
77
|
+
(err) => console.warn("clicky-ui: failed to load chat models", err)
|
|
78
|
+
);
|
|
67
79
|
return () => {
|
|
68
80
|
cancelled = true;
|
|
69
81
|
};
|
|
@@ -92,6 +104,7 @@ function Chat({
|
|
|
92
104
|
bodyRef.current = {
|
|
93
105
|
...body,
|
|
94
106
|
...model ? { model } : {},
|
|
107
|
+
...(selectedModel == null ? void 0 : selectedModel.runtime) ? { runtime: selectedModel.runtime } : {},
|
|
95
108
|
...effort ? { reasoningEffort: effort } : {},
|
|
96
109
|
...temperature !== void 0 ? { temperature } : {},
|
|
97
110
|
...budget && (budget.cost !== void 0 || budget.maxTokens !== void 0) ? { budget } : {},
|
|
@@ -102,7 +115,16 @@ function Chat({
|
|
|
102
115
|
() => transport ?? new ai.DefaultChatTransport({ api, body: () => bodyRef.current }),
|
|
103
116
|
[transport, api]
|
|
104
117
|
);
|
|
105
|
-
const {
|
|
118
|
+
const {
|
|
119
|
+
messages,
|
|
120
|
+
sendMessage,
|
|
121
|
+
regenerate,
|
|
122
|
+
addToolApprovalResponse,
|
|
123
|
+
status,
|
|
124
|
+
error,
|
|
125
|
+
clearError,
|
|
126
|
+
stop
|
|
127
|
+
} = react$1.useChat({
|
|
106
128
|
transport: resolvedTransport,
|
|
107
129
|
sendAutomaticallyWhen: ai.lastAssistantMessageIsCompleteWithApprovalResponses,
|
|
108
130
|
...initialMessages ? { messages: initialMessages } : {}
|
|
@@ -119,12 +141,12 @@ function Chat({
|
|
|
119
141
|
const onUsageRef = react.useRef(onUsage);
|
|
120
142
|
onUsageRef.current = onUsage;
|
|
121
143
|
react.useEffect(() => {
|
|
122
|
-
var
|
|
144
|
+
var _a2, _b, _c;
|
|
123
145
|
if (status !== "ready") return;
|
|
124
146
|
const last = [...messages].reverse().find((m) => m.role === "assistant");
|
|
125
147
|
const meta = last == null ? void 0 : last.metadata;
|
|
126
148
|
if (!meta) return;
|
|
127
|
-
const cost = meta.threadCostUsd ?? ((
|
|
149
|
+
const cost = meta.threadCostUsd ?? ((_a2 = meta.costBreakdown) == null ? void 0 : _a2.totalUsd) ?? meta.cost;
|
|
128
150
|
const snapshot = {
|
|
129
151
|
usedTokens: meta.contextTokens ?? ((_b = meta.usage) == null ? void 0 : _b.totalTokens) ?? 0,
|
|
130
152
|
maxTokens: (selectedModel == null ? void 0 : selectedModel.contextWindow) ?? 0,
|
|
@@ -145,32 +167,76 @@ function Chat({
|
|
|
145
167
|
setEffort(next);
|
|
146
168
|
onReasoningEffortChange == null ? void 0 : onReasoningEffortChange(next);
|
|
147
169
|
};
|
|
170
|
+
const resolveToolApproval = async (id, approved, reason) => {
|
|
171
|
+
setApprovalError(void 0);
|
|
172
|
+
if (approvalApi) {
|
|
173
|
+
try {
|
|
174
|
+
await approval.postToolApproval({
|
|
175
|
+
approvalApi,
|
|
176
|
+
threadId: threadId ?? "",
|
|
177
|
+
approvalId: id,
|
|
178
|
+
approved,
|
|
179
|
+
...reason ? { reason } : {}
|
|
180
|
+
});
|
|
181
|
+
} catch (cause) {
|
|
182
|
+
setApprovalError(
|
|
183
|
+
cause instanceof Error ? cause : new Error(String(cause))
|
|
184
|
+
);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
await addToolApprovalResponse(
|
|
189
|
+
reason ? { id, approved, reason } : { id, approved }
|
|
190
|
+
);
|
|
191
|
+
};
|
|
148
192
|
const ModelGlyph = providerIcons.providerIcon(selectedModel == null ? void 0 : selectedModel.provider);
|
|
149
|
-
const
|
|
193
|
+
const contextWindow = (selectedModel == null ? void 0 : selectedModel.contextWindow) ?? (usage == null ? void 0 : usage.maxTokens) ?? 0;
|
|
194
|
+
const usedTokens = (usage == null ? void 0 : usage.usedTokens) ?? 0;
|
|
195
|
+
const showContextMeter = Boolean(threadId || selectedModel || usage);
|
|
196
|
+
const toolbar = models$1.length > 0 || showEffort || showContextMeter ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 items-center gap-2", children: [
|
|
150
197
|
/* @__PURE__ */ jsxRuntime.jsx(ModelSelector.ModelSelector, { models: models$1, value: model, onChange: onModelSelect }),
|
|
151
|
-
showEffort && /* @__PURE__ */ jsxRuntime.jsx(
|
|
152
|
-
|
|
198
|
+
showEffort && /* @__PURE__ */ jsxRuntime.jsx(
|
|
199
|
+
ModelSelector.EffortSelector,
|
|
200
|
+
{
|
|
201
|
+
efforts: reasoningEfforts,
|
|
202
|
+
value: effort,
|
|
203
|
+
onChange: onEffortSelect
|
|
204
|
+
}
|
|
205
|
+
),
|
|
206
|
+
showContextMeter && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
153
207
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1" }),
|
|
154
208
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
155
209
|
ContextMeter.ContextMeter,
|
|
156
210
|
{
|
|
157
211
|
mode: "gauge",
|
|
158
|
-
usedPercent: Math.round(
|
|
159
|
-
usedTokens
|
|
160
|
-
windowTokens:
|
|
161
|
-
...usage.messageCount != null ? { messageCount: usage.messageCount } : {},
|
|
162
|
-
...usage.cost != null ? { cost: { total: usage.cost } } : {},
|
|
163
|
-
...
|
|
212
|
+
usedPercent: contextWindow > 0 ? Math.round(usedTokens / contextWindow * 100) : 0,
|
|
213
|
+
usedTokens,
|
|
214
|
+
...contextWindow > 0 ? { windowTokens: contextWindow } : {},
|
|
215
|
+
...(usage == null ? void 0 : usage.messageCount) != null ? { messageCount: usage.messageCount } : {},
|
|
216
|
+
...(usage == null ? void 0 : usage.cost) != null ? { cost: { total: usage.cost } } : {},
|
|
217
|
+
...threadId ? { sessionId: threadId } : {},
|
|
218
|
+
...(selectedModel == null ? void 0 : selectedModel.label) ? { model: selectedModel.label } : (usage == null ? void 0 : usage.modelLabel) ? { model: usage.modelLabel } : {},
|
|
164
219
|
...effort ? { effort } : {},
|
|
220
|
+
...((_a = selectedModel == null ? void 0 : selectedModel.runtime) == null ? void 0 : _a.mode) ? { executionMode: selectedModel.runtime.mode } : {},
|
|
165
221
|
...ModelGlyph ? { modelIcon: ModelGlyph } : {},
|
|
166
|
-
...(selectedModel == null ? void 0 : selectedModel.provider) ? {
|
|
222
|
+
...(selectedModel == null ? void 0 : selectedModel.provider) ? {
|
|
223
|
+
modelIconClassName: providerIcons.providerIconColor(
|
|
224
|
+
selectedModel.provider
|
|
225
|
+
)
|
|
226
|
+
} : {}
|
|
167
227
|
}
|
|
168
228
|
)
|
|
169
229
|
] })
|
|
170
230
|
] }) : void 0;
|
|
171
231
|
const empty = messages.length === 0 && (emptyState || (suggestions == null ? void 0 : suggestions.length)) ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-4", children: [
|
|
172
232
|
emptyState,
|
|
173
|
-
suggestions && suggestions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
233
|
+
suggestions && suggestions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
234
|
+
Suggestion.Suggestions,
|
|
235
|
+
{
|
|
236
|
+
suggestions,
|
|
237
|
+
onSelect: (text) => void sendMessage({ text })
|
|
238
|
+
}
|
|
239
|
+
)
|
|
174
240
|
] }) : void 0;
|
|
175
241
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: utils.cn("flex h-full flex-col", className), children: [
|
|
176
242
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -178,13 +244,16 @@ function Chat({
|
|
|
178
244
|
{
|
|
179
245
|
messages,
|
|
180
246
|
status,
|
|
181
|
-
error,
|
|
182
|
-
onClearError:
|
|
247
|
+
error: approvalError ?? error,
|
|
248
|
+
onClearError: () => {
|
|
249
|
+
setApprovalError(void 0);
|
|
250
|
+
clearError();
|
|
251
|
+
},
|
|
183
252
|
...threadId ? { sessionId: threadId } : {},
|
|
184
253
|
...model ? { model } : {},
|
|
185
254
|
emptyState: empty,
|
|
186
255
|
onRegenerate: (messageId) => void regenerate({ messageId }),
|
|
187
|
-
onApprove: (id, approved, reason) => void
|
|
256
|
+
onApprove: (id, approved, reason) => void resolveToolApproval(id, approved, reason),
|
|
188
257
|
...renderToolResult ? { renderToolResult } : {}
|
|
189
258
|
}
|
|
190
259
|
),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Chat.cjs","sources":["../../../src/data/chat/Chat.tsx"],"sourcesContent":["import { useEffect, useMemo, useRef, useState } from \"react\";\nimport { useChat } from \"@ai-sdk/react\";\nimport {\n DefaultChatTransport,\n lastAssistantMessageIsCompleteWithApprovalResponses,\n type ChatTransport,\n type UIMessage,\n} from \"ai\";\nimport { cn } from \"../../lib/utils\";\nimport { Conversation } from \"./Conversation\";\nimport { PromptInput } from \"./PromptInput\";\nimport { Suggestions } from \"./Suggestion\";\nimport { ModelSelector, EffortSelector } from \"./ModelSelector\";\nimport { providerIcon, providerIconColor } from \"./provider-icons\";\nimport { ContextMeter } from \"./ContextMeter\";\nimport { DEFAULT_REASONING_EFFORTS } from \"./effort-icons\";\nimport { defaultChatModelId } from \"./models\";\nimport {\n createAttachmentUploadAdapter,\n type AttachmentLimits,\n type AttachmentUploadAdapter,\n} from \"./attachment-upload\";\nimport type {\n ChatBudgetConfig,\n ChatModel,\n ChatMessageMetadata,\n ChatUsageSummary,\n ClaudePermissionMode,\n Suggestion,\n ToolResultRenderer,\n} from \"./types\";\n\n/** Assistant messages carry token usage + cost the backend rode on the finish\n * part's `messageMetadata`. */\ntype ChatUIMessage = UIMessage<ChatMessageMetadata>;\n\nexport type ChatProps = {\n /** Endpoint that speaks the AI SDK v6 UI Message Stream protocol.\n * Ignored when `transport` is supplied. Defaults to \"/api/chat\". */\n api?: string;\n /** Model menu. When omitted and `modelsApi` is set, it is fetched. */\n models?: ChatModel[];\n /** Endpoint returning the model menu (ModelInfo[]). Defaults to\n * \"/api/chat/models\". Set to null to disable fetching. */\n modelsApi?: string | null;\n /** Initially selected model id; otherwise the first configured model. */\n defaultModel?: string;\n /** Controlled selected model id. */\n model?: string;\n /** Reasoning-effort options for capable models. */\n reasoningEfforts?: string[];\n /** Initially selected reasoning effort (\"\" = none). */\n defaultReasoningEffort?: string;\n /** Controlled selected reasoning effort (\"\" = none). */\n reasoningEffort?: string;\n /** Sampling temperature forwarded to the backend when set. */\n temperature?: number;\n /** Per-request budget forwarded to the backend when set. */\n budget?: ChatBudgetConfig;\n /** Claude Agent SDK permission mode forwarded to the backend when set. */\n permissionMode?: ClaudePermissionMode;\n /** Notified when the user changes the model. */\n onModelChange?: (id: string) => void;\n /** Notified when the user changes reasoning effort. */\n onReasoningEffortChange?: (effort: string) => void;\n /** Notified when the user changes Claude permission mode. */\n onPermissionModeChange?: (mode: ClaudePermissionMode) => void;\n /** Notified after each assistant turn with a usage snapshot (tokens used out\n * of the model's context window + cumulative cost), for a usage gauge. */\n onUsage?: (usage: ChatUsageSummary) => void;\n /** Suggested prompts shown on the empty state. */\n suggestions?: Suggestion[];\n /** Enables file/image attachments. */\n enableAttachments?: boolean;\n /** Upload endpoint used before an attachment is added to a chat message. */\n attachmentsApi?: string;\n /** Custom durable upload adapter; overrides attachmentsApi. */\n attachmentUpload?: AttachmentUploadAdapter;\n attachmentLimits?: AttachmentLimits;\n /** Thread id to persist this conversation under (forwarded in the body). */\n threadId?: string;\n /** Optional host renderer for recognized completed tool outputs. */\n renderToolResult?: ToolResultRenderer;\n /** Extra fields merged into every request body. */\n body?: Record<string, unknown>;\n /** Pre-built transport (e.g. a mock for stories/tests). */\n transport?: ChatTransport<UIMessage>;\n /** Initial messages to seed the conversation. */\n initialMessages?: UIMessage[];\n /** Prompt to send automatically once. A new `id` sends even when text repeats. */\n initialPrompt?: { id: number; text: string } | null;\n /** Called after `initialPrompt` has been handed to the chat transport. */\n onInitialPromptSent?: () => void;\n placeholder?: string;\n emptyState?: React.ReactNode;\n className?: string;\n};\n\n/** Self-contained AI chat over a v6-compatible `/api/chat`: a streaming\n * conversation with model/effort selectors, suggestions, attachments,\n * per-message copy/regenerate, and human-in-the-loop tool approvals. The\n * backend owns model selection and tool execution; the selected model,\n * effort, permission mode and thread id are forwarded in the request body. */\nexport function Chat({\n api = \"/api/chat\",\n models: modelsProp,\n modelsApi = \"/api/chat/models\",\n defaultModel,\n model: controlledModel,\n reasoningEfforts = DEFAULT_REASONING_EFFORTS,\n defaultReasoningEffort = \"\",\n reasoningEffort: controlledEffort,\n temperature,\n budget,\n permissionMode,\n onModelChange,\n onReasoningEffortChange,\n onUsage,\n suggestions,\n enableAttachments = false,\n attachmentsApi = \"/api/attachments\",\n attachmentUpload,\n attachmentLimits,\n threadId,\n renderToolResult,\n body,\n transport,\n initialMessages,\n initialPrompt,\n onInitialPromptSent,\n placeholder,\n emptyState,\n className,\n}: ChatProps) {\n const [models, setModels] = useState<ChatModel[]>(modelsProp ?? []);\n const [model, setModel] = useState<string | undefined>(controlledModel ?? defaultModel);\n const [effort, setEffort] = useState(controlledEffort ?? defaultReasoningEffort);\n const [usage, setUsage] = useState<ChatUsageSummary | null>(null);\n const lastDefaultModel = useRef(defaultModel);\n const sentInitialPromptId = useRef<number | null>(null);\n\n useEffect(() => {\n if (!modelsProp) return;\n setModels(modelsProp);\n setModel((m) => m ?? controlledModel ?? defaultChatModelId(modelsProp));\n }, [modelsProp, controlledModel]);\n\n // Fetch the model menu unless one was supplied or fetching is disabled.\n useEffect(() => {\n if (modelsProp || !modelsApi) return;\n let cancelled = false;\n fetch(modelsApi)\n .then((r) => (r.ok ? r.json() : Promise.reject(new Error(`models ${r.status}`))))\n .then((data: ChatModel[]) => {\n if (cancelled) return;\n setModels(data);\n setModel((m) => m ?? controlledModel ?? defaultChatModelId(data));\n })\n .catch((err) => console.warn(\"clicky-ui: failed to load chat models\", err));\n return () => {\n cancelled = true;\n };\n }, [modelsProp, modelsApi, controlledModel]);\n\n useEffect(() => {\n if (controlledModel === undefined) return;\n setModel(controlledModel);\n }, [controlledModel]);\n\n useEffect(() => {\n if (controlledEffort === undefined) return;\n setEffort(controlledEffort);\n }, [controlledEffort]);\n\n useEffect(() => {\n if (controlledModel !== undefined) return;\n if (!defaultModel || defaultModel === lastDefaultModel.current) return;\n lastDefaultModel.current = defaultModel;\n setModel(defaultModel);\n }, [controlledModel, defaultModel]);\n\n const selectedModel = models.find((m) => m.id === model);\n const showEffort = !selectedModel || selectedModel.reasoning;\n const resolvedAttachmentUpload = useMemo(\n () =>\n attachmentUpload ??\n createAttachmentUploadAdapter({ endpoint: attachmentsApi }),\n [attachmentUpload, attachmentsApi],\n );\n\n // A function body keeps the transport stable while always sending the latest\n // model/effort/runtime selections.\n const bodyRef = useRef<Record<string, unknown>>({});\n bodyRef.current = {\n ...body,\n ...(model ? { model } : {}),\n ...(effort ? { reasoningEffort: effort } : {}),\n ...(temperature !== undefined ? { temperature } : {}),\n ...(budget && (budget.cost !== undefined || budget.maxTokens !== undefined)\n ? { budget }\n : {}),\n ...(permissionMode ? { permissionMode } : {}),\n ...(threadId ? { threadId } : {}),\n };\n\n const resolvedTransport = useMemo<ChatTransport<UIMessage>>(\n () => transport ?? new DefaultChatTransport({ api, body: () => bodyRef.current }),\n [transport, api],\n );\n\n const { messages, sendMessage, regenerate, addToolApprovalResponse, status, error, clearError, stop } =\n useChat<ChatUIMessage>({\n transport: resolvedTransport,\n sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithApprovalResponses,\n ...(initialMessages ? { messages: initialMessages as ChatUIMessage[] } : {}),\n });\n\n useEffect(() => {\n if (!initialPrompt || status !== \"ready\") return;\n if (sentInitialPromptId.current === initialPrompt.id) return;\n const text = initialPrompt.text.trim();\n if (!text) return;\n sentInitialPromptId.current = initialPrompt.id;\n void sendMessage({ text });\n onInitialPromptSent?.();\n }, [initialPrompt, onInitialPromptSent, sendMessage, status]);\n\n // Surface a usage snapshot after each settled assistant turn. The backend\n // rides usage/cost on the finish part's messageMetadata; we read it off the\n // last assistant message and resolve maxTokens from the selected model.\n const onUsageRef = useRef(onUsage);\n onUsageRef.current = onUsage;\n useEffect(() => {\n if (status !== \"ready\") return;\n const last = [...messages].reverse().find((m) => m.role === \"assistant\");\n const meta = last?.metadata;\n if (!meta) return;\n const cost = meta.threadCostUsd ?? meta.costBreakdown?.totalUsd ?? meta.cost;\n const snapshot: ChatUsageSummary = {\n usedTokens: meta.contextTokens ?? meta.usage?.totalTokens ?? 0,\n maxTokens: selectedModel?.contextWindow ?? 0,\n messageCount: messages.length,\n ...(cost != null ? { cost } : {}),\n ...(meta.usage ? { usage: meta.usage } : {}),\n ...(meta.costBreakdown ? { costBreakdown: meta.costBreakdown } : {}),\n ...(selectedModel?.label ? { modelLabel: selectedModel.label } : {}),\n };\n setUsage(snapshot);\n onUsageRef.current?.(snapshot);\n }, [messages, status, selectedModel]);\n\n const onModelSelect = (id: string) => {\n setModel(id);\n onModelChange?.(id);\n };\n\n const onEffortSelect = (next: string) => {\n setEffort(next);\n onReasoningEffortChange?.(next);\n };\n\n const ModelGlyph = providerIcon(selectedModel?.provider);\n const toolbar = models.length > 0 || showEffort || (usage && usage.maxTokens > 0) ? (\n <div className=\"flex flex-1 items-center gap-2\">\n <ModelSelector models={models} value={model} onChange={onModelSelect} />\n {showEffort && (\n <EffortSelector efforts={reasoningEfforts} value={effort} onChange={onEffortSelect} />\n )}\n {usage && usage.maxTokens > 0 && (\n <>\n <div className=\"flex-1\" />\n <ContextMeter\n mode=\"gauge\"\n usedPercent={Math.round((usage.usedTokens / usage.maxTokens) * 100)}\n usedTokens={usage.usedTokens}\n windowTokens={usage.maxTokens}\n {...(usage.messageCount != null ? { messageCount: usage.messageCount } : {})}\n {...(usage.cost != null ? { cost: { total: usage.cost } } : {})}\n {...(usage.modelLabel ? { model: usage.modelLabel } : {})}\n {...(effort ? { effort } : {})}\n {...(ModelGlyph ? { modelIcon: ModelGlyph } : {})}\n {...(selectedModel?.provider\n ? { modelIconClassName: providerIconColor(selectedModel.provider) }\n : {})}\n />\n </>\n )}\n </div>\n ) : undefined;\n\n const empty = (messages.length === 0 && (emptyState || suggestions?.length)) ? (\n <div className=\"flex flex-col items-center gap-4\">\n {emptyState}\n {suggestions && suggestions.length > 0 && (\n <Suggestions suggestions={suggestions} onSelect={(text) => void sendMessage({ text })} />\n )}\n </div>\n ) : undefined;\n\n return (\n <div className={cn(\"flex h-full flex-col\", className)}>\n <Conversation\n messages={messages}\n status={status}\n error={error}\n onClearError={clearError}\n {...(threadId ? { sessionId: threadId } : {})}\n {...(model ? { model } : {})}\n emptyState={empty}\n onRegenerate={(messageId) => void regenerate({ messageId })}\n onApprove={(id, approved, reason) =>\n void addToolApprovalResponse(reason ? { id, approved, reason } : { id, approved })\n }\n {...(renderToolResult ? { renderToolResult } : {})}\n />\n <div className=\"p-4 pt-0\">\n <PromptInput\n status={status}\n onStop={() => void stop()}\n placeholder={placeholder}\n enableAttachments={enableAttachments}\n attachmentUpload={resolvedAttachmentUpload}\n {...(selectedModel?.inputMediaTypes\n ? { acceptedMediaTypes: selectedModel.inputMediaTypes }\n : {})}\n {...(attachmentLimits ? { attachmentLimits } : {})}\n toolbar={toolbar}\n onSubmit={(text, files) => void sendMessage({ text, files })}\n />\n </div>\n </div>\n );\n}\n"],"names":["DEFAULT_REASONING_EFFORTS","attachmentUpload","models","useState","useRef","useEffect","defaultChatModelId","useMemo","createAttachmentUploadAdapter","DefaultChatTransport","useChat","lastAssistantMessageIsCompleteWithApprovalResponses","providerIcon","jsxs","jsx","ModelSelector","EffortSelector","Fragment","ContextMeter","providerIconColor","Suggestions","cn","Conversation","PromptInput"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Chat.cjs","sources":["../../../src/data/chat/Chat.tsx"],"sourcesContent":["import { useEffect, useMemo, useRef, useState } from \"react\";\nimport { useChat } from \"@ai-sdk/react\";\nimport {\n DefaultChatTransport,\n lastAssistantMessageIsCompleteWithApprovalResponses,\n type ChatTransport,\n type UIMessage,\n} from \"ai\";\nimport { cn } from \"../../lib/utils\";\nimport { Conversation } from \"./Conversation\";\nimport { PromptInput } from \"./PromptInput\";\nimport { Suggestions } from \"./Suggestion\";\nimport { ModelSelector, EffortSelector } from \"./ModelSelector\";\nimport { providerIcon, providerIconColor } from \"./provider-icons\";\nimport { ContextMeter } from \"./ContextMeter\";\nimport { DEFAULT_REASONING_EFFORTS } from \"./effort-icons\";\nimport { defaultChatModelId } from \"./models\";\nimport { postToolApproval } from \"./approval\";\nimport {\n createAttachmentUploadAdapter,\n type AttachmentLimits,\n type AttachmentUploadAdapter,\n} from \"./attachment-upload\";\nimport type {\n ChatBudgetConfig,\n ChatModel,\n ChatMessageMetadata,\n ChatUsageSummary,\n ClaudePermissionMode,\n Suggestion,\n ToolResultRenderer,\n} from \"./types\";\n\n/** Assistant messages carry token usage + cost the backend rode on the finish\n * part's `messageMetadata`. */\ntype ChatUIMessage = UIMessage<ChatMessageMetadata>;\n\nexport type ChatProps = {\n /** Endpoint that speaks the AI SDK v6 UI Message Stream protocol.\n * Ignored when `transport` is supplied. Defaults to \"/api/chat\". */\n api?: string;\n /** Model menu. When omitted and `modelsApi` is set, it is fetched. */\n models?: ChatModel[];\n /** Endpoint returning the model menu (ModelInfo[]). Defaults to\n * \"/api/chat/models\". Set to null to disable fetching. */\n modelsApi?: string | null;\n /** Initially selected model id; otherwise the first configured model. */\n defaultModel?: string;\n /** Controlled selected model id. */\n model?: string;\n /** Reasoning-effort options for capable models. */\n reasoningEfforts?: string[];\n /** Initially selected reasoning effort (\"\" = none). */\n defaultReasoningEffort?: string;\n /** Controlled selected reasoning effort (\"\" = none). */\n reasoningEffort?: string;\n /** Sampling temperature forwarded to the backend when set. */\n temperature?: number;\n /** Per-request budget forwarded to the backend when set. */\n budget?: ChatBudgetConfig;\n /** Claude Agent SDK permission mode forwarded to the backend when set. */\n permissionMode?: ClaudePermissionMode;\n /** Notified when the user changes the model. */\n onModelChange?: (id: string) => void;\n /** Notified when the user changes reasoning effort. */\n onReasoningEffortChange?: (effort: string) => void;\n /** Notified when the user changes Claude permission mode. */\n onPermissionModeChange?: (mode: ClaudePermissionMode) => void;\n /** Notified after each assistant turn with a usage snapshot (tokens used out\n * of the model's context window + cumulative cost), for a usage gauge. */\n onUsage?: (usage: ChatUsageSummary) => void;\n /** Suggested prompts shown on the empty state. */\n suggestions?: Suggestion[];\n /** Enables file/image attachments. */\n enableAttachments?: boolean;\n /** Upload endpoint used before an attachment is added to a chat message. */\n attachmentsApi?: string;\n /** Custom durable upload adapter; overrides attachmentsApi. */\n attachmentUpload?: AttachmentUploadAdapter;\n attachmentLimits?: AttachmentLimits;\n /** Thread id to persist this conversation under (forwarded in the body). */\n threadId?: string;\n /** Base endpoint for resolving a tool approval while the provider stream is\n * still active. The thread and approval ids are appended to this URL. */\n approvalApi?: string | null;\n /** Optional host renderer for recognized completed tool outputs. */\n renderToolResult?: ToolResultRenderer;\n /** Extra fields merged into every request body. */\n body?: Record<string, unknown>;\n /** Pre-built transport (e.g. a mock for stories/tests). */\n transport?: ChatTransport<UIMessage>;\n /** Initial messages to seed the conversation. */\n initialMessages?: UIMessage[];\n /** Prompt to send automatically once. A new `id` sends even when text repeats. */\n initialPrompt?: { id: number; text: string } | null;\n /** Called after `initialPrompt` has been handed to the chat transport. */\n onInitialPromptSent?: () => void;\n placeholder?: string;\n emptyState?: React.ReactNode;\n className?: string;\n};\n\n/** Self-contained AI chat over a v6-compatible `/api/chat`: a streaming\n * conversation with model/effort selectors, suggestions, attachments,\n * per-message copy/regenerate, and human-in-the-loop tool approvals. The\n * backend owns model selection and tool execution; the selected model,\n * effort, permission mode and thread id are forwarded in the request body. */\nexport function Chat({\n api = \"/api/chat\",\n models: modelsProp,\n modelsApi = \"/api/chat/models\",\n defaultModel,\n model: controlledModel,\n reasoningEfforts = DEFAULT_REASONING_EFFORTS,\n defaultReasoningEffort = \"\",\n reasoningEffort: controlledEffort,\n temperature,\n budget,\n permissionMode,\n onModelChange,\n onReasoningEffortChange,\n onUsage,\n suggestions,\n enableAttachments = false,\n attachmentsApi = \"/api/attachments\",\n attachmentUpload,\n attachmentLimits,\n threadId,\n approvalApi = null,\n renderToolResult,\n body,\n transport,\n initialMessages,\n initialPrompt,\n onInitialPromptSent,\n placeholder,\n emptyState,\n className,\n}: ChatProps) {\n const [models, setModels] = useState<ChatModel[]>(modelsProp ?? []);\n const [model, setModel] = useState<string | undefined>(\n controlledModel ?? defaultModel,\n );\n const [effort, setEffort] = useState(\n controlledEffort ?? defaultReasoningEffort,\n );\n const [usage, setUsage] = useState<ChatUsageSummary | null>(null);\n const [approvalError, setApprovalError] = useState<Error | undefined>();\n const lastDefaultModel = useRef(defaultModel);\n const sentInitialPromptId = useRef<number | null>(null);\n\n useEffect(() => {\n if (!modelsProp) return;\n setModels(modelsProp);\n setModel((m) => m ?? controlledModel ?? defaultChatModelId(modelsProp));\n }, [modelsProp, controlledModel]);\n\n // Fetch the model menu unless one was supplied or fetching is disabled.\n useEffect(() => {\n if (modelsProp || !modelsApi) return;\n let cancelled = false;\n fetch(modelsApi)\n .then((r) =>\n r.ok ? r.json() : Promise.reject(new Error(`models ${r.status}`)),\n )\n .then((data: ChatModel[]) => {\n if (cancelled) return;\n setModels(data);\n setModel((m) => m ?? controlledModel ?? defaultChatModelId(data));\n })\n .catch((err) =>\n console.warn(\"clicky-ui: failed to load chat models\", err),\n );\n return () => {\n cancelled = true;\n };\n }, [modelsProp, modelsApi, controlledModel]);\n\n useEffect(() => {\n if (controlledModel === undefined) return;\n setModel(controlledModel);\n }, [controlledModel]);\n\n useEffect(() => {\n if (controlledEffort === undefined) return;\n setEffort(controlledEffort);\n }, [controlledEffort]);\n\n useEffect(() => {\n if (controlledModel !== undefined) return;\n if (!defaultModel || defaultModel === lastDefaultModel.current) return;\n lastDefaultModel.current = defaultModel;\n setModel(defaultModel);\n }, [controlledModel, defaultModel]);\n\n const selectedModel = models.find((m) => m.id === model);\n const showEffort = !selectedModel || selectedModel.reasoning;\n const resolvedAttachmentUpload = useMemo(\n () =>\n attachmentUpload ??\n createAttachmentUploadAdapter({ endpoint: attachmentsApi }),\n [attachmentUpload, attachmentsApi],\n );\n\n // A function body keeps the transport stable while always sending the latest\n // model/effort/runtime selections.\n const bodyRef = useRef<Record<string, unknown>>({});\n bodyRef.current = {\n ...body,\n ...(model ? { model } : {}),\n ...(selectedModel?.runtime ? { runtime: selectedModel.runtime } : {}),\n ...(effort ? { reasoningEffort: effort } : {}),\n ...(temperature !== undefined ? { temperature } : {}),\n ...(budget && (budget.cost !== undefined || budget.maxTokens !== undefined)\n ? { budget }\n : {}),\n ...(permissionMode ? { permissionMode } : {}),\n ...(threadId ? { threadId } : {}),\n };\n\n const resolvedTransport = useMemo<ChatTransport<UIMessage>>(\n () =>\n transport ??\n new DefaultChatTransport({ api, body: () => bodyRef.current }),\n [transport, api],\n );\n\n const {\n messages,\n sendMessage,\n regenerate,\n addToolApprovalResponse,\n status,\n error,\n clearError,\n stop,\n } = useChat<ChatUIMessage>({\n transport: resolvedTransport,\n sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithApprovalResponses,\n ...(initialMessages\n ? { messages: initialMessages as ChatUIMessage[] }\n : {}),\n });\n\n useEffect(() => {\n if (!initialPrompt || status !== \"ready\") return;\n if (sentInitialPromptId.current === initialPrompt.id) return;\n const text = initialPrompt.text.trim();\n if (!text) return;\n sentInitialPromptId.current = initialPrompt.id;\n void sendMessage({ text });\n onInitialPromptSent?.();\n }, [initialPrompt, onInitialPromptSent, sendMessage, status]);\n\n // Surface a usage snapshot after each settled assistant turn. The backend\n // rides usage/cost on the finish part's messageMetadata; we read it off the\n // last assistant message and resolve maxTokens from the selected model.\n const onUsageRef = useRef(onUsage);\n onUsageRef.current = onUsage;\n useEffect(() => {\n if (status !== \"ready\") return;\n const last = [...messages].reverse().find((m) => m.role === \"assistant\");\n const meta = last?.metadata;\n if (!meta) return;\n const cost =\n meta.threadCostUsd ?? meta.costBreakdown?.totalUsd ?? meta.cost;\n const snapshot: ChatUsageSummary = {\n usedTokens: meta.contextTokens ?? meta.usage?.totalTokens ?? 0,\n maxTokens: selectedModel?.contextWindow ?? 0,\n messageCount: messages.length,\n ...(cost != null ? { cost } : {}),\n ...(meta.usage ? { usage: meta.usage } : {}),\n ...(meta.costBreakdown ? { costBreakdown: meta.costBreakdown } : {}),\n ...(selectedModel?.label ? { modelLabel: selectedModel.label } : {}),\n };\n setUsage(snapshot);\n onUsageRef.current?.(snapshot);\n }, [messages, status, selectedModel]);\n\n const onModelSelect = (id: string) => {\n setModel(id);\n onModelChange?.(id);\n };\n\n const onEffortSelect = (next: string) => {\n setEffort(next);\n onReasoningEffortChange?.(next);\n };\n\n const resolveToolApproval = async (\n id: string,\n approved: boolean,\n reason?: string,\n ) => {\n setApprovalError(undefined);\n if (approvalApi) {\n try {\n await postToolApproval({\n approvalApi,\n threadId: threadId ?? \"\",\n approvalId: id,\n approved,\n ...(reason ? { reason } : {}),\n });\n } catch (cause) {\n setApprovalError(\n cause instanceof Error ? cause : new Error(String(cause)),\n );\n return;\n }\n }\n await addToolApprovalResponse(\n reason ? { id, approved, reason } : { id, approved },\n );\n };\n\n const ModelGlyph = providerIcon(selectedModel?.provider);\n const contextWindow = selectedModel?.contextWindow ?? usage?.maxTokens ?? 0;\n const usedTokens = usage?.usedTokens ?? 0;\n const showContextMeter = Boolean(threadId || selectedModel || usage);\n const toolbar =\n models.length > 0 || showEffort || showContextMeter ? (\n <div className=\"flex flex-1 items-center gap-2\">\n <ModelSelector models={models} value={model} onChange={onModelSelect} />\n {showEffort && (\n <EffortSelector\n efforts={reasoningEfforts}\n value={effort}\n onChange={onEffortSelect}\n />\n )}\n {showContextMeter && (\n <>\n <div className=\"flex-1\" />\n <ContextMeter\n mode=\"gauge\"\n usedPercent={\n contextWindow > 0\n ? Math.round((usedTokens / contextWindow) * 100)\n : 0\n }\n usedTokens={usedTokens}\n {...(contextWindow > 0 ? { windowTokens: contextWindow } : {})}\n {...(usage?.messageCount != null\n ? { messageCount: usage.messageCount }\n : {})}\n {...(usage?.cost != null ? { cost: { total: usage.cost } } : {})}\n {...(threadId ? { sessionId: threadId } : {})}\n {...(selectedModel?.label\n ? { model: selectedModel.label }\n : usage?.modelLabel\n ? { model: usage.modelLabel }\n : {})}\n {...(effort ? { effort } : {})}\n {...(selectedModel?.runtime?.mode\n ? { executionMode: selectedModel.runtime.mode }\n : {})}\n {...(ModelGlyph ? { modelIcon: ModelGlyph } : {})}\n {...(selectedModel?.provider\n ? {\n modelIconClassName: providerIconColor(\n selectedModel.provider,\n ),\n }\n : {})}\n />\n </>\n )}\n </div>\n ) : undefined;\n\n const empty =\n messages.length === 0 && (emptyState || suggestions?.length) ? (\n <div className=\"flex flex-col items-center gap-4\">\n {emptyState}\n {suggestions && suggestions.length > 0 && (\n <Suggestions\n suggestions={suggestions}\n onSelect={(text) => void sendMessage({ text })}\n />\n )}\n </div>\n ) : undefined;\n\n return (\n <div className={cn(\"flex h-full flex-col\", className)}>\n <Conversation\n messages={messages}\n status={status}\n error={approvalError ?? error}\n onClearError={() => {\n setApprovalError(undefined);\n clearError();\n }}\n {...(threadId ? { sessionId: threadId } : {})}\n {...(model ? { model } : {})}\n emptyState={empty}\n onRegenerate={(messageId) => void regenerate({ messageId })}\n onApprove={(id, approved, reason) =>\n void resolveToolApproval(id, approved, reason)\n }\n {...(renderToolResult ? { renderToolResult } : {})}\n />\n <div className=\"p-4 pt-0\">\n <PromptInput\n status={status}\n onStop={() => void stop()}\n placeholder={placeholder}\n enableAttachments={enableAttachments}\n attachmentUpload={resolvedAttachmentUpload}\n {...(selectedModel?.inputMediaTypes\n ? { acceptedMediaTypes: selectedModel.inputMediaTypes }\n : {})}\n {...(attachmentLimits ? { attachmentLimits } : {})}\n toolbar={toolbar}\n onSubmit={(text, files) => void sendMessage({ text, files })}\n />\n </div>\n </div>\n );\n}\n"],"names":["DEFAULT_REASONING_EFFORTS","attachmentUpload","models","useState","useRef","useEffect","defaultChatModelId","useMemo","createAttachmentUploadAdapter","DefaultChatTransport","useChat","lastAssistantMessageIsCompleteWithApprovalResponses","_a","postToolApproval","providerIcon","jsxs","jsx","ModelSelector","EffortSelector","Fragment","ContextMeter","providerIconColor","Suggestions","cn","Conversation","PromptInput"],"mappings":"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"}
|
package/dist/data/chat/Chat.d.ts
CHANGED
|
@@ -46,6 +46,9 @@ export type ChatProps = {
|
|
|
46
46
|
attachmentLimits?: AttachmentLimits;
|
|
47
47
|
/** Thread id to persist this conversation under (forwarded in the body). */
|
|
48
48
|
threadId?: string;
|
|
49
|
+
/** Base endpoint for resolving a tool approval while the provider stream is
|
|
50
|
+
* still active. The thread and approval ids are appended to this URL. */
|
|
51
|
+
approvalApi?: string | null;
|
|
49
52
|
/** Optional host renderer for recognized completed tool outputs. */
|
|
50
53
|
renderToolResult?: ToolResultRenderer;
|
|
51
54
|
/** Extra fields merged into every request body. */
|
|
@@ -70,5 +73,5 @@ export type ChatProps = {
|
|
|
70
73
|
* per-message copy/regenerate, and human-in-the-loop tool approvals. The
|
|
71
74
|
* backend owns model selection and tool execution; the selected model,
|
|
72
75
|
* effort, permission mode and thread id are forwarded in the request body. */
|
|
73
|
-
export declare function Chat({ api, models: modelsProp, modelsApi, defaultModel, model: controlledModel, reasoningEfforts, defaultReasoningEffort, reasoningEffort: controlledEffort, temperature, budget, permissionMode, onModelChange, onReasoningEffortChange, onUsage, suggestions, enableAttachments, attachmentsApi, attachmentUpload, attachmentLimits, threadId, renderToolResult, body, transport, initialMessages, initialPrompt, onInitialPromptSent, placeholder, emptyState, className, }: ChatProps): import("react/jsx-runtime").JSX.Element;
|
|
76
|
+
export declare function Chat({ api, models: modelsProp, modelsApi, defaultModel, model: controlledModel, reasoningEfforts, defaultReasoningEffort, reasoningEffort: controlledEffort, temperature, budget, permissionMode, onModelChange, onReasoningEffortChange, onUsage, suggestions, enableAttachments, attachmentsApi, attachmentUpload, attachmentLimits, threadId, approvalApi, renderToolResult, body, transport, initialMessages, initialPrompt, onInitialPromptSent, placeholder, emptyState, className, }: ChatProps): import("react/jsx-runtime").JSX.Element;
|
|
74
77
|
//# sourceMappingURL=Chat.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Chat.d.ts","sourceRoot":"","sources":["../../../src/data/chat/Chat.tsx"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,aAAa,EAClB,KAAK,SAAS,EACf,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"Chat.d.ts","sourceRoot":"","sources":["../../../src/data/chat/Chat.tsx"],"names":[],"mappings":"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"}
|
package/dist/data/chat/Chat.js
CHANGED
|
@@ -11,6 +11,7 @@ import { providerIcon, providerIconColor } from "./provider-icons.js";
|
|
|
11
11
|
import { ContextMeter } from "./ContextMeter.js";
|
|
12
12
|
import { DEFAULT_REASONING_EFFORTS } from "./effort-icons.js";
|
|
13
13
|
import { defaultChatModelId } from "./models.js";
|
|
14
|
+
import { postToolApproval } from "./approval.js";
|
|
14
15
|
import { createAttachmentUploadAdapter } from "./attachment-upload.js";
|
|
15
16
|
function Chat({
|
|
16
17
|
api = "/api/chat",
|
|
@@ -33,6 +34,7 @@ function Chat({
|
|
|
33
34
|
attachmentUpload,
|
|
34
35
|
attachmentLimits,
|
|
35
36
|
threadId,
|
|
37
|
+
approvalApi = null,
|
|
36
38
|
renderToolResult,
|
|
37
39
|
body,
|
|
38
40
|
transport,
|
|
@@ -43,10 +45,16 @@ function Chat({
|
|
|
43
45
|
emptyState,
|
|
44
46
|
className
|
|
45
47
|
}) {
|
|
48
|
+
var _a;
|
|
46
49
|
const [models, setModels] = useState(modelsProp ?? []);
|
|
47
|
-
const [model, setModel] = useState(
|
|
48
|
-
|
|
50
|
+
const [model, setModel] = useState(
|
|
51
|
+
controlledModel ?? defaultModel
|
|
52
|
+
);
|
|
53
|
+
const [effort, setEffort] = useState(
|
|
54
|
+
controlledEffort ?? defaultReasoningEffort
|
|
55
|
+
);
|
|
49
56
|
const [usage, setUsage] = useState(null);
|
|
57
|
+
const [approvalError, setApprovalError] = useState();
|
|
50
58
|
const lastDefaultModel = useRef(defaultModel);
|
|
51
59
|
const sentInitialPromptId = useRef(null);
|
|
52
60
|
useEffect(() => {
|
|
@@ -57,11 +65,15 @@ function Chat({
|
|
|
57
65
|
useEffect(() => {
|
|
58
66
|
if (modelsProp || !modelsApi) return;
|
|
59
67
|
let cancelled = false;
|
|
60
|
-
fetch(modelsApi).then(
|
|
68
|
+
fetch(modelsApi).then(
|
|
69
|
+
(r) => r.ok ? r.json() : Promise.reject(new Error(`models ${r.status}`))
|
|
70
|
+
).then((data) => {
|
|
61
71
|
if (cancelled) return;
|
|
62
72
|
setModels(data);
|
|
63
73
|
setModel((m) => m ?? controlledModel ?? defaultChatModelId(data));
|
|
64
|
-
}).catch(
|
|
74
|
+
}).catch(
|
|
75
|
+
(err) => console.warn("clicky-ui: failed to load chat models", err)
|
|
76
|
+
);
|
|
65
77
|
return () => {
|
|
66
78
|
cancelled = true;
|
|
67
79
|
};
|
|
@@ -90,6 +102,7 @@ function Chat({
|
|
|
90
102
|
bodyRef.current = {
|
|
91
103
|
...body,
|
|
92
104
|
...model ? { model } : {},
|
|
105
|
+
...(selectedModel == null ? void 0 : selectedModel.runtime) ? { runtime: selectedModel.runtime } : {},
|
|
93
106
|
...effort ? { reasoningEffort: effort } : {},
|
|
94
107
|
...temperature !== void 0 ? { temperature } : {},
|
|
95
108
|
...budget && (budget.cost !== void 0 || budget.maxTokens !== void 0) ? { budget } : {},
|
|
@@ -100,7 +113,16 @@ function Chat({
|
|
|
100
113
|
() => transport ?? new DefaultChatTransport({ api, body: () => bodyRef.current }),
|
|
101
114
|
[transport, api]
|
|
102
115
|
);
|
|
103
|
-
const {
|
|
116
|
+
const {
|
|
117
|
+
messages,
|
|
118
|
+
sendMessage,
|
|
119
|
+
regenerate,
|
|
120
|
+
addToolApprovalResponse,
|
|
121
|
+
status,
|
|
122
|
+
error,
|
|
123
|
+
clearError,
|
|
124
|
+
stop
|
|
125
|
+
} = useChat({
|
|
104
126
|
transport: resolvedTransport,
|
|
105
127
|
sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithApprovalResponses,
|
|
106
128
|
...initialMessages ? { messages: initialMessages } : {}
|
|
@@ -117,12 +139,12 @@ function Chat({
|
|
|
117
139
|
const onUsageRef = useRef(onUsage);
|
|
118
140
|
onUsageRef.current = onUsage;
|
|
119
141
|
useEffect(() => {
|
|
120
|
-
var
|
|
142
|
+
var _a2, _b, _c;
|
|
121
143
|
if (status !== "ready") return;
|
|
122
144
|
const last = [...messages].reverse().find((m) => m.role === "assistant");
|
|
123
145
|
const meta = last == null ? void 0 : last.metadata;
|
|
124
146
|
if (!meta) return;
|
|
125
|
-
const cost = meta.threadCostUsd ?? ((
|
|
147
|
+
const cost = meta.threadCostUsd ?? ((_a2 = meta.costBreakdown) == null ? void 0 : _a2.totalUsd) ?? meta.cost;
|
|
126
148
|
const snapshot = {
|
|
127
149
|
usedTokens: meta.contextTokens ?? ((_b = meta.usage) == null ? void 0 : _b.totalTokens) ?? 0,
|
|
128
150
|
maxTokens: (selectedModel == null ? void 0 : selectedModel.contextWindow) ?? 0,
|
|
@@ -143,32 +165,76 @@ function Chat({
|
|
|
143
165
|
setEffort(next);
|
|
144
166
|
onReasoningEffortChange == null ? void 0 : onReasoningEffortChange(next);
|
|
145
167
|
};
|
|
168
|
+
const resolveToolApproval = async (id, approved, reason) => {
|
|
169
|
+
setApprovalError(void 0);
|
|
170
|
+
if (approvalApi) {
|
|
171
|
+
try {
|
|
172
|
+
await postToolApproval({
|
|
173
|
+
approvalApi,
|
|
174
|
+
threadId: threadId ?? "",
|
|
175
|
+
approvalId: id,
|
|
176
|
+
approved,
|
|
177
|
+
...reason ? { reason } : {}
|
|
178
|
+
});
|
|
179
|
+
} catch (cause) {
|
|
180
|
+
setApprovalError(
|
|
181
|
+
cause instanceof Error ? cause : new Error(String(cause))
|
|
182
|
+
);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
await addToolApprovalResponse(
|
|
187
|
+
reason ? { id, approved, reason } : { id, approved }
|
|
188
|
+
);
|
|
189
|
+
};
|
|
146
190
|
const ModelGlyph = providerIcon(selectedModel == null ? void 0 : selectedModel.provider);
|
|
147
|
-
const
|
|
191
|
+
const contextWindow = (selectedModel == null ? void 0 : selectedModel.contextWindow) ?? (usage == null ? void 0 : usage.maxTokens) ?? 0;
|
|
192
|
+
const usedTokens = (usage == null ? void 0 : usage.usedTokens) ?? 0;
|
|
193
|
+
const showContextMeter = Boolean(threadId || selectedModel || usage);
|
|
194
|
+
const toolbar = models.length > 0 || showEffort || showContextMeter ? /* @__PURE__ */ jsxs("div", { className: "flex flex-1 items-center gap-2", children: [
|
|
148
195
|
/* @__PURE__ */ jsx(ModelSelector, { models, value: model, onChange: onModelSelect }),
|
|
149
|
-
showEffort && /* @__PURE__ */ jsx(
|
|
150
|
-
|
|
196
|
+
showEffort && /* @__PURE__ */ jsx(
|
|
197
|
+
EffortSelector,
|
|
198
|
+
{
|
|
199
|
+
efforts: reasoningEfforts,
|
|
200
|
+
value: effort,
|
|
201
|
+
onChange: onEffortSelect
|
|
202
|
+
}
|
|
203
|
+
),
|
|
204
|
+
showContextMeter && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
151
205
|
/* @__PURE__ */ jsx("div", { className: "flex-1" }),
|
|
152
206
|
/* @__PURE__ */ jsx(
|
|
153
207
|
ContextMeter,
|
|
154
208
|
{
|
|
155
209
|
mode: "gauge",
|
|
156
|
-
usedPercent: Math.round(
|
|
157
|
-
usedTokens
|
|
158
|
-
windowTokens:
|
|
159
|
-
...usage.messageCount != null ? { messageCount: usage.messageCount } : {},
|
|
160
|
-
...usage.cost != null ? { cost: { total: usage.cost } } : {},
|
|
161
|
-
...
|
|
210
|
+
usedPercent: contextWindow > 0 ? Math.round(usedTokens / contextWindow * 100) : 0,
|
|
211
|
+
usedTokens,
|
|
212
|
+
...contextWindow > 0 ? { windowTokens: contextWindow } : {},
|
|
213
|
+
...(usage == null ? void 0 : usage.messageCount) != null ? { messageCount: usage.messageCount } : {},
|
|
214
|
+
...(usage == null ? void 0 : usage.cost) != null ? { cost: { total: usage.cost } } : {},
|
|
215
|
+
...threadId ? { sessionId: threadId } : {},
|
|
216
|
+
...(selectedModel == null ? void 0 : selectedModel.label) ? { model: selectedModel.label } : (usage == null ? void 0 : usage.modelLabel) ? { model: usage.modelLabel } : {},
|
|
162
217
|
...effort ? { effort } : {},
|
|
218
|
+
...((_a = selectedModel == null ? void 0 : selectedModel.runtime) == null ? void 0 : _a.mode) ? { executionMode: selectedModel.runtime.mode } : {},
|
|
163
219
|
...ModelGlyph ? { modelIcon: ModelGlyph } : {},
|
|
164
|
-
...(selectedModel == null ? void 0 : selectedModel.provider) ? {
|
|
220
|
+
...(selectedModel == null ? void 0 : selectedModel.provider) ? {
|
|
221
|
+
modelIconClassName: providerIconColor(
|
|
222
|
+
selectedModel.provider
|
|
223
|
+
)
|
|
224
|
+
} : {}
|
|
165
225
|
}
|
|
166
226
|
)
|
|
167
227
|
] })
|
|
168
228
|
] }) : void 0;
|
|
169
229
|
const empty = messages.length === 0 && (emptyState || (suggestions == null ? void 0 : suggestions.length)) ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-4", children: [
|
|
170
230
|
emptyState,
|
|
171
|
-
suggestions && suggestions.length > 0 && /* @__PURE__ */ jsx(
|
|
231
|
+
suggestions && suggestions.length > 0 && /* @__PURE__ */ jsx(
|
|
232
|
+
Suggestions,
|
|
233
|
+
{
|
|
234
|
+
suggestions,
|
|
235
|
+
onSelect: (text) => void sendMessage({ text })
|
|
236
|
+
}
|
|
237
|
+
)
|
|
172
238
|
] }) : void 0;
|
|
173
239
|
return /* @__PURE__ */ jsxs("div", { className: cn("flex h-full flex-col", className), children: [
|
|
174
240
|
/* @__PURE__ */ jsx(
|
|
@@ -176,13 +242,16 @@ function Chat({
|
|
|
176
242
|
{
|
|
177
243
|
messages,
|
|
178
244
|
status,
|
|
179
|
-
error,
|
|
180
|
-
onClearError:
|
|
245
|
+
error: approvalError ?? error,
|
|
246
|
+
onClearError: () => {
|
|
247
|
+
setApprovalError(void 0);
|
|
248
|
+
clearError();
|
|
249
|
+
},
|
|
181
250
|
...threadId ? { sessionId: threadId } : {},
|
|
182
251
|
...model ? { model } : {},
|
|
183
252
|
emptyState: empty,
|
|
184
253
|
onRegenerate: (messageId) => void regenerate({ messageId }),
|
|
185
|
-
onApprove: (id, approved, reason) => void
|
|
254
|
+
onApprove: (id, approved, reason) => void resolveToolApproval(id, approved, reason),
|
|
186
255
|
...renderToolResult ? { renderToolResult } : {}
|
|
187
256
|
}
|
|
188
257
|
),
|