Files
wehub-resource-sync a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

90 lines
2.9 KiB
Go

package wiki
import (
"context"
"fmt"
"strings"
"github.com/zzet/gortex/internal/llm"
)
// ClaudeCLIEnhancer wraps any llm.Provider (with the Claude CLI
// provider being the MVP target — but anything that satisfies the
// interface works) and runs one Complete call per section, with a
// content-addressable cache layered on top for determinism.
//
// The Enhance method is intentionally tolerant: if the provider
// errors, we return the original markdown so a flaky provider can't
// stop the wiki from being generated. The caller logs the error path.
type ClaudeCLIEnhancer struct {
provider llm.Provider
cache *EnhanceCache
maxTok int
}
// NewClaudeCLIEnhancer constructs the enhancer. Pass nil cache to
// disable caching.
func NewClaudeCLIEnhancer(provider llm.Provider, cache *EnhanceCache) *ClaudeCLIEnhancer {
return &ClaudeCLIEnhancer{
provider: provider,
cache: cache,
maxTok: 2048,
}
}
// Enhance implements Enhancer.
func (e *ClaudeCLIEnhancer) Enhance(ctx context.Context, s EnhanceSection) (string, error) {
if e == nil || e.provider == nil {
return s.RawMarkdown, nil
}
// Cache lookup first. Determinism: identical inputs → identical
// output without invoking the provider.
var key string
if e.cache != nil {
key = e.cache.Key(s, e.provider.Name())
if cached, hit, err := e.cache.Get(key); err == nil && hit {
return cached, nil
}
}
prompt := buildPrompt(s)
req := llm.CompletionRequest{
Messages: []llm.Message{
{Role: llm.RoleSystem, Content: enhancerSystemPrompt},
{Role: llm.RoleUser, Content: prompt},
},
MaxTokens: e.maxTok,
Shape: llm.ShapeFreeform,
}
resp, err := e.provider.Complete(ctx, req)
if err != nil {
// Provider failure → fall back to template content. The
// wiki still ships.
return s.RawMarkdown, fmt.Errorf("enhance %s: %w", s.Kind, err)
}
out := strings.TrimSpace(resp.Text)
if out == "" {
return s.RawMarkdown, nil
}
if e.cache != nil {
_ = e.cache.Set(key, out)
}
return out, nil
}
const enhancerSystemPrompt = `You are a documentation writer for software-engineering reference docs. You receive a markdown page that was rendered from a code-intelligence graph. Your job is to make small, targeted prose improvements while preserving every table, code block, and link verbatim. You never invent symbols, files, or relationships. Return only the rewritten markdown with no surrounding commentary.`
func buildPrompt(s EnhanceSection) string {
switch s.Kind {
case "community":
return fmt.Sprintf(promptCommunity, s.PageTitle, s.Context, s.RawMarkdown)
case "process":
return fmt.Sprintf(promptProcess, s.PageTitle, s.RawMarkdown)
case "architecture":
return fmt.Sprintf(promptArchitecture, s.PageTitle, s.RawMarkdown)
default:
return fmt.Sprintf("Improve the prose of this markdown page (%s). Keep tables, code, and links verbatim.\n\n%s", s.PageTitle, s.RawMarkdown)
}
}