gnosisllm-knowledge 0.2.0__py3-none-any.whl → 0.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. gnosisllm_knowledge/__init__.py +91 -39
  2. gnosisllm_knowledge/api/__init__.py +3 -2
  3. gnosisllm_knowledge/api/knowledge.py +287 -7
  4. gnosisllm_knowledge/api/memory.py +966 -0
  5. gnosisllm_knowledge/backends/__init__.py +14 -5
  6. gnosisllm_knowledge/backends/opensearch/agentic.py +341 -39
  7. gnosisllm_knowledge/backends/opensearch/config.py +49 -28
  8. gnosisllm_knowledge/backends/opensearch/indexer.py +1 -0
  9. gnosisllm_knowledge/backends/opensearch/mappings.py +2 -1
  10. gnosisllm_knowledge/backends/opensearch/memory/__init__.py +12 -0
  11. gnosisllm_knowledge/backends/opensearch/memory/client.py +1380 -0
  12. gnosisllm_knowledge/backends/opensearch/memory/config.py +127 -0
  13. gnosisllm_knowledge/backends/opensearch/memory/setup.py +322 -0
  14. gnosisllm_knowledge/backends/opensearch/searcher.py +235 -0
  15. gnosisllm_knowledge/backends/opensearch/setup.py +308 -148
  16. gnosisllm_knowledge/cli/app.py +378 -12
  17. gnosisllm_knowledge/cli/commands/agentic.py +11 -0
  18. gnosisllm_knowledge/cli/commands/memory.py +723 -0
  19. gnosisllm_knowledge/cli/commands/setup.py +24 -22
  20. gnosisllm_knowledge/cli/display/service.py +43 -0
  21. gnosisllm_knowledge/cli/utils/config.py +58 -0
  22. gnosisllm_knowledge/core/domain/__init__.py +41 -0
  23. gnosisllm_knowledge/core/domain/document.py +5 -0
  24. gnosisllm_knowledge/core/domain/memory.py +440 -0
  25. gnosisllm_knowledge/core/domain/result.py +11 -3
  26. gnosisllm_knowledge/core/domain/search.py +2 -0
  27. gnosisllm_knowledge/core/events/types.py +76 -0
  28. gnosisllm_knowledge/core/exceptions.py +134 -0
  29. gnosisllm_knowledge/core/interfaces/__init__.py +17 -0
  30. gnosisllm_knowledge/core/interfaces/memory.py +524 -0
  31. gnosisllm_knowledge/core/interfaces/streaming.py +127 -0
  32. gnosisllm_knowledge/core/streaming/__init__.py +36 -0
  33. gnosisllm_knowledge/core/streaming/pipeline.py +228 -0
  34. gnosisllm_knowledge/loaders/base.py +3 -4
  35. gnosisllm_knowledge/loaders/sitemap.py +129 -1
  36. gnosisllm_knowledge/loaders/sitemap_streaming.py +258 -0
  37. gnosisllm_knowledge/services/indexing.py +67 -75
  38. gnosisllm_knowledge/services/search.py +47 -11
  39. gnosisllm_knowledge/services/streaming_pipeline.py +302 -0
  40. {gnosisllm_knowledge-0.2.0.dist-info → gnosisllm_knowledge-0.3.0.dist-info}/METADATA +44 -1
  41. gnosisllm_knowledge-0.3.0.dist-info/RECORD +77 -0
  42. gnosisllm_knowledge-0.2.0.dist-info/RECORD +0 -64
  43. {gnosisllm_knowledge-0.2.0.dist-info → gnosisllm_knowledge-0.3.0.dist-info}/WHEEL +0 -0
  44. {gnosisllm_knowledge-0.2.0.dist-info → gnosisllm_knowledge-0.3.0.dist-info}/entry_points.txt +0 -0
@@ -63,13 +63,13 @@ def main_callback(
63
63
  @app.command()
64
64
  def setup(
65
65
  host: Annotated[
66
- str,
67
- typer.Option("--host", "-h", help="OpenSearch host."),
68
- ] = "localhost",
66
+ Optional[str],
67
+ typer.Option("--host", "-h", help="OpenSearch host (default: from OPENSEARCH_HOST env)."),
68
+ ] = None,
69
69
  port: Annotated[
70
- int,
71
- typer.Option("--port", "-p", help="OpenSearch port."),
72
- ] = 9200,
70
+ Optional[int],
71
+ typer.Option("--port", "-p", help="OpenSearch port (default: from OPENSEARCH_PORT env)."),
72
+ ] = None,
73
73
  username: Annotated[
74
74
  Optional[str],
75
75
  typer.Option("--username", "-u", help="OpenSearch username."),
@@ -79,13 +79,13 @@ def setup(
79
79
  typer.Option("--password", help="OpenSearch password."),
80
80
  ] = None,
81
81
  use_ssl: Annotated[
82
- bool,
83
- typer.Option("--use-ssl", help="Enable SSL."),
84
- ] = False,
82
+ Optional[bool],
83
+ typer.Option("--use-ssl/--no-ssl", help="Enable/disable SSL (default: from OPENSEARCH_USE_SSL env)."),
84
+ ] = None,
85
85
  verify_certs: Annotated[
86
- bool,
87
- typer.Option("--verify-certs", help="Verify SSL certificates."),
88
- ] = False,
86
+ Optional[bool],
87
+ typer.Option("--verify-certs/--no-verify-certs", help="Verify SSL certificates."),
88
+ ] = None,
89
89
  force: Annotated[
90
90
  bool,
91
91
  typer.Option("--force", "-f", help="Clean up existing resources first."),
@@ -367,6 +367,18 @@ def info() -> None:
367
367
 
368
368
  display.newline()
369
369
 
370
+ display.table(
371
+ "Agentic Memory Configuration",
372
+ [
373
+ ("LLM Model ID", config.memory_llm_model_id or "[dim]Not set[/dim]"),
374
+ ("Embedding Model ID", config.memory_embedding_model_id or "[dim]Not set[/dim]"),
375
+ ("LLM Model", config.memory_llm_model),
376
+ ("Embedding Model", config.memory_embedding_model),
377
+ ],
378
+ )
379
+
380
+ display.newline()
381
+
370
382
  display.table(
371
383
  "Content Fetching",
372
384
  [
@@ -500,6 +512,360 @@ def agentic_status() -> None:
500
512
  asyncio.run(agentic_status_command(display=display))
501
513
 
502
514
 
515
+ # ============================================================================
516
+ # MEMORY SUBCOMMAND GROUP
517
+ # ============================================================================
518
+
519
+ memory_app = typer.Typer(
520
+ name="memory",
521
+ help="Agentic Memory management commands.",
522
+ no_args_is_help=True,
523
+ rich_markup_mode="rich",
524
+ )
525
+ app.add_typer(memory_app, name="memory")
526
+
527
+ # Container sub-subcommand
528
+ container_app = typer.Typer(
529
+ name="container",
530
+ help="Memory container management.",
531
+ no_args_is_help=True,
532
+ rich_markup_mode="rich",
533
+ )
534
+ memory_app.add_typer(container_app, name="container")
535
+
536
+ # Session sub-subcommand
537
+ session_app = typer.Typer(
538
+ name="session",
539
+ help="Session management.",
540
+ no_args_is_help=True,
541
+ rich_markup_mode="rich",
542
+ )
543
+ memory_app.add_typer(session_app, name="session")
544
+
545
+
546
+ @memory_app.command("setup")
547
+ def memory_setup(
548
+ openai_key: Annotated[
549
+ Optional[str],
550
+ typer.Option("--openai-key", envvar="OPENAI_API_KEY", help="OpenAI API key for connector setup."),
551
+ ] = None,
552
+ llm_model: Annotated[
553
+ str,
554
+ typer.Option("--llm-model", help="LLM model for fact extraction."),
555
+ ] = "gpt-4o",
556
+ embedding_model: Annotated[
557
+ str,
558
+ typer.Option("--embedding-model", help="Embedding model name."),
559
+ ] = "text-embedding-3-small",
560
+ ) -> None:
561
+ """Setup OpenSearch for Agentic Memory.
562
+
563
+ Creates the required LLM and embedding connectors and models
564
+ for Agentic Memory to work.
565
+
566
+ [bold]Example:[/bold]
567
+ $ gnosisllm-knowledge memory setup --openai-key sk-...
568
+ $ gnosisllm-knowledge memory setup --llm-model gpt-4o --embedding-model text-embedding-3-small
569
+ """
570
+ from gnosisllm_knowledge.cli.commands.memory import memory_setup_command
571
+
572
+ asyncio.run(
573
+ memory_setup_command(
574
+ display=display,
575
+ openai_key=openai_key,
576
+ llm_model=llm_model,
577
+ embedding_model=embedding_model,
578
+ )
579
+ )
580
+
581
+
582
+ @memory_app.command("status")
583
+ def memory_status() -> None:
584
+ """Show memory configuration status.
585
+
586
+ Displays configured models and verifies their health.
587
+
588
+ [bold]Example:[/bold]
589
+ $ gnosisllm-knowledge memory status
590
+ """
591
+ from gnosisllm_knowledge.cli.commands.memory import memory_status_command
592
+
593
+ asyncio.run(memory_status_command(display=display))
594
+
595
+
596
+ @memory_app.command("store")
597
+ def memory_store(
598
+ container_id: Annotated[
599
+ str,
600
+ typer.Argument(help="Container ID to store messages in."),
601
+ ],
602
+ file: Annotated[
603
+ Optional[str],
604
+ typer.Option("--file", "-f", help="JSON file with messages."),
605
+ ] = None,
606
+ user_id: Annotated[
607
+ Optional[str],
608
+ typer.Option("--user-id", help="User ID for namespace."),
609
+ ] = None,
610
+ session_id: Annotated[
611
+ Optional[str],
612
+ typer.Option("--session-id", help="Session ID for namespace."),
613
+ ] = None,
614
+ infer: Annotated[
615
+ bool,
616
+ typer.Option("--infer/--no-infer", help="Enable/disable fact extraction."),
617
+ ] = True,
618
+ json_output: Annotated[
619
+ bool,
620
+ typer.Option("--json", "-j", help="Output as JSON."),
621
+ ] = False,
622
+ ) -> None:
623
+ """Store conversation in memory.
624
+
625
+ Stores messages in working memory and optionally extracts facts
626
+ to long-term memory using LLM inference.
627
+
628
+ [bold]Example:[/bold]
629
+ $ gnosisllm-knowledge memory store <container-id> -f messages.json --user-id alice
630
+ $ gnosisllm-knowledge memory store <container-id> -f messages.json --no-infer
631
+ """
632
+ from gnosisllm_knowledge.cli.commands.memory import memory_store_command
633
+
634
+ asyncio.run(
635
+ memory_store_command(
636
+ display=display,
637
+ container_id=container_id,
638
+ file=file,
639
+ user_id=user_id,
640
+ session_id=session_id,
641
+ infer=infer,
642
+ json_output=json_output,
643
+ )
644
+ )
645
+
646
+
647
+ @memory_app.command("recall")
648
+ def memory_recall(
649
+ container_id: Annotated[
650
+ str,
651
+ typer.Argument(help="Container ID to search."),
652
+ ],
653
+ query: Annotated[
654
+ str,
655
+ typer.Argument(help="Search query text."),
656
+ ],
657
+ user_id: Annotated[
658
+ Optional[str],
659
+ typer.Option("--user-id", help="Filter by user ID."),
660
+ ] = None,
661
+ session_id: Annotated[
662
+ Optional[str],
663
+ typer.Option("--session-id", help="Filter by session ID."),
664
+ ] = None,
665
+ limit: Annotated[
666
+ int,
667
+ typer.Option("--limit", "-n", help="Maximum results."),
668
+ ] = 10,
669
+ json_output: Annotated[
670
+ bool,
671
+ typer.Option("--json", "-j", help="Output as JSON."),
672
+ ] = False,
673
+ ) -> None:
674
+ """Search long-term memory.
675
+
676
+ Performs semantic search over extracted facts and memories.
677
+
678
+ [bold]Example:[/bold]
679
+ $ gnosisllm-knowledge memory recall <container-id> "user preferences" --user-id alice
680
+ $ gnosisllm-knowledge memory recall <container-id> "food preferences" --limit 5 --json
681
+ """
682
+ from gnosisllm_knowledge.cli.commands.memory import memory_recall_command
683
+
684
+ asyncio.run(
685
+ memory_recall_command(
686
+ display=display,
687
+ container_id=container_id,
688
+ query=query,
689
+ user_id=user_id,
690
+ session_id=session_id,
691
+ limit=limit,
692
+ json_output=json_output,
693
+ )
694
+ )
695
+
696
+
697
+ @memory_app.command("stats")
698
+ def memory_stats(
699
+ container_id: Annotated[
700
+ str,
701
+ typer.Argument(help="Container ID."),
702
+ ],
703
+ json_output: Annotated[
704
+ bool,
705
+ typer.Option("--json", "-j", help="Output as JSON."),
706
+ ] = False,
707
+ ) -> None:
708
+ """Show container statistics.
709
+
710
+ Displays memory counts, session count, and strategy breakdown.
711
+
712
+ [bold]Example:[/bold]
713
+ $ gnosisllm-knowledge memory stats <container-id>
714
+ $ gnosisllm-knowledge memory stats <container-id> --json
715
+ """
716
+ from gnosisllm_knowledge.cli.commands.memory import memory_stats_command
717
+
718
+ asyncio.run(
719
+ memory_stats_command(
720
+ display=display,
721
+ container_id=container_id,
722
+ json_output=json_output,
723
+ )
724
+ )
725
+
726
+
727
+ # === Container Commands ===
728
+
729
+
730
+ @container_app.command("create")
731
+ def container_create(
732
+ name: Annotated[
733
+ str,
734
+ typer.Argument(help="Container name."),
735
+ ],
736
+ description: Annotated[
737
+ Optional[str],
738
+ typer.Option("--description", "-d", help="Container description."),
739
+ ] = None,
740
+ config_file: Annotated[
741
+ Optional[str],
742
+ typer.Option("--config", "-c", help="JSON file with strategy configuration."),
743
+ ] = None,
744
+ ) -> None:
745
+ """Create a new memory container.
746
+
747
+ Containers hold memories with configurable extraction strategies.
748
+ Each strategy is scoped to namespace fields for partitioning.
749
+
750
+ [bold]Example config.json:[/bold]
751
+ {
752
+ "strategies": [
753
+ {"type": "SEMANTIC", "namespace": ["user_id"]},
754
+ {"type": "USER_PREFERENCE", "namespace": ["user_id"]},
755
+ {"type": "SUMMARY", "namespace": ["session_id"]}
756
+ ]
757
+ }
758
+
759
+ [bold]Example:[/bold]
760
+ $ gnosisllm-knowledge memory container create my-memory
761
+ $ gnosisllm-knowledge memory container create agent-memory -c config.json
762
+ """
763
+ from gnosisllm_knowledge.cli.commands.memory import container_create_command
764
+
765
+ asyncio.run(
766
+ container_create_command(
767
+ display=display,
768
+ name=name,
769
+ description=description,
770
+ config_file=config_file,
771
+ )
772
+ )
773
+
774
+
775
+ @container_app.command("list")
776
+ def container_list(
777
+ json_output: Annotated[
778
+ bool,
779
+ typer.Option("--json", "-j", help="Output as JSON."),
780
+ ] = False,
781
+ ) -> None:
782
+ """List all memory containers.
783
+
784
+ [bold]Example:[/bold]
785
+ $ gnosisllm-knowledge memory container list
786
+ $ gnosisllm-knowledge memory container list --json
787
+ """
788
+ from gnosisllm_knowledge.cli.commands.memory import container_list_command
789
+
790
+ asyncio.run(
791
+ container_list_command(
792
+ display=display,
793
+ json_output=json_output,
794
+ )
795
+ )
796
+
797
+
798
+ @container_app.command("delete")
799
+ def container_delete(
800
+ container_id: Annotated[
801
+ str,
802
+ typer.Argument(help="Container ID to delete."),
803
+ ],
804
+ force: Annotated[
805
+ bool,
806
+ typer.Option("--force", "-f", help="Skip confirmation prompt."),
807
+ ] = False,
808
+ ) -> None:
809
+ """Delete a memory container.
810
+
811
+ This permanently deletes the container and all its memories.
812
+
813
+ [bold]Example:[/bold]
814
+ $ gnosisllm-knowledge memory container delete <container-id>
815
+ $ gnosisllm-knowledge memory container delete <container-id> --force
816
+ """
817
+ from gnosisllm_knowledge.cli.commands.memory import container_delete_command
818
+
819
+ asyncio.run(
820
+ container_delete_command(
821
+ display=display,
822
+ container_id=container_id,
823
+ force=force,
824
+ )
825
+ )
826
+
827
+
828
+ # === Session Commands ===
829
+
830
+
831
+ @session_app.command("list")
832
+ def session_list(
833
+ container_id: Annotated[
834
+ str,
835
+ typer.Argument(help="Container ID."),
836
+ ],
837
+ user_id: Annotated[
838
+ Optional[str],
839
+ typer.Option("--user-id", help="Filter by user ID."),
840
+ ] = None,
841
+ limit: Annotated[
842
+ int,
843
+ typer.Option("--limit", "-n", help="Maximum sessions."),
844
+ ] = 20,
845
+ json_output: Annotated[
846
+ bool,
847
+ typer.Option("--json", "-j", help="Output as JSON."),
848
+ ] = False,
849
+ ) -> None:
850
+ """List sessions in a container.
851
+
852
+ [bold]Example:[/bold]
853
+ $ gnosisllm-knowledge memory session list <container-id>
854
+ $ gnosisllm-knowledge memory session list <container-id> --user-id alice
855
+ """
856
+ from gnosisllm_knowledge.cli.commands.memory import session_list_command
857
+
858
+ asyncio.run(
859
+ session_list_command(
860
+ display=display,
861
+ container_id=container_id,
862
+ user_id=user_id,
863
+ limit=limit,
864
+ json_output=json_output,
865
+ )
866
+ )
867
+
868
+
503
869
  def main() -> None:
504
870
  """CLI entry point."""
505
871
  app()
@@ -105,6 +105,17 @@ async def agentic_setup_command(
105
105
  if agent_type in ("conversational", "all"):
106
106
  agent_types_to_setup.append("conversational")
107
107
 
108
+ # If force, cleanup existing agents first
109
+ if force:
110
+ display.info("Force mode: cleaning up existing agents...")
111
+ try:
112
+ cleanup_result = await adapter.cleanup_agents()
113
+ for step in cleanup_result.steps_completed:
114
+ display.success(step)
115
+ except Exception as e:
116
+ display.warning(f"Cleanup warning (continuing): {e}")
117
+ display.newline()
118
+
108
119
  # Build step list
109
120
  steps = []
110
121
  if "flow" in agent_types_to_setup: