Documentation
¶
Overview ¶
Package db is the PostgreSQL data source for ARTEX (取代旧 graph 单文件 SQLite)。 它打开连接、应用 schema、并 seed 内置 agent 与变量目录。
Index ¶
- Constants
- Variables
- func AddFindingTrafficTx(tx *sql.Tx, findingID int64, prepared []PreparedTrafficEvidence) error
- func AssetInterceptKindLabel(kind string) string
- func DSN() (dsn, source string, err error)
- func DomainKey(fqdn string) string
- func EndpointKey(siteID int64, method, urlTemplate string) string
- func IPKey(ip string) string
- func InsertEvidenceSnapshotTx(tx *sql.Tx, s TrafficEvidenceSnapshot) error
- func IsTaskArchiveFormatSupported(version int) bool
- func IsTerminal(status string) bool
- func LockFindingEvidenceTx(tx *sql.Tx, findingID int64, version *int64) error
- func LockTaskEvidenceTx(tx *sql.Tx, taskID int64) error
- func NormalizeICP(value string) string
- func NormalizeParamName(name string) string
- func NormalizeTaskCompanyIDs(ids []int64) ([]int64, error)
- func ParameterKey(endpointID int64, location, name string) string
- func ParseDSL(s string) (*astNode, error)
- func ParseExpID(s string) int64
- func PortKey(ipID int64, proto string, port int) string
- func RecordNotificationEventTx(ctx context.Context, tx *sql.Tx, kind string, findingID int64, ...) bool
- func RootDomain(host string) (root string, isApex bool)
- func ServiceKey(portID int64, svcName string) string
- func SetFindingStatusTx(ctx context.Context, tx *sql.Tx, id int64, status string) (from string, found bool, changed bool, notified bool, err error)
- func SiteKey(scheme, host string, port int) string
- func SplitURL(raw, method string) (scheme, host string, port int, urlTemplate string, params []string, err error)
- func TechKey(name, version string) string
- func TemplatePath(path string) string
- func TrafficSnapshotID(snapshot TrafficEvidenceSnapshot) string
- func ValidChatMentionKind(kind string) bool
- func ValidFindingStatus(s string) bool
- func ValidNotifyMode(m string) bool
- func ValidSeverity(s string) bool
- func ValidTrafficRole(role string) bool
- func ValidateAssetIP(value string) error
- func ValidateCompanyScopeInputBounds(inputs []ScopeInput) error
- func ValidateDSL(dsl string) error
- type ActiveFindingRetest
- type Activity
- type ActivitySessionFilter
- type Agent
- type AgentTrigger
- type Asset
- type AssetGateDecision
- type AssetInterceptHit
- type AssetInterceptRule
- type AssetRef
- type AssetStore
- func (s *AssetStore) AddAgentScope(taskID int64, kind, value, reason, source string) (TaskScope, error)
- func (s *AssetStore) AddAutoScope(taskID int64, assetType, domain, rawURL, ip string) error
- func (s *AssetStore) AppendIPBoundDomain(ipStr, domain string) error
- func (s *AssetStore) AppendIPPort(ipStr string, port int, serviceName string) error
- func (s *AssetStore) AttachAssetsToTask(taskID int64, assetIDs []int64, sourceSummary string) (TaskAssetMutation, error)
- func (s *AssetStore) BuildCoverageGraph(taskID, _ int64) (*CoverageGraphData, error)
- func (s *AssetStore) CheckAssetsIntercept(taskID int64, ids []int64) ([]AssetInterceptHit, error)
- func (s *AssetStore) Companies() *CompanyStore
- func (s *AssetStore) CountByCompany(companyID int64, typ string) (int, error)
- func (s *AssetStore) CountByTask(taskID int64, typ string) (int, error)
- func (s *AssetStore) CountByType(typ string) (int, error)
- func (s *AssetStore) CountDSL(dsl, typ string, taskID int64) (int, error)
- func (s *AssetStore) CountsByType() (map[string]int, error)
- func (s *AssetStore) CountsByTypeForTask(taskID int64) (map[string]int, error)
- func (s *AssetStore) CoverageEnabled(taskID int64) bool
- func (s *AssetStore) CreateTaskInterceptRule(taskID int64, action, kind, pattern, note string, enabled bool) (AssetInterceptRule, error)
- func (s *AssetStore) DeleteByCompanyID(companyID int64) (int64, error)
- func (s *AssetStore) DeleteByHost(host string) (map[string]int64, error)
- func (s *AssetStore) DeleteByIDs(ids []int64) (int64, error)
- func (s *AssetStore) DeleteByTaskID(taskID int64) (int64, error)
- func (s *AssetStore) DeleteTaskInterceptRule(taskID, ruleID int64) (bool, error)
- func (s *AssetStore) DeleteTaskScope(taskID, scopeID int64) (bool, error)
- func (s *AssetStore) DetachAssetFromTask(taskID, assetID int64) (bool, error)
- func (a *AssetStore) FindingMetaByNodeID(taskID int64) (map[int64]FindingMeta, error)
- func (s *AssetStore) GetByIDs(ids []int64) ([]*Asset, error)
- func (s *AssetStore) GetByIDsInScope(taskID int64, ids []int64) ([]*Asset, error)
- func (s *AssetStore) HostsByTask(taskID int64) ([]string, error)
- func (s *AssetStore) HostsByTaskWithSources(taskID int64) ([]string, error)
- func (s *AssetStore) HostsForTaskDeletion(taskID, explorationID int64) ([]string, error)
- func (s *AssetStore) IntentAssets(taskID int64) ([]IntentAsset, error)
- func (s *AssetStore) ListAssetInterceptRules() ([]AssetInterceptRule, error)
- func (s *AssetStore) ListTaskInterceptRules(taskID int64) ([]AssetInterceptRule, error)
- func (s *AssetStore) ListTaskScope(taskID int64) ([]TaskScope, error)
- func (s *AssetStore) ListTaskScopeWithSources(taskID int64) ([]TaskScope, error)
- func (s *AssetStore) ListUntestedAssets(taskID, expID int64, typ string, limit, offset int) ([]CoverageAsset, int, error)
- func (s *AssetStore) ListUntestedAssetsWithSources(taskID int64, typ string, limit, offset int) ([]CoverageAsset, int, error)
- func (s *AssetStore) QueryByCompany(companyID int64, typ string, limit, offset int) ([]*Asset, error)
- func (s *AssetStore) QueryByTask(taskID int64, typ string, limit, offset int) ([]*Asset, error)
- func (s *AssetStore) QueryByType(typ string, limit, offset int) ([]*Asset, error)
- func (s *AssetStore) QueryDSL(dsl, typ string, taskID int64, limit, offset int) ([]*Asset, error)
- func (s *AssetStore) QueryDSLInScope(dsl, typ string, taskID int64, limit, offset int) ([]*Asset, error)
- func (s *AssetStore) RegisterTaskAssetScopes(taskID int64, inputs []ScopeInput) (TaskAssetScopeMutation, error)
- func (s *AssetStore) SetTaskAssetSource(taskID, assetID int64, source, summary string, sourceNodeID *int64) error
- func (s *AssetStore) TaskCoverage(taskID, expID int64) (*Coverage, error)
- func (s *AssetStore) TaskCoverageWithSources(taskID int64) (*Coverage, error)
- func (s *AssetStore) TaskInterceptRulesSplit(taskID int64) (block, allow []AssetInterceptRule, err error)
- func (s *AssetStore) ToggleTaskInterceptRule(taskID, ruleID int64, enabled bool) error
- func (s *AssetStore) UpdateTaskInterceptRule(taskID, ruleID int64, action, kind, pattern, note string, enabled bool) (AssetInterceptRule, error)
- func (s *AssetStore) UpsertApp(req UpsertAppReq) (int64, error)
- func (s *AssetStore) UpsertEndpoint(req UpsertEndpointReq) (int64, error)
- func (s *AssetStore) UpsertHTTPService(req UpsertHTTPServiceReq) (int64, error)
- func (s *AssetStore) UpsertIP(req UpsertIPReq) (int64, error)
- func (s *AssetStore) UpsertOtherService(req UpsertOtherServiceReq) (int64, error)
- func (s *AssetStore) UpsertRootDomain(req UpsertRootDomainReq) (int64, error)
- func (s *AssetStore) UpsertSubdomain(req UpsertSubdomainReq) (id int64, err error)
- type AuthItem
- type ChatMention
- type ChatMentionPage
- type CommandRecord
- type Company
- type CompanyScopeValidationError
- type CompanyStore
- func (s *CompanyStore) AddScope(companyID int64, lines []string, reason string) (added, skipped, invalid int, errors []string)
- func (s *CompanyStore) AddScopeInputs(companyID int64, inputs []ScopeInput, reason string) (added, skipped, invalid int, errors []string)
- func (s *CompanyStore) AddScopeInputsChecked(companyID int64, inputs []ScopeInput, reason string) (added, skipped, invalid int, validationErrors []string, err error)
- func (s *CompanyStore) CreateCompanyWithScope(name, logo string, inputs []ScopeInput, reason string) (id int64, added, skipped, invalid int, validationErrors []string, err error)
- func (s *CompanyStore) DeleteCompany(id int64) error
- func (s *CompanyStore) DeleteCompanyWithAssets(id int64, deleteAssets bool) (assetsDeleted int64, err error)
- func (s *CompanyStore) GetCompany(id int64) (*Company, error)
- func (s *CompanyStore) GetCompanyByName(name string) (*Company, error)
- func (s *CompanyStore) GetScope(companyID int64) ([]ScopeRule, error)
- func (s *CompanyStore) ListCompanies() ([]*CompanyWithScope, error)
- func (s *CompanyStore) MalformedIPAssetWarning() (string, error)
- func (s *CompanyStore) RecomputeAttribution() error
- func (s *CompanyStore) ResolveCompany(rootDomain, ipStr string) (*int64, error)
- func (s *CompanyStore) ResolveCompanyWithICP(rootDomain, ipStr, icp string) (*int64, error)
- func (s *CompanyStore) UpdateScope(companyID int64, lines []string, reason string) (added, invalid int, errs []string)
- func (s *CompanyStore) UpdateScopeInputs(companyID int64, inputs []ScopeInput, reason string) (added, invalid int, errs []string)
- func (s *CompanyStore) UpdateScopeInputsChecked(companyID int64, inputs []ScopeInput, reason string) (added, invalid int, validationErrors []string, err error)
- func (s *CompanyStore) UpsertByName(name string) (int64, error)
- func (s *CompanyStore) UpsertCompany(name, logo string) (id int64, created bool, err error)
- type CompanyWithScope
- type Constraint
- type ConvTokenSummary
- type Conversation
- type ConversationPatch
- type Coverage
- type CoverageAsset
- type CoverageByType
- type CoverageGraphData
- type CoverageGraphEdge
- type CoverageGraphNode
- type DB
- func (d *DB) ActiveProfile() (*LLMProfile, error)
- func (d *DB) AddAgentToToolBinding(agentKey string, keys []string) error
- func (d *DB) AddFinding(taskID, nodeID int64, ...) (int64, error)
- func (d *DB) AddNotificationEvent(ctx context.Context, kind string, findingID int64, snap notify.Snapshot) (int64, error)
- func (d *DB) AgentBindingCounts() (mcp map[int64]int, skill map[int64]int, tools map[string]int, err error)
- func (d *DB) AgentSkillNames(agentID int64) ([]string, error)
- func (d *DB) AgentVisible(agentID int64, kind string) ([]int64, error)
- func (d *DB) AppendConvActivity(convID int64, a Activity) (int64, error)
- func (d *DB) AppendTaskArchiveWarning(id int64, warning string) error
- func (d *DB) ArchivedAggregateStats() ([]json.RawMessage, error)
- func (d *DB) Assets() *AssetStore
- func (d *DB) BuildFindingAssetTree(f FindingFilter) (*FindingAssetTree, error)
- func (d *DB) ClaimDigestBatch(ctx context.Context, channelID int64, limit int, lease time.Duration) ([]*NotificationDelivery, error)
- func (d *DB) ClaimRealtimeDeliveries(ctx context.Context, channelID int64, limit int, lease time.Duration) ([]*NotificationDelivery, error)
- func (d *DB) ClaimTaskArchiveJob(ctx context.Context) (*TaskArchive, error)
- func (d *DB) ClearLLMHealth(profileID int64) error
- func (d *DB) ClearSideHistory(ctx context.Context, key string) error
- func (d *DB) Companies() *CompanyStore
- func (d *DB) CompleteIntercept(id int64, runID, toolUseID, status, output string, truncated bool) error
- func (d *DB) CompleteTaskArchive(archiveID int64, snapshot *TaskArchiveSnapshot, archivePath, sha256 string, ...) error
- func (d *DB) CompleteTaskArchiveRestore(archiveID int64) error
- func (d *DB) ConvActivityDetail(convID, id int64) (string, error)
- func (d *DB) ConvActivityList(convID, sinceID int64, limit int) ([]Activity, int64, error)
- func (d *DB) ConvActivityPage(convID, before int64, limit int) ([]Activity, bool, error)
- func (d *DB) ConversationTokenSummaries() ([]ConvTokenSummary, error)
- func (d *DB) CreateAgent(key, name, description string) (*Agent, error)
- func (d *DB) CreateAssetInterceptRule(kind, pattern, note string, enabled bool) (AssetInterceptRule, error)
- func (d *DB) CreateConversation(agentKey, title string, llmProfileID *int64) (*Conversation, error)
- func (d *DB) CreateCustomTool(t *Tool) error
- func (d *DB) CreateDecidedIntercept(ruleID, convID int64, taskID, agentName, toolName string, input []byte, ...) (int64, error)
- func (d *DB) CreateExploration(description, goal string) (int64, error)
- func (d *DB) CreateFindingRetest(ctx context.Context, findingID int64, notes string) (*FindingRetest, *Conversation, bool, error)
- func (d *DB) CreateInterceptPending(ruleID, convID int64, taskID, agentName, toolName string, input []byte, ...) (int64, error)
- func (d *DB) CreateInterceptRule(name, matchTarget, matchType, pattern, action, message string, priority int, ...) (InterceptRule, error)
- func (d *DB) CreateTask(description, goal string, llmProfileID *int64, ...) (*Task, error)
- func (d *DB) CreateTaskCategory(name string) (*TaskCategory, error)
- func (d *DB) CreateTaskTemplate(in TaskTemplateInput) (*TaskTemplate, error)
- func (d *DB) CreateTaskWithOptions(description, goal string, opts TaskCreateOptions) (*Task, error)
- func (d *DB) CreateTrigger(t *AgentTrigger) (*AgentTrigger, error)
- func (d *DB) CurrentPrompt(agentID int64) (string, error)
- func (d *DB) CurrentSideRequest(ctx context.Context, key string) (*sidequestion.Exchange, error)
- func (d *DB) DecideInterceptPending(id int64, status string) error
- func (d *DB) DeferDeliveries(ctx context.Context, ids []int64, reason string) error
- func (d *DB) DeleteAgent(key string) error
- func (d *DB) DeleteAssetInterceptRule(id int64) error
- func (d *DB) DeleteConversation(id int64) error
- func (d *DB) DeleteConversations(ids []int64) ([]int64, error)
- func (d *DB) DeleteCustomTool(key string) error
- func (d *DB) DeleteFinding(id int64) (n int64, err error)
- func (d *DB) DeleteFindingsByTask(taskID int64) (int64, error)
- func (d *DB) DeleteInterceptRule(id int64) error
- func (d *DB) DeleteLLMRecords(task string) (int64, error)
- func (d *DB) DeleteMCP(id int64) error
- func (d *DB) DeleteNotificationChannel(ctx context.Context, id int64) error
- func (d *DB) DeleteProfile(id int64) error
- func (d *DB) DeleteProfileContext(ctx context.Context, id int64) error
- func (d *DB) DeleteSkillVisibility(skillName string) error
- func (d *DB) DeleteTask(id int64) error
- func (d *DB) DeleteTaskArchiveStub(archiveID int64) error
- func (d *DB) DeleteTaskCascade(id int64, deleteAssets, deleteFindings bool, deleteLLMRecords ...bool) (TaskDeleteResult, error)
- func (d *DB) DeleteTaskCascadePrepared(id int64, deleteAssets, deleteFindings, deleteLLMRecords bool, ...) (TaskDeleteResult, error)
- func (d *DB) DeleteTaskCategory(id int64) (bool, error)
- func (d *DB) DeleteTaskTemplate(id int64) (bool, error)
- func (d *DB) DeleteTrigger(id int64) error
- func (d *DB) DeleteTriggersForAgent(agentKey string) error
- func (d *DB) Dequeue(id int64, clearMode bool) error
- func (d *DB) DigestBatchDue(ctx context.Context, channelID int64, minAge time.Duration) (bool, error)
- func (d *DB) EditFindingTraffic(ctx context.Context, findingID, bindingID, version int64, role, note *string, ...) error
- func (d *DB) Enqueue(id int64, mode string) error
- func (d *DB) EnsureLLMRecordsTable() error
- func (d *DB) EnsureLLMUsageTable() error
- func (d *DB) ExistingSideRequest(ctx context.Context, key, client string) (*sidequestion.Exchange, error)
- func (d *DB) Exploration(id int64) *ExplorationStore
- func (d *DB) ExplorationDiag(expID int64) (expExists bool, taskRefs int, maxExpID int64, err error)
- func (d *DB) FailDeliveries(ctx context.Context, ids []int64, errMsg string) error
- func (d *DB) FailPendingRetestForConversation(conversationID int64, reason string) error
- func (d *DB) FailTaskArchiveJob(id int64, activeState string, cause error) error
- func (d *DB) FanOutPendingEvents(ctx context.Context, limit int) (eventCount, deliveryCount int, err error)
- func (d *DB) FindingIDByNodeID(nodeID int64) (id int64, err error)
- func (d *DB) FindingMetaByNodeID(taskID int64) (map[int64]FindingMeta, error)
- func (d *DB) FindingRetestForConversation(ctx context.Context, conversationID int64) (*FindingRetest, error)
- func (d *DB) FindingStats() (*FindingStats, error)
- func (d *DB) FinishFindingRetest(id int64, status, reason string) error
- func (d *DB) GetAgentByKey(key string) (*Agent, error)
- func (d *DB) GetBool(key string, def bool) bool
- func (d *DB) GetConversation(id int64) (*Conversation, error)
- func (d *DB) GetFinding(id int64) (*DBFinding, error)
- func (d *DB) GetFindingTraffic(ctx context.Context, findingID int64) (out *FindingTraffic, err error)
- func (d *DB) GetInterceptDetail(id int64) (*InterceptDetail, error)
- func (d *DB) GetInterceptExecution(id int64) (*InterceptExecution, error)
- func (d *DB) GetInterceptPending(id int64) (*InterceptPending, error)
- func (d *DB) GetLLMRecord(id int64) (*LLMRecord, error)
- func (d *DB) GetSchedState(key string) (string, error)
- func (d *DB) GetSetting(key string) (value string, ok bool, err error)
- func (d *DB) GetTask(id int64) (*Task, error)
- func (d *DB) GetTaskArchive(id int64) (*TaskArchive, error)
- func (d *DB) GetTaskArchiveByTask(taskID int64) (*TaskArchive, error)
- func (d *DB) GetTaskCategory(id int64) (*TaskCategory, error)
- func (d *DB) GetTaskTemplate(id int64) (*TaskTemplate, error)
- func (d *DB) GetTool(key string) (*Tool, error)
- func (d *DB) GoalCountsAll() (map[int64]GoalCounts, error)
- func (d *DB) InsertLLMRecord(r *LLMRecord) error
- func (d *DB) InsertLLMUsage(u *LLMUsage) error
- func (d *DB) InsertLog(level, tag, text string) (int64, error)
- func (d *DB) InsertSettingIfAbsent(key, value string) (inserted bool, err error)
- func (d *DB) InsertSkillUsage(u *SkillUsage) error
- func (d *DB) InsertToolUsage(u *ToolUsage) error
- func (d *DB) InterruptSideRequests(ctx context.Context) error
- func (d *DB) IsTaskArchiveRestored(id int64) (bool, error)
- func (d *DB) JudgeUsageStats(days int) (JudgeUsage, error)
- func (d *DB) LLMRetryPolicy() LLMRetryPolicy
- func (d *DB) LLMTasks() ([]LLMTask, error)
- func (d *DB) LastActivityAll() (map[int64]int64, error)
- func (d *DB) ListActiveFindingRetests(ctx context.Context) ([]ActiveFindingRetest, error)
- func (d *DB) ListAgents() ([]*Agent, error)
- func (d *DB) ListAllIntercepts(limit int) ([]InterceptApprovalRow, error)
- func (d *DB) ListAllInterceptsPage(page, size int, filter InterceptApprovalFilter) ([]InterceptApprovalRow, int, error)
- func (d *DB) ListAssetInterceptRules() ([]AssetInterceptRule, error)
- func (d *DB) ListCommands(expID *int64, q string, page, size int) ([]CommandRecord, int, error)
- func (d *DB) ListConversations() ([]*Conversation, error)
- func (d *DB) ListCustomTools() ([]*Tool, error)
- func (d *DB) ListEnabledTriggers() ([]*AgentTrigger, error)
- func (d *DB) ListFindingGroups(f FindingFilter, page, pageSize int) ([]FindingGroup, int, int, error)
- func (d *DB) ListFindingRetests(findingID int64) ([]*FindingRetest, error)
- func (d *DB) ListFindings(limit int) ([]*DBFinding, error)
- func (d *DB) ListFindingsForExport(f FindingFilter, ids []int64) ([]*DBFinding, error)
- func (d *DB) ListFindingsPage(f FindingFilter, page, pageSize int) ([]*DBFinding, int, error)
- func (d *DB) ListInterceptRules() ([]InterceptRule, error)
- func (d *DB) ListLLMRecords(model, session, task string, page, size int) ([]LLMRecord, int, error)
- func (d *DB) ListLogsBefore(beforeID int64, limit int) ([]*DBLog, error)
- func (d *DB) ListMCP() ([]*MCPServer, error)
- func (d *DB) ListNotificationChannels(ctx context.Context) ([]*NotificationChannel, error)
- func (d *DB) ListNotificationDeliveries(ctx context.Context, f NotificationDeliveryFilter, page, pageSize int) ([]*NotificationDelivery, int, error)
- func (d *DB) ListPendingIntercepts() ([]InterceptPending, error)
- func (d *DB) ListProfiles() ([]*LLMProfile, error)
- func (d *DB) ListPromptVersions(agentID int64) ([]PromptVersion, error)
- func (d *DB) ListTaskArchives(search, state string, page, size int) (TaskArchivePage, error)
- func (d *DB) ListTaskCategories() ([]*TaskCategory, error)
- func (d *DB) ListTaskIntercepts(taskID string) ([]InterceptApprovalRow, error)
- func (d *DB) ListTaskInterceptsPage(taskID string, page, size int, filter InterceptApprovalFilter) ([]InterceptApprovalRow, int, error)
- func (d *DB) ListTaskTemplates() ([]*TaskTemplate, error)
- func (d *DB) ListTasks() ([]*Task, error)
- func (d *DB) ListTools() ([]*Tool, error)
- func (d *DB) ListTriggersFor(agentKey string) ([]*AgentTrigger, error)
- func (d *DB) LoadLLMHealth() ([]LLMHealth, error)
- func (d *DB) MCPToolNames(serverID int64) ([]string, error)
- func (d *DB) MCPToolsDetailed(serverID int64) ([]MCPTool, error)
- func (d *DB) MarkDeliveriesSent(ctx context.Context, ids []int64) error
- func (d *DB) MarkTaskLLMProfileQuotaExhausted(taskID, profileID int64, reason string) (TaskLLMTransition, error)
- func (d *DB) MarkTaskLLMProfileQuotaExhaustedAtRevision(taskID, profileID, revision int64, reason string) (TaskLLMTransition, error)
- func (d *DB) MetGoals() ([]TaskEvent, error)
- func (d *DB) MissingSkillStats(limit int) ([]SkillStat, error)
- func (d *DB) NewFindingsSince(lastID int64) ([]TaskEvent, error)
- func (d *DB) NewTasksSince(lastID int64) ([]TaskEvent, error)
- func (d *DB) NewToolCallsSince(lastID int64) ([]TaskEvent, error)
- func (d *DB) NotificationAssetNames(ctx context.Context, ids []int64) ([]string, error)
- func (d *DB) NotificationChannelByID(ctx context.Context, id int64) (*NotificationChannel, error)
- func (d *DB) NotificationStatsSnapshot(ctx context.Context) (*NotificationStats, error)
- func (d *DB) PatchTaskTemplate(id int64, patch TaskTemplatePatch) (*TaskTemplate, error)
- func (d *DB) PoolProfiles() ([]*LLMProfile, error)
- func (d *DB) ProfileByID(id int64) (*LLMProfile, error)
- func (d *DB) PromptVars(agentID int64) ([]PromptVar, error)
- func (d *DB) QueueTaskArchive(taskID int64) (*TaskArchive, error)
- func (d *DB) QueueTaskArchiveDelete(id int64) (*TaskArchive, error)
- func (d *DB) QueueTaskArchiveRestore(id int64) (*TaskArchive, error)
- func (d *DB) RecentLogs(limit int) ([]*DBLog, error)
- func (d *DB) RecentSkillCalls(skill string, limit int) ([]SkillCall, error)
- func (d *DB) RecordFindingRetestResult(ctx context.Context, conversationID int64, verdict, summary, evidence string) error
- func (d *DB) RecoverFindingRetests() error
- func (d *DB) RecoverTaskArchiveJobs() error
- func (d *DB) RefreshToolDefaults(key, desc string, schema json.RawMessage) error
- func (d *DB) RemoveAgentFromTool(agentKey, toolKey string) error
- func (d *DB) RemoveAgentFromToolBindings(agentKey string) error
- func (d *DB) RenameConversation(id int64, title string) error
- func (d *DB) RenameTaskCategory(id int64, name string) (*TaskCategory, error)
- func (d *DB) ReplaceTaskLLMProfiles(taskID int64, profileIDs []int64, activeProfileID int64) error
- func (d *DB) RescheduleDeliveries(ctx context.Context, ids []int64, delay time.Duration, errMsg string) error
- func (d *DB) ResetPromptToDefault(agentID int64, tmpl string) (int, error)
- func (d *DB) ResolveIntercept(id int64, status, action, reason string) (bool, error)
- func (d *DB) ResourceAgents(kind string, resourceID int64) ([]int64, error)
- func (d *DB) RestoreTaskArchive(archiveID int64, snapshot *TaskArchiveSnapshot, remainingTimeoutSeconds int64) ([]string, error)
- func (d *DB) RestoreTaskArchiveWithLLMRecords(archiveID int64, snapshot *TaskArchiveSnapshot, remainingTimeoutSeconds int64, ...) ([]string, error)
- func (d *DB) RetryNotificationDelivery(ctx context.Context, id int64) error
- func (d *DB) SaveLLMHealth(h LLMHealth) error
- func (d *DB) SaveMCP(m *MCPServer) (int64, error)
- func (d *DB) SaveMCPTools(serverID int64, tools []MCPTool) error
- func (d *DB) SaveNotificationChannel(ctx context.Context, c *NotificationChannel) (int64, error)
- func (d *DB) SaveProfile(p *LLMProfile) (int64, error)
- func (d *DB) SavePrompt(agentID int64, template, note, by string) (int, error)
- func (d *DB) SaveSideMemory(ctx context.Context, e sidequestion.Exchange, memory sidequestion.Memory) error
- func (d *DB) SaveSideSnapshot(ctx context.Context, s sidequestion.Snapshot) error
- func (d *DB) SearchChatMentions(ctx context.Context, kind, query string) ([]ChatMention, error)
- func (d *DB) SearchChatMentionsPage(ctx context.Context, kind, query, cursor string) (ChatMentionPage, error)
- func (d *DB) SeedPromptIfEmpty(agentID int64, tmpl string) error
- func (d *DB) SeedTool(key, desc string, schema, agents json.RawMessage) error
- func (d *DB) SetActiveProfile(id int64) error
- func (d *DB) SetAgentInteractiveShell(key string, on bool) error
- func (d *DB) SetAgentLLMProfile(key string, id *int64) error
- func (d *DB) SetAgentMaxTurns(key string, maxTurns int) error
- func (d *DB) SetAgentRunSeconds(key string, runSecs int) error
- func (d *DB) SetAgentSkillVisibility(agentID int64, names []string) error
- func (d *DB) SetAgentTaskTimeoutWrapup(key, prompt string, maxTurns int) error
- func (d *DB) SetAgentTriggerBehavior(key, runMode, mergeMode string, maxParallel int) error
- func (d *DB) SetAgentVisibilityKind(agentID int64, kind string, resourceIDs []int64) error
- func (d *DB) SetAgentWebSearch(key string, on bool) error
- func (d *DB) SetAgentWrapupMaxTurns(key string, n int) error
- func (d *DB) SetAgentWrapupPrompt(key, prompt string) error
- func (d *DB) SetBool(key string, val bool) error
- func (d *DB) SetFindingName(id int64, name string) (int64, error)
- func (d *DB) SetFindingReportByNodeID(nodeID int64, report string) (int64, error)
- func (d *DB) SetFindingReportVersionByNodeID(ctx context.Context, nodeID int64, report string, version *int64) (n int64, err error)
- func (d *DB) SetFindingSeverity(id int64, severity string) (int64, error)
- func (d *DB) SetFindingStatus(id int64, status string) (int64, error)
- func (d *DB) SetFindingStatusWithNotify(ctx context.Context, id int64, status string) (from string, found bool, notified bool, err error)
- func (d *DB) SetFindingVulnClass(id int64, vulnclass string) (int64, error)
- func (d *DB) SetLLMRetryPolicy(p LLMRetryPolicy) error
- func (d *DB) SetNotificationChannelEnabled(ctx context.Context, id int64, enabled bool) error
- func (d *DB) SetParentRef(id int64, parentRef string) error
- func (d *DB) SetPaused(id int64, paused bool) error
- func (d *DB) SetQueued(id int64, queued bool) error
- func (d *DB) SetSchedState(key, value string) error
- func (d *DB) SetSetting(key, value string) error
- func (d *DB) SetStatus(id int64, status string) error
- func (d *DB) SetTaskCategory(taskID int64, categoryID *int64) (*TaskCategory, error)
- func (d *DB) SetTasksCategory(taskIDs []int64, categoryID *int64) ([]int64, *TaskCategory, error)
- func (d *DB) SetTerminalStatusGuarded(id int64, status string) (won bool, err error)
- func (d *DB) SideHistory(ctx context.Context, key string, before int64, limit int) ([]sidequestion.Exchange, error)
- func (d *DB) SideMemory(ctx context.Context, e sidequestion.Exchange) (sidequestion.Memory, error)
- func (d *DB) SideReplay(ctx context.Context, key string) ([]sidequestion.Exchange, error)
- func (d *DB) SideReplayPage(ctx context.Context, e sidequestion.Exchange, after int64) ([]sidequestion.Exchange, error)
- func (d *DB) SideRequest(ctx context.Context, id string) (*sidequestion.Exchange, error)
- func (d *DB) SideSnapshot(ctx context.Context, key string) (*sidequestion.Snapshot, error)
- func (d *DB) SkillAgents(skillName string) ([]int64, error)
- func (d *DB) SkillCallsByTask(taskID int64) ([]SkillStat, error)
- func (d *DB) SkillStats() ([]SkillStat, error)
- func (d *DB) SnapshotTaskArchive(taskID int64) (*TaskArchiveSnapshot, error)
- func (d *DB) SnapshotTaskArchiveWithLLMRecords(taskID int64, llmRecords io.Writer) (*TaskArchiveSnapshot, error)
- func (d *DB) StampFirstRun(id int64, timeoutSeconds int) (*time.Time, error)
- func (d *DB) StartFindingRetest(ctx context.Context, id int64) (bool, error)
- func (d *DB) StartSideRequest(ctx context.Context, s sidequestion.Snapshot, clientID, question string) (*sidequestion.Exchange, bool, error)
- func (d *DB) TaskArchiveBlockers() (map[int64]int64, error)
- func (d *DB) TaskCompanyIDs(taskID int64) ([]int64, error)
- func (d *DB) TaskLLMProfiles(taskID int64) ([]TaskLLMProfile, error)
- func (d *DB) TaskListMetricsAll() (map[int64]TaskListMetrics, error)
- func (d *DB) TaskSourceIDs(taskID int64) ([]int64, error)
- func (d *DB) TaskSources(taskID int64) ([]TaskSource, error)
- func (d *DB) TimedOutTasksSince(lastID int64) ([]TaskEvent, error)
- func (d *DB) ToggleAssetInterceptRule(id int64, enabled bool) error
- func (d *DB) ToggleInterceptRule(id int64, enabled bool) error
- func (d *DB) ToggleSkillVisibility(agentID int64, skillName string, on bool) error
- func (d *DB) ToggleVisibility(agentID int64, kind string, resourceID int64, on bool) error
- func (d *DB) TokenByModel(taskID string) ([]ModelTokenStat, error)
- func (d *DB) TokenDailyAll(days int) ([]DailyTokenBucket, error)
- func (d *DB) TokenTotalsAll() (map[int64]TokenUsage, error)
- func (d *DB) ToolStats(expID *int64, q string) ([]ToolStat, error)
- func (d *DB) ToolUsageCounts() (map[string]int, error)
- func (d *DB) TouchConversation(id int64) error
- func (d *DB) TouchTriggerFire(id int64) error
- func (d *DB) UpdateAgentMeta(key, name, description string) error
- func (d *DB) UpdateAssetInterceptRule(id int64, kind, pattern, note string, enabled bool) (AssetInterceptRule, error)
- func (d *DB) UpdateConversation(id int64, patch ConversationPatch) (*Conversation, error)
- func (d *DB) UpdateConversationProfile(id int64, llmProfileID *int64) error
- func (d *DB) UpdateCustomTool(t *Tool) error
- func (d *DB) UpdateInterceptRule(id int64, name, matchTarget, matchType, pattern, action, message string, ...) (InterceptRule, error)
- func (d *DB) UpdateSideRequest(ctx context.Context, e sidequestion.Exchange) (bool, error)
- func (d *DB) UpdateTask(id int64, patch TaskPatch) (*Task, error)
- func (d *DB) UpdateTaskArchiveProgress(id int64, phase string, progress int) error
- func (d *DB) UpdateTaskTemplate(id int64, in TaskTemplateInput) (*TaskTemplate, error)
- func (d *DB) UpdateTool(key, desc string, schema, agents json.RawMessage, enabled bool) error
- func (d *DB) UpdateTrigger(t *AgentTrigger) error
- func (d *DB) UpsertToolForce(key, desc string, schema, agents json.RawMessage) error
- func (d *DB) UsageByProfile() ([]ProfileUsage, error)
- func (d *DB) UsageDaily(days int) ([]ProfileDayUsage, error)
- func (d *DB) WithEvidenceTx(ctx context.Context, fn func(*sql.Tx) error) error
- type DBFinding
- type DBLog
- type DailyTokenBucket
- type DirectSourceStore
- type Edge
- type ExplorationStore
- func (s *ExplorationStore) ActiveDigests() ([]*Node, error)
- func (s *ExplorationStore) ActivityByIDs(ids []int64) ([]Activity, error)
- func (s *ExplorationStore) ActivityByIDsForTerminalIntents(ids []int64) ([]Activity, error)
- func (s *ExplorationStore) ActivityByIDsWithSources(ids []int64) ([]Activity, error)
- func (s *ExplorationStore) ActivityDetail(id int64) (string, error)
- func (s *ExplorationStore) ActivityDetailWithSources(id int64) (string, error)
- func (s *ExplorationStore) ActivityList(nodeID *int64, sinceID int64, limit int) ([]Activity, int64, error)
- func (s *ExplorationStore) ActivityListForTerminalIntent(nodeID, sinceID int64, limit int) ([]Activity, int64, error)
- func (s *ExplorationStore) ActivityListWithSources(nodeID, sinceID int64, limit int) ([]Activity, int64, error)
- func (s *ExplorationStore) ActivityMaxID() (int64, error)
- func (s *ExplorationStore) ActivityPage(f ActivitySessionFilter, before int64, limit int) ([]Activity, bool, error)
- func (s *ExplorationStore) ActivityPageForTerminalIntent(nodeID, before int64, limit int) ([]Activity, bool, error)
- func (s *ExplorationStore) ActivityTrace(nodeID int64, limit int) ([]Activity, error)
- func (s *ExplorationStore) ActivityTraceForTerminalIntent(nodeID int64, limit int) ([]Activity, error)
- func (s *ExplorationStore) ActivityTraceSearch(nodeID *int64, q string, limit int) ([]Activity, error)
- func (s *ExplorationStore) ActivityTraceSearchAllWithSources(excludeNodeID int64, q string, limit int) ([]Activity, error)
- func (s *ExplorationStore) ActivityTraceSearchExcluding(excludeNodeID int64, q string, limit int) ([]Activity, error)
- func (s *ExplorationStore) ActivityTraceSearchForTerminalIntent(nodeID int64, q string, limit int) ([]Activity, error)
- func (s *ExplorationStore) ActivityTraceSearchTerminalIntents(q string, limit int) ([]Activity, error)
- func (s *ExplorationStore) ActivityTraceSearchWithSources(nodeID int64, q string, limit int) ([]Activity, error)
- func (s *ExplorationStore) ActivityTraceWithSources(nodeID int64, limit int) ([]Activity, error)
- func (s *ExplorationStore) AddConstraint(kind, text, origin string) (int64, error)
- func (s *ExplorationStore) AddDigest(payload map[string]any, memberIDs []int64) (int64, error)
- func (s *ExplorationStore) AddFindingFollowUpIntent(findingID, findingNodeID int64, description string, audit Activity) (int64, Activity, error)
- func (s *ExplorationStore) AddGoal(payload map[string]any, origin string) (int64, error)
- func (s *ExplorationStore) AddIntent(payload map[string]any, priority int, anchors []int64, origin string) (int64, error)
- func (s *ExplorationStore) AddNode(kind string, payload map[string]any, priority int, state, origin string, ...) (int64, error)
- func (s *ExplorationStore) AddStandaloneFinding(taskID, nodeID int64, ...) (int64, error)
- func (s *ExplorationStore) Anchor(nodeID, assetID int64) error
- func (s *ExplorationStore) AppendActivity(a Activity) (int64, error)
- func (s *ExplorationStore) ApplyStampOps(ops []StampOp) error
- func (s *ExplorationStore) AssetRefs(assetID int64) ([]AssetRef, error)
- func (s *ExplorationStore) AssetRefsWithSources(assetID int64) ([]AssetRef, error)
- func (s *ExplorationStore) BumpRound() (int64, error)
- func (s *ExplorationStore) CancelIntent(id int64) (IntentCleanup, error)
- func (s *ExplorationStore) ClaimIntent(id int64, owner string) (bool, error)
- func (s *ExplorationStore) ColdStamps() (map[int64]*int64, error)
- func (s *ExplorationStore) CompareAndSetIntentState(id int64, expected, state string) (bool, error)
- func (s *ExplorationStore) ContentVersions() (map[int64]int, error)
- func (s *ExplorationStore) CountFinishedIntents() (int, error)
- func (s *ExplorationStore) CountOpenIntents() (int, error)
- func (s *ExplorationStore) CoveredMembers() (map[int64]int64, error)
- func (s *ExplorationStore) CurrentMainSeg() (int, error)
- func (s *ExplorationStore) DeleteConstraint(id int64) error
- func (s *ExplorationStore) DeleteGoal(id int64) error
- func (s *ExplorationStore) DigestMembers(digestID int64) ([]int64, error)
- func (s *ExplorationStore) DirectSourceStores() ([]DirectSourceStore, error)
- func (s *ExplorationStore) DiscardOpenIntent(id int64) error
- func (s *ExplorationStore) Edges(limit int) ([]Edge, error)
- func (s *ExplorationStore) EdgesTouching(ids []int64) ([]Edge, error)
- func (s *ExplorationStore) FactsYielded(intentID int64) ([]int64, error)
- func (s *ExplorationStore) FindingIntents() (map[int64]int64, error)
- func (s *ExplorationStore) FindingIntentsTerminal() (map[int64]int64, error)
- func (s *ExplorationStore) FindingIntentsWithSources() (map[int64]int64, error)
- func (s *ExplorationStore) FindingLineage(nodeID int64) ([]*Node, []Edge, error)
- func (s *ExplorationStore) Frontier(limit int) ([]*Node, error)
- func (s *ExplorationStore) GetNode(id int64) (*Node, error)
- func (s *ExplorationStore) GetNodeWithSources(id int64) (*Node, error)
- func (s *ExplorationStore) HasActiveIntent() (bool, error)
- func (s *ExplorationStore) HasOpenGoal() (bool, error)
- func (s *ExplorationStore) ID() int64
- func (s *ExplorationStore) Link(from int64, rel string, to int64) error
- func (s *ExplorationStore) ListByKind(kind string, limit int) ([]*Node, error)
- func (s *ExplorationStore) ListByKindPage(kind string, before int64, limit int) ([]*Node, bool, error)
- func (s *ExplorationStore) ListByKindPageWithSources(kind string, before int64, limit int, q string) (nodes []*Node, hasMore bool, total int, err error)
- func (s *ExplorationStore) ListByKindWithSources(kind string, limit int) ([]*Node, error)
- func (s *ExplorationStore) ListConstraints() ([]Constraint, error)
- func (s *ExplorationStore) ListMainSessions() ([]MainSession, error)
- func (s *ExplorationStore) NewMainSession() (MainSession, error)
- func (s *ExplorationStore) NodeAssets(ids []int64) (map[int64][]int64, error)
- func (s *ExplorationStore) Nodes(limit int) ([]*Node, error)
- func (s *ExplorationStore) NodesByIDs(ids []int64) ([]*Node, error)
- func (s *ExplorationStore) NodesPage(f NodeFilter, page, size int) ([]*Node, int, error)
- func (s *ExplorationStore) OriginFactID() (int64, error)
- func (s *ExplorationStore) PopulateFindingTrafficIDs(nodes []*Node) error
- func (s *ExplorationStore) RecordFinding(ctx context.Context, in RecordFindingInput) (out *RecordedFinding, err error)
- func (s *ExplorationStore) ReopenBlockedIntents() (int64, error)
- func (s *ExplorationStore) ReopenIntent(id int64) (bool, error)
- func (s *ExplorationStore) ReopenIntentsByBlockedReason(reason string) (int64, error)
- func (s *ExplorationStore) ResetRunningIntents() (int64, error)
- func (s *ExplorationStore) Root() (description, goal string, err error)
- func (s *ExplorationStore) RoundNo() (int64, error)
- func (s *ExplorationStore) SetIntentBlockedReason(id int64, reason string) error
- func (s *ExplorationStore) SetIntentState(id int64, state string) error
- func (s *ExplorationStore) SetNodeState(id int64, state string) error
- func (s *ExplorationStore) SoftDeleteIntent(id int64, reason string) (string, error)
- func (s *ExplorationStore) Stats() (map[string]int, error)
- func (s *ExplorationStore) SupersedeDigests(ids []int64) error
- func (s *ExplorationStore) TaskID() (int64, error)
- func (s *ExplorationStore) TokenStatsBySession() ([]SessionTokenUsage, error)
- func (s *ExplorationStore) TokenStatsByWorker() ([]TokenUsage, error)
- func (s *ExplorationStore) TokenTotal() (TokenUsage, error)
- func (s *ExplorationStore) UpdateConstraint(id int64, kind, text string) error
- func (s *ExplorationStore) UpdateGoalPayload(id int64, text, vulnclass string) error
- type Expr
- type FindingAssetNode
- type FindingAssetTree
- type FindingFilter
- type FindingGroup
- type FindingMeta
- type FindingRetest
- type FindingSeverityCounts
- type FindingStats
- type FindingTaskOption
- type FindingTraffic
- type FindingTrafficBinding
- type GoalCounts
- type IntentAsset
- type IntentCleanup
- type InterceptApprovalFilter
- type InterceptApprovalRow
- type InterceptAudit
- type InterceptContextEntry
- type InterceptDetail
- type InterceptExecution
- type InterceptPending
- type InterceptRule
- type JudgeDayUsage
- type JudgeUsage
- type LLMHealth
- type LLMProfile
- type LLMRecord
- type LLMRetryPolicy
- type LLMTask
- type LLMUsage
- type MCPServer
- type MCPTool
- type MainSession
- type ModelTokenStat
- type Node
- type NodeFilter
- type NotificationChannel
- type NotificationDelivery
- type NotificationDeliveryFilter
- type NotificationEvent
- type NotificationStats
- type ParamItem
- type ParsedScope
- type PortService
- type PreparedTrafficEvidence
- type ProfileDayUsage
- type ProfileUsage
- type PromptVar
- type PromptVersion
- type RecordFindingInput
- type RecordedFinding
- type RetryOverride
- type RetryRule
- type ScopeInput
- type ScopeRule
- type SessionTokenUsage
- type SkillCall
- type SkillStat
- type SkillUsage
- type StampOp
- type Task
- type TaskArchive
- type TaskArchivePage
- type TaskArchiveSnapshot
- type TaskAssetMutation
- type TaskAssetScopeMutation
- type TaskCategory
- type TaskCreateOptions
- type TaskDeletePreparation
- type TaskDeleteResult
- type TaskEvent
- type TaskInterceptRuleInput
- type TaskLLMProfile
- type TaskLLMTransition
- type TaskListMetrics
- type TaskPatch
- type TaskScope
- type TaskSource
- type TaskTemplate
- type TaskTemplateInput
- type TaskTemplatePatch
- type TokenUsage
- type Tool
- type ToolStat
- type ToolUsage
- type TrafficEvidenceSnapshot
- type TrafficRef
- type UpsertAppReq
- type UpsertEndpointReq
- type UpsertHTTPServiceReq
- type UpsertIPReq
- type UpsertOtherServiceReq
- type UpsertRootDomainReq
- type UpsertSubdomainReq
Constants ¶
const ( // 企业范围不限制规则条数:逐个 IP / 域名录入的范围动辄上千条,封顶只会逼用户 // 拆成多个企业。请求体大小(server 侧 maxCompanyMutationBodyBytes)仍然兜底。 // // Raw and normalized textual scope payloads are bounded by Unicode rune // count so multi-byte input is treated consistently by the API and DB layer. MaxCompanyScopeRawRunes = 1024 MaxCompanyScopeValueRunes = 1024 )
const ( KindBegin = "begin" // DEPRECATED: legacy task root; new tasks seed an origin fact (KindFact + StateOrigin) instead KindGoal = "goal" // a task objective KindIntent = "intent" // an exploration direction (planner-generated) KindFact = "fact" // a worker's exploration result/conclusion (incl. negative results), tied to its intent KindFinding = "finding" // a confirmed vulnerability (report_finding), distinct from a fact KindHint = "hint" KindDigest = "digest" // a compressed fold of cold intents/facts (cold-digest-spec §1); lossless — members kept, restorable by id )
Exploration node kinds (exploration_nodes.kind).
const ( StateDigestActive = "active" StateDigestSuperseded = "superseded" )
Digest node states (kind='digest'). A digest is 'active' while it renders in graph_overview; major compaction retires a merged-away segment to 'superseded' (its covers edges repointed to the new digest) — cold-digest-spec §5.1.
const ( RelSpawns = "spawns" RelDerivedFrom = "derived_from" RelYields = "yields" RelProves = "proves" RelCovers = "covers" // digest --covers--> member (cold-digest-spec §1); source of truth for "which digest folds node X" )
Exploration edge relations (exploration_edges.rel).
const ( FindingPending = "pending" // 待处理 FindingInProgress = "in_progress" // 处理中 FindingConfirmed = "confirmed" // 已确认(真实漏洞,未修复) FindingResolved = "resolved" // 已处理 FindingFixed = "fixed" // 已修复 FindingFalsePositive = "false_positive" // 误报 FindingIgnored = "ignored" // 忽略 FindingDuplicate = "duplicate" // 重复 FindingRiskAccepted = "risk_accepted" // 风险接受 )
Finding triage states (findings.status).
const ( SeverityCritical = "critical" // 严重 SeverityHigh = "high" // 高 SeverityMedium = "medium" // 中 SeverityLow = "low" // 低 )
Finding severity levels (findings.severity).
const ( NotifyStatePending = "pending" // 待发 NotifyStateSending = "sending" // 已被某个 dispatcher 领取,租约未到期 NotifyStateSent = "sent" // 已送达 NotifyStateFailed = "failed" // 重试耗尽或永久失败,可手动重发 NotifyStateSkipped = "skipped" // 渠道已停用,不再发送 )
投递状态。
const ( NotifyModeRealtime = "realtime" NotifyModeDigest = "digest" )
推送模式。
const ( TaskArchiveFormatVersion = 3 TaskArchiveLegacyFormatVersion = 1 TaskArchiveLLMRecordsPath = "database/llm_records.ndjson" )
const ( ArchiveQueued = "archive_queued" Archiving = "archiving" ArchiveFailed = "archive_failed" ArchiveReady = "ready" RestoreQueued = "restore_queued" Restoring = "restoring" RestoreFailed = "restore_failed" DeleteQueued = "delete_queued" Deleting = "deleting" DeleteFailed = "delete_failed" )
const ( MaxTaskAssetMutationCount = 100 MaxTaskAssetSummaryRunes = 500 )
const ( MaxTaskTemplateNameRunes = 120 MaxTaskTemplateTextRunes = 16000 )
const FindingRetestAgentKey = "retester"
const FindingUnassignedAsset = "__none__"
FindingUnassignedAsset 是「未关联资产」的节点 key,也是列表接口的筛选哨兵: 命中 asset_ids 为空、或所指资产已被删除的发现。
const FindingUnassignedTask = "__unassigned__"
FindingUnassignedTask is the task filter sentinel for findings whose task is absent. That includes rows created without a task and rows retained after their originating task was deleted (the findings FK is ON DELETE SET NULL).
const IntentBlockedLLMQuota = "llm_quota_exhausted"
const MaxDigestBatchSize = 500
MaxDigestBatchSize 是单个汇总批次一次最多合并多少条投递。
存在的理由是资源:一个汇总周期内如果扫出几万个漏洞(完全可能——一次全量扫描 就能做到),不设上界的话领取会把全部行读进内存、渲染成一条超长消息, 然后被渠道的长度上限截掉大半——既浪费内存,又**静默丢失**被截掉的那些漏洞。 设上界后,超出的部分留在库里成为下一个批次,下个周期自然发出去,不会丢。
取 500 的依据:它是渲染成消息后在企微 4096 字节上限内还"有内容可读"的量级; 再大也只是让截断发生在更靠后的位置而已。
const MaxNotifyAttempts = 3
MaxNotifyAttempts 是一条投递的最大尝试次数(含首次)。 定义在这里而非投递引擎里:它是状态机自身的策略,引擎只是执行者。
const MaxTaskCategoryBatchSize = 100
MaxTaskCategoryBatchSize bounds one batch move so a single request cannot lock an unbounded number of task rows.
const MaxTaskCategoryNameRunes = 80
const MaxTaskCompanyCount = 32
MaxTaskCompanyCount bounds the number of company asset scopes attached to a task. Company scopes are prompt context, and their currently attributed assets are snapshotted into the task at creation time.
const MaxTaskSourceCount = 8
MaxTaskSourceCount bounds the amount of live inherited context one task can pull into every planner/main-agent prompt. Inheritance is intentionally direct only; keeping the fan-in bounded also prevents a single create request from multiplying graph and asset-context queries without limit.
const MinPlanHeartbeatSeconds = 600
CreateTask creates an exploration + task in one transaction and returns the task. timeoutSeconds is the task-level wall-clock budget (0 = 不限时); deadline_at is stamped later at first real run (see engine), not here. MinPlanHeartbeatSeconds 是 planner 心跳间隔的下限 = 默认 = 10min。 低于它(含缺省 0 / 负值 / 误配的小值)一律抬到 10min,防止把 planner 打爆。
const StateIntentDeleted = "deleted"
StateIntentDeleted marks an intent the user假删除(soft delete): it drops out of the frontier and graph_overview like other terminal states, but keeps its node and full lineage. The delete reason lives in exploration_nodes.delete_reason.
const StateOrigin = "origin"
StateOrigin marks the task root fact (KindFact) seeded at task creation — the exploration graph's origin. Every intent traces back to it, so "an intent must connect to a fact" holds uniformly from the very first intent. Worker-produced facts use state 'confirmed', so this never collides.
Variables ¶
var ( ErrCompanyNameConflict = errors.New("company name already exists") ErrCompanyNotFound = errors.New("company not found") )
var ( ErrActiveLLMProfileDelete = errors.New("cannot delete the active LLM profile; activate another profile first") ErrLLMProfileReferencesChanged = errors.New("LLM profile references changed while deleting; retry the request") ErrLLMProfileNotFound = errors.New("LLM profile not found") )
var ( ErrEvidenceConflict = errors.New("流量证据已变更,请刷新后重试") ErrFindingNotFound = errors.New("漏洞不存在") ErrEvidenceNotFound = errors.New("流量证据不存在") )
var ( ErrTaskArchiveNotFound = errors.New("task archive not found") ErrTaskArchiveIneligible = errors.New("task must be paused or terminal before archiving") ErrTaskArchiveQueued = errors.New("queued task must be paused before archiving") ErrTaskArchiveDependent = errors.New("task is inherited by a live task") ErrTaskArchiveState = errors.New("task archive state does not allow this operation") ErrTaskArchiveDeleteBlocked = errors.New("task archive is required by another archive") ErrTaskArchiveFormatMismatch = errors.New("task archive format is not supported") )
var ( ErrTaskAssetInvalid = errors.New("invalid task asset association") ErrTaskAssetTaskNotFound = errors.New("task not found") ErrTaskAssetAssetNotFound = errors.New("asset not found") )
var ( ErrTaskCategoryInvalid = errors.New("invalid task category") ErrTaskCategoryNameConflict = errors.New("task category name already exists") ErrTaskCategoryNotFound = errors.New("task category not found") ErrTaskCategoryTaskNotFound = errors.New("task not found") )
var ( ErrTaskTemplateInvalid = errors.New("invalid task template") ErrTaskTemplateNameConflict = errors.New("task template name already exists") ErrTaskTemplateNotFound = errors.New("task template not found") )
var ( ErrTaskCompanyIDsInvalid = errors.New("invalid task company ids") ErrTaskCompanyNotFound = errors.New("task company not found") )
var ErrAssetIPInvalid = errors.New("invalid asset ip")
ErrAssetIPInvalid marks a non-address value in an asset's ip field. Both insert_assets and the asset API report it per item with the item index, so one bad entry never costs the rest of the batch.
ErrFindingOriginUnavailable means a retained finding no longer has a live owning task and finding node from which a follow-up intent can be derived.
var ErrIntentStateConflict = errors.New("intent state changed concurrently")
ErrIntentStateConflict marks a failed compare-and-set transition. Callers use it to distinguish an expected control race (HTTP 409) from a storage failure.
var ErrInterceptSessionDeleted = errors.New("对应会话或执行记录已被删除或不存在")
var ErrInterceptTaskDeleted = errors.New("任务已被删除或归档")
var ErrInvalidChatMentionCursor = errors.New("分页位置无效,请重新搜索")
var ErrNotificationChannelNotFound = errors.New("通知渠道不存在")
ErrNotificationChannelNotFound 渠道不存在。
var ErrRetestNotRunning = errors.New("本次复测已结束或尚未开始,请从漏洞详情发起新的复测")
var ErrSideBusy = errors.New("当前会话已有旁路问题正在回答")
var ErrSideParentGone = errors.New("旁路父会话已删除或归档")
Functions ¶
func AddFindingTrafficTx ¶
func AddFindingTrafficTx(tx *sql.Tx, findingID int64, prepared []PreparedTrafficEvidence) error
func AssetInterceptKindLabel ¶
AssetInterceptKindLabel 返回 kind 的中文标签,用于给 agent 的说明消息。
func DSN ¶
DSN resolves the PostgreSQL connection string and reports where it came from. Precedence: env ARTEX_PG_DSN > config file (config.json). There is no built-in default — it errors if neither source is configured.
func EndpointKey ¶
func InsertEvidenceSnapshotTx ¶
func InsertEvidenceSnapshotTx(tx *sql.Tx, s TrafficEvidenceSnapshot) error
func IsTerminal ¶
IsTerminal reports whether a task status is a terminal (finished) state. 单一真源,替换散落各处的 done/failed 硬编码判定。
func LockFindingEvidenceTx ¶
func LockTaskEvidenceTx ¶
LockTaskEvidenceTx serializes writes with archive queueing (which locks the same task row). Once queued, its snapshot must not acquire new evidence.
func NormalizeICP ¶
NormalizeICP removes every Unicode whitespace character and folds case. ICP matching intentionally performs no fuzzy or punctuation normalization.
func NormalizeParamName ¶
NormalizeParamName 归一化参数名(endpoint.params 元素的「相同引用」判定)。 规则:lower + trim,不做同义词合并(userId/user_id/uid 视为不同)。写入与查询共享此实现, 保证「按参数名查同公司接口」可复现。
func NormalizeTaskCompanyIDs ¶
NormalizeTaskCompanyIDs validates IDs and removes duplicates while retaining the user's first-seen order.
func ParameterKey ¶
func ParseDSL ¶
ParseDSL parses a DSL query string into an expression tree.
Syntax:
field=value fuzzy match (ILIKE '%value%') field==value exact match field!=value exclude fuzzy port>8080 numeric comparison bare word full-text fuzzy across all main text fields
Operators: AND OR (case-insensitive), parentheses for grouping. AND binds tighter than OR.
func ParseExpID ¶
ParseExpID turns the exploration-id segment parsed from a session string into an int64 (0 when empty/non-numeric, e.g. chat sessions keyed by conversation id).
func RecordNotificationEventTx ¶ added in v0.3.15
func RecordNotificationEventTx(ctx context.Context, tx *sql.Tx, kind string, findingID int64, snap notify.Snapshot) bool
RecordNotificationEventTx 在调用方的事务里**尽力**写入一条推送事件。
这是漏洞写入路径上唯一的通知相关改动:一次 INSERT,不读任何表、不认识渠道、 不跑过滤。事务提交即保证「漏洞落库」与「推送任务存在」原子一致, 不存在提交成功却没入队、消息永久丢失的窗口。
两个关键设计,都不是随手写的:
**为什么用 SAVEPOINT**:PostgreSQL 里事务内任一语句报错会让整个事务进入 aborted 状态,此后所有语句(含 COMMIT)一律失败。所以「忽略这条 INSERT 的错误、让调用方继续提交」在 PG 里是做不到的——除非用保存点把错误隔离在 这一条语句上。没有保存点,就只剩「整笔回滚」这一个选项。
**为什么整笔回滚是错的**:推送是便利功能,漏洞记录才是产品本身。一个通知 表的问题(旧库未迁移、磁盘瞬时故障)不该让高危漏洞存不进库。所以这里隔离 错误、记日志、返回 false,让漏洞写入照常提交——代价是丢掉这一条推送。 返回 bool 而非 error 是刻意的:调用方不该把它当作会影响写入成败的错误。
func RootDomain ¶
RootDomain returns the registrable domain (eTLD+1) for a host and whether the host itself IS that apex (§3.1). Edge cases (§3.1 边界处理): an IP literal or a host publicsuffix can't classify (localhost / internal / non-ICANN TLD) is returned unchanged as its own root with isApex=true — best-effort, never treated as a subdomain.
func ServiceKey ¶
func SetFindingStatusTx ¶ added in v0.3.15
func SetFindingStatusTx(ctx context.Context, tx *sql.Tx, id int64, status string) (from string, found bool, changed bool, notified bool, err error)
SetFindingStatusTx 在**调用方的事务**内更新漏洞状态并登记状态变更推送事件。
抽成事务级函数是为了让所有改状态的路径共用同一套语义——此前只有 patchFinding 走带通知的版本,而**复测结论为「已修复」时**(finding_retests 里那条 `UPDATE findings SET status=...`)是直接写库的,于是配了 `on_status_change` 的渠道对这类状态流转完全收不到推送:界面上状态悄悄变了, 运维要到打开平台才发现。
返回 from=变更前状态、found=漏洞是否存在、changed=状态是否真的变了、 notified=事件是否登记成功(登记失败不影响状态更新,见 RecordNotificationEventTx)。
func SplitURL ¶
func SplitURL(raw, method string) (scheme, host string, port int, urlTemplate string, params []string, err error)
SplitURL parses a raw URL into scheme/host/port/urlTemplate/params for building site/endpoint/param keys.
func TemplatePath ¶
TemplatePath collapses high-cardinality path segments into placeholders so the graph is not flooded by instances: /user/123 -> /user/{id}.
func TrafficSnapshotID ¶
func TrafficSnapshotID(snapshot TrafficEvidenceSnapshot) string
func ValidChatMentionKind ¶
func ValidFindingStatus ¶
ValidFindingStatus reports whether s is a known triage state.
func ValidNotifyMode ¶ added in v0.3.15
ValidNotifyMode 白名单校验推送模式(与 findings.status 同理:不用 DB CHECK, 便于后续扩展)。
func ValidSeverity ¶
ValidSeverity reports whether s is a known severity level.
func ValidTrafficRole ¶
func ValidateAssetIP ¶
ValidateAssetIP keeps hostnames out of assets.ip. Network attribution casts that column to inet (see try_inet in schema.sql), so a hostname stored here is silently invisible to every IP/CIDR scope rule — the asset simply never gets attributed and nobody can tell why. The message states the fix rather than just the fault, so an agent can correct the item on its next turn. An empty value is accepted: the ip field is optional for service and endpoint assets.
func ValidateCompanyScopeInputBounds ¶
func ValidateCompanyScopeInputBounds(inputs []ScopeInput) error
ValidateCompanyScopeInputBounds applies request-wide limits before parsing. Store methods call it again so non-HTTP callers cannot bypass the limits. 只约束单条规则的长度,不限制条数。
func ValidateDSL ¶
ValidateDSL parses and compiles a DSL expression without touching the database. HTTP callers use it to distinguish client syntax errors from query failures, which must remain server errors.
Types ¶
type ActiveFindingRetest ¶
type ActiveFindingRetest struct {
ID int64 `json:"id"`
FindingID int64 `json:"finding_id,string"`
ConversationID int64 `json:"conversation_id"`
Status string `json:"status"`
}
ActiveFindingRetest is the small status payload polled by the findings list. Finding IDs use the same string representation as the findings API.
type Activity ¶
type Activity struct {
ID int64 `json:"id"`
NodeID *int64 `json:"node_id,omitempty"`
Worker string `json:"worker,omitempty"`
Kind string `json:"kind,omitempty"`
Tool string `json:"tool,omitempty"`
ToolUseID string `json:"tool_use_id,omitempty"`
IsError bool `json:"is_error"`
Summary string `json:"summary,omitempty"`
Detail string `json:"-"` // full blob; lazy-loaded, omitted from list payloads
Metadata json.RawMessage `json:"metadata,omitempty"`
CreatedAt time.Time `json:"created_at"`
// Token usage — set only on the terminal kind='result' record; nil elsewhere.
InputTokens *int `json:"input_tokens,omitempty"`
OutputTokens *int `json:"output_tokens,omitempty"`
CacheReadTokens *int `json:"cache_read_tokens,omitempty"`
CacheWriteTokens *int `json:"cache_write_tokens,omitempty"`
SourceTaskID int64 `json:"source_task_id,omitempty"`
Inherited bool `json:"inherited,omitempty"`
// MainSeg is the main-agent conversation segment (nil for non-mainagent rows;
// nil/0 == the original session). Lets the UI route a mainagent row to its segment.
MainSeg *int `json:"main_seg,omitempty"`
}
Activity is one worker execution step (= old task_activity).
type ActivitySessionFilter ¶
type ActivitySessionFilter struct {
Worker string
NodeID *int64
Main bool // main-agent session
MainSeg *int // segment for the main session (nil == current, resolved by caller; 0 == original)
}
ActivitySessionFilter selects one UI "session" within a task's activity stream. Exactly one field is meaningful:
- Main == true → the main-agent session (worker="mainagent") for one segment (MainSeg; nil/0 = the original segment, which also matches legacy NULL rows).
- Worker != "" → filter by worker name (Plan = "planner"). Goal Agent 的第 0 轮拆解也以 worker="planner" 落库,故 Plan 会话完整覆盖 Goal+Planner。
- NodeID != nil → a Worker session, filtered by node_id (= intent id).
A zero value (all empty) matches the whole task (no session filter).
type Agent ¶
type Agent struct {
ID int64 `json:"id"`
Key string `json:"key"`
Name string `json:"name"`
Description string `json:"description"`
Role string `json:"role"`
Builtin bool `json:"builtin"`
Enabled bool `json:"enabled"`
LLMProfileID *int64 `json:"llm_profile_id"` // 绑定的 LLM 配置;nil=跟随任务/会话 pin,再回退全局激活
MaxTurns int `json:"max_turns"` // 单次运行最大轮次;0=不限制
RunSecs int `json:"run_seconds"` // worker 单次运行墙钟上限(秒);0=不限制
WebSearch bool `json:"web_search"` // 是否启用网络搜索(受系统全局开关门控)
InteractiveShell bool `json:"interactive_shell"` // 是否启用交互式 shell(持久 PTY 会话工具族)
WrapupPrompt string `json:"wrapup_prompt"` // 收尾提示词(超时/步数耗尽时的 settlement 提示);空=用代码内置默认
WrapupMaxTurns int `json:"wrapup_max_turns"` // 收尾阶段自身的轮数预算;0=用代码内置默认(按 agent)
// 任务级超时收尾词(与 per-run 两套;仅 worker/planner 用);空/0=用代码内置默认。
TaskTimeoutWrapupPrompt string `json:"task_timeout_wrapup_prompt"`
TaskTimeoutWrapupMaxTurns int `json:"task_timeout_wrapup_max_turns"`
// P3 触发后处理策略(仅自定义 agent 有意义):
// TriggerRunMode serial|parallel — 串行排队 / 每次触发各自并发一个会话
// TriggerMergeMode by_task|all|none — 仅 serial 用:同任务合并 / 全部合并 / 不合并
// TriggerMaxParallel — 仅 parallel 用的每 agent 并发上限;0=不限
TriggerRunMode string `json:"trigger_run_mode"`
TriggerMergeMode string `json:"trigger_merge_mode"`
TriggerMaxParallel int `json:"trigger_max_parallel"`
}
type AgentTrigger ¶
type AgentTrigger struct {
ID int64 `json:"id"`
AgentKey string `json:"agent_key"`
Enabled bool `json:"enabled"`
IntervalSec int `json:"interval_sec"`
OnFinding bool `json:"on_finding"`
OnGoalMet bool `json:"on_goal_met"`
OnTaskTimeout bool `json:"on_task_timeout"`
OnToolCall bool `json:"on_tool_call"`
OnTaskCreate bool `json:"on_task_create"`
IntervalMessage string `json:"interval_message"` // 各触发条件的独立用户消息
FindingMessage string `json:"finding_message"`
GoalMessage string `json:"goal_message"`
TaskTimeoutMessage string `json:"task_timeout_message"`
ToolCallMessage string `json:"tool_call_message"`
TaskCreateMessage string `json:"task_create_message"`
ToolNames []string `json:"tool_names"` // 选中的工具 key 列表(DB 存 JSON 文本)
LastFire *time.Time `json:"last_fire,omitempty"`
}
AgentTrigger is one P3 trigger attached to a custom agent. Six trigger conditions can be on at once: interval / on_finding / on_goal_met / on_task_timeout / on_tool_call / on_task_create. ToolNames scopes the tool-call trigger to a non-empty set of tool keys (empty is rejected at the API layer for on_tool_call).
type Asset ¶
type Asset struct {
ID int64 `json:"id"`
Type string `json:"type"`
CompanyID *int64 `json:"company_id,omitempty"`
TaskIDs []int64 `json:"task_ids"`
Domain string `json:"domain,omitempty"`
RootDomain string `json:"root_domain,omitempty"`
IP string `json:"ip,omitempty"`
CSegment string `json:"c_segment,omitempty"`
Port *int `json:"port,omitempty"`
ICP string `json:"icp,omitempty"`
// ip fields
BoundDomains []string `json:"bound_domains,omitempty"`
OpenPorts []map[string]any `json:"open_ports,omitempty"`
// subdomain fields
RecordType string `json:"record_type,omitempty"`
RecordValue []string `json:"record_value,omitempty"`
// app fields
BundleID string `json:"bundle_id,omitempty"`
AppName string `json:"app_name,omitempty"`
Category string `json:"category,omitempty"`
AppDescription string `json:"app_description,omitempty"`
AppICP string `json:"app_icp,omitempty"`
// service fields
URL string `json:"url,omitempty"`
ServiceType string `json:"service_type,omitempty"`
ServiceName string `json:"service_name,omitempty"`
FaviconMMH3 string `json:"favicon_mmh3,omitempty"`
StatusCode *int `json:"status_code,omitempty"`
ContentLength *int64 `json:"content_length,omitempty"`
PageTitle string `json:"page_title,omitempty"`
Technologies []string `json:"technologies,omitempty"`
Auth []map[string]any `json:"auth,omitempty"`
// endpoint fields
Method string `json:"method,omitempty"`
Params []map[string]any `json:"params,omitempty"`
// meta
Extra map[string]any `json:"extra,omitempty"`
LastSeen string `json:"last_seen"`
TaskSource string `json:"task_source,omitempty"`
TaskSourceSummary string `json:"task_source_summary,omitempty"`
TaskSourceNodeID *int64 `json:"task_source_node_id,omitempty"`
}
Asset is a row in the assets table.
func (*Asset) InterceptLabel ¶
InterceptLabel 返回资产的简短标识,用于给 agent 的说明消息。
type AssetGateDecision ¶
AssetGateDecision 是「先拦截后允许」闸门对一组候选串的判定结果。
func EvaluateAssetGate ¶
func EvaluateAssetGate(blockRules, allowRules []AssetInterceptRule, domains, ips, urls []string) AssetGateDecision
EvaluateAssetGate 执行任务级闸门判定:
- 命中任一启用的 blockRules → 拒绝(拦截原因)。
- 否则若 allowRules 存在启用项且都不命中 → 拒绝(不在允许范围)。
- 否则放行。
allowRules 为空/无启用项时,允许闸门不生效(即不启用白名单,全部放行), 避免「未配置允许规则」把所有资产挡掉。
type AssetInterceptHit ¶
AssetInterceptHit 描述一个被闸门拒绝的资产(拦截命中 或 不在允许范围)。
func (AssetInterceptHit) Describe ¶
func (h AssetInterceptHit) Describe() string
Describe 返回一条可读的说明:资产信息 + 原因。
type AssetInterceptRule ¶
type AssetInterceptRule struct {
ID int64 `json:"id"`
Enabled bool `json:"enabled"`
Kind string `json:"kind"` // exact_domain|exact_ip|exact_url|fuzzy_domain|fuzzy_ip|fuzzy_url|cidr
Pattern string `json:"pattern"`
Note string `json:"note"`
Builtin bool `json:"builtin"`
// Action 仅用于任务级规则:'block'=拦截 'allow'=允许(白名单)。
// 全局规则(asset_intercept_rules)不带此列,恒为空,视为拦截。
Action string `json:"action,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
AssetInterceptRule is one row of asset_intercept_rules — a global asset blocklist entry. Unlike intercept_rules (which matches tool name / input), these match the *target asset*: an exact/fuzzy domain·ip·url, or a CIDR range. This layer only stores rules; the matching/enforcement logic lives elsewhere.
func MatchAssetInterceptRules ¶
func MatchAssetInterceptRules(rules []AssetInterceptRule, domains, ips, urls []string) (AssetInterceptRule, string, bool)
MatchAssetInterceptRules 返回第一条命中给定 域名/IP/URL 候选串的启用规则,及命中的具体值。 供 insert_assets 用原始输入(尚未落库的 assetInputItem)匹配。
func (AssetInterceptRule) Reason ¶
func (r AssetInterceptRule) Reason() string
Reason 返回一条可读的命中原因,形如:命中资产拦截规则 [域名(模糊): .gov.cn](备注)。
type AssetRef ¶
type AssetRef struct {
ID int64 `json:"id"`
Kind string `json:"kind"`
State string `json:"state"`
Summary string `json:"summary"`
SourceTaskID int64 `json:"source_task_id,omitempty"`
Inherited bool `json:"inherited,omitempty"`
}
AssetRef is a compact exploration node (intent/fact/finding) that references an asset via an anchor — for the coverage graph's node drawer.
type AssetStore ¶
type AssetStore struct {
// contains filtered or unexported fields
}
AssetStore operates on the assets table.
func (*AssetStore) AddAgentScope ¶
func (s *AssetStore) AddAgentScope(taskID int64, kind, value, reason, source string) (TaskScope, error)
AddAgentScope parses a (kind,value) pair and records it as task scope. source is "agent" when called from an LLM tool, "manual" from the UI. company: value = company name or id (must already exist). root_domain/subdomain: value = a domain. ip/cidr: value = an IP or CIDR (bare IP → /32,/128).
func (*AssetStore) AddAutoScope ¶
func (s *AssetStore) AddAutoScope(taskID int64, assetType, domain, rawURL, ip string) error
AddAutoScope records the conservative task scope implied by ONE explicitly-inserted asset item (source='auto'). MUST be called only from insertAssets' top-level loop — never from a db-layer side effect (linkHostAssets), so派生资产不会盲目扩大范围。 Rule: scope granularity follows the asset's own type. taskID<=0 → no-op.
func (*AssetStore) AppendIPBoundDomain ¶
func (s *AssetStore) AppendIPBoundDomain(ipStr, domain string) error
AppendIPBoundDomain appends a domain to an existing IP asset's bound_domains.
func (*AssetStore) AppendIPPort ¶
func (s *AssetStore) AppendIPPort(ipStr string, port int, serviceName string) error
AppendIPPort appends a {port, service} entry to an existing IP asset's open_ports.
func (*AssetStore) AttachAssetsToTask ¶
func (s *AssetStore) AttachAssetsToTask(taskID int64, assetIDs []int64, sourceSummary string) (TaskAssetMutation, error)
AttachAssetsToTask associates existing global assets with one live task and records an operator-authored source summary. Global asset rows are retained.
func (*AssetStore) BuildCoverageGraph ¶
func (s *AssetStore) BuildCoverageGraph(taskID, _ int64) (*CoverageGraphData, error)
BuildCoverageGraph assembles the full coverage graph for a task and its direct read-only sources: every in-scope asset plus connector root domains/companies, with current-or-source fact anchors reflected in Tested. The legacy expID argument is retained for API compatibility; the task registry is authoritative.
func (*AssetStore) CheckAssetsIntercept ¶
func (s *AssetStore) CheckAssetsIntercept(taskID int64, ids []int64) ([]AssetInterceptHit, error)
CheckAssetsIntercept 按 id 载入资产,逐个执行「先拦截后允许」闸门判定,返回所有 被拒的资产。拦截规则 = 全局 ∪ 任务级 block;允许规则 = 任务级 allow(仅本任务)。 无 id 时快速返回。用全局 GetByIDs(不受任务范围过滤)以保证拦截不被 scope 削弱。
func (*AssetStore) Companies ¶
func (s *AssetStore) Companies() *CompanyStore
Companies returns the company store associated with this asset store.
func (*AssetStore) CountByCompany ¶
func (s *AssetStore) CountByCompany(companyID int64, typ string) (int, error)
func (*AssetStore) CountByTask ¶
func (s *AssetStore) CountByTask(taskID int64, typ string) (int, error)
func (*AssetStore) CountByType ¶
func (s *AssetStore) CountByType(typ string) (int, error)
CountByType returns the total number of assets of a type (for server-side pagination).
func (*AssetStore) CountDSL ¶
func (s *AssetStore) CountDSL(dsl, typ string, taskID int64) (int, error)
CountDSL returns the total number of assets matching a DSL expression (and optional type), for server-side pagination — same WHERE as QueryDSL, without LIMIT/OFFSET. taskID > 0 scopes the count to assets attached to that task.
func (*AssetStore) CountsByType ¶
func (s *AssetStore) CountsByType() (map[string]int, error)
CountsByType returns asset counts per type.
func (*AssetStore) CountsByTypeForTask ¶
func (s *AssetStore) CountsByTypeForTask(taskID int64) (map[string]int, error)
func (*AssetStore) CoverageEnabled ¶
func (s *AssetStore) CoverageEnabled(taskID int64) bool
CoverageEnabled reports whether a task has the asset-coverage feature turned on (tasks.coverage_enabled). Missing row / error → true (fail open to the default), so unknown/legacy tasks keep the historical behavior. taskID<=0 → true.
func (*AssetStore) CreateTaskInterceptRule ¶
func (s *AssetStore) CreateTaskInterceptRule(taskID int64, action, kind, pattern, note string, enabled bool) (AssetInterceptRule, error)
CreateTaskInterceptRule inserts a rule under a task.
func (*AssetStore) DeleteByCompanyID ¶
func (s *AssetStore) DeleteByCompanyID(companyID int64) (int64, error)
DeleteByCompanyID hard-deletes all assets belonging to a company. Returns rows deleted.
func (*AssetStore) DeleteByHost ¶
func (s *AssetStore) DeleteByHost(host string) (map[string]int64, error)
DeleteByHost hard-deletes every asset whose host exactly matches the given value: root_domain / subdomain / service / endpoint (they carry the host in domain or root_domain) plus an ip asset and its services/endpoints (ip column). The host is normalized the same way it is stored (DomainKey: lowercase/trim/strip trailing dot) so matching is exact, not fuzzy. Passing a root domain also removes its subdomains and their services/endpoints (they carry root_domain = that host); passing a subdomain/IP removes only that host's own assets. Referencing exploration_anchors rows are cleaned by ON DELETE CASCADE. Returns rows deleted, grouped by type.
func (*AssetStore) DeleteByIDs ¶
func (s *AssetStore) DeleteByIDs(ids []int64) (int64, error)
DeleteByIDs hard-deletes assets by their IDs. Returns the number of rows deleted.
func (*AssetStore) DeleteByTaskID ¶
func (s *AssetStore) DeleteByTaskID(taskID int64) (int64, error)
DeleteByTaskID removes assets owned only by taskID and detaches taskID from assets shared with other tasks. Full task deletion uses the coordinated transaction in DeleteTaskCascadePrepared; this method remains for callers that explicitly manage only asset associations.
func (*AssetStore) DeleteTaskInterceptRule ¶
func (s *AssetStore) DeleteTaskInterceptRule(taskID, ruleID int64) (bool, error)
DeleteTaskInterceptRule removes a task's rule. Returns false if not found.
func (*AssetStore) DeleteTaskScope ¶
func (s *AssetStore) DeleteTaskScope(taskID, scopeID int64) (bool, error)
DeleteTaskScope removes a single scope row by id, scoped to the given task. Returns whether a row was actually deleted.
func (*AssetStore) DetachAssetFromTask ¶
func (s *AssetStore) DetachAssetFromTask(taskID, assetID int64) (bool, error)
DetachAssetFromTask removes only the task association. The global asset and exploration anchors remain available for historical blackboard auditing.
func (*AssetStore) FindingMetaByNodeID ¶
func (a *AssetStore) FindingMetaByNodeID(taskID int64) (map[int64]FindingMeta, error)
FindingMetaByNodeID maps a task's finding node ids to their standalone-row metadata (status + anchored asset ids) via the asset store, so callers holding only an AssetStore (e.g. the agent ToolSet) can reach it without a raw *DB.
func (*AssetStore) GetByIDs ¶
func (s *AssetStore) GetByIDs(ids []int64) ([]*Asset, error)
GetByIDs returns assets with the given ids (order preserved by id array order).
func (*AssetStore) GetByIDsInScope ¶
func (s *AssetStore) GetByIDsInScope(taskID int64, ids []int64) ([]*Asset, error)
GetByIDsInScope is GetByIDs restricted to ids that BELONG to taskID's (and its direct source tasks') declared scope, so an agent cannot reach out-of-scope assets by id. taskID<=0 (non-task contexts) falls back to the global GetByIDs. Out-of-scope ids are silently dropped from the result (not an error).
func (*AssetStore) HostsByTask ¶
func (s *AssetStore) HostsByTask(taskID int64) ([]string, error)
HostsByTask returns the exact HTTP host candidates attached to a task's assets. Domain/IP columns cover root domains, subdomains and non-HTTP services; URL covers HTTP services and endpoints.
func (*AssetStore) HostsByTaskWithSources ¶
func (s *AssetStore) HostsByTaskWithSources(taskID int64) ([]string, error)
HostsByTaskWithSources resolves exact HTTP host candidates from assets that are attached to, anchored by, or in scope for the current task or a direct source. Traffic remains global and is not copied. This read helper must not be used for destructive task cleanup; HostsByTask intentionally retains that narrower, task-owned behavior.
func (*AssetStore) HostsForTaskDeletion ¶
func (s *AssetStore) HostsForTaskDeletion(taskID, explorationID int64) ([]string, error)
HostsForTaskDeletion returns hosts that belong to the task being deleted and are not referenced by any other live task. Current-task candidates include both task_ids ownership and exploration anchors so legacy seeded assets (which were anchor-only) are covered. Protection is host-wide: if another live task references any asset for a candidate host, that host's global traffic remains.
func (*AssetStore) IntentAssets ¶
func (s *AssetStore) IntentAssets(taskID int64) ([]IntentAsset, error)
IntentAssets returns all local worker targets plus immutable targets from the task's direct sources. Inherited non-terminal intents remain hidden, matching the existing source-aware session contract.
func (*AssetStore) ListAssetInterceptRules ¶
func (s *AssetStore) ListAssetInterceptRules() ([]AssetInterceptRule, error)
ListAssetInterceptRules 是 *DB 同名方法的透传,让只持有 AssetStore 的调用方 (如 agent 工具)也能读取规则。
func (*AssetStore) ListTaskInterceptRules ¶
func (s *AssetStore) ListTaskInterceptRules(taskID int64) ([]AssetInterceptRule, error)
ListTaskInterceptRules returns a task's rules (both block and allow) as AssetInterceptRule (Builtin always false; Action carries block/allow). taskID <= 0 returns nothing.
func (*AssetStore) ListTaskScope ¶
func (s *AssetStore) ListTaskScope(taskID int64) ([]TaskScope, error)
ListTaskScope returns all scope rows for a task.
func (*AssetStore) ListTaskScopeWithSources ¶
func (s *AssetStore) ListTaskScopeWithSources(taskID int64) ([]TaskScope, error)
ListTaskScopeWithSources returns the current task's scope followed by the scopes of its direct source tasks. TaskScope.TaskID preserves provenance.
func (*AssetStore) ListUntestedAssets ¶
func (s *AssetStore) ListUntestedAssets(taskID, expID int64, typ string, limit, offset int) ([]CoverageAsset, int, error)
ListUntestedAssets returns a task's in-scope, not-yet-tested assets, optionally filtered by asset type, paginated. Returns the page + the total count. limit<=0 → 10.
func (*AssetStore) ListUntestedAssetsWithSources ¶
func (s *AssetStore) ListUntestedAssetsWithSources(taskID int64, typ string, limit, offset int) ([]CoverageAsset, int, error)
ListUntestedAssetsWithSources is the direct-source-aware backlog query used by inherited tasks. Source fact anchors remove assets from the backlog.
func (*AssetStore) QueryByCompany ¶
func (s *AssetStore) QueryByCompany(companyID int64, typ string, limit, offset int) ([]*Asset, error)
QueryByCompany returns assets for a company, optionally filtered by type. limit <= 0 means no limit.
func (*AssetStore) QueryByTask ¶
QueryByTask returns assets rows that have a given task_id in task_ids.
func (*AssetStore) QueryByType ¶
func (s *AssetStore) QueryByType(typ string, limit, offset int) ([]*Asset, error)
QueryByType returns assets rows of a given type, newest first.
func (*AssetStore) QueryDSL ¶
QueryDSL executes a DSL query string against the asset store. typ is an optional asset type filter applied independently of the DSL expression. taskID > 0 scopes results to assets attached to that task and hydrates each row's per-task source metadata (as QueryByTask does).
func (*AssetStore) QueryDSLInScope ¶
func (s *AssetStore) QueryDSLInScope(dsl, typ string, taskID int64, limit, offset int) ([]*Asset, error)
QueryDSLInScope is QueryDSL restricted to assets that BELONG to taskID's (and its direct source tasks') declared scope — membership, not literal value: a root_domain scope returns every subdomain / service / endpoint under it. This is the agent-facing list_assets path, so an agent queries the task's relevant assets instead of the whole shared库. taskID<=0 (non-task contexts: Auto / pentest / chat) has no scope to honor and falls back to the plain global QueryDSL. Rows carry the same per-task source metadata as QueryByTask.
func (*AssetStore) RegisterTaskAssetScopes ¶
func (s *AssetStore) RegisterTaskAssetScopes(taskID int64, inputs []ScopeInput) (TaskAssetScopeMutation, error)
RegisterTaskAssetScopes accepts the same structured scope rules as enterprise assets. The entire request is atomic: invalid input or any storage failure leaves both global assets and task scope unchanged.
func (*AssetStore) SetTaskAssetSource ¶
func (s *AssetStore) SetTaskAssetSource(taskID, assetID int64, source, summary string, sourceNodeID *int64) error
SetTaskAssetSource improves the generic trigger-created provenance for one existing task association. It never creates or deletes an asset.
func (*AssetStore) TaskCoverage ¶
func (s *AssetStore) TaskCoverage(taskID, expID int64) (*Coverage, error)
TaskCoverage computes rough per-type coverage for a task. taskID indexes task_scope + assets; expID indexes the fact anchors. Reference figure only.
func (*AssetStore) TaskCoverageWithSources ¶
func (s *AssetStore) TaskCoverageWithSources(taskID int64) (*Coverage, error)
TaskCoverageWithSources computes one coverage view over the union of the current task and its direct sources: source scopes and anchored assets extend the denominator, while fact anchors count as tested. No row is copied.
func (*AssetStore) TaskInterceptRulesSplit ¶
func (s *AssetStore) TaskInterceptRulesSplit(taskID int64) (block, allow []AssetInterceptRule, err error)
TaskInterceptRulesSplit loads a task's rules and splits them into block and allow sets, for the enforcement gate.
func (*AssetStore) ToggleTaskInterceptRule ¶
func (s *AssetStore) ToggleTaskInterceptRule(taskID, ruleID int64, enabled bool) error
ToggleTaskInterceptRule flips the enabled state of a task's rule.
func (*AssetStore) UpdateTaskInterceptRule ¶
func (s *AssetStore) UpdateTaskInterceptRule(taskID, ruleID int64, action, kind, pattern, note string, enabled bool) (AssetInterceptRule, error)
UpdateTaskInterceptRule replaces the editable fields of a task's rule (scoped by task_id so a rule can only be edited through its owning task).
func (*AssetStore) UpsertApp ¶
func (s *AssetStore) UpsertApp(req UpsertAppReq) (int64, error)
UpsertApp idempotently inserts or merges an app asset.
func (*AssetStore) UpsertEndpoint ¶
func (s *AssetStore) UpsertEndpoint(req UpsertEndpointReq) (int64, error)
UpsertEndpoint inserts or merges an endpoint asset. Domain, port, root_domain are auto-extracted from the URL.
func (*AssetStore) UpsertHTTPService ¶
func (s *AssetStore) UpsertHTTPService(req UpsertHTTPServiceReq) (int64, error)
UpsertHTTPService inserts or merges an HTTP service asset. Domain, port, service_name, and root_domain are auto-extracted from URL.
func (*AssetStore) UpsertIP ¶
func (s *AssetStore) UpsertIP(req UpsertIPReq) (int64, error)
UpsertIP idempotently inserts or merges an IP asset.
func (*AssetStore) UpsertOtherService ¶
func (s *AssetStore) UpsertOtherService(req UpsertOtherServiceReq) (int64, error)
UpsertOtherService inserts or merges a non-HTTP service asset.
func (*AssetStore) UpsertRootDomain ¶
func (s *AssetStore) UpsertRootDomain(req UpsertRootDomainReq) (int64, error)
UpsertRootDomain idempotently inserts or merges a root domain asset.
func (*AssetStore) UpsertSubdomain ¶
func (s *AssetStore) UpsertSubdomain(req UpsertSubdomainReq) (id int64, err error)
UpsertSubdomain idempotently inserts or merges a subdomain asset and triggers side effects: root_domain upsert + IP bound_domains update.
type AuthItem ¶
type AuthItem struct {
Type string `json:"type,omitempty"`
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
Token string `json:"token,omitempty"`
Description string `json:"description,omitempty"`
}
AuthItem is one entry in the auth array.
type ChatMention ¶
type ChatMention struct {
Kind string `json:"kind"`
ID int64 `json:"id"`
Label string `json:"label"`
Description string `json:"description"`
}
ChatMention is a lightweight search result. Details are read again on send.
type ChatMentionPage ¶
type ChatMentionPage struct {
Items []ChatMention `json:"items"`
NextCursor string `json:"next_cursor,omitempty"`
}
type CommandRecord ¶
type CommandRecord struct {
ID int64 `json:"id"`
ExpID int64 `json:"exploration_id"`
Worker string `json:"worker"`
Tool string `json:"tool"`
Command string `json:"command"`
Output string `json:"output"`
IsError bool `json:"is_error"`
CreatedAt time.Time `json:"created_at"`
}
CommandRecord is a paired tool_use + tool_result from the activity table (any tool, not just Bash). Command holds the raw tool input (JSON).
type Company ¶
type Company struct {
ID int64 `json:"id"`
Name string `json:"name"`
NKey string `json:"nkey"`
Logo *string `json:"logo,omitempty"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
Company is a row in the companies table.
type CompanyScopeValidationError ¶
type CompanyScopeValidationError struct{ Message string }
CompanyScopeValidationError identifies a client-correctable scope error. Storage and transaction failures are returned as ordinary errors instead.
func (*CompanyScopeValidationError) Error ¶
func (e *CompanyScopeValidationError) Error() string
type CompanyStore ¶
type CompanyStore struct {
// contains filtered or unexported fields
}
CompanyStore operates on the companies + company_scope tables.
func (*CompanyStore) AddScope ¶
func (s *CompanyStore) AddScope(companyID int64, lines []string, reason string) (added, skipped, invalid int, errors []string)
AddScope parses and inserts scope lines for a company, then reattributes assets. Returns counts of added, skipped, and invalid lines.
func (*CompanyStore) AddScopeInputs ¶
func (s *CompanyStore) AddScopeInputs(companyID int64, inputs []ScopeInput, reason string) (added, skipped, invalid int, errors []string)
AddScopeInputs inserts structured scope rules. Empty kinds use the automatic CIDR/IP/ICP/domain/keyword classification used by AddScope.
func (*CompanyStore) AddScopeInputsChecked ¶
func (s *CompanyStore) AddScopeInputsChecked(companyID int64, inputs []ScopeInput, reason string) ( added, skipped, invalid int, validationErrors []string, err error, )
AddScopeInputsChecked inserts structured scope rules while keeping input validation separate from storage and transaction errors.
func (*CompanyStore) CreateCompanyWithScope ¶
func (s *CompanyStore) CreateCompanyWithScope(name, logo string, inputs []ScopeInput, reason string) ( id int64, added, skipped, invalid int, validationErrors []string, err error, )
CreateCompanyWithScope creates a company without updating an existing row. The company, its valid initial scope rules, and derived asset attribution are committed atomically. Invalid inputs retain the legacy partial-validation contract and are reported without preventing valid rules from being stored.
func (*CompanyStore) DeleteCompany ¶
func (s *CompanyStore) DeleteCompany(id int64) error
DeleteCompany deletes a company and re-evaluates automatic ownership against the remaining companies in the same transaction. Explicitly-owned assets are detached by the FK and may then fall back to a remaining scope match.
func (*CompanyStore) DeleteCompanyWithAssets ¶
func (s *CompanyStore) DeleteCompanyWithAssets(id int64, deleteAssets bool) (assetsDeleted int64, err error)
DeleteCompanyWithAssets deletes a company and optionally all of its assets in one transaction, then re-evaluates ownership against the remaining companies.
func (*CompanyStore) GetCompany ¶
func (s *CompanyStore) GetCompany(id int64) (*Company, error)
GetCompany returns one company by id (nil if not found).
func (*CompanyStore) GetCompanyByName ¶
func (s *CompanyStore) GetCompanyByName(name string) (*Company, error)
GetCompanyByName returns one company by normalized name (nil if not found).
func (*CompanyStore) GetScope ¶
func (s *CompanyStore) GetScope(companyID int64) ([]ScopeRule, error)
GetScope returns all scope rules for a company.
func (*CompanyStore) ListCompanies ¶
func (s *CompanyStore) ListCompanies() ([]*CompanyWithScope, error)
ListCompanies returns all companies with scope and asset count.
func (*CompanyStore) MalformedIPAssetWarning ¶
func (s *CompanyStore) MalformedIPAssetWarning() (string, error)
MalformedIPAssetWarning reports assets with an unparseable ip outside of any mutation, letting the API attach the warning to a scope response without widening the mutation signatures — an unrelated data problem is not one of this request's validation errors.
func (*CompanyStore) RecomputeAttribution ¶
func (s *CompanyStore) RecomputeAttribution() error
RecomputeAttribution rebuilds only scope-derived ownership. Explicit company links are immutable under scope edits. Precedence is domain, IP/CIDR, then normalized exact ICP; keyword rules never attribute assets.
func (*CompanyStore) ResolveCompany ¶
func (s *CompanyStore) ResolveCompany(rootDomain, ipStr string) (*int64, error)
ResolveCompany returns the company_id for a given root_domain and/or ip, or nil if no scope rule matches. Mirrors the attribution logic used at asset insert time.
func (*CompanyStore) ResolveCompanyWithICP ¶
func (s *CompanyStore) ResolveCompanyWithICP(rootDomain, ipStr, icp string) (*int64, error)
ResolveCompanyWithICP mirrors RecomputeAttribution for insert-time ownership. ICP is consulted only after domain and IP/CIDR fail to match.
func (*CompanyStore) UpdateScope ¶
func (s *CompanyStore) UpdateScope(companyID int64, lines []string, reason string) (added, invalid int, errs []string)
UpdateScope replaces all scope rules for a company and reattributes.
func (*CompanyStore) UpdateScopeInputs ¶
func (s *CompanyStore) UpdateScopeInputs(companyID int64, inputs []ScopeInput, reason string) (added, invalid int, errs []string)
UpdateScopeInputs replaces all rules with a structured set.
func (*CompanyStore) UpdateScopeInputsChecked ¶
func (s *CompanyStore) UpdateScopeInputsChecked(companyID int64, inputs []ScopeInput, reason string) ( added, invalid int, validationErrors []string, err error, )
UpdateScopeInputsChecked replaces all rules while separating validation feedback from storage and transaction failures.
func (*CompanyStore) UpsertByName ¶
func (s *CompanyStore) UpsertByName(name string) (int64, error)
UpsertByName creates the company if it doesn't exist, then returns its id.
func (*CompanyStore) UpsertCompany ¶
func (s *CompanyStore) UpsertCompany(name, logo string) (id int64, created bool, err error)
UpsertCompany creates or updates a company by name. Returns the id and whether a new row was created.
type CompanyWithScope ¶
type CompanyWithScope struct {
Company
Scope []ScopeRule `json:"scope"`
AssetCount int `json:"asset_count"`
}
CompanyWithScope extends Company with its scope rules and asset count.
type Constraint ¶
type Constraint struct {
ID int64 `json:"id"`
Kind string `json:"kind"` // allow | deny
Text string `json:"text"`
Origin string `json:"origin,omitempty"` // goals | human | system
CreatedAt time.Time `json:"created_at"`
}
Constraint is one operator-authored operation constraint for a task: kind=allow (permitted operations) or kind=deny (forbidden operations), free-text. Stored in task_constraints, keyed by exploration_id (cascades with the exploration).
type ConvTokenSummary ¶
type ConvTokenSummary struct {
LLMProfileID *int64 `json:"llm_profile_id"`
CreatedAt string `json:"created_at"`
InputTokens int `json:"input_tokens"`
OutputTokens int `json:"output_tokens"`
CacheReadTokens int `json:"cache_read_tokens"`
CacheWriteTokens int `json:"cache_write_tokens"`
}
ConvTokenSummary is one conversation's token total (sum of its kind='result' rows) with its profile + created_at, used to merge conversation usage into the dashboard's per-profile / daily token stats (which otherwise cover only tasks).
type Conversation ¶
type Conversation struct {
ID int64 `json:"id"`
AgentKey string `json:"agent_key"`
Title string `json:"title"`
LLMProfileID *int64 `json:"llm_profile_id,omitempty"`
Pinned bool `json:"pinned"`
PinnedAt *time.Time `json:"pinned_at,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Conversation is one ChatGPT-style chat thread bound to an agent key. It lives independent of the pentest exploration graph — see schema.sql §I.
type ConversationPatch ¶
ConversationPatch updates only the fields whose pointers are non-nil.
type Coverage ¶
type Coverage struct {
Enabled bool `json:"enabled"` // 资产覆盖度功能是否开启;false 时其余字段为零值
ScopeRows int `json:"scope_rows"` // 0 → 范围未锚定
Denominator int `json:"denominator"` // 范围内资产数
Tested int `json:"tested"` // 已测(约)
Pct *float64 `json:"pct"` // 覆盖度;分母 0 时 null
ByType []CoverageByType `json:"by_type"` // 按资产类型的 总数/已测
}
Coverage is a task's rough asset test coverage — a reference figure for the agent, NOT a precise metric. Denominator = assets matching any active task_scope row; Tested = those anchored to at least one fact node in the exploration.
type CoverageAsset ¶
type CoverageAsset struct {
ID int64 `json:"id"`
Type string `json:"type"`
Label string `json:"label"`
}
CoverageAsset is one in-scope asset (used for the untested backlog sample).
type CoverageByType ¶
type CoverageByType struct {
Type string `json:"type"`
Total int `json:"total"`
Tested int `json:"tested"`
}
CoverageByType is per-asset-type coverage: total in scope vs tested.
type CoverageGraphData ¶
type CoverageGraphData struct {
Nodes []CoverageGraphNode `json:"nodes"`
Edges []CoverageGraphEdge `json:"edges"`
}
CoverageGraphData is the whole graph for one task.
type CoverageGraphEdge ¶
CoverageGraphEdge is a child→parent containment link (endpoint→service→ subdomain/ip→root_domain→company, app→company).
type CoverageGraphNode ¶
type CoverageGraphNode struct {
Key string `json:"key"`
Kind string `json:"kind"` // company|root_domain|subdomain|ip|service|app|endpoint
Label string `json:"label"`
Tested bool `json:"tested"`
InScope bool `json:"in_scope"`
AssetID int64 `json:"asset_id,omitempty"` // 0 for company / synthetic root
CompanyID int64 `json:"company_id,omitempty"`
Domain string `json:"domain,omitempty"`
RootDomain string `json:"root_domain,omitempty"`
IP string `json:"ip,omitempty"`
URL string `json:"url,omitempty"`
Port int `json:"port,omitempty"`
ServiceType string `json:"service_type,omitempty"`
AppName string `json:"app_name,omitempty"`
PageTitle string `json:"page_title,omitempty"`
StatusCode int `json:"status_code,omitempty"`
}
CoverageGraphNode is one node of the asset coverage graph. Node identity is a string key: an asset row is "a:<id>", a company is "c:<id>", and a root domain with no asset row of its own is the synthetic "r:<domain>". Out-of-scope connector nodes (roots pulled in only to link subdomains, and the companies above them) carry InScope=false and are rendered gray.
type DB ¶
DB wraps the shared *sql.DB. PG handles its own connection pool + concurrency (MVCC), so unlike the old SQLite store there is no process-wide write mutex.
func (*DB) ActiveProfile ¶
func (d *DB) ActiveProfile() (*LLMProfile, error)
ActiveProfile returns the default (active) profile with its api key, or nil.
func (*DB) AddAgentToToolBinding ¶
AddAgentToToolBinding adds an agent key to the given tools' `agents` arrays if not already present (idempotent). Used to give the built-in Auto agent its default toolset on existing DBs.
func (*DB) AddFinding ¶
func (d *DB) AddFinding(taskID, nodeID int64, vulnclass, name, severity, summary, evidence, worker string, assetIDs []int64) (int64, error)
AddFinding inserts a finding into the standalone findings table. taskID and nodeID may be 0 (stored as NULL). name may be "" (frontend falls back to vulnclass). Returns the new finding id.
func (*DB) AddNotificationEvent ¶ added in v0.3.15
func (d *DB) AddNotificationEvent(ctx context.Context, kind string, findingID int64, snap notify.Snapshot) (int64, error)
AddNotificationEvent 是 InsertNotificationEventTx 的独立事务版本,供不在 既有事务里的调用点使用(如渠道的「发送测试消息」,它没有真实 finding)。
func (*DB) AgentBindingCounts ¶
func (d *DB) AgentBindingCounts() (mcp map[int64]int, skill map[int64]int, tools map[string]int, err error)
AgentBindingCounts returns per-agent binding counts in a few grouped queries (NO N+1): visible MCP servers and skills keyed by agent id, and bound tools keyed by agent key (tools.agents is a JSONB array of agent keys). Missing keys mean zero. Used to show "MCP N · Skill N · 工具 N" on the agent cards.
func (*DB) AgentSkillNames ¶
AgentSkillNames returns the skill directory names visible to an agent.
func (*DB) AgentVisible ¶
AgentVisible returns the resource ids of a kind visible to an agent.
func (*DB) AppendConvActivity ¶
AppendConvActivity records one step of a conversation (human message or an agent execution step) and returns its id. Mirrors ExplorationStore.AppendActivity but keyed by conversation_id. Reuses the Activity struct (NodeID is ignored here).
func (*DB) AppendTaskArchiveWarning ¶
func (*DB) ArchivedAggregateStats ¶
func (d *DB) ArchivedAggregateStats() ([]json.RawMessage, error)
ArchivedAggregateStats returns compact summaries used by global dashboards so cold data does not disappear from historical totals.
func (*DB) BuildFindingAssetTree ¶
func (d *DB) BuildFindingAssetTree(f FindingFilter) (*FindingAssetTree, error)
BuildFindingAssetTree 按当前筛选构建资产树。AssetScope 自身不参与(否则树会随 选中节点塌缩成一条链)。
func (*DB) ClaimDigestBatch ¶ added in v0.3.15
func (d *DB) ClaimDigestBatch(ctx context.Context, channelID int64, limit int, lease time.Duration) ([]*NotificationDelivery, error)
ClaimDigestBatch 领取某渠道当前到期的待发投递,作为一个汇总批次, 单批最多 MaxDigestBatchSize 条。
同批次的所有投递共享 batch_id,用集合里的最小 id 作批次号(稳定、可读、 无需额外序列)。重试时用 COALESCE 保留原批次号,使「这批 N 条是一起发的」 在多次重试后依然成立。
按 id 升序取前 N 条而非随机取:最早产生的投递最先发出去,积压时不会出现 「新漏洞先发、老漏洞永远排在后面」的饥饿。
func (*DB) ClaimRealtimeDeliveries ¶ added in v0.3.15
func (d *DB) ClaimRealtimeDeliveries(ctx context.Context, channelID int64, limit int, lease time.Duration) ([]*NotificationDelivery, error)
ClaimRealtimeDeliveries 领取某渠道一批到期的实时投递,最多 limit 条。
刻意按**单个渠道**领取而不是「全局领一批再挑着发」:限流闸在投递引擎里按渠道 维护,只有先知道这个渠道这一轮还能发几条、再去领同样多的行,限流才不会消耗 重试次数。若反过来先领后弃,被限流挡下的行已经被计过一次 attempts, 3 次预算会被纯粹的等待耗光,最后落进 failed。
条件含「租约已过期的 sending」——那是崩溃自愈的落点。lease 必须显著大于单次 投递的最坏耗时(渠道 HTTP 客户端超时 15 秒),否则同一行会被两个 dispatcher 同时投递。同时挡掉已停用渠道:停用操作已把存量投递标记为 skipped, 这里再拦一道,避免停用与领取并发时的漏网。
func (*DB) ClaimTaskArchiveJob ¶
func (d *DB) ClaimTaskArchiveJob(ctx context.Context) (*TaskArchive, error)
ClaimTaskArchiveJob claims one persistent FIFO item for the single archive worker. It returns nil when the queue is empty.
func (*DB) ClearLLMHealth ¶
ClearLLMHealth drops one profile's state (manual "recover now" from the UI).
func (*DB) CompleteIntercept ¶
func (d *DB) CompleteIntercept(id int64, runID, toolUseID, status, output string, truncated bool) error
CompleteIntercept only updates the exact recorded call after it was allowed. A blocked tool_result must never be presented as a failed execution.
func (*DB) CompleteTaskArchive ¶
func (d *DB) CompleteTaskArchive( archiveID int64, snapshot *TaskArchiveSnapshot, archivePath, sha256 string, originalSize, compressedSize int64, ) error
CompleteTaskArchive performs the hot-store compaction only after the external package has been fully written and checksummed. The task/exploration rows remain as minimal ID stubs; all heavyweight task-owned rows move into the package.
func (*DB) CompleteTaskArchiveRestore ¶
CompleteTaskArchiveRestore removes compact metadata after every external component has been verified and the package has been consumed.
func (*DB) ConvActivityDetail ¶
ConvActivityDetail lazily returns the full detail blob for one step.
func (*DB) ConvActivityList ¶
ConvActivityList returns a conversation's steps after sinceID (exclusive) with the summary-only column set (detail is lazy-loaded via ConvActivityDetail).
func (*DB) ConvActivityPage ¶
ConvActivityPage returns one page for reverse (newest-first) pagination: up to `limit` steps ending before id `before` (exclusive; before<=0 = the latest page), returned in ASCENDING id order. hasMore reports whether still-older steps exist before the returned window, so the client can stop loading earlier history on scroll-up. Summary-only columns (detail is lazy-loaded via ConvActivityDetail).
func (*DB) ConversationTokenSummaries ¶
func (d *DB) ConversationTokenSummaries() ([]ConvTokenSummary, error)
ConversationTokenSummaries returns one row per conversation with its summed result-row token usage (0 for conversations with no completed run yet).
func (*DB) CreateAgent ¶
CreateAgent inserts a custom (builtin=false) conversational agent with role 'assistant'. Returns the new row. Callers validate key/name upstream; the DB enforces key charset + uniqueness and the role check constraint.
func (*DB) CreateAssetInterceptRule ¶
func (d *DB) CreateAssetInterceptRule(kind, pattern, note string, enabled bool) (AssetInterceptRule, error)
CreateAssetInterceptRule inserts a new user rule (builtin is always false here).
func (*DB) CreateConversation ¶
func (d *DB) CreateConversation(agentKey, title string, llmProfileID *int64) (*Conversation, error)
CreateConversation opens a new chat thread for agentKey with an initial title. llmProfileID may be nil to use the globally active profile.
func (*DB) CreateCustomTool ¶
CreateCustomTool inserts a user-defined tool (system=false) with an execution spec. Fails if the key already exists.
func (*DB) CreateDecidedIntercept ¶
func (d *DB) CreateDecidedIntercept(ruleID, convID int64, taskID, agentName, toolName string, input []byte, status, reason string, audits ...*InterceptAudit) (int64, error)
CreateDecidedIntercept inserts an intercept_pending row ALREADY in a final state (status = 'allowed' | 'denied'), decided_at stamped now. Used to log allow/deny rule matches for observability — they don't block and need no user action, so unlike CreateInterceptPending (which starts 'pending') this records the outcome directly.
func (*DB) CreateExploration ¶
CreateExploration creates a new exploration root and returns its id.
func (*DB) CreateFindingRetest ¶
func (d *DB) CreateFindingRetest(ctx context.Context, findingID int64, notes string) (*FindingRetest, *Conversation, bool, error)
CreateFindingRetest atomically snapshots the source, creates its conversation and persists the first message. A finding row lock deduplicates simultaneous clicks across clients; an existing active run is returned without dispatching.
func (*DB) CreateInterceptPending ¶
func (d *DB) CreateInterceptPending(ruleID, convID int64, taskID, agentName, toolName string, input []byte, reason string, audits ...*InterceptAudit) (int64, error)
CreateInterceptPending inserts a pending approval record and returns its ID. convID == 0 → conversation_id stored as NULL (background task). taskID == "" → task_id stored as NULL.
func (*DB) CreateInterceptRule ¶
func (d *DB) CreateInterceptRule(name, matchTarget, matchType, pattern, action, message string, priority int, enabled bool, timeoutEnabled bool, timeoutSeconds int, timeoutAction string) (InterceptRule, error)
CreateInterceptRule inserts a new rule.
func (*DB) CreateTask ¶
func (*DB) CreateTaskCategory ¶
func (d *DB) CreateTaskCategory(name string) (*TaskCategory, error)
func (*DB) CreateTaskTemplate ¶
func (d *DB) CreateTaskTemplate(in TaskTemplateInput) (*TaskTemplate, error)
CreateTaskTemplate inserts one globally reusable preset.
func (*DB) CreateTaskWithOptions ¶
func (d *DB) CreateTaskWithOptions(description, goal string, opts TaskCreateOptions) (*Task, error)
CreateTaskWithOptions creates an exploration, task, direct source relations, and the ordered task LLM chain in one transaction.
func (*DB) CreateTrigger ¶
func (d *DB) CreateTrigger(t *AgentTrigger) (*AgentTrigger, error)
CreateTrigger inserts a trigger for agentKey and returns it.
func (*DB) CurrentPrompt ¶
CurrentPrompt returns the agent's active template text ("" if none set yet).
func (*DB) CurrentSideRequest ¶
func (*DB) DecideInterceptPending ¶
DecideInterceptPending updates a pending record's status (allowed/denied/timeout).
func (*DB) DeferDeliveries ¶ added in v0.3.15
DeferDeliveries 把一批投递退回 pending、立即可再领,并**撤销领取时计的那一次尝试**。
用途只有一个:汇总消息按渠道长度上限分段发送时,没装进本条的条目要留到下一批。 那不是失败,所以不该消耗重试预算——领取时 attempts 已经乐观地 +1 了, 这里必须减回去。否则一个 500 条的积压会按每段 20 条切成 25 段, 尾部条目在第 3 段就被 MaxNotifyAttempts 判成 failed,而它们从未出过任何错。
GREATEST(...,0) 兜住「有人手工重发把 attempts 清零后又走到这里」的情况, 不让计数变成负数。
func (*DB) DeleteAgent ¶
DeleteAgent removes a custom agent. Built-in agents are protected by the builtin=false guard. agent_prompts / agent_prompt_vars / visibility rows cascade via FK; tools.agents bindings for the key are cleaned by the caller.
func (*DB) DeleteAssetInterceptRule ¶
DeleteAssetInterceptRule removes a rule (built-in rules are deletable too).
func (*DB) DeleteConversation ¶
DeleteConversation removes a thread; its activities cascade via FK.
func (*DB) DeleteConversations ¶
DeleteConversations removes existing threads in one statement and returns the ids that were actually present. Child activities and trigger runs cascade.
func (*DB) DeleteCustomTool ¶
DeleteCustomTool removes a custom tool (system=false only; built-ins protected).
func (*DB) DeleteFinding ¶
DeleteFinding removes a finding entirely: the standalone findings row and its originating exploration node (kind='finding'), so it disappears from the findings list, the per-task 发现 Tab, and the exploration graph alike. Deleting the node cascades its edges + node_assets and nulls any activity referencing it. Returns rows affected (0 = no finding with that id).
func (*DB) DeleteFindingsByTask ¶
DeleteFindingsByTask removes all findings rows of a task. The originating exploration finding nodes are cascade-deleted separately when the task's exploration subgraph is dropped. Returns rows deleted.
func (*DB) DeleteInterceptRule ¶
DeleteInterceptRule removes a rule.
func (*DB) DeleteLLMRecords ¶
DeleteLLMRecords removes every LLM record for one exact task_id — the same match the page's task picker/filter uses. Returns rows deleted.
func (*DB) DeleteNotificationChannel ¶ added in v0.3.15
DeleteNotificationChannel 删除渠道。其投递历史随外键级联删除 (渠道配置都没了,历史无从解读)。
func (*DB) DeleteProfile ¶
func (*DB) DeleteProfileContext ¶
DeleteProfileContext removes a non-default profile while preserving the task failover cursor. Reference changes are retried because a task, agent, or conversation may start pointing at the profile between the initial scan and the profile row lock. A bound prevents a continuously changing workload from keeping an HTTP request alive forever.
func (*DB) DeleteSkillVisibility ¶
DeleteSkillVisibility removes all visibility rows for a skill (called on skill delete).
func (*DB) DeleteTask ¶
DeleteTask preserves the historical behavior: remove the task and its exploration subgraph while retaining global assets.
func (*DB) DeleteTaskArchiveStub ¶
DeleteTaskArchiveStub permanently removes the cold task after its package has been staged for deletion. Dependency protection is rechecked transactionally.
func (*DB) DeleteTaskCascade ¶
func (d *DB) DeleteTaskCascade(id int64, deleteAssets, deleteFindings bool, deleteLLMRecords ...bool) (TaskDeleteResult, error)
DeleteTaskCascade hard-deletes a task and its exploration subgraph (nodes/edges/activity via ON DELETE CASCADE). Optional standalone findings and assets owned only by this task are deleted in the same transaction; shared assets are retained and only have this task id detached. deleteLLMRecords is optional to preserve callers of the original two-option API.
func (*DB) DeleteTaskCascadePrepared ¶
func (d *DB) DeleteTaskCascadePrepared( id int64, deleteAssets, deleteFindings, deleteLLMRecords bool, prepare func(TaskDeletePreparation) error, ) (TaskDeleteResult, error)
DeleteTaskCascadePrepared coordinates reversible external deletion with the PostgreSQL cascade. When prepare is non-nil, host ownership is resolved and prepare is invoked inside this transaction while asset and anchor writers are excluded. The locks remain held through commit, closing the window where a host could become shared after its traffic had already been staged.
prepare must only stage reversible work. Any returned error or later database error rolls PostgreSQL back; the caller remains responsible for rolling back external work that its callback staged successfully.
func (*DB) DeleteTaskCategory ¶
DeleteTaskCategory moves affected tasks to the uncategorized bucket through the tasks.category_id ON DELETE SET NULL foreign key.
func (*DB) DeleteTaskTemplate ¶
DeleteTaskTemplate deletes one preset and reports whether it existed.
func (*DB) DeleteTrigger ¶
DeleteTrigger removes a trigger.
func (*DB) DeleteTriggersForAgent ¶
DeleteTriggersForAgent removes all triggers of an agent (custom agent delete).
func (*DB) Dequeue ¶
Dequeue removes the concurrency hold. clearMode is false when a user pauses a queued task, preserving whether its next admission must bootstrap or resume.
func (*DB) DigestBatchDue ¶ added in v0.3.15
func (d *DB) DigestBatchDue(ctx context.Context, channelID int64, minAge time.Duration) (bool, error)
DigestBatchDue 报告该渠道是否已攒够一个到期批次:存在待发投递,且**最老的那条** 年龄已达到汇总周期。
判定依据是最老投递的年龄而非墙上时钟:这样刚建好的渠道不会因为对齐到整点而 立刻吐出一条只有一条的「汇总」,积压很久的批次也不会再白等一轮。
与 ClaimDigestBatch 分开是因为语义不同:本函数只回答「该不该发」, 而领取要拿走该渠道**全部**待发行(包括尚未满年龄的那些)——否则一个周期 会被拆成多条消息,汇总就失去意义了。
func (*DB) EditFindingTraffic ¶
func (*DB) Enqueue ¶
Enqueue places a task at the tail of the persistent admission queue. Repeating the operation while it is already queued keeps its original FIFO position.
func (*DB) EnsureLLMRecordsTable ¶
EnsureLLMRecordsTable creates the llm_records table if it does not exist.
func (*DB) EnsureLLMUsageTable ¶
EnsureLLMUsageTable creates the llm_usage metering table if it does not exist.
func (*DB) ExistingSideRequest ¶
func (*DB) Exploration ¶
func (d *DB) Exploration(id int64) *ExplorationStore
Exploration returns a handle bound to an exploration id.
func (*DB) ExplorationDiag ¶
ExplorationDiag probes, at the moment of an activity FK violation (23503), why the parent row is unreachable. It reports whether the exploration row still exists, how many task rows reference it (a live task should keep exactly 1 — and RESTRICT on tasks.exploration_id means the exploration CANNOT be deleted while that row lives), and the current MAX(explorations.id). Together these tell apart the failure modes:
- expExists=false, taskRefs=0 → the whole row set is gone (DB reset / wrong DB).
- expExists=false, taskRefs=1 → impossible under RESTRICT; would mean a broken FK.
- expExists=true → the write's expID is NOT this exploration (stale/ wrong id in the in-memory store); compare against Store.ID().
func (*DB) FailDeliveries ¶ added in v0.3.15
FailDeliveries 把一批投递标记为最终失败,等待人工在投递历史里重发。
func (*DB) FailPendingRetestForConversation ¶
FailPendingRetestForConversation seals a conversation's unfinished retest when the runner could not even load it — the retest ID is unknown on that path, so the conversation ID is the only handle. Without it a transient read error leaves the row 'pending' forever: the findings list keeps showing 复测中 and every later 发起复测 is deduped against a run that is not happening, with only a process restart (RecoverFindingRetests) able to clear it.
func (*DB) FailTaskArchiveJob ¶
func (*DB) FanOutPendingEvents ¶ added in v0.3.15
func (d *DB) FanOutPendingEvents(ctx context.Context, limit int) (eventCount, deliveryCount int, err error)
FanOutPendingEvents 把尚未分派的漏洞事件按当前启用的渠道展开成投递任务, 返回本轮处理的事件数与新建的投递数。
整轮操作在一个事务里:事件用 FOR UPDATE SKIP LOCKED 领取,多个进程同时跑 也各自领到不同的行(项目里归档队列的领取用的是同一套手法,见 db/task_archives.go 的 completeNextArchiveJob)。
过滤匹配刻意放在 Go 侧而非 SQL:渠道的过滤条件是一组可选字段的 JSONB, 用 SQL 表达六种组合的匹配会让查询难以维护,而渠道数量是「人手配的几条」, 全量加载后在内存里逐条比对更快也更好测。
未命中任何渠道的事件同样会被标记 fanned_out ——否则它会永远留在待分派集合里, 每个 tick 被重扫一遍。
func (*DB) FindingMetaByNodeID ¶
func (d *DB) FindingMetaByNodeID(taskID int64) (map[int64]FindingMeta, error)
FindingMetaByNodeID maps a task's finding node ids to their standalone-row metadata, so the per-task view (which reads exploration nodes) can show and edit the same status — and the same anchored assets — as the global 发现 page.
func (*DB) FindingRetestForConversation ¶
func (*DB) FindingStats ¶
func (d *DB) FindingStats() (*FindingStats, error)
FindingStats returns whole-table counts (by severity + pending) and the sorted set of distinct vuln classes.
func (*DB) FinishFindingRetest ¶
FinishFindingRetest seals the result. Cancellation/failure takes precedence over a staged verdict so an interrupted test cannot appear successfully fixed. Only a newly completed fixed verdict updates triage, in the same transaction.
func (*DB) GetConversation ¶
func (d *DB) GetConversation(id int64) (*Conversation, error)
GetConversation returns one thread (nil, nil if absent).
func (*DB) GetFinding ¶
GetFinding returns a single finding row (with task_description joined and the full Markdown report), or nil when no row has that id. Unlike the list queries it also selects `report` — that column is only needed on the detail page.
func (*DB) GetFindingTraffic ¶
func (*DB) GetInterceptDetail ¶
func (d *DB) GetInterceptDetail(id int64) (*InterceptDetail, error)
func (*DB) GetInterceptExecution ¶
func (d *DB) GetInterceptExecution(id int64) (*InterceptExecution, error)
func (*DB) GetInterceptPending ¶
func (d *DB) GetInterceptPending(id int64) (*InterceptPending, error)
GetInterceptPending returns one pending record (nil if absent).
func (*DB) GetLLMRecord ¶
GetLLMRecord returns a single LLM record with full request/response bodies.
func (*DB) GetSetting ¶
GetSetting returns the stored value and ok=false when the key is unset.
func (*DB) GetTaskArchive ¶
func (d *DB) GetTaskArchive(id int64) (*TaskArchive, error)
func (*DB) GetTaskArchiveByTask ¶
func (d *DB) GetTaskArchiveByTask(taskID int64) (*TaskArchive, error)
func (*DB) GetTaskCategory ¶
func (d *DB) GetTaskCategory(id int64) (*TaskCategory, error)
func (*DB) GetTaskTemplate ¶
func (d *DB) GetTaskTemplate(id int64) (*TaskTemplate, error)
GetTaskTemplate returns nil when id does not exist.
func (*DB) GoalCountsAll ¶
func (d *DB) GoalCountsAll() (map[int64]GoalCounts, error)
GoalCountsAll returns goal totals (total / met) per exploration id, one query for all tasks — used by listTasks so the task list shows progress for every task.
func (*DB) InsertLLMRecord ¶
InsertLLMRecord stores one LLM call record.
func (*DB) InsertLLMUsage ¶
InsertLLMUsage appends one metering row. Best-effort: callers log and continue on error (a lost metering row must never break the LLM call).
func (*DB) InsertSettingIfAbsent ¶ added in v0.3.15
InsertSettingIfAbsent 只在 key 尚未存在时写入,已存在则原样保留并返回 inserted=false。 给 auth.password_hash 这类"只允许首次设置"的键用:判定落在数据库的主键约束上, 调用方先 GetSetting 再写的那种检查就只是快速失败路径——读出错或并发撞车时, 已有的值也不会被 ON CONFLICT DO UPDATE 顺手覆盖掉。
func (*DB) InsertSkillUsage ¶
func (d *DB) InsertSkillUsage(u *SkillUsage) error
InsertSkillUsage appends one ledger row. Best-effort: callers log and continue on error (a lost metering row must never break a skill invocation).
func (*DB) InsertToolUsage ¶
InsertToolUsage appends one ledger row. Runtime callers treat metering as best-effort so a statistics failure never interrupts the tool itself.
func (*DB) JudgeUsageStats ¶ added in v0.3.15
func (d *DB) JudgeUsageStats(days int) (JudgeUsage, error)
JudgeUsageStats returns the fallback judge's all-time token totals and a per-day series over the past `days` days (default 30). Sourced from the always-on llm_usage ledger, so it is accurate across pool rotation and interrupted/failed judge calls. days only bounds the daily series; totals are all-time.
func (*DB) LLMRetryPolicy ¶
func (d *DB) LLMRetryPolicy() LLMRetryPolicy
LLMRetryPolicy reads the global retry policy. A missing or unparseable value yields the zero policy — i.e. every layer on its built-in default.
func (*DB) LLMTasks ¶
LLMTasks returns distinct non-empty task_ids with record counts, most recent first — powers the LLM-records page's task picker.
func (*DB) LastActivityAll ¶
LastActivityAll returns the unix time of the most recent activity per exploration (exploration_id → max created_at epoch), one query for all tasks. Persisted (unlike Engine.LastActivity's in-memory map), so it survives restarts and gives终态任务 a stable "ran until" time for computing run duration.
func (*DB) ListActiveFindingRetests ¶
func (d *DB) ListActiveFindingRetests(ctx context.Context) ([]ActiveFindingRetest, error)
func (*DB) ListAgents ¶
func (*DB) ListAllIntercepts ¶
func (d *DB) ListAllIntercepts(limit int) ([]InterceptApprovalRow, error)
ListAllIntercepts returns up to limit intercept_pending rows (newest first) joined with conversation and rule info.
func (*DB) ListAllInterceptsPage ¶
func (d *DB) ListAllInterceptsPage(page, size int, filter InterceptApprovalFilter) ([]InterceptApprovalRow, int, error)
ListAllInterceptsPage returns one 1-based page and the total matching count.
func (*DB) ListAssetInterceptRules ¶
func (d *DB) ListAssetInterceptRules() ([]AssetInterceptRule, error)
ListAssetInterceptRules returns all rules, built-ins first then newest first.
func (*DB) ListCommands ¶
ListCommands returns tool executions (tool_use + paired tool_result) across all explorations, with optional filtering and pagination. Covers every tool, not just Bash; q matches the tool name or its input.
func (*DB) ListConversations ¶
func (d *DB) ListConversations() ([]*Conversation, error)
ListConversations returns all threads, most-recently-updated first.
func (*DB) ListCustomTools ¶
ListCustomTools returns only the user-defined (system=false) tools.
func (*DB) ListEnabledTriggers ¶
func (d *DB) ListEnabledTriggers() ([]*AgentTrigger, error)
ListEnabledTriggers returns all enabled triggers (for the scheduler).
func (*DB) ListFindingGroups ¶
func (d *DB) ListFindingGroups(f FindingFilter, page, pageSize int) ([]FindingGroup, int, int, error)
ListFindingGroups returns a page of task groups matching the same filters as ListFindingsPage. The group count and finding count are independent totals so clients can page groups without losing the exact export/selection count.
func (*DB) ListFindingRetests ¶
func (d *DB) ListFindingRetests(findingID int64) ([]*FindingRetest, error)
func (*DB) ListFindings ¶
ListFindings returns all findings (newest first), joined with task description. Kept for the dashboard's summary; the paginated 发现 page uses ListFindingsPage.
func (*DB) ListFindingsForExport ¶
func (d *DB) ListFindingsForExport(f FindingFilter, ids []int64) ([]*DBFinding, error)
ListFindingsForExport returns findings for the 发现 page 导出功能,携带完整 report 字段、不分页。ids 非空时按这批 finding id 精确导出(勾选导出),忽略 filter;ids 为空时按 filter 导出(导出当前筛选/全部)。结果按严重等级降序、 再按时间倒序,与「导出汇总报告」的分组顺序一致。
func (*DB) ListFindingsPage ¶
ListFindingsPage returns one page of findings matching the filter, plus the total count of matching rows (for the frontend pager). page is 1-based.
func (*DB) ListInterceptRules ¶
func (d *DB) ListInterceptRules() ([]InterceptRule, error)
ListInterceptRules returns all rules ordered by priority DESC then id.
func (*DB) ListLLMRecords ¶
ListLLMRecords returns paginated LLM records with optional filters.
func (*DB) ListLogsBefore ¶
ListLogsBefore returns up to limit rows with id < beforeID, oldest-first.
func (*DB) ListNotificationChannels ¶ added in v0.3.15
func (d *DB) ListNotificationChannels(ctx context.Context) ([]*NotificationChannel, error)
ListNotificationChannels 返回全部渠道实例,启用的排在前面、同级按 id。 排序放在 SQL 里是为了让 UI 与 dispatcher 看到同一个稳定顺序。
func (*DB) ListNotificationDeliveries ¶ added in v0.3.15
func (d *DB) ListNotificationDeliveries(ctx context.Context, f NotificationDeliveryFilter, page, pageSize int) ([]*NotificationDelivery, int, error)
ListNotificationDeliveries 分页返回投递历史,新的在前。
func (*DB) ListPendingIntercepts ¶
func (d *DB) ListPendingIntercepts() ([]InterceptPending, error)
ListPendingIntercepts returns all unresolved approval requests, newest first.
func (*DB) ListProfiles ¶
func (d *DB) ListProfiles() ([]*LLMProfile, error)
func (*DB) ListPromptVersions ¶
func (d *DB) ListPromptVersions(agentID int64) ([]PromptVersion, error)
func (*DB) ListTaskArchives ¶
func (d *DB) ListTaskArchives(search, state string, page, size int) (TaskArchivePage, error)
func (*DB) ListTaskCategories ¶
func (d *DB) ListTaskCategories() ([]*TaskCategory, error)
func (*DB) ListTaskIntercepts ¶
func (d *DB) ListTaskIntercepts(taskID string) ([]InterceptApprovalRow, error)
ListTaskIntercepts returns all intercept_pending rows for a specific task (newest first).
func (*DB) ListTaskInterceptsPage ¶
func (d *DB) ListTaskInterceptsPage(taskID string, page, size int, filter InterceptApprovalFilter) ([]InterceptApprovalRow, int, error)
ListTaskInterceptsPage is the paginated variant of ListTaskIntercepts.
func (*DB) ListTaskTemplates ¶
func (d *DB) ListTaskTemplates() ([]*TaskTemplate, error)
ListTaskTemplates returns the most recently maintained templates first.
func (*DB) ListTriggersFor ¶
func (d *DB) ListTriggersFor(agentKey string) ([]*AgentTrigger, error)
ListTriggersFor returns an agent's triggers.
func (*DB) LoadLLMHealth ¶
LoadLLMHealth returns the profiles still in an UNEXPIRED cooling-off window. Expired rows are deliberately skipped: after a restart a profile that has finished cooling should be treated as healthy again and re-probed on its next call, not resurrected as broken.
func (*DB) MCPToolNames ¶
MCPToolNames returns the cached tool names for a server (empty until discovered).
func (*DB) MCPToolsDetailed ¶
MCPToolsDetailed returns the cached tools (name + description) for a server.
func (*DB) MarkDeliveriesSent ¶ added in v0.3.15
MarkDeliveriesSent 把一批投递标记为已送达。
func (*DB) MarkTaskLLMProfileQuotaExhausted ¶
func (d *DB) MarkTaskLLMProfileQuotaExhausted(taskID, profileID int64, reason string) (TaskLLMTransition, error)
MarkTaskLLMProfileQuotaExhausted advances the shared task cursor once. A late in-flight error from an older profile records that entry as exhausted but does not advance past the profile another call already selected.
func (*DB) MarkTaskLLMProfileQuotaExhaustedAtRevision ¶
func (d *DB) MarkTaskLLMProfileQuotaExhaustedAtRevision(taskID, profileID, revision int64, reason string) (TaskLLMTransition, error)
MarkTaskLLMProfileQuotaExhaustedAtRevision applies a provider failure only when it belongs to the chain snapshot used to start that call.
func (*DB) MetGoals ¶
MetGoals returns all met goals across live tasks (the scheduler filters out the ones it already fired for via the persisted fired-set).
func (*DB) MissingSkillStats ¶
MissingSkillStats returns the skill names agents asked for that do not exist, most-requested first — the "wished it existed" gap list. Names come from the model so they are shown as-is (already length-capped at insert time).
func (*DB) NewFindingsSince ¶
NewFindingsSince returns findings with node id > lastID across all live tasks, ordered by id (monotonic watermark → no double-fire).
func (*DB) NewTasksSince ¶
NewTasksSince returns tasks created with id > lastID (excluding deleted), ordered by id (monotonic watermark → no double-fire across restarts). Triggered agent runs are conversations, not tasks, so this never fires on its own output.
func (*DB) NewToolCallsSince ¶
NewToolCallsSince returns completed tool calls (a tool_result row) with activity id > lastID across all live tasks, ordered by id (monotonic watermark → no double-fire). It is driven by tool_result rows (the tool finished, so both input and output are available) and joins back to the paired tool_use row for the input. Only task-execution activity is scanned — triggered agent runs are conversations (conversation_activities), so a tool-call trigger never fires on its own output.
func (*DB) NotificationAssetNames ¶ added in v0.3.15
NotificationAssetNames 把资产 id 解析成简短展示名,供推送消息使用。
返回顺序与入参一致、长度可能小于入参(不存在的 id 被跳过)。保持入参顺序是 为了让同一条漏洞的消息在多次投递里资产顺序稳定——否则重试后收到的消息里 资产次序变了,会被误读成「资产变了」。
func (*DB) NotificationChannelByID ¶ added in v0.3.15
NotificationChannelByID 取单个渠道。
func (*DB) NotificationStatsSnapshot ¶ added in v0.3.15
func (d *DB) NotificationStatsSnapshot(ctx context.Context) (*NotificationStats, error)
NotificationStatsSnapshot 汇总通知系统的健康度。 BacklogAgeMS 是「推送是不是卡住了」最直接的指标——比 pending 计数有用得多, 因为积压 3 条和积压 3 条的差别可以是从 3 秒到 3 小时。
func (*DB) PatchTaskTemplate ¶
func (d *DB) PatchTaskTemplate(id int64, patch TaskTemplatePatch) (*TaskTemplate, error)
PatchTaskTemplate atomically changes only the supplied fields. Keeping the merge in one UPDATE prevents concurrent disjoint PATCH requests from losing each other's changes.
func (*DB) PoolProfiles ¶
func (d *DB) PoolProfiles() ([]*LLMProfile, error)
PoolProfiles returns the failover chain in run order, api keys included: the active profile first, then every other keyed profile that isn't excluded, by priority DESC (id ASC to stay stable). Profiles without an api key can't serve a request, so they never enter the chain. The ordering IS the policy — callers walk the slice front to back.
func (*DB) ProfileByID ¶
func (d *DB) ProfileByID(id int64) (*LLMProfile, error)
ProfileByID returns one profile with its api key by id, or nil if not found. Used to run a task on a specific (non-default) LLM profile.
func (*DB) QueueTaskArchive ¶
func (d *DB) QueueTaskArchive(taskID int64) (*TaskArchive, error)
QueueTaskArchive validates lifecycle and direct inheritance while holding the task row. A failed archive can be explicitly retried through the same API.
func (*DB) QueueTaskArchiveDelete ¶
func (d *DB) QueueTaskArchiveDelete(id int64) (*TaskArchive, error)
func (*DB) QueueTaskArchiveRestore ¶
func (d *DB) QueueTaskArchiveRestore(id int64) (*TaskArchive, error)
func (*DB) RecentLogs ¶
RecentLogs returns the most recent limit rows, oldest-first.
func (*DB) RecentSkillCalls ¶
RecentSkillCalls returns the most recent invocations of one skill, newest first.
func (*DB) RecordFindingRetestResult ¶
func (d *DB) RecordFindingRetestResult(ctx context.Context, conversationID int64, verdict, summary, evidence string) error
RecordFindingRetestResult never accepts a finding ID: ownership comes from the runtime conversation. Identical retries are safe; a second verdict is refused.
func (*DB) RecoverFindingRetests ¶
func (*DB) RecoverTaskArchiveJobs ¶
RecoverTaskArchiveJobs keeps restore/delete resumable after an unclean shutdown. An interrupted archive requires an explicit retry: automatic startup retries can otherwise form a crash loop when the prior process was killed by resource limits.
func (*DB) RefreshToolDefaults ¶
func (d *DB) RefreshToolDefaults(key, desc string, schema json.RawMessage) error
RefreshToolDefaults updates a system tool's model-facing description + schema to the code defaults, PRESERVING the user's agent binding + enabled flag. Used by one-time migrations to propagate a code schema change (SeedTool is first-insert-only, so a new parameter added in code otherwise never reaches an already-seeded row). No-op for custom tools or unknown keys.
func (*DB) RemoveAgentFromTool ¶
RemoveAgentFromTool strips one agent key from a SINGLE tool's `agents` array — used by one-time migrations that change a tool's default binding on existing DBs (SeedTool is first-insert-only, so a changed default never reaches a seeded row).
func (*DB) RemoveAgentFromToolBindings ¶
RemoveAgentFromToolBindings strips an agent key from every tool's `agents` JSONB array — called when a custom agent is deleted so no tool keeps a dangling binding. Uses jsonb `-` (remove array element) guarded by `?` (membership).
func (*DB) RenameConversation ¶
RenameConversation sets a thread's title. Kept for automatic first-message titles and compatibility with existing callers.
func (*DB) RenameTaskCategory ¶
func (d *DB) RenameTaskCategory(id int64, name string) (*TaskCategory, error)
func (*DB) ReplaceTaskLLMProfiles ¶
ReplaceTaskLLMProfiles atomically replaces and resets the explicit task chain. activeProfileID=0 selects the first entry. An empty list restores the existing agent-binding/global fallback behavior. 终态(done/failed/timeout)任务同样允许改链:任务结束后主 Agent 对话仍会走这条链, 链上模型不可用时必须能换,否则已完成任务就再也没法交互了。
func (*DB) RescheduleDeliveries ¶ added in v0.3.15
func (d *DB) RescheduleDeliveries(ctx context.Context, ids []int64, delay time.Duration, errMsg string) error
RescheduleDeliveries 把一批投递退回 pending 并推后重试时间。
退回 pending 而不是引入新的中间状态,是为了让「还剩几次机会」只由一个地方 表达(MaxNotifyAttempts),避免状态机的分支随重试策略膨胀。
func (*DB) ResetPromptToDefault ¶
ResetPromptToDefault appends the code-default template as a new version and points current at it — the explicit "恢复为内置默认" action.
func (*DB) ResolveIntercept ¶
ResolveIntercept atomically settles a pending request. A timeout cannot overwrite a human decision and repeat decisions cannot rewrite history.
func (*DB) ResourceAgents ¶
ResourceAgents returns the agent ids that can see a resource.
func (*DB) RestoreTaskArchive ¶
func (d *DB) RestoreTaskArchive(archiveID int64, snapshot *TaskArchiveSnapshot, remainingTimeoutSeconds int64) ([]string, error)
RestoreTaskArchive restores PostgreSQL rows from a verified manifest. It is idempotent for accounting/traffic retry scenarios and returns non-fatal warnings for global objects that intentionally are not recreated.
func (*DB) RestoreTaskArchiveWithLLMRecords ¶
func (d *DB) RestoreTaskArchiveWithLLMRecords( archiveID int64, snapshot *TaskArchiveSnapshot, remainingTimeoutSeconds int64, llmRecords io.Reader, ) ([]string, error)
RestoreTaskArchiveWithLLMRecords restores a v2 package whose heavyweight LLM record history is stored as a sequence of JSON objects outside manifest.json.
func (*DB) RetryNotificationDelivery ¶ added in v0.3.15
RetryNotificationDelivery 手动重发一条投递:重置为 pending、清零重试计数、 立即到期。清计数是刻意的——人工点「重发」意味着前几次失败的原因已被处理, 再拿旧计数限制它没有道理。
func (*DB) SaveLLMHealth ¶
SaveLLMHealth upserts one profile's circuit-breaker state.
func (*DB) SaveMCPTools ¶
SaveMCPTools replaces the cached tool list for a server (called after discovery).
func (*DB) SaveNotificationChannel ¶ added in v0.3.15
SaveNotificationChannel 新建或更新一个渠道。
更新时只覆盖调用方显式给出的字段(非 nil / 非空),这样前端可以提交局部 修改的抽屉表单,而不必回传 config 里那些它没展示的字段——回传反而会造成 「掩码值把真实密钥覆盖掉」的事故。
func (*DB) SaveProfile ¶
func (d *DB) SaveProfile(p *LLMProfile) (int64, error)
SaveProfile inserts (id==0) or updates a profile. Empty apiKey on update keeps existing.
func (*DB) SavePrompt ¶
SavePrompt appends a new version and points current_prompt_id at it.
func (*DB) SaveSideMemory ¶
func (d *DB) SaveSideMemory(ctx context.Context, e sidequestion.Exchange, memory sidequestion.Memory) error
func (*DB) SaveSideSnapshot ¶
func (*DB) SearchChatMentions ¶
SearchChatMentions searches the shared catalog, just like the asset/finding pages. Values remain SQL parameters; %, _ and backslash are literal search text.
func (*DB) SearchChatMentionsPage ¶
func (d *DB) SearchChatMentionsPage(ctx context.Context, kind, query, cursor string) (ChatMentionPage, error)
SearchChatMentionsPage uses the last result's stable sort key rather than an offset, so loading later pages does not repeatedly skip all earlier results.
func (*DB) SeedPromptIfEmpty ¶
SeedPromptIfEmpty writes the code-default template as the agent's first prompt version ONLY when it has none yet (current_prompt_id IS NULL). Mirrors SeedTool's first-insert-only philosophy: a user's edited prompt is never clobbered on restart. Idempotent — a no-op once any version exists.
func (*DB) SeedTool ¶
func (d *DB) SeedTool(key, desc string, schema, agents json.RawMessage) error
SeedTool inserts a built-in tool's code-defined defaults ONCE. ON CONFLICT DO NOTHING: an existing row (possibly edited in the UI) is never overwritten on startup — that's what keeps page edits from being wiped every restart. Use UpsertToolForce for an explicit "reset to code default".
func (*DB) SetActiveProfile ¶
SetActiveProfile makes one profile the global default (single-default invariant).
func (*DB) SetAgentInteractiveShell ¶
SetAgentInteractiveShell toggles whether an agent gets the interactive shell (持久 PTY 会话) tool family + Bash 提示词联动(见 docs/交互式shell设计.md §14.2).
func (*DB) SetAgentLLMProfile ¶
SetAgentLLMProfile binds an agent to a specific LLM profile (id != nil), or clears the binding (id == nil) so the agent follows the task/conversation pin, else the global active profile. Precedence at runtime: agent binding → task/conv pin → active.
func (*DB) SetAgentMaxTurns ¶
SetAgentMaxTurns updates an agent's max_turns (0 = unlimited).
func (*DB) SetAgentRunSeconds ¶
SetAgentRunSeconds updates an agent's run_seconds wall-clock budget (0 = unlimited).
func (*DB) SetAgentSkillVisibility ¶
SetAgentSkillVisibility replaces all skill visibility for an agent.
func (*DB) SetAgentTaskTimeoutWrapup ¶
SetAgentTaskTimeoutWrapup stores an agent's task-timeout wrap-up prompt (empty = use code built-in default; only worker/planner have one) and its turn budget (0 = default). Resolved at runtime by resolveTaskTimeoutWrapup / …Turns.
func (*DB) SetAgentTriggerBehavior ¶
SetAgentTriggerBehavior stores an agent's P3 trigger post-processing策略: runMode(serial|parallel) / mergeMode(by_task|all|none) / maxParallel(parallel 用,0=不限)。 枚举做白名单校验,非法值回落默认,避免脏数据把调度 pump 带偏。
func (*DB) SetAgentVisibilityKind ¶
SetAgentVisibilityKind replaces the full set of visible resources of a kind for an agent (agent-side bulk write). Bidirectional with the resource-side view — both read/write the same agent_visibility rows.
func (*DB) SetAgentWebSearch ¶
SetAgentWebSearch toggles whether an agent uses network search (still gated by the global web-search master switch + backend/key config).
func (*DB) SetAgentWrapupMaxTurns ¶
SetAgentWrapupMaxTurns stores the wrap-up phase's own turn budget. 0 means "use the code built-in default" — resolved at runtime by resolveWrapupTurns.
func (*DB) SetAgentWrapupPrompt ¶
SetAgentWrapupPrompt stores an agent's wrap-up (settlement) prompt. Empty string means "use the code built-in default" — resolved at runtime by resolveWrapup.
func (*DB) SetFindingName ¶
SetFindingName updates one finding's 漏洞名称 (+ node payload sync). Empty name is allowed — the frontend falls back to the vuln class for display.
func (*DB) SetFindingReportByNodeID ¶
SetFindingReportByNodeID sets the Markdown report on the standalone finding row whose node_id matches — report_finding returns that node id, so an agent tool can address the finding it just created. Returns rows affected (0 when no row).
func (*DB) SetFindingReportVersionByNodeID ¶
func (*DB) SetFindingSeverity ¶
SetFindingSeverity updates one finding's severity (+ node payload sync). Returns rows affected (0 when no finding has that id).
func (*DB) SetFindingStatus ¶
SetFindingStatus updates one finding's triage state. Returns rows affected.
底层 setter:只改状态、不登记推送事件。生产代码改状态请走 SetFindingStatusWithNotify —— 直接调本函数会让「状态变更推送」静默失效。 保留它是为了让不关心通知的用例(参数校验、复测流程)能单独驱动状态。
func (*DB) SetFindingStatusWithNotify ¶ added in v0.3.15
func (d *DB) SetFindingStatusWithNotify(ctx context.Context, id int64, status string) (from string, found bool, notified bool, err error)
SetFindingStatusWithNotify 更新漏洞处置状态,并在同一事务里登记一条状态变更 推送事件。
返回 from=变更前的状态;found=漏洞是否存在;notified=事件是否登记成功。
三条刻意的行为:
- 状态未实际变化时不登记事件。前端抽屉重复提交同一个值、或自动化脚本 幂等重放,都不该产出推送噪音。
- 漏洞不存在时返回 found=false 且不做任何写入,由调用方翻译成 404。
- 事件登记失败不影响状态更新(见 RecordNotificationEventTx 的保存点说明), 所以 notified=false 时状态已经改成功了,调用方不应因此报错。
func (*DB) SetFindingVulnClass ¶
SetFindingVulnClass updates one finding's 漏洞类别 (+ node payload sync).
func (*DB) SetLLMRetryPolicy ¶
func (d *DB) SetLLMRetryPolicy(p LLMRetryPolicy) error
SetLLMRetryPolicy persists the global retry policy (values are clamped first).
func (*DB) SetNotificationChannelEnabled ¶ added in v0.3.15
SetNotificationChannelEnabled 切换启停。
停用一个渠道时,把它尚未发出的投递一并标记为 skipped:否则重新启用后 会突然收到一批「停用期间积压」的旧漏洞,时效已失且容易误判为新增。
func (*DB) SetParentRef ¶
SetParentRef records a task's parent task id (编排 agent spawn_task 关联).
func (*DB) SetQueued ¶
SetQueued is the compatibility helper used by older callers and tests. New scheduling code should use Enqueue/Dequeue so FIFO metadata is explicit.
func (*DB) SetSchedState ¶
func (*DB) SetSetting ¶
SetSetting upserts a setting value.
func (*DB) SetStatus ¶
SetStatus updates a task's lifecycle status. Entering a terminal state (done/failed/timeout) stamps completed_at once (COALESCE keeps the first stamp stable); moving back to a non-terminal state clears it, so a re-run has no stale finish time.
func (*DB) SetTaskCategory ¶
func (d *DB) SetTaskCategory(taskID int64, categoryID *int64) (*TaskCategory, error)
SetTaskCategory updates one live task. A nil category means uncategorized.
func (*DB) SetTasksCategory ¶
SetTasksCategory moves several tasks into one category (nil = uncategorized) inside a single transaction, so a half-applied batch is never observable. It returns the ids that were actually updated — ids missing from that slice were deleted between selection and submit — plus the refreshed category row whose task_count already reflects this move.
func (*DB) SetTerminalStatusGuarded ¶
SetTerminalStatusGuarded sets a terminal status only when the task is NOT already terminal, so a completed↔timeout race resolves to the first writer (won=true). Returns won=false (no error) when another terminal status already stuck — the caller then leaves it alone. Non-terminal transitions / re-run still use SetStatus.
func (*DB) SideHistory ¶
func (*DB) SideMemory ¶
func (d *DB) SideMemory(ctx context.Context, e sidequestion.Exchange) (sidequestion.Memory, error)
func (*DB) SideReplay ¶
func (*DB) SideReplayPage ¶
func (d *DB) SideReplayPage(ctx context.Context, e sidequestion.Exchange, after int64) ([]sidequestion.Exchange, error)
Unlike SideReplay's UI-era 20-row window, this cursor visits all unsummarized successful exchanges, in bounded pages and only before the admitted request.
func (*DB) SideRequest ¶
func (*DB) SideSnapshot ¶
func (*DB) SkillAgents ¶
SkillAgents returns the agent IDs that can see a skill.
func (*DB) SkillCallsByTask ¶
SkillCallsByTask counts a task's skill loads, most-used first. Powers a per-task view of which procedures its agents actually reached for.
func (*DB) SkillStats ¶
SkillStats aggregates the whole ledger grouped by skill, most-used first. Skills that were never invoked are absent — callers merge against the skill list on disk. Only resolved calls count; misses are reported separately by MissingSkillStats.
func (*DB) SnapshotTaskArchive ¶
func (d *DB) SnapshotTaskArchive(taskID int64) (*TaskArchiveSnapshot, error)
SnapshotTaskArchive reads one repeatable PostgreSQL snapshot. Task-owned Agent writes are already quiescent at the server barrier; repeatable-read also keeps the asset and accounting views mutually consistent during serialization.
func (*DB) SnapshotTaskArchiveWithLLMRecords ¶
func (d *DB) SnapshotTaskArchiveWithLLMRecords(taskID int64, llmRecords io.Writer) (*TaskArchiveSnapshot, error)
SnapshotTaskArchiveWithLLMRecords streams the heavyweight record history to llmRecords while all other task-owned data is read from the same repeatable PostgreSQL snapshot.
func (*DB) StampFirstRun ¶
StampFirstRun records a task's first-real-run moment and computes its absolute deadline (= now + timeoutSeconds). Idempotent: only stamps when first_run_at is still NULL, so restarts / re-entries keep the original clock. timeoutSeconds<=0 leaves deadline_at NULL (不限时). Returns the resulting deadline (nil = 不限/未变).
func (*DB) StartFindingRetest ¶
func (*DB) StartSideRequest ¶
func (d *DB) StartSideRequest(ctx context.Context, s sidequestion.Snapshot, clientID, question string) (*sidequestion.Exchange, bool, error)
func (*DB) TaskArchiveBlockers ¶
TaskArchiveBlockers returns one live direct dependent for every source task that cannot currently be archived. Dependents already queued for archiving do not block their source because the FIFO worker will compact them first.
func (*DB) TaskCompanyIDs ¶
TaskCompanyIDs returns the companies whose asset scopes are available to the task. The task_scope rows remain the single source of truth.
func (*DB) TaskLLMProfiles ¶
func (d *DB) TaskLLMProfiles(taskID int64) ([]TaskLLMProfile, error)
func (*DB) TaskListMetricsAll ¶
func (d *DB) TaskListMetricsAll() (map[int64]TaskListMetrics, error)
TaskListMetricsAll returns list aggregates for every live task in one query. The lateral lookups use the per-exploration indexes instead of grouping the complete activity history on every poll.
func (*DB) TaskSources ¶
func (d *DB) TaskSources(taskID int64) ([]TaskSource, error)
func (*DB) TimedOutTasksSince ¶
TimedOutTasksSince returns tasks that reached status='timeout' with id > lastID, ordered by id (monotonic watermark → no double-fire across restarts).
func (*DB) ToggleAssetInterceptRule ¶
ToggleAssetInterceptRule flips the enabled state of a rule.
func (*DB) ToggleInterceptRule ¶
ToggleInterceptRule flips the enabled state of a rule.
func (*DB) ToggleSkillVisibility ¶
ToggleSkillVisibility sets one (agent, skill_name) visibility on/off.
func (*DB) ToggleVisibility ¶
ToggleVisibility sets one (agent, kind, resource) visibility on/off (idempotent).
func (*DB) TokenByModel ¶
func (d *DB) TokenByModel(taskID string) ([]ModelTokenStat, error)
TokenByModel aggregates a task's LLM token usage grouped by model, most-used first, from the always-on llm_usage ledger. taskID is the task registry id. Accurate even with per-agent model bindings, pool rotation/failover, and interrupted runs, since every call (success or error) is metered.
func (*DB) TokenDailyAll ¶
func (d *DB) TokenDailyAll(days int) ([]DailyTokenBucket, error)
TokenDailyAll aggregates token consumption by calendar day (UTC) for the past `days` days across all explorations. Only kind='result' rows carry token counts (the terminal per-run summary), so there is no double-counting.
func (*DB) TokenTotalsAll ¶
func (d *DB) TokenTotalsAll() (map[int64]TokenUsage, error)
TokenTotalsAll returns the whole-task token total for every exploration in one query (exploration_id → total), so the task list can show per-task consumption without a query per row.
func (*DB) ToolStats ¶
ToolStats counts executions grouped by tool under the same filters ListCommands takes. Unpaginated on purpose: the tally describes the whole filtered set, not the page currently on screen.
func (*DB) ToolUsageCounts ¶
ToolUsageCounts returns invocation totals keyed by catalog tool key. Entries without calls are absent; API callers merge the result into the tools catalog.
func (*DB) TouchConversation ¶
TouchConversation bumps updated_at so the thread floats to the top of the list.
func (*DB) TouchTriggerFire ¶
TouchTriggerFire records an interval trigger's fire time (now).
func (*DB) UpdateAgentMeta ¶
UpdateAgentMeta updates a custom agent's display name + description. Built-in agents are left untouched (guarded by the caller / the builtin flag).
func (*DB) UpdateAssetInterceptRule ¶
func (d *DB) UpdateAssetInterceptRule(id int64, kind, pattern, note string, enabled bool) (AssetInterceptRule, error)
UpdateAssetInterceptRule replaces the editable fields of an existing rule.
func (*DB) UpdateConversation ¶
func (d *DB) UpdateConversation(id int64, patch ConversationPatch) (*Conversation, error)
UpdateConversation applies a partial title/pin mutation and returns the updated row. Pinning an already-pinned conversation preserves its original pin order.
func (*DB) UpdateConversationProfile ¶
UpdateConversationProfile sets (or clears) the LLM profile override for a conversation.
func (*DB) UpdateCustomTool ¶
UpdateCustomTool updates a custom tool's editable fields (kind/exec/deferred + desc/schema/agents/enabled). Only touches system=false rows.
func (*DB) UpdateInterceptRule ¶
func (d *DB) UpdateInterceptRule(id int64, name, matchTarget, matchType, pattern, action, message string, priority int, enabled bool, timeoutEnabled bool, timeoutSeconds int, timeoutAction string) (InterceptRule, error)
UpdateInterceptRule replaces all editable fields of an existing rule.
func (*DB) UpdateSideRequest ¶
Conditional updates cannot resurrect deleted history or overwrite a terminal cancellation with a late provider callback.
func (*DB) UpdateTask ¶
UpdateTask applies a partial task name/pin mutation and returns the updated row. Re-pinning an already pinned task preserves its original position.
func (*DB) UpdateTaskArchiveProgress ¶
func (*DB) UpdateTaskTemplate ¶
func (d *DB) UpdateTaskTemplate(id int64, in TaskTemplateInput) (*TaskTemplate, error)
UpdateTaskTemplate replaces the editable fields of one preset.
func (*DB) UpdateTool ¶
UpdateTool saves the page-editable fields. key is never changed (it is welded to the Go handler). system tools: the caller must keep the schema structure — only per-param description/default and the agent binding are meant to move.
func (*DB) UpdateTrigger ¶
func (d *DB) UpdateTrigger(t *AgentTrigger) error
UpdateTrigger updates a trigger's fields (not last_fire).
func (*DB) UpsertToolForce ¶
func (d *DB) UpsertToolForce(key, desc string, schema, agents json.RawMessage) error
UpsertToolForce overwrites a tool row with the given code-default values (used by the per-tool "reset" action). It resets description/schema/agents and re-enables the tool, but keeps system=true.
func (*DB) UsageByProfile ¶
func (d *DB) UsageByProfile() ([]ProfileUsage, error)
UsageByProfile returns global token spend grouped by profile name, most-used first. profile_name may be empty for calls made on env/non-persisted configs.
func (*DB) UsageDaily ¶
func (d *DB) UsageDaily(days int) ([]ProfileDayUsage, error)
UsageDaily returns per-(profile, day) token buckets for the past `days` days (default 365 when days<=0), so the dashboard can slice by profile + range.
type DBFinding ¶
type DBFinding struct {
TrafficCount int
EvidenceVersion int64
ReportEvidenceVersion int64
TrafficBindings []FindingTrafficBinding // populated only for export
ID int64
TaskID *int64
NodeID *int64
VulnClass string
Name string // 漏洞名称(可读标题);为空时前端回退展示 VulnClass
Severity string
Summary string
Evidence string
Worker string
AssetIDs []int64
Status string
Report string // 详细报告(Markdown);仅 GetFinding 填充,列表查询不带
CreatedAt time.Time
TaskDescription string // populated via LEFT JOIN on tasks
}
DBFinding is a row in the standalone findings table. It persists across task deletion unless the caller explicitly requests related finding cleanup.
type DailyTokenBucket ¶
type DailyTokenBucket struct {
Day string `json:"day"` // "YYYY-MM-DD"
InputTokens int `json:"input_tokens"`
OutputTokens int `json:"output_tokens"`
CacheReadTokens int `json:"cache_read_tokens"`
}
DailyTokenBucket is one day's global token aggregate across all tasks.
type DirectSourceStore ¶
type DirectSourceStore struct {
Task TaskSource
Store *ExplorationStore
}
DirectSourceStore binds one directly related task to its exploration store. It is intentionally a read-side helper: callers keep using the receiver store for every graph mutation, frontier lookup, and intent claim.
type ExplorationStore ¶
type ExplorationStore struct {
// contains filtered or unexported fields
}
ExplorationStore is a handle onto one exploration's reasoning graph + activity.
func (*ExplorationStore) ActiveDigests ¶
func (s *ExplorationStore) ActiveDigests() ([]*Node, error)
ActiveDigests returns the exploration's live digest nodes (state='active'), oldest first.
func (*ExplorationStore) ActivityByIDs ¶
func (s *ExplorationStore) ActivityByIDs(ids []int64) ([]Activity, error)
ActivityByIDs loads full detail for specific step ids (the trace drill-down), scoped to this exploration. thinking rows are skipped (never returned, even if their id is asked for). Order is ascending id, not the input order.
func (*ExplorationStore) ActivityByIDsForTerminalIntents ¶
func (s *ExplorationStore) ActivityByIDsForTerminalIntents(ids []int64) ([]Activity, error)
ActivityByIDsForTerminalIntents is the inherited-detail read boundary. It deliberately excludes node-less planner/main rows, non-intent activities, live source work, and thinking. Local callers that need legacy behavior use ActivityByIDs instead.
func (*ExplorationStore) ActivityByIDsWithSources ¶
func (s *ExplorationStore) ActivityByIDsWithSources(ids []int64) ([]Activity, error)
ActivityByIDsWithSources loads local step details with the legacy behavior. For direct sources it only returns rows attached to terminal intents, preventing an arbitrary global activity id from exposing source planner/main transcripts.
func (*ExplorationStore) ActivityDetail ¶
func (s *ExplorationStore) ActivityDetail(id int64) (string, error)
ActivityDetail lazily returns the full detail blob for one step.
func (*ExplorationStore) ActivityDetailWithSources ¶
func (s *ExplorationStore) ActivityDetailWithSources(id int64) (string, error)
ActivityDetailWithSources keeps the legacy local-task lookup (including local thinking rows), while inherited details are restricted to terminal worker intents. Source planner/main rows have no node id and must never become part of inherited context.
func (*ExplorationStore) ActivityList ¶
func (s *ExplorationStore) ActivityList(nodeID *int64, sinceID int64, limit int) ([]Activity, int64, error)
ActivityList returns steps after sinceID (exclusive), optionally filtered by node. Returns items and the new cursor (max id seen).
func (*ExplorationStore) ActivityListForTerminalIntent ¶
func (s *ExplorationStore) ActivityListForTerminalIntent(nodeID, sinceID int64, limit int) ([]Activity, int64, error)
ActivityListForTerminalIntent is the inherited, incremental-read boundary. The intent state check and activity read happen in one statement so a source intent reopened between API-level checks cannot expose its new in-flight trace. Model reasoning and accounting rows are never inherited.
func (*ExplorationStore) ActivityListWithSources ¶
func (s *ExplorationStore) ActivityListWithSources(nodeID, sinceID int64, limit int) ([]Activity, int64, error)
ActivityListWithSources is the source-aware equivalent used by get_worker_output. Node ids are global, so the first owning exploration is unambiguous even when the work has not emitted any activity yet.
func (*ExplorationStore) ActivityMaxID ¶
func (s *ExplorationStore) ActivityMaxID() (int64, error)
ActivityMaxID returns the task's current maximum activity id (0 when empty). It is the task-level snapshot cursor handed to the SSE stream so history (id<=cursor) and the live tail (id>cursor) meet with no gap — deliberately task-level, not per session, since one SSE covers the whole task.
func (*ExplorationStore) ActivityPage ¶
func (s *ExplorationStore) ActivityPage(f ActivitySessionFilter, before int64, limit int) ([]Activity, bool, error)
ActivityPage returns one page for reverse (newest-first) pagination of a session: up to `limit` steps ending before id `before` (exclusive; before<=0 = the latest page), returned in ASCENDING id order for direct display. hasMore reports whether still-older steps exist before the returned window (so the client can stop loading on scroll-up). Summary-only columns — detail is lazy-loaded via ActivityDetail.
func (*ExplorationStore) ActivityPageForTerminalIntent ¶
func (s *ExplorationStore) ActivityPageForTerminalIntent(nodeID, before int64, limit int) ([]Activity, bool, error)
ActivityPageForTerminalIntent is the inherited session-history boundary. It combines ownership, terminal-state and row-kind checks in one query, closing the race where a previously completed source intent is reopened before paging.
func (*ExplorationStore) ActivityTrace ¶
func (s *ExplorationStore) ActivityTrace(nodeID int64, limit int) ([]Activity, error)
ActivityTrace lists one work's steps (by intent/node id) for the trace tools: summaries only (detail is lazy — fetch via ActivityByIDs). thinking/usage rows are dropped so the caller sees the work's actions + observations, not the model's internal reasoning or token-accounting noise.
func (*ExplorationStore) ActivityTraceForTerminalIntent ¶
func (s *ExplorationStore) ActivityTraceForTerminalIntent(nodeID int64, limit int) ([]Activity, error)
ActivityTraceForTerminalIntent returns one inherited work trace only while its source intent is still terminal at query time.
func (*ExplorationStore) ActivityTraceSearch ¶
func (s *ExplorationStore) ActivityTraceSearch(nodeID *int64, q string, limit int) ([]Activity, error)
ActivityTraceSearch finds steps whose summary OR detail matches q (case-insensitive), returning summaries only. nodeID != nil scopes to one work; nil searches across ALL works (node_id IS NOT NULL — planner/main steps have no node_id, so this cleanly means "worker traces"). thinking/usage rows dropped.
func (*ExplorationStore) ActivityTraceSearchAllWithSources ¶
func (s *ExplorationStore) ActivityTraceSearchAllWithSources(excludeNodeID int64, q string, limit int) ([]Activity, error)
ActivityTraceSearchAllWithSources searches local worker traces plus every direct source. The local owner is excluded only from the current exploration; inherited traces are immutable historical context.
func (*ExplorationStore) ActivityTraceSearchExcluding ¶
func (s *ExplorationStore) ActivityTraceSearchExcluding(excludeNodeID int64, q string, limit int) ([]Activity, error)
ActivityTraceSearchExcluding keyword-searches every node's steps in this exploration EXCEPT one node's own (excludeNodeID) — so a worker's search_all_worker_traces doesn't return its own in-progress trace (which is already in its context). excludeNodeID<=0 → no exclusion (searches all nodes).
func (*ExplorationStore) ActivityTraceSearchForTerminalIntent ¶
func (s *ExplorationStore) ActivityTraceSearchForTerminalIntent(nodeID int64, q string, limit int) ([]Activity, error)
ActivityTraceSearchForTerminalIntent is the scoped inherited search variant; terminal eligibility is evaluated by the same statement that reads the rows.
func (*ExplorationStore) ActivityTraceSearchTerminalIntents ¶
func (s *ExplorationStore) ActivityTraceSearchTerminalIntents(q string, limit int) ([]Activity, error)
ActivityTraceSearchTerminalIntents searches inherited worker history without exposing planner/main rows or work that is still open/running in the source.
func (*ExplorationStore) ActivityTraceSearchWithSources ¶
func (s *ExplorationStore) ActivityTraceSearchWithSources(nodeID int64, q string, limit int) ([]Activity, error)
ActivityTraceSearchWithSources performs the scoped worker-trace search used by get_worker_trace. A node id resolves to at most one exploration because exploration node ids are global.
func (*ExplorationStore) ActivityTraceWithSources ¶
func (s *ExplorationStore) ActivityTraceWithSources(nodeID int64, limit int) ([]Activity, error)
ActivityTraceWithSources returns a work trace when its intent belongs to the current exploration or a direct source. It never searches indirect sources.
func (*ExplorationStore) AddConstraint ¶
func (s *ExplorationStore) AddConstraint(kind, text, origin string) (int64, error)
AddConstraint inserts one constraint (kind must be allow|deny) and returns its id.
func (*ExplorationStore) AddDigest ¶
AddDigest writes one digest node and its covers edges (digest→member) in a single transaction. payload is the digest body + member_ids + generation + signature (see cold-digest §1). Returns the new digest id.
func (*ExplorationStore) AddFindingFollowUpIntent ¶
func (s *ExplorationStore) AddFindingFollowUpIntent(findingID, findingNodeID int64, description string, audit Activity) (int64, Activity, error)
AddFindingFollowUpIntent atomically creates a priority-10 human intent from a live finding node, copies that finding's asset anchors, records the finding --derived_from--> intent lineage edge, and persists its audit activity. The returned activity is the committed row and can be broadcast as-is without calling AppendActivity again.
func (*ExplorationStore) AddIntent ¶
func (s *ExplorationStore) AddIntent(payload map[string]any, priority int, anchors []int64, origin string) (int64, error)
AddIntent is a convenience: an open intent.
func (*ExplorationStore) AddNode ¶
func (s *ExplorationStore) AddNode(kind string, payload map[string]any, priority int, state, origin string, anchors []int64) (int64, error)
AddNode writes a typed reasoning node with optional anchors to asset ids.
func (*ExplorationStore) AddStandaloneFinding ¶
func (s *ExplorationStore) AddStandaloneFinding(taskID, nodeID int64, vulnclass, name, severity, summary, evidence, worker string, assetIDs []int64) (int64, error)
AddStandaloneFinding writes a finding to the standalone findings table, which persists across task deletion (task_id / node_id become NULL when the task or exploration node is deleted). taskID and nodeID may be 0 (stored as NULL).
func (*ExplorationStore) Anchor ¶
func (s *ExplorationStore) Anchor(nodeID, assetID int64) error
Anchor records a node→asset reference edge (many-to-many): it captures which global assets an exploration node touched, as lineage/provenance. The asset graph itself is global and shared — anchoring no longer gates visibility (any task may read any asset via search); it only preserves the reasoning trail. Idempotent.
func (*ExplorationStore) AppendActivity ¶
func (s *ExplorationStore) AppendActivity(a Activity) (int64, error)
AppendActivity records one worker step and returns its id.
func (*ExplorationStore) ApplyStampOps ¶
func (s *ExplorationStore) ApplyStampOps(ops []StampOp) error
ApplyStampOps writes a batch of cold_since_round changes in one transaction.
func (*ExplorationStore) AssetRefs ¶
func (s *ExplorationStore) AssetRefs(assetID int64) ([]AssetRef, error)
AssetRefs returns the intents / facts / findings in THIS exploration anchored to the given asset id (newest first) — what this task tested / concluded about it.
func (*ExplorationStore) AssetRefsWithSources ¶
func (s *ExplorationStore) AssetRefsWithSources(assetID int64) ([]AssetRef, error)
AssetRefsWithSources returns anchored nodes from this exploration and each direct source. Inherited entries retain their owning task id so API/UI callers can present them as immutable context.
func (*ExplorationStore) BumpRound ¶
func (s *ExplorationStore) BumpRound() (int64, error)
BumpRound advances this exploration's planner-round counter and returns the new value (§2.3). Called once per planner wake-up.
func (*ExplorationStore) CancelIntent ¶
func (s *ExplorationStore) CancelIntent(id int64) (IntentCleanup, error)
CancelIntent 物理删除一个意图,以及"仅由该意图支撑"的全部独占子孙节点——从该意图沿 yields/derived_from 向下可达、且所有父节点(所有指向它的边的源)都落在删除集内的节点。 goal 与 origin fact 永不删除;还被删除集之外的意图/digest 引用的共享节点也保留,以免破坏 其它分支、产生断链。被删的每个 intent 先做 token rollup(保留不可逆计量)并清理其 activity 与副会话;被删的 finding 先删 findings 表行(node_id FK 为 ON DELETE SET NULL,否则留孤儿)。 边随节点 CASCADE 清理,整个清理保持在一个事务内。调用方须先停掉运行中的 worker 防止其后续写入。
func (*ExplorationStore) ClaimIntent ¶
func (s *ExplorationStore) ClaimIntent(id int64, owner string) (bool, error)
ClaimIntent atomically moves an open intent to running. Returns true if claimed.
func (*ExplorationStore) ColdStamps ¶
func (s *ExplorationStore) ColdStamps() (map[int64]*int64, error)
ColdStamps returns cold_since_round for every foldable node (intent/fact): id → *round (nil when the node is hot / unstamped). Used to compute the ≥R debounce and to know which stamps to set/clear this round.
func (*ExplorationStore) CompareAndSetIntentState ¶
func (s *ExplorationStore) CompareAndSetIntentState(id int64, expected, state string) (bool, error)
CompareAndSetIntentState transitions one local intent only when its current state still matches expected. It is the state boundary used by pause/resume and worker settlement, so a stale API read cannot overwrite a concurrent finish.
func (*ExplorationStore) ContentVersions ¶
func (s *ExplorationStore) ContentVersions() (map[int64]int, error)
ContentVersions returns id → content_version for all nodes (§5.3 signature).
func (*ExplorationStore) CountFinishedIntents ¶
func (s *ExplorationStore) CountFinishedIntents() (int, error)
CountFinishedIntents counts this exploration's intents in a terminal explored state (done/blocked/exhausted) — graph_overview's done_intents_total, so the planner knows recent_done_intents (capped at a recent window) is a truncated view and stays cautious about "already tried" dedup. Excludes 'stopped' (killed/deleted), matching exactly what recent_done_intents surfaces.
func (*ExplorationStore) CountOpenIntents ¶ added in v0.3.14
func (s *ExplorationStore) CountOpenIntents() (int, error)
CountOpenIntents counts this exploration's open intents — graph_overview's frontier_open, so the planner knows open_intents (capped at the top-N by priority) is a truncated view and there may be more claimable work.
func (*ExplorationStore) CoveredMembers ¶
func (s *ExplorationStore) CoveredMembers() (map[int64]int64, error)
CoveredMembers maps member id → covering digest id, for ACTIVE digests only (§6.1 point 1). A node with no entry is not currently folded. Should a member carry covers edges from two digests (a torn major write), the lowest digest id wins deterministically — callers dedupe on this.
func (*ExplorationStore) CurrentMainSeg ¶
func (s *ExplorationStore) CurrentMainSeg() (int, error)
CurrentMainSeg returns the highest main-session segment (0 when none created yet).
func (*ExplorationStore) DeleteConstraint ¶
func (s *ExplorationStore) DeleteConstraint(id int64) error
DeleteConstraint removes a constraint; scoped to this exploration. Returns an error if no such constraint exists.
func (*ExplorationStore) DeleteGoal ¶
func (s *ExplorationStore) DeleteGoal(id int64) error
DeleteGoal hard-deletes a goal node; scoped to kind='goal' so it can never drop an intent/fact by id. The edges (spawns) and anchors reference it with ON DELETE CASCADE, so they go with it; activity.node_id is ON DELETE SET NULL. Returns an error if no such goal exists in this exploration.
func (*ExplorationStore) DigestMembers ¶
func (s *ExplorationStore) DigestMembers(digestID int64) ([]int64, error)
DigestMembers returns the member ids a digest covers (covers edges), sorted.
func (*ExplorationStore) DirectSourceStores ¶
func (s *ExplorationStore) DirectSourceStores() ([]DirectSourceStore, error)
DirectSourceStores resolves the live, direct task relations for this exploration. It deliberately queries on every call: relations disappear when a source task is deleted, and inherited context must not retain stale rows. Sources of a source are never expanded.
func (*ExplorationStore) DiscardOpenIntent ¶
func (s *ExplorationStore) DiscardOpenIntent(id int64) error
DiscardOpenIntent compensates a follow-up creation when task admission fails. The task execution gate must still be held by the caller, so the intent cannot be claimed between this check and deletion. Edges and anchors cascade with the node; activity is deleted explicitly because its node FK otherwise becomes NULL.
func (*ExplorationStore) Edges ¶
func (s *ExplorationStore) Edges(limit int) ([]Edge, error)
Edges lists exploration edges (for graph viz).
func (*ExplorationStore) EdgesTouching ¶
func (s *ExplorationStore) EdgesTouching(ids []int64) ([]Edge, error)
EdgesTouching returns every edge with one end among ids — the 播报板 uses it to spell out where a node came from and what it produced.
func (*ExplorationStore) FactsYielded ¶
func (s *ExplorationStore) FactsYielded(intentID int64) ([]int64, error)
FactsYielded returns the ids of fact nodes an intent produced (intent --yields--> fact), oldest first. Used to spell out the round's incremental facts to the planner alongside the finished worker's output. Best-effort: returns nil for an intent with no facts (or a missing one).
func (*ExplorationStore) FindingIntents ¶
func (s *ExplorationStore) FindingIntents() (map[int64]int64, error)
FindingIntents maps each finding id to the intent that produced it (the intent --yields--> finding edge; report_finding links it). Findings with no producing intent are absent. Precise (JOIN, no edge-scan limit).
func (*ExplorationStore) FindingIntentsTerminal ¶
func (s *ExplorationStore) FindingIntentsTerminal() (map[int64]int64, error)
FindingIntentsTerminal is the inherited-history variant: it returns finding lineage only when the producing intent has reached an immutable terminal state. This keeps a source task's live worker topology private.
func (*ExplorationStore) FindingIntentsWithSources ¶
func (s *ExplorationStore) FindingIntentsWithSources() (map[int64]int64, error)
FindingIntentsWithSources combines finding lineage for the current exploration and each direct source. Node ids are globally unique.
func (*ExplorationStore) FindingLineage ¶
func (s *ExplorationStore) FindingLineage(nodeID int64) ([]*Node, []Edge, error)
FindingLineage returns the sub-DAG that leads FROM the exploration root TO the given node: the node itself plus all its ancestors (nodes reverse-reachable by following edges backward), and every edge whose both endpoints are in that set. Used to render "how this finding was reached" — origin → … → finding. Returns empty (not error) for a nonexistent node.
func (*ExplorationStore) Frontier ¶
func (s *ExplorationStore) Frontier(limit int) ([]*Node, error)
Frontier returns open intents ordered by priority desc then id (FIFO tiebreak).
func (*ExplorationStore) GetNode ¶
func (s *ExplorationStore) GetNode(id int64) (*Node, error)
GetNode returns one node of this exploration by id (nil, nil if not found).
func (*ExplorationStore) GetNodeWithSources ¶
func (s *ExplorationStore) GetNodeWithSources(id int64) (*Node, error)
GetNodeWithSources reads a node only when it belongs to this exploration or one of its direct sources. Inherited nodes are tagged so tool callers can keep them read-only and show their provenance.
func (*ExplorationStore) HasActiveIntent ¶
func (s *ExplorationStore) HasActiveIntent() (bool, error)
HasActiveIntent reports whether this exploration has any intent still in play (state open OR running). Used to decide whether to kick the FIRST planner round: a seeded task's intent may already have been claimed (open→running) by a worker before the check, so counting only 'open' (Frontier) races with worker claim and wrongly kicks a redundant first round. Counting open+running is race-proof.
func (*ExplorationStore) HasOpenGoal ¶
func (s *ExplorationStore) HasOpenGoal() (bool, error)
HasOpenGoal reports whether this exploration still has any goal in state 'open'. false ⇒ 所有目标已 met/abandoned(或本任务无目标)⇒ 进入 goalless(人工直投)分支: planner 停跑,任务是否结束改由 frontier 是否抽干决定。met 与 abandoned 都算"已了结"。
func (*ExplorationStore) ID ¶
func (s *ExplorationStore) ID() int64
func (*ExplorationStore) Link ¶
func (s *ExplorationStore) Link(from int64, rel string, to int64) error
Link adds a typed exploration edge (idempotent).
func (*ExplorationStore) ListByKind ¶
func (s *ExplorationStore) ListByKind(kind string, limit int) ([]*Node, error)
ListByKind lists nodes of a kind (newest first).
func (*ExplorationStore) ListByKindPage ¶
func (s *ExplorationStore) ListByKindPage(kind string, before int64, limit int) ([]*Node, bool, error)
ListByKindPage returns one newest-first page of nodes of a kind for reverse pagination: up to `limit` nodes with id < `before` (before<=0 = the newest page). hasMore reports whether still-older nodes exist, so a client (e.g. the worker session list) can page past the old fixed cap instead of losing older intents.
func (*ExplorationStore) ListByKindPageWithSources ¶
func (s *ExplorationStore) ListByKindPageWithSources(kind string, before int64, limit int, q string) (nodes []*Node, hasMore bool, total int, err error)
ListByKindPageWithSources is the paginated, keyword-filterable sibling of ListByKindWithSources: it returns one newest-first page (id < before, before<=0 = newest) spanning this exploration and its direct sources, plus hasMore and the filtered total across all of them. Node ids are globally unique, so merging each store's own page and re-sorting by id DESC yields the true global page; fetching limit+1 per store guarantees the merged top-`limit` is complete.
func (*ExplorationStore) ListByKindWithSources ¶
func (s *ExplorationStore) ListByKindWithSources(kind string, limit int) ([]*Node, error)
ListByKindWithSources returns local nodes followed by nodes from each direct source in relation order. The limit remains per exploration, matching the existing ListByKind contract while ensuring one large task cannot hide all inherited context from another source.
func (*ExplorationStore) ListConstraints ¶
func (s *ExplorationStore) ListConstraints() ([]Constraint, error)
ListConstraints returns this exploration's constraints, allow before deny, oldest first within each group (stable render order for the prompt block + UI).
func (*ExplorationStore) ListMainSessions ¶
func (s *ExplorationStore) ListMainSessions() ([]MainSession, error)
ListMainSessions returns every main-session segment newest-first, always including the implicit original segment 0. Segment 0 carries no stored timestamp.
func (*ExplorationStore) NewMainSession ¶
func (s *ExplorationStore) NewMainSession() (MainSession, error)
NewMainSession creates the next main-session segment (seq = current+1) and returns it. It touches only main_sessions — the task's exploration graph/assets/goal are untouched, so the new session starts with a clean transcript over the same task.
func (*ExplorationStore) NodeAssets ¶
func (s *ExplorationStore) NodeAssets(ids []int64) (map[int64][]int64, error)
NodeAssets maps each of the given node ids → the asset ids it is anchored to (exploration_anchors). Used to group cold digests by asset (§6.2 index).
func (*ExplorationStore) Nodes ¶
func (s *ExplorationStore) Nodes(limit int) ([]*Node, error)
Nodes lists all nodes (for graph viz).
func (*ExplorationStore) NodesByIDs ¶
func (s *ExplorationStore) NodesByIDs(ids []int64) ([]*Node, error)
NodesByIDs loads the given nodes of this exploration in id order. Used to resolve the neighbours of a 播报板 page without fetching the whole graph.
func (*ExplorationStore) NodesPage ¶
func (s *ExplorationStore) NodesPage(f NodeFilter, page, size int) ([]*Node, int, error)
NodesPage returns one 1-based page of this exploration's nodes plus the total matching count. The 播报板 reads the graph as a time series, so it pages in SQL rather than pulling the whole graph like Nodes does. Ordering is by id, which is BIGSERIAL and therefore creation order — stable when several nodes share a created_at second.
func (*ExplorationStore) OriginFactID ¶
func (s *ExplorationStore) OriginFactID() (int64, error)
OriginFactID returns this exploration's root fact id — the KindFact node with state='origin' seeded at task creation (the task root). Every intent traces back to it. Returns 0 (no error) when none exists (legacy explorations created under the old 'begin' root, or none yet).
func (*ExplorationStore) PopulateFindingTrafficIDs ¶
func (s *ExplorationStore) PopulateFindingTrafficIDs(nodes []*Node) error
PopulateFindingTrafficIDs only enriches already-visible nodes. It performs no discovery or ID guessing, and leaves the legacy node ID unchanged.
func (*ExplorationStore) RecordFinding ¶
func (s *ExplorationStore) RecordFinding(ctx context.Context, in RecordFindingInput) (out *RecordedFinding, err error)
RecordFinding is the atomic legacy/no-recorder path used by tools and tests.
func (*ExplorationStore) ReopenBlockedIntents ¶
func (s *ExplorationStore) ReopenBlockedIntents() (int64, error)
ReopenBlockedIntents flips EVERY 'blocked' intent in this exploration back to 'open' (batch rerun after e.g. an LLM/network outage that blocked many at once). Returns the number reopened. Workers resume from their transcripts; kept graph writes remain.
func (*ExplorationStore) ReopenIntent ¶
func (s *ExplorationStore) ReopenIntent(id int64) (bool, error)
ReopenIntent flips ONE not-successfully-finished intent (blocked/exhausted/stopped) back to 'open' so a worker re-claims it (graph writes it already produced stay). The worker resumes from its prior LLM transcript instead of restarting from scratch. done/open/running are left untouched. Returns whether a row changed. Used by "重跑".
func (*ExplorationStore) ReopenIntentsByBlockedReason ¶
func (s *ExplorationStore) ReopenIntentsByBlockedReason(reason string) (int64, error)
func (*ExplorationStore) ResetRunningIntents ¶
func (s *ExplorationStore) ResetRunningIntents() (int64, error)
SetIntentState updates an intent node's state. ResetRunningIntents returns any intent left in 'running' back to 'open' so it is re-claimed. Called on startup: a 'running' intent with no live worker (a backend restart or crashed worker goroutine left it stuck) would otherwise spin forever in the UI. Workers resume from their transcript, so reopening is safe.
func (*ExplorationStore) Root ¶
func (s *ExplorationStore) Root() (description, goal string, err error)
Root returns the exploration's description and goal.
func (*ExplorationStore) RoundNo ¶
func (s *ExplorationStore) RoundNo() (int64, error)
RoundNo returns the current planner-round counter.
func (*ExplorationStore) SetIntentBlockedReason ¶
func (s *ExplorationStore) SetIntentBlockedReason(id int64, reason string) error
func (*ExplorationStore) SetIntentState ¶
func (s *ExplorationStore) SetIntentState(id int64, state string) error
func (*ExplorationStore) SetNodeState ¶
func (s *ExplorationStore) SetNodeState(id int64, state string) error
SetNodeState updates any node's state (never deletes). content_version bumps so a folded member's state flip invalidates its digest's cached body (§5.3).
func (*ExplorationStore) SoftDeleteIntent ¶
func (s *ExplorationStore) SoftDeleteIntent(id int64, reason string) (string, error)
SoftDeleteIntent 假删除一个待领/运行中/已暂停的意图:置 state='deleted' 并把用户填写的 删除原因记入 delete_reason 字段,保留意图节点及其全部产出/血缘(不再像旧实现那样在图上 另挂一条 fact)。返回删除前意图的 summary,供 planner 通知使用。副会话随删除态一并清理。 调用方须先停掉运行中的 worker,避免其后续写入。
func (*ExplorationStore) Stats ¶
func (s *ExplorationStore) Stats() (map[string]int, error)
Stats returns node counts grouped by kind (for dashboard).
func (*ExplorationStore) SupersedeDigests ¶
func (s *ExplorationStore) SupersedeDigests(ids []int64) error
SupersedeDigests retires digest nodes (state→superseded) AND removes their covers edges, atomically, so the active-coverage set (CoveredMembers) never double-counts a member during a major recompaction (§5.1). The digest node itself is kept (node_detail can still resolve it).
func (*ExplorationStore) TaskID ¶
func (s *ExplorationStore) TaskID() (int64, error)
TaskID returns the live task bound to this exploration. Explorations created directly in tests or maintenance code have no task and return zero.
func (*ExplorationStore) TokenStatsBySession ¶
func (s *ExplorationStore) TokenStatsBySession() ([]SessionTokenUsage, error)
TokenStatsBySession aggregates every persisted completed run, independent of activity-history pagination. Main/planner use fixed keys; Worker executions use their intent node id, even when a different work#N process handled a retry.
func (*ExplorationStore) TokenStatsByWorker ¶
func (s *ExplorationStore) TokenStatsByWorker() ([]TokenUsage, error)
TokenStatsByWorker sums token usage per worker for this exploration (from the kind='result' records that carry usage). Used by the per-agent token display.
func (*ExplorationStore) TokenTotal ¶
func (s *ExplorationStore) TokenTotal() (TokenUsage, error)
TokenTotal sums token usage across ALL workers for this exploration (whole-task total). Same source as TokenStatsByWorker (kind='result' rows), just ungrouped.
func (*ExplorationStore) UpdateConstraint ¶
func (s *ExplorationStore) UpdateConstraint(id int64, kind, text string) error
UpdateConstraint rewrites a constraint's kind + text; scoped to this exploration. Returns an error if no such constraint exists.
func (*ExplorationStore) UpdateGoalPayload ¶
func (s *ExplorationStore) UpdateGoalPayload(id int64, text, vulnclass string) error
UpdateGoalPayload rewrites a goal node's payload text (and optional vulnclass); scoped to kind='goal' so it can never mutate an intent/fact by id. Returns an error if no such goal exists in this exploration.
type Expr ¶
type Expr struct {
Field string // empty = bare-text full-text search
Op string // "=", "==", "!=", ">", ">=", "<", "<="
Value string
}
Expr is one leaf DSL clause.
type FindingAssetNode ¶
type FindingAssetNode struct {
Key string `json:"key"`
Parent string `json:"parent,omitempty"`
Kind string `json:"kind"` // company|root_domain|subdomain|ip|service|app|endpoint|none
Label string `json:"label"`
AssetID int64 `json:"asset_id,omitempty"`
CompanyID int64 `json:"company_id,omitempty"`
// Self 是直接挂在该资产上的发现数;Total 含全部子孙且按 finding 去重
// (一个发现挂多个资产时,只在共同祖先上计一次)。
Self int `json:"self"`
Total int `json:"total"`
Critical int `json:"critical"`
High int `json:"high"`
Medium int `json:"medium"`
Low int `json:"low"`
LastFoundAt time.Time `json:"last_found_at"`
}
FindingAssetNode 是资产树的一个节点。Key 与覆盖图同构:资产行是 "a:<id>"、 企业是 "c:<id>"、没有资产行的根域名是合成的 "r:<domain>"、未关联桶是 "__none__"。
type FindingAssetTree ¶
type FindingAssetTree struct {
Nodes []FindingAssetNode `json:"nodes"`
FindingTotal int `json:"finding_total"`
// Truncated=true 表示为控制体积丢弃了 DroppedKinds 里的层级。
Truncated bool `json:"truncated"`
DroppedKinds []string `json:"dropped_kinds,omitempty"`
}
FindingAssetTree 是整棵树的一次性快照。Nodes 已排好序:同一父节点下按发现数 降序、标签升序,「未关联资产」恒在最后。
type FindingFilter ¶
type FindingFilter struct {
Severity string // high | medium | low
Status string // pending | false_positive | ignored | resolved
VulnClass string
TaskID string // 任务 id(字符串形式;空/非法 = 不按任务筛选)
Query string // 名称/类型/摘要/证据/报告正文的模糊检索关键词
Sort string // "severity" | "time"
// AssetScope 是资产树的节点 key(a:<id> / c:<id> / r:<domain> / __none__),
// 选中一个节点等于选中它的整棵子树。空 = 不按资产筛选。
AssetScope string
// contains filtered or unexported fields
}
FindingFilter narrows a paginated findings query. Empty-string fields mean "no filter on that column". Sort is "severity" (severity desc, then newest) or anything else (newest first).
type FindingGroup ¶
type FindingGroup struct {
TaskID *int64 `json:"task_id"`
TaskName string `json:"task_name"` // 可选任务名称;空=未命名
TaskDescription string `json:"task_description"`
TaskStatus string `json:"task_status"`
Count int `json:"count"`
Critical int `json:"critical"`
High int `json:"high"`
Medium int `json:"medium"`
Low int `json:"low"`
LastFoundAt time.Time `json:"last_found_at"`
}
FindingGroup is one task-level bucket in the global findings view. TaskID is nil for both findings that never had a task and findings retained after task deletion; those records intentionally share one "unassigned/deleted" bucket.
type FindingMeta ¶
FindingMeta is the standalone-row data (id, triage state, anchored assets) the per-task view grafts onto its exploration-node findings.
type FindingRetest ¶
type FindingRetest struct {
ID int64 `json:"id"`
FindingID int64 `json:"finding_id"`
ConversationID *int64 `json:"conversation_id"`
Status string `json:"status"`
Verdict string `json:"verdict"`
Notes string `json:"notes"`
Snapshot json.RawMessage `json:"snapshot,omitempty"`
Summary string `json:"summary"`
Evidence string `json:"evidence"`
Error string `json:"error"`
CreatedAt time.Time `json:"created_at"`
StartedAt *time.Time `json:"started_at"`
FinishedAt *time.Time `json:"finished_at"`
}
FindingRetest is an immutable historical test once its conversation turn ends. Snapshot is only loaded for the agent, never sent with the history list.
func (*FindingRetest) InitialMessage ¶
func (r *FindingRetest) InitialMessage() string
type FindingSeverityCounts ¶ added in v0.3.14
type FindingSeverityCounts struct{ Critical, High, Medium, Low int }
FindingSeverityCounts breaks a task's findings down by severity for the task list (severity 白名单外/为空的记录不计入任一档)。
type FindingStats ¶
type FindingStats struct {
Total int `json:"total"`
Pending int `json:"pending"`
Critical int `json:"critical"`
High int `json:"high"`
Medium int `json:"medium"`
Low int `json:"low"`
VulnClasses []string `json:"vulnclasses"`
Tasks []FindingTaskOption `json:"tasks"` // 有漏洞的任务(供「按任务」下拉)
}
FindingStats is the whole-table aggregate powering the 发现 page's stat cards and vuln-class filter — computed server-side so it stays exact regardless of pagination.
type FindingTaskOption ¶
type FindingTaskOption struct {
ID int64 `json:"id"`
Name string `json:"name"` // 可选任务名称;空=未命名
Description string `json:"description"`
Count int `json:"count"`
}
FindingTaskOption is one entry in the 发现 page's 任务 filter: a task that has at least one finding, with its description and finding count. Description is empty when the task has since been deleted (finding rows persist), so the frontend falls back to the id.
type FindingTraffic ¶
type FindingTraffic struct {
FindingID int64 `json:"finding_id,string"`
Version int64 `json:"version"`
ReportVersion int64 `json:"report_version"`
Bindings []FindingTrafficBinding `json:"bindings"`
}
func FindingTrafficTx ¶
func FindingTrafficTx(tx *sql.Tx, findingID int64) (*FindingTraffic, error)
type FindingTrafficBinding ¶
type FindingTrafficBinding struct {
ID int64 `json:"id,string"`
FindingID int64 `json:"finding_id,string"`
SnapshotID string `json:"snapshot_id"`
Role string `json:"role"`
Note string `json:"note"`
Position int `json:"position"`
CreatedAt time.Time `json:"created_at"`
Snapshot TrafficEvidenceSnapshot `json:"snapshot"`
}
type GoalCounts ¶
type GoalCounts struct{ Total, Met int }
GoalCounts is the goal summary for one exploration.
type IntentAsset ¶
type IntentAsset struct {
IntentID int64 `json:"intent_id"`
AssetID int64 `json:"asset_id"`
Type string `json:"type"`
Label string `json:"label"`
Source string `json:"source"`
SourceSummary string `json:"source_summary"`
SourceNodeID *int64 `json:"source_node_id,omitempty"`
SourceTaskID int64 `json:"source_task_id"`
Inherited bool `json:"inherited"`
}
IntentAsset describes an asset explicitly anchored to a worker intent.
type IntentCleanup ¶
type IntentCleanup struct {
Intents int64 `json:"intents"`
Facts int64 `json:"facts"`
Findings int64 `json:"findings"`
Activities int64 `json:"activities"`
}
IntentCleanup summarizes the blackboard records removed when a user cancels one worker intent. Global assets and traffic are deliberately not part of this operation; exploration anchors disappear only because their owning nodes do.
type InterceptApprovalFilter ¶
InterceptApprovalFilter combines exact status and decision-source filters. Empty fields include all values.
type InterceptApprovalRow ¶
type InterceptApprovalRow struct {
InterceptPending
ConvTitle string `json:"conv_title"`
ConvAgentKey string `json:"conv_agent_key"`
RuleName string `json:"rule_name"`
}
InterceptApprovalRow is intercept_pending enriched with conversation and rule info.
type InterceptAudit ¶
type InterceptAudit struct {
RunID string `json:"run_id,omitempty"`
ToolUseID string `json:"tool_use_id,omitempty"`
Correlation string `json:"correlation"` // exact | ambiguous | unavailable
InputDigest string `json:"input_digest"`
UserMessage string `json:"user_message"`
UserTruncated bool `json:"user_truncated,omitempty"`
Context []InterceptContextEntry `json:"context"`
ContextTruncated bool `json:"context_truncated,omitempty"`
CapturedAt time.Time `json:"captured_at"`
ModelFallback bool `json:"model_fallback,omitempty"`
ModelInput json.RawMessage `json:"model_input,omitempty"`
ModelInputDigest string `json:"model_input_digest,omitempty"`
InitialAction string `json:"initial_action"`
InitialReason string `json:"initial_reason"`
EffectiveAction string `json:"effective_action,omitempty"`
DecisionReason string `json:"decision_reason,omitempty"`
RuleName string `json:"rule_name,omitempty"`
ConfigDigest string `json:"config_digest,omitempty"`
ProfileID int64 `json:"profile_id,omitempty"`
ExecutionStatus string `json:"execution_status"`
Output string `json:"output,omitempty"`
OutputTruncated bool `json:"output_truncated,omitempty"`
ExecutionEndedAt *time.Time `json:"execution_ended_at,omitempty"`
}
InterceptAudit is captured at review time. It is deliberately excluded from polling/list responses; old rows have no audit instead of reconstructed data.
type InterceptContextEntry ¶
type InterceptContextEntry struct {
Kind string `json:"kind"`
Tool string `json:"tool,omitempty"`
ToolUseID string `json:"tool_use_id,omitempty"`
Text string `json:"text"`
IsError bool `json:"is_error,omitempty"`
Truncated bool `json:"truncated,omitempty"`
}
InterceptContextEntry is a bounded, recorded session event, not model reasoning.
type InterceptDetail ¶
type InterceptDetail struct {
InterceptApprovalRow
Audit *InterceptAudit `json:"audit"`
}
type InterceptExecution ¶
type InterceptExecution struct {
ConversationID *int64 `json:"conversation_id,omitempty"`
TaskID *string `json:"task_id,omitempty"`
Session string `json:"session"`
Seq int64 `json:"seq"`
Items []Activity `json:"-"`
}
InterceptExecution is a navigation target read from original activity rows. It is not model context and never falls back to matching command text.
type InterceptPending ¶
type InterceptPending struct {
ID int64 `json:"id"`
RuleID *int64 `json:"rule_id"`
ConversationID *int64 `json:"conversation_id"`
TaskID *string `json:"task_id"`
AgentName string `json:"agent_name"`
ToolName string `json:"tool_name"`
ToolInput json.RawMessage `json:"tool_input"`
Status string `json:"status"`
DecisionSource string `json:"decision_source"`
Reason string `json:"reason"` // 规则 message 或模型判定理由(前缀 [模型])
DecidedAt *time.Time `json:"decided_at"`
CreatedAt time.Time `json:"created_at"`
}
InterceptPending is one row of intercept_pending.
type InterceptRule ¶
type InterceptRule struct {
ID int64 `json:"id"`
Name string `json:"name"`
Enabled bool `json:"enabled"`
Priority int `json:"priority"`
MatchTarget string `json:"match_target"`
MatchType string `json:"match_type"`
Pattern string `json:"pattern"`
Action string `json:"action"`
Message string `json:"message"`
TimeoutEnabled bool `json:"timeout_enabled"`
TimeoutSeconds int `json:"timeout_seconds"`
TimeoutAction string `json:"timeout_action"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
InterceptRule is one row of intercept_rules.
type JudgeDayUsage ¶ added in v0.3.15
type JudgeDayUsage struct {
Date string `json:"date"` // YYYY-MM-DD (UTC)
Calls int `json:"calls"`
InputTokens int `json:"input_tokens"`
OutputTokens int `json:"output_tokens"`
}
JudgeDayUsage is one UTC-day token bucket for the intercept fallback judge, for the config page's recent-spend sparkline.
type JudgeUsage ¶ added in v0.3.15
type JudgeUsage struct {
Calls int `json:"calls"`
InputTokens int `json:"input_tokens"`
OutputTokens int `json:"output_tokens"`
CacheReadTokens int `json:"cache_read_tokens"`
CacheWriteTokens int `json:"cache_write_tokens"`
Daily []JudgeDayUsage `json:"daily"`
}
JudgeUsage is the cumulative token spend of the intercept fallback judge (worker='judge' rows in the always-on ledger), plus a recent daily series.
type LLMHealth ¶
type LLMHealth struct {
ProfileID int64 `json:"profile_id"`
Fails int `json:"fails"` // consecutive failures; cleared on success
Trips int `json:"trips"` // total trips, drives the backoff ladder
OpenUntil *time.Time `json:"open_until"` // nil/past = closed (healthy)
LastError string `json:"last_error"`
LastAt time.Time `json:"last_at"`
}
LLMHealth is one profile's circuit-breaker state.
type LLMProfile ¶
type LLMProfile struct {
ID int64 `json:"id"`
Name string `json:"name"`
Format string `json:"format"`
BaseURL string `json:"base_url,omitempty"`
Proxy string `json:"proxy,omitempty"` // LLM 出站代理(http/https/socks5);空=用环境变量
Model string `json:"model"`
APIKey string `json:"-"` // never serialized to UI
APIKeyHint string `json:"api_key_hint,omitempty"`
RatePerSecond float64 `json:"rate_per_second"`
RatePerMinute float64 `json:"rate_per_minute"`
// ContextWindowK is the model's context window in K tokens, used to size
// compaction thresholds. 0 = use a 200K default; capped at 1000 (1M).
ContextWindowK int `json:"context_window_k"`
// ThinkingType 独立控制思考「开关」(thinking.type):"" = 不发送(默认);
// "disabled" = 显式关闭; "enabled" = 开启. 与 ReasoningEffort 解耦.
ThinkingType string `json:"thinking_type"`
// ReasoningEffort 独立控制思考「强度」:"" = 不发送(默认);
// "low"/"medium"/"high"/"xhigh"/"max" = 对应强度. 见 agent.Config.NewProvider.
ReasoningEffort string `json:"reasoning_effort"`
IsDefault bool `json:"is_default"`
// Priority orders the failover chain: higher goes first. The ACTIVE profile
// (IsDefault) always heads the chain regardless of this value.
Priority int `json:"priority"`
// PoolExclude=true keeps this profile out of the failover chain — it stays
// usable when an agent/task binds it explicitly, it just never gets picked up
// as a fallback target.
PoolExclude bool `json:"pool_exclude"`
// Streaming selects the wire protocol: true (default) = streaming (SSE);
// false = real non-streaming (stream:false, single JSON response via
// Provider.Complete). Non-streaming sidesteps flaky gateway SSE at the cost of
// live in-run progress. Maps to agent.Config.Stream.
Streaming bool `json:"streaming"`
// MaxTokens caps a single reply's output in tokens. 0 = send no cap and let
// the endpoint's own default apply (the historical behaviour). Unlike
// ContextWindowK — the model's total capacity, used locally to size compaction
// — this value travels with every request.
MaxTokens int `json:"max_tokens"`
// MaxTokensField picks the request key carrying MaxTokens, for format
// "openai" only: "" = max_tokens (default); "max_completion_tokens" = the
// newer key, which OpenAI's reasoning models require and whose budget covers
// reasoning tokens plus visible output. Ignored by anthropic and
// openai-responses, which name the field themselves.
MaxTokensField string `json:"max_tokens_field"`
// SessionHeaderKey, when non-empty, names a custom HTTP header sent on every
// request built from this profile; its value is the current run's session id
// (chat conversation / worker intent). For gateways that key prompt caching
// or sticky routing off a session-id header. "" = not sent. Maps to
// agent.Config.SessionHeaderKey.
SessionHeaderKey string `json:"session_header_key"`
// Retry overrides this profile's share of the retry ladder. Zero value =
// inherit the global policy (LLMRetryPolicy), so an untouched profile behaves
// exactly as before. See RetryOverride.
Retry RetryOverride `json:"retry"`
}
type LLMRecord ¶
type LLMRecord struct {
ID int64 `json:"id"`
Ts time.Time `json:"ts"`
Model string `json:"model"`
ProfileName string `json:"profile_name"`
SessionID string `json:"session_id"`
TaskID string `json:"task_id"`
Worker string `json:"worker"`
LatencyMs int `json:"latency_ms"`
InputTokens int `json:"input_tokens"`
OutputTokens int `json:"output_tokens"`
CacheRead int `json:"cache_read"`
CacheWrite int `json:"cache_write"`
Status string `json:"status"`
Error string `json:"error,omitempty"`
RequestBody string `json:"request_body,omitempty"`
ResponseBody string `json:"response_body,omitempty"`
// RawRequest / RawResponse are the untouched HTTP bodies exchanged with the
// provider — the request as buildBody() sent it (full tool schemas included)
// and the raw SSE frames. RequestBody/ResponseBody above are the normalized
// view, which drops tool schemas and tool_use blocks entirely. Empty for
// records written before this was added, or when the call never reached HTTP.
RawRequest string `json:"raw_request,omitempty"`
RawResponse string `json:"raw_response,omitempty"`
}
LLMRecord is one recorded LLM API call (request + response).
type LLMRetryPolicy ¶
type LLMRetryPolicy struct {
// Connect:SDK 建连重试(连接重置/超时/429/5xx,流开始前)。默认 3 次、指数退避。
Connect RetryRule `json:"connect"`
// Empty:SDK 空响应重试(完成但无 content block,仅 openai 格式)。默认 2 次、指数退避。
Empty RetryRule `json:"empty"`
// Stream:同 provider 安全窗口重试(未交付输出前的断流重放)。默认 2 次、0.5s 起指数(封顶 4s)。
Stream RetryRule `json:"stream"`
// Breaker:轮询熔断。Attempts=连续几次瞬时失败触发熔断(默认 3,-1=瞬时失败不熔断,
// 硬失败如余额不足/密钥失效仍立即熔断);IntervalMS=固定冷却时长(0=默认 1/5/30min 梯度)。
Breaker RetryRule `json:"breaker"`
// Intent:worker 以 model_error 收场后的整条意图重跑。默认 2 次、固定 3s。
Intent RetryRule `json:"intent"`
}
LLMRetryPolicy holds the五层 retry configuration. Connect/Empty/Stream are the per-request layers (a profile may override them, see LLMProfile.Retry); Breaker and Intent are process-wide by nature and live only here.
func (LLMRetryPolicy) Clamped ¶
func (p LLMRetryPolicy) Clamped() LLMRetryPolicy
Clamped returns the policy with every rule clamped.
type LLMUsage ¶
type LLMUsage struct {
TaskID string `json:"task_id"` // task registry id (matches llm_records.task_id)
ExplorationID int64 `json:"exploration_id"` // exploration id parsed from the session (0 = unknown/non-task)
Worker string `json:"worker"` // agent lane: worker / planner / mainagent / goals
Model string `json:"model"`
ProfileName string `json:"profile_name"`
LatencyMs int `json:"latency_ms"`
InputTokens int `json:"input_tokens"`
OutputTokens int `json:"output_tokens"`
CacheRead int `json:"cache_read"`
CacheWrite int `json:"cache_write"`
Status string `json:"status"` // ok | error
}
LLMUsage is one lightweight LLM-call metering row — the always-on usage ledger, distinct from llm_records (which stores full request/response bodies and is a gated debug feature). One row per completion call, written on both success and error, so token accounting is complete even for interrupted/failed runs. Carries only the dimensions needed to slice token spend (model / profile / task / agent), never any prompt or response content.
type MCPServer ¶
type MCPServer struct {
ID int64 `json:"id"`
Name string `json:"name"`
Transport string `json:"transport"`
Command string `json:"command,omitempty"`
Args json.RawMessage `json:"args"`
Env json.RawMessage `json:"env"`
URL string `json:"url,omitempty"`
Enabled bool `json:"enabled"`
Insecure bool `json:"insecure"` // http: skip TLS cert verification (self-signed servers, issue #108)
Tools []string `json:"tools,omitempty"` // cached tool names (mcp_tools_cache)
}
type MainSession ¶
MainSession is one resettable main-agent conversation segment of a task. Segment 0 is the original session (implicit, never stored); further segments are created by "新建会话" to start the main agent on a clean transcript while the task's graph, assets and goal stay shared.
type ModelTokenStat ¶
type ModelTokenStat struct {
Model string `json:"model"`
Calls int `json:"calls"`
InputTokens int `json:"input_tokens"`
OutputTokens int `json:"output_tokens"`
CacheReadTokens int `json:"cache_read_tokens"`
CacheWriteTokens int `json:"cache_write_tokens"`
}
ModelTokenStat is one model's aggregated token usage for a task, summed from the llm_usage metering ledger (see db/llm_usage.go). Calls is the number of LLM calls that hit this model.
type Node ¶
type Node struct {
FindingID int64 `json:"finding_id,omitempty"` // populated by finding-aware reads; never inferred from ID
FindingNodeID int64 `json:"finding_node_id,omitempty"`
TrafficCount int `json:"traffic_count,omitempty"`
ID int64 `json:"id"`
Kind string `json:"kind"`
Payload json.RawMessage `json:"payload"`
Priority int `json:"priority"`
State string `json:"state"`
Origin string `json:"origin,omitempty"`
Owner string `json:"owner,omitempty"`
BlockedReason string `json:"blocked_reason,omitempty"`
DeleteReason string `json:"delete_reason,omitempty"` // 仅意图假删除(state='deleted')时非空
Anchors []int64 `json:"anchors,omitempty"`
CreatedAt time.Time `json:"created_at"`
SourceTaskID int64 `json:"source_task_id,omitempty"`
Inherited bool `json:"inherited,omitempty"`
}
Node is a typed reasoning node (= old task_nodes). kind ∈ goal|intent|finding|hint.
type NodeFilter ¶
type NodeFilter struct {
Kinds []string // exploration_nodes.kind
States []string // exploration_nodes.state
Query string // case-insensitive substring over payload text / origin
Asc bool // true = oldest first (replay); default newest first (broadcast)
}
NodeFilter narrows a NodesPage query. Empty fields include every value.
type NotificationChannel ¶ added in v0.3.15
type NotificationChannel struct {
ID int64 `json:"id"`
Name string `json:"name"`
Kind string `json:"kind"`
Mode string `json:"mode"`
Config json.RawMessage `json:"config"`
Filter json.RawMessage `json:"filter"`
// Enabled 用指针是为了区分「没传这个字段」与「显式传 false」——
// 前端开关控件只提交被改动的字段。
Enabled *bool `json:"enabled,omitempty"`
RatePerMin int `json:"rate_per_min"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
NotificationChannel 是一个渠道实例配置。Config 与 Filter 保持原始 JSON, 解析交给 notify 包——db 层不理解它们的字段含义。
func (*NotificationChannel) IsEnabled ¶ added in v0.3.15
func (c *NotificationChannel) IsEnabled() bool
IsEnabled 返回渠道是否启用;Enabled 为 nil(未加载)时按启用处理。
type NotificationDelivery ¶ added in v0.3.15
type NotificationDelivery struct {
ID int64 `json:"id"`
EventID int64 `json:"event_id"`
ChannelID int64 `json:"channel_id"`
State string `json:"state"`
Attempts int `json:"attempts"`
NextAttemptAt time.Time `json:"next_attempt_at"`
LastError string `json:"last_error"`
BatchID *int64 `json:"batch_id,omitempty"`
CreatedAt time.Time `json:"created_at"`
SentAt *time.Time `json:"sent_at,omitempty"`
Snapshot json.RawMessage `json:"snapshot,omitempty"`
// 联合加载的渲染上下文,不进 JSON(由 server 层组装 DTO)。
Channel *NotificationChannel `json:"-"`
// FindingID/EventKind 从事件带出,供历史列表直接跳转漏洞详情。
FindingID int64 `json:"finding_id,string"`
EventKind string `json:"event_kind"`
// ChannelName/ChannelKind 是列表展示用的冗余字段,省掉前端二次查询。
ChannelName string `json:"channel_name"`
ChannelKind string `json:"channel_kind"`
}
NotificationDelivery 是一条投递任务,含渲染所需的渠道配置与事件快照。
type NotificationDeliveryFilter ¶ added in v0.3.15
NotificationDeliveryFilter 是投递历史的查询条件。
type NotificationEvent ¶ added in v0.3.15
type NotificationEvent struct {
ID int64 `json:"id"`
Kind string `json:"kind"`
FindingID int64 `json:"finding_id"`
Snapshot json.RawMessage `json:"snapshot"`
CreatedAt time.Time `json:"created_at"`
}
NotificationEvent 是一条事件事实。
type NotificationStats ¶ added in v0.3.15
type NotificationStats struct {
Channels int `json:"channels"`
ChannelsOn int `json:"channels_on"`
Pending int `json:"pending"`
Failed int `json:"failed"`
SentToday int `json:"sent_today"`
BacklogAgeMS int64 `json:"backlog_age_ms"` // 最老的待发投递距今毫秒数
}
NotificationStats 是通知页顶部的概览计数。
type ParamItem ¶
type ParamItem struct {
Location string `json:"location"`
Name string `json:"name"`
Value string `json:"value,omitempty"`
Type string `json:"type,omitempty"`
}
ParamItem is one entry in the params array.
type ParsedScope ¶
type ParsedScope struct {
Kind string // "domain" | "ip" | "cidr" | "icp" | "keyword"
Domain string // normalized registrable/root domain (kind=domain)
Net string // normalized CIDR, single IP as /32 or /128 (kind=ip|cidr)
Value string // normalized text (kind=icp|keyword)
Raw string // original input line
}
ParsedScope is one parsed asset-scope entry. Its kind selects Domain, Net, or Value. Used internally by the company scope parsers and CompanyStore.
func ParseAutoScopeLine ¶
func ParseAutoScopeLine(line string) (ParsedScope, error)
ParseAutoScopeLine classifies one untyped textarea line. Network-looking and domain-looking values remain strict so malformed ranges do not silently become Agent keywords; all other non-empty text is a keyword.
func ParseScopeInput ¶
func ParseScopeInput(input ScopeInput) (ParsedScope, error)
ParseScopeInput validates an explicitly typed rule. Legacy callers can omit Kind and use the same automatic classification as the single-textarea UI.
func ParseScopeLine ¶
func ParseScopeLine(line string) (ParsedScope, error)
ParseScopeLine classifies and validates one scope line (root domain / IP / CIDR). Guardrails reject bare TLDs and over-broad networks so a rule can never swallow the internet. IP ranges must be expressed as CIDR.
type PortService ¶
PortService is one entry in open_ports: {"port":22,"service":"ssh"}.
type PreparedTrafficEvidence ¶
type PreparedTrafficEvidence struct {
Ref TrafficRef
Snapshot TrafficEvidenceSnapshot
}
type ProfileDayUsage ¶
type ProfileDayUsage struct {
ProfileName string `json:"profile_name"`
Date string `json:"date"` // YYYY-MM-DD (UTC)
InputTokens int `json:"input_tokens"`
OutputTokens int `json:"output_tokens"`
CacheReadTokens int `json:"cache_read_tokens"`
}
ProfileDayUsage is one (profile, UTC calendar day) token bucket for the daily chart. Unlike the activity-based chart, ts is the real call time, so this is actual per-day consumption rather than tokens bucketed by task creation date.
type ProfileUsage ¶
type ProfileUsage struct {
ProfileName string `json:"profile_name"`
Calls int `json:"calls"`
Tasks int `json:"tasks"`
InputTokens int `json:"input_tokens"`
OutputTokens int `json:"output_tokens"`
CacheReadTokens int `json:"cache_read_tokens"`
CacheWriteTokens int `json:"cache_write_tokens"`
}
ProfileUsage aggregates the whole ledger's token spend for one LLM profile (global, all tasks). Powers the dashboard's per-profile token card (new source).
type PromptVersion ¶
type RecordFindingInput ¶
type RecordedFinding ¶
type RecordedFinding struct {
FindingID int64 `json:"finding_id,string"`
NodeID int64 `json:"finding_node_id,string"`
Traffic *FindingTraffic `json:"traffic"`
}
func RecordFindingTx ¶
func RecordFindingTx(ctx context.Context, tx *sql.Tx, in RecordFindingInput, prepared []PreparedTrafficEvidence) (*RecordedFinding, error)
ctx 由调用方传入本次事务所用的上下文(而非在内部取 context.Background): 事务内新加的推送事件写入同样应受调用方的取消与超时约束。
type RetryOverride ¶
type RetryOverride struct {
Connect RetryRule `json:"connect"`
Empty RetryRule `json:"empty"`
Stream RetryRule `json:"stream"`
}
RetryOverride is one profile's optional override of the three retry layers that are per-endpoint: 建连(connect) / 空响应(empty) / 同 provider 安全窗口 (stream). Each rule's zero value means "inherit the global policy"; see RetryRule for the -1 / 0 / >0 semantics.
func (RetryOverride) Clamped ¶
func (o RetryOverride) Clamped() RetryOverride
Clamped bounds a profile's override the same way the global policy is bounded, so a hand-crafted API payload can't land a value the CHECK constraint rejects.
type RetryRule ¶
RetryRule is one layer's knob pair. The zero value means "unset":
Attempts 0 = 用内置默认次数; -1 = 关闭该层重试; >0 = 用该值 IntervalMS 0 = 用该层原本的间隔策略(通常是指数退避); >0 = 改用固定毫秒间隔
-1 是「显式关掉」而不是「0 次」,因为 0 已经被「未配置」占用了。
func (RetryRule) Clamped ¶
Clamped returns the rule with out-of-range values pulled back into the sane band (attempts within [-1, 20], interval within [0, 1h]).
type ScopeInput ¶
ScopeInput is the structured API form for a company scope rule. Empty Kind uses the same automatic classification as the single-textarea UI.
type ScopeRule ¶
type ScopeRule struct {
ID int64 `json:"id"`
CompanyID int64 `json:"company_id"`
Kind string `json:"kind"`
Domain string `json:"domain,omitempty"`
Net string `json:"net,omitempty"`
Value string `json:"value,omitempty"`
Raw string `json:"raw"`
Reason string `json:"reason,omitempty"`
}
ScopeRule is one company_scope row.
type SessionTokenUsage ¶
type SessionTokenUsage struct {
Session string `json:"session"`
InputTokens int `json:"input_tokens"`
OutputTokens int `json:"output_tokens"`
CacheReadTokens int `json:"cache_read_tokens"`
CacheWriteTokens int `json:"cache_write_tokens"`
}
SessionTokenUsage is the authoritative completed-run total for one task UI session. Worker sessions are keyed by intent rather than the reusable work#N executor name, so retries and reassignment remain attached to the same row.
type SkillCall ¶
type SkillCall struct {
TS time.Time `json:"ts"`
AgentKey string `json:"agent_key"`
TaskID int64 `json:"task_id"`
SessionID string `json:"session_id"`
ArgsLen int `json:"args_len"`
}
SkillCall is one row of a skill's recent-call list (detail panel).
type SkillStat ¶
type SkillStat struct {
Skill string `json:"skill"`
Calls int `json:"calls"`
Tasks int `json:"tasks"` // distinct tasks that loaded it (chat runs excluded)
Agents []string `json:"agents"` // agent keys that loaded it, most-used first
LastUsed *time.Time `json:"last_used"` // nil when never called
}
SkillStat is one skill's aggregate usage, for the skills page.
type SkillUsage ¶
type SkillUsage struct {
Skill string `json:"skill"` // skill directory name (matches agent_skill_visibility.skill_name)
AgentKey string `json:"agent_key"` // worker / planner / mainagent / custom agent key
TaskID int64 `json:"task_id"` // 0 for non-task runs (chat sessions)
ExplorationID int64 `json:"exploration_id"` // 0 when unknown
IntentID int64 `json:"intent_id"` // worker's intent node; 0 for planner/mainagent/chat
SessionID string `json:"session_id"` // chat conversation id; empty for task runs
ArgsLen int `json:"args_len"`
Found bool `json:"found"` // false = the model named a skill that does not exist
}
SkillUsage is one Skill() invocation — the always-on skill call ledger. Written from the Skill meta-tool's OnInvoke hook (server/assembly.go), one row per load. Carries only dimensions (which skill, which agent, which task/session), never the caller's args text — args_len is kept so an "empty vs substantial context" split is still possible without storing prompt content, mirroring llm_usage.
Rows deliberately outlive their task: skill_usage has no foreign keys, so deleting a task keeps its skill statistics intact (same rationale as llm_usage).
type Task ¶
type Task struct {
ID int64 `json:"id"`
Name string `json:"name"` // 可选任务名称;空=未命名
CategoryID *int64 `json:"category_id,omitempty"`
CategoryName string `json:"category_name,omitempty"`
Pinned bool `json:"pinned"`
PinnedAt *time.Time `json:"pinned_at,omitempty"`
Description string `json:"description"`
Goal string `json:"goal"`
ExplorationID int64 `json:"exploration_id"`
Status string `json:"status"`
Paused bool `json:"paused"`
Queued bool `json:"queued"`
QueuedAt *time.Time `json:"queued_at,omitempty"`
QueueMode string `json:"queue_mode,omitempty"`
LLMProfileID *int64 `json:"llm_profile_id,omitempty"`
// Task-level ordered LLM chain. LLMProfileID remains the compatibility alias
// for ActiveLLMProfileID while older API clients still send one profile id.
LLMProfileIDs []int64 `json:"llm_profile_ids,omitempty"`
ActiveLLMProfileID *int64 `json:"active_llm_profile_id,omitempty"`
LLMChainRevision int64 `json:"-"`
LLMFailoverState string `json:"llm_failover_state,omitempty"`
LLMFailoverReason string `json:"llm_failover_reason,omitempty"`
SourceTaskIDs []int64 `json:"source_task_ids,omitempty"`
CompanyIDs []int64 `json:"company_ids,omitempty"`
ParentRef string `json:"parent_ref,omitempty"` // 父任务 id(编排 spawn 记录;空=顶层)
CreatedAt time.Time `json:"created_at"`
CompletedAt *time.Time `json:"completed_at,omitempty"` // 进入终态(done/failed/timeout)的时刻;非终态为 nil
// 任务级超时(见 docs/任务级超时与收尾设计.md)。
TimeoutSeconds int `json:"timeout_seconds"` // 0=不限时
FirstRunAt *time.Time `json:"first_run_at,omitempty"` // 首次真正开始运行的时刻(非 created_at);nil=尚未运行
DeadlineAt *time.Time `json:"deadline_at,omitempty"` // = first_run_at + timeout_seconds;nil=不限或未运行
// planner 心跳触发间隔(秒):距上轮 plan 结束/任务开始满该值且期间无触发 → 触发一轮。
// 下限=默认=300(5min),低于一律抬到 300(在 CreateTask 归一)。见 docs/planner-trigger-impl-plan.md
PlanHeartbeatSeconds int `json:"plan_heartbeat_seconds"`
// CoverageEnabled 是「资产覆盖度功能」总开关(默认 true)。false 时:不计算/不展示测试
// 覆盖度、不自动累积 task_scope(source=auto)、不给 agent 开放 add_task_scope/
// list_untested_assets、态势里不注入 coverage 块(scope 字段仍保留)。company 关联
// (task_scope kind=company)与此开关无关,永不受影响。见 db/task_scope.go。
CoverageEnabled bool `json:"coverage_enabled"`
}
Task is a row in the task registry (1:1 with an exploration).
type TaskArchive ¶
type TaskArchive struct {
ID int64 `json:"id"`
TaskID int64 `json:"task_id"`
State string `json:"state"`
Phase string `json:"phase"`
Progress int `json:"progress"`
Error string `json:"error,omitempty"`
Warnings json.RawMessage `json:"warnings"`
FormatVersion int `json:"format_version"`
ArchivePath string `json:"-"`
SHA256 string `json:"sha256,omitempty"`
OriginalSize int64 `json:"original_size"`
CompressedSize int64 `json:"compressed_size"`
TaskName string `json:"task_name"`
TaskDescription string `json:"task_description"`
TaskGoal string `json:"task_goal"`
OriginalStatus string `json:"original_status"`
CategoryIDSnapshot *int64 `json:"category_id,omitempty"`
CategoryNameSnapshot string `json:"category_name,omitempty"`
SourceTaskIDs []int64 `json:"source_task_ids"`
RemainingTimeoutSeconds int64 `json:"remaining_timeout_seconds"`
DataCounts json.RawMessage `json:"data_counts"`
AggregateStats json.RawMessage `json:"aggregate_stats"`
ArchivedAt *time.Time `json:"archived_at,omitempty"`
RequestedAt time.Time `json:"requested_at"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
TaskArchive is the compact PostgreSQL record retained while a task is cold. Sensitive profile configuration and API keys are intentionally absent.
type TaskArchivePage ¶
type TaskArchivePage struct {
Items []TaskArchive `json:"items"`
Total int `json:"total"`
Page int `json:"page"`
Size int `json:"size"`
}
type TaskArchiveSnapshot ¶
type TaskArchiveSnapshot struct {
FormatVersion int `json:"format_version"`
CreatedAt time.Time `json:"created_at"`
TaskID int64 `json:"task_id"`
ExplorationID int64 `json:"exploration_id"`
SourceTaskIDs []int64 `json:"source_task_ids"`
Hosts []string `json:"hosts"`
ExclusiveHosts []string `json:"exclusive_hosts"`
ExclusiveAssetIDs []int64 `json:"exclusive_asset_ids"`
Tables map[string]json.RawMessage `json:"tables"`
StreamedTables map[string]string `json:"streamed_tables,omitempty"`
DataCounts map[string]int64 `json:"data_counts"`
AggregateStats map[string]any `json:"aggregate_stats"`
}
TaskArchiveSnapshot is serialized into manifest.json inside the cold package. Small tables remain JSON arrays in Tables. Large v2 tables are streamed to package files listed in StreamedTables so their size is not bounded by memory.
type TaskAssetMutation ¶
type TaskAssetMutation struct {
Requested int `json:"requested"`
Attached int `json:"attached"`
Existing int `json:"existing"`
}
TaskAssetMutation summarizes one attach request. Attached counts newly added associations; Existing counts requested assets that were already on the task.
type TaskAssetScopeMutation ¶
type TaskAssetScopeMutation struct {
Requested int `json:"requested"`
AssetsLinked int `json:"assets_linked"`
AssetsExisting int `json:"assets_existing"`
ScopesAdded int `json:"scopes_added"`
ScopesExisting int `json:"scopes_existing"`
}
TaskAssetScopeMutation summarizes one free-form scope registration. Domain and IP entries create or reuse global assets; every entry also becomes an idempotent task_scope row.
type TaskCategory ¶
type TaskCategory struct {
ID int64 `json:"id"`
Name string `json:"name"`
NKey string `json:"-"`
TaskCount int `json:"task_count"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
TaskCategory is a globally reusable task grouping label.
type TaskCreateOptions ¶
type TaskCreateOptions struct {
Name string // 可选任务名称;空=未命名
CategoryID *int64
SourceTaskIDs []int64
CompanyIDs []int64
LLMProfileIDs []int64
TimeoutSeconds int
PlanHeartbeatSeconds int
// CoverageEnabled 是「资产覆盖度功能」开关;nil=默认开(true),让不关心该开关的创建
// 路径(编排 spawn、老 API)沿用原行为。仅 web 创建任务时可显式传 false 关闭。
CoverageEnabled *bool
// InterceptRules 是任务级资产拦截规则,创建时随任务在同一事务内写入 task_intercept_rules。
InterceptRules []TaskInterceptRuleInput
}
TaskCreateOptions contains the task data that must be committed atomically with the task/exploration row.
type TaskDeletePreparation ¶
TaskDeletePreparation is produced inside the PostgreSQL deletion transaction after asset and anchor writers have been excluded. Prepare callbacks may use TrafficHosts to stage an external traffic deletion before PostgreSQL commits.
type TaskDeleteResult ¶
type TaskDeleteResult struct {
AssetsDeleted int64
AssetsDetached int64
FindingsDeleted int64
LLMRecordsDeleted int64
}
TaskDeleteResult reports optional related-data cleanup performed in the same transaction as the task/exploration delete.
type TaskEvent ¶
type TaskEvent struct {
NodeID int64 `json:"node_id"`
TaskID int64 `json:"task_id"`
TaskDesc string `json:"task_description"`
TaskGoal string `json:"task_goal"`
Summary string `json:"summary"` // finding summary / goal text
VulnClass string `json:"vulnclass"` // finding only
Severity string `json:"severity"` // finding only
Tool string `json:"tool"` // tool-call only: tool name
ToolInput string `json:"tool_input"` // tool-call only: 入参(JSON 文本)
ToolOutput string `json:"tool_output"` // tool-call only: 返回内容
ToolIsErr bool `json:"tool_is_err"` // tool-call only: 工具返回是否为错误
}
TaskEvent is a finding/goal event carrying the owning task's info, used to compose the trigger message context.
type TaskInterceptRuleInput ¶
type TaskInterceptRuleInput struct {
Enabled bool `json:"enabled"`
Action string `json:"action"`
Kind string `json:"kind"`
Pattern string `json:"pattern"`
Note string `json:"note"`
}
TaskInterceptRuleInput is one task-level rule supplied at task creation. Action: 'block'=拦截 'allow'=允许(白名单);空视为 'block'。
type TaskLLMProfile ¶
type TaskLLMProfile struct {
ProfileID int64 `json:"profile_id"`
Position int `json:"position"`
Status string `json:"status"`
LastError string `json:"last_error,omitempty"`
ExhaustedAt *time.Time `json:"exhausted_at,omitempty"`
}
TaskLLMProfile is one ordered entry in a task's explicit failover chain.
type TaskLLMTransition ¶
type TaskLLMTransition struct {
PreviousProfileID int64
NextProfileID *int64
ChainExhausted bool
Advanced bool
// Stale means the chain was replaced after the failing call selected its
// provider. The caller may retry a pre-stream request against the new chain,
// but must not report or persist a transition for this result.
Stale bool
}
TaskLLMTransition reports the shared task-level result of marking one profile quota-exhausted. NextProfileID is nil when the explicit chain is exhausted.
type TaskListMetrics ¶
type TaskListMetrics struct {
Tokens TokenUsage
LastActivity int64
Goals GoalCounts
RunningIntents int // kind='intent' 且 state='running' 的条数,即运行中 Worker 数
Findings FindingSeverityCounts // findings 表里该任务的漏洞数(按严重度分档)
}
TaskListMetrics contains the aggregates rendered in task lists.
type TaskScope ¶
type TaskScope struct {
ID int64 `json:"id"`
TaskID int64 `json:"task_id"`
Kind string `json:"kind"` // company|root_domain|subdomain|ip|cidr|icp|keyword
CompanyID *int64 `json:"company_id,omitempty"`
// CompanyName is resolved for kind=company so callers can label a scope row
// without a second lookup. Empty when the row is not a company reference.
CompanyName string `json:"company_name,omitempty"`
Domain string `json:"domain,omitempty"`
Net string `json:"net,omitempty"`
Value string `json:"value,omitempty"`
Source string `json:"source"`
Reason string `json:"reason,omitempty"`
}
TaskScope is one row of a task's test scope — the coverage denominator and the per-task authorization edge. Rows come either from insertAssets (source='auto', conservative, one per explicitly-inserted asset) or from the add_task_scope tool (source='agent', for company / domain / network / ICP / keyword scope).
type TaskSource ¶
type TaskSource struct {
TaskID int64
ExplorationID int64
Description string
Goal string
Status string
}
TaskSource identifies one directly related task and its exploration.
type TaskTemplate ¶
type TaskTemplate struct {
ID int64 `json:"id"`
Name string `json:"name"`
NKey string `json:"-"`
Description string `json:"description"`
Goal string `json:"goal"`
CategoryID *int64 `json:"category_id"`
InterceptRules []TaskInterceptRuleInput `json:"intercept_rules"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
TaskTemplate is a reusable task preset (description/goal + optional category and task-level intercept/allow rules).
type TaskTemplateInput ¶
type TaskTemplateInput struct {
Name string
Description string
Goal string
CategoryID *int64
InterceptRules []TaskInterceptRuleInput
}
TaskTemplateInput is the create/update payload after normalization.
type TaskTemplatePatch ¶
type TaskTemplatePatch struct {
Name *string
Description *string
Goal *string
CategoryID *int64
SetCategoryID bool
InterceptRules []TaskInterceptRuleInput
SetInterceptRules bool
}
TaskTemplatePatch changes only fields flagged as set. Name/Description/Goal use non-nil pointers; CategoryID/InterceptRules use explicit Set flags (so a nil CategoryID can mean "clear" when SetCategoryID is true).
type TokenUsage ¶
type TokenUsage struct {
Worker string `json:"worker"`
InputTokens int `json:"input_tokens"`
OutputTokens int `json:"output_tokens"`
CacheReadTokens int `json:"cache_read_tokens"`
CacheWriteTokens int `json:"cache_write_tokens"`
}
TokenUsage is a per-worker token aggregate (TokenStatsByWorker).
type Tool ¶
type Tool struct {
Key string `json:"key"`
System bool `json:"system"`
Description string `json:"description"`
Schema json.RawMessage `json:"schema"`
Agents []string `json:"agents"`
Enabled bool `json:"enabled"`
Kind string `json:"kind"` // builtin | command | script | http
Exec json.RawMessage `json:"exec"` // 自定义工具执行规格(kind!=builtin)
Deferred bool `json:"deferred"` // schema 延迟(走 SearchExtraTools/ExecuteExtraTool)
Calls int `json:"calls"` // runtime ledger aggregate; not stored in tools
}
Tool is one row of the built-in tool catalog. key + handler live in code; this row carries only the page-editable surface: description, parameter schema (structure read-only, per-param description/default editable), agent binding, and the on/off switch. See schema.sql §H and agent/toolcatalog.go.
type ToolStat ¶
type ToolStat struct {
Tool string `json:"tool"`
Total int `json:"total"`
Errors int `json:"errors"`
}
ToolStat is one tool's execution tally for the usage summary.
type ToolUsage ¶
type ToolUsage struct {
ToolKey string `json:"tool_key"`
AgentKey string `json:"agent_key"`
TaskID int64 `json:"task_id"`
ExplorationID int64 `json:"exploration_id"`
IntentID int64 `json:"intent_id"`
SessionID string `json:"session_id"`
}
ToolUsage is one catalog tool invocation. It stores attribution dimensions only: tool arguments and results are deliberately excluded from the ledger.
type TrafficEvidenceSnapshot ¶
type TrafficEvidenceSnapshot struct {
ID string `json:"id"`
SourceTrafficID string `json:"source_traffic_id"`
CapturedAt int64 `json:"captured_at"`
URL string `json:"url"`
Method string `json:"method"`
Status int `json:"status"`
ContentType string `json:"content_type"`
ReqHead string `json:"req_head,omitempty"`
RespHead string `json:"resp_head,omitempty"`
ReqHash string `json:"req_hash"`
RespHash string `json:"resp_hash"`
ReqLen int64 `json:"req_len"`
RespLen int64 `json:"resp_len"`
CreatedAt time.Time `json:"created_at"`
}
func ArchiveEvidenceSnapshots ¶
func ArchiveEvidenceSnapshots(snapshot *TaskArchiveSnapshot) ([]TrafficEvidenceSnapshot, error)
func (TrafficEvidenceSnapshot) Normalize ¶
func (s TrafficEvidenceSnapshot) Normalize() TrafficEvidenceSnapshot
Normalize makes the snapshot's text columns safe for PostgreSQL. URL and the head blocks come straight off the wire, so a target answering with a non-UTF-8 header (a GBK `Content-Disposition: filename=…`, a NUL byte) would otherwise abort the INSERT and roll back the whole finding — losing a confirmed finding over a malformed response header. Applied before hashing so the ID always matches the bytes that actually land in the table.
type TrafficRef ¶
type TrafficRef struct {
TrafficID string `json:"traffic_id"`
Role string `json:"role"`
Note string `json:"note"`
}
func NormalizeTrafficRefs ¶
func NormalizeTrafficRefs(refs []TrafficRef) ([]TrafficRef, error)
type UpsertAppReq ¶
type UpsertAppReq struct {
Name string
BundleID string
Category string
Description string
ICP string
CompanyID *int64 // explicit override; nil = exact ICP auto-attribution when available
TaskID int64
}
UpsertAppReq is the input for UpsertApp.
type UpsertEndpointReq ¶
type UpsertEndpointReq struct {
URL string
Method string
Params []map[string]any
IP string // optional
TaskID int64
}
UpsertEndpointReq is the input for UpsertEndpoint.
type UpsertHTTPServiceReq ¶
type UpsertHTTPServiceReq struct {
URL string
Technologies []string
StatusCode *int
ContentLength *int64
PageTitle string
FaviconMMH3 string
Auth []map[string]any
IP string // optional, from async DNS
TaskID int64
}
UpsertHTTPServiceReq is the input for UpsertHTTPService.
type UpsertIPReq ¶
type UpsertIPReq struct {
IP string
BoundDomains []string
OpenPorts []PortService
TaskID int64
}
UpsertIPReq is the input for UpsertIP.
type UpsertOtherServiceReq ¶
type UpsertOtherServiceReq struct {
Domain string // domain or ip required
IP string
Port int
ServiceName string
Auth []map[string]any
TaskID int64
}
UpsertOtherServiceReq is the input for UpsertOtherService.
type UpsertRootDomainReq ¶
UpsertRootDomainReq is the input for UpsertRootDomain.
Source Files
¶
- asset_dsl.go
- asset_intercept.go
- asset_intercept_match.go
- assets.go
- chat_mentions.go
- commands.go
- companies.go
- company_scope.go
- config.go
- constants.go
- constraints.go
- conversation.go
- db.go
- digest.go
- exploration.go
- exploration_sources.go
- finding_assets.go
- finding_retests.go
- finding_traffic.go
- finding_traffic_archive.go
- findings.go
- intent_admission.go
- intercept.go
- intercept_detail.go
- intercept_execution.go
- llm_usage.go
- llmhealth.go
- llmretry.go
- logs.go
- nkey.go
- notification.go
- notification_delivery.go
- settings.go
- side_questions.go
- skill_usage.go
- task_archive_aggregate_stats.go
- task_archives.go
- task_archives_restore.go
- task_assets.go
- task_assets_context.go
- task_categories.go
- task_context.go
- task_intercept.go
- task_scope.go
- task_templates.go
- tasks.go
- tool_usage.go
- tools.go
- triggers.go