File size: 2,227 Bytes
b2c86fd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
/**
 * 渲染单条消息
 * - user 消息:简单文本
 * - assistant 消息:渲染 steps 流(thinking / code / tool_use / result / error)
 */
export default function MessageItem({ message }) {
  if (message.role === "user") {
    return (
      <div className="message user-message">
        <div className="message-content">{message.content}</div>
      </div>
    );
  }

  // assistant
  return (
    <div className="message assistant-message">
      {message.steps.map((step, i) => (
        <StepBlock key={i} step={step} />
      ))}
      {!message.done && message.steps.length === 0 && (
        <span className="placeholder">Agent is thinking…</span>
      )}
    </div>
  );
}

function StepBlock({ step }) {
  switch (step.type) {
    case "thinking":
      return (
        <div className="step thinking-step">
          <div className="result-label">💭 Reasoning</div>
          <pre>{step.content}</pre>
        </div>
      );

    case "code":
      return (
        <div className="step code-step">
          <div className="code-header">
            <span className="code-lang">{step.lang}</span>
            <button onClick={() => navigator.clipboard.writeText(step.content)}>
              Copy
            </button>
          </div>
          <pre className="code-block">{step.content}</pre>
        </div>
      );

    case "tool_use":
      return (
        <div className="step tool-step">
          🔧 <strong>{step.tool}</strong>
          <span className="tool-detail">{step.content?.slice(0, 80)}…</span>
        </div>
      );

    case "observation":
      return (
        <details className="step observation-step">
          <summary>📊 Observation</summary>
          <pre>{step.content}</pre>
        </details>
      );

    case "result":
      return (
        <div className="step result-step">
          <div className="result-label">✅ Result</div>
          <div className="result-content">{step.content}</div>
        </div>
      );

    case "error":
      return (
        <details className="step error-step" open>
          <summary>❌ Error</summary>
          <pre>{step.content}</pre>
        </details>
      );

    default:
      return null;
  }
}