Added examples and Rust SDK fix#78
Conversation
|
Caution Review failedFailed to post review comments WalkthroughThis 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
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120+ minutes Areas requiring special attention:
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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) andREADME.md(crewai==0.130.0). See the corresponding issue raised forrequirements.txtfor unified resolution.
🧹 Nitpick comments (47)
examples/lead-agent/lead-score-flow/requirements.txt (1)
1-3: Inconsistent version pinning reduces reproducibility.
crewaiis pinned to a specific version (1.2.0), butopenaiandPyYAMLare 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
openaiandPyYAMLto 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.envand__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.13will 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
textormermaid(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 Flaskexamples/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: Replaceprintln!with structured logging.Debug output uses
println!which lacks structure, log levels, and timestamps. Consider using thetracingcrate 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 witheprintln!for errors is inconsistent.Consider structured logging and clearer result handling:
match client.run_with_args(&[], ¶ms).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'sloggingmodule 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
Exceptioncatch 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
+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_testsuggests this is temporary or placeholder code. For a committed example, consider a more descriptive name likestockagent_exampleorrunagent_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_chaptersis 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_testis reasonable, but for consistency with other examples in the PR, consider whether a shorter name likelead_agent_examplewould 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.0binding 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.0This prevents unexpected breaking changes from upstream package updates.
examples/book_writer/backend/app.py (1)
1-7: Remove unused import.The
datetimemodule 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 ioexamples/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_leadsexamples/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=Trueon the Task itself (line 24) is not seen in similar crew implementations in this PR. The Crew already hasverbose=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 parameteris_new.The
is_newparameter is accepted but never used within the class. Based on the usage inmain.py, it's always passed asFalseand 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) andrunagent_wrapper.pyif 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 thelog/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
Exceptionwithout 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 + raiseAlternatively, 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_historyvariable 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 themThe bare
except: passhides any problems reading the Excel outputs, making debugging impossible. Please catchExceptionexplicitly 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: trueon 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: trueexamples/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_outlineis parsed intoBookOutline, but the prompt never tells the model to emit a JSON object namedchapters. Making that explicit inexpected_outputmaterially 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: outlinerexamples/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 insidewrite_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_threadorrun_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 + ], + }, + )
| 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 |
There was a problem hiding this comment.
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", |
There was a problem hiding this comment.
🧩 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.
| {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)} | ||
| /> |
There was a problem hiding this comment.
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)
| ```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" | ||
| ``` | ||
|
|
There was a problem hiding this comment.
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.
| # RunAgent SDK | ||
| runagent = { path = "/home/azureuser/runagent/runagent-rust/runagent" } |
There was a problem hiding this comment.
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.
| # 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.
| ``` | ||
| 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 | ||
| ``` |
There was a problem hiding this comment.
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 implementationAs 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.
| 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) | ||
|
|
There was a problem hiding this comment.
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.
| 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.
| 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 |
There was a problem hiding this comment.
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.
| 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.
| 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 |
There was a problem hiding this comment.
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.
| 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.
| """ | ||
| DONT FORGET TO DELETE!!! | ||
| """ | ||
| OPENAI_API_KEY = "" | ||
| GOOGLE_API_KEY = "" |
There was a problem hiding this comment.
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.
Restructure the RUST sdk codebase as well as added new examples which will run in both local and RunAgent Cloud
Summary by CodeRabbit