305 lines
15 KiB
Go
305 lines
15 KiB
Go
package model
|
|
|
|
import "time"
|
|
|
|
type LinkedItem struct {
|
|
ItemType string `json:"item_type"`
|
|
ID int64 `json:"id"`
|
|
Name string `json:"name,omitempty"`
|
|
}
|
|
|
|
type Ticket struct {
|
|
ID int64 `json:"id"`
|
|
Name string `json:"name"`
|
|
Content string `json:"content"`
|
|
DateMod string `json:"date_mod"`
|
|
StatusID int64 `json:"status_id"`
|
|
CategoryID int64 `json:"category_id"`
|
|
RequesterIDs []int64 `json:"requester_ids,omitempty"`
|
|
Items []LinkedItem `json:"items,omitempty"`
|
|
}
|
|
|
|
type Followup struct {
|
|
ID int64 `json:"id"`
|
|
Content string `json:"content"`
|
|
IsPrivate bool `json:"is_private"`
|
|
UserID int64 `json:"user_id"`
|
|
Date string `json:"date"`
|
|
}
|
|
|
|
type Category struct {
|
|
ID int64 `json:"id"`
|
|
Name string `json:"name"`
|
|
CompleteName string `json:"completename"`
|
|
// KnowbaseCategoryID is the GLPI knowledge-base category associated with
|
|
// this ITIL category, when the installed GLPI exposes that relation.
|
|
KnowbaseCategoryID int64 `json:"knowbase_category_id,omitempty"`
|
|
Hints []string `json:"hints,omitempty"`
|
|
Examples []string `json:"confirmed_examples,omitempty"`
|
|
}
|
|
|
|
type LearningExample struct {
|
|
ID string `json:"id"`
|
|
RunID string `json:"run_id,omitempty"`
|
|
TicketID int64 `json:"ticket_id,omitempty"`
|
|
Subject string `json:"subject"`
|
|
Text string `json:"text"`
|
|
CategoryID int64 `json:"category_id"`
|
|
CategoryName string `json:"category_name"`
|
|
AIRecommendedCategoryID int64 `json:"ai_recommended_category_id,omitempty"`
|
|
AIConfidence float64 `json:"ai_confidence,omitempty"`
|
|
Correction bool `json:"correction"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
Source string `json:"source"`
|
|
}
|
|
|
|
type KnowledgeDoc struct {
|
|
ID string `json:"id"`
|
|
Title string `json:"title"`
|
|
Text string `json:"text"`
|
|
Answer string `json:"answer"`
|
|
// AnswerHTML contains trusted rich text from a synchronized GLPI KB item.
|
|
// It is never sent to the LLM or used for embeddings.
|
|
AnswerHTML string `json:"answer_html,omitempty"`
|
|
AutoReply bool `json:"auto_reply"`
|
|
MinScore float64 `json:"min_score"`
|
|
Categories []int64 `json:"categories"`
|
|
Keywords []string `json:"keywords"`
|
|
Source string `json:"source"`
|
|
SourceURI string `json:"source_uri,omitempty"`
|
|
SourceCategoryIDs []int64 `json:"source_category_ids,omitempty"`
|
|
SourceModifiedAt string `json:"source_modified_at,omitempty"`
|
|
Language string `json:"language"`
|
|
CommunicationStyle string `json:"communication_style"`
|
|
}
|
|
|
|
// GLPIKnowledgeItem is the normalized read-only representation returned by
|
|
// the GLPI connector before it is converted into a KnowledgeDoc.
|
|
type GLPIKnowledgeItem struct {
|
|
ID int64 `json:"id"`
|
|
Title string `json:"title"`
|
|
Content string `json:"content"`
|
|
CategoryIDs []int64 `json:"category_ids,omitempty"`
|
|
Language string `json:"language,omitempty"`
|
|
ModifiedAt string `json:"modified_at,omitempty"`
|
|
}
|
|
|
|
type KnowledgeHit struct {
|
|
Doc KnowledgeDoc `json:"doc"`
|
|
Score float64 `json:"score"`
|
|
SemanticScore float64 `json:"semantic_score,omitempty"`
|
|
TitleScore float64 `json:"title_score,omitempty"`
|
|
LexicalScore float64 `json:"lexical_score,omitempty"`
|
|
KeywordScore float64 `json:"keyword_score,omitempty"`
|
|
CategoryScore float64 `json:"category_score,omitempty"`
|
|
BestChunkExcerpt string `json:"best_chunk_excerpt,omitempty"`
|
|
BestQueryExcerpt string `json:"best_query_excerpt,omitempty"`
|
|
QueryChunkCount int `json:"query_chunk_count,omitempty"`
|
|
DocumentChunkCount int `json:"document_chunk_count,omitempty"`
|
|
}
|
|
|
|
// ChangeContext is a normalized, read-only view of a GLPI Change. Only fields
|
|
// useful for ticket triage are passed to the model.
|
|
type ChangeContext struct {
|
|
ID int64 `json:"id"`
|
|
Name string `json:"name"`
|
|
Content string `json:"content,omitempty"`
|
|
StatusID int64 `json:"status_id,omitempty"`
|
|
CategoryID int64 `json:"category_id,omitempty"`
|
|
PlannedBegin string `json:"planned_begin,omitempty"`
|
|
PlannedEnd string `json:"planned_end,omitempty"`
|
|
DateMod string `json:"date_mod,omitempty"`
|
|
Relevance float64 `json:"relevance"`
|
|
Source string `json:"source"`
|
|
}
|
|
|
|
type MajorIncidentContext struct {
|
|
ID int64 `json:"id"`
|
|
Name string `json:"name"`
|
|
Content string `json:"content,omitempty"`
|
|
StatusID int64 `json:"status_id,omitempty"`
|
|
CategoryID int64 `json:"category_id,omitempty"`
|
|
Priority int64 `json:"priority,omitempty"`
|
|
Impact int64 `json:"impact,omitempty"`
|
|
Urgency int64 `json:"urgency,omitempty"`
|
|
DateMod string `json:"date_mod,omitempty"`
|
|
Relevance float64 `json:"relevance"`
|
|
Source string `json:"source"`
|
|
}
|
|
|
|
type ServiceIssueContext struct {
|
|
Source string `json:"source"`
|
|
StatusPage string `json:"status_page"`
|
|
Kind string `json:"kind"` // monitor | pinned_incident | maintenance
|
|
MonitorID int64 `json:"monitor_id,omitempty"`
|
|
MonitorName string `json:"monitor_name,omitempty"`
|
|
Status string `json:"status"`
|
|
Message string `json:"message,omitempty"`
|
|
LastHeartbeat string `json:"last_heartbeat,omitempty"`
|
|
Uptime24h float64 `json:"uptime_24h,omitempty"`
|
|
IncidentTitle string `json:"incident_title,omitempty"`
|
|
IncidentContent string `json:"incident_content,omitempty"`
|
|
Relevance float64 `json:"relevance"`
|
|
}
|
|
|
|
type UserDeviceContext struct {
|
|
UserID int64 `json:"user_id,omitempty"`
|
|
ItemType string `json:"item_type"`
|
|
ID int64 `json:"id"`
|
|
Name string `json:"name,omitempty"`
|
|
Serial string `json:"serial,omitempty"`
|
|
InventoryNumber string `json:"inventory_number,omitempty"`
|
|
Status string `json:"status,omitempty"`
|
|
Location string `json:"location,omitempty"`
|
|
LastInventoryDate string `json:"last_inventory_date,omitempty"`
|
|
Source string `json:"source"`
|
|
}
|
|
|
|
type ContextSnapshot struct {
|
|
FetchedAt time.Time `json:"fetched_at"`
|
|
Changes []ChangeContext `json:"changes,omitempty"`
|
|
MajorIncidents []MajorIncidentContext `json:"major_incidents,omitempty"`
|
|
ServiceIssues []ServiceIssueContext `json:"service_issues,omitempty"`
|
|
UserDevices []UserDeviceContext `json:"user_devices,omitempty"`
|
|
Warnings []string `json:"warnings,omitempty"`
|
|
Incomplete bool `json:"incomplete"`
|
|
}
|
|
|
|
func (c ContextSnapshot) HasRelevantIncident(minScore float64) bool {
|
|
for _, incident := range c.MajorIncidents {
|
|
if incident.Relevance >= minScore {
|
|
return true
|
|
}
|
|
}
|
|
for _, issue := range c.ServiceIssues {
|
|
if issue.Relevance >= minScore && (issue.Status == "down" || issue.Status == "pending" || issue.Kind == "pinned_incident") {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
type Decision struct {
|
|
Category struct {
|
|
ID int64 `json:"id"`
|
|
Confidence float64 `json:"confidence"`
|
|
} `json:"category"`
|
|
Reply struct {
|
|
Allowed bool `json:"allowed"`
|
|
Confidence float64 `json:"confidence"`
|
|
KnowledgeID string `json:"knowledge_id"`
|
|
} `json:"reply"`
|
|
Reason string `json:"reason"`
|
|
}
|
|
|
|
type PolicyResult struct {
|
|
ChangeCategory bool `json:"change_category"`
|
|
CategoryID int64 `json:"category_id"`
|
|
CategoryRecommendationID int64 `json:"category_recommendation_id"`
|
|
CategoryRecommendationName string `json:"category_recommendation_name,omitempty"`
|
|
CategoryConfidence float64 `json:"category_confidence"`
|
|
CategoryThreshold float64 `json:"category_threshold"`
|
|
CategoryDecision string `json:"category_decision"`
|
|
Reply bool `json:"reply"`
|
|
ReplyText string `json:"reply_text,omitempty"`
|
|
ReplyIsHTML bool `json:"reply_is_html,omitempty"`
|
|
KnowledgeID string `json:"knowledge_id,omitempty"`
|
|
ReplyRecommendation bool `json:"reply_recommendation"`
|
|
ReplyConfidence float64 `json:"reply_confidence"`
|
|
ReplyThreshold float64 `json:"reply_threshold"`
|
|
ReplyKnowledgeID string `json:"reply_knowledge_id,omitempty"`
|
|
ReplyDecision string `json:"reply_decision"`
|
|
KnowledgeThreshold float64 `json:"knowledge_threshold,omitempty"`
|
|
KnowledgeRetrievalScore float64 `json:"knowledge_retrieval_score,omitempty"`
|
|
KnowledgeEvidenceScore float64 `json:"knowledge_evidence_score,omitempty"`
|
|
KnowledgeRetrievalFloor float64 `json:"knowledge_retrieval_floor,omitempty"`
|
|
KnowledgeCategoryAligned bool `json:"knowledge_category_aligned,omitempty"`
|
|
AIReason string `json:"ai_reason,omitempty"`
|
|
}
|
|
|
|
// KnowledgeCandidateAudit captures the top retrieval candidates used for a run.
|
|
// It intentionally stores only normalized, non-secret diagnostic information.
|
|
type KnowledgeCandidateAudit struct {
|
|
ID string `json:"id"`
|
|
Title string `json:"title"`
|
|
Source string `json:"source"`
|
|
Score float64 `json:"score"`
|
|
SemanticScore float64 `json:"semantic_score,omitempty"`
|
|
TitleScore float64 `json:"title_score,omitempty"`
|
|
LexicalScore float64 `json:"lexical_score,omitempty"`
|
|
KeywordScore float64 `json:"keyword_score,omitempty"`
|
|
CategoryScore float64 `json:"category_score,omitempty"`
|
|
RequiredScore float64 `json:"required_score,omitempty"`
|
|
AutoReply bool `json:"auto_reply"`
|
|
BestChunkExcerpt string `json:"best_chunk_excerpt,omitempty"`
|
|
BestQueryExcerpt string `json:"best_query_excerpt,omitempty"`
|
|
QueryChunkCount int `json:"query_chunk_count,omitempty"`
|
|
DocumentChunkCount int `json:"document_chunk_count,omitempty"`
|
|
}
|
|
|
|
// ContextAuditItem is a compact snapshot of context that influenced a run.
|
|
type ContextAuditItem struct {
|
|
Kind string `json:"kind"`
|
|
ID int64 `json:"id,omitempty"`
|
|
Name string `json:"name"`
|
|
Status string `json:"status,omitempty"`
|
|
Relevance float64 `json:"relevance,omitempty"`
|
|
Detail string `json:"detail,omitempty"`
|
|
}
|
|
|
|
type RunRecord struct {
|
|
RunID string `json:"run_id"`
|
|
TicketID int64 `json:"ticket_id"`
|
|
TicketName string `json:"ticket_name"`
|
|
SourceVersion string `json:"source_version"`
|
|
StartedAt time.Time `json:"started_at"`
|
|
FinishedAt time.Time `json:"finished_at"`
|
|
Outcome string `json:"outcome"`
|
|
Reason string `json:"reason"`
|
|
AIReason string `json:"ai_reason,omitempty"`
|
|
PolicyReason string `json:"policy_reason,omitempty"`
|
|
CategoryBefore int64 `json:"category_before"`
|
|
CategoryBeforeName string `json:"category_before_name,omitempty"`
|
|
AIRecommendedCategoryID int64 `json:"ai_recommended_category_id,omitempty"`
|
|
AIRecommendedCategoryName string `json:"ai_recommended_category_name,omitempty"`
|
|
AICategoryConfidence float64 `json:"ai_category_confidence,omitempty"`
|
|
CategoryThreshold float64 `json:"category_threshold,omitempty"`
|
|
CategoryDecision string `json:"category_decision,omitempty"`
|
|
CategoryProposed int64 `json:"category_proposed"`
|
|
CategoryWouldChange bool `json:"category_would_change"`
|
|
CategoryChanged bool `json:"category_changed"`
|
|
AIReplyRecommended bool `json:"ai_reply_recommended,omitempty"`
|
|
AIReplyConfidence float64 `json:"ai_reply_confidence,omitempty"`
|
|
ReplyThreshold float64 `json:"reply_threshold,omitempty"`
|
|
AIKnowledgeID string `json:"ai_knowledge_id,omitempty"`
|
|
ReplyDecision string `json:"reply_decision,omitempty"`
|
|
ReplyProposed bool `json:"reply_proposed"`
|
|
ReplyWritten bool `json:"reply_written"`
|
|
KnowledgeID string `json:"knowledge_id,omitempty"`
|
|
KnowledgeTopID string `json:"knowledge_top_id,omitempty"`
|
|
KnowledgeTopTitle string `json:"knowledge_top_title,omitempty"`
|
|
KnowledgeScore float64 `json:"knowledge_score,omitempty"`
|
|
KnowledgeSemanticScore float64 `json:"knowledge_semantic_score,omitempty"`
|
|
KnowledgeTitleScore float64 `json:"knowledge_title_score,omitempty"`
|
|
KnowledgeLexicalScore float64 `json:"knowledge_lexical_score,omitempty"`
|
|
KnowledgeKeywordScore float64 `json:"knowledge_keyword_score,omitempty"`
|
|
KnowledgeCategoryScore float64 `json:"knowledge_category_score,omitempty"`
|
|
KnowledgeThreshold float64 `json:"knowledge_threshold,omitempty"`
|
|
KnowledgeEvidenceScore float64 `json:"knowledge_evidence_score,omitempty"`
|
|
KnowledgeRetrievalFloor float64 `json:"knowledge_retrieval_floor,omitempty"`
|
|
KnowledgeCategoryAligned bool `json:"knowledge_category_aligned,omitempty"`
|
|
KnowledgeBestChunk string `json:"knowledge_best_chunk,omitempty"`
|
|
KnowledgeBestQueryChunk string `json:"knowledge_best_query_chunk,omitempty"`
|
|
KnowledgeQueryChunks int `json:"knowledge_query_chunks,omitempty"`
|
|
KnowledgeDocumentChunks int `json:"knowledge_document_chunks,omitempty"`
|
|
ContextChanges int `json:"context_changes,omitempty"`
|
|
ContextIncidents int `json:"context_incidents,omitempty"`
|
|
ContextIssues int `json:"context_issues,omitempty"`
|
|
ContextDevices int `json:"context_devices,omitempty"`
|
|
ContextWarnings []string `json:"context_warnings,omitempty"`
|
|
KnowledgeCandidates []KnowledgeCandidateAudit `json:"knowledge_candidates,omitempty"`
|
|
ContextDetails []ContextAuditItem `json:"context_details,omitempty"`
|
|
DryRun bool `json:"dry_run"`
|
|
Error string `json:"error,omitempty"`
|
|
}
|