cite-agent 1.2.12__py3-none-any.whl → 1.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.

Potentially problematic release.


This version of cite-agent might be problematic. Click here for more details.

cite_agent/__version__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "1.2.12"
1
+ __version__ = "1.3.0"
@@ -2705,120 +2705,110 @@ class EnhancedNocturnalAgent:
2705
2705
  if debug_mode:
2706
2706
  print(f"🔍 Web search failed: {e}")
2707
2707
 
2708
- # PRODUCTION MODE: Check for shell/code execution needs FIRST
2708
+ # PRODUCTION MODE: Use small LLM to plan shell commands (smarter than hardcoded patterns)
2709
2709
  if self.client is None:
2710
- # Check if query needs directory/file info or exploration
2710
+ # Ask small LLM: What shell command should we run?
2711
+ planner_prompt = f"""You are a shell command planner. Given the user's query, determine what shell command(s) to run.
2712
+
2713
+ User query: "{request.question}"
2714
+ Previous conversation context: {json.dumps(self.conversation_history[-2:]) if self.conversation_history else "None"}
2715
+
2716
+ Respond with JSON:
2717
+ {{
2718
+ "action": "pwd|ls|find|none",
2719
+ "search_target": "directory/file name to search for (if action=find)",
2720
+ "search_path": "~/Downloads or ~/Documents or ~ (if action=find)",
2721
+ "target_path": "/full/path (if referring to previous result)"
2722
+ }}
2723
+
2724
+ Examples:
2725
+ Query: "where am i?" → {{"action": "pwd"}}
2726
+ Query: "what files are here?" → {{"action": "ls"}}
2727
+ Query: "find cm522 in downloads" → {{"action": "find", "search_target": "cm522", "search_path": "~/Downloads"}}
2728
+ Query: "can you look into it?" + Previous: "Found /home/user/Downloads/cm522-main" → {{"action": "ls", "target_path": "/home/user/Downloads/cm522-main"}}
2729
+ Query: "what's the capital of France?" → {{"action": "none"}}
2730
+
2731
+ JSON:"""
2732
+
2711
2733
  question_lower = request.question.lower()
2712
-
2713
- # Basic info queries
2714
- needs_shell_info = any(phrase in question_lower for phrase in [
2715
- 'directory', 'folder', 'where am i', 'pwd', 'current location',
2716
- 'list files', 'what files', 'ls', 'files in', 'show files',
2717
- 'data files', 'csv files', 'check if file', 'file exists'
2718
- ])
2719
-
2720
- # Fuzzy search queries (find similar directories/files)
2721
- needs_find = any(phrase in question_lower for phrase in [
2722
- 'looking for', 'find', 'search for', 'similar to',
2723
- 'go to', 'cd to', 'navigate to', 'or something', 'forgot the name',
2724
- 'look into', 'check what', 'what\'s in'
2734
+ needs_shell = any(word in question_lower for word in [
2735
+ 'directory', 'folder', 'where', 'find', 'list', 'files', 'look', 'search', 'check'
2725
2736
  ])
2726
2737
 
2727
- if (needs_shell_info or needs_find) and self.shell_session:
2728
- # Execute exploration commands
2738
+ if needs_shell and self.shell_session:
2729
2739
  try:
2740
+ # Use small LLM to plan shell command (smarter than regex)
2741
+ plan_response = await self.call_backend_query(
2742
+ query=planner_prompt,
2743
+ conversation_history=[],
2744
+ api_results={},
2745
+ tools_used=[]
2746
+ )
2747
+
2748
+ # Parse JSON plan
2749
+ import json as json_module
2750
+ plan_text = plan_response.response.strip()
2751
+ # Extract JSON if wrapped in markdown
2752
+ if '```' in plan_text:
2753
+ plan_text = plan_text.split('```')[1].replace('json', '').strip()
2754
+
2755
+ plan = json_module.loads(plan_text)
2756
+
2757
+ debug_mode = os.getenv("NOCTURNAL_DEBUG", "").lower() == "1"
2758
+ if debug_mode:
2759
+ print(f"🔍 LLM PLAN: {plan}")
2760
+
2730
2761
  api_results["shell_info"] = {}
2731
2762
 
2732
- # Always include current location
2733
- pwd_output = self.execute_command("pwd")
2734
- api_results["shell_info"]["current_directory"] = pwd_output.strip()
2763
+ # Execute based on plan
2764
+ action = plan.get("action", "none")
2765
+
2766
+ if action == "pwd":
2767
+ pwd_output = self.execute_command("pwd")
2768
+ api_results["shell_info"]["current_directory"] = pwd_output.strip()
2769
+ tools_used.append("shell_execution")
2735
2770
 
2736
- if needs_shell_info and not needs_find:
2737
- # Just list current directory
2738
- ls_output = self.execute_command("ls -lah")
2771
+ elif action == "ls":
2772
+ target = plan.get("target_path")
2773
+ if target:
2774
+ # List specific directory
2775
+ ls_output = self.execute_command(f"ls -lah {target}")
2776
+ else:
2777
+ # List current directory
2778
+ ls_output = self.execute_command("ls -lah")
2739
2779
  api_results["shell_info"]["directory_contents"] = ls_output
2780
+ if target:
2781
+ api_results["shell_info"]["target_path"] = target
2782
+ tools_used.append("shell_execution")
2740
2783
 
2741
- if needs_find:
2742
- # Smart search: extract directory name and location hints
2743
- import re
2784
+ elif action == "find":
2785
+ search_target = plan.get("search_target", "")
2786
+ search_path = plan.get("search_path", "~")
2744
2787
 
2745
- # Check if user is referring to previous context ("it", "there")
2746
- has_pronoun = any(word in question_lower for word in ['it', 'there', 'that folder', 'that directory'])
2747
- pronoun_resolved = False
2748
-
2749
- if has_pronoun and len(self.conversation_history) > 0:
2750
- # Look for directory path in last assistant message
2751
- last_assistant = None
2752
- for msg in reversed(self.conversation_history):
2753
- if msg.get('role') == 'assistant':
2754
- last_assistant = msg.get('content', '')
2755
- break
2756
-
2757
- if last_assistant:
2758
- # Extract paths like /home/user/Downloads/cm522-main
2759
- paths = re.findall(r'(/[\w/.-]+)', last_assistant)
2760
- if paths:
2761
- # List contents of the first path found
2762
- target_path = paths[0]
2763
- ls_output = self.execute_command(f"ls -lah {target_path}")
2764
- api_results["shell_info"]["directory_contents"] = ls_output
2765
- api_results["shell_info"]["target_path"] = target_path
2766
- tools_used.append("shell_execution")
2767
- pronoun_resolved = True
2768
-
2769
- # Generic search if no pronoun or pronoun not resolved
2770
- if not pronoun_resolved:
2771
- # Common words to ignore (add prepositions and articles)
2772
- ignore_words = {
2773
- 'looking', 'find', 'folder', 'directory', 'called', 'something',
2774
- 'forgot', 'name', 'think', 'can', 'you', 'look', 'for', 'somewhere',
2775
- 'computer', 'downloads', 'the', 'this', 'that', 'class', 'investment',
2776
- 'check', 'what', 'into', 'in', 'on', 'at', 'to', 'from', 'with',
2777
- 'and', 'or', 'is', 'it', 'my', 'me', 'there', 'here'
2778
- }
2779
-
2780
- # Extract potential target names
2781
- # Filter: must be 3+ chars (avoid "in", "to") AND not in ignore list
2782
- all_words = re.findall(r'\b([a-zA-Z0-9_-]+)\b', request.question)
2783
- potential_names = [w for w in all_words if len(w) >= 3 and w.lower() not in ignore_words]
2784
-
2785
- # Detect location hints
2786
- search_path = "~" # Default to home
2787
- if 'downloads' in question_lower:
2788
- search_path = "~/Downloads"
2789
- elif 'documents' in question_lower:
2790
- search_path = "~/Documents"
2791
-
2792
- search_results = []
2793
- searched_terms = []
2794
-
2795
- for name in potential_names[:2]: # Limit to 2 best candidates
2796
- if name in searched_terms:
2797
- continue
2798
- searched_terms.append(name)
2799
-
2800
- # Search with increasing depth if needed
2801
- find_cmd = f"find {search_path} -maxdepth 4 -type d -iname '*{name}*' 2>/dev/null | head -20"
2788
+ if search_target:
2789
+ find_cmd = f"find {search_path} -maxdepth 4 -type d -iname '*{search_target}*' 2>/dev/null | head -20"
2802
2790
  find_output = self.execute_command(find_cmd)
2803
2791
 
2804
- # DEBUG: Log exact output
2805
- debug_mode = os.getenv("NOCTURNAL_DEBUG", "").lower() == "1"
2806
2792
  if debug_mode:
2807
2793
  print(f"🔍 FIND EXECUTED: {find_cmd}")
2808
2794
  print(f"🔍 FIND OUTPUT: {repr(find_output)}")
2809
2795
 
2810
2796
  if find_output.strip():
2811
- search_results.append(f"Searched for '*{name}*' in {search_path}:\n{find_output}")
2812
-
2813
- if search_results:
2814
- api_results["shell_info"]["search_results"] = "\n\n".join(search_results)
2815
- elif potential_names:
2816
- api_results["shell_info"]["search_results"] = f"No directories matching '{', '.join(searched_terms)}' found in {search_path}"
2797
+ api_results["shell_info"]["search_results"] = f"Searched for '*{search_target}*' in {search_path}:\n{find_output}"
2798
+ else:
2799
+ api_results["shell_info"]["search_results"] = f"No directories matching '{search_target}' found in {search_path}"
2800
+ tools_used.append("shell_execution")
2817
2801
 
2818
- tools_used.append("shell_execution")
2802
+ # Always include current directory
2803
+ pwd_output = self.execute_command("pwd")
2804
+ api_results["shell_info"]["current_directory"] = pwd_output.strip()
2805
+
2819
2806
  except Exception as e:
2807
+ # LLM planner failed, skip shell execution
2808
+ debug_mode = os.getenv("NOCTURNAL_DEBUG", "").lower() == "1"
2820
2809
  if debug_mode:
2821
- print(f"🔍 Shell execution failed: {e}")
2810
+ print(f"🔍 Shell planner failed: {e}")
2811
+
2822
2812
 
2823
2813
  # DEBUG: Log exactly what we're sending to backend
2824
2814
  debug_mode = os.getenv("NOCTURNAL_DEBUG", "").lower() == "1"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cite-agent
3
- Version: 1.2.12
3
+ Version: 1.3.0
4
4
  Summary: Terminal AI assistant for academic research with citation verification
5
5
  Home-page: https://github.com/Spectating101/cite-agent
6
6
  Author: Cite-Agent Team
@@ -1,6 +1,6 @@
1
1
  cite_agent/__init__.py,sha256=wAXV2v8nNOmIAd0rh8196ItBl9hHWBVOBl5Re4VB77I,1645
2
2
  cite_agent/__main__.py,sha256=6x3lltwG-iZHeQbN12rwvdkPDfd2Rmdk71tOOaC89Mw,179
3
- cite_agent/__version__.py,sha256=dbW85A2PinQCZabwD2DNDTfOE9315GDtQQKAsJP8IXk,23
3
+ cite_agent/__version__.py,sha256=F5mW07pSyGrqDNY2Ehr-UpDzpBtN-FsYU0QGZWf6PJE,22
4
4
  cite_agent/account_client.py,sha256=yLuzhIJoIZuXHXGbaVMzDxRATQwcy-wiaLnUrDuwUhI,5725
5
5
  cite_agent/agent_backend_only.py,sha256=H4DH4hmKhT0T3rQLAb2xnnJVjxl3pOZaljL9r6JndFY,6314
6
6
  cite_agent/ascii_plotting.py,sha256=lk8BaECs6fmjtp4iH12G09-frlRehAN7HLhHt2crers,8570
@@ -11,7 +11,7 @@ cite_agent/cli_conversational.py,sha256=RAmgRNRyB8gQ8QLvWU-Tt23j2lmA34rQNT5F3_7S
11
11
  cite_agent/cli_enhanced.py,sha256=EAaSw9qtiYRWUXF6_05T19GCXlz9cCSz6n41ASnXIPc,7407
12
12
  cite_agent/cli_workflow.py,sha256=4oS_jW9D8ylovXbEFdsyLQONt4o0xxR4Xatfcc4tnBs,11641
13
13
  cite_agent/dashboard.py,sha256=VGV5XQU1PnqvTsxfKMcue3j2ri_nvm9Be6O5aVays_w,10502
14
- cite_agent/enhanced_ai_agent.py,sha256=V0iJfsIBZd0o41xWFcA5EKX0ux1Jtba8iBQyxqxLegU,166340
14
+ cite_agent/enhanced_ai_agent.py,sha256=7N9tNVgoHeaS1Y5mN3caBQ3CE07qGFsh310A9Kj_S6k,164642
15
15
  cite_agent/rate_limiter.py,sha256=-0fXx8Tl4zVB4O28n9ojU2weRo-FBF1cJo9Z5jC2LxQ,10908
16
16
  cite_agent/session_manager.py,sha256=B0MXSOsXdhO3DlvTG7S8x6pmGlYEDvIZ-o8TZM23niQ,9444
17
17
  cite_agent/setup_config.py,sha256=3m2e3gw0srEWA0OygdRo64r-8HK5ohyXfct0c__CF3s,16817
@@ -22,7 +22,7 @@ cite_agent/updater.py,sha256=udoAAN4gBKAvKDV7JTh2FJO_jIhNk9bby4x6n188MEY,8458
22
22
  cite_agent/web_search.py,sha256=FZCuNO7MAITiOIbpPbJyt2bzbXPzQla-9amJpnMpW_4,6520
23
23
  cite_agent/workflow.py,sha256=a0YC0Mzz4or1C5t2gZcuJBQ0uMOZrooaI8eLu2kkI0k,15086
24
24
  cite_agent/workflow_integration.py,sha256=A9ua0DN5pRtuU0cAwrUTGvqt2SXKhEHQbrHx16EGnDM,10910
25
- cite_agent-1.2.12.dist-info/licenses/LICENSE,sha256=XJkyO4IymhSUniN1ENY6lLrL2729gn_rbRlFK6_Hi9M,1074
25
+ cite_agent-1.3.0.dist-info/licenses/LICENSE,sha256=XJkyO4IymhSUniN1ENY6lLrL2729gn_rbRlFK6_Hi9M,1074
26
26
  src/__init__.py,sha256=0eEpjRfjRjOTilP66y-AbGNslBsVYr_clE-bZUzsX7s,40
27
27
  src/services/__init__.py,sha256=pTGLCH_84mz4nGtYMwQES5w-LzoSulUtx_uuNM6r-LA,4257
28
28
  src/services/simple_enhanced_main.py,sha256=IJoOplCqcVUg3GvN_BRyAhpGrLm_WEPy2jmHcNCY6R0,9257
@@ -49,8 +49,8 @@ src/services/research_service/synthesizer.py,sha256=lCcu37PWhWVNphHKaJJDIC-JQ5OI
49
49
  src/services/search_service/__init__.py,sha256=UZFXdd7r6wietQ2kESXEyGffdfBbpghquecQde7auF4,137
50
50
  src/services/search_service/indexer.py,sha256=u3-uwdAfmahWWsdebDF9i8XIyp7YtUMIHzlmBLBnPPM,7252
51
51
  src/services/search_service/search_engine.py,sha256=S9HqQ_mk-8W4d4MUOgBbEGQGV29-eSuceSFvVb4Xk-k,12500
52
- cite_agent-1.2.12.dist-info/METADATA,sha256=X53fF93c1oBock38Fg1mCIMXhUCyK3qUTq_L2nFZWKo,12232
53
- cite_agent-1.2.12.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
54
- cite_agent-1.2.12.dist-info/entry_points.txt,sha256=bJ0u28nFIxQKH1PWQ2ak4PV-FAjhoxTC7YADEdDenFw,83
55
- cite_agent-1.2.12.dist-info/top_level.txt,sha256=TgOFqJTIy8vDZuOoYA2QgagkqZtfhM5Acvt_IsWzAKo,15
56
- cite_agent-1.2.12.dist-info/RECORD,,
52
+ cite_agent-1.3.0.dist-info/METADATA,sha256=6dtwcnKUMiiB0MkFDa4yQm1AKsCEKuVkfoii5_YK87Q,12231
53
+ cite_agent-1.3.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
54
+ cite_agent-1.3.0.dist-info/entry_points.txt,sha256=bJ0u28nFIxQKH1PWQ2ak4PV-FAjhoxTC7YADEdDenFw,83
55
+ cite_agent-1.3.0.dist-info/top_level.txt,sha256=TgOFqJTIy8vDZuOoYA2QgagkqZtfhM5Acvt_IsWzAKo,15
56
+ cite_agent-1.3.0.dist-info/RECORD,,