mirror of
https://github.com/All-Hands-AI/OpenHands.git
synced 2026-01-09 14:57:59 -05:00
Feat: Add current working directory to LLM instructions (#9718)
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{% if repository_info %}
|
||||
<REPOSITORY_INFO>
|
||||
At the user's request, repository {{ repository_info.repo_name }} has been cloned to the current working directory {{ repository_info.repo_directory }}.
|
||||
At the user's request, repository {{ repository_info.repo_name }} has been cloned to {{ repository_info.repo_directory }} in the current working directory.
|
||||
</REPOSITORY_INFO>
|
||||
{% endif %}
|
||||
{% if repository_instructions -%}
|
||||
@@ -10,6 +10,9 @@ At the user's request, repository {{ repository_info.repo_name }} has been clone
|
||||
{% endif %}
|
||||
{% if runtime_info -%}
|
||||
<RUNTIME_INFORMATION>
|
||||
{% if runtime_info.working_dir %}
|
||||
The current working directory is {{ runtime_info.working_dir }}
|
||||
{% endif %}
|
||||
{% if runtime_info.available_hosts %}
|
||||
The user has access to the following hosts for accessing a web application,
|
||||
each of which has a corresponding port:
|
||||
|
||||
@@ -10,6 +10,9 @@ At the user's request, repository {{ repository_info.repo_name }} has been clone
|
||||
{% endif %}
|
||||
{% if runtime_info and (runtime_info.additional_agent_instructions or runtime_info.date) -%}
|
||||
<RUNTIME_INFORMATION>
|
||||
{% if runtime_info.working_dir %}
|
||||
The current working directory is {{ runtime_info.working_dir }}
|
||||
{% endif %}
|
||||
{% if runtime_info.additional_agent_instructions %}
|
||||
{{ runtime_info.additional_agent_instructions }}
|
||||
{% endif %}
|
||||
|
||||
@@ -277,6 +277,7 @@ async def run_session(
|
||||
selected_repository=config.sandbox.selected_repo,
|
||||
repo_directory=repo_directory,
|
||||
conversation_instructions=conversation_instructions,
|
||||
working_dir=os.getcwd(),
|
||||
)
|
||||
|
||||
# Add MCP tools to the agent
|
||||
|
||||
@@ -6,6 +6,7 @@ from pydantic.fields import FieldInfo
|
||||
|
||||
OH_DEFAULT_AGENT = 'CodeActAgent'
|
||||
OH_MAX_ITERATIONS = 500
|
||||
DEFAULT_WORKSPACE_MOUNT_PATH_IN_SANDBOX = '/workspace'
|
||||
|
||||
|
||||
def get_field_info(field: FieldInfo) -> dict[str, Any]:
|
||||
|
||||
@@ -7,6 +7,7 @@ from openhands.core import logger
|
||||
from openhands.core.config.agent_config import AgentConfig
|
||||
from openhands.core.config.cli_config import CLIConfig
|
||||
from openhands.core.config.config_utils import (
|
||||
DEFAULT_WORKSPACE_MOUNT_PATH_IN_SANDBOX,
|
||||
OH_DEFAULT_AGENT,
|
||||
OH_MAX_ITERATIONS,
|
||||
model_defaults_to_dict,
|
||||
@@ -78,10 +79,13 @@ class OpenHandsConfig(BaseModel):
|
||||
description='API key for Tavily search engine (https://tavily.com/). Required for search functionality.',
|
||||
)
|
||||
|
||||
workspace_base: str | None = Field(default=None)
|
||||
workspace_mount_path_in_sandbox: str = Field(
|
||||
default=DEFAULT_WORKSPACE_MOUNT_PATH_IN_SANDBOX
|
||||
)
|
||||
|
||||
# Deprecated parameters - will be removed in a future version
|
||||
workspace_base: str | None = Field(default=None, deprecated=True)
|
||||
workspace_mount_path: str | None = Field(default=None, deprecated=True)
|
||||
workspace_mount_path_in_sandbox: str = Field(default='/workspace', deprecated=True)
|
||||
workspace_mount_rewrite: str | None = Field(default=None, deprecated=True)
|
||||
# End of deprecated parameters
|
||||
|
||||
|
||||
@@ -130,6 +130,7 @@ async def run_controller(
|
||||
selected_repository=config.sandbox.selected_repo,
|
||||
repo_directory=repo_directory,
|
||||
conversation_instructions=conversation_instructions,
|
||||
working_dir=config.workspace_mount_path_in_sandbox,
|
||||
)
|
||||
|
||||
# Add MCP tools to the agent
|
||||
|
||||
@@ -12,6 +12,7 @@ from openhands.controller.state.state import State
|
||||
from openhands.core.config import (
|
||||
OpenHandsConfig,
|
||||
)
|
||||
from openhands.core.config.config_utils import DEFAULT_WORKSPACE_MOUNT_PATH_IN_SANDBOX
|
||||
from openhands.core.logger import openhands_logger as logger
|
||||
from openhands.events import EventStream
|
||||
from openhands.events.event import Event
|
||||
@@ -140,6 +141,7 @@ def create_memory(
|
||||
repo_directory: str | None = None,
|
||||
status_callback: Callable | None = None,
|
||||
conversation_instructions: str | None = None,
|
||||
working_dir: str = DEFAULT_WORKSPACE_MOUNT_PATH_IN_SANDBOX,
|
||||
) -> Memory:
|
||||
"""Create a memory for the agent to use.
|
||||
|
||||
@@ -162,7 +164,7 @@ def create_memory(
|
||||
|
||||
if runtime:
|
||||
# sets available hosts
|
||||
memory.set_runtime_info(runtime, {})
|
||||
memory.set_runtime_info(runtime, {}, working_dir)
|
||||
|
||||
# loads microagents from repo/.openhands/microagents
|
||||
microagents: list[BaseMicroagent] = runtime.get_microagents_from_selected_repo(
|
||||
|
||||
@@ -76,6 +76,7 @@ class RecallObservation(Observation):
|
||||
date: str = ''
|
||||
custom_secrets_descriptions: dict[str, str] = field(default_factory=dict)
|
||||
conversation_instructions: str = ''
|
||||
working_dir: str = ''
|
||||
|
||||
# knowledge
|
||||
microagent_knowledge: list[MicroagentKnowledge] = field(default_factory=list)
|
||||
|
||||
@@ -524,11 +524,13 @@ class ConversationMemory:
|
||||
additional_agent_instructions=obs.additional_agent_instructions,
|
||||
date=date,
|
||||
custom_secrets_descriptions=obs.custom_secrets_descriptions,
|
||||
working_dir=obs.working_dir,
|
||||
)
|
||||
else:
|
||||
runtime_info = RuntimeInfo(
|
||||
date=date,
|
||||
custom_secrets_descriptions=obs.custom_secrets_descriptions,
|
||||
working_dir=obs.working_dir,
|
||||
)
|
||||
|
||||
conversation_instructions = None
|
||||
|
||||
@@ -198,6 +198,7 @@ class Memory:
|
||||
conversation_instructions=self.conversation_instructions.content
|
||||
if self.conversation_instructions is not None
|
||||
else '',
|
||||
working_dir=self.runtime_info.working_dir if self.runtime_info else '',
|
||||
)
|
||||
return obs
|
||||
return None
|
||||
@@ -332,6 +333,7 @@ class Memory:
|
||||
self,
|
||||
runtime: Runtime,
|
||||
custom_secrets_descriptions: dict[str, str],
|
||||
working_dir: str,
|
||||
) -> None:
|
||||
"""Store runtime info (web hosts, ports, etc.)."""
|
||||
# e.g. { '127.0.0.1': 8080 }
|
||||
@@ -344,11 +346,13 @@ class Memory:
|
||||
additional_agent_instructions=runtime.additional_agent_instructions,
|
||||
date=date,
|
||||
custom_secrets_descriptions=custom_secrets_descriptions,
|
||||
working_dir=working_dir,
|
||||
)
|
||||
else:
|
||||
self.runtime_info = RuntimeInfo(
|
||||
date=date,
|
||||
custom_secrets_descriptions=custom_secrets_descriptions,
|
||||
working_dir=working_dir,
|
||||
)
|
||||
|
||||
def set_conversation_instructions(
|
||||
|
||||
@@ -154,6 +154,7 @@ class AgentSession:
|
||||
repo_directory=repo_directory,
|
||||
conversation_instructions=conversation_instructions,
|
||||
custom_secrets_descriptions=custom_secrets_handler.get_custom_secrets_descriptions(),
|
||||
working_dir=config.workspace_mount_path_in_sandbox,
|
||||
)
|
||||
|
||||
# NOTE: this needs to happen before controller is created
|
||||
@@ -464,6 +465,7 @@ class AgentSession:
|
||||
repo_directory: str | None,
|
||||
conversation_instructions: str | None,
|
||||
custom_secrets_descriptions: dict[str, str],
|
||||
working_dir: str,
|
||||
) -> Memory:
|
||||
memory = Memory(
|
||||
event_stream=self.event_stream,
|
||||
@@ -473,7 +475,9 @@ class AgentSession:
|
||||
|
||||
if self.runtime:
|
||||
# sets available hosts and other runtime info
|
||||
memory.set_runtime_info(self.runtime, custom_secrets_descriptions)
|
||||
memory.set_runtime_info(
|
||||
self.runtime, custom_secrets_descriptions, working_dir
|
||||
)
|
||||
memory.set_conversation_instructions(conversation_instructions)
|
||||
|
||||
# loads microagents from repo/.openhands/microagents
|
||||
|
||||
@@ -15,6 +15,7 @@ class RuntimeInfo:
|
||||
available_hosts: dict[str, int] = field(default_factory=dict)
|
||||
additional_agent_instructions: str = ''
|
||||
custom_secrets_descriptions: dict[str, str] = field(default_factory=dict)
|
||||
working_dir: str = ''
|
||||
|
||||
|
||||
@dataclass
|
||||
|
||||
@@ -389,7 +389,7 @@ async def test_custom_secrets_descriptions():
|
||||
}
|
||||
|
||||
# Set runtime info with custom secrets
|
||||
memory.set_runtime_info(mock_runtime, custom_secrets)
|
||||
memory.set_runtime_info(mock_runtime, custom_secrets, '/workspace')
|
||||
|
||||
# Set repository info
|
||||
memory.set_repository_info('test-owner/test-repo', '/workspace/test-repo')
|
||||
@@ -448,6 +448,7 @@ def test_custom_secrets_descriptions_serialization(prompt_dir):
|
||||
available_hosts={'test-host.example.com': 8080},
|
||||
additional_agent_instructions='Test instructions',
|
||||
custom_secrets_descriptions=custom_secrets,
|
||||
working_dir='/workspace',
|
||||
)
|
||||
|
||||
# Create a RepositoryInfo
|
||||
|
||||
@@ -242,6 +242,7 @@ def test_microagent_observation_serialization():
|
||||
'recall_type': 'workspace_context',
|
||||
'repo_name': 'some_repo_name',
|
||||
'repo_directory': 'some_repo_directory',
|
||||
'working_dir': '',
|
||||
'runtime_hosts': {'host1': 8080, 'host2': 8081},
|
||||
'repo_instructions': 'complex_repo_instructions',
|
||||
'additional_agent_instructions': 'You know it all about this runtime',
|
||||
@@ -265,6 +266,7 @@ def test_microagent_observation_microagent_knowledge_serialization():
|
||||
'repo_directory': '',
|
||||
'repo_instructions': '',
|
||||
'runtime_hosts': {},
|
||||
'working_dir': '',
|
||||
'additional_agent_instructions': '',
|
||||
'custom_secrets_descriptions': {},
|
||||
'conversation_instructions': 'additional_context',
|
||||
|
||||
@@ -236,6 +236,7 @@ Today's date is {{ runtime_info.date }}
|
||||
date='02/12/1232',
|
||||
available_hosts={'example.com': 8080},
|
||||
additional_agent_instructions='You know everything about this runtime.',
|
||||
working_dir='/workspace',
|
||||
)
|
||||
repo_instructions = 'This repository contains important code.'
|
||||
|
||||
|
||||
Reference in New Issue
Block a user