package agent

import (
	"context"
	"log/slog"

	"net/http"

	"github.com/gin-gonic/gin"

	"github.com/tidbcloud/AgentTeam/internal/api"
	"github.com/tidbcloud/AgentTeam/internal/api/dto"
	"github.com/tidbcloud/AgentTeam/internal/api/workflow/binding"
	"github.com/tidbcloud/AgentTeam/internal/api/workflow/plan"
	"github.com/tidbcloud/AgentTeam/internal/api/workflow/run"
	"github.com/tidbcloud/AgentTeam/internal/service/channeladmin"
	"github.com/tidbcloud/AgentTeam/internal/service/teamworkflow"
	storeagent "github.com/tidbcloud/AgentTeam/internal/store/agent"
	"github.com/tidbcloud/AgentTeam/internal/store/agentops"
	planstore "github.com/tidbcloud/AgentTeam/internal/store/workflow/plan"
	"github.com/tidbcloud/AgentTeam/internal/workflow/orchestrator"
)

// Dependencies wires the internal agent API handlers.
//
// Handler structs consume the narrow interfaces below; this struct is only a
// route assembly input and must not grow behavior methods.
type Dependencies struct {
	Logger *slog.Logger

	MinDaemonVersion string

	Auth AgentAuthenticator

	MessageStore    MessageStore
	RewindStore     RewindStore
	MessageRecovery MessageRecoveryGC
	MessageFanout   MessageFanout
	RuntimeOverlay  RuntimeOverlay
	WorkflowReplies WorkflowReplyService

	ReactionStore  ReactionStore
	ReactionFanout ReactionFanout

	FileStore        FileStore
	AgentAvatarStore AgentAvatarStore

	ReviewContextStore     ReviewContextStore
	ReviewContextValidator ReviewContextValidator

	TaskBoard          TaskBoardService
	TaskTargetResolver TaskTargetResolver
	TaskFanout         MessageFanout

	ProjectStore AgentProjectStore

	ApprovalSubjects ApprovalRuntime
	Teams            AgentTeamStore
	Channels         *channeladmin.Service
	RoleManagers     RoleManagerResolver
	RoleReads        RoleReadRuntime
	RoleRequests     RoleRequestRuntime
	SkillOwners      AgentSkillOwnerResolver
	SkillWorkspace   AgentSkillWorkspaceResolver
	Skills           AgentSkillGateway

	TriggerOwnerStore TriggerOwnerStore
	ScheduleService   ScheduleControlService
	TriggerService    TriggerControlService

	// Agent management mounts only on the canonical Agent Runtime path.
	// Lifecycle routes require all four lifecycle dependencies below; structural
	// routes are gated independently by AgentManagementOwner + ApprovalSubjects.
	AgentManagementOwner   AgentManagementOwner
	AgentLifecycleCommands AgentLifecycleCommands
	AgentRuntimeControl    AgentRuntimeControl
	AgentLifecycleReceipts AgentLifecycleReceipts

	LLMProxySessions    LLMProxySessionStore
	AgentThreadContexts AgentThreadContextStore
	AgentThreadGateway  AgentThreadGateway

	// WorkflowRunCallbacks owns typed Agent Step completion for the first-class
	// Run runtime. The daemon injects the active Step identity from hidden
	// delivery context; it is never accepted as model-authored input.
	WorkflowRunCallbacks orchestrator.CallbackRuntime

	// WorkflowPlans is the Agent-authenticated CLI authoring boundary. The
	// authenticated Agent principal supplies workspace and actor provenance;
	// the command payload contains business input only.
	WorkflowPlans              plan.Service
	WorkflowPlanAgentEditGuard WorkflowPlanAgentEditLifecycleGuard

	// TeamWorkflowPlans extends Plan authoring with Team ownership, direct
	// Team-leader publication, and Team-scoped discovery. Generic workspace
	// publication remains fenced for linked Plans.
	TeamWorkflowPlans AgentTeamWorkflowPlanService

	// WorkflowRuns is the Agent-authenticated management boundary for existing
	// immutable Runs. Step completion remains on WorkflowRunCallbacks,
	// where active Run/effect identity comes from hidden delivery context.
	WorkflowRuns run.Service

	// WorkflowRecovery is the shared success-exit persistence boundary for all
	// four Agent Workflow CLI routes. It resets only after an authenticated
	// handler returns a successful response.
	WorkflowRecovery WorkflowRecoveryResetter

	// Workflow Binding routes mount only on the canonical Agent Runtime path and
	// only when the complete trusted dependency set is present.
	WorkflowBindings         binding.Service
	WorkflowBindingOwners    WorkflowBindingOwnerResolver
	WorkflowBindingWorkspace WorkflowBindingWorkspaceResolver

	// WorkflowInvocations provides the internal acceptance service behind
	// Workflow Run start. Invocation is an audit/storage concept, not a public
	// Agent API object.
	WorkflowInvocations         WorkflowInvocationService
	WorkflowInvocationOwners    WorkflowInvocationOwnerResolver
	WorkflowInvocationWorkspace WorkflowInvocationWorkspaceResolver
}

// RegisterRoutes mounts the daemon-compatible internal agent HTTP routes.
func RegisterRoutes(router gin.IRoutes, dependencies Dependencies) {
	messages := &MessageHandler{
		auth:             dependencies.Auth,
		store:            dependencies.MessageStore,
		rewindStore:      dependencies.RewindStore,
		recoveryGC:       dependencies.MessageRecovery,
		fanout:           dependencies.MessageFanout,
		runtime:          dependencies.RuntimeOverlay,
		logger:           dependencies.Logger,
		minDaemonVersion: dependencies.MinDaemonVersion,
		workflowReplies:  dependencies.WorkflowReplies,
	}
	reactions := &ReactionHandler{
		auth:   dependencies.Auth,
		store:  dependencies.ReactionStore,
		fanout: dependencies.ReactionFanout,
	}
	files := &FileHandler{auth: dependencies.Auth, files: dependencies.FileStore, agents: dependencies.AgentAvatarStore}
	reviewContexts := &ReviewContextHandler{
		auth:      dependencies.Auth,
		store:     dependencies.ReviewContextStore,
		validator: dependencies.ReviewContextValidator,
	}
	tasks := &TaskHandler{
		taskBoard: dependencies.TaskBoard,
		resolver:  dependencies.TaskTargetResolver,
		fanout:    dependencies.TaskFanout,
		logger:    dependencies.Logger,
	}
	projects := &ProjectHandler{
		auth:   dependencies.Auth,
		store:  dependencies.ProjectStore,
		logger: dependencies.Logger,
	}
	schedules := &ScheduleHandler{
		auth:      dependencies.Auth,
		owners:    dependencies.TriggerOwnerStore,
		schedules: dependencies.ScheduleService,
	}
	triggers := &TriggerHandler{
		auth:     dependencies.Auth,
		owners:   dependencies.TriggerOwnerStore,
		triggers: dependencies.TriggerService,
	}
	llmProxySessions := &LLMProxySessionHandler{
		auth:     dependencies.Auth,
		sessions: dependencies.LLMProxySessions,
	}
	agentThreads := &AgentThreadHandler{
		auth:     dependencies.Auth,
		contexts: dependencies.AgentThreadContexts,
		gateway:  dependencies.AgentThreadGateway,
	}
	teams := &AgentTeamHandler{
		teams:     dependencies.Teams,
		approvals: dependencies.ApprovalSubjects,
	}
	channels := &AgentChannelHandler{channels: dependencies.Channels}
	roles := &AgentRoleHandler{
		managers: dependencies.RoleManagers, reads: dependencies.RoleReads,
		requests: dependencies.RoleRequests, approvals: dependencies.ApprovalSubjects,
	}
	skills := &AgentSkillHandler{
		owners: dependencies.SkillOwners, workspaces: dependencies.SkillWorkspace,
		skills: dependencies.Skills, approvals: dependencies.ApprovalSubjects,
	}
	management := &AgentManagementHandler{
		owners:          dependencies.AgentManagementOwner,
		runtimeCommands: dependencies.AgentLifecycleCommands,
		runtimeControl:  dependencies.AgentRuntimeControl,
		receipts:        dependencies.AgentLifecycleReceipts,
		approvals:       dependencies.ApprovalSubjects,
		logger:          dependencies.Logger,
	}

	registerAgentRuntimeRoutes := func(base string) {
		router.POST(base+"/send", messages.Create)
		router.POST(base+"/resolve-channel", messages.ResolveChannel)
		router.GET(base+"/workspace", messages.GetWorkspace)
		router.GET(base+"/history", messages.ListHistory)
		router.GET(base+"/search", messages.Search)
		router.GET(base+"/messages/:messageId/read-check", messages.ReadCheck)
		router.GET(base+"/scopes/:scopeId/members", messages.ListScopeMembers)

		router.POST(base+"/reactions/get", reactions.Get)
		router.POST(base+"/reactions/add", reactions.Add)
		router.POST(base+"/reactions/remove", reactions.Remove)

		router.POST(base+"/upload", files.Upload)
		router.POST(base+"/avatar", files.Avatar)

		router.DELETE(base+"/review-contexts/:contextId", reviewContexts.DeleteByID)
		router.GET(base+"/tasks/:taskScopeId/review-contexts", reviewContexts.GetTask)
		router.PUT(base+"/tasks/:taskScopeId/review-context", reviewContexts.UpdateTask)
		router.GET(base+"/threads/:threadChannelId/review-context", reviewContexts.GetThread)
		router.PUT(base+"/threads/:threadChannelId/review-context", reviewContexts.UpdateThread)
		router.DELETE(base+"/threads/:threadChannelId/review-context", reviewContexts.DeleteThread)
		router.GET(base+"/threads/:threadChannelId/review-contexts", reviewContexts.ListThread)

		registerAgentAutomationRoutes(router, base, triggers, schedules)
		registerAgentProviderRoutes(router, base, llmProxySessions, agentThreads)

		if dependencies.WorkflowRunCallbacks != nil {
			registerAgentWorkflowStepRoutes(
				router, base, dependencies.Auth, dependencies.WorkflowRunCallbacks, dependencies.Logger,
				dependencies.WorkflowRecovery,
			)
		}
		if dependencies.WorkflowPlans != nil {
			registerAgentWorkflowPlanRoutes(
				router, base, dependencies.Auth, dependencies.WorkflowPlans,
				dependencies.TeamWorkflowPlans,
				dependencies.WorkflowPlanAgentEditGuard, dependencies.WorkflowRecovery,
			)
		}
		if dependencies.WorkflowBindings != nil && dependencies.WorkflowBindingOwners != nil && dependencies.WorkflowBindingWorkspace != nil {
			registerAgentWorkflowBindingRoutes(
				router, base, dependencies.Auth, dependencies.WorkflowBindings,
				dependencies.WorkflowBindingOwners, dependencies.WorkflowBindingWorkspace,
				dependencies.WorkflowRecovery,
			)
		}
		if dependencies.WorkflowRuns != nil {
			registerAgentWorkflowRunRoutes(
				router, base, dependencies.Auth, dependencies.WorkflowRuns,
				dependencies.WorkflowInvocations, dependencies.WorkflowInvocationOwners,
				dependencies.WorkflowInvocationWorkspace, dependencies.WorkflowRecovery,
			)
		}
		registerAgentTaskRoutes(router, base, dependencies.Auth, tasks)
		if dependencies.ProjectStore != nil {
			registerAgentProjectRoutes(router, base, dependencies.Auth, projects)
		}
		registerAgentTeamRoutes(router, base, dependencies.Auth, teams)
		if dependencies.Channels != nil {
			registerAgentChannelRoutes(router, base, dependencies.Auth, channels)
		}
		if dependencies.RoleManagers != nil && dependencies.RoleReads != nil &&
			dependencies.RoleRequests != nil && dependencies.ApprovalSubjects != nil {
			registerAgentRoleRoutes(router, base, dependencies.Auth, roles)
		}
		if dependencies.SkillOwners != nil && dependencies.SkillWorkspace != nil &&
			dependencies.Skills != nil {
			registerAgentSkillRoutes(router, base, dependencies.Auth, skills)
		}
		if dependencies.AgentManagementOwner != nil && dependencies.AgentLifecycleCommands != nil &&
			dependencies.AgentRuntimeControl != nil && dependencies.AgentLifecycleReceipts != nil {
			registerAgentLifecycleManagementRoutes(router, base, dependencies.Auth, management)
		}
		if dependencies.AgentManagementOwner != nil && dependencies.ApprovalSubjects != nil {
			registerAgentStructuralManagementRoutes(router, base, dependencies.Auth, management)
		}
	}

	registerAgentRuntimeRoutes("/api/v1/workspaces/:workspaceId/agents/:agentId/runtime")
}

func registerAgentSkillRoutes(
	router gin.IRoutes,
	base string,
	auth AgentAuthenticator,
	handler *AgentSkillHandler,
) {
	requirePrincipal := RequireAgentRuntimePrincipal(auth)
	options := []api.HandlerOption{
		api.WithInvalidJSONMessage("invalid request body"),
		api.WithStrictJSON(),
	}
	router.GET(base+"/skills", requirePrincipal, api.HandleAgentScoped(handler.List, options...))
	router.POST(base+"/skills/get", requirePrincipal, api.HandleAgentScopedJSON[agentSkillGetRequest](handler.Get, options...))
	router.POST(base+"/skills/create", requirePrincipal, api.HandleAgentScopedJSON[dto.SkillCreateRequest](handler.Create, options...))
	router.POST(base+"/skills/update", requirePrincipal, api.HandleAgentScopedJSON[agentSkillUpdateRequest](handler.Update, options...))
	router.POST(base+"/skills/import", requirePrincipal, api.HandleAgentScoped(handler.Import, options...))
	if handler != nil && handler.approvals != nil {
		router.POST(base+"/skills/delete", requirePrincipal, api.HandleAgentScopedJSON[agentSkillDeleteRequest](handler.Delete, options...))
	}
}

func registerAgentRoleRoutes(
	router gin.IRoutes,
	base string,
	auth AgentAuthenticator,
	handler *AgentRoleHandler,
) {
	requirePrincipal := RequireAgentRuntimePrincipal(auth)
	options := []api.HandlerOption{
		api.WithInvalidJSONMessage("invalid request body"),
		api.WithErrorClassifier(roleAgentErrorClassifier),
		api.WithStrictJSON(),
	}
	router.GET(base+"/roles", requirePrincipal, api.HandleAgentScoped(handler.List, options...))
	router.POST(base+"/roles/get", requirePrincipal, api.HandleAgentScopedJSON[agentRoleGetRequest](handler.Get, options...))
	router.POST(base+"/roles/request-get", requirePrincipal, api.HandleAgentScopedJSON[agentRoleRequestGetRequest](handler.RequestGet, options...))
	router.POST(base+"/roles/create", requirePrincipal, api.HandleAgentScopedJSON[agentRoleCreateRequest](handler.Create, options...))
	router.POST(base+"/roles/update", requirePrincipal, api.HandleAgentScopedJSON[agentRoleUpdateRequest](handler.Update, options...))
	router.POST(base+"/roles/delete", requirePrincipal, api.HandleAgentScopedJSON[agentRoleDeleteRequest](handler.Delete, options...))
	router.POST(base+"/roles/apply", requirePrincipal, api.HandleAgentScopedJSON[agentRoleApplyRequest](handler.Apply, options...))
}

// AgentTeamWorkflowPlanService is the narrow Team-specific Plan boundary used
// by the canonical Agent Workflow Plan route. Team-linked publication is
// direct and leader-authorized; no approval subject is part of this boundary.
type AgentTeamWorkflowPlanService interface {
	Create(context.Context, storeagent.AuthenticatedAgent, teamworkflow.CreateInput) (teamworkflow.CreateResult, error)
	Update(context.Context, storeagent.AuthenticatedAgent, teamworkflow.UpdateInput) (teamworkflow.UpdateResult, error)
	ListAvailable(context.Context, storeagent.AuthenticatedAgent, string, int, string) (teamworkflow.AvailablePage, error)
	InspectPlan(context.Context, storeagent.AuthenticatedAgent, string) (teamworkflow.PlanInspection, bool, error)
	ArchivePlan(context.Context, storeagent.AuthenticatedAgent, string, int64) (planstore.Plan, bool, error)
	RequireUnlinkedPlan(context.Context, string, string) error
}

func registerAgentTeamRoutes(
	router gin.IRoutes,
	base string,
	auth AgentAuthenticator,
	handler *AgentTeamHandler,
) {
	requirePrincipal := RequireAgentRuntimePrincipal(auth)
	options := []api.HandlerOption{
		api.WithInvalidJSONMessage("invalid request body"),
		api.WithErrorClassifier(agentTaskErrorClassifier),
		api.WithStrictJSON(),
	}
	router.GET(
		base+"/teams",
		requirePrincipal,
		api.HandleAgentScoped(handler.List, options...),
	)
	router.POST(
		base+"/teams/get",
		requirePrincipal,
		api.HandleAgentScopedJSON[agentTeamGetRequest](handler.Get, options...),
	)
	router.POST(
		base+"/teams/update",
		requirePrincipal,
		api.HandleAgentScopedJSON[agentTeamUpdateRequest](handler.Update, options...),
	)
}

// channelMutationBodyLimit caps the request body for channel mutation routes
// (create/update/agent-add/agent-remove) at 1 MiB so a direct Agent API caller
// cannot bypass the Desktop 1 MiB body limit and trigger an oversized allocation
// or long transaction before the service-level agent-count check runs.
func channelMutationBodyLimit(c *gin.Context) {
	const maxChannelMutationBodyBytes int64 = 1 << 20 // 1 MiB
	c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, maxChannelMutationBodyBytes)
	c.Next()
}

func registerAgentChannelRoutes(
	router gin.IRoutes,
	base string,
	auth AgentAuthenticator,
	handler *AgentChannelHandler,
) {
	requirePrincipal := RequireAgentRuntimePrincipal(auth)
	options := []api.HandlerOption{
		api.WithInvalidJSONMessage("invalid request body"),
		api.WithErrorClassifier(channelAgentErrorClassifier),
		api.WithStrictJSON(),
	}
	router.GET(base+"/channels", requirePrincipal, api.HandleAgentScoped(handler.List, options...))
	router.POST(base+"/channels/get", requirePrincipal, api.HandleAgentScopedJSON[agentChannelGetRequest](handler.Get, options...))
	router.POST(base+"/channels/members", requirePrincipal, api.HandleAgentScopedJSON[agentChannelMembersRequest](handler.Members, options...))
	router.POST(base+"/channels/create", requirePrincipal, channelMutationBodyLimit, api.HandleAgentScopedJSON[agentChannelCreateRequest](handler.Create, options...))
	router.POST(base+"/channels/update", requirePrincipal, channelMutationBodyLimit, api.HandleAgentScopedJSON[agentChannelUpdateRequest](handler.Update, options...))
	router.POST(base+"/channels/agent-add", requirePrincipal, channelMutationBodyLimit, api.HandleAgentScopedJSON[agentChannelAgentMutationRequest](handler.AgentAdd, options...))
	router.POST(base+"/channels/agent-remove", requirePrincipal, channelMutationBodyLimit, api.HandleAgentScopedJSON[agentChannelAgentMutationRequest](handler.AgentRemove, options...))
}

func agentManagementRouteOptions() []api.HandlerOption {
	return []api.HandlerOption{
		api.WithInvalidJSONMessage("invalid request body"),
		api.WithErrorClassifier(agentManagementErrorClassifier),
		api.WithStrictJSON(),
	}
}

func registerAgentLifecycleManagementRoutes(router gin.IRoutes, base string, auth AgentAuthenticator, handler *AgentManagementHandler) {
	requirePrincipal := RequireAgentRuntimePrincipal(auth)
	options := agentManagementRouteOptions()
	for _, action := range []string{agentops.LifecycleActionStart, agentops.LifecycleActionStop, agentops.LifecycleActionRestart} {
		action := action
		router.POST(base+"/managed-agents/"+action, requirePrincipal,
			api.HandleAgentScopedJSON[agentManagementLifecycleRequest](func(request api.AgentScopedJSON[agentManagementLifecycleRequest]) (api.Response, error) {
				return handler.runLifecycle(request, action)
			}, options...),
		)
	}
}

func registerAgentStructuralManagementRoutes(router gin.IRoutes, base string, auth AgentAuthenticator, handler *AgentManagementHandler) {
	requirePrincipal := RequireAgentRuntimePrincipal(auth)
	options := agentManagementRouteOptions()
	router.POST(base+"/managed-agents/create", requirePrincipal, api.HandleAgentScopedJSON[agentManagementCreateRequest](handler.Create, options...))
	router.POST(base+"/managed-agents/update", requirePrincipal, api.HandleAgentScopedJSON[agentManagementUpdateRequest](handler.Update, options...))
	router.POST(base+"/managed-agents/delete", requirePrincipal, api.HandleAgentScopedJSON[agentManagementDeleteRequest](handler.Delete, options...))
	router.POST(base+"/managed-agents/duplicate", requirePrincipal, api.HandleAgentScopedJSON[agentManagementDuplicateRequest](handler.Duplicate, options...))
}

func registerAgentTaskRoutes(router gin.IRoutes, base string, auth AgentAuthenticator, tasks *TaskHandler) {
	requirePrincipal := RequireAgentRuntimePrincipal(auth)
	options := []api.HandlerOption{
		api.WithInvalidJSONMessage("invalid request body"),
		api.WithErrorClassifier(agentTaskErrorClassifier),
		api.WithStrictJSON(),
	}
	router.GET(base+"/tasks", requirePrincipal, api.HandleAgentScoped(tasks.list, options...))
	router.POST(base+"/tasks/get", requirePrincipal, api.HandleAgentScopedJSON[dto.AgentTaskGetRequest](tasks.get, options...))
	router.POST(base+"/tasks", requirePrincipal, api.HandleAgentScopedJSON[dto.AgentTaskCreateRequest](tasks.create, options...))
	router.POST(base+"/tasks/update", requirePrincipal, api.HandleAgentScopedJSON[dto.AgentTaskUpdateRequest](tasks.update, options...))
	router.POST(base+"/tasks/add-checkpoint", requirePrincipal, api.HandleAgentScopedJSON[dto.AgentTaskCheckpointRequest](tasks.checkpoint, options...))
	router.POST(base+"/tasks/delete", requirePrincipal, api.HandleAgentScopedJSON[dto.AgentTaskDeleteRequest](tasks.del, options...))
	router.POST(base+"/tasks/set-claim", requirePrincipal, api.HandleAgentScopedJSON[dto.AgentTaskSetClaimRequest](tasks.setClaim, options...))
}

func registerAgentProjectRoutes(router gin.IRoutes, base string, auth AgentAuthenticator, projects *ProjectHandler) {
	requirePrincipal := RequireAgentRuntimePrincipal(auth)
	options := []api.HandlerOption{
		api.WithInvalidJSONMessage("invalid request body"),
		api.WithErrorClassifier(agentTaskErrorClassifier),
	}
	router.GET(base+"/projects", requirePrincipal, api.HandleAgentScoped(projects.List, options...))
	router.POST(base+"/projects", requirePrincipal, api.HandleAgentScopedJSON[dto.AgentProjectCreateRequest](projects.Create, options...))
	router.DELETE(base+"/projects/:projectId", requirePrincipal, api.HandleAgentScoped(projects.Delete, options...))
}

func registerAgentAutomationRoutes(router gin.IRoutes, base string, triggers *TriggerHandler, schedules *ScheduleHandler) {
	router.GET(base+"/triggers", triggers.List)
	router.POST(base+"/triggers", triggers.Create)
	router.POST(base+"/triggers/validate", triggers.Validate)
	router.GET(base+"/triggers/:triggerId", triggers.Get)
	router.PATCH(base+"/triggers/:triggerId", triggers.Update)
	router.POST(base+"/triggers/:triggerId/pause", triggers.Pause)
	router.POST(base+"/triggers/:triggerId/resume", triggers.Resume)
	router.DELETE(base+"/triggers/:triggerId", triggers.Delete)
	router.GET(base+"/triggers/:triggerId/runs", triggers.ListRuns)
	router.GET(base+"/schedules", schedules.List)
	router.GET(base+"/schedules/:scheduleId", schedules.Get)
	router.POST(base+"/schedules/:scheduleId/pause", schedules.Pause)
	router.POST(base+"/schedules/:scheduleId/resume", schedules.Resume)
	router.DELETE(base+"/schedules/:scheduleId", schedules.Delete)
	router.GET(base+"/schedules/:scheduleId/runs", schedules.ListRuns)
	router.POST(base+"/schedules", schedules.Create)
	router.POST(base+"/schedules/validate", schedules.Validate)
	router.PATCH(base+"/schedules/:scheduleId", schedules.Update)
}

func registerAgentProviderRoutes(router gin.IRoutes, base string, llmProxySessions *LLMProxySessionHandler, agentThreads *AgentThreadHandler) {
	router.POST(base+"/llm-proxy-session", llmProxySessions.Issue)
	router.POST(base+"/llm-proxy-session/refresh", llmProxySessions.Refresh)
	router.POST(base+"/agent-thread/attestation", agentThreads.Attestation)
	router.POST(base+"/agent-thread/upstream", agentThreads.Upstream)
}
