pygpt-net 2.6.8__py3-none-any.whl → 2.6.10__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pygpt_net/CHANGELOG.txt +12 -0
- pygpt_net/__init__.py +3 -3
- pygpt_net/app.py +4 -0
- pygpt_net/controller/ctx/common.py +9 -3
- pygpt_net/controller/ctx/ctx.py +19 -17
- pygpt_net/controller/kernel/kernel.py +1 -2
- pygpt_net/core/agents/runner.py +19 -0
- pygpt_net/core/agents/tools.py +93 -52
- pygpt_net/core/render/web/body.py +11 -33
- pygpt_net/core/render/web/renderer.py +52 -79
- pygpt_net/data/config/config.json +4 -3
- pygpt_net/data/config/models.json +3 -3
- pygpt_net/data/config/presets/agent_openai_supervisor.json +54 -0
- pygpt_net/data/config/presets/agent_supervisor.json +52 -0
- pygpt_net/data/config/settings.json +14 -0
- pygpt_net/data/locale/locale.de.ini +2 -0
- pygpt_net/data/locale/locale.en.ini +2 -0
- pygpt_net/data/locale/locale.es.ini +2 -0
- pygpt_net/data/locale/locale.fr.ini +2 -0
- pygpt_net/data/locale/locale.it.ini +2 -0
- pygpt_net/data/locale/locale.pl.ini +3 -1
- pygpt_net/data/locale/locale.uk.ini +2 -0
- pygpt_net/data/locale/locale.zh.ini +2 -0
- pygpt_net/plugin/google/config.py +306 -1
- pygpt_net/plugin/google/plugin.py +22 -0
- pygpt_net/plugin/google/worker.py +579 -3
- pygpt_net/provider/agents/llama_index/supervisor_workflow.py +116 -0
- pygpt_net/provider/agents/llama_index/workflow/supervisor.py +303 -0
- pygpt_net/provider/agents/openai/supervisor.py +361 -0
- pygpt_net/provider/core/config/patch.py +11 -0
- pygpt_net/provider/core/preset/patch.py +18 -0
- pygpt_net/ui/main.py +1 -1
- pygpt_net/ui/widget/lists/context.py +10 -1
- pygpt_net/ui/widget/textarea/web.py +47 -4
- {pygpt_net-2.6.8.dist-info → pygpt_net-2.6.10.dist-info}/METADATA +93 -29
- {pygpt_net-2.6.8.dist-info → pygpt_net-2.6.10.dist-info}/RECORD +39 -34
- {pygpt_net-2.6.8.dist-info → pygpt_net-2.6.10.dist-info}/LICENSE +0 -0
- {pygpt_net-2.6.8.dist-info → pygpt_net-2.6.10.dist-info}/WHEEL +0 -0
- {pygpt_net-2.6.8.dist-info → pygpt_net-2.6.10.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,116 @@
|
|
|
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.17 02:00:00 #
|
|
10
|
+
# ================================================== #
|
|
11
|
+
|
|
12
|
+
from typing import Dict, Any, List
|
|
13
|
+
|
|
14
|
+
from pygpt_net.core.bridge import BridgeContext
|
|
15
|
+
from pygpt_net.core.types import (
|
|
16
|
+
AGENT_TYPE_LLAMA,
|
|
17
|
+
AGENT_MODE_WORKFLOW,
|
|
18
|
+
)
|
|
19
|
+
from llama_index.core.llms.llm import LLM
|
|
20
|
+
from llama_index.core.tools.types import BaseTool
|
|
21
|
+
|
|
22
|
+
from .workflow.supervisor import (
|
|
23
|
+
get_workflow,
|
|
24
|
+
SUPERVISOR_PROMPT,
|
|
25
|
+
WORKER_PROMPT,
|
|
26
|
+
)
|
|
27
|
+
from ..base import BaseAgent
|
|
28
|
+
|
|
29
|
+
class SupervisorAgent(BaseAgent):
|
|
30
|
+
def __init__(self, *args, **kwargs):
|
|
31
|
+
super(SupervisorAgent, self).__init__(*args, **kwargs)
|
|
32
|
+
self.id = "supervisor"
|
|
33
|
+
self.type = AGENT_TYPE_LLAMA
|
|
34
|
+
self.mode = AGENT_MODE_WORKFLOW
|
|
35
|
+
self.name = "Supervisor + worker"
|
|
36
|
+
|
|
37
|
+
def get_agent(self, window, kwargs: Dict[str, Any]):
|
|
38
|
+
"""
|
|
39
|
+
Get agent instance
|
|
40
|
+
|
|
41
|
+
:param window: Window instance
|
|
42
|
+
:param kwargs: Agent parameters
|
|
43
|
+
:return: PlannerWorkflow instance
|
|
44
|
+
"""
|
|
45
|
+
context = kwargs.get("context", BridgeContext())
|
|
46
|
+
preset = context.preset
|
|
47
|
+
tools: List[BaseTool] = kwargs.get("tools", []) or []
|
|
48
|
+
llm_supervisor: LLM = kwargs.get("llm", None)
|
|
49
|
+
verbose: bool = kwargs.get("verbose", False)
|
|
50
|
+
max_steps: int = kwargs.get("max_steps", 12)
|
|
51
|
+
|
|
52
|
+
# get prompts from options or use defaults
|
|
53
|
+
prompt_supervisor = self.get_option(preset, "supervisor", "prompt")
|
|
54
|
+
prompt_worker = self.get_option(preset, "worker", "prompt")
|
|
55
|
+
if not prompt_supervisor:
|
|
56
|
+
prompt_supervisor = SUPERVISOR_PROMPT
|
|
57
|
+
if not prompt_worker:
|
|
58
|
+
prompt_worker = WORKER_PROMPT
|
|
59
|
+
|
|
60
|
+
# get worker LLM from options
|
|
61
|
+
model_worker = window.core.models.get(
|
|
62
|
+
self.get_option(preset, "worker", "model")
|
|
63
|
+
)
|
|
64
|
+
llm_worker = window.core.idx.llm.get(model_worker, stream=False)
|
|
65
|
+
worker_memory_session_id = ""
|
|
66
|
+
if context.ctx and context.ctx.meta:
|
|
67
|
+
worker_memory_session_id = "llama_worker_session_" + str(context.ctx.meta.id)
|
|
68
|
+
|
|
69
|
+
# create workflow
|
|
70
|
+
return get_workflow(
|
|
71
|
+
tools,
|
|
72
|
+
llm_supervisor=llm_supervisor,
|
|
73
|
+
llm_worker=llm_worker,
|
|
74
|
+
verbose=verbose,
|
|
75
|
+
max_steps=max_steps,
|
|
76
|
+
prompt_supervisor=prompt_supervisor,
|
|
77
|
+
prompt_worker=prompt_worker,
|
|
78
|
+
worker_memory_session_id=worker_memory_session_id,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
def get_options(self) -> Dict[str, Any]:
|
|
82
|
+
"""
|
|
83
|
+
Return Agent options
|
|
84
|
+
|
|
85
|
+
:return: dict of options
|
|
86
|
+
"""
|
|
87
|
+
return {
|
|
88
|
+
"supervisor": {
|
|
89
|
+
"label": "Supervisor",
|
|
90
|
+
"options": {
|
|
91
|
+
"prompt": {
|
|
92
|
+
"type": "textarea",
|
|
93
|
+
"label": "Prompt",
|
|
94
|
+
"description": "Prompt for supervisor",
|
|
95
|
+
"default": SUPERVISOR_PROMPT,
|
|
96
|
+
},
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
"worker": {
|
|
100
|
+
"label": "Worker",
|
|
101
|
+
"options": {
|
|
102
|
+
"model": {
|
|
103
|
+
"label": "Model",
|
|
104
|
+
"type": "combo",
|
|
105
|
+
"use": "models",
|
|
106
|
+
"default": "gpt-4o",
|
|
107
|
+
},
|
|
108
|
+
"prompt": {
|
|
109
|
+
"type": "textarea",
|
|
110
|
+
"label": "Prompt",
|
|
111
|
+
"description": "Prompt for worker",
|
|
112
|
+
"default": WORKER_PROMPT,
|
|
113
|
+
},
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
}
|
|
@@ -0,0 +1,303 @@
|
|
|
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.17 02:00:00 #
|
|
10
|
+
# ================================================== #
|
|
11
|
+
|
|
12
|
+
import re
|
|
13
|
+
from typing import Optional, Literal, List
|
|
14
|
+
from pydantic import BaseModel, ValidationError
|
|
15
|
+
from llama_index.core.workflow import Workflow, Context, StartEvent, StopEvent, Event, step
|
|
16
|
+
from llama_index.core.agent.workflow import FunctionAgent, AgentStream
|
|
17
|
+
from llama_index.core.memory import Memory
|
|
18
|
+
|
|
19
|
+
# ==== Prompts ====
|
|
20
|
+
SUPERVISOR_PROMPT = """
|
|
21
|
+
You are the “Supervisor” – the main orchestrator. Do not use tools directly.
|
|
22
|
+
Your tasks:
|
|
23
|
+
- Break down the user's task into steps and create precise instructions for the “Worker” agent.
|
|
24
|
+
- Do not pass your history/memory to the Worker. Only pass minimal, self-sufficient instructions.
|
|
25
|
+
- After each Worker response, assess progress towards the Definition of Done (DoD). If not met – generate a better instruction.
|
|
26
|
+
- Ask the user only when absolutely necessary. Then stop and return the question.
|
|
27
|
+
- When the task is complete – return the final answer to the user.
|
|
28
|
+
Always return only ONE JSON object:
|
|
29
|
+
{
|
|
30
|
+
"action": "task" | "final" | "ask_user",
|
|
31
|
+
"instruction": "<Worker's instruction or ''>",
|
|
32
|
+
"final_answer": "<final answer or ''>",
|
|
33
|
+
"question": "<user question or ''>",
|
|
34
|
+
"reasoning": "<brief reasoning and quality control>",
|
|
35
|
+
"done_criteria": "<list/text of DoD criteria>"
|
|
36
|
+
}
|
|
37
|
+
Ensure proper JSON (no comments, no trailing commas). Respond in the user's language.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
WORKER_PROMPT = """
|
|
41
|
+
You are the “Worker” – executor of the Supervisor's instructions. You have your own memory and tools.
|
|
42
|
+
- Execute the Supervisor's instructions precisely and concisely.
|
|
43
|
+
- Use the available tools and return a brief result + relevant data/reasoning.
|
|
44
|
+
- Maintain the working context in your memory (only Worker).
|
|
45
|
+
- Return plain text (not JSON) unless instructed otherwise by the Supervisor.
|
|
46
|
+
- Respond in the user's language.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# ==== Supervisor's JSON Structures ====
|
|
51
|
+
class SupervisorDirective(BaseModel):
|
|
52
|
+
action: Literal["task", "final", "ask_user"]
|
|
53
|
+
instruction: str = ""
|
|
54
|
+
final_answer: str = ""
|
|
55
|
+
question: str = ""
|
|
56
|
+
reasoning: str = ""
|
|
57
|
+
done_criteria: str = ""
|
|
58
|
+
|
|
59
|
+
JSON_RE = re.compile(r"\{[\s\S]*\}$", re.MULTILINE)
|
|
60
|
+
|
|
61
|
+
def parse_supervisor_json(text: str) -> SupervisorDirective:
|
|
62
|
+
"""
|
|
63
|
+
Parse the Supervisor's JSON response from text.
|
|
64
|
+
|
|
65
|
+
:param text: The text response from the Supervisor.
|
|
66
|
+
:return: SupervisorDirective: Parsed directive from the Supervisor.
|
|
67
|
+
"""
|
|
68
|
+
try:
|
|
69
|
+
return SupervisorDirective.model_validate_json(text)
|
|
70
|
+
except Exception:
|
|
71
|
+
pass
|
|
72
|
+
fence = re.search(r"```json\s*([\s\S]*?)\s*```", text, re.IGNORECASE)
|
|
73
|
+
if fence:
|
|
74
|
+
try:
|
|
75
|
+
return SupervisorDirective.model_validate_json(fence.group(1).strip())
|
|
76
|
+
except Exception:
|
|
77
|
+
pass
|
|
78
|
+
tail = JSON_RE.findall(text)
|
|
79
|
+
for candidate in tail[::-1]:
|
|
80
|
+
try:
|
|
81
|
+
return SupervisorDirective.model_validate_json(candidate.strip())
|
|
82
|
+
except Exception:
|
|
83
|
+
continue
|
|
84
|
+
first = text.find("{")
|
|
85
|
+
if first != -1:
|
|
86
|
+
try:
|
|
87
|
+
return SupervisorDirective.model_validate_json(text[first:])
|
|
88
|
+
except Exception:
|
|
89
|
+
pass
|
|
90
|
+
raise ValueError("Failed to parse a valid JSON from the Supervisor's response.")
|
|
91
|
+
|
|
92
|
+
# ==== Workflow Events ====
|
|
93
|
+
class InputEvent(StartEvent):
|
|
94
|
+
user_msg: str
|
|
95
|
+
external_context: Optional[str] = ""
|
|
96
|
+
round_idx: int = 0
|
|
97
|
+
max_rounds: int = 8
|
|
98
|
+
stop_on_ask_user: bool = True
|
|
99
|
+
last_worker_output: Optional[str] = None
|
|
100
|
+
|
|
101
|
+
class ExecuteEvent(Event):
|
|
102
|
+
instruction: str
|
|
103
|
+
round_idx: int
|
|
104
|
+
max_rounds: int
|
|
105
|
+
external_context: str = ""
|
|
106
|
+
stop_on_ask_user: bool = True
|
|
107
|
+
|
|
108
|
+
class OutputEvent(StopEvent):
|
|
109
|
+
status: Literal["final", "ask_user", "max_rounds"]
|
|
110
|
+
final_answer: str
|
|
111
|
+
rounds_used: int
|
|
112
|
+
|
|
113
|
+
# ==== Main Workflow ====
|
|
114
|
+
class SupervisorWorkflow(Workflow):
|
|
115
|
+
_supervisor: FunctionAgent
|
|
116
|
+
_worker: FunctionAgent
|
|
117
|
+
_supervisor_memory: Memory
|
|
118
|
+
_worker_memory: Memory
|
|
119
|
+
_max_steps: int = 12
|
|
120
|
+
|
|
121
|
+
def __init__(self, **kwargs):
|
|
122
|
+
super().__init__(timeout=kwargs.get("timeout", 120), verbose=kwargs.get("verbose", True))
|
|
123
|
+
self._supervisor = kwargs["supervisor"]
|
|
124
|
+
self._worker = kwargs["worker"]
|
|
125
|
+
self._worker_memory = kwargs.get("worker_memory")
|
|
126
|
+
self._max_steps = kwargs.get("max_steps", 12)
|
|
127
|
+
|
|
128
|
+
def run(
|
|
129
|
+
self,
|
|
130
|
+
query: str,
|
|
131
|
+
ctx: Optional[Context] = None,
|
|
132
|
+
memory: Optional[Memory] = None, # <- only for Supervisor
|
|
133
|
+
verbose: bool = False,
|
|
134
|
+
**kwargs
|
|
135
|
+
):
|
|
136
|
+
"""
|
|
137
|
+
Run the SupervisorWorkflow with the given query and context.
|
|
138
|
+
|
|
139
|
+
:param query: The user's query to start the workflow.
|
|
140
|
+
:param ctx: Context for the workflow, used to write events.
|
|
141
|
+
:param memory: Optional memory for the Supervisor agent. If not provided, it uses the default memory.
|
|
142
|
+
:param verbose: If True, enables verbose output for the workflow.
|
|
143
|
+
:param kwargs: Additional keyword arguments for the workflow, such as `external_context`, `stop_on_ask_user`, etc.
|
|
144
|
+
:return: OutputEvent or ExecuteEvent based on the workflow's progress.
|
|
145
|
+
"""
|
|
146
|
+
if verbose:
|
|
147
|
+
self._verbose = True
|
|
148
|
+
|
|
149
|
+
if memory is not None:
|
|
150
|
+
self._supervisor_memory = memory # use external memory for Supervisor
|
|
151
|
+
|
|
152
|
+
start_event = InputEvent(
|
|
153
|
+
user_msg=query,
|
|
154
|
+
external_context=kwargs.get("external_context", ""),
|
|
155
|
+
round_idx=0,
|
|
156
|
+
max_rounds=self._max_steps,
|
|
157
|
+
stop_on_ask_user=kwargs.get("stop_on_ask_user", True),
|
|
158
|
+
last_worker_output=None,
|
|
159
|
+
)
|
|
160
|
+
return super().run(ctx=ctx, start_event=start_event)
|
|
161
|
+
|
|
162
|
+
async def _emit_text(
|
|
163
|
+
self,
|
|
164
|
+
ctx: Context,
|
|
165
|
+
text: str,
|
|
166
|
+
agent_name: str = "SupervisorWorkflow"
|
|
167
|
+
):
|
|
168
|
+
"""
|
|
169
|
+
Emit a text message to the context stream.
|
|
170
|
+
|
|
171
|
+
:param ctx: The context to write the event to
|
|
172
|
+
:param text: The text message to emit.
|
|
173
|
+
:param agent_name: The name of the agent emitting the text (default: "PlannerWorkflow").
|
|
174
|
+
"""
|
|
175
|
+
try:
|
|
176
|
+
ctx.write_event_to_stream(AgentStream(delta=text))
|
|
177
|
+
except ValidationError:
|
|
178
|
+
ctx.write_event_to_stream(
|
|
179
|
+
AgentStream(
|
|
180
|
+
delta=text,
|
|
181
|
+
response=text,
|
|
182
|
+
current_agent_name=agent_name,
|
|
183
|
+
tool_calls=[],
|
|
184
|
+
raw={},
|
|
185
|
+
)
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
@step
|
|
189
|
+
async def supervisor_step(self, ctx: Context, ev: InputEvent) -> ExecuteEvent | OutputEvent:
|
|
190
|
+
"""
|
|
191
|
+
Supervisor step to process the user's input and generate an instruction for the Worker.
|
|
192
|
+
|
|
193
|
+
:param ctx: Context for the workflow
|
|
194
|
+
:param ev: InputEvent containing the user's message and context.
|
|
195
|
+
:return: ExecuteEvent for the Worker or OutputEvent if final answer is reached.
|
|
196
|
+
"""
|
|
197
|
+
parts: List[str] = []
|
|
198
|
+
if ev.external_context:
|
|
199
|
+
parts.append(f"<external_context>\n{ev.external_context}\n</external_context>")
|
|
200
|
+
if ev.user_msg and ev.round_idx == 0:
|
|
201
|
+
parts.append(f"<task_from_user>\n{ev.user_msg}\n</task_from_user>")
|
|
202
|
+
if ev.last_worker_output:
|
|
203
|
+
parts.append(f"<last_worker_output>\n{ev.last_worker_output}\n</last_worker_output>")
|
|
204
|
+
parts.append(
|
|
205
|
+
f"<control>\nround={ev.round_idx} max_rounds={ev.max_rounds}\n"
|
|
206
|
+
"Return ONE JSON following the schema.\n</control>"
|
|
207
|
+
)
|
|
208
|
+
sup_input = "\n".join(parts)
|
|
209
|
+
sup_resp = await self._supervisor.run(user_msg=sup_input, memory=self._supervisor_memory)
|
|
210
|
+
directive = parse_supervisor_json(str(sup_resp))
|
|
211
|
+
|
|
212
|
+
if directive.action == "final":
|
|
213
|
+
await self._emit_text(ctx, f"\n\n{directive.final_answer or str(sup_resp)}", agent_name=self._supervisor.name)
|
|
214
|
+
return OutputEvent(status="final", final_answer=directive.final_answer or str(sup_resp), rounds_used=ev.round_idx)
|
|
215
|
+
if directive.action == "ask_user" and ev.stop_on_ask_user:
|
|
216
|
+
q = directive.question or "I need more information, please clarify."
|
|
217
|
+
await self._emit_text(ctx, f"\n\n{q}", agent_name=self._supervisor.name)
|
|
218
|
+
return OutputEvent(status="ask_user", final_answer=q, rounds_used=ev.round_idx)
|
|
219
|
+
if ev.round_idx >= ev.max_rounds:
|
|
220
|
+
await self._emit_text(ctx, "\n\nMax rounds exceeded.", agent_name=self._supervisor.name)
|
|
221
|
+
return OutputEvent(status="max_rounds", final_answer="Exceeded maximum number of iterations.", rounds_used=ev.round_idx)
|
|
222
|
+
|
|
223
|
+
instruction = (directive.instruction or "").strip() or "Perform a step that gets closest to fulfilling the DoD."
|
|
224
|
+
return ExecuteEvent(
|
|
225
|
+
instruction=instruction,
|
|
226
|
+
round_idx=ev.round_idx,
|
|
227
|
+
max_rounds=ev.max_rounds,
|
|
228
|
+
external_context=ev.external_context or "",
|
|
229
|
+
stop_on_ask_user=ev.stop_on_ask_user,
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
@step
|
|
233
|
+
async def worker_step(self, ctx: Context, ev: ExecuteEvent) -> InputEvent:
|
|
234
|
+
"""
|
|
235
|
+
Worker step to execute the Supervisor's instruction.
|
|
236
|
+
|
|
237
|
+
:param ctx: Context for the workflow
|
|
238
|
+
:param ev: ExecuteEvent containing the instruction and context.
|
|
239
|
+
:return: InputEvent for the next round or final output.
|
|
240
|
+
"""
|
|
241
|
+
worker_input = f"Instruction from Supervisor:\n{ev.instruction}\n"
|
|
242
|
+
await self._emit_text(ctx, f"\n\n**Supervisor:** {ev.instruction}", agent_name=self._worker.name)
|
|
243
|
+
|
|
244
|
+
worker_resp = await self._worker.run(user_msg=worker_input, memory=self._worker_memory)
|
|
245
|
+
await self._emit_text(ctx, f"\n\n**Worker:** {worker_resp}", agent_name=self._worker.name)
|
|
246
|
+
|
|
247
|
+
return InputEvent(
|
|
248
|
+
user_msg="",
|
|
249
|
+
last_worker_output=str(worker_resp),
|
|
250
|
+
round_idx=ev.round_idx + 1,
|
|
251
|
+
max_rounds=ev.max_rounds,
|
|
252
|
+
external_context=ev.external_context,
|
|
253
|
+
stop_on_ask_user=ev.stop_on_ask_user,
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
# ==== Factory ====
|
|
257
|
+
def get_workflow(
|
|
258
|
+
tools,
|
|
259
|
+
llm_supervisor,
|
|
260
|
+
llm_worker,
|
|
261
|
+
verbose: bool = False,
|
|
262
|
+
prompt_supervisor: str = SUPERVISOR_PROMPT,
|
|
263
|
+
prompt_worker: str = WORKER_PROMPT,
|
|
264
|
+
max_steps: int = 12,
|
|
265
|
+
worker_memory_session_id: str = "llama_worker_session" # session ID for worker memory
|
|
266
|
+
):
|
|
267
|
+
"""
|
|
268
|
+
Create a SupervisorWorkflow instance.
|
|
269
|
+
|
|
270
|
+
:param tools: List of tools for the Worker agent.
|
|
271
|
+
:param llm_supervisor: LLM instance for the Supervisor agent.
|
|
272
|
+
:param llm_worker: LLM instance for the Worker agent.
|
|
273
|
+
:param verbose: Verbose output flag.
|
|
274
|
+
:param prompt_supervisor: Prompt for the Supervisor agent.
|
|
275
|
+
:param prompt_worker: Prompt for the Worker agent.
|
|
276
|
+
:param max_steps: Maximum number of steps for the workflow.
|
|
277
|
+
:param worker_memory_session_id: Session ID for the Worker agent's memory.
|
|
278
|
+
:return: SupervisorWorkflow instance
|
|
279
|
+
"""
|
|
280
|
+
supervisor = FunctionAgent(
|
|
281
|
+
name="Supervisor",
|
|
282
|
+
llm=llm_supervisor,
|
|
283
|
+
system_prompt=prompt_supervisor,
|
|
284
|
+
tools=[],
|
|
285
|
+
)
|
|
286
|
+
worker = FunctionAgent(
|
|
287
|
+
name="Worker",
|
|
288
|
+
llm=llm_worker,
|
|
289
|
+
system_prompt=prompt_worker,
|
|
290
|
+
tools=tools,
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
# separate memory for the worker
|
|
294
|
+
worker_memory = Memory.from_defaults(session_id=worker_memory_session_id, token_limit=40000)
|
|
295
|
+
|
|
296
|
+
return SupervisorWorkflow(
|
|
297
|
+
supervisor=supervisor,
|
|
298
|
+
worker=worker,
|
|
299
|
+
worker_memory=worker_memory,
|
|
300
|
+
verbose=verbose,
|
|
301
|
+
timeout=120,
|
|
302
|
+
max_steps=max_steps,
|
|
303
|
+
)
|