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 ไบ‹ไปถ๏ผŒๆ‰€ๆœ‰ๅญ—ๆฎตๅ‡ไธบๅฏ้€‰๏ผš

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) ็ฎก็†๏ผš

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 ๆกฅๆŽฅ้€ป่พ‘