update-1.6.2a
ci / docker-build (push) Failing after 25s
ci / test (services/control) (push) Successful in 50s
ci / test (services/knowledge) (push) Successful in 52s
ci / test (platform/neuroforge) (push) Successful in 56s
ci / test (services/agent) (push) Successful in 1m1s
release-tag / release-image (push) Successful in 6m47s
ci / docker-build (push) Failing after 25s
ci / test (services/control) (push) Successful in 50s
ci / test (services/knowledge) (push) Successful in 52s
ci / test (platform/neuroforge) (push) Successful in 56s
ci / test (services/agent) (push) Successful in 1m1s
release-tag / release-image (push) Successful in 6m47s
This commit is contained in:
@@ -1293,7 +1293,7 @@ func (s *Service) RecordCategoryFeedback(ctx context.Context, runID string, cate
|
||||
}
|
||||
func (s *Service) LearningExamples() []model.LearningExample {
|
||||
if s.learning == nil {
|
||||
return nil
|
||||
return []model.LearningExample{}
|
||||
}
|
||||
return s.learning.List()
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@ type Client struct {
|
||||
tokenExpiry time.Time
|
||||
}
|
||||
|
||||
const maxGLPIResponseBytes = 32 << 20
|
||||
|
||||
func New(baseURL, version, clientID, clientSecret, username, password string, timeout time.Duration) *Client {
|
||||
return &Client{baseURL: strings.TrimRight(baseURL, "/"), version: version, clientID: clientID, clientSecret: clientSecret, username: username, password: password, http: &http.Client{Timeout: timeout}}
|
||||
}
|
||||
@@ -104,7 +106,7 @@ func (c *Client) do(ctx context.Context, method, path string, query url.Values,
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
b, _ := io.ReadAll(io.LimitReader(resp.Body, 4<<20))
|
||||
b, _ := io.ReadAll(io.LimitReader(resp.Body, maxGLPIResponseBytes))
|
||||
resp.Body.Close()
|
||||
if resp.StatusCode == http.StatusUnauthorized && attempt == 0 {
|
||||
continue
|
||||
@@ -426,70 +428,99 @@ func (c *Client) DiscoverKnowledgeBasePath(ctx context.Context, configured strin
|
||||
}
|
||||
return candidates[i].score > candidates[j].score
|
||||
})
|
||||
path := candidates[0].path
|
||||
// The OpenAPI document may include /api.php/vX.Y in documented paths while
|
||||
// c.do already prepends the configured API base. Keep only the route suffix.
|
||||
if i := strings.Index(path, "/api.php/"); i >= 0 {
|
||||
rest := path[i+len("/api.php/"):]
|
||||
if slash := strings.Index(rest, "/"); slash >= 0 {
|
||||
path = rest[slash:]
|
||||
}
|
||||
}
|
||||
versionPrefix := "/" + strings.Trim(c.version, "/")
|
||||
if strings.HasPrefix(path, versionPrefix+"/") {
|
||||
path = strings.TrimPrefix(path, versionPrefix)
|
||||
}
|
||||
if !strings.HasPrefix(path, "/") {
|
||||
path = "/" + path
|
||||
}
|
||||
return path, nil
|
||||
return normalizeDocumentedAPIPath(candidates[0].path, c.version), nil
|
||||
}
|
||||
|
||||
// ListKnowledgeBaseItems reads only items visible to the authenticated GLPI
|
||||
// service account. Visibility is therefore enforced by GLPI itself; an
|
||||
// optional filter can further restrict the collection on a per-instance basis.
|
||||
func (c *Client) ListKnowledgeBaseItems(ctx context.Context, path string, limit int, filter string) ([]model.GLPIKnowledgeItem, error) {
|
||||
q := url.Values{"limit": {strconv.Itoa(limit)}, "sort": {"date_mod"}, "order": {"DESC"}}
|
||||
if strings.TrimSpace(filter) != "" {
|
||||
q.Set("filter", filter)
|
||||
if limit <= 0 {
|
||||
return []model.GLPIKnowledgeItem{}, nil
|
||||
}
|
||||
b, _, err := c.do(ctx, http.MethodGet, path, q, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
arr, err := extractArray(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out := make([]model.GLPIKnowledgeItem, 0, len(arr))
|
||||
for _, r := range arr {
|
||||
id := int64Val(r["id"])
|
||||
if id <= 0 {
|
||||
continue
|
||||
const pageSize = 100
|
||||
out := make([]model.GLPIKnowledgeItem, 0, limit)
|
||||
seen := make(map[int64]struct{}, limit)
|
||||
start := 0
|
||||
for len(out) < limit {
|
||||
requestLimit := pageSize
|
||||
if remaining := limit - len(out); remaining < requestLimit {
|
||||
requestLimit = remaining
|
||||
}
|
||||
if firstString(r, "answer", "content", "text", "description") == "" {
|
||||
if detail, _, e := c.do(ctx, http.MethodGet, strings.TrimRight(path, "/")+"/"+strconv.FormatInt(id, 10), nil, nil); e == nil {
|
||||
q := url.Values{
|
||||
"start": {strconv.Itoa(start)},
|
||||
"limit": {strconv.Itoa(requestLimit)},
|
||||
"sort": {"date_mod"},
|
||||
"order": {"DESC"},
|
||||
}
|
||||
if strings.TrimSpace(filter) != "" {
|
||||
q.Set("filter", filter)
|
||||
}
|
||||
b, headers, err := c.do(ctx, http.MethodGet, path, q, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
arr, err := extractArray(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(arr) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
newIDs := 0
|
||||
for _, r := range arr {
|
||||
id := int64Val(r["id"])
|
||||
if id <= 0 {
|
||||
continue
|
||||
}
|
||||
if _, duplicate := seen[id]; duplicate {
|
||||
continue
|
||||
}
|
||||
seen[id] = struct{}{}
|
||||
newIDs++
|
||||
if firstString(r, "answer", "content", "text", "description") == "" {
|
||||
detail, _, detailErr := c.do(ctx, http.MethodGet, strings.TrimRight(path, "/")+"/"+strconv.FormatInt(id, 10), nil, nil)
|
||||
if detailErr != nil {
|
||||
return nil, fmt.Errorf("fetch GLPI knowledge item %d detail: %w", id, detailErr)
|
||||
}
|
||||
var full map[string]any
|
||||
if json.Unmarshal(detail, &full) == nil {
|
||||
for k, v := range full {
|
||||
r[k] = v
|
||||
}
|
||||
if err := json.Unmarshal(detail, &full); err != nil {
|
||||
return nil, fmt.Errorf("decode GLPI knowledge item %d detail: %w", id, err)
|
||||
}
|
||||
for k, v := range full {
|
||||
r[k] = v
|
||||
}
|
||||
}
|
||||
title := firstString(r, "name", "title", "subject")
|
||||
content := firstString(r, "answer", "content", "text", "description")
|
||||
if title == "" || content == "" {
|
||||
continue
|
||||
}
|
||||
out = append(out, model.GLPIKnowledgeItem{
|
||||
ID: id,
|
||||
Title: title,
|
||||
Content: content,
|
||||
CategoryIDs: knowledgeCategoryIDs(r),
|
||||
Language: firstString(r, "language", "locale"),
|
||||
ModifiedAt: firstString(r, "date_mod", "modified_at", "date_creation"),
|
||||
})
|
||||
if len(out) >= limit {
|
||||
break
|
||||
}
|
||||
}
|
||||
title := firstString(r, "name", "title", "subject")
|
||||
content := firstString(r, "answer", "content", "text", "description")
|
||||
if title == "" || content == "" {
|
||||
continue
|
||||
pageStart := start
|
||||
start += len(arr)
|
||||
moreKnown, hasMore := collectionHasMore(b, headers, pageStart, len(arr))
|
||||
if len(arr) < requestLimit && (!moreKnown || !hasMore) {
|
||||
break
|
||||
}
|
||||
out = append(out, model.GLPIKnowledgeItem{
|
||||
ID: id,
|
||||
Title: title,
|
||||
Content: content,
|
||||
CategoryIDs: knowledgeCategoryIDs(r),
|
||||
Language: firstString(r, "language", "locale"),
|
||||
ModifiedAt: firstString(r, "date_mod", "modified_at", "date_creation"),
|
||||
})
|
||||
if newIDs == 0 {
|
||||
return nil, fmt.Errorf("GLPI knowledge pagination made no progress at start=%d; server may be ignoring the start parameter", pageStart)
|
||||
}
|
||||
}
|
||||
if len(seen) > 0 && len(out) == 0 {
|
||||
return nil, fmt.Errorf("GLPI returned %d knowledge records but none contained a usable title and article body", len(seen))
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
@@ -543,23 +574,7 @@ func (c *Client) ListKnowledgeBaseLinkedItems(ctx context.Context, articleIDs []
|
||||
return candidates[i].score > candidates[j].score
|
||||
})
|
||||
chosen := candidates[0]
|
||||
cleanPath := func(p string) string {
|
||||
if i := strings.Index(p, "/api.php/"); i >= 0 {
|
||||
rest := p[i+len("/api.php/"):]
|
||||
if slash := strings.Index(rest, "/"); slash >= 0 {
|
||||
p = rest[slash:]
|
||||
}
|
||||
}
|
||||
versionPrefix := "/" + strings.Trim(c.version, "/")
|
||||
if strings.HasPrefix(p, versionPrefix+"/") {
|
||||
p = strings.TrimPrefix(p, versionPrefix)
|
||||
}
|
||||
if !strings.HasPrefix(p, "/") {
|
||||
p = "/" + p
|
||||
}
|
||||
return p
|
||||
}
|
||||
chosen.path = cleanPath(chosen.path)
|
||||
chosen.path = normalizeDocumentedAPIPath(chosen.path, c.version)
|
||||
if limit <= 0 {
|
||||
limit = 10000
|
||||
}
|
||||
@@ -690,6 +705,50 @@ func extractArray(b []byte) ([]map[string]any, error) {
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected GLPI collection response: %.200s", string(b))
|
||||
}
|
||||
|
||||
func collectionHasMore(body []byte, headers http.Header, start, count int) (known bool, more bool) {
|
||||
if raw := strings.TrimSpace(headers.Get("Content-Range")); raw != "" {
|
||||
if slash := strings.LastIndex(raw, "/"); slash >= 0 && slash+1 < len(raw) {
|
||||
totalText := strings.TrimSpace(raw[slash+1:])
|
||||
if totalText != "*" {
|
||||
if total, err := strconv.Atoi(totalText); err == nil && total >= 0 {
|
||||
return true, start+count < total
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var obj map[string]any
|
||||
if json.Unmarshal(body, &obj) == nil {
|
||||
for _, key := range []string{"total", "totalcount", "total_count"} {
|
||||
if total := int(int64Val(obj[key])); total > 0 {
|
||||
return true, start+count < total
|
||||
}
|
||||
}
|
||||
}
|
||||
return false, false
|
||||
}
|
||||
|
||||
var documentedVersionPrefix = regexp.MustCompile(`^/v[0-9]+(?:\.[0-9]+){0,2}/`)
|
||||
|
||||
func normalizeDocumentedAPIPath(path, configuredVersion string) string {
|
||||
path = strings.TrimSpace(path)
|
||||
if i := strings.Index(path, "/api.php/"); i >= 0 {
|
||||
rest := path[i+len("/api.php/"):]
|
||||
if slash := strings.Index(rest, "/"); slash >= 0 {
|
||||
path = rest[slash:]
|
||||
}
|
||||
}
|
||||
versionPrefix := "/" + strings.Trim(configuredVersion, "/")
|
||||
if strings.HasPrefix(path, versionPrefix+"/") {
|
||||
path = strings.TrimPrefix(path, versionPrefix)
|
||||
} else if documentedVersionPrefix.MatchString(path) {
|
||||
path = documentedVersionPrefix.ReplaceAllString(path, "/")
|
||||
}
|
||||
if !strings.HasPrefix(path, "/") {
|
||||
path = "/" + path
|
||||
}
|
||||
return path
|
||||
}
|
||||
func decodeTicket(r map[string]any) model.Ticket {
|
||||
t := model.Ticket{
|
||||
ID: int64Val(r["id"]),
|
||||
|
||||
@@ -3,8 +3,11 @@ package glpi
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -91,6 +94,142 @@ func TestDiscoverAndListKnowledgeBase(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDiscoverKnowledgeBaseStripsPatchVersionPrefix(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.URL.Path {
|
||||
case "/api.php/token":
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{"access_token": "x", "expires_in": 3600})
|
||||
case "/api.php/doc.json":
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{"paths": map[string]any{
|
||||
"/v2.3.0/Knowledge/KnowbaseItem": map[string]any{"get": map[string]any{}},
|
||||
}})
|
||||
default:
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
}))
|
||||
defer srv.Close()
|
||||
c := New(srv.URL, "v2.3", "cid", "sec", "u", "p", time.Second)
|
||||
path, err := c.DiscoverKnowledgeBasePath(context.Background(), "auto")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if path != "/Knowledge/KnowbaseItem" {
|
||||
t.Fatalf("path=%q, want /Knowledge/KnowbaseItem", path)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListKnowledgeBasePaginatesLargeCollections(t *testing.T) {
|
||||
const total = 235
|
||||
var starts []int
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.URL.Path {
|
||||
case "/api.php/token":
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{"access_token": "x", "expires_in": 3600})
|
||||
case "/api.php/v2.3/Knowledge/KnowbaseItem":
|
||||
start, _ := strconv.Atoi(r.URL.Query().Get("start"))
|
||||
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
|
||||
starts = append(starts, start)
|
||||
if limit <= 0 || limit > 100 {
|
||||
t.Fatalf("unexpected page limit %d", limit)
|
||||
}
|
||||
end := start + limit
|
||||
if end > total {
|
||||
end = total
|
||||
}
|
||||
rows := make([]map[string]any, 0, max(0, end-start))
|
||||
for i := start; i < end; i++ {
|
||||
rows = append(rows, map[string]any{
|
||||
"id": i + 1, "name": fmt.Sprintf("Artikel %d", i+1), "answer": "Inhalt", "date_mod": "2026-09-09 10:00:00",
|
||||
})
|
||||
}
|
||||
_ = json.NewEncoder(w).Encode(rows)
|
||||
default:
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
}))
|
||||
defer srv.Close()
|
||||
c := New(srv.URL, "v2.3", "cid", "sec", "u", "p", time.Second)
|
||||
items, err := c.ListKnowledgeBaseItems(context.Background(), "/Knowledge/KnowbaseItem", total, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(items) != total {
|
||||
t.Fatalf("items=%d, want %d", len(items), total)
|
||||
}
|
||||
wantStarts := []int{0, 100, 200}
|
||||
if !reflect.DeepEqual(starts, wantStarts) {
|
||||
t.Fatalf("starts=%v, want %v", starts, wantStarts)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListKnowledgeBaseContinuesWhenServerCapsPageSize(t *testing.T) {
|
||||
const total = 121
|
||||
const serverCap = 37
|
||||
var starts []int
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.URL.Path {
|
||||
case "/api.php/token":
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{"access_token": "x", "expires_in": 3600})
|
||||
case "/api.php/v2.3/Knowledge/KnowbaseItem":
|
||||
start, _ := strconv.Atoi(r.URL.Query().Get("start"))
|
||||
requested, _ := strconv.Atoi(r.URL.Query().Get("limit"))
|
||||
starts = append(starts, start)
|
||||
pageLimit := requested
|
||||
if pageLimit > serverCap {
|
||||
pageLimit = serverCap
|
||||
}
|
||||
end := start + pageLimit
|
||||
if end > total {
|
||||
end = total
|
||||
}
|
||||
rows := make([]map[string]any, 0, max(0, end-start))
|
||||
for i := start; i < end; i++ {
|
||||
rows = append(rows, map[string]any{"id": i + 1, "name": fmt.Sprintf("Artikel %d", i+1), "answer": "Inhalt"})
|
||||
}
|
||||
if len(rows) > 0 {
|
||||
w.Header().Set("Content-Range", fmt.Sprintf("items %d-%d/%d", start, end-1, total))
|
||||
}
|
||||
_ = json.NewEncoder(w).Encode(rows)
|
||||
default:
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
}))
|
||||
defer srv.Close()
|
||||
c := New(srv.URL, "v2.3", "cid", "sec", "u", "p", time.Second)
|
||||
items, err := c.ListKnowledgeBaseItems(context.Background(), "/Knowledge/KnowbaseItem", total, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(items) != total {
|
||||
t.Fatalf("items=%d, want %d", len(items), total)
|
||||
}
|
||||
wantStarts := []int{0, 37, 74, 111}
|
||||
if !reflect.DeepEqual(starts, wantStarts) {
|
||||
t.Fatalf("starts=%v, want %v", starts, wantStarts)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListKnowledgeBaseFailsWhenRequiredDetailCannotBeRead(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.URL.Path {
|
||||
case "/api.php/token":
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{"access_token": "x", "expires_in": 3600})
|
||||
case "/api.php/v2.3/Knowledge/KnowbaseItem":
|
||||
_ = json.NewEncoder(w).Encode([]map[string]any{{"id": 7, "name": "Konto gesperrt"}})
|
||||
case "/api.php/v2.3/Knowledge/KnowbaseItem/7":
|
||||
http.Error(w, "missing right", http.StatusForbidden)
|
||||
default:
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
}))
|
||||
defer srv.Close()
|
||||
c := New(srv.URL, "v2.3", "cid", "sec", "u", "p", time.Second)
|
||||
_, err := c.ListKnowledgeBaseItems(context.Background(), "/Knowledge/KnowbaseItem", 50, "")
|
||||
if err == nil || !strings.Contains(err.Error(), "knowledge item 7 detail") {
|
||||
t.Fatalf("expected explicit detail-read error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddFollowupPreservesRichHTML(t *testing.T) {
|
||||
var gotContent string
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@@ -98,11 +98,11 @@ func (s *Store) Delete(id string) error {
|
||||
|
||||
func (s *Store) List() []model.LearningExample {
|
||||
if s == nil {
|
||||
return nil
|
||||
return []model.LearningExample{}
|
||||
}
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
out := append([]model.LearningExample(nil), s.examples...)
|
||||
out := append([]model.LearningExample{}, s.examples...)
|
||||
sort.SliceStable(out, func(i, j int) bool { return out[i].CreatedAt.After(out[j].CreatedAt) })
|
||||
return out
|
||||
}
|
||||
|
||||
@@ -28,3 +28,17 @@ func TestAddReplaceAndDelete(t *testing.T) {
|
||||
t.Fatal("old replaced id should not exist")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmptyListIsNonNil(t *testing.T) {
|
||||
s, err := Open(t.TempDir(), 10)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rows := s.List()
|
||||
if rows == nil {
|
||||
t.Fatal("empty learning list must serialize as [] instead of null")
|
||||
}
|
||||
if len(rows) != 0 {
|
||||
t.Fatalf("rows=%d, want 0", len(rows))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -640,7 +640,11 @@ func (s *Server) knowledgeDelete(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
func (s *Server) learningList(w http.ResponseWriter, r *http.Request) {
|
||||
respondJSON(w, s.feedback.LearningExamples())
|
||||
rows := s.feedback.LearningExamples()
|
||||
if rows == nil {
|
||||
rows = []model.LearningExample{}
|
||||
}
|
||||
respondJSON(w, rows)
|
||||
}
|
||||
func (s *Server) learningAdd(w http.ResponseWriter, r *http.Request) {
|
||||
if !s.cfg.LearningEnabled {
|
||||
|
||||
@@ -51,6 +51,18 @@ func TestDashboardTemplateParses(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestLearningListSerializesEmptyArray(t *testing.T) {
|
||||
h, _ := newKnowledgeTestServer(t)
|
||||
rr := httptest.NewRecorder()
|
||||
h.ServeHTTP(rr, httptest.NewRequest(http.MethodGet, "/api/learning", nil))
|
||||
if rr.Code != http.StatusOK {
|
||||
t.Fatalf("learning list = %d: %s", rr.Code, rr.Body.String())
|
||||
}
|
||||
if got := strings.TrimSpace(rr.Body.String()); got != "[]" {
|
||||
t.Fatalf("learning list body=%q, want []", got)
|
||||
}
|
||||
}
|
||||
|
||||
type fakeFeedback struct {
|
||||
cats []model.Category
|
||||
outcomeRows []model.ValidatedOutcomeEvidence
|
||||
|
||||
@@ -107,6 +107,7 @@ const esc=s=>String(s??'').replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'&
|
||||
const pct=v=>`${Math.round(Number(v||0)*100)} %`; const fmtNum=v=>new Intl.NumberFormat('de-DE').format(Number(v||0));
|
||||
const fmtDate=v=>{if(!v)return '–';const d=new Date(v);return Number.isNaN(d.getTime())?'–':d.toLocaleString('de-DE')};
|
||||
const clamp=v=>Math.max(0,Math.min(1,Number(v||0))); const scoreClass=v=>Number(v)>=.8?'good':Number(v)>=.6?'warn':'bad';
|
||||
const asArray=v=>Array.isArray(v)?v:[];
|
||||
let statusData={},runsData=[],categories=[],kbDocs=[],learningRows=[],outcomeRows=[],currentRun=null,currentKbId='',currentLearnRun='',kbCategorySelection=new Set();
|
||||
const viewMeta={overview:['Übersicht','Gesundheit, Verarbeitung und die wichtigsten Stellschrauben auf einen Blick.'],runs:['Verarbeitungen','Audit-Trail mit KI-, Policy-, RAG- und Kontextdetails.'],knowledge:['Knowledge Base','Interne und synchronisierte Wissensquellen verwalten und kontrollieren.'],learning:['Bestätigtes Lernen','Menschlich bestätigte Beispiele, die die Kategorisierung schrittweise verbessern.'],settings:['Effektive Konfiguration','Alle nicht-geheimen Laufzeitwerte zum Tuning und Troubleshooting.']};
|
||||
function toast(text,kind='good'){const n=document.createElement('div');n.className=`toast ${kind}`;n.textContent=text;$('#toasts').appendChild(n);setTimeout(()=>n.remove(),5000)}
|
||||
@@ -164,11 +165,11 @@ async function deleteLearning(id){if(!confirm('Lernbeispiel wirklich löschen?')
|
||||
async function recordOutcome(runID,decision){const r=runsData.find(x=>x.run_id===runID);if(!r)return;let corrected='';if(decision==='corrected'){corrected=prompt('Korrigierte, fachlich bestätigte Antwort:',r.reply_proposed_text||'')||'';if(!corrected.trim())return}const note=prompt('Optionaler Prüfvermerk / Grund (kann leer bleiben):','')||'';if(!confirm(decision==='accepted'?'Diese KI-Antwort als technisch bestätigt lernen?':'Diese korrigierte Antwort als technisch bestätigt lernen?'))return;try{await api('/api/outcomes',{method:'POST',body:JSON.stringify({run_id:runID,decision,corrected_reply:corrected,note})});toast('Bestätigtes Ticket-Outcome wurde an NeuroForge übergeben.');await loadOutcomes();await loadRuns();const fresh=runsData.find(x=>x.run_id===runID);if(fresh)renderRunDrawer(fresh)}catch(e){toast(e.message,'error')}}
|
||||
async function reprocessTicket(){const id=Number($('#reprocessTicketID').value||0);if(!Number.isInteger(id)||id<=0){toast('Bitte eine gültige Ticket-ID eingeben.','error');return}const live=!statusData.dry_run;if(live&&!confirm(`Ticket #${id} im LIVE-Modus neu analysieren? Konfigurierte Auto-Aktionen können ausgeführt werden.`))return;const b=$('#reprocessTicketBtn');b.disabled=true;try{await api(`/api/tickets/${id}/reprocess`,{method:'POST',body:'{}'});toast(`Ticket #${id} wurde zur Neuanalyse eingereiht.`);setTimeout(()=>refreshAll(),800)}catch(e){toast(e.message,'error')}finally{b.disabled=false}}
|
||||
async function loadStatus(){statusData=await api('/api/status');renderStatusChrome();renderOverview();renderConfig();renderSourceOptions()}
|
||||
async function loadRuns(){const limit=Number($('#runLimit').value||50);runsData=await api(`/api/runs?limit=${limit}`);renderRuns();renderOverview()}
|
||||
async function loadKnowledge(){kbDocs=await api('/api/knowledge');renderSourceOptions();renderKB();renderOverview()}
|
||||
async function loadLearning(){learningRows=await api('/api/learning');renderLearning();renderOverview()}
|
||||
async function loadOutcomes(){outcomeRows=await api('/api/outcomes')}
|
||||
async function loadCategories(){categories=await api('/api/categories');renderCategoryPicker($('#kbCategorySearch').value||'')}
|
||||
async function loadRuns(){const limit=Number($('#runLimit').value||50);runsData=asArray(await api(`/api/runs?limit=${limit}`));renderRuns();renderOverview()}
|
||||
async function loadKnowledge(){kbDocs=asArray(await api('/api/knowledge'));renderSourceOptions();renderKB();renderOverview()}
|
||||
async function loadLearning(){learningRows=asArray(await api('/api/learning'));renderLearning();renderOverview()}
|
||||
async function loadOutcomes(){outcomeRows=asArray(await api('/api/outcomes'))}
|
||||
async function loadCategories(){categories=asArray(await api('/api/categories'));renderCategoryPicker($('#kbCategorySearch').value||'')}
|
||||
async function refreshAll(showToast=false){$('#refreshBtn').disabled=true;try{await Promise.all([loadStatus(),loadRuns(),loadKnowledge(),loadLearning(),loadOutcomes(),loadCategories()]);renderSourceOptions();renderOverview();renderRuns();renderKB();renderLearning();renderConfig();if(showToast)toast('Dashboard aktualisiert.')}catch(e){toast(e.message,'error')}finally{$('#refreshBtn').disabled=false;$('#lastRefresh').textContent=new Date().toLocaleTimeString('de-DE')}}
|
||||
|
||||
$('#nav').addEventListener('click',e=>{const b=e.target.closest('[data-view]');if(b)setView(b.dataset.view)});document.addEventListener('click',e=>{const g=e.target.closest('[data-goto]');if(g)setView(g.dataset.goto);const row=e.target.closest('[data-run-id]');if(row){const x=runsData.find(r=>r.run_id===row.dataset.runId);if(x)renderRunDrawer(x)}const ed=e.target.closest('[data-kb-edit]');if(ed)editKB(ed.dataset.kbEdit);const del=e.target.closest('[data-kb-delete]');if(del)deleteKB(del.dataset.kbDelete);const ld=e.target.closest('[data-learning-delete]');if(ld)deleteLearning(ld.dataset.learningDelete);const lr=e.target.closest('[data-learn-run]');if(lr)openLearn(lr.dataset.learnRun,Number(lr.dataset.learnCat||0));const oa=e.target.closest('[data-outcome-accept]');if(oa)recordOutcome(oa.dataset.outcomeAccept,'accepted');const oc=e.target.closest('[data-outcome-correct]');if(oc)recordOutcome(oc.dataset.outcomeCorrect,'corrected')});
|
||||
|
||||
@@ -2836,7 +2836,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": true,
|
||||
"line": 35,
|
||||
"line": 37,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -2848,7 +2848,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": true,
|
||||
"line": 314,
|
||||
"line": 316,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -2860,7 +2860,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": true,
|
||||
"line": 310,
|
||||
"line": 312,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -2872,7 +2872,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": true,
|
||||
"line": 373,
|
||||
"line": 375,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -2884,7 +2884,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": true,
|
||||
"line": 124,
|
||||
"line": 126,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -2896,7 +2896,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": true,
|
||||
"line": 354,
|
||||
"line": 356,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -2908,7 +2908,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": true,
|
||||
"line": 238,
|
||||
"line": 240,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -2920,7 +2920,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": true,
|
||||
"line": 227,
|
||||
"line": 229,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -2932,7 +2932,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": true,
|
||||
"line": 327,
|
||||
"line": 329,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -2944,7 +2944,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": true,
|
||||
"line": 949,
|
||||
"line": 1008,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -2956,7 +2956,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": true,
|
||||
"line": 207,
|
||||
"line": 209,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -2968,7 +2968,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": true,
|
||||
"line": 451,
|
||||
"line": 437,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -2980,7 +2980,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": true,
|
||||
"line": 501,
|
||||
"line": 532,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -2992,7 +2992,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": true,
|
||||
"line": 979,
|
||||
"line": 1038,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -3004,7 +3004,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": true,
|
||||
"line": 187,
|
||||
"line": 189,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -3016,7 +3016,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": true,
|
||||
"line": 1013,
|
||||
"line": 1072,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -3028,7 +3028,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": true,
|
||||
"line": 120,
|
||||
"line": 122,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -3040,7 +3040,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": true,
|
||||
"line": 262,
|
||||
"line": 264,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -3052,7 +3052,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": true,
|
||||
"line": 266,
|
||||
"line": 268,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -3064,7 +3064,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": true,
|
||||
"line": 253,
|
||||
"line": 255,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -3076,7 +3076,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": true,
|
||||
"line": 257,
|
||||
"line": 259,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -3088,7 +3088,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": true,
|
||||
"line": 146,
|
||||
"line": 148,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -3100,7 +3100,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": true,
|
||||
"line": 925,
|
||||
"line": 984,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -3112,7 +3112,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 318,
|
||||
"line": 320,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -3124,7 +3124,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 36,
|
||||
"line": 38,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -3136,7 +3136,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 76,
|
||||
"line": 78,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -3148,7 +3148,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 270,
|
||||
"line": 272,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -3160,7 +3160,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": true,
|
||||
"line": 31,
|
||||
"line": 33,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -3172,7 +3172,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 792,
|
||||
"line": 851,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -3184,7 +3184,19 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 910,
|
||||
"line": 969,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "function:github.com/example/glpi-ai-agent/internal/glpi:collectionHasMore",
|
||||
"kind": "function",
|
||||
"label": "collectionHasMore",
|
||||
"group": "engineering",
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 709,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -3196,7 +3208,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 865,
|
||||
"line": 924,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -3208,7 +3220,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 693,
|
||||
"line": 752,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -3220,7 +3232,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 716,
|
||||
"line": 775,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -3232,7 +3244,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 677,
|
||||
"line": 692,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -3244,7 +3256,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 812,
|
||||
"line": 871,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -3256,7 +3268,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 762,
|
||||
"line": 821,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -3268,7 +3280,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 629,
|
||||
"line": 644,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -3280,7 +3292,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 868,
|
||||
"line": 927,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -3292,7 +3304,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 1054,
|
||||
"line": 1113,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -3304,7 +3316,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 884,
|
||||
"line": 943,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -3316,7 +3328,19 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 638,
|
||||
"line": 653,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "function:github.com/example/glpi-ai-agent/internal/glpi:normalizeDocumentedAPIPath",
|
||||
"kind": "function",
|
||||
"label": "normalizeDocumentedAPIPath",
|
||||
"group": "engineering",
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 733,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -3328,7 +3352,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 175,
|
||||
"line": 177,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -3340,7 +3364,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 878,
|
||||
"line": 937,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -3352,7 +3376,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 1066,
|
||||
"line": 1125,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -3364,7 +3388,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 901,
|
||||
"line": 960,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -3376,7 +3400,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/glpi",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 294,
|
||||
"line": 296,
|
||||
"path": "services/agent/internal/glpi/client.go"
|
||||
}
|
||||
},
|
||||
@@ -6748,7 +6772,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/web",
|
||||
"meta": {
|
||||
"exported": true,
|
||||
"line": 867,
|
||||
"line": 871,
|
||||
"path": "services/agent/internal/web/server.go"
|
||||
}
|
||||
},
|
||||
@@ -6784,7 +6808,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/web",
|
||||
"meta": {
|
||||
"exported": true,
|
||||
"line": 870,
|
||||
"line": 874,
|
||||
"path": "services/agent/internal/web/server.go"
|
||||
}
|
||||
},
|
||||
@@ -6796,7 +6820,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/web",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 835,
|
||||
"line": 839,
|
||||
"path": "services/agent/internal/web/server.go"
|
||||
}
|
||||
},
|
||||
@@ -7072,7 +7096,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/web",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 645,
|
||||
"line": 649,
|
||||
"path": "services/agent/internal/web/server.go"
|
||||
}
|
||||
},
|
||||
@@ -7084,7 +7108,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/web",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 665,
|
||||
"line": 669,
|
||||
"path": "services/agent/internal/web/server.go"
|
||||
}
|
||||
},
|
||||
@@ -7108,7 +7132,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/web",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 706,
|
||||
"line": 710,
|
||||
"path": "services/agent/internal/web/server.go"
|
||||
}
|
||||
},
|
||||
@@ -7120,7 +7144,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/web",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 679,
|
||||
"line": 683,
|
||||
"path": "services/agent/internal/web/server.go"
|
||||
}
|
||||
},
|
||||
@@ -7132,7 +7156,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/web",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 676,
|
||||
"line": 680,
|
||||
"path": "services/agent/internal/web/server.go"
|
||||
}
|
||||
},
|
||||
@@ -7156,7 +7180,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/web",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 884,
|
||||
"line": 888,
|
||||
"path": "services/agent/internal/web/server.go"
|
||||
}
|
||||
},
|
||||
@@ -7180,7 +7204,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/web",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 720,
|
||||
"line": 724,
|
||||
"path": "services/agent/internal/web/server.go"
|
||||
}
|
||||
},
|
||||
@@ -7228,7 +7252,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/web",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 740,
|
||||
"line": 744,
|
||||
"path": "services/agent/internal/web/server.go"
|
||||
}
|
||||
},
|
||||
@@ -7324,7 +7348,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/web",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 768,
|
||||
"line": 772,
|
||||
"path": "services/agent/internal/web/server.go"
|
||||
}
|
||||
},
|
||||
@@ -7336,7 +7360,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/web",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 819,
|
||||
"line": 823,
|
||||
"path": "services/agent/internal/web/server.go"
|
||||
}
|
||||
},
|
||||
@@ -7360,7 +7384,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/web",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 858,
|
||||
"line": 862,
|
||||
"path": "services/agent/internal/web/server.go"
|
||||
}
|
||||
},
|
||||
@@ -7372,7 +7396,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/web",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 829,
|
||||
"line": 833,
|
||||
"path": "services/agent/internal/web/server.go"
|
||||
}
|
||||
},
|
||||
@@ -7384,7 +7408,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/web",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 830,
|
||||
"line": 834,
|
||||
"path": "services/agent/internal/web/server.go"
|
||||
}
|
||||
},
|
||||
@@ -7396,7 +7420,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/web",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 849,
|
||||
"line": 853,
|
||||
"path": "services/agent/internal/web/server.go"
|
||||
}
|
||||
},
|
||||
@@ -7408,7 +7432,7 @@
|
||||
"community": "github.com/example/glpi-ai-agent/internal/web",
|
||||
"meta": {
|
||||
"exported": false,
|
||||
"line": 781,
|
||||
"line": 785,
|
||||
"path": "services/agent/internal/web/server.go"
|
||||
}
|
||||
},
|
||||
@@ -30669,6 +30693,12 @@
|
||||
"to": "function:github.com/example/glpi-ai-agent/internal/glpi:boolVal",
|
||||
"kind": "defines"
|
||||
},
|
||||
{
|
||||
"id": "file:services/agent/internal/glpi/client.go-\u003efunction:github.com/example/glpi-ai-agent/internal/glpi:collectionHasMore:defines",
|
||||
"from": "file:services/agent/internal/glpi/client.go",
|
||||
"to": "function:github.com/example/glpi-ai-agent/internal/glpi:collectionHasMore",
|
||||
"kind": "defines"
|
||||
},
|
||||
{
|
||||
"id": "file:services/agent/internal/glpi/client.go-\u003efunction:github.com/example/glpi-ai-agent/internal/glpi:decodeFollowup:defines",
|
||||
"from": "file:services/agent/internal/glpi/client.go",
|
||||
@@ -30735,6 +30765,12 @@
|
||||
"to": "function:github.com/example/glpi-ai-agent/internal/glpi:knowledgeCategoryIDs",
|
||||
"kind": "defines"
|
||||
},
|
||||
{
|
||||
"id": "file:services/agent/internal/glpi/client.go-\u003efunction:github.com/example/glpi-ai-agent/internal/glpi:normalizeDocumentedAPIPath:defines",
|
||||
"from": "file:services/agent/internal/glpi/client.go",
|
||||
"to": "function:github.com/example/glpi-ai-agent/internal/glpi:normalizeDocumentedAPIPath",
|
||||
"kind": "defines"
|
||||
},
|
||||
{
|
||||
"id": "file:services/agent/internal/glpi/client.go-\u003efunction:github.com/example/glpi-ai-agent/internal/glpi:openAPIOperations:defines",
|
||||
"from": "file:services/agent/internal/glpi/client.go",
|
||||
@@ -38779,6 +38815,12 @@
|
||||
"to": "function:github.com/example/glpi-ai-agent/internal/glpi:New",
|
||||
"kind": "calls"
|
||||
},
|
||||
{
|
||||
"id": "function:github.com/example/glpi-ai-agent/internal/glpi:Client.DiscoverKnowledgeBasePath-\u003efunction:github.com/example/glpi-ai-agent/internal/glpi:normalizeDocumentedAPIPath:calls",
|
||||
"from": "function:github.com/example/glpi-ai-agent/internal/glpi:Client.DiscoverKnowledgeBasePath",
|
||||
"to": "function:github.com/example/glpi-ai-agent/internal/glpi:normalizeDocumentedAPIPath",
|
||||
"kind": "calls"
|
||||
},
|
||||
{
|
||||
"id": "function:github.com/example/glpi-ai-agent/internal/glpi:Client.DiscoverKnowledgeBasePath-\u003epackage:fmt:calls_package",
|
||||
"from": "function:github.com/example/glpi-ai-agent/internal/glpi:Client.DiscoverKnowledgeBasePath",
|
||||
@@ -39043,6 +39085,12 @@
|
||||
"to": "function:github.com/example/glpi-ai-agent/internal/glpi:Client.do",
|
||||
"kind": "calls"
|
||||
},
|
||||
{
|
||||
"id": "function:github.com/example/glpi-ai-agent/internal/glpi:Client.ListKnowledgeBaseItems-\u003efunction:github.com/example/glpi-ai-agent/internal/glpi:collectionHasMore:calls",
|
||||
"from": "function:github.com/example/glpi-ai-agent/internal/glpi:Client.ListKnowledgeBaseItems",
|
||||
"to": "function:github.com/example/glpi-ai-agent/internal/glpi:collectionHasMore",
|
||||
"kind": "calls"
|
||||
},
|
||||
{
|
||||
"id": "function:github.com/example/glpi-ai-agent/internal/glpi:Client.ListKnowledgeBaseItems-\u003efunction:github.com/example/glpi-ai-agent/internal/glpi:extractArray:calls",
|
||||
"from": "function:github.com/example/glpi-ai-agent/internal/glpi:Client.ListKnowledgeBaseItems",
|
||||
@@ -39074,6 +39122,13 @@
|
||||
"kind": "calls_package",
|
||||
"label": "Unmarshal"
|
||||
},
|
||||
{
|
||||
"id": "function:github.com/example/glpi-ai-agent/internal/glpi:Client.ListKnowledgeBaseItems-\u003epackage:fmt:calls_package",
|
||||
"from": "function:github.com/example/glpi-ai-agent/internal/glpi:Client.ListKnowledgeBaseItems",
|
||||
"to": "package:fmt",
|
||||
"kind": "calls_package",
|
||||
"label": "Errorf"
|
||||
},
|
||||
{
|
||||
"id": "function:github.com/example/glpi-ai-agent/internal/glpi:Client.ListKnowledgeBaseItems-\u003epackage:strconv:calls_package",
|
||||
"from": "function:github.com/example/glpi-ai-agent/internal/glpi:Client.ListKnowledgeBaseItems",
|
||||
@@ -39124,6 +39179,12 @@
|
||||
"to": "function:github.com/example/glpi-ai-agent/internal/glpi:firstString",
|
||||
"kind": "calls"
|
||||
},
|
||||
{
|
||||
"id": "function:github.com/example/glpi-ai-agent/internal/glpi:Client.ListKnowledgeBaseLinkedItems-\u003efunction:github.com/example/glpi-ai-agent/internal/glpi:normalizeDocumentedAPIPath:calls",
|
||||
"from": "function:github.com/example/glpi-ai-agent/internal/glpi:Client.ListKnowledgeBaseLinkedItems",
|
||||
"to": "function:github.com/example/glpi-ai-agent/internal/glpi:normalizeDocumentedAPIPath",
|
||||
"kind": "calls"
|
||||
},
|
||||
{
|
||||
"id": "function:github.com/example/glpi-ai-agent/internal/glpi:Client.ListKnowledgeBaseLinkedItems-\u003epackage:fmt:calls_package",
|
||||
"from": "function:github.com/example/glpi-ai-agent/internal/glpi:Client.ListKnowledgeBaseLinkedItems",
|
||||
@@ -39605,6 +39666,33 @@
|
||||
"kind": "calls_package",
|
||||
"label": "EqualFold"
|
||||
},
|
||||
{
|
||||
"id": "function:github.com/example/glpi-ai-agent/internal/glpi:collectionHasMore-\u003efunction:github.com/example/glpi-ai-agent/internal/glpi:int64Val:calls",
|
||||
"from": "function:github.com/example/glpi-ai-agent/internal/glpi:collectionHasMore",
|
||||
"to": "function:github.com/example/glpi-ai-agent/internal/glpi:int64Val",
|
||||
"kind": "calls"
|
||||
},
|
||||
{
|
||||
"id": "function:github.com/example/glpi-ai-agent/internal/glpi:collectionHasMore-\u003epackage:encoding/json:calls_package",
|
||||
"from": "function:github.com/example/glpi-ai-agent/internal/glpi:collectionHasMore",
|
||||
"to": "package:encoding/json",
|
||||
"kind": "calls_package",
|
||||
"label": "Unmarshal"
|
||||
},
|
||||
{
|
||||
"id": "function:github.com/example/glpi-ai-agent/internal/glpi:collectionHasMore-\u003epackage:strconv:calls_package",
|
||||
"from": "function:github.com/example/glpi-ai-agent/internal/glpi:collectionHasMore",
|
||||
"to": "package:strconv",
|
||||
"kind": "calls_package",
|
||||
"label": "Atoi"
|
||||
},
|
||||
{
|
||||
"id": "function:github.com/example/glpi-ai-agent/internal/glpi:collectionHasMore-\u003epackage:strings:calls_package",
|
||||
"from": "function:github.com/example/glpi-ai-agent/internal/glpi:collectionHasMore",
|
||||
"to": "package:strings",
|
||||
"kind": "calls_package",
|
||||
"label": "TrimSpace"
|
||||
},
|
||||
{
|
||||
"id": "function:github.com/example/glpi-ai-agent/internal/glpi:decodeFollowup-\u003efunction:github.com/example/glpi-ai-agent/internal/glpi:boolVal:calls",
|
||||
"from": "function:github.com/example/glpi-ai-agent/internal/glpi:decodeFollowup",
|
||||
@@ -39813,6 +39901,13 @@
|
||||
"kind": "calls_package",
|
||||
"label": "Slice"
|
||||
},
|
||||
{
|
||||
"id": "function:github.com/example/glpi-ai-agent/internal/glpi:normalizeDocumentedAPIPath-\u003epackage:strings:calls_package",
|
||||
"from": "function:github.com/example/glpi-ai-agent/internal/glpi:normalizeDocumentedAPIPath",
|
||||
"to": "package:strings",
|
||||
"kind": "calls_package",
|
||||
"label": "TrimSpace"
|
||||
},
|
||||
{
|
||||
"id": "function:github.com/example/glpi-ai-agent/internal/glpi:openAPIOperations-\u003epackage:strings:calls_package",
|
||||
"from": "function:github.com/example/glpi-ai-agent/internal/glpi:openAPIOperations",
|
||||
@@ -66907,10 +67002,10 @@
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"edges": 7278,
|
||||
"edges": 7289,
|
||||
"format_version": 1,
|
||||
"generator": "go-ast+compose",
|
||||
"modules": 4,
|
||||
"nodes": 1846
|
||||
"nodes": 1848
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user