pygpt-net 2.6.12__py3-none-any.whl → 2.6.14__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.
pygpt_net/CHANGELOG.txt CHANGED
@@ -1,3 +1,15 @@
1
+ 2.6.14 (2025-08-19)
2
+
3
+ - Fixed: Agent evaluation tool runs even if tools are disabled.
4
+ - Extended agent response evaluation by providing the full context of the output.
5
+
6
+ 2.6.13 (2025-08-19)
7
+
8
+ - Fix: Do not load the index in experts if it is not provided.
9
+ - Fix: Load remote images in the webview.
10
+ - Fix: Presets list refresh.
11
+ - Optimize context items reload.
12
+
1
13
  2.6.12 (2025-08-19)
2
14
 
3
15
  - Optimized web renderer memory cleanup.
pygpt_net/__init__.py CHANGED
@@ -13,7 +13,7 @@ __author__ = "Marcin Szczygliński"
13
13
  __copyright__ = "Copyright 2025, Marcin Szczygliński"
14
14
  __credits__ = ["Marcin Szczygliński"]
15
15
  __license__ = "MIT"
16
- __version__ = "2.6.12"
16
+ __version__ = "2.6.14"
17
17
  __build__ = "2025-08-19"
18
18
  __maintainer__ = "Marcin Szczygliński"
19
19
  __github__ = "https://github.com/szczyglis-dev/py-gpt"
@@ -291,8 +291,8 @@ class Output:
291
291
 
292
292
  if mode != MODE_ASSISTANT:
293
293
  self.window.controller.kernel.stack.handle() # handle reply
294
- event = RenderEvent(RenderEvent.RELOAD)
295
- self.window.dispatch(event) # reload chat window
294
+ # event = RenderEvent(RenderEvent.RELOAD)
295
+ # self.window.dispatch(event) # reload chat window
296
296
 
297
297
  mem_clean()
298
298
 
@@ -265,7 +265,12 @@ class Response:
265
265
  self.window.dispatch(event) # show cmd waiting
266
266
  self.window.controller.chat.output.handle_end(ctx, mode) # handle end.
267
267
 
268
- event = RenderEvent(RenderEvent.RELOAD)
268
+ data = {
269
+ "meta": ctx.meta,
270
+ "ctx": ctx,
271
+ "stream": self.window.core.config.get("stream", False),
272
+ }
273
+ event = RenderEvent(RenderEvent.END, data)
269
274
  self.window.dispatch(event)
270
275
 
271
276
  # if continue reasoning
@@ -900,7 +900,7 @@ class Editor:
900
900
  if not is_new:
901
901
  no_scroll = True
902
902
  self.window.core.presets.save(id)
903
- self.window.controller.presets.refresh(no_scroll=no_scroll)
903
+ self.window.controller.presets.refresh()
904
904
 
905
905
  # close dialog
906
906
  if close:
@@ -132,17 +132,37 @@ class Evaluation:
132
132
  :param force_prev: force to use previous input
133
133
  :return: last user input
134
134
  """
135
- input = ""
135
+ last_input = ""
136
136
  use_prev = self.window.core.config.get("agent.llama.append_eval", False)
137
137
  if force_prev:
138
138
  use_prev = True
139
139
  for ctx in history:
140
- if ctx.extra is not None and "agent_input" in ctx.extra:
140
+ if self.is_input(ctx): # ensure ctx is input
141
141
  if not use_prev and "agent_evaluate" in ctx.extra: # exclude evaluation inputs
142
142
  continue
143
143
  if ctx.input:
144
- input = ctx.input
145
- return input
144
+ last_input = ctx.input
145
+ return last_input
146
+
147
+ def is_input(self, ctx: CtxItem) -> bool:
148
+ """
149
+ Check if the context item is an input
150
+
151
+ :param ctx: context item
152
+ :return: True if input, False otherwise
153
+ """
154
+ return ctx.extra is not None and "agent_input" in ctx.extra
155
+
156
+ def is_output(self, ctx: CtxItem) -> bool:
157
+ """
158
+ Check if the context item is an output
159
+
160
+ :param ctx: context item
161
+ :return: True if output, False otherwise
162
+ """
163
+ return (ctx.extra is not None
164
+ and ("agent_output" in ctx.extra or "agent_finish" in ctx.extra)
165
+ and "agent_finish_evaluate" not in ctx.extra)
146
166
 
147
167
  def get_main_task(self, history: List[CtxItem]) -> str:
148
168
  """
@@ -151,10 +171,12 @@ class Evaluation:
151
171
  :param history: ctx items
152
172
  :return: main task
153
173
  """
154
- first = history[0]
155
174
  task = ""
156
- if first.extra is not None and "agent_input" in first.extra:
157
- task = first.input
175
+ for ctx in history:
176
+ if self.is_input(ctx):
177
+ if ctx.input:
178
+ task = ctx.input
179
+ break
158
180
  return task
159
181
 
160
182
  def get_final_response(self, history: List[CtxItem]) -> str:
@@ -164,19 +186,28 @@ class Evaluation:
164
186
  :param history: ctx items
165
187
  :return: final response from agent
166
188
  """
167
- output = ""
189
+ outputs = []
168
190
  for ctx in history:
169
- if ctx.extra is not None and "agent_finish" in ctx.extra and "agent_finish_evaluate" not in ctx.extra:
191
+ if self.is_output(ctx):
170
192
  if ctx.output:
171
- output = ctx.output
193
+ outputs.append(ctx.output)
194
+
195
+ # if next input then clear outputs - use only output after last user input
196
+ if self.is_input(ctx):
197
+ outputs.clear()
172
198
 
173
199
  # feedback for OpenAI agents
174
- if not output:
200
+ if len(outputs) == 0:
175
201
  for ctx in history:
176
- if ctx.extra is not None and "agent_output" in ctx.extra and "agent_finish_evaluate" not in ctx.extra:
202
+ if self.is_output(ctx):
177
203
  if ctx.output:
178
- output = ctx.output
179
- return output
204
+ outputs.append(ctx.output)
205
+
206
+ # if next input then clear outputs - use only output after last user input
207
+ if self.is_input(ctx):
208
+ outputs.clear()
209
+
210
+ return "\n\n".join(outputs) if outputs else ""
180
211
 
181
212
  def get_prompt_score(self, history: List[CtxItem]) -> str:
182
213
  """
@@ -224,9 +255,7 @@ class Evaluation:
224
255
  return "OK. Feedback has been sent."
225
256
 
226
257
  tool = FunctionTool.from_defaults(fn=send_feedback)
227
- tools = []
228
- tools.append(tool)
229
- return tools
258
+ return [tool]
230
259
 
231
260
  def handle_evaluation(
232
261
  self,
@@ -237,6 +237,7 @@ class Runner:
237
237
  model = context.model
238
238
  vector_store_idx = extra.get("agent_idx", None)
239
239
  system_prompt = context.system_prompt
240
+ is_expert_call = context.is_expert_call
240
241
  max_steps = self.window.core.config.get("agent.llama.steps", 10)
241
242
  is_cmd = self.window.core.command.is_cmd(inline=False)
242
243
  llm = self.window.core.idx.llm.get(model, stream=False)
@@ -250,16 +251,14 @@ class Runner:
250
251
  tools = extra["agent_tools"] # use tools from extra if provided
251
252
  else:
252
253
  tools = self.window.core.agents.tools.prepare(context, extra, force=True)
254
+ if not is_cmd:
255
+ tools = [] # disable tools if cmd is not enabled, force agent tools
253
256
 
254
257
  if "agent_history" in extra:
255
258
  history = extra["agent_history"]
256
259
  else:
257
260
  history = self.window.core.agents.memory.prepare(context)
258
261
 
259
- # disable tools if cmd is not enabled
260
- if not is_cmd:
261
- tools = []
262
-
263
262
  # append system prompt
264
263
  if agent_id in self.APPEND_SYSTEM_PROMPT_TO_MSG:
265
264
  if system_prompt:
@@ -301,6 +300,7 @@ class Runner:
301
300
  "verbose": verbose,
302
301
  "history": history,
303
302
  "llm": llm,
303
+ "is_expert_call": is_expert_call,
304
304
  }
305
305
  # TODO: add support for other modes
306
306
  if mode == AGENT_MODE_WORKFLOW:
@@ -106,6 +106,7 @@ class LlamaWorkflow(BaseRunner):
106
106
  verbose: bool = False,
107
107
  history: List[CtxItem] = None,
108
108
  llm: Any = None,
109
+ is_expert_call: bool = False,
109
110
  ) -> Union[CtxItem, None]:
110
111
  """
111
112
  Run agent workflow
@@ -117,6 +118,7 @@ class LlamaWorkflow(BaseRunner):
117
118
  :param verbose: verbose mode
118
119
  :param history: chat history
119
120
  :param llm: LLM instance
121
+ :param is_expert_call: if True, run as expert call
120
122
  :return: True if success
121
123
  """
122
124
  if self.is_stopped():
@@ -124,6 +126,9 @@ class LlamaWorkflow(BaseRunner):
124
126
 
125
127
  memory = self.window.core.idx.chat.get_memory_buffer(history, llm)
126
128
  agent_ctx = Context(agent)
129
+ flush = True
130
+ if is_expert_call:
131
+ flush = False
127
132
  try:
128
133
  ctx = await self.run_agent(
129
134
  agent=agent,
@@ -134,6 +139,7 @@ class LlamaWorkflow(BaseRunner):
134
139
  item_ctx=ctx,
135
140
  signals=signals,
136
141
  use_partials=False, # use partials for streaming
142
+ flush=flush, # flush output buffer to webview
137
143
  )
138
144
  except WorkflowCancelledByUser:
139
145
  print("\n\n[STOP] Workflow stopped by user.")
@@ -202,6 +208,7 @@ class LlamaWorkflow(BaseRunner):
202
208
  item_ctx: Optional[CtxItem] = None,
203
209
  signals: Optional[BridgeSignals] = None,
204
210
  use_partials: bool = True,
211
+ flush: bool = True,
205
212
  ):
206
213
  """
207
214
  Run agent workflow
@@ -215,6 +222,7 @@ class LlamaWorkflow(BaseRunner):
215
222
  :param item_ctx: Optional CtxItem for additional context
216
223
  :param signals: Optional BridgeSignals for communication
217
224
  :param use_partials: If True, use partial context items for streaming
225
+ :param flush: If True, flush the output buffer before starting
218
226
  :return: handler for the agent workflow
219
227
  """
220
228
  handler = agent.run(
@@ -237,7 +245,8 @@ class LlamaWorkflow(BaseRunner):
237
245
  # persist current output on stop
238
246
  item_ctx.output = item_ctx.live_output
239
247
  self.window.core.ctx.update_item(item_ctx)
240
- self.end_stream(item_ctx, signals)
248
+ if flush:
249
+ self.end_stream(item_ctx, signals)
241
250
  await handler.cancel_run() # cancel, will raise WorkflowCancelledByUser
242
251
  break
243
252
  if isinstance(event, ToolCallResult):
@@ -247,7 +256,7 @@ class LlamaWorkflow(BaseRunner):
247
256
  formatted = "\n```output\n" + str(event.tool_output) + "\n```\n"
248
257
  item_ctx.live_output += formatted
249
258
  item_ctx.stream = formatted
250
- if item_ctx.stream_agent_output:
259
+ if item_ctx.stream_agent_output and flush:
251
260
  self.send_stream(item_ctx, signals, begin)
252
261
  elif isinstance(event, ToolCall):
253
262
  if "code" in event.tool_kwargs:
@@ -257,7 +266,7 @@ class LlamaWorkflow(BaseRunner):
257
266
  formatted = "\n```python\n" + str(event.tool_kwargs['code']) + "\n```\n"
258
267
  item_ctx.live_output += formatted
259
268
  item_ctx.stream = formatted
260
- if item_ctx.stream_agent_output:
269
+ if item_ctx.stream_agent_output and flush:
261
270
  self.send_stream(item_ctx, signals, begin)
262
271
  elif isinstance(event, StepEvent):
263
272
  self.set_busy(signals)
@@ -278,7 +287,7 @@ class LlamaWorkflow(BaseRunner):
278
287
  if event.delta:
279
288
  item_ctx.live_output += event.delta
280
289
  item_ctx.stream = event.delta
281
- if item_ctx.stream_agent_output:
290
+ if item_ctx.stream_agent_output and flush:
282
291
  self.send_stream(item_ctx, signals, begin) # send stream to webview
283
292
  begin = False
284
293
  elif isinstance(event, AgentOutput):
@@ -651,7 +651,7 @@ class ExpertWorker(QRunnable):
651
651
 
652
652
  # index to use
653
653
  use_index = False
654
- if db_idx:
654
+ if db_idx and db_idx != '_':
655
655
  use_index = True
656
656
  if use_index:
657
657
  index, llm = self.window.core.idx.chat.get_index(db_idx, model_data, stream=False)
@@ -694,10 +694,6 @@ class ExpertWorker(QRunnable):
694
694
  tools = self.window.core.agents.tools.prepare(
695
695
  bridge_context, extra, verbose=False, force=True)
696
696
 
697
- # disable tools if cmd is not enabled
698
- if not self.window.core.command.is_cmd(inline=False):
699
- tools = []
700
-
701
697
  # remove expert_call tool from tools
702
698
  for tool in list(tools):
703
699
  if tool.metadata.name == "expert_call":
@@ -213,14 +213,13 @@ class Presets:
213
213
  """
214
214
  attr = self._MODE_TO_ATTR.get(mode)
215
215
  if not attr:
216
- raise IndexError(idx)
216
+ return
217
217
  i = 0
218
218
  for key, item in self.items.items():
219
219
  if getattr(item, attr, False):
220
220
  if i == idx:
221
221
  return key
222
222
  i += 1
223
- raise IndexError(idx)
224
223
 
225
224
  def get_by_id(self, mode: str, id: str) -> Optional[PresetItem]:
226
225
  """
@@ -36,6 +36,7 @@ class PidData:
36
36
  self.last_time_called = 0
37
37
  self.cooldown = 1 / 6
38
38
  self.throttling_min_chars = 5000
39
+ self.header = None
39
40
 
40
41
  @property
41
42
  def buffer(self) -> str:
@@ -108,6 +108,7 @@ class Renderer(BaseRenderer):
108
108
  pid = tab.pid
109
109
  if pid is None or pid not in self.pids:
110
110
  return
111
+
111
112
  self.pids[pid].loaded = True
112
113
  if self.pids[pid].html != "" and not self.pids[pid].use_buffer:
113
114
  self.clear_chunks_input(pid)
@@ -189,7 +190,8 @@ class Renderer(BaseRenderer):
189
190
  node = self.get_output_node_by_pid(pid)
190
191
  try:
191
192
  node.page().runJavaScript(
192
- "if (typeof window.showLoading !== 'undefined') showLoading();")
193
+ "if (typeof window.showLoading !== 'undefined') showLoading();"
194
+ )
193
195
  except Exception as e:
194
196
  pass
195
197
 
@@ -199,7 +201,8 @@ class Renderer(BaseRenderer):
199
201
  if node is not None:
200
202
  try:
201
203
  node.page().runJavaScript(
202
- "if (typeof window.hideLoading !== 'undefined') hideLoading();")
204
+ "if (typeof window.hideLoading !== 'undefined') hideLoading();"
205
+ )
203
206
  except Exception as e:
204
207
  pass
205
208
 
@@ -209,7 +212,8 @@ class Renderer(BaseRenderer):
209
212
  if node is not None:
210
213
  try:
211
214
  node.page().runJavaScript(
212
- "if (typeof window.hideLoading !== 'undefined') hideLoading();")
215
+ "if (typeof window.hideLoading !== 'undefined') hideLoading();"
216
+ )
213
217
  except Exception as e:
214
218
  pass
215
219
 
@@ -251,6 +255,8 @@ class Renderer(BaseRenderer):
251
255
  if self.pids[pid].item is not None and stream:
252
256
  self.append_context_item(meta, self.pids[pid].item)
253
257
  self.pids[pid].item = None
258
+ else:
259
+ self.reload()
254
260
  self.pids[pid].clear()
255
261
 
256
262
  def end_extra(
@@ -320,7 +326,27 @@ class Renderer(BaseRenderer):
320
326
  clear: bool = True
321
327
  ):
322
328
  """
323
- Append all context to output
329
+ Append all context items to output
330
+
331
+ :param meta: Context meta
332
+ :param items: context items
333
+ :param clear: True if clear all output before append
334
+ """
335
+ self.tool_output_end()
336
+ self.append_context_all(
337
+ meta,
338
+ items,
339
+ clear=clear,
340
+ )
341
+
342
+ def append_context_partial(
343
+ self,
344
+ meta: CtxMeta,
345
+ items: List[CtxItem],
346
+ clear: bool = True
347
+ ):
348
+ """
349
+ Append all context items to output (part by part)
324
350
 
325
351
  :param meta: Context meta
326
352
  :param items: context items
@@ -351,7 +377,7 @@ class Renderer(BaseRenderer):
351
377
  meta,
352
378
  item,
353
379
  prev_ctx=prev_ctx,
354
- next_ctx=next_item
380
+ next_ctx=next_item,
355
381
  )
356
382
  prev_ctx = item
357
383
 
@@ -362,35 +388,126 @@ class Renderer(BaseRenderer):
362
388
  self.append(
363
389
  pid,
364
390
  self.pids[pid].html,
365
- flush=True
391
+ flush=True,
366
392
  )
367
393
  self.parser.reset()
368
394
 
369
- def append_input(
395
+ def append_context_all(
396
+ self,
397
+ meta: CtxMeta,
398
+ items: List[CtxItem],
399
+ clear: bool = True
400
+ ):
401
+ """
402
+ Append all context items to output (whole context at once)
403
+
404
+ :param meta: Context meta
405
+ :param items: context items
406
+ :param clear: True if clear all output before append
407
+ """
408
+ if len(items) == 0:
409
+ if meta is None:
410
+ return
411
+
412
+ pid = self.get_or_create_pid(meta)
413
+ self.init(pid)
414
+
415
+ if clear:
416
+ self.reset(meta)
417
+
418
+ self.pids[pid].use_buffer = True
419
+ self.pids[pid].html = ""
420
+ prev_ctx = None
421
+ next_ctx = None
422
+ total = len(items)
423
+ html_parts = []
424
+ for i, item in enumerate(items):
425
+ self.update_names(meta, item)
426
+ item.idx = i
427
+ if i == 0:
428
+ item.first = True
429
+ next_ctx = items[i + 1] if i + 1 < total else None
430
+
431
+ # ignore hidden items
432
+ if item.hidden:
433
+ prev_ctx = item
434
+ continue
435
+
436
+ # input node
437
+ data = self.prepare_input(meta, item, flush=False)
438
+ if data:
439
+ html = self.prepare_node(
440
+ meta=meta,
441
+ ctx=item,
442
+ html=data,
443
+ type=self.NODE_INPUT,
444
+ prev_ctx=prev_ctx,
445
+ next_ctx=next_ctx,
446
+ )
447
+ if html:
448
+ html_parts.append(html)
449
+
450
+ # output node
451
+ data = self.prepare_output(
452
+ meta,
453
+ item,
454
+ flush=False,
455
+ prev_ctx=prev_ctx,
456
+ next_ctx=next_ctx,
457
+ )
458
+ if data:
459
+ html = self.prepare_node(
460
+ meta=meta,
461
+ ctx=item,
462
+ html=data,
463
+ type=self.NODE_OUTPUT,
464
+ prev_ctx=prev_ctx,
465
+ next_ctx=next_ctx,
466
+ )
467
+ if html:
468
+ html_parts.append(html)
469
+
470
+ prev_ctx = item
471
+
472
+ # flush all nodes at once
473
+ if html_parts:
474
+ self.append(
475
+ pid,
476
+ "".join(html_parts)
477
+ )
478
+
479
+ html_parts.clear()
480
+ html_parts = None
481
+ prev_ctx = None
482
+ next_ctx = None
483
+ self.pids[pid].use_buffer = False
484
+ if self.pids[pid].html != "":
485
+ self.append(
486
+ pid,
487
+ self.pids[pid].html,
488
+ flush=True,
489
+ )
490
+ self.parser.reset()
491
+
492
+ def prepare_input(
370
493
  self, meta: CtxMeta,
371
494
  ctx: CtxItem,
372
495
  flush: bool = True,
373
496
  append: bool = False
374
- ):
497
+ ) -> Optional[str]:
375
498
  """
376
- Append text input to output
499
+ Prepare text input
377
500
 
378
501
  :param meta: context meta
379
502
  :param ctx: context item
380
503
  :param flush: flush HTML
381
504
  :param append: True if force append node
505
+ :return: Prepared input text or None if internal or empty input
382
506
  """
383
- self.tool_output_end()
384
- pid = self.get_or_create_pid(meta)
385
- if not flush:
386
- self.clear_chunks_input(pid)
387
-
388
- self.update_names(meta, ctx)
389
507
  if ctx.input is None or ctx.input == "":
390
508
  return
391
509
 
392
510
  text = ctx.input
393
-
394
511
  if isinstance(ctx.extra, dict) and "sub_reply" in ctx.extra and ctx.extra["sub_reply"]:
395
512
  try:
396
513
  json_encoded = json.loads(text)
@@ -410,32 +527,60 @@ class Renderer(BaseRenderer):
410
527
  if ctx.internal and ctx.input.startswith("user: "):
411
528
  text = re.sub(r'^user: ', '> ', ctx.input)
412
529
 
413
- if flush:
414
- if self.is_stream() and not append:
415
- content = self.prepare_node(meta, ctx, text.strip(), self.NODE_INPUT)
416
- self.append_chunk_input(meta, ctx, content, False)
417
- return
530
+ return text.strip()
418
531
 
419
- self.append_node(meta, ctx, text.strip(), self.NODE_INPUT)
532
+ def append_input(
533
+ self, meta: CtxMeta,
534
+ ctx: CtxItem,
535
+ flush: bool = True,
536
+ append: bool = False
537
+ ):
538
+ """
539
+ Append text input to output
420
540
 
421
- def append_output(
541
+ :param meta: context meta
542
+ :param ctx: context item
543
+ :param flush: flush HTML
544
+ :param append: True if force append node
545
+ """
546
+ self.tool_output_end()
547
+ pid = self.get_or_create_pid(meta)
548
+ if not flush:
549
+ self.clear_chunks_input(pid)
550
+
551
+ self.update_names(meta, ctx)
552
+ text = self.prepare_input(meta, ctx, flush, append)
553
+ if text:
554
+ if flush:
555
+ if self.is_stream() and not append:
556
+ content = self.prepare_node(meta, ctx, text, self.NODE_INPUT)
557
+ self.append_chunk_input(meta, ctx, content, begin=False)
558
+ return
559
+ self.append_node(
560
+ meta=meta,
561
+ ctx=ctx,
562
+ html=text,
563
+ type=self.NODE_INPUT,
564
+ )
565
+
566
+ def prepare_output(
422
567
  self,
423
568
  meta: CtxMeta,
424
569
  ctx: CtxItem,
425
570
  flush: bool = True,
426
571
  prev_ctx: Optional[CtxItem] = None,
427
572
  next_ctx: Optional[CtxItem] = None
428
- ):
573
+ ) -> Optional[str]:
429
574
  """
430
- Append text output to output
575
+ Prepare text output
431
576
 
432
577
  :param meta: context meta
433
578
  :param ctx: context item
434
579
  :param flush: flush HTML
435
580
  :param prev_ctx: previous context
436
581
  :param next_ctx: next context
582
+ :return: Prepared output text or None if empty output
437
583
  """
438
- self.tool_output_end()
439
584
  output = ctx.output
440
585
  if isinstance(ctx.extra, dict) and ctx.extra.get("output"):
441
586
  if self.window.core.config.get("llama.idx.chat.agent.render.all", False):
@@ -445,14 +590,42 @@ class Renderer(BaseRenderer):
445
590
  else:
446
591
  if not output:
447
592
  return
448
- self.append_node(
593
+ return output.strip()
594
+
595
+ def append_output(
596
+ self,
597
+ meta: CtxMeta,
598
+ ctx: CtxItem,
599
+ flush: bool = True,
600
+ prev_ctx: Optional[CtxItem] = None,
601
+ next_ctx: Optional[CtxItem] = None
602
+ ):
603
+ """
604
+ Append text output to output
605
+
606
+ :param meta: context meta
607
+ :param ctx: context item
608
+ :param flush: flush HTML
609
+ :param prev_ctx: previous context
610
+ :param next_ctx: next context
611
+ """
612
+ self.tool_output_end()
613
+ output = self.prepare_output(
449
614
  meta=meta,
450
615
  ctx=ctx,
451
- html=output.strip(),
452
- type=self.NODE_OUTPUT,
616
+ flush=flush,
453
617
  prev_ctx=prev_ctx,
454
- next_ctx=next_ctx
618
+ next_ctx=next_ctx,
455
619
  )
620
+ if output:
621
+ self.append_node(
622
+ meta=meta,
623
+ ctx=ctx,
624
+ html=output,
625
+ type=self.NODE_OUTPUT,
626
+ prev_ctx=prev_ctx,
627
+ next_ctx=next_ctx,
628
+ )
456
629
 
457
630
  def append_chunk(
458
631
  self,
@@ -479,8 +652,11 @@ class Renderer(BaseRenderer):
479
652
  self._throttle_reset(pid)
480
653
  return
481
654
 
482
- name_header_str = self.get_name_header(ctx)
483
- self.update_names(meta, ctx)
655
+ if begin: # prepare name and avatar header only at the beginning to avoid unnecessary checks
656
+ pctx.header = self.get_name_header(ctx)
657
+ self.update_names(meta, ctx)
658
+
659
+ name_header_str = pctx.header
484
660
  text_chunk = text_chunk if isinstance(text_chunk, str) else str(text_chunk)
485
661
  text_chunk = text_chunk.translate({ord('<'): '&lt;', ord('>'): '&gt;'})
486
662
 
@@ -540,7 +716,7 @@ class Renderer(BaseRenderer):
540
716
  except Exception:
541
717
  pass
542
718
 
543
- self._throttle_queue(pid, name_header_str or "", html, text_chunk, replace, bool(is_code_block))
719
+ self._throttle_queue(pid, name_header_str or "", html, text_chunk, replace, is_code_block)
544
720
  self._throttle_emit(pid, force=False)
545
721
 
546
722
  def next_chunk(
@@ -623,6 +799,7 @@ class Renderer(BaseRenderer):
623
799
  if begin:
624
800
  self.pids[pid].live_buffer = ""
625
801
  return
802
+
626
803
  self.update_names(meta, ctx)
627
804
  raw_chunk = str(text_chunk).translate({ord('<'): '&lt;', ord('>'): '&gt;'})
628
805
  if begin:
@@ -648,7 +825,6 @@ class Renderer(BaseRenderer):
648
825
  )});"""
649
826
  )
650
827
  except Exception as e:
651
- print(e)
652
828
  pass
653
829
 
654
830
  def clear_live(self, meta: CtxMeta, ctx: CtxItem):
@@ -701,7 +877,7 @@ class Renderer(BaseRenderer):
701
877
  html=html,
702
878
  type=type,
703
879
  prev_ctx=prev_ctx,
704
- next_ctx=next_ctx
880
+ next_ctx=next_ctx,
705
881
  )
706
882
  )
707
883
 
@@ -745,14 +921,14 @@ class Renderer(BaseRenderer):
745
921
  self.append_input(
746
922
  meta,
747
923
  ctx,
748
- flush=False
924
+ flush=False,
749
925
  )
750
926
  self.append_output(
751
927
  meta,
752
928
  ctx,
753
929
  flush=False,
754
930
  prev_ctx=prev_ctx,
755
- next_ctx=next_ctx
931
+ next_ctx=next_ctx,
756
932
  )
757
933
 
758
934
  def append_extra(
@@ -1029,7 +1205,7 @@ class Renderer(BaseRenderer):
1029
1205
  ctx=ctx,
1030
1206
  html=html,
1031
1207
  prev_ctx=prev_ctx,
1032
- next_ctx=next_ctx
1208
+ next_ctx=next_ctx,
1033
1209
  )
1034
1210
  elif type == self.NODE_INPUT:
1035
1211
  return self.prepare_node_input(
@@ -1037,7 +1213,7 @@ class Renderer(BaseRenderer):
1037
1213
  ctx=ctx,
1038
1214
  html=html,
1039
1215
  prev_ctx=prev_ctx,
1040
- next_ctx=next_ctx
1216
+ next_ctx=next_ctx,
1041
1217
  )
1042
1218
 
1043
1219
  def prepare_node_input(
@@ -1141,8 +1317,10 @@ class Renderer(BaseRenderer):
1141
1317
  or out.startswith(('<tool>{"cmd"', '&lt;tool&gt;{"cmd"'))
1142
1318
  or out.rstrip().endswith(('}</tool>', '}&lt;/tool&gt;'))
1143
1319
  ):
1144
- spinner_class = "" if ctx.live else "display:none"
1145
- spinner = f"<span class=\"spinner\" style=\"{spinner_class}\"><img src=\"{self._file_prefix}{self._icon_sync}\" width=\"30\" height=\"30\" class=\"loading\"></span>"
1320
+ spinner_class = ""
1321
+ spinner = ""
1322
+ # spinner_class = "" if ctx.live else "display:none"
1323
+ # spinner = f"<span class=\"spinner\" style=\"{spinner_class}\"><img src=\"{self._file_prefix}{self._icon_sync}\" width=\"30\" height=\"30\" class=\"loading\"></span>"
1146
1324
 
1147
1325
  tool_extra = self.body.prepare_tool_extra(ctx)
1148
1326
  debug = self.append_debug(ctx, pid, "output") if self.is_debug() else ""
@@ -1240,6 +1418,7 @@ class Renderer(BaseRenderer):
1240
1418
  node = self.get_output_node_by_pid(pid)
1241
1419
  if node is not None:
1242
1420
  node.resetPage()
1421
+
1243
1422
  self._throttle_reset(pid)
1244
1423
 
1245
1424
  def get_output_node(
@@ -1282,7 +1461,8 @@ class Renderer(BaseRenderer):
1282
1461
  """
1283
1462
  try:
1284
1463
  self.get_output_node(ctx.meta).page().runJavaScript(
1285
- f"if (typeof window.removeNode !== 'undefined') removeNode({self.to_json(ctx.id)});")
1464
+ f"if (typeof window.removeNode !== 'undefined') removeNode({self.to_json(ctx.id)});"
1465
+ )
1286
1466
  except Exception:
1287
1467
  pass
1288
1468
 
@@ -1294,7 +1474,8 @@ class Renderer(BaseRenderer):
1294
1474
  """
1295
1475
  try:
1296
1476
  self.get_output_node(ctx.meta).page().runJavaScript(
1297
- f"if (typeof window.removeNodesFromId !== 'undefined') removeNodesFromId({self.to_json(ctx.id)});")
1477
+ f"if (typeof window.removeNodesFromId !== 'undefined') removeNodesFromId({self.to_json(ctx.id)});"
1478
+ )
1298
1479
  except Exception:
1299
1480
  pass
1300
1481
 
@@ -1456,12 +1637,16 @@ class Renderer(BaseRenderer):
1456
1637
  for node in nodes:
1457
1638
  try:
1458
1639
  node.page().runJavaScript(
1459
- f"if (typeof window.updateCSS !== 'undefined') updateCSS({to_json});")
1640
+ f"if (typeof window.updateCSS !== 'undefined') updateCSS({to_json});"
1641
+ )
1460
1642
  if self.window.core.config.get('render.blocks'):
1461
- node.page().runJavaScript("if (typeof window.enableBlocks !== 'undefined') enableBlocks();")
1643
+ node.page().runJavaScript(
1644
+ "if (typeof window.enableBlocks !== 'undefined') enableBlocks();"
1645
+ )
1462
1646
  else:
1463
1647
  node.page().runJavaScript(
1464
- "if (typeof window.disableBlocks !== 'undefined') disableBlocks();")
1648
+ "if (typeof window.disableBlocks !== 'undefined') disableBlocks();"
1649
+ )
1465
1650
  except Exception as e:
1466
1651
  pass
1467
1652
  return
@@ -1636,60 +1821,62 @@ class Renderer(BaseRenderer):
1636
1821
  is_code_block: bool
1637
1822
  ):
1638
1823
  """
1639
- Queue chunk for throttled emit
1824
+ Queue text chunk for throttled output
1640
1825
 
1641
1826
  :param pid: context PID
1642
- :param name: name of the chunk
1643
- :param html: HTML content of the chunk
1644
- :param text_chunk: raw text chunk
1645
- :param replace: whether to replace the current content
1646
- :param is_code_block: whether the chunk is a code block
1827
+ :param name: name header string
1828
+ :param html: HTML content to replace or append
1829
+ :param text_chunk: text chunk to append
1830
+ :param replace: True if the chunk should replace existing content
1831
+ :param is_code_block: True if the chunk is a code block
1647
1832
  """
1648
1833
  thr = self._throttle_get(pid)
1649
1834
  if name:
1650
1835
  thr["name"] = name
1836
+
1651
1837
  if replace:
1652
1838
  thr["op"] = 1
1653
1839
  thr["replace_html"] = html
1654
1840
  thr["append"].clear()
1655
1841
  thr["code"] = bool(is_code_block)
1656
1842
  else:
1657
- if thr["op"] != 1:
1658
- thr["op"] = 2
1843
+ if thr["op"] == 1:
1844
+ thr["replace_html"] = html
1845
+ thr["code"] = bool(is_code_block)
1846
+ return
1847
+ thr["op"] = 2
1659
1848
  thr["append"].append(text_chunk)
1660
1849
  thr["code"] = bool(is_code_block)
1661
1850
 
1662
1851
  def _throttle_emit(self, pid: int, force: bool = False):
1663
1852
  """
1664
- Emit queued chunks if due
1853
+ Emit throttled output to the node
1665
1854
 
1666
1855
  :param pid: context PID
1667
- :param force: force emit regardless of throttle interval
1856
+ :param force: Force emit even if throttle interval has not passed
1668
1857
  """
1669
1858
  thr = self._throttle_get(pid)
1670
1859
  now = monotonic()
1671
1860
  if not force and (now - thr["last"] < self._throttle_interval):
1672
1861
  return
1673
- if thr["op"] == 1:
1674
- try:
1675
- node = self.get_output_node_by_pid(pid)
1676
- if node is not None:
1677
- node.page().bridge.chunk.emit(
1678
- thr["name"],
1679
- self.sanitize_html(thr["replace_html"]),
1680
- "",
1681
- True,
1682
- bool(thr["code"]),
1683
- )
1684
- except Exception:
1685
- pass
1686
- thr["last"] = now
1687
- self._throttle_reset(pid)
1688
- elif thr["op"] == 2 and thr["append"]:
1689
- append_str = "".join(thr["append"])
1690
- try:
1691
- node = self.get_output_node_by_pid(pid)
1692
- if node is not None:
1862
+
1863
+ node = self.get_output_node_by_pid(pid)
1864
+ if node is None:
1865
+ return
1866
+
1867
+ try:
1868
+ if thr["op"] == 1:
1869
+ node.page().bridge.chunk.emit(
1870
+ thr["name"],
1871
+ self.sanitize_html(thr["replace_html"]),
1872
+ "",
1873
+ True,
1874
+ bool(thr["code"]),
1875
+ )
1876
+ thr["last"] = now
1877
+
1878
+ if thr["append"]:
1879
+ append_str = "".join(thr["append"])
1693
1880
  node.page().bridge.chunk.emit(
1694
1881
  thr["name"],
1695
1882
  "",
@@ -1697,7 +1884,20 @@ class Renderer(BaseRenderer):
1697
1884
  False,
1698
1885
  bool(thr["code"]),
1699
1886
  )
1700
- except Exception:
1701
- pass
1702
- thr["last"] = now
1703
- self._throttle_reset(pid)
1887
+ thr["last"] = now
1888
+
1889
+ self._throttle_reset(pid)
1890
+
1891
+ elif thr["op"] == 2 and thr["append"]:
1892
+ append_str = "".join(thr["append"])
1893
+ node.page().bridge.chunk.emit(
1894
+ thr["name"],
1895
+ "",
1896
+ self.sanitize_html(append_str),
1897
+ False,
1898
+ bool(thr["code"]),
1899
+ )
1900
+ thr["last"] = now
1901
+ self._throttle_reset(pid)
1902
+ except Exception:
1903
+ pass
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "__meta__": {
3
- "version": "2.6.12",
4
- "app.version": "2.6.12",
3
+ "version": "2.6.14",
4
+ "app.version": "2.6.14",
5
5
  "updated_at": "2025-08-19T00:00:00"
6
6
  },
7
7
  "access.audio.event.speech": false,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "__meta__": {
3
- "version": "2.6.12",
4
- "app.version": "2.6.12",
3
+ "version": "2.6.14",
4
+ "app.version": "2.6.14",
5
5
  "updated_at": "2025-08-19T23:07:35"
6
6
  },
7
7
  "items": {
@@ -118,8 +118,6 @@ class Presets:
118
118
  self.window.ui.models[self.id] = model
119
119
  view.setModel(model)
120
120
 
121
- blocker = QtCore.QSignalBlocker(model)
122
-
123
121
  rc = model.rowCount()
124
122
  if rc:
125
123
  model.removeRows(0, rc)
@@ -144,6 +142,4 @@ class Presets:
144
142
  model.setData(index, name, QtCore.Qt.DisplayRole)
145
143
  model.setData(index, tooltip, QtCore.Qt.ToolTipRole)
146
144
 
147
- del blocker
148
-
149
145
  view.restore_selection()
@@ -124,7 +124,6 @@ class ChatWebOutput(QWebEngineView):
124
124
  """
125
125
  p = QWebEngineProfile(parent or self)
126
126
  try:
127
- p.setHttpCacheType(QWebEngineProfile.NoCache)
128
127
  p.setHttpCacheMaximumSize(0)
129
128
  p.setPersistentCookiesPolicy(QWebEngineProfile.NoPersistentCookies)
130
129
  p.setSpellCheckEnabled(False)
@@ -193,7 +192,6 @@ class ChatWebOutput(QWebEngineView):
193
192
  p.runJavaScript(
194
193
  f"""clean();"""
195
194
  )
196
- p.profile().clearHttpCache()
197
195
  try:
198
196
  p.history().clear()
199
197
  except Exception:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pygpt-net
3
- Version: 2.6.12
3
+ Version: 2.6.14
4
4
  Summary: Desktop AI Assistant powered by: OpenAI GPT-5, o1, o3, GPT-4, Gemini, Claude, Grok, DeepSeek, and other models supported by Llama Index, and Ollama. Chatbot, agents, completion, image generation, vision analysis, speech-to-text, plugins, internet access, file handling, command execution and more.
5
5
  License: MIT
6
6
  Keywords: py_gpt,py-gpt,pygpt,desktop,app,o1,o3,gpt-5,gpt,gpt4,gpt-4o,gpt-4v,gpt3.5,gpt-4,gpt-4-vision,gpt-3.5,llama3,mistral,gemini,grok,deepseek,bielik,claude,tts,whisper,vision,chatgpt,dall-e,chat,chatbot,assistant,text completion,image generation,ai,api,openai,api key,langchain,llama-index,ollama,presets,ui,qt,pyside
@@ -108,7 +108,7 @@ Description-Content-Type: text/markdown
108
108
 
109
109
  [![pygpt](https://snapcraft.io/pygpt/badge.svg)](https://snapcraft.io/pygpt)
110
110
 
111
- Release: **2.6.12** | build: **2025-08-19** | Python: **>=3.10, <3.14**
111
+ Release: **2.6.14** | build: **2025-08-19** | Python: **>=3.10, <3.14**
112
112
 
113
113
  > Official website: https://pygpt.net | Documentation: https://pygpt.readthedocs.io
114
114
  >
@@ -4566,6 +4566,18 @@ may consume additional tokens that are not displayed in the main window.
4566
4566
 
4567
4567
  ## Recent changes:
4568
4568
 
4569
+ **2.6.14 (2025-08-19)**
4570
+
4571
+ - Fixed: Agent evaluation tool runs even if tools are disabled.
4572
+ - Extended agent response evaluation by providing the full context of the output.
4573
+
4574
+ **2.6.13 (2025-08-19)**
4575
+
4576
+ - Fix: Do not load the index in experts if it is not provided.
4577
+ - Fix: Load remote images in the webview.
4578
+ - Fix: Presets list refresh.
4579
+ - Optimize context items reload.
4580
+
4569
4581
  **2.6.12 (2025-08-19)**
4570
4582
 
4571
4583
  - Optimized web renderer memory cleanup.
@@ -1,6 +1,6 @@
1
- pygpt_net/CHANGELOG.txt,sha256=gEIPus9VmASjLbiQjZvhZR9-sgBQER3PfEL46R57xz4,99610
1
+ pygpt_net/CHANGELOG.txt,sha256=MteKitJVszN9R1u3hfVWk11KFOxt9a4NIkyIVhWVffE,99967
2
2
  pygpt_net/LICENSE,sha256=dz9sfFgYahvu2NZbx4C1xCsVn9GVer2wXcMkFRBvqzY,1146
3
- pygpt_net/__init__.py,sha256=1_gsJg2YfCYG2fGGUHA1yUGFG0C-20YiqcLOldiEyW8,1373
3
+ pygpt_net/__init__.py,sha256=qxhiFAYY-bI6byswkH6rOhEXbQF7ZpcYWH2apkXFhaM,1373
4
4
  pygpt_net/app.py,sha256=2IXjjYJ0tm-iFn3pHu3-JGoFAnN9YvmXGHPmeOhpU3Y,20999
5
5
  pygpt_net/config.py,sha256=LCKrqQfePVNrAvH3EY_1oZx1Go754sDoyUneJ0iGWFI,16660
6
6
  pygpt_net/container.py,sha256=NsMSHURaEC_eW8vrCNdztwqkxB7jui3yVlzUOMYvCHg,4124
@@ -40,9 +40,9 @@ pygpt_net/controller/chat/common.py,sha256=mOHvXqj3pPCzNPU82i7NXSmglW8jh7G5cCKDe
40
40
  pygpt_net/controller/chat/files.py,sha256=QZAi1Io57EU7htKt9M5I9OoGAFX51OH2V5-NsJktOto,2838
41
41
  pygpt_net/controller/chat/image.py,sha256=yPX26gsz0fLnyXR88lpVyvvHnKA-yZwfXJ4paUDYkeM,8579
42
42
  pygpt_net/controller/chat/input.py,sha256=EPA90r6GqHIlu4JJbr0cuvKIEYSs6LVkimxrWHAyyX0,12390
43
- pygpt_net/controller/chat/output.py,sha256=VL4OmC6MMy2KvJlMo6ipFqvd0oVNUK9F14BzUHWFfno,10860
43
+ pygpt_net/controller/chat/output.py,sha256=aSgZ8E8IaP4Jjd0ab6eXhebM_YIRPW7pRJUesYCgDQg,10864
44
44
  pygpt_net/controller/chat/render.py,sha256=YIKWMZIUXD3f_11p9mXjgg-TtudZTjJ26iHXTn553Qc,20401
45
- pygpt_net/controller/chat/response.py,sha256=6Z9IdMCbkWebM6kTzL19tLqSHRrjQqe6QV7ildGxIpE,12391
45
+ pygpt_net/controller/chat/response.py,sha256=tacJOG_iG7IjEFiZ4iDggEVVS9mbL0e92JBC--7bnCY,12543
46
46
  pygpt_net/controller/chat/stream.py,sha256=zmDGI_Z9Rn8IYv6vEIVBMTOGjjY0zlfmM3qJMddRGRI,21994
47
47
  pygpt_net/controller/chat/text.py,sha256=ktluNw9ItG4g9p3OpOSmgALhFf1Gnonhl3J9kLzdTqU,10743
48
48
  pygpt_net/controller/chat/vision.py,sha256=LsFc0TZZwY8dVtJH6Q5iha8rUQCf5HhOMuRXMtnLzZU,3578
@@ -112,7 +112,7 @@ pygpt_net/controller/plugins/plugins.py,sha256=jO5KcC0jsIcwF2U6eSZqicGKUr2MzC0F7
112
112
  pygpt_net/controller/plugins/presets.py,sha256=8EsEwpU2MjWMQu1kcY4JTcyqqN8pjBrcxA2uW2tFU_A,11674
113
113
  pygpt_net/controller/plugins/settings.py,sha256=pa0iJvpb1SXWD8hqYoC_BuSogx2-5u6nwcFF3TH5sWw,5732
114
114
  pygpt_net/controller/presets/__init__.py,sha256=Bb9_aAvGxQcKCW2fvG5CAJ6ZUwNYN3GaCf3BXB9eGfI,511
115
- pygpt_net/controller/presets/editor.py,sha256=NJypX8a4QAZ_S1YuLHk5YKfKl0QASZ4xcJnSVK2VLHQ,39468
115
+ pygpt_net/controller/presets/editor.py,sha256=-fFDkIqDwhYwAaSRuK6IayjX8RriqFoc0_LKblSOi-Q,39449
116
116
  pygpt_net/controller/presets/experts.py,sha256=dfPKmAPO-7gaUD2ILs3lR005ir32G5vV-Sa5TGEHwOU,5820
117
117
  pygpt_net/controller/presets/presets.py,sha256=Tq9AIgr042ALu6hEQunBxnUZTzLdzmp4IStWprzmyjg,21918
118
118
  pygpt_net/controller/settings/__init__.py,sha256=hn5n_Hti6byJQdQCs4Ld2EbPoZF7dHVMwqaBPscePQ8,512
@@ -146,16 +146,16 @@ pygpt_net/core/agents/bridge.py,sha256=KhCbMTZNigNlgOhXEMN1kqWGNUhkEdjFdiHBBVTAr
146
146
  pygpt_net/core/agents/legacy.py,sha256=DdlyIpFjmeAC4XUGtq3F5_1BLGZLPOej0RZ6x9ycFjM,1731
147
147
  pygpt_net/core/agents/memory.py,sha256=9Jz9kT-xT8QPpGeXEpWopJUGBLLHu6Ys_-fRrg6BWDg,5210
148
148
  pygpt_net/core/agents/observer/__init__.py,sha256=qVIBJKpGbc0k7PTESAwAR7SbN-pbkBMJUTzeliCAaJU,651
149
- pygpt_net/core/agents/observer/evaluation.py,sha256=VngvBMXzgJaAvWV10oo1HDJ_Nzce55A59DsDGDKLlVo,7633
149
+ pygpt_net/core/agents/observer/evaluation.py,sha256=r-zIRXZpOgo8TJ0qbNPL2Qm_9zmPac9AEWwIbnIW4T8,8491
150
150
  pygpt_net/core/agents/provider.py,sha256=rjxnuqzRxv2Z1d9i_wKpREwJBTeTgtyBDYtyHuwcSPA,2440
151
- pygpt_net/core/agents/runner.py,sha256=haHO3HXEpRVSB3b__vHaiaUUNaMDwoXJAFNy9SqivAc,12069
151
+ pygpt_net/core/agents/runner.py,sha256=C3BQkpHLrd92EuM55mR4PnCJMVvZ4nV0kDhed4xfl9o,12186
152
152
  pygpt_net/core/agents/runners/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
153
153
  pygpt_net/core/agents/runners/base.py,sha256=XjheBYhBZan51r3vkUh5uf00sYiRj8btZUeUP1jpqlA,5687
154
154
  pygpt_net/core/agents/runners/helpers.py,sha256=0iQQlSg_pJfxY_gQEWImnyAVkTUQYYSW67Z9DS7oUYw,8305
155
155
  pygpt_net/core/agents/runners/llama_assistant.py,sha256=a_Abkc8u1S8vr6lUIDRrzTM9sQnEvyZA8nZxXaYp05w,2492
156
156
  pygpt_net/core/agents/runners/llama_plan.py,sha256=CC3WPG9KUxd_dRjPZROOrmPQrWQ_u8C0nRx0TCzi9bE,13391
157
157
  pygpt_net/core/agents/runners/llama_steps.py,sha256=1SBLp5t4TUsxpYIUtSSnBy5Sd2AxheDlv2AXimls-Vg,7328
158
- pygpt_net/core/agents/runners/llama_workflow.py,sha256=YkhEcV_dI6uzJBVtgBRYmRW_gLt2Uz4IK6l028VmbPk,11685
158
+ pygpt_net/core/agents/runners/llama_workflow.py,sha256=yDy1YDnG0A2OIs1FnJArXql8-BPnT7qpEywh3HqhR8c,12086
159
159
  pygpt_net/core/agents/runners/loop.py,sha256=opcVGx8WFjJesLlmMzoCBgP06Ajh6j_Taat4zCTumHg,6022
160
160
  pygpt_net/core/agents/runners/openai_workflow.py,sha256=J47INptxu8Uc40UfAWNRRiHRYL6ZM6lPojoqeHsC-mc,7989
161
161
  pygpt_net/core/agents/tools.py,sha256=6V2IjSF0m8cNY0HI7vW9bTLjKzR1KtcP0XTcHBvrPjU,21727
@@ -232,7 +232,7 @@ pygpt_net/core/events/event.py,sha256=uxNdPGaV5KDBaosPM6uxio7dPig091wAoz-OdOPCmx
232
232
  pygpt_net/core/events/kernel.py,sha256=Y5zQ-YCex04OQNMRMC7Q8g55A-imyj9XQ0Jkuyk2eCU,2074
233
233
  pygpt_net/core/events/render.py,sha256=Xfncp6ESvjPyBLtFq6KiNxckAFDN0DsUOJ_mrowjfnM,2525
234
234
  pygpt_net/core/experts/__init__.py,sha256=oscAmAEsCZclyHU7k3z5JzYqilwIO7J90e6oTa29tZ0,511
235
- pygpt_net/core/experts/experts.py,sha256=iLMgzV9wXzI4Rn48UC_hOSkLsPpNAdWI6obJ-IrAErE,30425
235
+ pygpt_net/core/experts/experts.py,sha256=Bq7-xsXK-UBs7ZbjC6kPDULOIwndDcAJSHlV1vXIMug,30287
236
236
  pygpt_net/core/filesystem/__init__.py,sha256=KZLS3s_otd3Md9eDA6FN-b4CtOCWl_fplUlM9V6hTy8,514
237
237
  pygpt_net/core/filesystem/actions.py,sha256=2lRVF_MpIxCwbH8DkugP0K6pY6FymLeH6LKVR2rtQGQ,4152
238
238
  pygpt_net/core/filesystem/editor.py,sha256=or7cT2xhZfDwjX47reyXQCt-_1c4h_xPJDddYi1auNw,4284
@@ -280,7 +280,7 @@ pygpt_net/core/platforms/platforms.py,sha256=599XwekDL1cNs5p8i89rcUO05Dl4t1XFBPf
280
280
  pygpt_net/core/plugins/__init__.py,sha256=NOKL-CNsF4rrKTBpsN-ue92H4pTUGKlgDCwr1iA0geY,511
281
281
  pygpt_net/core/plugins/plugins.py,sha256=2tARWlrBbjarWINp-woHMqB4jzp2SvzVVZVrLzFhgxg,14832
282
282
  pygpt_net/core/presets/__init__.py,sha256=NZjBxjGv4fgEX6Hp8FznsWK5QqD1Tl7zyp2Ir3ufXv4,511
283
- pygpt_net/core/presets/presets.py,sha256=zDe5S5YX5IySlXWz6_AOBjktm6-BFVZgFWfl7gsKYgg,13006
283
+ pygpt_net/core/presets/presets.py,sha256=rdumbBggdXJCZ45o4aFOBswzW4GDGXrWBAAEZneJRig,12961
284
284
  pygpt_net/core/profile/__init__.py,sha256=ovh37AKXCbEz1owutNltCXRkmhZj097wcdZLSzkJUvk,511
285
285
  pygpt_net/core/profile/profile.py,sha256=ZpXKTwbViskCUDBn8JvxSk7wRFdfrwMfs7Gb3O7N_48,7840
286
286
  pygpt_net/core/prompt/__init__.py,sha256=4GH-2XlmPjySjMTEWWb_gZDDetT8lZaoUc-P6FzECus,510
@@ -306,8 +306,8 @@ pygpt_net/core/render/web/__init__.py,sha256=istp5dsn6EkLEP7lOBeDb8RjodUcWZqjcEv
306
306
  pygpt_net/core/render/web/body.py,sha256=rybg76GiLWowR-qEvM0Y64woSsO4KSBnww4f8BU7GgI,54872
307
307
  pygpt_net/core/render/web/helpers.py,sha256=ivrXrCqRIUWHDmu3INu-i6XUlB2W9IOO8iYyqpbnSRU,5438
308
308
  pygpt_net/core/render/web/parser.py,sha256=pDFc9Tf8P-jvrDilXyT1fukcQHbixHRJ9Dn9hF10Gko,12892
309
- pygpt_net/core/render/web/pid.py,sha256=4NuTQAb7LyljKOjmbXUG_o-HBU7hbfPWJdrLsMNglAU,3658
310
- pygpt_net/core/render/web/renderer.py,sha256=bIg6lKOAy2_k9xkwOYVS80mDAMl56ePQjTP-RoSz3Ss,50710
309
+ pygpt_net/core/render/web/pid.py,sha256=pXBdPb8hw_aZS2Rtz3pLBpuybpXrzoqwYAFWBal9bLE,3685
310
+ pygpt_net/core/render/web/renderer.py,sha256=b7nKnICWSrqZqdd6VBN-JPbm_x5WIkTQ7auhF72Hm-Y,56128
311
311
  pygpt_net/core/render/web/syntax_highlight.py,sha256=QSLGF5cJL_Xeqej7_TYwY_5C2w9enXV_cMEuaJ3C43U,2005
312
312
  pygpt_net/core/settings/__init__.py,sha256=GQ6_gJ2jf_Chm7ZuZLvkcvEh_sfMDVMBieeoJi2iPI4,512
313
313
  pygpt_net/core/settings/settings.py,sha256=onqwNiICm2VhHfmXLvp1MiEJ14m2jzeeI2pjUiaUwtY,7787
@@ -343,8 +343,8 @@ pygpt_net/css_rc.py,sha256=i13kX7irhbYCWZ5yJbcMmnkFp_UfS4PYnvRFSPF7XXo,11349
343
343
  pygpt_net/data/audio/click_off.mp3,sha256=aNiRDP1pt-Jy7ija4YKCNFBwvGWbzU460F4pZWZDS90,65201
344
344
  pygpt_net/data/audio/click_on.mp3,sha256=qfdsSnthAEHVXzeyN4LlC0OvXuyW8p7stb7VXtlvZ1k,65201
345
345
  pygpt_net/data/audio/ok.mp3,sha256=LTiV32pEBkpUGBkKkcOdOFB7Eyt_QoP2Nv6c5AaXftk,32256
346
- pygpt_net/data/config/config.json,sha256=Qg03MSmjEyjvVZy-DIaLQfInXRGWFhiFn3VtgmvZ2w8,24924
347
- pygpt_net/data/config/models.json,sha256=4w3c_lo1lAhChheQKalYiVJE_wRWwb9X7bKDUtZOAAU,109650
346
+ pygpt_net/data/config/config.json,sha256=pYWdDpJvFUZg2YhkGAe2sfqhzyb8nC5ZmZMMrZN0c8U,24924
347
+ pygpt_net/data/config/models.json,sha256=eD8uuC55qsr7lljL0b-JdwL6ieTBjvKGqUnrZ3wN8Uw,109650
348
348
  pygpt_net/data/config/modes.json,sha256=M882iiqX_R2sNQl9cqZ3k-uneEvO9wpARtHRMLx_LHw,2265
349
349
  pygpt_net/data/config/presets/agent_code_act.json,sha256=GYHqhxtKFLUCvRI3IJAJ7Qe1k8yD9wGGNwManldWzlI,754
350
350
  pygpt_net/data/config/presets/agent_openai.json,sha256=bpDJgLRey_effQkzFRoOEGd4aHUrmzeODSDdNzrf62I,730
@@ -2308,7 +2308,7 @@ pygpt_net/ui/layout/toolbox/image.py,sha256=QiMDZmsLklIEVDibq1FRraD30NJll_bn4HVp
2308
2308
  pygpt_net/ui/layout/toolbox/indexes.py,sha256=fPRuMS96HX3VJdvbGVg0Z7N6P0LTbrYM0BYjXZOUUic,8502
2309
2309
  pygpt_net/ui/layout/toolbox/mode.py,sha256=EoXDzzhh3XRE5i42sWmiOCLT_m_sUELYXfk_vpDNoSs,1772
2310
2310
  pygpt_net/ui/layout/toolbox/model.py,sha256=9JHW8yzTHUh6TJmOAylriwlDsyrB8J9wDpJpHR__z9I,1789
2311
- pygpt_net/ui/layout/toolbox/presets.py,sha256=uEmMy3gudpjKFQbDVNShjK1iBw-bl-1IXSnrhitTJgI,5634
2311
+ pygpt_net/ui/layout/toolbox/presets.py,sha256=praww59pJLD7l5TITJh--B5H7V_OH1_8t3KSw2yvgFw,5565
2312
2312
  pygpt_net/ui/layout/toolbox/prompt.py,sha256=jebF-q1S1Et6ISa9vI0_nM4sb7liDesAXJHtZ5Ll7ZI,4006
2313
2313
  pygpt_net/ui/layout/toolbox/toolbox.py,sha256=zEZr_XDz9QbPKL0u0KMSt1b8yOG-ao1gmZPvWWVpuVs,3392
2314
2314
  pygpt_net/ui/layout/toolbox/vision.py,sha256=GZY-N2z8re1LN1ntsy-3Ius8OY4DujmJpyJ1qP2ZRxs,2447
@@ -2433,12 +2433,12 @@ pygpt_net/ui/widget/textarea/output.py,sha256=8T2spzqVYHKopSB83p1ULazGZ14nFJhXLB
2433
2433
  pygpt_net/ui/widget/textarea/rename.py,sha256=NwuGRIeWMo7WfsMguAFpTqdOz1eTiXbxrDXGsbWF_TY,1358
2434
2434
  pygpt_net/ui/widget/textarea/search_input.py,sha256=phEXf50VcfCRBen0p2iEAzuX2zmrSE3nWVRfWmtHKpo,5228
2435
2435
  pygpt_net/ui/widget/textarea/url.py,sha256=xbNQxoM5fYI1ZWbvybQkPmNPrIq3yhtNPBOSOWftZCg,1337
2436
- pygpt_net/ui/widget/textarea/web.py,sha256=EWx9mE3Qxn_6zuVtM8wB_V572Vx_Z_48jCdw7rbQnas,19520
2436
+ pygpt_net/ui/widget/textarea/web.py,sha256=3XA7Ue8PtxYkVbZRaOPIGjpC5Iko37RlxfO358UEdrk,19425
2437
2437
  pygpt_net/ui/widget/vision/__init__.py,sha256=8HT4tQFqQogEEpGYTv2RplKBthlsFKcl5egnv4lzzEw,488
2438
2438
  pygpt_net/ui/widget/vision/camera.py,sha256=T8b5cmK6uhf_WSSxzPt_Qod8JgMnst6q8sQqRvgQiSA,2584
2439
2439
  pygpt_net/utils.py,sha256=gGbw-lBTodGg_uBx6zKEwa58GaVNZN1I9zY_ZDyJ9xg,8872
2440
- pygpt_net-2.6.12.dist-info/LICENSE,sha256=rbPqNB_xxANH8hKayJyIcTwD4bj4Y2G-Mcm85r1OImM,1126
2441
- pygpt_net-2.6.12.dist-info/METADATA,sha256=J5a2R9BBBuEl2cai2hgfwLHYP71UbcMNbiZNM3MXxEM,189317
2442
- pygpt_net-2.6.12.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
2443
- pygpt_net-2.6.12.dist-info/entry_points.txt,sha256=qvpII6UHIt8XfokmQWnCYQrTgty8FeJ9hJvOuUFCN-8,43
2444
- pygpt_net-2.6.12.dist-info/RECORD,,
2440
+ pygpt_net-2.6.14.dist-info/LICENSE,sha256=rbPqNB_xxANH8hKayJyIcTwD4bj4Y2G-Mcm85r1OImM,1126
2441
+ pygpt_net-2.6.14.dist-info/METADATA,sha256=unXw9fPsGAEbt_rxZ0LGD0J5d4z9T1y-9SxBWKSBjs0,189682
2442
+ pygpt_net-2.6.14.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
2443
+ pygpt_net-2.6.14.dist-info/entry_points.txt,sha256=qvpII6UHIt8XfokmQWnCYQrTgty8FeJ9hJvOuUFCN-8,43
2444
+ pygpt_net-2.6.14.dist-info/RECORD,,