lollms-client 1.6.7__py3-none-any.whl → 1.6.10__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 lollms-client might be problematic. Click here for more details.

lollms_client/__init__.py CHANGED
@@ -8,7 +8,7 @@ from lollms_client.lollms_utilities import PromptReshaper # Keep general utiliti
8
8
  from lollms_client.lollms_mcp_binding import LollmsMCPBinding, LollmsMCPBindingManager
9
9
  from lollms_client.lollms_llm_binding import LollmsLLMBindingManager
10
10
 
11
- __version__ = "1.6.7" # Updated version
11
+ __version__ = "1.6.10" # Updated version
12
12
 
13
13
  # Optionally, you could define __all__ if you want to be explicit about exports
14
14
  __all__ = [
@@ -65,19 +65,21 @@ class TaskPlanner:
65
65
  def __init__(self, llm_client):
66
66
  self.llm_client = llm_client
67
67
 
68
- def decompose_task(self, user_request: str, context: str = "") -> ExecutionPlan:
68
+ def decompose_task(self, user_request: str, context: str = "", all_visible_tools:str="") -> ExecutionPlan:
69
69
  """Break down complex requests into manageable subtasks"""
70
70
  decomposition_prompt = f"""
71
71
  Analyze this user request and break it down into specific, actionable subtasks:
72
72
 
73
73
  USER REQUEST: "{user_request}"
74
74
  CONTEXT: {context}
75
+ AVAILABLE TOOLS: {all_visible_tools}
75
76
 
76
77
  Create a JSON plan with subtasks that are:
77
78
  1. Specific and actionable
78
79
  2. Have clear success criteria
79
80
  3. Include estimated complexity (1-5 scale)
80
81
  4. List required tool types
82
+ 5. The tasks should either be thought based, or use one of the available tools. Do not plan tasks we can not do.
81
83
 
82
84
  Output format:
83
85
  {{
@@ -358,4 +360,4 @@ class UncertaintyManager:
358
360
  else:
359
361
  level = ConfidenceLevel.LOW
360
362
 
361
- return confidence, level
363
+ return confidence, level
@@ -91,21 +91,6 @@ class LollmsClient():
91
91
  stt_binding_config (Optional[Dict]): Additional config for the STT binding.
92
92
  ttv_binding_config (Optional[Dict]): Additional config for the TTV binding.
93
93
  ttm_binding_config (Optional[Dict]): Additional config for the TTM binding.
94
- service_key (Optional[str]): Shared authentication key or client_id.
95
- verify_ssl_certificate (bool): Whether to verify SSL certificates.
96
- ctx_size (Optional[int]): Default context size for LLM.
97
- n_predict (Optional[int]): Default max tokens for LLM.
98
- stream (bool): Default streaming mode for LLM.
99
- temperature (float): Default temperature for LLM.
100
- top_k (int): Default top_k for LLM.
101
- top_p (float): Default top_p for LLM.
102
- repeat_penalty (float): Default repeat penalty for LLM.
103
- repeat_last_n (int): Default repeat last n for LLM.
104
- seed (Optional[int]): Default seed for LLM.
105
- n_threads (int): Default threads for LLM.
106
- streaming_callback (Optional[Callable]): Default streaming callback for LLM.
107
- user_name (str): Default user name for prompts.
108
- ai_name (str): Default AI name for prompts.
109
94
 
110
95
  Raises:
111
96
  ValueError: If the primary LLM binding cannot be created.
@@ -160,93 +145,119 @@ class LollmsClient():
160
145
  except Exception as e:
161
146
  trace_exception(e)
162
147
  ASCIIColors.warning(f"Exception occurred while creating TTS binding: {str(e)}")
148
+ self.tts = None
163
149
 
164
150
  if tti_binding_name:
165
- if tti_binding_config:
166
- self.tti = self.tti_binding_manager.create_binding(
167
- binding_name=tti_binding_name,
168
- **{
169
- k: v
170
- for k, v in (tti_binding_config or {}).items()
171
- if k != "binding_name"
172
- }
173
- )
174
- else:
175
- self.tti = self.tti_binding_manager.create_binding(
176
- binding_name=tti_binding_name
177
- )
178
- if self.tti is None:
179
- ASCIIColors.warning(f"Failed to create TTI binding: {tti_binding_name}. Available: {self.tti_binding_manager.get_available_bindings()}")
180
-
151
+ try:
152
+ if tti_binding_config:
153
+ self.tti = self.tti_binding_manager.create_binding(
154
+ binding_name=tti_binding_name,
155
+ **{
156
+ k: v
157
+ for k, v in (tti_binding_config or {}).items()
158
+ if k != "binding_name"
159
+ }
160
+ )
161
+ else:
162
+ self.tti = self.tti_binding_manager.create_binding(
163
+ binding_name=tti_binding_name
164
+ )
165
+ if self.tti is None:
166
+ ASCIIColors.warning(f"Failed to create TTI binding: {tti_binding_name}. Available: {self.tti_binding_manager.get_available_bindings()}")
167
+ except Exception as e:
168
+ trace_exception(e)
169
+ ASCIIColors.warning(f"Exception occurred while creating TTI binding: {str(e)}")
170
+ self.tti = None
171
+
181
172
  if stt_binding_name:
182
- if stt_binding_config:
183
- self.stt = self.stt_binding_manager.create_binding(
184
- binding_name=stt_binding_name,
185
- **{
186
- k: v
187
- for k, v in (stt_binding_config or {}).items()
188
- if k != "binding_name"
189
- }
190
- )
173
+ try:
174
+ if stt_binding_config:
175
+ self.stt = self.stt_binding_manager.create_binding(
176
+ binding_name=stt_binding_name,
177
+ **{
178
+ k: v
179
+ for k, v in (stt_binding_config or {}).items()
180
+ if k != "binding_name"
181
+ }
182
+ )
191
183
 
192
- else:
193
- self.stt = self.stt_binding_manager.create_binding(
194
- binding_name=stt_binding_name,
195
- )
196
- if self.stt is None:
197
- ASCIIColors.warning(f"Failed to create STT binding: {stt_binding_name}. Available: {self.stt_binding_manager.get_available_bindings()}")
184
+ else:
185
+ self.stt = self.stt_binding_manager.create_binding(
186
+ binding_name=stt_binding_name,
187
+ )
188
+ if self.stt is None:
189
+ ASCIIColors.warning(f"Failed to create STT binding: {stt_binding_name}. Available: {self.stt_binding_manager.get_available_bindings()}")
190
+ except Exception as e:
191
+ trace_exception(e)
192
+ ASCIIColors.warning(f"Exception occurred while creating STT binding: {str(e)}")
193
+ self.stt = None
194
+
198
195
  if ttv_binding_name:
199
- if ttv_binding_config:
200
- self.ttv = self.ttv_binding_manager.create_binding(
201
- binding_name=ttv_binding_name,
202
- **{
203
- k: v
204
- for k, v in ttv_binding_config.items()
205
- if k != "binding_name"
206
- }
207
- )
196
+ try:
197
+ if ttv_binding_config:
198
+ self.ttv = self.ttv_binding_manager.create_binding(
199
+ binding_name=ttv_binding_name,
200
+ **{
201
+ k: v
202
+ for k, v in ttv_binding_config.items()
203
+ if k != "binding_name"
204
+ }
205
+ )
208
206
 
209
- else:
210
- self.ttv = self.ttv_binding_manager.create_binding(
211
- binding_name=ttv_binding_name
212
- )
213
- if self.ttv is None:
214
- ASCIIColors.warning(f"Failed to create TTV binding: {ttv_binding_name}. Available: {self.ttv_binding_manager.get_available_bindings()}")
207
+ else:
208
+ self.ttv = self.ttv_binding_manager.create_binding(
209
+ binding_name=ttv_binding_name
210
+ )
211
+ if self.ttv is None:
212
+ ASCIIColors.warning(f"Failed to create TTV binding: {ttv_binding_name}. Available: {self.ttv_binding_manager.get_available_bindings()}")
213
+ except Exception as e:
214
+ trace_exception(e)
215
+ ASCIIColors.warning(f"Exception occurred while creating TTV binding: {str(e)}")
216
+ self.ttv = None
215
217
 
216
218
  if ttm_binding_name:
217
- if ttm_binding_config:
218
- self.ttm = self.ttm_binding_manager.create_binding(
219
- binding_name=ttm_binding_name,
220
- **{
221
- k: v
222
- for k, v in (ttm_binding_config or {}).items()
223
- if k != "binding_name"
224
- }
225
- )
226
- else:
227
- self.ttm = self.ttm_binding_manager.create_binding(
228
- binding_name=ttm_binding_name
229
- )
230
- if self.ttm is None:
231
- ASCIIColors.warning(f"Failed to create TTM binding: {ttm_binding_name}. Available: {self.ttm_binding_manager.get_available_bindings()}")
219
+ try:
220
+ if ttm_binding_config:
221
+ self.ttm = self.ttm_binding_manager.create_binding(
222
+ binding_name=ttm_binding_name,
223
+ **{
224
+ k: v
225
+ for k, v in (ttm_binding_config or {}).items()
226
+ if k != "binding_name"
227
+ }
228
+ )
229
+ else:
230
+ self.ttm = self.ttm_binding_manager.create_binding(
231
+ binding_name=ttm_binding_name
232
+ )
233
+ if self.ttm is None:
234
+ ASCIIColors.warning(f"Failed to create TTM binding: {ttm_binding_name}. Available: {self.ttm_binding_manager.get_available_bindings()}")
235
+ except Exception as e:
236
+ trace_exception(e)
237
+ ASCIIColors.warning(f"Exception occurred while creating TTM binding: {str(e)}")
238
+ self.ttm = None
232
239
 
233
240
  if mcp_binding_name:
234
- if mcp_binding_config:
235
- self.mcp = self.mcp_binding_manager.create_binding(
236
- binding_name=mcp_binding_name,
237
- **{
238
- k: v
239
- for k, v in (mcp_binding_config or {}).items()
240
- if k != "binding_name"
241
- }
242
- )
243
- else:
244
- self.mcp = self.mcp_binding_manager.create_binding(
245
- mcp_binding_name
246
- )
247
- if self.mcp is None:
248
- ASCIIColors.warning(f"Failed to create MCP binding: {mcp_binding_name}. Available: {self.mcp_binding_manager.get_available_bindings()}")
249
-
241
+ try:
242
+ if mcp_binding_config:
243
+ self.mcp = self.mcp_binding_manager.create_binding(
244
+ binding_name=mcp_binding_name,
245
+ **{
246
+ k: v
247
+ for k, v in (mcp_binding_config or {}).items()
248
+ if k != "binding_name"
249
+ }
250
+ )
251
+ else:
252
+ self.mcp = self.mcp_binding_manager.create_binding(
253
+ mcp_binding_name
254
+ )
255
+ if self.mcp is None:
256
+ ASCIIColors.warning(f"Failed to create MCP binding: {mcp_binding_name}. Available: {self.mcp_binding_manager.get_available_bindings()}")
257
+ except Exception as e:
258
+ trace_exception(e)
259
+ ASCIIColors.warning(f"Exception occurred while creating MCP binding: {str(e)}")
260
+ self.mcp = None
250
261
  # --- Store Default Generation Parameters ---
251
262
 
252
263
  # --- Prompt Formatting Attributes ---
@@ -1465,7 +1476,7 @@ Provide your response as a single JSON object inside a JSON markdown tag. Use th
1465
1476
  return "🎨 Creating an image based on your request"
1466
1477
 
1467
1478
  # Handle RAG (data store) tools by their pattern
1468
- elif "research::" in tool_name:
1479
+ elif "rag::" in tool_name:
1469
1480
  # Extract the friendly name of the data source
1470
1481
  source_name = tool_name.split("::")[-1].replace("_", " ").title()
1471
1482
  return f"🔍 Searching {source_name} for relevant information"
@@ -1516,7 +1527,8 @@ Provide your response as a single JSON object inside a JSON markdown tag. Use th
1516
1527
  final_answer_temperature=0.7
1517
1528
  if rag_top_k is None:
1518
1529
  rag_top_k=5
1519
-
1530
+
1531
+ tools_infos = []
1520
1532
  def log_event(desc, event_type=MSG_TYPE.MSG_TYPE_CHUNK, meta=None, event_id=None) -> Optional[str]:
1521
1533
  if not streaming_callback: return None
1522
1534
  is_start = event_type == MSG_TYPE.MSG_TYPE_STEP_START
@@ -1543,38 +1555,44 @@ Provide your response as a single JSON object inside a JSON markdown tag. Use th
1543
1555
  mcp_tools = self.mcp.discover_tools(force_refresh=True)
1544
1556
  if isinstance(use_mcps, list):
1545
1557
  filtered_tools = [t for t in mcp_tools if t["name"] in use_mcps]
1558
+ tools_infos+=[f" 🛠️{f['name']}" for f in filtered_tools]
1546
1559
  all_discovered_tools.extend(filtered_tools)
1547
1560
  log_event(f" ✅ Loaded {len(filtered_tools)} specific MCP tools: {', '.join(use_mcps)}", MSG_TYPE.MSG_TYPE_INFO)
1548
1561
  elif use_mcps is True:
1562
+ tools_infos+=[f" 🛠️{f['name']}" for f in mcp_tools]
1549
1563
  all_discovered_tools.extend(mcp_tools)
1550
1564
  log_event(f" ✅ Loaded {len(mcp_tools)} MCP tools", MSG_TYPE.MSG_TYPE_INFO)
1551
1565
 
1552
1566
  if use_data_store:
1553
1567
  log_event(f" 📚 Setting up {len(use_data_store)} knowledge bases...", MSG_TYPE.MSG_TYPE_INFO)
1554
1568
  for name, info in use_data_store.items():
1555
- tool_name, description, call_fn = f"research::{name}", f"Queries the '{name}' knowledge base.", None
1569
+ ASCIIColors.info(f"use_data_store item:\n{name}\n{info}")
1570
+ tool_name, description, call_fn = f"rag::{name}", f"Queries the '{name}' knowledge base.", None
1556
1571
  if callable(info): call_fn = info
1557
1572
  elif isinstance(info, dict):
1558
1573
  if "callable" in info and callable(info["callable"]): call_fn = info["callable"]
1559
- description = info.get("description", description)
1574
+ description = info.get("description", "This is a datastore with the following description: \n" + description)
1560
1575
  if call_fn:
1561
1576
  visible_tools.append({"name": tool_name, "description": description, "input_schema": {"type": "object", "properties": {"query": {"type": "string"}}, "required": ["query"]}})
1562
1577
  rag_registry[tool_name] = call_fn
1563
1578
  rag_tool_specs[tool_name] = {"default_top_k": rag_top_k, "default_min_sim": rag_min_similarity_percent}
1564
- log_event(f" 📖 Ready: {name}", MSG_TYPE.MSG_TYPE_INFO)
1565
-
1579
+ tools_infos.append(f" 📖 {name}")
1566
1580
  visible_tools.extend(all_discovered_tools)
1567
1581
  built_in_tools = [
1568
1582
  {"name": "local_tools::final_answer", "description": "Provide the final answer directly to the user.", "input_schema": {}},
1569
1583
  {"name": "local_tools::request_clarification", "description": "Ask the user for more specific information when the request is ambiguous.", "input_schema": {"type": "object", "properties": {"question": {"type": "string"}}, "required": ["question"]}},
1570
1584
  {"name": "local_tools::revise_plan", "description": "Update the execution plan based on new discoveries or changing requirements.", "input_schema": {"type": "object", "properties": {"reason": {"type": "string"}, "new_plan": {"type": "array"}}, "required": ["reason", "new_plan"]}}
1571
1585
  ]
1586
+ tools_infos+=[f" 🔨 final_answer"," 🔨 request_clarification"," 🔨 revise_plan"]
1587
+
1588
+
1572
1589
  if getattr(self, "tti", None):
1573
1590
  built_in_tools.append({"name": "local_tools::generate_image", "description": "Generate an image from a text description.", "input_schema": {"type": "object", "properties": {"prompt": {"type": "string"}}, "required": ["prompt"]}})
1574
1591
 
1575
1592
  all_visible_tools = visible_tools + built_in_tools
1576
1593
  tool_summary = "\n".join([f"- **{t['name']}**: {t['description']}" for t in all_visible_tools[:20]])
1577
1594
 
1595
+ log_event("\n".join(tools_infos), MSG_TYPE.MSG_TYPE_INFO)
1578
1596
  log_event(f"✅ Ready with {len(all_visible_tools)} total capabilities", MSG_TYPE.MSG_TYPE_STEP_END, event_id=discovery_step_id, meta={"tool_count": len(all_visible_tools), "mcp_tools": len(all_discovered_tools), "rag_tools": len(rag_registry)})
1579
1597
 
1580
1598
  # Enhanced triage with better prompting
@@ -1594,7 +1612,7 @@ AVAILABLE CAPABILITIES:
1594
1612
  Based on the request complexity and available tools, choose the optimal strategy:
1595
1613
 
1596
1614
  1. **DIRECT_ANSWER**: For simple greetings, basic questions, or requests that don't require any tools
1597
- - Use when: The request can be fully answered with your existing knowledge
1615
+ - Use when: The request can be fully answered with your existing knowledge with confidence, and no tool seems to add any significant value to the answer
1598
1616
  - Example: "Hello", "What is Python?", "Explain quantum physics"
1599
1617
 
1600
1618
  2. **REQUEST_CLARIFICATION**: When the request is too vague or ambiguous
@@ -1612,16 +1630,14 @@ Based on the request complexity and available tools, choose the optimal strategy
1612
1630
  Provide your analysis in JSON format:
1613
1631
  {{"thought": "Detailed reasoning about the request complexity and requirements", "strategy": "ONE_OF_THE_FOUR_OPTIONS", "confidence": 0.8, "text_output": "Direct answer or clarification question if applicable", "required_tool_name": "specific tool name if SINGLE_TOOL strategy", "estimated_steps": 3}}"""
1614
1632
 
1615
- log_prompt("Triage Prompt", triage_prompt)
1616
-
1617
1633
  triage_schema = {
1618
1634
  "thought": "string", "strategy": "string", "confidence": "number",
1619
1635
  "text_output": "string", "required_tool_name": "string", "estimated_steps": "number"
1620
1636
  }
1621
- strategy_data = self.generate_structured_content(prompt=triage_prompt, schema=triage_schema, temperature=0.1, **llm_generation_kwargs)
1637
+ strategy_data = self.generate_structured_content(prompt=triage_prompt, schema=triage_schema, temperature=0.1, system_prompt=system_prompt, **llm_generation_kwargs)
1622
1638
  strategy = strategy_data.get("strategy") if strategy_data else "COMPLEX_PLAN"
1623
1639
 
1624
- log_event(f"Strategy analysis complete", MSG_TYPE.MSG_TYPE_INFO, meta={
1640
+ log_event(f"Strategy analysis complete.\n**confidence**: {strategy_data.get('confidence', 0.5)}\n**reasoning**: {strategy_data.get('thought', 'None')}", MSG_TYPE.MSG_TYPE_INFO, meta={
1625
1641
  "strategy": strategy,
1626
1642
  "confidence": strategy_data.get("confidence", 0.5),
1627
1643
  "estimated_steps": strategy_data.get("estimated_steps", 1),
@@ -1760,7 +1776,7 @@ RESPONSE:"""
1760
1776
  }
1761
1777
  if tool_name in descriptions:
1762
1778
  return descriptions[tool_name]
1763
- if "research::" in tool_name:
1779
+ if "rag::" in tool_name:
1764
1780
  return f"🔍 Searching {tool_name.split('::')[-1]} knowledge base"
1765
1781
  if requires_code:
1766
1782
  return "💻 Processing code"
@@ -1829,7 +1845,7 @@ RESPONSE:"""
1829
1845
 
1830
1846
  # Enhanced planning phase
1831
1847
  planning_step_id = log_event_fn("📋 Creating adaptive execution plan...", MSG_TYPE.MSG_TYPE_STEP_START)
1832
- execution_plan = planner.decompose_task(original_user_prompt, context or "")
1848
+ execution_plan = planner.decompose_task(original_user_prompt, context or "", "\n".join([f"{tool['name']}:{tool['description']}" for tool in all_visible_tools]))
1833
1849
  current_plan_version = 1
1834
1850
 
1835
1851
  log_event_fn(f"Initial plan created with {len(execution_plan.tasks)} tasks", MSG_TYPE.MSG_TYPE_INFO, meta={
@@ -4309,27 +4325,29 @@ Provide the final aggregated answer in {output_format} format, directly addressi
4309
4325
  context_fill_percentage: float = 0.75,
4310
4326
  overlap_tokens: int = 150,
4311
4327
  expected_generation_tokens: int = 1500,
4312
- max_scratchpad_tokens: int = 4000, # NEW: Hard limit for scratchpad
4313
- scratchpad_compression_threshold: int = 3000, # NEW: When to compress
4328
+ max_scratchpad_tokens: int = 4000,
4329
+ scratchpad_compression_threshold: int = 3000,
4314
4330
  streaming_callback: Optional[Callable] = None,
4315
4331
  return_scratchpad_only: bool = False,
4316
4332
  debug: bool = True,
4333
+ ctx_size=None,
4317
4334
  **kwargs
4318
4335
  ) -> str:
4319
4336
  """
4320
4337
  Processes long text with FIXED chunk sizing and managed scratchpad growth.
4338
+ Now uses dynamic token calculation based on actual model tokenizer.
4321
4339
  """
4322
4340
 
4323
4341
  if debug:
4324
4342
  print(f"\n🔧 DEBUG: Starting processing with {len(text_to_process):,} characters")
4325
4343
 
4326
4344
  # Validate context fill percentage
4327
- if not (0.1 <= context_fill_percentage <= 0.9):
4328
- raise ValueError(f"context_fill_percentage must be between 0.1 and 0.9, got {context_fill_percentage}")
4345
+ if not (0.1 <= context_fill_percentage <= 1.0):
4346
+ raise ValueError(f"context_fill_percentage must be between 0.1 and 1.0, got {context_fill_percentage}")
4329
4347
 
4330
4348
  # Get context size
4331
4349
  try:
4332
- context_size = self.llm.get_context_size() or 8192
4350
+ context_size = ctx_size or self.llm.default_ctx_size or self.llm.get_context_size() or 8192
4333
4351
  except:
4334
4352
  context_size = 8192
4335
4353
 
@@ -4346,26 +4364,97 @@ Provide the final aggregated answer in {output_format} format, directly addressi
4346
4364
  print(f"🔧 DEBUG: Tokenized into {len(tokens):,} word tokens")
4347
4365
 
4348
4366
  # ========================================
4349
- # FIXED: Calculate chunk size ONCE upfront
4367
+ # ENHANCED: Dynamically calculate token sizes using actual tokenizer
4350
4368
  # ========================================
4351
- base_system_tokens = 150
4352
- user_template_tokens = 250
4353
-
4369
+
4370
+ # Create template system prompt to measure its token size
4371
+ template_system_prompt = (
4372
+ f"You are a component in a multi-step text processing pipeline analyzing step 1 of 100.\n\n"
4373
+ f"**Your Task:** Analyze the 'New Text Chunk' and extract key information relevant to the 'Global Objective'. "
4374
+ f"Review the 'Existing Scratchpad' to avoid repetition. Add ONLY new insights.\n\n"
4375
+ f"**CRITICAL:** Do NOT repeat information already in the scratchpad. "
4376
+ f"If no new relevant information exists, respond with '[No new information found in this chunk.]'"
4377
+ )
4378
+ base_system_tokens = len(self.tokenize(template_system_prompt))
4379
+
4380
+ # Create MINIMAL template user prompt (structure only, without content placeholders)
4381
+ summarization_objective = contextual_prompt or "Create a comprehensive summary by extracting all key facts, concepts, and conclusions."
4382
+
4383
+ # Measure only the structural overhead (headers, formatting, instructions)
4384
+ template_structure = (
4385
+ f"--- Global Objective ---\n{summarization_objective}\n\n"
4386
+ f"--- Progress ---\nStep 100/100 | 10 sections completed, 4000 tokens\n\n" # Worst-case progress text
4387
+ f"--- Existing Scratchpad (for context) ---\n"
4388
+ f"--- New Text Chunk ---\n"
4389
+ f"--- Instructions ---\n"
4390
+ f"Extract NEW key information from this chunk that aligns with the objective. "
4391
+ f"Be concise. Avoid repeating scratchpad content."
4392
+ )
4393
+ user_template_overhead = len(self.tokenize(template_structure))
4394
+
4395
+ if debug:
4396
+ print(f"🔧 DEBUG: Computed system prompt tokens: {base_system_tokens}")
4397
+ print(f"🔧 DEBUG: Computed user template overhead: {user_template_overhead}")
4398
+ print(f"🔧 DEBUG: (Note: Scratchpad and chunk content allocated separately)")
4399
+
4354
4400
  # Reserve space for maximum expected scratchpad size
4355
4401
  reserved_scratchpad_tokens = max_scratchpad_tokens
4356
-
4402
+
4357
4403
  total_budget = int(context_size * context_fill_percentage)
4358
- used_tokens = base_system_tokens + user_template_tokens + reserved_scratchpad_tokens + expected_generation_tokens
4359
-
4404
+ # Only count overhead, not the actual chunk/scratchpad content (that's reserved separately)
4405
+ used_tokens = base_system_tokens + user_template_overhead + reserved_scratchpad_tokens + expected_generation_tokens
4406
+
4360
4407
  # FIXED chunk size - never changes during processing
4361
- FIXED_CHUNK_SIZE = max(500, int(total_budget - used_tokens))
4408
+ FIXED_CHUNK_SIZE = max(1024, int(total_budget - used_tokens))
4409
+
4362
4410
 
4363
4411
  if debug:
4364
- print(f"🔧 DEBUG: FIXED chunk size: {FIXED_CHUNK_SIZE} tokens (will not change)")
4365
- print(f"🔧 DEBUG: Reserved scratchpad space: {reserved_scratchpad_tokens} tokens")
4366
- print(f"🔧 DEBUG: Total budget: {total_budget} tokens")
4412
+ print(f"\n🔧 DEBUG: Token budget breakdown:")
4413
+ print(f" - Context size: {context_size} tokens")
4414
+ print(f" - Fill percentage: {context_fill_percentage} ({int(context_fill_percentage*100)}%)")
4415
+ print(f" - Total budget: {total_budget} tokens")
4416
+ print(f" - System prompt: {base_system_tokens} tokens")
4417
+ print(f" - User template overhead: {user_template_overhead} tokens")
4418
+ print(f" - Reserved scratchpad: {reserved_scratchpad_tokens} tokens")
4419
+ print(f" - Expected generation: {expected_generation_tokens} tokens")
4420
+ print(f" - Total overhead: {used_tokens} tokens")
4421
+ print(f" - Remaining for chunks: {total_budget - used_tokens} tokens")
4422
+ print(f"🔧 DEBUG: FIXED chunk size: {FIXED_CHUNK_SIZE} tokens")
4423
+
4424
+ # Safety check
4425
+ if FIXED_CHUNK_SIZE == 1024:
4426
+ print(f"⚠️ WARNING: Chunk size is at minimum (1024)!")
4427
+ print(f"⚠️ Budget exhausted: {used_tokens} used / {total_budget} available")
4428
+ print(f"⚠️ Consider reducing max_scratchpad_tokens or expected_generation_tokens")
4367
4429
 
4368
4430
  if streaming_callback:
4431
+ streaming_callback(
4432
+ "\n".join([
4433
+ f"\n🔧 DEBUG: Token budget breakdown:",
4434
+ f" - Context size: {context_size} tokens",
4435
+ f" - Fill percentage: {context_fill_percentage} ({int(context_fill_percentage*100)}%)",
4436
+ f" - Total budget: {total_budget} tokens",
4437
+ f" - System prompt: {base_system_tokens} tokens",
4438
+ f" - User template overhead: {user_template_overhead} tokens",
4439
+ f" - Reserved scratchpad: {reserved_scratchpad_tokens} tokens",
4440
+ f" - Expected generation: {expected_generation_tokens} tokens",
4441
+ f" - Total overhead: {used_tokens} tokens",
4442
+ f" - Remaining for chunks: {total_budget - used_tokens} tokens",
4443
+ f"🔧 DEBUG: FIXED chunk size: {FIXED_CHUNK_SIZE} tokens"
4444
+ ]
4445
+ ),
4446
+ MSG_TYPE.MSG_TYPE_STEP
4447
+ )
4448
+ if FIXED_CHUNK_SIZE == 1024:
4449
+ streaming_callback(
4450
+ "\n".join([
4451
+ f"⚠️ WARNING: Chunk size is at minimum (1024)!",
4452
+ f"⚠️ Budget exhausted: {used_tokens} used / {total_budget} available",
4453
+ f"⚠️ Consider reducing max_scratchpad_tokens or expected_generation_tokens"
4454
+ ]
4455
+ ),
4456
+ MSG_TYPE.MSG_TYPE_STEP
4457
+ )
4369
4458
  streaming_callback(
4370
4459
  f"Context Budget: {FIXED_CHUNK_SIZE:,}/{total_budget:,} tokens per chunk (fixed)",
4371
4460
  MSG_TYPE.MSG_TYPE_STEP,
@@ -4416,7 +4505,7 @@ Provide the final aggregated answer in {output_format} format, directly addressi
4416
4505
  print(f"🔧 DEBUG: Total estimated steps: {total_steps}")
4417
4506
 
4418
4507
  # ========================================
4419
- # NEW: Scratchpad compression helper
4508
+ # NEW: Scratchpad compression helper with dynamic token counting
4420
4509
  # ========================================
4421
4510
  def compress_scratchpad(scratchpad_sections: list) -> list:
4422
4511
  """Compress scratchpad when it gets too large"""
@@ -4424,7 +4513,8 @@ Provide the final aggregated answer in {output_format} format, directly addressi
4424
4513
  return scratchpad_sections
4425
4514
 
4426
4515
  combined = "\n\n---\n\n".join(scratchpad_sections)
4427
- current_size = len(combined.split())
4516
+ # ENHANCED: Use actual tokenizer to count
4517
+ current_size = len(self.tokenize(combined))
4428
4518
 
4429
4519
  if current_size <= scratchpad_compression_threshold:
4430
4520
  return scratchpad_sections
@@ -4448,7 +4538,8 @@ Provide the final aggregated answer in {output_format} format, directly addressi
4448
4538
  )
4449
4539
 
4450
4540
  if debug:
4451
- compressed_size = len(compressed.split())
4541
+ # ENHANCED: Use actual tokenizer
4542
+ compressed_size = len(self.tokenize(compressed))
4452
4543
  print(f"🔧 DEBUG: Compressed to {compressed_size} tokens (reduction: {100*(1-compressed_size/current_size):.1f}%)")
4453
4544
 
4454
4545
  return [compressed]
@@ -4479,16 +4570,16 @@ Provide the final aggregated answer in {output_format} format, directly addressi
4479
4570
  {"step": step_number, "total_steps": total_steps, "progress": progress}
4480
4571
  )
4481
4572
 
4482
- # Check and compress scratchpad if needed
4573
+ # ENHANCED: Check and compress scratchpad with actual token counting
4483
4574
  current_scratchpad = "\n\n---\n\n".join(chunk_summaries)
4484
- scratchpad_size = len(current_scratchpad.split())
4575
+ scratchpad_size = len(self.tokenize(current_scratchpad)) if current_scratchpad else 0
4485
4576
 
4486
4577
  if scratchpad_size > scratchpad_compression_threshold:
4487
4578
  if debug:
4488
4579
  print(f"🔧 DEBUG: Scratchpad size ({scratchpad_size}) exceeds threshold, compressing...")
4489
4580
  chunk_summaries = compress_scratchpad(chunk_summaries)
4490
4581
  current_scratchpad = "\n\n---\n\n".join(chunk_summaries)
4491
- scratchpad_size = len(current_scratchpad.split())
4582
+ scratchpad_size = len(self.tokenize(current_scratchpad)) if current_scratchpad else 0
4492
4583
 
4493
4584
  try:
4494
4585
  system_prompt = (
@@ -4512,8 +4603,15 @@ Provide the final aggregated answer in {output_format} format, directly addressi
4512
4603
  f"Be concise. Avoid repeating scratchpad content."
4513
4604
  )
4514
4605
 
4606
+ # ENHANCED: Compute actual prompt size
4607
+ actual_prompt_tokens = len(self.tokenize(user_prompt))
4608
+ actual_system_tokens = len(self.tokenize(system_prompt))
4609
+
4515
4610
  if debug:
4516
- print(f"🔧 DEBUG: Prompt size: {len(user_prompt)} chars, Scratchpad: {scratchpad_size} tokens")
4611
+ print(f"🔧 DEBUG: Actual prompt tokens: {actual_prompt_tokens}")
4612
+ print(f"🔧 DEBUG: Actual system tokens: {actual_system_tokens}")
4613
+ print(f"🔧 DEBUG: Total input tokens: {actual_prompt_tokens + actual_system_tokens}")
4614
+ print(f"🔧 DEBUG: Scratchpad: {scratchpad_size} tokens")
4517
4615
 
4518
4616
  chunk_summary = self.remove_thinking_blocks(self.llm.generate_text(user_prompt, system_prompt=system_prompt, **kwargs))
4519
4617
 
@@ -4589,7 +4687,7 @@ Provide the final aggregated answer in {output_format} format, directly addressi
4589
4687
  streaming_callback("Returning scratchpad content", MSG_TYPE.MSG_TYPE_STEP, {})
4590
4688
  return final_scratchpad.strip()
4591
4689
 
4592
- # Final synthesis
4690
+ # Final synthesis with STRONG objective reinforcement
4593
4691
  if streaming_callback:
4594
4692
  streaming_callback("Synthesizing final response...", MSG_TYPE.MSG_TYPE_STEP_START, {"progress": 95})
4595
4693
 
@@ -4603,20 +4701,47 @@ Provide the final aggregated answer in {output_format} format, directly addressi
4603
4701
  synthesis_objective = contextual_prompt or "Provide a comprehensive, well-structured summary and analysis."
4604
4702
 
4605
4703
  if debug:
4606
- print(f"🔧 DEBUG: Synthesizing from {len(combined_scratchpad):,} chars, {len(chunk_summaries)} sections")
4704
+ final_scratchpad_tokens = len(self.tokenize(combined_scratchpad))
4705
+ print(f"🔧 DEBUG: Synthesizing from {len(combined_scratchpad):,} chars, {final_scratchpad_tokens} tokens, {len(chunk_summaries)} sections")
4607
4706
 
4707
+ # ENHANCED: Strong objective-focused synthesis
4608
4708
  synthesis_system_prompt = (
4609
- "You are an expert at synthesizing information. "
4610
- "Consolidate the analysis sections into a coherent final response. "
4611
- "Eliminate redundancy, organize logically, and use markdown formatting."
4709
+ f"You are completing a multi-step text processing task. "
4710
+ f"Your role is to take analysis sections and produce the FINAL OUTPUT that directly fulfills the user's original objective.\n\n"
4711
+ f"**CRITICAL:** Your output must DIRECTLY ADDRESS the user's objective, NOT just summarize the sections. "
4712
+ f"The sections are intermediate work - transform them into the final deliverable the user requested."
4612
4713
  )
4613
4714
 
4715
+ # ENHANCED: Explicit task reinforcement with examples of what NOT to do
4716
+ task_type_hint = ""
4717
+ if contextual_prompt:
4718
+ lower_prompt = contextual_prompt.lower()
4719
+ if any(word in lower_prompt for word in ['extract', 'list', 'identify', 'find']):
4720
+ task_type_hint = "\n**Task Type:** This is an EXTRACTION/IDENTIFICATION task. Provide a structured list or catalog of items found, NOT a narrative summary."
4721
+ elif any(word in lower_prompt for word in ['analyze', 'evaluate', 'assess', 'examine']):
4722
+ task_type_hint = "\n**Task Type:** This is an ANALYSIS task. Provide insights, patterns, and evaluations, NOT just a description of content."
4723
+ elif any(word in lower_prompt for word in ['compare', 'contrast', 'difference']):
4724
+ task_type_hint = "\n**Task Type:** This is a COMPARISON task. Highlight similarities and differences, NOT separate summaries."
4725
+ elif any(word in lower_prompt for word in ['answer', 'question', 'explain why', 'how does']):
4726
+ task_type_hint = "\n**Task Type:** This is a QUESTION-ANSWERING task. Provide a direct answer, NOT a general overview."
4727
+
4614
4728
  synthesis_user_prompt = (
4615
- f"--- Final Objective ---\n{synthesis_objective}\n\n"
4616
- f"--- Collected Analysis Sections ---\n{combined_scratchpad}\n\n"
4617
- f"--- Instructions ---\n"
4618
- f"Synthesize all information into a comprehensive response addressing the objective. "
4619
- f"Organize with markdown headers, remove repetition, create a polished final document."
4729
+ f"=== ORIGINAL USER OBJECTIVE (MOST IMPORTANT) ===\n{synthesis_objective}\n"
4730
+ f"{task_type_hint}\n\n"
4731
+ f"=== ANALYSIS SECTIONS (Raw Working Material) ===\n{combined_scratchpad}\n\n"
4732
+ f"=== YOUR TASK ===\n"
4733
+ f"Transform the analysis sections above into a final output that DIRECTLY FULFILLS the original objective.\n\n"
4734
+ f"**DO:**\n"
4735
+ f"- Focus exclusively on satisfying the user's original objective stated above\n"
4736
+ f"- Organize information in whatever format best serves that objective\n"
4737
+ f"- Remove redundancy and consolidate related points\n"
4738
+ f"- Use markdown formatting for clarity\n\n"
4739
+ f"**DO NOT:**\n"
4740
+ f"- Provide a generic summary of the sections\n"
4741
+ f"- Describe what the sections contain\n"
4742
+ f"- Create an overview of the analysis process\n"
4743
+ f"- Change the task into something different\n\n"
4744
+ f"Remember: The user asked for '{synthesis_objective}' - deliver exactly that."
4620
4745
  )
4621
4746
 
4622
4747
  try:
@@ -1208,14 +1208,27 @@ class LollmsDiscussion:
1208
1208
  prompt_for_agent = self.export("markdown", branch_tip_id if branch_tip_id else self.active_branch_id)
1209
1209
  if debug:
1210
1210
  ASCIIColors.cyan("\n" + "="*50 + "\n--- DEBUG: AGENTIC TURN TRIGGERED ---\n" + f"--- PROMPT FOR AGENT (from discussion history) ---\n{prompt_for_agent}\n" + "="*50 + "\n")
1211
-
1211
+
1212
+
1213
+ # Combine system prompt and data zones
1214
+ system_prompt_part = (self._system_prompt or "").strip()
1215
+ data_zone_part = self.get_full_data_zone() # This now returns a clean, multi-part block or an empty string
1216
+ full_system_prompt = ""
1217
+
1218
+ # Combine them intelligently
1219
+ if system_prompt_part and data_zone_part:
1220
+ full_system_prompt = f"{system_prompt_part}\n\n{data_zone_part}"
1221
+ elif system_prompt_part:
1222
+ full_system_prompt = system_prompt_part
1223
+ else:
1224
+ full_system_prompt = data_zone_part
1212
1225
  agent_result = self.lollmsClient.generate_with_mcp_rag(
1213
1226
  prompt=prompt_for_agent,
1214
1227
  use_mcps=effective_use_mcps,
1215
1228
  use_data_store=use_data_store,
1216
1229
  max_reasoning_steps=max_reasoning_steps,
1217
1230
  images=images,
1218
- system_prompt = self._system_prompt,
1231
+ system_prompt = full_system_prompt,
1219
1232
  debug=debug,
1220
1233
  **kwargs
1221
1234
  )
@@ -4,7 +4,7 @@ import importlib
4
4
  from pathlib import Path
5
5
  from typing import Optional, List, Dict, Any, Union
6
6
  from ascii_colors import trace_exception
7
-
7
+ import yaml
8
8
  class LollmsSTTBinding(ABC):
9
9
  """Abstract base class for all LOLLMS Speech-to-Text bindings."""
10
10
 
@@ -122,4 +122,58 @@ class LollmsSTTBindingManager:
122
122
  list[str]: List of binding names.
123
123
  """
124
124
  return [binding_dir.name for binding_dir in self.stt_bindings_dir.iterdir()
125
- if binding_dir.is_dir() and (binding_dir / "__init__.py").exists()]
125
+ if binding_dir.is_dir() and (binding_dir / "__init__.py").exists()]
126
+
127
+
128
+ @staticmethod
129
+ def _get_fallback_description(binding_name: str) -> Dict:
130
+ return {
131
+ "binding_name": binding_name,
132
+ "title": binding_name.replace("_", " ").title(),
133
+ "author": "Unknown",
134
+ "version": "N/A",
135
+ "description": f"A binding for {binding_name}. No description.yaml file was found.",
136
+ "input_parameters": [
137
+ {
138
+ "name": "model_name",
139
+ "type": "str",
140
+ "description": "The model name or ID to be used.",
141
+ "mandatory": False,
142
+ "default": ""
143
+ }
144
+ ],
145
+ "generate_audio_parameters": []
146
+ }
147
+ @staticmethod
148
+ def get_bindings_list(stt_bindings_dir: Union[str, Path]) -> List[Dict]:
149
+ bindings_dir = Path(stt_bindings_dir)
150
+ if not bindings_dir.is_dir():
151
+ return []
152
+
153
+ bindings_list = []
154
+ for binding_folder in bindings_dir.iterdir():
155
+ if binding_folder.is_dir() and (binding_folder / "__init__.py").exists():
156
+ binding_name = binding_folder.name
157
+ description_file = binding_folder / "description.yaml"
158
+
159
+ binding_info = {}
160
+ if description_file.exists():
161
+ try:
162
+ with open(description_file, 'r', encoding='utf-8') as f:
163
+ binding_info = yaml.safe_load(f)
164
+ binding_info['binding_name'] = binding_name
165
+ except Exception as e:
166
+ print(f"Error loading description.yaml for {binding_name}: {e}")
167
+ binding_info = LollmsSTTBindingManager._get_fallback_description(binding_name)
168
+ else:
169
+ binding_info = LollmsSTTBindingManager._get_fallback_description(binding_name)
170
+
171
+ bindings_list.append(binding_info)
172
+
173
+ return sorted(bindings_list, key=lambda b: b.get('title', b['binding_name']))
174
+
175
+
176
+ def get_available_bindings(stt_bindings_dir: Union[str, Path] = None) -> List[Dict]:
177
+ if stt_bindings_dir is None:
178
+ stt_bindings_dir = Path(__file__).resolve().parent / "stt_bindings"
179
+ return LollmsSTTBindingManager.get_bindings_list(stt_bindings_dir)
@@ -82,6 +82,7 @@ class WhisperSTTBinding(LollmsSTTBinding):
82
82
  If None, `torch` will attempt to auto-detect. Defaults to None.
83
83
  """
84
84
  super().__init__(binding_name="whisper") # Not applicable
85
+ self.default_model_name = kwargs.get("model_name", "base")
85
86
 
86
87
  if not _whisper_installed:
87
88
  raise ImportError(f"Whisper STT binding dependencies not met. Please ensure 'openai-whisper' and 'torch' are installed. Error: {_whisper_installation_error}")
@@ -104,7 +105,7 @@ class WhisperSTTBinding(LollmsSTTBinding):
104
105
 
105
106
  def _load_whisper_model(self, model_name_to_load: str):
106
107
  """Loads or reloads the Whisper model."""
107
- if model_name_to_load not in self.WHISPER_MODEL_SIZES:
108
+ if model_name_to_load not in whisper.available_models():
108
109
  ASCIIColors.warning(f"'{model_name_to_load}' is not a standard Whisper model size. Attempting to load anyway. Known sizes: {self.WHISPER_MODEL_SIZES}")
109
110
 
110
111
  if self.model is not None and self.loaded_model_name == model_name_to_load:
@@ -202,7 +203,7 @@ class WhisperSTTBinding(LollmsSTTBinding):
202
203
  Returns:
203
204
  List[str]: A list of available Whisper model size identifiers.
204
205
  """
205
- return self.WHISPER_MODEL_SIZES.copy() # Return a copy
206
+ return whisper.available_models() # Return a copy
206
207
 
207
208
  def __del__(self):
208
209
  """Clean up: Unload the model to free resources."""
@@ -31,6 +31,8 @@ class WhisperCppSTTBinding(LollmsSTTBinding):
31
31
  n_threads = kwargs.get("n_threads", 4)
32
32
  extra_whisper_args = kwargs.get("extra_whisper_args", []) # e.g. ["--no-timestamps"]
33
33
 
34
+ self.default_model_name = "base"
35
+
34
36
  # --- Validate FFMPEG ---
35
37
  self.ffmpeg_exe = None
36
38
  if ffmpeg_path:
@@ -376,4 +378,8 @@ if __name__ == '__main__':
376
378
  TEST_MODELS_SEARCH_DIR.rmdir()
377
379
  except OSError: pass # Ignore if not empty or other issues
378
380
 
379
- ASCIIColors.yellow("\n--- WhisperCppSTTBinding Test Finished ---")
381
+ ASCIIColors.yellow("\n--- WhisperCppSTTBinding Test Finished ---")
382
+
383
+ def list_models(self) -> List[Dict[str, Any]]:
384
+ return ["base" , "small", "medium", "large"]
385
+
@@ -45,7 +45,7 @@ class DiffusersBinding(LollmsTTIBinding):
45
45
 
46
46
  self.config = kwargs
47
47
  self.host = kwargs.get("host", "localhost")
48
- self.port = kwargs.get("port", 9630)
48
+ self.port = kwargs.get("port", 9632)
49
49
  self.auto_start_server = kwargs.get("auto_start_server", True)
50
50
  self.server_process = None
51
51
  self.base_url = f"http://{self.host}:{self.port}"
@@ -61,7 +61,7 @@ class DiffusersBinding(LollmsTTIBinding):
61
61
  def is_server_running(self) -> bool:
62
62
  """Checks if the server is already running and responsive."""
63
63
  try:
64
- response = requests.get(f"{self.base_url}/status", timeout=2)
64
+ response = requests.get(f"{self.base_url}/status", timeout=4)
65
65
  if response.status_code == 200 and response.json().get("status") == "running":
66
66
  return True
67
67
  except requests.exceptions.RequestException:
@@ -90,7 +90,7 @@ class DiffusersBinding(LollmsTTIBinding):
90
90
  try:
91
91
  # Try to acquire the lock with a timeout. If another process is starting
92
92
  # the server, this will wait until it's finished.
93
- with lock.acquire(timeout=60):
93
+ with lock.acquire(timeout=3):
94
94
  # After acquiring the lock, we MUST re-check if the server is running.
95
95
  # Another process might have started it and released the lock while we were waiting.
96
96
  if not self.is_server_running():
@@ -105,7 +105,7 @@ class DiffusersBinding(LollmsTTIBinding):
105
105
  # This happens if the process holding the lock takes more than 60 seconds to start the server.
106
106
  # We don't try to start another one. We just wait for the existing one to be ready.
107
107
  ASCIIColors.yellow("Could not acquire lock, another process is taking a long time to start the server. Waiting...")
108
- self._wait_for_server(timeout=300) # Give it a longer timeout here just in case.
108
+ self._wait_for_server(timeout=60) # Give it a longer timeout here just in case.
109
109
 
110
110
  # A final verification to ensure we are connected.
111
111
  if not self.is_server_running():
@@ -214,7 +214,7 @@ class DiffusersBinding(LollmsTTIBinding):
214
214
  self.server_process = subprocess.Popen(command, creationflags=creationflags)
215
215
  ASCIIColors.info("Diffusers server process launched in the background.")
216
216
 
217
- def _wait_for_server(self, timeout=300):
217
+ def _wait_for_server(self, timeout=30):
218
218
  """Waits for the server to become responsive."""
219
219
  ASCIIColors.info("Waiting for Diffusers server to become available...")
220
220
  start_time = time.time()
@@ -374,4 +374,4 @@ class DiffusersBinding(LollmsTTIBinding):
374
374
  def __del__(self):
375
375
  # The client destructor does not stop the server,
376
376
  # as it is a shared resource for all worker processes.
377
- pass
377
+ pass
@@ -60,66 +60,14 @@ MODELS_PATH = Path("./models")
60
60
 
61
61
  # --- START: Core Logic (Complete and Unabridged) ---
62
62
  CIVITAI_MODELS = {
63
- "realistic-vision-v6": {
64
- "display_name": "Realistic Vision V6.0", "url": "https://civitai.com/api/download/models/501240?type=Model&format=SafeTensor&size=pruned&fp=fp16",
65
- "filename": "realisticVisionV60_v60B1.safetensors", "description": "Photorealistic SD1.5 checkpoint.", "owned_by": "civitai"
66
- },
67
- "absolute-reality": {
68
- "display_name": "Absolute Reality", "url": "https://civitai.com/api/download/models/132760?type=Model&format=SafeTensor&size=pruned&fp=fp16",
69
- "filename": "absolutereality_v181.safetensors", "description": "General realistic SD1.5.", "owned_by": "civitai"
70
- },
71
- "dreamshaper-8": {
63
+ "DreamShaper-8": {
72
64
  "display_name": "DreamShaper 8", "url": "https://civitai.com/api/download/models/128713",
73
65
  "filename": "dreamshaper_8.safetensors", "description": "Versatile SD1.5 style model.", "owned_by": "civitai"
74
66
  },
75
- "juggernaut-xl": {
67
+ "Juggernaut-xl": {
76
68
  "display_name": "Juggernaut XL", "url": "https://civitai.com/api/download/models/133005",
77
69
  "filename": "juggernautXL_version6Rundiffusion.safetensors", "description": "Artistic SDXL.", "owned_by": "civitai"
78
70
  },
79
- "lyriel-v1.6": {
80
- "display_name": "Lyriel v1.6", "url": "https://civitai.com/api/download/models/72396?type=Model&format=SafeTensor&size=full&fp=fp16",
81
- "filename": "lyriel_v16.safetensors", "description": "Fantasy/stylized SD1.5.", "owned_by": "civitai"
82
- },
83
- "ui_icons": {
84
- "display_name": "UI Icons", "url": "https://civitai.com/api/download/models/367044?type=Model&format=SafeTensor&size=full&fp=fp16",
85
- "filename": "uiIcons_v10.safetensors", "description": "A model for generating UI icons.", "owned_by": "civitai"
86
- },
87
- "meinamix": {
88
- "display_name": "MeinaMix", "url": "https://civitai.com/api/download/models/948574?type=Model&format=SafeTensor&size=pruned&fp=fp16",
89
- "filename": "meinamix_meinaV11.safetensors", "description": "Anime/illustration SD1.5.", "owned_by": "civitai"
90
- },
91
- "rpg-v5": {
92
- "display_name": "RPG v5", "url": "https://civitai.com/api/download/models/124626?type=Model&format=SafeTensor&size=pruned&fp=fp16",
93
- "filename": "rpg_v5.safetensors", "description": "RPG assets SD1.5.", "owned_by": "civitai"
94
- },
95
- "pixel-art-xl": {
96
- "display_name": "Pixel Art XL", "url": "https://civitai.com/api/download/models/135931?type=Model&format=SafeTensor",
97
- "filename": "pixelartxl_v11.safetensors", "description": "Pixel art SDXL.", "owned_by": "civitai"
98
- },
99
- "lowpoly-world": {
100
- "display_name": "Lowpoly World", "url": "https://civitai.com/api/download/models/146502?type=Model&format=SafeTensor",
101
- "filename": "LowpolySDXL.safetensors", "description": "Lowpoly style SD1.5.", "owned_by": "civitai"
102
- },
103
- "toonyou": {
104
- "display_name": "ToonYou", "url": "https://civitai.com/api/download/models/125771?type=Model&format=SafeTensor&size=pruned&fp=fp16",
105
- "filename": "toonyou_beta6.safetensors", "description": "Cartoon/Disney SD1.5.", "owned_by": "civitai"
106
- },
107
- "papercut": {
108
- "display_name": "Papercut", "url": "https://civitai.com/api/download/models/133503?type=Model&format=SafeTensor",
109
- "filename": "papercut.safetensors", "description": "Paper cutout SD1.5.", "owned_by": "civitai"
110
- },
111
- "fantassifiedIcons": {
112
- "display_name": "Fantassified Icons", "url": "https://civitai.com/api/download/models/67584?type=Model&format=SafeTensor&size=pruned&fp=fp16",
113
- "filename": "fantassifiedIcons_fantassifiedIconsV20.safetensors", "description": "Flat, modern Icons.", "owned_by": "civitai"
114
- },
115
- "game_icon_institute": {
116
- "display_name": "Game icon institute", "url": "https://civitai.com/api/download/models/158776?type=Model&format=SafeTensor&size=full&fp=fp16",
117
- "filename": "gameIconInstituteV10_v10.safetensors", "description": "Flat, modern game Icons.", "owned_by": "civitai"
118
- },
119
- "M4RV3LS_DUNGEONS": {
120
- "display_name": "M4RV3LS & DUNGEONS", "url": "https://civitai.com/api/download/models/139417?type=Model&format=SafeTensor&size=pruned&fp=fp16",
121
- "filename": "M4RV3LSDUNGEONSNEWV40COMICS_mD40.safetensors", "description": "comics.", "owned_by": "civitai"
122
- },
123
71
  }
124
72
 
125
73
  HF_PUBLIC_MODELS = {
@@ -183,6 +131,7 @@ SCHEDULER_MAPPING = {
183
131
  "dpm2_karras": "KDPM2DiscreteScheduler", "dpm2_a": "KDPM2AncestralDiscreteScheduler", "dpm2_a_karras": "KDPM2AncestralDiscreteScheduler",
184
132
  "euler": "EulerDiscreteScheduler", "euler_a": "EulerAncestralDiscreteScheduler", "heun": "HeunDiscreteScheduler", "lms": "LMSDiscreteScheduler"
185
133
  }
134
+
186
135
  SCHEDULER_USES_KARRAS_SIGMAS = [
187
136
  "dpm_multistep_karras","dpm++_2m_karras","dpm++_2s_ancestral_karras", "dpm++_sde_karras","heun_karras","lms_karras",
188
137
  "dpm++_2m_sde_karras","dpm2_karras","dpm2_a_karras"
@@ -604,7 +553,7 @@ class ServerState:
604
553
  return {
605
554
  "model_name": "", "device": "auto", "torch_dtype_str": "auto", "use_safetensors": True,
606
555
  "scheduler_name": "default", "safety_checker_on": True, "num_inference_steps": 25,
607
- "guidance_scale": 7.0, "width": 512, "height": 512, "seed": -1,
556
+ "guidance_scale": 7.0, "width": 1024, "height": 1024, "seed": -1,
608
557
  "enable_cpu_offload": False, "enable_sequential_cpu_offload": False, "enable_xformers": False,
609
558
  "hf_variant": None, "hf_token": None, "hf_cache_path": None, "local_files_only": False,
610
559
  "unload_inactive_model_after": 0
@@ -749,8 +698,8 @@ async def generate_image(request: T2IRequest):
749
698
  # Add prompts and ensure types for specific args
750
699
  pipeline_args["prompt"] = request.prompt
751
700
  pipeline_args["negative_prompt"] = request.negative_prompt
752
- pipeline_args["width"] = int(pipeline_args.get("width", 512))
753
- pipeline_args["height"] = int(pipeline_args.get("height", 512))
701
+ pipeline_args["width"] = int(pipeline_args.get("width", 1024))
702
+ pipeline_args["height"] = int(pipeline_args.get("height", 1024))
754
703
  pipeline_args["num_inference_steps"] = int(pipeline_args.get("num_inference_steps", 25))
755
704
  pipeline_args["guidance_scale"] = float(pipeline_args.get("guidance_scale", 7.0))
756
705
 
@@ -989,4 +938,4 @@ if __name__ == "__main__":
989
938
  else:
990
939
  ASCIIColors.info(f"Detected device: {state.config['device']}")
991
940
 
992
- uvicorn.run(app, host=args.host, port=args.port, reload=False)
941
+ uvicorn.run(app, host=args.host, port=args.port, reload=False)
@@ -32,7 +32,7 @@ class XTTSClientBinding(LollmsTTSBinding):
32
32
 
33
33
  self.config = kwargs
34
34
  self.host = kwargs.get("host", "localhost")
35
- self.port = kwargs.get("port", 8081)
35
+ self.port = kwargs.get("port", 9633)
36
36
  self.auto_start_server = kwargs.get("auto_start_server", True)
37
37
  self.server_process = None
38
38
  self.base_url = f"http://{self.host}:{self.port}"
@@ -69,7 +69,7 @@ class XTTSClientBinding(LollmsTTSBinding):
69
69
  return
70
70
 
71
71
  try:
72
- with lock.acquire(timeout=60):
72
+ with lock.acquire(timeout=10):
73
73
  if not self.is_server_running():
74
74
  ASCIIColors.yellow("Lock acquired. Starting dedicated XTTS server...")
75
75
  self.start_server()
@@ -78,7 +78,7 @@ class XTTSClientBinding(LollmsTTSBinding):
78
78
  ASCIIColors.green("Server was started by another process while we waited. Connected successfully.")
79
79
  except Timeout:
80
80
  ASCIIColors.yellow("Could not acquire lock, another process is starting the server. Waiting...")
81
- self._wait_for_server(timeout=180)
81
+ self._wait_for_server(timeout=60)
82
82
 
83
83
  if not self.is_server_running():
84
84
  raise RuntimeError("Failed to start or connect to the XTTS server after all attempts.")
@@ -140,7 +140,7 @@ class XTTSClientBinding(LollmsTTSBinding):
140
140
  self.server_process = subprocess.Popen(command, creationflags=creationflags)
141
141
  ASCIIColors.info("XTTS server process launched in the background.")
142
142
 
143
- def _wait_for_server(self, timeout=1):
143
+ def _wait_for_server(self, timeout=10):
144
144
  """Waits for the server to become responsive."""
145
145
  ASCIIColors.info("Waiting for XTTS server to become available...")
146
146
  start_time = time.time()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lollms_client
3
- Version: 1.6.7
3
+ Version: 1.6.10
4
4
  Summary: A client library for LoLLMs generate endpoint
5
5
  Author-email: ParisNeo <parisneoai@gmail.com>
6
6
  License: Apache License
@@ -1,15 +1,15 @@
1
- lollms_client/__init__.py,sha256=CrN8dkGE49W-rpFHEln-GE74Rp-Ezq3zbu5sRAcnvXc,1146
2
- lollms_client/lollms_agentic.py,sha256=pQiMEuB_XkG29-SW6u4KTaMFPr6eKqacInggcCuCW3k,13914
1
+ lollms_client/__init__.py,sha256=0D-nwmkSe8qYbyPSuKdYU09t7x5P2BYwfpI4mbzEZlU,1147
2
+ lollms_client/lollms_agentic.py,sha256=ljalnmeSU-sbzH19-c9TzrJ-HhEeo4mxXmpJGkXj720,14094
3
3
  lollms_client/lollms_config.py,sha256=goEseDwDxYJf3WkYJ4IrLXwg3Tfw73CXV2Avg45M_hE,21876
4
- lollms_client/lollms_core.py,sha256=kF42KKd9UCOr_-ME0vgB0_1Ae00B4ZWXjfTvFymeRP0,244203
5
- lollms_client/lollms_discussion.py,sha256=LZc9jYbUMRTovehiFJKEp-NXuCl_WnrqUtT3t4Nzayk,123922
4
+ lollms_client/lollms_core.py,sha256=PGHPu_V5rKnO-032EjgMw8M5T0SLpNOWrzSUlWKBBgE,253052
5
+ lollms_client/lollms_discussion.py,sha256=4uzXLqGz72xZcXEtamWGudTOR54cYwuo6k8JY37scqY,124574
6
6
  lollms_client/lollms_js_analyzer.py,sha256=01zUvuO2F_lnUe_0NLxe1MF5aHE1hO8RZi48mNPv-aw,8361
7
7
  lollms_client/lollms_llm_binding.py,sha256=_6d0q9g9lk8FRZ1oYnLpuqG7Y_WLyBJBn4ANdk-C8gU,25020
8
8
  lollms_client/lollms_mcp_binding.py,sha256=psb27A23VFWDfZsR2WUbQXQxiZDW5yfOak6ZtbMfszI,10222
9
9
  lollms_client/lollms_mcp_security.py,sha256=FhVTDhSBjksGEZnopVnjFmEF5dv7D8bBTqoaj4BiF0E,3562
10
10
  lollms_client/lollms_personality.py,sha256=kGuFwmgA9QDLcQlLQ9sKeceMujdEo0Aw28fN5H8MpjI,8847
11
11
  lollms_client/lollms_python_analyzer.py,sha256=7gf1fdYgXCOkPUkBAPNmr6S-66hMH4_KonOMsADASxc,10246
12
- lollms_client/lollms_stt_binding.py,sha256=jAUhLouEhh2hmm1bK76ianfw_6B59EHfY3FmLv6DU-g,5111
12
+ lollms_client/lollms_stt_binding.py,sha256=WkREwu0uc0UzeCv5Z9ok8AFG42iBq20ZOQJnydSTE0s,7505
13
13
  lollms_client/lollms_tti_binding.py,sha256=MhDntyXVNoZeqMH0YpoNtiLijXPL8Y--if2qjQAS0-w,8520
14
14
  lollms_client/lollms_ttm_binding.py,sha256=FjVVSNXOZXK1qvcKEfxdiX6l2b4XdGOSNnZ0utAsbDg,4167
15
15
  lollms_client/lollms_tts_binding.py,sha256=k13rNq4YmuR50kkAEacwADW7COoDUOMLGAcnm27xjO4,5150
@@ -49,11 +49,11 @@ lollms_client/mcp_bindings/remote_mcp/__init__.py,sha256=YpSclbNJDYVUe2W0H5Xki4g
49
49
  lollms_client/mcp_bindings/standard_mcp/__init__.py,sha256=wJQofr4zS5RIS9V5_WuMMFsJxSDJgXDW3PQPX1hlx6g,31519
50
50
  lollms_client/stt_bindings/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
51
51
  lollms_client/stt_bindings/lollms/__init__.py,sha256=9Vmn1sQQZKLGLe7nZnc-0LnNeSY8r9xw3pYZF-wVtPo,5889
52
- lollms_client/stt_bindings/whisper/__init__.py,sha256=1Ej67GdRKBy1bba14jMaYDYHiZkxJASkWm5eF07ztDQ,15363
53
- lollms_client/stt_bindings/whispercpp/__init__.py,sha256=xSAQRjAhljak3vWCpkP0Vmdb6WmwTzPjXyaIB85KLGU,21439
52
+ lollms_client/stt_bindings/whisper/__init__.py,sha256=HVVYRGIPkTTwNw5uhvxvRkSYeAv6nNRZp_geS8SwKZ4,15428
53
+ lollms_client/stt_bindings/whispercpp/__init__.py,sha256=5YQKFy3UaN-S-HGZiFCIcuPGTJTELPgqqct1AcTqz-Q,21595
54
54
  lollms_client/tti_bindings/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
- lollms_client/tti_bindings/diffusers/__init__.py,sha256=esrcyy_z_6HVCFKMVXl1h_qY_pX3kMHwO81M2C8hSIg,17706
56
- lollms_client/tti_bindings/diffusers/server/main.py,sha256=7xWANWnxHeDAF_NQTbJD4QToxoVtaAEdxGHMXOotz5s,51907
55
+ lollms_client/tti_bindings/diffusers/__init__.py,sha256=_Nd3OotY1kBlEmHBuxVsNwIc_vvUy8sBo1Ug9_lUOzI,17705
56
+ lollms_client/tti_bindings/diffusers/server/main.py,sha256=-Eo9vrpsK_LXRFJWkplriSdUX8VnkcL6tfFdxontNnM,48136
57
57
  lollms_client/tti_bindings/gemini/__init__.py,sha256=eYGz6gnOxWGdJu2O0H-EwGG-Hg7Yo3Hzsgn4neqx29Q,12963
58
58
  lollms_client/tti_bindings/leonardo_ai/__init__.py,sha256=pUbF1rKPZib1x0Kn2Bk1A7sTFWmZzNG02kmW6Iu1j2w,5885
59
59
  lollms_client/tti_bindings/lollms/__init__.py,sha256=5Tnsn4b17djvieQkcjtIDBm3qf0pg5ZWWov-4_2wmo0,8762
@@ -76,13 +76,13 @@ lollms_client/tts_bindings/piper_tts/__init__.py,sha256=7LQUuWV8I3IEdacc65NRHmDf
76
76
  lollms_client/tts_bindings/piper_tts/server/install_piper.py,sha256=g71Ne2T18wAytOPipfQ9DNeTAOD9PrII5qC-vr9DtLA,3256
77
77
  lollms_client/tts_bindings/piper_tts/server/main.py,sha256=DMozfSR1aCbrlmOXltRFjtXhYhXajsGcNKQjsWgRwZk,17402
78
78
  lollms_client/tts_bindings/piper_tts/server/setup_voices.py,sha256=UdHaPa5aNcw8dR-aRGkZr2OfSFFejH79lXgfwT0P3ss,1964
79
- lollms_client/tts_bindings/xtts/__init__.py,sha256=sQnmlXbFb5r6mX-4DfExuM7YJ_aSv551NM8ZzTrMauo,8073
79
+ lollms_client/tts_bindings/xtts/__init__.py,sha256=q5xuNUYz4l9ajmZo4yvcTgxPuv9HT6T16u-weh3lzC8,8073
80
80
  lollms_client/tts_bindings/xtts/server/main.py,sha256=feTAX4eAo2HY6PpcDTrgRMak5AXocO7UIhKPuGuWpxY,12303
81
81
  lollms_client/tts_bindings/xtts/server/setup_voices.py,sha256=UdHaPa5aNcw8dR-aRGkZr2OfSFFejH79lXgfwT0P3ss,1964
82
82
  lollms_client/ttv_bindings/__init__.py,sha256=UZ8o2izQOJLQgtZ1D1cXoNST7rzqW22rL2Vufc7ddRc,3141
83
83
  lollms_client/ttv_bindings/lollms/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
84
- lollms_client-1.6.7.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
85
- lollms_client-1.6.7.dist-info/METADATA,sha256=c5Bud1Xae1bMbN5IZVYYJNva_f7DPvFaxrNnaHcRsSE,76835
86
- lollms_client-1.6.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
87
- lollms_client-1.6.7.dist-info/top_level.txt,sha256=Bk_kz-ri6Arwsk7YG-T5VsRorV66uVhcHGvb_g2WqgE,14
88
- lollms_client-1.6.7.dist-info/RECORD,,
84
+ lollms_client-1.6.10.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
85
+ lollms_client-1.6.10.dist-info/METADATA,sha256=Mqk7RqLL6F5By0K_XIJemPSNoQhDcaW9JBT5-H9Tewg,76836
86
+ lollms_client-1.6.10.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
87
+ lollms_client-1.6.10.dist-info/top_level.txt,sha256=Bk_kz-ri6Arwsk7YG-T5VsRorV66uVhcHGvb_g2WqgE,14
88
+ lollms_client-1.6.10.dist-info/RECORD,,