summaryrefslogtreecommitdiff
path: root/internal/api/webhook.go
diff options
context:
space:
mode:
authorClaude <noreply@anthropic.com>2026-05-02 07:54:51 +0000
committerClaude <noreply@anthropic.com>2026-05-02 07:54:51 +0000
commit6c5762848f4f3114a6ece9ce0bc70a84fca040ce (patch)
treec118fe596c66b23dbf23d7aee5d6d6f823d0903a /internal/api/webhook.go
parentae833b2765c7c8086bf8e1ea8e8ec8ee9b73e656 (diff)
feat(api): enrich CI failure task instructions via local LLM
Phase 3 of "local OSS models as agents" plan. When the webhook handler creates a task for a failed CI run AND a local LLM is configured on the server, the hardcoded 4-step investigation template is replaced with a project-aware investigation plan generated by the LLM. Scope adjustment from the original sketch: the original plan said "summarize fetched workflow logs", but fetching logs requires GitHub API auth that isn't wired. Narrowed to project-context triage — recent git log + CLAUDE.md content + webhook metadata, fed to the LLM with a system prompt asking for 6-12 lines of concrete next steps. Deferred GitHub log fetching to post-epic cleanup. Implementation: - New internal/api/webhook_llm.go holds enrichCIInstructions and its helpers (readRecentCommits via `git log`, readProjectDoc). - enrichCIInstructions is truly additive: any failure mode (no client, HTTP error, empty body, 10s timeout) returns the original fallback template unchanged. Existing webhook tests pass byte-for-byte. - Always preserves a metadata header (repo/branch/SHA/check/URL) ahead of the LLM body so investigators don't lose context if the LLM is terse. - Reuses s.llm (set via Server.SetLLM in Phase 2) — no new config knob, no per-feature gating. Asymmetric opt-out (yes-elaborate, no-CI-triage) deferred until there's actual demand. Tests: - enrichCIInstructions: nil client, LLM 500, empty body all return fallback unchanged. - enrichCIInstructions: success path produces enriched body with metadata header preserved; user prompt contains repo/branch/SHA. - enrichCIInstructions: real git repo (init + 2 commits) → recent commits appear in user prompt. - Webhook handler regression guard: no-LLM path produces the exact legacy template substrings. - Webhook handler with LLM stubbed: task instructions contain LLM body + metadata header. Plan: docs/plans/local-oss-runner.md. https://claude.ai/code/session_017Edeq947TpSm1vQTxMhi1J
Diffstat (limited to 'internal/api/webhook.go')
-rw-r--r--internal/api/webhook.go15
1 files changed, 14 insertions, 1 deletions
diff --git a/internal/api/webhook.go b/internal/api/webhook.go
index 8bf1676..9437f7d 100644
--- a/internal/api/webhook.go
+++ b/internal/api/webhook.go
@@ -1,6 +1,7 @@
package api
import (
+ "context"
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
@@ -154,7 +155,7 @@ func (s *Server) handleWorkflowRunEvent(w http.ResponseWriter, body []byte) {
func (s *Server) createCIFailureTask(w http.ResponseWriter, repoName, fullName, branch, sha, checkName, htmlURL string) {
project := matchProject(s.projects, repoName)
- instructions := fmt.Sprintf(
+ fallback := fmt.Sprintf(
"A CI failure has been detected and requires investigation.\n\n"+
"Repository: %s\n"+
"Branch: %s\n"+
@@ -169,6 +170,18 @@ func (s *Server) createCIFailureTask(w http.ResponseWriter, repoName, fullName,
fullName, branch, sha, checkName, htmlURL,
)
+ tctx := ciTriageContext{
+ Repo: fullName,
+ Branch: branch,
+ SHA: sha,
+ CheckName: checkName,
+ URL: htmlURL,
+ }
+ if project != nil {
+ tctx.ProjectDir = project.Dir
+ }
+ instructions := enrichCIInstructions(context.Background(), s.llm, tctx, fallback)
+
now := time.Now().UTC()
t := &task.Task{
ID: uuid.New().String(),