Skip to content

Commit 6924077

Browse files
committed
Release v3.9.17
1 parent 63101d7 commit 6924077

File tree

10 files changed

+898
-43
lines changed

10 files changed

+898
-43
lines changed

docker/Dockerfile.chat

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ RUN mkdir -p /root/.praison
1616
# Install Python packages (using latest versions)
1717
RUN pip install --no-cache-dir \
1818
praisonai_tools \
19-
"praisonai>=3.9.16" \
19+
"praisonai>=3.9.17" \
2020
"praisonai[chat]" \
2121
"embedchain[github,youtube]"
2222

docker/Dockerfile.dev

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ RUN mkdir -p /root/.praison
2020
# Install Python packages (using latest versions)
2121
RUN pip install --no-cache-dir \
2222
praisonai_tools \
23-
"praisonai>=3.9.16" \
23+
"praisonai>=3.9.17" \
2424
"praisonai[ui]" \
2525
"praisonai[chat]" \
2626
"praisonai[realtime]" \

docker/Dockerfile.ui

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ RUN mkdir -p /root/.praison
1616
# Install Python packages (using latest versions)
1717
RUN pip install --no-cache-dir \
1818
praisonai_tools \
19-
"praisonai>=3.9.16" \
19+
"praisonai>=3.9.17" \
2020
"praisonai[ui]" \
2121
"praisonai[crewai]"
2222

src/praisonai/praisonai.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ class Praisonai < Formula
33

44
desc "AI tools for various AI applications"
55
homepage "https://github.com/MervinPraison/PraisonAI"
6-
url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v3.9.16.tar.gz"
7-
sha256 `curl -sL https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v3.9.16.tar.gz | shasum -a 256`.split.first
6+
url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v3.9.17.tar.gz"
7+
sha256 `curl -sL https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v3.9.17.tar.gz | shasum -a 256`.split.first
88
license "MIT"
99

1010
depends_on "python@3.11"

src/praisonai/praisonai/browser/agent.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -313,11 +313,12 @@ def process_observation(
313313
vision_capable = any(m in model_lower for m in ['gpt-4', 'gpt-4o', 'gemini', 'claude'])
314314
use_vision = screenshot_base64 and vision_capable
315315

316-
# *** DEBUG: Log screenshot presence ***
316+
# Structured debug logging for automation flow tracing
317+
logger.debug(f"[AGENT][VISION] process_observation:agent.py model={self.model} vision_capable={vision_capable} use_vision={use_vision}")
317318
if screenshot_base64:
318-
logger.info(f"[SCREENSHOT] Screenshot present: {len(screenshot_base64)} chars, vision={use_vision}, model={model_lower}")
319+
logger.debug(f"[AGENT][VISION] Screenshot present: {len(screenshot_base64)} chars")
319320
else:
320-
logger.info(f"[SCREENSHOT] No screenshot in observation")
321+
logger.debug(f"[AGENT][VISION] No screenshot in observation")
321322

322323

323324
# Get agent response with structured output if available

src/praisonai/praisonai/browser/cli.py

Lines changed: 261 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1936,41 +1936,273 @@ def doctor_db():
19361936
raise typer.Exit(1)
19371937

19381938

1939+
@doctor_app.command("bridge")
1940+
def doctor_bridge(
1941+
host: str = typer.Option("localhost", "--host", "-H", help="Server host"),
1942+
port: int = typer.Option(8765, "--port", "-p", help="Server port"),
1943+
):
1944+
"""Test bridge WebSocket connectivity.
1945+
1946+
Performs:
1947+
1. HTTP health check
1948+
2. WebSocket handshake test
1949+
3. Welcome message validation
1950+
1951+
Examples:
1952+
praisonai browser doctor bridge
1953+
praisonai browser doctor bridge --port 8766
1954+
"""
1955+
import asyncio
1956+
from .diagnostics import check_bridge_server, check_bridge_websocket
1957+
1958+
console.print("[bold]Bridge Server Test[/bold]\n")
1959+
1960+
async def run_checks():
1961+
results = []
1962+
results.append(await check_bridge_server(host, port))
1963+
results.append(await check_bridge_websocket(host, port))
1964+
return results
1965+
1966+
results = asyncio.run(run_checks())
1967+
1968+
all_pass = True
1969+
for r in results:
1970+
if r.status.value == "pass":
1971+
console.print(f"[green]✅ {r.name}:[/green] {r.message}")
1972+
elif r.status.value == "fail":
1973+
console.print(f"[red]❌ {r.name}:[/red] {r.message}")
1974+
all_pass = False
1975+
else:
1976+
console.print(f"[yellow]⚠️ {r.name}:[/yellow] {r.message}")
1977+
1978+
if r.details:
1979+
for k, v in r.details.items():
1980+
console.print(f" {k}: {v}")
1981+
1982+
if not all_pass:
1983+
raise typer.Exit(1)
1984+
1985+
1986+
@doctor_app.command("api-keys")
1987+
def doctor_api_keys(
1988+
model: Optional[str] = typer.Option(None, "--model", "-m", help="Test specific model API"),
1989+
validate: bool = typer.Option(False, "--validate", "-V", help="Actually call API to validate key"),
1990+
):
1991+
"""Check API key configuration.
1992+
1993+
Verifies:
1994+
- OPENAI_API_KEY
1995+
- GEMINI_API_KEY
1996+
- ANTHROPIC_API_KEY
1997+
1998+
Examples:
1999+
praisonai browser doctor api-keys
2000+
praisonai browser doctor api-keys --validate
2001+
praisonai browser doctor api-keys --model gemini/gemini-2.0-flash --validate
2002+
"""
2003+
from .diagnostics import check_api_keys, check_api_key_valid
2004+
2005+
console.print("[bold]API Key Check[/bold]\n")
2006+
2007+
results = check_api_keys()
2008+
2009+
all_pass = True
2010+
for r in results:
2011+
provider = r.details.get('provider', r.name)
2012+
if r.status.value == "pass":
2013+
console.print(f"[green]✅ {provider}:[/green] {r.message}")
2014+
elif r.status.value == "fail":
2015+
console.print(f"[red]❌ {provider}:[/red] {r.message}")
2016+
all_pass = False
2017+
else:
2018+
console.print(f"[yellow]⚠️ {provider}:[/yellow] {r.message}")
2019+
2020+
2021+
# Validate with actual API call
2022+
if validate:
2023+
console.print("\n[dim]Validating with API call...[/dim]")
2024+
test_model = model or "gpt-4o-mini"
2025+
result = check_api_key_valid(test_model)
2026+
2027+
if result.status.value == "pass":
2028+
console.print(f"[green]✅ API validation:[/green] {result.message}")
2029+
else:
2030+
console.print(f"[red]❌ API validation:[/red] {result.message}")
2031+
if result.details.get("error"):
2032+
console.print(f" Error: {result.details['error'][:100]}")
2033+
all_pass = False
2034+
2035+
if not all_pass:
2036+
raise typer.Exit(1)
2037+
2038+
2039+
@doctor_app.command("env")
2040+
def doctor_env():
2041+
"""Show environment configuration.
2042+
2043+
Displays:
2044+
- Python version
2045+
- Platform
2046+
- API key status
2047+
- Working directory
2048+
2049+
Examples:
2050+
praisonai browser doctor env
2051+
"""
2052+
from .diagnostics import get_environment_info
2053+
2054+
console.print("[bold]Environment Configuration[/bold]\n")
2055+
2056+
result = get_environment_info()
2057+
details = result.details
2058+
2059+
console.print(f"Python: {details.get('python_version', 'unknown')}")
2060+
console.print(f"Platform: {details.get('platform', 'unknown')}")
2061+
console.print(f"Home: {details.get('home', 'unknown')}")
2062+
console.print(f"CWD: {details.get('cwd', 'unknown')}")
2063+
2064+
console.print("\n[bold]API Keys:[/bold]")
2065+
api_keys = details.get("api_keys_set", {})
2066+
for key, is_set in api_keys.items():
2067+
if key == "OPENAI_BASE_URL":
2068+
console.print(f" {key}: {is_set}")
2069+
elif is_set:
2070+
console.print(f" [green]✅ {key}[/green]: Set")
2071+
else:
2072+
console.print(f" [yellow]⚠️ {key}[/yellow]: Not set")
2073+
2074+
2075+
@doctor_app.command("agent")
2076+
def doctor_agent(
2077+
model: str = typer.Option("gpt-4o-mini", "--model", "-m", help="LLM model to test"),
2078+
):
2079+
"""Test agent LLM capability.
2080+
2081+
Sends a mock observation and verifies agent returns valid action.
2082+
This tests the full LLM call path.
2083+
2084+
Examples:
2085+
praisonai browser doctor agent
2086+
praisonai browser doctor agent --model gemini/gemini-2.0-flash
2087+
"""
2088+
import asyncio
2089+
from .diagnostics import check_agent_llm, check_vision_capability
2090+
2091+
console.print(f"[bold]Agent LLM Test ({model})[/bold]\n")
2092+
2093+
# Check vision capability
2094+
vision_result = check_vision_capability(model)
2095+
if vision_result.status.value == "pass":
2096+
console.print(f"[green]✅ Vision:[/green] {vision_result.message}")
2097+
else:
2098+
console.print(f"[yellow]⚠️ Vision:[/yellow] {vision_result.message}")
2099+
2100+
# Test LLM call
2101+
console.print("\n[dim]Testing LLM call...[/dim]")
2102+
result = asyncio.run(check_agent_llm(model))
2103+
2104+
if result.status.value == "pass":
2105+
console.print(f"[green]✅ Agent:[/green] {result.message}")
2106+
if result.details.get("thought"):
2107+
console.print(f" Thought: {result.details['thought'][:80]}...")
2108+
elif result.status.value == "fail":
2109+
console.print(f"[red]❌ Agent:[/red] {result.message}")
2110+
if result.details.get("error"):
2111+
console.print(f" Error: {result.details['error'][:150]}")
2112+
raise typer.Exit(1)
2113+
else:
2114+
console.print(f"[yellow]⚠️ Agent:[/yellow] {result.message}")
2115+
2116+
2117+
@doctor_app.command("flow")
2118+
def doctor_flow(
2119+
bridge_port: int = typer.Option(8765, "--bridge-port", help="Bridge server port"),
2120+
chrome_port: int = typer.Option(9222, "--chrome-port", help="Chrome debug port"),
2121+
model: str = typer.Option("gpt-4o-mini", "--model", "-m", help="LLM model"),
2122+
skip_llm: bool = typer.Option(False, "--skip-llm", help="Skip LLM API test"),
2123+
json_output: bool = typer.Option(False, "--json", help="Output as JSON"),
2124+
):
2125+
"""Run full automation flow diagnostics.
2126+
2127+
Tests all components in sequence:
2128+
1. Environment & API keys
2129+
2. Bridge server connectivity
2130+
3. Chrome CDP & extension
2131+
4. Agent LLM capability
2132+
2133+
Examples:
2134+
praisonai browser doctor flow
2135+
praisonai browser doctor flow --json
2136+
praisonai browser doctor flow --skip-llm
2137+
"""
2138+
import asyncio
2139+
import json as json_lib
2140+
from .diagnostics import run_all_diagnostics
2141+
2142+
if not json_output:
2143+
console.print("[bold]Full Automation Flow Diagnostics[/bold]\n")
2144+
2145+
results = asyncio.run(run_all_diagnostics(
2146+
bridge_port=bridge_port,
2147+
chrome_port=chrome_port,
2148+
model=model,
2149+
skip_llm=skip_llm,
2150+
))
2151+
2152+
if json_output:
2153+
console.print(json_lib.dumps(results, indent=2))
2154+
return
2155+
2156+
# Display results
2157+
for r in results["results"]:
2158+
status = r["status"]
2159+
name = r["name"]
2160+
message = r["message"]
2161+
2162+
if status == "pass":
2163+
console.print(f"[green]✅ {name}:[/green] {message}")
2164+
elif status == "fail":
2165+
console.print(f"[red]❌ {name}:[/red] {message}")
2166+
elif status == "warn":
2167+
console.print(f"[yellow]⚠️ {name}:[/yellow] {message}")
2168+
else:
2169+
console.print(f"[dim]⏭️ {name}:[/dim] {message}")
2170+
2171+
# Summary
2172+
summary = results["summary"]
2173+
console.print(f"\n[bold]Summary:[/bold] {summary['passed']}/{summary['total']} passed")
2174+
2175+
if summary["failed"] > 0:
2176+
console.print(f"[red] ❌ {summary['failed']} failed[/red]")
2177+
if summary["warned"] > 0:
2178+
console.print(f"[yellow] ⚠️ {summary['warned']} warnings[/yellow]")
2179+
2180+
if not summary["all_pass"]:
2181+
raise typer.Exit(1)
2182+
2183+
19392184
@doctor_app.callback(invoke_without_command=True)
19402185
def doctor_all(
19412186
ctx: typer.Context,
19422187
json_output: bool = typer.Option(False, "--json", help="Output as JSON"),
19432188
):
1944-
"""Run all browser health checks."""
2189+
"""Run all browser health checks.
2190+
2191+
Runs comprehensive diagnostics on all components.
2192+
2193+
Examples:
2194+
praisonai browser doctor
2195+
praisonai browser doctor --json
2196+
"""
19452197
if ctx.invoked_subcommand is None:
1946-
console.print("[bold]Browser Health Check[/bold]\n")
1947-
1948-
# Run all checks with explicit defaults
1949-
try:
1950-
doctor_server(host="localhost", port=8765)
1951-
except typer.Exit:
1952-
pass
1953-
1954-
console.print()
1955-
1956-
try:
1957-
doctor_chrome(port=9222)
1958-
except typer.Exit:
1959-
pass
1960-
1961-
console.print()
1962-
1963-
try:
1964-
doctor_extension(port=9222)
1965-
except typer.Exit:
1966-
pass
1967-
1968-
console.print()
1969-
1970-
try:
1971-
doctor_db()
1972-
except typer.Exit:
1973-
pass
2198+
# Use full flow diagnostics
2199+
doctor_flow(
2200+
bridge_port=8765,
2201+
chrome_port=9222,
2202+
model="gpt-4o-mini",
2203+
skip_llm=True, # Skip by default for speed
2204+
json_output=json_output,
2205+
)
19742206

19752207

19762208
# ============================================================

0 commit comments

Comments
 (0)