besser-agentic-framework-ui 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,10 @@
1
+ import type { ChatMessage } from '../types/agent';
2
+ import type { ConnectionStatus } from '../hooks/useWebSocket';
3
+ interface ChatAreaProps {
4
+ messages: ChatMessage[];
5
+ setMessages: React.Dispatch<React.SetStateAction<ChatMessage[]>>;
6
+ status: ConnectionStatus;
7
+ send: (action: string, message: unknown) => void;
8
+ }
9
+ export declare function ChatArea({ messages, setMessages, status, send }: ChatAreaProps): import("react/jsx-runtime").JSX.Element;
10
+ export {};
@@ -0,0 +1,6 @@
1
+ interface GUIRendererProps {
2
+ content: unknown;
3
+ onInteract?: (eventJson: string) => void;
4
+ }
5
+ export declare function GUIRenderer({ content, onInteract }: GUIRendererProps): import("react/jsx-runtime").JSX.Element;
6
+ export {};
@@ -0,0 +1,8 @@
1
+ import type { ChatMessage } from '../types/agent';
2
+ interface MessageBubbleProps {
3
+ message: ChatMessage;
4
+ onOptionSelect?: (option: string) => void;
5
+ onUIInteract?: (eventJson: string) => void;
6
+ }
7
+ export declare function MessageBubble({ message, onOptionSelect, onUIInteract }: MessageBubbleProps): import("react/jsx-runtime").JSX.Element | null;
8
+ export {};
@@ -0,0 +1,19 @@
1
+ import { type ReasoningTraceMessage } from '../types/reasoningStep';
2
+ interface ReasoningTraceProps {
3
+ trace: ReasoningTraceMessage;
4
+ }
5
+ /**
6
+ * Renders a streamed reasoning trace.
7
+ *
8
+ * - While `inProgress` is true, the trace is shown expanded so the user can
9
+ * watch the agent think. Steps are grouped by their `step` number so each
10
+ * loop iteration shows a single "STEP N" header followed by every event
11
+ * that happened during it.
12
+ * - Once `inProgress` flips to false (the BAF emitted `reasoning_finished`),
13
+ * the trace collapses to a single header line; clicking re-expands it.
14
+ * - The task list (sent on a parallel channel via `task_list_update`) is
15
+ * shown above the step trace as its own checklist panel with colored
16
+ * status boxes.
17
+ */
18
+ export declare function ReasoningTrace({ trace }: ReasoningTraceProps): import("react/jsx-runtime").JSX.Element;
19
+ export {};
@@ -0,0 +1,14 @@
1
+ import type { Payload } from '../types/payload';
2
+ export type ConnectionStatus = 'disconnected' | 'connecting' | 'connected' | 'error';
3
+ interface UseWebSocketOptions {
4
+ onMessage: (payload: Payload) => void;
5
+ onHistoryMessage?: (payload: Payload) => void;
6
+ onOpen?: () => void;
7
+ }
8
+ interface UseWebSocketReturn {
9
+ status: ConnectionStatus;
10
+ send: (action: string, message: unknown) => void;
11
+ disconnect: () => void;
12
+ }
13
+ export declare function useWebSocket(url: string | null, options: UseWebSocketOptions): UseWebSocketReturn;
14
+ export {};
package/dist/lib.d.ts ADDED
@@ -0,0 +1,15 @@
1
+ import './lib.css';
2
+ import './App.css';
3
+ export { ChatArea } from './components/ChatArea';
4
+ export { MessageBubble } from './components/MessageBubble';
5
+ export { ReasoningTrace } from './components/ReasoningTrace';
6
+ export { GUIRenderer } from './components/GUIRenderer';
7
+ export { useWebSocket } from './hooks/useWebSocket';
8
+ export type { ConnectionStatus } from './hooks/useWebSocket';
9
+ export type { ChatMessage, Agent } from './types/agent';
10
+ export { PayloadAction } from './types/payload';
11
+ export type { Payload } from './types/payload';
12
+ export { ReasoningStepKind, TaskStatus, REASONING_TRACE_ACTION, isReasoningStart, isReasoningEnd, visibleSteps, isEmptyTrace, } from './types/reasoningStep';
13
+ export type { ReasoningStep, Task, ReasoningTraceMessage } from './types/reasoningStep';
14
+ export { looksLikeMarkdown, looksLikeCode, detectContentKind } from './utils/contentDetect';
15
+ export type { RenderHint } from './utils/contentDetect';
package/dist/style.css ADDED
@@ -0,0 +1,2 @@
1
+ .baf-chat{--bg:#f8f9fa;--surface:#fff;--border:#e2e8f0;--code-bg:#f1f5f9;--text-primary:#1a202c;--text-secondary:#64748b;--accent:#2563eb;--accent-hover:#1d4ed8;--accent-bg:#2563eb14;--error:#ef4444;--error-bg:#ef44441a}@media (prefers-color-scheme:dark){.baf-chat{--bg:#0f172a;--surface:#1e293b;--border:#334155;--code-bg:#1a2535;--text-primary:#f1f5f9;--text-secondary:#94a3b8;--accent:#3b82f6;--accent-hover:#2563eb;--accent-bg:#3b82f61a;--error:#f87171;--error-bg:#f871711a}}.baf-chat *,.baf-chat :before,.baf-chat :after{box-sizing:border-box;margin:0;padding:0}.btn{cursor:pointer;border:none;border-radius:8px;padding:9px 18px;font-family:inherit;font-size:.9rem;font-weight:500;transition:background .15s,opacity .15s,color .15s}.btn--primary{background:var(--accent);color:#fff}.btn--primary:hover:not(:disabled){background:var(--accent-hover)}.btn--primary:disabled{opacity:.45;cursor:not-allowed}.btn--secondary{background:var(--border);color:var(--text-primary)}.btn--secondary:hover{filter:brightness(.93)}.btn--ghost{color:var(--text-secondary);background:0 0;padding:8px 12px}.btn--ghost:hover{background:var(--border);color:var(--text-primary)}.agent-selector{background:var(--bg);flex-direction:column;align-items:center;min-height:100vh;padding:64px 24px 40px;display:flex}.agent-selector__header{text-align:center;margin-bottom:48px}.agent-selector__title{color:var(--text-primary);margin-bottom:8px;font-size:2rem;font-weight:700}.agent-selector__subtitle{color:var(--text-secondary);font-size:1rem}.agent-selector__username-bar{align-items:center;gap:12px;width:100%;max-width:360px;margin-top:20px;display:flex}.agent-selector__username-label{color:var(--text-secondary);white-space:nowrap;font-size:.875rem;font-weight:500}.agent-selector__username-input{background:var(--surface);border:1px solid var(--border);color:var(--text);border-radius:8px;outline:none;flex:1;padding:8px 12px;font-size:.9rem;transition:border-color .15s}.agent-selector__username-input:focus{border-color:var(--accent)}.agent-selector__grid{grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:16px;width:100%;max-width:900px;display:grid}.agent-card{background:var(--surface);border:1px solid var(--border);cursor:pointer;text-align:left;width:100%;color:var(--text-primary);border-radius:12px;align-items:center;gap:14px;padding:20px;font-family:inherit;transition:box-shadow .2s,border-color .2s;display:flex;position:relative}.agent-card:hover{border-color:var(--accent);box-shadow:0 4px 16px #00000012}.agent-card--add{color:var(--text-secondary);background:0 0;border-style:dashed;flex-direction:column;justify-content:center;gap:6px;font-size:.95rem}.agent-card--add:hover{color:var(--accent)}.agent-card__icon{flex-shrink:0;font-size:1.8rem}.agent-card__plus{font-size:2rem;line-height:1}.agent-card__info{flex:1;min-width:0}.agent-card__name{margin-bottom:4px;font-size:1rem;font-weight:600}.agent-card__url{color:var(--text-secondary);text-overflow:ellipsis;white-space:nowrap;font-family:monospace;font-size:.8rem;overflow:hidden}.agent-card__remove{width:24px;height:24px;color:var(--text-secondary);cursor:pointer;opacity:0;background:0 0;border:none;border-radius:50%;justify-content:center;align-items:center;font-size:1.2rem;line-height:1;transition:opacity .15s,background .15s,color .15s;display:flex;position:absolute;top:8px;right:8px}.agent-card:hover .agent-card__remove{opacity:1}.agent-card__remove:hover{background:var(--error-bg);color:var(--error)}.modal-overlay{z-index:100;background:#00000073;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.modal{background:var(--surface);border-radius:16px;width:100%;max-width:440px;padding:32px;box-shadow:0 20px 60px #00000026}.modal__title{color:var(--text-primary);margin-bottom:24px;font-size:1.25rem;font-weight:700}.modal__form{flex-direction:column;gap:16px;display:flex}.modal__label{color:var(--text-secondary);flex-direction:column;gap:6px;font-size:.88rem;font-weight:500;display:flex}.modal__input{border:1px solid var(--border);background:var(--bg);color:var(--text-primary);border-radius:8px;outline:none;padding:10px 14px;font-family:inherit;font-size:.95rem;transition:border-color .15s}.modal__input:focus{border-color:var(--accent)}.modal__input--error{border-color:var(--error)!important}.modal__error{color:var(--error);margin-top:2px;font-size:.82rem}.modal__actions{justify-content:flex-end;gap:10px;margin-top:8px;display:flex}.chat-layout{background:var(--bg);flex-direction:column;height:100vh;display:flex}.chat-layout__header{background:var(--surface);border-bottom:1px solid var(--border);flex-shrink:0;align-items:center;gap:12px;padding:10px 16px;display:flex}.chat-layout__agent-info{flex-direction:column;flex:1;min-width:0;display:flex}.chat-layout__agent-name{color:var(--text-primary);font-size:1rem;font-weight:600}.chat-layout__agent-url{color:var(--text-secondary);white-space:nowrap;text-overflow:ellipsis;font-family:monospace;font-size:.78rem;overflow:hidden}.chat-layout__body{flex:1;display:flex;overflow:hidden}.status-badge{flex-shrink:0;align-items:center;gap:7px;font-size:.85rem;font-weight:500;display:flex}.status-badge__dot{border-radius:50%;flex-shrink:0;width:8px;height:8px}.session-sidebar{background:var(--surface);border-right:1px solid var(--border);flex-direction:column;flex-shrink:0;width:240px;display:flex}.session-sidebar__header{border-bottom:1px solid var(--border);flex-direction:column;gap:10px;padding:14px 16px;display:flex}.session-sidebar__title{text-transform:uppercase;letter-spacing:.06em;color:var(--text-secondary);font-size:.8rem;font-weight:600}.session-sidebar__new{flex-direction:column;gap:6px;display:flex}.session-sidebar__name-input{background:var(--bg);border:1px solid var(--border);color:var(--text);border-radius:6px;outline:none;padding:6px 10px;font-size:.825rem;transition:border-color .15s}.session-sidebar__name-input:focus{border-color:var(--accent)}.session-sidebar__start-btn{width:100%;padding:6px 10px;font-size:.825rem}.session-sidebar__empty{color:var(--text-secondary);flex:1;justify-content:center;align-items:center;font-size:.875rem;display:flex}.session-sidebar__body{flex-direction:column;flex:1;padding:6px 0;display:flex;overflow-y:auto}.session-sidebar__status{color:var(--text-secondary);text-align:center;padding:12px 16px;font-size:.825rem}.session-sidebar__status--error{color:#ef4444}.session-item{border-left:3px solid #0000;flex-direction:row;align-items:center;transition:background .15s,border-color .15s;display:flex}.session-item:hover{background:var(--border)}.session-item--active{border-left-color:var(--accent);background:color-mix(in srgb, var(--accent) 12%, transparent)}.session-item__content{all:unset;cursor:pointer;flex-direction:column;flex:1;gap:2px;min-width:0;padding:8px 16px;display:flex}.session-item__delete{all:unset;width:28px;height:28px;color:var(--text-secondary);cursor:pointer;border-radius:6px;flex-shrink:0;justify-content:center;align-items:center;margin-right:8px;transition:background .15s,color .15s;display:flex}.session-item__delete:hover{color:#ef4444;background:#ef444426}.session-item__id{color:var(--text);white-space:nowrap;text-overflow:ellipsis;font-family:monospace;font-size:.75rem;overflow:hidden}.session-item__meta{color:var(--text-secondary);font-size:.7rem}.agent-card__username{color:var(--text-secondary);margin-top:2px;font-size:.75rem}.start-session{background:var(--bg);flex-direction:column;flex:1;justify-content:center;align-items:center;gap:12px;display:flex}.start-session__name-input{background:var(--surface);border:1px solid var(--border);width:280px;color:var(--text);text-align:center;border-radius:8px;outline:none;padding:10px 14px;font-size:.9rem;transition:border-color .15s}.start-session__name-input:focus{border-color:var(--accent)}.start-session__btn{padding:14px 36px;font-size:1rem}.chat-area{background:var(--bg);flex-direction:column;flex:1;display:flex;overflow:hidden}.chat-area__messages{flex-direction:column;flex:1;gap:16px;padding:24px 1%;display:flex;overflow-y:auto}.chat-area__empty{color:var(--text-secondary);text-align:center;margin:auto;font-size:.95rem}.chat-area__input-row{background:0 0;border-top:none;align-items:flex-end;gap:10px;padding:14px 10%;display:flex}.chat-area__textarea{resize:none;border:1px solid var(--border);background:var(--bg);color:var(--text-primary);border-radius:10px;outline:none;flex:1;min-height:42px;max-height:160px;padding:10px 14px;font-family:inherit;font-size:.95rem;line-height:1.5;transition:border-color .15s;overflow-y:auto}.chat-area__textarea:focus{border-color:var(--accent)}.chat-area__textarea:disabled{opacity:.5;cursor:not-allowed}.chat-area__send-btn{border-radius:50%;flex-shrink:0;justify-content:center;align-items:center;width:42px;height:42px;padding:0;font-size:1.2rem;line-height:1;display:flex}.chat-area__composer{flex-direction:column;flex:1;gap:6px;min-width:0;display:flex}.chat-area__input-line{align-items:flex-end;display:flex}.chat-area__input-line .chat-area__textarea{flex:1}.chat-area__attachments{flex-wrap:wrap;gap:6px;padding:0 2px;display:flex}.attachment-chip{background:var(--code-bg);border:1px solid var(--border);border-radius:20px;align-items:center;gap:5px;max-width:220px;padding:4px 8px;font-size:.82rem;display:inline-flex}.attachment-chip__icon{flex-shrink:0}.attachment-chip__name{text-overflow:ellipsis;white-space:nowrap;color:var(--text-primary);overflow:hidden}.attachment-chip__remove{all:unset;cursor:pointer;color:var(--text-secondary);border-radius:50%;flex-shrink:0;padding:1px 2px;font-size:.75rem;line-height:1;transition:color .1s}.attachment-chip__remove:hover{color:#ef4444}.chat-area__icon-btn{width:42px;height:42px;color:var(--text-secondary);border:1px solid var(--border);cursor:pointer;background:0 0;border-radius:50%;flex-shrink:0;justify-content:center;align-items:center;padding:0;font-size:1.5rem;font-weight:400;line-height:1;transition:background .15s,color .15s;display:flex}.chat-area__icon-btn:hover:not(:disabled){background:var(--border);color:var(--text-primary)}.chat-area__icon-btn:disabled{opacity:.4;cursor:not-allowed}.chat-area__mic-btn{color:var(--text-secondary)}.chat-area__mic-btn--recording{color:#ef4444;background:#ef444414;border-color:#ef4444;animation:1.2s ease-in-out infinite mic-pulse}@keyframes mic-pulse{0%,to{box-shadow:0 0 #ef444459}50%{box-shadow:0 0 0 6px #ef444400}}.attach-menu-anchor{flex-shrink:0;position:relative}.attach-menu{background:var(--surface);border:1px solid var(--border);z-index:100;border-radius:10px;min-width:160px;position:absolute;bottom:calc(100% + 8px);right:0;overflow:hidden;box-shadow:0 4px 16px #0000001f}.attach-menu__item{all:unset;width:100%;color:var(--text-primary);cursor:pointer;box-sizing:border-box;align-items:center;gap:10px;padding:10px 14px;font-size:.9rem;transition:background .12s;display:flex}.attach-menu__item:hover{background:var(--border)}.attach-menu__item-icon{font-size:1rem}.message{gap:10px;max-width:78%;display:flex}.message--user{flex-direction:row-reverse;align-self:flex-end}.message--agent{align-self:flex-start}.message__avatar{display:none}.message__body{flex-direction:column;display:flex}.message__timestamp{color:var(--text-secondary);white-space:nowrap;opacity:0;pointer-events:none;flex-shrink:0;align-self:center;font-size:.72rem;transition:opacity .2s,transform .2s;transform:translate(-8px)}.message__timestamp--user{transform:translate(8px)}.message:hover .message__timestamp{opacity:1;transform:translate(0)}.message__bubble{word-break:break-word;font-size:.95rem;line-height:1.55}.message__bubble--user{background:var(--accent);color:#fff;border-radius:16px 16px 4px;padding:10px 14px}.message__bubble--agent{color:var(--text-primary);background:0 0;border:none;padding:2px 0}.msg-text{margin:0}.msg-text--muted{color:var(--text-secondary);font-style:italic}.msg-markdown{line-height:1.6}.msg-markdown p{margin:0 0 6px}.msg-markdown p:last-child{margin-bottom:0}.msg-markdown h1,.msg-markdown h2,.msg-markdown h3{margin:8px 0 4px;font-size:1em}.msg-markdown ul,.msg-markdown ol{margin:4px 0;padding-left:20px}.msg-markdown li{margin:2px 0}.msg-markdown code{background:var(--code-bg);border-radius:4px;padding:1px 5px;font-family:monospace;font-size:.87em}.msg-markdown pre{background:var(--code-bg);border-radius:6px;margin:6px 0;padding:10px 12px;overflow-x:auto}.msg-markdown pre code{background:0 0;padding:0;font-size:.85em}.msg-markdown blockquote{border-left:3px solid var(--border);color:var(--text-secondary);margin:4px 0;padding-left:10px}.msg-markdown table{border-collapse:collapse;width:100%;font-size:.88em}.msg-markdown th,.msg-markdown td{border:1px solid var(--border);text-align:left;padding:4px 8px}.msg-markdown th{background:var(--code-bg)}.msg-markdown a{color:var(--accent)}.msg-html{line-height:1.55}.msg-html a{color:var(--accent)}.msg-file-btn{background:var(--accent-bg);border:1px solid var(--accent);color:var(--accent);cursor:pointer;border-radius:8px;align-items:center;gap:8px;padding:9px 16px;font-family:inherit;font-size:.9rem;font-weight:500;transition:background .15s,color .15s;display:inline-flex}.msg-file-btn:hover{background:var(--accent);color:#fff}.msg-image img{border-radius:8px;max-width:100%;max-height:360px;display:block}.msg-table-wrapper{max-width:100%;overflow-x:auto}.msg-table{border-collapse:collapse;width:100%;font-size:.84rem}.msg-table th,.msg-table td{border:1px solid var(--border);text-align:left;white-space:nowrap;padding:6px 10px}.msg-table th{background:var(--code-bg);font-weight:600}.msg-table__th{cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap}.msg-table__th:hover{background:color-mix(in srgb, var(--accent) 10%, var(--code-bg))}.msg-table__th--sorted{color:var(--accent)}.msg-table__sort-icon{opacity:.6;margin-left:4px;font-size:.75em;display:inline-block}.msg-table__th--sorted .msg-table__sort-icon{opacity:1}.msg-table tr:nth-child(2n){background:var(--code-bg)}.msg-plotly{border-radius:8px;width:100%;min-height:360px;overflow:hidden}.msg-code{background:var(--code-bg);color:var(--text-primary);border-radius:6px;margin-top:6px;padding:10px 12px;font-family:monospace;font-size:.82rem;overflow-x:auto}.msg-options{flex-wrap:wrap;gap:8px;display:flex}.msg-option-btn{border:1px solid var(--accent);color:var(--accent);cursor:pointer;background:0 0;border-radius:20px;padding:7px 14px;font-family:inherit;font-size:.9rem;transition:background .15s,color .15s}.msg-option-btn:hover{background:var(--accent);color:#fff}.msg-location{flex-direction:column;gap:8px;display:flex}.msg-location__map{border:1px solid var(--border);border-radius:8px;width:100%;height:300px;display:block}.msg-location__link{color:var(--accent);font-size:.88rem}.msg-audio{flex-direction:column;gap:6px;display:flex}.msg-audio__player{width:100%;min-width:260px;accent-color:var(--accent)}.msg-audio__meta{color:var(--text-secondary);font-size:.78rem}.message__bubble--media{box-shadow:none!important;background:0 0!important;border:none!important;padding:4px 0!important}.msg-rag__answer{margin:0 0 10px;line-height:1.6}.msg-rag__details{border:1px solid var(--border);border-radius:8px;overflow:hidden}.msg-rag__summary{cursor:pointer;width:100%;color:var(--text-secondary);background:var(--code-bg);text-align:left;-webkit-user-select:none;user-select:none;border:none;align-items:center;gap:6px;padding:8px 12px;font-size:.85rem;font-weight:500;display:flex}.msg-rag__summary-arrow{font-size:.65rem;transition:transform .25s;display:inline-block}.msg-rag__summary--open .msg-rag__summary-arrow{transform:rotate(90deg)}.msg-rag__body-wrapper{grid-template-rows:0fr;transition:grid-template-rows .3s;display:grid}.msg-rag__body-wrapper--open{grid-template-rows:1fr}.msg-rag__body-inner{overflow:hidden}.msg-rag__details-body{flex-direction:column;gap:10px;padding:12px;display:flex}.msg-rag__rag-answer-label{color:var(--text-secondary);text-transform:uppercase;letter-spacing:.06em;font-size:.78rem;font-weight:700}.msg-rag__llm-row{align-items:center;gap:8px;display:flex}.msg-rag__llm-label{color:var(--text-secondary);font-size:.8rem}.msg-rag__llm-badge{background:var(--code-bg);border:1px solid var(--border);color:var(--accent);border-radius:4px;padding:1px 6px;font-size:.78rem}.msg-rag__context-label{color:var(--text-secondary);text-transform:uppercase;letter-spacing:.04em;font-size:.8rem;font-weight:600}.msg-rag__docs{flex-direction:column;gap:8px;display:flex}.msg-rag__doc-card{border:1px solid var(--border);border-radius:6px;font-size:.85rem;overflow:hidden}.msg-rag__doc-header{color:var(--text-secondary);background:var(--code-bg);border-bottom:1px solid var(--border);padding:5px 10px;font-size:.78rem;font-weight:600}.msg-rag__doc-row{border-bottom:1px solid var(--border);gap:8px;padding:5px 10px;line-height:1.5;display:flex}.msg-rag__doc-row:last-child{border-bottom:none}.msg-rag__doc-key{width:58px;color:var(--text-secondary);flex-shrink:0;padding-top:1px;font-size:.78rem;font-weight:600}.msg-rag__doc-value{word-break:break-word;flex:1}.msg-rag__doc-content{white-space:pre-wrap}.gui-renderer{border:1px solid var(--border);background:#fff;border-radius:10px;flex-direction:column;max-width:100%;font-size:.9rem;display:flex;overflow:hidden}.gui-renderer__header{background:var(--code-bg);border-bottom:1px solid var(--border);flex-shrink:0;align-items:center;gap:10px;padding:8px 14px;display:flex}.gui-renderer__title{color:var(--text-primary);font-size:.82rem;font-weight:600}.gui-renderer__description{color:var(--text-secondary);font-size:.78rem}.gui-renderer__tabs{background:var(--code-bg);border-bottom:1px solid var(--border);flex-wrap:wrap;gap:2px;padding:6px 10px 0;display:flex}.gui-renderer__tab{color:var(--text-secondary);cursor:pointer;background:0 0;border:1px solid #0000;border-bottom:none;border-radius:6px 6px 0 0;align-items:center;gap:5px;padding:5px 12px;font-size:.8rem;transition:background .15s,color .15s;display:flex}.gui-renderer__tab:hover{background:var(--border);color:var(--text-primary)}.gui-renderer__tab--active{border-color:var(--border);color:var(--accent);background:#fff;font-weight:600}.gui-renderer__tab-badge{background:var(--accent);color:#fff;border-radius:4px;padding:1px 5px;font-size:.68rem}.gui-renderer__screen{background:#fff;min-width:280px;min-height:200px;padding:0;overflow-x:auto}.gui-chart-placeholder{background:var(--code-bg);border:1px dashed var(--border);min-height:120px;color:var(--text-secondary);border-radius:8px;flex-direction:column;justify-content:center;align-items:center;gap:6px;padding:16px;font-size:.85rem;display:flex}.gui-chart-placeholder__icon{font-size:2rem;line-height:1}.gui-chart-placeholder__title{color:var(--text-primary);font-size:.9rem;font-weight:600}.gui-chart-placeholder__type{color:var(--text-secondary);font-size:.75rem}.gui-chart-placeholder__series{color:var(--text-secondary);font-size:.75rem;font-style:italic}.gui-metric-card{border:1px solid var(--border);background:#fff;border-radius:8px;flex-direction:column;gap:4px;padding:16px;display:flex}.gui-metric-card__title{color:var(--text-secondary);text-transform:uppercase;letter-spacing:.04em;font-size:.8rem}.gui-metric-card__value{font-size:2em;font-weight:700;line-height:1.1}.gui-metric-card__format{color:var(--text-secondary);font-size:.75rem}.gui-agent-component{border:1px dashed var(--border);color:var(--text-secondary);border-radius:8px;align-items:center;gap:8px;padding:12px 14px;font-size:.85rem;display:flex}.message--reasoning .message__body{width:100%;margin:4px 0}.reasoning-trace{border:1px dashed var(--border);color:var(--text-secondary);background:#7d7d7d0d;border-radius:8px;font-size:.82rem;overflow:hidden}.reasoning-trace--live{background:#6366f10f;border-style:solid;border-color:#6366f159}.reasoning-trace__summary{cursor:pointer;width:100%;font:inherit;color:var(--text-secondary);text-align:left;background:0 0;border:none;align-items:center;gap:8px;padding:8px 12px;display:flex}.reasoning-trace__summary:disabled{cursor:default}.reasoning-trace__summary:not(:disabled):hover{background:#7d7d7d0f}.reasoning-trace__icon{font-size:.95rem}.reasoning-trace--live .reasoning-trace__icon{animation:1.4s ease-in-out infinite reasoning-pulse}@keyframes reasoning-pulse{0%,to{opacity:1}50%{opacity:.45}}.reasoning-trace__label{flex:1;font-style:italic;font-weight:500}.reasoning-trace__chevron{font-size:.65rem;transition:transform .25s}.reasoning-trace__summary--open .reasoning-trace__chevron{transform:rotate(90deg)}.reasoning-trace__body-wrapper{grid-template-rows:0fr;transition:grid-template-rows .3s;display:grid}.reasoning-trace__body-wrapper--open{grid-template-rows:1fr}.reasoning-trace__body-inner{overflow:hidden}.reasoning-trace__steps{flex-direction:column;gap:10px;padding:0 12px 10px;display:flex}.reasoning-trace__step-group{flex-direction:column;gap:2px;display:flex}.reasoning-trace__step-header{letter-spacing:.08em;text-transform:uppercase;color:var(--text-secondary);opacity:.6;border-left:2px solid var(--border);font-variant-numeric:tabular-nums;padding:2px 0 2px 8px;font-size:.65rem;font-weight:700}.reasoning-trace__step-list{flex-direction:column;gap:2px;margin:0;padding:0 0 0 10px;list-style:none;display:flex}.reasoning-trace__step{flex-direction:column;display:flex}.reasoning-trace__step-line{text-align:left;width:100%;font:inherit;color:inherit;cursor:pointer;background:0 0;border:none;border-radius:4px;align-items:baseline;gap:8px;padding:3px 6px;display:flex}.reasoning-trace__step-line:disabled{cursor:default}.reasoning-trace__step-line:not(:disabled):hover{background:#7d7d7d14}.reasoning-trace__step-icon{flex-shrink:0;font-size:.85rem}.reasoning-trace__step-summary{word-break:break-word;flex:1;font-size:.82rem;font-style:italic}.reasoning-trace__step-list--nested{border-left:2px solid #7d7d7d33;margin-top:2px;padding-left:20px}.reasoning-trace__step-details{white-space:pre-wrap;word-break:break-word;background:#0000000a;border-radius:6px;max-height:240px;margin:4px 0 6px 32px;padding:8px 10px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.72rem;overflow:auto}.task-panel{border:1px solid var(--border);background:#7d7d7d0f;border-radius:6px;margin:4px 12px 12px;padding:10px 12px}.task-panel__header{align-items:baseline;gap:10px;margin-bottom:8px;display:flex}.task-panel__title{letter-spacing:.08em;text-transform:uppercase;color:var(--text-secondary);font-size:.7rem;font-weight:700}.task-panel__counts{color:var(--text-secondary);gap:6px;font-size:.72rem;display:flex}.task-panel__count{background:#7d7d7d1a;border-radius:4px;padding:1px 6px}.task-panel__count--completed{color:#16a34a}.task-panel__count--skipped{color:#ea580c}.task-panel__count--pending{opacity:.7}.task-panel__list{flex-direction:column;gap:4px;margin:0;padding:0;list-style:none;display:flex}.task-panel__item{word-break:break-word;align-items:flex-start;gap:8px;font-size:.82rem;line-height:1.35;display:flex}.task-panel__text{flex:1;display:inline}.task-panel__item--completed .task-panel__description{color:var(--text-secondary);-webkit-text-decoration:line-through #16a34a66;text-decoration:line-through #16a34a66}.task-panel__item--skipped .task-panel__description{color:var(--text-secondary);-webkit-text-decoration:line-through #ea580c66;text-decoration:line-through #ea580c66}.task-panel__box{border:1.5px solid var(--border);background:0 0;border-radius:3px;flex-shrink:0;width:12px;height:12px;display:inline-block;position:relative;top:1px}.task-panel__box--pending,.task-panel__box--in_progress{border-color:var(--border);background:0 0}.task-panel__box--in_progress{background:#6366f126;border-color:#6366f1}.task-panel__box--completed{background:#16a34a;border-color:#16a34a}.task-panel__box--completed:after{content:"✓";color:#fff;justify-content:center;align-items:center;font-size:9px;font-weight:800;line-height:1;display:flex;position:absolute;inset:0}.task-panel__box--skipped{background:#ea580c;border-color:#ea580c}.task-panel__box--skipped:after{content:"⊘";color:#fff;justify-content:center;align-items:center;font-size:10px;font-weight:700;line-height:1;display:flex;position:absolute;inset:0}.task-panel__id{font-variant-numeric:tabular-nums;opacity:.55;margin-right:6px;font-size:.7rem}.task-panel__description{word-break:break-word}.task-panel__result{color:var(--text-secondary);opacity:.85;margin-top:2px;font-size:.74rem;font-style:italic;display:block}
2
+ /*$vite$:1*/
@@ -0,0 +1,12 @@
1
+ export interface Agent {
2
+ id: string;
3
+ name: string;
4
+ url: string;
5
+ }
6
+ export interface ChatMessage {
7
+ id: string;
8
+ action: string;
9
+ message: unknown;
10
+ isUser: boolean;
11
+ timestamp?: string;
12
+ }
@@ -0,0 +1,30 @@
1
+ export declare const PayloadAction: {
2
+ readonly USER_MESSAGE: "user_message";
3
+ readonly USER_VOICE: "user_voice";
4
+ readonly USER_FILE: "user_file";
5
+ readonly USER_SET_VARIABLE: "user_set_variable";
6
+ readonly RESET: "reset";
7
+ readonly AGENT_REPLY_STR: "agent_reply_str";
8
+ readonly AGENT_REPLY_MARKDOWN: "agent_reply_markdown";
9
+ readonly AGENT_REPLY_HTML: "agent_reply_html";
10
+ readonly AGENT_REPLY_FILE: "agent_reply_file";
11
+ readonly AGENT_REPLY_IMAGE: "agent_reply_image";
12
+ readonly AGENT_REPLY_DF: "agent_reply_dataframe";
13
+ readonly AGENT_REPLY_PLOTLY: "agent_reply_plotly";
14
+ readonly AGENT_REPLY_OPTIONS: "agent_reply_options";
15
+ readonly AGENT_REPLY_LOCATION: "agent_reply_location";
16
+ readonly AGENT_REPLY_RAG: "agent_reply_rag";
17
+ readonly AGENT_REPLY_REASONING_STEP: "agent_reply_reasoning_step";
18
+ readonly AGENT_REPLY_TASK_LIST_UPDATE: "agent_reply_task_list_update";
19
+ readonly AGENT_REPLY_AUDIO: "agent_reply_audio";
20
+ readonly AGENT_REPLY_UI: "agent_reply_ui";
21
+ readonly USER_UPDATE_UI: "user_update_ui";
22
+ readonly FETCH_USER_MESSAGES: "fetch_user_messages";
23
+ };
24
+ export type PayloadAction = (typeof PayloadAction)[keyof typeof PayloadAction];
25
+ export interface Payload {
26
+ action: string;
27
+ message: unknown;
28
+ history?: boolean;
29
+ timestamp?: string;
30
+ }
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Mirrors the BAF `ReasoningStep` dataclass
3
+ * (baf/library/state/reasoning_state_library.py).
4
+ *
5
+ * Every reasoning event the BAF reasoning state emits is shipped over the
6
+ * websocket as `AGENT_REPLY_REASONING_STEP` with this shape as the message.
7
+ * `REASONING_STARTED` and `REASONING_FINISHED` bracket every reasoning loop —
8
+ * the UI uses them to know when to open and close a "live trace" group around
9
+ * the steps in between.
10
+ */
11
+ export declare const ReasoningStepKind: {
12
+ readonly REASONING_STARTED: "reasoning_started";
13
+ readonly REASONING_FINISHED: "reasoning_finished";
14
+ readonly LLM_TEXT: "llm_text";
15
+ readonly LLM_TOOL_CALLS: "llm_tool_calls";
16
+ readonly TOOL_RESULT: "tool_result";
17
+ readonly TASK_ADDED: "task_added";
18
+ readonly TASK_COMPLETED: "task_completed";
19
+ readonly TASK_SKIPPED: "task_skipped";
20
+ readonly PUSHBACK: "pushback";
21
+ readonly MAX_STEPS: "max_steps";
22
+ };
23
+ export type ReasoningStepKind = (typeof ReasoningStepKind)[keyof typeof ReasoningStepKind];
24
+ export interface ReasoningStep {
25
+ kind: ReasoningStepKind | string;
26
+ step: number;
27
+ summary: string;
28
+ details: Record<string, unknown>;
29
+ }
30
+ /**
31
+ * Mirrors the BAF `Task` dataclass.
32
+ *
33
+ * Carried inside the `agent_reply_task_list_update` payload as a list of
34
+ * snapshots — every task list mutation re-sends the full list, so the UI
35
+ * just replaces its state on each update.
36
+ */
37
+ export declare const TaskStatus: {
38
+ readonly PENDING: "pending";
39
+ readonly IN_PROGRESS: "in_progress";
40
+ readonly COMPLETED: "completed";
41
+ readonly SKIPPED: "skipped";
42
+ };
43
+ export type TaskStatus = (typeof TaskStatus)[keyof typeof TaskStatus];
44
+ export interface Task {
45
+ id: number;
46
+ description: string;
47
+ status: TaskStatus | string;
48
+ result: string;
49
+ }
50
+ /**
51
+ * A reasoning trace as displayed in the chat: a single bracketed group of
52
+ * steps from `reasoning_started` to `reasoning_finished`, plus the live task
53
+ * list maintained alongside the step stream.
54
+ *
55
+ * The synthetic action `'reasoning_trace'` is internal to the UI — it never
56
+ * appears on the wire. It is the action used on the ChatMessage that
57
+ * aggregates the streamed steps and task-list snapshots.
58
+ */
59
+ export interface ReasoningTraceMessage {
60
+ steps: ReasoningStep[];
61
+ tasks: Task[];
62
+ inProgress: boolean;
63
+ }
64
+ export declare const REASONING_TRACE_ACTION = "reasoning_trace";
65
+ /** Returns true when the kind marks the start of a new reasoning trace. */
66
+ export declare function isReasoningStart(step: ReasoningStep): boolean;
67
+ /** Returns true when the kind marks the end of a reasoning trace. */
68
+ export declare function isReasoningEnd(step: ReasoningStep): boolean;
69
+ /**
70
+ * Steps that the user actually sees (everything except the
71
+ * `reasoning_started` / `reasoning_finished` bracket markers).
72
+ */
73
+ export declare function visibleSteps(trace: ReasoningTraceMessage): ReasoningStep[];
74
+ /**
75
+ * True when the trace produced no observable reasoning at all — i.e., the
76
+ * LLM answered directly without calling any tools or planning any tasks.
77
+ * Empty traces should not be rendered: the user only sees the final reply.
78
+ */
79
+ export declare function isEmptyTrace(trace: ReasoningTraceMessage): boolean;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Heuristics that decide how to render an `agent_reply_str` message.
3
+ *
4
+ * BAF's `session.reply(text)` always sends `AGENT_REPLY_STR`, but the LLM
5
+ * inside the reasoning loop frequently produces Markdown — headings, lists,
6
+ * fenced code blocks, links — which would look terrible rendered as plain
7
+ * text. These helpers sniff the content and pick a renderer:
8
+ *
9
+ * 1. Markdown (`looksLikeMarkdown`) — for any text containing common
10
+ * Markdown signals (headings, lists, **bold**, `code`, fenced ``` blocks,
11
+ * links, blockquotes, tables, horizontal rules).
12
+ * 2. Code (`looksLikeCode`) — for text that has no Markdown signals but is
13
+ * clearly source code: programming keywords at the start of a line, or
14
+ * very high density of `{};()=` characters across multiple lines.
15
+ * 3. Plain text — fallback when neither matches.
16
+ *
17
+ * The functions are deliberately conservative: a false negative (rendering
18
+ * Markdown as plain text) is uglier but harmless; a false positive (rendering
19
+ * plain prose as Markdown) can mangle words like "5 * 3" or "use _foo_ to…".
20
+ * Each pattern below requires a clear delimiter pair or a specific line shape
21
+ * to keep noise low.
22
+ */
23
+ /**
24
+ * True if the text contains at least one Markdown signal (any of: heading,
25
+ * list, bold, fenced/inline code, link, blockquote, table, hr).
26
+ */
27
+ export declare function looksLikeMarkdown(text: string): boolean;
28
+ /**
29
+ * True if the text has no Markdown signals but looks like source code:
30
+ * either a programming keyword on its own line, or a high density of
31
+ * code-shaped punctuation across multiple lines.
32
+ */
33
+ export declare function looksLikeCode(text: string): boolean;
34
+ export type RenderHint = 'markdown' | 'code' | 'plain';
35
+ /** Pick the best renderer for an unknown-format text reply. */
36
+ export declare function detectContentKind(text: string): RenderHint;
package/package.json ADDED
@@ -0,0 +1,75 @@
1
+ {
2
+ "name": "besser-agentic-framework-ui",
3
+ "version": "0.1.0",
4
+ "description": "React chat UI components for the BESSER Agentic Framework",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/BESSER-PEARL/BESSER-Agentic-Framework-UI.git"
9
+ },
10
+ "type": "module",
11
+ "files": ["dist"],
12
+ "main": "./dist/besser-agentic-framework-ui.js",
13
+ "module": "./dist/besser-agentic-framework-ui.js",
14
+ "types": "./dist/lib.d.ts",
15
+ "exports": {
16
+ ".": {
17
+ "import": "./dist/besser-agentic-framework-ui.js",
18
+ "types": "./dist/lib.d.ts"
19
+ },
20
+ "./style.css": "./dist/style.css"
21
+ },
22
+ "scripts": {
23
+ "dev": "vite",
24
+ "build": "tsc -b && vite build",
25
+ "build:lib": "vite build --config vite.config.lib.ts && tsc --project tsconfig.lib.json",
26
+ "lint": "eslint .",
27
+ "preview": "vite preview"
28
+ },
29
+ "peerDependencies": {
30
+ "react": ">=18",
31
+ "react-dom": ">=18",
32
+ "react-markdown": ">=9",
33
+ "remark-gfm": ">=3",
34
+ "dompurify": ">=3",
35
+ "plotly.js-dist-min": ">=2"
36
+ },
37
+ "peerDependenciesMeta": {
38
+ "plotly.js-dist-min": {
39
+ "optional": true
40
+ }
41
+ },
42
+ "dependencies": {
43
+ "cors": "^2.8.6",
44
+ "dotenv": "^17.4.1",
45
+ "express": "^5.2.1",
46
+ "pg": "^8.20.0",
47
+ "ws": "^8.20.0"
48
+ },
49
+ "devDependencies": {
50
+ "@eslint/js": "^9.39.4",
51
+ "@types/cors": "^2.8.19",
52
+ "@types/dompurify": "^3.0.5",
53
+ "@types/express": "^5.0.6",
54
+ "@types/node": "^24.12.2",
55
+ "@types/pg": "^8.20.0",
56
+ "@types/react": "^19.2.14",
57
+ "@types/react-dom": "^19.2.3",
58
+ "@types/ws": "^8.18.1",
59
+ "@vitejs/plugin-react": "^6.0.1",
60
+ "concurrently": "^9.2.1",
61
+ "dompurify": "^3.3.3",
62
+ "eslint": "^9.39.4",
63
+ "eslint-plugin-react-hooks": "^7.0.1",
64
+ "eslint-plugin-react-refresh": "^0.5.2",
65
+ "globals": "^17.4.0",
66
+ "plotly.js-dist-min": "^3.5.0",
67
+ "react": "^19.2.4",
68
+ "react-dom": "^19.2.4",
69
+ "react-markdown": "^10.1.0",
70
+ "remark-gfm": "^4.0.1",
71
+ "typescript": "~6.0.2",
72
+ "typescript-eslint": "^8.58.0",
73
+ "vite": "^8.0.4"
74
+ }
75
+ }