nandi/oripublic Fork 0
main
Commits
Clone
git clone https://git.rickub.com/nandi/ori.git
git clone ssh://git@rickub.com/nandi/ori.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

forked from bots-garden/ori

ChatThread.tsx · 101 lines · 2.9 KBTypeScript Blame HistoryRaw
✨ Introduce new feature(s): ACP web client — Go backend (agent, bridge, httpserver, mockagent) + React SPA (Zed-like agent panel), tests, quality gate PASS 2434cc7 k33g yesterday1/**
2 * ChatThread renders the conversation: user prompts, streamed agent answers
3 * (markdown) and inline errors, auto-scrolled to the latest entry.
4 *
5 * @example
6 * <ChatThread thread={[{ kind: "user", text: "hi" }]} turnActive={false} />
7 */
8
9import { useEffect, useRef } from "react";
10import type { ThreadItem } from "../reducer";
11import { Markdown } from "./Markdown";
12import { ToolCallCard } from "./ToolCallCard";
✨ Workspace panel, selectors, previews, desktop app, sandbox template, resizable file tree, light/dark theme 76d62ac k33g yesterday13import { WorkingIndicator } from "./WorkingIndicator";
Add copy-paste functionality for code blocks and completion widgets 7895c1d k33g 19h ago14import { CopyButton } from "./CopyButton";
✨ Introduce new feature(s): ACP web client — Go backend (agent, bridge, httpserver, mockagent) + React SPA (Zed-like agent panel), tests, quality gate PASS 2434cc7 k33g yesterday15
16interface ChatThreadProps {
17 thread: ThreadItem[];
18 turnActive: boolean;
19}
20
21export function ChatThread({ thread, turnActive }: ChatThreadProps) {
22 const endRef = useRef<HTMLDivElement>(null);
23
24 // biome-ignore lint/correctness/useExhaustiveDependencies: thread and turnActive intentionally retrigger the scroll-to-bottom on every conversation change.
25 useEffect(() => {
26 // Optional call: test DOMs (jsdom) do not implement scrollIntoView.
27 endRef.current?.scrollIntoView?.({ behavior: "smooth" });
28 }, [thread, turnActive]);
29
30 return (
31 <section className="thread" aria-label="conversation">
32 {thread.length === 0 && (
33 <p className="thread-empty">
34 Send a prompt to start working with the agent.
35 </p>
36 )}
37 {thread.map((item, index) => (
38 // biome-ignore lint/suspicious/noArrayIndexKey: the thread is append-only (never reordered or spliced), so the index is a stable identity.
39 <ThreadEntry key={index} item={item} />
40 ))}
✨ Workspace panel, selectors, previews, desktop app, sandbox template, resizable file tree, light/dark theme 76d62ac k33g yesterday41 {turnActive && <WorkingIndicator />}
✨ Introduce new feature(s): ACP web client — Go backend (agent, bridge, httpserver, mockagent) + React SPA (Zed-like agent panel), tests, quality gate PASS 2434cc7 k33g yesterday42 <div ref={endRef} />
43 </section>
44 );
45}
46
47function ThreadEntry({ item }: { item: ThreadItem }) {
48 switch (item.kind) {
49 case "user":
50 return <div className="message message-user">{item.text}</div>;
51 case "agent":
52 return (
53 <div className="message message-agent">
Add copy-paste functionality for code blocks and completion widgets 7895c1d k33g 19h ago54 <CopyButton content={item.text} label="Copy response" />
✨ Introduce new feature(s): ACP web client — Go backend (agent, bridge, httpserver, mockagent) + React SPA (Zed-like agent panel), tests, quality gate PASS 2434cc7 k33g yesterday55 <Markdown text={item.text} />
56 </div>
57 );
58 case "thought":
✨ Workspace panel, selectors, previews, desktop app, sandbox template, resizable file tree, light/dark theme 76d62ac k33g yesterday59 return <ThoughtEntry text={item.text} closed={item.closed} />;
✨ Introduce new feature(s): ACP web client — Go backend (agent, bridge, httpserver, mockagent) + React SPA (Zed-like agent panel), tests, quality gate PASS 2434cc7 k33g yesterday60 case "tool":
61 return <ToolCallCard call={item.call} />;
62 case "error":
63 return (
64 <div className="message message-error" role="alert">
65 {item.text}
66 </div>
67 );
68 }
69}
✨ Workspace panel, selectors, previews, desktop app, sandbox template, resizable file tree, light/dark theme 76d62ac k33g yesterday70
71/**
72 * ThoughtEntry renders one thinking block: while the thought streams its
73 * content stays visible; once the turn ends it collapses into a reopenable
74 * summary.
75 */
76function ThoughtEntry({ text, closed }: { text: string; closed: boolean }) {
77 if (!closed) {
78 return (
79 <div className="thought thought-live">
Add copy-paste functionality for code blocks and completion widgets 7895c1d k33g 19h ago80 <p className="thought-summary">
81 💭 Thinking
82 <CopyButton content={text} label="Copy thought" />
83 </p>
✨ Workspace panel, selectors, previews, desktop app, sandbox template, resizable file tree, light/dark theme 76d62ac k33g yesterday84 <div className="thought-body">
85 <Markdown text={text} />
86 </div>
87 </div>
88 );
89 }
90 return (
91 <details className="thought">
Add copy-paste functionality for code blocks and completion widgets 7895c1d k33g 19h ago92 <summary className="thought-summary">
93 💭 Thought for a moment
94 <CopyButton content={text} label="Copy thought" />
95 </summary>
✨ Workspace panel, selectors, previews, desktop app, sandbox template, resizable file tree, light/dark theme 76d62ac k33g yesterday96 <div className="thought-body">
97 <Markdown text={text} />
98 </div>
99 </details>
100 );
101}