'use client'; /** * ToolPayloadValue — the single, shared renderer for a tool call's * `input` / `output` / live `streaming` payload. * * Routing (one implementation, reused everywhere): * - object / array (and NOT streaming) → interactive collapsible * `LazyJsonTree` (the same viewer the chat `json` block + document * inspector use). It renders values as React children — never * `innerHTML` — so a tool result carrying HTML/markdown (e.g. a fetched * web page) is shown as text, not executed: XSS-safe. * - string / scalar / streaming → plain `
` text. A streaming payload
 *     arrives as a partial string and must NOT be parsed mid-flight; prose /
 *     scalars have no tree to show.
 *
 * Both the default `DefaultPayload` (inside `ToolCalls`) AND a host that owns
 * its own tool-call card (e.g. cmdop's `` action card, reached via
 * the `renderToolCall` override) render THROUGH this — so the object→tree
 * behaviour can't drift between the two. `surfaceClassName` lets a host match
 * its own card's surface token (the only thing that differed when the two
 * implementations were separate).
 */

import { cn } from '@djangocfg/ui-core/lib';

import { LazyJsonTree } from '../../data/JsonTree/lazy';

// Defined locally (NOT imported from ./ToolCalls) on purpose: ToolCalls
// imports ToolPayloadValue, so importing the type back would form an import
// cycle. Under the `'use client'` + subpath-barrel (`./chat` → lazy.tsx) setup
// that cycle makes Vite drop this module's symbol from the re-export graph at
// runtime (the export typechecks via index.ts but fails to bundle — the exact
// `MarkdownMessage` gotcha documented in lazy.tsx). The union is the SAME shape
// ToolCalls re-exports as `ToolPayloadKind`; keep them in sync (trivial).
export type ToolPayloadKind = 'input' | 'output' | 'streaming';

/** A structured value worth showing in the JSON tree (object or array). */
function isStructured(value: unknown): value is object {
  return value !== null && typeof value === 'object';
}

function safeStringify(value: unknown): string {
  try {
    return JSON.stringify(value, null, 2);
  } catch {
    return String(value);
  }
}

export interface ToolPayloadValueProps {
  value: unknown;
  /** Drives expand depth (input collapsed, output 1 level), muted text, and
   *  whether a streaming partial is parsed (it never is). */
  kind: ToolPayloadKind;
  /** Surface token for the tree wrapper + `
` background. Defaults to the
   *  chat panel's `bg-background/60`; a host card can pass e.g. `bg-muted/40`. */
  surfaceClassName?: string;
  /**
   * Show the JsonTree toolbar (search / expand / copy). Default **false**:
   * the tool-call panel already has its own header (tool name + status), so a
   * second toolbar is visual noise — and in `'auto'` mode JsonTree RESERVES the
   * toolbar's height even while hidden, leaving an empty gap above the tree.
   * Opt in (`toolbar`) only when copy/search on the raw payload is worth the
   * extra chrome. When true the toolbar is hover-revealed (`'auto'`).
   */
  toolbar?: boolean;
}

export function ToolPayloadValue({
  value,
  kind,
  surfaceClassName = 'bg-background/60',
  toolbar = false,
}: ToolPayloadValueProps) {
  if (kind !== 'streaming' && isStructured(value)) {
    return (
      
); } return (
      {typeof value === 'string' ? value : safeStringify(value)}
    
); }