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

Files changed (48) hide show
  1. cite_agent/__init__.py +1 -1
  2. cite_agent/account_client.py +19 -46
  3. cite_agent/agent_backend_only.py +30 -4
  4. cite_agent/cli.py +397 -64
  5. cite_agent/cli_conversational.py +294 -0
  6. cite_agent/cli_workflow.py +276 -0
  7. cite_agent/enhanced_ai_agent.py +3222 -117
  8. cite_agent/session_manager.py +215 -0
  9. cite_agent/setup_config.py +5 -21
  10. cite_agent/streaming_ui.py +252 -0
  11. cite_agent/updater.py +50 -17
  12. cite_agent/workflow.py +427 -0
  13. cite_agent/workflow_integration.py +275 -0
  14. cite_agent-1.2.3.dist-info/METADATA +442 -0
  15. cite_agent-1.2.3.dist-info/RECORD +54 -0
  16. {cite_agent-1.0.4.dist-info → cite_agent-1.2.3.dist-info}/top_level.txt +1 -0
  17. src/__init__.py +1 -0
  18. src/services/__init__.py +132 -0
  19. src/services/auth_service/__init__.py +3 -0
  20. src/services/auth_service/auth_manager.py +33 -0
  21. src/services/graph/__init__.py +1 -0
  22. src/services/graph/knowledge_graph.py +194 -0
  23. src/services/llm_service/__init__.py +5 -0
  24. src/services/llm_service/llm_manager.py +495 -0
  25. src/services/paper_service/__init__.py +5 -0
  26. src/services/paper_service/openalex.py +231 -0
  27. src/services/performance_service/__init__.py +1 -0
  28. src/services/performance_service/rust_performance.py +395 -0
  29. src/services/research_service/__init__.py +23 -0
  30. src/services/research_service/chatbot.py +2056 -0
  31. src/services/research_service/citation_manager.py +436 -0
  32. src/services/research_service/context_manager.py +1441 -0
  33. src/services/research_service/conversation_manager.py +597 -0
  34. src/services/research_service/critical_paper_detector.py +577 -0
  35. src/services/research_service/enhanced_research.py +121 -0
  36. src/services/research_service/enhanced_synthesizer.py +375 -0
  37. src/services/research_service/query_generator.py +777 -0
  38. src/services/research_service/synthesizer.py +1273 -0
  39. src/services/search_service/__init__.py +5 -0
  40. src/services/search_service/indexer.py +186 -0
  41. src/services/search_service/search_engine.py +342 -0
  42. src/services/simple_enhanced_main.py +287 -0
  43. cite_agent/__distribution__.py +0 -7
  44. cite_agent-1.0.4.dist-info/METADATA +0 -234
  45. cite_agent-1.0.4.dist-info/RECORD +0 -23
  46. {cite_agent-1.0.4.dist-info → cite_agent-1.2.3.dist-info}/WHEEL +0 -0
  47. {cite_agent-1.0.4.dist-info → cite_agent-1.2.3.dist-info}/entry_points.txt +0 -0
  48. {cite_agent-1.0.4.dist-info → cite_agent-1.2.3.dist-info}/licenses/LICENSE +0 -0
cite_agent/__init__.py CHANGED
@@ -7,7 +7,7 @@ prior stacks preserved only in Git history, kept out of the runtime footprint.
7
7
 
8
8
  from .enhanced_ai_agent import EnhancedNocturnalAgent, ChatRequest, ChatResponse
9
9
 
10
- __version__ = "1.0.4"
10
+ __version__ = "0.9.0b1"
11
11
  __author__ = "Nocturnal Archive Team"
12
12
  __email__ = "contact@nocturnal.dev"
13
13
 
@@ -63,28 +63,14 @@ class AccountClient:
63
63
  )
64
64
  self.timeout = timeout
65
65
 
66
- def provision(self, email: str, password: str, is_new_user: bool = False) -> AccountCredentials:
67
- """
68
- Provision account credentials (login or register).
69
-
70
- Args:
71
- email: User email address
72
- password: User password
73
- is_new_user: True for registration, False for login
74
-
75
- Returns:
76
- AccountCredentials object
77
-
78
- Raises:
79
- AccountProvisioningError: If authentication fails
80
- """
66
+ def provision(self, email: str, password: str) -> AccountCredentials:
81
67
  if self.base_url:
82
- payload = self._request_credentials(email, password, is_new_user=is_new_user)
68
+ payload = self._request_credentials(email, password)
83
69
  return AccountCredentials.from_payload(email=email, payload=payload)
84
70
  return self._generate_offline_credentials(email, password)
85
71
 
86
72
  # -- internal helpers -------------------------------------------------
87
- def _request_credentials(self, email: str, password: str, is_new_user: bool = False) -> Dict[str, Any]:
73
+ def _request_credentials(self, email: str, password: str) -> Dict[str, Any]:
88
74
  try: # pragma: no cover - requires network
89
75
  import requests # type: ignore
90
76
  except Exception as exc: # pragma: no cover - executed when requests missing
@@ -92,42 +78,29 @@ class AccountClient:
92
78
  "The 'requests' package is required for control-plane authentication"
93
79
  ) from exc
94
80
 
95
- # Choose endpoint based on is_new_user flag
96
- if is_new_user:
97
- endpoint = self.base_url.rstrip("/") + "/api/auth/register"
98
- operation = "registration"
99
- else:
100
- endpoint = self.base_url.rstrip("/") + "/api/auth/login"
101
- operation = "login"
102
-
81
+ # Try login first
82
+ login_endpoint = self.base_url.rstrip("/") + "/api/auth/login"
103
83
  body = {"email": email, "password": password}
104
84
 
105
85
  try:
106
- response = requests.post(endpoint, json=body, timeout=self.timeout)
86
+ response = requests.post(login_endpoint, json=body, timeout=self.timeout)
107
87
  except Exception as exc: # pragma: no cover - network failure
108
- raise AccountProvisioningError(f"Failed to reach control plane for {operation}") from exc
88
+ raise AccountProvisioningError("Failed to reach control plane") from exc
109
89
 
110
- # Handle errors
90
+ # If login fails with 401 (user doesn't exist), try registration
91
+ if response.status_code == 401:
92
+ register_endpoint = self.base_url.rstrip("/") + "/api/auth/register"
93
+ try:
94
+ response = requests.post(register_endpoint, json=body, timeout=self.timeout)
95
+ except Exception as exc:
96
+ raise AccountProvisioningError("Failed to register account") from exc
97
+
98
+ # If still failing, raise error
111
99
  if response.status_code >= 400:
112
100
  detail = self._extract_error_detail(response)
113
-
114
- # Provide helpful error messages
115
- if response.status_code == 401 and not is_new_user:
116
- raise AccountProvisioningError(
117
- f"Login failed: Invalid email or password. If you're a new user, please register first."
118
- )
119
- elif response.status_code == 409:
120
- raise AccountProvisioningError(
121
- f"Registration failed: This email is already registered. Please log in instead."
122
- )
123
- elif response.status_code == 400 and "academic" in detail.lower():
124
- raise AccountProvisioningError(
125
- f"Registration requires an academic email address (.edu, .ac.uk, etc.)"
126
- )
127
- else:
128
- raise AccountProvisioningError(
129
- f"{operation.capitalize()} failed (status {response.status_code}): {detail}"
130
- )
101
+ raise AccountProvisioningError(
102
+ f"Authentication failed (status {response.status_code}): {detail}"
103
+ )
131
104
 
132
105
  try:
133
106
  payload = response.json()
@@ -24,6 +24,7 @@ class ChatResponse:
24
24
  tools_used: list = None
25
25
  model: str = "backend"
26
26
  timestamp: str = None
27
+ tokens_used: int = 0
27
28
 
28
29
  def __post_init__(self):
29
30
  if self.timestamp is None:
@@ -45,6 +46,7 @@ class EnhancedNocturnalAgent:
45
46
  or "https://cite-agent-api-720dfadd602c.herokuapp.com"
46
47
  )
47
48
  self.auth_token = None
49
+ self.daily_token_usage = 0
48
50
  self._load_auth()
49
51
 
50
52
  def _load_auth(self):
@@ -66,10 +68,8 @@ class EnhancedNocturnalAgent:
66
68
  async def initialize(self):
67
69
  """Initialize agent"""
68
70
  if not self.auth_token:
69
- raise RuntimeError(
70
- "Not authenticated. Please run 'cite-agent --setup' first."
71
- )
72
- print(f"✅ Connected to backend: {self.backend_url}")
71
+ return False
72
+ return True
73
73
 
74
74
  async def chat(self, request: ChatRequest) -> ChatResponse:
75
75
  """
@@ -170,3 +170,29 @@ class EnhancedNocturnalAgent:
170
170
  "tokens_remaining": data.get("tokens_remaining", 0),
171
171
  "daily_limit": 25000,
172
172
  }
173
+
174
+ async def process_request(self, request: ChatRequest) -> ChatResponse:
175
+ """Process request (alias for chat method for CLI compatibility)"""
176
+ return await self.chat(request)
177
+
178
+ def get_usage_stats(self) -> Dict[str, Any]:
179
+ """Get usage statistics for CLI display"""
180
+ try:
181
+ quota = self.check_quota()
182
+ tokens_used = quota.get("tokens_used", 0)
183
+ daily_limit = quota.get("daily_limit", 50000)
184
+ usage_pct = (tokens_used / daily_limit * 100) if daily_limit > 0 else 0
185
+
186
+ return {
187
+ "daily_tokens_used": tokens_used,
188
+ "daily_token_limit": daily_limit,
189
+ "usage_percentage": usage_pct,
190
+ "tokens_remaining": quota.get("tokens_remaining", 0)
191
+ }
192
+ except Exception:
193
+ return {
194
+ "daily_tokens_used": 0,
195
+ "daily_token_limit": 50000,
196
+ "usage_percentage": 0,
197
+ "tokens_remaining": 50000
198
+ }