feat: add params_schema column for function composability
Nueva columna params_schema en functions con migración 009. Almacena JSON con descripción semántica de inputs/outputs para que agentes razonen sobre composabilidad de funciones. Incluye: campo en modelo Go, parsing de params/output del frontmatter YAML, serialización a JSON, FTS5 rebuild con nueva columna, hash de contenido actualizado, y warning en indexer cuando faltan params.
This commit is contained in:
@@ -37,6 +37,7 @@ func ComputeFunctionHash(f *Function) string {
|
||||
fmt.Fprintf(h, "|%s", marshalStrings(f.Variant))
|
||||
fmt.Fprintf(h, "|%s|%s|%s", f.Notes, f.Documentation, f.Code)
|
||||
fmt.Fprintf(h, "|%s|%s|%s", f.SourceRepo, f.SourceLicense, f.SourceFile)
|
||||
fmt.Fprintf(h, "|%s", f.ParamsSchema)
|
||||
return fmt.Sprintf("%x", h.Sum(nil))
|
||||
}
|
||||
|
||||
|
||||
@@ -238,6 +238,8 @@ func Index(db *DB, root string) (*IndexResult, error) {
|
||||
}
|
||||
|
||||
// Post-insert: warn about file_path entries that don't exist on disk
|
||||
// and functions missing params_schema
|
||||
missingParams := 0
|
||||
for _, f := range functions {
|
||||
if f.FilePath != "" {
|
||||
abs := filepath.Join(root, f.FilePath)
|
||||
@@ -251,6 +253,12 @@ func Index(db *DB, root string) (*IndexResult, error) {
|
||||
result.Warnings = append(result.Warnings, fmt.Sprintf("%s: test_file_path %q not found", f.ID, f.TestFilePath))
|
||||
}
|
||||
}
|
||||
if f.ParamsSchema == "" {
|
||||
missingParams++
|
||||
}
|
||||
}
|
||||
if missingParams > 0 {
|
||||
result.Warnings = append(result.Warnings, fmt.Sprintf("%d functions missing params_schema (run 'fn check params' to list)", missingParams))
|
||||
}
|
||||
for _, t := range types {
|
||||
if t.FilePath != "" {
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
-- Add params_schema to functions: JSON with semantic descriptions of inputs/outputs.
|
||||
-- Format: {"params":[{"name":"x","desc":"..."}],"output":"..."}
|
||||
-- Enables agent reasoning about function composability.
|
||||
|
||||
ALTER TABLE functions ADD COLUMN params_schema TEXT NOT NULL DEFAULT '';
|
||||
|
||||
-- Rebuild FTS for functions: add params_schema
|
||||
DROP TRIGGER IF EXISTS functions_ai;
|
||||
DROP TRIGGER IF EXISTS functions_ad;
|
||||
DROP TRIGGER IF EXISTS functions_au;
|
||||
|
||||
INSERT INTO functions_fts(functions_fts) VALUES('rebuild');
|
||||
DROP TABLE IF EXISTS functions_fts;
|
||||
|
||||
CREATE VIRTUAL TABLE functions_fts USING fts5(
|
||||
id,
|
||||
name,
|
||||
description,
|
||||
tags,
|
||||
signature,
|
||||
domain,
|
||||
example,
|
||||
notes,
|
||||
documentation,
|
||||
code,
|
||||
params_schema,
|
||||
content='functions',
|
||||
content_rowid='rowid'
|
||||
);
|
||||
|
||||
-- Populate FTS from existing data
|
||||
INSERT INTO functions_fts(rowid, id, name, description, tags, signature, domain, example, notes, documentation, code, params_schema)
|
||||
SELECT rowid, id, name, description, tags, signature, domain, example, notes, documentation, code, params_schema
|
||||
FROM functions;
|
||||
|
||||
CREATE TRIGGER functions_ai AFTER INSERT ON functions BEGIN
|
||||
INSERT INTO functions_fts(rowid, id, name, description, tags, signature, domain, example, notes, documentation, code, params_schema)
|
||||
VALUES (new.rowid, new.id, new.name, new.description, new.tags, new.signature, new.domain, new.example, new.notes, new.documentation, new.code, new.params_schema);
|
||||
END;
|
||||
|
||||
CREATE TRIGGER functions_ad AFTER DELETE ON functions BEGIN
|
||||
INSERT INTO functions_fts(functions_fts, rowid, id, name, description, tags, signature, domain, example, notes, documentation, code, params_schema)
|
||||
VALUES ('delete', old.rowid, old.id, old.name, old.description, old.tags, old.signature, old.domain, old.example, old.notes, old.documentation, old.code, old.params_schema);
|
||||
END;
|
||||
|
||||
CREATE TRIGGER functions_au AFTER UPDATE ON functions BEGIN
|
||||
INSERT INTO functions_fts(functions_fts, rowid, id, name, description, tags, signature, domain, example, notes, documentation, code, params_schema)
|
||||
VALUES ('delete', old.rowid, old.id, old.name, old.description, old.tags, old.signature, old.domain, old.example, old.notes, old.documentation, old.code, old.params_schema);
|
||||
INSERT INTO functions_fts(rowid, id, name, description, tags, signature, domain, example, notes, documentation, code, params_schema)
|
||||
VALUES (new.rowid, new.id, new.name, new.description, new.tags, new.signature, new.domain, new.example, new.notes, new.documentation, new.code, new.params_schema);
|
||||
END;
|
||||
@@ -50,6 +50,7 @@ type Function struct {
|
||||
Notes string `json:"notes"`
|
||||
Documentation string `json:"documentation"`
|
||||
Code string `json:"code"`
|
||||
ParamsSchema string `json:"params_schema"`
|
||||
Tested bool `json:"tested"`
|
||||
Tests []string `json:"tests"`
|
||||
TestFilePath string `json:"test_file_path"`
|
||||
|
||||
@@ -2,6 +2,7 @@ package registry
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -32,6 +33,10 @@ type rawFunction struct {
|
||||
TestFilePath string `yaml:"test_file_path"`
|
||||
FilePath string `yaml:"file_path"`
|
||||
|
||||
// Params schema
|
||||
Params []rawParam `yaml:"params"`
|
||||
Output string `yaml:"output"`
|
||||
|
||||
// Source attribution
|
||||
SourceRepo string `yaml:"source_repo"`
|
||||
SourceLicense string `yaml:"source_license"`
|
||||
@@ -45,6 +50,12 @@ type rawFunction struct {
|
||||
Variant []string `yaml:"variant"`
|
||||
}
|
||||
|
||||
// rawParam describes a function parameter with semantic meaning.
|
||||
type rawParam struct {
|
||||
Name string `yaml:"name" json:"name"`
|
||||
Desc string `yaml:"desc" json:"desc"`
|
||||
}
|
||||
|
||||
// rawType mirrors the YAML frontmatter of a type .md file.
|
||||
type rawType struct {
|
||||
Name string `yaml:"name"`
|
||||
@@ -175,6 +186,17 @@ func ParseFunctionMD(path string, root string) (*Function, error) {
|
||||
SourceFile: raw.SourceFile,
|
||||
}
|
||||
|
||||
// Serialize params + output to JSON for params_schema column
|
||||
if len(raw.Params) > 0 || raw.Output != "" {
|
||||
schema := struct {
|
||||
Params []rawParam `json:"params,omitempty"`
|
||||
Output string `json:"output,omitempty"`
|
||||
}{Params: raw.Params, Output: raw.Output}
|
||||
if b, err := json.Marshal(schema); err == nil {
|
||||
f.ParamsSchema = string(b)
|
||||
}
|
||||
}
|
||||
|
||||
if root != "" && raw.FilePath != "" {
|
||||
codePath := filepath.Join(root, raw.FilePath)
|
||||
if codeData, err := os.ReadFile(codePath); err == nil {
|
||||
|
||||
+6
-2
@@ -86,7 +86,8 @@ func (db *DB) InsertFunction(f *Function) error {
|
||||
tests, test_file_path, file_path, content_hash, created_at, updated_at,
|
||||
props, emits, has_state, framework, variant,
|
||||
notes, documentation, code,
|
||||
source_repo, source_license, source_file
|
||||
source_repo, source_license, source_file,
|
||||
params_schema
|
||||
) VALUES (
|
||||
?, ?, ?, ?, ?, ?, ?, ?,
|
||||
?, ?, ?, ?, ?,
|
||||
@@ -94,7 +95,8 @@ func (db *DB) InsertFunction(f *Function) error {
|
||||
?, ?, ?, ?, ?, ?,
|
||||
?, ?, ?, ?, ?,
|
||||
?, ?, ?,
|
||||
?, ?, ?
|
||||
?, ?, ?,
|
||||
?
|
||||
)`,
|
||||
f.ID, f.Name, string(f.Kind), f.Lang, f.Domain, f.Version, string(f.Purity), f.Signature,
|
||||
f.Description, marshalStrings(f.Tags), marshalStrings(f.UsesFunctions), marshalStrings(f.UsesTypes), marshalStrings(f.Returns),
|
||||
@@ -103,6 +105,7 @@ func (db *DB) InsertFunction(f *Function) error {
|
||||
marshalProps(f.Props), marshalStrings(f.Emits), hasState, f.Framework, marshalStrings(f.Variant),
|
||||
f.Notes, f.Documentation, f.Code,
|
||||
f.SourceRepo, f.SourceLicense, f.SourceFile,
|
||||
f.ParamsSchema,
|
||||
)
|
||||
return err
|
||||
}
|
||||
@@ -559,6 +562,7 @@ func scanFunctions(rows interface{ Next() bool; Scan(...any) error }) ([]Functio
|
||||
&propsJSON, &emitsJSON, &hasState, &f.Framework, &variantJSON,
|
||||
&f.Notes, &f.Documentation, &f.Code, &f.ContentHash,
|
||||
&f.SourceRepo, &f.SourceLicense, &f.SourceFile,
|
||||
&f.ParamsSchema,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("scanning function: %w", err)
|
||||
|
||||
Reference in New Issue
Block a user