Skip to content

Added examples and Rust SDK fix#78

Merged
sawradip merged 23 commits into
mainfrom
rad/examples_v2
Nov 6, 2025
Merged

Added examples and Rust SDK fix#78
sawradip merged 23 commits into
mainfrom
rad/examples_v2

Conversation

@RadeenXALNW
Copy link
Copy Markdown
Collaborator

@RadeenXALNW RadeenXALNW commented Nov 6, 2025

Restructure the RUST sdk codebase as well as added new examples which will run in both local and RunAgent Cloud

Summary by CodeRabbit

  • New Features
    • StockAgent: Multi-agent LLM-based stock trading simulation with autonomous decision-making.
    • AI Lead Generation: Automated lead extraction and qualification from web sources.
    • Book Writer SaaS: Full-stack AI application for generating books using multi-agent workflows.
    • Lead Score Flow: Intelligent candidate evaluation with automated email generation.
    • RAG Agent: Document router for querying across multiple knowledge bases with streaming support.
    • LightRAG Agent: Comprehensive document management system with multimodal support and vector search.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Nov 6, 2025

Caution

Review failed

Failed to post review comments

Walkthrough

This pull request introduces six comprehensive example projects demonstrating RunAgent-based AI workflows: a stock trading simulation agent with multi-agent orchestration, an AI lead generation system using web search and extraction, a book writing flow with outline and chapter generation, lead scoring with lead-to-sales automation, a LightRAG integration for multi-document RAG queries, and a query-routing RAG agent. Each example includes backend APIs, configuration files, and supporting infrastructure (frontend UIs, Rust/Python SDKs, TypeScript integrations).

Changes

Cohort / File(s) Summary
StockAgent: Core Implementation
examples/Stockagent/agent.py, examples/Stockagent/main.py, examples/Stockagent/secretary.py, examples/Stockagent/stock.py, examples/Stockagent/util.py
Multi-agent stock trading simulation with LLM-driven decision making. Includes agent state management, multi-backend chat (GPT/Gemini), loan/trading/bankruptcy logic, secretary-based validation, and orchestration of daily simulations with event handling.
StockAgent: Prompts & Logging
examples/Stockagent/prompt/agent_prompt.py, examples/Stockagent/log/custom_logger.py
Prompt templates for agent workflows (background, loan decisions, trading, estimates) and colored console logger with file output.
StockAgent: Records & Wrappers
examples/Stockagent/record.py, examples/Stockagent/runagent_wrapper.py, examples/Stockagent/runagent.config.json
Excel-based trade/stock/agent record persistence, streaming simulation wrapper with log capture, and RunAgent configuration.
StockAgent: Tests & Config
examples/Stockagent/requirements.txt, examples/Stockagent/README.md, examples/Stockagent/sdk_test/*
Dependencies, documentation, Python and Rust SDK tests.
AI Lead Generation: Agent
examples/ai_lead_generation/agents/main.py, examples/ai_lead_generation/agents/README.md, examples/ai_lead_generation/agents/runagent.config.json
Quora lead search via Firecrawl, OpenAI extraction, CSV formatting/saving, and RunAgent configuration.
AI Lead Generation: SDK & Config
examples/ai_lead_generation/agents/requirements.txt, examples/ai_lead_generation/sdk/python/test.py
Dependencies and Python SDK usage example.
Book Writer: Backend & Frontend
examples/book_writer/backend/app.py, examples/book_writer/frontend/src/App.tsx, examples/book_writer/frontend/src/...
Flask backend with outline/book generation endpoints; React/Vite frontend with multi-step UI (config, processing, results), markdown rendering, and chapter management.
Book Writer: Frontend Config
examples/book_writer/frontend/package.json, examples/book_writer/frontend/tsconfig.json, examples/book_writer/frontend/vite.config.ts, examples/book_writer/frontend/tailwind.config.js, examples/book_writer/frontend/postcss.config.cjs, examples/book_writer/frontend/src/main.tsx, examples/book_writer/frontend/src/index.css
Build, type, and style configuration for React frontend.
Book Writer: CrewAI Flow
examples/book_writer/write_a_book_with_flows/main.py, examples/book_writer/write_a_book_with_flows/src/write_a_book_with_flows/types.py, examples/book_writer/write_a_book_with_flows/src/write_a_book_with_flows/crews/...
CrewAI-based outline and chapter generation with async orchestration; agent/task YAML configs for research and writing crews.
Book Writer: CrewAI Config
examples/book_writer/write_a_book_with_flows/README.md, examples/book_writer/write_a_book_with_flows/runagent.config.json, examples/book_writer/write_a_book_with_flows/pyproject.toml, examples/book_writer/write_a_book_with_flows/requirements.txt, examples/book_writer/write_a_book_with_flows/.gitignore
Documentation, RunAgent and project configuration, dependencies.
Book Writer: Sample Content
examples/book_writer/write_a_book_with_flows/Automating_Tasks_with_CrewAI.md, examples/book_writer/write_a_book_with_flows/The_Current_State_of_AI_in_July_2025.md
Example book markdown outputs.
Book Writer: SDK & Tests
examples/book_writer/sdk/python/test.py
Python SDK usage example.
Lead Agent: Core Agent
examples/lead-agent/lead-score-flow/main.py, examples/lead-agent/lead-score-flow/src/lead_score_flow/...
Lead scoring orchestrator with CSV loading, async candidate scoring, email generation, and top-N ranking. Includes crew configurations for scoring and email follow-up.
Lead Agent: Backend (Python)
examples/lead-agent/backend/app.py, examples/lead-agent/backend/requirements.txt
Flask API for lead scoring with endpoints for batch/single scoring, health checks, and debug logging.
Lead Agent: Backend (Rust)
examples/lead-agent/backend-rust/src/main.rs, examples/lead-agent/backend-rust/Cargo.toml, examples/lead-agent/backend-rust/README.md
Axum-based Rust backend with equivalent endpoints and CORS support.
Lead Agent: Frontend
examples/lead-agent/frontend/src/App.tsx, examples/lead-agent/frontend/src/..., examples/lead-agent/frontend/package.json, examples/lead-agent/frontend/vite.config.ts, examples/lead-agent/frontend/tailwind.config.js, examples/lead-agent/frontend/tsconfig.json
React/Vite frontend with CSV upload, column mapping, lead scoring, results display, and email/CSV downloads.
Lead Agent: Config & SDKs
examples/lead-agent/lead-score-flow/runagent.config.json, examples/lead-agent/lead-score-flow/pyproject.toml, examples/lead-agent/runagent_sdk/python/test_sdk.py, examples/lead-agent/runagent_sdk/rust/src/main.rs, examples/lead-agent/deployment_guide.md
RunAgent configuration, CLI entry points, SDK examples (Python/Rust), and deployment guide.
LightRAG Agent: Core Services
examples/lightrag_agent_(developing)/agent/lightrag_agent.py, examples/lightrag_agent_(developing)/services/rag_service.py, examples/lightrag_agent_(developing)/services/document_processor.py
LightRAG integration with document processing, RAG querying, multimodal support, and service orchestration.
LightRAG Agent: Storage & Config
examples/lightrag_agent_(developing)/agent/config.py, examples/lightrag_agent_(developing)/agent/storage.py, examples/lightrag_agent_(developing)/services/neon_service.py
Configuration management, Neon PostgreSQL storage with health checks and agent lifecycle, and Neon API integration.
LightRAG Agent: Utilities & Setup
examples/lightrag_agent_(developing)/utils/helpers.py, examples/lightrag_agent_(developing)/requirements.txt, examples/lightrag_agent_(developing)/runagent.config.json, examples/lightrag_agent_(developing)/sdk/python/test.py
Helper functions (file size, JSON parsing, logging), dependencies, RunAgent config, and Python SDK test.
RAG Agent: Core Agent
examples/rag_agent/agent/agent.py, examples/rag_agent/agent/requirements.txt, examples/rag_agent/agent/runagent.config.json
Query routing across Qdrant collections (products, support, finance) with LLM-based fallback and web search fallback.
RAG Agent: Backend
examples/rag_agent/backend/app.py, examples/rag_agent/backend/requirements.txt
Flask API with PDF upload, query/streaming query, stats, and database listing endpoints.
RAG Agent: Frontend & Docs
examples/rag_agent/frontend/index.html, examples/rag_agent/frontend/app.js, examples/rag_agent/README.md
HTML UI scaffold with tabbed interface (Query/Upload/Statistics), JavaScript with streaming query support, markdown rendering, and comprehensive README.
Root Configuration
.gitignore
Minor newline adjustment.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120+ minutes

Areas requiring special attention:

  • StockAgent agent orchestration logic (examples/Stockagent/agent.py, examples/Stockagent/main.py): Complex multi-day simulation with state management, retry logic, bankruptcy handling, and LLM-driven decision making across loans, trading, and interest calculations.
  • Book Writer CrewAI integration (examples/book_writer/write_a_book_with_flows/main.py): Async orchestration with nest_asyncio workarounds, lazy imports, and parallel chapter generation; error handling across multiple failure modes.
  • Lead Agent full-stack flow (examples/lead-agent/lead-score-flow/main.py): Complex async/await patterns with event loop management, batch processing, and email generation; dual Python and Rust backend implementations.
  • LightRAG Service architecture (examples/lightrag_agent_(developing)/services/rag_service.py, examples/lightrag_agent_(developing)/agent/lightrag_agent.py): Heavy async initialization, multimodal document processing, RAG chain construction, and conditional storage backend selection (Neon/Neo4j).
  • RAG Agent routing logic (examples/rag_agent/agent/agent.py): Multi-database routing with similarity threshold decisions, LLM-based fallback, and web search integration.
  • Frontend streaming and state management: Multiple frontends implement real-time updates, CSV parsing/mapping, markdown rendering, and complex multi-step workflows; ensure consistency across React implementations.
  • Configuration and validation: Extensive use of environment variables, API key handling, and conditional logic based on storage/model backends; verify error messages and fallback behavior.

Suggested reviewers

  • sawradip

Poem

🐰 Six agents hopped into the warren today,
Trading stocks, scoring leads, writing books—hooray!
With RAG and retrieval, search and flows,
LightRAG glows where knowledge grows,
A symphony of examples to light up the way!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 26.83% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'Added examples and Rust SDK fix' is partially related to the changeset but misses the primary focus. While the PR adds numerous examples, the title does not clearly convey the scope and nature of the changes. Consider revising the title to better reflect the main changes, such as 'Add multiple agent examples and restructure Rust SDK' to capture both key aspects of the changeset.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch rad/examples_v2

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

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@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: 47

♻️ Duplicate comments (1)
examples/book_writer/write_a_book_with_flows/pyproject.toml (1)

10-10: Align crewai version with other configuration files.

This dependency specification conflicts with versions referenced in requirements.txt (crewai==1.3.0) and README.md (crewai==0.130.0). See the corresponding issue raised for requirements.txt for unified resolution.

🧹 Nitpick comments (47)
examples/lead-agent/lead-score-flow/requirements.txt (1)

1-3: Inconsistent version pinning reduces reproducibility.

crewai is pinned to a specific version (1.2.0), but openai and PyYAML are unpinned. This mixed strategy means different users or CI/CD runs may install different versions, leading to inconsistent behavior.

Pin all dependencies to specific versions for reproducibility:

 crewai==1.2.0
-openai
-PyYAML
+openai==1.42.0
+PyYAML==6.0.1

(Adjust the versions for openai and PyYAML to match your tested/desired versions.)

If you intentionally want to allow flexibility for example projects to use the latest versions, document this decision and consider using version ranges (e.g., openai>=1.0,<2.0) instead of leaving them completely unpinned.

examples/book_writer/write_a_book_with_flows/The_Current_State_of_AI_in_July_2025.md (1)

1-891: Remove duplicate section headings throughout the document.

This markdown document repeats the main heading for each chapter twice in succession (e.g., lines 1–3, 75–77, 186–188, etc.). Each top-level heading appears on consecutive lines with only a blank line between them. This violates markdown structure best practices and creates visual clutter.

Remove the second occurrence of each duplicate heading:

# Introduction to AI Trends in 2025

-# Introduction to AI Trends in 2025
-
 In 2025, artificial intelligence (AI) continues to surge forward...

Apply the same fix to all 11 duplicate heading pairs throughout the document (lines 3, 77, 188, 371, 443, 492, 566, 634, 696, 762, and 844).

examples/lead-agent/lead-score-flow/.gitignore (1)

1-2: Consider adding .venv/ for consistency with other Python examples.

The book_writer example includes .venv/ alongside .env and __pycache__/. Adding it here would make the pattern coverage consistent across Python example projects, improving clarity for developers copying these examples to new projects.

examples/book_writer/write_a_book_with_flows/Automating_Tasks_with_CrewAI.md (2)

270-285: Clarify and standardize configuration file patterns.

Configuration examples use inconsistent approaches:

  • Lines 271-285: YAML-based config for CrewAI setup
  • Lines 426-434: Python dict config for agent setup
  • Lines 1091-1115: Inline Python task definitions

For a comprehensive guide, clarify which configuration method is preferred and when each pattern is most appropriate. Add a section contrasting YAML vs. Python config with pros/cons to help readers choose.

Consider adding a subsection titled "Configuration Approaches" that explains the trade-offs (YAML for simpler projects, Python for dynamic configurations, etc.) and provides a decision tree for readers.

Also applies to: 426-434, 1091-1115


1-3: Content is well-structured and comprehensive; approve overall approach.

The documentation provides clear progression from fundamentals (chapters 1-3) through practical examples (chapters 4-6) to advanced topics (chapter 7). Writing is professional, examples are diverse, and best practices are well-emphasized. Chapter breaks with introductions, examples, and conclusions are consistent.

Minor suggestion: Add a "Prerequisites" section early (before chapter 1) listing required knowledge level, software (Python 3.7+), and hardware requirements in one place, as these are scattered across chapters.

Also applies to: 5-7, 94-96, 374-376, 478-484

examples/lead-agent/lead-score-flow/pyproject.toml (2)

8-8: Remove the upper Python version bound to avoid future compatibility issues.

The constraint <=3.13 will prevent the package from running on Python 3.14 and later. For example projects and libraries, it's better to omit the upper bound unless there's a specific compatibility issue documented.

Apply this change:

-requires-python = ">=3.10,<=3.13"
+requires-python = ">=3.10"

6-6: Update placeholder author information.

The author metadata uses template values ("Your Name" and "you@example.com"). While acceptable for an example/template project, consider updating it with actual author details before deployment.

examples/lead-agent/deployment_guide.md (3)

17-17: Specify language identifier for code block.

The ASCII architecture diagram should have a language specifier for markdown consistency. Use a generic identifier like text or mermaid (if supporting mermaid diagrams).

-```
+```text
 ┌─────────────────┐
 │   React Frontend │
 │   (Port 5173)   │
 └────────┬────────┘
          │ HTTP REST API
          ↓
 ┌─────────────────┐
 │  Flask Backend  │
 │   (Port 8000)   │
 └────────┬────────┘
          │ RunAgent Python SDK
          ↓
 ┌─────────────────┐
 │  RunAgent Agent │
 │  (CrewAI Flow)  │
 └─────────────────┘
-```
+```

368-368: Format bare URLs as markdown links.

URLs should be properly formatted as markdown links for better documentation consistency and accessibility.

 ## 📞 Support
 
-- **Documentation**: https://docs.run-agent.ai
-- **Discord**: https://discord.gg/Q9P9AdHVHz
-- **GitHub Issues**: https://github.com/runagent-dev/runagent
+- **Documentation**: [https://docs.run-agent.ai](https://docs.run-agent.ai)
+- **Discord**: [https://discord.gg/Q9P9AdHVHz](https://discord.gg/Q9P9AdHVHz)
+- **GitHub Issues**: [https://github.com/runagent-dev/runagent](https://github.com/runagent-dev/runagent)

Also applies to: 369-369, 370-370


378-378: Convert emphasis to proper heading.

The final line uses emphasis formatting (**...**) but reads like a footer or closing statement. Consider converting it to a comment-style footer or proper heading for better structure.

 This project is licensed under the MIT License.
 
 ---
 
-**Made with ❤️ using RunAgent, CrewAI, React, and Flask**
+<!-- Made with ❤️ using RunAgent, CrewAI, React, and Flask -->

Alternatively, if you prefer to keep it visible:

-**Made with ❤️ using RunAgent, CrewAI, React, and Flask**
+## Made with ❤️
+
+Built using RunAgent, CrewAI, React, and Flask
examples/lead-agent/frontend/tailwind.config.js (1)

1-11: Add newline at end of file.

The configuration is correct, but the file should end with a newline character to follow common conventions and avoid potential issues with some tools.

examples/lead-agent/backend-rust/src/main.rs (4)

107-112: Replace println! with structured logging.

Debug output uses println! which lacks structure, log levels, and timestamps. Consider using the tracing crate for production-grade observability.

Add tracing to Cargo.toml dependencies, then replace:

-// Debug: Log candidate types before sending to SDK
-println!("[DEBUG] Number of candidates: {}", normalized_candidates.len());
-if let Some(first) = normalized_candidates.first() {
-    println!("[DEBUG] First candidate type: object");
-    println!("[DEBUG] First candidate sample: {}", serde_json::to_string(first).unwrap_or_default());
-}
+tracing::debug!(
+    count = normalized_candidates.len(),
+    sample = ?normalized_candidates.first(),
+    "Processing candidates"
+);

152-186: Consider simplifying result processing and using consistent logging.

The double-parsing logic (lines 158-172) attempts to parse JSON strings but falls back silently. This defensive approach may hide issues. Additionally, mixing println! debug statements with eprintln! for errors is inconsistent.

Consider structured logging and clearer result handling:

 match client.run_with_args(&[], &params).await {
     Ok(result) => {
-        // Debug: Log the result structure
-        println!("[DEBUG] Agent result type: {}", result);
-        println!("[DEBUG] Agent result keys: {:?}", result.as_object().map(|o| o.keys().collect::<Vec<_>>()));
-        
-        // Check if result is a JSON string that needs parsing
-        let final_result = if let Some(result_str) = result.as_str() {
-            match serde_json::from_str::<Value>(result_str) {
-                Ok(parsed) => {
-                    println!("[DEBUG] Parsed JSON string result");
-                    parsed
-                }
-                Err(_) => {
-                    println!("[DEBUG] Result is not JSON string, using as-is");
-                    result
-                }
-            }
-        } else {
-            result
-        };
-        
-        Ok(JsonResponse(final_result))
+        tracing::debug!(result = ?result, "Agent execution completed");
+        Ok(JsonResponse(result))
     }
     Err(e) => {
-        eprintln!("Error in score_leads: {:?}", e);
+        tracing::error!(error = ?e, "Agent execution failed");
         Err((
             StatusCode::INTERNAL_SERVER_ERROR,
             JsonResponse(ErrorResponse {
                 error: format!("Agent execution failed: {}", e),
                 traceback: Some(format!("{:?}", e)),
             }),
         ))
     }
 }

291-304: Move CORS origins to environment configuration.

Hardcoded IP addresses (lines 292-295) make deployment to different environments inflexible. Consider reading allowed origins from environment variables.

-let allowed_origins = vec![
-    "http://localhost:5173",
-    "http://127.0.0.1:5173",
-    "http://10.1.0.5:5173",
-    "http://20.84.81.110:5173",
-]
-.into_iter()
-.map(|s| HeaderValue::from_static(s))
-.collect::<Vec<_>>();
+let allowed_origins: Vec<HeaderValue> = std::env::var("CORS_ORIGINS")
+    .unwrap_or_else(|_| "http://localhost:5173".to_string())
+    .split(',')
+    .filter_map(|s| HeaderValue::from_str(s.trim()).ok())
+    .collect();

286-330: Server initialization is clean and functional.

The main function properly reads the port from environment variables with a sensible default, binds to all interfaces for Docker compatibility, and clearly logs available endpoints.

For consistency, consider using structured logging for startup messages as well:

-println!("🚀 Starting Lead Score API Backend (Rust)...");
+tracing::info!("Starting Lead Score API Backend (Rust)");
examples/lead-agent/backend/app.py (2)

67-71: Replace print statements with structured logging.

Debug output uses print() which lacks log levels and structure. Consider using Python's logging module for production deployments.

+import logging
+
+logger = logging.getLogger(__name__)
+
-# Debug: Log candidate types before sending to SDK
-print(f"[DEBUG] Number of candidates: {len(candidates)}")
-if candidates:
-    print(f"[DEBUG] First candidate type: {type(candidates[0])}")
-    print(f"[DEBUG] First candidate sample: {str(candidates[0])[:200]}")
+logger.debug(
+    "Processing candidates",
+    extra={
+        "count": len(candidates),
+        "sample": str(candidates[0])[:200] if candidates else None
+    }
+)

91-97: Broad exception catching is acceptable for example code.

The broad Exception catch provides helpful error responses with tracebacks for debugging. For production, consider catching more specific exceptions (e.g., RunAgentError, ValueError) separately for better error handling granularity.

examples/rag_agent/agent/agent.py (2)

129-166: Intelligent routing logic with proper fallback.

The two-tier routing strategy (vector similarity first, LLM fallback) is well-designed. The confidence threshold approach (line 147) ensures high-quality matches.

Replace print with proper logging:

+import logging
+logger = logging.getLogger(__name__)
+
-    except Exception as e:
-        print(f"Routing error: {str(e)}")
-        return None
+    except Exception as e:
+        logger.error(f"Routing error: {str(e)}", exc_info=True)
+        return None

221-255: Well-structured query orchestration with proper fallback chain.

The query method implements a clean control flow: routing → database query OR web search → structured response. The return format is consistent and includes helpful metadata.

Consider logging exceptions before returning error responses for debugging:

+import logging
+logger = logging.getLogger(__name__)
+
     except Exception as e:
+        logger.error(f"Query failed: {str(e)}", exc_info=True)
         return {
             "success": False,
             "error": str(e),
             "question": question
         }
examples/lead-agent/runagent_sdk/python/test_sdk.py (1)

10-13: Remove commented out code.

The commented code serves no purpose in the example and creates confusion about the correct usage pattern. If both string and typed parameters are valid approaches, consider documenting this in a comment rather than leaving alternative code commented out.

Apply this diff to clean up the file:

-# result = client.run(
-#     top_n="1",
-#     generate_emails="true"
-# )
-
 result = client.run(
     top_n=1,
     generate_emails=True
 )
examples/Stockagent/sdk_test/rust/Cargo.toml (1)

1-4: Consider renaming the package.

The package name temp_rust_test suggests this is temporary or placeholder code. For a committed example, consider a more descriptive name like stockagent_example or runagent_stock_test.

Apply this diff:

 [package]
-name = "temp_rust_test"
+name = "stockagent_example"
 version = "0.1.1"
 edition = "2021"
examples/book_writer/sdk/python/test.py (1)

9-14: Remove commented out code.

The commented code creates clutter in the example. If num_chapters is an optional parameter, document it in a comment rather than leaving unused code.

Apply this diff:

+# Optional parameters:
+# - num_chapters: Number of chapters to generate (default behavior if not specified)
+
-# result = client.run(
-#     title="Introduction to Python",
-#     topic="Python programming basics",
-#     goal="Teach beginners fundamental Python concepts",
-#     num_chapters=3
-# )
-
 result = client.run(
     title="Introduction to Python",
     topic="Python programming basics",
     goal="Teach beginners fundamental Python concepts"
 )
examples/lead-agent/runagent_sdk/rust/Cargo.toml (1)

1-4: Consider renaming the package.

The package name lead_score_agent_test is reasonable, but for consistency with other examples in the PR, consider whether a shorter name like lead_agent_example would be clearer.

examples/book_writer/frontend/vite.config.ts (1)

1-17: LGTM with optional documentation suggestion.

The Vite configuration is well-structured with appropriate server settings and API proxy configuration.

Consider adding a comment explaining the 0.0.0.0 binding for developers unfamiliar with network configuration:

   server: {
+    // Bind to all interfaces (0.0.0.0) to allow access from containers/VMs
     host: '0.0.0.0',
     port: 5173,
     strictPort: true,
examples/lightrag_agent_(developing)/requirements.txt (1)

1-32: Consider pinning dependency versions for reproducibility.

The dependencies are well-organized, but most packages lack version constraints. For production deployments and reproducible builds, consider pinning specific versions or at minimum specifying version ranges.

Example for critical dependencies:

 # Core LightRAG dependencies
-lightrag-hku
-raganything
+lightrag-hku>=0.1.0,<1.0.0
+raganything>=0.1.0,<1.0.0

 # OpenAI and embeddings
-openai
+openai>=1.0.0,<2.0.0

This prevents unexpected breaking changes from upstream package updates.

examples/book_writer/backend/app.py (1)

1-7: Remove unused import.

The datetime module is imported on line 6 but never used in the code.

 from flask import Flask, request, jsonify, send_file, Response
 from flask_cors import CORS
 from runagent import RunAgentClient
 import os
 import traceback
-from datetime import datetime
 import io
examples/lightrag_agent_(developing)/services/neon_service.py (1)

137-137: Consider replacing ambiguous Unicode emoji.

The information emoji ℹ️ contains an ambiguous Unicode character that may render inconsistently across terminals.

-                    logger.info(f"ℹ️  Database already exists: {database_name}")
+                    logger.info(f"ℹ Database already exists: {database_name}")

Or use a plain text indicator:

-                    logger.info(f"ℹ️  Database already exists: {database_name}")
+                    logger.info(f"INFO: Database already exists: {database_name}")
examples/Stockagent/sdk_test/python/test_agent.py (1)

10-16: Consider adding basic error handling for production examples.

While the streaming pattern is clear, adding basic error handling would make this a more robust example for users to learn from.

Consider wrapping the client execution in a try-except block:

-for update in client.run(
-    num_agents="5",        
-    total_days="2",        
-    sessions_per_day="2",  
-    model="gpt-4o-mini"
-):
-    print(update)
+try:
+    for update in client.run(
+        num_agents="5",        
+        total_days="2",        
+        sessions_per_day="2",  
+        model="gpt-4o-mini"
+    ):
+        print(update)
+except Exception as e:
+    print(f"Error running agent: {e}")
examples/ai_lead_generation/sdk/python/test.py (1)

9-14: Consider adding error handling for robustness.

Adding basic error handling would make this example more production-ready and educational for users.

-result = client.run(
-    search_query="Ai powered car sell automation",
-    num_links=3
-)
-
-print(result)
+try:
+    result = client.run(
+        search_query="Ai powered car sell automation",
+        num_links=3
+    )
+    print(result)
+except Exception as e:
+    print(f"Error: {e}")
examples/Stockagent/runagent.config.json (1)

1-32: Add trailing newline for consistency.

The configuration structure is sound, but the file is missing a trailing newline. While not critical, adding one aligns with POSIX standards and common Git practices.

Add a newline at the end of the file:

   "env_vars": {
     "OPENAI_API_KEY": "",
     "GOOGLE_API_KEY": ""
   }
-}
+}
+
examples/ai_lead_generation/agents/README.md (1)

40-52: Add security warning about API key handling.

The example shows API keys passed as function parameters with placeholder strings. Consider adding a security note warning users never to hardcode API keys in source code and to use environment variables or secure secret management instead.

Add a security note before the example:

 ### Local Testing
 
+> **Security Note**: Never hardcode API keys in your source code. Use environment variables or a secure secret manager instead.
+
 ```python
 from main import generate_leads
examples/lead-agent/lead-score-flow/src/lead_score_flow/constants.py (2)

36-47: Reconsider including "CrewAI" in the skills list.

The SKILLS list includes "CrewAI" which appears to be an implementation framework rather than a typical job requirement. Consider whether this is intentionally part of the job criteria or if it's an implementation detail that shouldn't be in the candidate requirements.


1-47: Consider adding type hints for module-level constants.

Adding type hints for JOB_DESCRIPTION and SKILLS would improve IDE support and code clarity.

+from typing import List
+
-JOB_DESCRIPTION = """
+JOB_DESCRIPTION: str = """
 # Junior React Developer
 ...
 """
 
-SKILLS = [
+SKILLS: List[str] = [
     "React",
examples/lead-agent/lead-score-flow/src/lead_score_flow/utils/candidateUtils.py (1)

20-33: Log when candidates are skipped due to missing scores.

The function silently skips candidates without matching scores. This could hide data issues. Consider logging a warning when a candidate has no corresponding score.

     scored_candidates = []
     for candidate in candidates:
         score = score_dict.get(candidate.id)
         if score:
             scored_candidates.append(
                 ScoredCandidate(
                     id=candidate.id,
                     name=candidate.name,
                     email=candidate.email,
                     bio=candidate.bio,
                     skills=candidate.skills,
                     score=score.score,
                     reason=score.reason,
                 )
             )
+        else:
+            logger.warning("No score found for candidate ID: %s", candidate.id)
examples/lead-agent/lead-score-flow/src/lead_score_flow/crews/lead_response_crew/lead_response_crew.py (1)

20-25: Consider if verbose flag on Task is necessary.

Setting verbose=True on the Task itself (line 24) is not seen in similar crew implementations in this PR. The Crew already has verbose=True (line 34), which typically controls verbosity for all components. Unless task-level verbosity is specifically needed, this may be redundant.

Apply this diff if you want to remove the redundant verbose flag:

     @task
     def send_followup_email_task(self) -> Task:
         return Task(
             config=self.tasks_config["send_followup_email"],
-            verbose=True,
         )
examples/Stockagent/stock.py (1)

4-11: Remove unused parameter is_new.

The is_new parameter is accepted but never used within the class. Based on the usage in main.py, it's always passed as False and serves no purpose.

Apply this diff to remove the unused parameter:

-    def __init__(self, name, initial_price, initial_stock, is_new=False):
+    def __init__(self, name, initial_price, initial_stock):
         self.name = name
         self.price = initial_price
         self.ideal_price = 0
         self.initial_stock = initial_stock
         self.history = {}   # {date: session_deal}
         self.session_deal = [] # [{"price", "amount"}]

Also update the Stock instantiation calls in main.py (lines 78, 80) and runagent_wrapper.py if present.

examples/Stockagent/log/custom_logger.py (2)

20-26: Consider ensuring log directory exists.

The hardcoded log file path 'log/test.txt' (line 21) will fail if the log/ directory doesn't exist. Consider creating the directory or using an absolute path.

Apply this diff to ensure the directory exists:

+import os
 import logging
 from colorama import Fore, Style, Back

 class ColoredFormatter(logging.Formatter):
     def format(self, record):
         levelname_color = {
             'DEBUG': Fore.CYAN + Style.BRIGHT,
             'INFO': Fore.GREEN + Style.BRIGHT,
             'WARNING': Fore.YELLOW + Style.BRIGHT,
             'ERROR': Fore.RED + Style.BRIGHT,
             'CRITICAL': Fore.RED + Style.BRIGHT,
         }
         message = super().format(record)
         if record.levelname in levelname_color:
             message = levelname_color[record.levelname] + message + Style.RESET_ALL
         return message


 class CustomLogger:
     def __init__(self):
         self.log_file = 'log/test.txt'
+        os.makedirs(os.path.dirname(self.log_file), exist_ok=True)
         self.logger = logging.getLogger('Stocklogger')
         self.logger.setLevel(logging.DEBUG)

31-31: Replace fullwidth parentheses in comment.

The comment contains Chinese fullwidth parentheses () instead of ASCII parentheses ().

Apply this diff:

-        # 创建一个handler用于输出到控制台(带有颜色)
+        # 创建一个handler用于输出到控制台(带有颜色)
         console_handler = logging.StreamHandler()
examples/Stockagent/main.py (3)

70-72: Avoid bare exception catching.

Catching Exception without specific handling can hide unexpected errors and make debugging difficult.

Apply this diff to improve error handling:

     except Exception as e:
-        log.logger.error(f"handle_action error: {e}")
+        log.logger.error(f"handle_action error: {e}", exc_info=True)
-        return
+        raise

Alternatively, if you want to continue execution despite errors:

-    except Exception as e:
+    except (KeyError, AttributeError, ValueError) as e:
         log.logger.error(f"handle_action error: {e}")
         return

186-187: Remove unused variable assignment.

The chat_history variable is assigned but never used.

Apply this diff:

         log.logger.debug(f"DAY {date} ends, display forum messages...")
         for agent in all_agents:
-            chat_history = agent.chat_history
             message = agent.post_message()

94-111: Consider removing commented-out code.

Lines 94-111 contain commented-out code related to stock B publishing. If this functionality is no longer needed, remove it entirely. If it might be needed in the future, document why it's commented out or move it to version control history.

examples/Stockagent/runagent_wrapper.py (1)

373-379: Log result-loading failures instead of swallowing them

The bare except: pass hides any problems reading the Excel outputs, making debugging impossible. Please catch Exception explicitly and at least log the failure with context.


-        except: pass
+        except Exception as exc:
+            logging.getLogger(__name__).warning(
+                "Failed to load simulation results from disk",
+                exc_info=exc,
+            )
examples/book_writer/write_a_book_with_flows/README.md (1)

68-68: Hyphenate "book-writing" for consistency.

Line 68 uses "book writing process"; for consistency with other hyphenations in the document (e.g., "multi-agent," "book-writing"), this should be "book-writing process."

examples/book_writer/write_a_book_with_flows/src/write_a_book_with_flows/crews/write_book_chapter_crew/config/tasks.yaml (1)

20-35: Enable the built-in markdown guardrail for chapter drafts.

Since the chapter brief explicitly requires markdown output, please set markdown: true on this task so CrewAI appends the formatting guardrails automatically. This keeps the output consistently structured without depending solely on prompt phrasing.(docs.crewai.com)

 write_chapter:
   description: >
     Write a well-structured chapter based on the chapter title, goal, and outline description. 
     Each chapter should be written in markdown and should contain around 3,000 words.
@@
   expected_output: >
     A markdown-formatted chapter of around 3,000 words that covers the provided chapter title and outline description.
   agent: writer
+  markdown: true
examples/book_writer/write_a_book_with_flows/src/write_a_book_with_flows/crews/outline_book_crew/config/tasks.yaml (1)

11-22: Spell out the JSON shape for the Pydantic hand-off.

generate_outline is parsed into BookOutline, but the prompt never tells the model to emit a JSON object named chapters. Making that explicit in expected_output materially reduces the “string instead of JSON” failures we’ve seen in production when structured outputs are enabled.(docs.crewai.com)

   expected_output: >
-    An outline of chapters, with titles and descriptions of what each chapter will contain.
+    A JSON object with a `chapters` array, where each element has `title` and `description` fields describing the chapter.
   agent: outliner
examples/book_writer/write_a_book_with_flows/src/write_a_book_with_flows/crews/outline_book_crew/outline_crew.py (1)

12-14: Qualify the provider in the model string.

It’s safer to declare the fully-qualified model name (openai/gpt-4o) so alternative defaults (e.g., Anthropic or Gemini) don’t accidentally intercept this crew when environment settings change.(docs.crewai.com)

-    llm = LLM(model="gpt-4o")
+    llm = LLM(model="openai/gpt-4o")
examples/book_writer/write_a_book_with_flows/src/write_a_book_with_flows/main_back.py (1)

55-75: Don’t block the event loop inside write_chapters

WriteBookChapterCrew().crew().kickoff(...) is synchronous and heavy. Calling it directly inside this coroutine blocks the event loop, so the “concurrent” chapter tasks still execute one after another and any other Flow listeners on the same loop stall. Offload that work to a worker thread (e.g., asyncio.to_thread or run_in_executor) so each chapter generation runs truly in parallel.

Apply this diff:

-            output = (
-                WriteBookChapterCrew()
-                .crew()
-                .kickoff(
-                    inputs={
-                        "goal": self.state.goal,
-                        "topic": self.state.topic,
-                        "chapter_title": chapter_outline.title,
-                        "chapter_description": chapter_outline.description,
-                        "book_outline": [
-                            chapter_outline.model_dump_json()
-                            for chapter_outline in self.state.book_outline
-                        ],
-                    }
-                )
-            )
+            crew = WriteBookChapterCrew().crew()
+            output = await asyncio.to_thread(
+                crew.kickoff,
+                inputs={
+                    "goal": self.state.goal,
+                    "topic": self.state.topic,
+                    "chapter_title": chapter_outline.title,
+                    "chapter_description": chapter_outline.description,
+                    "book_outline": [
+                        chapter_outline.model_dump_json()
+                        for chapter_outline in self.state.book_outline
+                    ],
+                },
+            )

Comment on lines +187 to +189
if __name__ == '__main__':
port = int(os.getenv('PORT', 8000))
app.run(host='0.0.0.0', port=port, debug=True) No newline at end of file
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

CRITICAL: Remove debug mode before production deployment.

Running Flask with debug=True in production exposes the Werkzeug debugger, which allows arbitrary code execution and leaks sensitive information. This is a serious security vulnerability.

Apply this diff to make debug mode configurable:

 if __name__ == '__main__':
     port = int(os.getenv('PORT', 8000))
-    app.run(host='0.0.0.0', port=port, debug=True)
+    debug_mode = os.getenv('FLASK_DEBUG', 'false').lower() == 'true'
+    app.run(host='0.0.0.0', port=port, debug=debug_mode)

This allows enabling debug mode only when explicitly set via the FLASK_DEBUG environment variable, defaulting to safe production behavior.

🧰 Tools
🪛 ast-grep (0.39.7)

[warning] 188-188: Detected Flask app with debug=True. Do not deploy to production with this flag enabled as it will leak sensitive information. Instead, consider using Flask configuration variables or setting 'debug' using system environment variables.
Context: app.run(host='0.0.0.0', port=port, debug=True)
Note: [CWE-489] Active Debug Code. [REFERENCES]
- https://labs.detectify.com/2015/10/02/how-patreon-got-hacked-publicly-exposed-werkzeug-debugger/

(debug-enabled-python)

🪛 Ruff (0.14.3)

189-189: Possible binding to all interfaces

(S104)


189-189: Use of debug=True in Flask app detected

(S201)

🤖 Prompt for AI Agents
In examples/book_writer/backend/app.py around lines 187 to 189, the app is
started with debug=True which is unsafe for production; change it to read
FLASK_DEBUG from the environment, convert it to a boolean (e.g. treat
"1","true","True" as true) defaulting to False, and pass that boolean into
app.run(debug=...) so debug mode is only enabled when explicitly set via
FLASK_DEBUG.

"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"axios": "^1.6.0",
Copy link
Copy Markdown

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 axios version for security vulnerabilities.

The axios version ^1.6.0 is approximately 2 years old. Ensure this version doesn't have known security vulnerabilities and consider upgrading to the latest stable version.

Run the following script to check for security advisories:


🏁 Script executed:

#!/bin/bash
# Check for security advisories for axios 1.6.0

gh api graphql -f query='
{
  securityVulnerabilities(first: 10, ecosystem: NPM, package: "axios") {
    nodes {
      advisory {
        summary
        severity
        publishedAt
      }
      vulnerableVersionRange
      firstPatchedVersion {
        identifier
      }
    }
  }
}'

Length of output: 2362


Upgrade axios to 1.12.0 or higher to resolve multiple HIGH severity vulnerabilities.

axios 1.6.0 is affected by three critical HIGH severity vulnerabilities:

  • DoS attack through lack of data size check (requires < 1.12.0)
  • SSRF and Credential Leakage via Absolute URL (requires < 1.8.2)
  • Server-Side Request Forgery (requires 1.7.4+)

Update the version constraint to "^1.12.0" to ensure these vulnerabilities are resolved.

🤖 Prompt for AI Agents
In examples/book_writer/frontend/package.json around line 15, the axios
dependency is pinned to "axios": "^1.6.0" which is vulnerable; update the
version constraint to at least "^1.12.0" to pull a non-vulnerable release, then
run your package manager (npm install or yarn install) and update lockfile
(package-lock.json or yarn.lock) to record the change; finally, run tests or a
quick CI install step to verify no breakage from the minor version upgrade.

Comment on lines +448 to +454
{viewMode === 'full' && result.book_content && (
<div className="mb-6 border-b border-gray-200 pb-6">
<div className="prose prose-lg max-w-none">
<div
className="markdown-content bg-gray-50 rounded-xl p-8 border border-gray-200"
dangerouslySetInnerHTML={formatMarkdown(result.book_content)}
/>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Sanitize generated HTML before injecting

Both result.book_content and each chapter’s content flow straight into dangerouslySetInnerHTML with no sanitization. Because these strings ultimately come from upstream text (LLM output + user prompts), an attacker can inject arbitrary HTML/JS and execute code in the browser. Please sanitize before rendering (e.g., DOMPurify or a trusted markdown renderer) so we keep React’s XSS guarantees intact.

Apply this diff to sanitize the rendered HTML:

-import React, { useState } from 'react';
+import React, { useState } from 'react';
+import DOMPurify from 'dompurify';
@@
-    return { __html: processed.join('\n') };
+    const html = processed.join('\n');
+    return { __html: DOMPurify.sanitize(html) };

Remember to add dompurify (and @types/dompurify for TypeScript) to the frontend dependencies.

Also applies to: 506-513

🧰 Tools
🪛 ast-grep (0.39.7)

[warning] 452-452: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html

(react-unsafe-html-injection)

🪛 Biome (2.1.2)

[error] 453-453: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

Comment on lines +810 to +825
```yaml
api_key: YOUR_API_KEY
project_id: YOUR_PROJECT_ID
```

Replace `YOUR_API_KEY` and `YOUR_PROJECT_ID` with your actual API key and project ID from CrewAI.

**Step 4: Setting Environment Variables**

You can also set environment variables for sensitive information, such as API keys. For example, on Unix-based systems, you can add to your `.bashrc` or `.zshrc`:

```sh
export CREWAI_API_KEY="YOUR_API_KEY"
export CREWAI_PROJECT_ID="YOUR_PROJECT_ID"
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Security: Replace hardcoded credentials in all code examples with environment variable references.

Multiple code examples expose sensitive information (API keys, passwords, database credentials, email credentials) directly in the code. For production-grade documentation, credentials must use environment variables or secrets management.

Affected locations:

  • Lines 810-814: YAML config with placeholders
  • Lines 836-841, 1496-1502: API keys in Python code
  • Lines 905-908, 923: Email credentials
  • Lines 979-987: Email credentials in SMTP example
  • Lines 1074-1078: Database credentials

Example fix (lines 836-841): Replace hardcoded keys with environment variables:

-client = crewai.Client(api_key="YOUR_API_KEY", project_id="YOUR_PROJECT_ID")
+import os
+client = crewai.Client(
+    api_key=os.getenv("CREWAI_API_KEY"),
+    project_id=os.getenv("CREWAI_PROJECT_ID")
+)

Apply the same pattern to all credential-bearing examples (email logins, database URIs, API keys). Consider adding a sidebar note on best practices for credential management across all affected sections.

Also applies to: 836-841, 905-908, 923-923, 979-987, 1074-1078, 1496-1502

🤖 Prompt for AI Agents
In examples/book_writer/write_a_book_with_flows/Automating_Tasks_with_CrewAI.md
around lines 810-825 (and also affecting 836-841, 905-908, 923, 979-987,
1074-1078, 1496-1502), replace all hardcoded credential placeholders and literal
keys with environment-variable references and instructions to load them from a
secure source; update the YAML example to indicate values come from environment
(or a .env/secrets manager) rather than embedding keys, change Python snippets
to read API keys, email logins and DB URIs from os.environ (or a config loader)
instead of literals, update SMTP and DB examples to use env vars for
username/password/host, and add a small sidebar note directing readers to use
environment variables or secrets management and not to commit credentials to
source control.

Comment on lines +16 to +17
# RunAgent SDK
runagent = { path = "/home/azureuser/runagent/runagent-rust/runagent" }
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Replace hardcoded absolute path with relative path.

The hardcoded absolute path /home/azureuser/runagent/runagent-rust/runagent prevents portability and will break on any other machine or environment. This makes the example unusable for other developers.

Apply this diff to use a relative path:

 # RunAgent SDK
-runagent = { path = "/home/azureuser/runagent/runagent-rust/runagent" }
+runagent = { path = "../../../runagent-rust/runagent" }

Adjust the relative path based on the actual repository structure. Alternatively, if the RunAgent SDK is published to crates.io, use a version specification instead.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# RunAgent SDK
runagent = { path = "/home/azureuser/runagent/runagent-rust/runagent" }
# RunAgent SDK
runagent = { path = "../../../runagent-rust/runagent" }
🤖 Prompt for AI Agents
In examples/lead-agent/backend-rust/Cargo.toml around lines 16 to 17, the
dependency uses a hardcoded absolute path (/home/azureuser/...), which breaks
portability; replace it with a relative path pointing to the runagent crate
within the repo (e.g., ../runagent/runagent-rust/runagent or the correct
relative location from this crate), or, if runagent is published, change to a
crates.io version specification; update the path value accordingly so the
manifest works across environments.

Comment on lines +15 to +28
```
rag_agent/
├── agent/ # RunAgent agent implementation
├── backend/ # Flask backend API
│ ├── app.py # Main Flask application
│ └── requirements.txt
├── frontend/ # Frontend web application
│ ├── index.html
│ ├── app.js
│ ├── style.css
│ └── package.json
├── manage_documents.py # Document management utilities
└── README.md
```
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Specify language for fenced code block.

The directory structure code block should specify a language identifier for proper syntax highlighting and rendering.

Apply this diff:

-```
+```text
 rag_agent/
 ├── agent/              # RunAgent agent implementation

As per static analysis hints.

🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

15-15: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
In examples/rag_agent/README.md around lines 15 to 28, the fenced code block
showing the directory tree lacks a language identifier; update the opening fence
from ``` to ```text (i.e., replace the first ``` with ```text) so the block
starts with ```text rag_agent/ ... and ensure the closing ``` remains unchanged,
resulting in a properly annotated fenced code block for correct syntax
highlighting.

Comment on lines +195 to +209
loan_format_check, fail_response, loan = self.secretary.check_loan(resp,
max_loan) # secretary check loan format
while not loan_format_check:
# log.logger.debug("WARNING: Loan format check failed because of these issues: {}".format(fail_response))
try_times += 1
if try_times > MAX_TRY_TIMES:
log.logger.warning("WARNING: Loan format try times > MAX_TRY_TIMES. Skip as no loan today.")
loan = {"loan": "no"}
break

resp = self.run_api(format_prompt(LOAN_RETRY_PROMPT, {"fail_response": fail_response}))
if resp == "":
return {"loan": "no"}
loan_format_check, fail_response, loan = self.secretary.check_loan(date, resp)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix the check_loan retry call signature.

On retries we call self.secretary.check_loan(date, resp), so the LLM response is fed into the max_loan slot. Once the secretary reaches parsed_json["amount"] > max_loan, we hit a TypeError ('>' not supported between instances of 'int' and 'str'). Please keep the original (resp, max_loan) ordering when retrying.

-            loan_format_check, fail_response, loan = self.secretary.check_loan(date, resp)
+            loan_format_check, fail_response, loan = self.secretary.check_loan(resp, max_loan)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
loan_format_check, fail_response, loan = self.secretary.check_loan(resp,
max_loan) # secretary check loan format
while not loan_format_check:
# log.logger.debug("WARNING: Loan format check failed because of these issues: {}".format(fail_response))
try_times += 1
if try_times > MAX_TRY_TIMES:
log.logger.warning("WARNING: Loan format try times > MAX_TRY_TIMES. Skip as no loan today.")
loan = {"loan": "no"}
break
resp = self.run_api(format_prompt(LOAN_RETRY_PROMPT, {"fail_response": fail_response}))
if resp == "":
return {"loan": "no"}
loan_format_check, fail_response, loan = self.secretary.check_loan(date, resp)
loan_format_check, fail_response, loan = self.secretary.check_loan(resp,
max_loan) # secretary check loan format
while not loan_format_check:
# log.logger.debug("WARNING: Loan format check failed because of these issues: {}".format(fail_response))
try_times += 1
if try_times > MAX_TRY_TIMES:
log.logger.warning("WARNING: Loan format try times > MAX_TRY_TIMES. Skip as no loan today.")
loan = {"loan": "no"}
break
resp = self.run_api(format_prompt(LOAN_RETRY_PROMPT, {"fail_response": fail_response}))
if resp == "":
return {"loan": "no"}
loan_format_check, fail_response, loan = self.secretary.check_loan(resp, max_loan)
🧰 Tools
🪛 Ruff (0.14.3)

205-205: LOAN_RETRY_PROMPT may be undefined, or defined from star imports

(F405)

🤖 Prompt for AI Agents
In examples/Stockagent/agent.py around lines 195 to 209 the retry call to
self.secretary.check_loan incorrectly uses (date, resp) causing the LLM response
to be passed as max_loan and leading to type errors; change the retry invocation
to preserve the original argument order (resp, max_loan) so check_loan receives
the response first and the max_loan second, matching the initial call and
avoiding the type mismatch.

Comment on lines +20 to +72
def handle_action(action, stock_deals, all_agents, stock, session):
# action = JSON{"agent": 1, "action_type": "buy"|"sell", "stock": "A"|"B", "amount": 10, "price": 10}
try:
if action["action_type"] == "buy":
for sell_action in stock_deals["sell"][:]:
if action["price"] == sell_action["price"]:
# 交易成交
close_amount = min(action["amount"], sell_action["amount"])
get_agent(all_agents, action["agent"]).buy_stock(stock.name, close_amount, action["price"])
if not sell_action["agent"] == -1: # B发行
get_agent(all_agents, sell_action["agent"]).sell_stock(stock.name, close_amount, action["price"])
stock.add_session_deal({"price": action["price"], "amount": close_amount})
create_trade_record(action["date"], session, stock.name, action["agent"], sell_action["agent"],
close_amount, action["price"])

if action["amount"] > close_amount: # 买单未结束,卖单结束,继续循环
log.logger.info(f"ACTION - BUY:{action['agent']}, SELL:{sell_action['agent']}, "
f"STOCK:{stock.name}, PRICE:{action['price']}, AMOUNT:{close_amount}")
stock_deals["sell"].remove(sell_action)
action["amount"] -= close_amount
else: # 卖单未结束,买单结束
log.logger.info(f"ACTION - BUY:{action['agent']}, SELL:{sell_action['agent']}, "
f"STOCK:{stock.name}, PRICE:{action['price']}, AMOUNT:{close_amount}")
sell_action["amount"] -= close_amount
return
# 遍历卖单后仍然有剩余
stock_deals["buy"].append(action)

else:
for buy_action in stock_deals["buy"][:]:
if action["price"] == buy_action["price"]:
# 交易成交
close_amount = min(action["amount"], buy_action["amount"])
get_agent(all_agents, action["agent"]).sell_stock(stock.name, close_amount, action["price"])
get_agent(all_agents, buy_action["agent"]).buy_stock(stock.name, close_amount, action["price"])
stock.add_session_deal({"price": action["price"], "amount": close_amount})
create_trade_record(action["date"], session, stock.name, buy_action["agent"], action["agent"],
close_amount, action["price"])

if action["amount"] > close_amount: # 卖单未结束,买单结束,继续循环
log.logger.info(f"ACTION - BUY:{buy_action['agent']}, SELL:{action['agent']}, "
f"STOCK:{stock.name}, PRICE:{action['price']}, AMOUNT:{close_amount}")
stock_deals["buy"].remove(buy_action)
action["amount"] -= close_amount
else: # 买单未结束,卖单结束
log.logger.info(f"ACTION - BUY:{buy_action['agent']}, SELL:{action['agent']}, "
f"STOCK:{stock.name}, PRICE:{action['price']}, AMOUNT:{close_amount}")
buy_action["amount"] -= close_amount
return
stock_deals["sell"].append(action)
except Exception as e:
log.logger.error(f"handle_action error: {e}")
return
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: Fix parameter order in stock buy/sell operations.

Lines 28, 30, 53, and 54 have incorrect parameter order when calling buy_stock and sell_stock. According to the Agent class definition in agent.py, the signatures are:

  • buy_stock(self, stock_name, price, amount)
  • sell_stock(self, stock_name, price, amount)

However, the calls pass (stock.name, close_amount, action["price"]) with amount and price swapped.

Apply this diff to fix the parameter order:

                 if action["price"] == sell_action["price"]:
                     # 交易成交
                     close_amount = min(action["amount"], sell_action["amount"])
-                    get_agent(all_agents, action["agent"]).buy_stock(stock.name, close_amount, action["price"])
+                    get_agent(all_agents, action["agent"]).buy_stock(stock.name, action["price"], close_amount)
                     if not sell_action["agent"] == -1:  # B发行
-                        get_agent(all_agents, sell_action["agent"]).sell_stock(stock.name, close_amount, action["price"])
+                        get_agent(all_agents, sell_action["agent"]).sell_stock(stock.name, action["price"], close_amount)
                     stock.add_session_deal({"price": action["price"], "amount": close_amount})
                 if action["price"] == buy_action["price"]:
                     # 交易成交
                     close_amount = min(action["amount"], buy_action["amount"])
-                    get_agent(all_agents, action["agent"]).sell_stock(stock.name, close_amount, action["price"])
-                    get_agent(all_agents, buy_action["agent"]).buy_stock(stock.name, close_amount, action["price"])
+                    get_agent(all_agents, action["agent"]).sell_stock(stock.name, action["price"], close_amount)
+                    get_agent(all_agents, buy_action["agent"]).buy_stock(stock.name, action["price"], close_amount)
                     stock.add_session_deal({"price": action["price"], "amount": close_amount})
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def handle_action(action, stock_deals, all_agents, stock, session):
# action = JSON{"agent": 1, "action_type": "buy"|"sell", "stock": "A"|"B", "amount": 10, "price": 10}
try:
if action["action_type"] == "buy":
for sell_action in stock_deals["sell"][:]:
if action["price"] == sell_action["price"]:
# 交易成交
close_amount = min(action["amount"], sell_action["amount"])
get_agent(all_agents, action["agent"]).buy_stock(stock.name, close_amount, action["price"])
if not sell_action["agent"] == -1: # B发行
get_agent(all_agents, sell_action["agent"]).sell_stock(stock.name, close_amount, action["price"])
stock.add_session_deal({"price": action["price"], "amount": close_amount})
create_trade_record(action["date"], session, stock.name, action["agent"], sell_action["agent"],
close_amount, action["price"])
if action["amount"] > close_amount: # 买单未结束,卖单结束,继续循环
log.logger.info(f"ACTION - BUY:{action['agent']}, SELL:{sell_action['agent']}, "
f"STOCK:{stock.name}, PRICE:{action['price']}, AMOUNT:{close_amount}")
stock_deals["sell"].remove(sell_action)
action["amount"] -= close_amount
else: # 卖单未结束,买单结束
log.logger.info(f"ACTION - BUY:{action['agent']}, SELL:{sell_action['agent']}, "
f"STOCK:{stock.name}, PRICE:{action['price']}, AMOUNT:{close_amount}")
sell_action["amount"] -= close_amount
return
# 遍历卖单后仍然有剩余
stock_deals["buy"].append(action)
else:
for buy_action in stock_deals["buy"][:]:
if action["price"] == buy_action["price"]:
# 交易成交
close_amount = min(action["amount"], buy_action["amount"])
get_agent(all_agents, action["agent"]).sell_stock(stock.name, close_amount, action["price"])
get_agent(all_agents, buy_action["agent"]).buy_stock(stock.name, close_amount, action["price"])
stock.add_session_deal({"price": action["price"], "amount": close_amount})
create_trade_record(action["date"], session, stock.name, buy_action["agent"], action["agent"],
close_amount, action["price"])
if action["amount"] > close_amount: # 卖单未结束,买单结束,继续循环
log.logger.info(f"ACTION - BUY:{buy_action['agent']}, SELL:{action['agent']}, "
f"STOCK:{stock.name}, PRICE:{action['price']}, AMOUNT:{close_amount}")
stock_deals["buy"].remove(buy_action)
action["amount"] -= close_amount
else: # 买单未结束,卖单结束
log.logger.info(f"ACTION - BUY:{buy_action['agent']}, SELL:{action['agent']}, "
f"STOCK:{stock.name}, PRICE:{action['price']}, AMOUNT:{close_amount}")
buy_action["amount"] -= close_amount
return
stock_deals["sell"].append(action)
except Exception as e:
log.logger.error(f"handle_action error: {e}")
return
def handle_action(action, stock_deals, all_agents, stock, session):
# action = JSON{"agent": 1, "action_type": "buy"|"sell", "stock": "A"|"B", "amount": 10, "price": 10}
try:
if action["action_type"] == "buy":
for sell_action in stock_deals["sell"][:]:
if action["price"] == sell_action["price"]:
# 交易成交
close_amount = min(action["amount"], sell_action["amount"])
get_agent(all_agents, action["agent"]).buy_stock(stock.name, action["price"], close_amount)
if not sell_action["agent"] == -1: # B发行
get_agent(all_agents, sell_action["agent"]).sell_stock(stock.name, action["price"], close_amount)
stock.add_session_deal({"price": action["price"], "amount": close_amount})
create_trade_record(action["date"], session, stock.name, action["agent"], sell_action["agent"],
close_amount, action["price"])
if action["amount"] > close_amount: # 买单未结束,卖单结束,继续循环
log.logger.info(f"ACTION - BUY:{action['agent']}, SELL:{sell_action['agent']}, "
f"STOCK:{stock.name}, PRICE:{action['price']}, AMOUNT:{close_amount}")
stock_deals["sell"].remove(sell_action)
action["amount"] -= close_amount
else: # 卖单未结束,买单结束
log.logger.info(f"ACTION - BUY:{action['agent']}, SELL:{sell_action['agent']}, "
f"STOCK:{stock.name}, PRICE:{action['price']}, AMOUNT:{close_amount}")
sell_action["amount"] -= close_amount
return
# 遍历卖单后仍然有剩余
stock_deals["buy"].append(action)
else:
for buy_action in stock_deals["buy"][:]:
if action["price"] == buy_action["price"]:
# 交易成交
close_amount = min(action["amount"], buy_action["amount"])
get_agent(all_agents, action["agent"]).sell_stock(stock.name, action["price"], close_amount)
get_agent(all_agents, buy_action["agent"]).buy_stock(stock.name, action["price"], close_amount)
stock.add_session_deal({"price": action["price"], "amount": close_amount})
create_trade_record(action["date"], session, stock.name, buy_action["agent"], action["agent"],
close_amount, action["price"])
if action["amount"] > close_amount: # 卖单未结束,买单结束,继续循环
log.logger.info(f"ACTION - BUY:{buy_action['agent']}, SELL:{action['agent']}, "
f"STOCK:{stock.name}, PRICE:{action['price']}, AMOUNT:{close_amount}")
stock_deals["buy"].remove(buy_action)
action["amount"] -= close_amount
else: # 买单未结束,卖单结束
log.logger.info(f"ACTION - BUY:{buy_action['agent']}, SELL:{action['agent']}, "
f"STOCK:{stock.name}, PRICE:{action['price']}, AMOUNT:{close_amount}")
buy_action["amount"] -= close_amount
return
stock_deals["sell"].append(action)
except Exception as e:
log.logger.error(f"handle_action error: {e}")
return
🧰 Tools
🪛 Ruff (0.14.3)

35-35: Comment contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF003)


35-35: Comment contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF003)


40-40: Comment contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF003)


59-59: Comment contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF003)


59-59: Comment contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF003)


64-64: Comment contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF003)


70-70: Do not catch blind exception: Exception

(BLE001)

🤖 Prompt for AI Agents
In examples/Stockagent/main.py around lines 20 to 72, four calls (lines ~28, 30,
53, 54) pass parameters to buy_stock/sell_stock in the wrong order (stock.name,
amount, price); change each to match Agent signatures buy_stock(stock_name,
price, amount) and sell_stock(stock_name, price, amount) by swapping the price
and amount arguments (i.e., use stock.name, action["price"], close_amount) for
all four calls.

Comment on lines +7 to +18
def run_api(model, prompt, temperature: float = 0):
openai.api_key = ""
client = openai.OpenAI(api_key=openai.api_key)
response = client.chat.completions.create(
model=model,
messages=[
{"role": "user", "content": prompt},
],
temperature=temperature,
)
resp = response.choices[0].message.content
return resp
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Restore OpenAI authentication before calling the API.

Blanking out openai.api_key forces every completion request to fail with 401, so the Stockagent flow can never get a model response. Please read the key from configuration instead of hard-coding an empty string, and fail fast if it’s missing.

 def run_api(model, prompt, temperature: float = 0):
-    openai.api_key = ""
-    client = openai.OpenAI(api_key=openai.api_key)
+    api_key = os.getenv("OPENAI_API_KEY")
+    if not api_key:
+        raise RuntimeError("OPENAI_API_KEY is not configured; cannot call OpenAI chat completions.")
+    client = openai.OpenAI(api_key=api_key)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def run_api(model, prompt, temperature: float = 0):
openai.api_key = ""
client = openai.OpenAI(api_key=openai.api_key)
response = client.chat.completions.create(
model=model,
messages=[
{"role": "user", "content": prompt},
],
temperature=temperature,
)
resp = response.choices[0].message.content
return resp
def run_api(model, prompt, temperature: float = 0):
api_key = os.getenv("OPENAI_API_KEY")
if not api_key:
raise RuntimeError("OPENAI_API_KEY is not configured; cannot call OpenAI chat completions.")
client = openai.OpenAI(api_key=api_key)
response = client.chat.completions.create(
model=model,
messages=[
{"role": "user", "content": prompt},
],
temperature=temperature,
)
resp = response.choices[0].message.content
return resp
🤖 Prompt for AI Agents
In examples/Stockagent/secretary.py around lines 7 to 18, the code clears
openai.api_key (causing 401s); instead read the API key from configuration or
environment (e.g., a config loader or os.environ["OPENAI_API_KEY"]) and assign
it to openai.api_key before creating the client, and if the key is missing raise
a clear error or exit fast so the caller immediately knows authentication is not
configured.

Comment on lines +1 to +5
"""
DONT FORGET TO DELETE!!!
"""
OPENAI_API_KEY = ""
GOOGLE_API_KEY = ""
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Remove hardcoded API key placeholders and use environment variables.

The hardcoded API key placeholders (lines 4-5) with the "DONT FORGET TO DELETE!!!" comment represent a security risk pattern. Even though they're currently empty, this pattern encourages developers to paste actual keys into source code.

Apply this diff to use environment variables instead:

-"""
-DONT FORGET TO DELETE!!!
-"""
-OPENAI_API_KEY = ""
-GOOGLE_API_KEY = ""
+import os
+
+# API keys should be set via environment variables
+OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY", "")
+GOOGLE_API_KEY = os.environ.get("GOOGLE_API_KEY", "")

Also add a note in the project README or a .env.example file documenting the required environment variables.

🤖 Prompt for AI Agents
In examples/Stockagent/util.py around lines 1 to 5, remove the hardcoded API key
placeholders and instead load keys from environment variables (e.g.,
OPENAI_API_KEY and GOOGLE_API_KEY) using a secure environment-access method
(os.environ.get or dotenv if project uses .env), fail fast or raise a clear
error if required variables are missing, and delete the "DONT FORGET TO
DELETE!!!" comment; additionally add or update a .env.example (or README)
documenting the required environment variable names and expected format for
developers.

@sawradip sawradip merged commit 7aa44e4 into main Nov 6, 2025
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants