// Package describe implements the English→Go code generation pipeline. // // This package provides structural utilities: extracting Go source from // markdown, extracting self-knowledge from a lattice, composing code queries, // and evaluating generated source against descriptions. The actual code // generation (formerly via LLM oracle) has been removed — the organism // relies on its own deterministic lattice dynamics for growth. package describe import ( "fmt" "go/ast" "go/parser" "go/token" "os" "path/filepath" "regexp" "strings" "os/exec" "git.mleku.dev/mleku/dendrite/pkg/emit" "git.mleku.dev/mleku/dendrite/pkg/lattice" "git.mleku.dev/mleku/dendrite/pkg/ratio" ) // Description is an English description of desired Go code. type Description struct { Text string // what the code should do TargetPkg string // target package (empty = inferred from oracle response) TestInputs []string // optional: expected behaviors to verify } // Result captures the output of description-driven code generation. type Result struct { Description Description GoSource string // the produced Go code Compiles bool // whether it compiled successfully CompileError string // compiler output on failure Declarations []string // what was declared (e.g., "func:CountNodes", "type:Summary") BondRatio ratio.Ratio // how well the oracle response aligned with the self-lattice Fitness ratio.Ratio // overall description fitness score } // ExtractGoSource finds Go source code inside a markdown-formatted oracle // response. It looks for content between ```go and ``` markers. If multiple // code blocks exist, returns the longest one. Falls back to the entire // response if no code blocks are found. func ExtractGoSource(answer string) string { // Match ```go ... ``` blocks. re := regexp.MustCompile("(?s)```go\\s*\n(.*?)```") matches := re.FindAllStringSubmatch(answer, -1) if len(matches) == 0 { // Fallback: try plain ``` blocks. re = regexp.MustCompile("(?s)```\\s*\n(.*?)```") matches = re.FindAllStringSubmatch(answer, -1) } if len(matches) == 0 { // No code blocks at all. If the response starts with "package", // treat the whole thing as source. trimmed := strings.TrimSpace(answer) if strings.HasPrefix(trimmed, "package ") { return trimmed } return "" } // Return the longest code block (most likely the complete source). best := "" for _, m := range matches { if len(m) > 1 && len(m[1]) > len(best) { best = m[1] } } return strings.TrimSpace(best) } // ExtractSelfKnowledge reads the lattice's bonded elements and produces // a compact summary of the organism's current structure. This summary is // sent to the oracle as context so it can match existing patterns. func ExtractSelfKnowledge(l *lattice.Lattice) string { if l == nil { return "" } files := emit.Harvest(l) // Collect unique declarations across all file groups. types := make(map[string]bool) funcs := make(map[string]bool) methods := make(map[string]bool) imports := make(map[string]bool) var pkgName string for _, fragments := range files { for _, f := range fragments { switch f.Type { case "type": if f.Value != "" { types[f.Value] = true } case "func": if f.Value != "" { funcs[f.Value] = true } case "method": if f.Value != "" { methods[f.Value] = true } case "import": if f.Value != "" { imports[f.Value] = true } case "package": if f.Value != "" { pkgName = f.Value } } } } var b strings.Builder if pkgName != "" { fmt.Fprintf(&b, "Package: %s\n", pkgName) } // Cap each category to avoid overwhelming the oracle with context. const maxPerCategory = 10 if len(types) > 0 { fmt.Fprintf(&b, "Types: %s\n", joinKeysLimited(types, maxPerCategory)) } if len(funcs) > 0 { fmt.Fprintf(&b, "Functions: %s\n", joinKeysLimited(funcs, maxPerCategory)) } if len(methods) > 0 { fmt.Fprintf(&b, "Methods: %s\n", joinKeysLimited(methods, maxPerCategory)) } if len(imports) > 0 { fmt.Fprintf(&b, "Imports: %s\n", joinKeysLimited(imports, maxPerCategory)) } return b.String() } // ComposeCodeQuery builds an oracle prompt from a description and // the organism's self-knowledge. func ComposeCodeQuery(desc Description, selfKnowledge string) string { var b strings.Builder if selfKnowledge != "" { b.WriteString("Context (for reference only — do NOT include these in your output):\n") b.WriteString("The codebase already has these declarations:\n") b.WriteString(selfKnowledge) b.WriteString("\n") } b.WriteString("Generate ONLY the following:\n\n") b.WriteString(desc.Text) b.WriteString("\n\nRequirements:\n") b.WriteString("- The code MUST compile as a standalone file\n") b.WriteString("- Generate ONLY the requested function/type — do NOT reproduce or stub existing declarations\n") b.WriteString("- Use only standard library imports unless the description specifies otherwise\n") if desc.TargetPkg != "" { fmt.Fprintf(&b, "- Use package %s\n", desc.TargetPkg) } else { b.WriteString("- Use package main if no package is specified in the description\n") } b.WriteString("- Include all necessary imports\n") b.WriteString("- Return the complete Go source inside a single ```go code block\n") return b.String() } // EvaluateDescription computes a fitness score for how well generated code // fulfills a description. // // Weights: // - 0.50: compiles (binary pass/fail) // - 0.30: declares expected types/functions from the description // - 0.20: bond ratio (alignment with existing organism structure) func EvaluateDescription(goSource string, desc Description, bondRatio ratio.Ratio, goRoot string) ratio.Ratio { score := ratio.Zero // Compile check — vet (type-check), not build. tmpDir, err := os.MkdirTemp("", "describe-fitness-*") if err != nil { return ratio.New(1, 5).Mul(bondRatio) } defer os.RemoveAll(tmpDir) if vetCheck(goSource, tmpDir, goRoot) == nil { score = score.Add(ratio.Half) } // Declaration match. expected := extractExpectedNames(desc.Text) if len(expected) > 0 { actual := extractDeclarations(goSource) actualSet := make(map[string]bool) for _, d := range actual { // Match both full ("func:CountNodes") and name-only ("CountNodes"). actualSet[d] = true parts := strings.SplitN(d, ":", 2) if len(parts) == 2 { actualSet[parts[1]] = true } } matches := 0 for _, name := range expected { if actualSet[name] { matches++ } } score = score.Add(ratio.New(3, 10).Mul(ratio.New(int64(matches), int64(len(expected))))) } else { // No expected names found in description — give partial credit if it compiles. score = score.Add(ratio.New(3, 20)) } // Bond ratio. score = score.Add(ratio.New(1, 5).Mul(bondRatio)) return score } // extractDeclarations parses Go source and returns declared names. func extractDeclarations(src string) []string { fset := token.NewFileSet() f, err := parser.ParseFile(fset, "", src, parser.SkipObjectResolution) if err != nil { return nil } var decls []string if f.Name != nil { decls = append(decls, "package:"+f.Name.Name) } for _, d := range f.Decls { switch decl := d.(type) { case *ast.FuncDecl: if decl.Recv != nil && len(decl.Recv.List) > 0 { decls = append(decls, "method:"+decl.Name.Name) } else { decls = append(decls, "func:"+decl.Name.Name) } case *ast.GenDecl: for _, spec := range decl.Specs { if ts, ok := spec.(*ast.TypeSpec); ok { decls = append(decls, "type:"+ts.Name.Name) } } } } return decls } // extractExpectedNames looks for function and type names mentioned // in a description. Patterns like "function named X", "type called Y", // "function X", "type Y" are recognized. func extractExpectedNames(desc string) []string { var names []string seen := make(map[string]bool) patterns := []*regexp.Regexp{ regexp.MustCompile(`(?i)function\s+(?:named|called)\s+(\w+)`), regexp.MustCompile(`(?i)func(?:tion)?\s+(\w+)\s+that`), regexp.MustCompile(`(?i)(?:a\s+)?type\s+(?:named|called|for)?\s*(\w+)`), regexp.MustCompile(`(?i)method\s+(?:named|called)\s+(\w+)`), regexp.MustCompile(`(?i)struct\s+(?:named|called)\s+(\w+)`), } for _, p := range patterns { for _, m := range p.FindAllStringSubmatch(desc, -1) { if len(m) > 1 { name := m[1] if !seen[name] { seen[name] = true names = append(names, name) } } } } return names } // vetCheck writes Go source to a temp module and runs `go vet` to verify it // type-checks. This doesn't require func main() — it just checks that the code // is valid Go. tmpDir must exist; a subdirectory is created inside it. func vetCheck(goSource, tmpDir, goRoot string) error { modDir := filepath.Join(tmpDir, "vetmod") os.MkdirAll(modDir, 0o755) // Write go.mod. os.WriteFile(filepath.Join(modDir, "go.mod"), []byte("module vetcheck\n\ngo 1.24\n"), 0o644) // Write source file. if err := os.WriteFile(filepath.Join(modDir, "code.go"), []byte(goSource), 0o644); err != nil { return err } goBin := filepath.Join(goRoot, "bin", "go") cmd := exec.Command(goBin, "vet", "./...") cmd.Dir = modDir cmd.Env = cleanGoEnv(goRoot) out, err := cmd.CombinedOutput() if err != nil { return fmt.Errorf("%s", string(out)) } return nil } // cleanGoEnv returns an environment with GOROOT, PATH, and GOTOOLCHAIN set. func cleanGoEnv(root string) []string { env := os.Environ() clean := make([]string, 0, len(env)+3) for _, e := range env { if strings.HasPrefix(e, "GOROOT=") || strings.HasPrefix(e, "GOTOOLCHAIN=") || strings.HasPrefix(e, "PATH=") { continue } clean = append(clean, e) } clean = append(clean, "GOROOT="+root, "GOTOOLCHAIN=local", "PATH="+filepath.Join(root, "bin")+":"+os.Getenv("PATH"), ) return clean } // joinKeys returns sorted, comma-separated keys from a string-bool map. func joinKeys(m map[string]bool) string { return joinKeysLimited(m, 0) } // joinKeysLimited returns sorted, comma-separated keys from a string-bool map. // If limit > 0 and there are more keys, it truncates and appends "... (N more)". func joinKeysLimited(m map[string]bool, limit int) string { keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } // Simple sort for deterministic output. for i := range keys { for j := i + 1; j < len(keys); j++ { if keys[j] < keys[i] { keys[i], keys[j] = keys[j], keys[i] } } } if limit > 0 && len(keys) > limit { return strings.Join(keys[:limit], ", ") + fmt.Sprintf(" ... (%d more)", len(keys)-limit) } return strings.Join(keys, ", ") }