-
Notifications
You must be signed in to change notification settings - Fork 1
feat: Increase MAX_CONTENT_LENGTH to 50,000 chars and make it configurable #46
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
0713d57
db20af3
c00a18f
919d425
fc6232a
b6103b4
bfdf872
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| # Copyright (c) 2024 Travis Frisinger | ||
| # | ||
| # This source code is licensed under the MIT license found in the | ||
| # LICENSE file in the root directory of this source tree. | ||
|
|
||
| """Perplexity API client - deep research search using Perplexity's sonar models.""" | ||
|
|
||
| import logging | ||
| from typing import List, Literal | ||
|
|
||
| from perplexity import Perplexity | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| def fetch_perplexity_deep_research( | ||
| query: str, | ||
| api_key: str, | ||
| max_results: int = 5, | ||
| research_effort: Literal["low", "medium", "high"] = "high", | ||
| ) -> tuple[str, List[str]]: | ||
| """ | ||
| Fetch deep research results from Perplexity AI using official SDK. | ||
|
|
||
| Uses Perplexity's sonar-deep-research model which performs dozens of searches, | ||
| reads hundreds of sources, and reasons through material to deliver comprehensive | ||
| research reports. This is ideal for in-depth analysis and multi-source synthesis. | ||
|
|
||
| Args: | ||
| query: The research query/question | ||
| api_key: Perplexity API key | ||
| max_results: Maximum number of results to return (default: 5) | ||
| research_effort: Computational effort level - "low" (fast), "medium" (balanced), | ||
| or "high" (deepest research). Only applies to sonar-deep-research. | ||
|
|
||
| Returns: | ||
| Tuple of (research_report: str, citations: List[str]) | ||
| - research_report: Full synthesized research content in markdown | ||
| - citations: List of citation URLs used in the research | ||
| """ | ||
| try: | ||
| logger.info( | ||
| f"Fetching Perplexity deep research (effort: {research_effort}): {query}" | ||
| ) | ||
|
|
||
| # Initialize Perplexity client with 10-minute timeout for deep research | ||
| client = Perplexity(api_key=api_key, timeout=600.0) | ||
|
|
||
| # Create chat completion with deep research | ||
| # Note: Official SDK may not support all parameters, using minimal set | ||
| response = client.chat.completions.create( | ||
| model="sonar-deep-research", | ||
| messages=[ | ||
| { | ||
| "role": "system", | ||
| "content": ( | ||
| "You are a comprehensive research assistant. Provide detailed, " | ||
| "well-researched answers with clear structure and citations. " | ||
| f"Focus on returning {max_results} most relevant sources." | ||
| ), | ||
| }, | ||
| {"role": "user", "content": query}, | ||
| ], | ||
| ) | ||
|
|
||
| # Extract research content | ||
| research_report = "" | ||
| citation_urls: List[str] = [] | ||
|
|
||
| if response.choices and len(response.choices) > 0: | ||
| research_report = response.choices[0].message.content or "" | ||
|
|
||
| # Extract citations from response | ||
| if hasattr(response, "citations") and response.citations: | ||
| citation_urls = [ | ||
| citation if isinstance(citation, str) else citation.get("url", "") | ||
| for citation in response.citations | ||
| if citation | ||
| ][:max_results] | ||
|
|
||
| token_count = ( | ||
| response.usage.total_tokens if hasattr(response, "usage") else "N/A" | ||
| ) | ||
| logger.info( | ||
| f"Perplexity deep research completed: {len(research_report)} chars, " | ||
| f"{len(citation_urls)} citations, {token_count} tokens" | ||
| ) | ||
|
|
||
| return research_report, citation_urls | ||
|
|
||
| except Exception as e: | ||
| logger.exception(f"Error fetching Perplexity deep research: {str(e)}") | ||
| return "", [] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,8 @@ | |
|
|
||
| """Constants for WebCat application.""" | ||
|
|
||
| import os | ||
|
|
||
| # Application version | ||
| VERSION = "2.3.1" | ||
|
|
||
|
|
@@ -22,7 +24,10 @@ | |
| ] | ||
|
|
||
| # Content limits | ||
| MAX_CONTENT_LENGTH = 8000 | ||
| try: | ||
| MAX_CONTENT_LENGTH = int(os.environ.get("MAX_CONTENT_LENGTH", "1000000")) | ||
| except ValueError: | ||
| MAX_CONTENT_LENGTH = 1000000 | ||
|
Comment on lines
+27
to
+30
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Critical: Default value contradicts PR objectives. The PR title and objectives state increasing Additionally, the current implementation has no validation:
Apply this diff to align with PR objectives and add validation: -try:
- MAX_CONTENT_LENGTH = int(os.environ.get("MAX_CONTENT_LENGTH", "1000000"))
-except ValueError:
- MAX_CONTENT_LENGTH = 1000000
+try:
+ MAX_CONTENT_LENGTH = int(os.environ.get("MAX_CONTENT_LENGTH", "50000"))
+ if MAX_CONTENT_LENGTH <= 0:
+ logger.warning(
+ f"Invalid MAX_CONTENT_LENGTH={MAX_CONTENT_LENGTH}, using default 50000"
+ )
+ MAX_CONTENT_LENGTH = 50000
+except ValueError as e:
+ logger.warning(
+ f"Invalid MAX_CONTENT_LENGTH format: {e}, using default 50000"
+ )
+ MAX_CONTENT_LENGTH = 50000Note: You'll need to add
|
||
| DEFAULT_SEARCH_RESULTS = 5 | ||
|
|
||
| # Timeout settings | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| #!/usr/bin/env python3 | ||
| # Copyright (c) 2024 Travis Frisinger | ||
| # | ||
| # This source code is licensed under the MIT license found in the | ||
| # LICENSE file in the root directory of this source tree. | ||
|
|
||
| """Test deep_research tool via MCP server.""" | ||
|
|
||
| import json | ||
|
|
||
| import requests | ||
|
|
||
| MCP_SERVER_URL = "http://localhost:8000/mcp" | ||
|
|
||
| # Create session with required headers | ||
| session = requests.Session() | ||
| session.headers.update({"Accept": "application/json, text/event-stream"}) | ||
|
|
||
| # Step 1: Initialize | ||
| print("🔧 Initializing MCP session...") | ||
| init_payload = { | ||
| "jsonrpc": "2.0", | ||
| "id": 1, | ||
| "method": "initialize", | ||
| "params": { | ||
| "protocolVersion": "2024-11-05", | ||
| "capabilities": {}, | ||
| "clientInfo": {"name": "test-client", "version": "1.0.0"}, | ||
| }, | ||
| } | ||
|
|
||
| init_resp = session.post(MCP_SERVER_URL, json=init_payload) | ||
| session_id = init_resp.headers.get("mcp-session-id") | ||
| print(f"✅ Session ID: {session_id}\n") | ||
|
|
||
| # Step 2: Send initialized notification | ||
| print("🔔 Sending initialized notification...") | ||
| initialized_payload = {"jsonrpc": "2.0", "method": "notifications/initialized"} | ||
| session.post( | ||
| MCP_SERVER_URL, json=initialized_payload, headers={"mcp-session-id": session_id} | ||
| ) | ||
|
|
||
| # Step 3: Call deep_research tool | ||
| print("\n🔍 Calling deep_research tool...") | ||
| print("Query: What is Python programming language?") | ||
| print("Effort: low") | ||
| print("\nThis will take ~1-2 minutes...\n") | ||
|
|
||
| tool_payload = { | ||
| "jsonrpc": "2.0", | ||
| "id": 2, | ||
| "method": "tools/call", | ||
| "params": { | ||
| "name": "deep_research", | ||
| "arguments": { | ||
| "query": "What is Python programming language?", | ||
| "research_effort": "low", | ||
| "max_results": 5, | ||
| }, | ||
| }, | ||
| } | ||
|
|
||
| tool_resp = session.post( | ||
| MCP_SERVER_URL, | ||
| json=tool_payload, | ||
| headers={"mcp-session-id": session_id}, | ||
| timeout=300, | ||
| ) | ||
|
|
||
| print(f"Status: {tool_resp.status_code}\n") | ||
|
|
||
| # Parse SSE response | ||
| if tool_resp.status_code == 200: | ||
| lines = tool_resp.text.strip().split("\n") | ||
| for line in lines: | ||
| if line.startswith("data: "): | ||
| data_json = line[6:] # Remove "data: " prefix | ||
| result = json.loads(data_json) | ||
|
|
||
| if "result" in result and "content" in result["result"]: | ||
| content = result["result"]["content"] | ||
| if isinstance(content, list) and len(content) > 0: | ||
| text_content = content[0].get("text", "") | ||
| # Parse the JSON string inside text | ||
| research_result = json.loads(text_content) | ||
|
|
||
| print("=" * 80) | ||
| print("DEEP RESEARCH RESULT:") | ||
| print("=" * 80) | ||
| print(f"Query: {research_result.get('query')}") | ||
| print(f"Source: {research_result.get('search_source')}") | ||
| print(f"Results: {len(research_result.get('results', []))}") | ||
|
|
||
| if research_result.get("results"): | ||
| print("\n" + "=" * 80) | ||
| print("RESEARCH REPORT:") | ||
| print("=" * 80) | ||
| print(research_result["results"][0].get("content", "")) | ||
|
|
||
| break | ||
| else: | ||
| print(f"❌ Error: {tool_resp.text}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Documentation contradicts PR objectives.
The documented default of
1,000,000contradicts the PR title and objectives, which state increasingMAX_CONTENT_LENGTHfrom 8,000 to 50,000 characters. This same inconsistency appears indocker/constants.py.Apply this diff:
📝 Committable suggestion
🤖 Prompt for AI Agents