Skip to content

Commit f188ae1

Browse files
committed
Release v4.5.102
1 parent 17ca3f8 commit f188ae1

File tree

13 files changed

+122
-41
lines changed

13 files changed

+122
-41
lines changed

docker/Dockerfile.chat

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ RUN mkdir -p /root/.praison
1616
# Install Python packages (using latest versions)
1717
RUN pip install --no-cache-dir \
1818
praisonai_tools \
19-
"praisonai>=4.5.101" \
19+
"praisonai>=4.5.102" \
2020
"praisonai[chat]" \
2121
"embedchain[github,youtube]"
2222

docker/Dockerfile.dev

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ RUN mkdir -p /root/.praison
2020
# Install Python packages (using latest versions)
2121
RUN pip install --no-cache-dir \
2222
praisonai_tools \
23-
"praisonai>=4.5.101" \
23+
"praisonai>=4.5.102" \
2424
"praisonai[ui]" \
2525
"praisonai[chat]" \
2626
"praisonai[realtime]" \

docker/Dockerfile.ui

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ RUN mkdir -p /root/.praison
1616
# Install Python packages (using latest versions)
1717
RUN pip install --no-cache-dir \
1818
praisonai_tools \
19-
"praisonai>=4.5.101" \
19+
"praisonai>=4.5.102" \
2020
"praisonai[ui]" \
2121
"praisonai[crewai]"
2222

src/praisonai-agents/praisonaiagents/agents/agents.py

Lines changed: 48 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -665,16 +665,22 @@ async def aexecute_task(self, task_id):
665665
if executor_agent and executor_agent.tools:
666666
tools.extend(executor_agent.tools)
667667

668-
task_prompt = f"""
669-
You need to do the following task: {task.description}.
670-
Expected Output: {task.expected_output}.
671-
"""
668+
# Substitute variables in task description if provided
669+
task_description = task.description
670+
if getattr(task, 'variables', None):
671+
for key, value in task.variables.items():
672+
task_description = task_description.replace(f"{{{{{key}}}}}", str(value))
673+
674+
# Build context first to include in task prompt
675+
context_text = ""
672676
if task.context:
673677
context_results = [] # Use list to avoid duplicates
674678
for context_item in task.context:
675679
# Use the centralized helper function
676680
context_str = process_task_context(context_item, self.verbose, self.user_id)
677-
context_results.append(context_str)
681+
# Only add non-empty context strings
682+
if context_str and context_str.strip():
683+
context_results.append(context_str)
678684

679685
# Join unique context results with proper formatting
680686
unique_contexts = list(dict.fromkeys(context_results)) # Remove duplicates
@@ -683,15 +689,26 @@ async def aexecute_task(self, task_id):
683689
for i, ctx in enumerate(unique_contexts):
684690
logger.debug(f"Context {i+1}: {ctx[:100]}...")
685691
context_separator = '\n\n'
686-
task_prompt += f"""
687-
Context:
692+
context_text = context_separator.join(unique_contexts)
693+
694+
# Build task prompt - only use "User Input/Topic" format if there's actual content
695+
if context_text and context_text.strip():
696+
task_prompt = f"""
697+
User Input/Topic: {context_text}
688698
689-
{context_separator.join(unique_contexts)}
690-
"""
691-
task_prompt += "Please provide only the final result of your work. Do not add any conversation or extra explanation."
699+
Task: {task_description}
700+
Expected Output: {task.expected_output}
701+
702+
IMPORTANT: Your response must be about the user's input/topic above. Incorporate it into your task.
703+
Please provide only the final result of your work. Do not add any conversation or extra explanation."""
704+
else:
705+
task_prompt = f"""
706+
You need to do the following task: {task_description}.
707+
Expected Output: {task.expected_output}.
708+
Please provide only the final result of your work. Do not add any conversation or extra explanation."""
692709

693710
if self.verbose >= 2:
694-
logger.info(f"Executing task {task_id}: {task.description} using {executor_agent.display_name}")
711+
logger.info(f"Executing task {task_id}: {task_description} using {executor_agent.display_name}")
695712
logger.debug(f"Starting execution of task {task_id} with prompt:\n{task_prompt}")
696713

697714
if task.images:
@@ -989,16 +1006,16 @@ def execute_task(self, task_id):
9891006
for key, value in task.variables.items():
9901007
task_description = task_description.replace(f"{{{{{key}}}}}", str(value))
9911008

992-
task_prompt = f"""
993-
You need to do the following task: {task_description}.
994-
Expected Output: {task.expected_output}.
995-
"""
1009+
# Build context first to include in task prompt
1010+
context_text = ""
9961011
if task.context:
9971012
context_results = [] # Use list to avoid duplicates
9981013
for context_item in task.context:
9991014
# Use the centralized helper function
10001015
context_str = process_task_context(context_item, self.verbose, self.user_id)
1001-
context_results.append(context_str)
1016+
# Only add non-empty context strings
1017+
if context_str and context_str.strip():
1018+
context_results.append(context_str)
10021019

10031020
# Join unique context results with proper formatting
10041021
unique_contexts = list(dict.fromkeys(context_results)) # Remove duplicates
@@ -1007,11 +1024,21 @@ def execute_task(self, task_id):
10071024
for i, ctx in enumerate(unique_contexts):
10081025
logger.debug(f"Context {i+1}: {ctx[:100]}...")
10091026
context_separator = '\n\n'
1010-
task_prompt += f"""
1011-
Context:
1027+
context_text = context_separator.join(unique_contexts)
1028+
1029+
# Build task prompt - only use "User Input/Topic" format if there's actual content
1030+
if context_text and context_text.strip():
1031+
task_prompt = f"""
1032+
User Input/Topic: {context_text}
1033+
1034+
Task: {task_description}
1035+
Expected Output: {task.expected_output}
10121036
1013-
{context_separator.join(unique_contexts)}
1014-
"""
1037+
IMPORTANT: Your response must be about the user's input/topic above. Incorporate it into your task."""
1038+
else:
1039+
task_prompt = f"""
1040+
You need to do the following task: {task_description}.
1041+
Expected Output: {task.expected_output}."""
10151042

10161043
# Add memory context if available
10171044
if task.memory:
@@ -1025,7 +1052,7 @@ def execute_task(self, task_id):
10251052
except Exception as e:
10261053
logger.error(f"Error getting memory context: {e}")
10271054

1028-
task_prompt += "Please provide only the final result of your work. Do not add any conversation or extra explanation."
1055+
task_prompt += "\nPlease provide only the final result of your work. Do not add any conversation or extra explanation."
10291056

10301057
if self.verbose >= 2:
10311058
logger.info(f"Executing task {task_id}: {task.description} using {executor_agent.display_name}")

src/praisonai-agents/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "praisonaiagents"
7-
version = "1.5.101"
7+
version = "1.5.102"
88
description = "Praison AI agents for completing complex tasks with Self Reflection Agents"
99
readme = "README.md"
1010
requires-python = ">=3.10"

src/praisonai-agents/uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/praisonai/praisonai.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ class Praisonai < Formula
33

44
desc "AI tools for various AI applications"
55
homepage "https://github.com/MervinPraison/PraisonAI"
6-
url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v4.5.101.tar.gz"
7-
sha256 `curl -sL https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v4.5.101.tar.gz | shasum -a 256`.split.first
6+
url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v4.5.102.tar.gz"
7+
sha256 `curl -sL https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v4.5.102.tar.gz | shasum -a 256`.split.first
88
license "MIT"
99

1010
depends_on "python@3.11"

src/praisonai/praisonai/deploy.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def create_dockerfile(self):
5757
file.write("FROM python:3.11-slim\n")
5858
file.write("WORKDIR /app\n")
5959
file.write("COPY . .\n")
60-
file.write("RUN pip install flask praisonai==4.5.101 gunicorn markdown\n")
60+
file.write("RUN pip install flask praisonai==4.5.102 gunicorn markdown\n")
6161
file.write("EXPOSE 8080\n")
6262
file.write('CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]\n')
6363

src/praisonai/praisonai/flow/components/PraisonAI/praisonai_agent.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,11 @@ class PraisonAIAgentComponent(Component):
4848
info="Name for identification and logging.",
4949
value="Agent",
5050
),
51-
IntInput(
52-
name="order",
53-
display_name="Order",
54-
info="Execution order in sequential workflows (1 = first, 2 = second, etc.).",
55-
value=1,
51+
HandleInput(
52+
name="previous_agent",
53+
display_name="Previous Agent",
54+
info="Connect from previous agent to define execution order (Agent 1 → Agent 2 → Agent 3).",
55+
input_types=["Agent"],
5656
),
5757
MultilineInput(
5858
name="role",
@@ -396,8 +396,8 @@ def build_agent(self) -> Any:
396396
# Build agent
397397
agent = agent_class(**kwargs)
398398

399-
# Store order for sequential execution sorting
400-
agent._langflow_order = self.order or 1
399+
# Store previous agent reference for chaining
400+
agent._langflow_previous = self.previous_agent
401401

402402
self.status = f"Agent '{self.agent_name}' created"
403403
return agent

src/praisonai/praisonai/flow/components/PraisonAI/praisonai_agents.py

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,60 @@ def _import_agents(self):
187187
else:
188188
return AgentTeam
189189

190+
def _sort_agents_by_chain(self, agents: list) -> list:
191+
"""Sort agents by their chain order (previous_agent connections).
192+
193+
Agents are connected: Agent1 → Agent2 → Agent3
194+
The first agent has no previous_agent, subsequent agents point to their predecessor.
195+
"""
196+
if len(agents) <= 1:
197+
return agents
198+
199+
# Find agents that have a previous_agent set
200+
has_previous = set()
201+
202+
for agent in agents:
203+
prev = getattr(agent, '_langflow_previous', None)
204+
if prev is not None:
205+
has_previous.add(id(agent))
206+
207+
# Find starting agents (those with no previous)
208+
starting_agents = [a for a in agents if id(a) not in has_previous or getattr(a, '_langflow_previous', None) is None]
209+
210+
if not starting_agents:
211+
# No clear start, return as-is
212+
return agents
213+
214+
# Build chain from each starting agent
215+
sorted_agents = []
216+
visited = set()
217+
218+
# Start with agents that have no previous
219+
for start in starting_agents:
220+
if id(start) in visited:
221+
continue
222+
sorted_agents.append(start)
223+
visited.add(id(start))
224+
225+
# Now add agents that follow (have previous_agent set)
226+
# Keep iterating until all agents are placed
227+
remaining = [a for a in agents if id(a) not in visited]
228+
while remaining:
229+
added = False
230+
for agent in remaining[:]:
231+
prev = getattr(agent, '_langflow_previous', None)
232+
if prev is not None and id(prev) in visited:
233+
sorted_agents.append(agent)
234+
visited.add(id(agent))
235+
remaining.remove(agent)
236+
added = True
237+
if not added:
238+
# No progress, add remaining as-is
239+
sorted_agents.extend(remaining)
240+
break
241+
242+
return sorted_agents
243+
190244
def build_agents(self) -> Any:
191245
"""Build and return the PraisonAI Agents instance."""
192246
agents_class = self._import_agents()
@@ -198,8 +252,8 @@ def build_agents(self) -> Any:
198252
msg = "At least one agent is required."
199253
raise ValueError(msg)
200254

201-
# Sort agents by their order (set in Agent component)
202-
agents = sorted(agents, key=lambda a: getattr(a, '_langflow_order', 1))
255+
# Sort agents by chain order (previous_agent connections)
256+
agents = self._sort_agents_by_chain(agents)
203257

204258
# Build kwargs - tasks auto-generated from agents
205259
kwargs = {

0 commit comments

Comments
 (0)