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>
This commit is contained in:
2026-06-01 23:45:10 +08:00
co-authored by Claude Opus 4.8
parent 12602ebcd6
commit 0fe1d20d67
112 changed files with 4305 additions and 3139 deletions
@@ -21,7 +21,7 @@ import (
"gorm.io/gorm"
)
func setupAgnetRuntimeHTTPSmokeDB(t *testing.T) *gorm.DB {
func setupAgentRuntimeHTTPSmokeDB(t *testing.T) *gorm.DB {
t.Helper()
common.UsingSQLite = true
common.UsingMySQL = false
@@ -35,8 +35,8 @@ func setupAgnetRuntimeHTTPSmokeDB(t *testing.T) *gorm.DB {
model.LOG_DB = db
require.NoError(t, db.AutoMigrate(
&model.User{},
&model.AgnetDeployment{},
&model.AgnetAuditEvent{},
&model.AgentDeployment{},
&model.AgentAuditEvent{},
))
adminToken := "runtime-smoke-admin-token"
require.NoError(t, db.Create(&model.User{
@@ -64,7 +64,7 @@ func setupAgnetRuntimeHTTPSmokeDB(t *testing.T) *gorm.DB {
return db
}
func startAgnetRuntimeManagerSmokeServer(t *testing.T) string {
func startAgentRuntimeManagerSmokeServer(t *testing.T) string {
t.Helper()
gin.SetMode(gin.TestMode)
engine := gin.New()
@@ -82,7 +82,7 @@ func startAgnetRuntimeManagerSmokeServer(t *testing.T) string {
return "http://" + listener.Addr().String()
}
func agnetRuntimeAdminRequest(t *testing.T, method string, url string, body string) *http.Response {
func agentRuntimeAdminRequest(t *testing.T, method string, url string, body string) *http.Response {
t.Helper()
req, err := http.NewRequest(method, url, bytes.NewBufferString(body))
require.NoError(t, err)
@@ -96,7 +96,7 @@ func agnetRuntimeAdminRequest(t *testing.T, method string, url string, body stri
return resp
}
func readAgnetRuntimeSmokeBody(t *testing.T, resp *http.Response) string {
func readAgentRuntimeSmokeBody(t *testing.T, resp *http.Response) string {
t.Helper()
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
@@ -104,16 +104,16 @@ func readAgnetRuntimeSmokeBody(t *testing.T, resp *http.Response) string {
return string(body)
}
func TestAgnetRuntimeRealHTTPHealthAndShadowCreateSmoke(t *testing.T) {
db := setupAgnetRuntimeHTTPSmokeDB(t)
func TestAgentRuntimeRealHTTPHealthAndShadowCreateSmoke(t *testing.T) {
db := setupAgentRuntimeHTTPSmokeDB(t)
runtimeCreateCalled := false
runtime := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch {
case r.Method == http.MethodGet && r.URL.Path == "/api/agnet/health":
case r.Method == http.MethodGet && r.URL.Path == "/api/agent/health":
require.Equal(t, "Bearer runtime-service-token", r.Header.Get("Authorization"))
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"success":true,"data":{"status":"healthy"}}`))
case r.Method == http.MethodPost && r.URL.Path == "/api/agnet/deployments":
case r.Method == http.MethodPost && r.URL.Path == "/api/agent/sub-agile/deployments":
runtimeCreateCalled = true
require.Equal(t, "Bearer runtime-service-token", r.Header.Get("Authorization"))
require.Equal(t, "corr-http-smoke", r.Header.Get("X-Correlation-ID"))
@@ -142,23 +142,23 @@ func TestAgnetRuntimeRealHTTPHealthAndShadowCreateSmoke(t *testing.T) {
}))
defer runtime.Close()
t.Setenv("AGNET_RUNTIME_ENABLED", "true")
t.Setenv("AGNET_RUNTIME_ASYNC", "false")
t.Setenv("AGNET_RUNTIME_BASE_URL", runtime.URL)
t.Setenv("AGNET_RUNTIME_SERVICE_TOKEN", "runtime-service-token")
t.Setenv("AGNET_RUNTIME_CALLBACK_SIGNING_SECRET_REF", "azkv://heicode-kv.vault.azure.net/secrets/callback-signing")
t.Setenv("AGENT_RUNTIME_ENABLED", "true")
t.Setenv("AGENT_RUNTIME_ASYNC", "false")
t.Setenv("AGENT_RUNTIME_BASE_URL", runtime.URL)
t.Setenv("AGENT_RUNTIME_SERVICE_TOKEN", "runtime-service-token")
t.Setenv("AGENT_RUNTIME_CALLBACK_SIGNING_SECRET_REF", "azkv://heicode-kv.vault.azure.net/secrets/callback-signing")
managerURL := startAgnetRuntimeManagerSmokeServer(t)
managerURL := startAgentRuntimeManagerSmokeServer(t)
healthResp := agnetRuntimeAdminRequest(t, http.MethodGet, managerURL+"/api/agnet/runtime/health", "")
healthBody := readAgnetRuntimeSmokeBody(t, healthResp)
healthResp := agentRuntimeAdminRequest(t, http.MethodGet, managerURL+"/api/agent/runtime/health", "")
healthBody := readAgentRuntimeSmokeBody(t, healthResp)
require.Equal(t, http.StatusOK, healthResp.StatusCode)
require.Contains(t, healthBody, `"success":true`)
require.Contains(t, healthBody, `"status":"healthy"`)
schemaResp, err := http.Get(managerURL + "/api/agnet/callbacks/swarm-events/schema")
schemaResp, err := http.Get(managerURL + "/api/agent/callbacks/runtime-events/schema")
require.NoError(t, err)
schemaBody := readAgnetRuntimeSmokeBody(t, schemaResp)
schemaBody := readAgentRuntimeSmokeBody(t, schemaResp)
require.Equal(t, http.StatusOK, schemaResp.StatusCode)
require.Contains(t, schemaBody, `"event_type":"task.claimed"`)
require.Contains(t, schemaBody, `"event_type":"approval.requested"`)
@@ -179,44 +179,44 @@ func TestAgnetRuntimeRealHTTPHealthAndShadowCreateSmoke(t *testing.T) {
"user_context":{"user_id":"101","channel_id":"default"},
"billing_context":{"provider":"newapi","newapi_user_ref":"newapi-http-smoke"},
"agile_context":{"iteration":"2026-05-27~2026-05-28","stage":"development","checkpoint":"ready_for_test","acceptance_criteria":["接口返回成功"],"next_action":"submit_test_result","requires_user_approval":false},
"agent_runtime":{"platform":"agnet","agents":[{"role":"builder","model_ref":"model-http-smoke","instance_count":1}]},
"agent_runtime":{"platform":"agent","agents":[{"role":"builder","model_ref":"model-http-smoke","instance_count":1}]},
"agents":[{"role_template":"builder","goal":"smoke","default_model_id":"model-http-smoke","resource_grants":[{"grant_id":"grant-http-git","resource_id":"git-http","resource_type":"git","user_id":"101","binding_scope":"https://example.invalid/heicode/smoke.git#main","target_role":"builder","target_agent_ref":"agent-builder-1","permission_scope":["repo:read"],"metadata":{"repo_url":"https://example.invalid/heicode/smoke.git"},"secret_ref":"azkv://heicode-kv.vault.azure.net/secrets/http-smoke-git","status":"active"}]}],
"constraints":{"allowed_model_ids":["model-http-smoke"]},
"metadata":{"correlation_id":"corr-http-smoke"}
}
}`
createResp := agnetRuntimeAdminRequest(t, http.MethodPost, managerURL+"/api/agnet/deployments", createBody)
responseBody := readAgnetRuntimeSmokeBody(t, createResp)
createResp := agentRuntimeAdminRequest(t, http.MethodPost, managerURL+"/api/agent/deployments", createBody)
responseBody := readAgentRuntimeSmokeBody(t, createResp)
require.Equal(t, http.StatusOK, createResp.StatusCode)
require.Contains(t, responseBody, `"success":true`)
require.Contains(t, responseBody, `"runtime_deployment_id":"runtime-http-dep"`)
require.Contains(t, responseBody, `"runtime_swarm_id":"runtime-http-swarm"`)
require.True(t, runtimeCreateCalled)
var stored model.AgnetDeployment
var stored model.AgentDeployment
require.NoError(t, db.Where("runtime_swarm_id = ?", "runtime-http-swarm").First(&stored).Error)
require.Equal(t, "accepted", stored.RuntimeState)
logsResp := agnetRuntimeAdminRequest(t, http.MethodGet, managerURL+"/api/agnet/deployments/"+stored.DeploymentID+"/logs", "")
logsBody := readAgnetRuntimeSmokeBody(t, logsResp)
logsResp := agentRuntimeAdminRequest(t, http.MethodGet, managerURL+"/api/agent/deployments/"+stored.DeploymentID+"/logs", "")
logsBody := readAgentRuntimeSmokeBody(t, logsResp)
require.Equal(t, http.StatusOK, logsResp.StatusCode)
require.Contains(t, logsBody, `"data_source":"manager_control_plane"`)
require.Contains(t, logsBody, `"runtime_source":"not_connected"`)
metricsResp := agnetRuntimeAdminRequest(t, http.MethodGet, managerURL+"/api/agnet/deployments/"+stored.DeploymentID+"/metrics", "")
metricsBody := readAgnetRuntimeSmokeBody(t, metricsResp)
metricsResp := agentRuntimeAdminRequest(t, http.MethodGet, managerURL+"/api/agent/deployments/"+stored.DeploymentID+"/metrics", "")
metricsBody := readAgentRuntimeSmokeBody(t, metricsResp)
require.Equal(t, http.StatusOK, metricsResp.StatusCode)
require.Contains(t, metricsBody, `"data_source":"manager_control_plane"`)
require.Contains(t, metricsBody, `"platform_estimated":true`)
}
func TestSwarmRuntimeHTTPCreateUsesSwarmConfigAndPayload(t *testing.T) {
db := setupAgnetRuntimeHTTPSmokeDB(t)
db := setupAgentRuntimeHTTPSmokeDB(t)
swarmCreateCalled := false
swarmStopCalled := false
swarm := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch {
case r.Method == http.MethodGet && r.URL.Path == "/api/agnet/health":
case r.Method == http.MethodGet && r.URL.Path == "/api/agent/health":
require.Equal(t, "Bearer swarm-runtime-token", r.Header.Get("Authorization"))
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"success":true,"data":{"status":"healthy","service":"heicode-swarm-runtime"}}`))
@@ -253,16 +253,16 @@ func TestSwarmRuntimeHTTPCreateUsesSwarmConfigAndPayload(t *testing.T) {
}))
defer swarm.Close()
t.Setenv("AGNET_RUNTIME_ENABLED", "false")
t.Setenv("AGENT_RUNTIME_ENABLED", "false")
t.Setenv("SWARM_RUNTIME_ENABLED", "true")
t.Setenv("SWARM_RUNTIME_ASYNC", "false")
t.Setenv("SWARM_RUNTIME_BASE_URL", swarm.URL)
t.Setenv("SWARM_RUNTIME_SERVICE_TOKEN", "swarm-runtime-token")
managerURL := startAgnetRuntimeManagerSmokeServer(t)
managerURL := startAgentRuntimeManagerSmokeServer(t)
healthResp := agnetRuntimeAdminRequest(t, http.MethodGet, managerURL+"/api/agnet/runtime/health?mode=swarm", "")
healthBody := readAgnetRuntimeSmokeBody(t, healthResp)
healthResp := agentRuntimeAdminRequest(t, http.MethodGet, managerURL+"/api/agent/runtime/health?mode=swarm", "")
healthBody := readAgentRuntimeSmokeBody(t, healthResp)
require.Equal(t, http.StatusOK, healthResp.StatusCode)
require.Contains(t, healthBody, `"mode":"swarm"`)
require.Contains(t, healthBody, `"status":"healthy"`)
@@ -279,7 +279,7 @@ func TestSwarmRuntimeHTTPCreateUsesSwarmConfigAndPayload(t *testing.T) {
"user_context":{"user_id":"101","channel_id":"default"},
"billing_context":{"provider":"newapi","newapi_user_ref":"newapi-swarm-smoke"},
"agile_context":{"iteration":"2026-05-29","stage":"testing","checkpoint":"runtime_accepted","acceptance_criteria":["Runtime creates a swarm run"],"next_action":"submit_test_result","requires_user_approval":false},
"agent_runtime":{"platform":"agnet","agents":[{"role":"planner","model_ref":"model-swarm","instance_count":1},{"role":"builder","model_ref":"model-swarm","instance_count":1},{"role":"reviewer","model_ref":"model-swarm","instance_count":1}]},
"agent_runtime":{"platform":"agent","agents":[{"role":"planner","model_ref":"model-swarm","instance_count":1},{"role":"builder","model_ref":"model-swarm","instance_count":1},{"role":"reviewer","model_ref":"model-swarm","instance_count":1}]},
"agents":[
{"role_template":"planner","goal":"plan the swarm task","default_model_id":"model-swarm","resource_grants":[{"grant_id":"grant-swarm-plan","resource_id":"doc-swarm","resource_type":"project_doc","user_id":"101","binding_scope":"task-swarm-smoke","target_role":"planner","target_agent_ref":"agent-planner-1","permission_scope":["doc:read"],"metadata":{"resource_ref":"task-swarm-smoke"},"status":"active"}]},
{"role_template":"builder","goal":"build the swarm output","default_model_id":"model-swarm","resource_grants":[{"grant_id":"grant-swarm-build","resource_id":"git-swarm","resource_type":"git","user_id":"101","binding_scope":"task-swarm-smoke","target_role":"builder","target_agent_ref":"agent-builder-1","permission_scope":["repo:read"],"metadata":{"repo_url":"https://example.invalid/heicode/swarm.git"},"secret_ref":"azkv://heicode-kv.vault.azure.net/secrets/swarm-git","status":"active"}]},
@@ -289,21 +289,21 @@ func TestSwarmRuntimeHTTPCreateUsesSwarmConfigAndPayload(t *testing.T) {
"metadata":{"correlation_id":"corr-swarm-smoke"}
}
}`
createResp := agnetRuntimeAdminRequest(t, http.MethodPost, managerURL+"/api/swarms", createBody)
responseBody := readAgnetRuntimeSmokeBody(t, createResp)
createResp := agentRuntimeAdminRequest(t, http.MethodPost, managerURL+"/api/swarms", createBody)
responseBody := readAgentRuntimeSmokeBody(t, createResp)
require.Equal(t, http.StatusOK, createResp.StatusCode)
require.Contains(t, responseBody, `"success":true`)
require.Contains(t, responseBody, `"runtime_deployment_id":"swarm-runtime-dep"`)
require.Contains(t, responseBody, `"runtime_swarm_id":"swarm-runtime-id"`)
require.True(t, swarmCreateCalled)
var stored model.AgnetDeployment
var stored model.AgentDeployment
require.NoError(t, db.Where("runtime_swarm_id = ?", "swarm-runtime-id").First(&stored).Error)
require.Equal(t, "agile", stored.SubMode)
require.Contains(t, stored.PlanJSON, `"runtime_mode":"swarm"`)
stopResp := agnetRuntimeAdminRequest(t, http.MethodPost, managerURL+"/api/agnet/user/deployments/"+stored.DeploymentID+"/stop", `{"reason":"smoke done"}`)
stopBody := readAgnetRuntimeSmokeBody(t, stopResp)
stopResp := agentRuntimeAdminRequest(t, http.MethodPost, managerURL+"/api/agent/user/deployments/"+stored.DeploymentID+"/stop", `{"reason":"smoke done"}`)
stopBody := readAgentRuntimeSmokeBody(t, stopResp)
require.Equal(t, http.StatusOK, stopResp.StatusCode)
require.Contains(t, stopBody, `"success":true`)
require.Contains(t, stopBody, `"runtime_state":"stopped"`)
+76 -44
View File
@@ -59,9 +59,11 @@ func SetApiRouter(router *gin.Engine) {
apiRouter.POST("/stripe/webhook", controller.StripeWebhook)
apiRouter.POST("/creem/webhook", controller.CreemWebhook)
apiRouter.POST("/waffo/webhook", controller.WaffoWebhook)
apiRouter.GET("/agnet/callbacks/swarm-events/schema", controller.AgnetGetSwarmEventCallbackSchema)
apiRouter.POST("/agnet/callbacks/swarm-events", controller.AgnetReceiveSwarmEventCallback)
apiRouter.POST("/swarms", middleware.UserOrV2DeviceAuth(), controller.AgnetCreateUserSwarm)
apiRouter.GET("/agent/callbacks/runtime-events/schema", controller.AgentGetRuntimeEventCallbackSchema)
apiRouter.POST("/agent/callbacks/runtime-events", controller.AgentReceiveRuntimeEventCallback)
// Client-facing capability discovery (unified spec §6). Catalog data only.
apiRouter.GET("/heicode/capabilities", controller.HeicodeCapabilities)
apiRouter.POST("/swarms", middleware.UserOrV2DeviceAuth(), controller.AgentCreateUserSwarm)
//apiRouter.POST("/waffo-pancake/webhook", controller.WaffoPancakeWebhook)
// Universal secure verification routes
@@ -81,7 +83,7 @@ func SetApiRouter(router *gin.Engine) {
userRoute := apiRouter.Group("/user")
{
userRoute.POST("/register", middleware.CriticalRateLimit(), middleware.TurnstileCheck(), controller.Register)
userRoute.POST("/session/from-agnet", middleware.CriticalRateLimit(), controller.HeicodeAgnetSessionLogin)
userRoute.POST("/session/from-agent", middleware.CriticalRateLimit(), controller.HeicodeAgentSessionLogin)
userRoute.POST("/login", middleware.CriticalRateLimit(), middleware.TurnstileCheck(), controller.Login)
userRoute.POST("/login/2fa", middleware.CriticalRateLimit(), controller.Verify2FALogin)
userRoute.POST("/passkey/login/begin", middleware.CriticalRateLimit(), controller.PasskeyLoginBegin)
@@ -491,50 +493,80 @@ func SetApiRouter(router *gin.Engine) {
deploymentsRoute.DELETE("/:id", controller.DeleteDeployment)
}
// Agnet user approval gates and short-lived credential leases.
agnetApprovalRoute := apiRouter.Group("/agnet")
agnetApprovalRoute.Use(middleware.UserOrV2DeviceAuth())
// Agent user approval gates and short-lived credential leases.
agentApprovalRoute := apiRouter.Group("/agent")
agentApprovalRoute.Use(middleware.UserOrV2DeviceAuth())
{
agnetApprovalRoute.GET("/approvals", controller.ListAgnetApprovalRequests)
agnetApprovalRoute.POST("/approvals", controller.CreateAgnetApprovalRequest)
agnetApprovalRoute.GET("/approvals/:approval_id", controller.GetAgnetApprovalRequest)
agnetApprovalRoute.POST("/approvals/:approval_id/approve", controller.ApproveAgnetApprovalRequest)
agnetApprovalRoute.POST("/approvals/:approval_id/reject", controller.RejectAgnetApprovalRequest)
agnetApprovalRoute.GET("/credential-leases", controller.ListAgnetCredentialLeases)
agnetApprovalRoute.POST("/credential-leases/:lease_id/revoke", controller.RevokeAgnetCredentialLease)
agnetApprovalRoute.GET("/role-templates", controller.AgnetListRoleTemplates)
agnetApprovalRoute.GET("/user/deployments", controller.AgnetListUserDeployments)
agnetApprovalRoute.POST("/user/deployments", controller.AgnetCreateUserDeployment)
agnetApprovalRoute.GET("/user/deployments/:deployment_id", controller.AgnetGetUserDeployment)
agnetApprovalRoute.POST("/user/deployments/:deployment_id/stop", controller.AgnetStopUserDeployment)
agnetApprovalRoute.GET("/user/deployments/:deployment_id/logs", controller.AgnetListUserDeploymentLogs)
agnetApprovalRoute.GET("/user/deployments/:deployment_id/metrics", controller.AgnetGetUserDeploymentMetrics)
agnetApprovalRoute.GET("/user/deployments/:deployment_id/runtime-diagnostics", controller.AgnetGetUserDeploymentRuntimeDiagnostics)
agnetApprovalRoute.GET("/user/deployments/:deployment_id/events", controller.AgnetListUserDeploymentEvents)
agnetApprovalRoute.POST("/user/deployments/:deployment_id/simulate-events", controller.AgnetSimulateUserDeploymentEvents)
agnetApprovalRoute.GET("/user/deployments/:deployment_id/artifacts", controller.AgnetListUserDeploymentArtifacts)
agnetApprovalRoute.GET("/user/deployments/:deployment_id/artifacts/:artifact_id/content", controller.AgnetGetUserDeploymentArtifactContent)
agnetApprovalRoute.GET("/user/deployments/:deployment_id/sk-snapshots", controller.AgnetListUserSKSnapshots)
agnetApprovalRoute.GET("/user/deployments/:deployment_id/timeline", controller.AgnetGetUserDeploymentTimeline)
agnetApprovalRoute.POST("/user/tasks/:task_id/deployment-draft", controller.AgnetCreateTaskDeploymentDraft)
agentApprovalRoute.GET("/approvals", controller.ListAgentApprovalRequests)
agentApprovalRoute.POST("/approvals", controller.CreateAgentApprovalRequest)
agentApprovalRoute.GET("/approvals/:approval_id", controller.GetAgentApprovalRequest)
agentApprovalRoute.POST("/approvals/:approval_id/approve", controller.ApproveAgentApprovalRequest)
agentApprovalRoute.POST("/approvals/:approval_id/reject", controller.RejectAgentApprovalRequest)
agentApprovalRoute.GET("/credential-leases", controller.ListAgentCredentialLeases)
agentApprovalRoute.POST("/credential-leases/:lease_id/revoke", controller.RevokeAgentCredentialLease)
agentApprovalRoute.GET("/role-templates", controller.AgentListRoleTemplates)
agentApprovalRoute.GET("/user/deployments", controller.AgentListUserDeployments)
agentApprovalRoute.POST("/user/deployments", controller.AgentCreateUserDeployment)
agentApprovalRoute.GET("/user/deployments/:deployment_id", controller.AgentGetUserDeployment)
agentApprovalRoute.POST("/user/deployments/:deployment_id/stop", controller.AgentStopUserDeployment)
agentApprovalRoute.GET("/user/deployments/:deployment_id/logs", controller.AgentListUserDeploymentLogs)
agentApprovalRoute.GET("/user/deployments/:deployment_id/metrics", controller.AgentGetUserDeploymentMetrics)
agentApprovalRoute.GET("/user/deployments/:deployment_id/runtime-diagnostics", controller.AgentGetUserDeploymentRuntimeDiagnostics)
agentApprovalRoute.GET("/user/deployments/:deployment_id/events", controller.AgentListUserDeploymentEvents)
agentApprovalRoute.POST("/user/deployments/:deployment_id/simulate-events", controller.AgentSimulateUserDeploymentEvents)
agentApprovalRoute.GET("/user/deployments/:deployment_id/artifacts", controller.AgentListUserDeploymentArtifacts)
agentApprovalRoute.GET("/user/deployments/:deployment_id/artifacts/:artifact_id/content", controller.AgentGetUserDeploymentArtifactContent)
agentApprovalRoute.GET("/user/deployments/:deployment_id/sk-snapshots", controller.AgentListUserSKSnapshots)
agentApprovalRoute.GET("/user/deployments/:deployment_id/timeline", controller.AgentGetUserDeploymentTimeline)
agentApprovalRoute.POST("/user/tasks/:task_id/deployment-draft", controller.AgentCreateTaskDeploymentDraft)
}
// Agnet orchestration control plane (minimal integration endpoints)
agnetRoute := apiRouter.Group("/agnet")
agnetRoute.Use(middleware.AdminAuth())
// Client-facing unified task routes (unified spec §5.1). task_id == the
// deployment_id, so these reuse the deployment control-plane handlers.
// Sub Agile -> agent_management; Swarm -> HeiCode-Swarm (mode is carried
// by the deployment record created at POST /tasks).
registerHeicodeTaskRoutes := func(group *gin.RouterGroup, createHandler gin.HandlerFunc) {
group.GET("/tasks", controller.AgentListUserDeployments)
group.POST("/tasks", createHandler)
group.GET("/tasks/:deployment_id", controller.AgentGetUserDeployment)
group.POST("/tasks/:deployment_id/stop", controller.AgentStopUserDeployment)
group.GET("/tasks/:deployment_id/timeline", controller.AgentGetUserDeploymentTimeline)
group.GET("/tasks/:deployment_id/workflow", controller.HeicodeTaskWorkflow)
group.GET("/tasks/:deployment_id/logs", controller.AgentListUserDeploymentLogs)
group.GET("/tasks/:deployment_id/events", controller.AgentListUserDeploymentEvents)
group.GET("/tasks/:deployment_id/metrics", controller.AgentGetUserDeploymentMetrics)
group.GET("/tasks/:deployment_id/diagnostics", controller.AgentGetUserDeploymentRuntimeDiagnostics)
group.GET("/tasks/:deployment_id/artifacts", controller.AgentListUserDeploymentArtifacts)
group.GET("/tasks/:deployment_id/artifacts/:artifact_id/content", controller.AgentGetUserDeploymentArtifactContent)
group.GET("/tasks/:deployment_id/sk-snapshots", controller.AgentListUserSKSnapshots)
group.POST("/tasks/:deployment_id/approvals/:approval_id/approve", controller.ApproveAgentApprovalRequest)
group.POST("/tasks/:deployment_id/approvals/:approval_id/reject", controller.RejectAgentApprovalRequest)
}
heicodeSubAgileRoute := apiRouter.Group("/heicode/sub-agile")
heicodeSubAgileRoute.Use(middleware.UserOrV2DeviceAuth())
registerHeicodeTaskRoutes(heicodeSubAgileRoute, controller.AgentCreateUserDeployment)
heicodeSwarmRoute := apiRouter.Group("/heicode/swarm")
heicodeSwarmRoute.Use(middleware.UserOrV2DeviceAuth())
registerHeicodeTaskRoutes(heicodeSwarmRoute, controller.AgentCreateUserSwarm)
// Agent orchestration control plane (minimal integration endpoints)
agentRoute := apiRouter.Group("/agent")
agentRoute.Use(middleware.AdminAuth())
{
agnetRoute.GET("/deployments", controller.AgnetListDeployments)
agnetRoute.POST("/deployments", controller.AgnetCreateDeployment)
agnetRoute.GET("/deployments/:deployment_id", controller.AgnetGetDeployment)
agnetRoute.POST("/deployments/:deployment_id/stop", controller.AgnetStopDeployment)
agnetRoute.GET("/deployments/:deployment_id/logs", controller.AgnetListDeploymentLogs)
agnetRoute.GET("/deployments/:deployment_id/metrics", controller.AgnetGetDeploymentMetrics)
agnetRoute.GET("/deployments/:deployment_id/events", controller.AgnetListDeploymentEvents)
agnetRoute.GET("/deployments/:deployment_id/sk-snapshots", controller.AgnetListSKSnapshots)
agnetRoute.POST("/sk-snapshots/resolve", controller.AgnetResolveSKSnapshots)
agnetRoute.GET("/runtime/health", controller.AgnetRuntimeHealth)
agnetRoute.GET("/projects/:project_id/dashboard-snapshot", controller.AgnetProjectDashboardSnapshot)
agnetRoute.GET("/audit-logs", controller.AgnetListAuditLogs)
agentRoute.GET("/deployments", controller.AgentListDeployments)
agentRoute.POST("/deployments", controller.AgentCreateDeployment)
agentRoute.GET("/deployments/:deployment_id", controller.AgentGetDeployment)
agentRoute.POST("/deployments/:deployment_id/stop", controller.AgentStopDeployment)
agentRoute.GET("/deployments/:deployment_id/logs", controller.AgentListDeploymentLogs)
agentRoute.GET("/deployments/:deployment_id/metrics", controller.AgentGetDeploymentMetrics)
agentRoute.GET("/deployments/:deployment_id/events", controller.AgentListDeploymentEvents)
agentRoute.GET("/deployments/:deployment_id/sk-snapshots", controller.AgentListSKSnapshots)
agentRoute.POST("/sk-snapshots/resolve", controller.AgentResolveSKSnapshots)
agentRoute.GET("/runtime/health", controller.AgentRuntimeHealth)
agentRoute.GET("/projects/:project_id/dashboard-snapshot", controller.AgentProjectDashboardSnapshot)
agentRoute.GET("/audit-logs", controller.AgentListAuditLogs)
}
}
}