@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,40 +0,0 @@
1
- import type { LucideIcon } from "lucide-react";
2
- import {
3
- Code,
4
- Database,
5
- Layers,
6
- Search,
7
- Sparkles,
8
- Table,
9
- Terminal,
10
- Wrench,
11
- Zap,
12
- } from "lucide-react";
13
-
14
- const PROMPT_ICONS: Record<string, LucideIcon> = {
15
- database: Database,
16
- db: Database,
17
- search: Search,
18
- find: Search,
19
- terminal: Terminal,
20
- shell: Terminal,
21
- wrench: Wrench,
22
- tool: Wrench,
23
- sparkles: Sparkles,
24
- magic: Sparkles,
25
- table: Table,
26
- grid: Table,
27
- code: Code,
28
- layers: Layers,
29
- stack: Layers,
30
- zap: Zap,
31
- lightning: Zap,
32
- };
33
-
34
- export function resolvePromptIcon(name?: string): LucideIcon | undefined {
35
- if (!name) return undefined;
36
- const key = name.trim().toLowerCase();
37
- return PROMPT_ICONS[key];
38
- }
39
-
40
- export { Sparkles as DEFAULT_PROMPT_ICON };
@@ -1,83 +0,0 @@
1
- import type { LucideIcon } from "lucide-react";
2
- import type { ReactNode } from "react";
3
- import type { AssistantStore } from "../core/create-assistant-store.ts";
4
- import type {
5
- AssistantStoreDependencies,
6
- AssistantSuggestedPrompt,
7
- AssistantToolDefinition,
8
- } from "../core/types.ts";
9
-
10
- export interface AssistantSuggestedPromptWithIcon
11
- extends Omit<AssistantSuggestedPrompt, "icon"> {
12
- icon?: LucideIcon;
13
- hint?: string;
14
- }
15
-
16
- export interface AssistantEmptyStateConfig {
17
- title: string;
18
- description: string;
19
- /** Static fallback prompts when LLM is disabled or fetch fails */
20
- suggestedPrompts?: AssistantSuggestedPromptWithIcon[];
21
- /** Allow fetching contextual prompts via LLM (manual trigger; default: true) */
22
- dynamicSuggestedPrompts?: boolean;
23
- }
24
-
25
- export interface AssistantHeaderConfig {
26
- title?: string;
27
- subtitle?: string;
28
- icon?: LucideIcon;
29
- showClearButton?: boolean;
30
- /** Show button to generate LLM suggested prompts (default: true when fetchSuggestedPrompts is set) */
31
- showSuggestionsButton?: boolean;
32
- }
33
-
34
- export interface AssistantUiConfig {
35
- composerPlaceholder?: string;
36
- showModelSelector?: boolean;
37
- /** Show LLM settings button in the composer footer (default: true) */
38
- showLlmSettings?: boolean;
39
- maxWidth?: string;
40
- className?: string;
41
- }
42
-
43
- export interface AssistantConfig extends AssistantStoreDependencies {
44
- emptyState?: AssistantEmptyStateConfig;
45
- header?: AssistantHeaderConfig;
46
- ui?: AssistantUiConfig;
47
- /** Load LLM config on mount (default: true) */
48
- autoLoadLlmStatus?: boolean;
49
- /** Optional hook to fetch contextual empty-state prompts via the configured LLM */
50
- fetchSuggestedPrompts?: (ctx: {
51
- llmEnabled: boolean;
52
- model: string | null;
53
- tools: AssistantToolDefinition[];
54
- }) => Promise<
55
- Array<{
56
- id: string;
57
- label: string;
58
- description?: string;
59
- prompt: string;
60
- icon?: string;
61
- }>
62
- >;
63
- }
64
-
65
- export interface AssistantContextValue {
66
- store: AssistantStore;
67
- config: AssistantConfig;
68
- }
69
-
70
- export interface AssistantProviderProps {
71
- config: AssistantConfig;
72
- children: ReactNode;
73
- }
74
-
75
- export interface AssistantProps {
76
- className?: string;
77
- /** Override header from provider config */
78
- header?: AssistantHeaderConfig;
79
- /** Override empty state from provider config */
80
- emptyState?: AssistantEmptyStateConfig;
81
- /** Override UI options from provider config */
82
- ui?: AssistantUiConfig;
83
- }
@@ -1,5 +0,0 @@
1
- export function cn(
2
- ...classes: Array<string | false | null | undefined>
3
- ): string {
4
- return classes.filter(Boolean).join(" ");
5
- }
@@ -1,95 +0,0 @@
1
- import { expect, test } from "bun:test";
2
- import { buildLlmHistory, sanitizeLlmMessages } from "../src/core/llm-chat.ts";
3
- import type { LlmChatMessage } from "../src/core/llm-types.ts";
4
-
5
- test("buildLlmHistory keeps assistant tool_calls grouped with tool results when trimming", () => {
6
- const messages = Array.from({ length: 15 }, (_, index) => ({
7
- role: "user" as const,
8
- content: `question ${index}`,
9
- }));
10
-
11
- messages.push({
12
- role: "assistant",
13
- content: "Found users",
14
- activity: [
15
- {
16
- name: "query_entities",
17
- args: { dataClass: "User" },
18
- result: { __COUNT: 1 },
19
- },
20
- {
21
- name: "suggest_replies",
22
- args: { question: "Next?", suggestions: ["A", "B"] },
23
- result: { displayed: true },
24
- },
25
- ],
26
- });
27
-
28
- const history = buildLlmHistory(messages);
29
- expect(history[0]?.role).not.toBe("tool");
30
- expect(history.some((message) => message.role === "tool")).toBe(true);
31
-
32
- const assistantWithTools = history.find(
33
- (message) => message.role === "assistant" && message.tool_calls?.length,
34
- );
35
- expect(assistantWithTools).toBeDefined();
36
- for (const toolCall of assistantWithTools?.tool_calls ?? []) {
37
- expect(
38
- history.some(
39
- (message) =>
40
- message.role === "tool" && message.tool_call_id === toolCall.id,
41
- ),
42
- ).toBe(true);
43
- }
44
- });
45
-
46
- test("sanitizeLlmMessages drops orphan tool messages", () => {
47
- const messages: LlmChatMessage[] = [
48
- {
49
- role: "tool",
50
- tool_call_id: "call_orphan",
51
- content: "{}",
52
- },
53
- { role: "user", content: "hello" },
54
- {
55
- role: "assistant",
56
- content: null,
57
- tool_calls: [
58
- {
59
- id: "call_ok_0",
60
- type: "function",
61
- function: { name: "query_entities", arguments: "{}" },
62
- },
63
- {
64
- id: "call_ok_1",
65
- type: "function",
66
- function: { name: "suggest_replies", arguments: "{}" },
67
- },
68
- ],
69
- },
70
- { role: "tool", tool_call_id: "call_ok_0", content: "{}" },
71
- { role: "tool", tool_call_id: "call_ok_1", content: "{}" },
72
- ];
73
-
74
- expect(sanitizeLlmMessages(messages)).toEqual([
75
- { role: "user", content: "hello" },
76
- {
77
- role: "assistant",
78
- content: null,
79
- tool_calls: [
80
- {
81
- id: "call_ok_0",
82
- type: "function",
83
- function: { name: "query_entities", arguments: "{}" },
84
- },
85
- {
86
- id: "call_ok_1",
87
- type: "function",
88
- function: { name: "suggest_replies", arguments: "{}" },
89
- },
90
- ],
91
- },
92
- { role: "tool", tool_call_id: "call_ok_0", content: "{}" },
93
- { role: "tool", tool_call_id: "call_ok_1", content: "{}" },
94
- ]);
95
- });
@@ -1,72 +0,0 @@
1
- import { describe, expect, test } from "bun:test";
2
- import {
3
- isLlmConfigured,
4
- isLlmUnavailableMessage,
5
- isLocalLlmBaseUrl,
6
- } from "../src/core/llm-config.ts";
7
-
8
- describe("isLocalLlmBaseUrl", () => {
9
- test("detects localhost providers", () => {
10
- expect(isLocalLlmBaseUrl("http://127.0.0.1:11434/v1")).toBe(true);
11
- expect(isLocalLlmBaseUrl("http://localhost:1234/v1")).toBe(true);
12
- });
13
-
14
- test("rejects remote providers", () => {
15
- expect(isLocalLlmBaseUrl("https://api.openai.com/v1")).toBe(false);
16
- });
17
- });
18
-
19
- describe("isLlmConfigured", () => {
20
- test("requires an api key for remote providers", () => {
21
- expect(
22
- isLlmConfigured({
23
- enabled: true,
24
- baseUrl: "https://api.openai.com/v1",
25
- apiKey: null,
26
- model: "gpt-4o-mini",
27
- }),
28
- ).toBe(false);
29
- });
30
-
31
- test("allows local providers without an api key", () => {
32
- expect(
33
- isLlmConfigured({
34
- enabled: true,
35
- baseUrl: "http://127.0.0.1:11434/v1",
36
- apiKey: null,
37
- model: "llama3.2",
38
- }),
39
- ).toBe(true);
40
- });
41
-
42
- test("accepts remote providers with an api key", () => {
43
- expect(
44
- isLlmConfigured({
45
- enabled: true,
46
- baseUrl: "https://api.openai.com/v1",
47
- apiKey: "sk-test",
48
- model: "gpt-4o-mini",
49
- }),
50
- ).toBe(true);
51
- });
52
- });
53
-
54
- describe("isLlmUnavailableMessage", () => {
55
- test("detects explicit setup flag", () => {
56
- expect(
57
- isLlmUnavailableMessage({
58
- content: "anything",
59
- llmSetupRequired: true,
60
- }),
61
- ).toBe(true);
62
- });
63
-
64
- test("detects legacy plain-text content", () => {
65
- expect(
66
- isLlmUnavailableMessage({
67
- content:
68
- "Chat requires an LLM. Open LLM settings to add your provider base URL, model, and API key (optional for local servers).",
69
- }),
70
- ).toBe(true);
71
- });
72
- });
@@ -1,121 +0,0 @@
1
- import { expect, test } from "bun:test";
2
- import {
3
- assistantToStored,
4
- createDefaultStoredSettings,
5
- isLlmSettingsFormDirty,
6
- mergeLlmSettings,
7
- normalizeStoredSettings,
8
- normalizeStoredSystemPrompt,
9
- resolveSelectedModel,
10
- storedSettingsHaveOverrides,
11
- storedToAssistant,
12
- toStoredSettings,
13
- } from "../src/core/llm-settings-storage.ts";
14
-
15
- const base = {
16
- enabled: true,
17
- baseUrl: "https://api.openai.com/v1",
18
- apiKey: "env-key",
19
- model: "gpt-4o-mini",
20
- models: ["gpt-4o-mini", "gpt-4o"],
21
- systemPrompt: "Default prompt",
22
- };
23
-
24
- test("toStoredSettings persists all fields including empty system prompt", () => {
25
- const stored = toStoredSettings(
26
- {
27
- baseUrl: "https://custom.example/v1",
28
- apiKey: "",
29
- model: "gpt-4o",
30
- modelsText: "gpt-4o, gpt-4o-mini",
31
- systemPrompt: "",
32
- },
33
- "existing-key",
34
- );
35
-
36
- expect(stored).toEqual({
37
- baseUrl: "https://custom.example/v1",
38
- apiKey: "existing-key",
39
- model: "gpt-4o",
40
- models: ["gpt-4o", "gpt-4o-mini"],
41
- systemPrompt: "",
42
- });
43
- });
44
-
45
- test("stored settings round-trip through merge", () => {
46
- const stored = assistantToStored(base);
47
- const merged = mergeLlmSettings(
48
- { enabled: false, baseUrl: "x", apiKey: null, model: "y" },
49
- stored,
50
- );
51
-
52
- expect(merged).toEqual(storedToAssistant(stored));
53
- });
54
-
55
- test("normalizeStoredSettings fills missing legacy fields from base", () => {
56
- const normalized = normalizeStoredSettings({ model: "gpt-4.1" }, base);
57
-
58
- expect(normalized?.model).toBe("gpt-4.1");
59
- expect(normalized?.baseUrl).toBe(base.baseUrl);
60
- expect(normalized?.apiKey).toBe(base.apiKey);
61
- expect(normalized?.systemPrompt).toBe(base.systemPrompt);
62
- });
63
-
64
- test("empty stored system prompt falls back to base default", () => {
65
- const stored = createDefaultStoredSettings(base);
66
- const merged = mergeLlmSettings(base, stored);
67
-
68
- expect(merged.systemPrompt).toBe(base.systemPrompt);
69
- });
70
-
71
- test("storedSettingsHaveOverrides ignores default system prompt content", () => {
72
- const defaults = createDefaultStoredSettings(base);
73
- expect(storedSettingsHaveOverrides(defaults, base)).toBe(false);
74
- expect(
75
- storedSettingsHaveOverrides(
76
- { ...defaults, systemPrompt: base.systemPrompt ?? "" },
77
- base,
78
- ),
79
- ).toBe(false);
80
- expect(
81
- storedSettingsHaveOverrides(
82
- { ...defaults, systemPrompt: "Custom prompt" },
83
- base,
84
- ),
85
- ).toBe(true);
86
- });
87
-
88
- test("normalizeStoredSystemPrompt collapses base prompt to empty", () => {
89
- expect(normalizeStoredSystemPrompt("", base)).toBe("");
90
- expect(normalizeStoredSystemPrompt("Default prompt", base)).toBe("");
91
- expect(normalizeStoredSystemPrompt("Custom prompt", base)).toBe(
92
- "Custom prompt",
93
- );
94
- });
95
-
96
- test("isLlmSettingsFormDirty detects unsaved form edits", () => {
97
- const saved = {
98
- baseUrl: "https://api.openai.com/v1",
99
- apiKey: "",
100
- model: "gpt-4o-mini",
101
- modelsText: "",
102
- systemPrompt: "",
103
- };
104
-
105
- expect(isLlmSettingsFormDirty(saved, saved)).toBe(false);
106
- expect(isLlmSettingsFormDirty({ ...saved, model: "gpt-4o" }, saved)).toBe(
107
- true,
108
- );
109
- });
110
-
111
- test("resolveSelectedModel keeps stored custom models", () => {
112
- expect(
113
- resolveSelectedModel("gpt-4o", "gpt-4o-mini", ["gpt-4o-mini", "gpt-4o"]),
114
- ).toBe("gpt-4o");
115
- expect(
116
- resolveSelectedModel("gpt-5.5", "gpt-4o-mini", ["gpt-4o-mini", "gpt-4o"]),
117
- ).toBe("gpt-5.5");
118
- expect(
119
- resolveSelectedModel("", "gpt-4o-mini", ["gpt-4o-mini", "gpt-4o"]),
120
- ).toBe("gpt-4o-mini");
121
- });
@@ -1,24 +0,0 @@
1
- import { describe, expect, test } from "bun:test";
2
- import { parseAssistantError } from "../src/react/lib/parse-assistant-error.ts";
3
-
4
- describe("parseAssistantError", () => {
5
- test("strips chat prefix and maps fetch failures to network", () => {
6
- const parsed = parseAssistantError("Chat failed: Failed to fetch");
7
- expect(parsed.title).toBe("Connection lost");
8
- expect(parsed.detail).toBe("Failed to fetch");
9
- expect(parsed.kind).toBe("network");
10
- expect(parsed.hint).toContain("LLM endpoint");
11
- });
12
-
13
- test("maps auth errors", () => {
14
- const parsed = parseAssistantError("401 Unauthorized");
15
- expect(parsed.title).toBe("Authentication failed");
16
- expect(parsed.kind).toBe("auth");
17
- });
18
-
19
- test("uses suggestions context copy", () => {
20
- const parsed = parseAssistantError("Failed to fetch", "suggestions");
21
- expect(parsed.title).toBe("Connection lost");
22
- expect(parsed.hint).toContain("LLM settings");
23
- });
24
- });
package/tsconfig.json DELETED
@@ -1,8 +0,0 @@
1
- {
2
- "extends": "@4d/typescript-config/base.json",
3
- "compilerOptions": {
4
- "jsx": "react-jsx",
5
- "lib": ["ESNext", "DOM", "DOM.Iterable"]
6
- },
7
- "include": ["src"]
8
- }
File without changes