MCPcopy Index your code
hub / github.com/ChatLab/ChatLab / runChatTurn

Function runChatTurn

apps/cli/src/ai/chat-command.ts:149–338  ·  view source on GitHub ↗
(
  options: Required<Pick<ChatCommandOptions, 'question'>> &
    Pick<ChatCommandOptions, 'sessionId' | 'aiChatId' | 'json' | 'stream' | 'locale' | 'includeEvents'>,
  deps: ChatCommandDeps
)

Source from the content-addressed store, hash-verified

147}
148
149export async function runChatTurn(
150 options: Required<Pick<ChatCommandOptions, 'question'>> &
151 Pick<ChatCommandOptions, 'sessionId' | 'aiChatId' | 'json' | 'stream' | 'locale' | 'includeEvents'>,
152 deps: ChatCommandDeps
153): Promise<ChatTurnResult> {
154 const stdout = deps.stdout ?? process.stdout
155 const target = resolveAIChatTarget(options, deps)
156 const startedAt = Date.now()
157 let answer = ''
158 let tokenUsage: TokenUsageData | null = null
159 let streamError: Error | null = null
160 const events: AgentStreamChunk[] = []
161 const contentBlocks: ContentBlock[] = []
162 let hasReplayContentBlocks = false
163
164 const runAgentStream = (deps.createRunAgentStream ?? createCliRunAgentStream)(deps.dbManager, deps.aiChatManager)
165
166 // 中文注释:CLI 历史回放依赖 contentBlocks 的时序;只要出现计划/思考块,
167 // 就同步保留后续正文 text block,避免 UI 使用 blocks 渲染时丢失最终回答。
168 const appendTextBlock = (text: string) => {
169 if (!text) return
170 const lastBlock = contentBlocks[contentBlocks.length - 1]
171 if (lastBlock?.type === 'text') {
172 lastBlock.text += text
173 } else {
174 contentBlocks.push({ type: 'text', text })
175 }
176 }
177
178 const appendThinkBlock = (text: string, tag = 'thinking', durationMs?: number) => {
179 if (!text && durationMs === undefined) return
180 const lastBlock = contentBlocks[contentBlocks.length - 1]
181 let targetBlock: ContentBlock | undefined
182
183 if (lastBlock?.type === 'think' && lastBlock.tag === tag) {
184 lastBlock.text += text
185 targetBlock = lastBlock
186 } else if (text.trim().length > 0) {
187 targetBlock = { type: 'think', tag, text }
188 contentBlocks.push(targetBlock)
189 } else if (durationMs !== undefined) {
190 for (let index = contentBlocks.length - 1; index >= 0; index--) {
191 const block = contentBlocks[index]
192 if (block.type === 'think' && block.tag === tag) {
193 targetBlock = block
194 break
195 }
196 }
197 }
198
199 if (durationMs !== undefined && targetBlock?.type === 'think') {
200 targetBlock.durationMs = durationMs
201 }
202 if (targetBlock?.type === 'think') {
203 hasReplayContentBlocks = true
204 }
205 }
206

Callers 2

runChatCommandFunction · 0.85

Calls 14

resolveAIChatTargetFunction · 0.85
runAgentStreamFunction · 0.85
createAgentStreamErrorFunction · 0.85
appendPlanDraftBlockFunction · 0.85
appendFinalPlanBlockFunction · 0.85
appendThinkBlockFunction · 0.85
appendChartBlocksFunction · 0.85
appendTextBlockFunction · 0.85
parseMethod · 0.80
removePlanDraftBlocksFunction · 0.70
extractChartPayloadsFunction · 0.70
writeFunction · 0.70

Tested by

no test coverage detected