Documentation
¶
Overview ¶
Package controlapi contains stateless HTTP handlers for Fort's cloud control plane. Durable state and execution are supplied through explicit ports; a handler must not start a scheduler, runtime, or permanent listener.
Index ¶
- Constants
- Variables
- func AccountIDFromContext(ctx context.Context) (string, bool)
- func AgentCanonicalConversationHandler(repository AgentConversationReader) http.Handler
- func AgentConversationCreateHandler(repository AgentConversationCreateRepository, clock func() time.Time) http.Handler
- func AgentConversationMutationHandler(repository AgentConversationMutationRepository, clock func() time.Time) http.Handler
- func AgentConversationProjectionHandler(repository ReadAgentConversationRepository) http.Handler
- func AgentConversationTurnsHandler(repository SendAgentTurnRepository, clock func() time.Time) http.Handler
- func AgentConversationsHandler(repository AgentConversationReader) http.Handler
- func AgentCreateHandler(repository AgentCreateRepository, resolver AgentOptionResolver, ...) http.Handler
- func AgentDetailHandler(repository AgentReader) http.Handler
- func AgentMutationHandler(repository AgentMutationRepository, clock func() time.Time) http.Handler
- func AgentRebindHandler(repository AgentRebindRepository, resolver AgentOptionResolver, ...) http.Handler
- func AgentTargetCancelHandler(repository CancelAgentTargetRepository, clock func() time.Time) http.Handler
- func AgentTargetRetryHandler(repository RetryAgentTargetRepository, clock func() time.Time) http.Handler
- func AgentsHandler(repository AgentLister) http.Handler
- func CloudWriteAuthorityActive(getenv func(string) string) bool
- func CronHandler(config CronHandlerConfig, provider ScheduleTickerProvider) http.Handler
- func CursorHandler(reader CursorReader) http.Handler
- func GroupCreateHandler(repository GroupCreateRepository, clock func() time.Time) http.Handler
- func GroupDetailHandler(repository GroupDetailRepository) http.Handler
- func GroupMembersHandler(repository GroupMembersRepository, clock func() time.Time) http.Handler
- func GroupMutationHandler(repository GroupMutationRepository, clock func() time.Time) http.Handler
- func GroupTurnsHandler(repository GroupTurnRepository, clock func() time.Time) http.Handler
- func GroupsHandler(repository GroupLister) http.Handler
- func HandoffCancelHandler(repository HandoffCancelRepository, clock func() time.Time) http.Handler
- func HandoffCreateHandler(repository HandoffCreateRepository, clock func() time.Time) http.Handler
- func HandoffDetailHandler(repository HandoffDetailRepository) http.Handler
- func HandoffsHandler(repository HandoffListRepository) http.Handler
- func HealthHandler(info BuildInfo) http.Handler
- func IssueServiceAssertion(key []byte, assertion ServiceAssertion) (string, error)
- func RequireServiceAssertion(verifier ServiceAssertionVerifier, routeClass string, next http.Handler) http.Handler
- func RoutineMutationHandler(repository RoutineOwnerRepository, clock func() time.Time) http.Handler
- func RoutineRunsHandler(repository RoutineOwnerRepository) http.Handler
- func RoutineTestHandler(repository RoutineOwnerRepository, clock func() time.Time) http.Handler
- func RoutinesHandler(repository RoutineOwnerRepository, clock func() time.Time) http.Handler
- func WorkerHandler(repository WorkerRepository, clock func() time.Time) http.Handler
- func WorkerOutputMessageRecordID(targetID, executionAttemptID string, fenceToken int64) string
- type AgentConversationCreateRepository
- type AgentConversationMutationRepository
- type AgentConversationReader
- type AgentCreateRepository
- type AgentDirectChatRepository
- type AgentLifecycleCommandRepository
- type AgentLister
- type AgentMutationRepository
- type AgentOptionResolver
- type AgentReader
- type AgentRebindRepository
- type BuildInfo
- type CancelAgentTargetRepository
- type CronHandlerConfig
- type CursorEvent
- type CursorPage
- type CursorReader
- type EligibleAgentOption
- type EncryptedEnvelope
- type GroupCreateRepository
- type GroupDetailRepository
- type GroupLister
- type GroupMembersRepository
- type GroupMutationRepository
- type GroupTurnRepository
- type HandoffCancelRepository
- type HandoffCreateRepository
- type HandoffDetailRepository
- type HandoffListRepository
- type HumanHandoffRepository
- type MachineCredential
- type MachineCredentialState
- type NonceClaimer
- type ReadAgentConversationRepository
- type RebindAcceptanceGrant
- type RebindAcceptanceTokens
- type RetryAgentTargetRepository
- type RoutineOccurrence
- type RoutineOccurrenceState
- type RoutineOwnerRepository
- type RoutineSchedule
- type ScheduleRepository
- type ScheduleTickResult
- type ScheduleTickService
- type ScheduleTickTransaction
- type ScheduleTicker
- type ScheduleTickerProvider
- type SendAgentTurnRepository
- type ServiceAssertion
- type ServiceAssertionVerifier
- type WorkerArtifact
- type WorkerArtifactChunk
- type WorkerArtifactChunkCommand
- type WorkerArtifactCreateCommand
- type WorkerArtifactFinalizeCommand
- type WorkerArtifactStatusCommand
- type WorkerAssignment
- type WorkerCancellationAck
- type WorkerCancellationAckCommand
- type WorkerClaimCommand
- type WorkerClaimNextCommand
- type WorkerContextArtifactReference
- type WorkerContextItem
- type WorkerContextMessage
- type WorkerContextPage
- type WorkerContextPageCommand
- type WorkerContextRepository
- type WorkerExecutionBinding
- type WorkerLeaseHeartbeatCommand
- type WorkerLeaseHeartbeatResult
- type WorkerOutputReference
- type WorkerReadinessCommand
- type WorkerReadinessResult
- type WorkerRepository
- type WorkerTerminalCommand
- type WorkerTerminalResult
Constants ¶
const ( // MaximumFunctionBodyBytes is Fort's normative encoded request/response // limit, kept below Vercel's platform limit. MaximumFunctionBodyBytes = 4 << 20 ServiceAssertionHeader = "X-Fort-Service-Assertion" )
const ( // DefaultScheduleCatchUp bounds how much scheduler downtime one invocation // reconciles. Older gaps require explicit operator attention rather than an // unbounded Vercel invocation. DefaultScheduleCatchUp = 5 * time.Minute // DefaultScheduleLookAhead materializes the next minute without making its // occurrences worker-claimable before their exact due time. DefaultScheduleLookAhead = time.Minute // MaximumScheduleRoutines and MaximumScheduleOccurrences are hard one-shot // work limits. Exceeding either aborts the transaction and its watermark. MaximumScheduleRoutines = 128 MaximumScheduleOccurrences = 512 MaximumScheduleLateness = 90 * time.Second // MaximumExpiredWorkerLeaseRecoveries bounds the worker recovery work // performed by one scheduled invocation. MaximumExpiredWorkerLeaseRecoveries = 128 // MaximumLateRoutineRunExpirations bounds persisted Routine lateness // reconciliation performed by one scheduled invocation. MaximumLateRoutineRunExpirations = 128 )
const ( WorkerAccountHeader = "X-Fort-Account-ID" WorkerIDHeader = "X-Fort-Worker-ID" WorkerMachineHeader = "X-Fort-Machine-ID" DefaultWorkerLease = 2 * time.Minute // WorkerOutputMessageRecordType is the authenticated-encryption scope for // a renderable terminal output before the control plane persists it as an // authoritative Conversation message. WorkerOutputMessageRecordType = "worker_output_message" MaximumArtifactChunkPlaintextBytes = 2 << 20 MaximumArtifactChunks = 64 MaximumArtifactPlaintextBytes = 128 << 20 MaximumArtifactEncodedBytes = MaximumArtifactChunks * MaximumFunctionBodyBytes )
const ( // MaximumWorkerContextPageEncodedBytes is the normative JSON response // boundary from Spec 047. It includes the trailing newline written by the // worker handler. MaximumWorkerContextPageEncodedBytes = 1 << 20 MaximumWorkerContextPageItems = 256 MaximumWorkerContextCursorBytes = 2048 WorkerContextMessageKind = "message" WorkerContextArtifactKind = "artifact" )
const CloudWriteAuthorityMode = "cloud_v2_write"
const MaximumCursorPageBytes = 1 << 20
Variables ¶
var ( ErrAssertionInvalid = errors.New("service assertion invalid") ErrAssertionSignature = errors.New("service assertion signature invalid") ErrAssertionAudience = errors.New("service assertion audience mismatch") ErrAssertionRoute = errors.New("service assertion route mismatch") ErrAssertionDigest = errors.New("service assertion request digest mismatch") ErrAssertionExpired = errors.New("service assertion expired") ErrAssertionNotYetValid = errors.New("service assertion not yet valid") ErrAssertionReplay = errors.New("service assertion replayed") ErrAssertionNonceStore = errors.New("service assertion nonce store unavailable") )
var ( ErrScheduleClockNotMonotonic = errors.New("schedule tick clock is not monotonic") ErrScheduleTickBoundExceeded = errors.New("schedule tick bound exceeded") )
var ( ErrWorkerNotFound = errors.New("worker not found") ErrWorkerRevoked = errors.New("worker credential revoked") ErrWorkerNoCompatibleTarget = errors.New("worker target is not compatible") ErrWorkerStaleLease = errors.New("worker lease or fence is stale") ErrWorkerIdempotencyConflict = errors.New("worker idempotency key conflicts") ErrWorkerRequestInvalid = errors.New("worker request is invalid") ErrWorkerArtifactIncomplete = errors.New("worker artifact is incomplete") )
var ErrAssertionConfiguration = errors.New("service assertion configuration invalid")
var ErrNoEligibleAgentOption = errors.New("no approved eligible Agent option")
var (
ErrWorkerContextPageLimit = errors.New("worker context page exceeds payload limit")
)
Functions ¶
func AccountIDFromContext ¶
AccountIDFromContext returns the account authenticated by the signed fort-gateway assertion. Handlers must not read account identity from input.
func AgentCanonicalConversationHandler ¶
func AgentCanonicalConversationHandler(repository AgentConversationReader) http.Handler
func AgentConversationCreateHandler ¶
func AgentConversationCreateHandler(repository AgentConversationCreateRepository, clock func() time.Time) http.Handler
AgentConversationCreateHandler creates only a secondary Conversation. The verified account, stable Agent parent, identifiers, state, actor, and times are all allocated by the control plane rather than accepted from a client.
func AgentConversationMutationHandler ¶
func AgentConversationMutationHandler(repository AgentConversationMutationRepository, clock func() time.Time) http.Handler
AgentConversationMutationHandler exposes one closed mutation vocabulary for secondary Conversations. Repositories enforce the canonical Home guard and the complete account -> Agent -> Conversation parent chain.
func AgentConversationProjectionHandler ¶
func AgentConversationProjectionHandler(repository ReadAgentConversationRepository) http.Handler
AgentConversationProjectionHandler returns the complete durable projection for one Conversation only after verifying its stable Agent parent.
func AgentConversationTurnsHandler ¶
func AgentConversationTurnsHandler(repository SendAgentTurnRepository, clock func() time.Time) http.Handler
AgentConversationTurnsHandler creates one direct human message, frozen context, Turn, and exact current-Agent target in the repository transaction.
func AgentConversationsHandler ¶
func AgentConversationsHandler(repository AgentConversationReader) http.Handler
func AgentCreateHandler ¶
func AgentCreateHandler(repository AgentCreateRepository, resolver AgentOptionResolver, clock func() time.Time) http.Handler
func AgentDetailHandler ¶
func AgentDetailHandler(repository AgentReader) http.Handler
func AgentMutationHandler ¶
func AgentMutationHandler(repository AgentMutationRepository, clock func() time.Time) http.Handler
func AgentRebindHandler ¶
func AgentRebindHandler(repository AgentRebindRepository, resolver AgentOptionResolver, tokens RebindAcceptanceTokens, clock func() time.Time) http.Handler
func AgentTargetCancelHandler ¶
func AgentTargetCancelHandler(repository CancelAgentTargetRepository, clock func() time.Time) http.Handler
AgentTargetCancelHandler durably requests cancellation for the exact target. The repository preserves its parent chain and accepted revision pins.
func AgentTargetRetryHandler ¶
func AgentTargetRetryHandler(repository RetryAgentTargetRepository, clock func() time.Time) http.Handler
AgentTargetRetryHandler requeues the same exact target. The repository retains its original Behavior and Binding Revision pins.
func AgentsHandler ¶
func AgentsHandler(repository AgentLister) http.Handler
func CloudWriteAuthorityActive ¶
CloudWriteAuthorityActive is the fail-closed deployment fence shared by owner commands and execution workers. Reads remain available in rollback mode, but no v2 mutation may reach Postgres until one exact positive epoch designates the cloud control plane as the sole write authority.
func CronHandler ¶
func CronHandler(config CronHandlerConfig, provider ScheduleTickerProvider) http.Handler
CronHandler authenticates and runs one bounded tick. In legacy_v1_write rollback mode it remains authenticated but performs no database operation.
func CursorHandler ¶
func CursorHandler(reader CursorReader) http.Handler
CursorHandler serves the bounded JSON half of the Node SSE reconnect loop.
func GroupCreateHandler ¶
func GroupCreateHandler(repository GroupCreateRepository, clock func() time.Time) http.Handler
func GroupDetailHandler ¶
func GroupDetailHandler(repository GroupDetailRepository) http.Handler
func GroupMembersHandler ¶
func GroupMembersHandler(repository GroupMembersRepository, clock func() time.Time) http.Handler
GroupMembersHandler replaces the complete ordered stable-Agent membership. Behavior, Binding, participant, revision number, IDs, actor, and time are resolved by Fort and cannot be selected by the client.
func GroupMutationHandler ¶
func GroupMutationHandler(repository GroupMutationRepository, clock func() time.Time) http.Handler
GroupMutationHandler exposes the closed presentation/state lifecycle for a stable Group. It never accepts membership or execution revision fields.
func GroupTurnsHandler ¶
func GroupTurnsHandler(repository GroupTurnRepository, clock func() time.Time) http.Handler
func GroupsHandler ¶
func GroupsHandler(repository GroupLister) http.Handler
func HandoffCancelHandler ¶
func HandoffCancelHandler(repository HandoffCancelRepository, clock func() time.Time) http.Handler
func HandoffCreateHandler ¶
func HandoffCreateHandler(repository HandoffCreateRepository, clock func() time.Time) http.Handler
func HandoffDetailHandler ¶
func HandoffDetailHandler(repository HandoffDetailRepository) http.Handler
func HandoffsHandler ¶
func HandoffsHandler(repository HandoffListRepository) http.Handler
func HealthHandler ¶
HealthHandler reports only public deployment compatibility metadata.
func IssueServiceAssertion ¶
func IssueServiceAssertion(key []byte, assertion ServiceAssertion) (string, error)
IssueServiceAssertion creates a compact HS256 assertion. The assertion key must contain at least 256 bits of secret material.
func RequireServiceAssertion ¶
func RequireServiceAssertion( verifier ServiceAssertionVerifier, routeClass string, next http.Handler, ) http.Handler
RequireServiceAssertion bounds and digests the exact request body, verifies the gateway assertion, and injects only its signed account into context.
func RoutineMutationHandler ¶
func RoutineMutationHandler(repository RoutineOwnerRepository, clock func() time.Time) http.Handler
func RoutineRunsHandler ¶
func RoutineRunsHandler(repository RoutineOwnerRepository) http.Handler
RoutineRunsHandler exposes the durable attempt, lease, failure, next-action, and result history for one exact Agent-owned Routine.
func RoutineTestHandler ¶
func RoutineTestHandler(repository RoutineOwnerRepository, clock func() time.Time) http.Handler
func RoutinesHandler ¶
func RoutinesHandler(repository RoutineOwnerRepository, clock func() time.Time) http.Handler
RoutinesHandler lists or creates Agent-owned fort_cloud Routines. The stable Agent parent and current Behavior/Binding pins are always resolved by the server; the client supplies only Routine semantics and idempotency.
func WorkerHandler ¶
func WorkerHandler(repository WorkerRepository, clock func() time.Time) http.Handler
WorkerHandler serves one bounded POST /api/v2/worker command. Machine authentication is intentionally independent from owner assertions and cron secrets, and completes before a request can invoke account-scoped work.
func WorkerOutputMessageRecordID ¶
WorkerOutputMessageRecordID binds a renderable output envelope to one exact target execution fence. Account identity is the remaining securebody scope component, so a stale or cross-account envelope cannot be replayed.
Types ¶
type AgentConversationCreateRepository ¶
type AgentConversationCreateRepository interface {
CreateSecondaryConversation(context.Context, ledger.CreateSecondaryConversationCommand) (ledger.AgentConversationRecord, error)
}
type AgentConversationMutationRepository ¶
type AgentConversationMutationRepository interface {
RenameAgentConversation(context.Context, ledger.RenameAgentConversationCommand) (ledger.AgentConversationRecord, error)
SetAgentConversationState(context.Context, ledger.SetAgentConversationStateCommand) (ledger.AgentConversationRecord, error)
SetAgentConversationPin(context.Context, ledger.SetAgentConversationPinCommand) (ledger.AgentConversationRecord, error)
}
type AgentConversationReader ¶
type AgentCreateRepository ¶
type AgentCreateRepository interface {
CreateAgent(context.Context, ledger.CreateAgentCommand) (ledger.AgentRecord, error)
}
type AgentDirectChatRepository ¶
type AgentDirectChatRepository interface {
ReadAgentConversationRepository
SendAgentTurnRepository
RetryAgentTargetRepository
CancelAgentTargetRepository
}
type AgentLifecycleCommandRepository ¶
type AgentLifecycleCommandRepository interface {
AgentCreateRepository
AgentRebindRepository
}
type AgentLister ¶
type AgentLister interface {
ListAgents(context.Context, string, conversation.AgentState) ([]ledger.AgentRecord, error)
}
AgentLister is the read-only owner projection required by the v2 Agent roster. The account always comes from the verified gateway assertion.
type AgentMutationRepository ¶
type AgentMutationRepository interface {
GetAgent(context.Context, string, string) (ledger.AgentRecord, error)
AppendAgentProfile(context.Context, ledger.AppendAgentProfileCommand) (ledger.AgentRecord, error)
AppendAgentBehavior(context.Context, ledger.AppendAgentBehaviorCommand) (ledger.AgentBindingAdvanceResult, error)
}
AgentMutationRepository is the owner-facing presentation/behavior seam. The handler can advance Fort-owned revisions but cannot select or alter any provider, model, machine, adapter, authority, policy, or source identity.
type AgentOptionResolver ¶
type AgentOptionResolver interface {
ResolveEligibleAgentOption(context.Context, string, string) (EligibleAgentOption, error)
}
func NoEligibleAgentOptions ¶
func NoEligibleAgentOptions() AgentOptionResolver
NoEligibleAgentOptions is the production-safe default. Enrollment and Rebind remain unavailable until composition injects an approved inventory.
type AgentReader ¶
type AgentRebindRepository ¶
type AgentRebindRepository interface {
GetAgent(context.Context, string, string) (ledger.AgentRecord, error)
PreviewAgentRebind(context.Context, ledger.PreviewAgentRebindCommand) (ledger.AgentRebindPreview, error)
AcceptAgentRebind(context.Context, ledger.AcceptAgentRebindCommand) (ledger.AgentBindingAdvanceResult, error)
}
type BuildInfo ¶
type BuildInfo struct {
Commit string
SchemaVersion string
APIMinVersion int
APIMaxVersion int
AuthorityEpoch int64
AuthorityMode string
}
BuildInfo identifies the exact compatible deployment pair. AuthorityMode is intentionally explicit so clients never infer the write owner from reachability.
type CancelAgentTargetRepository ¶
type CancelAgentTargetRepository interface {
CancelAgentTarget(ctx context.Context, command ledger.CancelAgentTargetCommand) (ledger.AgentConversationTarget, error)
}
type CronHandlerConfig ¶
type CronHandlerConfig struct {
Secret string
AuthorityMode string
AccountID string
SchedulerID string
}
CronHandlerConfig contains no database-selected account input. AccountID is trusted server configuration for this single-account first release.
type CursorEvent ¶
type CursorPage ¶
type CursorPage struct {
Events []CursorEvent `json:"events"`
NextCursor string `json:"next_cursor"`
}
type CursorReader ¶
CursorReader returns durable events after one exact cursor. Implementations may long-poll, but must return before the bounded request context expires.
type EligibleAgentOption ¶
type EligibleAgentOption struct {
ID string `json:"id"`
ExecutionSource conversation.ExecutionSource `json:"execution_source"`
SourceAgent conversation.SourceAgent `json:"source_agent"`
Binding conversation.AgentBindingRevision `json:"binding"`
NonTransferableResources []ledger.RebindResource `json:"non_transferable_resources"`
ReadinessEvidence []string `json:"readiness_evidence"`
AuthorityEvidence []string `json:"authority_evidence"`
}
EligibleAgentOption is server-held execution evidence selected by one opaque ID. Identity, revision, seat, and activation fields are deliberately absent from the option and are allocated by Fort for each command.
type EncryptedEnvelope ¶
type GroupCreateRepository ¶
type GroupCreateRepository interface {
GetAgent(context.Context, string, string) (ledger.AgentRecord, error)
CreateGroup(context.Context, ledger.CreateGroupCommand) (ledger.GroupRecord, error)
}
type GroupDetailRepository ¶
type GroupLister ¶
type GroupLister interface {
ListGroups(context.Context, string, conversation.ConversationState) ([]ledger.GroupRecord, error)
}
GroupLister is the minimal owner projection for the stable Group roster. Account identity always comes from a verified gateway assertion.
type GroupMembersRepository ¶
type GroupMutationRepository ¶
type GroupMutationRepository interface {
RenameGroup(context.Context, ledger.RenameGroupCommand) (ledger.GroupRecord, error)
SetGroupState(context.Context, ledger.SetGroupStateCommand) (ledger.GroupRecord, error)
}
type GroupTurnRepository ¶
type HandoffCancelRepository ¶
type HandoffCancelRepository interface {
CancelHandoff(context.Context, ledger.CancelHandoffCommand) (ledger.HandoffRecord, error)
}
type HandoffCreateRepository ¶
type HandoffCreateRepository interface {
CreateHumanHandoff(context.Context, ledger.CreateHumanHandoffCommand) (ledger.HandoffRecord, error)
}
type HandoffDetailRepository ¶
type HandoffListRepository ¶
type HumanHandoffRepository ¶
type HumanHandoffRepository interface {
HandoffCreateRepository
HandoffListRepository
HandoffDetailRepository
HandoffCancelRepository
}
HumanHandoffRepository is the bounded owner-facing persistence contract. Execution identity and immutable revision evidence are resolved below this seam; handlers accept only human intent and an idempotency key.
type MachineCredential ¶
type MachineCredential struct {
AccountID string
WorkerID string
MachineID string
TokenHash string
State MachineCredentialState
}
MachineCredential is server-side enrollment evidence. TokenHash is the lowercase SHA-256 digest of a random bearer; raw machine tokens are never passed into the persistence layer.
type MachineCredentialState ¶
type MachineCredentialState string
const ( MachineCredentialEnrolled MachineCredentialState = "enrolled" MachineCredentialOffline MachineCredentialState = "offline" MachineCredentialRevoked MachineCredentialState = "revoked" )
type NonceClaimer ¶
type NonceClaimer interface {
Claim(context.Context, string, string, string, time.Time) (bool, error)
}
NonceClaimer atomically records a nonce until the assertion expires. A production implementation must be durable and shared by all function instances; an in-memory implementation is not safe for deployment.
type RebindAcceptanceGrant ¶
type RebindAcceptanceGrant struct {
Audience string `json:"aud"`
Route string `json:"route"`
AccountID string `json:"account_id"`
AgentID string `json:"agent_id"`
OptionID string `json:"option_id"`
Preview ledger.AgentRebindPreview `json:"preview"`
IssuedAt time.Time `json:"issued_at"`
ExpiresAt time.Time `json:"expires_at"`
}
RebindAcceptanceGrant is the complete server-issued disclosure accepted by the human. It is never decoded from an unsigned request body.
type RebindAcceptanceTokens ¶
type RebindAcceptanceTokens interface {
Issue(RebindAcceptanceGrant) (string, time.Time, error)
Verify(string, time.Time) (RebindAcceptanceGrant, error)
}
func HMACRebindAcceptanceTokensFromEnvironment ¶
func HMACRebindAcceptanceTokensFromEnvironment(getenv func(string) string) (RebindAcceptanceTokens, error)
HMACRebindAcceptanceTokensFromEnvironment loads the dedicated, server-only Rebind acceptance key. It intentionally does not fall back to assertion, body-encryption, or client-session key material.
func NewHMACRebindAcceptanceTokens ¶
func NewHMACRebindAcceptanceTokens(key []byte, ttl time.Duration) (RebindAcceptanceTokens, error)
type RetryAgentTargetRepository ¶
type RetryAgentTargetRepository interface {
RetryAgentTarget(ctx context.Context, command ledger.RetryAgentTargetCommand) (ledger.AgentConversationTarget, error)
}
type RoutineOccurrence ¶
type RoutineOccurrence struct {
OccurrenceID string
RoutineID string
RoutineRevisionID string
ScheduledFor time.Time
State RoutineOccurrenceState
IdempotencyKey string
RecordedAt time.Time
}
RoutineOccurrence is the exact durable timestamp materialized by a tick. OccurrenceID and IdempotencyKey are deterministic functions of RoutineID and ScheduledFor, so recycled or overlapping functions converge on one row.
type RoutineOccurrenceState ¶
type RoutineOccurrenceState string
RoutineOccurrenceState deliberately separates future materialization from work eligibility. Workers may claim only queued occurrences.
const ( OccurrenceScheduled RoutineOccurrenceState = "scheduled" OccurrenceQueued RoutineOccurrenceState = "queued" OccurrenceMissedNeedsAttention RoutineOccurrenceState = "missed_needs_attention" )
type RoutineOwnerRepository ¶
type RoutineOwnerRepository interface {
AgentReader
ListRoutines(context.Context, string, string) ([]ledger.RoutineRecord, error)
CreateRoutine(context.Context, ledger.CreateRoutineCommand) (ledger.RoutineRecord, error)
GetRoutine(context.Context, string, string) (ledger.RoutineRecord, error)
ListRoutineRuns(context.Context, string, string) ([]ledger.RoutineRunRecord, error)
RevalidateRoutine(context.Context, ledger.RevalidateRoutineCommand) (ledger.RoutineRecord, error)
EnqueueRoutineOccurrence(context.Context, ledger.EnqueueRoutineOccurrenceCommand) (ledger.RoutineRunRecord, error)
}
type RoutineSchedule ¶
type RoutineSchedule struct {
RoutineID string
RoutineRevisionID string
Expression string
Timezone string
StartsAt time.Time
}
RoutineSchedule is the immutable scheduling portion of one active fort_cloud Routine revision.
type ScheduleRepository ¶
type ScheduleRepository interface {
WithScheduleTick(context.Context, string, string, func(ScheduleTickTransaction) error) (acquired bool, err error)
}
ScheduleRepository provides one bounded, atomic schedule-tick transaction. A false acquired result means another invocation owns the advisory lock.
type ScheduleTickResult ¶
type ScheduleTickResult struct {
Status string `json:"status"`
TickID string `json:"tick_id,omitempty"`
Watermark time.Time `json:"watermark,omitempty"`
OccurrencesChanged int `json:"occurrences_changed"`
InvalidRoutinesSkipped int `json:"invalid_routines_skipped"`
ExpiredLeasesRecovered int `json:"expired_leases_recovered"`
LateRoutineRunsExpired int `json:"late_routine_runs_expired"`
}
ScheduleTickResult is safe operational metadata returned to Vercel Cron.
type ScheduleTickService ¶
type ScheduleTickService struct {
Repository ScheduleRepository
Clock func() time.Time
TickIDs func() string
}
ScheduleTickService deterministically expands six-field cron schedules inside a single repository transaction.
func (ScheduleTickService) Tick ¶
func (service ScheduleTickService) Tick(ctx context.Context, accountID, schedulerID string) (ScheduleTickResult, error)
Tick performs exactly one bounded reconciliation and then returns.
type ScheduleTickTransaction ¶
type ScheduleTickTransaction interface {
Watermark(context.Context, string) (time.Time, bool, error)
RecoverExpiredWorkerLeases(context.Context, time.Time, int) (int, error)
ExpireLateRoutineRuns(context.Context, time.Time, int) (int, error)
ActiveRoutineSchedules(context.Context, int) ([]RoutineSchedule, error)
ApplyOccurrence(context.Context, RoutineOccurrence) (bool, error)
SaveWatermark(context.Context, string, string, time.Time) error
}
ScheduleTickTransaction is an account-scoped database transaction holding both the advisory lock and the watermark row lock for one scheduler.
type ScheduleTicker ¶
ScheduleTicker is the narrow handler seam; it cannot run a provider or a permanent scheduler loop.
type ScheduleTickerProvider ¶
type ScheduleTickerProvider func(context.Context) (ScheduleTicker, error)
ScheduleTickerProvider is invoked only after method, secret, authority mode, and static scope validation have succeeded.
type SendAgentTurnRepository ¶
type SendAgentTurnRepository interface {
SendAgentTurn(ctx context.Context, command ledger.SendAgentTurnCommand) (ledger.AgentTurnDispatch, error)
}
type ServiceAssertion ¶
type ServiceAssertion struct {
KeyID string
AccountID string
RouteClass string
Audience string
RequestDigest string
IssuedAt time.Time
ExpiresAt time.Time
Nonce string
}
ServiceAssertion is the short-lived, server-to-server identity envelope used between fort-gateway and fort-control. AccountID is derived by the gateway from its authenticated owner session and is never accepted from a client.
type ServiceAssertionVerifier ¶
type ServiceAssertionVerifier struct {
Audience string
Keys map[string][]byte
Clock func() time.Time
Nonces NonceClaimer
MaxTTL time.Duration
ClockSkew time.Duration
}
ServiceAssertionVerifier verifies signed gateway assertions and consumes their nonces exactly once.
func ServiceAssertionVerifierFromEnvironment ¶
func ServiceAssertionVerifierFromEnvironment( getenv func(string) string, nonces NonceClaimer, ) (ServiceAssertionVerifier, error)
ServiceAssertionVerifierFromEnvironment loads the control-side verification key ring. The gateway carries one active signing key, while control may authenticate multiple explicitly configured keys during a bounded rotation.
func (ServiceAssertionVerifier) Verify ¶
func (verifier ServiceAssertionVerifier) Verify( ctx context.Context, token string, routeClass string, requestDigest string, ) (ServiceAssertion, error)
Verify authenticates an assertion against the exact request route class and SHA-256 body digest, then atomically consumes its nonce.
type WorkerArtifact ¶
type WorkerArtifact struct {
ArtifactID string `json:"artifact_id"`
ExecutionAttemptID string `json:"execution_attempt_id"`
Kind string `json:"kind"`
State string `json:"state"`
ExpectedChunkCount int `json:"expected_chunk_count"`
ExpectedPlaintextLength int64 `json:"expected_plaintext_length"`
ExpectedEncodedLength int64 `json:"expected_encoded_length"`
LogicalDigest string `json:"logical_digest"`
EncryptionKeyID string `json:"encryption_key_id"`
Chunks []WorkerArtifactChunk `json:"chunks"`
CreatedAt time.Time `json:"created_at"`
FinalizedAt *time.Time `json:"finalized_at,omitempty"`
Created bool `json:"created"`
}
WorkerArtifact is the resumable upload projection returned to a worker. It deliberately contains manifest and receipt metadata only; encrypted chunk bodies remain private Postgres data and never inflate a status response.
type WorkerArtifactChunk ¶
type WorkerArtifactChunk struct {
ArtifactID string `json:"artifact_id"`
ChunkIndex int `json:"chunk_index"`
EncodedLength int `json:"encoded_length"`
PlaintextLength int `json:"plaintext_length"`
EncryptionKeyID string `json:"encryption_key_id"`
AuthenticatedDigest string `json:"authenticated_digest"`
CreatedAt time.Time `json:"created_at"`
Created bool `json:"created"`
}
type WorkerArtifactChunkCommand ¶
type WorkerArtifactChunkCommand struct {
AccountID, WorkerID, MachineID, TargetID, ExecutionAttemptID, LeaseID string
FenceToken int64
IdempotencyKey, ArtifactID string
ChunkIndex int
Plaintext []byte
PlaintextDigest string
// The remaining fields are populated only by the key-ring-enabled
// repository after it encrypts Plaintext. They are never worker input.
Ciphertext []byte
EncodedLength, PlaintextLength int
EncryptionKeyID string
Nonce []byte
AuthenticatedDigest string
CreatedAt time.Time
}
type WorkerArtifactCreateCommand ¶
type WorkerArtifactCreateCommand struct {
AccountID, WorkerID, MachineID, TargetID, ExecutionAttemptID, LeaseID string
FenceToken int64
IdempotencyKey, ArtifactID string
ExpectedChunkCount int
ExpectedPlaintextLength, ExpectedEncodedLength int64
LogicalDigest, EncryptionKeyID string
CreatedAt time.Time
}
type WorkerAssignment ¶
type WorkerAssignment struct {
TargetID string `json:"target_id"`
TargetKind string `json:"target_kind"`
OriginID string `json:"origin_id"`
ExecutionAttemptID string `json:"execution_attempt_id"`
LeaseID string `json:"lease_id"`
FenceToken int64 `json:"fence_token"`
WorkerID string `json:"worker_id"`
MachineID string `json:"machine_id"`
CapabilityRevisionID string `json:"capability_revision_id"`
Pins coreworker.ExecutionPins `json:"pins"`
Execution WorkerExecutionBinding `json:"execution"`
ContextManifestID string `json:"context_manifest_id"`
Prompt string `json:"prompt"`
OutputConversationID string `json:"output_conversation_id"`
OutputMessageKind string `json:"output_message_kind"`
OutputAuthorAgentID string `json:"output_author_agent_id"`
MaximumOutputPlaintextBytes int64 `json:"maximum_output_plaintext_bytes"`
InlineOutputPlaintextBytes int64 `json:"inline_output_plaintext_bytes"`
// PromptEnvelope exists only between the key-ring-enabled repository and
// its decryption boundary. It is never serialized to a worker.
PromptEnvelope EncryptedEnvelope `json:"-"`
ClaimedAt time.Time `json:"claimed_at"`
ExpiresAt time.Time `json:"expires_at"`
HardDeadline time.Time `json:"hard_deadline"`
}
type WorkerCancellationAck ¶
type WorkerCancellationAck struct {
AcknowledgementID string `json:"acknowledgement_id"`
TargetID string `json:"target_id"`
ExecutionAttemptID string `json:"execution_attempt_id"`
LeaseID string `json:"lease_id"`
FenceToken int64 `json:"fence_token"`
AcknowledgedAt time.Time `json:"acknowledged_at"`
}
type WorkerClaimCommand ¶
type WorkerClaimNextCommand ¶
type WorkerClaimNextCommand struct {
AccountID string
WorkerID string
MachineID string
ExecutionAttemptID string
LeaseID string
IdempotencyKey string
CapabilityRevisionID string
ClaimedAt time.Time
ExpiresAt time.Time
}
WorkerClaimNextCommand asks the control plane to atomically select the oldest queued target whose immutable Binding is assigned to this exact worker and machine. Target selection remains server-side so a worker never guesses or scans account work.
type WorkerContextArtifactReference ¶
type WorkerContextArtifactReference struct {
ArtifactID string `json:"artifact_id"`
Kind string `json:"kind"`
ExecutionAttemptID string `json:"execution_attempt_id"`
ExpectedChunkCount int `json:"expected_chunk_count"`
ExpectedPlaintextLength int64 `json:"expected_plaintext_length"`
ExpectedEncodedLength int64 `json:"expected_encoded_length"`
LogicalDigest string `json:"logical_digest"`
CreatedAt time.Time `json:"created_at"`
FinalizedAt time.Time `json:"finalized_at"`
}
type WorkerContextItem ¶
type WorkerContextItem struct {
Kind string `json:"kind"`
Ordinal int `json:"ordinal"`
Message *WorkerContextMessage `json:"message,omitempty"`
Artifact *WorkerContextArtifactReference `json:"artifact,omitempty"`
}
type WorkerContextMessage ¶
type WorkerContextMessage struct {
MessageID int64 `json:"message_id"`
ConversationID string `json:"conversation_id"`
TurnID string `json:"turn_id,omitempty"`
TargetID string `json:"target_id,omitempty"`
HandoffID string `json:"handoff_id,omitempty"`
RoutineRunID string `json:"routine_run_id,omitempty"`
MessageKind string `json:"message_kind"`
AuthorKind string `json:"author_kind"`
AuthorID string `json:"author_id"`
AuthorAgentID string `json:"author_agent_id,omitempty"`
Body string `json:"body"`
CreatedAt time.Time `json:"created_at"`
}
type WorkerContextPage ¶
type WorkerContextPage struct {
ContextManifestID string `json:"context_manifest_id"`
ManifestDigest string `json:"manifest_digest"`
Items []WorkerContextItem `json:"items"`
NextCursor string `json:"next_cursor"`
}
WorkerContextPage contains only decrypted message content and immutable artifact references. Application AEAD keys, ciphertext, nonces, and raw artifact chunks are deliberately not represented by this transport type.
type WorkerContextPageCommand ¶
type WorkerContextPageCommand struct {
AccountID string
WorkerID string
MachineID string
TargetID string
ExecutionAttemptID string
LeaseID string
FenceToken int64
IdempotencyKey string
Cursor string
ObservedAt time.Time
}
WorkerContextPageCommand identifies one exact, actively fenced assignment. ContextManifestID is intentionally absent: the repository resolves the immutable manifest pinned by the target's Turn rather than trusting worker input.
type WorkerContextRepository ¶
type WorkerContextRepository interface {
ReadWorkerContextPage(context.Context, WorkerContextPageCommand) (WorkerContextPage, error)
}
WorkerContextRepository is kept separate from WorkerRepository so rollout remains additive: older endpoint fakes and adapters continue to satisfy the base machine-command contract, while context_page fails closed unless the backing repository explicitly implements this capability.
type WorkerExecutionBinding ¶
type WorkerExecutionBinding struct {
ExecutionSourceID string `json:"execution_source_id"`
SourceAgentID string `json:"source_agent_id"`
OpaqueSourceAgentID string `json:"opaque_source_agent_id"`
FortProfile string `json:"fort_profile"`
Provider string `json:"provider"`
RequestedModel string `json:"requested_model"`
ResolvedModel string `json:"resolved_model"`
AdapterID string `json:"adapter_id"`
AdapterRevision string `json:"adapter_revision"`
SourceConfigDigest string `json:"source_config_digest"`
AuthorityID string `json:"authority_id"`
AuthorityRevision string `json:"authority_revision"`
PolicyID string `json:"policy_id"`
PolicyRevision string `json:"policy_revision"`
SessionBehavior string `json:"session_behavior"`
MemoryBehavior string `json:"memory_behavior"`
CapabilityEvidence json.RawMessage `json:"capability_evidence"`
ReadinessContractID string `json:"readiness_contract_id"`
ReadinessContractRevision string `json:"readiness_contract_revision"`
Workdir string `json:"workdir"`
ComputerID string `json:"computer_id,omitempty"`
CloudRuntime string `json:"cloud_runtime,omitempty"`
}
WorkerExecutionBinding is the immutable execution selector copied from the target's pinned Agent Binding Revision. It contains no provider credential, key material, or server-side application-encryption secret.
type WorkerLeaseHeartbeatResult ¶
type WorkerLeaseHeartbeatResult struct {
TargetID string `json:"target_id"`
ExecutionAttemptID string `json:"execution_attempt_id"`
LeaseID string `json:"lease_id"`
FenceToken int64 `json:"fence_token"`
Directive coreworker.WorkerDirective `json:"directive"`
ExpiresAt time.Time `json:"expires_at"`
}
type WorkerOutputReference ¶
type WorkerReadinessCommand ¶
type WorkerReadinessResult ¶
type WorkerRepository ¶
type WorkerRepository interface {
MachineCredential(context.Context, string, string, string) (MachineCredential, error)
RecordWorkerReadiness(context.Context, WorkerReadinessCommand) (WorkerReadinessResult, error)
ClaimWorkerTarget(context.Context, WorkerClaimCommand) (WorkerAssignment, error)
ClaimNextWorkerTarget(context.Context, WorkerClaimNextCommand) (WorkerAssignment, error)
HeartbeatWorkerLease(context.Context, WorkerLeaseHeartbeatCommand) (WorkerLeaseHeartbeatResult, error)
AcknowledgeWorkerCancellation(context.Context, WorkerCancellationAckCommand) (WorkerCancellationAck, error)
CommitWorkerTerminal(context.Context, WorkerTerminalCommand) (WorkerTerminalResult, error)
CreateWorkerArtifact(context.Context, WorkerArtifactCreateCommand) (WorkerArtifact, error)
GetWorkerArtifactStatus(context.Context, WorkerArtifactStatusCommand) (WorkerArtifact, error)
AppendWorkerArtifactChunk(context.Context, WorkerArtifactChunkCommand) (WorkerArtifactChunk, error)
FinalizeWorkerArtifact(context.Context, WorkerArtifactFinalizeCommand) (WorkerArtifact, error)
}
WorkerRepository is the narrow server-side command seam. Implementations receive an already authenticated account/worker/machine identity and retain all atomic claim, lease, fence, and receipt rules inside the ledger adapter.
type WorkerTerminalCommand ¶
type WorkerTerminalCommand struct {
AccountID string
WorkerID string
MachineID string
TargetID string
ExecutionAttemptID string
LeaseID string
FenceToken int64
TerminalReceiptID string
IdempotencyKey string
Status coreworker.TerminalStatus
ReceiptPlaintext json.RawMessage
OutputMessagePlaintext *string
// Receipt and OutputMessage are populated only by the key-ring-enabled
// repository. Authenticated workers submit bounded plaintext over TLS and
// never receive or use the application AEAD key.
Receipt EncryptedEnvelope
Output WorkerOutputReference
OutputMessage *EncryptedEnvelope
CommittedAt time.Time
}
type WorkerTerminalResult ¶
type WorkerTerminalResult struct {
TargetID string `json:"target_id"`
ExecutionAttemptID string `json:"execution_attempt_id"`
LeaseID string `json:"lease_id"`
FenceToken int64 `json:"fence_token"`
TerminalReceiptID string `json:"terminal_receipt_id"`
Status coreworker.TerminalStatus `json:"status"`
Output WorkerOutputReference `json:"output"`
MessageID int64 `json:"message_id,omitempty"`
CommittedAt time.Time `json:"committed_at"`
Created bool `json:"created"`
}