update QoL and ai integration
This commit is contained in:
67
ai_tui.go
67
ai_tui.go
@@ -98,9 +98,14 @@ func (m *App) beginAIPrepare(threadID, message string) tea.Cmd {
|
||||
controller, details := m.ai, m.details
|
||||
m.aiMode = aiPreparing
|
||||
m.aiSpinner = 0
|
||||
started := time.Now()
|
||||
summary := "Checking the provider and loading the authenticated GitHub diff"
|
||||
if threadID != "" {
|
||||
summary = "Checking the provider and loading exact-head repository context"
|
||||
}
|
||||
m.aiProgress = AIRunProgress{
|
||||
Stage: "Preparing local AI review",
|
||||
Summary: "Checking the provider and loading the authenticated GitHub diff",
|
||||
Summary: summary, StartedAt: started, StageStartedAt: started,
|
||||
}
|
||||
prepare := func() tea.Msg {
|
||||
preview, err := controller.Prepare(ctx, details, threadID, message)
|
||||
@@ -120,9 +125,11 @@ func (m *App) beginAIRun() tea.Cmd {
|
||||
controller, preview := m.ai, m.aiPreview
|
||||
m.aiMode = aiBusy
|
||||
m.aiSpinner = 0
|
||||
started := time.Now()
|
||||
m.aiProgress = AIRunProgress{
|
||||
Stage: "Starting local AI review", Model: preview.Model,
|
||||
CurrentCall: 1, TotalCalls: preview.Calls,
|
||||
StartedAt: started, StageStartedAt: started,
|
||||
}
|
||||
events := make(chan tea.Msg, 64)
|
||||
m.aiEvents = events
|
||||
@@ -153,9 +160,11 @@ func (m *App) beginAIProviderTest() tea.Cmd {
|
||||
controller := m.ai
|
||||
m.aiMode = aiProviderTestBusy
|
||||
m.aiSpinner = 0
|
||||
started := time.Now()
|
||||
m.aiProgress = AIRunProgress{
|
||||
Stage: "Testing provider", Summary: "Preparing one minimal structured model call",
|
||||
CurrentCall: 1, TotalCalls: 1,
|
||||
StartedAt: started, StageStartedAt: started,
|
||||
}
|
||||
events := make(chan tea.Msg, 32)
|
||||
m.aiEvents = events
|
||||
@@ -245,10 +254,19 @@ func (m App) updateAI(msg tea.Msg) (tea.Model, tea.Cmd, bool) {
|
||||
}
|
||||
}
|
||||
m.aiMode = aiNone
|
||||
m.recordHealth("AI provider", healthOK, fmt.Sprintf(
|
||||
healthMessage := fmt.Sprintf(
|
||||
"local review complete: %d findings, %d thread comments",
|
||||
msg.result.Findings, msg.result.Comments,
|
||||
))
|
||||
)
|
||||
if timing := msg.result.Timing; timing.Total > 0 {
|
||||
healthMessage += fmt.Sprintf(
|
||||
" in %s (GitHub %s, filtering %s, provider %s across %d call(s), %d requested file(s))",
|
||||
formatAIDuration(timing.Total), formatAIDuration(timing.GitHub),
|
||||
formatAIDuration(timing.Filtering), formatAIDuration(timing.Provider),
|
||||
timing.Calls, timing.Files,
|
||||
)
|
||||
}
|
||||
m.recordHealth("AI provider", healthOK, healthMessage)
|
||||
return m, nil, true
|
||||
case aiProviderTestCompletedMsg:
|
||||
if m.aiMode != aiProviderTestBusy {
|
||||
@@ -466,9 +484,26 @@ func (m App) viewAI() string {
|
||||
m.aiPreview.Redactions, len(m.aiPreview.Excluded)),
|
||||
"",
|
||||
warnStyle.Render("Code and PR discussion will leave GitHub. No local files or commands are available to the model."),
|
||||
"",
|
||||
titleStyle.Render("Included files"),
|
||||
}
|
||||
if m.aiPreview.thread != nil {
|
||||
treeStatus := fmt.Sprintf(
|
||||
"%d visible tree entries • %d unavailable • %d sensitive hidden",
|
||||
m.aiPreview.TreeEntries, m.aiPreview.TreeUnavailable, m.aiPreview.TreeHidden,
|
||||
)
|
||||
if m.aiPreview.TreeTruncated {
|
||||
treeStatus += " • truncated"
|
||||
}
|
||||
lines = append(lines,
|
||||
"",
|
||||
fmt.Sprintf("Initial file revision: %s", shortOID(m.aiPreview.InitialRevision)),
|
||||
treeStatus,
|
||||
fmt.Sprintf(
|
||||
"Confirmation allows up to %d automatic request round(s) and %d additional file(s).",
|
||||
m.aiPreview.ContextRounds, m.aiPreview.ContextFiles,
|
||||
),
|
||||
)
|
||||
}
|
||||
lines = append(lines, "", titleStyle.Render("Included files"))
|
||||
for _, path := range m.aiPreview.Included {
|
||||
lines = append(lines, " "+path)
|
||||
}
|
||||
@@ -543,6 +578,18 @@ func (m App) aiProgressLines(width int) []string {
|
||||
if progress.Model != "" {
|
||||
lines = append(lines, dimStyle.Render("Model: "+progress.Model))
|
||||
}
|
||||
if !progress.StartedAt.IsZero() {
|
||||
elapsed := time.Since(progress.StartedAt)
|
||||
stage := time.Duration(0)
|
||||
if !progress.StageStartedAt.IsZero() {
|
||||
stage = time.Since(progress.StageStartedAt)
|
||||
}
|
||||
timing := "Elapsed: " + formatAIDuration(elapsed)
|
||||
if stage > 0 {
|
||||
timing += " • current stage: " + formatAIDuration(stage)
|
||||
}
|
||||
lines = append(lines, dimStyle.Render(timing))
|
||||
}
|
||||
if progress.Summary != "" {
|
||||
label := "Provider update"
|
||||
if progress.SummaryKind == "reasoning" {
|
||||
@@ -560,6 +607,16 @@ func (m App) aiProgressLines(width int) []string {
|
||||
return lines
|
||||
}
|
||||
|
||||
func formatAIDuration(value time.Duration) string {
|
||||
if value < 0 {
|
||||
value = 0
|
||||
}
|
||||
if value < time.Second {
|
||||
return value.Round(10 * time.Millisecond).String()
|
||||
}
|
||||
return value.Round(100 * time.Millisecond).String()
|
||||
}
|
||||
|
||||
func renderAIProgressBar(width int, progress AIRunProgress, spinner int) string {
|
||||
width = max(8, width)
|
||||
filled := 0
|
||||
|
||||
Reference in New Issue
Block a user