diff --git a/apps/client/src/widgets/type_widgets/llm_chat/ChatInputBar.css b/apps/client/src/widgets/type_widgets/llm_chat/ChatInputBar.css new file mode 100644 index 0000000000..4599e6a511 --- /dev/null +++ b/apps/client/src/widgets/type_widgets/llm_chat/ChatInputBar.css @@ -0,0 +1,169 @@ +/* Input form */ +.llm-chat-input-form { + display: flex; + flex-direction: column; + gap: 0.5rem; + padding-top: 1rem; + border-top: 1px solid var(--main-border-color); +} + +.llm-chat-input { + flex: 1; + min-height: 60px; + max-height: 200px; + resize: vertical; + padding: 0.75rem; + border: 1px solid var(--main-border-color); + border-radius: 8px; + font-family: inherit; + font-size: inherit; + background: var(--main-background-color); + color: var(--main-text-color); +} + +.llm-chat-input:focus { + outline: none; + border-color: var(--main-selection-color); + box-shadow: 0 0 0 2px var(--main-selection-color-soft, rgba(0, 123, 255, 0.25)); +} + +.llm-chat-input:disabled { + opacity: 0.6; + cursor: not-allowed; +} + +/* Options row */ +.llm-chat-options { + display: flex; + align-items: center; + gap: 0.75rem; +} + +.llm-chat-send-btn { + margin-left: auto; + font-size: 1.25rem; +} + +.llm-chat-send-btn.disabled { + opacity: 0.4; +} + +/* Model selector */ +.llm-chat-model-selector { + display: flex; + align-items: center; + gap: 0.375rem; + font-size: 0.85rem; + color: var(--muted-text-color); +} + +.llm-chat-model-selector .bx { + font-size: 1rem; +} + +.llm-chat-model-selector .dropdown { + display: flex; + + small { + margin-left: 0.5em; + color: var(--muted-text-color); + } + + /* Position legacy models submenu to open upward */ + .dropdown-submenu .dropdown-menu { + bottom: 0; + top: auto; + } +} + +.llm-chat-model-select.select-button { + padding: 0.25rem 0.5rem; + border: 1px solid var(--main-border-color); + border-radius: 4px; + background: var(--main-background-color); + color: var(--main-text-color); + font-family: inherit; + font-size: 0.85rem; + cursor: pointer; + min-width: 140px; + text-align: left; +} + +.llm-chat-model-select.select-button:focus { + outline: none; + border-color: var(--main-selection-color); +} + +.llm-chat-model-select.select-button:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +/* Note context toggle */ +.llm-chat-note-context.tn-low-profile { + max-width: 150px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + opacity: 0.5; + background: none; + border: none; +} + +.llm-chat-note-context.tn-low-profile:hover:not(:disabled) { + opacity: 0.8; + background: none; +} + +.llm-chat-note-context.tn-low-profile.active { + opacity: 1; +} + +/* Context window indicator */ +.llm-chat-context-indicator { + display: flex; + align-items: center; + gap: 0.375rem; + margin-left: 0.5rem; + cursor: help; +} + +.llm-chat-context-pie { + width: 14px; + height: 14px; + border-radius: 50%; + flex-shrink: 0; +} + +.llm-chat-context-text { + font-size: 0.75rem; + color: var(--muted-text-color); +} + +/* No provider state */ +.llm-chat-no-provider { + display: flex; + align-items: center; + justify-content: center; + padding: 1rem; + border-top: 1px solid var(--main-border-color); +} + +.llm-chat-no-provider-content { + display: flex; + flex-direction: column; + align-items: center; + gap: 0.75rem; + text-align: center; + color: var(--muted-text-color); +} + +.llm-chat-no-provider-icon { + font-size: 2rem; + opacity: 0.5; +} + +.llm-chat-no-provider-content p { + margin: 0; + font-size: 0.9rem; +} diff --git a/apps/client/src/widgets/type_widgets/llm_chat/ChatInputBar.tsx b/apps/client/src/widgets/type_widgets/llm_chat/ChatInputBar.tsx index cbf95fe1ea..6491a595b0 100644 --- a/apps/client/src/widgets/type_widgets/llm_chat/ChatInputBar.tsx +++ b/apps/client/src/widgets/type_widgets/llm_chat/ChatInputBar.tsx @@ -1,3 +1,5 @@ +import "./ChatInputBar.css"; + import type { RefObject } from "preact"; import { useState, useCallback } from "preact/hooks"; diff --git a/apps/client/src/widgets/type_widgets/llm_chat/ChatMessage.css b/apps/client/src/widgets/type_widgets/llm_chat/ChatMessage.css new file mode 100644 index 0000000000..498f2e4cb4 --- /dev/null +++ b/apps/client/src/widgets/type_widgets/llm_chat/ChatMessage.css @@ -0,0 +1,372 @@ +/* Message wrapper and bubble */ +.llm-chat-message-wrapper { + position: relative; + margin-top: 1rem; + padding-bottom: 1.25rem; + max-width: 85%; +} + +.llm-chat-message-wrapper:first-child { + margin-top: 0; +} + +.llm-chat-message-wrapper-user { + margin-left: auto; +} + +.llm-chat-message-wrapper-assistant { + margin-right: auto; +} + +/* Show footer only on hover */ +.llm-chat-message-wrapper:hover .llm-chat-footer { + opacity: 1; +} + +.llm-chat-message { + padding: 0.75rem 1rem; + border-radius: 8px; + user-select: text; +} + +.llm-chat-message-user { + background: var(--accented-background-color); +} + +.llm-chat-message-assistant { + background: var(--main-background-color); + border: 1px solid var(--main-border-color); +} + +.llm-chat-message-role { + font-weight: 600; + margin-bottom: 0.25rem; + font-size: 0.8rem; + color: var(--muted-text-color); +} + +.llm-chat-message-content { + word-wrap: break-word; + line-height: 1.5; +} + +/* Preserve whitespace only for user messages (plain text) */ +.llm-chat-message-user .llm-chat-message-content { + white-space: pre-wrap; +} + +.llm-chat-cursor { + display: inline-block; + width: 8px; + height: 1.1em; + background: currentColor; + margin-left: 2px; + vertical-align: text-bottom; + animation: llm-chat-blink 1s infinite; +} + +@keyframes llm-chat-blink { + 0%, 50% { opacity: 1; } + 51%, 100% { opacity: 0; } +} + +/* Tool activity indicator */ +.llm-chat-tool-activity { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem 1rem; + margin-bottom: 1rem; + border-radius: 8px; + background: var(--accented-background-color); + color: var(--muted-text-color); + font-size: 0.9rem; + max-width: 85%; +} + +.llm-chat-tool-spinner { + width: 16px; + height: 16px; + border: 2px solid var(--muted-text-color); + border-top-color: transparent; + border-radius: 50%; + animation: llm-chat-spin 0.8s linear infinite; +} + +@keyframes llm-chat-spin { + to { transform: rotate(360deg); } +} + +/* Citations */ +.llm-chat-citations { + margin-top: 0.75rem; + padding-top: 0.75rem; + border-top: 1px solid var(--main-border-color); +} + +.llm-chat-citations-label { + display: flex; + align-items: center; + gap: 0.25rem; + font-size: 0.8rem; + font-weight: 600; + color: var(--muted-text-color); + margin-bottom: 0.25rem; +} + +.llm-chat-citations-list { + margin: 0; + padding: 0; + list-style: none; + display: flex; + flex-wrap: wrap; + gap: 0.5rem; +} + +.llm-chat-citations-list li { + font-size: 0.8rem; +} + +.llm-chat-citations-list a { + color: var(--link-color, #007bff); + text-decoration: none; + padding: 0.125rem 0.5rem; + background: var(--accented-background-color); + border-radius: 4px; + display: inline-block; +} + +.llm-chat-citations-list a:hover { + text-decoration: underline; +} + +/* Error */ +.llm-chat-error { + padding: 0.75rem 1rem; + margin-bottom: 1rem; + border-radius: 8px; + background: var(--danger-background-color, #fee); + border: 1px solid var(--danger-border-color, #fcc); + color: var(--danger-text-color, #c00); + user-select: text; +} + +/* Error message (persisted in conversation) */ +.llm-chat-message-error { + background: var(--danger-background-color, #fee); + border: 1px solid var(--danger-border-color, #fcc); + color: var(--danger-text-color, #c00); +} + +.llm-chat-message-error .llm-chat-message-role { + color: var(--danger-text-color, #c00); +} + +/* Thinking message (collapsible) */ +.llm-chat-message-thinking { + background: var(--accented-background-color); + border: 1px dashed var(--main-border-color); + cursor: pointer; +} + +.llm-chat-thinking-summary { + display: flex; + align-items: center; + gap: 0.5rem; + font-size: 0.85rem; + font-weight: 500; + color: var(--muted-text-color); + padding: 0.25rem 0; + list-style: none; +} + +.llm-chat-thinking-summary::-webkit-details-marker { + display: none; +} + +.llm-chat-thinking-summary::before { + content: "▶"; + font-size: 0.7em; + transition: transform 0.2s ease; +} + +.llm-chat-message-thinking[open] .llm-chat-thinking-summary::before { + transform: rotate(90deg); +} + +.llm-chat-thinking-summary .bx { + font-size: 1rem; +} + +.llm-chat-thinking-content { + margin-top: 0.5rem; + padding-top: 0.5rem; + border-top: 1px solid var(--main-border-color); + font-size: 0.9rem; + color: var(--muted-text-color); + white-space: pre-wrap; +} + +/* Markdown styles */ +.llm-chat-markdown { + line-height: 1.6; +} + +.llm-chat-markdown p { + margin: 0 0 0.75em 0; +} + +.llm-chat-markdown p:last-child { + margin-bottom: 0; +} + +.llm-chat-markdown h1, +.llm-chat-markdown h2, +.llm-chat-markdown h3, +.llm-chat-markdown h4, +.llm-chat-markdown h5, +.llm-chat-markdown h6 { + margin: 1em 0 0.5em 0; + font-weight: 600; + line-height: 1.3; +} + +.llm-chat-markdown h1:first-child, +.llm-chat-markdown h2:first-child, +.llm-chat-markdown h3:first-child { + margin-top: 0; +} + +.llm-chat-markdown h1 { font-size: 1.4em; } +.llm-chat-markdown h2 { font-size: 1.25em; } +.llm-chat-markdown h3 { font-size: 1.1em; } + +.llm-chat-markdown ul, +.llm-chat-markdown ol { + margin: 0.5em 0; + padding-left: 1.5em; +} + +.llm-chat-markdown li { + margin: 0.25em 0; +} + +.llm-chat-markdown code { + background: var(--accented-background-color); + padding: 0.15em 0.4em; + border-radius: 4px; + font-family: var(--monospace-font-family, monospace); + font-size: 0.9em; +} + +.llm-chat-markdown pre { + background: var(--accented-background-color); + padding: 0.75em 1em; + border-radius: 6px; + overflow-x: auto; + margin: 0.75em 0; +} + +.llm-chat-markdown pre code { + background: none; + padding: 0; + font-size: 0.85em; +} + +.llm-chat-markdown blockquote { + margin: 0.75em 0; + padding: 0.5em 1em; + border-left: 3px solid var(--main-border-color); + background: var(--accented-background-color); +} + +.llm-chat-markdown blockquote p { + margin: 0; +} + +.llm-chat-markdown a { + color: var(--link-color, #007bff); + text-decoration: none; +} + +.llm-chat-markdown a:hover { + text-decoration: underline; +} + +.llm-chat-markdown hr { + border: none; + border-top: 1px solid var(--main-border-color); + margin: 1em 0; +} + +.llm-chat-markdown table { + border-collapse: collapse; + width: 100%; + margin: 0.75em 0; +} + +.llm-chat-markdown th, +.llm-chat-markdown td { + border: 1px solid var(--main-border-color); + padding: 0.5em 0.75em; + text-align: left; +} + +.llm-chat-markdown th { + background: var(--accented-background-color); + font-weight: 600; +} + +.llm-chat-markdown strong { + font-weight: 600; +} + +.llm-chat-markdown em { + font-style: italic; +} + +/* Message footer (timestamp + token usage, sits below the bubble) */ +.llm-chat-footer { + position: absolute; + bottom: 0; + left: 0; + right: 0; + display: flex; + align-items: center; + gap: 0.375rem; + padding: 0.125rem 0.5rem; + font-size: 0.7rem; + color: var(--muted-text-color); + cursor: default; + opacity: 0; + transition: opacity 0.15s ease; +} + +.llm-chat-footer-user { + justify-content: flex-end; +} + +.llm-chat-footer .bx { + font-size: 0.875rem; +} + +.llm-chat-footer-time { + cursor: help; +} + +.llm-chat-usage-model { + font-weight: 500; +} + +.llm-chat-usage-separator { + opacity: 0.5; +} + +.llm-chat-usage-tokens { + cursor: help; + font-family: var(--monospace-font-family, monospace); +} + +.llm-chat-usage-cost { + font-family: var(--monospace-font-family, monospace); +} diff --git a/apps/client/src/widgets/type_widgets/llm_chat/ChatMessage.tsx b/apps/client/src/widgets/type_widgets/llm_chat/ChatMessage.tsx index 1a57c3e542..60e24f844f 100644 --- a/apps/client/src/widgets/type_widgets/llm_chat/ChatMessage.tsx +++ b/apps/client/src/widgets/type_widgets/llm_chat/ChatMessage.tsx @@ -1,4 +1,4 @@ -import "./LlmChat.css"; +import "./ChatMessage.css"; import { Marked } from "marked"; import { useMemo } from "preact/hooks"; diff --git a/apps/client/src/widgets/type_widgets/llm_chat/LlmChat.css b/apps/client/src/widgets/type_widgets/llm_chat/LlmChat.css index 5e040c8a01..06af4bac6c 100644 --- a/apps/client/src/widgets/type_widgets/llm_chat/LlmChat.css +++ b/apps/client/src/widgets/type_widgets/llm_chat/LlmChat.css @@ -11,786 +11,3 @@ overflow-y: auto; padding-bottom: 1rem; } - -.llm-chat-message-wrapper { - position: relative; - margin-top: 1rem; - padding-bottom: 1.25rem; - max-width: 85%; -} - -.llm-chat-message-wrapper:first-child { - margin-top: 0; -} - -.llm-chat-message-wrapper-user { - margin-left: auto; -} - -.llm-chat-message-wrapper-assistant { - margin-right: auto; -} - -/* Show footer only on hover */ -.llm-chat-message-wrapper:hover .llm-chat-footer { - opacity: 1; -} - -.llm-chat-message { - padding: 0.75rem 1rem; - border-radius: 8px; - user-select: text; -} - -.llm-chat-message-user { - background: var(--accented-background-color); -} - -.llm-chat-message-assistant { - background: var(--main-background-color); - border: 1px solid var(--main-border-color); -} - -.llm-chat-message-role { - font-weight: 600; - margin-bottom: 0.25rem; - font-size: 0.8rem; - color: var(--muted-text-color); -} - -.llm-chat-message-content { - word-wrap: break-word; - line-height: 1.5; -} - -/* Preserve whitespace only for user messages (plain text) */ -.llm-chat-message-user .llm-chat-message-content { - white-space: pre-wrap; -} - -.llm-chat-cursor { - display: inline-block; - width: 8px; - height: 1.1em; - background: currentColor; - margin-left: 2px; - vertical-align: text-bottom; - animation: llm-chat-blink 1s infinite; -} - -@keyframes llm-chat-blink { - 0%, 50% { opacity: 1; } - 51%, 100% { opacity: 0; } -} - -/* Tool activity indicator */ -.llm-chat-tool-activity { - display: flex; - align-items: center; - gap: 0.5rem; - padding: 0.5rem 1rem; - margin-bottom: 1rem; - border-radius: 8px; - background: var(--accented-background-color); - color: var(--muted-text-color); - font-size: 0.9rem; - max-width: 85%; -} - -.llm-chat-tool-spinner { - width: 16px; - height: 16px; - border: 2px solid var(--muted-text-color); - border-top-color: transparent; - border-radius: 50%; - animation: llm-chat-spin 0.8s linear infinite; -} - -@keyframes llm-chat-spin { - to { transform: rotate(360deg); } -} - -/* Citations */ -.llm-chat-citations { - margin-top: 0.75rem; - padding-top: 0.75rem; - border-top: 1px solid var(--main-border-color); -} - -.llm-chat-citations-label { - display: flex; - align-items: center; - gap: 0.25rem; - font-size: 0.8rem; - font-weight: 600; - color: var(--muted-text-color); - margin-bottom: 0.25rem; -} - -.llm-chat-citations-list { - margin: 0; - padding: 0; - list-style: none; - display: flex; - flex-wrap: wrap; - gap: 0.5rem; -} - -.llm-chat-citations-list li { - font-size: 0.8rem; -} - -.llm-chat-citations-list a { - color: var(--link-color, #007bff); - text-decoration: none; - padding: 0.125rem 0.5rem; - background: var(--accented-background-color); - border-radius: 4px; - display: inline-block; -} - -.llm-chat-citations-list a:hover { - text-decoration: underline; -} - -/* Error */ -.llm-chat-error { - padding: 0.75rem 1rem; - margin-bottom: 1rem; - border-radius: 8px; - background: var(--danger-background-color, #fee); - border: 1px solid var(--danger-border-color, #fcc); - color: var(--danger-text-color, #c00); - user-select: text; -} - -/* Error message (persisted in conversation) */ -.llm-chat-message-error { - background: var(--danger-background-color, #fee); - border: 1px solid var(--danger-border-color, #fcc); - color: var(--danger-text-color, #c00); -} - -.llm-chat-message-error .llm-chat-message-role { - color: var(--danger-text-color, #c00); -} - -/* Thinking message (collapsible) */ -.llm-chat-message-thinking { - background: var(--accented-background-color); - border: 1px dashed var(--main-border-color); - cursor: pointer; -} - -.llm-chat-thinking-summary { - display: flex; - align-items: center; - gap: 0.5rem; - font-size: 0.85rem; - font-weight: 500; - color: var(--muted-text-color); - padding: 0.25rem 0; - list-style: none; -} - -.llm-chat-thinking-summary::-webkit-details-marker { - display: none; -} - -.llm-chat-thinking-summary::before { - content: "▶"; - font-size: 0.7em; - transition: transform 0.2s ease; -} - -.llm-chat-message-thinking[open] .llm-chat-thinking-summary::before { - transform: rotate(90deg); -} - -.llm-chat-thinking-summary .bx { - font-size: 1rem; -} - -.llm-chat-thinking-content { - margin-top: 0.5rem; - padding-top: 0.5rem; - border-top: 1px solid var(--main-border-color); - font-size: 0.9rem; - color: var(--muted-text-color); - white-space: pre-wrap; -} - -/* Input form */ -.llm-chat-input-form { - display: flex; - flex-direction: column; - gap: 0.5rem; - padding-top: 1rem; - border-top: 1px solid var(--main-border-color); -} - -.llm-chat-input { - flex: 1; - min-height: 60px; - max-height: 200px; - resize: vertical; - padding: 0.75rem; - border: 1px solid var(--main-border-color); - border-radius: 8px; - font-family: inherit; - font-size: inherit; - background: var(--main-background-color); - color: var(--main-text-color); -} - -.llm-chat-input:focus { - outline: none; - border-color: var(--main-selection-color); - box-shadow: 0 0 0 2px var(--main-selection-color-soft, rgba(0, 123, 255, 0.25)); -} - -.llm-chat-input:disabled { - opacity: 0.6; - cursor: not-allowed; -} - -/* Options row */ -.llm-chat-options { - display: flex; - align-items: center; - gap: 0.75rem; -} - -.llm-chat-send-btn { - margin-left: auto; - font-size: 1.25rem; -} - -.llm-chat-send-btn.disabled { - opacity: 0.4; -} - -/* Model selector */ -.llm-chat-model-selector { - display: flex; - align-items: center; - gap: 0.375rem; - font-size: 0.85rem; - color: var(--muted-text-color); -} - -.llm-chat-model-selector .bx { - font-size: 1rem; -} - -.llm-chat-model-selector .dropdown { - display: flex; - - small { - margin-left: 0.5em; - color: var(--muted-text-color); - } - - /* Position legacy models submenu to open upward */ - .dropdown-submenu .dropdown-menu { - bottom: 0; - top: auto; - } -} - -.llm-chat-model-select.select-button { - padding: 0.25rem 0.5rem; - border: 1px solid var(--main-border-color); - border-radius: 4px; - background: var(--main-background-color); - color: var(--main-text-color); - font-family: inherit; - font-size: 0.85rem; - cursor: pointer; - min-width: 140px; - text-align: left; -} - -.llm-chat-model-select.select-button:focus { - outline: none; - border-color: var(--main-selection-color); -} - -.llm-chat-model-select.select-button:disabled { - opacity: 0.5; - cursor: not-allowed; -} - -/* Note context toggle */ -.llm-chat-note-context.tn-low-profile { - max-width: 150px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - opacity: 0.5; - background: none; - border: none; -} - -.llm-chat-note-context.tn-low-profile:hover:not(:disabled) { - opacity: 0.8; - background: none; -} - -.llm-chat-note-context.tn-low-profile.active { - opacity: 1; -} - -/* Markdown styles */ -.llm-chat-markdown { - line-height: 1.6; -} - -.llm-chat-markdown p { - margin: 0 0 0.75em 0; -} - -.llm-chat-markdown p:last-child { - margin-bottom: 0; -} - -.llm-chat-markdown h1, -.llm-chat-markdown h2, -.llm-chat-markdown h3, -.llm-chat-markdown h4, -.llm-chat-markdown h5, -.llm-chat-markdown h6 { - margin: 1em 0 0.5em 0; - font-weight: 600; - line-height: 1.3; -} - -.llm-chat-markdown h1:first-child, -.llm-chat-markdown h2:first-child, -.llm-chat-markdown h3:first-child { - margin-top: 0; -} - -.llm-chat-markdown h1 { font-size: 1.4em; } -.llm-chat-markdown h2 { font-size: 1.25em; } -.llm-chat-markdown h3 { font-size: 1.1em; } - -.llm-chat-markdown ul, -.llm-chat-markdown ol { - margin: 0.5em 0; - padding-left: 1.5em; -} - -.llm-chat-markdown li { - margin: 0.25em 0; -} - -.llm-chat-markdown code { - background: var(--accented-background-color); - padding: 0.15em 0.4em; - border-radius: 4px; - font-family: var(--monospace-font-family, monospace); - font-size: 0.9em; -} - -.llm-chat-markdown pre { - background: var(--accented-background-color); - padding: 0.75em 1em; - border-radius: 6px; - overflow-x: auto; - margin: 0.75em 0; -} - -.llm-chat-markdown pre code { - background: none; - padding: 0; - font-size: 0.85em; -} - -.llm-chat-markdown blockquote { - margin: 0.75em 0; - padding: 0.5em 1em; - border-left: 3px solid var(--main-border-color); - background: var(--accented-background-color); -} - -.llm-chat-markdown blockquote p { - margin: 0; -} - -.llm-chat-markdown a { - color: var(--link-color, #007bff); - text-decoration: none; -} - -.llm-chat-markdown a:hover { - text-decoration: underline; -} - -.llm-chat-markdown hr { - border: none; - border-top: 1px solid var(--main-border-color); - margin: 1em 0; -} - -.llm-chat-markdown table { - border-collapse: collapse; - width: 100%; - margin: 0.75em 0; -} - -.llm-chat-markdown th, -.llm-chat-markdown td { - border: 1px solid var(--main-border-color); - padding: 0.5em 0.75em; - text-align: left; -} - -.llm-chat-markdown th { - background: var(--accented-background-color); - font-weight: 600; -} - -.llm-chat-markdown strong { - font-weight: 600; -} - -.llm-chat-markdown em { - font-style: italic; -} - -/* Tool calls display */ -.llm-chat-tool-calls { - margin-top: 0.75rem; - padding-top: 0.75rem; - border-top: 1px solid var(--main-border-color); -} - -.llm-chat-tool-calls-summary { - display: flex; - align-items: center; - gap: 0.5rem; - font-size: 0.85rem; - font-weight: 500; - color: var(--muted-text-color); - padding: 0.25rem 0; - cursor: pointer; - list-style: none; -} - -.llm-chat-tool-calls-summary::-webkit-details-marker { - display: none; -} - -.llm-chat-tool-calls-summary::before { - content: "▶"; - font-size: 0.7em; - transition: transform 0.2s ease; -} - -.llm-chat-tool-calls[open] .llm-chat-tool-calls-summary::before { - transform: rotate(90deg); -} - -.llm-chat-tool-calls-summary .bx { - font-size: 1rem; -} - -.llm-chat-tool-calls-list { - margin-top: 0.5rem; - display: flex; - flex-direction: column; - gap: 0.75rem; -} - -.llm-chat-tool-call { - background: var(--accented-background-color); - border-radius: 6px; - padding: 0.75rem; - font-size: 0.85rem; -} - -.llm-chat-tool-call-name { - font-weight: 600; - margin-bottom: 0.5rem; - color: var(--main-text-color); -} - -.llm-chat-tool-call-input, -.llm-chat-tool-call-result { - margin-top: 0.5rem; -} - -.llm-chat-tool-call-input strong, -.llm-chat-tool-call-result strong { - display: block; - font-size: 0.75rem; - color: var(--muted-text-color); - margin-bottom: 0.25rem; -} - -.llm-chat-tool-call pre { - margin: 0; - padding: 0.5rem; - background: var(--main-background-color); - border-radius: 4px; - overflow-x: auto; - font-size: 0.8rem; - font-family: var(--monospace-font-family, monospace); - max-height: 200px; - overflow-y: auto; -} - -/* Inline tool call cards */ -.llm-chat-tool-call-inline { - margin: 0.5rem 0; - border: 1px solid var(--main-border-color); - border-radius: 8px; - font-size: 0.85rem; -} - -.llm-chat-tool-call-inline-summary { - display: flex; - flex-wrap: wrap; - align-items: baseline; - gap: 0.25rem; - padding: 0.5rem 0.75rem; - cursor: pointer; - list-style: none; - font-weight: 500; - color: var(--muted-text-color); -} - -.llm-chat-tool-call-inline-summary::-webkit-details-marker { - display: none; -} - -.llm-chat-tool-call-inline-summary::after { - content: "▾"; - margin-left: auto; - font-size: 1em; - transition: transform 0.2s ease; -} - -.llm-chat-tool-call-inline[open] .llm-chat-tool-call-inline-summary::after { - transform: rotate(180deg); -} - -.llm-chat-tool-call-inline-summary > .bx { - font-size: 1rem; - margin-right: 0.15rem; -} - -.llm-chat-tool-call-detail, -.llm-chat-tool-call-note-ref { - font-weight: 400; - color: var(--main-text-color); -} - -.llm-chat-tool-call-detail::before, -.llm-chat-tool-call-note-ref::before { - content: "—"; - margin-right: 0.35rem; - color: var(--muted-text-color); -} - -.llm-chat-tool-call-inline-body { - padding: 0; -} - -.llm-chat-tool-call-inline-body .llm-chat-tool-call-input, -.llm-chat-tool-call-inline-body .llm-chat-tool-call-result { - padding: 0.5rem 0.75rem; - max-height: 300px; - overflow: auto; -} - -.llm-chat-tool-call-inline-body .llm-chat-tool-call-result { - border-top: 1px solid var(--main-border-color); -} - -.llm-chat-tool-call-inline-body pre { - margin: 0; - padding: 0.5rem; - background: var(--main-background-color); - border-radius: 4px; - font-size: 0.8rem; - font-family: var(--monospace-font-family, monospace); -} - -.llm-chat-tool-call-inline-body strong { - display: block; - font-size: 0.75rem; - color: var(--muted-text-color); - margin-bottom: 0.25rem; -} - -/* Tool call key-value table */ -.llm-chat-tool-call-table { - width: 100%; - table-layout: auto; - border-collapse: collapse; - font-size: 0.8rem; - background: var(--main-background-color); - border-radius: 4px; - overflow: hidden; -} - -.llm-chat-tool-call-table td { - padding: 0.25rem 0.5rem; - vertical-align: top; - border-bottom: 1px solid var(--main-border-color); -} - -.llm-chat-tool-call-table tr:last-child td { - border-bottom: none; -} - -.llm-chat-tool-call-table-key { - font-weight: 600; - white-space: nowrap; - color: var(--muted-text-color); -} - -.llm-chat-tool-call-table-value pre { - margin: 0; - padding: 0; - background: none; - white-space: pre-wrap; - word-break: break-word; -} - -/* Nested tables */ -.llm-chat-tool-call-table-value .llm-chat-tool-call-table { - background: none; - width: auto; - min-width: 100%; -} - -.llm-chat-tool-call-table-array { - display: flex; - flex-direction: column; -} - -.llm-chat-tool-call-table-array > .llm-chat-tool-call-table { - background: none; -} - -.llm-chat-tool-call-table-array > .llm-chat-tool-call-table + .llm-chat-tool-call-table { - border-top: 1px solid var(--main-border-color); -} - -/* Tool call error styling */ -.llm-chat-tool-call-error { - border-color: var(--danger-color, #dc3545); -} - -.llm-chat-tool-call-error .llm-chat-tool-call-inline-summary { - color: var(--danger-color, #dc3545); -} - -.llm-chat-tool-call-error-badge { - font-size: 0.75rem; - font-weight: 400; - color: var(--danger-color, #dc3545); - opacity: 0.8; -} - -.llm-chat-tool-call-result-error pre { - color: var(--danger-color, #dc3545); -} - -/* Message footer (timestamp + token usage, sits below the bubble) */ -.llm-chat-footer { - position: absolute; - bottom: 0; - left: 0; - right: 0; - display: flex; - align-items: center; - gap: 0.375rem; - padding: 0.125rem 0.5rem; - font-size: 0.7rem; - color: var(--muted-text-color); - cursor: default; - opacity: 0; - transition: opacity 0.15s ease; -} - -.llm-chat-footer-user { - justify-content: flex-end; -} - -.llm-chat-footer .bx { - font-size: 0.875rem; -} - -.llm-chat-footer-time { - cursor: help; -} - -.llm-chat-usage-model { - font-weight: 500; -} - -.llm-chat-usage-separator { - opacity: 0.5; -} - -.llm-chat-usage-tokens { - cursor: help; - font-family: var(--monospace-font-family, monospace); -} - -.llm-chat-usage-cost { - font-family: var(--monospace-font-family, monospace); -} - -/* Context window indicator */ -.llm-chat-context-indicator { - display: flex; - align-items: center; - gap: 0.375rem; - margin-left: 0.5rem; - cursor: help; -} - -.llm-chat-context-pie { - width: 14px; - height: 14px; - border-radius: 50%; - flex-shrink: 0; -} - -.llm-chat-context-text { - font-size: 0.75rem; - color: var(--muted-text-color); -} - -/* No provider state */ -.llm-chat-no-provider { - display: flex; - align-items: center; - justify-content: center; - padding: 1rem; - border-top: 1px solid var(--main-border-color); -} - -.llm-chat-no-provider-content { - display: flex; - flex-direction: column; - align-items: center; - gap: 0.75rem; - text-align: center; - color: var(--muted-text-color); -} - -.llm-chat-no-provider-icon { - font-size: 2rem; - opacity: 0.5; -} - -.llm-chat-no-provider-content p { - margin: 0; - font-size: 0.9rem; -} diff --git a/apps/client/src/widgets/type_widgets/llm_chat/ToolCallCard.css b/apps/client/src/widgets/type_widgets/llm_chat/ToolCallCard.css new file mode 100644 index 0000000000..0d95e00e44 --- /dev/null +++ b/apps/client/src/widgets/type_widgets/llm_chat/ToolCallCard.css @@ -0,0 +1,240 @@ +/* Tool calls display (legacy wrapper) */ +.llm-chat-tool-calls { + margin-top: 0.75rem; + padding-top: 0.75rem; + border-top: 1px solid var(--main-border-color); +} + +.llm-chat-tool-calls-summary { + display: flex; + align-items: center; + gap: 0.5rem; + font-size: 0.85rem; + font-weight: 500; + color: var(--muted-text-color); + padding: 0.25rem 0; + cursor: pointer; + list-style: none; +} + +.llm-chat-tool-calls-summary::-webkit-details-marker { + display: none; +} + +.llm-chat-tool-calls-summary::before { + content: "▶"; + font-size: 0.7em; + transition: transform 0.2s ease; +} + +.llm-chat-tool-calls[open] .llm-chat-tool-calls-summary::before { + transform: rotate(90deg); +} + +.llm-chat-tool-calls-summary .bx { + font-size: 1rem; +} + +.llm-chat-tool-calls-list { + margin-top: 0.5rem; + display: flex; + flex-direction: column; + gap: 0.75rem; +} + +.llm-chat-tool-call { + background: var(--accented-background-color); + border-radius: 6px; + padding: 0.75rem; + font-size: 0.85rem; +} + +.llm-chat-tool-call-name { + font-weight: 600; + margin-bottom: 0.5rem; + color: var(--main-text-color); +} + +.llm-chat-tool-call-input, +.llm-chat-tool-call-result { + margin-top: 0.5rem; +} + +.llm-chat-tool-call-input strong, +.llm-chat-tool-call-result strong { + display: block; + font-size: 0.75rem; + color: var(--muted-text-color); + margin-bottom: 0.25rem; +} + +.llm-chat-tool-call pre { + margin: 0; + padding: 0.5rem; + background: var(--main-background-color); + border-radius: 4px; + overflow-x: auto; + font-size: 0.8rem; + font-family: var(--monospace-font-family, monospace); + max-height: 200px; + overflow-y: auto; +} + +/* Inline tool call cards */ +.llm-chat-tool-call-inline { + margin: 0.5rem 0; + border: 1px solid var(--main-border-color); + border-radius: 8px; + font-size: 0.85rem; +} + +.llm-chat-tool-call-inline-summary { + display: flex; + flex-wrap: wrap; + align-items: baseline; + gap: 0.25rem; + padding: 0.5rem 0.75rem; + cursor: pointer; + list-style: none; + font-weight: 500; + color: var(--muted-text-color); +} + +.llm-chat-tool-call-inline-summary::-webkit-details-marker { + display: none; +} + +.llm-chat-tool-call-inline-summary::after { + content: "▾"; + margin-left: auto; + font-size: 1em; + transition: transform 0.2s ease; +} + +.llm-chat-tool-call-inline[open] .llm-chat-tool-call-inline-summary::after { + transform: rotate(180deg); +} + +.llm-chat-tool-call-inline-summary > .bx { + font-size: 1rem; + margin-right: 0.15rem; +} + +.llm-chat-tool-call-detail, +.llm-chat-tool-call-note-ref { + font-weight: 400; + color: var(--main-text-color); +} + +.llm-chat-tool-call-detail::before, +.llm-chat-tool-call-note-ref::before { + content: "—"; + margin-right: 0.35rem; + color: var(--muted-text-color); +} + +.llm-chat-tool-call-inline-body { + padding: 0; +} + +.llm-chat-tool-call-inline-body .llm-chat-tool-call-input, +.llm-chat-tool-call-inline-body .llm-chat-tool-call-result { + padding: 0.5rem 0.75rem; + max-height: 300px; + overflow: auto; +} + +.llm-chat-tool-call-inline-body .llm-chat-tool-call-result { + border-top: 1px solid var(--main-border-color); +} + +.llm-chat-tool-call-inline-body pre { + margin: 0; + padding: 0.5rem; + background: var(--main-background-color); + border-radius: 4px; + font-size: 0.8rem; + font-family: var(--monospace-font-family, monospace); +} + +.llm-chat-tool-call-inline-body strong { + display: block; + font-size: 0.75rem; + color: var(--muted-text-color); + margin-bottom: 0.25rem; +} + +/* Tool call key-value table */ +.llm-chat-tool-call-table { + width: 100%; + table-layout: auto; + border-collapse: collapse; + font-size: 0.8rem; + background: var(--main-background-color); + border-radius: 4px; + overflow: hidden; +} + +.llm-chat-tool-call-table td { + padding: 0.25rem 0.5rem; + vertical-align: top; + border-bottom: 1px solid var(--main-border-color); +} + +.llm-chat-tool-call-table tr:last-child td { + border-bottom: none; +} + +.llm-chat-tool-call-table-key { + font-weight: 600; + white-space: nowrap; + color: var(--muted-text-color); +} + +.llm-chat-tool-call-table-value pre { + margin: 0; + padding: 0; + background: none; + white-space: pre-wrap; + word-break: break-word; +} + +/* Nested tables */ +.llm-chat-tool-call-table-value .llm-chat-tool-call-table { + background: none; + width: auto; + min-width: 100%; +} + +.llm-chat-tool-call-table-array { + display: flex; + flex-direction: column; +} + +.llm-chat-tool-call-table-array > .llm-chat-tool-call-table { + background: none; +} + +.llm-chat-tool-call-table-array > .llm-chat-tool-call-table + .llm-chat-tool-call-table { + border-top: 1px solid var(--main-border-color); +} + +/* Tool call error styling */ +.llm-chat-tool-call-error { + border-color: var(--danger-color, #dc3545); +} + +.llm-chat-tool-call-error .llm-chat-tool-call-inline-summary { + color: var(--danger-color, #dc3545); +} + +.llm-chat-tool-call-error-badge { + font-size: 0.75rem; + font-weight: 400; + color: var(--danger-color, #dc3545); + opacity: 0.8; +} + +.llm-chat-tool-call-result-error pre { + color: var(--danger-color, #dc3545); +} diff --git a/apps/client/src/widgets/type_widgets/llm_chat/ToolCallCard.tsx b/apps/client/src/widgets/type_widgets/llm_chat/ToolCallCard.tsx index 6cc983a2b2..5962fa74ff 100644 --- a/apps/client/src/widgets/type_widgets/llm_chat/ToolCallCard.tsx +++ b/apps/client/src/widgets/type_widgets/llm_chat/ToolCallCard.tsx @@ -1,3 +1,5 @@ +import "./ToolCallCard.css"; + import { Trans } from "react-i18next"; import { t } from "../../../services/i18n.js";