pygpt-net 2.6.20__py3-none-any.whl → 2.6.22__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.
Files changed (221) hide show
  1. pygpt_net/CHANGELOG.txt +13 -0
  2. pygpt_net/__init__.py +3 -3
  3. pygpt_net/app.py +3 -1
  4. pygpt_net/controller/__init__.py +4 -8
  5. pygpt_net/controller/access/voice.py +2 -2
  6. pygpt_net/controller/agent/agent.py +130 -2
  7. pygpt_net/controller/agent/experts.py +93 -96
  8. pygpt_net/controller/agent/llama.py +2 -1
  9. pygpt_net/controller/assistant/assistant.py +18 -1
  10. pygpt_net/controller/assistant/batch.py +2 -3
  11. pygpt_net/controller/assistant/editor.py +2 -2
  12. pygpt_net/controller/assistant/files.py +2 -3
  13. pygpt_net/controller/assistant/store.py +2 -2
  14. pygpt_net/controller/attachment/attachment.py +17 -1
  15. pygpt_net/controller/audio/audio.py +2 -2
  16. pygpt_net/controller/camera/camera.py +15 -7
  17. pygpt_net/controller/chat/chat.py +2 -2
  18. pygpt_net/controller/chat/common.py +50 -33
  19. pygpt_net/controller/chat/image.py +67 -77
  20. pygpt_net/controller/chat/input.py +94 -166
  21. pygpt_net/controller/chat/output.py +83 -140
  22. pygpt_net/controller/chat/response.py +83 -102
  23. pygpt_net/controller/chat/text.py +116 -149
  24. pygpt_net/controller/ctx/common.py +2 -1
  25. pygpt_net/controller/ctx/ctx.py +87 -6
  26. pygpt_net/controller/files/files.py +13 -1
  27. pygpt_net/controller/idx/idx.py +26 -2
  28. pygpt_net/controller/idx/indexer.py +85 -76
  29. pygpt_net/controller/kernel/reply.py +53 -66
  30. pygpt_net/controller/kernel/stack.py +16 -16
  31. pygpt_net/controller/lang/lang.py +52 -34
  32. pygpt_net/controller/model/importer.py +3 -2
  33. pygpt_net/controller/model/model.py +62 -3
  34. pygpt_net/controller/notepad/notepad.py +86 -84
  35. pygpt_net/controller/plugins/settings.py +3 -4
  36. pygpt_net/controller/settings/editor.py +4 -4
  37. pygpt_net/controller/settings/profile.py +105 -124
  38. pygpt_net/controller/theme/menu.py +154 -57
  39. pygpt_net/controller/theme/nodes.py +51 -44
  40. pygpt_net/controller/theme/theme.py +33 -9
  41. pygpt_net/controller/tools/tools.py +2 -2
  42. pygpt_net/controller/ui/tabs.py +2 -3
  43. pygpt_net/controller/ui/ui.py +16 -2
  44. pygpt_net/core/agents/observer/evaluation.py +3 -3
  45. pygpt_net/core/agents/provider.py +25 -3
  46. pygpt_net/core/agents/runner.py +4 -1
  47. pygpt_net/core/agents/runners/llama_workflow.py +19 -7
  48. pygpt_net/core/agents/runners/loop.py +3 -1
  49. pygpt_net/core/agents/runners/openai_workflow.py +17 -3
  50. pygpt_net/core/agents/tools.py +4 -1
  51. pygpt_net/core/bridge/context.py +34 -37
  52. pygpt_net/core/ctx/container.py +13 -12
  53. pygpt_net/core/ctx/ctx.py +1 -1
  54. pygpt_net/core/ctx/output.py +7 -4
  55. pygpt_net/core/db/database.py +2 -2
  56. pygpt_net/core/debug/console/console.py +2 -2
  57. pygpt_net/core/debug/debug.py +12 -1
  58. pygpt_net/core/dispatcher/dispatcher.py +24 -1
  59. pygpt_net/core/events/app.py +7 -7
  60. pygpt_net/core/events/control.py +26 -26
  61. pygpt_net/core/events/event.py +6 -3
  62. pygpt_net/core/events/kernel.py +2 -2
  63. pygpt_net/core/events/render.py +13 -13
  64. pygpt_net/core/experts/experts.py +76 -82
  65. pygpt_net/core/experts/worker.py +12 -12
  66. pygpt_net/core/filesystem/actions.py +1 -2
  67. pygpt_net/core/models/models.py +5 -1
  68. pygpt_net/core/models/ollama.py +14 -5
  69. pygpt_net/core/render/plain/helpers.py +2 -5
  70. pygpt_net/core/render/plain/renderer.py +26 -30
  71. pygpt_net/core/render/web/body.py +1 -1
  72. pygpt_net/core/render/web/helpers.py +2 -2
  73. pygpt_net/core/render/web/renderer.py +4 -4
  74. pygpt_net/core/settings/settings.py +43 -13
  75. pygpt_net/core/tabs/tabs.py +20 -13
  76. pygpt_net/core/types/__init__.py +2 -1
  77. pygpt_net/core/types/agent.py +4 -4
  78. pygpt_net/core/types/base.py +19 -0
  79. pygpt_net/core/types/console.py +6 -6
  80. pygpt_net/core/types/mode.py +8 -8
  81. pygpt_net/core/types/multimodal.py +3 -3
  82. pygpt_net/core/types/openai.py +2 -1
  83. pygpt_net/data/config/config.json +5 -5
  84. pygpt_net/data/config/models.json +19 -3
  85. pygpt_net/data/config/settings.json +14 -14
  86. pygpt_net/data/locale/locale.de.ini +4 -1
  87. pygpt_net/data/locale/locale.en.ini +6 -3
  88. pygpt_net/data/locale/locale.es.ini +4 -1
  89. pygpt_net/data/locale/locale.fr.ini +4 -1
  90. pygpt_net/data/locale/locale.it.ini +4 -1
  91. pygpt_net/data/locale/locale.pl.ini +5 -4
  92. pygpt_net/data/locale/locale.uk.ini +4 -1
  93. pygpt_net/data/locale/locale.zh.ini +4 -1
  94. pygpt_net/item/ctx.py +256 -240
  95. pygpt_net/item/model.py +59 -116
  96. pygpt_net/item/preset.py +122 -105
  97. pygpt_net/plugin/twitter/plugin.py +2 -2
  98. pygpt_net/provider/agents/llama_index/workflow/planner.py +3 -3
  99. pygpt_net/provider/agents/openai/agent.py +4 -12
  100. pygpt_net/provider/agents/openai/agent_b2b.py +10 -15
  101. pygpt_net/provider/agents/openai/agent_planner.py +4 -4
  102. pygpt_net/provider/agents/openai/agent_with_experts.py +3 -7
  103. pygpt_net/provider/agents/openai/agent_with_experts_feedback.py +4 -8
  104. pygpt_net/provider/agents/openai/agent_with_feedback.py +4 -8
  105. pygpt_net/provider/agents/openai/bot_researcher.py +2 -18
  106. pygpt_net/provider/agents/openai/bots/__init__.py +0 -0
  107. pygpt_net/provider/agents/openai/bots/research_bot/__init__.py +0 -0
  108. pygpt_net/provider/agents/openai/bots/research_bot/agents/__init__.py +0 -0
  109. pygpt_net/provider/agents/openai/bots/research_bot/agents/planner_agent.py +1 -1
  110. pygpt_net/provider/agents/openai/bots/research_bot/agents/search_agent.py +1 -0
  111. pygpt_net/provider/agents/openai/bots/research_bot/agents/writer_agent.py +1 -1
  112. pygpt_net/provider/agents/openai/bots/research_bot/manager.py +1 -10
  113. pygpt_net/provider/agents/openai/evolve.py +5 -9
  114. pygpt_net/provider/agents/openai/supervisor.py +4 -8
  115. pygpt_net/provider/core/config/patch.py +10 -3
  116. pygpt_net/provider/core/ctx/db_sqlite/utils.py +43 -43
  117. pygpt_net/provider/core/model/patch.py +11 -1
  118. pygpt_net/provider/core/preset/json_file.py +47 -49
  119. pygpt_net/provider/gpt/agents/experts.py +2 -2
  120. pygpt_net/tools/audio_transcriber/ui/dialogs.py +44 -54
  121. pygpt_net/tools/code_interpreter/body.py +1 -2
  122. pygpt_net/tools/code_interpreter/tool.py +7 -4
  123. pygpt_net/tools/code_interpreter/ui/html.py +1 -3
  124. pygpt_net/tools/code_interpreter/ui/widgets.py +2 -3
  125. pygpt_net/tools/html_canvas/ui/widgets.py +1 -3
  126. pygpt_net/tools/image_viewer/ui/dialogs.py +40 -37
  127. pygpt_net/tools/indexer/ui/widgets.py +2 -4
  128. pygpt_net/tools/media_player/tool.py +2 -5
  129. pygpt_net/tools/media_player/ui/widgets.py +60 -36
  130. pygpt_net/tools/text_editor/ui/widgets.py +18 -19
  131. pygpt_net/tools/translator/ui/widgets.py +39 -35
  132. pygpt_net/ui/base/context_menu.py +9 -4
  133. pygpt_net/ui/dialog/db.py +1 -3
  134. pygpt_net/ui/dialog/models.py +1 -3
  135. pygpt_net/ui/dialog/models_importer.py +2 -4
  136. pygpt_net/ui/dialogs.py +34 -30
  137. pygpt_net/ui/layout/chat/attachments.py +72 -84
  138. pygpt_net/ui/layout/chat/attachments_ctx.py +40 -44
  139. pygpt_net/ui/layout/chat/attachments_uploaded.py +36 -39
  140. pygpt_net/ui/layout/chat/calendar.py +100 -70
  141. pygpt_net/ui/layout/chat/chat.py +23 -17
  142. pygpt_net/ui/layout/chat/input.py +95 -118
  143. pygpt_net/ui/layout/chat/output.py +100 -162
  144. pygpt_net/ui/layout/chat/painter.py +89 -61
  145. pygpt_net/ui/layout/ctx/ctx_list.py +43 -52
  146. pygpt_net/ui/layout/status.py +23 -14
  147. pygpt_net/ui/layout/toolbox/agent.py +27 -38
  148. pygpt_net/ui/layout/toolbox/agent_llama.py +42 -45
  149. pygpt_net/ui/layout/toolbox/assistants.py +42 -38
  150. pygpt_net/ui/layout/toolbox/computer_env.py +32 -23
  151. pygpt_net/ui/layout/toolbox/footer.py +13 -16
  152. pygpt_net/ui/layout/toolbox/image.py +18 -21
  153. pygpt_net/ui/layout/toolbox/indexes.py +46 -89
  154. pygpt_net/ui/layout/toolbox/mode.py +20 -7
  155. pygpt_net/ui/layout/toolbox/model.py +12 -10
  156. pygpt_net/ui/layout/toolbox/presets.py +68 -52
  157. pygpt_net/ui/layout/toolbox/prompt.py +31 -58
  158. pygpt_net/ui/layout/toolbox/toolbox.py +25 -21
  159. pygpt_net/ui/layout/toolbox/vision.py +20 -22
  160. pygpt_net/ui/main.py +2 -4
  161. pygpt_net/ui/menu/about.py +64 -84
  162. pygpt_net/ui/menu/audio.py +87 -63
  163. pygpt_net/ui/menu/config.py +121 -127
  164. pygpt_net/ui/menu/debug.py +69 -76
  165. pygpt_net/ui/menu/file.py +32 -35
  166. pygpt_net/ui/menu/menu.py +2 -3
  167. pygpt_net/ui/menu/plugins.py +69 -33
  168. pygpt_net/ui/menu/theme.py +45 -46
  169. pygpt_net/ui/menu/tools.py +56 -60
  170. pygpt_net/ui/menu/video.py +20 -25
  171. pygpt_net/ui/tray.py +1 -2
  172. pygpt_net/ui/widget/audio/bar.py +1 -3
  173. pygpt_net/ui/widget/audio/input_button.py +3 -4
  174. pygpt_net/ui/widget/calendar/select.py +1 -2
  175. pygpt_net/ui/widget/dialog/base.py +12 -9
  176. pygpt_net/ui/widget/dialog/editor_file.py +20 -23
  177. pygpt_net/ui/widget/dialog/find.py +25 -24
  178. pygpt_net/ui/widget/dialog/profile.py +57 -53
  179. pygpt_net/ui/widget/draw/painter.py +62 -93
  180. pygpt_net/ui/widget/element/button.py +42 -30
  181. pygpt_net/ui/widget/element/checkbox.py +23 -15
  182. pygpt_net/ui/widget/element/group.py +6 -5
  183. pygpt_net/ui/widget/element/labels.py +1 -2
  184. pygpt_net/ui/widget/filesystem/explorer.py +93 -102
  185. pygpt_net/ui/widget/image/display.py +1 -2
  186. pygpt_net/ui/widget/lists/assistant.py +1 -2
  187. pygpt_net/ui/widget/lists/attachment.py +1 -2
  188. pygpt_net/ui/widget/lists/attachment_ctx.py +1 -2
  189. pygpt_net/ui/widget/lists/context.py +2 -4
  190. pygpt_net/ui/widget/lists/index.py +1 -2
  191. pygpt_net/ui/widget/lists/model.py +1 -2
  192. pygpt_net/ui/widget/lists/model_editor.py +1 -2
  193. pygpt_net/ui/widget/lists/model_importer.py +1 -2
  194. pygpt_net/ui/widget/lists/preset.py +1 -2
  195. pygpt_net/ui/widget/lists/preset_plugins.py +1 -2
  196. pygpt_net/ui/widget/lists/profile.py +1 -2
  197. pygpt_net/ui/widget/lists/uploaded.py +1 -2
  198. pygpt_net/ui/widget/option/checkbox.py +2 -4
  199. pygpt_net/ui/widget/option/checkbox_list.py +1 -4
  200. pygpt_net/ui/widget/option/cmd.py +1 -4
  201. pygpt_net/ui/widget/option/dictionary.py +25 -28
  202. pygpt_net/ui/widget/option/input.py +1 -3
  203. pygpt_net/ui/widget/tabs/Input.py +16 -12
  204. pygpt_net/ui/widget/tabs/body.py +5 -3
  205. pygpt_net/ui/widget/tabs/layout.py +36 -25
  206. pygpt_net/ui/widget/tabs/output.py +96 -74
  207. pygpt_net/ui/widget/textarea/calendar_note.py +1 -2
  208. pygpt_net/ui/widget/textarea/editor.py +41 -73
  209. pygpt_net/ui/widget/textarea/find.py +11 -10
  210. pygpt_net/ui/widget/textarea/html.py +3 -6
  211. pygpt_net/ui/widget/textarea/input.py +63 -64
  212. pygpt_net/ui/widget/textarea/notepad.py +54 -38
  213. pygpt_net/ui/widget/textarea/output.py +65 -54
  214. pygpt_net/ui/widget/textarea/search_input.py +5 -4
  215. pygpt_net/ui/widget/textarea/web.py +2 -4
  216. pygpt_net/ui/widget/vision/camera.py +2 -31
  217. {pygpt_net-2.6.20.dist-info → pygpt_net-2.6.22.dist-info}/METADATA +25 -154
  218. {pygpt_net-2.6.20.dist-info → pygpt_net-2.6.22.dist-info}/RECORD +218 -217
  219. {pygpt_net-2.6.20.dist-info → pygpt_net-2.6.22.dist-info}/LICENSE +0 -0
  220. {pygpt_net-2.6.20.dist-info → pygpt_net-2.6.22.dist-info}/WHEEL +0 -0
  221. {pygpt_net-2.6.20.dist-info → pygpt_net-2.6.22.dist-info}/entry_points.txt +0 -0
@@ -6,23 +6,31 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2025.08.18 01:00:00 #
9
+ # Updated Date: 2025.08.23 15:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from typing import Any, Optional
13
13
 
14
14
  from pygpt_net.core.bridge import BridgeContext
15
15
  from pygpt_net.core.types import (
16
- MODE_AGENT,
17
16
  MODE_ASSISTANT,
18
17
  MODE_IMAGE,
19
18
  )
20
19
  from pygpt_net.core.events import Event, AppEvent, RenderEvent, KernelEvent
21
20
  from pygpt_net.item.ctx import CtxItem
22
- from pygpt_net.utils import mem_clean
23
21
 
24
22
 
25
23
  class Output:
24
+
25
+ STATE_PARAMS = {
26
+ "id": "chat",
27
+ }
28
+
29
+ NOT_STREAM_MODES = (
30
+ MODE_ASSISTANT,
31
+ MODE_IMAGE
32
+ )
33
+
26
34
  def __init__(self, window=None):
27
35
  """
28
36
  Output controller
@@ -30,16 +38,12 @@ class Output:
30
38
  :param window: Window instance
31
39
  """
32
40
  self.window = window
33
- self.not_stream_modes = [
34
- MODE_ASSISTANT,
35
- MODE_IMAGE,
36
- ]
37
41
 
38
42
  def handle(
39
43
  self,
40
44
  ctx: CtxItem,
41
45
  mode: str,
42
- stream_mode: bool = False,
46
+ stream: bool = False,
43
47
  is_response: bool = False,
44
48
  reply: bool = False,
45
49
  internal: bool = False,
@@ -51,20 +55,20 @@ class Output:
51
55
 
52
56
  :param ctx: CtxItem
53
57
  :param mode: mode (global)
54
- :param stream_mode: stream mode
58
+ :param stream: stream enabled (local)
55
59
  :param is_response: Is response output
56
60
  :param reply: is reply
57
61
  :param internal: is internal command
58
62
  :param context: BridgeContext (optional)
59
63
  :param extra: Extra data (optional)
60
64
  """
61
- self.window.stateChanged.emit(self.window.STATE_BUSY)
65
+ self.window.dispatch(KernelEvent(KernelEvent.STATE_BUSY)) # state: busy
62
66
 
63
- # if stream mode then append chunk by chunk
67
+ # if stream then append chunk by chunk
64
68
  end = True
65
- if stream_mode: # local stream enabled
66
- if mode not in self.not_stream_modes:
67
- end = False # don't end stream mode, append chunk by chunk
69
+ if stream: # local, not global config
70
+ if mode not in self.NOT_STREAM_MODES:
71
+ end = False # don't end if stream mode, append chunk by chunk
68
72
  self.window.controller.chat.stream.append(
69
73
  ctx=ctx,
70
74
  mode=mode,
@@ -79,7 +83,7 @@ class Output:
79
83
  self.handle_after(
80
84
  ctx=ctx,
81
85
  mode=mode,
82
- stream=stream_mode
86
+ stream=stream,
83
87
  )
84
88
 
85
89
  def handle_after(
@@ -93,59 +97,52 @@ class Output:
93
97
 
94
98
  :param ctx: CtxItem
95
99
  :param mode: mode (global)
96
- :param stream: stream mode
100
+ :param stream: stream enabled (local)
97
101
  """
102
+ core = self.window.core
103
+ dispatch = self.window.dispatch
104
+ log = self.window.controller.chat.log
105
+
98
106
  # check if tool calls detected
99
107
  if ctx.tool_calls:
100
108
  # if not internal commands in a text body then append tool calls as commands (prevent double commands)
101
- if not self.window.core.command.has_cmds(ctx.output):
102
- self.window.core.command.append_tool_calls(ctx) # append tool calls as commands
109
+ if not core.command.has_cmds(ctx.output):
110
+ core.command.append_tool_calls(ctx) # append tool calls as commands
103
111
  if not isinstance(ctx.extra, dict):
104
112
  ctx.extra = {}
105
113
  ctx.extra["tool_calls"] = ctx.tool_calls
106
114
  stream = False # disable stream mode, show tool calls at the end
107
- self.log("Tool call received...")
115
+ log("Tool call received...")
108
116
  else: # prevent execute twice
109
- self.log("Ignoring tool call because command received...")
110
-
111
- # agent mode
112
- if mode == MODE_AGENT:
113
- self.window.controller.agent.legacy.on_ctx_after(ctx)
117
+ log("Ignoring tool call because command received...")
114
118
 
115
119
  # event: context after
116
- event = Event(Event.CTX_AFTER)
117
- event.ctx = ctx
118
- self.window.dispatch(event)
120
+ dispatch(Event(Event.CTX_AFTER, {
121
+ 'mode': mode,
122
+ }, ctx=ctx))
119
123
 
120
- self.log("Appending output to chat window...")
124
+ log("Appending output to chat window...")
121
125
 
122
126
  # only append output if not in stream mode, TODO: plugin output add
123
- stream_enabled = self.window.core.config.get('stream', False)
127
+ stream_global = core.config.get('stream', False)
124
128
  if not stream:
125
- if stream_enabled: # use global stream settings here to persist previously added input
126
- data = {
129
+ if stream_global: # use global stream settings here to persist previously added input
130
+ dispatch(RenderEvent(RenderEvent.INPUT_APPEND, {
127
131
  "meta": ctx.meta,
128
132
  "ctx": ctx,
129
133
  "flush": True,
130
134
  "append": True,
131
- }
132
- event = RenderEvent(RenderEvent.INPUT_APPEND, data)
133
- self.window.dispatch(event)
135
+ }))
134
136
 
135
- data = {
137
+ dispatch(RenderEvent(RenderEvent.OUTPUT_APPEND, {
136
138
  "meta": ctx.meta,
137
139
  "ctx": ctx,
138
- }
139
- event = RenderEvent(RenderEvent.OUTPUT_APPEND, data)
140
- self.window.dispatch(event)
141
-
142
- data = {
140
+ }))
141
+ dispatch(RenderEvent(RenderEvent.EXTRA_APPEND, {
143
142
  "meta": ctx.meta,
144
143
  "ctx": ctx,
145
144
  "footer": True,
146
- }
147
- event = RenderEvent(RenderEvent.EXTRA_APPEND, data)
148
- self.window.dispatch(event) # + icons
145
+ })) # + icons
149
146
 
150
147
  self.handle_complete(ctx)
151
148
 
@@ -155,29 +152,22 @@ class Output:
155
152
 
156
153
  :param ctx: CtxItem
157
154
  """
158
- mode = self.window.core.config.get('mode')
159
- self.window.core.ctx.post_update(mode) # post update context, store last mode, etc.
160
- self.window.core.ctx.store()
161
- self.window.controller.ctx.update_ctx() # update current ctx info
162
-
163
- # update response tokens
164
- self.window.controller.chat.common.show_response_tokens(ctx)
155
+ core = self.window.core
156
+ controller = self.window.controller
157
+ dispatch = self.window.dispatch
158
+ mode = core.config.get('mode')
165
159
 
166
- # handle audio output
167
- self.window.controller.chat.audio.handle_output(ctx)
160
+ # post update context, store last mode, etc.
161
+ core.ctx.post_update(mode)
162
+ core.ctx.store()
168
163
 
169
- # store to history
170
- if self.window.core.config.get('store_history'):
171
- self.window.core.history.append(ctx, "output")
164
+ controller.ctx.update_ctx()
165
+ controller.ctx.store_history(ctx, "output") # store to history
172
166
 
173
- if self.window.controller.chat.common.can_unlock(ctx):
174
- if not self.window.controller.kernel.stopped():
175
- self.window.controller.chat.common.unlock_input() # unlock input
176
-
177
- # reset state to: idle
178
- self.window.dispatch(KernelEvent(KernelEvent.STATE_IDLE, {
179
- "id": "chat",
180
- }))
167
+ controller.chat.audio.handle_output(ctx) # handle audio output
168
+ controller.chat.common.auto_unlock(ctx) # unlock input if allowed
169
+ controller.chat.common.show_response_tokens(ctx) # update tokens
170
+ dispatch(KernelEvent(KernelEvent.STATE_IDLE, self.STATE_PARAMS)) # state: idle
181
171
 
182
172
  def post_handle(
183
173
  self,
@@ -196,46 +186,33 @@ class Output:
196
186
  :param reply: is reply
197
187
  :param internal: is internal
198
188
  """
189
+ core = self.window.core
190
+ controller = self.window.controller
191
+ dispatch = self.window.dispatch
192
+
199
193
  # if commands enabled: post-execute commands (not assistant mode)
200
194
  if mode != MODE_ASSISTANT:
201
195
  ctx.clear_reply() # reset results
202
-
203
- # extract expert mentions and handle experts reply
204
- num_calls = self.window.controller.agent.experts.handle(ctx)
205
- if num_calls == 0:
206
- # handle commands only if no expert calls in queue
207
- self.window.controller.chat.command.handle(ctx)
196
+ expert_calls = controller.agent.experts.handle(ctx)
197
+ if expert_calls == 0: # handle commands only if no expert calls in queue
198
+ controller.chat.command.handle(ctx)
208
199
 
209
200
  ctx.from_previous() # append previous result again before save
210
- self.window.core.ctx.update_item(ctx) # update ctx in DB
201
+ core.ctx.update_item(ctx) # update ctx in DB
211
202
 
212
203
  # render: end
213
204
  if ctx.sub_calls == 0: # if no experts called
214
- data = {
205
+ dispatch(RenderEvent(RenderEvent.END, {
215
206
  "meta": ctx.meta,
216
207
  "ctx": ctx,
217
208
  "stream": stream,
218
- }
219
- event = RenderEvent(RenderEvent.END, data)
220
- self.window.dispatch(event)
221
-
222
- # don't unlock input and leave stop btn if assistant mode or if agent/autonomous is enabled
223
- # send btn will be unlocked in agent mode on stop
224
- if self.window.controller.chat.common.can_unlock(ctx):
225
- if not self.window.controller.kernel.stopped():
226
- self.window.controller.chat.common.unlock_input() # unlock input
227
-
228
- # handle ctx name (generate title from summary if not initialized)
229
- if not ctx.meta or not ctx.meta.initialized: # don't call if reply or internal mode
230
- if self.window.core.config.get('ctx.auto_summary'):
231
- self.log("Calling for prepare context name...")
232
- self.window.controller.ctx.prepare_name(ctx) # async
209
+ }))
233
210
 
234
- if self.window.state != self.window.STATE_ERROR:
235
- if mode != MODE_ASSISTANT:
236
- self.window.dispatch(KernelEvent(KernelEvent.STATE_IDLE, {
237
- "id": "chat",
238
- }))
211
+ controller.chat.common.auto_unlock(ctx) # unlock input if allowed
212
+ controller.ctx.prepare_summary(ctx) # prepare ctx name
213
+
214
+ if self.window.state != self.window.STATE_ERROR and mode != MODE_ASSISTANT:
215
+ dispatch(KernelEvent(KernelEvent.STATE_IDLE, self.STATE_PARAMS)) # state: idle
239
216
 
240
217
  def handle_end(
241
218
  self,
@@ -248,60 +225,26 @@ class Output:
248
225
  :param ctx: CtxItem
249
226
  :param mode: mode
250
227
  """
251
- # clear attachments after send, only if attachments has been provided before send
252
- auto_clear = self.window.core.config.get('attachments_send_clear')
253
- if self.window.controller.attachment.clear_allowed(ctx):
254
- if auto_clear and not self.window.controller.attachment.is_locked():
255
- self.window.controller.attachment.clear(force=True, auto=True)
256
- self.window.controller.attachment.update()
257
- self.log("Attachments cleared.") # log
258
-
259
- if self.window.core.config.get("log.ctx"):
260
- self.log(f"Context: END: {ctx}")
261
- else:
262
- self.log("Context: END.")
263
-
264
- # agent mode
265
- if mode == MODE_AGENT:
266
- agent_iterations = int(self.window.core.config.get("agent.iterations"))
267
- self.log(f"Agent: ctx end, iterations: {agent_iterations}")
268
- self.window.controller.agent.legacy.on_ctx_end(
269
- ctx,
270
- iterations=agent_iterations,
271
- )
228
+ controller = self.window.controller
229
+ dispatch = self.window.dispatch
230
+ log = controller.chat.log
272
231
 
273
- # event: context end
274
- event = Event(Event.CTX_END)
275
- event.ctx = ctx
276
- self.window.dispatch(event)
277
- self.window.controller.ui.update_tokens() # update UI
278
- self.window.controller.chat.input.generating = False # unlock
232
+ controller.attachment.cleanup(ctx) # clear after send
233
+ log(f"Context: END: {ctx}" if self.window.core.config.get("log.ctx") else "Context: END.")
279
234
 
280
- if (mode not in self.window.controller.chat.input.no_ctx_idx_modes
281
- and not self.window.controller.agent.legacy.enabled()):
282
- self.window.controller.idx.on_ctx_end(ctx, mode=mode) # update ctx DB index
283
- # disabled in agent mode here to prevent loops, handled in agent flow internally if agent mode
235
+ # event: context end
236
+ dispatch(Event(Event.CTX_END, {
237
+ 'mode': mode,
238
+ }, ctx=ctx))
239
+ controller.chat.input.generating = False # unlock
284
240
 
285
- self.log("End.")
286
- self.window.dispatch(AppEvent(AppEvent.CTX_END)) # app event
241
+ log("End.")
242
+ dispatch(AppEvent(AppEvent.CTX_END)) # app event
287
243
 
288
244
  # restore state to idle if no errors
289
245
  if self.window.state != self.window.STATE_ERROR:
290
- self.window.stateChanged.emit(self.window.STATE_IDLE)
246
+ dispatch(KernelEvent(KernelEvent.STATE_IDLE, self.STATE_PARAMS))
291
247
 
292
248
  if mode != MODE_ASSISTANT:
293
- self.window.controller.kernel.stack.handle() # handle reply
294
- event = RenderEvent(RenderEvent.RELOAD)
295
- self.window.dispatch(event) # reload chat window
296
-
297
- mem_clean()
298
-
299
- # self.window.core.debug.mem("END") # debug memory usage
300
-
301
- def log(self, data: Any):
302
- """
303
- Log data to debug
304
-
305
- :param data: Data to log
306
- """
307
- self.window.controller.chat.log(data)
249
+ controller.kernel.stack.handle() # handle reply
250
+ dispatch(RenderEvent(RenderEvent.RELOAD)) # reload chat window