Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ dependencies = [
"fastparquet>=2024.11.0,<2025.0.0",
"traceloop-sdk>=0.43.1,<1.0.0",
"vlmrun[all]>=0.2.0",
"cuga==0.1.2",
"cuga==0.1.4",
"agent-lifecycle-toolkit",
"astrapy>=2.1.0,<3.0.0",
]
Expand Down
8 changes: 8 additions & 0 deletions src/backend/tests/unit/components/agents/test_cuga_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ def default_kwargs(self):
"browser_enabled": False,
"web_apps": "",
"API": False,
"lite_mode": True,
"lite_mode_tool_threshold": 25,
}

async def test_build_config_update(self, component_class, default_kwargs):
Expand Down Expand Up @@ -389,6 +391,8 @@ async def test_new_input_fields_present(self, component_class, default_kwargs):
assert "browser_enabled" in input_names
assert "web_apps" in input_names
assert "API" in input_names
assert "lite_mode" in input_names
assert "lite_mode_tool_threshold" in input_names

# Verify default values
assert hasattr(component, "policies")
Expand All @@ -398,9 +402,13 @@ async def test_new_input_fields_present(self, component_class, default_kwargs):
assert hasattr(component, "browser_enabled")
assert hasattr(component, "web_apps")
assert hasattr(component, "API")
assert hasattr(component, "lite_mode")
assert hasattr(component, "lite_mode_tool_threshold")
assert component.n_messages == 100
assert component.browser_enabled is False
assert component.API is False
assert component.lite_mode is True
assert component.lite_mode_tool_threshold == 25

async def test_cuga_has_correct_outputs(self, component_class, default_kwargs):
"""Test that Cuga component has the correct output configuration.
Expand Down
2 changes: 1 addition & 1 deletion src/lfx/src/lfx/_assets/component_index.json

Large diffs are not rendered by default.

71 changes: 45 additions & 26 deletions src/lfx/src/lfx/components/agents/cuga_agent.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import asyncio
import json
import os
import re
import traceback
import uuid
Expand Down Expand Up @@ -108,9 +107,9 @@ class CugaComponent(ToolCallingAgentComponent):
info=(
"Custom instructions or policies for the agent to adhere to during its operation.\n"
"Example:\n"
"# Plan\n"
"## Plan\n"
"< planning instructions e.g. which tools and when to use>\n"
"# Answer\n"
"## Answer\n"
"< final answer instructions how to answer>"
),
value="",
Expand Down Expand Up @@ -193,6 +192,20 @@ class CugaComponent(ToolCallingAgentComponent):
info="If true, will add a tool to the agent that returns the current date.",
value=True,
),
BoolInput(
name="lite_mode",
display_name="Enable CugaLite",
info="Enable CugaLite for simple API tasks (faster execution).",
value=True,
advanced=False,
),
IntInput(
name="lite_mode_tool_threshold",
display_name="CugaLite Tool Threshold",
info="Route to CugaLite if app has fewer than this many tools.",
value=25,
advanced=False,
),
BoolInput(
name="browser_enabled",
display_name="Enable Browser",
Expand Down Expand Up @@ -254,33 +267,27 @@ async def call_agent(
}
logger.debug(f"LLM MODEL TYPE: {type(llm)}")
if current_input:
try:
from cuga.config import settings as cuga_settings
# Import settings first
from cuga.config import settings

logger.info("Updating cuga settings programmatically")
cuga_settings.set("advanced_features.registry", False) # noqa: FBT003
# Use Dynaconf's set() method to update settings dynamically
# This properly updates the settings object without corruption
logger.debug("Updating CUGA settings via Dynaconf set() method")

if self.browser_enabled:
logger.info("browser_enabled is true, setting mode to hybrid")
cuga_settings.set("advanced_features.mode", "hybrid")
cuga_settings.set("advanced_features.use_vision", False) # noqa: FBT003
else:
logger.info("browser_enabled is false, setting mode to api")
cuga_settings.set("advanced_features.mode", "api")

logger.info(f"Cuga settings updated - MODE: {cuga_settings.get('advanced_features.mode')}")
except (ImportError, AttributeError) as e:
logger.warning(f"Could not update cuga settings: {e}")
os.environ["DYNACONF_ADVANCED_FEATURES__REGISTRY"] = "false"
if self.browser_enabled:
logger.info("browser_enabled is true, setting env to hybrid")
os.environ["DYNACONF_ADVANCED_FEATURES__MODE"] = "hybrid"
os.environ["DYNACONF_ADVANCED_FEATURES__USE_VISION"] = "false"
else:
logger.info("browser_enabled is false, setting env to api")
os.environ["DYNACONF_ADVANCED_FEATURES__MODE"] = "api"
settings.advanced_features.registry = False
settings.advanced_features.lite_mode = self.lite_mode
settings.advanced_features.lite_mode_tool_threshold = self.lite_mode_tool_threshold

if self.browser_enabled:
logger.info("browser_enabled is true, setting mode to hybrid")
settings.advanced_features.mode = "hybrid"
settings.advanced_features.use_vision = False
else:
logger.info("browser_enabled is false, setting mode to api")
settings.advanced_features.mode = "api"

Comment on lines +270 to 288
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Comment claims to use Dynaconf's set() method, but code uses direct attribute assignment.

The comment states "Use Dynaconf's set() method to update settings dynamically" but the implementation uses direct attribute assignment (e.g., settings.advanced_features.registry = False). Either update the comment to reflect the actual implementation or switch to using Dynaconf's set() method if that's the intended approach.

If direct assignment is correct, apply this diff:

-            # Use Dynaconf's set() method to update settings dynamically
-            # This properly updates the settings object without corruption
-            logger.debug("Updating CUGA settings via Dynaconf set() method")
+            # Update CUGA settings via direct attribute assignment
+            logger.debug("Updating CUGA advanced_features settings")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Import settings first
from cuga.config import settings
logger.info("Updating cuga settings programmatically")
cuga_settings.set("advanced_features.registry", False) # noqa: FBT003
# Use Dynaconf's set() method to update settings dynamically
# This properly updates the settings object without corruption
logger.debug("Updating CUGA settings via Dynaconf set() method")
if self.browser_enabled:
logger.info("browser_enabled is true, setting mode to hybrid")
cuga_settings.set("advanced_features.mode", "hybrid")
cuga_settings.set("advanced_features.use_vision", False) # noqa: FBT003
else:
logger.info("browser_enabled is false, setting mode to api")
cuga_settings.set("advanced_features.mode", "api")
logger.info(f"Cuga settings updated - MODE: {cuga_settings.get('advanced_features.mode')}")
except (ImportError, AttributeError) as e:
logger.warning(f"Could not update cuga settings: {e}")
os.environ["DYNACONF_ADVANCED_FEATURES__REGISTRY"] = "false"
if self.browser_enabled:
logger.info("browser_enabled is true, setting env to hybrid")
os.environ["DYNACONF_ADVANCED_FEATURES__MODE"] = "hybrid"
os.environ["DYNACONF_ADVANCED_FEATURES__USE_VISION"] = "false"
else:
logger.info("browser_enabled is false, setting env to api")
os.environ["DYNACONF_ADVANCED_FEATURES__MODE"] = "api"
settings.advanced_features.registry = False
settings.advanced_features.lite_mode = self.lite_mode
settings.advanced_features.lite_mode_tool_threshold = self.lite_mode_tool_threshold
if self.browser_enabled:
logger.info("browser_enabled is true, setting mode to hybrid")
settings.advanced_features.mode = "hybrid"
settings.advanced_features.use_vision = False
else:
logger.info("browser_enabled is false, setting mode to api")
settings.advanced_features.mode = "api"
# Import settings first
from cuga.config import settings
# Update CUGA settings via direct attribute assignment
logger.debug("Updating CUGA advanced_features settings")
settings.advanced_features.registry = False
settings.advanced_features.lite_mode = self.lite_mode
settings.advanced_features.lite_mode_tool_threshold = self.lite_mode_tool_threshold
if self.browser_enabled:
logger.info("browser_enabled is true, setting mode to hybrid")
settings.advanced_features.mode = "hybrid"
settings.advanced_features.use_vision = False
else:
logger.info("browser_enabled is false, setting mode to api")
settings.advanced_features.mode = "api"
🤖 Prompt for AI Agents
In src/lfx/src/lfx/components/agents/cuga_agent.py around lines 270-288, the
inline comment claims Dynaconf's set() is used but the code performs direct
attribute assignment; update the comment to accurately state that settings are
modified via direct attribute assignment (or, if you intended to use Dynaconf
set(), replace the assignments with settings.set(...) calls for each key),
ensuring the comment and implementation match.

from cuga.backend.activity_tracker.tracker import ActivityTracker
from cuga.backend.cuga_graph.nodes.api.variables_manager.manager import VariablesManager
from cuga.backend.cuga_graph.utils.agent_loop import StreamEvent
from cuga.backend.cuga_graph.utils.controller import (
AgentRunner as CugaAgent,
Expand All @@ -291,6 +298,16 @@ async def call_agent(
from cuga.backend.llm.models import LLMManager
from cuga.configurations.instructions_manager import InstructionsManager

var_manager = VariablesManager()

# Reset var_manager if this is the first message in history
logger.info(f"[CUGA] Checking history_messages: count={len(history_messages) if history_messages else 0}")
if not history_messages or len(history_messages) == 0:
logger.info("[CUGA] First message in history detected, resetting var_manager")
var_manager.reset()
else:
logger.info(f"[CUGA] Continuing conversation with {len(history_messages)} previous messages")

llm_manager = LLMManager()
llm_manager.set_llm(llm)
instructions_manager = InstructionsManager()
Expand Down Expand Up @@ -760,11 +777,13 @@ async def get_memory_data(self):
list: List of Message objects representing the chat history
"""
logger.info("[CUGA] Retrieving chat history messages.")
logger.info(f"[CUGA] Session ID: {self.graph.session_id}")
messages = (
await MemoryComponent(**self.get_base_args())
.set(session_id=self.graph.session_id, order="Ascending", n_messages=self.n_messages)
.retrieve_messages()
)
logger.info(f"[CUGA] Retrieved {len(messages)} messages from memory")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd move most of these types of logs to debug

return [
message for message in messages if getattr(message, "id", None) != getattr(self.input_value, "id", None)
]
Expand Down
8 changes: 4 additions & 4 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading