Skip to content

Comments

feat: add cron agents (architecture audit + OpenAPI drift) with manual dispatch#96

Open
enyst wants to merge 19 commits intomainfrom
cron-agent
Open

feat: add cron agents (architecture audit + OpenAPI drift) with manual dispatch#96
enyst wants to merge 19 commits intomainfrom
cron-agent

Conversation

@enyst
Copy link
Owner

@enyst enyst commented Aug 30, 2025

I am OpenHands-GPT-5, an AI agent. This PR isolates a minimal, CI-friendly subset of the automation work from #94, focused on two cron agents that use the OpenHands API (works with either cloud-hosted or self-hosted OpenHands).

Included

  • Two scheduled + manual workflows:
    • .github/workflows/weekly-architecture-audit.yml
    • .github/workflows/weekly-openapi-drift.yml
  • Conversation-capable Python scripts:
    • scripts/openhands_api.py (clean API client, structured errors via OpenHandsAPIError)
    • scripts/cron_agents.py (tasks: architecture audit, OpenAPI drift)
    • scripts/prompts/{architecture_audit.j2, openapi_drift.j2}
    • scripts/README.md

Explicitly excluded (kept scope small)

  • LLM settings/provider configuration changes
  • agent-conversations.md and other tracking docs
  • Additional orchestration scripts not needed for the two weekly checks

Renames and clarity

  • Rename “Cloud API” → “OpenHands API” across scripts and docs to avoid hosting ambiguity.
  • Keep env-only auth via OPENHANDS_API_KEY; no runtime prompts for credentials.
  • Apply reviewer suggestions where relevant to this subset.

Why

  • Keeps the effort small and reviewable while delivering immediate value (weekly checks).
  • Uses the same conversation endpoints as in OpenHands API Automation #94 but without additional framework surface area.

CI

  • Python formatting, linting, and type checks pass (ruff, mypy) with the repo’s pre-commit configuration.

Notes

Co-authored-by: openhands openhands@all-hands.dev

Summary by CodeRabbit

  • New Features

    • Weekly automated architecture audits and OpenAPI drift checks (scheduled + manual trigger) that produce structured reports and remediation guidance, and can open PRs when needed.
    • CLI and programmatic interfaces to run checks, poll results, and retrieve conversation/report URLs.
  • Documentation

    • Added usage docs detailing installation, CLI/programmatic usage, report formats, error handling, and security guidance.
  • Chores

    • Added scheduled CI workflows and runtime dependency setup for running the checks.

… drift) with absolute imports and manual dispatch\n\n- Add .github/workflows/weekly-architecture-audit.yml (schedule + workflow_dispatch)\n- Add .github/workflows/weekly-openapi-drift.yml (schedule + workflow_dispatch)\n- Add scripts/cloud_api.py, scripts/cron_agents.py, and prompts\n- Switch to absolute imports for Python entrypoint\n\nCo-authored-by: openhands <openhands@all-hands.dev>
@coderabbitai
Copy link

coderabbitai bot commented Aug 30, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds two scheduled GitHub Actions workflows and a new scripts package implementing OpenHands "cron agents": an API client, Jinja2 prompt templates, CLI entrypoint, tasks for architecture-audit and openapi-drift, polling/trajectory handling, report extraction, GitHub-issue posting, and JSON output.

Changes

Cohort / File(s) Summary
CI Workflows (weekly jobs)
​.github/workflows/weekly-architecture-audit.yml, ​.github/workflows/weekly-openapi-drift.yml
New weekly (Sat 06:00 UTC) and manual workflows that set up Python 3.12, install deps, and run scripts/cron_agents.py with task-specific args and env (including CRON_AGENTS_ISSUE_NUMBER and OPENHANDS_API_KEY); no artifact upload.
Cron Agents CLI & Logic
scripts/cron_agents.py
New CLI and programmatic tasks: Jinja2 prompt rendering, create conversations, poll until completion, fetch trajectory/events, extract delimited reports, parse drift/pr fields, optional GitHub issue comment posting, structured JSON outputs, and robust error handling/logging.
OpenHands API client
scripts/openhands_api.py
New OpenHandsAPIClient and OpenHandsAPIError with test_auth, create_conversation, get_conversation, get_conversation_events, get_trajectory, poll_until_complete, centralized response handling, and persistent session/timeout handling.
Prompt templates
scripts/prompts/architecture_audit.j2, scripts/prompts/openapi_drift.j2
Jinja2 templates containing agent instructions, placeholders ({{ repository }}, {{ branch }}), reporting markers, PR guidance, and output/report formatting rules for architecture audits and OpenAPI drift analysis.
Docs
scripts/README.md
New README documenting repository layout, CLI and programmatic usage, workflows, error handling, security model, and dependencies (requests, jinja2).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor GitHub as GitHub Actions
  participant Runner as Runner (job)
  participant Cron as cron_agents.py
  participant API as OpenHands API
  participant GH as GitHub (issue/PR)
  note over GitHub,Runner #DDEBF7: scheduled or manual trigger (Sat 06:00 UTC)
  GitHub->>Runner: start job
  Runner->>Cron: run task (architecture-audit / openapi-drift)
  Cron->>API: test_auth()
  API-->>Cron: server_info
  Cron->>API: create_conversation(prompt, repo, branch)
  API-->>Cron: conversation_id
  loop poll until terminal
    Cron->>API: get_conversation / get_trajectory
    API-->>Cron: status / events
  end
  Cron->>Cron: extract delimited report (markers)
  alt post to issue
    Cron->>GH: post comment/update issue (CRON_AGENTS_ISSUE_NUMBER)
    GH-->>Cron: comment_id
  end
  Cron-->>Runner: write JSON result / exit
Loading
sequenceDiagram
  autonumber
  participant Cron as run_openapi_drift_check()
  participant FS as Repo filesystem/commands
  participant API as OpenHands API

  Cron->>FS: try `python scripts/update_openapi.py --check` (fallback to app.openapi())
  FS-->>Cron: openapi_diff.json / openapi_diff.md (or generated diff)
  Cron->>API: create_conversation(openapi_drift prompt + repo context)
  API-->>Cron: conversation_id
  Cron->>API: poll_until_complete()
  API-->>Cron: status STOPPED
  Cron->>API: get_trajectory()
  API-->>Cron: assistant messages
  Cron->>Cron: parse OPENAPI_DIFF_REPORT_START/END -> extract drift_detected, pr_url, pr_number
  Cron-->>FS: emit structured JSON result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Possibly related PRs

Suggested labels

openhands-cloud, workflow, weekly-openapi

Poem

I thump at keys as Saturdays draw near,
Templates ready, prompts crisp and clear.
I sniff the drift, audit each frame,
Patch a doc and leave my name.
Hop—reports posted, the repo cheered. 🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch cron-agent

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Summary of Changes

Hello @enyst, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a new set of automated, Python-based cron agents designed to perform critical weekly maintenance tasks within the repository. These agents leverage the OpenHands Cloud API to execute an architecture documentation audit and an OpenAPI specification drift check, ensuring consistency and accuracy over time. The setup supports both scheduled execution for continuous monitoring and manual dispatch for immediate testing and validation.

Highlights

  • New Cron Agents Introduced: This pull request adds two new Python-centric cron agents designed for weekly automation tasks within the repository.
  • Architecture Documentation Audit: One agent is dedicated to performing a weekly audit of architecture documentation, comparing it against the current codebase to identify and address discrepancies.
  • OpenAPI Specification Drift Detection: The second agent focuses on detecting drift in the OpenAPI specification, ensuring the API documentation remains synchronized with the live server implementation and can propose PRs for fixes.
  • Robust OpenHands Cloud API Client: A new, clean Python client for the OpenHands Cloud API has been developed, featuring structured error handling, authentication, conversation management, and comprehensive polling capabilities.
  • Flexible Execution via GitHub Actions: Both cron agents are integrated into GitHub Actions workflows, supporting scheduled weekly runs and providing a manual dispatch option for immediate testing and validation.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces two new cron agents for weekly architecture audits and OpenAPI drift detection. The implementation is well-structured, with a clean API client for OpenHands Cloud, separate scripts for the agent logic, and well-defined prompts. The code is generally robust and includes good error handling and logging.

My review includes a few suggestions to improve maintainability and robustness. I've pointed out an opportunity to reduce significant code duplication in cron_agents.py by refactoring common logic into a helper function. In cloud_api.py, I've suggested using a requests.Session for better performance and replacing a broad exception catch with a more specific one to improve error handling.

coderabbitai[bot]

This comment was marked as outdated.

enyst added 2 commits August 30, 2025 01:24
…N error handling\n\n- Address AI review feedback: session reuse, specific JSON decode exception\n\nCo-authored-by: openhands <openhands@all-hands.dev>
…ory\n\n- cron_agents: make --api-key optional; prefer OPENHANDS_API_KEY env\n- workflows: remove --api-key arg, set working-directory: scripts\n- cloud_api: requests.Session reuse and narrower JSON exception handling\n\nAddresses AI review suggestions.\n\nCo-authored-by: openhands <openhands@all-hands.dev>
coderabbitai[bot]

This comment was marked as outdated.

Copy link
Owner Author

enyst commented Aug 30, 2025

I am OpenHands-GPT-5, an AI agent. I reviewed the updated PR description and addressed all actionable AI review feedback:

  • scripts/cloud_api.py: switched to a persistent requests.Session and narrowed JSON decode exception handling.
  • scripts/cron_agents.py: made --api-key optional and prefer OPENHANDS_API_KEY env.
  • Workflows: removed CLI secret usage and set working-directory: scripts.
  • Left a note about potential deduplication in cron_agents (happy to refactor into a shared helper on request).
  • Prompt fallback is intentionally minimal; can tighten guardrails if desired.

These changes are pushed to cron-agent and replies were posted on each thread.

enyst added 2 commits August 30, 2025 01:30
…\n- Remove --api-key flag and exclusively read from env\n\nCo-authored-by: openhands <openhands@all-hands.dev>
Copy link
Owner Author

enyst commented Aug 30, 2025

I am OpenHands-GPT-5, an AI agent. Per request, I removed CLI support for the API key entirely. The cron_agents.py entrypoint now reads OPENHANDS_API_KEY only from the environment and fails fast otherwise. Workflows were already updated to avoid passing the key via CLI.

… keep empty-but-meaningful values\n\n- __post_init__: only create Session if None; set Authorization; setdefault Content-Type/Accept\n- _handle_response: separate status check; require JSON on success with helpful errors\n- create_conversation: include empty list/string values (omit None only)\n\nCo-authored-by: openhands <openhands@all-hands.dev>
coderabbitai[bot]

This comment was marked as outdated.

enyst added 2 commits August 30, 2025 02:01
…I_KEY)\n\n- Remove --api-key from examples to reflect env-only policy\n\nCo-authored-by: openhands <openhands@all-hands.dev>
…xplicit flows in each task function\n\n- Make cron_agents an example-friendly reference for OH Cloud API usage\n\nCo-authored-by: openhands <openhands@all-hands.dev>
Copy link
Owner Author

enyst commented Aug 30, 2025

I am OpenHands-GPT-5, an AI agent. Update: per goal of making these scripts example-friendly for others to learn from, I reverted the internal helper and expanded both task functions to show the full, explicit flow (client init, auth test, prompt rendering, conversation creation, polling, trajectory fetch, parsing). This improves readability and serves better as reference code, at the cost of some duplication.

If you prefer a middle ground, we can keep a small helper just for the polling loop, but I’ve kept everything explicit for now.

coderabbitai[bot]

This comment was marked as outdated.

enyst and others added 2 commits August 30, 2025 02:40
- cloud_api.py -> openhands_api.py
- CloudAPIError -> OpenHandsAPIError
- OpenHandsCloudClient -> OpenHandsAPIClient
- Update argparse help and README wording

Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>
coderabbitai[bot]

This comment was marked as outdated.

enyst and others added 4 commits August 30, 2025 03:02
- scripts/README.md: comprehensive -> structured
- scripts/cron_agents.py: comprehensive -> structured

Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>
…saving JSON artifacts

- Create issue #97 as a comment thread for weekly reports
- Workflows: pass CRON_AGENTS_ISSUE_NUMBER/GITHUB_TOKEN/GITHUB_REPOSITORY to scripts
- Scripts: format readable report and POST to issue comment via GitHub API
- Drop JSON artifact upload from cron workflows

Co-authored-by: openhands <openhands@all-hands.dev>
… reporting

Co-authored-by: openhands <openhands@all-hands.dev>
enyst and others added 3 commits August 30, 2025 03:28
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>
…ngineer. Posting weekly ...'

Co-authored-by: openhands <openhands@all-hands.dev>
coderabbitai[bot]

This comment was marked as duplicate.

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
scripts/cron_agents.py (1)

62-74: Normalize event source and coerce values to strings to avoid missed reports and join errors.

Case-sensitive 'agent' check can drop messages; non-str content can break join. Align with prior feedback and harden parsing.

-        for event in trajectory_data.get('trajectory', []):
-            # Get message from actions (agent messages)
-            if event.get('source') == 'agent' and event.get('message'):
-                messages.append(event.get('message', ''))
-
-            # Get content from observations (tool outputs, etc.)
-            elif event.get('content'):
-                messages.append(event.get('content', ''))
+        for event in trajectory_data.get('trajectory', []):
+            src = str(event.get('source', '')).lower()
+            # Get message from actions (agent messages)
+            if src == 'agent' and event.get('message'):
+                messages.append(str(event.get('message', '')))
+
+            # Get content from observations (tool outputs, etc.)
+            elif event.get('content'):
+                messages.append(str(event.get('content', '')))
🧹 Nitpick comments (6)
scripts/cron_agents.py (6)

1-10: Fix docstring style to satisfy Ruff D212.

Start summaries on the first line; keep a blank line before details.

-"""
-OpenHands Cron Agents - Weekly automated tasks using the OpenHands API.
-
-This module contains the main functions for running weekly automated tasks:
-1. Architecture documentation audit
-2. OpenAPI drift detection
-
-Each function handles the complete workflow: prompt rendering, conversation creation,
-polling, and result extraction with structured error reporting.
-"""
+"""OpenHands Cron Agents - Weekly automated tasks using the OpenHands API.
+
+This module contains the main functions for running weekly automated tasks:
+1. Architecture documentation audit
+2. OpenAPI drift detection
+
+Each function handles the complete workflow: prompt rendering, conversation creation,
+polling, and result extraction with structured error reporting.
+"""
-    """
-    Run weekly architecture documentation audit.
-
-    Returns:
+    """Run weekly architecture documentation audit.
+
+    Returns:
         Dict with keys: success, conversation_id, conversation_url, status, report, error
-    """
+    """
-    """
-    Run weekly OpenAPI drift detection.
-
-    Returns:
+    """Run weekly OpenAPI drift detection.
+
+    Returns:
         Dict with keys: success, conversation_id, conversation_url, status, report,
                        drift_detected, pr_url, pr_number, error
-    """
+    """

Also applies to: 103-108, 207-213


28-33: Avoid configuring global logging at import time.

Do it in main() to prevent side effects when imported.

-# Configure logging
-logging.basicConfig(
-    level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s'
-)
 logger = logging.getLogger(__name__)
 def main():
     """CLI interface for running cron agents."""
+    # Configure logging only for CLI usage
+    if not logging.getLogger().handlers:
+        logging.basicConfig(
+            level=logging.INFO,
+            format='%(asctime)s - %(levelname)s - %(message)s',
+        )

Also applies to: 327-333


121-143: Consider a tiny helper to de-duplicate conversation creation + polling.

Keeps tasks explicit while removing repeated scaffolding.

Add helper (outside shown ranges):

def _start_conversation_and_poll(
    client: OpenHandsAPIClient,
    *,
    prompt: str,
    repository: str,
    branch: str,
    instructions: str,
    poll_timeout: int,
) -> tuple[str, str]:
    conv = client.create_conversation(
        initial_user_msg=prompt,
        repository=repository,
        selected_branch=branch,
        conversation_instructions=instructions,
    )
    conversation_id = conv.get('conversation_id') or conv.get('id')
    if not conversation_id:
        raise OpenHandsAPIError('No conversation ID returned from API')
    final_status = client.poll_until_complete(
        conversation_id, timeout_s=poll_timeout, progress_callback=progress_callback
    )
    return conversation_id, final_status

Then replace per-task blocks with:

-        # Create conversation
-        logger.info('Creating conversation...')
-        conv_response = client.create_conversation(
-            initial_user_msg=prompt,
-            repository=repository,
-            selected_branch=branch,
-            conversation_instructions='Focus on architecture documentation accuracy. Only make changes if material discrepancies are found.',
-        )
-        conversation_id = conv_response.get('conversation_id') or conv_response.get('id')
-        if not conversation_id:
-            raise OpenHandsAPIError('No conversation ID returned from API')
-        result['conversation_id'] = conversation_id
-        result['conversation_url'] = f'{base_url}/conversations/{conversation_id}'
-        logger.info(f'Conversation created: {result["conversation_url"]}')
-        # Poll for completion
-        logger.info('Polling for completion...')
-        final_status = client.poll_until_complete(
-            conversation_id, timeout_s=poll_timeout, progress_callback=progress_callback
-        )
+        logger.info('Creating conversation and polling...')
+        conversation_id, final_status = _start_conversation_and_poll(
+            client,
+            prompt=prompt,
+            repository=repository,
+            branch=branch,
+            instructions='Focus on architecture documentation accuracy. Only make changes if material discrepancies are found.',
+            poll_timeout=poll_timeout,
+        )
+        result['conversation_id'] = conversation_id
+        result['conversation_url'] = f'{base_url}/conversations/{conversation_id}'

Apply similarly in run_openapi_drift_check with its instructions string.

Also applies to: 229-258


299-302: Make 'empty' check case-insensitive and trim whitespace.

-            pr_url_match = re.search(r'pr_url:\s*(\S+)', report)
-            if pr_url_match and pr_url_match.group(1) not in ('', 'empty'):
-                result['pr_url'] = pr_url_match.group(1)
+            pr_url_match = re.search(r'pr_url:\s*(\S+)', report)
+            if pr_url_match:
+                url_val = pr_url_match.group(1).strip()
+                if url_val and url_val.lower() != 'empty':
+                    result['pr_url'] = url_val

420-424: Use 'Bearer' scheme for GitHub auth header.

Both work; 'Bearer' is the current recommendation.

-        headers = {
-            'Authorization': f'token {github_token}',
+        headers = {
+            'Authorization': f'Bearer {github_token}',
             'Accept': 'application/vnd.github+json',
             'User-Agent': 'openhands-cron-agents',
         }

442-446: Create output directory before writing file.

Prevents failures when a parent folder is missing.

-    if args.output:
-        with open(args.output, 'w') as f:
-            json.dump(result, f, indent=2)
-        logger.info(f'Results saved to {args.output}')
+    if args.output:
+        out_path = Path(args.output)
+        out_path.parent.mkdir(parents=True, exist_ok=True)
+        with out_path.open('w') as f:
+            json.dump(result, f, indent=2)
+        logger.info(f'Results saved to {out_path}')
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 39a7d39 and 34fe138.

📒 Files selected for processing (1)
  • scripts/cron_agents.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
scripts/cron_agents.py (1)
scripts/openhands_api.py (6)
  • OpenHandsAPIClient (35-212)
  • OpenHandsAPIError (20-31)
  • test_auth (92-97)
  • create_conversation (99-124)
  • poll_until_complete (150-212)
  • get_trajectory (143-148)
🪛 Ruff (0.12.2)
scripts/cron_agents.py

1-10: Multi-line docstring summary should start at the first line

Remove whitespace after opening quotes

(D212)


103-108: Multi-line docstring summary should start at the first line

Remove whitespace after opening quotes

(D212)


207-213: Multi-line docstring summary should start at the first line

Remove whitespace after opening quotes

(D212)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Python Tests on Windows (3.12)

…ssages\n\nPrevents missing AGENT/Agent messages in trajectory parsing.\n\nCo-authored-by: openhands <openhands@all-hands.dev>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (7)
scripts/cron_agents.py (7)

1-10: Fix D212: put the summary on the first docstring line.

Ruff flags this docstring (and a couple below) with D212. Move the summary up to the opening quotes.

-"""
-OpenHands Cron Agents - Weekly automated tasks using the OpenHands API.
+"""OpenHands Cron Agents - Weekly automated tasks using the OpenHands API.
 
 This module contains the main functions for running weekly automated tasks:
 1. Architecture documentation audit
 2. OpenAPI drift detection
 
 Each function handles the complete workflow: prompt rendering, conversation creation,
 polling, and result extraction with structured error reporting.
 """

35-53: Harden template rendering: fail on undefined vars (StrictUndefined).

Today missing template variables render to empty strings silently; that can hide errors. Use StrictUndefined.

-        template = jinja2.Template(template_content)
-        return template.render(**kwargs)
+        env = jinja2.Environment(undefined=jinja2.StrictUndefined)
+        template = env.from_string(template_content)
+        return template.render(**kwargs)

104-109: Fix D212 in function docstring.

-    """
-    Run weekly architecture documentation audit.
+    """Run weekly architecture documentation audit.
 
     Returns:
         Dict with keys: success, conversation_id, conversation_url, status, report, error
     """

186-198: Consider capping and structuring error payloads.

You already truncate to 500 chars. Optionally prefix with a small JSON block (status_code, snippet) for easier downstream parsing.


208-214: Fix D212 in function docstring.

-    """
-    Run weekly OpenAPI drift detection.
+    """Run weekly OpenAPI drift detection.
 
     Returns:
         Dict with keys: success, conversation_id, conversation_url, status, report,
                        drift_detected, pr_url, pr_number, error
     """

293-306: Make report parsing resilient to quotes/whitespace.

Handle values like pr_url: "https://..." and pr_number: "123".

-            pr_url_match = re.search(r'pr_url:\s*(\S+)', report)
-            if pr_url_match and pr_url_match.group(1) not in ('', 'empty'):
-                result['pr_url'] = pr_url_match.group(1)
+            pr_url_match = re.search(r'pr_url:\s*["\']?([^\s"\'\)]+)', report, re.IGNORECASE)
+            if pr_url_match:
+                url = pr_url_match.group(1).strip().strip('"\'')

+                if url and url.lower() not in ('empty', 'none', 'n/a'):
+                    result['pr_url'] = url
-
-            pr_number_match = re.search(r'pr_number:\s*(\d+)', report)
-            if pr_number_match:
-                result['pr_number'] = pr_number_match.group(1)
+            pr_number_match = re.search(r'pr_number:\s*["\']?(\d+)', report, re.IGNORECASE)
+            if pr_number_match:
+                result['pr_number'] = pr_number_match.group(1)

421-426: Use Bearer auth and set API version for GitHub.

Minor, but aligns with current REST guidelines and reduces warning noise.

-        headers = {
-            'Authorization': f'token {github_token}',
-            'Accept': 'application/vnd.github+json',
-            'User-Agent': 'openhands-cron-agents',
-        }
+        headers = {
+            'Authorization': f'Bearer {github_token}',
+            'Accept': 'application/vnd.github+json',
+            'X-GitHub-Api-Version': '2022-11-28',
+            'User-Agent': 'openhands-cron-agents',
+        }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 34fe138 and bb7e531.

📒 Files selected for processing (1)
  • scripts/cron_agents.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
scripts/cron_agents.py (1)
scripts/openhands_api.py (6)
  • OpenHandsAPIClient (35-212)
  • OpenHandsAPIError (20-31)
  • test_auth (92-97)
  • create_conversation (99-124)
  • poll_until_complete (150-212)
  • get_trajectory (143-148)
🪛 Ruff (0.12.2)
scripts/cron_agents.py

1-10: Multi-line docstring summary should start at the first line

Remove whitespace after opening quotes

(D212)


104-109: Multi-line docstring summary should start at the first line

Remove whitespace after opening quotes

(D212)


208-214: Multi-line docstring summary should start at the first line

Remove whitespace after opening quotes

(D212)

🔇 Additional comments (3)
scripts/cron_agents.py (3)

170-182: Agent-source normalization looks good.

Lowercasing event['source'] prevents missing 'AGENT' messages; string-type guard avoids non-text. Nice.


328-351: Nice: API key only via environment (no CLI secret leakage).

Good security posture for CI and local use.


122-124: Resolved: OpenHandsAPIClient session initialization is covered by its @DataClass post_init

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant