cite-agent 1.0.5__py3-none-any.whl → 1.2.4__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.

@@ -0,0 +1,276 @@
1
+ """
2
+ Enhanced CLI with workflow integration features
3
+ Reduces context switching for scholars
4
+ """
5
+
6
+ import asyncio
7
+ import json
8
+ import os
9
+ from pathlib import Path
10
+ from typing import Dict, List, Any, Optional
11
+ try:
12
+ import structlog
13
+ except ImportError:
14
+ import logging
15
+ structlog = logging
16
+
17
+ from .enhanced_ai_agent import EnhancedNocturnalAgent, ChatRequest
18
+ from .workflow_integration import WorkflowIntegration
19
+
20
+ logger = structlog.getLogger(__name__)
21
+
22
+ class WorkflowCLI:
23
+ """Enhanced CLI with workflow integration"""
24
+
25
+ def __init__(self):
26
+ self.agent = None
27
+ self.workflow = WorkflowIntegration()
28
+ self.session_id = f"workflow_{os.getpid()}"
29
+
30
+ async def initialize(self):
31
+ """Initialize the agent and workflow"""
32
+ self.agent = EnhancedNocturnalAgent()
33
+ await self.agent.initialize()
34
+
35
+ async def close(self):
36
+ """Clean up resources"""
37
+ if self.agent:
38
+ await self.agent.close()
39
+
40
+ async def search_and_save(self, query: str, user_id: str = "default") -> Dict[str, Any]:
41
+ """Search papers and save to library"""
42
+ try:
43
+ # Search for papers
44
+ request = ChatRequest(
45
+ question=f"Find academic papers about: {query}",
46
+ user_id=user_id,
47
+ conversation_id=self.session_id
48
+ )
49
+
50
+ response = await self.agent.process_request(request)
51
+
52
+ # Extract papers from response
53
+ papers = self._extract_papers_from_response(response)
54
+
55
+ # Save papers to library
56
+ saved_papers = []
57
+ for paper in papers:
58
+ paper_id = self.workflow.save_paper_to_library(paper, user_id)
59
+ saved_papers.append({
60
+ "id": paper_id,
61
+ "title": paper.get("title", "Unknown Title")
62
+ })
63
+
64
+ # Save session
65
+ session_id = self.workflow.save_session_history(
66
+ user_id,
67
+ query,
68
+ {
69
+ "response": response.response,
70
+ "papers": papers,
71
+ "tools_used": response.tools_used
72
+ }
73
+ )
74
+
75
+ return {
76
+ "success": True,
77
+ "papers_found": len(papers),
78
+ "papers_saved": len(saved_papers),
79
+ "session_id": session_id,
80
+ "saved_papers": saved_papers
81
+ }
82
+
83
+ except Exception as e:
84
+ logger.error("Error in search_and_save", error=str(e))
85
+ return {"success": False, "error": str(e)}
86
+
87
+ def _extract_papers_from_response(self, response) -> List[Dict[str, Any]]:
88
+ """Extract paper data from agent response"""
89
+ papers = []
90
+
91
+ # Try to extract from execution_results
92
+ if hasattr(response, 'execution_results') and response.execution_results:
93
+ for result in response.execution_results.values():
94
+ if isinstance(result, dict) and 'papers' in result:
95
+ papers.extend(result['papers'])
96
+
97
+ # Try to extract from api_results
98
+ if hasattr(response, 'api_results') and response.api_results:
99
+ for result in response.api_results.values():
100
+ if isinstance(result, dict) and 'papers' in result:
101
+ papers.extend(result['papers'])
102
+
103
+ return papers
104
+
105
+ async def export_library(self, user_id: str, format: str = "bibtex") -> str:
106
+ """Export user's library in specified format"""
107
+ try:
108
+ library = self.workflow.get_user_library(user_id)
109
+ papers = [paper_data.get('paper', {}) for paper_data in library]
110
+
111
+ if format == "bibtex":
112
+ filename = f"library_{user_id}.bib"
113
+ file_path = self.workflow.export_to_bibtex(papers, filename)
114
+ elif format == "markdown":
115
+ filename = f"library_{user_id}.md"
116
+ file_path = self.workflow.export_to_markdown(papers, filename)
117
+ else:
118
+ raise ValueError(f"Unsupported format: {format}")
119
+
120
+ return file_path
121
+
122
+ except Exception as e:
123
+ logger.error("Error exporting library", error=str(e))
124
+ raise
125
+
126
+ def search_library(self, user_id: str, query: str) -> List[Dict[str, Any]]:
127
+ """Search user's saved library"""
128
+ return self.workflow.search_library(user_id, query)
129
+
130
+ def get_library_stats(self, user_id: str) -> Dict[str, Any]:
131
+ """Get library statistics"""
132
+ library = self.workflow.get_user_library(user_id)
133
+ sessions = self.workflow.get_session_history(user_id, 100)
134
+
135
+ # Calculate stats
136
+ total_papers = len(library)
137
+
138
+ # Papers by year
139
+ papers_by_year = {}
140
+ for paper_data in library:
141
+ paper = paper_data.get('paper', {})
142
+ year = paper.get('year', 'Unknown')
143
+ papers_by_year[year] = papers_by_year.get(year, 0) + 1
144
+
145
+ # Most used tools
146
+ tools_used = {}
147
+ for session in sessions:
148
+ for tool in session.get('tools_used', []):
149
+ tools_used[tool] = tools_used.get(tool, 0) + 1
150
+
151
+ return {
152
+ "total_papers": total_papers,
153
+ "total_sessions": len(sessions),
154
+ "papers_by_year": papers_by_year,
155
+ "most_used_tools": dict(sorted(tools_used.items(), key=lambda x: x[1], reverse=True)[:5])
156
+ }
157
+
158
+ async def get_citation_suggestions(self, paper: Dict[str, Any]) -> List[str]:
159
+ """Get citation suggestions for a paper"""
160
+ return self.workflow.generate_citation_suggestions(paper)
161
+
162
+ def get_session_history(self, user_id: str, limit: int = 10) -> List[Dict[str, Any]]:
163
+ """Get recent session history"""
164
+ return self.workflow.get_session_history(user_id, limit)
165
+
166
+ async def interactive_workflow(self, user_id: str = "default"):
167
+ """Interactive workflow mode"""
168
+ print("🔬 Cite-Agent Workflow Mode")
169
+ print("=" * 50)
170
+ print("Commands:")
171
+ print(" search <query> - Search and save papers")
172
+ print(" library - Show saved papers")
173
+ print(" export <format> - Export library (bibtex/markdown)")
174
+ print(" stats - Show library statistics")
175
+ print(" history - Show recent searches")
176
+ print(" suggest <title> - Get citation suggestions")
177
+ print(" quit - Exit workflow mode")
178
+ print()
179
+
180
+ while True:
181
+ try:
182
+ command = input("workflow> ").strip()
183
+
184
+ if command.lower() in ['quit', 'exit', 'q']:
185
+ break
186
+ elif command.startswith('search '):
187
+ query = command[7:].strip()
188
+ if query:
189
+ result = await self.search_and_save(query, user_id)
190
+ if result['success']:
191
+ print(f"✅ Found {result['papers_found']} papers, saved {result['papers_saved']}")
192
+ else:
193
+ print(f"❌ Error: {result.get('error', 'Unknown error')}")
194
+ else:
195
+ print("❌ Please provide a search query")
196
+
197
+ elif command == 'library':
198
+ library = self.workflow.get_user_library(user_id)
199
+ if library:
200
+ print(f"📚 Library ({len(library)} papers):")
201
+ for i, paper_data in enumerate(library[:10], 1):
202
+ paper = paper_data.get('paper', {})
203
+ title = paper.get('title', 'Unknown Title')[:60]
204
+ year = paper.get('year', 'Unknown')
205
+ print(f" {i}. {title}... ({year})")
206
+ if len(library) > 10:
207
+ print(f" ... and {len(library) - 10} more")
208
+ else:
209
+ print("📚 Library is empty")
210
+
211
+ elif command.startswith('export '):
212
+ format = command[7:].strip().lower()
213
+ if format in ['bibtex', 'markdown']:
214
+ try:
215
+ file_path = await self.export_library(user_id, format)
216
+ print(f"✅ Exported to: {file_path}")
217
+ except Exception as e:
218
+ print(f"❌ Export error: {e}")
219
+ else:
220
+ print("❌ Supported formats: bibtex, markdown")
221
+
222
+ elif command == 'stats':
223
+ stats = self.get_library_stats(user_id)
224
+ print("📊 Library Statistics:")
225
+ print(f" Total papers: {stats['total_papers']}")
226
+ print(f" Total sessions: {stats['total_sessions']}")
227
+ print(" Papers by year:")
228
+ for year, count in sorted(stats['papers_by_year'].items()):
229
+ print(f" {year}: {count}")
230
+ print(" Most used tools:")
231
+ for tool, count in stats['most_used_tools'].items():
232
+ print(f" {tool}: {count}")
233
+
234
+ elif command == 'history':
235
+ history = self.get_session_history(user_id, 5)
236
+ if history:
237
+ print("🕒 Recent Searches:")
238
+ for i, session in enumerate(history, 1):
239
+ query = session.get('query', 'Unknown')[:50]
240
+ timestamp = session.get('timestamp', 'Unknown')[:19]
241
+ papers = session.get('papers_found', 0)
242
+ print(f" {i}. {query}... ({papers} papers) - {timestamp}")
243
+ else:
244
+ print("🕒 No search history")
245
+
246
+ elif command.startswith('suggest '):
247
+ title = command[8:].strip()
248
+ if title:
249
+ # Find paper in library
250
+ library = self.workflow.get_user_library(user_id)
251
+ paper = None
252
+ for paper_data in library:
253
+ if title.lower() in paper_data.get('paper', {}).get('title', '').lower():
254
+ paper = paper_data.get('paper', {})
255
+ break
256
+
257
+ if paper:
258
+ suggestions = await self.get_citation_suggestions(paper)
259
+ print(f"💡 Suggestions for '{paper.get('title', 'Unknown')}':")
260
+ for suggestion in suggestions:
261
+ print(f" • {suggestion}")
262
+ else:
263
+ print(f"❌ Paper not found in library: {title}")
264
+ else:
265
+ print("❌ Please provide a paper title")
266
+
267
+ else:
268
+ print("❌ Unknown command. Type 'quit' to exit.")
269
+
270
+ except KeyboardInterrupt:
271
+ print("\n👋 Goodbye!")
272
+ break
273
+ except Exception as e:
274
+ print(f"❌ Error: {e}")
275
+
276
+ print("👋 Workflow mode ended")