Port postgres to Go and install the extensions a consumer asks for
letta crash-loops on 'type "vector" does not exist': pgvector is not a trusted extension, so only the provider's superuser can create it, and the provisioner never did. A contribution may now name extensions; the provider creates each (IF NOT EXISTS, available ones only) in the consumer's database on every pass. Go per the standing rule for a TypeScript module that changes. letta asks for vector.
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
package main
|
||||
|
||||
// postgres's tools, and the mesh-store seat's verbs (novox/hq ADR 0159, 0160). The seat's verbs are
|
||||
// named `mesh-store.<verb>`, so the runtime serves them as the seat's wherever this module holds it
|
||||
// and never lists them as postgres's own; they are scoped to what the store enables — asking what it
|
||||
// holds and reading from it — so retiring a database is postgres's tool and not the store's.
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
stdio "git.novox.be/novox/mesh-sdk/go"
|
||||
)
|
||||
|
||||
// Seat is the store seat this module claims.
|
||||
const Seat = "mesh-store"
|
||||
|
||||
var queryInput = map[string]any{
|
||||
"database": map[string]any{"type": "string", "description": "the database to query"},
|
||||
"sql": map[string]any{"type": "string", "description": "the SELECT (or other read-only) statement"},
|
||||
}
|
||||
|
||||
func str(args map[string]any, key string) string {
|
||||
if s, ok := args[key].(string); ok {
|
||||
return s
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func listTool(pg *Client, name, description string) stdio.Tool {
|
||||
return stdio.Tool{Name: name, Description: description, Run: func(map[string]any) (any, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||
defer cancel()
|
||||
dbs, err := pg.ListDatabases(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return map[string]any{"databases": dbs}, nil
|
||||
}}
|
||||
}
|
||||
|
||||
func queryTool(pg *Client, name, prefix, description string) stdio.Tool {
|
||||
return stdio.Tool{Name: name, Description: description, Input: queryInput, Run: func(args map[string]any) (any, error) {
|
||||
database, sql := str(args, "database"), str(args, "sql")
|
||||
if database == "" {
|
||||
return nil, fmt.Errorf("%s: database is required", prefix)
|
||||
}
|
||||
if sql == "" {
|
||||
return nil, fmt.Errorf("%s: sql is required", prefix)
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 90*time.Second)
|
||||
defer cancel()
|
||||
r, err := pg.ReadOnlyQuery(ctx, database, sql)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return map[string]any{"database": database, "command": r.Command, "rows": r.Maps()}, nil
|
||||
}}
|
||||
}
|
||||
|
||||
// Tools are postgres's own and the seat's verbs.
|
||||
func Tools(pg *Client) []stdio.Tool {
|
||||
return []stdio.Tool{
|
||||
listTool(pg, "postgres_list_databases", "List the databases on the postgres server, with their on-disk size."),
|
||||
queryTool(pg, "postgres_query", "postgres_query",
|
||||
"Run a read-only SQL query against a named database, as a login that can read every table and change nothing."),
|
||||
{
|
||||
Name: "postgres_retire_database",
|
||||
Description: "Take one database out of service on purpose: rename it to <name>_deleted_<date> and lock its owner's login. " +
|
||||
"Nothing is dropped — the data stays on the server under the new name until a person removes it by hand. " +
|
||||
"Repeat the database's name in confirm.",
|
||||
Input: map[string]any{
|
||||
"database": map[string]any{"type": "string", "description": "the database to retire"},
|
||||
"confirm": map[string]any{"type": "string", "description": "the same name again, to say this is meant"},
|
||||
},
|
||||
Run: func(args map[string]any) (any, error) {
|
||||
database := str(args, "database")
|
||||
if database == "" {
|
||||
return nil, errors.New("postgres_retire_database: database is required")
|
||||
}
|
||||
if str(args, "confirm") != database {
|
||||
return nil, errors.New("postgres_retire_database: confirm must repeat the database's name")
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||
defer cancel()
|
||||
aside, err := pg.RetireDatabase(ctx, database, time.Now())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return map[string]any{"database": database, "renamedTo": aside, "dropped": false}, nil
|
||||
},
|
||||
},
|
||||
listTool(pg, Seat+".databases", "Every database the store holds, with its on-disk size."),
|
||||
queryTool(pg, Seat+".query", "query", "One read-only statement against one database the store holds."),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user