package controller import ( "github.com/gin-gonic/gin" "github.com/heicode/manager/common" ) // AgentRoleTemplate is the platform-recommended role catalog Manager // surfaces to users when they assemble an AI development team. The // six canonical roles come from docs/product-package/13-platform- // description.md §3 and 04-platform-usage-guide.md §第五步. // // Why constants, not a DB table: // - Roles are platform-defined contracts, not user-editable data. // Treating them like rows would invite drift between deployments. // - Permission hints below are *recommendations* the UI uses to // pre-fill the "what can this Agent do" confirmation card — // the actual permission grant still goes through ResourceGrant. // - If we ever need per-tenant role customization, we add an // overlay table; the canonical set still lives here as the // baseline. // // Wire-format note: keys (key column) are stable identifiers used // across persistence and the client picker. Display strings can // be translated, but the key must NEVER change without a coordinated // frontend rollout. type AgentRoleTemplate struct { Key string `json:"key"` DisplayName string `json:"display_name"` Summary string `json:"summary"` DefaultModel string `json:"default_model"` DefaultPermissions []string `json:"default_permissions"` RiskLevel string `json:"risk_level"` } // defaultAgentModelID is the single source of truth for the default sub-agent // model. It is aligned to the production-verified NewAPI model and overridable // via AGENT_DEFAULT_MODEL_ID, so role templates, deployment drafts and runtime // agent refs never fall back to placeholder names (e.g. agent-model-) // that production NewAPI cannot route ("No available channel for model ..."). func defaultAgentModelID() string { return common.GetEnvOrDefaultString("AGENT_DEFAULT_MODEL_ID", "gpt-5.4") } // agentRoleTemplates returns the canonical six-role catalog. Order // matches the typical lifecycle a user walks through when assembling // a team: discover -> design -> build -> review -> operate. // // Permission hints use the verbs from docs §13.3.4 (Resource Grant) // and stay deliberately broad — concrete grants come from the user // resource-binding flow. func agentRoleTemplates() []AgentRoleTemplate { return []AgentRoleTemplate{ { Key: "product", DisplayName: "Product Agent", Summary: "Refines the user idea into product scope, requirements and acceptance criteria.", DefaultModel: defaultAgentModelID(), DefaultPermissions: []string{ "read:project_docs", "write:product_spec", }, RiskLevel: agentRiskLow, }, { Key: "architect", DisplayName: "Architect Agent", Summary: "Designs the technical approach, picks frameworks, and breaks work into sub-tasks.", DefaultModel: defaultAgentModelID(), DefaultPermissions: []string{ "read:repo", "write:architecture_doc", }, RiskLevel: agentRiskLow, }, { Key: "frontend", DisplayName: "Frontend Agent", Summary: "Implements UI, components and client-side state per the architect's plan.", DefaultModel: defaultAgentModelID(), DefaultPermissions: []string{ "read:repo", "write:repo:frontend", }, RiskLevel: agentRiskMedium, }, { Key: "backend", DisplayName: "Backend Agent", Summary: "Implements server-side APIs, data models and integrations.", DefaultModel: defaultAgentModelID(), DefaultPermissions: []string{ "read:repo", "write:repo:backend", "read:dev_database", }, RiskLevel: agentRiskMedium, }, { Key: "reviewer", DisplayName: "Reviewer Agent", Summary: "Performs code review, security checks and runs the test suite.", DefaultModel: defaultAgentModelID(), DefaultPermissions: []string{ "read:repo", "run:tests", "comment:pull_request", }, RiskLevel: agentRiskLow, }, { Key: "ops", DisplayName: "Ops Agent", Summary: "Deploys to test environments, watches logs and prepares production rollouts (production requires approval).", DefaultModel: defaultAgentModelID(), DefaultPermissions: []string{ "read:repo", "deploy:test_env", "read:metrics", "approval_required:deploy_prod", }, RiskLevel: agentRiskHigh, }, } } // AgentListRoleTemplates is the GET /api/agent/role-templates handler. // Returns the canonical six-role catalog so the deployment-creation // UI can pre-populate role pickers and the documentation page can // render the role overview. // // Auth: requires UserAuth (mounted by router). Anyone logged in to // Manager can read the catalog; there are no secrets in the payload. func AgentListRoleTemplates(c *gin.Context) { tpls := agentRoleTemplates() common.ApiSuccess(c, gin.H{ "items": tpls, "total": len(tpls), }) } // agentRoleTemplateKeys is a helper for validation in deployment // creation — checks whether a user-provided role_template string is // one of the canonical six. Returns true for any of the canonical // keys; returns true for unknown keys too (deployment flow today // accepts free-form role_template strings, see agent_control_plane. // go:552), so this helper is currently advisory. When we tighten // validation (after frontend ships the new picker), flip the // fallback to false and add a unit test. func agentRoleTemplateKeys() map[string]bool { keys := make(map[string]bool) for _, t := range agentRoleTemplates() { keys[t.Key] = true } return keys } // agentIsCanonicalRoleKey reports whether `key` matches one of the // six platform-defined roles. Today the deployment endpoint accepts // any non-empty string; this helper is reserved for the next step // when we move to a closed set. func agentIsCanonicalRoleKey(key string) bool { return agentRoleTemplateKeys()[key] }