Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/rogue.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jobs:
echo "🚀 Starting AI agent..."

# Not using uv because it will reinstall the sdk from pypi
source .venv/bin/activate && python examples/tshirt_store_agent --host 0.0.0.0 --port 10001 &
source .venv/bin/activate && uv run python -m examples.tshirt_store_agent --host 0.0.0.0 --port 10001 &
AGENT_PID=$!
echo "Agent started with PID: $AGENT_PID"
trap 'echo "🛑 Stopping agent..."; kill $AGENT_PID' EXIT
Expand Down
7 changes: 6 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ This file provides instructions for AI agents working in this repository.

## Dependencies

- **Install**: `uv sync --dev --examples`
- **Install**: `uv sync --all-groups`
- **Install (specific groups)**: `uv sync --group dev --group examples`

## Build, Lint, and Test

Expand Down Expand Up @@ -42,10 +43,14 @@ This file provides instructions for AI agents working in this repository.

- **CLI**: `uv run python -m rogue`
- **UI**: `uv run gradio rogue/ui/app.py`
- **With Example Agent**: `uv run rogue-ai --example=tshirt_store` (starts rogue with the t-shirt store example agent running on port 10001)

## Running the examples

- **T-Shirt Store**: `uv run python -m examples.tshirt_store_agent`
- **T-Shirt Store (via script)**: `uv run rogue-ai-example-tshirt` (or `uvx rogue-ai-example-tshirt` if installed)
- **T-Shirt Store (all-in-one)**: `uv run rogue-ai --example=tshirt_store` (starts rogue with the agent running automatically)
- Custom host/port: `uv run rogue-ai --example=tshirt_store --example-host localhost --example-port 10001`
- **T-Shirt Store (LangGraph)**: `uv run python -m examples.tshirt_store_langgraph_agent`

## Running the evaluator
Expand Down
40 changes: 35 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,12 +178,36 @@ Navigate to the URL displayed in your terminal (usually `http://127.0.0.1:7860`)

This repository includes a simple example agent that sells T-shirts. You can use it to see Rogue in action.

1. **Install exmaple dependencies:**
### Option 1: All-in-One (Recommended)

The easiest way to try Rogue with the example agent is to use the `--example` flag, which starts both Rogue and the example agent automatically:

```bash
uvx rogue-ai --example=tshirt_store
```

This will:

- Start the T-Shirt Store agent on `http://localhost:10001`
- Launch Rogue with the TUI interface
- Automatically clean up when you exit

You can customize the host and port:

```bash
uvx rogue-ai --example=tshirt_store --example-host localhost --example-port 10001
```

### Option 2: Manual Setup

If you prefer to run the example agent separately:

1. **Install example dependencies:**

If you are using uv:

```bash
uv sync --group examples
uv sync --group examples
```

or, if you are using pip:
Expand All @@ -197,13 +221,19 @@ This repository includes a simple example agent that sells T-shirts. You can use
If you are using uv:

```bash
uv run examples/tshirt_store_agent
uv run python -m examples.tshirt_store_agent
```

Or using the script command:

```bash
uv run rogue-ai-example-tshirt
```

If not:
Or if installed:

```bash
python examples/tshirt_store_agent
uvx rogue-ai-example-tshirt
```

This will start the agent on `http://localhost:10001`.
Expand Down
4 changes: 2 additions & 2 deletions examples/tshirt_store_agent/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService

from tshirt_store_agent import create_tshirt_store_agent # type: ignore
from tshirt_store_agent_executor import TShirtStoreAgentExecutor
from .tshirt_store_agent import create_tshirt_store_agent
from .tshirt_store_agent_executor import TShirtStoreAgentExecutor
Comment on lines +19 to +20
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify package structure to resolve ImportError.

The pipeline failure indicates ImportError: attempted relative import with no known parent package on line 19. Relative imports require that examples/tshirt_store_agent/ is a proper Python package with an __init__.py file.

Ensure the following:

  1. Verify that examples/__init__.py and examples/tshirt_store_agent/__init__.py exist (even if empty) to establish the package hierarchy.
  2. The module should be executed as a package (python -m examples.tshirt_store_agent) or via the new script entry (rogue-ai-example-tshirt), not as a standalone script (python examples/tshirt_store_agent/__main__.py).

Run this script to verify the package structure:


🏁 Script executed:

#!/bin/bash
# Description: Check for required __init__.py files in the examples package hierarchy

# Check for __init__.py files
echo "Checking for __init__.py files..."
for path in "examples/__init__.py" "examples/tshirt_store_agent/__init__.py"; do
  if [ -f "$path" ]; then
    echo "✓ Found: $path"
  else
    echo "✗ Missing: $path"
    echo "  This file is required for relative imports to work."
  fi
done

# Check how tests are running the example
echo -e "\nChecking test execution method..."
rg -n "examples/tshirt_store_agent/__main__.py" -g "*.{yml,yaml,py,sh}"

Length of output: 203


Add missing examples/__init__.py to fix relative imports.
The top‐level examples directory needs an (even empty) __init__.py so that from .tshirt_store_agent import … works. After adding it, run the agent via python -m examples.tshirt_store_agent or the CLI entry, not by executing __main__.py directly.

🧰 Tools
🪛 GitHub Actions: Rogue

[error] 19-19: ImportError: attempted relative import with no known parent package.

🤖 Prompt for AI Agents
In examples/tshirt_store_agent/__main__.py around lines 19-20: the module uses
relative imports (from .tshirt_store_agent ...) which fail unless the examples
package is a proper package; add an __init__.py file (can be empty) to the
top-level examples directory so Python recognizes it as a package, then run the
agent as a module (python -m examples.tshirt_store_agent) or via the CLI entry
rather than executing __main__.py directly.


load_dotenv()

Expand Down
27 changes: 26 additions & 1 deletion packages/tui/internal/tui/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ type Model struct {
eventsViewport components.Viewport
summaryViewport components.Viewport
reportViewport components.Viewport
helpViewport components.Viewport
focusedViewport int // 0 = events, 1 = summary
eventsAutoScroll bool // Track if events should auto-scroll to bottom

Expand Down Expand Up @@ -273,7 +274,7 @@ func (a *App) Run() error {
Theme: "aura",
APIKeys: make(map[string]string),
},
version: "v0.1.5",
version: "v0.1.6",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify version consistency across the codebase.

The version has been updated to "v0.1.6". Ensure this is consistent with other version references (e.g., package.json, setup.py, README, etc.).

Run the following script to check for version references:


🏁 Script executed:

#!/bin/bash
# Search for version references in common files
rg -n --type-add 'config:*.{json,toml,yaml,yml}' --type config -C2 "version.*0\.1\.[0-9]"
rg -n --type py -C2 "version.*0\.1\.[0-9]"
rg -n --type md -C2 "version.*0\.1\.[0-9]|v0\.1\.[0-9]"

Length of output: 3411


🏁 Script executed:

#!/bin/bash
# List version fields from all package.json files
rg -n '"version"\s*:' -g "package.json"

Length of output: 239


Sync Python SDK version

  • sdks/python/pyproject.toml still declares version = "0.1.4"; bump to "0.1.6" to match root and CLI.
  • Root pyproject.toml and rogue/init.py are at 0.1.6; Go TUI code at v0.1.6.
  • package.json files remain at 1.0.0—confirm whether the Node SDK/examples should follow their own 1.x scheme or align with 0.1.x.
🤖 Prompt for AI Agents
packages/tui/internal/tui/app.go around line 277: the Go TUI hardcodes version
"v0.1.6" while the Python SDK (sdks/python/pyproject.toml) is still at "0.1.4";
update sdks/python/pyproject.toml to version = "0.1.6" to match root and CLI,
and verify sdks/python/rogue/__init__.py (if present) also reflects 0.1.6;
additionally confirm whether Node package.json files should remain on their 1.x
scheme or be aligned—if Node SDK/examples use a separate major version strategy,
leave them as-is and document the divergence, otherwise bump their version to
match the 0.1.6 scheme.

commandInput: components.NewCommandInput(),
scenarioEditor: components.NewScenarioEditor(),

Expand All @@ -286,6 +287,7 @@ func (a *App) Run() error {
eventsViewport: components.NewViewport(1, 80, 20),
summaryViewport: components.NewViewport(2, 80, 20),
reportViewport: components.NewViewport(3, 80, 15),
helpViewport: components.NewViewport(4, 80, 20),
focusedViewport: 0, // Start with events viewport focused
eventsAutoScroll: true, // Start with auto-scroll enabled
}
Expand Down Expand Up @@ -423,6 +425,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.eventsViewport.SetSize(viewportWidth, viewportHeight)
m.summaryViewport.SetSize(viewportWidth, viewportHeight)
m.reportViewport.SetSize(viewportWidth, viewportHeight)
m.helpViewport.SetSize(viewportWidth, viewportHeight)
return m, nil

case AutoRefreshMsg:
Expand Down Expand Up @@ -1226,6 +1229,28 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}
}

// Help screen keys
if m.currentScreen == HelpScreen {
switch msg.String() {
case "home":
// Go to top of help content
m.helpViewport.GotoTop()
return m, nil
case "end":
// Go to bottom of help content
m.helpViewport.GotoBottom()
return m, nil
default:
// Update the help viewport for scrolling
helpViewportPtr, cmd := m.helpViewport.Update(msg)
if cmd != nil {
cmds = append(cmds, cmd)
}
m.helpViewport = *helpViewportPtr
return m, tea.Batch(cmds...)
}
}

// Let the command input handle non-shortcut keys if it's focused
if m.commandInput.IsFocused() {
m.commandInput, cmd = m.commandInput.Update(msg)
Expand Down
106 changes: 80 additions & 26 deletions packages/tui/internal/tui/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,33 @@ import (
"github.com/rogue/tui/internal/theme"
)

// RenderHelp renders the help screen
// RenderHelp renders the help screen with viewport for scrollable content
func (m Model) RenderHelp() string {
t := theme.CurrentTheme()

// Main container style
containerStyle := lipgloss.NewStyle().
Border(lipgloss.RoundedBorder()).
BorderForeground(t.Border()).
BorderBackground(t.BackgroundPanel()).
Padding(1, 2).
Width(m.width - 4).
Height(m.height - 4).
Background(t.BackgroundPanel())
// Main container style with full width and height background
mainStyle := lipgloss.NewStyle().
Width(m.width).
Height(m.height - 1).
Background(t.Background())

// Title style
titleStyle := lipgloss.NewStyle().
Foreground(t.Primary()).
Background(t.BackgroundPanel()).
Background(t.Background()).
Bold(true).
Width(m.width).
Align(lipgloss.Center).
Width(m.width - 8)
Padding(1, 0)

header := titleStyle.Render("❓ Rogue")

// Section header style
sectionHeaderStyle := lipgloss.NewStyle().
Foreground(t.Accent()).
Background(t.BackgroundPanel()).
Bold(true).
MarginTop(1).
MarginBottom(1)
MarginTop(1)

// Content style
contentStyle := lipgloss.NewStyle().
Expand All @@ -60,12 +58,9 @@ func (m Model) RenderHelp() string {
Background(t.BackgroundPanel()).
Bold(true)

// Build content sections
// Build content sections for viewport
var sections []string

// Title
sections = append(sections, titleStyle.Render("❓ Rogue"))

// About section
sections = append(sections, sectionHeaderStyle.Render("📖 About Rogue"))
aboutText := `Rogue is a powerful tool designed to evaluate the performance, compliance, and reliability
Expand Down Expand Up @@ -117,15 +112,74 @@ Key Features:
4. View Report - Review detailed Markdown report with findings and recommendations`
sections = append(sections, contentStyle.Render(workflowText))

// Footer
footerStyle := lipgloss.NewStyle().
Foreground(t.TextMuted()).
helpContent := strings.Join(sections, "\n")

// Calculate viewport dimensions
viewportWidth := m.width - 8
viewportHeight := m.height - 6

// Create a temporary copy of the viewport to avoid modifying the original
viewport := m.helpViewport
viewport.SetSize(viewportWidth-4, viewportHeight-4)
viewport.SetContent(helpContent)
Comment on lines +117 to +124
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Flag viewport sizing inconsistency between render and resize handler.

The viewport is sized twice with different dimensions:

  • In the window resize handler (app.go:428): m.helpViewport.SetSize(msg.Width - 4, msg.Height - 8)
  • In this render function (line 123): viewport.SetSize(viewportWidth-4, viewportHeight-4) where viewportWidth = m.width - 8, resulting in m.width - 12

This inconsistency could cause visual glitches or unexpected behavior. Consider either:

  1. Using the viewport's already-set size from the resize handler instead of resizing in the render function, or
  2. Ensuring consistent sizing calculations in both places

Apply this approach to simplify and use the resize handler's dimensions:

-	// Calculate viewport dimensions
-	viewportWidth := m.width - 8
-	viewportHeight := m.height - 6
-
 	// Create a temporary copy of the viewport to avoid modifying the original
 	viewport := m.helpViewport
-	viewport.SetSize(viewportWidth-4, viewportHeight-4)
 	viewport.SetContent(helpContent)
+
+	// Get dimensions from the already-sized viewport
+	viewportWidth := viewport.Width + 8  // Add back the margins/borders
+	viewportHeight := viewport.Height + 6
🤖 Prompt for AI Agents
In packages/tui/internal/tui/help.go around lines 117 to 124, the viewport is
being resized in render using calculations (viewportWidth-4, viewportHeight-4)
that conflict with the resize handler (app.go:428) which sets m.helpViewport
size to msg.Width-4 by msg.Height-8; to fix, stop recomputing and overriding the
viewport size in the render path: remove the SetSize call here and use the
already-sized m.helpViewport (or, if a copy is needed, copy the viewport without
altering its size or query and reuse its existing dimensions), then only call
SetContent(helpContent) on that viewport copy so sizing is exclusively handled
by the resize handler.


// Style the viewport with border
viewportStyle := lipgloss.NewStyle().
Height(viewportHeight).
Border(lipgloss.RoundedBorder()).
BorderForeground(t.Border()).
BorderBackground(t.BackgroundPanel()).
Background(t.BackgroundPanel())

// Apply viewport styling
viewport.Style = lipgloss.NewStyle().
Foreground(t.Text()).
Background(t.BackgroundPanel()).
Width(viewportWidth-4).
Height(viewportHeight-4).
Padding(1, 2)

// Help text style
helpStyle := lipgloss.NewStyle().
Foreground(t.TextMuted()).
Background(t.Background()).
Width(m.width).
Align(lipgloss.Center).
MarginTop(2).
Width(m.width - 8)
sections = append(sections, footerStyle.Render("Press Esc to return to dashboard"))
Padding(0, 1)

content := strings.Join(sections, "\n")
return containerStyle.Render(content)
// Include scroll indicators in help text
scrollInfo := ""
if !viewport.AtTop() || !viewport.AtBottom() {
scrollInfo = "↑↓ Scroll "
}
helpText := helpStyle.Render(scrollInfo + "Esc Back to Dashboard")

// Create the viewport content area
viewportContent := viewportStyle.Render(viewport.View())

// Center the viewport in the available space
contentArea := lipgloss.NewStyle().
Width(m.width).
Height(viewportHeight).
Background(t.Background())

centeredViewport := contentArea.Render(
lipgloss.Place(
m.width,
viewportHeight,
lipgloss.Center,
lipgloss.Top,
viewportContent,
lipgloss.WithWhitespaceStyle(lipgloss.NewStyle().Background(t.Background())),
),
)

// Combine all sections
fullLayout := lipgloss.JoinVertical(lipgloss.Left,
header,
centeredViewport,
helpText,
)

return mainStyle.Render(fullLayout)
}
19 changes: 10 additions & 9 deletions packages/tui/internal/tui/report_view.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func (m Model) renderReport() string {
// Main container style with full width and height background
mainStyle := lipgloss.NewStyle().
Width(m.width).
Height(m.height - 12).
Height(m.height - 1). // -1 for footer
Background(t.Background())

// Title style
Expand Down Expand Up @@ -58,17 +58,18 @@ func (m Model) renderReport() string {
}

// Calculate viewport dimensions
viewportWidth := m.width - 8 // Leave margins
viewportHeight := m.height - 8 // title(3) + help(1) + margins(4)
// Reserve space for: header (3 lines) + help text (1 line) + margins (2 lines)
viewportWidth := m.width - 8
viewportHeight := m.height - 6

// Create a temporary copy of the viewport to avoid modifying the original
viewport := m.reportViewport
viewport.SetSize(viewportWidth, viewportHeight-2)
viewport.SetSize(viewportWidth-4, viewportHeight-4) // Account for border and padding
viewport.SetContent(reportContent)

// Style the viewport with border
viewportStyle := lipgloss.NewStyle().
Height(viewportHeight - 8).
Height(viewportHeight).
Border(lipgloss.RoundedBorder()).
BorderForeground(t.Border()).
BorderBackground(t.BackgroundPanel()).
Expand All @@ -78,8 +79,8 @@ func (m Model) renderReport() string {
viewport.Style = lipgloss.NewStyle().
Foreground(t.Text()).
Background(t.BackgroundPanel()).
Width(viewportWidth).
Height(viewportHeight-8).
Width(viewportWidth-4).
Height(viewportHeight-4).
Padding(1, 2)

// Help text style
Expand All @@ -103,13 +104,13 @@ func (m Model) renderReport() string {
// Center the viewport in the available space
contentArea := lipgloss.NewStyle().
Width(m.width).
Height(viewportHeight - 8).
Height(viewportHeight).
Background(t.Background())

centeredViewport := contentArea.Render(
lipgloss.Place(
m.width,
viewportHeight-8,
viewportHeight,
lipgloss.Center,
lipgloss.Top,
viewportContent,
Expand Down
Loading
Loading