diff --git a/python/configs/agent_cards/sec_agent.json b/python/configs/agent_cards/sec_agent.json index c0dbd0d85..ddbc072c8 100644 --- a/python/configs/agent_cards/sec_agent.json +++ b/python/configs/agent_cards/sec_agent.json @@ -2,7 +2,6 @@ "name": "SecAgent", "display_name": "SEC Agent", "url": "http://localhost:10003/", - "icon_url": "https://valuecell-test.oss-cn-hangzhou.aliyuncs.com/images/sec_agent.png", "description": "SecAgent can analyze SEC filings like 10-Q, 10-K, 13-F and analyze stock holdings of institutional investment managers. It can chat about stock performance, financial metrics, and market trends or track specific stocks and provide updates.", "skills": [ { diff --git a/python/valuecell/agents/sec_agent.py b/python/valuecell/agents/sec_agent.py index 1d90230d6..c03bad447 100644 --- a/python/valuecell/agents/sec_agent.py +++ b/python/valuecell/agents/sec_agent.py @@ -1,5 +1,6 @@ import asyncio import hashlib +import json import logging import os from datetime import datetime @@ -17,6 +18,7 @@ # Configure logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) +SEC_FILLINGS_COMPONENT_TYPE = "sec_feed" class QueryType(str, Enum): @@ -201,7 +203,7 @@ async def _detect_filing_changes( async def _generate_filing_summary( self, ticker: str, changed_filings: Dict[str, bool] ) -> str: - """Generate AI summary of filing changes""" + """Generate AI summary of filing changes in JSON format""" try: changed_types = [ filing_type @@ -210,7 +212,7 @@ async def _generate_filing_summary( ] if not changed_types: - return f"No new filings detected for {ticker}." + return "" summary_prompt = f""" New SEC filings have been detected for {ticker}. The following filing types have been updated: @@ -228,11 +230,26 @@ async def _generate_filing_summary( """ response = await self.analysis_agent.arun(summary_prompt) - return response.content + + # Create JSON structure + summary_data = { + "ticker": ticker, + "source": "SEC", + "data": response.content, + "create_time": datetime.now().isoformat(), + } + + return json.dumps(summary_data) except Exception as e: logger.error(f"Failed to generate filing summary: {e}") - return f"New filings detected for {ticker}: {', '.join(changed_types)}, but summary generation failed." + error_summary_data = { + "ticker": ticker, + "source": "SEC", + "data": f"New filings detected for {ticker}: {', '.join(changed_types) if 'changed_types' in locals() else 'unknown'}, but summary generation failed.", + "create_time": datetime.now().isoformat(), + } + return "" async def _classify_query(self, query: str) -> QueryType: """ @@ -569,7 +586,10 @@ async def notify(self, query: str, session_id: str, task_id: str): ticker, changes ) - yield notification.component_generator(summary, "sec_feed") + if summary: + yield notification.component_generator( + summary, SEC_FILLINGS_COMPONENT_TYPE + ) # Wait before next check await asyncio.sleep(check_interval) diff --git a/start.sh b/start.sh new file mode 100755 index 000000000..c6c8489bc --- /dev/null +++ b/start.sh @@ -0,0 +1,183 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +# Simple project launcher with auto-install for bun and uv +# - macOS: use Homebrew to install missing tools +# - other OS: print guidance + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}" )" && pwd)" +FRONTEND_DIR="$SCRIPT_DIR/frontend" +PY_DIR="$SCRIPT_DIR/python" + +BACKEND_PID="" +FRONTEND_PID="" + +info() { echo "[INFO] $*"; } +success(){ echo "[ OK ] $*"; } +warn() { echo "[WARN] $*"; } +error() { echo "[ERR ] $*" 1>&2; } + +command_exists() { command -v "$1" >/dev/null 2>&1; } + +ensure_brew_on_macos() { + if [[ "${OSTYPE:-}" == darwin* ]]; then + if ! command_exists brew; then + error "Homebrew is not installed. Please install Homebrew: https://brew.sh/" + error "Example install: /bin/bash -c \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\"" + exit 1 + fi + fi +} + +ensure_tool() { + local tool_name="$1"; shift + local brew_formula="$1"; shift || true + + if command_exists "$tool_name"; then + success "$tool_name is installed ($($tool_name --version 2>/dev/null | head -n1 || echo version unknown))" + return 0 + fi + + case "$(uname -s)" in + Darwin) + ensure_brew_on_macos + info "Installing $tool_name via Homebrew..." + brew install "$brew_formula" + ;; + Linux) + info "Detected Linux, auto-installing $tool_name..." + if [[ "$tool_name" == "bun" ]]; then + curl -fsSL https://bun.sh/install | bash + # Add Bun default install dir to PATH (current process only) + if ! command_exists bun && [[ -x "$HOME/.bun/bin/bun" ]]; then + export PATH="$HOME/.bun/bin:$PATH" + fi + elif [[ "$tool_name" == "uv" ]]; then + curl -LsSf https://astral.sh/uv/install.sh | sh + # Add uv default install dir to PATH (current process only) + if ! command_exists uv && [[ -x "$HOME/.local/bin/uv" ]]; then + export PATH="$HOME/.local/bin:$PATH" + fi + else + warn "Unknown tool: $tool_name" + fi + ;; + *) + warn "$tool_name not installed. Auto-install is not provided on this OS. Please install manually and retry." + exit 1 + ;; + esac + + if command_exists "$tool_name"; then + success "$tool_name installed successfully" + else + error "$tool_name installation failed. Please install manually and retry." + exit 1 + fi +} + +install_dependencies() { + # Backend deps + if [[ -d "$PY_DIR" ]]; then + info "Sync Python dependencies (uv sync)..." + (cd "$PY_DIR" && uv sync) + success "Python dependencies synced" + else + warn "Backend directory not found: $PY_DIR. Skipping" + fi + + # Frontend deps + if [[ -d "$FRONTEND_DIR" ]]; then + info "Install frontend dependencies (bun install)..." + (cd "$FRONTEND_DIR" && bun install) + success "Frontend dependencies installed" + } else { + warn "Frontend directory not found: $FRONTEND_DIR. Skipping" + fi +} + +start_backend() { + if [[ ! -d "$PY_DIR" ]]; then + warn "Backend directory not found; skipping backend start" + return 0 + fi + info "Starting backend (uv run python -m valuecell.server.main)..." + ( + cd "$PY_DIR" && uv run python -m valuecell.server.main + ) & BACKEND_PID=$! + info "Backend PID: $BACKEND_PID" +} + +start_frontend() { + if [[ ! -d "$FRONTEND_DIR" ]]; then + warn "Frontend directory not found; skipping frontend start" + return 0 + fi + info "Starting frontend dev server (bun run dev)..." + ( + cd "$FRONTEND_DIR" && bun run dev + ) & FRONTEND_PID=$! + info "Frontend PID: $FRONTEND_PID" +} + +cleanup() { + echo + info "Stopping services..." + if [[ -n "$FRONTEND_PID" ]] && kill -0 "$FRONTEND_PID" 2>/dev/null; then + kill "$FRONTEND_PID" 2>/dev/null || true + fi + if [[ -n "$BACKEND_PID" ]] && kill -0 "$BACKEND_PID" 2>/dev/null; then + kill "$BACKEND_PID" 2>/dev/null || true + fi + success "Stopped" +} + +trap cleanup EXIT INT TERM + +print_usage() { + cat <<'EOF' +Usage: ./start.sh [options] + +Description: + - Checks whether bun and uv are installed; on macOS, missing tools will be auto-installed via Homebrew. + - Then installs backend and frontend dependencies and starts services. + +Options: + --no-frontend Start backend only + --no-backend Start frontend only + -h, --help Show help +EOF +} + +main() { + local start_frontend_flag=1 + local start_backend_flag=1 + + while [[ $# -gt 0 ]]; do + case "$1" in + --no-frontend) start_frontend_flag=0; shift ;; + --no-backend) start_backend_flag=0; shift ;; + -h|--help) print_usage; exit 0 ;; + *) error "Unknown argument: $1"; print_usage; exit 1 ;; + esac + done + + # Ensure tools + ensure_tool bun oven-sh/bun/bun + ensure_tool uv uv + + install_dependencies + + if (( start_backend_flag )); then + start_backend + fi + if (( start_frontend_flag )); then + start_frontend + fi + + info "Services started. Press Ctrl+C to stop." + # Wait for background jobs + wait +} + +main "$@" \ No newline at end of file