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
@@ -1,3 +1,15 @@
1
+ # -*- coding: utf-8 -*-
2
+ # ================================================== #
3
+ # This file is a part of PYGPT package #
4
+ # Website: https://pygpt.net #
5
+ # GitHub: https://github.com/szczyglis-dev/py-gpt #
6
+ # MIT License #
7
+ # Created By : Marcin Szczygliński #
8
+ # Updated Date: 2025.08.14 01:00:00 #
9
+ # ================================================== #
10
+
11
+ # >>> Based on LlamaIndex CodeActAgent implementation, with custom plugin tool support <<<
12
+
1
13
  import asyncio
2
14
  import inspect
3
15
  import json
@@ -23,6 +35,9 @@ from llama_index.core.objects import ObjectRetriever
23
35
  from llama_index.core.prompts import BasePromptTemplate, PromptTemplate
24
36
  from llama_index.core.tools import BaseTool, FunctionTool
25
37
  from llama_index.core.workflow import Context
38
+ from workflows.errors import WorkflowCancelledByUser
39
+
40
+ from pygpt_net.provider.agents.llama_index.workflow.events import StepEvent
26
41
 
27
42
  DEFAULT_CODE_ACT_PROMPT = """You are a helpful AI assistant that can write and execute Python code to solve problems.
28
43
  In addition to executing code using the <execute> tags, you have access to a unified plugin tool via the function tool(cmd, **params).
@@ -107,6 +122,7 @@ class CodeActAgent(BaseWorkflowAgent):
107
122
  _plugin_tools: Dict[str, Callable] = PrivateAttr(default_factory=dict)
108
123
  _plugin_specs: Optional[List] = PrivateAttr(default_factory=list)
109
124
  _plugin_tool_fn: Union[Callable, Awaitable] = PrivateAttr(default=None)
125
+ _on_stop: Optional[Callable] = PrivateAttr(default=None)
110
126
 
111
127
  def __init__(
112
128
  self,
@@ -122,6 +138,7 @@ class CodeActAgent(BaseWorkflowAgent):
122
138
  can_handoff_to: Optional[List[str]] = None,
123
139
  llm: Optional[LLM] = None,
124
140
  code_act_system_prompt: Union[str, BasePromptTemplate] = DEFAULT_CODE_ACT_PROMPT,
141
+ on_stop: Optional[Callable] = None,
125
142
  ):
126
143
  tools = tools or []
127
144
  tools.append(FunctionTool.from_defaults(plugin_tool_fn, name=PLUGIN_TOOL_NAME))
@@ -130,6 +147,7 @@ class CodeActAgent(BaseWorkflowAgent):
130
147
  object.__setattr__(self, "_plugin_tools", plugin_tools or {})
131
148
  object.__setattr__(self, "_plugin_tool_fn", plugin_tool_fn)
132
149
  object.__setattr__(self, "_plugin_specs", plugin_specs or [])
150
+ object.__setattr__(self, "_on_stop", on_stop)
133
151
 
134
152
  if self._plugin_tools and self._plugin_specs:
135
153
  available_commands = "\n".join(self._plugin_specs)
@@ -175,9 +193,26 @@ class CodeActAgent(BaseWorkflowAgent):
175
193
  code_execute_fn=code_execute_fn,
176
194
  )
177
195
 
196
+ def _stopped(self) -> bool:
197
+ """
198
+ Check if the workflow has been stopped.
199
+
200
+ :return: True if the workflow is stopped, False otherwise.
201
+ """
202
+ if self._on_stop:
203
+ try:
204
+ return self._on_stop()
205
+ except Exception:
206
+ return False
207
+ return False
208
+
178
209
  def _get_tool_fns(self, tools: Sequence[BaseTool]) -> List[Callable]:
179
210
  """
180
211
  Get the tool functions while validating that they are valid for CodeActAgent.
212
+
213
+ :param tools: A sequence of BaseTool instances.
214
+ :return: A list of callable functions from the tools.
215
+ :raises ValueError: If a tool requires context or is not a FunctionTool.
181
216
  """
182
217
  callables = []
183
218
  for tool in tools:
@@ -200,6 +235,14 @@ class CodeActAgent(BaseWorkflowAgent):
200
235
  def _extract_code_from_response(self, response_text: str) -> Optional[str]:
201
236
  """
202
237
  Extract code from the LLM response using XML-style <execute> tags.
238
+
239
+ Expected format:
240
+ <execute>
241
+ print('Hello, World!')
242
+ </execute>
243
+
244
+ :param response_text: The text response from the LLM.
245
+ :return: The extracted code as a string, or None if no code is found.
203
246
  """
204
247
  execute_pattern = r"<execute>(.*?)</execute>"
205
248
  execute_matches = re.findall(execute_pattern, response_text, re.DOTALL)
@@ -210,10 +253,14 @@ class CodeActAgent(BaseWorkflowAgent):
210
253
  def _extract_plugin_tool_calls(self, response_text: str) -> List[Dict]:
211
254
  """
212
255
  Extract plugin tool calls from the LLM response.
256
+
213
257
  Expected format (JSON inside XML-style <tool> tags):
214
258
  <tool>
215
259
  { "cmd": "tool_name", "params": {"arg": "value"} }
216
260
  </tool>
261
+
262
+ :param response_text: The text response from the LLM.
263
+ :return: A list of dictionaries representing the plugin tool calls.
217
264
  """
218
265
  pattern = r"<tool>(.*?)</tool>"
219
266
  matches = re.findall(pattern, response_text, re.DOTALL)
@@ -227,9 +274,48 @@ class CodeActAgent(BaseWorkflowAgent):
227
274
  continue
228
275
  return plugin_calls
229
276
 
277
+ def _emit_step_event(
278
+ self,
279
+ ctx: Context,
280
+ name: str,
281
+ index: Optional[int] = None,
282
+ total: Optional[int] = None,
283
+ meta: Optional[dict] = None,
284
+ ) -> None:
285
+ """
286
+ Emits a step event to the context stream.
287
+
288
+ :param ctx: The context to write the event to.
289
+ :param name: The name of the step (e.g., "make_plan", "execute_plan", "subtask").
290
+ :param index: The index of the step (optional).
291
+ :param total: The total number of steps (optional).
292
+ :param meta: Additional metadata for the step (optional).
293
+ """
294
+ try:
295
+ ctx.write_event_to_stream(
296
+ StepEvent(name=name, index=index, total=total, meta=meta or {})
297
+ )
298
+ except Exception:
299
+ # Fallback for older versions of AgentStream
300
+ try:
301
+ ctx.write_event_to_stream(
302
+ AgentStream(
303
+ delta="",
304
+ response="",
305
+ current_agent_name="PlannerWorkflow",
306
+ tool_calls=[],
307
+ raw={"StepEvent": {"name": name, "index": index, "total": total, "meta": meta or {}}}
308
+ )
309
+ )
310
+ except Exception:
311
+ pass
312
+
230
313
  def _get_tool_descriptions(self, tools: Sequence[BaseTool]) -> str:
231
314
  """
232
315
  Generate tool descriptions for the system prompt using tool metadata.
316
+
317
+ :param tools: A sequence of BaseTool instances.
318
+ :return: A string containing the formatted tool descriptions.
233
319
  """
234
320
  tool_descriptions = []
235
321
  tool_fns = self._get_tool_fns(tools)
@@ -253,11 +339,20 @@ class CodeActAgent(BaseWorkflowAgent):
253
339
  ) -> AgentOutput:
254
340
  """
255
341
  Takes a step in the agent's workflow, executing code and calling tools as needed.
342
+
343
+ :param ctx: The context for the agent's execution.
344
+ :param llm_input: The input messages for the LLM.
345
+ :param tools: The tools available for the agent to use.
346
+ :param memory: The memory object to store and retrieve messages.
347
+ :return: An AgentOutput object containing the response and any tool calls made.
348
+ :raises ValueError: If code_execute_fn is not provided or if an unknown tool name is encountered.
256
349
  """
257
350
  if not self.code_execute_fn:
258
351
  raise ValueError("code_execute_fn must be provided for CodeActAgent")
259
352
 
260
- scratchpad: List[ChatMessage] = await ctx.get(self.scratchpad_key, default=[])
353
+ # self._emit_step_event(ctx, name="step", meta={"query": str(llm_input)})
354
+
355
+ scratchpad: List[ChatMessage] = await ctx.store.get(self.scratchpad_key, default=[])
261
356
  current_llm_input = [*llm_input, *scratchpad]
262
357
  tool_descriptions = self._get_tool_descriptions(tools)
263
358
  system_prompt = self.code_act_system_prompt.format(tool_descriptions=tool_descriptions)
@@ -287,6 +382,11 @@ class CodeActAgent(BaseWorkflowAgent):
287
382
  full_response_text = ""
288
383
 
289
384
  async for last_chat_response in response:
385
+
386
+ # stop callback
387
+ if self._stopped():
388
+ raise WorkflowCancelledByUser("Workflow was stopped by user.")
389
+
290
390
  delta = last_chat_response.delta or ""
291
391
  full_response_text += delta
292
392
  raw = (
@@ -331,7 +431,7 @@ class CodeActAgent(BaseWorkflowAgent):
331
431
 
332
432
  message = ChatMessage(role="assistant", content=full_response_text)
333
433
  scratchpad.append(message)
334
- await ctx.set(self.scratchpad_key, scratchpad)
434
+ await ctx.store.set(self.scratchpad_key, scratchpad)
335
435
 
336
436
  raw = (
337
437
  last_chat_response.raw.model_dump()
@@ -347,12 +447,20 @@ class CodeActAgent(BaseWorkflowAgent):
347
447
  )
348
448
 
349
449
  async def handle_tool_call_results(
350
- self, ctx: Context, results: List[ToolCallResult], memory: BaseMemory
450
+ self,
451
+ ctx: Context,
452
+ results: List[ToolCallResult],
453
+ memory: BaseMemory
351
454
  ) -> None:
352
455
  """
353
456
  Handles the results of tool calls made by the agent.
457
+
458
+ :param ctx: The context for the agent's execution.
459
+ :param results: The results of the tool calls made.
460
+ :param memory: The memory object to store and retrieve messages.
461
+ :raises ValueError: If an unknown tool name is encountered.
354
462
  """
355
- scratchpad: List[ChatMessage] = await ctx.get(self.scratchpad_key, default=[])
463
+ scratchpad: List[ChatMessage] = await ctx.store.get(self.scratchpad_key, default=[])
356
464
 
357
465
  for tool_call_result in results:
358
466
  if tool_call_result.tool_name == EXECUTE_TOOL_NAME:
@@ -376,15 +484,23 @@ class CodeActAgent(BaseWorkflowAgent):
376
484
  else:
377
485
  raise ValueError(f"Unknown tool name: {tool_call_result.tool_name}")
378
486
 
379
- await ctx.set(self.scratchpad_key, scratchpad)
487
+ await ctx.store.set(self.scratchpad_key, scratchpad)
380
488
 
381
489
  async def finalize(
382
- self, ctx: Context, output: AgentOutput, memory: BaseMemory
490
+ self,
491
+ ctx: Context,
492
+ output: AgentOutput,
493
+ memory: BaseMemory
383
494
  ) -> AgentOutput:
384
495
  """
385
496
  Finalizes the agent's workflow, clearing the scratchpad and returning the output.
497
+
498
+ :param ctx: The context for the agent's execution.
499
+ :param output: The output from the agent's workflow.
500
+ :param memory: The memory object to store and retrieve messages.
501
+ :return: The final output of the agent's workflow.
386
502
  """
387
- scratchpad: List[ChatMessage] = await ctx.get(self.scratchpad_key, default=[])
503
+ scratchpad: List[ChatMessage] = await ctx.store.get(self.scratchpad_key, default=[])
388
504
  await memory.aput_messages(scratchpad)
389
- await ctx.set(self.scratchpad_key, [])
505
+ await ctx.store.set(self.scratchpad_key, [])
390
506
  return output
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # ================================================== #
4
+ # This file is a part of PYGPT package #
5
+ # Website: https://pygpt.net #
6
+ # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
+ # MIT License #
8
+ # Created By : Marcin Szczygliński #
9
+ # Updated Date: 2025.08.14 01:00:00 #
10
+ # ================================================== #
11
+
12
+ from typing import Optional, Dict, Any
13
+ from pydantic import Field
14
+
15
+ from llama_index.core.workflow import (
16
+ Event,
17
+ )
18
+
19
+ class StepEvent(Event):
20
+ """Represents an event that occurs during a step in the workflow."""
21
+ name: str # eg. "make_plan", "execute_plan", "subtask"
22
+ index: Optional[int] = None
23
+ total: Optional[int] = None
24
+ meta: Dict[str, Any] = Field(default_factory=dict)