Skip to content

Commit

Permalink
Merge branch 'main' of github.com:All-Hands-AI/OpenHands into enyst/r…
Browse files Browse the repository at this point in the history
…etrieve-prompt
  • Loading branch information
enyst committed Feb 24, 2025
2 parents 2c5018f + aa15c9d commit bec0594
Show file tree
Hide file tree
Showing 28 changed files with 798 additions and 326 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/py-unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ jobs:
- name: Build Environment
run: make build
- name: Run Tests
run: poetry run pytest --forked -n auto --cov=openhands --cov-report=xml -svv ./tests/unit --ignore=tests/unit/test_memory.py
run: poetry run pytest --forked -n auto --cov=openhands --cov-report=xml -svv ./tests/unit --ignore=tests/unit/test_long_term_memory.py
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
env:
Expand Down
6 changes: 6 additions & 0 deletions config.template.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@
#modal_api_token_id = ""
#modal_api_token_secret = ""

# API key for Daytona
#daytona_api_key = ""

# Daytona Target
#daytona_target = ""

# Base path for the workspace
workspace_base = "./workspace"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ export function StyledSwitchComponent({
className={cn(
"w-12 h-6 rounded-xl flex items-center p-1.5 cursor-pointer",
isToggled && "justify-end bg-primary",
!isToggled && "justify-start bg-[#1F2228] border border-tertiary-alt",
!isToggled &&
"justify-start bg-base-secondary border border-tertiary-light",
)}
>
<div
className={cn(
"bg-[#1F2228] w-3 h-3 rounded-xl",
isToggled ? "bg-[#1F2228]" : "bg-tertiary-alt",
"w-3 h-3 rounded-xl",
isToggled ? "bg-base-secondary" : "bg-tertiary-light",
)}
/>
</div>
Expand Down
1 change: 1 addition & 0 deletions openhands/core/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ async def main(loop: asyncio.AbstractEventLoop):
initial_user_action = MessageAction(content=task_str) if task_str else None

sid = str(uuid4())
display_message(f'Session ID: {sid}')

runtime = create_runtime(config, sid=sid, headless_mode=True)
await runtime.connect()
Expand Down
3 changes: 3 additions & 0 deletions openhands/core/config/app_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ class AppConfig(BaseModel):
file_uploads_restrict_file_types: bool = Field(default=False)
file_uploads_allowed_extensions: list[str] = Field(default_factory=lambda: ['.*'])
runloop_api_key: SecretStr | None = Field(default=None)
daytona_api_key: SecretStr | None = Field(default=None)
daytona_api_url: str = Field(default='https://app.daytona.io/api')
daytona_target: str = Field(default='us')
cli_multiline_input: bool = Field(default=False)
conversation_max_age_seconds: int = Field(default=864000) # 10 days in seconds
microagents_dir: str = Field(
Expand Down
10 changes: 8 additions & 2 deletions openhands/core/config/config_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,20 @@ def get_field_info(field: FieldInfo) -> dict[str, Any]:
# Note: this only works for UnionTypes with None as one of the types
if get_origin(field_type) is UnionType:
types = get_args(field_type)
non_none_arg = next((t for t in types if t is not type(None)), None)
non_none_arg = next(
(t for t in types if t is not None and t is not type(None)), None
)
if non_none_arg is not None:
field_type = non_none_arg
optional = True

# type name in a pretty format
type_name = (
field_type.__name__ if hasattr(field_type, '__name__') else str(field_type)
str(field_type)
if field_type is None
else (
field_type.__name__ if hasattr(field_type, '__name__') else str(field_type)
)
)

# default is always present
Expand Down
46 changes: 25 additions & 21 deletions openhands/core/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@ class AgentError(Exception):


class AgentNoInstructionError(AgentError):
def __init__(self, message='Instruction must be provided'):
def __init__(self, message: str = 'Instruction must be provided') -> None:
super().__init__(message)


class AgentEventTypeError(AgentError):
def __init__(self, message='Event must be a dictionary'):
def __init__(self, message: str = 'Event must be a dictionary') -> None:
super().__init__(message)


class AgentAlreadyRegisteredError(AgentError):
def __init__(self, name=None):
def __init__(self, name: str | None = None) -> None:
if name is not None:
message = f"Agent class already registered under '{name}'"
else:
Expand All @@ -29,7 +29,7 @@ def __init__(self, name=None):


class AgentNotRegisteredError(AgentError):
def __init__(self, name=None):
def __init__(self, name: str | None = None) -> None:
if name is not None:
message = f"No agent class registered under '{name}'"
else:
Expand All @@ -38,7 +38,7 @@ def __init__(self, name=None):


class AgentStuckInLoopError(AgentError):
def __init__(self, message='Agent got stuck in a loop'):
def __init__(self, message: str = 'Agent got stuck in a loop') -> None:
super().__init__(message)


Expand All @@ -48,7 +48,7 @@ def __init__(self, message='Agent got stuck in a loop'):


class TaskInvalidStateError(Exception):
def __init__(self, state=None):
def __init__(self, state: str | None = None) -> None:
if state is not None:
message = f'Invalid state {state}'
else:
Expand All @@ -64,45 +64,47 @@ def __init__(self, state=None):
# This exception gets sent back to the LLM
# It might be malformed JSON
class LLMMalformedActionError(Exception):
def __init__(self, message='Malformed response'):
def __init__(self, message: str = 'Malformed response') -> None:
self.message = message
super().__init__(message)

def __str__(self):
def __str__(self) -> str:
return self.message


# This exception gets sent back to the LLM
# For some reason, the agent did not return an action
class LLMNoActionError(Exception):
def __init__(self, message='Agent must return an action'):
def __init__(self, message: str = 'Agent must return an action') -> None:
super().__init__(message)


# This exception gets sent back to the LLM
# The LLM output did not include an action, or the action was not the expected type
class LLMResponseError(Exception):
def __init__(self, message='Failed to retrieve action from LLM response'):
def __init__(
self, message: str = 'Failed to retrieve action from LLM response'
) -> None:
super().__init__(message)


class UserCancelledError(Exception):
def __init__(self, message='User cancelled the request'):
def __init__(self, message: str = 'User cancelled the request') -> None:
super().__init__(message)


class OperationCancelled(Exception):
"""Exception raised when an operation is cancelled (e.g. by a keyboard interrupt)."""

def __init__(self, message='Operation was cancelled'):
def __init__(self, message: str = 'Operation was cancelled') -> None:
super().__init__(message)


class LLMContextWindowExceedError(RuntimeError):
def __init__(
self,
message='Conversation history longer than LLM context window limit. Consider turning on enable_history_truncation config to avoid this error',
):
message: str = 'Conversation history longer than LLM context window limit. Consider turning on enable_history_truncation config to avoid this error',
) -> None:
super().__init__(message)


Expand All @@ -117,7 +119,7 @@ class FunctionCallConversionError(Exception):
This typically happens when there's a malformed message (e.g., missing <function=...> tags). But not due to LLM output.
"""

def __init__(self, message):
def __init__(self, message: str) -> None:
super().__init__(message)


Expand All @@ -127,14 +129,14 @@ class FunctionCallValidationError(Exception):
This typically happens when the LLM outputs unrecognized function call / parameter names / values.
"""

def __init__(self, message):
def __init__(self, message: str) -> None:
super().__init__(message)


class FunctionCallNotExistsError(Exception):
"""Exception raised when an LLM call a tool that is not registered."""

def __init__(self, message):
def __init__(self, message: str) -> None:
super().__init__(message)


Expand Down Expand Up @@ -191,15 +193,17 @@ class AgentRuntimeNotFoundError(AgentRuntimeUnavailableError):


class BrowserInitException(Exception):
def __init__(self, message='Failed to initialize browser environment'):
def __init__(
self, message: str = 'Failed to initialize browser environment'
) -> None:
super().__init__(message)


class BrowserUnavailableException(Exception):
def __init__(
self,
message='Browser environment is not available, please check if has been initialized',
):
message: str = 'Browser environment is not available, please check if has been initialized',
) -> None:
super().__init__(message)


Expand All @@ -217,5 +221,5 @@ class MicroAgentError(Exception):
class MicroAgentValidationError(MicroAgentError):
"""Raised when there's a validation error in microagent metadata."""

def __init__(self, message='Micro agent validation failed'):
def __init__(self, message: str = 'Micro agent validation failed') -> None:
super().__init__(message)
Loading

0 comments on commit bec0594

Please sign in to comment.