OpenHands / OpenHands/software-agent-sdk
GraySwan analyzer: guarantee system message first when history window drops the SystemPromptEvent
Nobody has claimed this yet.
- 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:
- Clip the window to always include the leading
SystemPromptEvent(e.g., compute a start index that keeps index 0). - Re-synthesize a minimal system message when the sliced window contains no
SystemPromptEvent(e.g., a short role description for the security analysis task). - Make
convert_events_to_openai_messagesresilient: 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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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