From d326242667d9ac994dcc07a75112ad0a2d8d9adf Mon Sep 17 00:00:00 2001 From: Ed_ Date: Mon, 23 Feb 2026 19:20:24 -0500 Subject: [PATCH] feat(simulation): implement UserSimAgent for human-like interaction --- simulation/user_agent.py | 47 ++++++++++++++++++++++++++++++++++++++++ tests/test_user_agent.py | 22 +++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 simulation/user_agent.py create mode 100644 tests/test_user_agent.py diff --git a/simulation/user_agent.py b/simulation/user_agent.py new file mode 100644 index 0000000..6c661e5 --- /dev/null +++ b/simulation/user_agent.py @@ -0,0 +1,47 @@ +import time +import random +import ai_client + +class UserSimAgent: + def __init__(self, hook_client, model="gemini-2.0-flash"): + self.hook_client = hook_client + self.model = model + self.system_prompt = ( + "You are a software engineer testing an AI coding assistant called 'Manual Slop'. " + "You want to build a small Python project and verify the assistant's capabilities. " + "Keep your responses concise and human-like. " + "Do not use markdown blocks for your main message unless you are providing code." + ) + + def generate_response(self, conversation_history): + """ + Generates a human-like response based on the conversation history. + conversation_history: list of dicts with 'role' and 'content' + """ + # Format history for ai_client + # ai_client expects md_content and user_message. + # It handles its own internal history. + # We want the 'User AI' to have context of what the 'Assistant AI' said. + + # For now, let's just use the last message from Assistant as the prompt. + last_ai_msg = "" + for entry in reversed(conversation_history): + if entry.get('role') == 'AI': + last_ai_msg = entry.get('content', '') + break + + # We need to set a custom system prompt for the User Simulator + ai_client.set_custom_system_prompt(self.system_prompt) + + # We'll use a blank md_content for now as the 'User' doesn't need to read its own files + # via the same mechanism, but we could provide it if needed. + response = ai_client.send(md_content="", user_message=last_ai_msg) + return response + + def perform_action_with_delay(self, action_func, *args, **kwargs): + """ + Executes an action with a human-like delay. + """ + delay = random.uniform(0.5, 2.0) + time.sleep(delay) + return action_func(*args, **kwargs) diff --git a/tests/test_user_agent.py b/tests/test_user_agent.py new file mode 100644 index 0000000..a2584d9 --- /dev/null +++ b/tests/test_user_agent.py @@ -0,0 +1,22 @@ +import pytest +import sys +import os + +# Ensure project root is in path for imports +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) + +from simulation.user_agent import UserSimAgent + +def test_user_agent_instantiation(): + agent = UserSimAgent(hook_client=None) + assert agent is not None + +def test_perform_action_with_delay(): + agent = UserSimAgent(hook_client=None) + called = False + def action(): + nonlocal called + called = True + + agent.perform_action_with_delay(action) + assert called is True