diff --git a/heicode/controller/agnet_control_plane.go b/heicode/controller/agnet_control_plane.go index 43953a5..deefb86 100644 --- a/heicode/controller/agnet_control_plane.go +++ b/heicode/controller/agnet_control_plane.go @@ -27,11 +27,27 @@ type agnetSKSource struct { ArtifactID string `json:"artifact_id"` } +// agnetRuntimeExecution mirrors docs/integration/agnet-platform-api-design.md §5.0 (runtime_execution). +type agnetRuntimeExecution struct { + ProfileID string `json:"profile_id"` + CloudPrincipalRefs []string `json:"cloud_principal_refs"` + NetworkPolicyRef string `json:"network_policy_ref"` +} + +// agnetSKAccessPolicy mirrors docs/integration/agnet-platform-api-design.md §5.0 (sk_access_policy). +type agnetSKAccessPolicy struct { + PolicyRef string `json:"policy_ref"` + DenySkillIDs []string `json:"deny_skill_ids"` + InheritDeploymentDefaults bool `json:"inherit_deployment_defaults"` +} + type agnetAgentPlan struct { - RoleTemplate string `json:"role_template"` - Goal string `json:"goal"` - DefaultModelID string `json:"default_model_id"` - SKSources []agnetSKSource `json:"sk_sources"` + RoleTemplate string `json:"role_template"` + Goal string `json:"goal"` + DefaultModelID string `json:"default_model_id"` + SKSources []agnetSKSource `json:"sk_sources"` + RuntimeExecution agnetRuntimeExecution `json:"runtime_execution"` + SKAccessPolicy agnetSKAccessPolicy `json:"sk_access_policy"` } type agnetConstraints struct { @@ -132,6 +148,37 @@ func containsString(values []string, target string) bool { return false } +func agnetRuntimePartiallySet(r agnetRuntimeExecution) bool { + return strings.TrimSpace(r.ProfileID) != "" || + len(r.CloudPrincipalRefs) > 0 || + strings.TrimSpace(r.NetworkPolicyRef) != "" +} + +func validateAgentRuntimeBindings(c *gin.Context, agent agnetAgentPlan) bool { + r := agent.RuntimeExecution + if !agnetRuntimePartiallySet(r) { + return true + } + if strings.TrimSpace(r.ProfileID) == "" { + agnetError(c, "RUNTIME_BINDING_INVALID", "runtime_execution.profile_id is required when runtime bindings are present") + return false + } + return true +} + +func validateAgentSKAccessPolicy(c *gin.Context, agent agnetAgentPlan) bool { + p := agent.SKAccessPolicy + hasDeny := len(p.DenySkillIDs) > 0 + if !hasDeny { + return true + } + if strings.TrimSpace(p.PolicyRef) == "" && !p.InheritDeploymentDefaults { + agnetError(c, "SK_POLICY_REJECTED", "sk_access_policy.policy_ref or inherit_deployment_defaults is required when deny_skill_ids is set") + return false + } + return true +} + func validateOrchestrationPlan(c *gin.Context, plan agnetOrchestrationPlan) bool { if strings.TrimSpace(plan.IntentID) == "" || strings.TrimSpace(plan.TemplateHint) == "" || @@ -187,6 +234,12 @@ func validateOrchestrationPlan(c *gin.Context, plan agnetOrchestrationPlan) bool agnetError(c, "MODEL_NOT_ALLOWED", "agent default_model_id is outside allowed_model_ids") return false } + if !validateAgentRuntimeBindings(c, agent) { + return false + } + if !validateAgentSKAccessPolicy(c, agent) { + return false + } } return true diff --git a/heicode/web/default/src/features/agnet-console/api.ts b/heicode/web/default/src/features/agnet-console/api.ts index 7e2781f..0889116 100644 --- a/heicode/web/default/src/features/agnet-console/api.ts +++ b/heicode/web/default/src/features/agnet-console/api.ts @@ -1,5 +1,19 @@ import { api } from '@/lib/api' +/** Sub-agent cloud/runtime binding (passed to Agnet on deploy). */ +export type AgnetRuntimeExecution = { + profile_id?: string + cloud_principal_refs?: string[] + network_policy_ref?: string +} + +/** SK allow/deny policy attached to the agent in the deployment plan. */ +export type AgnetSKAccessPolicy = { + policy_ref?: string + deny_skill_ids?: string[] + inherit_deployment_defaults?: boolean +} + export type AgnetDeployment = { deployment_id: string status: string @@ -14,6 +28,8 @@ export type AgnetDeployment = { goal?: string default_model_id?: string sk_sources?: Array<{ type?: string; artifact_id?: string }> + runtime_execution?: AgnetRuntimeExecution + sk_access_policy?: AgnetSKAccessPolicy }> metadata?: { tenant_id?: string diff --git a/heicode/web/default/src/features/agnet-console/pages.tsx b/heicode/web/default/src/features/agnet-console/pages.tsx index 3bc0348..5333505 100644 --- a/heicode/web/default/src/features/agnet-console/pages.tsx +++ b/heicode/web/default/src/features/agnet-console/pages.tsx @@ -42,6 +42,8 @@ import { getAgnetSnapshots, listAgnetDeployments, type AgnetDeployment, + type AgnetRuntimeExecution, + type AgnetSKAccessPolicy, } from './api' type StatusKey = 'running' | 'success' | 'failed' | 'pending' @@ -820,6 +822,24 @@ export function AgnetTemplatesPage() { ) } +function runtimeSummary(rt: AgnetRuntimeExecution | undefined): boolean { + if (!rt) return false + return Boolean( + (rt.profile_id && rt.profile_id.trim() !== '') || + (rt.cloud_principal_refs && rt.cloud_principal_refs.length > 0) || + (rt.network_policy_ref && rt.network_policy_ref.trim() !== '') + ) +} + +function policySummary(p: AgnetSKAccessPolicy | undefined): boolean { + if (!p) return false + return Boolean( + (p.policy_ref && p.policy_ref.trim() !== '') || + (p.deny_skill_ids && p.deny_skill_ids.length > 0) || + p.inherit_deployment_defaults + ) +} + export function AgnetAgentsPage() { const { t } = useTranslation() const { data = [] } = useQuery({ @@ -835,6 +855,8 @@ export function AgnetAgentsPage() { role: agent.role_template || '-', model: agent.default_model_id || '-', goal: agent.goal || '-', + runtime: agent.runtime_execution, + skPolicy: agent.sk_access_policy, })) ), [data] @@ -861,6 +883,80 @@ export function AgnetAgentsPage() { {row.dep} · model: {row.model}
{row.goal}
+ {runtimeSummary(row.runtime) && ( ++ {t('Runtime binding')} +
+ {row.runtime?.profile_id ? ( ++ + {t('Execution profile')} + :{' '} + + + {row.runtime.profile_id} + +
+ ) : null} + {(row.runtime?.cloud_principal_refs?.length ?? 0) > 0 ? ( ++ + {t('Cloud principals')} + :{' '} + + + {row.runtime?.cloud_principal_refs?.join(', ')} + +
+ ) : null} + {row.runtime?.network_policy_ref ? ( ++ + {t('Network policy')} + :{' '} + + + {row.runtime.network_policy_ref} + +
+ ) : null} ++ {t('SK access policy')} +
+ {row.skPolicy?.policy_ref ? ( ++ + {t('Policy ref')} + :{' '} + + + {row.skPolicy.policy_ref} + +
+ ) : null} + {(row.skPolicy?.deny_skill_ids?.length ?? 0) > 0 ? ( ++ + {t('Denied skills')} + :{' '} + + + {row.skPolicy?.deny_skill_ids?.join(', ')} + +
+ ) : null} + {row.skPolicy?.inherit_deployment_defaults ? ( ++ {t('Inherits deployment defaults')} +
+ ) : null} +