codev / docs /architecture /data-flow.md
chenbhao's picture
chore: rename VersperClaw to Codev, update org to chenbhao
96f34e3
|
Raw
History Blame Contribute Delete
18.3 kB
# ๆ ธๅฟƒๆ•ฐๆฎๆต
ๆœฌๆ–‡ๆกฃ่ฏฆ็ป†ๆ่ฟฐ Codev ็š„ๅ…ญๅคงๆ ธๅฟƒๆ•ฐๆฎๆต๏ผŒๅŒ…ๅซ ASCII ๅบๅˆ—ๅ›พๅ’Œๅ…ณ้”ฎไปฃ็ ่ทฏๅพ„ใ€‚
---
## 1. ็”จๆˆท่พ“ๅ…ฅๆต
็”จๆˆท้€š่ฟ‡็ปˆ็ซฏ่พ“ๅ…ฅๆ–‡ๆœฌๅˆฐ AI ๅ“ๅบ”็š„ๅฎŒๆ•ด้“พ่ทฏใ€‚
```
User (้”ฎ็›˜)
โ”‚
โ”‚ ้”ฎๅ…ฅๆ–‡ๆœฌ + Enter
โ–ผ
PromptInput ็ป„ไปถ
(screens/PromptInput.tsx)
โ”‚
โ”‚ handlePromptSubmit()
โ–ผ
messageQueueManager.enqueue()
(utils/messageQueueManager.ts)
โ”‚
โ”‚ ๅ‘ฝไปคๅ…ฅ้˜Ÿ (priority: 'now' | 'next' | 'later')
โ”‚ FIFO ๆŒ‰ไผ˜ๅ…ˆ็บงๆŽ’ๅบ
โ–ผ
useCommandQueue hook
(hooks/useCommandQueue.ts)
โ”‚
โ”‚ ๅ‡บ้˜Ÿ โ†’ ไบค็ป™ REPL ไธปๅพช็Žฏ
โ–ผ
query() ๅ‡ฝๆ•ฐ
(query.ts โ†’ QueryEngine.ts)
โ”‚
โ”œโ”€โ”€ ็ป„่ฃ…ๆถˆๆฏๅކๅฒ
โ”œโ”€โ”€ ่Žทๅ–็ณป็ปŸๆ็คบ่ฏ (src/context.ts)
โ”œโ”€โ”€ ๅˆๅนถๅทฅๅ…ทๅˆ—่กจ (assembleToolPool)
โ””โ”€โ”€ ้€‰ๆ‹ฉ Provider
โ”‚
โ”œโ”€โ”€ [1P Anthropic] โ”€โ”€ Anthropic SDK โ”€โ”€ POST /v1/messages
โ”‚
โ””โ”€โ”€ [3P Provider] โ”€โ”€ server/proxy/handler.ts
โ”‚
โ”œโ”€โ”€ anthropicToOpenaiChat.ts (่ฏทๆฑ‚่ฝฌๆข)
โ”œโ”€โ”€ POST provider API (OpenAI/Groq/DeepSeek...)
โ””โ”€โ”€ openaiChatToAnthropic.ts (ๅ“ๅบ”่ฝฌๆข)
โ”‚
โ–ผ
ๆตๅผๅ“ๅบ”ๅ›žๅˆฐ query()
โ”‚
โ–ผ
ๅทฅๅ…ท่ฐƒ็”จๅˆ†ๅ‘ (Tool Execution)
โ”‚
โ–ผ
ๆธฒๆŸ“ๅ“ๅบ”ๅˆฐ็ปˆ็ซฏ (Ink UI)
```
### ๅ…ณ้”ฎไปฃ็ ่ทฏๅพ„
| ๆญฅ้ชค | ๆ–‡ไปถ | ๆ ธๅฟƒๅ‡ฝๆ•ฐ |
|------|------|----------|
| ่พ“ๅ…ฅ | `src/components/PromptInput/PromptInput.tsx` | `handlePromptSubmit()` |
| ้˜Ÿๅˆ— | `src/utils/messageQueueManager.ts` | `enqueue()`, `dequeue()` |
| ๆŸฅ่ฏข | `src/query.ts` | `query()` |
| ๅผ•ๆ“Ž | `src/QueryEngine.ts` | `QueryEngine` ็ฑป |
| ๅทฅๅ…ท | `src/tools.ts` | `assembleToolPool()`, `getTools()` |
| ไปฃ็† | `src/server/proxy/handler.ts` | `handleProxyRequest()` |
| ๅ“ๅบ”ๆธฒๆŸ“ | `src/screens/REPL.tsx` | ๆถˆๆฏๅˆ—่กจ + ๆตๅผๆธฒๆŸ“ |
### ้˜Ÿๅˆ—ไผ˜ๅ…ˆ็บงๆœบๅˆถ
```
ไผ˜ๅ…ˆ็บง: 'now' > 'next' > 'later'
ๅŒไธ€ไผ˜ๅ…ˆ็บงๅ†… FIFO
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ 'now' โ”‚ โ”‚ 'next' โ”‚ โ”‚ 'later' โ”‚
โ”‚ (็ดงๆ€ฅ) โ”‚ โ”‚ (ๆญฃๅธธ) โ”‚ โ”‚ (้€š็Ÿฅ) โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ โ•โ•โ•โ–ถ โ”‚ โ”‚ โ•โ•โ•โ–ถ โ”‚ โ”‚ โ•โ•โ•โ–ถ โ”‚
โ”‚ ๅ‡บ้˜Ÿไผ˜ๅ…ˆ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
```
---
## 2. ่ฏญ้Ÿณๆ•่Žทๆต
ไปŽ้บฆๅ…‹้ฃŽๅˆฐ VRM ๅ‰็ซฏ่ฏญ้Ÿณๆ’ญๆ”พ็š„ๅฎŒๆ•ด็ฎก้“ใ€‚
### ่ฏญ้Ÿณๆ•่Žทๆžถๆž„
Codev ไฝฟ็”จ่ฟ›็จ‹ๅ†…้Ÿณ้ข‘ๆ•่Žท๏ผˆcpal Rust ๅบ“๏ผŒ้€š่ฟ‡ `native-modules/audio-capture-napi`๏ผ‰๏ผŒ่€Œไธๆ˜ฏไผ ็ปŸ็š„ arecord/parecord ๅญ่ฟ›็จ‹ใ€‚
```
้บฆๅ…‹้ฃŽ (็กฌไปถ)
โ”‚
โ”‚ 16kHz S16LE PCM
โ–ผ
cpal (Rust ๅŽŸ็”Ÿๆจกๅ—)
(native-modules/audio-capture-napi)
โ”‚
โ”‚ onData(chunk: Buffer)
โ–ผ
FriendService.startVoiceCapture()
(friend/FriendService.ts)
โ”‚
โ”œโ”€โ”€โ–ถ Silero VAD (่ฏญ้ŸณๆดปๅŠจๆฃ€ๆต‹)
โ”‚ (friend/voice/vad-service.ts)
โ”‚ โ”‚
โ”‚ โ”‚ onnxruntime-web WASM ๆŽจ็†
โ”‚ โ”‚ 512 samples/frame @ 16kHz (32ms)
โ”‚ โ”‚
โ”‚ โ”œโ”€โ”€ ่ฏด่ฏๅผ€ๅง‹ โ†’ ๅผ€ๅง‹็งฏ็ดฏ้Ÿณ้ข‘
โ”‚ โ”œโ”€โ”€ ๆฃ€ๆต‹ๆŒ็ปญ่ฏญ้Ÿณ (โ‰ฅ10 ๅธง โ‰ˆ 320ms ๆฟ€ๆดป)
โ”‚ โ””โ”€โ”€ ๆฃ€ๆต‹้™้Ÿณ (โ‰ฅ20 ๅธง โ‰ˆ 640ms) โ†’ onSpeechEnd
โ”‚ โ”‚
โ”‚ โ–ผ
โ”‚ ้Ÿณ้ข‘ๆฎต (Float32Array)
โ”‚ โ”‚
โ”‚ โ–ผ
โ”‚ STT (่ฏญ้Ÿณ่ฝฌๆ–‡ๅญ—)
โ”‚ โ”œโ”€โ”€ Doubao ASM (็ซๅฑฑๅผ•ๆ“Ž)
โ”‚ โ”‚ (doubaoime-asr ๅŒ…)
โ”‚ โ”œโ”€โ”€ Anthropic STT
โ”‚ โ””โ”€โ”€ Whisper (OpenAI)
โ”‚ โ”‚
โ”‚ โ–ผ
โ”‚ ่ฝฌๅฝ•ๆ–‡ๆœฌ (transcript)
โ”‚
โ””โ”€โ”€โ–ถ messageQueueManager.enqueue()
โ”‚
โ”‚ { value: transcript, mode: 'prompt', origin: { kind: 'channel', server: 'friend' } }
โ–ผ
AI ๅค„็† (ๅŒ็”จๆˆท่พ“ๅ…ฅๆต)
โ”‚
โ”‚ AI ๅ“ๅบ”ๆ–‡ๆœฌ
โ–ผ
TTS (ๆ–‡ๆœฌ่ฝฌ่ฏญ้Ÿณ)
โ”œโ”€โ”€ Edge TTS (node-edge-tts, ้ป˜่ฎค zh-CN-XiaoxiaoNeural)
โ””โ”€โ”€ Qwen TTS (DashScope API, qwen3-tts-flash)
โ”‚
โ”‚ ็”Ÿๆˆ MP3 ๆ–‡ไปถ
โ–ผ
broadcastToVrm()
(friend/sse.ts)
โ”‚
โ”‚ SSE โ†’ { text, audioUrl, audioIndex }
โ–ผ
VRM ๅ‰็ซฏ
โ”œโ”€โ”€ ๆ’ญๆ”พ้Ÿณ้ข‘
โ”œโ”€โ”€ ๆ˜พ็คบๆ–‡ๆœฌๆฐ”ๆณก
โ””โ”€โ”€ ่งฆๅ‘ๅฃๅž‹ๅŒๆญฅ
```
### VAD ็Šถๆ€ๆœบ
```
Silero VAD ๅ†…้ƒจ็Šถๆ€:
[้™้Ÿณ] โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ ๅธงๆฆ‚็އ < ๆญฃ้˜ˆๅ€ผ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ถ [้™้Ÿณ]
โ”‚ โ–ฒ
โ”‚ ๅธงๆฆ‚็އ โ‰ฅ positiveSpeechThreshold โ”‚
โ”‚ (่ฟž็ปญ โ‰ฅ preSpeechTriggerFrames) โ”‚ ๅธงๆฆ‚็އ < ่ดŸ้˜ˆๅ€ผ
โ–ผ โ”‚ (่ฟž็ปญ โ‰ฅ redemptionFrames)
[ๅฏ่ƒฝ่ฏด่ฏ] โ”€โ”€โ”€โ”€โ”€โ”€ ๅธงๆฆ‚็އ < ๆญฃ้˜ˆๅ€ผ โ”€โ”€โ”€โ”€โ”€โ”€โ–ถ [็กฎ่ฎค่ฏด่ฏ] โ”€โ”€โ”˜
โ”‚ โ”‚
โ”‚ onSpeechStart() โ”‚ onSpeechEnd(audio)
โ–ผ โ–ผ
[็งฏ็ดฏ้Ÿณ้ข‘ๅธง] [ๅ‘้€้Ÿณ้ข‘ๆฎตๅˆฐ STT]
```
| ๅ‚ๆ•ฐ | ้ป˜่ฎคๅ€ผ | ๅซไน‰ |
|------|--------|------|
| `positiveSpeechThreshold` | 0.75 | ๅˆคๅฎšไธบ่ฏญ้Ÿณ็š„็ฝฎไฟกๅบฆ้˜ˆๅ€ผ |
| `negativeSpeechThreshold` | 0.50 | ๅˆคๅฎšไธบ้™้Ÿณ็š„็ฝฎไฟกๅบฆ้˜ˆๅ€ผ |
| `preSpeechTriggerFrames` | 10 | ๆฟ€ๆดปๅ‰้œ€่ฆ่ฟž็ปญ่ฏญ้Ÿณๅธงๆ•ฐ |
| `redemptionFrames` | 20 | ็ป“ๆŸๅ‰้œ€่ฆ่ฟž็ปญ้™้Ÿณๅธงๆ•ฐ |
| `minSpeechFrames` | 6 | ๆœ€ๅฐๆœ‰ๆ•ˆ่ฏญ้Ÿณๅธงๆ•ฐ |
| `rmsThreshold` | 0.004 | RMS ่ƒฝ้‡้˜ˆๅ€ผ (-48dBFS)๏ผŒไฝŽไบŽๆญคๅ€ผ่ทณ่ฟ‡ๆŽจ็† |
### ๅ›žๅฃฐๆถˆ้™คๆœบๅˆถ
```
FriendService ๅœจ TTS ๆ’ญๆ”พๆ—ถ่‡ชๅŠจ้™้Ÿณ้บฆๅ…‹้ฃŽ:
AI ๅ“ๅบ”ๆ–‡ๆœฌ
โ”‚
โ–ผ
TTS ๅผ€ๅง‹็”Ÿๆˆ
โ”‚
โ–ผ
friend.muted = true
โ”‚ muteTimer = setTimeout(unmute, estimatedTtsDuration)
โ”‚
โ–ผ
TTS ๆ’ญๆ”พๆœŸ้—ด: ้บฆๅ…‹้ฃŽๆ•ฐๆฎ โ†’ ไธขๅผƒ (ไธ้€ VAD/STT)
โ”‚
โ–ผ
TTS ๆ’ญๆ”พ็ป“ๆŸ (ๆˆ–ไผฐ็ฎ—ๆ—ถ้—ดๅˆฐ)
โ”‚
โ–ผ
friend.muted = false
โ”‚
โ–ผ
ๆขๅคๆญฃๅธธๆ•่Žท
```
---
## 3. ่ฟœ็จ‹ๆกฅๆŽฅๆต
Local CLI ๅˆฐ `claude.ai` ่ฟœ็จ‹ไผš่ฏ็š„ WebSocket ๆกฅๆŽฅใ€‚
```
Local CLI (ไฝ ็š„ๆœบๅ™จ) claude.ai ๆœๅŠกๅ™จ
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
claude --remote start
โ”‚
โ–ผ
bridgeMain()
(bridge/bridgeMain.ts)
โ”‚
โ”‚ ๅˆ›ๅปบๆœฌๅœฐ HTTP ๆœๅŠก
โ”‚ ๅ‘่ตท OAuth ็™ปๅฝ•
โ–ผ
WebSocket ่ฟžๆŽฅ
(bridge/replBridgeTransport.ts)
โ”‚ โ—„โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ–บ claude.ai ่ฟœ็จ‹ไผš่ฏ
โ”‚ wss://api.claude.ai/...
โ”‚
โ–ผ
replBridge.ts
โ”‚
โ”œโ”€โ”€ ไปŽ่ฟœ็จ‹ๆŽฅๆ”ถ่พ“ๅ…ฅ โ†’ ๅ…ฅ้˜Ÿๅˆฐๆœฌๅœฐ messageQueueManager
โ”œโ”€โ”€ ๅฐ†ๆœฌๅœฐ่พ“ๅ‡บ/ๅทฅๅ…ท็ป“ๆžœ โ†’ ๅ‘้€ๅ›ž่ฟœ็จ‹
โ””โ”€โ”€ ๅŒๆญฅๆœฌๅœฐๅ‘ฝไปคๅˆฐ่ฟœ็จ‹็™ฝๅๅ•
(BRIDGE_SAFE_COMMANDS)
```
### ๅ‘ฝไปค่ฟ‡ๆปค
่ฟœ็จ‹ๆจกๅผไธ‹ๅชๅ…่ฎธๅฎ‰ๅ…จๅ‘ฝไปคๆ‰ง่กŒ๏ผš
```
REMOTE_SAFE_COMMANDS = {
session, // ๆ˜พ็คบ QR/URL
exit, // ้€€ๅ‡บ
clear, // ๆธ…ๅฑ
help, // ๅธฎๅŠฉ
theme, // ไธป้ข˜
color, // ้ขœ่‰ฒ
vim, // Vim ๆจกๅผ
cost, // ่ฎก่ดน
usage, // ็”จ้‡
copy, // ๅคๅˆถ
btw, // ไพฟ็ญพ
feedback, // ๅ้ฆˆ
plan, // ่ฎกๅˆ’ๆจกๅผ
keybindings, // ๅฟซๆท้”ฎ
statusline, // ็Šถๆ€ๆ 
stickers, // ่ดด็บธ
mobile, // ็งปๅŠจ็ซฏ
}
```
ๆกฅๆŽฅๅฎ‰ๅ…จๅ‘ฝไปค๏ผˆไปŽ็งปๅŠจ็ซฏไนŸๅฏๆ‰ง่กŒ๏ผ‰๏ผš
```
BRIDGE_SAFE_COMMANDS = {
compact, // ๅŽ‹็ผฉไธŠไธ‹ๆ–‡
clear, // ๆธ…ๅฑ
cost, // ่ฎก่ดน
summary, // ไผš่ฏๆ€ป็ป“
releaseNotes, // ๆ›ดๆ–ฐๆ—ฅๅฟ—
files, // ๆ–‡ไปถๅˆ—่กจ
}
```
---
## 4. Friend ่กจๆƒ…ๆต
LLM ่ฐƒ็”จ `friend_emotion` ๅทฅๅ…ทๅˆฐ VRM ๅ‰็ซฏ 3D ่ง’่‰ฒ่กจๆƒ…ๆธฒๆŸ“็š„ๅฎŒๆ•ด้“พ่ทฏใ€‚
```
LLM ๆŽจ็†
โ”‚
โ”‚ ๆ€่€ƒไธŠไธ‹ๆ–‡ๅŽ่ฐƒ็”จ FriendEmotionTool
โ–ผ
FriendEmotionTool.call({ emotion, intensity, mood_delta })
(tools/FriendEmotionTool.ts)
โ”‚
โ”œโ”€โ”€ ๆ›ดๆ–ฐๅฟƒๆƒ…ๆŒ‡ๆ•ฐ moodIndex (0-100, ๅŸบๅ‡†ๅ€ผ 60)
โ”‚ โ”œโ”€โ”€ mood_delta > 0: moodIndex += delta (ไธŠ้™ 100)
โ”‚ โ””โ”€โ”€ mood_delta < 0: moodIndex -= delta (ไธ‹้™ 0)
โ”‚
โ””โ”€โ”€ broadcastToVrm({
โ”‚ emotion: 'happy'|'sad'|'angry'|...,
โ”‚ emotionIntensity: 0..1,
โ”‚ moodDelta: n,
โ”‚ moodIndex: n
โ”‚ })
โ”‚
โ–ผ
broadcastToVrm()
(friend/sse.ts)
โ”‚
โ”‚ SSE data: JSON.stringify(payload) + "\n\n"
โ”‚ ๅ‘้€็ป™ๆ‰€ๆœ‰ๅทฒ่ฟžๆŽฅ็š„ SSE ๅฎขๆˆท็ซฏ
โ–ผ
VRM ๅ‰็ซฏ (Three.js / React Three Fiber)
โ”‚
โ”œโ”€โ”€ SSE ไบ‹ไปถ่งฃๆž
โ”‚
โ”œโ”€โ”€ VRMScene ็ป„ไปถ
โ”‚ โ”œโ”€โ”€ EmoteController โ€” ่ฎพ็ฝฎ BlendShape ๆททๅˆๅฝข็Šถ
โ”‚ โ”‚ (happy โ†’ ๅ˜ด่ง’ไธŠๆ‰ฌ, sad โ†’ ็œ‰็œผไธ‹ๅž‚, ็ญ‰)
โ”‚ โ”œโ”€โ”€ MotionController โ€” ่งฆๅ‘็”Ÿ็†ๅŠจ็”ป (ๅ‘ผๅธใ€็œจ็œผ)
โ”‚ โ””โ”€โ”€ TextBubble โ€” ๆ˜พ็คบ่Šๅคฉๆ–‡ๆœฌๆฐ”ๆณก
โ”‚
โ””โ”€โ”€ AudioPlayback (ๅฆ‚ๆžœๆœ‰ audioUrl)
โ””โ”€โ”€ ๆ’ญๆ”พ TTS ้Ÿณ้ข‘ + ๅฃๅž‹ๅŒๆญฅ
```
### ๅฏ็”จ่กจๆƒ…ๅˆ—่กจ
| ่กจๆƒ… | ่ฏดๆ˜Ž |
|------|------|
| `happy` | ๅผ€ๅฟƒ |
| `sad` | ๆ‚ฒไผค |
| `angry` | ็”Ÿๆฐ” |
| `surprised` | ๆƒŠ่ฎถ |
| `think` | ๆ€่€ƒ |
| `awkward` | ๅฐดๅฐฌ |
| `question` | ็–‘้—ฎ |
| `curious` | ๅฅฝๅฅ‡ |
| `neutral` | ไธญๆ€ง/้ป˜่ฎค |
| `love` | ๅ–œ็ˆฑ |
| `flirty` | ่ฐƒๆƒ… |
| `greeting` | ๆ‰“ๆ‹›ๅ‘ผ |
| `relaxed` | ๆ”พๆพ |
### ๅฟƒๆƒ…็ณป็ปŸ
```
ๅฟƒๆƒ…ๆŒ‡ๆ•ฐ (moodIndex) ่Œƒๅ›ด 0-100๏ผŒๅŸบๅ‡†ๅ€ผ 60
0 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ 60 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ 100
[ไฝŽ่ฝ] [ไธญๆ€ง] [้ซ˜ๆถจ]
ๆฏๆฌก mood_delta: -3 ๅˆฐ +3 (ๆœ€ๅฐ็ปๅฏนๅ€ผ 1)
้€š่ฟ‡ prefs ๆŒไน…ๅŒ– (friend/prefs.ts)
moodIndex ๅฝฑๅ“:
- ๆ–‡ๆœฌๆฐ”ๆณก้ขœ่‰ฒ/ๆ ทๅผ
- ๅๅงฟๅงฟๆ€ (ๆ”พๆพ vs ็ดงๅผ )
- ๆ‰‹่‡‚ๅŠจไฝœๅน…ๅบฆ
```
### SSE ๅนฟๆ’ญไบ‹ไปถ็ฑปๅž‹
Friend SSE ้€š้“้€š่ฟ‡ `broadcastToVrm()` ๅ‘้€ JSON ไบ‹ไปถ๏ผŒๆ‰€ๆœ‰ๅญ—ๆฎตๅ‡ไธบๅฏ้€‰๏ผš
```typescript
type VrmBroadcastPayload = {
text?: string; // ๆ˜พ็คบๆ–‡ๆœฌ
emotion?: string; // ่กจๆƒ…ๅ็งฐ
emotionIntensity?: number; // ่กจๆƒ…ๅผบๅบฆ 0-1
audioUrl?: string; // TTS ้Ÿณ้ข‘ URL
audioIndex?: number; // ้Ÿณ้ข‘ๅบๅˆ—ๅท
clearText?: boolean; // ๆธ…้™คๅฝ“ๅ‰ๆ–‡ๆœฌ
imageUrl?: string; // ๆ˜พ็คบ็š„ๅ›พ็‰‡ URL
moodDelta?: number; // ๅฟƒๆƒ…ๅ˜ๅŒ–้‡
moodIndex?: number; // ๅฝ“ๅ‰ๅฟƒๆƒ…ๆŒ‡ๆ•ฐ
sendFirstTts?: boolean; // ๅ‘้€็ฌฌไธ€ไธช TTS ๆฎต
appendText?: boolean; // ่ฟฝๅŠ ๅˆฐๅทฒๆœ‰ๆ–‡ๆœฌ
replyDone?: boolean; // ๅ“ๅบ”็ป“ๆŸๆ ‡่ฎฐ
};
```
---
## 5. Provider ไปฃ็†ๆต
CLI ้€š่ฟ‡็ปŸไธ€ๆŽฅๅฃๅ‘ไธๅŒ LLM Provider ๅ‘้€่ฏทๆฑ‚็š„ๅฎŒๆ•ด่ทฏๅพ„ใ€‚
### ๅŒ่ทฏ็”ฑๆžถๆž„
```
CLI (Anthropic Messages API format)
โ”‚
โ”‚ ้€‰ๆ‹ฉ Provider
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Provider ่ทฏ็”ฑๅ†ณ็ญ– โ”‚
โ”‚ โ”‚
โ”‚ isFirstPartyAnthropicBaseUrl() โ”‚
โ”‚ + isClaudeAISubscriber() โ”‚
โ”‚ + !isUsing3PServices() โ”‚
โ”‚ โ”‚ โ”‚ โ”‚
โ”‚ ๆ˜ฏ/ โ”‚ ๅฆ โ”‚
โ”‚ โ”‚ โ”‚ โ”‚
โ”‚ โ–ผ โ–ผ โ”‚
โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚ โ”‚ Anthropicโ”‚ โ”‚ Proxy Handler โ”‚ โ”‚
โ”‚ โ”‚ SDK ็›ด่ฟž โ”‚ โ”‚ (server/proxy/ โ”‚ โ”‚
โ”‚ โ”‚ โ”‚ โ”‚ handler.ts) โ”‚ โ”‚
โ”‚ โ”‚POST /v1/ โ”‚ โ”‚ โ”‚ โ”‚
โ”‚ โ”‚messages โ”‚ โ”‚ apiFormat? โ”‚ โ”‚
โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚
โ”‚ โ”‚ โ”Œโ”€โ”€ 'openai' โ”€โ”€โ–ถ โ”‚ โ”‚
โ”‚ โ”‚ โ”‚ Anthropic โ†’ โ”‚ โ”‚
โ”‚ โ”‚ โ”‚ OpenAI Chat โ”‚ โ”‚
โ”‚ โ”‚ โ”‚ Completions โ”‚ โ”‚
โ”‚ โ”‚ โ”‚ โ”‚ โ”‚
โ”‚ โ”‚ โ”‚โ”€โ”€ 'openai- โ”‚ โ”‚
โ”‚ โ”‚ โ”‚ responses' โ”‚ โ”‚
โ”‚ โ”‚ โ”‚ Anthropic โ†’ โ”‚ โ”‚
โ”‚ โ”‚ โ”‚ OpenAI โ”‚ โ”‚
โ”‚ โ”‚ โ”‚ Responses API โ”‚ โ”‚
โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ โ”‚
โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
```
### ่ฏทๆฑ‚/ๅ“ๅบ”่ฝฌๆขๆต็จ‹
```
Anthropic Messages API ่ฏทๆฑ‚
{
model: "claude-3-opus",
messages: [{role: "user", content: "Hello"}],
system: "You are helpful",
max_tokens: 1024,
stream: true
}
โ”‚
โ–ผ
anthropicToOpenaiChat.ts / anthropicToOpenaiResponses.ts
โ”‚
โ”‚ ่ฝฌๆข้€ป่พ‘:
โ”‚ - system โ†’ system message (prefix)
โ”‚ - messages[] โ†’ messages[] (role ๆ˜ ๅฐ„)
โ”‚ - max_tokens โ†’ max_tokens
โ”‚ - stream โ†’ stream
โ”‚ - tools โ†’ tools (ๆ ผๅผ้€‚้…)
โ”‚
โ–ผ
OpenAI Chat/Responses API ่ฏทๆฑ‚
{
model: "gpt-4",
messages: [
{role: "system", content: "You are helpful"},
{role: "user", content: "Hello"}
],
max_tokens: 1024,
stream: true
}
โ”‚
โ”‚ POST ๅˆฐไธŠๆธธ Provider URL
โ–ผ
OpenAI ๆตๅผๅ“ๅบ”
โ”‚
โ–ผ
openaiChatToAnthropic.ts / openaiResponsesToAnthropic.ts (ๆตๅผ)
โ”‚
โ”‚ ่ฝฌๆข้€ป่พ‘:
โ”‚ - delta.content โ†’ delta.text
โ”‚ - tool_calls โ†’ content_block / tool_use
โ”‚ - finish_reason โ†’ stop_reason
โ”‚
โ–ผ
Anthropic ๆ ผๅผๆตๅผไบ‹ไปถๅ›ž CLI
```
### Provider ้…็ฝฎ
้€š่ฟ‡ ProviderService (`src/server/services/providerService.ts`) ็ฎก็†๏ผš
```typescript
type ProviderConfig = {
id: string;
name: string;
apiFormat: 'openai' | 'openai-responses' | 'anthropic';
baseUrl: string;
apiKey: string;
models: string[];
};
```
ๆ”ฏๆŒ็š„ๅ†…็ฝฎ Provider๏ผˆ้ƒจๅˆ†๏ผ‰๏ผš
- OpenAI (GPT-4, GPT-4o)
- Groq (Llama, Mixtral)
- DeepSeek
- ่‡ชๅฎšไน‰ OpenAI ๅ…ผๅฎน API
---
## ๆ•ฐๆฎๆตๆฑ‡ๆ€ปๅ›พ
```
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ ็”จๆˆท็š„่พ“ๅ…ฅๆฅๆบ โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚้”ฎ็›˜ โ”‚่ฏญ้Ÿณ โ”‚่ฟœ็จ‹ โ”‚ Bot โ”‚
โ”‚ โ”‚ โ”‚WebSocket โ”‚
โ””โ”€โ”€โ”ฌโ”€โ”€โ”ดโ”€โ”€โ”ฌโ”€โ”€โ”ดโ”€โ”€โ”ฌโ”€โ”€โ”€โ”ดโ”€โ”€โ”ฌโ”€โ”€โ”˜
โ”‚ โ”‚ โ”‚ โ”‚
โ–ผ โ”‚ โ”‚ โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚
โ”‚ message โ”‚โ—„โ”˜ โ”‚ โ”‚
โ”‚ Queue โ”‚โ—„โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ”‚ Manager โ”‚โ—„โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ””โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”˜
โ”‚
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ query() โ”‚
โ”‚ AI ๅผ•ๆ“Ž โ”‚
โ””โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”˜
โ”‚ โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ–ผ โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Tool ๆ‰ง่กŒ โ”‚ โ”‚ LLM ๆ–‡ๆœฌๅ“ๅบ” โ”‚
โ”‚ (Bash/Read/ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ”‚ Edit/... โ”‚ โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ ๅˆ†ๅ‘ๅˆฐๆถˆ่ดน่€… โ”‚
โ”œโ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚TUI โ”‚TTS โ”‚SSE โ”‚
โ”‚ๆ˜พ็คบ โ”‚ๆ’ญๆ”พ โ”‚ๆŽจ้€ โ”‚
โ””โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”˜
```
---
## ๅ‚่€ƒๆ–‡ไปถ่ทฏๅพ„
| ๆ–‡ไปถ | ่ฏดๆ˜Ž |
|------|------|
| `src/utils/messageQueueManager.ts` | ็ปŸไธ€ๅ‘ฝไปค้˜Ÿๅˆ— |
| `src/query.ts` | AI ๆŸฅ่ฏขๅ…ฅๅฃ |
| `src/QueryEngine.ts` | ๆŸฅ่ฏขๅผ•ๆ“Žๅฎž็Žฐ |
| `src/friend/FriendService.ts` | Friend ่ฏญ้Ÿณ/ๆ–‡ๆœฌๆœๅŠก |
| `src/friend/voice/vad-service.ts` | Silero VAD ๅฎž็Žฐ |
| `src/friend/tts.ts` | Edge TTS / Qwen TTS |
| `src/friend/sse.ts` | SSE ๅนฟๆ’ญไธŽๅฎขๆˆท็ซฏ็ฎก็† |
| `src/friend/server.ts` | Friend HTTP ๆœๅŠก (Bun.serve) |
| `src/tools/FriendEmotionTool.ts` | VRM ่กจๆƒ…ๅทฅๅ…ท |
| `src/friend/constants.ts` | ๆƒ…็ปชๅˆ—่กจๅธธ้‡ |
| `src/server/proxy/handler.ts` | Provider ไปฃ็†ๅฅๆŸ„ |
| `src/server/proxy/transform/` | ๅ่ฎฎ่ฝฌๆขๅ™จ |
| `src/server/proxy/streaming/` | ๆตๅผๅ“ๅบ”่ฝฌๆข |
| `src/server/services/providerService.ts` | Provider ้…็ฝฎ็ฎก็† |
| `src/bridge/bridgeMain.ts` | ่ฟœ็จ‹ๆกฅๆŽฅไธปๅ…ฅๅฃ |
| `src/bridge/replBridgeTransport.ts` | WebSocket ไผ ่พ“ๅฑ‚ |
| `src/bridge/replBridge.ts` | REPL ๆกฅๆŽฅ้€ป่พ‘ |