Documentation
¶
Overview ¶
Package server provides the two HTTP servers for wsproxy:
- terminal.go: :9003 WebSocket terminal reverse-proxy
- internal.go: :9004 internal management API (Gin + OpenAPI-generated routes)
Package server contains the two HTTP servers that wsproxy exposes:
- terminal.go (:9003) — WebSocket terminal proxy toward Worker clusters
- internal.go (:9004) — Internal management API for Dashboard BFF
Index ¶
- Constants
- func BridgeConns(a, b *websocket.Conn)
- func NewInternalServer(cfg *config.Config, deps RouterDeps) *http.Server
- func NewManagedAgentGatewayServer(addr string, g *ManagedAgentGateway, auth gin.HandlerFunc) *http.Server
- func NewTerminalServer(cfg *config.Config, store *cluster.Store) *http.Server
- func ParseTerminalPath(rawPath string) (clusterID, sandboxID string, ok bool)
- type ManagedAgentAPI
- type ManagedAgentGateway
- type PlatformDefaults
- type RouterDeps
Constants ¶
const APIKeyHeader = "AGENTBOX-API-KEY"
APIKeyHeader is the header every AgentBox API reads its credential from.
const WorkspaceFSPrefix = "/_fs"
WorkspaceFSPrefix routes to the agent's workspace-fs server instead of its gateway. The two are separate ports on the Brain, and publishing them as two base URLs made every caller carry two addresses and get one of them wrong — redirecting only the gateway leaves the file panel and attachment upload silently broken. One base URL with a reserved segment keeps them together.
The segment leads with an underscore because everything else under an agent is the gateway's own path space: no gateway route starts with one, so this cannot shadow a real endpoint now or after the gateway grows new ones.
Variables ¶
This section is empty.
Functions ¶
func BridgeConns ¶
BridgeConns copies messages bidirectionally between two WebSocket connections until one of them closes or returns an error.
func NewInternalServer ¶
func NewInternalServer(cfg *config.Config, deps RouterDeps) *http.Server
NewInternalServer creates the :9004 management HTTP server. It registers the OpenAPI-generated strict routes (templates, api-keys, images catalog) behind jwtOrManagerTokenMiddleware, plus legacy /internal/* routes behind the static manager-token middleware.
func NewManagedAgentGatewayServer ¶ added in v0.0.8
func NewManagedAgentGatewayServer(addr string, g *ManagedAgentGateway, auth gin.HandlerFunc) *http.Server
NewManagedAgentGatewayServer serves the published agents on their own listener, behind auth.
A separate port from the internal API is what keeps the ingress honest: the internal API trusts a manager token and must never be routable from outside, so the two cannot share a listener that an ingress is pointed at.
func NewTerminalServer ¶
NewTerminalServer creates the :9003 HTTP server that proxies WebSocket terminal connections from the Dashboard to the target Worker cluster.
func ParseTerminalPath ¶
ParseTerminalPath parses a terminal proxy path of the form:
[<prefix>]/ws/clusters/{clusterID}/sandboxes/{sandboxID}/terminal
Returns (clusterID, sandboxID, true) on success, ("", "", false) otherwise.
Types ¶
type ManagedAgentAPI ¶ added in v0.0.8
type ManagedAgentAPI struct {
Client client.Client
Scheme *runtime.Scheme
Namespace string
// Hands creates a SandboxEnv on a worker cluster when a create request asks
// for one. Nil on a control plane without an admin key — a request that needs
// it is then refused rather than silently creating an agent with no sandbox
// supply. Shared with the ManagedAgent controller, which uses it for
// hands.auto.
Hands managedagent.HandsProvisioner
// Gateway forwards the console's own requests to an agent's Brain, so a user
// can talk to their agent from the platform. Nil leaves that surface off,
// which is why every route below still works without it.
//
// It is the SAME proxy the public listener uses, deliberately: the alternative
// is two forwarders that agree today and diverge on the next Brain endpoint —
// and the one that diverges silently is whichever gets less traffic.
Gateway *ManagedAgentGateway
// Defaults is what this deployment supplies for an agent that names none. It
// is served so a console can present the same agent the controller would
// render — a form that asked for an image, an endpoint and an environment the
// platform already has an answer for is a form the platform failed to fill in.
Defaults PlatformDefaults
}
ManagedAgentAPI serves the console's CRUD over ManagedAgent objects.
ManagedAgent is a control-plane object, so it is served here rather than by the per-cluster API: the console reaches it through the same BFF path it uses for global API keys and templates, with no cluster in the route.
func (*ManagedAgentAPI) RegisterManagedAgentRoutes ¶ added in v0.0.8
func (a *ManagedAgentAPI) RegisterManagedAgentRoutes(g *gin.RouterGroup)
RegisterManagedAgentRoutes mounts the CRUD surface on the given group.
type ManagedAgentGateway ¶ added in v0.0.8
type ManagedAgentGateway struct {
Client client.Client
Namespace string
// contains filtered or unexported fields
}
ManagedAgentGateway publishes agents outside the cluster.
It exists because the Brain has no authentication of its own: it takes the caller's word for which end user is asking, which is safe only while nothing outside the cluster can reach it. This gateway is the hop that makes an external route safe — it authenticates the API key, checks that the key's owner may use the agent named in the path, and only then forwards.
It deliberately does not terminate the protocol. Everything past the agent name is proxied verbatim, so the agent's surface stays whatever the Brain serves and this file never has to learn about threads, runs or AG-UI.
func NewManagedAgentGateway ¶ added in v0.0.8
func NewManagedAgentGateway(c client.Client, namespace string) *ManagedAgentGateway
NewManagedAgentGateway wires the reverse proxy.
func (*ManagedAgentGateway) RegisterManagedAgentGatewayRoutes ¶ added in v0.0.8
func (g *ManagedAgentGateway) RegisterManagedAgentGatewayRoutes(r gin.IRouter)
RegisterManagedAgentGatewayRoutes mounts the public surface.
The caller must already be authenticated by the group's middleware — the same one the internal API uses, so an AGENTBOX-API-KEY works here exactly as it does against a worker cluster. The manager token deliberately does NOT: it is the inter-component secret and must not be a credential anyone outside the cluster can present.
The route carries the agent name because one route serves every agent: the ingress strips the shared public prefix and leaves "/<agent>/<path>".
type PlatformDefaults ¶ added in v0.0.10
type PlatformDefaults struct {
BrainImage agentsv1alpha1.ManagedAgentImage
Hands *agentsv1alpha1.ManagedAgentHands
ModelProvider config.ModelProviderDefaults
}
PlatformDefaults mirrors the deployment-level defaults the controller applies.
Held here as the API types rather than a flattened copy so this and the controller cannot drift on what a default means.
type RouterDeps ¶
type RouterDeps struct {
SyncManager *syncmgr.SyncManager
AdminKeyMgr *apikey.AdminKeyManager
KeyStore syncmgr.KeyStore
JWTSecret string
ManagerToken string
IAMService service.IAMService
// Notify serves the daily-report / idle-alert admin API. Nil when the
// notification service is not configured (no Prometheus URL), in which
// case those routes answer 503 rather than being unregistered.
Notify *notify.Service
// ManagedAgentAPI serves the console's ManagedAgent CRUD. Nil when the
// ManagedAgent controller is not enabled, in which case the routes are not
// registered at all rather than answering with an empty list — a console
// pointed at a control plane without the feature should see a 404, not the
// impression that the tenant simply owns no agents.
ManagedAgentAPI *ManagedAgentAPI
}
RouterDeps bundles all dependencies required to build the internal HTTP router.