import React, {useState} from 'react'; import {Box, render, Text, useInput} from 'ink'; import TextInput from 'ink-text-input'; import Spinner from 'ink-spinner'; import {addMessage, callTools, type ChatMessage, findMessages, getMessages, requestLLMStream} from "./src/llm.ts"; import dayjs from "dayjs"; const App = () => { const [input, setInput] = useState(''); // 当前输入框内容 const [isChatting, setIsChatting] = useState(false); // 是否正在对话 const [history, setHistory] = useState(getMessages()); // 对话历史 const [currentResponse, setCurrentResponse] = useState(''); // 当前流式输出的内容 const [currentReasoningResponse, setCurrentReasoningResponse] = useState(''); // 当前流式输出的内容 // 处理提交 const handleSubmit = async (value: string) => { if (!value) return; setIsChatting(true); await addMessage("now is " + dayjs().format("YYYY-MM-DD HH:mm:ss"), "system"); await addMessage(value); setHistory(getMessages()); setInput(''); await dealRequest(); }; const dealRequest = async () => { let request_id = ""; let fullText = ''; let reasoningFullText = ''; for await (const token of requestLLMStream(false)) { fullText += token.content || ""; reasoningFullText += token.reasoning_content || ""; setCurrentResponse(fullText); setCurrentReasoningResponse(reasoningFullText); if (token.id) { request_id = token.id; } } const lastMsg = findMessages(request_id); if (lastMsg && lastMsg.finish_reason === "tool_calls") { // 处理工具调用 if (lastMsg.tool_call_id && lastMsg.tool_call_name) { await callTools( lastMsg.tool_call_id, lastMsg.tool_call_name, lastMsg.tool_call_arguments ) await dealRequest() } return; } else { // 流结束,归档到历史 setHistory(getMessages()); setCurrentResponse(''); setCurrentReasoningResponse(''); setIsChatting(false); } } // 监听退出快捷键 (Ctrl+C) useInput((input, key) => { if (input === 'q' || (key.ctrl && input === 'c')) { process.exit(); } }); return ( {/* 1. 标题栏 */} 🤖 iCoder {/* 2. 渲染历史记录 */} {history.map((msg) => ( {msg.reasoning_content ?? ""} {msg.content ?? ""} {msg.finish_reason} {msg.tool_call_id} {msg.tool_call_name} {msg.tool_call_arguments} { msg.role === "user" ? ( {msg.createdAt ?? ""} ) : null } ))} {/* 3. 渲染当前正在生成的流 */} {isChatting && currentResponse && ( 正在工作... {currentReasoningResponse} {currentResponse} )} {/* 4. 加载状态 */} {isChatting && !currentResponse && ( 正在思考... )} {/* 5. 输入区 */} {!isChatting && ( 🎨 )} 按 Ctrl+C 退出 ); }; render();