@4djs/assistant 0.0.0 → 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (188) hide show
  1. package/dist/core/chat-activity.d.ts +19 -0
  2. package/dist/core/chat-activity.d.ts.map +1 -0
  3. package/dist/core/chat-commands.d.ts +33 -0
  4. package/dist/core/chat-commands.d.ts.map +1 -0
  5. package/dist/core/chat-history.d.ts +14 -0
  6. package/dist/core/chat-history.d.ts.map +1 -0
  7. package/dist/core/chat-reply-suggestions-parse.d.ts +20 -0
  8. package/dist/core/chat-reply-suggestions-parse.d.ts.map +1 -0
  9. package/dist/core/code-highlight.d.ts +3 -0
  10. package/dist/core/code-highlight.d.ts.map +1 -0
  11. package/dist/core/create-assistant-store.d.ts +33 -0
  12. package/dist/core/create-assistant-store.d.ts.map +1 -0
  13. package/dist/core/fetch-suggested-prompts.d.ts +11 -0
  14. package/dist/core/fetch-suggested-prompts.d.ts.map +1 -0
  15. package/dist/core/index.d.ts +19 -0
  16. package/dist/core/index.d.ts.map +1 -0
  17. package/dist/core/index.js +2876 -0
  18. package/dist/core/interactive-tools/choices.d.ts +22 -0
  19. package/dist/core/interactive-tools/choices.d.ts.map +1 -0
  20. package/dist/core/interactive-tools/confirmation.d.ts +15 -0
  21. package/dist/core/interactive-tools/confirmation.d.ts.map +1 -0
  22. package/dist/core/interactive-tools/constants.d.ts +6 -0
  23. package/dist/core/interactive-tools/constants.d.ts.map +1 -0
  24. package/dist/core/interactive-tools/execute.d.ts +11 -0
  25. package/dist/core/interactive-tools/execute.d.ts.map +1 -0
  26. package/dist/core/interactive-tools/index.d.ts +7 -0
  27. package/dist/core/interactive-tools/index.d.ts.map +1 -0
  28. package/dist/core/interactive-tools/suggestions.d.ts +13 -0
  29. package/dist/core/interactive-tools/suggestions.d.ts.map +1 -0
  30. package/dist/core/interactive-tools/waiters.d.ts +4 -0
  31. package/dist/core/interactive-tools/waiters.d.ts.map +1 -0
  32. package/dist/core/llm-chat.d.ts +96 -0
  33. package/dist/core/llm-chat.d.ts.map +1 -0
  34. package/dist/core/llm-config.d.ts +24 -0
  35. package/dist/core/llm-config.d.ts.map +1 -0
  36. package/dist/core/llm-models.d.ts +14 -0
  37. package/dist/core/llm-models.d.ts.map +1 -0
  38. package/dist/core/llm-provider.d.ts +13 -0
  39. package/dist/core/llm-provider.d.ts.map +1 -0
  40. package/dist/core/llm-settings-storage.d.ts +47 -0
  41. package/dist/core/llm-settings-storage.d.ts.map +1 -0
  42. package/dist/core/llm-sse.d.ts +13 -0
  43. package/dist/core/llm-sse.d.ts.map +1 -0
  44. package/dist/core/llm-types.d.ts +49 -0
  45. package/dist/core/llm-types.d.ts.map +1 -0
  46. package/dist/core/markdown-utils.d.ts +3 -0
  47. package/dist/core/markdown-utils.d.ts.map +1 -0
  48. package/dist/core/prepare-markdown.d.ts +7 -0
  49. package/dist/core/prepare-markdown.d.ts.map +1 -0
  50. package/dist/core/types.d.ts +74 -0
  51. package/dist/core/types.d.ts.map +1 -0
  52. package/dist/index.css +1195 -0
  53. package/dist/index.js +184948 -0
  54. package/dist/react/Assistant.d.ts +10 -0
  55. package/dist/react/Assistant.d.ts.map +1 -0
  56. package/dist/react/components/HighlightedJsonCode.d.ts +6 -0
  57. package/dist/react/components/HighlightedJsonCode.d.ts.map +1 -0
  58. package/dist/react/components/MarkdownContent.d.ts +10 -0
  59. package/dist/react/components/MarkdownContent.d.ts.map +1 -0
  60. package/dist/react/components/MarkdownEditor.d.ts +11 -0
  61. package/dist/react/components/MarkdownEditor.d.ts.map +1 -0
  62. package/dist/react/components/MermaidDiagram.d.ts +8 -0
  63. package/dist/react/components/MermaidDiagram.d.ts.map +1 -0
  64. package/dist/react/components/ModelSelector.d.ts +8 -0
  65. package/dist/react/components/ModelSelector.d.ts.map +1 -0
  66. package/dist/react/components/chat/AssistantErrorCallout.d.ts +11 -0
  67. package/dist/react/components/chat/AssistantErrorCallout.d.ts.map +1 -0
  68. package/dist/react/components/chat/ChatActivity.d.ts +8 -0
  69. package/dist/react/components/chat/ChatActivity.d.ts.map +1 -0
  70. package/dist/react/components/chat/ChatComposer.d.ts +36 -0
  71. package/dist/react/components/chat/ChatComposer.d.ts.map +1 -0
  72. package/dist/react/components/chat/ChatEmptyState.d.ts +10 -0
  73. package/dist/react/components/chat/ChatEmptyState.d.ts.map +1 -0
  74. package/dist/react/components/chat/ChatInteractivePrompt/choices-prompt.d.ts +7 -0
  75. package/dist/react/components/chat/ChatInteractivePrompt/choices-prompt.d.ts.map +1 -0
  76. package/dist/react/components/chat/ChatInteractivePrompt/confirmation-prompt.d.ts +7 -0
  77. package/dist/react/components/chat/ChatInteractivePrompt/confirmation-prompt.d.ts.map +1 -0
  78. package/dist/react/components/chat/ChatInteractivePrompt/index.d.ts +7 -0
  79. package/dist/react/components/chat/ChatInteractivePrompt/index.d.ts.map +1 -0
  80. package/dist/react/components/chat/ChatInteractivePrompt/shell.d.ts +13 -0
  81. package/dist/react/components/chat/ChatInteractivePrompt/shell.d.ts.map +1 -0
  82. package/dist/react/components/chat/ChatInteractivePrompt/utils.d.ts +4 -0
  83. package/dist/react/components/chat/ChatInteractivePrompt/utils.d.ts.map +1 -0
  84. package/dist/react/components/chat/ChatMessage.d.ts +11 -0
  85. package/dist/react/components/chat/ChatMessage.d.ts.map +1 -0
  86. package/dist/react/components/chat/ChatMessageScroll.d.ts +8 -0
  87. package/dist/react/components/chat/ChatMessageScroll.d.ts.map +1 -0
  88. package/dist/react/components/chat/ChatReplySuggestions.d.ts +9 -0
  89. package/dist/react/components/chat/ChatReplySuggestions.d.ts.map +1 -0
  90. package/dist/react/components/chat/ComposerCommandMenu.d.ts +10 -0
  91. package/dist/react/components/chat/ComposerCommandMenu.d.ts.map +1 -0
  92. package/dist/react/components/chat/LlmSettingsStrip.d.ts +7 -0
  93. package/dist/react/components/chat/LlmSettingsStrip.d.ts.map +1 -0
  94. package/dist/react/components/chat/LlmSetupPrompt.d.ts +7 -0
  95. package/dist/react/components/chat/LlmSetupPrompt.d.ts.map +1 -0
  96. package/dist/react/components/chat/LlmUnavailableBanner.d.ts +6 -0
  97. package/dist/react/components/chat/LlmUnavailableBanner.d.ts.map +1 -0
  98. package/dist/react/components/chat/SuggestedPromptsList.d.ts +14 -0
  99. package/dist/react/components/chat/SuggestedPromptsList.d.ts.map +1 -0
  100. package/dist/react/components/chat/SuggestedPromptsStrip.d.ts +11 -0
  101. package/dist/react/components/chat/SuggestedPromptsStrip.d.ts.map +1 -0
  102. package/dist/react/components/chat/SystemPromptField.d.ts +10 -0
  103. package/dist/react/components/chat/SystemPromptField.d.ts.map +1 -0
  104. package/dist/react/components/highlighted-code.d.ts +8 -0
  105. package/dist/react/components/highlighted-code.d.ts.map +1 -0
  106. package/dist/react/context.d.ts +11 -0
  107. package/dist/react/context.d.ts.map +1 -0
  108. package/dist/react/hooks/use-composer-commands.d.ts +21 -0
  109. package/dist/react/hooks/use-composer-commands.d.ts.map +1 -0
  110. package/dist/react/hooks/use-suggested-prompts.d.ts +29 -0
  111. package/dist/react/hooks/use-suggested-prompts.d.ts.map +1 -0
  112. package/dist/react/index.d.ts +17 -0
  113. package/dist/react/index.d.ts.map +1 -0
  114. package/dist/react/lib/parse-assistant-error.d.ts +9 -0
  115. package/dist/react/lib/parse-assistant-error.d.ts.map +1 -0
  116. package/dist/react/lib/prompt-icons.d.ts +5 -0
  117. package/dist/react/lib/prompt-icons.d.ts.map +1 -0
  118. package/dist/react/types.d.ts +69 -0
  119. package/dist/react/types.d.ts.map +1 -0
  120. package/dist/react/utils/cn.d.ts +2 -0
  121. package/dist/react/utils/cn.d.ts.map +1 -0
  122. package/package.json +16 -5
  123. package/src/core/chat-activity.ts +0 -107
  124. package/src/core/chat-commands.ts +0 -173
  125. package/src/core/chat-history.ts +0 -113
  126. package/src/core/chat-reply-suggestions-parse.ts +0 -119
  127. package/src/core/code-highlight.ts +0 -20
  128. package/src/core/create-assistant-store.ts +0 -639
  129. package/src/core/fetch-suggested-prompts.ts +0 -53
  130. package/src/core/index.ts +0 -125
  131. package/src/core/interactive-tools/choices.ts +0 -155
  132. package/src/core/interactive-tools/confirmation.ts +0 -63
  133. package/src/core/interactive-tools/constants.ts +0 -22
  134. package/src/core/interactive-tools/execute.ts +0 -70
  135. package/src/core/interactive-tools/index.ts +0 -41
  136. package/src/core/interactive-tools/suggestions.ts +0 -87
  137. package/src/core/interactive-tools/waiters.ts +0 -55
  138. package/src/core/llm-chat.ts +0 -686
  139. package/src/core/llm-config.ts +0 -101
  140. package/src/core/llm-models.ts +0 -96
  141. package/src/core/llm-provider.ts +0 -99
  142. package/src/core/llm-settings-storage.ts +0 -331
  143. package/src/core/llm-sse.ts +0 -166
  144. package/src/core/llm-types.ts +0 -52
  145. package/src/core/markdown-utils.ts +0 -11
  146. package/src/core/prepare-markdown.ts +0 -38
  147. package/src/core/types.ts +0 -86
  148. package/src/css.d.ts +0 -1
  149. package/src/react/Assistant.tsx +0 -358
  150. package/src/react/components/HighlightedJsonCode.tsx +0 -24
  151. package/src/react/components/MarkdownContent.tsx +0 -98
  152. package/src/react/components/MarkdownEditor.tsx +0 -60
  153. package/src/react/components/MermaidDiagram.tsx +0 -139
  154. package/src/react/components/ModelSelector.tsx +0 -243
  155. package/src/react/components/chat/AssistantErrorCallout.tsx +0 -79
  156. package/src/react/components/chat/ChatActivity.tsx +0 -274
  157. package/src/react/components/chat/ChatComposer.tsx +0 -189
  158. package/src/react/components/chat/ChatEmptyState.tsx +0 -145
  159. package/src/react/components/chat/ChatInteractivePrompt/choices-prompt.tsx +0 -262
  160. package/src/react/components/chat/ChatInteractivePrompt/confirmation-prompt.tsx +0 -97
  161. package/src/react/components/chat/ChatInteractivePrompt/index.tsx +0 -60
  162. package/src/react/components/chat/ChatInteractivePrompt/shell.tsx +0 -60
  163. package/src/react/components/chat/ChatInteractivePrompt/utils.ts +0 -14
  164. package/src/react/components/chat/ChatMessage.tsx +0 -150
  165. package/src/react/components/chat/ChatMessageScroll.tsx +0 -116
  166. package/src/react/components/chat/ChatReplySuggestions.tsx +0 -231
  167. package/src/react/components/chat/ComposerCommandMenu.tsx +0 -69
  168. package/src/react/components/chat/LlmSettingsStrip.tsx +0 -348
  169. package/src/react/components/chat/LlmSetupPrompt.tsx +0 -58
  170. package/src/react/components/chat/LlmUnavailableBanner.tsx +0 -11
  171. package/src/react/components/chat/SuggestedPromptsList.tsx +0 -121
  172. package/src/react/components/chat/SuggestedPromptsStrip.tsx +0 -72
  173. package/src/react/components/chat/SystemPromptField.tsx +0 -107
  174. package/src/react/components/highlighted-code.tsx +0 -107
  175. package/src/react/context.tsx +0 -72
  176. package/src/react/hooks/use-composer-commands.ts +0 -129
  177. package/src/react/hooks/use-suggested-prompts.ts +0 -128
  178. package/src/react/index.ts +0 -39
  179. package/src/react/lib/parse-assistant-error.ts +0 -96
  180. package/src/react/lib/prompt-icons.ts +0 -40
  181. package/src/react/types.ts +0 -83
  182. package/src/react/utils/cn.ts +0 -5
  183. package/test/buildLlmHistory.test.ts +0 -95
  184. package/test/llm-config.test.ts +0 -72
  185. package/test/llmSettingsStorage.test.ts +0 -121
  186. package/test/parse-assistant-error.test.ts +0 -24
  187. package/tsconfig.json +0 -8
  188. /package/{src/styles/assistant.css → dist/styles.css} +0 -0
@@ -0,0 +1,69 @@
1
+ import type { LucideIcon } from "lucide-react";
2
+ import type { ReactNode } from "react";
3
+ import type { AssistantStore } from "../core/create-assistant-store.js";
4
+ import type { AssistantStoreDependencies, AssistantSuggestedPrompt, AssistantToolDefinition } from "../core/types.js";
5
+ export interface AssistantSuggestedPromptWithIcon extends Omit<AssistantSuggestedPrompt, "icon"> {
6
+ icon?: LucideIcon;
7
+ hint?: string;
8
+ }
9
+ export interface AssistantEmptyStateConfig {
10
+ title: string;
11
+ description: string;
12
+ /** Static fallback prompts when LLM is disabled or fetch fails */
13
+ suggestedPrompts?: AssistantSuggestedPromptWithIcon[];
14
+ /** Allow fetching contextual prompts via LLM (manual trigger; default: true) */
15
+ dynamicSuggestedPrompts?: boolean;
16
+ }
17
+ export interface AssistantHeaderConfig {
18
+ title?: string;
19
+ subtitle?: string;
20
+ icon?: LucideIcon;
21
+ showClearButton?: boolean;
22
+ /** Show button to generate LLM suggested prompts (default: true when fetchSuggestedPrompts is set) */
23
+ showSuggestionsButton?: boolean;
24
+ }
25
+ export interface AssistantUiConfig {
26
+ composerPlaceholder?: string;
27
+ showModelSelector?: boolean;
28
+ /** Show LLM settings button in the composer footer (default: true) */
29
+ showLlmSettings?: boolean;
30
+ maxWidth?: string;
31
+ className?: string;
32
+ }
33
+ export interface AssistantConfig extends AssistantStoreDependencies {
34
+ emptyState?: AssistantEmptyStateConfig;
35
+ header?: AssistantHeaderConfig;
36
+ ui?: AssistantUiConfig;
37
+ /** Load LLM config on mount (default: true) */
38
+ autoLoadLlmStatus?: boolean;
39
+ /** Optional hook to fetch contextual empty-state prompts via the configured LLM */
40
+ fetchSuggestedPrompts?: (ctx: {
41
+ llmEnabled: boolean;
42
+ model: string | null;
43
+ tools: AssistantToolDefinition[];
44
+ }) => Promise<Array<{
45
+ id: string;
46
+ label: string;
47
+ description?: string;
48
+ prompt: string;
49
+ icon?: string;
50
+ }>>;
51
+ }
52
+ export interface AssistantContextValue {
53
+ store: AssistantStore;
54
+ config: AssistantConfig;
55
+ }
56
+ export interface AssistantProviderProps {
57
+ config: AssistantConfig;
58
+ children: ReactNode;
59
+ }
60
+ export interface AssistantProps {
61
+ className?: string;
62
+ /** Override header from provider config */
63
+ header?: AssistantHeaderConfig;
64
+ /** Override empty state from provider config */
65
+ emptyState?: AssistantEmptyStateConfig;
66
+ /** Override UI options from provider config */
67
+ ui?: AssistantUiConfig;
68
+ }
69
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/react/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,KAAK,EACX,0BAA0B,EAC1B,wBAAwB,EACxB,uBAAuB,EACvB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,WAAW,gCAChB,SAAQ,IAAI,CAAC,wBAAwB,EAAE,MAAM,CAAC;IAC9C,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,yBAAyB;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,kEAAkE;IAClE,gBAAgB,CAAC,EAAE,gCAAgC,EAAE,CAAC;IACtD,gFAAgF;IAChF,uBAAuB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED,MAAM,WAAW,qBAAqB;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,sGAAsG;IACtG,qBAAqB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,MAAM,WAAW,iBAAiB;IACjC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,sEAAsE;IACtE,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAgB,SAAQ,0BAA0B;IAClE,UAAU,CAAC,EAAE,yBAAyB,CAAC;IACvC,MAAM,CAAC,EAAE,qBAAqB,CAAC;IAC/B,EAAE,CAAC,EAAE,iBAAiB,CAAC;IACvB,+CAA+C;IAC/C,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,mFAAmF;IACnF,qBAAqB,CAAC,EAAE,CAAC,GAAG,EAAE;QAC7B,UAAU,EAAE,OAAO,CAAC;QACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,KAAK,EAAE,uBAAuB,EAAE,CAAC;KACjC,KAAK,OAAO,CACZ,KAAK,CAAC;QACL,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;KACd,CAAC,CACF,CAAC;CACF;AAED,MAAM,WAAW,qBAAqB;IACrC,KAAK,EAAE,cAAc,CAAC;IACtB,MAAM,EAAE,eAAe,CAAC;CACxB;AAED,MAAM,WAAW,sBAAsB;IACtC,MAAM,EAAE,eAAe,CAAC;IACxB,QAAQ,EAAE,SAAS,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,MAAM,CAAC,EAAE,qBAAqB,CAAC;IAC/B,gDAAgD;IAChD,UAAU,CAAC,EAAE,yBAAyB,CAAC;IACvC,+CAA+C;IAC/C,EAAE,CAAC,EAAE,iBAAiB,CAAC;CACvB"}
@@ -0,0 +1,2 @@
1
+ export declare function cn(...classes: Array<string | false | null | undefined>): string;
2
+ //# sourceMappingURL=cn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cn.d.ts","sourceRoot":"","sources":["../../../src/react/utils/cn.ts"],"names":[],"mappings":"AAAA,wBAAgB,EAAE,CACjB,GAAG,OAAO,EAAE,KAAK,CAAC,MAAM,GAAG,KAAK,GAAG,IAAI,GAAG,SAAS,CAAC,GAClD,MAAM,CAER"}
package/package.json CHANGED
@@ -1,18 +1,29 @@
1
1
  {
2
2
  "name": "@4djs/assistant",
3
- "version": "0.0.0",
3
+ "version": "0.0.1",
4
4
  "type": "module",
5
+ "types": "./dist/react/index.d.ts",
6
+ "files": [
7
+ "dist"
8
+ ],
5
9
  "exports": {
6
- ".": "./src/react/index.ts",
7
- "./core": "./src/core/index.ts",
8
- "./styles.css": "./src/styles/assistant.css"
10
+ ".": {
11
+ "types": "./dist/react/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ },
14
+ "./core": {
15
+ "types": "./dist/core/index.d.ts",
16
+ "import": "./dist/core/index.js"
17
+ },
18
+ "./styles.css": "./dist/styles.css"
9
19
  },
10
20
  "scripts": {
11
21
  "typecheck": "tsc --noEmit",
12
- "build": "bun run build:core && bun run build:react && bun run build:styles",
22
+ "build": "bun run build:core && bun run build:react && bun run build:styles && bun run build:types",
13
23
  "build:core": "bun build ./src/core/index.ts --outdir ./dist/core --target node --format esm",
14
24
  "build:react": "bun build ./src/react/index.ts --outdir ./dist --target browser --external react --external react-dom --format esm",
15
25
  "build:styles": "mkdir -p dist && cp src/styles/assistant.css dist/styles.css",
26
+ "build:types": "tsc -p tsconfig.build.json && bun ./scripts/normalize-dts.ts",
16
27
  "prepack": "bun run build"
17
28
  },
18
29
  "dependencies": {
@@ -1,107 +0,0 @@
1
- export type ChatActivityStatus = "active" | "done" | "error";
2
-
3
- export interface ChatActivityStep {
4
- id: string;
5
- kind: "tool";
6
- name: string;
7
- args: Record<string, unknown>;
8
- callId?: string;
9
- status: ChatActivityStatus;
10
- result?: unknown;
11
- error?: string;
12
- }
13
-
14
- export function summarizeActivityResult(result: unknown): unknown {
15
- if (result === undefined || result === null) return result;
16
- if (typeof result !== "object") return result;
17
-
18
- const value = result as Record<string, unknown>;
19
- if ("structuredContent" in value) {
20
- return value.structuredContent ?? value;
21
- }
22
- if ("content" in value && Array.isArray(value.content)) {
23
- return value.content;
24
- }
25
- return result;
26
- }
27
-
28
- export function chatActivityStepLabel(step: ChatActivityStep): string {
29
- if (step.status === "active") {
30
- if (step.name === "request_confirmation")
31
- return "Waiting for confirmation…";
32
- if (step.name === "request_choices") return "Waiting for your choice…";
33
- if (step.name === "suggest_replies") return "Suggesting replies…";
34
- return `Running ${step.name}…`;
35
- }
36
- if (step.status === "error") return `${step.name} failed`;
37
- if (step.name === "request_confirmation") return "Confirmation answered";
38
- if (step.name === "request_choices") return "Choice submitted";
39
- if (step.name === "suggest_replies") return "Reply suggestions shown";
40
- return `Ran ${step.name}`;
41
- }
42
-
43
- export function formatJsonIfLarge(raw: string): string {
44
- const trimmed = raw.trim();
45
- const JSON_PRETTY_MIN_LENGTH = 80;
46
-
47
- if (trimmed.length < JSON_PRETTY_MIN_LENGTH) {
48
- return trimmed;
49
- }
50
-
51
- try {
52
- return JSON.stringify(JSON.parse(trimmed), null, 2);
53
- } catch {
54
- return trimmed;
55
- }
56
- }
57
-
58
- export function formatActivityJson(raw?: string): string | null {
59
- if (!raw?.trim()) return null;
60
-
61
- try {
62
- return JSON.stringify(JSON.parse(raw), null, 2);
63
- } catch {
64
- return raw;
65
- }
66
- }
67
-
68
- export function formatActivityJsonValue(value: unknown): string | null {
69
- if (value === undefined || value === null) return null;
70
- if (typeof value === "string") return formatActivityJson(value);
71
- try {
72
- return JSON.stringify(value, null, 2);
73
- } catch {
74
- return String(value);
75
- }
76
- }
77
-
78
- export function isEmptyActivityJson(value: unknown): boolean {
79
- if (value === undefined || value === null) return true;
80
-
81
- if (typeof value === "object" && !Array.isArray(value)) {
82
- return Object.keys(value as Record<string, unknown>).length === 0;
83
- }
84
-
85
- if (typeof value === "string") {
86
- if (!value.trim()) return true;
87
- try {
88
- const parsed = JSON.parse(value) as unknown;
89
- return (
90
- (typeof parsed === "object" &&
91
- parsed !== null &&
92
- Object.keys(parsed).length === 0) ||
93
- parsed === null
94
- );
95
- } catch {
96
- return false;
97
- }
98
- }
99
-
100
- return false;
101
- }
102
-
103
- export function stepHasDetails(step: ChatActivityStep): boolean {
104
- if (step.error?.trim()) return true;
105
- if (step.result !== undefined && step.result !== null) return true;
106
- return !isEmptyActivityJson(step.args);
107
- }
@@ -1,173 +0,0 @@
1
- export type ChatCommandSurface = "assistant";
2
-
3
- export type ChatCommandRunResult = {
4
- handled: boolean;
5
- clearInput?: boolean;
6
- error?: string;
7
- };
8
-
9
- export type AssistantCommandDeps = {
10
- clearMessages: () => void;
11
- setError: (error: string | null) => void;
12
- streaming: boolean;
13
- };
14
-
15
- const CHAT_COMMANDS = [
16
- {
17
- name: "clear",
18
- description: "Clear the current conversation",
19
- surfaces: ["assistant"] as const,
20
- run: async (args: string, deps: AssistantCommandDeps) => {
21
- if (args) {
22
- throw new Error("The /clear command does not accept arguments.");
23
- }
24
- if (deps.streaming) {
25
- throw new Error("Wait for the assistant to finish before clearing.");
26
- }
27
- deps.clearMessages();
28
- deps.setError(null);
29
- },
30
- },
31
- ] satisfies Array<{
32
- name: string;
33
- description: string;
34
- surfaces: readonly ChatCommandSurface[];
35
- run: (args: string, deps: AssistantCommandDeps) => void | Promise<void>;
36
- }>;
37
-
38
- export type ChatCommandSuggestion = {
39
- name: string;
40
- description: string;
41
- usage: string;
42
- };
43
-
44
- export function getChatCommandSuggestions(
45
- surface: ChatCommandSurface,
46
- ): ChatCommandSuggestion[] {
47
- return CHAT_COMMANDS.filter((command) =>
48
- command.surfaces.includes(surface),
49
- ).map(({ name, description }) => ({
50
- name,
51
- description,
52
- usage: `/${name}`,
53
- }));
54
- }
55
-
56
- export function isChatCommandInput(value: string): boolean {
57
- return value.trimStart().startsWith("/");
58
- }
59
-
60
- export function filterChatCommands(
61
- value: string,
62
- surface: ChatCommandSurface,
63
- ): ChatCommandSuggestion[] {
64
- if (!isChatCommandInput(value)) {
65
- return [];
66
- }
67
-
68
- const query = value.trimStart().slice(1).toLowerCase();
69
- const commands = getChatCommandSuggestions(surface);
70
-
71
- if (!query) {
72
- return commands;
73
- }
74
-
75
- return commands.filter(
76
- (command) =>
77
- command.name.startsWith(query) ||
78
- command.usage.toLowerCase().startsWith(`/${query}`),
79
- );
80
- }
81
-
82
- export function shouldShowChatCommandMenu(
83
- value: string,
84
- surface: ChatCommandSurface,
85
- ): boolean {
86
- if (!isChatCommandInput(value) || value.includes("\n")) {
87
- return false;
88
- }
89
-
90
- const trimmed = value.trimStart();
91
- if (trimmed.includes(" ")) {
92
- return false;
93
- }
94
-
95
- return filterChatCommands(value, surface).length > 0;
96
- }
97
-
98
- export function completionForChatCommand(
99
- command: ChatCommandSuggestion,
100
- ): string {
101
- return `${command.usage} `;
102
- }
103
-
104
- export function listChatCommands(surface?: ChatCommandSurface): Array<{
105
- name: string;
106
- description: string;
107
- }> {
108
- return CHAT_COMMANDS.filter(
109
- (command) => !surface || command.surfaces.includes(surface),
110
- ).map(({ name, description }) => ({ name, description }));
111
- }
112
-
113
- export function parseChatCommand(
114
- input: string,
115
- ): { name: string; args: string } | null {
116
- const trimmed = input.trim();
117
- const match = /^\/([a-z][a-z0-9_-]*)(?:\s+([\s\S]*))?$/i.exec(trimmed);
118
- if (!match) {
119
- return null;
120
- }
121
-
122
- const name = match[1];
123
- if (!name) {
124
- return null;
125
- }
126
-
127
- return {
128
- name: name.toLowerCase(),
129
- args: (match[2] ?? "").trim(),
130
- };
131
- }
132
-
133
- async function executeCommand(
134
- parsed: { name: string; args: string },
135
- deps: AssistantCommandDeps,
136
- ): Promise<ChatCommandRunResult> {
137
- const command = CHAT_COMMANDS.find((entry) => entry.name === parsed.name);
138
- if (!command?.surfaces.includes("assistant")) {
139
- return {
140
- handled: true,
141
- clearInput: true,
142
- error: `Unknown command: /${parsed.name}`,
143
- };
144
- }
145
-
146
- try {
147
- await command.run(parsed.args, deps);
148
- return { handled: true, clearInput: true };
149
- } catch (error) {
150
- return {
151
- handled: true,
152
- clearInput: true,
153
- error: error instanceof Error ? error.message : "Command failed",
154
- };
155
- }
156
- }
157
-
158
- export async function runAssistantChatCommand(
159
- input: string,
160
- deps: AssistantCommandDeps,
161
- ): Promise<ChatCommandRunResult> {
162
- const parsed = parseChatCommand(input);
163
- if (!parsed) {
164
- return { handled: false };
165
- }
166
-
167
- return executeCommand(parsed, deps);
168
- }
169
-
170
- /** @deprecated Use runAssistantChatCommand instead */
171
- export function isClearCommand(text: string): boolean {
172
- return parseChatCommand(text)?.name === "clear";
173
- }
@@ -1,113 +0,0 @@
1
- import type { ChatActivityStep } from "./chat-activity.ts";
2
- import type { ReplySuggestions } from "./interactive-tools/index.ts";
3
- import { isValidReplySuggestions } from "./interactive-tools/index.ts";
4
- import type { AssistantMessage, AssistantWelcomeContext } from "./types.ts";
5
-
6
- const DEFAULT_HISTORY_KEY = "assistant-chat-history";
7
- const DEFAULT_MAX_STORED = 100;
8
-
9
- export interface ChatHistoryOptions {
10
- storageKey?: string;
11
- maxStored?: number;
12
- welcomeMessage: (ctx: AssistantWelcomeContext) => AssistantMessage;
13
- }
14
-
15
- interface StoredChatMessage {
16
- id: string;
17
- role: "user" | "assistant" | "system";
18
- content: string;
19
- activity?: ChatActivityStep[];
20
- toolCall?: { name: string; args: Record<string, unknown> };
21
- replySuggestions?: ReplySuggestions;
22
- isError?: boolean;
23
- llmSetupRequired?: boolean;
24
- timestamp: number;
25
- }
26
-
27
- function toStored(message: AssistantMessage): StoredChatMessage {
28
- return {
29
- id: message.id,
30
- role: message.role,
31
- content: message.content,
32
- activity: message.activity,
33
- toolCall: message.toolCall,
34
- replySuggestions: message.replySuggestions,
35
- isError: message.isError,
36
- llmSetupRequired: message.llmSetupRequired,
37
- timestamp: message.timestamp,
38
- };
39
- }
40
-
41
- function fromStored(message: StoredChatMessage): AssistantMessage {
42
- return {
43
- id: message.id,
44
- role: message.role,
45
- content: message.content,
46
- activity: message.activity,
47
- toolCall: message.toolCall,
48
- replySuggestions: isValidReplySuggestions(message.replySuggestions)
49
- ? message.replySuggestions
50
- : undefined,
51
- isError: message.isError,
52
- llmSetupRequired: message.llmSetupRequired,
53
- timestamp: message.timestamp,
54
- };
55
- }
56
-
57
- function isStoredChatMessage(value: unknown): value is StoredChatMessage {
58
- if (!value || typeof value !== "object") return false;
59
- const message = value as StoredChatMessage;
60
- return (
61
- typeof message.id === "string" &&
62
- (message.role === "user" ||
63
- message.role === "assistant" ||
64
- message.role === "system") &&
65
- typeof message.content === "string" &&
66
- typeof message.timestamp === "number"
67
- );
68
- }
69
-
70
- export function createChatHistoryHelpers(options: ChatHistoryOptions) {
71
- const storageKey = options.storageKey ?? DEFAULT_HISTORY_KEY;
72
- const maxStored = options.maxStored ?? DEFAULT_MAX_STORED;
73
-
74
- function getStored(): AssistantMessage[] | null {
75
- try {
76
- const raw = localStorage.getItem(storageKey);
77
- if (!raw) return null;
78
- const parsed: unknown = JSON.parse(raw);
79
- if (!Array.isArray(parsed)) return null;
80
- const messages = parsed.filter(isStoredChatMessage).map(fromStored);
81
- return messages.length > 0 ? messages : null;
82
- } catch {
83
- return null;
84
- }
85
- }
86
-
87
- function persist(messages: AssistantMessage[]) {
88
- const storable = messages
89
- .filter((message) => !message.streaming)
90
- .slice(-maxStored)
91
- .map(toStored);
92
- localStorage.setItem(storageKey, JSON.stringify(storable));
93
- }
94
-
95
- function clear() {
96
- localStorage.removeItem(storageKey);
97
- }
98
-
99
- function loadInitial(ctx: AssistantWelcomeContext): AssistantMessage[] {
100
- const stored = getStored();
101
- const welcome = options.welcomeMessage(ctx);
102
- if (stored) {
103
- const hasWelcome = stored.some((message) => message.id === "welcome");
104
- if (hasWelcome) return stored;
105
- return [welcome, ...stored];
106
- }
107
- return [welcome];
108
- }
109
-
110
- return { getStored, persist, clear, loadInitial };
111
- }
112
-
113
- export type { AssistantMessage };
@@ -1,119 +0,0 @@
1
- export type SuggestionField = {
2
- label: string;
3
- value: string;
4
- };
5
-
6
- export type ParsedSuggestion =
7
- | { kind: "compact"; text: string }
8
- | {
9
- kind: "structured";
10
- title: string;
11
- description?: string;
12
- fields: SuggestionField[];
13
- raw: string;
14
- }
15
- | { kind: "custom"; text: string };
16
-
17
- const STRUCTURED_FIELD_LABELS = new Set([
18
- "name",
19
- "description",
20
- "model",
21
- "enabled",
22
- "tools",
23
- "prompt",
24
- "agent",
25
- "dataclass",
26
- "filter",
27
- ]);
28
-
29
- export function parseSuggestionText(text: string): ParsedSuggestion {
30
- const trimmed = text.trim();
31
- if (!trimmed) {
32
- return { kind: "compact", text: trimmed };
33
- }
34
-
35
- if (isCustomDeclineSuggestion(trimmed)) {
36
- return { kind: "custom", text: trimmed };
37
- }
38
-
39
- const fields = parseKeyValueFields(trimmed);
40
- if (fields && fields.length >= 2) {
41
- const nameField = fields.find(
42
- (field) => field.label.toLowerCase() === "name",
43
- );
44
- const descriptionField = fields.find(
45
- (field) => field.label.toLowerCase() === "description",
46
- );
47
- const detailFields = fields.filter(
48
- (field) => !["name", "description"].includes(field.label.toLowerCase()),
49
- );
50
-
51
- return {
52
- kind: "structured",
53
- title: nameField?.value ?? trimmed,
54
- description: descriptionField?.value,
55
- fields: detailFields,
56
- raw: trimmed,
57
- };
58
- }
59
-
60
- if (trimmed.length <= 32 && !trimmed.includes(",")) {
61
- return { kind: "compact", text: trimmed };
62
- }
63
-
64
- return { kind: "compact", text: trimmed };
65
- }
66
-
67
- function isCustomDeclineSuggestion(text: string): boolean {
68
- return /\b(myself|my own|custom answer|provide the details|type my own|enter manually)\b/i.test(
69
- text,
70
- );
71
- }
72
-
73
- function parseKeyValueFields(text: string): SuggestionField[] | null {
74
- const pattern = /([A-Za-z][A-Za-z\s]*?):\s*/g;
75
- const matches = [...text.matchAll(pattern)];
76
-
77
- if (matches.length < 2) {
78
- return null;
79
- }
80
-
81
- const fields: SuggestionField[] = [];
82
-
83
- for (let index = 0; index < matches.length; index += 1) {
84
- const match = matches[index];
85
- if (!match || match.index === undefined) {
86
- continue;
87
- }
88
-
89
- const label = match[1]?.trim() ?? "";
90
- if (!STRUCTURED_FIELD_LABELS.has(label.toLowerCase())) {
91
- return null;
92
- }
93
-
94
- const valueStart = match.index + match[0].length;
95
- const nextMatch = matches[index + 1];
96
- const valueEnd = nextMatch?.index ?? text.length;
97
- const value = text.slice(valueStart, valueEnd).replace(/,\s*$/, "").trim();
98
-
99
- if (!label || !value) {
100
- return null;
101
- }
102
-
103
- fields.push({ label, value });
104
- }
105
-
106
- return fields.length >= 2 ? fields : null;
107
- }
108
-
109
- export function splitToolValues(value: string): string[] {
110
- const normalized = value.trim();
111
- if (!normalized || /^none$/i.test(normalized)) {
112
- return [];
113
- }
114
-
115
- return normalized
116
- .split(/,\s*/)
117
- .map((entry) => entry.trim())
118
- .filter(Boolean);
119
- }
@@ -1,20 +0,0 @@
1
- import hljs from "highlight.js/lib/core";
2
- import jsonLang from "highlight.js/lib/languages/json";
3
- import markdownLang from "highlight.js/lib/languages/markdown";
4
-
5
- hljs.registerLanguage("json", jsonLang);
6
- hljs.registerLanguage("markdown", markdownLang);
7
-
8
- export function normalizeCodeLineEndings(code: string): string {
9
- return code.replace(/\r\n?/g, "\n");
10
- }
11
-
12
- export function highlightCode(code: string, language: string | null): string {
13
- const source = normalizeCodeLineEndings(code);
14
-
15
- if (language && hljs.getLanguage(language)) {
16
- return hljs.highlight(source, { language, ignoreIllegals: true }).value;
17
- }
18
-
19
- return hljs.highlightAuto(source).value;
20
- }