sandbox-agent/sdks/react/src/AgentConversation.tsx
Nathan Flurry bf543d225d fix: mock agent process, React 18/19 types, release version refs
- Add hidden `mock-agent-process` CLI subcommand implementing a stdio
  JSON-RPC echo agent (ported from examples/mock-acp-agent)
- Update write_mock_agent_process_launcher() to exec the new subcommand
  instead of exiting with error
- Update sdks/react to support React 18 and 19 peer dependencies
- Update @types/react to v19 across workspace (pnpm override + inspector)
- Fix RefObject<T | null> compatibility for React 19 useRef() signatures
- Add version reference replacement logic to release update_version.ts
  covering all docs, examples, and code files listed in CLAUDE.md
- Add missing files to CLAUDE.md Install Version References list
  (architecture.mdx, boxlite, modal, computesdk docs and examples)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 22:36:48 -07:00

85 lines
3.2 KiB
TypeScript

"use client";
import type { ReactNode, RefObject } from "react";
import { AgentTranscript, type AgentTranscriptClassNames, type AgentTranscriptProps, type TranscriptEntry } from "./AgentTranscript.tsx";
import { ChatComposer, type ChatComposerClassNames, type ChatComposerProps } from "./ChatComposer.tsx";
export interface AgentConversationClassNames {
root: string;
transcript: string;
emptyState: string;
composer: string;
}
export interface AgentConversationProps {
entries: TranscriptEntry[];
className?: string;
classNames?: Partial<AgentConversationClassNames>;
emptyState?: ReactNode;
transcriptClassName?: string;
transcriptClassNames?: Partial<AgentTranscriptClassNames>;
scrollRef?: RefObject<HTMLDivElement | null>;
composerClassName?: string;
composerClassNames?: Partial<ChatComposerClassNames>;
transcriptProps?: Omit<AgentTranscriptProps, "entries" | "className" | "classNames" | "scrollRef">;
composerProps?: Omit<ChatComposerProps, "className" | "classNames">;
}
const DEFAULT_CLASS_NAMES: AgentConversationClassNames = {
root: "sa-agent-conversation",
transcript: "sa-agent-conversation-transcript",
emptyState: "sa-agent-conversation-empty-state",
composer: "sa-agent-conversation-composer",
};
const cx = (...values: Array<string | false | null | undefined>) => values.filter(Boolean).join(" ");
const mergeClassNames = (defaults: AgentConversationClassNames, overrides?: Partial<AgentConversationClassNames>): AgentConversationClassNames => ({
root: cx(defaults.root, overrides?.root),
transcript: cx(defaults.transcript, overrides?.transcript),
emptyState: cx(defaults.emptyState, overrides?.emptyState),
composer: cx(defaults.composer, overrides?.composer),
});
export const AgentConversation = ({
entries,
className,
classNames: classNameOverrides,
emptyState,
transcriptClassName,
transcriptClassNames,
scrollRef,
composerClassName,
composerClassNames,
transcriptProps,
composerProps,
}: AgentConversationProps) => {
const resolvedClassNames = mergeClassNames(DEFAULT_CLASS_NAMES, classNameOverrides);
const hasTranscriptContent = entries.length > 0 || Boolean(transcriptProps?.sessionError) || Boolean(transcriptProps?.eventError);
return (
<div className={cx(resolvedClassNames.root, className)} data-slot="root">
{hasTranscriptContent ? (
scrollRef ? (
<div className={cx(resolvedClassNames.transcript, transcriptClassName)} data-slot="transcript" ref={scrollRef}>
<AgentTranscript entries={entries} classNames={transcriptClassNames} {...transcriptProps} />
</div>
) : (
<AgentTranscript
entries={entries}
className={cx(resolvedClassNames.transcript, transcriptClassName)}
classNames={transcriptClassNames}
{...transcriptProps}
/>
)
) : emptyState ? (
<div className={resolvedClassNames.emptyState} data-slot="empty-state">
{emptyState}
</div>
) : null}
{composerProps ? (
<ChatComposer className={cx(resolvedClassNames.composer, composerClassName)} classNames={composerClassNames} {...composerProps} />
) : null}
</div>
);
};