Always provide full activation message upon calling activate_project

This is necessary, because some clients (e.g. Claude Desktop) will
reuse a single session across chats.

Resolves #1384
This commit is contained in:
Dominik Jain authored and Dominik Jain committed 2026-04-21 14:34:10 +02:00
1 parent 364c08c6e2
commit f0a3a279b7
3 files changed
+30 -9

No files matched your search

+2
View File
@@ -14,6 +14,8 @@ Status of the `main` branch. Changes prior to the next official version change w
`initial_instructions`). Now they are passed directly in the activation message (and excluded from a subsequent `initial_instructions` call).
- Fix: Project activation message was provided more than once for case of dynamic project activation followed
by `initial_instructions` #1372
- Always provide full activation message upon calling `activate_project` (even if project was already active in the same session) #1384
This is necessary, because some clients (e.g. Claude Desktop) will reuse a single session across chats.
- Security: Forbid `".."` in memory names to disallow accessing files outside dedicated memory directories
- Security: Add check for tool being read-only in the project server (previously only checked in `query_project` tool, i.e. client side)
- Usage reporting now also includes the name of the Serena context that is used
+6 -2
View File
@@ -800,9 +800,13 @@ class SerenaAgent:
proj = self._active_project
assert proj is not None, "A project must be active before calling this."
# if activation message was already provided in the current session, don't provide it again
# Note: The activation message is always returned in full, even if it was already provided in the current session,
# because some clients (e.g. Claude Desktop) will use the same session across multiple chats.
# So while we don't want the activation message to be additionally included in the system prompt
# (initial_instructions), an explicit project activation should always return it.
# (The check below deliberately left in place for documentation purposes, preventing a regression)
if self._project_prompt_status.is_project_activation_message_already_provided(session_id):
return "Project was already activated."
pass # no special handling
# provide basic project information (name, location, languages, encoding)
if proj.is_newly_created:
+22 -7
View File
@@ -728,14 +728,16 @@ class TestPromptProvision:
but not on subsequent calls within the same session. #1372
"""
project_name = "test_repo_python"
session1 = "session1"
session2 = "session2"
result1 = self._call_tool(serena_agent, InitialInstructionsTool, session_id="session1")
result1 = self._call_tool(serena_agent, InitialInstructionsTool, session_id=session1)
self._assert_activation_message(result1, project_name, present=True)
result2 = self._call_tool(serena_agent, InitialInstructionsTool, session_id="session2")
result2 = self._call_tool(serena_agent, InitialInstructionsTool, session_id=session2)
self._assert_activation_message(result2, project_name, present=True)
result3 = self._call_tool(serena_agent, InitialInstructionsTool, session_id="session1")
result3 = self._call_tool(serena_agent, InitialInstructionsTool, session_id=session1)
self._assert_activation_message(result3, project_name, present=False)
@pytest.mark.parametrize("serena_agent", [Language.PYTHON], indirect=True)
@@ -747,16 +749,18 @@ class TestPromptProvision:
"""
project_name1 = "test_repo_python"
project_name2 = "test_repo_java"
session1 = "session1"
session2 = "session2"
# the initial instructions must contain the project activation message for the first project
result1 = self._call_tool(serena_agent, InitialInstructionsTool, session_id="session1")
result1 = self._call_tool(serena_agent, InitialInstructionsTool, session_id=session1)
self._assert_activation_message(result1, project_name1, present=True)
# now activate another project which dynamically enables a new mode (no-onboarding)
reg_project = serena_agent.serena_config.get_registered_project(project_name2)
reg_project.project_config.default_modes = ["no-onboarding"]
expected_new_mode_message = "The onboarding process is not applied."
result2 = self._call_tool(serena_agent, ActivateProjectTool, project=project_name2, session_id="session1")
result2 = self._call_tool(serena_agent, ActivateProjectTool, project=project_name2, session_id=session1)
# the new mode's prompt must be included in the activation message
self._assert_activation_message(result2, project_name2, present=True)
@@ -765,16 +769,27 @@ class TestPromptProvision:
)
# the mode prompt must not be included in subsequent calls to the initial instructions tool within the same session
result3 = self._call_tool(serena_agent, InitialInstructionsTool, session_id="session1")
result3 = self._call_tool(serena_agent, InitialInstructionsTool, session_id=session1)
assert expected_new_mode_message not in result3, (
f"Expected new mode message '{expected_new_mode_message}' to not be included in subsequent calls, but it was found in result:\n{result3}"
)
# the mode prompt must be included in the initial instructions of a new session
result4 = self._call_tool(serena_agent, InitialInstructionsTool, session_id="session2")
result4 = self._call_tool(serena_agent, InitialInstructionsTool, session_id=session2)
assert expected_new_mode_message in result4, (
f"Expected new mode message '{expected_new_mode_message}' to be included in new session, but it was not found in result:\n{result4}"
)
# the initial instructions for the new session must also include the activation message for the project
self._assert_activation_message(result4, project_name2, present=True)
@pytest.mark.parametrize("serena_agent", [Language.PYTHON], indirect=True)
def test_activate_project_tool_always_returns_activation_message(self, serena_agent: SerenaAgent) -> None:
project_name = "test_repo_python"
session = "session1"
result1 = self._call_tool(serena_agent, ActivateProjectTool, project=project_name, session_id=session)
self._assert_activation_message(result1, project_name, present=True)
result2 = self._call_tool(serena_agent, ActivateProjectTool, project=project_name, session_id=session)
self._assert_activation_message(result2, project_name, present=True)