@4djs/assistant 0.0.0 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. package/README.md +49 -68
  2. package/dist/core/chat-activity.d.ts +19 -0
  3. package/dist/core/chat-activity.d.ts.map +1 -0
  4. package/dist/core/chat-commands.d.ts +33 -0
  5. package/dist/core/chat-commands.d.ts.map +1 -0
  6. package/dist/core/chat-history.d.ts +14 -0
  7. package/dist/core/chat-history.d.ts.map +1 -0
  8. package/dist/core/chat-reply-suggestions-parse.d.ts +20 -0
  9. package/dist/core/chat-reply-suggestions-parse.d.ts.map +1 -0
  10. package/dist/core/code-highlight.d.ts +3 -0
  11. package/dist/core/code-highlight.d.ts.map +1 -0
  12. package/dist/core/create-assistant-store.d.ts +33 -0
  13. package/dist/core/create-assistant-store.d.ts.map +1 -0
  14. package/dist/core/fetch-suggested-prompts.d.ts +11 -0
  15. package/dist/core/fetch-suggested-prompts.d.ts.map +1 -0
  16. package/dist/core/index.d.ts +19 -0
  17. package/dist/core/index.d.ts.map +1 -0
  18. package/dist/core/index.js +2876 -0
  19. package/dist/core/interactive-tools/choices.d.ts +22 -0
  20. package/dist/core/interactive-tools/choices.d.ts.map +1 -0
  21. package/dist/core/interactive-tools/confirmation.d.ts +15 -0
  22. package/dist/core/interactive-tools/confirmation.d.ts.map +1 -0
  23. package/dist/core/interactive-tools/constants.d.ts +6 -0
  24. package/dist/core/interactive-tools/constants.d.ts.map +1 -0
  25. package/dist/core/interactive-tools/execute.d.ts +11 -0
  26. package/dist/core/interactive-tools/execute.d.ts.map +1 -0
  27. package/dist/core/interactive-tools/index.d.ts +7 -0
  28. package/dist/core/interactive-tools/index.d.ts.map +1 -0
  29. package/dist/core/interactive-tools/suggestions.d.ts +13 -0
  30. package/dist/core/interactive-tools/suggestions.d.ts.map +1 -0
  31. package/dist/core/interactive-tools/waiters.d.ts +4 -0
  32. package/dist/core/interactive-tools/waiters.d.ts.map +1 -0
  33. package/dist/core/llm-chat.d.ts +96 -0
  34. package/dist/core/llm-chat.d.ts.map +1 -0
  35. package/dist/core/llm-config.d.ts +24 -0
  36. package/dist/core/llm-config.d.ts.map +1 -0
  37. package/dist/core/llm-models.d.ts +14 -0
  38. package/dist/core/llm-models.d.ts.map +1 -0
  39. package/dist/core/llm-provider.d.ts +13 -0
  40. package/dist/core/llm-provider.d.ts.map +1 -0
  41. package/dist/core/llm-settings-storage.d.ts +47 -0
  42. package/dist/core/llm-settings-storage.d.ts.map +1 -0
  43. package/dist/core/llm-sse.d.ts +13 -0
  44. package/dist/core/llm-sse.d.ts.map +1 -0
  45. package/dist/core/llm-types.d.ts +49 -0
  46. package/dist/core/llm-types.d.ts.map +1 -0
  47. package/dist/core/markdown-utils.d.ts +3 -0
  48. package/dist/core/markdown-utils.d.ts.map +1 -0
  49. package/dist/core/prepare-markdown.d.ts +7 -0
  50. package/dist/core/prepare-markdown.d.ts.map +1 -0
  51. package/dist/core/types.d.ts +74 -0
  52. package/dist/core/types.d.ts.map +1 -0
  53. package/dist/index.css +1195 -0
  54. package/dist/index.js +184948 -0
  55. package/dist/react/Assistant.d.ts +10 -0
  56. package/dist/react/Assistant.d.ts.map +1 -0
  57. package/dist/react/components/HighlightedJsonCode.d.ts +6 -0
  58. package/dist/react/components/HighlightedJsonCode.d.ts.map +1 -0
  59. package/dist/react/components/MarkdownContent.d.ts +10 -0
  60. package/dist/react/components/MarkdownContent.d.ts.map +1 -0
  61. package/dist/react/components/MarkdownEditor.d.ts +11 -0
  62. package/dist/react/components/MarkdownEditor.d.ts.map +1 -0
  63. package/dist/react/components/MermaidDiagram.d.ts +8 -0
  64. package/dist/react/components/MermaidDiagram.d.ts.map +1 -0
  65. package/dist/react/components/ModelSelector.d.ts +8 -0
  66. package/dist/react/components/ModelSelector.d.ts.map +1 -0
  67. package/dist/react/components/chat/AssistantErrorCallout.d.ts +11 -0
  68. package/dist/react/components/chat/AssistantErrorCallout.d.ts.map +1 -0
  69. package/dist/react/components/chat/ChatActivity.d.ts +8 -0
  70. package/dist/react/components/chat/ChatActivity.d.ts.map +1 -0
  71. package/dist/react/components/chat/ChatComposer.d.ts +36 -0
  72. package/dist/react/components/chat/ChatComposer.d.ts.map +1 -0
  73. package/dist/react/components/chat/ChatEmptyState.d.ts +10 -0
  74. package/dist/react/components/chat/ChatEmptyState.d.ts.map +1 -0
  75. package/dist/react/components/chat/ChatInteractivePrompt/choices-prompt.d.ts +7 -0
  76. package/dist/react/components/chat/ChatInteractivePrompt/choices-prompt.d.ts.map +1 -0
  77. package/dist/react/components/chat/ChatInteractivePrompt/confirmation-prompt.d.ts +7 -0
  78. package/dist/react/components/chat/ChatInteractivePrompt/confirmation-prompt.d.ts.map +1 -0
  79. package/dist/react/components/chat/ChatInteractivePrompt/index.d.ts +7 -0
  80. package/dist/react/components/chat/ChatInteractivePrompt/index.d.ts.map +1 -0
  81. package/dist/react/components/chat/ChatInteractivePrompt/shell.d.ts +13 -0
  82. package/dist/react/components/chat/ChatInteractivePrompt/shell.d.ts.map +1 -0
  83. package/dist/react/components/chat/ChatInteractivePrompt/utils.d.ts +4 -0
  84. package/dist/react/components/chat/ChatInteractivePrompt/utils.d.ts.map +1 -0
  85. package/dist/react/components/chat/ChatMessage.d.ts +11 -0
  86. package/dist/react/components/chat/ChatMessage.d.ts.map +1 -0
  87. package/dist/react/components/chat/ChatMessageScroll.d.ts +8 -0
  88. package/dist/react/components/chat/ChatMessageScroll.d.ts.map +1 -0
  89. package/dist/react/components/chat/ChatReplySuggestions.d.ts +9 -0
  90. package/dist/react/components/chat/ChatReplySuggestions.d.ts.map +1 -0
  91. package/dist/react/components/chat/ComposerCommandMenu.d.ts +10 -0
  92. package/dist/react/components/chat/ComposerCommandMenu.d.ts.map +1 -0
  93. package/dist/react/components/chat/LlmSettingsStrip.d.ts +7 -0
  94. package/dist/react/components/chat/LlmSettingsStrip.d.ts.map +1 -0
  95. package/dist/react/components/chat/LlmSetupPrompt.d.ts +7 -0
  96. package/dist/react/components/chat/LlmSetupPrompt.d.ts.map +1 -0
  97. package/dist/react/components/chat/LlmUnavailableBanner.d.ts +6 -0
  98. package/dist/react/components/chat/LlmUnavailableBanner.d.ts.map +1 -0
  99. package/dist/react/components/chat/SuggestedPromptsList.d.ts +14 -0
  100. package/dist/react/components/chat/SuggestedPromptsList.d.ts.map +1 -0
  101. package/dist/react/components/chat/SuggestedPromptsStrip.d.ts +11 -0
  102. package/dist/react/components/chat/SuggestedPromptsStrip.d.ts.map +1 -0
  103. package/dist/react/components/chat/SystemPromptField.d.ts +10 -0
  104. package/dist/react/components/chat/SystemPromptField.d.ts.map +1 -0
  105. package/dist/react/components/highlighted-code.d.ts +8 -0
  106. package/dist/react/components/highlighted-code.d.ts.map +1 -0
  107. package/dist/react/context.d.ts +11 -0
  108. package/dist/react/context.d.ts.map +1 -0
  109. package/dist/react/hooks/use-composer-commands.d.ts +21 -0
  110. package/dist/react/hooks/use-composer-commands.d.ts.map +1 -0
  111. package/dist/react/hooks/use-suggested-prompts.d.ts +29 -0
  112. package/dist/react/hooks/use-suggested-prompts.d.ts.map +1 -0
  113. package/dist/react/index.d.ts +17 -0
  114. package/dist/react/index.d.ts.map +1 -0
  115. package/dist/react/lib/parse-assistant-error.d.ts +9 -0
  116. package/dist/react/lib/parse-assistant-error.d.ts.map +1 -0
  117. package/dist/react/lib/prompt-icons.d.ts +5 -0
  118. package/dist/react/lib/prompt-icons.d.ts.map +1 -0
  119. package/dist/react/types.d.ts +69 -0
  120. package/dist/react/types.d.ts.map +1 -0
  121. package/dist/react/utils/cn.d.ts +2 -0
  122. package/dist/react/utils/cn.d.ts.map +1 -0
  123. package/package.json +16 -5
  124. package/src/core/chat-activity.ts +0 -107
  125. package/src/core/chat-commands.ts +0 -173
  126. package/src/core/chat-history.ts +0 -113
  127. package/src/core/chat-reply-suggestions-parse.ts +0 -119
  128. package/src/core/code-highlight.ts +0 -20
  129. package/src/core/create-assistant-store.ts +0 -639
  130. package/src/core/fetch-suggested-prompts.ts +0 -53
  131. package/src/core/index.ts +0 -125
  132. package/src/core/interactive-tools/choices.ts +0 -155
  133. package/src/core/interactive-tools/confirmation.ts +0 -63
  134. package/src/core/interactive-tools/constants.ts +0 -22
  135. package/src/core/interactive-tools/execute.ts +0 -70
  136. package/src/core/interactive-tools/index.ts +0 -41
  137. package/src/core/interactive-tools/suggestions.ts +0 -87
  138. package/src/core/interactive-tools/waiters.ts +0 -55
  139. package/src/core/llm-chat.ts +0 -686
  140. package/src/core/llm-config.ts +0 -101
  141. package/src/core/llm-models.ts +0 -96
  142. package/src/core/llm-provider.ts +0 -99
  143. package/src/core/llm-settings-storage.ts +0 -331
  144. package/src/core/llm-sse.ts +0 -166
  145. package/src/core/llm-types.ts +0 -52
  146. package/src/core/markdown-utils.ts +0 -11
  147. package/src/core/prepare-markdown.ts +0 -38
  148. package/src/core/types.ts +0 -86
  149. package/src/css.d.ts +0 -1
  150. package/src/react/Assistant.tsx +0 -358
  151. package/src/react/components/HighlightedJsonCode.tsx +0 -24
  152. package/src/react/components/MarkdownContent.tsx +0 -98
  153. package/src/react/components/MarkdownEditor.tsx +0 -60
  154. package/src/react/components/MermaidDiagram.tsx +0 -139
  155. package/src/react/components/ModelSelector.tsx +0 -243
  156. package/src/react/components/chat/AssistantErrorCallout.tsx +0 -79
  157. package/src/react/components/chat/ChatActivity.tsx +0 -274
  158. package/src/react/components/chat/ChatComposer.tsx +0 -189
  159. package/src/react/components/chat/ChatEmptyState.tsx +0 -145
  160. package/src/react/components/chat/ChatInteractivePrompt/choices-prompt.tsx +0 -262
  161. package/src/react/components/chat/ChatInteractivePrompt/confirmation-prompt.tsx +0 -97
  162. package/src/react/components/chat/ChatInteractivePrompt/index.tsx +0 -60
  163. package/src/react/components/chat/ChatInteractivePrompt/shell.tsx +0 -60
  164. package/src/react/components/chat/ChatInteractivePrompt/utils.ts +0 -14
  165. package/src/react/components/chat/ChatMessage.tsx +0 -150
  166. package/src/react/components/chat/ChatMessageScroll.tsx +0 -116
  167. package/src/react/components/chat/ChatReplySuggestions.tsx +0 -231
  168. package/src/react/components/chat/ComposerCommandMenu.tsx +0 -69
  169. package/src/react/components/chat/LlmSettingsStrip.tsx +0 -348
  170. package/src/react/components/chat/LlmSetupPrompt.tsx +0 -58
  171. package/src/react/components/chat/LlmUnavailableBanner.tsx +0 -11
  172. package/src/react/components/chat/SuggestedPromptsList.tsx +0 -121
  173. package/src/react/components/chat/SuggestedPromptsStrip.tsx +0 -72
  174. package/src/react/components/chat/SystemPromptField.tsx +0 -107
  175. package/src/react/components/highlighted-code.tsx +0 -107
  176. package/src/react/context.tsx +0 -72
  177. package/src/react/hooks/use-composer-commands.ts +0 -129
  178. package/src/react/hooks/use-suggested-prompts.ts +0 -128
  179. package/src/react/index.ts +0 -39
  180. package/src/react/lib/parse-assistant-error.ts +0 -96
  181. package/src/react/lib/prompt-icons.ts +0 -40
  182. package/src/react/types.ts +0 -83
  183. package/src/react/utils/cn.ts +0 -5
  184. package/test/buildLlmHistory.test.ts +0 -95
  185. package/test/llm-config.test.ts +0 -72
  186. package/test/llmSettingsStorage.test.ts +0 -121
  187. package/test/parse-assistant-error.test.ts +0 -24
  188. package/tsconfig.json +0 -8
  189. /package/{src/styles/assistant.css → dist/styles.css} +0 -0
@@ -1,348 +0,0 @@
1
- import {
2
- ChevronDown,
3
- Loader2,
4
- PlugZap,
5
- RotateCcw,
6
- Settings2,
7
- X,
8
- } from "lucide-react";
9
- import { type FormEvent, useCallback, useEffect, useState } from "react";
10
- import type { LlmSettingsFormState } from "../../../core/llm-settings-storage.ts";
11
- import { isLlmSettingsFormDirty } from "../../../core/llm-settings-storage.ts";
12
- import { useAssistantActions } from "../../context.tsx";
13
- import { SystemPromptField } from "./SystemPromptField.tsx";
14
-
15
- interface LlmSettingsStripProps {
16
- open: boolean;
17
- onClose: () => void;
18
- }
19
-
20
- export function LlmSettingsStrip({ open, onClose }: LlmSettingsStripProps) {
21
- const {
22
- getLlmSettingsForm,
23
- saveLlmSettings,
24
- clearLlmSettings,
25
- testLlmSettings,
26
- llmSettingsHasOverrides,
27
- } = useAssistantActions();
28
-
29
- const [form, setForm] = useState<LlmSettingsFormState | null>(null);
30
- const [savedForm, setSavedForm] = useState<LlmSettingsFormState | null>(null);
31
- const [loading, setLoading] = useState(false);
32
- const [testing, setTesting] = useState(false);
33
- const [saving, setSaving] = useState(false);
34
- const [error, setError] = useState<string | null>(null);
35
- const [testResult, setTestResult] = useState<string | null>(null);
36
- const [hasOverrides, setHasOverrides] = useState(false);
37
- const [advancedOpen, setAdvancedOpen] = useState(false);
38
-
39
- const loadForm = useCallback(async () => {
40
- setLoading(true);
41
- setError(null);
42
- setTestResult(null);
43
- try {
44
- const next = await getLlmSettingsForm();
45
- setForm(next);
46
- setSavedForm(next);
47
- setHasOverrides(await llmSettingsHasOverrides());
48
- setAdvancedOpen(false);
49
- } catch (loadError) {
50
- setError(
51
- loadError instanceof Error
52
- ? loadError.message
53
- : "Failed to load LLM settings",
54
- );
55
- } finally {
56
- setLoading(false);
57
- }
58
- }, [getLlmSettingsForm, llmSettingsHasOverrides]);
59
-
60
- useEffect(() => {
61
- if (open) {
62
- void loadForm();
63
- }
64
- }, [open, loadForm]);
65
-
66
- if (!open) return null;
67
-
68
- function updateField<K extends keyof LlmSettingsFormState>(
69
- key: K,
70
- value: LlmSettingsFormState[K],
71
- ) {
72
- setForm((current) => (current ? { ...current, [key]: value } : current));
73
- setTestResult(null);
74
- setError(null);
75
- }
76
-
77
- async function handleTest() {
78
- if (!form) return;
79
- setTesting(true);
80
- setError(null);
81
- setTestResult(null);
82
- try {
83
- const result = await testLlmSettings(form);
84
- if (result.ok) {
85
- setTestResult(`Connected · ${result.model}`);
86
- } else {
87
- setError(result.error);
88
- }
89
- } finally {
90
- setTesting(false);
91
- }
92
- }
93
-
94
- async function handleSave() {
95
- if (!form || saving) return;
96
- setSaving(true);
97
- setError(null);
98
- try {
99
- await saveLlmSettings(form);
100
- onClose();
101
- } catch (saveError) {
102
- setError(
103
- saveError instanceof Error
104
- ? saveError.message
105
- : "Failed to save LLM settings",
106
- );
107
- } finally {
108
- setSaving(false);
109
- }
110
- }
111
-
112
- async function handleSubmit(event: FormEvent) {
113
- event.preventDefault();
114
- await handleSave();
115
- }
116
-
117
- async function handleReset() {
118
- if (!form) return;
119
- setSaving(true);
120
- setError(null);
121
- setTestResult(null);
122
- try {
123
- if (hasOverrides) {
124
- await clearLlmSettings();
125
- }
126
- await loadForm();
127
- } catch (resetError) {
128
- setError(
129
- resetError instanceof Error
130
- ? resetError.message
131
- : "Failed to reset LLM settings",
132
- );
133
- } finally {
134
- setSaving(false);
135
- }
136
- }
137
-
138
- const isDirty =
139
- form && savedForm ? isLlmSettingsFormDirty(form, savedForm) : false;
140
- const canReset = Boolean(hasOverrides || isDirty);
141
-
142
- const statusMessage = error ?? testResult;
143
- const statusTone = error ? "error" : testResult ? "success" : null;
144
-
145
- return (
146
- <section className="assistant-llm-settings-strip" aria-label="LLM settings">
147
- <div className="assistant-llm-settings-strip__header">
148
- <div className="assistant-llm-settings-strip__title">
149
- <Settings2 size={14} aria-hidden />
150
- <span>LLM settings</span>
151
- </div>
152
- <div className="assistant-llm-settings-strip__header-actions">
153
- <button
154
- type="button"
155
- className="assistant-btn assistant-btn--ghost assistant-llm-settings-strip__header-btn"
156
- onClick={() => void handleTest()}
157
- disabled={!form || saving || testing}
158
- aria-label="Test connection"
159
- title="Test connection"
160
- >
161
- {testing ? (
162
- <Loader2 size={14} className="assistant-icon-spin" aria-hidden />
163
- ) : (
164
- <PlugZap size={14} aria-hidden />
165
- )}
166
- </button>
167
- {canReset ? (
168
- <button
169
- type="button"
170
- className="assistant-btn assistant-btn--ghost assistant-llm-settings-strip__header-btn"
171
- onClick={() => void handleReset()}
172
- disabled={saving || testing}
173
- aria-label="Reset all settings"
174
- title="Reset all settings"
175
- >
176
- <RotateCcw size={14} aria-hidden />
177
- </button>
178
- ) : null}
179
- <button
180
- type="button"
181
- className="assistant-btn assistant-btn--ghost assistant-llm-settings-strip__header-btn"
182
- onClick={onClose}
183
- aria-label="Close LLM settings"
184
- >
185
- <X size={14} aria-hidden />
186
- </button>
187
- </div>
188
- </div>
189
-
190
- {loading ? (
191
- <div className="assistant-llm-settings-strip__loading" role="status">
192
- <Loader2 size={16} className="assistant-icon-spin" aria-hidden />
193
- Loading…
194
- </div>
195
- ) : form ? (
196
- <form
197
- className="assistant-llm-settings-strip__form"
198
- onSubmit={handleSubmit}
199
- >
200
- <div className="assistant-llm-settings-strip__fields">
201
- <label className="assistant-llm-settings-strip__field">
202
- <span className="assistant-llm-settings-strip__label">
203
- Base URL
204
- </span>
205
- <input
206
- className="assistant-input assistant-llm-settings-strip__input assistant-llm-settings-strip__input--mono"
207
- type="url"
208
- value={form.baseUrl}
209
- onChange={(event) => updateField("baseUrl", event.target.value)}
210
- placeholder="https://api.openai.com/v1"
211
- autoComplete="off"
212
- spellCheck={false}
213
- />
214
- </label>
215
-
216
- <label className="assistant-llm-settings-strip__field">
217
- <span className="assistant-llm-settings-strip__label">
218
- API key
219
- </span>
220
- <input
221
- className="assistant-input assistant-llm-settings-strip__input"
222
- type="password"
223
- value={form.apiKey}
224
- onChange={(event) => updateField("apiKey", event.target.value)}
225
- placeholder={
226
- form.hasStoredApiKey
227
- ? "Configured — leave blank to keep"
228
- : "sk-…"
229
- }
230
- autoComplete="off"
231
- spellCheck={false}
232
- />
233
- </label>
234
-
235
- <label className="assistant-llm-settings-strip__field">
236
- <span className="assistant-llm-settings-strip__label">Model</span>
237
- <input
238
- className="assistant-input assistant-llm-settings-strip__input"
239
- type="text"
240
- value={form.model}
241
- onChange={(event) => updateField("model", event.target.value)}
242
- placeholder="gpt-4o-mini"
243
- autoComplete="off"
244
- spellCheck={false}
245
- />
246
- </label>
247
-
248
- <button
249
- type="button"
250
- className="assistant-llm-settings-strip__advanced-toggle"
251
- onClick={() => setAdvancedOpen((value) => !value)}
252
- aria-expanded={advancedOpen}
253
- aria-controls="assistant-llm-settings-advanced"
254
- >
255
- <ChevronDown
256
- size={14}
257
- className={`assistant-llm-settings-strip__chevron ${advancedOpen ? "assistant-llm-settings-strip__chevron--open" : ""}`.trim()}
258
- aria-hidden
259
- />
260
- Advanced
261
- </button>
262
-
263
- {advancedOpen ? (
264
- <div
265
- id="assistant-llm-settings-advanced"
266
- className="assistant-llm-settings-strip__advanced"
267
- >
268
- <label className="assistant-llm-settings-strip__field">
269
- <span className="assistant-llm-settings-strip__label">
270
- Model list
271
- </span>
272
- <input
273
- className="assistant-input assistant-llm-settings-strip__input"
274
- type="text"
275
- value={form.modelsText}
276
- onChange={(event) =>
277
- updateField("modelsText", event.target.value)
278
- }
279
- placeholder="Optional — comma-separated"
280
- autoComplete="off"
281
- spellCheck={false}
282
- />
283
- </label>
284
-
285
- <SystemPromptField
286
- value={form.systemPrompt}
287
- defaultPrompt={form.defaultSystemPrompt}
288
- onChange={(next) => updateField("systemPrompt", next)}
289
- onReset={() => updateField("systemPrompt", "")}
290
- disabled={saving || testing}
291
- />
292
- </div>
293
- ) : null}
294
-
295
- {statusMessage ? (
296
- <p
297
- className={`assistant-llm-settings-strip__status assistant-llm-settings-strip__status--${statusTone}`.trim()}
298
- role={error ? "alert" : "status"}
299
- >
300
- {statusMessage}
301
- </p>
302
- ) : null}
303
- </div>
304
-
305
- <div className="assistant-llm-settings-strip__footer">
306
- {canReset ? (
307
- <button
308
- type="button"
309
- className="assistant-btn assistant-btn--ghost assistant-llm-settings-strip__footer-btn assistant-llm-settings-strip__footer-btn--reset"
310
- onClick={() => void handleReset()}
311
- disabled={saving || testing}
312
- >
313
- <RotateCcw size={14} aria-hidden />
314
- Reset all
315
- </button>
316
- ) : null}
317
- <button
318
- type="button"
319
- className="assistant-btn assistant-btn--ghost assistant-llm-settings-strip__footer-btn"
320
- onClick={onClose}
321
- disabled={saving}
322
- >
323
- Cancel
324
- </button>
325
- <button
326
- type="submit"
327
- className="assistant-btn assistant-btn--primary assistant-llm-settings-strip__footer-btn"
328
- disabled={saving || testing}
329
- >
330
- {saving ? (
331
- <>
332
- <Loader2
333
- size={14}
334
- className="assistant-icon-spin"
335
- aria-hidden
336
- />
337
- Saving
338
- </>
339
- ) : (
340
- "Save"
341
- )}
342
- </button>
343
- </div>
344
- </form>
345
- ) : null}
346
- </section>
347
- );
348
- }
@@ -1,58 +0,0 @@
1
- import { Settings2, Sparkles } from "lucide-react";
2
-
3
- interface LlmSetupPromptProps {
4
- variant: "banner" | "inline";
5
- onConfigure: () => void;
6
- }
7
-
8
- export function LlmSetupPrompt({ variant, onConfigure }: LlmSetupPromptProps) {
9
- if (variant === "inline") {
10
- return (
11
- <div
12
- className="assistant-llm-setup assistant-llm-setup--inline"
13
- role="status"
14
- >
15
- <p className="assistant-llm-setup__copy">
16
- <span className="assistant-llm-setup__label">LLM not connected.</span>{" "}
17
- Add a cloud or local provider in{" "}
18
- <button
19
- type="button"
20
- className="assistant-llm-setup__action"
21
- onClick={onConfigure}
22
- >
23
- LLM settings
24
- </button>
25
- .
26
- </p>
27
- </div>
28
- );
29
- }
30
-
31
- return (
32
- <div
33
- className="assistant-llm-setup assistant-llm-setup--banner"
34
- role="status"
35
- >
36
- <div className="assistant-llm-setup__row">
37
- <span className="assistant-llm-setup__badge" aria-hidden>
38
- <Sparkles size={12} strokeWidth={2} />
39
- </span>
40
- <p className="assistant-llm-setup__copy">
41
- <strong>Connect an LLM</strong>
42
- <span className="assistant-llm-setup__sep" aria-hidden>
43
- ·
44
- </span>
45
- OpenAI-compatible endpoint — cloud or local
46
- </p>
47
- <button
48
- type="button"
49
- className="assistant-llm-setup__chip"
50
- onClick={onConfigure}
51
- >
52
- <Settings2 size={12} strokeWidth={2} aria-hidden />
53
- Configure
54
- </button>
55
- </div>
56
- </div>
57
- );
58
- }
@@ -1,11 +0,0 @@
1
- import { LlmSetupPrompt } from "./LlmSetupPrompt.tsx";
2
-
3
- interface LlmUnavailableBannerProps {
4
- onConfigure: () => void;
5
- }
6
-
7
- export function LlmUnavailableBanner({
8
- onConfigure,
9
- }: LlmUnavailableBannerProps) {
10
- return <LlmSetupPrompt variant="banner" onConfigure={onConfigure} />;
11
- }
@@ -1,121 +0,0 @@
1
- import { ChevronRight } from "lucide-react";
2
- import { DEFAULT_PROMPT_ICON } from "../../lib/prompt-icons.ts";
3
- import type { AssistantSuggestedPromptWithIcon } from "../../types.ts";
4
- import { AssistantErrorCallout } from "./AssistantErrorCallout.tsx";
5
-
6
- function PromptSkeleton({
7
- index,
8
- compact,
9
- }: {
10
- index: number;
11
- compact?: boolean;
12
- }) {
13
- return (
14
- <div
15
- className={`assistant-empty-state__prompt assistant-empty-state__prompt--skeleton ${compact ? "assistant-empty-state__prompt--compact" : ""}`.trim()}
16
- style={{ animationDelay: `${index * 45}ms` }}
17
- aria-hidden
18
- >
19
- <span className="assistant-empty-state__icon assistant-empty-state__icon--skeleton" />
20
- <span className="assistant-empty-state__prompt-text">
21
- <span className="assistant-empty-state__skeleton-line assistant-empty-state__skeleton-line--title" />
22
- <span className="assistant-empty-state__skeleton-line assistant-empty-state__skeleton-line--hint" />
23
- </span>
24
- </div>
25
- );
26
- }
27
-
28
- interface SuggestedPromptsListProps {
29
- prompts: AssistantSuggestedPromptWithIcon[];
30
- loading?: boolean;
31
- error?: string | null;
32
- onSelect: (prompt: string) => void;
33
- onRetry?: () => void;
34
- retryLoading?: boolean;
35
- className?: string;
36
- compact?: boolean;
37
- }
38
-
39
- export function SuggestedPromptsList({
40
- prompts,
41
- loading,
42
- error,
43
- onSelect,
44
- onRetry,
45
- retryLoading,
46
- className,
47
- compact,
48
- }: SuggestedPromptsListProps) {
49
- if (loading) {
50
- return (
51
- <div
52
- className={`assistant-empty-state__grid ${compact ? "assistant-empty-state__grid--compact" : ""} ${className ?? ""}`.trim()}
53
- role="status"
54
- aria-live="polite"
55
- aria-busy="true"
56
- >
57
- <span className="sr-only">Loading suggestions</span>
58
- {(compact ? ["a", "b", "c"] : ["a", "b", "c", "d", "e", "f"]).map(
59
- (key, index) => (
60
- <PromptSkeleton key={key} index={index} compact={compact} />
61
- ),
62
- )}
63
- </div>
64
- );
65
- }
66
-
67
- if (error) {
68
- return (
69
- <AssistantErrorCallout
70
- error={error}
71
- context="suggestions"
72
- variant="panel"
73
- onRetry={onRetry}
74
- retryLoading={retryLoading}
75
- retryLabel="Regenerate"
76
- />
77
- );
78
- }
79
-
80
- if (prompts.length === 0) {
81
- return null;
82
- }
83
-
84
- return (
85
- <div
86
- className={`assistant-empty-state__grid ${compact ? "assistant-empty-state__grid--compact" : ""} ${className ?? ""}`.trim()}
87
- >
88
- {prompts.map(({ id, icon: Icon, label, hint, prompt }, index) => {
89
- const PromptIcon = Icon ?? DEFAULT_PROMPT_ICON;
90
- return (
91
- <button
92
- key={id}
93
- type="button"
94
- className={`assistant-empty-state__prompt ${compact ? "assistant-empty-state__prompt--compact" : ""}`.trim()}
95
- style={{ animationDelay: `${index * 45}ms` }}
96
- onClick={() => onSelect(prompt)}
97
- >
98
- <span className="assistant-empty-state__icon" aria-hidden>
99
- <PromptIcon size={14} strokeWidth={2} />
100
- </span>
101
- <span className="assistant-empty-state__prompt-text">
102
- <span className="assistant-empty-state__prompt-label">
103
- {label}
104
- </span>
105
- {hint ? (
106
- <span className="assistant-empty-state__prompt-hint">
107
- {hint}
108
- </span>
109
- ) : null}
110
- </span>
111
- <ChevronRight
112
- size={14}
113
- className="assistant-empty-state__prompt-arrow"
114
- aria-hidden
115
- />
116
- </button>
117
- );
118
- })}
119
- </div>
120
- );
121
- }
@@ -1,72 +0,0 @@
1
- import { Loader2, Sparkles, X } from "lucide-react";
2
- import type { useSuggestedPrompts } from "../../hooks/use-suggested-prompts.ts";
3
- import { SuggestedPromptsList } from "./SuggestedPromptsList.tsx";
4
-
5
- interface SuggestedPromptsStripProps {
6
- open: boolean;
7
- onClose: () => void;
8
- onRefresh: () => void;
9
- onSelect: (prompt: string) => void;
10
- suggestions: ReturnType<typeof useSuggestedPrompts>;
11
- }
12
-
13
- export function SuggestedPromptsStrip({
14
- open,
15
- onClose,
16
- onRefresh,
17
- onSelect,
18
- suggestions,
19
- }: SuggestedPromptsStripProps) {
20
- if (!open) return null;
21
-
22
- const { prompts, loading, error, hasFetched } = suggestions;
23
-
24
- return (
25
- <section
26
- className="assistant-suggestions-strip"
27
- aria-label="Suggested prompts"
28
- >
29
- <div className="assistant-suggestions-strip__header">
30
- <div className="assistant-suggestions-strip__title">
31
- <Sparkles size={14} aria-hidden />
32
- <span>Suggestions</span>
33
- </div>
34
- <div className="assistant-suggestions-strip__actions">
35
- <button
36
- type="button"
37
- className="assistant-btn assistant-btn--ghost assistant-suggestions-strip__refresh"
38
- onClick={onRefresh}
39
- disabled={loading}
40
- >
41
- {loading ? (
42
- <Loader2 size={14} className="assistant-icon-spin" aria-hidden />
43
- ) : (
44
- <Sparkles size={14} aria-hidden />
45
- )}
46
- {hasFetched ? "Regenerate" : "Generate"}
47
- </button>
48
- <button
49
- type="button"
50
- className="assistant-btn assistant-btn--ghost assistant-suggestions-strip__close"
51
- onClick={onClose}
52
- aria-label="Close suggestions"
53
- >
54
- <X size={14} aria-hidden />
55
- </button>
56
- </div>
57
- </div>
58
- <SuggestedPromptsList
59
- prompts={prompts}
60
- loading={loading}
61
- error={error}
62
- onRetry={onRefresh}
63
- retryLoading={loading}
64
- onSelect={(prompt) => {
65
- onSelect(prompt);
66
- onClose();
67
- }}
68
- compact
69
- />
70
- </section>
71
- );
72
- }