Files
heicode-mananger/heicode/controller/agent_role_template.go
T
chenchenandClaude Opus 4.8 0fe1d20d67 feat(agent): unify agnet→agent and implement client/runtime unification spec v0.1 core
按桌面客户端统一方案 v0.1 + agent_management Sub Mode Runtime 对接,强制全量统一,不留兼容。

命名统一(强制,无兼容):
- 全仓 agnet/Agnet/AGNET → agent/Agent/AGENT:后端 Go(路由 /api/agent/*、env AGENT_*、
  结构体/函数、19 个文件改名)、前端(agent-console/agent-hub、/api/agent 调用、i18n)、
  DB(表 agent_*、列 agent_id)、compose/.env、文档、脚本。
- DB 加幂等迁移 renameAgnetTablesToAgent():启动时 rename 老 agnet_* 表/列,保住生产数据。

统一方案核心(10 项):
- callback 统一 /api/agent/callbacks/runtime-events(路由/广播URL/函数名)。
- artifact 兜底判定改用 Runtime 权威信号 metadata.synthesized(§7.2)+ 结构化 artifact_type。
- Manager→Runtime 路径对齐 /api/agent/sub-agile/deployments(§2.2),{deployment_id} 回退 swarm_id。
- 状态裁决 display_status:Manager 唯一裁判,completed 无有效产物→needs_codegen/
  completed_without_deliverable(§10.6),接入 detail/timeline/workflow。
- GET /api/heicode/capabilities 能力发现(§6)。
- 模型策略 per_role(role_models)+ 收集 allowed_model_ids(§9)。
- resource_binding_id→secret_ref 服务端解析,客户端不再 inline secret_ref(§17.6)。
- 客户端统一路由层 /api/heicode/sub-agile|swarm/*(task≡deployment,复用控制面)+ workflow 投影。
- 日志分层 user_logs/debug_logs(§13)。

验证:go build ./... + go test(controller/router/model/middleware)全绿;前端 tsc -b + rsbuild build 通过。
待部署:VM .env 的 AGNET_*→AGENT_*;启动迁移自动 rename 表;其他三仓库需同步切到 /api/agent。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 23:45:10 +08:00

165 lines
5.8 KiB
Go

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-<role>)
// 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]
}