h2ogpte 1.6.42__py3-none-any.whl → 1.6.43__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 (107) hide show
  1. h2ogpte/__init__.py +1 -1
  2. h2ogpte/cli/__init__.py +0 -0
  3. h2ogpte/cli/commands/__init__.py +0 -0
  4. h2ogpte/cli/commands/command_handlers/__init__.py +0 -0
  5. h2ogpte/cli/commands/command_handlers/agent.py +41 -0
  6. h2ogpte/cli/commands/command_handlers/chat.py +37 -0
  7. h2ogpte/cli/commands/command_handlers/clear.py +8 -0
  8. h2ogpte/cli/commands/command_handlers/collection.py +67 -0
  9. h2ogpte/cli/commands/command_handlers/config.py +113 -0
  10. h2ogpte/cli/commands/command_handlers/disconnect.py +36 -0
  11. h2ogpte/cli/commands/command_handlers/exit.py +37 -0
  12. h2ogpte/cli/commands/command_handlers/help.py +8 -0
  13. h2ogpte/cli/commands/command_handlers/history.py +29 -0
  14. h2ogpte/cli/commands/command_handlers/rag.py +146 -0
  15. h2ogpte/cli/commands/command_handlers/research_agent.py +45 -0
  16. h2ogpte/cli/commands/command_handlers/session.py +77 -0
  17. h2ogpte/cli/commands/command_handlers/status.py +33 -0
  18. h2ogpte/cli/commands/dispatcher.py +79 -0
  19. h2ogpte/cli/core/__init__.py +0 -0
  20. h2ogpte/cli/core/app.py +105 -0
  21. h2ogpte/cli/core/config.py +199 -0
  22. h2ogpte/cli/core/encryption.py +104 -0
  23. h2ogpte/cli/core/session.py +171 -0
  24. h2ogpte/cli/integrations/__init__.py +0 -0
  25. h2ogpte/cli/integrations/agent.py +338 -0
  26. h2ogpte/cli/integrations/rag.py +442 -0
  27. h2ogpte/cli/main.py +90 -0
  28. h2ogpte/cli/ui/__init__.py +0 -0
  29. h2ogpte/cli/ui/hbot_prompt.py +435 -0
  30. h2ogpte/cli/ui/prompts.py +129 -0
  31. h2ogpte/cli/ui/status_bar.py +133 -0
  32. h2ogpte/cli/utils/__init__.py +0 -0
  33. h2ogpte/cli/utils/file_manager.py +411 -0
  34. h2ogpte/connectors.py +11 -0
  35. h2ogpte/h2ogpte.py +619 -69
  36. h2ogpte/h2ogpte_async.py +631 -70
  37. h2ogpte/h2ogpte_sync_base.py +8 -1
  38. h2ogpte/rest_async/__init__.py +8 -3
  39. h2ogpte/rest_async/api/chat_api.py +29 -0
  40. h2ogpte/rest_async/api/collections_api.py +293 -0
  41. h2ogpte/rest_async/api/document_ingestion_api.py +1365 -436
  42. h2ogpte/rest_async/api/extractors_api.py +2874 -70
  43. h2ogpte/rest_async/api/prompt_templates_api.py +32 -32
  44. h2ogpte/rest_async/api_client.py +1 -1
  45. h2ogpte/rest_async/configuration.py +1 -1
  46. h2ogpte/rest_async/models/__init__.py +7 -2
  47. h2ogpte/rest_async/models/chat_completion.py +4 -2
  48. h2ogpte/rest_async/models/chat_completion_delta.py +5 -3
  49. h2ogpte/rest_async/models/chat_completion_request.py +1 -1
  50. h2ogpte/rest_async/models/chat_session.py +4 -2
  51. h2ogpte/rest_async/models/chat_settings.py +1 -1
  52. h2ogpte/rest_async/models/collection.py +4 -2
  53. h2ogpte/rest_async/models/collection_create_request.py +4 -2
  54. h2ogpte/rest_async/models/confluence_credentials.py +89 -0
  55. h2ogpte/rest_async/models/create_chat_session_request.py +87 -0
  56. h2ogpte/rest_async/models/extraction_request.py +1 -1
  57. h2ogpte/rest_async/models/extractor.py +4 -2
  58. h2ogpte/rest_async/models/guardrails_settings.py +8 -4
  59. h2ogpte/rest_async/models/guardrails_settings_create_request.py +1 -1
  60. h2ogpte/rest_async/models/ingest_from_confluence_body.py +97 -0
  61. h2ogpte/rest_async/models/process_document_job_request.py +1 -1
  62. h2ogpte/rest_async/models/question_request.py +1 -1
  63. h2ogpte/rest_async/models/{reset_and_share_prompt_template_request.py → reset_and_share_request.py} +6 -6
  64. h2ogpte/{rest_sync/models/reset_and_share_prompt_template_with_groups_request.py → rest_async/models/reset_and_share_with_groups_request.py} +6 -6
  65. h2ogpte/rest_async/models/summarize_request.py +1 -1
  66. h2ogpte/rest_async/models/update_collection_privacy_request.py +6 -4
  67. h2ogpte/rest_async/models/update_collection_workspace_request.py +87 -0
  68. h2ogpte/rest_async/models/update_extractor_privacy_request.py +87 -0
  69. h2ogpte/rest_sync/__init__.py +8 -3
  70. h2ogpte/rest_sync/api/chat_api.py +29 -0
  71. h2ogpte/rest_sync/api/collections_api.py +293 -0
  72. h2ogpte/rest_sync/api/document_ingestion_api.py +1365 -436
  73. h2ogpte/rest_sync/api/extractors_api.py +2874 -70
  74. h2ogpte/rest_sync/api/prompt_templates_api.py +32 -32
  75. h2ogpte/rest_sync/api_client.py +1 -1
  76. h2ogpte/rest_sync/configuration.py +1 -1
  77. h2ogpte/rest_sync/models/__init__.py +7 -2
  78. h2ogpte/rest_sync/models/chat_completion.py +4 -2
  79. h2ogpte/rest_sync/models/chat_completion_delta.py +5 -3
  80. h2ogpte/rest_sync/models/chat_completion_request.py +1 -1
  81. h2ogpte/rest_sync/models/chat_session.py +4 -2
  82. h2ogpte/rest_sync/models/chat_settings.py +1 -1
  83. h2ogpte/rest_sync/models/collection.py +4 -2
  84. h2ogpte/rest_sync/models/collection_create_request.py +4 -2
  85. h2ogpte/rest_sync/models/confluence_credentials.py +89 -0
  86. h2ogpte/rest_sync/models/create_chat_session_request.py +87 -0
  87. h2ogpte/rest_sync/models/extraction_request.py +1 -1
  88. h2ogpte/rest_sync/models/extractor.py +4 -2
  89. h2ogpte/rest_sync/models/guardrails_settings.py +8 -4
  90. h2ogpte/rest_sync/models/guardrails_settings_create_request.py +1 -1
  91. h2ogpte/rest_sync/models/ingest_from_confluence_body.py +97 -0
  92. h2ogpte/rest_sync/models/process_document_job_request.py +1 -1
  93. h2ogpte/rest_sync/models/question_request.py +1 -1
  94. h2ogpte/rest_sync/models/{reset_and_share_prompt_template_request.py → reset_and_share_request.py} +6 -6
  95. h2ogpte/{rest_async/models/reset_and_share_prompt_template_with_groups_request.py → rest_sync/models/reset_and_share_with_groups_request.py} +6 -6
  96. h2ogpte/rest_sync/models/summarize_request.py +1 -1
  97. h2ogpte/rest_sync/models/update_collection_privacy_request.py +6 -4
  98. h2ogpte/rest_sync/models/update_collection_workspace_request.py +87 -0
  99. h2ogpte/rest_sync/models/update_extractor_privacy_request.py +87 -0
  100. h2ogpte/session.py +14 -2
  101. h2ogpte/session_async.py +33 -6
  102. h2ogpte/types.py +9 -1
  103. {h2ogpte-1.6.42.dist-info → h2ogpte-1.6.43.dist-info}/METADATA +5 -1
  104. {h2ogpte-1.6.42.dist-info → h2ogpte-1.6.43.dist-info}/RECORD +107 -64
  105. h2ogpte-1.6.43.dist-info/entry_points.txt +2 -0
  106. {h2ogpte-1.6.42.dist-info → h2ogpte-1.6.43.dist-info}/WHEEL +0 -0
  107. {h2ogpte-1.6.42.dist-info → h2ogpte-1.6.43.dist-info}/top_level.txt +0 -0
h2ogpte/__init__.py CHANGED
@@ -3,7 +3,7 @@ from h2ogpte.h2ogpte import H2OGPTE
3
3
  from h2ogpte.h2ogpte_async import H2OGPTEAsync
4
4
  from h2ogpte.session_async import SessionAsync
5
5
 
6
- __version__ = "1.6.42"
6
+ __version__ = "1.6.43"
7
7
 
8
8
  __all__ = [
9
9
  "H2OGPTE",
File without changes
File without changes
File without changes
@@ -0,0 +1,41 @@
1
+ from ...core.app import get_app_state
2
+
3
+
4
+ async def handle_agent(args: str) -> bool:
5
+ app = get_app_state()
6
+
7
+ if not args or not args.strip():
8
+ app.ui.show_error("Please provide a message")
9
+ app.ui.show_info("Example: /agent Help me analyze this code")
10
+ return True
11
+
12
+ message = args.strip()
13
+
14
+ if app.rag_manager.connected:
15
+ usage_stats = await app.rag_manager.send_message(message, use_agent=True)
16
+
17
+ if usage_stats:
18
+ total_input_tokens = sum(
19
+ u.get("input_tokens", 0) for u in usage_stats.get("usage", [])
20
+ )
21
+ total_output_tokens = sum(
22
+ u.get("output_tokens", 0) for u in usage_stats.get("usage", [])
23
+ )
24
+ response_time = usage_stats.get("response_time", "N/A")
25
+ queued_for = usage_stats.get("queue_time", "N/A")
26
+ llm = usage_stats.get("llm", "N/A")
27
+ app.ui.show_info(
28
+ f"[Agent] Tokens: {total_input_tokens} (in), {total_output_tokens} (out), "
29
+ f"Response time: {response_time}, "
30
+ f"Queued for: {queued_for}, "
31
+ f"LLM: {llm}"
32
+ )
33
+
34
+ await app.update_status_bar()
35
+ else:
36
+ app.ui.show_error("Not connected to H2OGPTE. Use /register to connect first.")
37
+ app.ui.show_info(
38
+ "Example: /register https://your-h2ogpte-endpoint.com your-api-key"
39
+ )
40
+
41
+ return True
@@ -0,0 +1,37 @@
1
+ from ...core.app import get_app_state
2
+
3
+
4
+ async def handle_chat(message: str) -> bool:
5
+ app = get_app_state()
6
+
7
+ if not message or not message.strip():
8
+ return True
9
+
10
+ if app.rag_manager.connected:
11
+ usage_stats = await app.rag_manager.send_message(message)
12
+
13
+ if usage_stats:
14
+ total_input_tokens = sum(
15
+ u.get("input_tokens", 0) for u in usage_stats.get("usage", [])
16
+ )
17
+ total_output_tokens = sum(
18
+ u.get("output_tokens", 0) for u in usage_stats.get("usage", [])
19
+ )
20
+ response_time = usage_stats.get("response_time", "N/A")
21
+ queued_for = usage_stats.get("queue_time", "N/A")
22
+ llm = usage_stats.get("llm", "N/A")
23
+ app.ui.show_info(
24
+ f"Tokens: {total_input_tokens} (in), {total_output_tokens} (out), "
25
+ f"Response time: {response_time}, "
26
+ f"Queued for: {queued_for}, "
27
+ f"LLM: {llm}"
28
+ )
29
+
30
+ await app.update_status_bar()
31
+ else:
32
+ app.ui.show_error("Not connected to H2OGPTE. Use /register to connect first.")
33
+ app.ui.show_info(
34
+ "Example: /register https://your-h2ogpte-endpoint.com your-api-key"
35
+ )
36
+
37
+ return True
@@ -0,0 +1,8 @@
1
+ from ...core.app import get_app_state
2
+
3
+
4
+ async def handle_clear(args: str) -> bool:
5
+ """Clear screen."""
6
+ app = get_app_state()
7
+ app.ui.clear_screen()
8
+ return True
@@ -0,0 +1,67 @@
1
+ from ...core.app import get_app_state
2
+
3
+
4
+ async def handle_create_collection(args: str) -> bool:
5
+ """Create a new collection and switch to it."""
6
+ app = get_app_state()
7
+
8
+ if not app.rag_manager.connected:
9
+ app.ui.show_error("Not connected to H2OGPTE. Use /register first.")
10
+ return True
11
+
12
+ if not args:
13
+ collection_name = app.ui.prompt.get_input_with_default(
14
+ "Enter collection name", "CLI-Collection"
15
+ )
16
+ else:
17
+ collection_name = args.strip()
18
+
19
+ if collection_name:
20
+ app.ui.show_info(f"Creating and switching to collection '{collection_name}'...")
21
+ success = await app.rag_manager.switch_to_collection(collection_name)
22
+
23
+ if success:
24
+ await app.update_status_bar()
25
+ app.ui.show_success(f"Collection '{collection_name}' created and activated")
26
+ app.ui.show_info("Chat session reset - ready for new conversation")
27
+ else:
28
+ app.ui.show_error("Failed to create collection")
29
+ else:
30
+ app.ui.show_error("Collection name is required")
31
+
32
+ return True
33
+
34
+
35
+ async def handle_new_chat(args: str) -> bool:
36
+ """Create a new chat session."""
37
+ app = get_app_state()
38
+
39
+ if not app.rag_manager.connected:
40
+ app.ui.show_error("Not connected to H2OGPTE. Use /register first.")
41
+ return True
42
+
43
+ # Ensure we have a collection first
44
+ if not await app.rag_manager.get_collection_name():
45
+ app.ui.show_info("No active collection. Creating default collection...")
46
+ success = await app.rag_manager.switch_to_collection("CLI-Collection")
47
+ if not success:
48
+ app.ui.show_error("Failed to create collection")
49
+ return True
50
+
51
+ if not args:
52
+ import datetime
53
+
54
+ session_name = f"chat-{datetime.datetime.now().strftime('%Y%m%d-%H%M%S')}"
55
+ else:
56
+ session_name = args.strip()
57
+
58
+ app.ui.show_info(f"Creating new chat session '{session_name}'...")
59
+ success = await app.rag_manager.create_chat_session(session_name)
60
+
61
+ if success:
62
+ await app.update_status_bar()
63
+ app.ui.show_success(f"Chat session '{session_name}' created and activated")
64
+ else:
65
+ app.ui.show_error("Failed to create chat session")
66
+
67
+ return True
@@ -0,0 +1,113 @@
1
+ from rich.table import Table
2
+
3
+ from ...core.app import get_app_state
4
+
5
+
6
+ async def handle_config(args: str) -> bool:
7
+ """Configure settings."""
8
+ app = get_app_state()
9
+
10
+ try:
11
+ categories = ["RAG", "Agent", "UI", "View Current", "Save & Exit"]
12
+ choice = app.ui.prompt.select_from_list(
13
+ categories, "Select configuration category:"
14
+ )
15
+
16
+ if choice == "RAG":
17
+ app.console.print("[cyan]RAG Configuration[/cyan]")
18
+
19
+ current_endpoint = app.settings.rag.endpoint or "not set"
20
+ new_endpoint = app.ui.prompt.get_input(
21
+ f"RAG Endpoint [{current_endpoint}]: "
22
+ )
23
+ if new_endpoint:
24
+ app.settings.rag.endpoint = new_endpoint
25
+
26
+ current_key = "*" * 8 if app.settings.rag.api_key else "not set"
27
+ new_key = app.ui.prompt.get_input(f"API Key [{current_key}]: ")
28
+ if new_key:
29
+ app.settings.rag.api_key = new_key
30
+
31
+ current_collection = app.settings.rag.collection_name
32
+ new_collection = app.ui.prompt.get_input(
33
+ f"Collection [{current_collection}]: "
34
+ )
35
+ if new_collection:
36
+ app.settings.rag.collection_name = new_collection
37
+
38
+ elif choice == "Agent":
39
+ app.console.print("[cyan]Agent Configuration[/cyan]")
40
+
41
+ current_endpoint = app.settings.agent.endpoint or "not set"
42
+ new_endpoint = app.ui.prompt.get_input(
43
+ f"Agent Endpoint [{current_endpoint}]: "
44
+ )
45
+ if new_endpoint:
46
+ app.settings.agent.endpoint = new_endpoint
47
+
48
+ current_key = "*" * 8 if app.settings.agent.api_key else "not set"
49
+ new_key = app.ui.prompt.get_input(f"API Key [{current_key}]: ")
50
+ if new_key:
51
+ app.settings.agent.api_key = new_key
52
+
53
+ current_model = app.settings.agent.model
54
+ new_model = app.ui.prompt.get_input(f"Model [{current_model}]: ")
55
+ if new_model:
56
+ app.settings.agent.model = new_model
57
+
58
+ elif choice == "UI":
59
+ app.console.print("[cyan]UI Configuration[/cyan]")
60
+
61
+ current_theme = app.settings.ui.theme
62
+ new_theme = app.ui.prompt.get_input(f"Theme [{current_theme}]: ")
63
+ if new_theme:
64
+ app.settings.ui.theme = new_theme
65
+
66
+ app.settings.ui.show_progress = app.ui.prompt.confirm(
67
+ "Show progress bars", default=app.settings.ui.show_progress
68
+ )
69
+
70
+ app.settings.ui.animation = app.ui.prompt.confirm(
71
+ "Enable animations", default=app.settings.ui.animation
72
+ )
73
+
74
+ elif choice == "View Current":
75
+ _show_current_config(app)
76
+
77
+ if choice not in ["View Current", "Save & Exit"]:
78
+ try:
79
+ app.settings.save()
80
+ app.ui.show_success("Configuration saved")
81
+ # Update status bar after config changes
82
+ app.update_status_bar()
83
+ except Exception as e:
84
+ app.ui.show_error(f"Failed to save configuration: {e}")
85
+
86
+ except Exception as e:
87
+ app.ui.show_error(f"Configuration error: {e}")
88
+
89
+ return True
90
+
91
+
92
+ def _show_current_config(app):
93
+ """Show current configuration."""
94
+ table = Table(title="Current Configuration")
95
+ table.add_column("Setting", style="cyan")
96
+ table.add_column("Value", style="white")
97
+
98
+ # RAG settings
99
+ table.add_row("RAG Endpoint", app.settings.rag.endpoint or "not set")
100
+ table.add_row("RAG API Key", "*" * 8 if app.settings.rag.api_key else "not set")
101
+ table.add_row("RAG Collection", app.settings.rag.collection_name)
102
+
103
+ # Agent settings
104
+ table.add_row("Agent Endpoint", app.settings.agent.endpoint or "not set")
105
+ table.add_row("Agent API Key", "*" * 8 if app.settings.agent.api_key else "not set")
106
+ table.add_row("Agent Model", app.settings.agent.model)
107
+
108
+ # UI settings
109
+ table.add_row("UI Theme", app.settings.ui.theme)
110
+ table.add_row("Show Progress", str(app.settings.ui.show_progress))
111
+ table.add_row("Animations", str(app.settings.ui.animation))
112
+
113
+ app.console.print(table)
@@ -0,0 +1,36 @@
1
+ from ...core.app import get_app_state
2
+
3
+
4
+ async def handle_disconnect(args: str) -> bool:
5
+ """Disconnect from H2OGPTE and clear saved credentials."""
6
+ app = get_app_state()
7
+
8
+ if not app.rag_manager.connected:
9
+ app.ui.show_info("Already disconnected from H2OGPTE")
10
+ return True
11
+
12
+ # Confirm disconnection
13
+ if not app.ui.prompt.confirm(
14
+ "Disconnect and clear saved credentials?", default=False
15
+ ):
16
+ app.ui.show_info("Disconnection cancelled")
17
+ return True
18
+
19
+ # Disconnect from RAG manager
20
+ await app.rag_manager.close()
21
+
22
+ # Clear credentials from settings
23
+ app.settings.rag.endpoint = ""
24
+ app.settings.rag.api_key = ""
25
+ app.settings.rag.collection_name = "default"
26
+
27
+ # Save cleared settings
28
+ app.settings.save()
29
+
30
+ # Update status bar
31
+ await app.update_status_bar()
32
+
33
+ app.ui.show_success("Disconnected and credentials cleared")
34
+ app.ui.show_info("Use /register to connect again")
35
+
36
+ return True
@@ -0,0 +1,37 @@
1
+ from rich.panel import Panel
2
+
3
+ from ...core.app import get_app_state
4
+
5
+
6
+ async def handle_exit(args: str) -> bool:
7
+ """Exit the application."""
8
+ app = get_app_state()
9
+
10
+ # Check if user provided 'y' as an argument for immediate exit
11
+ if args and args.strip().lower() in ["y", "yes"]:
12
+ # Exit immediately without confirmation
13
+ await app.cleanup()
14
+
15
+ app.console.print(
16
+ Panel(
17
+ "[bold cyan]Thank you for using H2OGPTE CLI![/bold cyan]\n"
18
+ "[dim]Session saved automatically[/dim]",
19
+ border_style="cyan",
20
+ )
21
+ )
22
+ return False
23
+
24
+ # Otherwise, ask for confirmation
25
+ if app.ui.prompt.confirm("Are you sure you want to exit?", default=False):
26
+ # Clean up
27
+ await app.cleanup()
28
+
29
+ app.console.print(
30
+ Panel(
31
+ "[bold cyan]Thank you for using H2OGPTE CLI![/bold cyan]\n"
32
+ "[dim]Session saved automatically[/dim]",
33
+ border_style="cyan",
34
+ )
35
+ )
36
+ return False
37
+ return True
@@ -0,0 +1,8 @@
1
+ from ...core.app import get_app_state
2
+
3
+
4
+ async def handle_help(args: str) -> bool:
5
+ """Show help information."""
6
+ app = get_app_state()
7
+ app.ui.show_help()
8
+ return True
@@ -0,0 +1,29 @@
1
+ from datetime import datetime
2
+ from rich.table import Table
3
+
4
+ from ...core.app import get_app_state
5
+
6
+
7
+ async def handle_history(args: str) -> bool:
8
+ """Show command history."""
9
+ app = get_app_state()
10
+ limit = int(args) if args.isdigit() else 20
11
+
12
+ history = app.session.history[-limit:]
13
+ if not history:
14
+ app.ui.show_info("No command history")
15
+ return True
16
+
17
+ table = Table(title=f"Command History (last {len(history)} entries)")
18
+ table.add_column("#", style="dim")
19
+ table.add_column("Time", style="cyan")
20
+ table.add_column("Command", style="white")
21
+ table.add_column("Status", style="white")
22
+
23
+ for i, entry in enumerate(history, 1):
24
+ time_str = datetime.fromisoformat(entry["timestamp"]).strftime("%H:%M:%S")
25
+ status = "[green]✓[/green]" if entry["success"] else "[red]✗[/red]"
26
+ table.add_row(str(i), time_str, entry["command"][:50], status)
27
+
28
+ app.console.print(table)
29
+ return True
@@ -0,0 +1,146 @@
1
+ from pathlib import Path
2
+
3
+ from ...core.app import get_app_state
4
+
5
+
6
+ async def handle_register(args: str) -> bool:
7
+ """Register H2OGPTE system."""
8
+ app = get_app_state()
9
+
10
+ # Parse arguments or prompt for them
11
+ parts = args.split()
12
+
13
+ if len(parts) < 2:
14
+ # Check if user explicitly wants to clear credentials (special keyword)
15
+ if args.strip().lower() in ["clear", "disconnect", "reset"]:
16
+ app.ui.show_info("Clearing credentials...")
17
+ # Clear existing connection
18
+ if app.rag_manager.connected:
19
+ await app.rag_manager.close()
20
+
21
+ # Clear credentials
22
+ app.settings.rag.endpoint = ""
23
+ app.settings.rag.api_key = ""
24
+ app.settings.rag.collection_name = "default"
25
+ app.settings.save()
26
+
27
+ # Update status bar
28
+ await app.update_status_bar()
29
+
30
+ app.ui.show_success(
31
+ "Credentials cleared. Use /register <address> <api_key> to reconnect"
32
+ )
33
+ return True
34
+
35
+ # Interactive mode with defaults and secure input
36
+ address = app.ui.prompt.get_input_with_default(
37
+ "H2OGPTE Address", "https://h2ogpte.genai.h2o.ai"
38
+ )
39
+ api_key = app.ui.prompt.get_secret("API Key")
40
+
41
+ # If user cancels input, don't proceed
42
+ if not address or not api_key:
43
+ app.ui.show_info("Registration cancelled")
44
+ return True
45
+ else:
46
+ address = parts[0]
47
+ api_key = parts[1]
48
+
49
+ # Step 1: Connect and get username only
50
+ app.ui.show_info("Step 1: Connecting and retrieving user information...")
51
+
52
+ # Save to settings with encrypted API key
53
+ app.settings.rag.endpoint = address
54
+ app.settings.set_rag_api_key(api_key)
55
+
56
+ # Try to connect and get username (without creating collection yet)
57
+ success = await app.rag_manager.connect_and_get_user(address, api_key)
58
+
59
+ if success:
60
+ # Get username and update status bar
61
+ username = await app.rag_manager.get_username()
62
+ if username:
63
+ app.ui.show_success(f"Connected as user: {username}")
64
+
65
+ # Save settings on successful connection
66
+ app.settings.save()
67
+
68
+ # Update status bar with username
69
+ await app.update_status_bar()
70
+ app.ui.show_success("Connected successfully! Ready to chat.")
71
+
72
+ else:
73
+ app.ui.show_error("Connected but failed to get username")
74
+ else:
75
+ app.ui.show_error("Failed to connect to H2OGPTE")
76
+
77
+ return True
78
+
79
+
80
+ async def handle_upload(args: str) -> bool:
81
+ """Upload files to RAG."""
82
+ app = get_app_state()
83
+
84
+ if not args:
85
+ # Interactive file selection
86
+ path = app.ui.prompt.get_path("Select file or directory to upload: ")
87
+ if not path:
88
+ return True
89
+ else:
90
+ path = Path(args.strip())
91
+
92
+ if not path.exists():
93
+ app.ui.show_error(f"Path not found: {path}")
94
+ return True
95
+
96
+ # Collect files
97
+ if path.is_file():
98
+ files = [path]
99
+ else:
100
+ # Scan directory
101
+ patterns = app.ui.prompt.get_multiselect(
102
+ ["*.py", "*.js", "*.txt", "*.md", "*.json", "*"],
103
+ "Select file patterns to include:",
104
+ )
105
+ files = app.file_manager.scan_directory(
106
+ path, patterns if patterns != ["*"] else None
107
+ )
108
+
109
+ if not files:
110
+ app.ui.show_warning("No files to upload")
111
+ return True
112
+
113
+ # Display files to upload
114
+ app.file_manager.display_file_list(files, show_details=False)
115
+
116
+ if not app.ui.prompt.confirm(f"Upload {len(files)} file(s)?", default=True):
117
+ return True
118
+
119
+ # Upload files
120
+ await app.rag_manager.upload_files(files)
121
+ return True
122
+
123
+
124
+ async def handle_analyze(args: str) -> bool:
125
+ """Analyze directory."""
126
+ app = get_app_state()
127
+
128
+ if not args:
129
+ path = Path.cwd()
130
+ else:
131
+ path = Path(args.strip())
132
+
133
+ if not path.exists() or not path.is_dir():
134
+ app.ui.show_error(f"Invalid directory: {path}")
135
+ return True
136
+
137
+ # Analyze directory
138
+ analysis = await app.dir_analyzer.analyze(path)
139
+
140
+ # Ask if user wants to upload
141
+ if analysis["total_files"] > 0:
142
+ if app.ui.prompt.confirm("Upload directory contents to RAG?"):
143
+ files = app.file_manager.scan_directory(path)
144
+ await app.rag_manager.upload_files(files)
145
+
146
+ return True
@@ -0,0 +1,45 @@
1
+ from ...core.app import get_app_state
2
+
3
+
4
+ async def handle_research_agent(args: str) -> bool:
5
+ app = get_app_state()
6
+
7
+ if not args or not args.strip():
8
+ app.ui.show_error("Please provide a research query")
9
+ app.ui.show_info(
10
+ "Example: /research What are the latest developments in quantum computing?"
11
+ )
12
+ return True
13
+
14
+ message = args.strip()
15
+
16
+ if app.rag_manager.connected:
17
+ usage_stats = await app.rag_manager.send_message(
18
+ message, use_agent=True, agent_type="deep_research"
19
+ )
20
+
21
+ if usage_stats:
22
+ total_input_tokens = sum(
23
+ u.get("input_tokens", 0) for u in usage_stats.get("usage", [])
24
+ )
25
+ total_output_tokens = sum(
26
+ u.get("output_tokens", 0) for u in usage_stats.get("usage", [])
27
+ )
28
+ response_time = usage_stats.get("response_time", "N/A")
29
+ queued_for = usage_stats.get("queue_time", "N/A")
30
+ llm = usage_stats.get("llm", "N/A")
31
+ app.ui.show_info(
32
+ f"[Research] Tokens: {total_input_tokens} (in), {total_output_tokens} (out), "
33
+ f"Response time: {response_time}, "
34
+ f"Queued for: {queued_for}, "
35
+ f"LLM: {llm}"
36
+ )
37
+
38
+ await app.update_status_bar()
39
+ else:
40
+ app.ui.show_error("Not connected to H2OGPTE. Use /register to connect first.")
41
+ app.ui.show_info(
42
+ "Example: /register https://your-h2ogpte-endpoint.com your-api-key"
43
+ )
44
+
45
+ return True
@@ -0,0 +1,77 @@
1
+ from pathlib import Path
2
+ import datetime
3
+
4
+ from ...core.app import get_app_state
5
+
6
+
7
+ async def handle_session(args: str) -> bool:
8
+ """Create a new chat session with optional name."""
9
+ app = get_app_state()
10
+
11
+ if not app.rag_manager.connected:
12
+ app.ui.show_error("Not connected to H2OGPTE. Use /register first.")
13
+ return True
14
+
15
+ # Ensure we have a collection first
16
+ if not await app.rag_manager.get_collection_name():
17
+ app.ui.show_info("No active collection. Creating default collection...")
18
+ success = await app.rag_manager.switch_to_collection("CLI-Collection")
19
+ if not success:
20
+ app.ui.show_error("Failed to create collection")
21
+ return True
22
+
23
+ # Determine session name
24
+ if not args:
25
+ session_name = f"chat-{datetime.datetime.now().strftime('%Y%m%d-%H%M%S')}"
26
+ else:
27
+ session_name = args.strip()
28
+
29
+ app.ui.show_info(f"Creating new chat session '{session_name}'...")
30
+
31
+ # Create the chat session and get the session ID
32
+ session_id = await app.rag_manager.create_chat_session_with_name(session_name)
33
+
34
+ if session_id:
35
+ await app.update_status_bar()
36
+ app.ui.show_success(f"Chat session '{session_name}' created and activated")
37
+ else:
38
+ app.ui.show_error("Failed to create chat session")
39
+
40
+ return True
41
+
42
+
43
+ async def handle_save(args: str) -> bool:
44
+ """Save session."""
45
+ app = get_app_state()
46
+
47
+ if args:
48
+ path = Path(args)
49
+ else:
50
+ path = None
51
+
52
+ app.session.save_session(path)
53
+ return True
54
+
55
+
56
+ async def handle_load(args: str) -> bool:
57
+ """Load session."""
58
+ app = get_app_state()
59
+
60
+ if not args:
61
+ app.ui.show_error("Please provide a session file path")
62
+ return True
63
+
64
+ path = Path(args)
65
+ if not path.exists():
66
+ app.ui.show_error(f"Session file not found: {path}")
67
+ return True
68
+
69
+ try:
70
+ from ...core.session import Session
71
+
72
+ app.session = Session.load_session(path)
73
+ app.ui.show_success(f"Session loaded from {path}")
74
+ except Exception as e:
75
+ app.ui.show_error(f"Failed to load session: {e}")
76
+
77
+ return True