package runtime_test import ( "context" "errors" "fmt" "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) } }