feat(agent): 云端 Agent - 增加上下文预算、任务事实与终态恢复保障

This commit is contained in:
ddCat
2026-09-19 20:43:20 +08:00
parent 16bd4b923b
commit adf3a5be3c
61 changed files with 3512 additions and 309 deletions

View File

@@ -4,10 +4,18 @@ import "time"
// CloudAgentExecution checkpoints orchestration independently of billed tasks.
type CloudAgentExecution struct {
ID string `gorm:"primaryKey;size:80"`
UserID string `gorm:"index;size:36"`
Status string `gorm:"index;size:32"`
Revision int64
ID string `gorm:"primaryKey;size:80"`
UserID string `gorm:"index;size:36"`
Status string `gorm:"index;size:32"`
Revision int64
CheckpointVersion int `gorm:"not null;default:0"`
ConversationID string `gorm:"index;size:80"`
ParentID string `gorm:"index;size:80"`
Title string `gorm:"size:240"`
EventCount int
MessageCount int
Journal []CloudAgentEventRecord `gorm:"foreignKey:RunID;references:ID" json:"-"`
Transcript []CloudAgentMessageRecord `gorm:"foreignKey:RunID;references:ID" json:"-"`
// Control fields remain writable even when the transcript cannot be decoded or saved.
CanvasID string `gorm:"size:80"`
ActiveTaskID string `gorm:"size:80"`
@@ -19,6 +27,25 @@ type CloudAgentExecution struct {
UpdatedAt time.Time
}
// Journal rows are append-only and commit in the same transaction as the run.
type CloudAgentEventRecord struct {
RunID string `gorm:"primaryKey;size:80"`
Sequence int `gorm:"primaryKey;autoIncrement:false"`
UserID string `gorm:"index;size:36"`
EventJSON string `gorm:"type:text;not null"`
CreatedAt time.Time
}
// Transcript bodies do not share the bounded execution checkpoint. Canonical
// messages may be compacted; the append-only journal retains execution receipts.
type CloudAgentMessageRecord struct {
RunID string `gorm:"primaryKey;size:80"`
Kind string `gorm:"primaryKey;size:24"`
Sequence int `gorm:"primaryKey;autoIncrement:false"`
UserID string `gorm:"index;size:36"`
MessageJSON string `gorm:"type:text;not null"`
}
// CloudAgentCanvasMutation records one atomic canvas change made by an Agent.
// BeforeJSON is intentionally bounded by the application layer; mutations that
// cannot retain a safe snapshot are marked not_undoable instead of truncating it.

View File

@@ -0,0 +1,13 @@
package model
import "time"
// CloudAgentResourceLease pins immutable inputs while a prepared action waits
// for approval. Submitted tasks subsequently own their resource references.
type CloudAgentResourceLease struct {
UserID string `gorm:"primaryKey;size:36"`
RunID string `gorm:"index;size:80"`
OwnerID string `gorm:"primaryKey;size:160"`
ResourceID string `gorm:"primaryKey;size:36;index"`
ExpiresAt time.Time `gorm:"index"`
}

View File

@@ -54,7 +54,9 @@ type BillingOrder struct {
Quantity int64 `json:"quantity"`
AmountMicrocredits int64 `json:"amountMicrocredits"`
ReservedAmountMicrocredits int64 `json:"reservedAmountMicrocredits"`
// ChargeLimitMicrocredits 非零时限制最终用户扣费;Agent 的 Token 报价用它把预授权金额固化为本轮硬上限。
// ChargeLimitSet distinguishes an authorized zero price from an uncapped order.
// All Agent prices remain capped across route changes and settlement.
ChargeLimitSet bool `json:"chargeLimitSet,omitempty" gorm:"not null;default:false"`
ChargeLimitMicrocredits int64 `json:"chargeLimitMicrocredits,omitempty"`
ActualAmountMicrocredits int64 `json:"actualAmountMicrocredits"`
RefundedAmountMicrocredits int64 `json:"refundedAmountMicrocredits"`

View File

@@ -3,24 +3,33 @@ package model
import "time"
type Task struct {
CreationSubmissionID *string `json:"creationSubmissionId,omitempty" gorm:"size:36;uniqueIndex"`
ID string `json:"id" gorm:"primaryKey;size:36"`
UserID string `json:"userId" gorm:"index;size:36;index:idx_tasks_user_created,priority:1;index:idx_tasks_user_project_created,priority:1"`
TraceID string `json:"-" gorm:"index;size:96"`
RequestID string `json:"-" gorm:"index;size:96"`
ProjectID string `json:"projectId" gorm:"index;size:80;index:idx_tasks_user_project_created,priority:2"`
Type string `json:"type" gorm:"index;size:64"`
Status TaskStatus `json:"status" gorm:"index;size:24;index:idx_tasks_status_created,priority:1;index:idx_tasks_claim,priority:1;index:idx_tasks_provider_cancel,priority:1"`
Stage string `json:"stage" gorm:"size:80"`
Progress int `json:"progress"`
Prompt string `json:"prompt"`
Operation string `json:"operation" gorm:"size:64"`
Provider string `json:"provider" gorm:"size:64"`
Model string `json:"model" gorm:"size:120"`
LogicalModelID string `json:"logicalModelId,omitempty" gorm:"size:36;index"`
LogicalModelRevisionID string `json:"logicalModelRevisionId,omitempty" gorm:"size:36;index"`
RouteID string `json:"routeId,omitempty" gorm:"size:36;index"`
ChannelModelID string `json:"channelModelId,omitempty" gorm:"size:36;index"`
AgentRunID string `json:"agentRunId,omitempty" gorm:"size:36;index"`
GenerationID string `json:"generationId,omitempty" gorm:"size:36;index"`
ApprovalID string `json:"approvalId,omitempty" gorm:"size:160"`
AuthorizedChargeMicrocredits int64 `json:"authorizedChargeMicrocredits,omitempty"`
ExecutionDiagnosticJSON string `json:"-" gorm:"type:text"`
Diagnostic *TaskExecutionDiagnostic `json:"diagnostic,omitempty" gorm:"-"`
CancellationSource string `json:"cancellationSource,omitempty" gorm:"size:40"`
CancellationActorID string `json:"cancellationActorId,omitempty" gorm:"size:36"`
CancellationRequestedAt *time.Time `json:"cancellationRequestedAt,omitempty"`
CreationSubmissionID *string `json:"creationSubmissionId,omitempty" gorm:"size:36;uniqueIndex"`
ID string `json:"id" gorm:"primaryKey;size:36"`
UserID string `json:"userId" gorm:"index;size:36;index:idx_tasks_user_created,priority:1;index:idx_tasks_user_project_created,priority:1"`
TraceID string `json:"-" gorm:"index;size:96"`
RequestID string `json:"-" gorm:"index;size:96"`
ProjectID string `json:"projectId" gorm:"index;size:80;index:idx_tasks_user_project_created,priority:2"`
Type string `json:"type" gorm:"index;size:64"`
Status TaskStatus `json:"status" gorm:"index;size:24;index:idx_tasks_status_created,priority:1;index:idx_tasks_claim,priority:1;index:idx_tasks_provider_cancel,priority:1"`
Stage string `json:"stage" gorm:"size:80"`
Progress int `json:"progress"`
Prompt string `json:"prompt"`
Operation string `json:"operation" gorm:"size:64"`
Provider string `json:"provider" gorm:"size:64"`
Model string `json:"model" gorm:"size:120"`
LogicalModelID string `json:"logicalModelId,omitempty" gorm:"size:36;index"`
LogicalModelRevisionID string `json:"logicalModelRevisionId,omitempty" gorm:"size:36;index"`
RouteID string `json:"routeId,omitempty" gorm:"size:36;index"`
ChannelModelID string `json:"channelModelId,omitempty" gorm:"size:36;index"`
// RouteRun 只在用户主动重试时递增;worker 租约恢复不应创建新的路由选择世代。
RouteRun int `json:"-" gorm:"index"`
BillingOrderID string `json:"billingOrderId,omitempty" gorm:"index;size:36"`

View File

@@ -0,0 +1,34 @@
package model
import "time"
const (
TaskCancellationUserRequest = "user_request"
TaskCancellationParentCancelled = "parent_cancelled"
TaskCancellationParentFailed = "parent_failed"
TaskCancellationWorkerContext = "worker_context"
)
// TaskExecutionDiagnostic records execution facts independently of the node's
// presentation state. SafeMessage is suitable for users and model context.
type TaskExecutionDiagnostic struct {
Code string `json:"code"`
Phase string `json:"phase"`
FieldPath string `json:"fieldPath,omitempty"`
TaskSubmitted bool `json:"taskSubmitted"`
SubmissionOutcome string `json:"submissionOutcome"`
RetryClass string `json:"retryClass"`
SafeMessage string `json:"safeMessage"`
DiagnosticID string `json:"diagnosticId"`
WritebackOutcome string `json:"writebackOutcome,omitempty"`
WritebackReason string `json:"writebackReason,omitempty"`
WritebackNodeID string `json:"writebackNodeId,omitempty"`
WritebackMessage string `json:"writebackMessage,omitempty"`
}
type TaskCancellationIntent struct {
Source string
ActorID string
RequestedAt time.Time
Diagnostic TaskExecutionDiagnostic
}