ompchamber 1.2.1 → 2.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.
- package/README.md +143 -147
- package/dist/client/index.html +4 -2
- package/dist/client/static/css/index.5f630421b7.css +2 -0
- package/dist/client/static/js/77.0d81c74cf0.js +139 -0
- package/dist/client/static/js/async/1k.973e8e21fc.js +2 -0
- package/dist/client/static/js/async/{3y.3186ecdd63.js → 3y.3530b824ad.js} +6 -6
- package/dist/client/static/js/async/{q.b453193538.js → 4m.928a1dde85.js} +10 -10
- package/dist/client/static/js/async/66.5dfa29f957.js +93 -0
- package/dist/client/static/js/async/7g.a7814350c3.js +1 -0
- package/dist/client/static/js/async/ar.9303e5f2e8.js +2 -0
- package/dist/client/static/js/async/{cx.9c8268d542.js → cx.3cb0242a3a.js} +1 -1
- package/dist/client/static/js/async/e.93214d622b.js +79 -0
- package/dist/client/static/js/async/g.cb81980498.js +2 -0
- package/dist/client/static/js/async/h1.393f066d09.js +1 -0
- package/dist/client/static/js/async/jl.874d352278.js +1 -0
- package/dist/client/static/js/async/{k.d16cd09ae7.js → k.3210286401.js} +1 -1
- package/dist/client/static/js/async/{m.2e1ea3db9e.js → m.eb2e6752e2.js} +3 -3
- package/dist/client/static/js/async/m.eb2e6752e2.js.LICENSE.txt +11 -0
- package/dist/client/static/js/async/mt.0352e976d8.js +1 -0
- package/dist/client/static/js/async/{oc.eb22093f05.js → oc.b73042e8bd.js} +1 -1
- package/dist/client/static/js/async/{og.53f068804c.js → og.8eb577893a.js} +1 -1
- package/dist/client/static/js/async/px.fc6877924b.js +1 -0
- package/dist/client/static/js/async/q.22588845a9.js +21 -0
- package/dist/client/static/js/async/{q5.88b50ffa95.js → q5.97dc1481b6.js} +1 -1
- package/dist/client/static/js/async/s.0f395cdda5.js +94 -0
- package/dist/client/static/js/async/{tr.2a0d2b7600.js → tr.e878658140.js} +1 -1
- package/dist/client/static/js/async/vt.42416b707d.js +1 -0
- package/dist/client/static/js/async/x1.da8687159b.js +90 -0
- package/dist/client/static/js/async/xe.da8dcc2015.js +2 -0
- package/dist/client/static/js/async/xe.da8dcc2015.js.LICENSE.txt +11 -0
- package/dist/client/static/js/async/{xn.6360379f71.js → xn.6510c0abe2.js} +2 -2
- package/dist/client/static/js/async/{yx.af2936c368.js → xn1.83a7784fe1.js} +3 -3
- package/dist/client/static/js/async/xn1.83a7784fe1.js.LICENSE.txt +11 -0
- package/dist/client/static/js/async/yg.35bebd6d0c.js +149 -0
- package/dist/client/static/js/async/yv.d99d829136.js +1 -0
- package/dist/client/static/js/index.1fd9e1c543.js +38 -0
- package/package.json +3 -3
- package/src/client/components/common/ComposerTextarea.tsx +9 -1
- package/src/client/components/common/MarkdownRenderer.tsx +50 -12
- package/src/client/components/mobile/mobile-right-sidebar/FullEditor.tsx +9 -3
- package/src/client/components/settings/Modal.tsx +11 -2
- package/src/client/components/settings/categories/AppearanceSettings.tsx +7 -30
- package/src/client/components/settings/categories/ProviderSettings.tsx +2 -0
- package/src/client/components/settings/categories/appearance-settings/ThemeCard.tsx +61 -0
- package/src/client/components/settings/categories/appearance-settings/ThemeGrid.tsx +80 -0
- package/src/client/components/settings/categories/chat-settings/TitleSection.tsx +1 -1
- package/src/client/components/settings/categories/provider-settings/AddProviderModal.tsx +43 -6
- package/src/client/components/settings/categories/provider-settings/ModelConfigModal.tsx +54 -54
- package/src/client/components/workspace/SearchPanel.tsx +16 -3
- package/src/client/components/workspace/btw-panel/AskCard.tsx +11 -6
- package/src/client/components/workspace/btw-panel/Messages.tsx +105 -51
- package/src/client/components/workspace/btw-panel/index.tsx +124 -45
- package/src/client/components/workspace/chat-timeline/AiMessageFooter.tsx +30 -14
- package/src/client/components/workspace/chat-timeline/ComposerDock.tsx +10 -1
- package/src/client/components/workspace/chat-timeline/GeneratingIndicator.tsx +8 -2
- package/src/client/components/workspace/chat-timeline/MessageItem.tsx +27 -16
- package/src/client/components/workspace/chat-timeline/MessageList.tsx +11 -0
- package/src/client/components/workspace/chat-timeline/RunFooter.tsx +8 -0
- package/src/client/components/workspace/chat-timeline/chat-input/index.tsx +12 -1
- package/src/client/components/workspace/chat-timeline/index.tsx +7 -2
- package/src/client/components/workspace/chat-timeline/tool-renderers/ask-panel/QuestionBlock.tsx +42 -15
- package/src/client/components/workspace/chat-timeline/tool-renderers/ask-panel/index.tsx +13 -1
- package/src/client/components/workspace/chat-timeline/tool-renderers/extension-dialog/index.tsx +13 -4
- package/src/client/components/workspace/diff-panel/SplitView.tsx +4 -1
- package/src/client/components/workspace/diff-panel/UnifiedView.tsx +70 -65
- package/src/client/components/workspace/diff-panel/index.tsx +8 -1
- package/src/client/components/workspace/editor/index.tsx +18 -2
- package/src/client/components/workspace/file-explorer/GitRepoDropdown.tsx +15 -41
- package/src/client/components/workspace/file-explorer/index.tsx +86 -16
- package/src/client/components/workspace/git-panel/index.tsx +60 -78
- package/src/client/components/workspace/terminal-panel/Header.tsx +16 -1
- package/src/client/components/workspace/terminal-panel/RealtimeXtermView.tsx +5 -5
- package/src/client/components/workspace/terminal-panel/index.tsx +6 -2
- package/src/client/components/workspace/terminal-panel/mount.ts +2 -2
- package/src/client/data/theme/terminal.ts +50 -52
- package/src/client/hooks/chat/btw/index.ts +139 -18
- package/src/client/hooks/chat/btw/intercept.ts +8 -8
- package/src/client/hooks/chat/btw/mode.ts +111 -16
- package/src/client/hooks/chat/composer/index.ts +10 -4
- package/src/client/hooks/chat/timeline/access-mode.ts +41 -0
- package/src/client/hooks/chat/timeline/ask-frames.test.ts +87 -0
- package/src/client/hooks/chat/timeline/ask-frames.ts +20 -1
- package/src/client/hooks/chat/timeline/auto-scroll.ts +13 -4
- package/src/client/hooks/chat/timeline/index.ts +8 -20
- package/src/client/hooks/chat/timeline/queue.ts +66 -9
- package/src/client/hooks/chat/timeline/scroll.test.ts +260 -0
- package/src/client/hooks/chat/timeline/scroll.ts +93 -20
- package/src/client/hooks/chat/timeline/session-load.ts +7 -1
- package/src/client/hooks/chat/timeline/session-pagination.test.ts +167 -0
- package/src/client/hooks/chat/timeline/session-pagination.ts +37 -11
- package/src/client/hooks/editor/save-file.ts +62 -0
- package/src/client/hooks/editor/use-file-editor.test.ts +61 -5
- package/src/client/hooks/editor/use-file-editor.ts +38 -29
- package/src/client/hooks/editor/use-file-transfer.ts +5 -2
- package/src/client/hooks/settings/providers.ts +34 -3
- package/src/client/hooks/ui/open-file.ts +7 -1
- package/src/client/hooks/ui/theme.ts +82 -57
- package/src/client/hooks/workspace/file-tabs.ts +5 -1
- package/src/client/hooks/workspace/repo-scope/index.ts +119 -0
- package/src/client/hooks/workspace/repo-scope/store.test.ts +161 -0
- package/src/client/hooks/workspace/repo-scope/store.ts +201 -0
- package/src/client/hooks/workspace/search-stream.ts +24 -5
- package/src/client/main.tsx +6 -0
- package/src/client/tailwind.css +19 -56
- package/src/server/lib/btw/child.server.ts +41 -0
- package/src/server/lib/btw/lifecycle.server.ts +254 -0
- package/src/server/lib/btw/prompt.ts +13 -5
- package/src/server/lib/btw/registry.server.ts +13 -4
- package/src/server/lib/btw/runtime.server.ts +149 -156
- package/src/server/lib/btw/schema.server.ts +27 -0
- package/src/server/lib/btw/service.server.ts +106 -5
- package/src/server/lib/btw/store.server.ts +57 -6
- package/src/server/lib/db/schema.ts +4 -0
- package/src/server/lib/db/settings-store.test.ts +65 -0
- package/src/server/lib/db/settings-store.ts +25 -0
- package/src/server/lib/fs/atomic-write.ts +42 -4
- package/src/server/lib/fs/config-lock.ts +74 -0
- package/src/server/lib/fs/git-ignore.ts +55 -5
- package/src/server/lib/fs/ripgrep.ts +119 -0
- package/src/server/lib/lifecycle/identity.ts +10 -64
- package/src/server/lib/lifecycle/proc/darwin.ts +238 -0
- package/src/server/lib/lifecycle/proc/index.ts +38 -0
- package/src/server/lib/lifecycle/proc/linux.ts +80 -0
- package/src/server/lib/lifecycle/proc/ps.ts +86 -0
- package/src/server/lib/lifecycle/proc/types.ts +33 -0
- package/src/server/lib/lifecycle/proc/win32.ts +53 -0
- package/src/server/lib/models/provider-registry.server.ts +2 -2
- package/src/server/lib/models/registry.server.ts +1 -1
- package/src/server/lib/omp/config/behavior.ts +17 -17
- package/src/server/lib/omp/config/disabled-providers.ts +84 -35
- package/src/server/lib/omp/config/document.ts +128 -0
- package/src/server/lib/omp/config/extensions.ts +11 -10
- package/src/server/lib/omp/config/mcp.ts +4 -57
- package/src/server/lib/omp/config/model-overrides.ts +123 -0
- package/src/server/lib/omp/config/models-config.ts +92 -0
- package/src/server/lib/omp/config/models-validation.ts +159 -0
- package/src/server/lib/omp/config/path-scoped.ts +74 -0
- package/src/server/lib/omp/config/providers.ts +241 -211
- package/src/server/lib/omp/config/roles.ts +6 -14
- package/src/server/lib/omp/core/auth-credentials.ts +1 -1
- package/src/server/lib/omp/rpc/frame-fold.test.ts +124 -0
- package/src/server/lib/omp/rpc/frame-fold.ts +43 -24
- package/src/server/lib/omp/rpc/lifecycle.test.ts +41 -0
- package/src/server/lib/omp/rpc/manager.ts +21 -21
- package/src/server/lib/omp/rpc/pending-ui-dialogs.ts +11 -7
- package/src/server/lib/omp/rpc/session-commands.ts +17 -29
- package/src/server/lib/omp/rpc/session-registry.ts +5 -66
- package/src/server/lib/omp/rpc/web-state.ts +0 -6
- package/src/server/lib/omp/session/auto-title.server.test.ts +109 -11
- package/src/server/lib/omp/session/auto-title.server.ts +95 -20
- package/src/server/lib/omp/session/sidebar-data.server.ts +11 -6
- package/src/server/lib/queue/delivery-dispatch.server.test.ts +162 -0
- package/src/server/lib/queue/delivery-harness.ts +88 -0
- package/src/server/lib/queue/delivery.server.test.ts +78 -149
- package/src/server/lib/queue/delivery.server.ts +105 -13
- package/src/server/lib/queue/store.server.ts +30 -5
- package/src/server/lib/terminal/foreground.test.ts +164 -0
- package/src/server/lib/terminal/foreground.ts +34 -6
- package/src/server/lib/terminal/history.ts +8 -7
- package/src/server/plugins/compress.ts +33 -5
- package/src/server/plugins/ssr.ts +14 -7
- package/src/server/routes/btw/topics.ts +89 -2
- package/src/server/routes/fs/action.test.ts +64 -0
- package/src/server/routes/fs/action.ts +10 -1
- package/src/server/routes/fs/git.ts +5 -6
- package/src/server/routes/fs/search.ts +17 -26
- package/src/server/routes/sessions/queue.ts +17 -4
- package/src/server/routes/settings/index.ts +2 -0
- package/src/server/routes/settings/model-override.ts +69 -0
- package/src/server/routes/settings/provider-models.ts +35 -12
- package/src/server/routes/settings/providers.ts +31 -1
- package/src/server/routes/settings/root.ts +8 -3
- package/src/shared/lib/chat/btw/client.ts +34 -0
- package/src/shared/lib/chat/timeline/tool-phrases.ts +7 -0
- package/src/shared/lib/code/line-endings.test.ts +38 -0
- package/src/shared/lib/code/line-endings.ts +56 -0
- package/src/shared/lib/code/shiki-themes.ts +9 -5
- package/src/shared/lib/fs/file-tree.ts +17 -12
- package/src/shared/lib/markdown/autolink.test.ts +32 -0
- package/src/shared/lib/markdown/autolink.ts +50 -0
- package/src/shared/lib/markdown/document-urls.test.ts +68 -0
- package/src/shared/lib/markdown/document-urls.ts +118 -0
- package/src/shared/lib/markdown/marked.ts +27 -15
- package/src/shared/lib/markdown/mermaid.ts +2 -2
- package/src/shared/lib/models/catalog.ts +1 -1
- package/src/shared/lib/omp/session/schema-migrations.ts +30 -0
- package/src/shared/lib/omp/session/stream-state.server.test.ts +54 -0
- package/src/shared/lib/omp/session/stream-state.server.ts +70 -21
- package/src/shared/lib/settings/client.ts +10 -4
- package/src/shared/lib/settings/diff.test.ts +31 -0
- package/src/shared/lib/settings/diff.ts +37 -0
- package/src/shared/lib/theme/catalog.test.ts +168 -0
- package/src/shared/lib/theme/catalog.ts +98 -0
- package/src/shared/lib/theme/color.ts +88 -0
- package/src/shared/lib/theme/css.ts +70 -0
- package/src/shared/lib/theme/palettes/chamber.ts +61 -0
- package/src/shared/lib/theme/palettes/dark.ts +313 -0
- package/src/shared/lib/theme/palettes/light.ts +313 -0
- package/src/shared/types/btw.ts +83 -4
- package/src/shared/types/index.ts +1 -0
- package/src/shared/types/settings/provider.ts +8 -1
- package/src/shared/types/settings/state.ts +10 -4
- package/src/shared/types/theme.ts +48 -0
- package/dist/client/static/css/index.b938f4a693.css +0 -2
- package/dist/client/static/js/77.8022a800b5.js +0 -139
- package/dist/client/static/js/async/1k.a411fe5b43.js +0 -2
- package/dist/client/static/js/async/66.86544ad741.js +0 -93
- package/dist/client/static/js/async/7g.db82aca7ba.js +0 -1
- package/dist/client/static/js/async/ar.ad5c8822a8.js +0 -2
- package/dist/client/static/js/async/e.6443e739a2.js +0 -79
- package/dist/client/static/js/async/g.ee41bfed7f.js +0 -2
- package/dist/client/static/js/async/h1.d7091cef78.js +0 -1
- package/dist/client/static/js/async/jl.4911fa3383.js +0 -1
- package/dist/client/static/js/async/m.2e1ea3db9e.js.LICENSE.txt +0 -6
- package/dist/client/static/js/async/mt.853be2b5aa.js +0 -1
- package/dist/client/static/js/async/ot.84c71b308f.js +0 -2
- package/dist/client/static/js/async/px.783b6f91f2.js +0 -1
- package/dist/client/static/js/async/q8.7f1b48e9cd.js +0 -21
- package/dist/client/static/js/async/q8.7f1b48e9cd.js.LICENSE.txt +0 -6
- package/dist/client/static/js/async/s.aad2ecebc6.js +0 -94
- package/dist/client/static/js/async/vt.20406a5604.js +0 -1
- package/dist/client/static/js/async/x1.fe8af17016.js +0 -90
- package/dist/client/static/js/async/xn.6360379f71.js.LICENSE.txt +0 -6
- package/dist/client/static/js/async/yg.5a94e1fc8a.js +0 -149
- package/dist/client/static/js/async/yv.2fa22f009a.js +0 -1
- package/dist/client/static/js/index.5fe7a2cb64.js +0 -34
- package/src/client/components/workspace/btw-panel/Composer.tsx +0 -183
- package/src/client/components/workspace/btw-panel/attachments.ts +0 -80
- /package/dist/client/static/js/{77.8022a800b5.js.LICENSE.txt → 77.0d81c74cf0.js.LICENSE.txt} +0 -0
- /package/dist/client/static/js/async/{g.ee41bfed7f.js.LICENSE.txt → 1k.973e8e21fc.js.LICENSE.txt} +0 -0
- /package/dist/client/static/js/async/{3y.3186ecdd63.js.LICENSE.txt → 3y.3530b824ad.js.LICENSE.txt} +0 -0
- /package/dist/client/static/js/async/{ot.84c71b308f.js.LICENSE.txt → 4m.928a1dde85.js.LICENSE.txt} +0 -0
- /package/dist/client/static/js/async/{q.b453193538.js.LICENSE.txt → ar.9303e5f2e8.js.LICENSE.txt} +0 -0
- /package/dist/client/static/js/async/{yx.af2936c368.js.LICENSE.txt → g.cb81980498.js.LICENSE.txt} +0 -0
- /package/dist/client/static/js/async/{1k.a411fe5b43.js.LICENSE.txt → q.22588845a9.js.LICENSE.txt} +0 -0
- /package/dist/client/static/js/async/{ar.ad5c8822a8.js.LICENSE.txt → xn.6510c0abe2.js.LICENSE.txt} +0 -0
- /package/dist/client/static/js/{index.5fe7a2cb64.js.LICENSE.txt → index.1fd9e1c543.js.LICENSE.txt} +0 -0
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* BTW panel composer card — the side question's own input.
|
|
3
|
-
*
|
|
4
|
-
* Pure presentation: text, attachments and the running turn are owned by the
|
|
5
|
-
* parent; this file only autosizes the textarea, reads keys and renders.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { useEffect, useRef } from 'preact/hooks';
|
|
9
|
-
import type { TargetedEvent, TargetedKeyboardEvent } from 'preact';
|
|
10
|
-
import { File as FileIcon, Paperclip, Send, Shield, Square, X } from 'lucide-preact';
|
|
11
|
-
import { formatBytes } from '@/shared/lib/format/number';
|
|
12
|
-
import { providerLabel } from '@/shared/lib/models/provider-label';
|
|
13
|
-
|
|
14
|
-
export interface BtwComposerProps {
|
|
15
|
-
value: string;
|
|
16
|
-
onChange: (value: string) => void;
|
|
17
|
-
onSubmit: () => void;
|
|
18
|
-
onStop: () => void;
|
|
19
|
-
running: boolean;
|
|
20
|
-
modelLabel?: string;
|
|
21
|
-
provider?: string;
|
|
22
|
-
providerNames?: Record<string, string>;
|
|
23
|
-
attachments: { id: string; name: string; size: number }[];
|
|
24
|
-
onFilesSelected: (files: File[]) => void;
|
|
25
|
-
onRemoveAttachment: (id: string) => void;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const ICON_BUTTON = 'p-1.5 rounded text-ink/60 hover:text-ink hover:bg-ink/5 transition-colors cursor-pointer';
|
|
29
|
-
|
|
30
|
-
export function BtwComposer({
|
|
31
|
-
value,
|
|
32
|
-
onChange,
|
|
33
|
-
onSubmit,
|
|
34
|
-
onStop,
|
|
35
|
-
running,
|
|
36
|
-
modelLabel,
|
|
37
|
-
provider,
|
|
38
|
-
providerNames,
|
|
39
|
-
attachments,
|
|
40
|
-
onFilesSelected,
|
|
41
|
-
onRemoveAttachment,
|
|
42
|
-
}: BtwComposerProps) {
|
|
43
|
-
const fileInputRef = useRef<HTMLInputElement>(null);
|
|
44
|
-
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
|
45
|
-
|
|
46
|
-
const canSend = value.trim().length > 0 || attachments.length > 0;
|
|
47
|
-
const providerText = provider ? providerLabel(provider, providerNames) : '';
|
|
48
|
-
|
|
49
|
-
// The form replaces the chat composer that had focus, so the caret is put
|
|
50
|
-
// here — the field the form is for, and the one a restored draft is waiting
|
|
51
|
-
// in — instead of being left on the document body.
|
|
52
|
-
useEffect(() => {
|
|
53
|
-
const textarea = textareaRef.current;
|
|
54
|
-
if (!textarea) return;
|
|
55
|
-
textarea.focus();
|
|
56
|
-
textarea.setSelectionRange(textarea.value.length, textarea.value.length);
|
|
57
|
-
}, []);
|
|
58
|
-
|
|
59
|
-
// Grow with the content and collapse again when the parent clears `value`
|
|
60
|
-
// after a submit — `height: auto` first, otherwise the box can only expand.
|
|
61
|
-
useEffect(() => {
|
|
62
|
-
const textarea = textareaRef.current;
|
|
63
|
-
if (!textarea) return;
|
|
64
|
-
textarea.style.height = 'auto';
|
|
65
|
-
textarea.style.height = `${textarea.scrollHeight}px`;
|
|
66
|
-
}, [value]);
|
|
67
|
-
|
|
68
|
-
const handleKeyDown = (event: TargetedKeyboardEvent<HTMLTextAreaElement>) => {
|
|
69
|
-
if (event.key === 'Escape') {
|
|
70
|
-
event.currentTarget.blur();
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
if (event.key !== 'Enter' || event.shiftKey) return;
|
|
74
|
-
// IME candidate selection must not submit the question.
|
|
75
|
-
if (event.isComposing || event.keyCode === 229) return;
|
|
76
|
-
event.preventDefault();
|
|
77
|
-
if (canSend) onSubmit();
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
const handleFileSelect = (event: TargetedEvent<HTMLInputElement>) => {
|
|
81
|
-
const files = event.currentTarget.files;
|
|
82
|
-
if (files && files.length > 0) onFilesSelected(Array.from(files));
|
|
83
|
-
if (fileInputRef.current) fileInputRef.current.value = '';
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
return (
|
|
87
|
-
<div className="bg-paper border border-ink/20 rounded-2xl shadow-lg flex flex-col overflow-hidden">
|
|
88
|
-
<textarea
|
|
89
|
-
ref={textareaRef}
|
|
90
|
-
rows={1}
|
|
91
|
-
value={value}
|
|
92
|
-
onInput={(event) => onChange(event.currentTarget.value)}
|
|
93
|
-
onKeyDown={handleKeyDown}
|
|
94
|
-
placeholder="Ask in this btw session..."
|
|
95
|
-
className="w-full bg-transparent text-[13px] text-ink placeholder-ink/40 resize-none outline-none px-3.5 pt-3 pb-1 max-h-32"
|
|
96
|
-
/>
|
|
97
|
-
|
|
98
|
-
{attachments.length > 0 && (
|
|
99
|
-
<div className="flex items-center flex-wrap gap-1.5 px-3 pt-2">
|
|
100
|
-
{attachments.map((attachment) => (
|
|
101
|
-
<div
|
|
102
|
-
key={attachment.id}
|
|
103
|
-
className="relative flex items-center bg-canvas border border-ink/10 rounded-md p-0.5 pr-6 text-xs"
|
|
104
|
-
>
|
|
105
|
-
<div className="w-6 h-6 flex items-center justify-center bg-ink/5 rounded-sm mr-1.5 text-ink/60">
|
|
106
|
-
<FileIcon size={12} strokeWidth={2} />
|
|
107
|
-
</div>
|
|
108
|
-
<span className="truncate max-w-[120px] font-mono text-[10px] text-ink/80">{attachment.name}</span>
|
|
109
|
-
{formatBytes(attachment.size) && (
|
|
110
|
-
<span className="ml-1.5 font-mono text-[10px] text-ink/40">{formatBytes(attachment.size)}</span>
|
|
111
|
-
)}
|
|
112
|
-
<button
|
|
113
|
-
type="button"
|
|
114
|
-
onClick={() => onRemoveAttachment(attachment.id)}
|
|
115
|
-
className="absolute right-0.5 top-1/2 -translate-y-1/2 p-0.5 text-ink/40 hover:text-error hover:bg-error/10 rounded transition-colors cursor-pointer"
|
|
116
|
-
aria-label={`Remove ${attachment.name}`}
|
|
117
|
-
title="Remove attachment"
|
|
118
|
-
>
|
|
119
|
-
<X size={10} strokeWidth={2} />
|
|
120
|
-
</button>
|
|
121
|
-
</div>
|
|
122
|
-
))}
|
|
123
|
-
</div>
|
|
124
|
-
)}
|
|
125
|
-
|
|
126
|
-
<div className="flex items-center justify-between px-2 pb-2">
|
|
127
|
-
<div className="flex items-center gap-0.5">
|
|
128
|
-
<button
|
|
129
|
-
type="button"
|
|
130
|
-
onClick={() => fileInputRef.current?.click()}
|
|
131
|
-
className={ICON_BUTTON}
|
|
132
|
-
aria-label="Attach files"
|
|
133
|
-
title="Attach files"
|
|
134
|
-
>
|
|
135
|
-
<Paperclip size={14} strokeWidth={2} />
|
|
136
|
-
</button>
|
|
137
|
-
|
|
138
|
-
<span
|
|
139
|
-
className="p-1.5 text-ink/40"
|
|
140
|
-
aria-label="Side answers never use tools"
|
|
141
|
-
title="Side answers never use tools"
|
|
142
|
-
>
|
|
143
|
-
<Shield size={14} strokeWidth={2} />
|
|
144
|
-
</span>
|
|
145
|
-
</div>
|
|
146
|
-
|
|
147
|
-
<div className="flex items-center gap-2 min-w-0">
|
|
148
|
-
{(providerText || modelLabel) && (
|
|
149
|
-
<div className="flex items-baseline gap-1.5 min-w-0">
|
|
150
|
-
{providerText && <span className="text-[10px] text-ink/40 shrink-0">{providerText}</span>}
|
|
151
|
-
{modelLabel && <span className="text-[11px] text-ink/70 truncate">{modelLabel}</span>}
|
|
152
|
-
</div>
|
|
153
|
-
)}
|
|
154
|
-
|
|
155
|
-
{running ? (
|
|
156
|
-
<button
|
|
157
|
-
type="button"
|
|
158
|
-
onClick={onStop}
|
|
159
|
-
className="bg-ink text-canvas rounded p-1.5 cursor-pointer"
|
|
160
|
-
aria-label="Stop side answer"
|
|
161
|
-
title="Stop side answer"
|
|
162
|
-
>
|
|
163
|
-
<Square size={14} strokeWidth={2} />
|
|
164
|
-
</button>
|
|
165
|
-
) : (
|
|
166
|
-
<button
|
|
167
|
-
type="button"
|
|
168
|
-
onClick={onSubmit}
|
|
169
|
-
disabled={!canSend}
|
|
170
|
-
className="bg-ink text-canvas hover:bg-ink/80 rounded p-1.5 cursor-pointer disabled:opacity-40 disabled:cursor-not-allowed"
|
|
171
|
-
aria-label="Send side question"
|
|
172
|
-
title="Send side question"
|
|
173
|
-
>
|
|
174
|
-
<Send size={14} strokeWidth={2} />
|
|
175
|
-
</button>
|
|
176
|
-
)}
|
|
177
|
-
</div>
|
|
178
|
-
</div>
|
|
179
|
-
|
|
180
|
-
<input type="file" accept="image/*" multiple className="hidden" ref={fileInputRef} onChange={handleFileSelect} />
|
|
181
|
-
</div>
|
|
182
|
-
);
|
|
183
|
-
}
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Attachment handling for the side composer.
|
|
8
|
-
*
|
|
9
|
-
* A side question reaches the model with images only — no text files and no
|
|
10
|
-
* tools (the prompt says so, and the child runs `--no-tools`), so an
|
|
11
|
-
* attachment that cannot be an image payload is not offered in the first
|
|
12
|
-
* place. The file picker is `accept="image/*"`; this reads what it returns.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import type { AgentImage } from '@/shared/types';
|
|
16
|
-
|
|
17
|
-
/** An attachment held by the side composer until it is sent. */
|
|
18
|
-
export interface BtwAttachment {
|
|
19
|
-
id: string;
|
|
20
|
-
name: string;
|
|
21
|
-
size: number;
|
|
22
|
-
dataBase64?: string;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function readImage(file: File): Promise<string | undefined> {
|
|
26
|
-
const { promise, resolve } = Promise.withResolvers<string | undefined>();
|
|
27
|
-
const reader = new FileReader();
|
|
28
|
-
reader.onload = () => {
|
|
29
|
-
const result = typeof reader.result === 'string' ? reader.result : '';
|
|
30
|
-
const comma = result.indexOf(',');
|
|
31
|
-
resolve(comma >= 0 ? result.slice(comma + 1) : undefined);
|
|
32
|
-
};
|
|
33
|
-
reader.onerror = () => resolve(undefined);
|
|
34
|
-
reader.readAsDataURL(file);
|
|
35
|
-
return promise;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/** Read picked files into attachments, keeping only images. */
|
|
39
|
-
export async function readBtwAttachments(files: File[]): Promise<BtwAttachment[]> {
|
|
40
|
-
const images = files.filter((file) => file.type.startsWith('image/'));
|
|
41
|
-
return Promise.all(
|
|
42
|
-
images.map(async (file) => {
|
|
43
|
-
const dataBase64 = await readImage(file);
|
|
44
|
-
return {
|
|
45
|
-
id: `btw-${file.name}-${file.size}-${file.lastModified}`,
|
|
46
|
-
name: file.name,
|
|
47
|
-
size: file.size,
|
|
48
|
-
...(dataBase64 ? { dataBase64 } : {}),
|
|
49
|
-
};
|
|
50
|
-
}),
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/** The model payload for an ask — images only, base64 already read. */
|
|
55
|
-
export function btwImagesFrom(attachments: BtwAttachment[]): AgentImage[] {
|
|
56
|
-
return attachments
|
|
57
|
-
.filter((attachment): attachment is BtwAttachment & { dataBase64: string } => typeof attachment.dataBase64 === 'string')
|
|
58
|
-
.map((attachment) => ({
|
|
59
|
-
type: 'image' as const,
|
|
60
|
-
data: attachment.dataBase64,
|
|
61
|
-
mimeType: mimeTypeOf(attachment.name),
|
|
62
|
-
}));
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const MIME_BY_EXTENSION: Record<string, string> = {
|
|
66
|
-
png: 'image/png',
|
|
67
|
-
jpg: 'image/jpeg',
|
|
68
|
-
jpeg: 'image/jpeg',
|
|
69
|
-
gif: 'image/gif',
|
|
70
|
-
webp: 'image/webp',
|
|
71
|
-
bmp: 'image/bmp',
|
|
72
|
-
svg: 'image/svg+xml',
|
|
73
|
-
avif: 'image/avif',
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
function mimeTypeOf(name: string): string {
|
|
77
|
-
const dot = name.lastIndexOf('.');
|
|
78
|
-
const extension = dot >= 0 ? name.slice(dot + 1).toLowerCase() : '';
|
|
79
|
-
return MIME_BY_EXTENSION[extension] ?? 'image/png';
|
|
80
|
-
}
|
/package/dist/client/static/js/{77.8022a800b5.js.LICENSE.txt → 77.0d81c74cf0.js.LICENSE.txt}
RENAMED
|
File without changes
|
/package/dist/client/static/js/async/{g.ee41bfed7f.js.LICENSE.txt → 1k.973e8e21fc.js.LICENSE.txt}
RENAMED
|
File without changes
|
/package/dist/client/static/js/async/{3y.3186ecdd63.js.LICENSE.txt → 3y.3530b824ad.js.LICENSE.txt}
RENAMED
|
File without changes
|
/package/dist/client/static/js/async/{ot.84c71b308f.js.LICENSE.txt → 4m.928a1dde85.js.LICENSE.txt}
RENAMED
|
File without changes
|
/package/dist/client/static/js/async/{q.b453193538.js.LICENSE.txt → ar.9303e5f2e8.js.LICENSE.txt}
RENAMED
|
File without changes
|
/package/dist/client/static/js/async/{yx.af2936c368.js.LICENSE.txt → g.cb81980498.js.LICENSE.txt}
RENAMED
|
File without changes
|
/package/dist/client/static/js/async/{1k.a411fe5b43.js.LICENSE.txt → q.22588845a9.js.LICENSE.txt}
RENAMED
|
File without changes
|
/package/dist/client/static/js/async/{ar.ad5c8822a8.js.LICENSE.txt → xn.6510c0abe2.js.LICENSE.txt}
RENAMED
|
File without changes
|
/package/dist/client/static/js/{index.5fe7a2cb64.js.LICENSE.txt → index.1fd9e1c543.js.LICENSE.txt}
RENAMED
|
File without changes
|