@adecore/agents-react 0.23.0 → 0.24.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 +14 -11
- package/dist/agents/AccountDot.js +3 -1
- package/dist/agents/accounts.d.ts +3 -2
- package/dist/agents/accounts.js +5 -6
- package/dist/chat/actions.d.ts +2 -2
- package/dist/chat/actions.js +8 -5
- package/dist/chat/bookmarks.d.ts +5 -3
- package/dist/chat/bookmarks.js +13 -14
- package/dist/chat/chat-client.d.ts +1 -0
- package/dist/chat/chat-client.js +7 -0
- package/dist/chat/composer-send.d.ts +3 -0
- package/dist/chat/composer-send.js +22 -0
- package/dist/chat/forks.js +22 -5
- package/dist/chat/index.d.ts +31 -0
- package/dist/chat/index.js +28 -0
- package/dist/chat/logic/embedded-code.d.ts +8 -0
- package/dist/chat/logic/embedded-code.js +371 -0
- package/dist/chat/logic/fork.js +1 -0
- package/dist/chat/logic/goal.d.ts +6 -0
- package/dist/chat/logic/goal.js +26 -0
- package/dist/chat/logic/scrubber.d.ts +1 -1
- package/dist/chat/logic/scrubber.js +6 -5
- package/dist/chat/logic/thought.d.ts +3 -0
- package/dist/chat/logic/thought.js +35 -0
- package/dist/chat/logic/thread-cards.js +2 -0
- package/dist/chat/logic/timeline.d.ts +5 -0
- package/dist/chat/logic/timeline.js +22 -1
- package/dist/chat/logic/tool-catalog.d.ts +1 -0
- package/dist/chat/logic/tool-catalog.js +3 -1
- package/dist/chat/logic/tools.d.ts +14 -0
- package/dist/chat/logic/tools.js +57 -0
- package/dist/chat/preferences.d.ts +6 -0
- package/dist/chat/preferences.js +19 -3
- package/dist/chat/reading-width.d.ts +9 -0
- package/dist/chat/reading-width.js +27 -0
- package/dist/chat/send-key.d.ts +10 -0
- package/dist/chat/send-key.js +24 -0
- package/dist/chat/ui/BookmarkMarker.js +4 -2
- package/dist/chat/ui/BookmarkSubmenu.js +4 -3
- package/dist/chat/ui/ChatActivity.js +14 -10
- package/dist/chat/ui/ChatReferenceChip.js +3 -4
- package/dist/chat/ui/CodeBlock.d.ts +2 -1
- package/dist/chat/ui/CodeBlock.js +14 -96
- package/dist/chat/ui/Composer.d.ts +1 -1
- package/dist/chat/ui/Composer.js +117 -906
- package/dist/chat/ui/ComposerInput.js +5 -4
- package/dist/chat/ui/EditDiff.js +3 -2
- package/dist/chat/ui/GoalDock.d.ts +9 -0
- package/dist/chat/ui/GoalDock.js +63 -0
- package/dist/chat/ui/LimitState.js +5 -3
- package/dist/chat/ui/Markdown.d.ts +2 -1
- package/dist/chat/ui/Markdown.js +70 -31
- package/dist/chat/ui/MermaidBlock.d.ts +3 -0
- package/dist/chat/ui/MermaidBlock.js +73 -0
- package/dist/chat/ui/MessageActions.js +12 -7
- package/dist/chat/ui/Pickers.js +6 -5
- package/dist/chat/ui/PromptComposer.js +4 -3
- package/dist/chat/ui/RowTime.d.ts +3 -0
- package/dist/chat/ui/RowTime.js +12 -0
- package/dist/chat/ui/RunSettings.js +5 -4
- package/dist/chat/ui/ShellCommand.d.ts +3 -0
- package/dist/chat/ui/ShellCommand.js +110 -0
- package/dist/chat/ui/SubagentInfo.js +4 -3
- package/dist/chat/ui/SubagentStopButton.js +4 -3
- package/dist/chat/ui/SubagentTimeline.js +4 -1
- package/dist/chat/ui/Timeline.js +70 -40
- package/dist/chat/ui/TimelineMenu.d.ts +2 -1
- package/dist/chat/ui/TimelineMenu.js +18 -8
- package/dist/chat/ui/UnifiedDiff.js +3 -2
- package/dist/chat/ui/VisualFrame.js +6 -7
- package/dist/chat/ui/code-theme.d.ts +2 -1
- package/dist/chat/ui/code-theme.js +4 -4
- package/dist/chat/ui/composer/ComposerControls.d.ts +27 -0
- package/dist/chat/ui/composer/ComposerControls.js +34 -0
- package/dist/chat/ui/composer/ComposerMenu.d.ts +4 -0
- package/dist/chat/ui/composer/ComposerMenu.js +46 -0
- package/dist/chat/ui/composer/DraftParts.d.ts +18 -0
- package/dist/chat/ui/composer/DraftParts.js +25 -0
- package/dist/chat/ui/composer/QueuedMessages.d.ts +10 -0
- package/dist/chat/ui/composer/QueuedMessages.js +20 -0
- package/dist/chat/ui/composer/key-handler.d.ts +20 -0
- package/dist/chat/ui/composer/key-handler.js +150 -0
- package/dist/chat/ui/composer/keys.d.ts +7 -2
- package/dist/chat/ui/composer/keys.js +19 -9
- package/dist/chat/ui/composer/placeholder.d.ts +9 -0
- package/dist/chat/ui/composer/placeholder.js +38 -0
- package/dist/chat/ui/composer/use-chat-controls.d.ts +28 -0
- package/dist/chat/ui/composer/use-chat-controls.js +112 -0
- package/dist/chat/ui/composer/use-compaction-offer.d.ts +2 -0
- package/dist/chat/ui/composer/use-compaction-offer.js +23 -0
- package/dist/chat/ui/composer/use-composer-draft.d.ts +14 -0
- package/dist/chat/ui/composer/use-composer-draft.js +39 -0
- package/dist/chat/ui/composer/use-composer-menus.d.ts +52 -0
- package/dist/chat/ui/composer/use-composer-menus.js +232 -0
- package/dist/chat/ui/composer/use-composer-submit.d.ts +32 -0
- package/dist/chat/ui/composer/use-composer-submit.js +113 -0
- package/dist/chat/ui/composer/use-draft-files.d.ts +27 -0
- package/dist/chat/ui/composer/use-draft-files.js +111 -0
- package/dist/chat/ui/composer/use-notice.d.ts +6 -0
- package/dist/chat/ui/composer/use-notice.js +18 -0
- package/dist/chat/ui/composer/use-pending-requests.d.ts +2 -0
- package/dist/chat/ui/composer/use-pending-requests.js +22 -0
- package/dist/chat/ui/composer/use-prompt-history.d.ts +8 -0
- package/dist/chat/ui/composer/use-prompt-history.js +57 -0
- package/dist/chat/ui/composer/use-prompt-hold.d.ts +6 -0
- package/dist/chat/ui/composer/use-prompt-hold.js +48 -0
- package/dist/chat/ui/composer/use-take-back.d.ts +13 -0
- package/dist/chat/ui/composer/use-take-back.js +82 -0
- package/dist/chat/ui/diff/EditorEditDiff.js +4 -3
- package/dist/chat/ui/diff/LegacyDiffPool.js +3 -2
- package/dist/chat/ui/diff/LegacyEditDiff.js +3 -2
- package/dist/chat/ui/diff/LegacyUnifiedDiff.js +3 -2
- package/dist/chat/ui/diff/syntax-runtime.d.ts +2 -1
- package/dist/chat/ui/diff/syntax-runtime.js +9 -5
- package/dist/chat/ui/diff-syntax.d.ts +2 -2
- package/dist/chat/ui/diff-syntax.js +1 -2
- package/dist/chat/ui/diff-theme.js +10 -9
- package/dist/chat/ui/file-links.d.ts +1 -1
- package/dist/chat/ui/file-links.js +7 -5
- package/dist/chat/ui/highlighter.d.ts +27 -0
- package/dist/chat/ui/highlighter.js +151 -0
- package/dist/chat/ui/index.d.ts +67 -0
- package/dist/chat/ui/index.js +64 -0
- package/dist/chat/ui/intelligent-ui/UiReply.js +3 -2
- package/dist/chat/ui/intelligent-ui/renderers/content.js +3 -2
- package/dist/chat/ui/intelligent-ui/use-ui-links.js +2 -2
- package/dist/chat/ui/intelligent-ui/use-ui-queries.js +4 -3
- package/dist/chat/ui/markdown-blocks.d.ts +8 -0
- package/dist/chat/ui/markdown-blocks.js +260 -12
- package/dist/chat/ui/mermaid.d.ts +23 -0
- package/dist/chat/ui/mermaid.js +93 -0
- package/dist/chat/ui/rows/ForksRow.js +5 -3
- package/dist/chat/ui/rows/GeneratedImageRow.js +6 -4
- package/dist/chat/ui/rows/MessageRows.d.ts +4 -0
- package/dist/chat/ui/rows/MessageRows.js +36 -13
- package/dist/chat/ui/rows/Rows.js +3 -1
- package/dist/chat/ui/rows/SubagentRow.js +3 -2
- package/dist/chat/ui/rows/VisualRow.js +3 -2
- package/dist/chat/ui/rows/WorkRows.d.ts +6 -3
- package/dist/chat/ui/rows/WorkRows.js +57 -20
- package/dist/chat/ui/rows/WorkflowRow.js +3 -2
- package/dist/chat/ui/timestamp-format.d.ts +1 -0
- package/dist/chat/ui/timestamp-format.js +2 -0
- package/dist/chat/ui/use-diff-source-tokens.js +6 -3
- package/dist/chat/ui/visual-theme.js +3 -2
- package/dist/host.d.ts +9 -6
- package/dist/host.js +19 -8
- package/dist/index.d.ts +8 -0
- package/dist/index.js +9 -0
- package/dist/locales/en/agent-chat.d.ts +658 -0
- package/dist/locales/en/agent-chat.js +657 -0
- package/dist/locales/en/agent-prompts.d.ts +44 -0
- package/dist/locales/en/agent-prompts.js +43 -0
- package/dist/locales/en/agent-providers.d.ts +132 -0
- package/dist/locales/en/agent-providers.js +131 -0
- package/dist/locales/en/agent-usage.d.ts +132 -0
- package/dist/locales/en/agent-usage.js +131 -0
- package/dist/locales/nl/agent-chat.d.ts +658 -0
- package/dist/locales/nl/agent-chat.js +657 -0
- package/dist/locales/nl/agent-prompts.d.ts +44 -0
- package/dist/locales/nl/agent-prompts.js +43 -0
- package/dist/locales/nl/agent-providers.d.ts +132 -0
- package/dist/locales/nl/agent-providers.js +131 -0
- package/dist/locales/nl/agent-usage.d.ts +132 -0
- package/dist/locales/nl/agent-usage.js +131 -0
- package/dist/locales.js +9 -8
- package/dist/prompts/index.d.ts +11 -0
- package/dist/prompts/index.js +12 -0
- package/dist/prompts/logic/subjects.d.ts +2 -1
- package/dist/prompts/logic/subjects.js +6 -4
- package/dist/prompts/ui/ApprovalBody.js +6 -4
- package/dist/prompts/ui/PromptCard.js +5 -4
- package/dist/prompts/ui/PromptView.js +3 -2
- package/dist/prompts/ui/QuestionBody.js +3 -2
- package/dist/providers/AccountColors.js +2 -2
- package/dist/providers/AccountDetail.js +7 -6
- package/dist/providers/AccountVariables.js +3 -1
- package/dist/providers/AddAccountForm.js +3 -2
- package/dist/providers/ProvidersPane.js +4 -3
- package/dist/providers/account-actions.d.ts +4 -3
- package/dist/providers/account-actions.js +6 -7
- package/dist/providers/index.d.ts +16 -0
- package/dist/providers/index.js +17 -0
- package/dist/providers/provider-abilities.d.ts +2 -1
- package/dist/providers/provider-abilities.js +4 -0
- package/dist/state/chats.js +4 -2
- package/dist/state/index.d.ts +4 -0
- package/dist/state/index.js +5 -0
- package/dist/testing/index.d.ts +1 -0
- package/dist/testing/index.js +2 -0
- package/dist/{prompts/logic/prompts.fixtures.d.ts → testing/prompts.d.ts} +1 -1
- package/dist/theme.css +13 -3
- package/dist/usage/UsageBreakdown.js +3 -2
- package/dist/usage/UsageLimits.js +4 -3
- package/dist/usage/UsagePage.js +3 -2
- package/dist/usage/index.d.ts +15 -0
- package/dist/usage/index.js +15 -0
- package/package.json +53 -1031
- package/src/agents/AccountDot.tsx +3 -1
- package/src/agents/accounts.ts +6 -6
- package/src/chat/actions.ts +8 -5
- package/src/chat/bookmarks.ts +23 -14
- package/src/chat/chat-client.ts +8 -0
- package/src/chat/composer-send.ts +27 -0
- package/src/chat/forks.ts +27 -6
- package/src/chat/index.ts +98 -0
- package/src/chat/logic/embedded-code.ts +409 -0
- package/src/chat/logic/fork.ts +1 -0
- package/src/chat/logic/goal.ts +33 -0
- package/src/chat/logic/scrubber.ts +6 -5
- package/src/chat/logic/thought.ts +40 -0
- package/src/chat/logic/thread-cards.ts +2 -0
- package/src/chat/logic/timeline.ts +25 -1
- package/src/chat/logic/tool-catalog.ts +5 -1
- package/src/chat/logic/tools.ts +76 -0
- package/src/chat/preferences.ts +26 -3
- package/src/chat/reading-width.ts +39 -0
- package/src/chat/send-key.ts +38 -0
- package/src/chat/ui/BookmarkMarker.tsx +4 -2
- package/src/chat/ui/BookmarkSubmenu.tsx +4 -3
- package/src/chat/ui/ChatActivity.tsx +14 -10
- package/src/chat/ui/ChatReferenceChip.tsx +3 -4
- package/src/chat/ui/CodeBlock.tsx +33 -124
- package/src/chat/ui/Composer.tsx +162 -1324
- package/src/chat/ui/ComposerInput.tsx +5 -4
- package/src/chat/ui/EditDiff.tsx +3 -2
- package/src/chat/ui/GoalDock.tsx +104 -0
- package/src/chat/ui/LimitState.tsx +5 -3
- package/src/chat/ui/Markdown.tsx +113 -39
- package/src/chat/ui/MermaidBlock.tsx +119 -0
- package/src/chat/ui/MessageActions.tsx +13 -8
- package/src/chat/ui/Pickers.tsx +8 -7
- package/src/chat/ui/PromptComposer.tsx +4 -3
- package/src/chat/ui/RowTime.tsx +21 -0
- package/src/chat/ui/RunSettings.tsx +9 -4
- package/src/chat/ui/ShellCommand.tsx +134 -0
- package/src/chat/ui/SubagentInfo.tsx +4 -3
- package/src/chat/ui/SubagentStopButton.tsx +4 -3
- package/src/chat/ui/SubagentTimeline.tsx +5 -1
- package/src/chat/ui/Timeline.tsx +167 -105
- package/src/chat/ui/TimelineMenu.tsx +42 -7
- package/src/chat/ui/UnifiedDiff.tsx +3 -2
- package/src/chat/ui/VisualFrame.tsx +6 -7
- package/src/chat/ui/code-theme.ts +4 -4
- package/src/chat/ui/composer/ComposerControls.tsx +147 -0
- package/src/chat/ui/composer/ComposerMenu.tsx +138 -0
- package/src/chat/ui/composer/DraftParts.tsx +86 -0
- package/src/chat/ui/composer/QueuedMessages.tsx +64 -0
- package/src/chat/ui/composer/key-handler.ts +174 -0
- package/src/chat/ui/composer/keys.ts +32 -10
- package/src/chat/ui/composer/placeholder.ts +48 -0
- package/src/chat/ui/composer/use-chat-controls.ts +134 -0
- package/src/chat/ui/composer/use-compaction-offer.ts +25 -0
- package/src/chat/ui/composer/use-composer-draft.ts +71 -0
- package/src/chat/ui/composer/use-composer-menus.ts +289 -0
- package/src/chat/ui/composer/use-composer-submit.ts +163 -0
- package/src/chat/ui/composer/use-draft-files.ts +135 -0
- package/src/chat/ui/composer/use-notice.ts +28 -0
- package/src/chat/ui/composer/use-pending-requests.ts +23 -0
- package/src/chat/ui/composer/use-prompt-history.ts +76 -0
- package/src/chat/ui/composer/use-prompt-hold.ts +58 -0
- package/src/chat/ui/composer/use-take-back.ts +91 -0
- package/src/chat/ui/diff/DiffFallbackBoundary.tsx +2 -2
- package/src/chat/ui/diff/EditorEditDiff.tsx +4 -3
- package/src/chat/ui/diff/LegacyDiffPool.tsx +3 -2
- package/src/chat/ui/diff/LegacyEditDiff.tsx +3 -2
- package/src/chat/ui/diff/LegacyUnifiedDiff.tsx +3 -2
- package/src/chat/ui/diff/syntax-runtime.ts +10 -5
- package/src/chat/ui/diff-syntax.ts +2 -2
- package/src/chat/ui/diff-theme.ts +10 -9
- package/src/chat/ui/file-links.ts +7 -5
- package/src/chat/ui/highlighter.ts +185 -0
- package/src/chat/ui/index.ts +109 -0
- package/src/chat/ui/intelligent-ui/UiReply.tsx +5 -4
- package/src/chat/ui/intelligent-ui/renderers/content.tsx +3 -2
- package/src/chat/ui/intelligent-ui/use-ui-links.ts +2 -2
- package/src/chat/ui/intelligent-ui/use-ui-queries.ts +4 -3
- package/src/chat/ui/markdown-blocks.ts +300 -12
- package/src/chat/ui/mermaid.ts +118 -0
- package/src/chat/ui/rows/ForksRow.tsx +5 -3
- package/src/chat/ui/rows/GeneratedImageRow.tsx +6 -4
- package/src/chat/ui/rows/MessageRows.tsx +73 -18
- package/src/chat/ui/rows/Rows.tsx +14 -1
- package/src/chat/ui/rows/SubagentRow.tsx +3 -2
- package/src/chat/ui/rows/VisualRow.tsx +3 -2
- package/src/chat/ui/rows/WorkRows.tsx +148 -47
- package/src/chat/ui/rows/WorkflowRow.tsx +3 -2
- package/src/chat/ui/timestamp-format.ts +2 -0
- package/src/chat/ui/use-diff-source-tokens.ts +10 -4
- package/src/chat/ui/visual-theme.ts +3 -2
- package/src/host.ts +31 -15
- package/src/index.ts +49 -0
- package/src/locales/en/agent-chat.ts +657 -0
- package/src/locales/en/agent-prompts.ts +43 -0
- package/src/locales/en/agent-providers.ts +131 -0
- package/src/locales/en/agent-usage.ts +131 -0
- package/src/locales/nl/agent-chat.ts +657 -0
- package/src/locales/nl/agent-prompts.ts +43 -0
- package/src/locales/nl/agent-providers.ts +131 -0
- package/src/locales/nl/agent-usage.ts +132 -0
- package/src/locales.ts +9 -8
- package/src/prompts/index.ts +35 -0
- package/src/prompts/logic/subjects.ts +12 -4
- package/src/prompts/ui/ApprovalBody.tsx +6 -4
- package/src/prompts/ui/PromptCard.tsx +11 -4
- package/src/prompts/ui/PromptView.tsx +3 -2
- package/src/prompts/ui/QuestionBody.tsx +3 -2
- package/src/providers/AccountColors.tsx +2 -2
- package/src/providers/AccountDetail.tsx +13 -7
- package/src/providers/AccountVariables.tsx +3 -1
- package/src/providers/AddAccountForm.tsx +3 -2
- package/src/providers/ProvidersPane.tsx +4 -3
- package/src/providers/account-actions.ts +7 -7
- package/src/providers/index.ts +17 -0
- package/src/providers/provider-abilities.ts +6 -1
- package/src/state/chats.ts +4 -2
- package/src/state/index.ts +39 -0
- package/src/testing/index.ts +2 -0
- package/src/{prompts/logic/prompts.fixtures.ts → testing/prompts.ts} +1 -1
- package/src/theme.css +13 -3
- package/src/usage/UsageBreakdown.tsx +3 -2
- package/src/usage/UsageLimits.tsx +4 -3
- package/src/usage/UsagePage.tsx +3 -2
- package/src/usage/index.ts +16 -0
- package/dist/locales/en/agent-chat.json +0 -597
- package/dist/locales/en/agent-prompts.json +0 -43
- package/dist/locales/en/agent-providers.json +0 -131
- package/dist/locales/en/agent-usage.json +0 -131
- package/dist/locales/nl/agent-chat.json +0 -597
- package/dist/locales/nl/agent-prompts.json +0 -43
- package/dist/locales/nl/agent-providers.json +0 -131
- package/dist/locales/nl/agent-usage.json +0 -131
- package/src/locales/en/agent-chat.json +0 -597
- package/src/locales/en/agent-prompts.json +0 -43
- package/src/locales/en/agent-providers.json +0 -131
- package/src/locales/en/agent-usage.json +0 -131
- package/src/locales/nl/agent-chat.json +0 -597
- package/src/locales/nl/agent-prompts.json +0 -43
- package/src/locales/nl/agent-providers.json +0 -131
- package/src/locales/nl/agent-usage.json +0 -131
- /package/dist/{prompts/logic/prompts.fixtures.js → testing/prompts.js} +0 -0
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import type { AgentKind, ChatPreferencesPayload, ModelSelection, ProviderInfo, ProviderAccounts, RuntimeMode } from '@adecore/agent-contracts';
|
|
2
|
+
import { type ChatReadingWidth } from './reading-width.js';
|
|
3
|
+
import { type ChatSendKey } from './send-key.js';
|
|
2
4
|
export interface ChatPreferences {
|
|
3
5
|
selectionByProvider: Partial<Record<AgentKind, ModelSelection>>;
|
|
4
6
|
lastProvider: AgentKind | null;
|
|
5
7
|
runtimeMode: RuntimeMode;
|
|
6
8
|
terminalRuntimeMode: RuntimeMode;
|
|
7
9
|
accountByMachine: Record<string, Partial<Record<AgentKind, string>>>;
|
|
10
|
+
readingWidth: ChatReadingWidth;
|
|
11
|
+
sendKey: ChatSendKey;
|
|
8
12
|
changedAt: number;
|
|
9
13
|
}
|
|
10
14
|
export declare const DEFAULT_CHAT_PREFERENCES: ChatPreferences;
|
|
@@ -22,6 +26,8 @@ export declare let CHAT_PREFERENCES_KEY: string;
|
|
|
22
26
|
export declare function chatPreferencesKey(): string;
|
|
23
27
|
export declare function reloadChatPreferences(): void;
|
|
24
28
|
export declare function rememberChatPreferences(patch: Partial<ChatPreferences>): void;
|
|
29
|
+
export declare function rememberReadingWidth(readingWidth: ChatReadingWidth): void;
|
|
30
|
+
export declare function rememberSendKey(sendKey: ChatSendKey): void;
|
|
25
31
|
export declare function rememberChatSelection(provider: AgentKind, selection: ModelSelection): void;
|
|
26
32
|
export declare function rememberChatAccount(scopeId: string, provider: AgentKind, account: string | null): void;
|
|
27
33
|
export declare function forgetChatSelection(provider: AgentKind): void;
|
package/dist/chat/preferences.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { chatStorageKey, chatStorageLegacyKeys, createChatStore, onChatStorageConfiguration } from '../storage.js';
|
|
2
2
|
import { persistedJson } from './persisted-json.js';
|
|
3
|
+
import { DEFAULT_READING_WIDTH, isChatReadingWidth } from './reading-width.js';
|
|
4
|
+
import { DEFAULT_SEND_KEY, isChatSendKey } from './send-key.js';
|
|
3
5
|
const storageKey = () => chatStorageKey('preferences');
|
|
4
6
|
export const DEFAULT_CHAT_PREFERENCES = {
|
|
5
7
|
selectionByProvider: {},
|
|
@@ -7,6 +9,8 @@ export const DEFAULT_CHAT_PREFERENCES = {
|
|
|
7
9
|
runtimeMode: 'full-access',
|
|
8
10
|
terminalRuntimeMode: 'full-access',
|
|
9
11
|
accountByMachine: {},
|
|
12
|
+
readingWidth: DEFAULT_READING_WIDTH,
|
|
13
|
+
sendKey: DEFAULT_SEND_KEY,
|
|
10
14
|
changedAt: 0
|
|
11
15
|
};
|
|
12
16
|
/*
|
|
@@ -26,6 +30,8 @@ export function parseChatPreferences(raw) {
|
|
|
26
30
|
runtimeMode: stored.runtimeMode ?? DEFAULT_CHAT_PREFERENCES.runtimeMode,
|
|
27
31
|
terminalRuntimeMode: stored.terminalRuntimeMode ?? DEFAULT_CHAT_PREFERENCES.terminalRuntimeMode,
|
|
28
32
|
accountByMachine: { ...stored.accountByMachine },
|
|
33
|
+
readingWidth: isChatReadingWidth(stored.readingWidth) ? stored.readingWidth : DEFAULT_READING_WIDTH,
|
|
34
|
+
sendKey: isChatSendKey(stored.sendKey) ? stored.sendKey : DEFAULT_SEND_KEY,
|
|
29
35
|
changedAt: typeof stored.changedAt === 'number' ? stored.changedAt : 0
|
|
30
36
|
};
|
|
31
37
|
}
|
|
@@ -108,15 +114,25 @@ export function chatPreferencesKey() {
|
|
|
108
114
|
export function reloadChatPreferences() {
|
|
109
115
|
useChatPreferences.setState(storage.read(), true);
|
|
110
116
|
}
|
|
117
|
+
function store(preferences) {
|
|
118
|
+
useChatPreferences.setState(preferences);
|
|
119
|
+
storage.write(preferences);
|
|
120
|
+
}
|
|
111
121
|
function write(preferences) {
|
|
112
|
-
|
|
113
|
-
useChatPreferences.setState(next);
|
|
114
|
-
storage.write(next);
|
|
122
|
+
store({ ...preferences, changedAt: Date.now() });
|
|
115
123
|
}
|
|
116
124
|
/* The composer writes here on every change and the settings dialog too; both edit the same remembered default. */
|
|
117
125
|
export function rememberChatPreferences(patch) {
|
|
118
126
|
write({ ...useChatPreferences.getState(), ...patch });
|
|
119
127
|
}
|
|
128
|
+
/* The reading width leaves `changedAt` alone: it is no pick a machine weighs against another client's. */
|
|
129
|
+
export function rememberReadingWidth(readingWidth) {
|
|
130
|
+
store({ ...useChatPreferences.getState(), readingWidth });
|
|
131
|
+
}
|
|
132
|
+
/* Leaves `changedAt` alone, like the reading width. */
|
|
133
|
+
export function rememberSendKey(sendKey) {
|
|
134
|
+
store({ ...useChatPreferences.getState(), sendKey });
|
|
135
|
+
}
|
|
120
136
|
export function rememberChatSelection(provider, selection) {
|
|
121
137
|
const current = useChatPreferences.getState();
|
|
122
138
|
const previous = current.selectionByProvider[provider];
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CSSProperties } from 'react';
|
|
2
|
+
export type ChatReadingWidth = 'narrow' | 'comfortable' | 'full';
|
|
3
|
+
export declare const CHAT_READING_WIDTHS: readonly ChatReadingWidth[];
|
|
4
|
+
export declare const DEFAULT_READING_WIDTH: ChatReadingWidth;
|
|
5
|
+
export declare function isChatReadingWidth(value: unknown): value is ChatReadingWidth;
|
|
6
|
+
export declare function readingMeasure(width: ChatReadingWidth): number;
|
|
7
|
+
export declare function readingWidthStyle(width: ChatReadingWidth): CSSProperties;
|
|
8
|
+
export declare function readingWidthLabel(width: ChatReadingWidth): string;
|
|
9
|
+
export declare function readingWidthHint(width: ChatReadingWidth): string;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import i18next from 'i18next';
|
|
2
|
+
export const CHAT_READING_WIDTHS = ['narrow', 'comfortable', 'full'];
|
|
3
|
+
export const DEFAULT_READING_WIDTH = 'comfortable';
|
|
4
|
+
// About 75 and 90 characters of the thread's text a line.
|
|
5
|
+
const MEASURES = {
|
|
6
|
+
narrow: 640,
|
|
7
|
+
comfortable: 768,
|
|
8
|
+
full: Number.POSITIVE_INFINITY
|
|
9
|
+
};
|
|
10
|
+
export function isChatReadingWidth(value) {
|
|
11
|
+
return typeof value === 'string' && CHAT_READING_WIDTHS.includes(value);
|
|
12
|
+
}
|
|
13
|
+
/* The widest the content column runs, in pixels; `full` is unbounded. */
|
|
14
|
+
export function readingMeasure(width) {
|
|
15
|
+
return MEASURES[width];
|
|
16
|
+
}
|
|
17
|
+
/* What `.chat-column-content` and `.chat-composer-content` read their width from. */
|
|
18
|
+
export function readingWidthStyle(width) {
|
|
19
|
+
const measure = MEASURES[width];
|
|
20
|
+
return { '--chat-measure': Number.isFinite(measure) ? `${measure}px` : '100%' };
|
|
21
|
+
}
|
|
22
|
+
export function readingWidthLabel(width) {
|
|
23
|
+
return i18next.t(`agent-chat:readingWidth.${width}.label`);
|
|
24
|
+
}
|
|
25
|
+
export function readingWidthHint(width) {
|
|
26
|
+
return i18next.t(`agent-chat:readingWidth.${width}.hint`);
|
|
27
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type Shortcut } from '@adecore/ui';
|
|
2
|
+
export type ChatSendKey = 'enter' | 'mod-enter-multiline' | 'mod-enter';
|
|
3
|
+
export declare const CHAT_SEND_KEYS: readonly ChatSendKey[];
|
|
4
|
+
export declare const DEFAULT_SEND_KEY: ChatSendKey;
|
|
5
|
+
export declare const SEND_AND_NEW_SHORTCUT: Shortcut;
|
|
6
|
+
export declare function isChatSendKey(value: unknown): value is ChatSendKey;
|
|
7
|
+
export declare function modSends(sendKey: ChatSendKey, multiline: boolean): boolean;
|
|
8
|
+
export declare function sendShortcut(sendKey: ChatSendKey, multiline: boolean): Shortcut;
|
|
9
|
+
export declare function sendKeyLabel(sendKey: ChatSendKey, apple: boolean): string;
|
|
10
|
+
export declare function sendKeyHint(sendKey: ChatSendKey, apple: boolean): string;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import i18next from 'i18next';
|
|
2
|
+
import { KEY_SHORTCUTS, shortcut } from '@adecore/ui';
|
|
3
|
+
export const CHAT_SEND_KEYS = ['enter', 'mod-enter-multiline', 'mod-enter'];
|
|
4
|
+
export const DEFAULT_SEND_KEY = 'enter';
|
|
5
|
+
/* Sends, then opens a new chat through the host's `openNewChat`; a key of the composer, for a menu or a list of keys to print. */
|
|
6
|
+
export const SEND_AND_NEW_SHORTCUT = /* @__PURE__ */ shortcut('Mod+Alt+Enter');
|
|
7
|
+
export function isChatSendKey(value) {
|
|
8
|
+
return typeof value === 'string' && CHAT_SEND_KEYS.includes(value);
|
|
9
|
+
}
|
|
10
|
+
/* Whether Enter alone adds a line to a message, so only Mod+Enter sends it. */
|
|
11
|
+
export function modSends(sendKey, multiline) {
|
|
12
|
+
return sendKey === 'mod-enter' || (sendKey === 'mod-enter-multiline' && multiline);
|
|
13
|
+
}
|
|
14
|
+
/* The key that sends a message, as a hint prints it. */
|
|
15
|
+
export function sendShortcut(sendKey, multiline) {
|
|
16
|
+
return modSends(sendKey, multiline) ? KEY_SHORTCUTS.modEnter : KEY_SHORTCUTS.enter;
|
|
17
|
+
}
|
|
18
|
+
/* `apple` writes Mod as the Command sign, and as Ctrl elsewhere. */
|
|
19
|
+
export function sendKeyLabel(sendKey, apple) {
|
|
20
|
+
return i18next.t(`agent-chat:sendKey.${sendKey}.label`, { mod: apple ? '⌘' : 'Ctrl' });
|
|
21
|
+
}
|
|
22
|
+
export function sendKeyHint(sendKey, apple) {
|
|
23
|
+
return i18next.t(`agent-chat:sendKey.${sendKey}.hint`, { mod: apple ? '⌘' : 'Ctrl' });
|
|
24
|
+
}
|
|
@@ -6,6 +6,7 @@ import { Bookmark, Pencil, X } from 'lucide-react';
|
|
|
6
6
|
import { CHAT_BOOKMARK_LIMITS } from '@adecore/agent-contracts';
|
|
7
7
|
import { nameBookmark, removeBookmark, useBookmarkNaming } from '../bookmarks.js';
|
|
8
8
|
import { bookmarkLabel } from '../logic/bookmarks.js';
|
|
9
|
+
import { useChatHost } from '../../host.js';
|
|
9
10
|
import { useChatScope } from '../../scope.js';
|
|
10
11
|
import { ButtonGroup, Icon, IconButton, Input } from '@adecore/ui';
|
|
11
12
|
/*
|
|
@@ -15,6 +16,7 @@ import { ButtonGroup, Icon, IconButton, Input } from '@adecore/ui';
|
|
|
15
16
|
export function BookmarkMarker({ chatId, itemId, bookmark }) {
|
|
16
17
|
const { t } = useTranslation('agent-chat');
|
|
17
18
|
const scope = useChatScope();
|
|
19
|
+
const host = useChatHost();
|
|
18
20
|
const chatKey = scope.keyOf(chatId);
|
|
19
21
|
const naming = useBookmarkNaming((s) => s.chatKey === chatKey && s.itemId === itemId);
|
|
20
22
|
if (bookmark === null && !naming) {
|
|
@@ -23,9 +25,9 @@ export function BookmarkMarker({ chatId, itemId, bookmark }) {
|
|
|
23
25
|
return (_jsxs("div", { className: "group/bookmark mb-2 flex h-7 min-w-0 items-center gap-2 text-xs select-none", children: [_jsx(Icon, { icon: Bookmark, size: 14, className: "shrink-0 text-accent" }), naming ? (_jsx(NameField, { initial: bookmark?.name ?? '', onDone: (name) => {
|
|
24
26
|
useBookmarkNaming.getState().close();
|
|
25
27
|
if (name !== null) {
|
|
26
|
-
void nameBookmark(scope, chatId, itemId, name, bookmark?.name);
|
|
28
|
+
void nameBookmark(scope, host, chatId, itemId, name, bookmark?.name);
|
|
27
29
|
}
|
|
28
|
-
} })) : (bookmark !== null && (_jsx("span", { className: clsx('min-w-0 truncate', bookmark.name === undefined ? 'text-text-muted' : 'text-text'), children: bookmarkLabel(bookmark) }))), _jsx("span", { className: "min-w-6 grow border-t border-border" }), bookmark !== null && !naming && (_jsxs(ButtonGroup, { render: _jsx("span", {}), className: "-ml-2 max-w-0 shrink-0 overflow-hidden opacity-0 group-hover/bookmark:ml-0 group-hover/bookmark:max-w-none group-hover/bookmark:opacity-100 group-has-focus-visible/bookmark:ml-0 group-has-focus-visible/bookmark:max-w-none group-has-focus-visible/bookmark:opacity-100", children: [_jsx(IconButton, { icon: Pencil, size: "xs", label: t('bookmarks.rename'), onClick: () => useBookmarkNaming.getState().open(chatKey, itemId) }), _jsx(IconButton, { icon: X, size: "xs", label: t('bookmarks.remove'), onClick: () => void removeBookmark(scope, chatId, bookmark) })] }))] }));
|
|
30
|
+
} })) : (bookmark !== null && (_jsx("span", { className: clsx('min-w-0 truncate', bookmark.name === undefined ? 'text-text-muted' : 'text-text'), children: bookmarkLabel(bookmark) }))), _jsx("span", { className: "min-w-6 grow border-t border-border" }), bookmark !== null && !naming && (_jsxs(ButtonGroup, { render: _jsx("span", {}), className: "-ml-2 max-w-0 shrink-0 overflow-hidden opacity-0 group-hover/bookmark:ml-0 group-hover/bookmark:max-w-none group-hover/bookmark:opacity-100 group-has-focus-visible/bookmark:ml-0 group-has-focus-visible/bookmark:max-w-none group-has-focus-visible/bookmark:opacity-100", children: [_jsx(IconButton, { icon: Pencil, size: "xs", label: t('bookmarks.rename'), onClick: () => useBookmarkNaming.getState().open(chatKey, itemId) }), _jsx(IconButton, { icon: X, size: "xs", label: t('bookmarks.remove'), onClick: () => void removeBookmark(scope, host, chatId, bookmark) })] }))] }));
|
|
29
31
|
}
|
|
30
32
|
/* Settles with the name on Enter or when the focus leaves, and with null on Escape, which keeps the name as it was. */
|
|
31
33
|
function NameField({ initial, onDone }) {
|
|
@@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next';
|
|
|
5
5
|
import { Bookmark, Pencil, X } from 'lucide-react';
|
|
6
6
|
import { goToBookmark, removeBookmark } from '../bookmarks.js';
|
|
7
7
|
import { bookmarkLabel, bookmarksInThreadOrder } from '../logic/bookmarks.js';
|
|
8
|
-
import {
|
|
8
|
+
import { useChatHost } from '../../host.js';
|
|
9
9
|
import { useChatScope } from '../../scope.js';
|
|
10
10
|
import { useChatRow } from '../../state/chats.js';
|
|
11
11
|
import { Icon, Menu } from '@adecore/ui';
|
|
@@ -15,7 +15,8 @@ export function BookmarkSubmenu({ chatId }) {
|
|
|
15
15
|
const scope = useChatScope();
|
|
16
16
|
const bookmarks = useChatRow(chatId, (row) => row?.bookmarks);
|
|
17
17
|
const order = useChatRow(chatId, (row) => row?.order);
|
|
18
|
-
const
|
|
18
|
+
const host = useChatHost();
|
|
19
|
+
const place = host.useChatPlace(chatId);
|
|
19
20
|
const sorted = useMemo(() => bookmarksInThreadOrder(bookmarks ?? [], order ?? []), [bookmarks, order]);
|
|
20
21
|
if (sorted.length === 0) {
|
|
21
22
|
return null;
|
|
@@ -25,5 +26,5 @@ export function BookmarkSubmenu({ chatId }) {
|
|
|
25
26
|
place.go();
|
|
26
27
|
}
|
|
27
28
|
};
|
|
28
|
-
return (_jsxs(Menu.SubmenuRoot, { children: [_jsxs(Menu.SubmenuTrigger, { children: [_jsx(Icon, { icon: Bookmark, size: 14 }), " ", t('bookmarks.menu')] }), _jsx(Menu.Popup, { className: "max-w-80 min-w-56", children: sorted.map((bookmark) => (_jsxs(Menu.Row, { "aria-label": bookmarkLabel(bookmark), children: [_jsxs(Menu.Item, { onClick: () => go(bookmark.itemId, false), children: [_jsx(Icon, { icon: Bookmark, size: 14, className: "shrink-0 text-accent" }), _jsx("span", { className: clsx('min-w-0 grow truncate', bookmark.name === undefined && 'text-text-muted'), children: bookmarkLabel(bookmark) })] }), _jsx(Menu.RowAction, { icon: Pencil, label: t('bookmarks.rename'), onClick: () => go(bookmark.itemId, true) }), _jsx(Menu.RowAction, { icon: X, label: t('bookmarks.remove'), onClick: () => void removeBookmark(scope, chatId, bookmark) })] }, bookmark.itemId))) })] }));
|
|
29
|
+
return (_jsxs(Menu.SubmenuRoot, { children: [_jsxs(Menu.SubmenuTrigger, { children: [_jsx(Icon, { icon: Bookmark, size: 14 }), " ", t('bookmarks.menu')] }), _jsx(Menu.Popup, { className: "max-w-80 min-w-56", children: sorted.map((bookmark) => (_jsxs(Menu.Row, { "aria-label": bookmarkLabel(bookmark), children: [_jsxs(Menu.Item, { onClick: () => go(bookmark.itemId, false), children: [_jsx(Icon, { icon: Bookmark, size: 14, className: "shrink-0 text-accent" }), _jsx("span", { className: clsx('min-w-0 grow truncate', bookmark.name === undefined && 'text-text-muted'), children: bookmarkLabel(bookmark) })] }), _jsx(Menu.RowAction, { icon: Pencil, label: t('bookmarks.rename'), onClick: () => go(bookmark.itemId, true) }), _jsx(Menu.RowAction, { icon: X, label: t('bookmarks.remove'), onClick: () => void removeBookmark(scope, host, chatId, bookmark) })] }, bookmark.itemId))) })] }));
|
|
29
30
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useMemo } from 'react';
|
|
3
3
|
import clsx from 'clsx';
|
|
4
|
+
import { useShallow } from 'zustand/shallow';
|
|
4
5
|
import { useTranslation } from 'react-i18next';
|
|
5
6
|
import { Activity, MessageCircleQuestionMark, Square, SquareTerminal } from 'lucide-react';
|
|
6
7
|
import { backgroundCounts } from '../activity.js';
|
|
@@ -11,7 +12,7 @@ import { SubagentStopButton } from './SubagentStopButton.js';
|
|
|
11
12
|
import { formatElapsedShort } from '@adecore/ui/format';
|
|
12
13
|
import { Icon, IconButton, Popover, Surface, useNow } from '@adecore/ui';
|
|
13
14
|
import { useChatRow, useChats } from '../../state/chats.js';
|
|
14
|
-
import {
|
|
15
|
+
import { useChatHost } from '../../host.js';
|
|
15
16
|
import { useChatScope } from '../../scope.js';
|
|
16
17
|
import { useChatActions } from '../actions.js';
|
|
17
18
|
import { statusLookOf } from '../../agents/status-look.js';
|
|
@@ -20,18 +21,19 @@ const NO_ITEMS = [];
|
|
|
20
21
|
const ROW_BODY = 'flex min-h-9 min-w-0 grow items-center gap-2.5 rounded-md px-2.5 py-1.5 text-left';
|
|
21
22
|
/* What the chat keeps working on beside the thread, in one small line over the composer: its sub-agents and what runs in the background. */
|
|
22
23
|
export function ChatActivity({ chatId }) {
|
|
24
|
+
const host = useChatHost();
|
|
23
25
|
const { t } = useTranslation('agent-chat');
|
|
24
26
|
const order = useChatRow(chatId, (row) => row?.order) ?? NO_ITEMS;
|
|
25
27
|
const structure = useChatRow(chatId, (row) => row?.structure);
|
|
26
28
|
const subagents = useMemo(() => (structure === undefined ? [] : flyoutSubagents(order, structure)), [order, structure]);
|
|
27
29
|
const { id, keyOf } = useChatScope();
|
|
28
|
-
const tasks =
|
|
29
|
-
|
|
30
|
-
const
|
|
30
|
+
const tasks = host.tasks.useTasks(id);
|
|
31
|
+
// The infos of these sub-agents' own chats, so the info of any other chat changing does not draw this again.
|
|
32
|
+
const children = useChats(useShallow((s) => subagents.map((item) => (item.childId === undefined ? undefined : s.statusByKey[keyOf(item.childId)]?.info))));
|
|
33
|
+
const progress = useMemo(() => progressOf(subagents.map((item, index) => {
|
|
31
34
|
const taskId = taskIdOf(item);
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
})), [subagents, tasks, statuses, keyOf]);
|
|
35
|
+
return taskRowStateOf(item, taskId === null ? null : (tasks?.[taskId] ?? null), children[index]);
|
|
36
|
+
})), [subagents, tasks, children]);
|
|
35
37
|
const words = useMemo(() => subagents.map((item) => {
|
|
36
38
|
const taskId = taskIdOf(item);
|
|
37
39
|
return statusWordOf(item, taskId === null ? null : (tasks?.[taskId] ?? null));
|
|
@@ -41,7 +43,7 @@ export function ChatActivity({ chatId }) {
|
|
|
41
43
|
return null;
|
|
42
44
|
}
|
|
43
45
|
const { shells, monitors } = backgroundCounts(background);
|
|
44
|
-
const Slot =
|
|
46
|
+
const Slot = host.SubagentSlot;
|
|
45
47
|
const counting = progress.active > 0 && progress.total > 1;
|
|
46
48
|
const label = counting
|
|
47
49
|
? [t('activity.progress', { done: progress.done, total: progress.total }), progress.waiting > 0 && t('activity.needsYou', { count: progress.waiting })]
|
|
@@ -73,10 +75,11 @@ function SubagentRows({ chatId, items }) {
|
|
|
73
75
|
return items.map((item) => _jsx(SubagentEntry, { chatId: chatId, item: item, now: now }, item.id));
|
|
74
76
|
}
|
|
75
77
|
function SubagentEntry({ chatId, item, now }) {
|
|
78
|
+
const host = useChatHost();
|
|
76
79
|
const { t } = useTranslation('agent-chat');
|
|
77
80
|
const { id, keyOf } = useChatScope();
|
|
78
81
|
const refused = useSubagentSupport((s) => s.unsupported[id] === true);
|
|
79
|
-
const task =
|
|
82
|
+
const task = host.tasks.useTask(id, taskIdOf(item));
|
|
80
83
|
const { show } = useSubagentTrail(chatId);
|
|
81
84
|
const child = useChats((s) => (item.childId === undefined ? undefined : s.statusByKey[keyOf(item.childId)]?.info));
|
|
82
85
|
const word = statusWordOf(item, task);
|
|
@@ -85,13 +88,14 @@ function SubagentEntry({ chatId, item, now }) {
|
|
|
85
88
|
}
|
|
86
89
|
/* Only drawn while the flyout is open, so the clock ticks for nobody otherwise. */
|
|
87
90
|
function BackgroundTaskRows({ chatId, tasks }) {
|
|
91
|
+
const host = useChatHost();
|
|
88
92
|
const { t } = useTranslation('agent-chat');
|
|
89
93
|
const now = useNow(1000);
|
|
90
94
|
const actions = useChatActions();
|
|
91
95
|
function stop(taskId) {
|
|
92
96
|
void actions.stopTask(chatId, taskId).catch((e) => {
|
|
93
97
|
const description = e instanceof Error ? e.message : t('subagents.noAnswer');
|
|
94
|
-
|
|
98
|
+
host.notify({ kind: 'error', title: t('activity.stopFailed'), description });
|
|
95
99
|
});
|
|
96
100
|
}
|
|
97
101
|
return tasks.map((task) => (_jsx(ActivityRow, { icon: _jsx(Icon, { icon: task.kind === 'shell' ? SquareTerminal : Activity, size: 14, className: "shrink-0 text-text-faint" }), title: task.description || task.command || t(`activity.${task.kind}`), detail: task.description ? task.command : null, time: formatElapsedShort(now - task.startedAt), children: _jsx(IconButton, { icon: Square, size: "xs", label: t('activity.stop'), className: "mr-1.5", onClick: () => stop(task.id) }) }, task.id)));
|
|
@@ -2,15 +2,14 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import clsx from 'clsx';
|
|
3
3
|
import { useTranslation } from 'react-i18next';
|
|
4
4
|
import { MessageSquare, X } from 'lucide-react';
|
|
5
|
-
import {
|
|
5
|
+
import { useChatHost } from '../../host.js';
|
|
6
6
|
import { CHIP_IN_MESSAGE, MENTION_TONE } from './chips.js';
|
|
7
7
|
import { Icon, Tooltip } from '@adecore/ui';
|
|
8
8
|
/* A chat attached to a message, under the title it has now rather than the one it had when it was attached. */
|
|
9
9
|
export function ChatReferenceChip({ chatId, onRemove }) {
|
|
10
|
+
const host = useChatHost();
|
|
10
11
|
const { t } = useTranslation('agent-chat');
|
|
11
|
-
const chat =
|
|
12
|
-
.useReferableChats()
|
|
13
|
-
.find((candidate) => candidate.id === chatId);
|
|
12
|
+
const chat = host.useReferableChats().find((candidate) => candidate.id === chatId);
|
|
14
13
|
const title = chat === undefined ? t('chatReference.gone') : chat.title || t('chatReference.untitled');
|
|
15
14
|
return (_jsxs("span", { className: clsx(MENTION_TONE, CHIP_IN_MESSAGE), children: [_jsx(Icon, { icon: MessageSquare, size: 12, className: "shrink-0" }), _jsx("span", { className: "truncate", children: title }), onRemove && (_jsx(Tooltip, { label: t('chatReference.remove', { title }), name: true, children: _jsx("button", { className: "-mr-0.5 shrink-0 rounded-sm opacity-70 hover:opacity-100", onClick: onRemove, children: _jsx(Icon, { icon: X, size: 12 }) }) }))] }));
|
|
16
15
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type ReactNode } from 'react';
|
|
2
|
-
export declare function CodeBlock({ code, lang, actions }: {
|
|
2
|
+
export declare function CodeBlock({ code, lang, actions, view }: {
|
|
3
3
|
code: string;
|
|
4
4
|
lang: string;
|
|
5
5
|
actions?: ReactNode;
|
|
6
|
+
view?: ReactNode;
|
|
6
7
|
}): import("react").JSX.Element;
|
|
@@ -7,113 +7,31 @@ import { ButtonGroup, IconButton } from '@adecore/ui';
|
|
|
7
7
|
import { IncrementalLines } from './code-lines.js';
|
|
8
8
|
import { CodeStreamingContext } from './code-streaming.js';
|
|
9
9
|
import { WHOLE_FADE_CLASS } from './rehype-fade.js';
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
import { useChatHost } from '../../host.js';
|
|
11
|
+
import { useCodeTheme } from './code-theme.js';
|
|
12
|
+
import { tokenStyle, useCodeHighlighter } from './highlighter.js';
|
|
13
13
|
const COPIED_MS = 1500;
|
|
14
|
-
let highlighter = null;
|
|
15
|
-
let highlighterLoad = null;
|
|
16
|
-
const loadedLanguages = new Set([PLAIN]);
|
|
17
|
-
const languageLoads = new Map();
|
|
18
|
-
const loadedThemes = new Set();
|
|
19
|
-
const themeLoads = new Map();
|
|
20
|
-
const tokenizers = new Map();
|
|
21
|
-
// Shiki loads on the first code block, not with the app; the web bundle covers the languages a coding agent writes.
|
|
22
|
-
function loadHighlighter() {
|
|
23
|
-
highlighterLoad ??= import('shiki/bundle/web').then(async ({ createHighlighter }) => {
|
|
24
|
-
highlighter = await createHighlighter({ themes: [], langs: [] });
|
|
25
|
-
return highlighter;
|
|
26
|
-
});
|
|
27
|
-
return highlighterLoad;
|
|
28
|
-
}
|
|
29
|
-
function resolveLanguage(lang, known) {
|
|
30
|
-
return known !== null && lang in known ? lang : PLAIN;
|
|
31
|
-
}
|
|
32
|
-
let bundled = null;
|
|
33
|
-
/* Loads the highlighter and the grammar of one language, once each. */
|
|
34
|
-
function loadLanguage(lang) {
|
|
35
|
-
let load = languageLoads.get(lang);
|
|
36
|
-
if (!load) {
|
|
37
|
-
load = Promise.all([loadHighlighter(), import('shiki/bundle/web')]).then(async ([loaded, { bundledLanguages }]) => {
|
|
38
|
-
bundled = bundledLanguages;
|
|
39
|
-
const language = resolveLanguage(lang, bundledLanguages);
|
|
40
|
-
if (!loadedLanguages.has(language)) {
|
|
41
|
-
await loaded.loadLanguage(language);
|
|
42
|
-
loadedLanguages.add(language);
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
languageLoads.set(lang, load);
|
|
46
|
-
}
|
|
47
|
-
return load;
|
|
48
|
-
}
|
|
49
|
-
/* Loads a theme into the highlighter, once. */
|
|
50
|
-
function loadTheme(theme) {
|
|
51
|
-
let load = themeLoads.get(theme);
|
|
52
|
-
if (!load) {
|
|
53
|
-
load = loadHighlighter().then(async (loaded) => {
|
|
54
|
-
await loaded.loadTheme(shikiThemeOf(theme));
|
|
55
|
-
loadedThemes.add(theme);
|
|
56
|
-
});
|
|
57
|
-
themeLoads.set(theme, load);
|
|
58
|
-
}
|
|
59
|
-
return load;
|
|
60
|
-
}
|
|
61
|
-
/* The tokenizer for a language in a theme, or null while shiki, the grammar or the theme is still on its way. */
|
|
62
|
-
function tokenizerFor(lang, theme) {
|
|
63
|
-
if (highlighter === null || bundled === null || !languageLoads.has(lang) || !loadedThemes.has(theme)) {
|
|
64
|
-
return null;
|
|
65
|
-
}
|
|
66
|
-
const language = resolveLanguage(lang, bundled);
|
|
67
|
-
if (!loadedLanguages.has(language)) {
|
|
68
|
-
return null;
|
|
69
|
-
}
|
|
70
|
-
const key = `${language}:${theme}`;
|
|
71
|
-
let entry = tokenizers.get(key);
|
|
72
|
-
if (!entry) {
|
|
73
|
-
const loaded = highlighter;
|
|
74
|
-
const options = { lang: language, theme };
|
|
75
|
-
entry = {
|
|
76
|
-
tokenize: (code, state) => {
|
|
77
|
-
const result = loaded.codeToTokens(code, state ? { ...options, grammarState: state } : options);
|
|
78
|
-
return { lines: result.tokens, state: result.grammarState };
|
|
79
|
-
},
|
|
80
|
-
fg: loaded.getTheme(theme).fg
|
|
81
|
-
};
|
|
82
|
-
tokenizers.set(key, entry);
|
|
83
|
-
}
|
|
84
|
-
return entry;
|
|
85
|
-
}
|
|
86
|
-
function styleOf(token) {
|
|
87
|
-
const style = token.fontStyle ?? 0;
|
|
88
|
-
if (token.color === undefined && style <= 0) {
|
|
89
|
-
return undefined;
|
|
90
|
-
}
|
|
91
|
-
const decorations = [style & 4 ? 'underline' : '', style & 8 ? 'line-through' : ''].filter(Boolean).join(' ');
|
|
92
|
-
return {
|
|
93
|
-
color: token.color,
|
|
94
|
-
...(style & 1 ? { fontStyle: 'italic' } : {}),
|
|
95
|
-
...(style & 2 ? { fontWeight: 'bold' } : {}),
|
|
96
|
-
...(decorations ? { textDecoration: decorations } : {})
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
14
|
/* A line whose tokens did not change keeps its elements, so a selection in it survives the next delta. */
|
|
100
15
|
const CodeLine = memo(function CodeLine({ tokens }) {
|
|
101
|
-
return (_jsx("span", { className: "line", children: tokens.map((token, index) => (_jsx("span", { style:
|
|
16
|
+
return (_jsx("span", { className: "line", children: tokens.map((token, index) => (_jsx("span", { style: tokenStyle(token), children: token.content }, index))) }));
|
|
102
17
|
});
|
|
103
18
|
/*
|
|
104
19
|
* A fenced block, highlighted a line at a time. Until shiki and the grammar are there it holds its
|
|
105
20
|
* place invisibly, so bare code never turns colored. An open fence is tokenized as it grows, and
|
|
106
|
-
* closing it does not draw it again.
|
|
21
|
+
* closing it does not draw it again. `view` takes the place of the code, such as what the code draws,
|
|
22
|
+
* and Copy still copies the code.
|
|
107
23
|
*/
|
|
108
|
-
export function CodeBlock({ code, lang, actions }) {
|
|
24
|
+
export function CodeBlock({ code, lang, actions, view }) {
|
|
109
25
|
const { t } = useTranslation('agent-chat');
|
|
110
26
|
const theme = useCodeTheme();
|
|
27
|
+
const { custom } = useChatHost().code;
|
|
28
|
+
const highlighter = useCodeHighlighter();
|
|
111
29
|
const streaming = useContext(CodeStreamingContext);
|
|
112
30
|
const [copyState, setCopyState] = useState('idle');
|
|
113
31
|
const copying = useRef(false);
|
|
114
32
|
// What loaded last, so a block whose theme changes draws again once the new one is in.
|
|
115
33
|
const [loaded, setLoaded] = useState(null);
|
|
116
|
-
const tokenizer =
|
|
34
|
+
const tokenizer = highlighter.tokenizer(lang, theme);
|
|
117
35
|
// Only a block that had to wait fades in; one drawn highlighted from its first frame just stands there.
|
|
118
36
|
const [waited] = useState(tokenizer === null);
|
|
119
37
|
const lines = useMemo(() => (tokenizer ? new IncrementalLines(tokenizer.tokenize) : null), [tokenizer]);
|
|
@@ -148,15 +66,15 @@ export function CodeBlock({ code, lang, actions }) {
|
|
|
148
66
|
return;
|
|
149
67
|
}
|
|
150
68
|
let cancelled = false;
|
|
151
|
-
Promise.all([loadLanguage(lang), loadTheme(theme)])
|
|
69
|
+
Promise.all([highlighter.loadLanguage(lang), highlighter.loadTheme(theme, custom)])
|
|
152
70
|
.then(() => !cancelled && setLoaded(`${lang}:${theme}`))
|
|
153
71
|
.catch(() => !cancelled && setLoaded('failed'));
|
|
154
72
|
return () => {
|
|
155
73
|
cancelled = true;
|
|
156
74
|
};
|
|
157
|
-
}, [lang, theme, tokenizer]);
|
|
75
|
+
}, [highlighter, lang, theme, custom, tokenizer]);
|
|
158
76
|
const pending = (tokenizer === null || tokens === null) && loaded !== 'failed';
|
|
159
|
-
return (_jsxs("div", { className: "chat-code", "data-copy-state": copyState, children: [_jsx("pre", { className: clsx(pending && 'invisible', !pending && tokens !== null && waited && WHOLE_FADE_CLASS), "aria-hidden": pending || undefined, style: { color: tokenizer?.fg }, children: _jsx("code", { children: tokens === null
|
|
77
|
+
return (_jsxs("div", { className: "chat-code", "data-copy-state": copyState, children: [view ?? (_jsx("pre", { className: clsx(pending && 'invisible', !pending && tokens !== null && waited && WHOLE_FADE_CLASS), "aria-hidden": pending || undefined, style: { color: tokenizer?.fg }, children: _jsx("code", { children: tokens === null
|
|
160
78
|
? code
|
|
161
|
-
: tokens.map((line, index) => (_jsxs(Fragment, { children: [_jsx(CodeLine, { tokens: line }), index < tokens.length - 1 && '\n'] }, index))) }) }), _jsxs(ButtonGroup, { className: "chat-code-actions", role: "group", "aria-label": t('code.actions'), children: [_jsx(IconButton, { icon: copyState === 'copied' ? Check : Copy, size: "sm", label: copyState === 'copied' ? t('timeline.actions.copied') : t('timeline.menu.copyCode'), busy: copyState === 'copying', "aria-busy": copyState === 'copying', "aria-disabled": copyState === 'copying', onClick: () => void copy() }), actions] }), _jsx("span", { className: "sr-only", role: "status", children: copyState === 'copied' ? t('timeline.actions.copied') : '' }), copyState === 'failed' && (_jsx("p", { className: "chat-code-error", role: "alert", children: t('code.copyFailed') }))] }));
|
|
79
|
+
: tokens.map((line, index) => (_jsxs(Fragment, { children: [_jsx(CodeLine, { tokens: line }), index < tokens.length - 1 && '\n'] }, index))) }) })), _jsxs(ButtonGroup, { className: "chat-code-actions", role: "group", "aria-label": t('code.actions'), children: [_jsx(IconButton, { icon: copyState === 'copied' ? Check : Copy, size: "sm", label: copyState === 'copied' ? t('timeline.actions.copied') : t('timeline.menu.copyCode'), busy: copyState === 'copying', "aria-busy": copyState === 'copying', "aria-disabled": copyState === 'copying', onClick: () => void copy() }), actions] }), _jsx("span", { className: "sr-only", role: "status", children: copyState === 'copied' ? t('timeline.actions.copied') : '' }), copyState === 'failed' && (_jsx("p", { className: "chat-code-error", role: "alert", children: t('code.copyFailed') }))] }));
|
|
162
80
|
}
|
|
@@ -8,7 +8,7 @@ interface ComposerProps {
|
|
|
8
8
|
disabled: boolean;
|
|
9
9
|
readOnly?: boolean;
|
|
10
10
|
providerFixed: boolean;
|
|
11
|
-
onSend(text: string, extras: ChatSendExtras): void
|
|
11
|
+
onSend(text: string, extras: ChatSendExtras): void | Promise<boolean>;
|
|
12
12
|
onRetarget(provider: AgentKind, selection: ModelSelection): Promise<void>;
|
|
13
13
|
}
|
|
14
14
|
export declare function Composer({ chatId, info, focused, answerPromptsElsewhere, disabled, readOnly, providerFixed, onSend, onRetarget }: ComposerProps): import("react").JSX.Element;
|