fix: use system role for user-idle prompt injections

The UserIdleHandler injected its "are you still there?" and disconnect
prompts as role="user" messages. These are agent-side directives, not
user utterances, so they should be injected as role="system" to avoid
polluting the conversation transcript with fake user turns and to read
correctly by the LLM. Updated the realtime append tests to match.

Also forward ports 3000 (UI) and 8000 (API) in the devcontainer so the
running services are reachable from the host.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Mohamed Mamdouh 2026-06-12 13:39:19 +01:00
parent 97d7103480
commit b5a192557b
3 changed files with 7 additions and 5 deletions

View file

@ -24,6 +24,8 @@
"postCreateCommand": "bash .devcontainer/scripts/post-create.sh",
"postStartCommand": "bash .devcontainer/scripts/post-start.sh",
"forwardPorts": [
3000,
8000,
5432,
6379,
9000,

View file

@ -46,14 +46,14 @@ class UserIdleHandler:
if self._retry_count == 1:
message = {
"role": "user",
"role": "system",
"content": "The user has been quiet. Politely and briefly ask if they're still there in the language that the user has been speaking so far.",
}
await aggregator.push_frame(LLMMessagesAppendFrame([message], run_llm=True))
return
message = {
"role": "user",
"role": "system",
"content": "The user has been quiet. We will be disconnecting the call now. Wish them a good day in the language that the user has been speaking so far.",
}
await aggregator.push_frame(LLMMessagesAppendFrame([message], run_llm=True))

View file

@ -20,7 +20,7 @@ async def test_openai_realtime_messages_append_frame_sends_conversation_item():
await service._handle_messages_append(
LLMMessagesAppendFrame(
[{"role": "user", "content": "Are you still there?"}],
[{"role": "system", "content": "Are you still there?"}],
run_llm=True,
)
)
@ -28,7 +28,7 @@ async def test_openai_realtime_messages_append_frame_sends_conversation_item():
service.send_client_event.assert_awaited_once()
event = service.send_client_event.await_args.args[0]
assert isinstance(event, events.ConversationItemCreateEvent)
assert event.item.role == "user"
assert event.item.role == "system"
assert event.item.type == "message"
assert event.item.content == [
events.ItemContent(type="input_text", text="Are you still there?")
@ -53,7 +53,7 @@ async def test_user_idle_handler_uses_realtime_append_path():
assert frame.run_llm is True
assert frame.messages == [
{
"role": "user",
"role": "system",
"content": "The user has been quiet. Politely and briefly ask if they're still there in the language that the user has been speaking so far.",
}
]