@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.
- package/README.md +49 -68
- package/dist/core/chat-activity.d.ts +19 -0
- package/dist/core/chat-activity.d.ts.map +1 -0
- package/dist/core/chat-commands.d.ts +33 -0
- package/dist/core/chat-commands.d.ts.map +1 -0
- package/dist/core/chat-history.d.ts +14 -0
- package/dist/core/chat-history.d.ts.map +1 -0
- package/dist/core/chat-reply-suggestions-parse.d.ts +20 -0
- package/dist/core/chat-reply-suggestions-parse.d.ts.map +1 -0
- package/dist/core/code-highlight.d.ts +3 -0
- package/dist/core/code-highlight.d.ts.map +1 -0
- package/dist/core/create-assistant-store.d.ts +33 -0
- package/dist/core/create-assistant-store.d.ts.map +1 -0
- package/dist/core/fetch-suggested-prompts.d.ts +11 -0
- package/dist/core/fetch-suggested-prompts.d.ts.map +1 -0
- package/dist/core/index.d.ts +19 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +2876 -0
- package/dist/core/interactive-tools/choices.d.ts +22 -0
- package/dist/core/interactive-tools/choices.d.ts.map +1 -0
- package/dist/core/interactive-tools/confirmation.d.ts +15 -0
- package/dist/core/interactive-tools/confirmation.d.ts.map +1 -0
- package/dist/core/interactive-tools/constants.d.ts +6 -0
- package/dist/core/interactive-tools/constants.d.ts.map +1 -0
- package/dist/core/interactive-tools/execute.d.ts +11 -0
- package/dist/core/interactive-tools/execute.d.ts.map +1 -0
- package/dist/core/interactive-tools/index.d.ts +7 -0
- package/dist/core/interactive-tools/index.d.ts.map +1 -0
- package/dist/core/interactive-tools/suggestions.d.ts +13 -0
- package/dist/core/interactive-tools/suggestions.d.ts.map +1 -0
- package/dist/core/interactive-tools/waiters.d.ts +4 -0
- package/dist/core/interactive-tools/waiters.d.ts.map +1 -0
- package/dist/core/llm-chat.d.ts +96 -0
- package/dist/core/llm-chat.d.ts.map +1 -0
- package/dist/core/llm-config.d.ts +24 -0
- package/dist/core/llm-config.d.ts.map +1 -0
- package/dist/core/llm-models.d.ts +14 -0
- package/dist/core/llm-models.d.ts.map +1 -0
- package/dist/core/llm-provider.d.ts +13 -0
- package/dist/core/llm-provider.d.ts.map +1 -0
- package/dist/core/llm-settings-storage.d.ts +47 -0
- package/dist/core/llm-settings-storage.d.ts.map +1 -0
- package/dist/core/llm-sse.d.ts +13 -0
- package/dist/core/llm-sse.d.ts.map +1 -0
- package/dist/core/llm-types.d.ts +49 -0
- package/dist/core/llm-types.d.ts.map +1 -0
- package/dist/core/markdown-utils.d.ts +3 -0
- package/dist/core/markdown-utils.d.ts.map +1 -0
- package/dist/core/prepare-markdown.d.ts +7 -0
- package/dist/core/prepare-markdown.d.ts.map +1 -0
- package/dist/core/types.d.ts +74 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/index.css +1195 -0
- package/dist/index.js +184948 -0
- package/dist/react/Assistant.d.ts +10 -0
- package/dist/react/Assistant.d.ts.map +1 -0
- package/dist/react/components/HighlightedJsonCode.d.ts +6 -0
- package/dist/react/components/HighlightedJsonCode.d.ts.map +1 -0
- package/dist/react/components/MarkdownContent.d.ts +10 -0
- package/dist/react/components/MarkdownContent.d.ts.map +1 -0
- package/dist/react/components/MarkdownEditor.d.ts +11 -0
- package/dist/react/components/MarkdownEditor.d.ts.map +1 -0
- package/dist/react/components/MermaidDiagram.d.ts +8 -0
- package/dist/react/components/MermaidDiagram.d.ts.map +1 -0
- package/dist/react/components/ModelSelector.d.ts +8 -0
- package/dist/react/components/ModelSelector.d.ts.map +1 -0
- package/dist/react/components/chat/AssistantErrorCallout.d.ts +11 -0
- package/dist/react/components/chat/AssistantErrorCallout.d.ts.map +1 -0
- package/dist/react/components/chat/ChatActivity.d.ts +8 -0
- package/dist/react/components/chat/ChatActivity.d.ts.map +1 -0
- package/dist/react/components/chat/ChatComposer.d.ts +36 -0
- package/dist/react/components/chat/ChatComposer.d.ts.map +1 -0
- package/dist/react/components/chat/ChatEmptyState.d.ts +10 -0
- package/dist/react/components/chat/ChatEmptyState.d.ts.map +1 -0
- package/dist/react/components/chat/ChatInteractivePrompt/choices-prompt.d.ts +7 -0
- package/dist/react/components/chat/ChatInteractivePrompt/choices-prompt.d.ts.map +1 -0
- package/dist/react/components/chat/ChatInteractivePrompt/confirmation-prompt.d.ts +7 -0
- package/dist/react/components/chat/ChatInteractivePrompt/confirmation-prompt.d.ts.map +1 -0
- package/dist/react/components/chat/ChatInteractivePrompt/index.d.ts +7 -0
- package/dist/react/components/chat/ChatInteractivePrompt/index.d.ts.map +1 -0
- package/dist/react/components/chat/ChatInteractivePrompt/shell.d.ts +13 -0
- package/dist/react/components/chat/ChatInteractivePrompt/shell.d.ts.map +1 -0
- package/dist/react/components/chat/ChatInteractivePrompt/utils.d.ts +4 -0
- package/dist/react/components/chat/ChatInteractivePrompt/utils.d.ts.map +1 -0
- package/dist/react/components/chat/ChatMessage.d.ts +11 -0
- package/dist/react/components/chat/ChatMessage.d.ts.map +1 -0
- package/dist/react/components/chat/ChatMessageScroll.d.ts +8 -0
- package/dist/react/components/chat/ChatMessageScroll.d.ts.map +1 -0
- package/dist/react/components/chat/ChatReplySuggestions.d.ts +9 -0
- package/dist/react/components/chat/ChatReplySuggestions.d.ts.map +1 -0
- package/dist/react/components/chat/ComposerCommandMenu.d.ts +10 -0
- package/dist/react/components/chat/ComposerCommandMenu.d.ts.map +1 -0
- package/dist/react/components/chat/LlmSettingsStrip.d.ts +7 -0
- package/dist/react/components/chat/LlmSettingsStrip.d.ts.map +1 -0
- package/dist/react/components/chat/LlmSetupPrompt.d.ts +7 -0
- package/dist/react/components/chat/LlmSetupPrompt.d.ts.map +1 -0
- package/dist/react/components/chat/LlmUnavailableBanner.d.ts +6 -0
- package/dist/react/components/chat/LlmUnavailableBanner.d.ts.map +1 -0
- package/dist/react/components/chat/SuggestedPromptsList.d.ts +14 -0
- package/dist/react/components/chat/SuggestedPromptsList.d.ts.map +1 -0
- package/dist/react/components/chat/SuggestedPromptsStrip.d.ts +11 -0
- package/dist/react/components/chat/SuggestedPromptsStrip.d.ts.map +1 -0
- package/dist/react/components/chat/SystemPromptField.d.ts +10 -0
- package/dist/react/components/chat/SystemPromptField.d.ts.map +1 -0
- package/dist/react/components/highlighted-code.d.ts +8 -0
- package/dist/react/components/highlighted-code.d.ts.map +1 -0
- package/dist/react/context.d.ts +11 -0
- package/dist/react/context.d.ts.map +1 -0
- package/dist/react/hooks/use-composer-commands.d.ts +21 -0
- package/dist/react/hooks/use-composer-commands.d.ts.map +1 -0
- package/dist/react/hooks/use-suggested-prompts.d.ts +29 -0
- package/dist/react/hooks/use-suggested-prompts.d.ts.map +1 -0
- package/dist/react/index.d.ts +17 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/lib/parse-assistant-error.d.ts +9 -0
- package/dist/react/lib/parse-assistant-error.d.ts.map +1 -0
- package/dist/react/lib/prompt-icons.d.ts +5 -0
- package/dist/react/lib/prompt-icons.d.ts.map +1 -0
- package/dist/react/types.d.ts +69 -0
- package/dist/react/types.d.ts.map +1 -0
- package/dist/react/utils/cn.d.ts +2 -0
- package/dist/react/utils/cn.d.ts.map +1 -0
- package/package.json +16 -5
- package/src/core/chat-activity.ts +0 -107
- package/src/core/chat-commands.ts +0 -173
- package/src/core/chat-history.ts +0 -113
- package/src/core/chat-reply-suggestions-parse.ts +0 -119
- package/src/core/code-highlight.ts +0 -20
- package/src/core/create-assistant-store.ts +0 -639
- package/src/core/fetch-suggested-prompts.ts +0 -53
- package/src/core/index.ts +0 -125
- package/src/core/interactive-tools/choices.ts +0 -155
- package/src/core/interactive-tools/confirmation.ts +0 -63
- package/src/core/interactive-tools/constants.ts +0 -22
- package/src/core/interactive-tools/execute.ts +0 -70
- package/src/core/interactive-tools/index.ts +0 -41
- package/src/core/interactive-tools/suggestions.ts +0 -87
- package/src/core/interactive-tools/waiters.ts +0 -55
- package/src/core/llm-chat.ts +0 -686
- package/src/core/llm-config.ts +0 -101
- package/src/core/llm-models.ts +0 -96
- package/src/core/llm-provider.ts +0 -99
- package/src/core/llm-settings-storage.ts +0 -331
- package/src/core/llm-sse.ts +0 -166
- package/src/core/llm-types.ts +0 -52
- package/src/core/markdown-utils.ts +0 -11
- package/src/core/prepare-markdown.ts +0 -38
- package/src/core/types.ts +0 -86
- package/src/css.d.ts +0 -1
- package/src/react/Assistant.tsx +0 -358
- package/src/react/components/HighlightedJsonCode.tsx +0 -24
- package/src/react/components/MarkdownContent.tsx +0 -98
- package/src/react/components/MarkdownEditor.tsx +0 -60
- package/src/react/components/MermaidDiagram.tsx +0 -139
- package/src/react/components/ModelSelector.tsx +0 -243
- package/src/react/components/chat/AssistantErrorCallout.tsx +0 -79
- package/src/react/components/chat/ChatActivity.tsx +0 -274
- package/src/react/components/chat/ChatComposer.tsx +0 -189
- package/src/react/components/chat/ChatEmptyState.tsx +0 -145
- package/src/react/components/chat/ChatInteractivePrompt/choices-prompt.tsx +0 -262
- package/src/react/components/chat/ChatInteractivePrompt/confirmation-prompt.tsx +0 -97
- package/src/react/components/chat/ChatInteractivePrompt/index.tsx +0 -60
- package/src/react/components/chat/ChatInteractivePrompt/shell.tsx +0 -60
- package/src/react/components/chat/ChatInteractivePrompt/utils.ts +0 -14
- package/src/react/components/chat/ChatMessage.tsx +0 -150
- package/src/react/components/chat/ChatMessageScroll.tsx +0 -116
- package/src/react/components/chat/ChatReplySuggestions.tsx +0 -231
- package/src/react/components/chat/ComposerCommandMenu.tsx +0 -69
- package/src/react/components/chat/LlmSettingsStrip.tsx +0 -348
- package/src/react/components/chat/LlmSetupPrompt.tsx +0 -58
- package/src/react/components/chat/LlmUnavailableBanner.tsx +0 -11
- package/src/react/components/chat/SuggestedPromptsList.tsx +0 -121
- package/src/react/components/chat/SuggestedPromptsStrip.tsx +0 -72
- package/src/react/components/chat/SystemPromptField.tsx +0 -107
- package/src/react/components/highlighted-code.tsx +0 -107
- package/src/react/context.tsx +0 -72
- package/src/react/hooks/use-composer-commands.ts +0 -129
- package/src/react/hooks/use-suggested-prompts.ts +0 -128
- package/src/react/index.ts +0 -39
- package/src/react/lib/parse-assistant-error.ts +0 -96
- package/src/react/lib/prompt-icons.ts +0 -40
- package/src/react/types.ts +0 -83
- package/src/react/utils/cn.ts +0 -5
- package/test/buildLlmHistory.test.ts +0 -95
- package/test/llm-config.test.ts +0 -72
- package/test/llmSettingsStorage.test.ts +0 -121
- package/test/parse-assistant-error.test.ts +0 -24
- package/tsconfig.json +0 -8
- /package/{src/styles/assistant.css → dist/styles.css} +0 -0
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import { Eye, Pencil, RotateCcw } from "lucide-react";
|
|
2
|
-
import { useState } from "react";
|
|
3
|
-
import { MarkdownContent } from "../MarkdownContent.tsx";
|
|
4
|
-
import { MarkdownEditor } from "../MarkdownEditor.tsx";
|
|
5
|
-
|
|
6
|
-
type SystemPromptMode = "edit" | "preview";
|
|
7
|
-
|
|
8
|
-
interface SystemPromptFieldProps {
|
|
9
|
-
value: string;
|
|
10
|
-
defaultPrompt: string;
|
|
11
|
-
onChange: (value: string) => void;
|
|
12
|
-
onReset?: () => void;
|
|
13
|
-
disabled?: boolean;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function SystemPromptField({
|
|
17
|
-
value,
|
|
18
|
-
defaultPrompt,
|
|
19
|
-
onChange,
|
|
20
|
-
onReset,
|
|
21
|
-
disabled = false,
|
|
22
|
-
}: SystemPromptFieldProps) {
|
|
23
|
-
const [mode, setMode] = useState<SystemPromptMode>("preview");
|
|
24
|
-
const usingDefault = !value.trim() || value.trim() === defaultPrompt.trim();
|
|
25
|
-
const previewContent = usingDefault ? defaultPrompt : value;
|
|
26
|
-
|
|
27
|
-
return (
|
|
28
|
-
<div className="assistant-system-prompt">
|
|
29
|
-
<div className="assistant-system-prompt__shell">
|
|
30
|
-
<div className="assistant-system-prompt__bar">
|
|
31
|
-
<div className="assistant-system-prompt__bar-start">
|
|
32
|
-
<span className="assistant-system-prompt__label">
|
|
33
|
-
System prompt
|
|
34
|
-
</span>
|
|
35
|
-
{usingDefault ? (
|
|
36
|
-
<span className="assistant-system-prompt__tag">Default</span>
|
|
37
|
-
) : null}
|
|
38
|
-
</div>
|
|
39
|
-
<div
|
|
40
|
-
className="assistant-system-prompt__modes"
|
|
41
|
-
role="tablist"
|
|
42
|
-
aria-label="System prompt view"
|
|
43
|
-
>
|
|
44
|
-
{!usingDefault && onReset ? (
|
|
45
|
-
<button
|
|
46
|
-
type="button"
|
|
47
|
-
className="assistant-system-prompt__mode"
|
|
48
|
-
onClick={onReset}
|
|
49
|
-
disabled={disabled}
|
|
50
|
-
aria-label="Reset system prompt"
|
|
51
|
-
title="Reset to default"
|
|
52
|
-
>
|
|
53
|
-
<RotateCcw size={12} aria-hidden />
|
|
54
|
-
</button>
|
|
55
|
-
) : null}
|
|
56
|
-
<button
|
|
57
|
-
type="button"
|
|
58
|
-
className={`assistant-system-prompt__mode ${mode === "edit" ? "assistant-system-prompt__mode--active" : ""}`.trim()}
|
|
59
|
-
role="tab"
|
|
60
|
-
aria-selected={mode === "edit"}
|
|
61
|
-
aria-label="Edit"
|
|
62
|
-
title="Edit"
|
|
63
|
-
onClick={() => setMode("edit")}
|
|
64
|
-
>
|
|
65
|
-
<Pencil size={12} aria-hidden />
|
|
66
|
-
</button>
|
|
67
|
-
<button
|
|
68
|
-
type="button"
|
|
69
|
-
className={`assistant-system-prompt__mode ${mode === "preview" ? "assistant-system-prompt__mode--active" : ""}`.trim()}
|
|
70
|
-
role="tab"
|
|
71
|
-
aria-selected={mode === "preview"}
|
|
72
|
-
aria-label="Preview"
|
|
73
|
-
title="Preview"
|
|
74
|
-
onClick={() => setMode("preview")}
|
|
75
|
-
>
|
|
76
|
-
<Eye size={12} aria-hidden />
|
|
77
|
-
</button>
|
|
78
|
-
</div>
|
|
79
|
-
</div>
|
|
80
|
-
|
|
81
|
-
{mode === "edit" ? (
|
|
82
|
-
<div role="tabpanel">
|
|
83
|
-
<MarkdownEditor
|
|
84
|
-
className="assistant-system-prompt__editor"
|
|
85
|
-
value={value}
|
|
86
|
-
onChange={onChange}
|
|
87
|
-
placeholder="Optional — replaces app default"
|
|
88
|
-
disabled={disabled}
|
|
89
|
-
aria-label="System prompt editor"
|
|
90
|
-
/>
|
|
91
|
-
</div>
|
|
92
|
-
) : (
|
|
93
|
-
<div
|
|
94
|
-
className="assistant-system-prompt__doc"
|
|
95
|
-
role="tabpanel"
|
|
96
|
-
aria-label="System prompt preview"
|
|
97
|
-
>
|
|
98
|
-
<MarkdownContent
|
|
99
|
-
content={previewContent}
|
|
100
|
-
className="assistant-system-prompt__md"
|
|
101
|
-
/>
|
|
102
|
-
</div>
|
|
103
|
-
)}
|
|
104
|
-
</div>
|
|
105
|
-
</div>
|
|
106
|
-
);
|
|
107
|
-
}
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type ComponentPropsWithoutRef,
|
|
3
|
-
createElement,
|
|
4
|
-
type ReactNode,
|
|
5
|
-
useMemo,
|
|
6
|
-
} from "react";
|
|
7
|
-
import { highlightCode } from "../../core/code-highlight.ts";
|
|
8
|
-
import { cn } from "../utils/cn.ts";
|
|
9
|
-
|
|
10
|
-
const HIGHLIGHT_HTML_PATTERN = /<span class="(hljs-[^"]+)">|<\/span>|([^<]+)/g;
|
|
11
|
-
|
|
12
|
-
type HighlightPart =
|
|
13
|
-
| { type: "open"; className: string }
|
|
14
|
-
| { type: "close" }
|
|
15
|
-
| { type: "text"; value: string };
|
|
16
|
-
|
|
17
|
-
function decodeHighlightEntities(text: string): string {
|
|
18
|
-
return text
|
|
19
|
-
.replace(/"/g, '"')
|
|
20
|
-
.replace(/&/g, "&")
|
|
21
|
-
.replace(/</g, "<")
|
|
22
|
-
.replace(/>/g, ">");
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function tokenizeHighlightHtml(html: string): HighlightPart[] {
|
|
26
|
-
const parts: HighlightPart[] = [];
|
|
27
|
-
|
|
28
|
-
for (const match of html.matchAll(HIGHLIGHT_HTML_PATTERN)) {
|
|
29
|
-
if (match[1]) {
|
|
30
|
-
parts.push({ type: "open", className: match[1] });
|
|
31
|
-
continue;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (match[0] === "</span>") {
|
|
35
|
-
parts.push({ type: "close" });
|
|
36
|
-
continue;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (match[2]) {
|
|
40
|
-
parts.push({ type: "text", value: decodeHighlightEntities(match[2]) });
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return parts;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function highlightNodes(
|
|
48
|
-
code: string,
|
|
49
|
-
language: string | null,
|
|
50
|
-
): ReactNode[] {
|
|
51
|
-
const html = highlightCode(code, language);
|
|
52
|
-
const parts = tokenizeHighlightHtml(html);
|
|
53
|
-
const nodes: ReactNode[] = [];
|
|
54
|
-
const stack: { className: string; children: ReactNode[] }[] = [];
|
|
55
|
-
let key = 0;
|
|
56
|
-
|
|
57
|
-
for (const part of parts) {
|
|
58
|
-
if (part.type === "text") {
|
|
59
|
-
const target = stack.at(-1)?.children ?? nodes;
|
|
60
|
-
target.push(part.value);
|
|
61
|
-
continue;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (part.type === "open") {
|
|
65
|
-
stack.push({ className: part.className, children: [] });
|
|
66
|
-
continue;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const span = stack.pop();
|
|
70
|
-
if (!span) continue;
|
|
71
|
-
|
|
72
|
-
const element = createElement(
|
|
73
|
-
"span",
|
|
74
|
-
{ key: key++, className: span.className },
|
|
75
|
-
...span.children,
|
|
76
|
-
);
|
|
77
|
-
const target = stack.at(-1)?.children ?? nodes;
|
|
78
|
-
target.push(element);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return nodes;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export function HighlightedCodeBlock({
|
|
85
|
-
className,
|
|
86
|
-
code,
|
|
87
|
-
language = "json",
|
|
88
|
-
...props
|
|
89
|
-
}: {
|
|
90
|
-
className?: string;
|
|
91
|
-
code: string;
|
|
92
|
-
language?: string | null;
|
|
93
|
-
} & ComponentPropsWithoutRef<"code">) {
|
|
94
|
-
const children = useMemo(
|
|
95
|
-
() => highlightNodes(code, language),
|
|
96
|
-
[code, language],
|
|
97
|
-
);
|
|
98
|
-
|
|
99
|
-
return (
|
|
100
|
-
<code
|
|
101
|
-
className={cn("hljs font-mono text-[11px] leading-snug", className)}
|
|
102
|
-
{...props}
|
|
103
|
-
>
|
|
104
|
-
{children}
|
|
105
|
-
</code>
|
|
106
|
-
);
|
|
107
|
-
}
|
package/src/react/context.tsx
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createContext,
|
|
3
|
-
type ReactNode,
|
|
4
|
-
useContext,
|
|
5
|
-
useEffect,
|
|
6
|
-
useMemo,
|
|
7
|
-
useRef,
|
|
8
|
-
} from "react";
|
|
9
|
-
import { createAssistantStore } from "../core/create-assistant-store.ts";
|
|
10
|
-
import type { AssistantContextValue, AssistantProviderProps } from "./types.ts";
|
|
11
|
-
|
|
12
|
-
const AssistantContext = createContext<AssistantContextValue | null>(null);
|
|
13
|
-
|
|
14
|
-
export function AssistantProvider({
|
|
15
|
-
config,
|
|
16
|
-
children,
|
|
17
|
-
}: AssistantProviderProps) {
|
|
18
|
-
const storeRef = useRef<ReturnType<typeof createAssistantStore> | null>(null);
|
|
19
|
-
if (!storeRef.current) {
|
|
20
|
-
storeRef.current = createAssistantStore(config);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const value = useMemo(
|
|
24
|
-
(): AssistantContextValue => ({
|
|
25
|
-
store: storeRef.current as ReturnType<typeof createAssistantStore>,
|
|
26
|
-
config,
|
|
27
|
-
}),
|
|
28
|
-
[config],
|
|
29
|
-
);
|
|
30
|
-
|
|
31
|
-
return (
|
|
32
|
-
<AssistantContext.Provider value={value}>
|
|
33
|
-
{children}
|
|
34
|
-
</AssistantContext.Provider>
|
|
35
|
-
);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function useAssistantContext(): AssistantContextValue {
|
|
39
|
-
const context = useContext(AssistantContext);
|
|
40
|
-
if (!context) {
|
|
41
|
-
throw new Error(
|
|
42
|
-
"useAssistantContext must be used within AssistantProvider",
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
return context;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function useAssistant<T>(
|
|
49
|
-
selector: (
|
|
50
|
-
state: ReturnType<ReturnType<typeof createAssistantStore>["getState"]>,
|
|
51
|
-
) => T,
|
|
52
|
-
): T {
|
|
53
|
-
const { store } = useAssistantContext();
|
|
54
|
-
return store(selector);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export function useAssistantActions() {
|
|
58
|
-
const { store } = useAssistantContext();
|
|
59
|
-
return store.getState();
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export function AssistantBootstrap({ children }: { children: ReactNode }) {
|
|
63
|
-
const { store, config } = useAssistantContext();
|
|
64
|
-
const autoLoad = config.autoLoadLlmStatus !== false;
|
|
65
|
-
|
|
66
|
-
useEffect(() => {
|
|
67
|
-
if (!autoLoad) return;
|
|
68
|
-
void store.getState().loadLlmStatus();
|
|
69
|
-
}, [autoLoad, store]);
|
|
70
|
-
|
|
71
|
-
return children;
|
|
72
|
-
}
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import { type KeyboardEvent, useEffect, useMemo, useState } from "react";
|
|
2
|
-
import {
|
|
3
|
-
type ChatCommandSuggestion,
|
|
4
|
-
type ChatCommandSurface,
|
|
5
|
-
completionForChatCommand,
|
|
6
|
-
filterChatCommands,
|
|
7
|
-
parseChatCommand,
|
|
8
|
-
shouldShowChatCommandMenu,
|
|
9
|
-
} from "../../core/chat-commands.ts";
|
|
10
|
-
|
|
11
|
-
type UseComposerCommandsOptions = {
|
|
12
|
-
value: string;
|
|
13
|
-
onChange: (value: string) => void;
|
|
14
|
-
surface: ChatCommandSurface;
|
|
15
|
-
onExecute: (commandText: string) => void | Promise<void>;
|
|
16
|
-
disabled?: boolean;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export function useComposerCommands({
|
|
20
|
-
value,
|
|
21
|
-
onChange,
|
|
22
|
-
surface,
|
|
23
|
-
onExecute,
|
|
24
|
-
disabled = false,
|
|
25
|
-
}: UseComposerCommandsOptions) {
|
|
26
|
-
const suggestions = useMemo(
|
|
27
|
-
() => filterChatCommands(value, surface),
|
|
28
|
-
[value, surface],
|
|
29
|
-
);
|
|
30
|
-
const menuOpen = !disabled && shouldShowChatCommandMenu(value, surface);
|
|
31
|
-
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
32
|
-
|
|
33
|
-
const handleInputChange = (next: string) => {
|
|
34
|
-
setSelectedIndex(0);
|
|
35
|
-
onChange(next);
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
useEffect(() => {
|
|
39
|
-
if (selectedIndex >= suggestions.length) {
|
|
40
|
-
setSelectedIndex(0);
|
|
41
|
-
}
|
|
42
|
-
}, [selectedIndex, suggestions.length]);
|
|
43
|
-
|
|
44
|
-
function completeCommand(command: ChatCommandSuggestion) {
|
|
45
|
-
onChange(completionForChatCommand(command));
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
async function tryExecuteCommand(): Promise<boolean> {
|
|
49
|
-
const parsed = parseChatCommand(value);
|
|
50
|
-
if (!parsed) {
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const command = suggestions.find((entry) => entry.name === parsed.name);
|
|
55
|
-
if (!command) {
|
|
56
|
-
return false;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
onChange("");
|
|
60
|
-
await onExecute(command.usage);
|
|
61
|
-
return true;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function handleKeyDown(event: KeyboardEvent<HTMLTextAreaElement>): boolean {
|
|
65
|
-
if (menuOpen && suggestions.length > 0) {
|
|
66
|
-
if (event.key === "ArrowDown") {
|
|
67
|
-
event.preventDefault();
|
|
68
|
-
setSelectedIndex((current) => (current + 1) % suggestions.length);
|
|
69
|
-
return true;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (event.key === "ArrowUp") {
|
|
73
|
-
event.preventDefault();
|
|
74
|
-
setSelectedIndex(
|
|
75
|
-
(current) => (current - 1 + suggestions.length) % suggestions.length,
|
|
76
|
-
);
|
|
77
|
-
return true;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if (event.key === "Tab") {
|
|
81
|
-
event.preventDefault();
|
|
82
|
-
const command = suggestions[selectedIndex] ?? suggestions[0];
|
|
83
|
-
if (command) {
|
|
84
|
-
completeCommand(command);
|
|
85
|
-
}
|
|
86
|
-
return true;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (event.key === "Enter" && !event.shiftKey) {
|
|
90
|
-
event.preventDefault();
|
|
91
|
-
const command = suggestions[selectedIndex] ?? suggestions[0];
|
|
92
|
-
if (!command) {
|
|
93
|
-
return true;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const parsed = parseChatCommand(value);
|
|
97
|
-
if (parsed && suggestions.some((entry) => entry.name === parsed.name)) {
|
|
98
|
-
void tryExecuteCommand();
|
|
99
|
-
} else {
|
|
100
|
-
onChange("");
|
|
101
|
-
void onExecute(command.usage);
|
|
102
|
-
}
|
|
103
|
-
return true;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (event.key === "Enter" && !event.shiftKey) {
|
|
108
|
-
const parsed = parseChatCommand(value);
|
|
109
|
-
if (parsed) {
|
|
110
|
-
event.preventDefault();
|
|
111
|
-
void tryExecuteCommand();
|
|
112
|
-
return true;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return false;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
return {
|
|
120
|
-
suggestions,
|
|
121
|
-
menuOpen,
|
|
122
|
-
selectedIndex,
|
|
123
|
-
setSelectedIndex,
|
|
124
|
-
handleInputChange,
|
|
125
|
-
completeCommand,
|
|
126
|
-
tryExecuteCommand,
|
|
127
|
-
handleKeyDown,
|
|
128
|
-
};
|
|
129
|
-
}
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import { useCallback, useEffect, useState } from "react";
|
|
2
|
-
import type { AssistantToolDefinition } from "../../core/types.ts";
|
|
3
|
-
import { resolvePromptIcon } from "../lib/prompt-icons.ts";
|
|
4
|
-
import type { AssistantSuggestedPromptWithIcon } from "../types.ts";
|
|
5
|
-
|
|
6
|
-
function withIcons(
|
|
7
|
-
prompts: Array<{
|
|
8
|
-
id: string;
|
|
9
|
-
label: string;
|
|
10
|
-
description?: string;
|
|
11
|
-
prompt: string;
|
|
12
|
-
icon?: string;
|
|
13
|
-
}>,
|
|
14
|
-
): AssistantSuggestedPromptWithIcon[] {
|
|
15
|
-
return prompts.map((entry) => ({
|
|
16
|
-
id: entry.id,
|
|
17
|
-
label: entry.label,
|
|
18
|
-
hint: entry.description,
|
|
19
|
-
prompt: entry.prompt,
|
|
20
|
-
icon: resolvePromptIcon(entry.icon),
|
|
21
|
-
}));
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function useSuggestedPrompts(input: {
|
|
25
|
-
staticPrompts?: AssistantSuggestedPromptWithIcon[];
|
|
26
|
-
llmEnabled: boolean;
|
|
27
|
-
model: string | null;
|
|
28
|
-
enabled: boolean;
|
|
29
|
-
dynamicSuggestedPrompts?: boolean;
|
|
30
|
-
listTools: () => Promise<AssistantToolDefinition[]>;
|
|
31
|
-
fetchSuggestedPrompts?: (ctx: {
|
|
32
|
-
llmEnabled: boolean;
|
|
33
|
-
model: string | null;
|
|
34
|
-
tools: AssistantToolDefinition[];
|
|
35
|
-
}) => Promise<
|
|
36
|
-
Array<{
|
|
37
|
-
id: string;
|
|
38
|
-
label: string;
|
|
39
|
-
description?: string;
|
|
40
|
-
prompt: string;
|
|
41
|
-
icon?: string;
|
|
42
|
-
}>
|
|
43
|
-
>;
|
|
44
|
-
}) {
|
|
45
|
-
const {
|
|
46
|
-
staticPrompts,
|
|
47
|
-
llmEnabled,
|
|
48
|
-
model,
|
|
49
|
-
enabled,
|
|
50
|
-
dynamicSuggestedPrompts,
|
|
51
|
-
listTools,
|
|
52
|
-
fetchSuggestedPrompts,
|
|
53
|
-
} = input;
|
|
54
|
-
|
|
55
|
-
const useDynamic =
|
|
56
|
-
dynamicSuggestedPrompts !== false &&
|
|
57
|
-
llmEnabled &&
|
|
58
|
-
enabled &&
|
|
59
|
-
Boolean(fetchSuggestedPrompts);
|
|
60
|
-
|
|
61
|
-
const [prompts, setPrompts] = useState<AssistantSuggestedPromptWithIcon[]>(
|
|
62
|
-
useDynamic ? [] : (staticPrompts ?? []),
|
|
63
|
-
);
|
|
64
|
-
const [loading, setLoading] = useState(false);
|
|
65
|
-
const [error, setError] = useState<string | null>(null);
|
|
66
|
-
const [hasFetched, setHasFetched] = useState(false);
|
|
67
|
-
|
|
68
|
-
useEffect(() => {
|
|
69
|
-
if (useDynamic) {
|
|
70
|
-
setPrompts([]);
|
|
71
|
-
setHasFetched(false);
|
|
72
|
-
setError(null);
|
|
73
|
-
setLoading(false);
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
setPrompts(staticPrompts ?? []);
|
|
78
|
-
setHasFetched(false);
|
|
79
|
-
setError(null);
|
|
80
|
-
setLoading(false);
|
|
81
|
-
}, [useDynamic, staticPrompts]);
|
|
82
|
-
|
|
83
|
-
const refresh = useCallback(async () => {
|
|
84
|
-
if (!useDynamic || !fetchSuggestedPrompts) {
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
setLoading(true);
|
|
89
|
-
setError(null);
|
|
90
|
-
|
|
91
|
-
try {
|
|
92
|
-
const tools = await listTools();
|
|
93
|
-
const fetched = await fetchSuggestedPrompts({
|
|
94
|
-
llmEnabled,
|
|
95
|
-
model,
|
|
96
|
-
tools,
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
if (fetched.length > 0) {
|
|
100
|
-
setPrompts(withIcons(fetched));
|
|
101
|
-
} else if (staticPrompts?.length) {
|
|
102
|
-
setPrompts(staticPrompts);
|
|
103
|
-
} else {
|
|
104
|
-
setPrompts([]);
|
|
105
|
-
}
|
|
106
|
-
setHasFetched(true);
|
|
107
|
-
} catch (loadError) {
|
|
108
|
-
setError(
|
|
109
|
-
loadError instanceof Error
|
|
110
|
-
? loadError.message
|
|
111
|
-
: "Failed to load suggestions",
|
|
112
|
-
);
|
|
113
|
-
setPrompts(staticPrompts ?? []);
|
|
114
|
-
setHasFetched(true);
|
|
115
|
-
} finally {
|
|
116
|
-
setLoading(false);
|
|
117
|
-
}
|
|
118
|
-
}, [
|
|
119
|
-
useDynamic,
|
|
120
|
-
fetchSuggestedPrompts,
|
|
121
|
-
listTools,
|
|
122
|
-
llmEnabled,
|
|
123
|
-
model,
|
|
124
|
-
staticPrompts,
|
|
125
|
-
]);
|
|
126
|
-
|
|
127
|
-
return { prompts, loading, error, useDynamic, refresh, hasFetched };
|
|
128
|
-
}
|
package/src/react/index.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
export type {
|
|
2
|
-
AssistantMessage,
|
|
3
|
-
AssistantStoreDependencies,
|
|
4
|
-
AssistantToolDefinition,
|
|
5
|
-
AssistantToolResult,
|
|
6
|
-
} from "../core/types.ts";
|
|
7
|
-
export {
|
|
8
|
-
Assistant,
|
|
9
|
-
AssistantRoot,
|
|
10
|
-
} from "./Assistant.tsx";
|
|
11
|
-
export { ChatActivity } from "./components/chat/ChatActivity.tsx";
|
|
12
|
-
export { ChatComposer } from "./components/chat/ChatComposer.tsx";
|
|
13
|
-
export { ChatEmptyState } from "./components/chat/ChatEmptyState.tsx";
|
|
14
|
-
export { ChatInteractivePrompt } from "./components/chat/ChatInteractivePrompt/index.tsx";
|
|
15
|
-
export { ChatMessageView } from "./components/chat/ChatMessage.tsx";
|
|
16
|
-
export { ChatMessageScroll } from "./components/chat/ChatMessageScroll.tsx";
|
|
17
|
-
export { ChatReplySuggestions } from "./components/chat/ChatReplySuggestions.tsx";
|
|
18
|
-
export { LlmSettingsStrip } from "./components/chat/LlmSettingsStrip.tsx";
|
|
19
|
-
export { MarkdownContent } from "./components/MarkdownContent.tsx";
|
|
20
|
-
export { MermaidDiagram } from "./components/MermaidDiagram.tsx";
|
|
21
|
-
export { ModelSelector } from "./components/ModelSelector.tsx";
|
|
22
|
-
export {
|
|
23
|
-
AssistantBootstrap,
|
|
24
|
-
AssistantProvider,
|
|
25
|
-
useAssistant,
|
|
26
|
-
useAssistantActions,
|
|
27
|
-
useAssistantContext,
|
|
28
|
-
} from "./context.tsx";
|
|
29
|
-
export { useComposerCommands } from "./hooks/use-composer-commands.ts";
|
|
30
|
-
export type {
|
|
31
|
-
AssistantConfig,
|
|
32
|
-
AssistantContextValue,
|
|
33
|
-
AssistantEmptyStateConfig,
|
|
34
|
-
AssistantHeaderConfig,
|
|
35
|
-
AssistantProps,
|
|
36
|
-
AssistantProviderProps,
|
|
37
|
-
AssistantSuggestedPromptWithIcon,
|
|
38
|
-
AssistantUiConfig,
|
|
39
|
-
} from "./types.ts";
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
export type AssistantErrorKind =
|
|
2
|
-
| "network"
|
|
3
|
-
| "auth"
|
|
4
|
-
| "timeout"
|
|
5
|
-
| "rate-limit"
|
|
6
|
-
| "unknown";
|
|
7
|
-
|
|
8
|
-
export type ParsedAssistantError = {
|
|
9
|
-
title: string;
|
|
10
|
-
detail: string;
|
|
11
|
-
hint?: string;
|
|
12
|
-
kind: AssistantErrorKind;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
function stripKnownPrefix(message: string): string {
|
|
16
|
-
const chatPrefix = "Chat failed: ";
|
|
17
|
-
if (message.startsWith(chatPrefix)) {
|
|
18
|
-
return message.slice(chatPrefix.length).trim();
|
|
19
|
-
}
|
|
20
|
-
return message.trim();
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function parseAssistantError(
|
|
24
|
-
raw: string,
|
|
25
|
-
context: "chat" | "suggestions" = "chat",
|
|
26
|
-
): ParsedAssistantError {
|
|
27
|
-
const detail = stripKnownPrefix(raw);
|
|
28
|
-
const lower = detail.toLowerCase();
|
|
29
|
-
|
|
30
|
-
if (
|
|
31
|
-
lower.includes("failed to fetch") ||
|
|
32
|
-
lower.includes("networkerror") ||
|
|
33
|
-
lower.includes("network error") ||
|
|
34
|
-
lower.includes("load failed") ||
|
|
35
|
-
lower.includes("connection refused") ||
|
|
36
|
-
lower.includes("econnrefused")
|
|
37
|
-
) {
|
|
38
|
-
return {
|
|
39
|
-
title: "Connection lost",
|
|
40
|
-
detail,
|
|
41
|
-
hint:
|
|
42
|
-
context === "chat"
|
|
43
|
-
? "Check your network or LLM endpoint, then try again."
|
|
44
|
-
: "Check your connection and LLM settings.",
|
|
45
|
-
kind: "network",
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (
|
|
50
|
-
lower.includes("unauthorized") ||
|
|
51
|
-
lower.includes("401") ||
|
|
52
|
-
lower.includes("invalid api key") ||
|
|
53
|
-
lower.includes("authentication") ||
|
|
54
|
-
lower.includes("permission denied")
|
|
55
|
-
) {
|
|
56
|
-
return {
|
|
57
|
-
title: "Authentication failed",
|
|
58
|
-
detail,
|
|
59
|
-
hint: "Verify your API key or credentials in LLM settings.",
|
|
60
|
-
kind: "auth",
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (lower.includes("timeout") || lower.includes("timed out")) {
|
|
65
|
-
return {
|
|
66
|
-
title: "Request timed out",
|
|
67
|
-
detail,
|
|
68
|
-
hint: "The model took too long to respond. Try again in a moment.",
|
|
69
|
-
kind: "timeout",
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (
|
|
74
|
-
lower.includes("rate limit") ||
|
|
75
|
-
lower.includes("429") ||
|
|
76
|
-
lower.includes("too many requests")
|
|
77
|
-
) {
|
|
78
|
-
return {
|
|
79
|
-
title: "Rate limit reached",
|
|
80
|
-
detail,
|
|
81
|
-
hint: "Wait a few seconds before sending another request.",
|
|
82
|
-
kind: "rate-limit",
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return {
|
|
87
|
-
title:
|
|
88
|
-
context === "chat" ? "Something went wrong" : "Couldn't load suggestions",
|
|
89
|
-
detail,
|
|
90
|
-
hint:
|
|
91
|
-
context === "chat"
|
|
92
|
-
? "Try again, or review your LLM settings."
|
|
93
|
-
: "Try regenerating, or check your LLM configuration.",
|
|
94
|
-
kind: "unknown",
|
|
95
|
-
};
|
|
96
|
-
}
|