MCPcopy Create free account
hub / github.com/alibaba/open-code-review / RunPerFile

Method RunPerFile

internal/llmloop/loop.go:149–268  ·  view source on GitHub ↗

RunPerFile drives the main LLM conversation loop for a single file. It sends messages with the configured tool definitions, executes any tool calls returned by the model, and collects review comments until task_done is called or limits are reached. Token usage and warnings are aggregated on the Runn

(ctx context.Context, messages []llm.Message, newPath string)

Source from the content-addressed store, hash-verified

147// are aggregated on the Runner across all files. The returned bool is true
148// only when the model explicitly calls task_done.
149func (r *Runner) RunPerFile(ctx context.Context, messages []llm.Message, newPath string) (bool, error) {
150 toolReqCount := r.deps.Template.MaxToolRequestTimes
151 const maxConsecutiveEmptyRounds = 3
152 consecutiveEmptyRounds := 0
153 sessionID := uuid.NewString()
154
155 // Async compression is owned by this conversation alone; the deferred
156 // cancel aborts any job still in flight when the conversation ends.
157 st := &compressionState{}
158 defer r.cancelPendingCompression(st)
159
160 for toolReqCount > 0 {
161 select {
162 case <-ctx.Done():
163 return false, ctx.Err()
164 default:
165 }
166
167 toolReqCount--
168
169 fs := r.deps.Session.GetOrCreateFileSession(newPath)
170 rec := fs.AppendTaskRecord(session.MainTask, append([]llm.Message(nil), messages...))
171 startTime := time.Now()
172
173 _, llmSpan := telemetry.StartLLMSpan(ctx, r.deps.Model)
174 resp, err := r.deps.LLMClient.CompletionsWithCtx(ctx, llm.ChatRequest{
175 Model: r.deps.Model,
176 Messages: messages,
177 Tools: r.deps.MainToolDefs,
178 MaxTokens: r.deps.Template.MaxTokens,
179 SessionID: sessionID,
180 })
181 duration := time.Since(startTime)
182 if err != nil {
183 rec.SetError(err, duration)
184 telemetry.RecordLLMResult(llmSpan, duration, 0, err)
185 llmSpan.End()
186 telemetry.RecordLLMRequest(ctx, r.deps.Model, duration, 0, "error")
187 return false, fmt.Errorf("LLM completion error: %w", err)
188 }
189 rec.SetResponse(resp, duration)
190 totalTokens := int64(0)
191 if resp.Usage != nil {
192 totalTokens = resp.Usage.TotalTokens
193 atomic.AddInt64(&r.totalInputTokens, resp.Usage.PromptTokens)
194 atomic.AddInt64(&r.totalOutputTokens, resp.Usage.CompletionTokens)
195 atomic.AddInt64(&r.totalCacheReadTokens, resp.Usage.CacheReadTokens)
196 atomic.AddInt64(&r.totalCacheWriteTokens, resp.Usage.CacheWriteTokens)
197 }
198 telemetry.RecordLLMResult(llmSpan, duration, totalTokens, nil)
199 llmSpan.End()
200 telemetry.RecordLLMRequest(ctx, r.deps.Model, duration, totalTokens, "ok")
201
202 content := resp.Content()
203 calls := resp.ToolCalls()
204
205 if len(calls) == 0 {
206 fmt.Fprintf(stdout.Writer(), "[ocr] No tool calls parsed for %s, retrying...\n", newPath)

Calls 15

executeToolCallMethod · 0.95
addNextMessageMethod · 0.95
StartLLMSpanFunction · 0.92
RecordLLMResultFunction · 0.92
RecordLLMRequestFunction · 0.92
WriterFunction · 0.92
NewTextMessageFunction · 0.92
AppendTaskRecordMethod · 0.80
SinceMethod · 0.80
SetErrorMethod · 0.80