Files

370 lines
13 KiB
Go

package controlplane
import (
"encoding/json"
"time"
)
const ProtocolVersion = "v1"
const MaxTaskResultBytes = 512 * 1024
type TaskStatus string
const (
TaskPending TaskStatus = "Pending"
TaskWaitingForClient TaskStatus = "WaitingForClient"
TaskAccepted TaskStatus = "Accepted"
TaskRunning TaskStatus = "Running"
TaskSucceeded TaskStatus = "Succeeded"
TaskFailed TaskStatus = "Failed"
TaskCancelled TaskStatus = "Cancelled"
TaskExpired TaskStatus = "Expired"
TaskResultUnconfirmed TaskStatus = "ResultUnconfirmed"
)
type NodeStatus string
const (
NodeRegistered NodeStatus = "Registered"
NodeOnline NodeStatus = "Online"
NodeDegraded NodeStatus = "Degraded"
NodeOffline NodeStatus = "Offline"
NodeSessionLocked NodeStatus = "SessionLocked"
NodeWechatNotRunning NodeStatus = "WechatNotRunning"
NodeWechatNotLogged NodeStatus = "WechatNotLoggedIn"
)
type ChatType string
const (
ChatGroup ChatType = "Group"
ChatPrivate ChatType = "Private"
)
type NodeRegistration struct {
NodeID string `json:"node_id"`
ConnectionID string `json:"connection_id,omitempty"`
AgentVersion string `json:"agent_version"`
ProtocolVersion string `json:"protocol_version"`
Capabilities []string `json:"capabilities"`
ReportingConfigVersion int64 `json:"reporting_config_version"`
Accounts []AccountSummary `json:"accounts"`
}
type AccountSummary struct {
AccountID string `json:"account_id"`
Active bool `json:"active"`
Verified bool `json:"verified"`
AllowedGroupCount int `json:"allowed_group_count"`
AllowedPrivateCount int `json:"allowed_private_count"`
AllowedChats []AllowedChatSummary `json:"allowed_chats,omitempty"`
}
type AllowedChatSummary struct {
ChatID string `json:"chat_id"`
ChatType ChatType `json:"chat_type"`
}
type Heartbeat struct {
NodeID string `json:"node_id"`
ConnectionID string `json:"connection_id,omitempty"`
AgentVersion string `json:"agent_version"`
ProtocolVersion string `json:"protocol_version"`
NodeStatus NodeStatus `json:"node_status"`
WechatRunning bool `json:"wechat_running"`
WechatLoggedIn bool `json:"wechat_logged_in"`
SessionLocked bool `json:"session_locked"`
ActiveAccountID string `json:"active_account_id,omitempty"`
QueueLength int `json:"queue_length"`
ReportingConfigVersion int64 `json:"reporting_config_version"`
CorrelationID string `json:"correlation_id"`
LastErrorCode string `json:"last_error_code,omitempty"`
}
type Task struct {
TaskID string `json:"task_id"`
NodeID string `json:"node_id"`
AccountID string `json:"account_id"`
Kind string `json:"kind"`
IdempotencyKey string `json:"idempotency_key"`
Payload jsonRaw `json:"payload"`
NotAfter *time.Time `json:"not_after,omitempty"`
Status TaskStatus `json:"status"`
StateVersion int64 `json:"state_version"`
LeaseGeneration int64 `json:"lease_generation"`
LeaseExpiresAt *time.Time `json:"lease_expires_at,omitempty"`
LeaseOwner string `json:"lease_owner,omitempty"`
CancelRequestedAt *time.Time `json:"cancel_requested_at,omitempty"`
Result *TaskResult `json:"result,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
LastCorrelationID string `json:"last_correlation_id,omitempty"`
}
// jsonRaw preserves task/content JSON without coupling the API to a concrete payload type.
type jsonRaw = json.RawMessage
type TaskSubmission struct {
NodeID string `json:"node_id"`
AccountID string `json:"account_id"`
Kind string `json:"kind"`
IdempotencyKey string `json:"idempotency_key"`
Payload jsonRaw `json:"payload"`
NotAfter *time.Time `json:"not_after,omitempty"`
}
type ReadTaskSubmission struct {
NodeID string `json:"node_id"`
AccountID string `json:"account_id"`
IdempotencyKey string `json:"idempotency_key"`
Limit int `json:"limit,omitempty"`
Offset int `json:"offset,omitempty"`
Contains string `json:"contains,omitempty"`
GroupsOnly *bool `json:"groups_only,omitempty"`
ChatID string `json:"chat_id,omitempty"`
IncludeContent bool `json:"include_content,omitempty"`
NotAfter *time.Time `json:"not_after,omitempty"`
}
type TaskResult struct {
TaskID string `json:"task_id"`
AccountID string `json:"account_id"`
LeaseGeneration int64 `json:"lease_generation"`
Status TaskStatus `json:"status"`
ErrorCode string `json:"error_code,omitempty"`
Message string `json:"message,omitempty"`
HasSideEffect bool `json:"has_side_effect"`
Content jsonRaw `json:"content,omitempty"`
CorrelationID string `json:"correlation_id"`
}
type TaskAck struct {
TaskID string `json:"task_id"`
AccountID string `json:"account_id"`
LeaseGeneration int64 `json:"lease_generation"`
}
type MessageEvent struct {
NodeID string `json:"node_id"`
AccountID string `json:"account_id"`
ChatID string `json:"chat_id"`
ChatType ChatType `json:"chat_type"`
EventSeq int64 `json:"event_seq"`
EventType string `json:"event_type"`
OccurredAt time.Time `json:"occurred_at"`
Content string `json:"content,omitempty"`
ConfigVersion int64 `json:"config_version"`
AuthorizationVersion int64 `json:"authorization_version"`
CorrelationID string `json:"correlation_id"`
Authorized bool `json:"authorized"`
}
type StoredEvent struct {
MessageEvent
EventID string `json:"event_id"`
ContentHash string `json:"content_hash"`
ReceivedAt time.Time `json:"received_at"`
}
type AuditEntry struct {
ID string `json:"id"`
At time.Time `json:"at"`
Principal string `json:"principal"`
Action string `json:"action"`
Resource string `json:"resource"`
CorrelationID string `json:"correlation_id"`
Outcome string `json:"outcome"`
}
type Node struct {
NodeID string `json:"node_id"`
ConnectionID string `json:"connection_id,omitempty"`
AgentVersion string `json:"agent_version"`
ProtocolVersion string `json:"protocol_version"`
Capabilities []string `json:"capabilities"`
Status NodeStatus `json:"status"`
LastHeartbeatAt *time.Time `json:"last_heartbeat_at,omitempty"`
WechatRunning bool `json:"wechat_running"`
WechatLoggedIn bool `json:"wechat_logged_in"`
SessionLocked bool `json:"session_locked"`
ActiveAccountID string `json:"active_account_id,omitempty"`
QueueLength int `json:"queue_length"`
ReportingConfigVersion int64 `json:"reporting_config_version"`
Accounts []AccountSummary `json:"accounts"`
LastErrorCode string `json:"last_error_code,omitempty"`
LastCorrelationID string `json:"last_correlation_id,omitempty"`
}
type PersistedState struct {
Nodes map[string]Node `json:"nodes"`
Tasks map[string]Task `json:"tasks"`
Events []StoredEvent `json:"events"`
Audit []AuditEntry `json:"audit"`
AIFlows map[string]AIFlow `json:"ai_flows,omitempty"`
AIRuns map[string]AIRun `json:"ai_runs,omitempty"`
AIPullTasks map[string]AIPullTask `json:"ai_pull_tasks,omitempty"`
AIMessageKeys map[string]string `json:"ai_message_keys,omitempty"`
}
type AITriggerType string
const (
AITriggerRealtime AITriggerType = "realtime"
AITriggerInterval AITriggerType = "interval"
)
type AIRunStatus string
const (
AIRunPending AIRunStatus = "Pending"
AIRunRunning AIRunStatus = "Running"
AIRunSucceeded AIRunStatus = "Succeeded"
AIRunFailed AIRunStatus = "Failed"
)
type AITarget struct {
NodeID string `json:"node_id"`
AccountID string `json:"account_id"`
ChatID string `json:"chat_id"`
ChatType ChatType `json:"chat_type"`
}
type AITrigger struct {
Type AITriggerType `json:"type"`
IntervalSeconds int `json:"interval_seconds,omitempty"`
BatchLimit int `json:"batch_limit,omitempty"`
}
type AIFlowRequest struct {
Name string `json:"name"`
Targets []AITarget `json:"targets"`
Trigger AITrigger `json:"trigger"`
Instruction string `json:"instruction"`
OutputSchema jsonRaw `json:"output_schema"`
Tools []string `json:"tools"`
Enabled bool `json:"enabled"`
}
type AIFlow struct {
AIFlowRequest
FlowID string `json:"flow_id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
NextRunAt *time.Time `json:"next_run_at,omitempty"`
LastRunAt *time.Time `json:"last_run_at,omitempty"`
LastError string `json:"last_error,omitempty"`
}
type AIMessage struct {
MessageID string `json:"message_id,omitempty"`
Fingerprint string `json:"fingerprint,omitempty"`
Type string `json:"type,omitempty"`
Sender string `json:"sender,omitempty"`
OccurredAt time.Time `json:"occurred_at,omitempty"`
Content string `json:"content,omitempty"`
}
type AIPullTask struct {
FlowID string `json:"flow_id"`
TaskID string `json:"task_id"`
Target AITarget `json:"target"`
CreatedAt time.Time `json:"created_at"`
}
type AIRun struct {
RunID string `json:"run_id"`
FlowID string `json:"flow_id"`
TriggerType AITriggerType `json:"trigger_type"`
MessageKey string `json:"message_key"`
SourceEventID string `json:"source_event_id,omitempty"`
SourceTaskID string `json:"source_task_id,omitempty"`
Target AITarget `json:"target"`
Messages []AIMessage `json:"messages"`
Status AIRunStatus `json:"status"`
Output jsonRaw `json:"output,omitempty"`
RawOutput string `json:"raw_output,omitempty"`
ToolCalls []AIToolCallRecord `json:"tool_calls,omitempty"`
ErrorCode string `json:"error_code,omitempty"`
Error string `json:"error,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
type AIToolDefinition struct {
Name string `json:"name"`
Description string `json:"description"`
Parameters jsonRaw `json:"parameters"`
}
type AIToolCall struct {
ID string `json:"id"`
Name string `json:"name"`
Arguments jsonRaw `json:"arguments"`
}
type AIToolCallRecord struct {
ID string `json:"id"`
Name string `json:"name"`
Arguments jsonRaw `json:"arguments"`
Result jsonRaw `json:"result,omitempty"`
Status string `json:"status"`
}
type AIChatMessage struct {
Role string `json:"role"`
Content string `json:"content,omitempty"`
Name string `json:"name,omitempty"`
ToolCallID string `json:"tool_call_id,omitempty"`
ToolCalls []AIToolCall `json:"tool_calls,omitempty"`
}
type AICompletionRequest struct {
System string
Messages []AIChatMessage
Schema jsonRaw
Tools []AIToolDefinition
}
type AICompletionResponse struct {
Content string
ToolCalls []AIToolCall
}
type PersistedAIConfig struct {
ProviderConfigured bool `json:"provider_configured"`
Model string `json:"model"`
}
type NodeResponse struct {
NodeID string `json:"node_id"`
ConnectionID string `json:"connection_id,omitempty"`
Status NodeStatus `json:"status"`
Authenticated bool `json:"authenticated,omitempty"`
LastHeartbeatAt *time.Time `json:"last_heartbeat_at,omitempty"`
CorrelationID string `json:"correlation_id"`
}
type TaskBatch struct {
Tasks []Task `json:"tasks"`
}
type EventReceipt struct {
Accepted bool `json:"accepted"`
Duplicate bool `json:"duplicate"`
EventID string `json:"event_id,omitempty"`
Reason string `json:"reason,omitempty"`
}
type TaskSubmissionResponse struct {
TaskID string `json:"task_id"`
Status TaskStatus `json:"status"`
Duplicate bool `json:"duplicate"`
StateVersion int64 `json:"state_version"`
}
type APIError struct {
Code string `json:"code"`
Message string `json:"message"`
CorrelationID string `json:"correlation_id"`
}