@@ -466,10 +466,11 @@ func (s *AgentPoolService) Chat(name, message string) (string, error) {
466466 s .collectAndCopyMetadata (metadata , chatUserID )
467467 }
468468
469+ content := s .appendLocalAGIKBCitations (response .Response , name , message , response .State )
469470 msg := map [string ]any {
470471 "id" : messageID + "-agent" ,
471472 "sender" : "agent" ,
472- "content" : response . Response ,
473+ "content" : content ,
473474 "timestamp" : time .Now ().Format (time .RFC3339 ),
474475 }
475476 if len (metadata ) > 0 {
@@ -489,6 +490,79 @@ func (s *AgentPoolService) Chat(name, message string) (string, error) {
489490 return messageID , nil
490491}
491492
493+ func (s * AgentPoolService ) appendLocalAGIKBCitations (response , agentKey , message string , states []coreTypes.ActionState ) string {
494+ if strings .TrimSpace (response ) == "" {
495+ return response
496+ }
497+
498+ userID , collection := splitAgentKey (agentKey )
499+ cfg := s .localAGI .pool .GetConfig (agentKey )
500+ if cfg == nil || ! cfg .EnableKnowledgeBase {
501+ return response
502+ }
503+
504+ citations := kbCitationsFromActionStates (states )
505+ if len (citations ) == 0 && cfg .KBAutoSearch {
506+ maxResults := cfg .KnowledgeBaseResults
507+ if maxResults <= 0 {
508+ maxResults = 5
509+ }
510+ ctx , cancel := context .WithTimeout (context .Background (), 30 * time .Second )
511+ defer cancel ()
512+ kbResult := agents .KBAutoSearchPrompt (ctx , s .apiURL , s .apiKey , collection , message , maxResults , userID )
513+ citations = kbResult .Citations
514+ }
515+
516+ return agents .AppendKBCitations (response , collection , userID , citations )
517+ }
518+
519+ func splitAgentKey (agentKey string ) (userID , name string ) {
520+ if uid , n , ok := strings .Cut (agentKey , ":" ); ok {
521+ return uid , n
522+ }
523+ return "" , agentKey
524+ }
525+
526+ func kbCitationsFromActionStates (states []coreTypes.ActionState ) []agents.KBCitation {
527+ var citations []agents.KBCitation
528+ for _ , state := range states {
529+ citations = append (citations , kbCitationsFromMetadata (state .Metadata )... )
530+ }
531+ return citations
532+ }
533+
534+ func kbCitationsFromMetadata (metadata map [string ]any ) []agents.KBCitation {
535+ if len (metadata ) == 0 {
536+ return nil
537+ }
538+
539+ fileName := metadata ["file_name" ]
540+ source := metadata ["source" ]
541+ if fileName == nil && source == nil {
542+ return nil
543+ }
544+
545+ citation := agents.KBCitation {
546+ FileName : metadataString (fileName ),
547+ EntryKey : metadataString (source ),
548+ }
549+ if citation .FileName == "" && citation .EntryKey == "" {
550+ return nil
551+ }
552+ return []agents.KBCitation {citation }
553+ }
554+
555+ func metadataString (value any ) string {
556+ switch v := value .(type ) {
557+ case string :
558+ return v
559+ case fmt.Stringer :
560+ return v .String ()
561+ default :
562+ return ""
563+ }
564+ }
565+
492566// userOutputsDir returns the per-user outputs directory, creating it if needed.
493567// If userID is empty, falls back to the shared outputs directory.
494568func (s * AgentPoolService ) userOutputsDir (userID string ) string {
0 commit comments