Rename service (#8791)

This commit is contained in:
Engel Nyst
2025-05-29 21:43:42 +02:00
committed by GitHub
parent 30d53f8df0
commit 0e0687efc3
22 changed files with 82 additions and 53 deletions

View File

@@ -266,5 +266,6 @@ class CodeActAgent(Agent):
def response_to_actions(self, response: 'ModelResponse') -> list['Action']:
return codeact_function_calling.response_to_actions(
response, mcp_tool_names=list(self.mcp_tools.keys()),
response,
mcp_tool_names=list(self.mcp_tools.keys()),
)

View File

@@ -5,14 +5,13 @@ This is similar to the functionality of `CodeActResponseParser`.
import json
from litellm import (
ChatCompletionToolParam,
ModelResponse,
)
from openhands.agenthub.codeact_agent.tools import FinishTool
from openhands.agenthub.codeact_agent.function_calling import combine_thought
from openhands.agenthub.codeact_agent.tools import FinishTool
from openhands.agenthub.loc_agent.tools import (
SearchEntityTool,
SearchRepoTool,
@@ -32,7 +31,8 @@ from openhands.events.tool import ToolCallMetadata
def response_to_actions(
response: ModelResponse, mcp_tool_names: list[str] | None = None,
response: ModelResponse,
mcp_tool_names: list[str] | None = None,
) -> list[Action]:
actions: list[Action] = []
assert len(response.choices) == 1, 'Only one choice is supported for now'
@@ -87,7 +87,7 @@ def response_to_actions(
raise FunctionCallNotExistsError(
f'Tool {tool_call.function.name} is not registered. (arguments: {arguments}). Please check the tool name and retry with an existing tool.'
)
# We only add thought to the first action
if i == 0:
action = combine_thought(action, thought)
@@ -106,7 +106,7 @@ def response_to_actions(
wait_for_response=True,
)
)
# Add response id to actions
# This will ensure we can match both actions without tool calls (e.g. MessageAction)
# and actions with tool calls (e.g. CmdRunAction, IPythonRunCellAction, etc.)
@@ -116,7 +116,7 @@ def response_to_actions(
assert len(actions) >= 1
return actions
def get_tools() -> list[ChatCompletionToolParam]:
tools = [FinishTool]

View File

@@ -1,13 +1,12 @@
from openhands.agenthub.codeact_agent import CodeActAgent
from typing import TYPE_CHECKING
import openhands.agenthub.loc_agent.function_calling as locagent_function_calling
from openhands.agenthub.codeact_agent import CodeActAgent
from openhands.core.config import AgentConfig
from openhands.core.logger import openhands_logger as logger
from openhands.llm.llm import LLM
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from openhands.events.action import Action
from openhands.llm.llm import ModelResponse
@@ -35,5 +34,6 @@ class LocAgent(CodeActAgent):
def response_to_actions(self, response: 'ModelResponse') -> list['Action']:
return locagent_function_calling.response_to_actions(
response, mcp_tool_names=list(self.mcp_tools.keys()),
response,
mcp_tool_names=list(self.mcp_tools.keys()),
)

View File

@@ -11,7 +11,9 @@ class MCPObservation(Observation):
observation: str = ObservationType.MCP
name: str = '' # The name of the MCP tool that was called
arguments: dict[str, Any] = field(default_factory=dict) # The arguments passed to the MCP tool
arguments: dict[str, Any] = field(
default_factory=dict
) # The arguments passed to the MCP tool
@property
def message(self) -> str:

View File

@@ -1 +1 @@
{{ issue_comment }}
{{ issue_comment }}

View File

@@ -1 +1 @@
Please fix issue number #{{ issue_number }} in your repository.
Please fix issue number #{{ issue_number }} in your repository.

View File

@@ -1 +1 @@
{{ pr_comment }}
{{ pr_comment }}

View File

@@ -4,4 +4,4 @@ You SHOULD INCLUDE PROPER INDENTATION in your edit commands.{% if repo_instructi
Some basic information about this repository:
{{ repo_instruction }}{% endif %}
When you think you have fixed the issue through code changes, please finish the interaction.
When you think you have fixed the issue through code changes, please finish the interaction.

View File

@@ -13,4 +13,4 @@ You SHOULD INCLUDE PROPER INDENTATION in your edit commands.{% if repo_instructi
Some basic information about this repository:
{{ repo_instruction }}{% endif %}
When you think you have fixed the issue through code changes, please finish the interaction.
When you think you have fixed the issue through code changes, please finish the interaction.

View File

@@ -2,4 +2,4 @@ Please fix the following issue for the repository in /workspace.
An environment has been set up for you to start working. You may assume all necessary tools are installed.
# Problem Statement
{{ body }}
{{ body }}

View File

@@ -2,4 +2,4 @@ Please fix the following issue for the repository in /workspace.
An environment has been set up for you to start working. You may assume all necessary tools are installed.
# Problem Statement
{{ body }}
{{ body }}

View File

@@ -1,7 +1,9 @@
import io
import base64
from PIL import Image
import io
import numpy as np
from PIL import Image
def image_to_png_base64_url(
image: np.ndarray | Image.Image, add_data_prefix: bool = False
@@ -21,6 +23,7 @@ def image_to_png_base64_url(
else f'{image_base64}'
)
def png_base64_url_to_image(png_base64_url: str) -> Image.Image:
"""Convert a base64 encoded png image url to a PIL Image."""
splited = png_base64_url.split(',')

View File

@@ -12,13 +12,14 @@ from browsergym.utils.obs import flatten_dom_to_str, overlay_som
from openhands.core.exceptions import BrowserInitException
from openhands.core.logger import openhands_logger as logger
from openhands.runtime.browser.base64 import image_to_png_base64_url
from openhands.utils.shutdown_listener import should_continue, should_exit
from openhands.utils.tenacity_stop import stop_if_should_exit
from openhands.runtime.browser.base64 import image_to_png_base64_url
BROWSER_EVAL_GET_GOAL_ACTION = 'GET_EVAL_GOAL'
BROWSER_EVAL_GET_REWARDS_ACTION = 'GET_EVAL_REWARDS'
class BrowserEnv:
def __init__(self, browsergym_eval_env: str | None = None):
self.html_text_converter = self.get_html_text_converter()

View File

@@ -6,22 +6,22 @@ from contextlib import asynccontextmanager
@asynccontextmanager
async def capture_logs(logger_name, level=logging.ERROR):
logger = logging.getLogger(logger_name)
# Store original handlers and level
original_handlers = logger.handlers[:]
original_level = logger.level
# Set up capture
log_capture = io.StringIO()
handler = logging.StreamHandler(log_capture)
handler.setLevel(level)
logger.handlers = [handler]
logger.setLevel(level)
try:
yield log_capture
finally:
# Restore original configuration
logger.handlers = original_handlers
logger.setLevel(original_level)
logger.setLevel(original_level)

View File

@@ -22,7 +22,7 @@ class ServerConfig(ServerConfigInterface):
'openhands.storage.conversation.file_conversation_store.FileConversationStore'
)
conversation_manager_class: str = os.environ.get(
"CONVERSATION_MANAGER_CLASS",
'CONVERSATION_MANAGER_CLASS',
'openhands.server.conversation_manager.standalone_conversation_manager.StandaloneConversationManager',
)
monitoring_listener_class: str = 'openhands.server.monitoring.MonitoringListener'

View File

@@ -9,6 +9,7 @@ class AgentLoopInfo:
"""
Information about an agent loop - the URL on which to locate it and the event store
"""
conversation_id: str
url: str | None
session_api_key: str | None

View File

@@ -1,4 +1,5 @@
import time
from fastapi import FastAPI, Request
from openhands.runtime.utils.system_stats import get_system_stats
@@ -6,17 +7,16 @@ from openhands.runtime.utils.system_stats import get_system_stats
start_time = time.time()
last_execution_time = start_time
def add_health_endpoints(app: FastAPI):
@app.get('/alive')
async def alive():
return {'status': 'ok'}
@app.get('/health')
async def health() -> str:
return 'OK'
@app.get('/server_info')
async def get_server_info():
current_time = time.time()
@@ -29,9 +29,8 @@ def add_health_endpoints(app: FastAPI):
'resources': get_system_stats(),
}
return response
@app.middleware("http")
@app.middleware('http')
async def update_last_execution_time(request: Request, call_next):
global last_execution_time
response = await call_next(request)

View File

@@ -23,7 +23,7 @@ from openhands.server.data_models.conversation_info_result_set import (
ConversationInfoResultSet,
)
from openhands.server.dependencies import get_dependencies
from openhands.server.services.conversation import create_new_conversation
from openhands.server.services.conversation_service import create_new_conversation
from openhands.server.shared import (
ConversationStoreImpl,
config,
@@ -103,8 +103,10 @@ async def new_conversation(
if auth_type == AuthType.BEARER:
conversation_trigger = ConversationTrigger.REMOTE_API_KEY
if conversation_trigger == ConversationTrigger.REMOTE_API_KEY and not initial_user_msg:
if (
conversation_trigger == ConversationTrigger.REMOTE_API_KEY
and not initial_user_msg
):
return JSONResponse(
content={
'status': 'error',
@@ -193,19 +195,27 @@ async def search_conversations(
conversation_ids = set(
conversation.conversation_id for conversation in filtered_results
)
connection_ids_to_conversation_ids = await conversation_manager.get_connections(filter_to_sids=conversation_ids)
agent_loop_info = await conversation_manager.get_agent_loop_info(filter_to_sids=conversation_ids)
agent_loop_info_by_conversation_id = {info.conversation_id: info for info in agent_loop_info}
connection_ids_to_conversation_ids = await conversation_manager.get_connections(
filter_to_sids=conversation_ids
)
agent_loop_info = await conversation_manager.get_agent_loop_info(
filter_to_sids=conversation_ids
)
agent_loop_info_by_conversation_id = {
info.conversation_id: info for info in agent_loop_info
}
result = ConversationInfoResultSet(
results=await wait_all(
_get_conversation_info(
conversation=conversation,
num_connections=sum(
1 for conversation_id in connection_ids_to_conversation_ids.values()
1
for conversation_id in connection_ids_to_conversation_ids.values()
if conversation_id == conversation.conversation_id
),
agent_loop_info=agent_loop_info_by_conversation_id.get(conversation.conversation_id),
agent_loop_info=agent_loop_info_by_conversation_id.get(
conversation.conversation_id
),
)
for conversation in filtered_results
),
@@ -221,10 +231,16 @@ async def get_conversation(
) -> ConversationInfo | None:
try:
metadata = await conversation_store.get_metadata(conversation_id)
num_connections = len(await conversation_manager.get_connections(filter_to_sids={conversation_id}))
agent_loop_infos = await conversation_manager.get_agent_loop_info(filter_to_sids={conversation_id})
num_connections = len(
await conversation_manager.get_connections(filter_to_sids={conversation_id})
)
agent_loop_infos = await conversation_manager.get_agent_loop_info(
filter_to_sids={conversation_id}
)
agent_loop_info = agent_loop_infos[0] if agent_loop_infos else None
conversation_info = await _get_conversation_info(metadata, num_connections, agent_loop_info)
conversation_info = await _get_conversation_info(
metadata, num_connections, agent_loop_info
)
return conversation_info
except FileNotFoundError:
return None
@@ -268,11 +284,15 @@ async def _get_conversation_info(
selected_branch=conversation.selected_branch,
git_provider=conversation.git_provider,
status=(
agent_loop_info.status if agent_loop_info else ConversationStatus.STOPPED
agent_loop_info.status
if agent_loop_info
else ConversationStatus.STOPPED
),
num_connections=num_connections,
url=agent_loop_info.url if agent_loop_info else None,
session_api_key=agent_loop_info.session_api_key if agent_loop_info else None,
session_api_key=agent_loop_info.session_api_key
if agent_loop_info
else None,
)
except Exception as e:
logger.error(

View File

@@ -218,7 +218,9 @@ async def create_custom_secret(
) -> JSONResponse:
try:
existing_secrets = await secrets_store.load()
custom_secrets = dict(existing_secrets.custom_secrets) if existing_secrets else {}
custom_secrets = (
dict(existing_secrets.custom_secrets) if existing_secrets else {}
)
secret_name = incoming_secret.name
secret_value = incoming_secret.value
@@ -238,7 +240,9 @@ async def create_custom_secret(
# Create a new UserSecrets that preserves provider tokens
updated_user_secrets = UserSecrets(
custom_secrets=custom_secrets,
provider_tokens=existing_secrets.provider_tokens if existing_secrets else {},
provider_tokens=existing_secrets.provider_tokens
if existing_secrets
else {},
)
await secrets_store.store(updated_user_secrets)

View File

@@ -7,8 +7,8 @@ from fastapi import Request
from pydantic import SecretStr
from openhands.integrations.provider import PROVIDER_TOKEN_TYPE
from openhands.server.shared import server_config
from openhands.server.settings import Settings
from openhands.server.shared import server_config
from openhands.storage.data_models.user_secrets import UserSecrets
from openhands.storage.secrets.secrets_store import SecretsStore
from openhands.storage.settings.settings_store import SettingsStore

View File

@@ -137,7 +137,6 @@ class UserSecrets(BaseModel):
new_data['custom_secrets'] = secrets
return new_data
def set_event_stream_secrets(self, event_stream: EventStream) -> None:
"""
@@ -158,10 +157,9 @@ class UserSecrets(BaseModel):
return secrets
def get_custom_secrets_descriptions(self) -> dict[str, str]:
secrets = {}
for secret_name, secret in self.custom_secrets.items():
secrets[secret_name] = secret.description
return secrets
return secrets