pygpt-net 2.6.0.post2__py3-none-any.whl → 2.6.2__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 (98) hide show
  1. pygpt_net/CHANGELOG.txt +8 -0
  2. pygpt_net/__init__.py +3 -3
  3. pygpt_net/app.py +27 -9
  4. pygpt_net/controller/chat/response.py +10 -4
  5. pygpt_net/controller/chat/stream.py +40 -2
  6. pygpt_net/controller/model/editor.py +45 -4
  7. pygpt_net/controller/plugins/plugins.py +25 -0
  8. pygpt_net/controller/presets/editor.py +100 -100
  9. pygpt_net/controller/presets/experts.py +20 -1
  10. pygpt_net/controller/presets/presets.py +5 -4
  11. pygpt_net/controller/ui/mode.py +17 -66
  12. pygpt_net/core/agents/provider.py +2 -1
  13. pygpt_net/core/agents/runner.py +123 -9
  14. pygpt_net/core/agents/runners/helpers.py +3 -2
  15. pygpt_net/core/agents/runners/llama_workflow.py +176 -22
  16. pygpt_net/core/agents/runners/loop.py +22 -13
  17. pygpt_net/core/experts/experts.py +19 -25
  18. pygpt_net/core/idx/chat.py +24 -34
  19. pygpt_net/core/idx/response.py +5 -2
  20. pygpt_net/core/locale/locale.py +73 -45
  21. pygpt_net/core/render/web/body.py +152 -207
  22. pygpt_net/core/render/web/renderer.py +4 -2
  23. pygpt_net/data/config/config.json +3 -3
  24. pygpt_net/data/config/models.json +3 -3
  25. pygpt_net/data/locale/locale.de.ini +12 -8
  26. pygpt_net/data/locale/locale.en.ini +12 -8
  27. pygpt_net/data/locale/locale.es.ini +12 -8
  28. pygpt_net/data/locale/locale.fr.ini +12 -8
  29. pygpt_net/data/locale/locale.it.ini +12 -8
  30. pygpt_net/data/locale/locale.pl.ini +12 -8
  31. pygpt_net/data/locale/locale.uk.ini +12 -8
  32. pygpt_net/data/locale/locale.zh.ini +12 -8
  33. pygpt_net/item/ctx.py +2 -1
  34. pygpt_net/plugin/base/plugin.py +35 -3
  35. pygpt_net/plugin/bitbucket/__init__.py +12 -0
  36. pygpt_net/plugin/bitbucket/config.py +267 -0
  37. pygpt_net/plugin/bitbucket/plugin.py +125 -0
  38. pygpt_net/plugin/bitbucket/worker.py +569 -0
  39. pygpt_net/plugin/cmd_files/worker.py +19 -16
  40. pygpt_net/plugin/facebook/__init__.py +12 -0
  41. pygpt_net/plugin/facebook/config.py +359 -0
  42. pygpt_net/plugin/facebook/plugin.py +114 -0
  43. pygpt_net/plugin/facebook/worker.py +698 -0
  44. pygpt_net/plugin/github/__init__.py +12 -0
  45. pygpt_net/plugin/github/config.py +441 -0
  46. pygpt_net/plugin/github/plugin.py +124 -0
  47. pygpt_net/plugin/github/worker.py +674 -0
  48. pygpt_net/plugin/google/__init__.py +12 -0
  49. pygpt_net/plugin/google/config.py +367 -0
  50. pygpt_net/plugin/google/plugin.py +126 -0
  51. pygpt_net/plugin/google/worker.py +826 -0
  52. pygpt_net/plugin/slack/__init__.py +12 -0
  53. pygpt_net/plugin/slack/config.py +349 -0
  54. pygpt_net/plugin/slack/plugin.py +116 -0
  55. pygpt_net/plugin/slack/worker.py +639 -0
  56. pygpt_net/plugin/telegram/__init__.py +12 -0
  57. pygpt_net/plugin/telegram/config.py +308 -0
  58. pygpt_net/plugin/telegram/plugin.py +118 -0
  59. pygpt_net/plugin/telegram/worker.py +563 -0
  60. pygpt_net/plugin/twitter/__init__.py +12 -0
  61. pygpt_net/plugin/twitter/config.py +491 -0
  62. pygpt_net/plugin/twitter/plugin.py +126 -0
  63. pygpt_net/plugin/twitter/worker.py +837 -0
  64. pygpt_net/provider/agents/base.py +4 -1
  65. pygpt_net/provider/agents/llama_index/codeact_workflow.py +95 -0
  66. pygpt_net/provider/agents/llama_index/legacy/__init__.py +0 -0
  67. pygpt_net/provider/agents/llama_index/{openai.py → legacy/openai.py} +2 -2
  68. pygpt_net/provider/agents/llama_index/{openai_assistant.py → legacy/openai_assistant.py} +37 -5
  69. pygpt_net/provider/agents/llama_index/{planner.py → legacy/planner.py} +3 -3
  70. pygpt_net/provider/agents/llama_index/{react.py → legacy/react.py} +3 -3
  71. pygpt_net/provider/agents/llama_index/openai_workflow.py +52 -0
  72. pygpt_net/provider/agents/llama_index/planner_workflow.py +115 -0
  73. pygpt_net/provider/agents/llama_index/react_workflow.py +6 -4
  74. pygpt_net/provider/agents/llama_index/workflow/__init__.py +0 -0
  75. pygpt_net/provider/agents/llama_index/{codeact_agent_custom.py → workflow/codeact.py} +124 -8
  76. pygpt_net/provider/agents/llama_index/workflow/events.py +24 -0
  77. pygpt_net/provider/agents/llama_index/workflow/openai.py +634 -0
  78. pygpt_net/provider/agents/llama_index/workflow/planner.py +601 -0
  79. pygpt_net/provider/agents/openai/agent.py +1 -0
  80. pygpt_net/provider/agents/openai/agent_b2b.py +2 -0
  81. pygpt_net/provider/agents/openai/agent_planner.py +1 -0
  82. pygpt_net/provider/agents/openai/agent_with_experts.py +1 -0
  83. pygpt_net/provider/agents/openai/agent_with_experts_feedback.py +1 -0
  84. pygpt_net/provider/agents/openai/agent_with_feedback.py +1 -0
  85. pygpt_net/provider/agents/openai/evolve.py +1 -0
  86. pygpt_net/provider/core/preset/patch.py +11 -17
  87. pygpt_net/ui/base/config_dialog.py +4 -0
  88. pygpt_net/ui/dialog/preset.py +34 -77
  89. pygpt_net/ui/layout/toolbox/presets.py +2 -2
  90. pygpt_net/ui/main.py +3 -1
  91. pygpt_net/ui/widget/lists/experts.py +3 -2
  92. {pygpt_net-2.6.0.post2.dist-info → pygpt_net-2.6.2.dist-info}/METADATA +155 -4
  93. {pygpt_net-2.6.0.post2.dist-info → pygpt_net-2.6.2.dist-info}/RECORD +96 -62
  94. pygpt_net/data/config/presets/agent_react_workflow.json +0 -34
  95. pygpt_net/provider/agents/llama_index/code_act.py +0 -58
  96. {pygpt_net-2.6.0.post2.dist-info → pygpt_net-2.6.2.dist-info}/LICENSE +0 -0
  97. {pygpt_net-2.6.0.post2.dist-info → pygpt_net-2.6.2.dist-info}/WHEEL +0 -0
  98. {pygpt_net-2.6.0.post2.dist-info → pygpt_net-2.6.2.dist-info}/entry_points.txt +0 -0
@@ -6,9 +6,9 @@
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.03 14:00:00 #
9
+ # Updated Date: 2025.08.14 01:00:00 #
10
10
  # ================================================== #
11
- import asyncio
11
+
12
12
  import json
13
13
  from typing import Optional, Dict, Any, List
14
14
 
@@ -338,7 +338,7 @@ class Chat:
338
338
  tools=tools,
339
339
  ctx=ctx,
340
340
  query=query,
341
- history=history,
341
+ history=context.history,
342
342
  llm=llm,
343
343
  index=index,
344
344
  system_prompt=system_prompt,
@@ -377,7 +377,7 @@ class Chat:
377
377
  tools=tools,
378
378
  ctx=ctx,
379
379
  query=query,
380
- history=history,
380
+ history=context.history,
381
381
  llm=llm,
382
382
  index=index,
383
383
  system_prompt=system_prompt,
@@ -490,7 +490,7 @@ class Chat:
490
490
  chat_mode: str = MODE_CHAT,
491
491
  verbose: bool = False,
492
492
 
493
- ) -> bool:
493
+ ) -> str:
494
494
  """
495
495
  Call agent with tools and index
496
496
 
@@ -507,7 +507,6 @@ class Chat:
507
507
  :param verbose: Verbose mode, default is False
508
508
  :return: True if success, False otherwise
509
509
  """
510
- index_tool = None
511
510
  if index:
512
511
  query_engine = index.as_query_engine(
513
512
  llm=llm,
@@ -522,35 +521,26 @@ class Chat:
522
521
  )
523
522
  tools.append(index_tool)
524
523
 
525
- workdir = self.window.core.config.get_user_dir('data')
526
- if self.window.core.plugins.get_option("cmd_code_interpreter", "sandbox_ipython"):
527
- workdir = "/data"
528
-
529
- kwargs = {
530
- "context": context,
531
- "tools": tools,
532
- "retriever_tool": index_tool,
533
- "llm": llm,
534
- "chat_history": history,
535
- "max_iterations": 0,
536
- "verbose": verbose,
537
- "system_prompt": system_prompt,
538
- "are_commands": True,
539
- "workdir": workdir,
540
- }
541
- provider = self.window.core.agents.provider.get("react_workflow")
542
- agent = provider.get_agent(self.window, kwargs)
543
-
544
- kwargs = {
545
- "agent": agent,
546
- "ctx": ctx,
547
- "prompt": query,
548
- "signals": signals,
549
- "verbose": verbose,
550
- "history": history,
551
- "llm": llm,
524
+ bridge_context = BridgeContext(
525
+ ctx=ctx,
526
+ model=context.model,
527
+ history=history,
528
+ prompt=query,
529
+ stream=False,
530
+ )
531
+ extra = {
532
+ "agent_provider": "react", # use React workflow provider
533
+ "agent_tools": tools,
552
534
  }
553
- return asyncio.run(self.window.core.agents.runner.llama_workflow.run(**kwargs))
535
+ response_ctx = self.window.core.agents.runner.call_once(
536
+ context=bridge_context,
537
+ extra=extra,
538
+ signals=None,
539
+ )
540
+ if response_ctx:
541
+ return str(response_ctx.output)
542
+ else:
543
+ return "No response from agent."
554
544
 
555
545
  def is_stream_allowed(self) -> bool:
556
546
  """
@@ -6,7 +6,7 @@
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.07.22 22:00:00 #
9
+ # Updated Date: 2025.08.14 01:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from typing import Any
@@ -28,7 +28,10 @@ class Response:
28
28
  model: ModelItem,
29
29
  response: Any
30
30
  ) -> None:
31
- pass
31
+ output = str(response)
32
+ if output is None:
33
+ output = ""
34
+ ctx.set_output(output, "")
32
35
 
33
36
  def from_index(
34
37
  self,
@@ -6,13 +6,12 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2024.12.14 00:00:00 #
9
+ # Updated Date: 2025.08.13 16:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
13
13
  import configparser
14
- import io
15
- from typing import Optional
14
+ from typing import Optional, Dict, Tuple
16
15
 
17
16
  from pygpt_net.config import Config
18
17
 
@@ -29,20 +28,27 @@ class Locale:
29
28
  :param domain: translation domain
30
29
  :param config: Config instance
31
30
  """
32
- if config is None:
33
- self.config = Config()
34
- else:
35
- self.config = config
31
+ self.config = config if config is not None else Config()
36
32
  self.lang = 'en' # default language = en
37
33
  self.fallback = 'en' # fallback language = en
38
34
  self.default_domain = 'locale' # default translation domain
39
35
  self.ini_key = 'LOCALE' # ini key for translations
40
- self.data = {}
41
- self.config.init(False) # load config
36
+ self.data: Dict[str, Dict[str, str]] = {}
37
+
38
+ # cache: path -> (mtime, parsed_dict)
39
+ self._file_cache: Dict[str, Tuple[float, Dict[str, str]]] = {}
40
+
41
+ # load config once
42
+ self.config.init(False)
42
43
  if self.config.has('lang'):
43
44
  self.lang = self.config.get_lang()
45
+
44
46
  self.load(self.lang, domain)
45
47
 
48
+ def _clear_cache(self):
49
+ """Clear internal file cache."""
50
+ self._file_cache.clear()
51
+
46
52
  def reload_config(self):
47
53
  """Reload configuration"""
48
54
  workdir = self.config.prepare_workdir()
@@ -50,6 +56,7 @@ class Locale:
50
56
  self.config.load(False)
51
57
  if self.config.has('lang'):
52
58
  self.lang = self.config.get_lang()
59
+ self._clear_cache() # ensure fresh read
53
60
  self.load(self.lang)
54
61
 
55
62
  def reload(self, domain: Optional[str] = None):
@@ -61,19 +68,32 @@ class Locale:
61
68
  self.config.load(False)
62
69
  if self.config.has('lang'):
63
70
  self.lang = self.config.get_lang()
71
+ self._clear_cache() # ensure fresh read
64
72
  self.load(self.lang, domain)
65
73
 
66
74
  def from_file(self, path: str) -> dict:
67
75
  """
68
- Load and parse translations from file
76
+ Load and parse translations from file (cached by mtime)
69
77
 
70
78
  :param path: path to ini file
71
79
  :return: dict with translations
72
80
  """
73
- ini = configparser.ConfigParser()
74
- data = io.open(path, mode="r", encoding="utf-8")
75
- ini.read_string(data.read())
76
- return dict(ini.items(self.ini_key))
81
+ try:
82
+ mtime = os.path.getmtime(path)
83
+ except FileNotFoundError:
84
+ return {}
85
+
86
+ cached = self._file_cache.get(path)
87
+ if cached is not None and cached[0] == mtime:
88
+ return cached[1]
89
+
90
+ # RawConfigParser with interpolation disabled
91
+ ini = configparser.RawConfigParser(interpolation=None)
92
+ ini.read(path, encoding='utf-8')
93
+
94
+ data = dict(ini.items(self.ini_key))
95
+ self._file_cache[path] = (mtime, data)
96
+ return data
77
97
 
78
98
  def load_by_lang(
79
99
  self,
@@ -86,22 +106,17 @@ class Locale:
86
106
  :param lang: language code
87
107
  :param domain: translation domain
88
108
  """
89
- id = self.default_domain
90
- if domain is not None:
91
- id = domain
92
- if id not in self.data:
93
- self.data[id] = {}
109
+ domain_id = domain or self.default_domain
110
+ mapping = self.data.setdefault(domain_id, {})
111
+
94
112
  try:
95
- path = self.get_base_path(id, lang)
96
- if os.path.exists(path):
97
- data = self.from_file(path)
98
- for key in data:
99
- self.data[id][key] = data[key]
100
- path = self.get_user_path(id, lang)
101
- if os.path.exists(path):
102
- data = self.from_file(path)
103
- for key in data:
104
- self.data[id][key] = data[key]
113
+ base_path = self.get_base_path(domain_id, lang)
114
+ if os.path.isfile(base_path):
115
+ mapping.update(self.from_file(base_path))
116
+
117
+ user_path = self.get_user_path(domain_id, lang)
118
+ if os.path.isfile(user_path):
119
+ mapping.update(self.from_file(user_path))
105
120
  except Exception as e:
106
121
  print(e)
107
122
 
@@ -116,10 +131,11 @@ class Locale:
116
131
  :param lang: language code
117
132
  :param domain: translation domain
118
133
  """
119
- if type(lang) is not str:
134
+ if not isinstance(lang, str) or not lang:
120
135
  lang = self.fallback
136
+
121
137
  if lang != self.fallback:
122
- self.load_by_lang(self.fallback, domain) # load fallback first
138
+ self.load_by_lang(self.fallback, domain)
123
139
  self.load_by_lang(lang, domain)
124
140
 
125
141
  def get(
@@ -136,20 +152,24 @@ class Locale:
136
152
  :param params: translation params dict for replacement
137
153
  :return: translated string or key if not found
138
154
  """
139
- id = self.default_domain
140
- if domain is not None:
141
- id = domain
142
- if id not in self.data:
155
+ domain_id = domain or self.default_domain
156
+ mapping = self.data.get(domain_id)
157
+
158
+ if mapping is None:
143
159
  self.load(self.lang, domain)
144
- if id in self.data and key in self.data[id]:
145
- if type(params) is dict and len(params) > 0:
146
- try:
147
- return self.data[id][key].replace('\\n', "\n").format(**params)
148
- except KeyError:
149
- pass
150
- return self.data[id][key].replace('\\n', "\n")
151
- else:
160
+ mapping = self.data.get(domain_id, {})
161
+
162
+ val = mapping.get(key)
163
+ if val is None:
152
164
  return key
165
+ text = val.replace('\\n', '\n')
166
+
167
+ if isinstance(params, dict) and params:
168
+ try:
169
+ return text.format(**params)
170
+ except KeyError:
171
+ pass
172
+ return text
153
173
 
154
174
  def get_base_path(
155
175
  self,
@@ -163,7 +183,11 @@ class Locale:
163
183
  :param lang: language code
164
184
  :return: path to translations file
165
185
  """
166
- return os.path.join(self.config.get_app_path(), 'data', 'locale', domain + '.' + lang + '.ini')
186
+ return os.path.join(
187
+ self.config.get_app_path(),
188
+ 'data', 'locale',
189
+ f'{domain}.{lang}.ini'
190
+ )
167
191
 
168
192
  def get_user_path(
169
193
  self,
@@ -177,4 +201,8 @@ class Locale:
177
201
  :param lang: language code
178
202
  :return: path to translations file
179
203
  """
180
- return os.path.join(self.config.get_user_path(), 'locale', domain + '.' + lang + '.ini')
204
+ return os.path.join(
205
+ self.config.get_user_path(),
206
+ 'locale',
207
+ f'{domain}.{lang}.ini'
208
+ )