File size: 5,378 Bytes
6e62ad1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import { useState } from 'react'

interface TeachPanelProps {
  onTeach: (question: string, answer: string) => Promise<any>
  loading: boolean
}

interface TeachResult {
  question: string
  answer: string
  tokensWritten: number
  message: string
  timestamp: number
}

export function TeachPanel({ onTeach, loading }: TeachPanelProps) {
  const [question, setQuestion] = useState('')
  const [answer, setAnswer] = useState('')
  const [history, setHistory] = useState<TeachResult[]>([])

  const handleTeach = async () => {
    if (!question.trim() || !answer.trim() || loading) return
    try {
      const resp = await onTeach(question.trim(), answer.trim())
      setHistory(prev => [{
        question: question.trim(),
        answer: answer.trim(),
        tokensWritten: resp.tokens_written,
        message: resp.message,
        timestamp: Date.now(),
      }, ...prev])
      setQuestion('')
      setAnswer('')
    } catch {
      setHistory(prev => [{
        question: question.trim(),
        answer: answer.trim(),
        tokensWritten: 0,
        message: 'Error: API not reachable',
        timestamp: Date.now(),
      }, ...prev])
    }
  }

  return (
    <div className="flex flex-col h-full glass-card overflow-hidden">
      <div className="px-5 py-3 border-b border-pal-border">
        <div className="flex items-center gap-2">
          <span className="text-base">📚</span>
          <h2 className="text-sm font-semibold text-pal-text">Teach</h2>
          <span className="text-xs text-pal-muted">O(1) learning</span>
        </div>
      </div>

      <div className="flex-1 overflow-y-auto p-4 space-y-3">
        {/* Input form */}
        <div className="space-y-2">
          <div>
            <label className="text-[11px] text-pal-muted font-medium uppercase tracking-wide block mb-1">
              Question
            </label>
            <input
              type="text"
              value={question}
              onChange={e => setQuestion(e.target.value)}
              onKeyDown={e => e.key === 'Enter' && !e.shiftKey && handleTeach()}
              placeholder="what is the capital of france"
              className="w-full bg-pal-surface border border-pal-border rounded-lg px-3 py-2 text-sm text-pal-text placeholder:text-pal-muted focus:outline-none focus:border-pal-green/50 transition-all"
            />
          </div>
          <div>
            <label className="text-[11px] text-pal-muted font-medium uppercase tracking-wide block mb-1">
              Answer
            </label>
            <input
              type="text"
              value={answer}
              onChange={e => setAnswer(e.target.value)}
              onKeyDown={e => e.key === 'Enter' && !e.shiftKey && handleTeach()}
              placeholder="paris"
              className="w-full bg-pal-surface border border-pal-border rounded-lg px-3 py-2 text-sm text-pal-text placeholder:text-pal-muted focus:outline-none focus:border-pal-green/50 transition-all"
            />
          </div>
          <button
            onClick={handleTeach}
            disabled={!question.trim() || !answer.trim() || loading}
            className="w-full py-2 rounded-lg bg-gradient-to-r from-pal-green to-pal-accent2 text-white font-semibold text-sm transition-all hover:scale-[1.02] hover:shadow-lg hover:shadow-pal-green/20 disabled:opacity-30 disabled:cursor-not-allowed disabled:hover:scale-100"
          >
            {loading ? 'Teaching...' : '⚡ Teach Instantly'}
          </button>
        </div>

        {/* History */}
        {history.length > 0 && (
          <div className="space-y-2 pt-2 border-t border-pal-border">
            <span className="text-[11px] text-pal-muted font-medium uppercase tracking-wide">
              Taught ({history.length})
            </span>
            {history.map((h, i) => (
              <div
                key={i}
                className="p-2.5 rounded-lg bg-pal-surface/60 border border-pal-border/50 animate-slide-up"
              >
                <div className="flex items-start justify-between gap-2 mb-1">
                  <div className="flex-1 min-w-0">
                    <div className="text-xs text-pal-text font-medium truncate">
                      {h.question}
                    </div>
                    <div className="text-xs text-pal-green font-medium">
                      → {h.answer}
                    </div>
                  </div>
                  {h.tokensWritten > 0 && (
                    <span className="text-[10px] px-1.5 py-0.5 rounded-full bg-pal-green/10 text-pal-green font-mono whitespace-nowrap">
                      +{h.tokensWritten} tok
                    </span>
                  )}
                </div>
                {h.message && (
                  <p className="text-[10px] text-pal-muted mt-1">{h.message}</p>
                )}
              </div>
            ))}
          </div>
        )}

        {history.length === 0 && (
          <div className="text-center py-8">
            <div className="text-3xl mb-2 opacity-50"></div>
            <p className="text-xs text-pal-muted">
              Teach PALIMPSESTE new facts.<br/>
              Each fact is written to memory in O(1) —<br/>
              instantly retrievable, never forgotten.
            </p>
          </div>
        )}
      </div>
    </div>
  )
}