ayechat-dev 0.36.9.20260204171331__py3-none-any.whl → 0.36.9.20260205235944__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.
@@ -13,12 +13,16 @@ from aye.model.source_collector import collect_sources
13
13
  from aye.model.auth import get_user_config
14
14
  from aye.model.offline_llm_manager import is_offline_model
15
15
  from aye.controller.util import is_truncated_json
16
- from aye.model.config import SYSTEM_PROMPT, MODELS, DEFAULT_MAX_OUTPUT_TOKENS, DEFAULT_CONTEXT_TARGET_KB
16
+ from aye.model.config import SYSTEM_PROMPT, MODELS, DEFAULT_MAX_OUTPUT_TOKENS, DEFAULT_CONTEXT_TARGET_KB, CONTEXT_HARD_LIMIT_KB
17
17
  from aye.model import telemetry
18
18
 
19
19
  import os
20
20
 
21
21
 
22
+ def _is_verbose():
23
+ return get_user_config("verbose", "off").lower() == "on"
24
+
25
+
22
26
  def _is_debug():
23
27
  return get_user_config("debug", "off").lower() == "on"
24
28
 
@@ -77,7 +81,7 @@ def _get_context_hard_limit(model_id: str) -> int:
77
81
  model_config = _get_model_config(model_id)
78
82
  if model_config and "max_prompt_kb" in model_config:
79
83
  return model_config["max_prompt_kb"] * 1024
80
- return 170 * 1024
84
+ return CONTEXT_HARD_LIMIT_KB * 1024
81
85
 
82
86
 
83
87
  def _filter_ground_truth(files: Dict[str, str], conf: Any, verbose: bool) -> Dict[str, str]:
@@ -134,6 +138,8 @@ def _get_rag_context_files(prompt: str, conf: Any, verbose: bool) -> Dict[str, s
134
138
 
135
139
  context_target_size = _get_context_target_size(conf.selected_model)
136
140
  context_hard_limit = _get_context_hard_limit(conf.selected_model)
141
+ #context_target_size = DEFAULT_CONTEXT_TARGET_KB #_get_context_target_size(conf.selected_model)
142
+ #context_hard_limit = CONTEXT_HARD_LIMIT_KB # _get_context_hard_limit(conf.selected_model)
137
143
 
138
144
  if _is_debug():
139
145
  rprint(f"[yellow]Context target: {context_target_size / 1024:.1f}KB, hard limit: {context_hard_limit / 1024:.1f}KB[/]")
@@ -298,50 +304,54 @@ def invoke_llm(
298
304
  model_config = _get_model_config(conf.selected_model)
299
305
  max_output_tokens = model_config.get("max_output_tokens", DEFAULT_MAX_OUTPUT_TOKENS) if model_config else DEFAULT_MAX_OUTPUT_TOKENS
300
306
 
301
- # 1. Try local/offline model plugins first (no streaming UI for local models)
302
- local_response = plugin_manager.handle_command("local_model_invoke", {
303
- "prompt": prompt,
304
- "model_id": conf.selected_model,
305
- "source_files": source_files,
306
- "chat_id": chat_id,
307
- "root": conf.root,
308
- "system_prompt": system_prompt,
309
- "max_output_tokens": max_output_tokens
310
- })
311
-
312
- if local_response is not None:
313
- return LLMResponse(
314
- summary=local_response.get("summary", ""),
315
- updated_files=local_response.get("updated_files", []),
316
- chat_id=None,
317
- source=LLMSource.LOCAL
318
- )
319
-
320
- # 2. API call with spinner + streaming display
321
- if _is_debug():
322
- print(f"[DEBUG] Processing chat message with chat_id={chat_id or -1}, model={conf.selected_model}")
323
-
324
- telemetry_payload = telemetry.build_payload(top_n=20) if telemetry.is_enabled() else None
325
-
326
- # Create spinner - will be stopped when streaming starts
307
+ # Create spinner - will be shown for ALL model types (local, databricks, API)
327
308
  spinner = StoppableSpinner(
328
309
  console,
329
310
  messages=DEFAULT_THINKING_MESSAGES,
330
311
  interval=15.0
331
312
  )
332
313
 
314
+ # For API calls, we also have streaming display
315
+ streaming_display: Optional[StreamingResponseDisplay] = None
316
+
333
317
  def stop_spinner():
334
- """Callback to stop spinner when first content arrives."""
318
+ """Callback to stop spinner when first content arrives (for streaming API)."""
335
319
  spinner.stop()
336
-
337
- # Create streaming display with callback to stop spinner on first content
338
- streaming_display = StreamingResponseDisplay(on_first_content=stop_spinner)
339
- stream_callback = create_streaming_callback(streaming_display)
340
320
 
341
321
  try:
342
- # Start the spinner before the API call
322
+ # Start the spinner before ANY LLM call (local or API)
343
323
  spinner.start()
344
324
 
325
+ # 1. Try local/offline model plugins first
326
+ local_response = plugin_manager.handle_command("local_model_invoke", {
327
+ "prompt": prompt,
328
+ "model_id": conf.selected_model,
329
+ "source_files": source_files,
330
+ "chat_id": chat_id,
331
+ "root": conf.root,
332
+ "system_prompt": system_prompt,
333
+ "max_output_tokens": max_output_tokens
334
+ })
335
+
336
+ if local_response is not None:
337
+ # Local model handled the request - spinner will be stopped in finally block
338
+ return LLMResponse(
339
+ summary=local_response.get("summary", ""),
340
+ updated_files=local_response.get("updated_files", []),
341
+ chat_id=None,
342
+ source=LLMSource.LOCAL
343
+ )
344
+
345
+ # 2. API call with streaming display
346
+ if _is_debug():
347
+ print(f"[DEBUG] Processing chat message with chat_id={chat_id or -1}, model={conf.selected_model}")
348
+
349
+ telemetry_payload = telemetry.build_payload(top_n=20) if telemetry.is_enabled() else None
350
+
351
+ # Create streaming display with callback to stop spinner on first content
352
+ streaming_display = StreamingResponseDisplay(on_first_content=stop_spinner)
353
+ stream_callback = create_streaming_callback(streaming_display)
354
+
345
355
  api_resp = cli_invoke(
346
356
  message=prompt,
347
357
  chat_id=chat_id or -1,
@@ -352,29 +362,29 @@ def invoke_llm(
352
362
  telemetry=telemetry_payload,
353
363
  on_stream_update=stream_callback
354
364
  )
355
- finally:
356
- # Ensure spinner is stopped (in case no streaming content was received)
357
- spinner.stop()
358
-
359
- # Always stop the streaming display when done
360
- if streaming_display.is_active():
361
- streaming_display.stop()
362
365
 
363
- if telemetry_payload is not None:
364
- telemetry.reset()
366
+ if telemetry_payload is not None:
367
+ telemetry.reset()
365
368
 
366
- if _is_debug():
367
- print(f"[DEBUG] Chat message processed, response keys: {api_resp.keys() if api_resp else 'None'}")
369
+ if _is_debug():
370
+ print(f"[DEBUG] Chat message processed, response keys: {api_resp.keys() if api_resp else 'None'}")
368
371
 
369
- # Check if we already displayed the response via streaming
370
- streamed_summary = bool(api_resp.get("_streamed_summary")) if isinstance(api_resp, dict) else False
372
+ # Check if we already displayed the response via streaming
373
+ streamed_summary = bool(api_resp.get("_streamed_summary")) if isinstance(api_resp, dict) else False
371
374
 
372
- # 3. Parse API response
373
- assistant_resp, new_chat_id = _parse_api_response(api_resp)
375
+ # 3. Parse API response
376
+ assistant_resp, new_chat_id = _parse_api_response(api_resp)
374
377
 
375
- return LLMResponse(
376
- summary="" if streamed_summary else assistant_resp.get("answer_summary", ""),
377
- updated_files=assistant_resp.get("source_files", []),
378
- chat_id=new_chat_id,
379
- source=LLMSource.API
380
- )
378
+ return LLMResponse(
379
+ summary="" if streamed_summary else assistant_resp.get("answer_summary", ""),
380
+ updated_files=assistant_resp.get("source_files", []),
381
+ chat_id=new_chat_id,
382
+ source=LLMSource.API
383
+ )
384
+ finally:
385
+ # Ensure spinner is stopped for ALL code paths (local model, API, or error)
386
+ spinner.stop()
387
+
388
+ # Stop the streaming display if it was created and is active
389
+ if streaming_display is not None and streaming_display.is_active():
390
+ streaming_display.stop()
aye/model/config.py CHANGED
@@ -17,12 +17,17 @@ SMALL_PROJECT_FILE_LIMIT = 200
17
17
  # Projects smaller than this will skip RAG and include all files directly.
18
18
  # Set to match default max_prompt_kb (170KB) so all files can fit in context.
19
19
  SMALL_PROJECT_TOTAL_SIZE_LIMIT = 170 * 1024 # 170KB
20
+ #SMALL_PROJECT_TOTAL_SIZE_LIMIT = 100 * 1024 # 170KB
20
21
 
21
22
  # Default maximum output tokens for LLM responses
22
23
  DEFAULT_MAX_OUTPUT_TOKENS = 32000
24
+ #DEFAULT_MAX_OUTPUT_TOKENS = 16000
23
25
 
24
26
  # Default context target size in KB (used when model doesn't specify one)
25
27
  DEFAULT_CONTEXT_TARGET_KB = 150
28
+ #DEFAULT_CONTEXT_TARGET_KB = 20
29
+
30
+ CONTEXT_HARD_LIMIT_KB = 170
26
31
 
27
32
  # Shared system prompt for all LLM interactions
28
33
  SYSTEM_PROMPT = (
@@ -245,7 +245,8 @@ class DatabricksModelPlugin(Plugin):
245
245
  try:
246
246
  with httpx.Client(timeout=LLM_TIMEOUT) as client:
247
247
  response = client.post(api_url, json=payload, headers=headers)
248
- if self.debug:
248
+ if self.verbose and response.status_code != 200:
249
+ print(f"Status code: {response.status_code}")
249
250
  print("-----------------")
250
251
  print(response.text)
251
252
  print("-----------------")
@@ -136,48 +136,6 @@ class LocalModelPlugin(Plugin):
136
136
  "updated_files": []
137
137
  }
138
138
 
139
- def _handle_databricks(self, prompt: str, source_files: Dict[str, str], chat_id: Optional[int] = None, system_prompt: Optional[str] = None, max_output_tokens: int = DEFAULT_MAX_OUTPUT_TOKENS) -> Optional[Dict[str, Any]]:
140
- api_url = os.environ.get("AYE_DBX_API_URL")
141
- api_key = os.environ.get("AYE_DBX_API_KEY")
142
- model_name = os.environ.get("AYE_DBX_MODEL", "gpt-3.5-turbo")
143
-
144
- if not api_url or not api_key:
145
- return None
146
-
147
- conv_id = self._get_conversation_id(chat_id)
148
- if conv_id not in self.chat_history:
149
- self.chat_history[conv_id] = []
150
-
151
- user_message = self._build_user_message(prompt, source_files)
152
- effective_system_prompt = system_prompt if system_prompt else SYSTEM_PROMPT
153
-
154
- messages = [{"role": "system", "content": effective_system_prompt}] + self.chat_history[conv_id] + [{"role": "user", "content": user_message}]
155
-
156
- headers = {"Content-Type": "application/json", "Authorization": f"Bearer {api_key}"}
157
- payload = {"model": model_name, "messages": messages, "temperature": 0.7, "max_tokens": max_output_tokens, "response_format": {"type": "json_object"}}
158
-
159
- try:
160
- with httpx.Client(timeout=LLM_TIMEOUT) as client:
161
- response = client.post(api_url, json=payload, headers=headers)
162
- response.raise_for_status()
163
- result = response.json()
164
- if result.get("choices") and result["choices"][0].get("message"):
165
- generated_text = result["choices"][0]["message"]["content"][0]["text"]
166
- self.chat_history[conv_id].append({"role": "user", "content": user_message})
167
- self.chat_history[conv_id].append({"role": "assistant", "content": generated_text})
168
- self._save_history()
169
- return self._parse_llm_response(generated_text)
170
- return self._create_error_response("Failed to get a valid response from the Databricks API")
171
- except httpx.HTTPStatusError as e:
172
- error_msg = f"DBX API error: {e.response.status_code}"
173
- try:
174
- error_detail = e.response.json()
175
- if "error" in error_detail:
176
- error_msg += f" - {error_detail['error'].get('message', str(error_detail['error']))}"
177
- except: error_msg += f" - {e.response.text[:200]}"
178
- return self._create_error_response(error_msg)
179
- except Exception as e:
180
- return self._create_error_response(f"Error calling Databricks API: {str(e)}")
181
139
 
182
140
  def _handle_openai_compatible(self, prompt: str, source_files: Dict[str, str], chat_id: Optional[int] = None, system_prompt: Optional[str] = None, max_output_tokens: int = DEFAULT_MAX_OUTPUT_TOKENS) -> Optional[Dict[str, Any]]:
183
141
  """Handle OpenAI-compatible API endpoints.
@@ -288,9 +246,6 @@ class LocalModelPlugin(Plugin):
288
246
  result = self._handle_openai_compatible(prompt, source_files, chat_id, system_prompt, max_output_tokens)
289
247
  if result is not None: return result
290
248
 
291
- result = self._handle_databricks(prompt, source_files, chat_id, system_prompt, max_output_tokens)
292
- if result is not None: return result
293
-
294
249
  if model_id == "google/gemini-2.5-pro":
295
250
  return self._handle_gemini_pro_25(prompt, source_files, chat_id, system_prompt, max_output_tokens)
296
251
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ayechat-dev
3
- Version: 0.36.9.20260204171331
3
+ Version: 0.36.9.20260205235944
4
4
  Summary: Aye Chat: Terminal-first AI Code Generator
5
5
  Author-email: "Acrotron, Inc." <info@acrotron.com>
6
6
  License: MIT
@@ -6,7 +6,7 @@ aye/controller/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  aye/controller/command_handlers.py,sha256=S_HOYY91lbLkGtCkby28T8qUFPNtfy-CbOGn9VGZtTo,17446
7
7
  aye/controller/commands.py,sha256=sXmK_sgNBrw9Fs7mKcr93-wsu740ZlvWSisQfS-1EUE,12278
8
8
  aye/controller/llm_handler.py,sha256=gY3X2rHcvhPp8iqp_Vor7QpbwHltmcm_Uu9MWF1Z598,7120
9
- aye/controller/llm_invoker.py,sha256=p_Vk2a3YrWKwDupLfSVRinR5llDfq1Fb_f7WrYozK6M,14127
9
+ aye/controller/llm_invoker.py,sha256=1TMsF5q9HT5r8F4zZ5HQo_g_eYyt7uBX4d46QsUHY4k,14868
10
10
  aye/controller/plugin_manager.py,sha256=9ZuITyA5sQJJJU-IntLQ1SsxXsDnbgZKPOF4e9VmsEU,3018
11
11
  aye/controller/repl.py,sha256=nSlzAHD8MQlQ7vnpBTLVzA1jQ8jkNjxUnUoqE31chxY,27028
12
12
  aye/controller/tutorial.py,sha256=lc92jOcJOYCVrrjTEF0Suk4-8jn-ku98kTJEIL8taUA,7254
@@ -16,7 +16,7 @@ aye/model/api.py,sha256=HhSMQQ_szdC2ZPOSfNsJRbs1FRwb6WyYIeLejB2ScbA,13272
16
16
  aye/model/ast_chunker.py,sha256=rVcDdynVUXXyxWVgtUcsee_STqB7SAwP776ktWTlYig,4462
17
17
  aye/model/auth.py,sha256=ozV_uQxdqXtUoWO3nZwpzVnDOIfnRAmSMC6W0N724vE,4800
18
18
  aye/model/autodiff_config.py,sha256=b8pyudkJFYXF5JWPxft0bH5uazeCab9i-A11dNt1d7U,931
19
- aye/model/config.py,sha256=o6bQhj5gqhSqtWD6DLow7NNy6Hdaede02h_xb7uPLXo,9280
19
+ aye/model/config.py,sha256=s9c5w4bmOegpNu2CM1z8ITWUbsEzMaX9_BliqHr7KLA,9430
20
20
  aye/model/download_plugins.py,sha256=6omyFGdxlEIb7tKPLq4rRVrRYeCPUUCE8aZHvJAKGSc,4442
21
21
  aye/model/file_processor.py,sha256=b7YGvHAmhGto9JbtzcfrsdkFtksHbosYt-42EnR22Uo,2131
22
22
  aye/model/ignore_patterns.py,sha256=AhcnZuU9_a77Q4yKFRTG6yIrDG4HcECwdY7D1NQkBDY,2767
@@ -43,8 +43,8 @@ aye/plugins/__init__.py,sha256=dSTxs461ICx0O1tbCBCca0W_7QIAa0Yt9PQhHiT5uZQ,173
43
43
  aye/plugins/at_file_completer.py,sha256=uNS4gWpfKvn9_nGxZbhQVjVg_S82g977gfBR-pL3XrQ,19582
44
44
  aye/plugins/auto_detect_mask.py,sha256=gZKH4qkR-A73uKpMkPXhlgI452Ae_2YG1nHtaIkOvwM,6864
45
45
  aye/plugins/completer.py,sha256=qhxke5Q76P2u0LojSIL3V48RTNG5tWL-5-TK5tNutrE,13893
46
- aye/plugins/databricks_model.py,sha256=GovUJIYfX1cez7QitIg0q0NDwJC2XWPbuN5-ij_ap0E,12394
47
- aye/plugins/local_model.py,sha256=q0RjSjLhEQcDMOCLAK6k1YCW5ECrvdT_g0lKRHMX-AE,14810
46
+ aye/plugins/databricks_model.py,sha256=TpERRIZKh_vJBVu630ModfT2geMXwEEX5XDqzlLt7dI,12494
47
+ aye/plugins/local_model.py,sha256=u3cVLkAD2XGaEvXEFKnmZcDhmqFOi1aqD0ocgysxwCc,12036
48
48
  aye/plugins/offline_llm.py,sha256=qFmd1e8Lbl7yiMgXpXjOQkQTNxOk0_WXU7km2DTKXGY,13357
49
49
  aye/plugins/plugin_base.py,sha256=t5hTOnA0dZC237BnseAgdXbOqErlSCNLUo_Uul09TSw,1673
50
50
  aye/plugins/shell_executor.py,sha256=a0mlZnQeURONdtPM7iageTcQ8PiNLQbjxoY54EsS32o,7502
@@ -55,9 +55,9 @@ aye/presenter/diff_presenter.py,sha256=cbxfOEqGomPTDvQpKdybfYeNUD2DYVAl85j1uy5--
55
55
  aye/presenter/repl_ui.py,sha256=PVENlAQM_tm_k2dANsmQH6I8ATMVXhrdj_hNzc38pSw,8156
56
56
  aye/presenter/streaming_ui.py,sha256=_3tBEuNH9UQ9Gyq2yuvRfX4SWVkcGMYirEUGj-MXVJ0,12768
57
57
  aye/presenter/ui_utils.py,sha256=6KXR4_ZZZUdF5pCHrPqO8yywlQk7AOzWe-2B4Wj_-ZQ,5441
58
- ayechat_dev-0.36.9.20260204171331.dist-info/licenses/LICENSE,sha256=U1ou6lkMKmPo16-E9YowIu3goU7sOWKUprGo0AOA72s,1065
59
- ayechat_dev-0.36.9.20260204171331.dist-info/METADATA,sha256=RBqHPQMpPSHeodf19lvhv16fVdbDMweFxpdUg0EBY50,7718
60
- ayechat_dev-0.36.9.20260204171331.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
61
- ayechat_dev-0.36.9.20260204171331.dist-info/entry_points.txt,sha256=KGsOma6szoefNN6vHozg3Pbf1fjZ7ZbmwrOiVwBd0Ik,41
62
- ayechat_dev-0.36.9.20260204171331.dist-info/top_level.txt,sha256=7WZL0LOx4-GKKvgU1mtI5s4Dhk2OdieVZZvVnxFJHr8,4
63
- ayechat_dev-0.36.9.20260204171331.dist-info/RECORD,,
58
+ ayechat_dev-0.36.9.20260205235944.dist-info/licenses/LICENSE,sha256=U1ou6lkMKmPo16-E9YowIu3goU7sOWKUprGo0AOA72s,1065
59
+ ayechat_dev-0.36.9.20260205235944.dist-info/METADATA,sha256=5Q9LhxUYe4U-aCCtJqe4zSXokZWji5uVCwdMgjgWqL0,7718
60
+ ayechat_dev-0.36.9.20260205235944.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
61
+ ayechat_dev-0.36.9.20260205235944.dist-info/entry_points.txt,sha256=KGsOma6szoefNN6vHozg3Pbf1fjZ7ZbmwrOiVwBd0Ik,41
62
+ ayechat_dev-0.36.9.20260205235944.dist-info/top_level.txt,sha256=7WZL0LOx4-GKKvgU1mtI5s4Dhk2OdieVZZvVnxFJHr8,4
63
+ ayechat_dev-0.36.9.20260205235944.dist-info/RECORD,,