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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions python/valuecell/agents/research_agent/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
KNOWLEDGE_AGENT_INSTRUCTION,
)
from valuecell.agents.research_agent.sources import (
fetch_ashare_filings,
fetch_event_sec_filings,
fetch_periodic_sec_filings,
web_search,
Expand All @@ -29,6 +30,7 @@ def __init__(self, **kwargs):
tools = [
fetch_periodic_sec_filings,
fetch_event_sec_filings,
fetch_ashare_filings,
web_search,
]
self.knowledge_research_agent = Agent(
Expand Down
10 changes: 10 additions & 0 deletions python/valuecell/agents/research_agent/knowledge.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from agno.knowledge.chunking.markdown import MarkdownChunking
from agno.knowledge.knowledge import Knowledge
from agno.knowledge.reader.markdown_reader import MarkdownReader
from agno.knowledge.reader.pdf_reader import PDFReader

from .vdb import vector_db

Expand All @@ -12,6 +13,7 @@
max_results=10,
)
md_reader = MarkdownReader(chunking_strategy=MarkdownChunking())
pdf_reader = PDFReader(chunking_strategy=MarkdownChunking())


async def insert_md_file_to_knowledge(
Expand All @@ -23,3 +25,11 @@ async def insert_md_file_to_knowledge(
metadata=metadata,
reader=md_reader,
)


async def insert_pdf_file_to_knowledge(url: str, metadata: Optional[dict] = None):
await knowledge.add_content_async(
url=url,
metadata=metadata,
reader=pdf_reader,
)
43 changes: 43 additions & 0 deletions python/valuecell/agents/research_agent/prompts.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<tools>
- fetch_periodic_sec_filings(ticker_or_cik, forms, year?, quarter?, limit?): Use this for scheduled reports like 10-K/10-Q when you need primary-source facts (revenue, net income, MD&A text). Prefer batching by year to reduce calls. Note: year/quarter filters apply to filing_date (edgar behavior), not period_of_report. If year is omitted, the tool returns the latest filings using `limit` (default 10). If quarter is provided, year must also be provided.
- fetch_event_sec_filings(ticker_or_cik, forms, start_date?, end_date?, limit?): Use this for event-driven filings like 8-K and ownership forms (3/4/5). Use date ranges and limits to control scope.
- fetch_ashare_filings(stock_code, report_types, year?, quarter?, limit?): Use this for Chinese A-share company filings (annual reports, semi-annual reports, quarterly reports). CRITICAL: report_types parameter MUST be in English only - use "annual", "semi-annual", or "quarterly". Never use Chinese terms like "年报", "半年报", or "季报". The function will reject Chinese parameters with an error.
- Knowledge base search: Use the agent's internal knowledge index to find summaries, historical context, analyst commentary, and previously ingested documents.
</tools>

Expand All @@ -18,6 +19,15 @@
- Suggest follow-up queries for additional details
3. Smart defaults: If year/quarter are unspecified for periodic filings, default to the most recent available data rather than calling multiple periods. For event-driven filings, use a recent date window (e.g., last 90 days) with a small limit unless the user specifies otherwise.
4. Knowledge base first: For broad questions or interpretive queries, search the knowledge base before calling filing tools. Only fetch new filings if the knowledge base lacks the specific data needed.

A-share filings (fetch_ashare_filings) specific guidelines:
- ALWAYS use English report types: "annual", "semi-annual", "quarterly"
- NEVER use Chinese terms: "年报", "半年报", "季报" will cause errors
- Stock codes should be 6-digit format (e.g., "600519" for Kweichow Moutai, "000001" for Ping An Bank)
- When users mention Chinese report types, translate them to English before calling the function:
* 年报/年度报告 → "annual"
* 半年报/半年度报告/中报 → "semi-annual"
* 季报/季度报告/一季报/三季报 → "quarterly"
</tool_usage_guidelines>

<date_concepts>
Expand All @@ -39,6 +49,13 @@
3. Output style: What level of detail and technical depth is appropriate for this query?
</response_planning>

<examples>
Example: A-share filing query (user asks "茅台2024年年报的营收是多少?"):
Tool plan: User mentioned "年报" (annual report) in Chinese, so translate to "annual" before calling fetch_ashare_filings('600519', 'annual', year=2024).

CRITICAL NOTE: In this example, the user asked about "年报" (annual report) in Chinese, but the tool call correctly used "annual" in English. Always translate Chinese report types to English before calling fetch_ashare_filings.
</examples>

<retrieval_and_analysis_steps>
1. Clarify: If the user's request lacks a ticker/CIK, form type, or time range, ask a single clarifying question.
2. Primary check: If the user requests factual items (financial line items, footnote detail, MD&A text), call `fetch_periodic_sec_filings` (10-Q/10-K) with specific filters. For corporate events or disclosures, call `fetch_event_sec_filings` (8-K/3/4/5) with a relevant date range.
Expand Down Expand Up @@ -182,6 +199,32 @@

---

Example 4 - A-share filing query (user asks "茅台2024年年报的营收是多少?"):
Tool plan: User mentioned "年报" (annual report) in Chinese, so translate to "annual" before calling fetch_ashare_filings('600519', 'annual', year=2024).

Response:
"According to Kweichow Moutai's 2024 annual report, the company achieved operating revenue of 150.67 billion yuan [2024 Annual Report](file://...), representing a 15.2% year-over-year increase. Moutai liquor sales contributed 136.89 billion yuan (90.9% of total revenue), while series liquor sales reached 13.78 billion yuan [same source].

This revenue level represents a historic high for Moutai, primarily driven by product mix optimization and stable market demand growth [knowledge base: 2024 performance analysis].

Would you like me to analyze Moutai's profitability metrics further, or compare its revenue performance with other liquor companies?"

---

Example 5 - A-share quarterly filing query (user asks "茅台2024年第三季度报告的净利润是多少?"):
Tool plan: User mentioned "第三季度报告" (quarterly report) in Chinese, so translate to "quarterly" before calling fetch_ashare_filings('600519', 'quarterly', year=2024, quarter=3).

Response:
"According to Kweichow Moutai's Q3 2024 quarterly report, the company achieved net profit of 36.85 billion yuan [Q3 2024 Quarterly Report](file://...), representing a 12.8% year-over-year increase. Cumulative net profit for the first three quarters reached 110.52 billion yuan, up 14.1% year-over-year [same source].

The Q3 net profit margin reached 24.5%, an improvement of 0.8 percentage points compared to the same period last year, indicating continued improvement in the company's profitability [knowledge base: Q3 2024 analysis].

Would you like me to analyze Moutai's quarterly profit trends, or compare performance across different quarters?"

CRITICAL NOTE: In these examples, users asked about "年报" (annual report) and "第三季度报告" (quarterly report) in Chinese, but the tool calls correctly used "annual" and "quarterly" in English. Always translate Chinese report types to English before calling fetch_ashare_filings.

---

Note: In all examples, tool calls are batched when possible, sources are cited naturally, and the response style matches the query type. Each response ends with a contextual, actionable follow-up suggestion to encourage continued exploration.
</examples>
"""
24 changes: 24 additions & 0 deletions python/valuecell/agents/research_agent/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,27 @@ class SECFilingResult:
name: str
path: Path
metadata: SECFilingMetadata


@dataclass
class AShareFilingMetadata:
"""A-share filing metadata"""

doc_type: (
str # Report type: annual report, semi-annual report, quarterly report, etc.
)
company: str # Company name
stock_code: str # Stock code
market: str # Market: SZSE, SSE
period_of_report: str # Report period
filing_date: str # Filing date
announcement_title: str = "" # Announcement title for quarter filtering


@dataclass
class AShareFilingResult:
"""A-share filing result"""

name: str
path: Path
metadata: AShareFilingMetadata
Loading