OpenHands / OpenHands/software-agent-sdk

GraySwan analyzer: guarantee system message first when history window drops the SystemPromptEvent

Open
#5,147 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

invariants
Dominant language
Python
Stars
1.1k
Forks
542
Avg merge
1d 19h
Merged PRs (30d)
137

Description

Problem

GraySwanAnalyzer.security_risk() in openhands-sdk/openhands/sdk/security/grayswan/analyzer.py converts a tail window of conversation events into OpenAI messages and sends them to the GraySwan API:

recent_events = self._events
if len(recent_events) > self.history_limit:        # history_limit default 20
    recent_events = recent_events[-self.history_limit:]

events_to_process: list[LLMConvertibleEvent] = list(recent_events) + [action]
openai_messages = convert_events_to_openai_messages(events_to_process)

convert_events_to_openai_messages() (openhands-sdk/openhands/sdk/security/grayswan/utils.py) only appends a {"role": "system", ...} entry when it encounters a SystemPromptEvent in the supplied events. Once the conversation exceeds history_limit events, the leading SystemPromptEvent (normally at index 0/1) is sliced off, and the rebuilt message list starts with a non-system message (user/assistant/tool) with no system role anywhere in the window.

This violates the repo convention that every LLM request starts with a system message (see parent tracking issue #5144).

Proposed change

Ensure the request always has a system lead-in even when the history window excludes the original SystemPromptEvent. Options:

  1. Clip the window to always include the leading SystemPromptEvent (e.g., compute a start index that keeps index 0).
  2. Re-synthesize a minimal system message when the sliced window contains no SystemPromptEvent (e.g., a short role description for the security analysis task).
  3. Make convert_events_to_openai_messages resilient: if no system message is present and the first message is not system, prepend a default system message.

Prefer the option that keeps the analyzer's bounded-history intent (20 events) while guaranteeing a system-first message list.

Parent issue: #5144


This issue was created by an AI agent (OpenHands) on behalf of juanmichelini.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in openhands-sdk/openhands/sdk/security/grayswan/analyzer.py at GraySwanAnalyzer.security_risk(), then inspect convert_events_to_openai_messages() in openhands-sdk/openhands/sdk/security/grayswan/utils.py. Trace the tail-window behavior and verify that a history exceeding history_limit still produces a bounded message list whose first entry has the system role.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
ai, security
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.