All checks were successful
Build and Release / Create Release (push) Has been skipped
Build and Release / Unit Tests (push) Successful in 6m49s
Build and Release / Integration Tests (PostgreSQL) (push) Successful in 7m6s
Build and Release / Lint (push) Successful in 7m15s
Build and Release / Build Binaries (amd64, windows, windows-latest) (push) Has been skipped
Build and Release / Build Binaries (amd64, darwin, macos) (push) Has been skipped
Build and Release / Build Binaries (amd64, linux, linux-latest) (push) Has been skipped
Build and Release / Build Binaries (arm64, darwin, macos) (push) Has been skipped
Build and Release / Build Binary (linux/arm64) (push) Has been skipped
Implement critical production readiness features for AI integration: per-request provider config, admin dashboard, workflow inspection, and plugin framework foundation. Per-Request Provider Config: - Add ProviderConfig struct to all AI request types - Update queue to resolve provider/model/API key from cascade (repo > org > system) - Pass resolved config to AI sidecar on every request - Fixes multi-tenant issue where all orgs shared sidecar's hardcoded config Admin AI Dashboard: - Add /admin/ai page with sidecar health status - Display global operation stats (total, 24h, success/fail/escalated counts) - Show operations by tier, top 5 repos, token usage - Recent operations table with repo, operation, status, duration - Add GetGlobalOperationStats model method Workflow Inspection: - Add InspectWorkflow client method and types - Implement workflow-inspect queue handler - Add notifier trigger on workflow file push - Analyzes YAML for syntax errors, security issues, best practices - Returns structured issues with line numbers and suggested fixes Plugin Framework (Phase 5 Foundation): - Add external plugin config loading from app.ini - Define ExternalPlugin interface and manager - Add plugin.proto contract (Initialize, Shutdown, HealthCheck, OnEvent, HandleHTTP) - Implement health monitoring with auto-restart for managed plugins - Add event routing to subscribed plugins - HTTP proxy support for plugin-served routes This completes Tasks 1-4 from the production readiness plan and establishes the foundation for managed plugin lifecycle.
225 lines
8.9 KiB
Handlebars
225 lines
8.9 KiB
Handlebars
{{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin ai")}}
|
|
<div class="admin ai">
|
|
<h4 class="ui top attached header">
|
|
{{ctx.Locale.Tr "admin.ai.title"}}
|
|
</h4>
|
|
|
|
<!-- Stat Tiles -->
|
|
<div class="ui attached segment">
|
|
<div style="display: flex; justify-content: space-around; text-align: center; flex-wrap: wrap; gap: 10px;">
|
|
<!-- Sidecar Status -->
|
|
<div style="padding: 15px 25px; background: var(--color-box-body); border: 1px solid var(--color-secondary); border-radius: 8px; min-width: 150px;">
|
|
{{if .SidecarHealthy}}
|
|
<div style="font-size: 2em; font-weight: bold; color: #21ba45;">{{svg "octicon-check-circle-fill" 32}}</div>
|
|
<div style="color: #21ba45; font-weight: bold; margin-top: 5px;">Online</div>
|
|
{{else}}
|
|
<div style="font-size: 2em; font-weight: bold; color: #db2828;">{{svg "octicon-x-circle-fill" 32}}</div>
|
|
<div style="color: #db2828; font-weight: bold; margin-top: 5px;">Offline</div>
|
|
{{end}}
|
|
<div style="color: var(--color-text-light); margin-top: 5px;">{{ctx.Locale.Tr "admin.ai.sidecar_status"}}</div>
|
|
{{if .SidecarVersion}}<div style="color: var(--color-text-light); font-size: 0.85em;">v{{.SidecarVersion}}</div>{{end}}
|
|
</div>
|
|
<!-- Total Ops -->
|
|
<div style="padding: 15px 25px; background: var(--color-box-body); border: 1px solid var(--color-secondary); border-radius: 8px; min-width: 150px;">
|
|
<div style="font-size: 2em; font-weight: bold; color: #2185d0;">{{.Stats.TotalOperations}}</div>
|
|
<div style="color: var(--color-text-light); margin-top: 5px;">{{ctx.Locale.Tr "admin.ai.total_operations"}}</div>
|
|
</div>
|
|
<!-- 24h Ops -->
|
|
<div style="padding: 15px 25px; background: var(--color-box-body); border: 1px solid var(--color-secondary); border-radius: 8px; min-width: 150px;">
|
|
<div style="font-size: 2em; font-weight: bold; color: #6435c9;">{{.Stats.Operations24h}}</div>
|
|
<div style="color: var(--color-text-light); margin-top: 5px;">{{ctx.Locale.Tr "admin.ai.operations_24h"}}</div>
|
|
</div>
|
|
<!-- Success Rate -->
|
|
<div style="padding: 15px 25px; background: var(--color-box-body); border: 1px solid var(--color-secondary); border-radius: 8px; min-width: 150px;">
|
|
<div style="font-size: 2em; font-weight: bold; color: #21ba45;">{{printf "%.1f" .SuccessRate}}%</div>
|
|
<div style="color: var(--color-text-light); margin-top: 5px;">{{ctx.Locale.Tr "admin.ai.success_rate"}}</div>
|
|
</div>
|
|
<!-- Tokens Used -->
|
|
<div style="padding: 15px 25px; background: var(--color-box-body); border: 1px solid var(--color-secondary); border-radius: 8px; min-width: 150px;">
|
|
<div style="font-size: 2em; font-weight: bold; color: #f2711c;">{{.TotalTokens}}</div>
|
|
<div style="color: var(--color-text-light); margin-top: 5px;">{{ctx.Locale.Tr "admin.ai.tokens_used"}}</div>
|
|
<div style="color: var(--color-text-light); font-size: 0.85em;">In: {{.Stats.TotalInputTokens}} / Out: {{.Stats.TotalOutputTokens}}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Configuration Summary -->
|
|
<h4 class="ui attached header">
|
|
{{ctx.Locale.Tr "admin.ai.config"}}
|
|
</h4>
|
|
<div class="ui attached segment">
|
|
<div class="ui two column stackable grid">
|
|
<div class="column">
|
|
<table class="ui very basic table">
|
|
<tbody>
|
|
<tr>
|
|
<td><strong>AI Enabled</strong></td>
|
|
<td>
|
|
{{if .AIConfig.Enabled}}
|
|
<span class="ui small green label">On</span>
|
|
{{else}}
|
|
<span class="ui small red label">Off</span>
|
|
{{end}}
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>Provider</strong></td>
|
|
<td>{{.AIConfig.DefaultProvider}}</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>Model</strong></td>
|
|
<td><code>{{.AIConfig.DefaultModel}}</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>Service URL</strong></td>
|
|
<td><code>{{.AIConfig.ServiceURL}}</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>Rate Limit</strong></td>
|
|
<td>{{.AIConfig.MaxOperationsPerHour}} ops/hr, {{.AIConfig.MaxTokensPerOperation}} tokens/op</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<div class="column">
|
|
<table class="ui very basic table">
|
|
<tbody>
|
|
<tr>
|
|
<td><strong>Code Review</strong></td>
|
|
<td>{{if .AIConfig.EnableCodeReview}}<span class="ui small green label">On</span>{{else}}<span class="ui small red label">Off</span>{{end}}</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>Issue Triage</strong></td>
|
|
<td>{{if .AIConfig.EnableIssueTriage}}<span class="ui small green label">On</span>{{else}}<span class="ui small red label">Off</span>{{end}}</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>Doc Generation</strong></td>
|
|
<td>{{if .AIConfig.EnableDocGen}}<span class="ui small green label">On</span>{{else}}<span class="ui small red label">Off</span>{{end}}</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>Explain Code</strong></td>
|
|
<td>{{if .AIConfig.EnableExplainCode}}<span class="ui small green label">On</span>{{else}}<span class="ui small red label">Off</span>{{end}}</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>Chat</strong></td>
|
|
<td>{{if .AIConfig.EnableChat}}<span class="ui small green label">On</span>{{else}}<span class="ui small red label">Off</span>{{end}}</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>Auto-Respond</strong></td>
|
|
<td>{{if .AIConfig.AllowAutoRespond}}<span class="ui small green label">On</span>{{else}}<span class="ui small red label">Off</span>{{end}}</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>Auto-Review</strong></td>
|
|
<td>{{if .AIConfig.AllowAutoReview}}<span class="ui small green label">On</span>{{else}}<span class="ui small red label">Off</span>{{end}}</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>Agent Mode</strong></td>
|
|
<td>{{if .AIConfig.AllowAgentMode}}<span class="ui small green label">On</span>{{else}}<span class="ui small red label">Off</span>{{end}}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
{{if .ProviderStatus}}
|
|
<div class="ui divider"></div>
|
|
<h5>Provider Status</h5>
|
|
<div>
|
|
{{range $provider, $status := .ProviderStatus}}
|
|
<span class="ui label" style="margin: 2px; background-color: {{if eq $status "ok"}}#21ba45{{else if eq $status "healthy"}}#21ba45{{else}}#db2828{{end}}; color: white;">
|
|
{{$provider}}: {{$status}}
|
|
</span>
|
|
{{end}}
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
|
|
<!-- Status Breakdown -->
|
|
<h4 class="ui attached header">
|
|
{{ctx.Locale.Tr "admin.ai.stats"}}
|
|
</h4>
|
|
<div class="ui attached segment">
|
|
<div style="display: flex; gap: 15px; flex-wrap: wrap;">
|
|
<div class="ui small statistic" style="margin: 5px 15px;">
|
|
<div class="value" style="color: #21ba45;">{{.Stats.SuccessCount}}</div>
|
|
<div class="label">Success</div>
|
|
</div>
|
|
<div class="ui small statistic" style="margin: 5px 15px;">
|
|
<div class="value" style="color: #db2828;">{{.Stats.FailedCount}}</div>
|
|
<div class="label">Failed</div>
|
|
</div>
|
|
<div class="ui small statistic" style="margin: 5px 15px;">
|
|
<div class="value" style="color: #f2711c;">{{.Stats.EscalatedCount}}</div>
|
|
<div class="label">Escalated</div>
|
|
</div>
|
|
<div class="ui small statistic" style="margin: 5px 15px;">
|
|
<div class="value" style="color: #2185d0;">{{.Stats.PendingCount}}</div>
|
|
<div class="label">Pending</div>
|
|
</div>
|
|
{{range $tier, $count := .Stats.CountByTier}}
|
|
<div class="ui small statistic" style="margin: 5px 15px;">
|
|
<div class="value" style="color: #6435c9;">{{$count}}</div>
|
|
<div class="label">Tier {{$tier}}</div>
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Recent Operations -->
|
|
<h4 class="ui attached header">
|
|
{{ctx.Locale.Tr "admin.ai.recent_operations"}}
|
|
</h4>
|
|
<div class="ui attached segment">
|
|
<table class="ui celled striped table">
|
|
<thead>
|
|
<tr>
|
|
<th>Time</th>
|
|
<th>Repo ID</th>
|
|
<th>Operation</th>
|
|
<th>Tier</th>
|
|
<th>Status</th>
|
|
<th>Duration</th>
|
|
<th>Provider</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{{range .RecentOps}}
|
|
<tr>
|
|
<td>{{DateUtils.TimeSince .CreatedUnix}}</td>
|
|
<td>{{.RepoID}}</td>
|
|
<td><code>{{.Operation}}</code></td>
|
|
<td>
|
|
<span class="ui small label" style="background-color: {{if eq .Tier 1}}#2185d0{{else}}#6435c9{{end}}; color: white;">
|
|
Tier {{.Tier}}
|
|
</span>
|
|
</td>
|
|
<td>
|
|
{{if eq .Status "success"}}
|
|
<span class="ui small green label">{{.Status}}</span>
|
|
{{else if eq .Status "failed"}}
|
|
<span class="ui small red label">{{.Status}}</span>
|
|
{{else if eq .Status "escalated"}}
|
|
<span class="ui small orange label">{{.Status}}</span>
|
|
{{else}}
|
|
<span class="ui small blue label">{{.Status}}</span>
|
|
{{end}}
|
|
</td>
|
|
<td>{{.DurationMs}}ms</td>
|
|
<td>
|
|
{{if .Provider}}{{.Provider}}{{else}}-{{end}}
|
|
{{if .Model}}<br><small style="color: var(--color-text-light);">{{.Model}}</small>{{end}}
|
|
</td>
|
|
</tr>
|
|
{{else}}
|
|
<tr>
|
|
<td colspan="7" class="center aligned">
|
|
<i>No recent operations</i>
|
|
</td>
|
|
</tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
{{template "admin/layout_footer" .}}
|