Feat: Add current working directory to LLM instructions (#9718)

This commit is contained in:
Tim O'Farrell
2025-07-16 15:10:03 -06:00
committed by GitHub
parent fba2218760
commit b057af8d63
15 changed files with 37 additions and 6 deletions

View File

@@ -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:

View File

@@ -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 %}

View File

@@ -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

View File

@@ -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]:

View File

@@ -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

View File

@@ -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

View File

@@ -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(

View File

@@ -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)

View File

@@ -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

View File

@@ -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(

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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',

View File

@@ -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.'