Files
krow_backend/go-api/internal/runtime/runtime_test.go
2026-08-28 12:21:44 +05:30

1035 lines
29 KiB
Go

package runtime_test
import (
"context"
"errors"
"fmt"
"strings"
"testing"
"github.com/krow/krow-backend/go-api/internal/authctx"
"github.com/krow/krow-backend/go-api/internal/repo"
"github.com/krow/krow-backend/go-api/internal/runtime"
"github.com/krow/krow-backend/go-api/internal/testutil"
)
type fixture struct {
h *testutil.Harness
loader *runtime.Loader
engine *runtime.Engine
defRepo *repo.DefinitionsRepo
org1 string
org2 string
userA authctx.Identity
userB authctx.Identity
userOther authctx.Identity
}
func newFixture(t *testing.T) *fixture {
t.Helper()
h := testutil.New(t)
ctx := context.Background()
var org2 string
if err := h.Pool.QueryRow(ctx,
`INSERT INTO organizations (name, slug) VALUES ('Second Org', 'second-org') RETURNING id::text`).
Scan(&org2); err != nil {
t.Fatalf("create second org: %v", err)
}
var userAID, userBID, userOtherID string
if err := h.Pool.QueryRow(ctx,
`INSERT INTO users (org_id, full_name, email, role, status) VALUES ($1::uuid, 'User A', 'user-a@example.test', 'admin', 'active') RETURNING id::text`,
h.OrgID).Scan(&userAID); err != nil {
t.Fatalf("create userA: %v", err)
}
if err := h.Pool.QueryRow(ctx,
`INSERT INTO users (org_id, full_name, email, role, status) VALUES ($1::uuid, 'User B', 'user-b@example.test', 'talent', 'active') RETURNING id::text`,
h.OrgID).Scan(&userBID); err != nil {
t.Fatalf("create userB: %v", err)
}
if err := h.Pool.QueryRow(ctx,
`INSERT INTO users (org_id, full_name, email, role, status) VALUES ($1::uuid, 'User Other', 'user-other@example.test', 'admin', 'active') RETURNING id::text`,
org2).Scan(&userOtherID); err != nil {
t.Fatalf("create userOther: %v", err)
}
f := &fixture{
h: h,
loader: runtime.NewLoader(h.Pool),
engine: runtime.NewEngine(h.Pool),
defRepo: repo.NewDefinitionsRepo(h.Pool),
org1: h.OrgID,
org2: org2,
userA: authctx.Identity{
UserID: userAID,
OrgID: h.OrgID,
Role: "admin",
Email: "user-a@example.test",
},
userB: authctx.Identity{
UserID: userBID,
OrgID: h.OrgID,
Role: "talent",
Email: "user-b@example.test",
},
userOther: authctx.Identity{
UserID: userOtherID,
OrgID: org2,
Role: "admin",
Email: "user-other@example.test",
},
}
return f
}
/* ── 1. Loader Tests ──────────────────────────────────────────────────────── */
func TestRuntimeLoader_Agent(t *testing.T) {
f := newFixture(t)
ctx := context.Background()
// 1. Published org agent
agentMD := `---
id: talent-scout
name: Talent Scout
description: Discovers matching candidates
status: published
version: 2
pages:
- candidates
icon: sparkles
reasoning: deep
trigger: manual
webSearch: true
skills:
- resume-evaluator
subagents:
- profile-enricher
---
## Instructions
Review candidate profiles with diligence.
`
rec, err := f.defRepo.InsertAgent(ctx, f.userA, repo.AgentInsertInput{
DefinitionID: "talent-scout",
OrgID: f.org1,
Visibility: "organization",
CreatedBy: &f.userA.UserID,
Markdown: agentMD,
Status: "published",
Version: 2,
Name: "Talent Scout",
Description: "Discovers matching candidates",
Pages: []string{"candidates"},
})
if err != nil {
t.Fatalf("insert agent: %v", err)
}
dbUUID := rec["id"].(string)
// Load by definition_id
agentByDefID, err := f.loader.LoadAgent(ctx, f.userB, "talent-scout")
if err != nil {
t.Fatalf("load agent by definition_id: %v", err)
}
if agentByDefID.ID != "talent-scout" || agentByDefID.DatabaseID != dbUUID {
t.Errorf("agent ID mismatch: %+v", agentByDefID)
}
if agentByDefID.Name != "Talent Scout" || agentByDefID.Version != 2 || agentByDefID.Status != "published" {
t.Errorf("agent fields mismatch: %+v", agentByDefID)
}
if agentByDefID.Icon != "sparkles" || agentByDefID.Reasoning != "deep" || !agentByDefID.WebSearch {
t.Errorf("agent config mismatch: %+v", agentByDefID)
}
if len(agentByDefID.Skills) != 1 || agentByDefID.Skills[0] != "resume-evaluator" {
t.Errorf("agent skills mismatch: %v", agentByDefID.Skills)
}
if agentByDefID.Instructions == "" || agentByDefID.RawMarkdown != agentMD {
t.Errorf("agent markdown/instructions mismatch")
}
// Load by UUID
agentByUUID, err := f.loader.LoadAgent(ctx, f.userA, dbUUID)
if err != nil {
t.Fatalf("load agent by UUID: %v", err)
}
if agentByUUID.ID != "talent-scout" {
t.Errorf("agent by UUID ID mismatch: %+v", agentByUUID)
}
// Personal agent for User B
persMD := `---
id: personal-agent
name: Personal Agent
status: draft
version: 1
pages:
- candidates
---
## Instructions
Personal instructions.
`
persRec, err := f.defRepo.InsertAgent(ctx, f.userB, repo.AgentInsertInput{
DefinitionID: "personal-agent",
OrgID: f.org1,
Visibility: "personal",
OwnerUserID: &f.userB.UserID,
CreatedBy: &f.userB.UserID,
Markdown: persMD,
Status: "draft",
Version: 1,
Name: "Personal Agent",
Pages: []string{"candidates"},
})
if err != nil {
t.Fatalf("insert personal agent: %v", err)
}
persUUID := persRec["id"].(string)
// Owner (User B) can load personal agent
persAgent, err := f.loader.LoadAgent(ctx, f.userB, "personal-agent")
if err != nil {
t.Fatalf("load own personal agent: %v", err)
}
if persAgent.DatabaseID != persUUID {
t.Errorf("personal agent uuid mismatch: %s != %s", persAgent.DatabaseID, persUUID)
}
// Other user in same org (User A) CANNOT load User B's personal agent -> ErrNotFound
_, err = f.loader.LoadAgent(ctx, f.userA, "personal-agent")
if !errors.Is(err, runtime.ErrNotFound) {
t.Errorf("userA loading userB personal agent: got error %v, want ErrNotFound", err)
}
// Outsider CANNOT load org agent from org 1 -> ErrNotFound
_, err = f.loader.LoadAgent(ctx, f.userOther, "talent-scout")
if !errors.Is(err, runtime.ErrNotFound) {
t.Errorf("outsider loading org1 agent: got error %v, want ErrNotFound", err)
}
// Missing agent -> ErrNotFound
_, err = f.loader.LoadAgent(ctx, f.userA, "nonexistent-agent")
if !errors.Is(err, runtime.ErrNotFound) {
t.Errorf("load nonexistent agent: got %v, want ErrNotFound", err)
}
}
func TestRuntimeLoader_Skill(t *testing.T) {
f := newFixture(t)
ctx := context.Background()
skillMD := `---
id: resume-evaluator
name: Resume Evaluator
description: Evaluates candidate resume text
status: active
pages:
- candidates
category: screening
actions:
- score
- summarize
triggers:
- resume
- cv
prompt: Evaluate the candidate resume thoroughly.
---
# Resume Evaluator Body
Detailed skill instructions.
`
rec, err := f.defRepo.InsertSkill(ctx, f.userA, repo.SkillInsertInput{
DefinitionID: "resume-evaluator",
OrgID: f.org1,
Visibility: "organization",
CreatedBy: &f.userA.UserID,
Markdown: skillMD,
Status: "active",
Name: "Resume Evaluator",
Description: "Evaluates candidate resume text",
Pages: []string{"candidates"},
})
if err != nil {
t.Fatalf("insert skill: %v", err)
}
skillUUID := rec["id"].(string)
// Load by definition_id
skillByDefID, err := f.loader.LoadSkill(ctx, f.userB, "resume-evaluator")
if err != nil {
t.Fatalf("load skill by definition_id: %v", err)
}
if skillByDefID.ID != "resume-evaluator" || skillByDefID.DatabaseID != skillUUID {
t.Errorf("skill ID mismatch: %+v", skillByDefID)
}
if skillByDefID.Name != "Resume Evaluator" || skillByDefID.Status != "active" {
t.Errorf("skill fields mismatch: %+v", skillByDefID)
}
if skillByDefID.Category != "screening" || len(skillByDefID.Actions) != 2 || len(skillByDefID.Triggers) != 2 {
t.Errorf("skill actions/triggers mismatch: %+v", skillByDefID)
}
if skillByDefID.Prompt == nil || *skillByDefID.Prompt != "Evaluate the candidate resume thoroughly." {
t.Errorf("skill prompt mismatch: %v", skillByDefID.Prompt)
}
if skillByDefID.RawMarkdown != skillMD {
t.Errorf("skill raw markdown not verbatim")
}
// Load by UUID
skillByUUID, err := f.loader.LoadSkill(ctx, f.userA, skillUUID)
if err != nil {
t.Fatalf("load skill by UUID: %v", err)
}
if skillByUUID.ID != "resume-evaluator" {
t.Errorf("skill by UUID mismatch: %+v", skillByUUID)
}
// Missing skill -> ErrNotFound
_, err = f.loader.LoadSkill(ctx, f.userA, "nonexistent-skill")
if !errors.Is(err, runtime.ErrNotFound) {
t.Errorf("missing skill: got %v, want ErrNotFound", err)
}
// Cross-org skill -> ErrNotFound
_, err = f.loader.LoadSkill(ctx, f.userOther, "resume-evaluator")
if !errors.Is(err, runtime.ErrNotFound) {
t.Errorf("cross-org skill: got %v, want ErrNotFound", err)
}
}
/* ── 2. Status Eligibility Tests ─────────────────────────────────────────── */
func TestRuntime_StatusEligibility(t *testing.T) {
f := newFixture(t)
ctx := context.Background()
// 1. Draft Agent
draftMD := `---
id: draft-agent
name: Draft Agent
status: draft
version: 1
pages:
- candidates
---
`
_, _ = f.defRepo.InsertAgent(ctx, f.userA, repo.AgentInsertInput{
DefinitionID: "draft-agent",
OrgID: f.org1,
Visibility: "organization",
CreatedBy: &f.userA.UserID,
Markdown: draftMD,
Status: "draft",
Version: 1,
Name: "Draft Agent",
Pages: []string{"candidates"},
})
_, err := f.loader.LoadExecutableAgent(ctx, f.userA, "draft-agent")
if !errors.Is(err, runtime.ErrDraftAgent) {
t.Errorf("draft agent: got %v, want ErrDraftAgent", err)
}
// 2. Archived Agent
archivedMD := `---
id: archived-agent
name: Archived Agent
status: archived
version: 1
pages:
- candidates
---
`
_, _ = f.defRepo.InsertAgent(ctx, f.userA, repo.AgentInsertInput{
DefinitionID: "archived-agent",
OrgID: f.org1,
Visibility: "organization",
CreatedBy: &f.userA.UserID,
Markdown: archivedMD,
Status: "archived",
Version: 1,
Name: "Archived Agent",
Pages: []string{"candidates"},
})
_, err = f.loader.LoadExecutableAgent(ctx, f.userA, "archived-agent")
if !errors.Is(err, runtime.ErrArchivedAgent) {
t.Errorf("archived agent: got %v, want ErrArchivedAgent", err)
}
// 3. Published Agent without dependencies -> Success
pubMD := `---
id: published-agent
name: Published Agent
status: published
version: 1
pages:
- candidates
---
`
_, _ = f.defRepo.InsertAgent(ctx, f.userA, repo.AgentInsertInput{
DefinitionID: "published-agent",
OrgID: f.org1,
Visibility: "organization",
CreatedBy: &f.userA.UserID,
Markdown: pubMD,
Status: "published",
Version: 1,
Name: "Published Agent",
Pages: []string{"candidates"},
})
pubAgent, err := f.loader.LoadExecutableAgent(ctx, f.userA, "published-agent")
if err != nil {
t.Fatalf("load published agent: %v", err)
}
if pubAgent.Status != "published" {
t.Errorf("published agent status: %s", pubAgent.Status)
}
// 4. Inactive Skill
inactiveSkillMD := `---
id: inactive-skill
name: Inactive Skill
status: inactive
pages:
- candidates
---
`
_, _ = f.defRepo.InsertSkill(ctx, f.userA, repo.SkillInsertInput{
DefinitionID: "inactive-skill",
OrgID: f.org1,
Visibility: "organization",
CreatedBy: &f.userA.UserID,
Markdown: inactiveSkillMD,
Status: "inactive",
Name: "Inactive Skill",
Pages: []string{"candidates"},
})
_, err = f.loader.LoadExecutableSkill(ctx, f.userA, "inactive-skill")
if !errors.Is(err, runtime.ErrInactiveSkill) {
t.Errorf("inactive skill: got %v, want ErrInactiveSkill", err)
}
// 5. Active Skill -> Success
activeSkillMD := `---
id: active-skill
name: Active Skill
status: active
pages:
- candidates
---
`
_, _ = f.defRepo.InsertSkill(ctx, f.userA, repo.SkillInsertInput{
DefinitionID: "active-skill",
OrgID: f.org1,
Visibility: "organization",
CreatedBy: &f.userA.UserID,
Markdown: activeSkillMD,
Status: "active",
Name: "Active Skill",
Pages: []string{"candidates"},
})
activeSkill, err := f.loader.LoadExecutableSkill(ctx, f.userA, "active-skill")
if err != nil {
t.Fatalf("load active skill: %v", err)
}
if activeSkill.Status != "active" {
t.Errorf("active skill status: %s", activeSkill.Status)
}
}
/* ── 3. Version Semantics Tests ──────────────────────────────────────────── */
func TestRuntime_VersionSemantics(t *testing.T) {
f := newFixture(t)
ctx := context.Background()
v5MD := `---
id: v5-agent
name: Version 5 Agent
version: 5
status: published
pages:
- candidates
---
`
_, err := f.defRepo.InsertAgent(ctx, f.userA, repo.AgentInsertInput{
DefinitionID: "v5-agent",
OrgID: f.org1,
Visibility: "organization",
CreatedBy: &f.userA.UserID,
Markdown: v5MD,
Status: "published",
Version: 5,
Name: "Version 5 Agent",
Pages: []string{"candidates"},
})
if err != nil {
t.Fatalf("insert v5 agent: %v", err)
}
agent, err := f.loader.LoadAgent(ctx, f.userA, "v5-agent")
if err != nil {
t.Fatalf("load v5 agent: %v", err)
}
if agent.Version != 5 {
t.Errorf("agent version = %d, want 5", agent.Version)
}
}
/* ── 4. Dependency Resolution Tests ──────────────────────────────────────── */
func TestRuntime_DependencyResolution(t *testing.T) {
f := newFixture(t)
ctx := context.Background()
// 1. Create active skill 1
skill1MD := `---
id: skill-one
name: Skill One
status: active
pages:
- candidates
---
`
_, _ = f.defRepo.InsertSkill(ctx, f.userA, repo.SkillInsertInput{
DefinitionID: "skill-one",
OrgID: f.org1,
Visibility: "organization",
CreatedBy: &f.userA.UserID,
Markdown: skill1MD,
Status: "active",
Name: "Skill One",
Pages: []string{"candidates"},
})
// 2. Create active skill 2 (personal for userB)
skill2MD := `---
id: skill-two
name: Skill Two
status: active
pages:
- candidates
---
`
_, _ = f.defRepo.InsertSkill(ctx, f.userB, repo.SkillInsertInput{
DefinitionID: "skill-two",
OrgID: f.org1,
Visibility: "personal",
OwnerUserID: &f.userB.UserID,
CreatedBy: &f.userB.UserID,
Markdown: skill2MD,
Status: "active",
Name: "Skill Two",
Pages: []string{"candidates"},
})
// 3. Create inactive skill 3
skill3MD := `---
id: skill-inactive
name: Skill Inactive
status: inactive
pages:
- candidates
---
`
_, _ = f.defRepo.InsertSkill(ctx, f.userA, repo.SkillInsertInput{
DefinitionID: "skill-inactive",
OrgID: f.org1,
Visibility: "organization",
CreatedBy: &f.userA.UserID,
Markdown: skill3MD,
Status: "inactive",
Name: "Skill Inactive",
Pages: []string{"candidates"},
})
// Agent with valid and duplicate dependencies
validDepMD := `---
id: dep-agent
name: Dependency Agent
status: published
version: 1
pages:
- candidates
skills:
- skill-one
- skill-two
- skill-one
---
`
_, _ = f.defRepo.InsertAgent(ctx, f.userB, repo.AgentInsertInput{
DefinitionID: "dep-agent",
OrgID: f.org1,
Visibility: "personal",
OwnerUserID: &f.userB.UserID,
CreatedBy: &f.userB.UserID,
Markdown: validDepMD,
Status: "published",
Version: 1,
Name: "Dependency Agent",
Pages: []string{"candidates"},
})
// User B resolves dep-agent: sees skill-one (org) and skill-two (personal), deduplicates skill-one
loadedAgent, err := f.loader.LoadExecutableAgent(ctx, f.userB, "dep-agent")
if err != nil {
t.Fatalf("load executable agent with deps: %v", err)
}
if len(loadedAgent.ResolvedSkills) != 2 {
t.Fatalf("expected 2 resolved skills (deduplicated), got %d", len(loadedAgent.ResolvedSkills))
}
if loadedAgent.ResolvedSkills[0].ID != "skill-one" || loadedAgent.ResolvedSkills[1].ID != "skill-two" {
t.Errorf("resolved skill IDs mismatch: %v, %v", loadedAgent.ResolvedSkills[0].ID, loadedAgent.ResolvedSkills[1].ID)
}
// Agent with missing dependency
missingDepMD := `---
id: missing-dep-agent
name: Missing Dep Agent
status: published
version: 1
pages:
- candidates
skills:
- nonexistent-skill
---
`
_, _ = f.defRepo.InsertAgent(ctx, f.userA, repo.AgentInsertInput{
DefinitionID: "missing-dep-agent",
OrgID: f.org1,
Visibility: "organization",
CreatedBy: &f.userA.UserID,
Markdown: missingDepMD,
Status: "published",
Version: 1,
Name: "Missing Dep Agent",
Pages: []string{"candidates"},
})
_, err = f.loader.LoadExecutableAgent(ctx, f.userA, "missing-dep-agent")
if !errors.Is(err, runtime.ErrDependencyMissing) {
t.Errorf("missing dep agent: got %v, want ErrDependencyMissing", err)
}
// Agent with inactive dependency
inactiveDepMD := `---
id: inactive-dep-agent
name: Inactive Dep Agent
status: published
version: 1
pages:
- candidates
skills:
- skill-inactive
---
`
_, _ = f.defRepo.InsertAgent(ctx, f.userA, repo.AgentInsertInput{
DefinitionID: "inactive-dep-agent",
OrgID: f.org1,
Visibility: "organization",
CreatedBy: &f.userA.UserID,
Markdown: inactiveDepMD,
Status: "published",
Version: 1,
Name: "Inactive Dep Agent",
Pages: []string{"candidates"},
})
_, err = f.loader.LoadExecutableAgent(ctx, f.userA, "inactive-dep-agent")
if !errors.Is(err, runtime.ErrDependencyInactive) {
t.Errorf("inactive dep agent: got %v, want ErrDependencyInactive", err)
}
// Agent with cross-org dependency: outsider creates agent referencing org1's skill
outsiderAgentMD := `---
id: outsider-agent
name: Outsider Agent
status: published
version: 1
pages:
- candidates
skills:
- skill-one
---
`
_, _ = f.defRepo.InsertAgent(ctx, f.userOther, repo.AgentInsertInput{
DefinitionID: "outsider-agent",
OrgID: f.org2,
Visibility: "organization",
CreatedBy: &f.userOther.UserID,
Markdown: outsiderAgentMD,
Status: "published",
Version: 1,
Name: "Outsider Agent",
Pages: []string{"candidates"},
})
_, err = f.loader.LoadExecutableAgent(ctx, f.userOther, "outsider-agent")
if !errors.Is(err, runtime.ErrDependencyMissing) {
t.Errorf("outsider cross-org dep: got %v, want ErrDependencyMissing", err)
}
}
/* ── 5. Executor Boundary Tests ──────────────────────────────────────────── */
type testEchoExecutor struct {
lastAgent *runtime.Agent
lastInput runtime.ExecutionInput
}
func (e *testEchoExecutor) ExecuteAgent(_ context.Context, agent *runtime.Agent, input runtime.ExecutionInput) (*runtime.ExecutionResult, error) {
e.lastAgent = agent
e.lastInput = input
return &runtime.ExecutionResult{
Success: true,
Output: fmt.Sprintf("executed %s with %s", agent.Name, input.Input),
AgentID: agent.ID,
AgentVersion: agent.Version,
}, nil
}
func (e *testEchoExecutor) ExecuteSkill(_ context.Context, skill *runtime.Skill, input runtime.ExecutionInput) (*runtime.ExecutionResult, error) {
return &runtime.ExecutionResult{
Success: true,
Output: fmt.Sprintf("executed skill %s", skill.Name),
}, nil
}
func TestRuntime_ExecutorBoundary(t *testing.T) {
f := newFixture(t)
ctx := context.Background()
pubMD := `---
id: exec-agent
name: Exec Agent
status: published
version: 1
pages:
- candidates
---
`
_, _ = f.defRepo.InsertAgent(ctx, f.userA, repo.AgentInsertInput{
DefinitionID: "exec-agent",
OrgID: f.org1,
Visibility: "organization",
CreatedBy: &f.userA.UserID,
Markdown: pubMD,
Status: "published",
Version: 1,
Name: "Exec Agent",
Pages: []string{"candidates"},
})
// 1. Default engine without configured executor returns ErrExecutorUnavailable
res, err := f.engine.RunAgent(ctx, f.userA, "exec-agent", runtime.ExecutionInput{
Identity: f.userA,
Input: "Hello agent",
})
if !errors.Is(err, runtime.ErrExecutorUnavailable) {
t.Errorf("default engine run agent: got %v, want ErrExecutorUnavailable", err)
}
if res.Success {
t.Errorf("default engine must not succeed without executor")
}
// 2. Custom executor plugged in
echo := &testEchoExecutor{}
customEngine := runtime.NewEngine(f.h.Pool, runtime.WithAgentExecutor(echo), runtime.WithSkillExecutor(echo))
resCustom, err := customEngine.RunAgent(ctx, f.userA, "exec-agent", runtime.ExecutionInput{
Identity: f.userA,
Input: "Hello agent",
})
if err != nil {
t.Fatalf("custom engine run agent failed: %v", err)
}
if !resCustom.Success || resCustom.Output != "executed Exec Agent with Hello agent" {
t.Errorf("custom executor output mismatch: %+v", resCustom)
}
if echo.lastAgent.ID != "exec-agent" || echo.lastInput.Input != "Hello agent" {
t.Errorf("executor received incorrect arguments: agent=%v, input=%v", echo.lastAgent, echo.lastInput)
}
}
func TestRuntime_PersonalSkillShadowing(t *testing.T) {
f := newFixture(t)
ctx := context.Background()
// Org skill
orgSkillMD := `---
id: shadow-skill
name: Org Shadow Skill
status: active
pages:
- candidates
---
`
_, _ = f.defRepo.InsertSkill(ctx, f.userA, repo.SkillInsertInput{
DefinitionID: "shadow-skill",
OrgID: f.org1,
Visibility: "organization",
CreatedBy: &f.userA.UserID,
Markdown: orgSkillMD,
Status: "active",
Name: "Org Shadow Skill",
Pages: []string{"candidates"},
})
// User B's personal skill with the SAME definition_id
persSkillMD := `---
id: shadow-skill
name: User B Personal Shadow Skill
status: active
pages:
- candidates
---
`
persRec, _ := f.defRepo.InsertSkill(ctx, f.userB, repo.SkillInsertInput{
DefinitionID: "shadow-skill",
OrgID: f.org1,
Visibility: "personal",
OwnerUserID: &f.userB.UserID,
CreatedBy: &f.userB.UserID,
Markdown: persSkillMD,
Status: "active",
Name: "User B Personal Shadow Skill",
Pages: []string{"candidates"},
})
persUUID := persRec["id"].(string)
// When User A loads shadow-skill -> gets Org Shadow Skill
skillA, err := f.loader.LoadSkill(ctx, f.userA, "shadow-skill")
if err != nil {
t.Fatalf("userA load shadow skill: %v", err)
}
if skillA.Name != "Org Shadow Skill" {
t.Errorf("userA got %s, want Org Shadow Skill", skillA.Name)
}
// When User B loads shadow-skill -> gets User B Personal Shadow Skill (shadow precedence)
skillB, err := f.loader.LoadSkill(ctx, f.userB, "shadow-skill")
if err != nil {
t.Fatalf("userB load shadow skill: %v", err)
}
if skillB.Name != "User B Personal Shadow Skill" || skillB.DatabaseID != persUUID {
t.Errorf("userB got %s, want User B Personal Shadow Skill", skillB.Name)
}
}
func TestRuntime_MalformedMarkdown(t *testing.T) {
f := newFixture(t)
ctx := context.Background()
// Broken YAML
brokenMD := `---
id: [broken-id
name: Invalid
---
`
_, _ = f.h.Pool.Exec(ctx, `INSERT INTO agent_definitions (definition_id, org_id, visibility, created_by, markdown, status, version, name, description, pages)
VALUES ('broken-agent', $1::uuid, 'organization', $2::uuid, $3::text, 'published', 1, 'Broken', '', ARRAY['candidates'])`,
f.org1, f.userA.UserID, brokenMD)
_, err := f.loader.LoadAgent(ctx, f.userA, "broken-agent")
if !errors.Is(err, runtime.ErrInvalidDefinition) {
t.Errorf("load broken agent: got %v, want ErrInvalidDefinition", err)
}
}
func TestRuntime_SkillExecution(t *testing.T) {
f := newFixture(t)
ctx := context.Background()
skillMD := `---
id: run-skill
name: Runnable Skill
status: active
pages:
- candidates
---
`
_, _ = f.defRepo.InsertSkill(ctx, f.userA, repo.SkillInsertInput{
DefinitionID: "run-skill",
OrgID: f.org1,
Visibility: "organization",
CreatedBy: &f.userA.UserID,
Markdown: skillMD,
Status: "active",
Name: "Runnable Skill",
Pages: []string{"candidates"},
})
// Default engine
res, err := f.engine.RunSkill(ctx, f.userA, "run-skill", runtime.ExecutionInput{
Identity: f.userA,
Input: "skill input",
})
if !errors.Is(err, runtime.ErrExecutorUnavailable) {
t.Errorf("default engine run skill: got %v, want ErrExecutorUnavailable", err)
}
if res.Success {
t.Errorf("default engine run skill must not succeed")
}
// Custom executor
echo := &testEchoExecutor{}
customEngine := runtime.NewEngine(f.h.Pool, runtime.WithSkillExecutor(echo))
resCustom, err := customEngine.RunSkill(ctx, f.userA, "run-skill", runtime.ExecutionInput{
Identity: f.userA,
})
if err != nil {
t.Fatalf("custom engine run skill failed: %v", err)
}
if !resCustom.Success || resCustom.Output != "executed skill Runnable Skill" {
t.Errorf("custom skill output mismatch: %+v", resCustom)
}
}
/* ── Pinned versions ────────────────────────────────────────────────────── */
// TestAPinnedRunUsesTheAgentAsItWas.
//
// §3: "Running conversations pin the version they started with."
//
// The reason this matters is not tidiness. A person approves a write while
// looking at version 1; somebody publishes version 2 with different
// instructions and a different tool list; the approval is then carried out. If
// the run silently moved to version 2, the thing performed would not be the
// thing that was shown — which is the failure the whole confirmation mechanism
// exists to prevent, arriving through the registry instead of through the gate.
func TestAPinnedRunUsesTheAgentAsItWas(t *testing.T) {
f := newFixture(t)
ctx := context.Background()
v1 := `---
id: pinned-agent
name: Pinned Agent
status: published
version: 1
pages:
- activity
tools:
- activity_breakdown
---
## Instructions
Version one instructions.
`
v2 := `---
id: pinned-agent
name: Pinned Agent
status: published
version: 2
pages:
- activity
tools:
- activity_breakdown
- activity_signals
---
## Instructions
Version two instructions.
`
if _, err := f.h.Pool.Exec(ctx, `
INSERT INTO agent_definitions (definition_id, org_id, visibility, created_by,
markdown, status, version, name, description, pages)
VALUES ('pinned-agent', $1::uuid, 'organization', $2::uuid, $3::text,
'published', 2, 'Pinned Agent', '', ARRAY['activity'])`,
f.org1, f.userA.UserID, v2); err != nil {
t.Fatalf("seed current definition: %v", err)
}
versions := repo.NewVersionsRepo(f.h.Pool)
for _, s := range []repo.SnapshotInput{
{Kind: repo.KindAgent, DefinitionID: "pinned-agent", Version: 1, Markdown: v1, Name: "Pinned Agent"},
{Kind: repo.KindAgent, DefinitionID: "pinned-agent", Version: 2, Markdown: v2, Name: "Pinned Agent"},
} {
if err := versions.Snapshot(ctx, f.userA, s); err != nil {
t.Fatalf("snapshot v%d: %v", s.Version, err)
}
}
// Unpinned: the current definition, which is version 2.
current, fellBack, err := f.loader.LoadAgentVersion(ctx, f.userA, "pinned-agent", 0)
if err != nil {
t.Fatalf("load current: %v", err)
}
if fellBack {
t.Error("an unpinned load reported a fallback")
}
if current.Version != 2 || !strings.Contains(current.Instructions, "Version two") {
t.Errorf("current is v%d: %q", current.Version, current.Instructions)
}
if len(current.Tools) != 2 {
t.Errorf("v2 should carry 2 tools, got %v", current.Tools)
}
// Pinned to 1: the agent as it was, INCLUDING its narrower tool list. That
// last part is the one that would let an approved write reach a tool the
// approver's version never offered.
pinned, fellBack, err := f.loader.LoadAgentVersion(ctx, f.userA, "pinned-agent", 1)
if err != nil {
t.Fatalf("load v1: %v", err)
}
if fellBack {
t.Error("a version that exists reported a fallback")
}
if pinned.Version != 1 {
t.Errorf("pinned version = %d, want 1", pinned.Version)
}
if !strings.Contains(pinned.Instructions, "Version one") {
t.Errorf("pinned instructions are v2's: %q", pinned.Instructions)
}
if len(pinned.Tools) != 1 || pinned.Tools[0] != "activity_breakdown" {
t.Errorf("pinned tools are %v; v1 offered only activity_breakdown", pinned.Tools)
}
}
func TestAVersionWithNoSnapshotFallsBackAndSaysSo(t *testing.T) {
// Every definition published before versions were recorded has no snapshot.
// Refusing those would break every conversation that predates the feature,
// to enforce a rule they could not have followed. The run continues on the
// current definition and the fallback is REPORTED, because a silent
// substitution is the thing worth preventing.
f := newFixture(t)
ctx := context.Background()
md := `---
id: unversioned-agent
name: Unversioned
status: published
version: 1
pages:
- activity
---
## Instructions
Only ever existed as one thing.
`
if _, err := f.h.Pool.Exec(ctx, `
INSERT INTO agent_definitions (definition_id, org_id, visibility, created_by,
markdown, status, version, name, description, pages)
VALUES ('unversioned-agent', $1::uuid, 'organization', $2::uuid, $3::text,
'published', 1, 'Unversioned', '', ARRAY['activity'])`,
f.org1, f.userA.UserID, md); err != nil {
t.Fatalf("seed: %v", err)
}
agent, fellBack, err := f.loader.LoadAgentVersion(ctx, f.userA, "unversioned-agent", 7)
if err != nil {
t.Fatalf("a missing snapshot failed the load: %v", err)
}
if !fellBack {
t.Error("a version with no snapshot did not report a fallback")
}
if agent == nil || agent.Version != 1 {
t.Errorf("the fallback did not return the current definition: %+v", agent)
}
}