@brainpilot/web 0.0.4 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/index-Br55rkHb.css +1 -0
- package/dist/assets/index-CeUzk-ej.js +445 -0
- package/dist/index.html +2 -2
- package/index.html +13 -0
- package/package.json +12 -3
- package/src/App.tsx +10 -0
- package/src/__tests__/agentsReducer.test.ts +67 -0
- package/src/__tests__/api.test.ts +221 -0
- package/src/__tests__/chatScrollMemory.test.ts +49 -0
- package/src/__tests__/demoConversation.test.ts +73 -0
- package/src/__tests__/demoReset.test.ts +24 -0
- package/src/__tests__/messageGroups.test.ts +80 -0
- package/src/__tests__/newUiComponents.test.tsx +101 -0
- package/src/__tests__/newUiEvents.test.ts +236 -0
- package/src/__tests__/runningToast.test.ts +29 -0
- package/src/__tests__/tokenUsage.test.ts +48 -0
- package/src/__tests__/toolDisplay.test.ts +55 -0
- package/src/__tests__/traceReducer.test.ts +62 -0
- package/src/components/chat/AskUserCard.tsx +123 -0
- package/src/components/chat/AutoRetryIndicator.tsx +71 -0
- package/src/components/chat/ComposerInput.tsx +73 -0
- package/src/components/chat/ComposerSendButton.tsx +26 -0
- package/src/components/chat/MarkdownMessage.tsx +24 -0
- package/src/components/chat/MessageStream.tsx +505 -0
- package/src/components/chat/PromptComposer.tsx +489 -0
- package/src/components/chat/SystemMessageBubble.tsx +46 -0
- package/src/components/chat/chatScrollMemory.ts +49 -0
- package/src/components/demo/DemoFileTree.tsx +146 -0
- package/src/components/demo/DemoView.tsx +730 -0
- package/src/components/demo/TraceNodeModal.tsx +80 -0
- package/src/components/demo/demoBundle.ts +223 -0
- package/src/components/demo/demoCache.ts +42 -0
- package/src/components/demo/demoReset.ts +16 -0
- package/src/components/files/FilePreviewView.tsx +153 -0
- package/src/components/files/FileSidebar.tsx +664 -0
- package/src/components/files/filePreview.ts +113 -0
- package/src/components/primitives/CustomSelect.tsx +200 -0
- package/src/components/primitives/IconButton.tsx +27 -0
- package/src/components/quota/DiskQuotaCriticalDialog.tsx +56 -0
- package/src/components/quota/DiskQuotaWarningDialog.tsx +65 -0
- package/src/components/quota/QuotaFileManager.tsx +197 -0
- package/src/components/search/SearchDialog.tsx +101 -0
- package/src/components/session/AgentNetwork.tsx +1233 -0
- package/src/components/session/AgentTraceViews.tsx +346 -0
- package/src/components/session/AnalyticsTab.tsx +220 -0
- package/src/components/session/GlobalOverview.tsx +108 -0
- package/src/components/session/NodeTooltip.tsx +127 -0
- package/src/components/session/TimelineTab.tsx +320 -0
- package/src/components/session/TraceGraphView.tsx +307 -0
- package/src/components/session/TraceNodeDetail.tsx +179 -0
- package/src/components/session/agentAnalytics.ts +397 -0
- package/src/components/session/agentNetworkShared.ts +339 -0
- package/src/components/session/traceLayout.ts +182 -0
- package/src/components/settings/SettingsDialog.tsx +737 -0
- package/src/components/shell/DesktopShell.tsx +261 -0
- package/src/components/shell/SandboxBuildingOverlay.tsx +73 -0
- package/src/components/shell/SandboxStatus.tsx +287 -0
- package/src/components/shell/TerminalDrawer.tsx +387 -0
- package/src/components/sidebar/Sidebar.tsx +191 -0
- package/src/config.ts +10 -0
- package/src/contexts/AppProviders.tsx +20 -0
- package/src/contexts/AuthContext.tsx +61 -0
- package/src/contexts/PreferencesContext.tsx +125 -0
- package/src/contexts/SSEContext.tsx +264 -0
- package/src/contexts/SandboxContext.tsx +310 -0
- package/src/contexts/SessionContext.tsx +919 -0
- package/src/contexts/agentsReducer.ts +49 -0
- package/src/contexts/draftStore.ts +103 -0
- package/src/contexts/messageFilters.ts +29 -0
- package/src/contexts/messageGroups.ts +77 -0
- package/src/contexts/messageReducer.ts +401 -0
- package/src/contexts/newUiEvents.ts +190 -0
- package/src/contexts/runningToast.ts +33 -0
- package/src/contexts/traceReducer.ts +62 -0
- package/src/contexts/turnTimer.test.ts +97 -0
- package/src/contexts/turnTimer.ts +108 -0
- package/src/contexts/useTurnTimer.ts +104 -0
- package/src/contracts/backend.ts +897 -0
- package/src/contracts/demoBundle.ts +83 -0
- package/src/i18n/messages/analytics.ts +106 -0
- package/src/i18n/messages/chat.ts +130 -0
- package/src/i18n/messages/contexts.ts +42 -0
- package/src/i18n/messages/demo.ts +80 -0
- package/src/i18n/messages/files.ts +82 -0
- package/src/i18n/messages/network.ts +190 -0
- package/src/i18n/messages/profile.ts +44 -0
- package/src/i18n/messages/quota.ts +36 -0
- package/src/i18n/messages/sandbox.ts +116 -0
- package/src/i18n/messages/search.ts +16 -0
- package/src/i18n/messages/settings.ts +188 -0
- package/src/i18n/messages/shell.ts +38 -0
- package/src/i18n/messages/sidebar.ts +52 -0
- package/src/i18n/messages/terminal.ts +22 -0
- package/src/i18n/messages/trace.ts +136 -0
- package/src/i18n/messages.ts +32 -0
- package/src/i18n/translate.ts +46 -0
- package/src/i18n/types.ts +15 -0
- package/src/i18n/useT.ts +15 -0
- package/src/main.tsx +13 -0
- package/src/mocks/backend.ts +729 -0
- package/src/styles/global.css +7578 -0
- package/src/styles/tokens.css +161 -0
- package/src/utils/api.ts +724 -0
- package/src/utils/download.ts +18 -0
- package/src/utils/format.ts +7 -0
- package/src/utils/toolDisplay.ts +74 -0
- package/src/utils/zip.ts +119 -0
- package/src/vite-env.d.ts +1 -0
- package/tsconfig.app.json +22 -0
- package/tsconfig.json +7 -0
- package/tsconfig.node.json +13 -0
- package/vite.config.ts +13 -0
- package/dist/assets/index-Cd0Mi_WU.css +0 -1
- package/dist/assets/index-FGg-DeYR.js +0 -448
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { useEffect, useMemo, useState } from "react";
|
|
2
|
+
import { RotateCw, X } from "lucide-react";
|
|
3
|
+
import type { AutoRetryView } from "../../contracts/backend";
|
|
4
|
+
import { autoRetryCountdownSeconds } from "../../contexts/newUiEvents";
|
|
5
|
+
import { useT } from "../../i18n/useT";
|
|
6
|
+
|
|
7
|
+
interface AutoRetryIndicatorProps {
|
|
8
|
+
view: AutoRetryView;
|
|
9
|
+
/** Abort the pending retry (wired to the interrupt / abort path). */
|
|
10
|
+
onCancel: () => void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 修正6 — auto-retry countdown + cancel. Surfaces a Pi `auto_retry_start`
|
|
15
|
+
* (attempt/maxAttempts/delayMs) as a countdown indicator with a Cancel button
|
|
16
|
+
* that calls the interrupt/abort path.
|
|
17
|
+
*/
|
|
18
|
+
export function AutoRetryIndicator({ view, onCancel }: AutoRetryIndicatorProps) {
|
|
19
|
+
const t = useT();
|
|
20
|
+
const cancelled = view.cancelled === true;
|
|
21
|
+
|
|
22
|
+
const initialSec = useMemo(() => autoRetryCountdownSeconds(view), [view]);
|
|
23
|
+
const [secondsLeft, setSecondsLeft] = useState(initialSec);
|
|
24
|
+
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
if (cancelled || initialSec <= 0) return;
|
|
27
|
+
setSecondsLeft(initialSec);
|
|
28
|
+
const id = window.setInterval(() => {
|
|
29
|
+
setSecondsLeft((prev) => {
|
|
30
|
+
if (prev <= 1) {
|
|
31
|
+
window.clearInterval(id);
|
|
32
|
+
return 0;
|
|
33
|
+
}
|
|
34
|
+
return prev - 1;
|
|
35
|
+
});
|
|
36
|
+
}, 1000);
|
|
37
|
+
return () => window.clearInterval(id);
|
|
38
|
+
}, [cancelled, initialSec]);
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<div
|
|
42
|
+
className={`auto-retry${cancelled ? " auto-retry--cancelled" : ""}`}
|
|
43
|
+
role="status"
|
|
44
|
+
data-testid="auto-retry"
|
|
45
|
+
>
|
|
46
|
+
<RotateCw size={14} className="auto-retry__icon" aria-hidden="true" />
|
|
47
|
+
<div className="auto-retry__body">
|
|
48
|
+
<span className="auto-retry__title">{t("chat.retry.title")}</span>
|
|
49
|
+
<span className="auto-retry__attempt">
|
|
50
|
+
{t("chat.retry.attempt", { attempt: view.attempt, max: view.maxAttempts })}
|
|
51
|
+
</span>
|
|
52
|
+
{cancelled ? (
|
|
53
|
+
<span className="auto-retry__status">{t("chat.retry.cancelled")}</span>
|
|
54
|
+
) : secondsLeft > 0 ? (
|
|
55
|
+
<span className="auto-retry__countdown">{t("chat.retry.countdown", { sec: secondsLeft })}</span>
|
|
56
|
+
) : null}
|
|
57
|
+
</div>
|
|
58
|
+
{!cancelled ? (
|
|
59
|
+
<button
|
|
60
|
+
type="button"
|
|
61
|
+
className="auto-retry__cancel"
|
|
62
|
+
onClick={onCancel}
|
|
63
|
+
aria-label={t("chat.retry.cancel")}
|
|
64
|
+
>
|
|
65
|
+
<X size={13} aria-hidden="true" />
|
|
66
|
+
{t("chat.retry.cancel")}
|
|
67
|
+
</button>
|
|
68
|
+
) : null}
|
|
69
|
+
</div>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { useEffect, useRef } from "react";
|
|
2
|
+
import type { KeyboardEvent } from "react";
|
|
3
|
+
import { useDraft } from "../../contexts/draftStore";
|
|
4
|
+
|
|
5
|
+
interface ComposerInputProps {
|
|
6
|
+
/** Active session id; drafts are isolated per session. null disables editing. */
|
|
7
|
+
sessionId: string | null;
|
|
8
|
+
placeholder: string;
|
|
9
|
+
/** Aria label for the textarea (sr-only label uses the same text). */
|
|
10
|
+
ariaLabel: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Isolated textarea bound to draftStore[sessionId].
|
|
15
|
+
*
|
|
16
|
+
* Splitting this out of PromptComposer is the whole point of the input-lag
|
|
17
|
+
* fix: keystrokes used to re-render the whole chat subtree because draft state
|
|
18
|
+
* lived on SessionContext. Now keystrokes only re-render this component (and
|
|
19
|
+
* its sibling ComposerSendButton, which also subscribes to the same store).
|
|
20
|
+
*
|
|
21
|
+
* Form submission is owned by the enclosing <form> in PromptComposer; this
|
|
22
|
+
* component just handles Enter-to-submit by walking up to the form.
|
|
23
|
+
*/
|
|
24
|
+
export function ComposerInput({ sessionId, placeholder, ariaLabel }: ComposerInputProps) {
|
|
25
|
+
const [draft, setDraft] = useDraft(sessionId);
|
|
26
|
+
const textareaRef = useRef<HTMLTextAreaElement | null>(null);
|
|
27
|
+
|
|
28
|
+
// Grow textarea to fit content. Reading scrollHeight forces a layout — fine
|
|
29
|
+
// here because only this component re-renders on draft change.
|
|
30
|
+
const autoResize = () => {
|
|
31
|
+
const textarea = textareaRef.current;
|
|
32
|
+
if (!textarea) return;
|
|
33
|
+
textarea.style.height = "auto";
|
|
34
|
+
textarea.style.height = `${textarea.scrollHeight}px`;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// Resize on draft change (covers store-driven updates: slash menu /
|
|
38
|
+
// suggestions / switching sessions) and initial mount with a pre-existing
|
|
39
|
+
// draft (e.g. user typed, switched tabs, switched back).
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
autoResize();
|
|
42
|
+
}, [draft]);
|
|
43
|
+
|
|
44
|
+
const handleKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>) => {
|
|
45
|
+
// Shift+Enter inserts a newline; bare Enter submits. Skip while IME is
|
|
46
|
+
// composing so CJK candidate selection doesn't fire submit.
|
|
47
|
+
if (event.key !== "Enter" || event.shiftKey || event.nativeEvent.isComposing) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
event.preventDefault();
|
|
51
|
+
event.currentTarget.form?.requestSubmit();
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<>
|
|
56
|
+
<label className="sr-only" htmlFor="prompt-input">
|
|
57
|
+
{ariaLabel}
|
|
58
|
+
</label>
|
|
59
|
+
<textarea
|
|
60
|
+
ref={textareaRef}
|
|
61
|
+
id="prompt-input"
|
|
62
|
+
rows={1}
|
|
63
|
+
value={draft}
|
|
64
|
+
onChange={(event) => {
|
|
65
|
+
setDraft(event.target.value);
|
|
66
|
+
autoResize();
|
|
67
|
+
}}
|
|
68
|
+
onKeyDown={handleKeyDown}
|
|
69
|
+
placeholder={placeholder}
|
|
70
|
+
/>
|
|
71
|
+
</>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ArrowUp } from "lucide-react";
|
|
2
|
+
import { useDraft } from "../../contexts/draftStore";
|
|
3
|
+
import { IconButton } from "../primitives/IconButton";
|
|
4
|
+
|
|
5
|
+
interface ComposerSendButtonProps {
|
|
6
|
+
sessionId: string | null;
|
|
7
|
+
canSend: boolean;
|
|
8
|
+
label: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Send button that subscribes only to draftStore[sessionId] to compute its
|
|
13
|
+
* disabled state. Sibling of ComposerInput; lives inside the same <form> in
|
|
14
|
+
* PromptComposer, so click triggers normal form submission.
|
|
15
|
+
*
|
|
16
|
+
* Subscribing here (rather than passing isEmpty down from PromptComposer)
|
|
17
|
+
* keeps the parent off the keystroke render path entirely.
|
|
18
|
+
*/
|
|
19
|
+
export function ComposerSendButton({ sessionId, canSend, label }: ComposerSendButtonProps) {
|
|
20
|
+
const [draft] = useDraft(sessionId);
|
|
21
|
+
return (
|
|
22
|
+
<IconButton disabled={!canSend || !draft.trim()} label={label} type="submit" variant="strong">
|
|
23
|
+
<ArrowUp size={18} />
|
|
24
|
+
</IconButton>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { memo } from "react";
|
|
2
|
+
import ReactMarkdown from "react-markdown";
|
|
3
|
+
import remarkGfm from "remark-gfm";
|
|
4
|
+
import rehypeHighlight from "rehype-highlight";
|
|
5
|
+
|
|
6
|
+
interface MarkdownMessageProps {
|
|
7
|
+
content: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function MarkdownMessageImpl({ content }: MarkdownMessageProps) {
|
|
11
|
+
return (
|
|
12
|
+
<div className="message-card__content">
|
|
13
|
+
<ReactMarkdown remarkPlugins={[remarkGfm]} rehypePlugins={[rehypeHighlight]}>
|
|
14
|
+
{content}
|
|
15
|
+
</ReactMarkdown>
|
|
16
|
+
</div>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Memoized so re-renders driven by unrelated parent state (e.g. a sibling
|
|
21
|
+
// component changing) don't re-parse markdown for every visible message —
|
|
22
|
+
// `content` is a string so default shallow-equal compare is precise.
|
|
23
|
+
export const MarkdownMessage = memo(MarkdownMessageImpl);
|
|
24
|
+
|