Files
amcs/internal/store/project_personas.go
T
warkanum c179e014ad
CI / build-and-test (push) Failing after 1m52s
feat(db): add project personas and skills tables
* Introduce project_personas table with foreign keys to projects and agent_personas
* Add project_skills table with foreign key to projects and agent_skills
* Include override boolean field in agent_persona_skills and project_skills
* Update schema and migration files to reflect new tables and fields
* Enhance CORS handling to reflect request origin
2026-07-04 23:45:51 +02:00

100 lines
3.3 KiB
Go

package store
import (
"context"
"fmt"
"github.com/jackc/pgx/v5"
ext "git.warky.dev/wdevs/amcs/internal/types"
)
func (db *DB) AddProjectPersona(ctx context.Context, projectID, personaID int64, isDefault bool) error {
tx, err := db.pool.Begin(ctx)
if err != nil {
return fmt.Errorf("begin add project persona: %w", err)
}
defer func() { _ = tx.Rollback(ctx) }()
if _, err := tx.Exec(ctx, `select pg_advisory_xact_lock($1)`, projectID); err != nil {
return fmt.Errorf("lock project persona defaults: %w", err)
}
if isDefault {
if _, err := tx.Exec(ctx, `update project_personas set is_default = false where project_id = $1`, projectID); err != nil {
return fmt.Errorf("clear default project persona: %w", err)
}
}
if _, err := tx.Exec(ctx, `
insert into project_personas (project_id, persona_id, is_default)
values ($1, $2, $3)
on conflict (project_id, persona_id) do update set is_default = excluded.is_default
`, projectID, personaID, isDefault); err != nil {
return fmt.Errorf("add project persona: %w", err)
}
if err := tx.Commit(ctx); err != nil {
return fmt.Errorf("commit add project persona: %w", err)
}
return nil
}
func (db *DB) RemoveProjectPersona(ctx context.Context, projectID, personaID int64) error {
tag, err := db.pool.Exec(ctx, `delete from project_personas where project_id = $1 and persona_id = $2`, projectID, personaID)
if err != nil {
return fmt.Errorf("remove project persona: %w", err)
}
if tag.RowsAffected() == 0 {
return fmt.Errorf("project persona link not found")
}
return nil
}
func (db *DB) ListProjectPersonas(ctx context.Context, projectID int64) ([]ext.ProjectPersona, error) {
rows, err := db.pool.Query(ctx, `
select p.id, p.guid, p.name, p.description, p.summary, p.detail,
p.compiled_summary, p.compiled_detail, p.compiled_at, p.tags::text[],
p.created_at, p.updated_at, pp.is_default
from agent_personas p
join project_personas pp on pp.persona_id = p.id
where pp.project_id = $1
order by pp.is_default desc, p.name
`, projectID)
if err != nil {
return nil, fmt.Errorf("list project personas: %w", err)
}
defer rows.Close()
var result []ext.ProjectPersona
for rows.Next() {
var item ext.ProjectPersona
var tags []string
if err := rows.Scan(&item.Persona.ID, &item.Persona.GUID, &item.Persona.Name,
&item.Persona.Description, &item.Persona.Summary, &item.Persona.Detail,
&item.Persona.CompiledSummary, &item.Persona.CompiledDetail, &item.Persona.CompiledAt,
&tags, &item.Persona.CreatedAt, &item.Persona.UpdatedAt, &item.IsDefault); err != nil {
return nil, fmt.Errorf("scan project persona: %w", err)
}
item.Persona.Tags = nilToEmptyStrings(tags)
result = append(result, item)
}
return result, rows.Err()
}
func (db *DB) GetDefaultProjectPersona(ctx context.Context, projectID int64) (*ext.Persona, error) {
row := db.pool.QueryRow(ctx, `
select p.id, p.guid, p.name, p.description, p.summary, p.detail,
p.compiled_summary, p.compiled_detail, p.compiled_at, p.tags::text[],
p.created_at, p.updated_at
from agent_personas p
join project_personas pp on pp.persona_id = p.id
where pp.project_id = $1 and pp.is_default
`, projectID)
persona, err := scanPersona(row)
if err == pgx.ErrNoRows {
return nil, nil
}
if err != nil {
return nil, fmt.Errorf("get default project persona: %w", err)
}
return &persona, nil
}