Add verbose logging (-v) for config, API key and requests

This commit is contained in:
Markov 2026-02-23 09:52:39 +01:00
parent 4f07bf7bec
commit 3ccce3eae6
3 changed files with 36 additions and 4 deletions

View File

@ -4,6 +4,7 @@ Command line interface for PicoGent
import asyncio import asyncio
import argparse import argparse
import logging
import sys import sys
import os import os
from .agent import Agent from .agent import Agent
@ -13,6 +14,7 @@ from .config import Config
async def main(): async def main():
"""Main CLI entry point""" """Main CLI entry point"""
parser = argparse.ArgumentParser(description="PicoGent - Minimal AI Coding Agent") parser = argparse.ArgumentParser(description="PicoGent - Minimal AI Coding Agent")
parser.add_argument("--verbose", "-v", action="store_true", help="Enable debug logging")
parser.add_argument("message", nargs="*", help="Message to send to the agent") parser.add_argument("message", nargs="*", help="Message to send to the agent")
parser.add_argument("--config", "-c", default="config.json", help="Config file path") parser.add_argument("--config", "-c", default="config.json", help="Config file path")
parser.add_argument("--session", "-s", help="Session file path (JSONL)") parser.add_argument("--session", "-s", help="Session file path (JSONL)")
@ -20,6 +22,14 @@ async def main():
args = parser.parse_args() args = parser.parse_args()
# Setup logging
log_level = logging.DEBUG if args.verbose else logging.INFO
logging.basicConfig(
level=log_level,
format="[%(name)s] %(message)s",
stream=sys.stderr
)
# Join message parts # Join message parts
message = " ".join(args.message) if args.message else None message = " ".join(args.message) if args.message else None

View File

@ -23,29 +23,42 @@ class Config:
@classmethod @classmethod
def from_file(cls, config_path: str) -> "Config": def from_file(cls, config_path: str) -> "Config":
"""Load configuration from JSON file""" """Load configuration from JSON file"""
import logging
logger = logging.getLogger("picogent.config")
logger.info(f"Loading config from: {os.path.abspath(config_path)}")
if not os.path.exists(config_path): if not os.path.exists(config_path):
raise FileNotFoundError(f"Config file not found: {config_path}") raise FileNotFoundError(f"Config file not found: {config_path}")
with open(config_path, 'r') as f: with open(config_path, 'r') as f:
data = json.load(f) data = json.load(f)
provider = data.get('provider', 'anthropic')
model = data.get('model', 'claude-sonnet-4-20250514')
base_url = data.get('base_url', None)
logger.info(f"Provider: {provider} | Model: {model} | Base URL: {base_url}")
# Resolve environment variables in API key # Resolve environment variables in API key
api_key = data.get('api_key', '') api_key = data.get('api_key', '')
if api_key.startswith('env:'): if api_key.startswith('env:'):
env_var = api_key[4:] # Remove 'env:' prefix env_var = api_key[4:] # Remove 'env:' prefix
logger.info(f"Resolving API key from env var: {env_var}")
api_key = os.getenv(env_var, '') api_key = os.getenv(env_var, '')
if not api_key: if not api_key:
raise ValueError(f"Environment variable {env_var} is not set") raise ValueError(f"Environment variable {env_var} is not set")
logger.info(f"API key resolved: {api_key[:8]}...{api_key[-4:]} (len={len(api_key)})")
else:
logger.info(f"API key from config: {api_key[:8]}...{api_key[-4:]} (len={len(api_key)})" if len(api_key) > 12 else f"API key from config: *** (len={len(api_key)})")
return cls( return cls(
provider=data.get('provider', 'anthropic'), provider=provider,
model=data.get('model', 'claude-sonnet-4-20250514'), model=model,
api_key=api_key, api_key=api_key,
max_tokens=data.get('max_tokens', 8192), max_tokens=data.get('max_tokens', 8192),
max_iterations=data.get('max_iterations', 20), max_iterations=data.get('max_iterations', 20),
workspace=data.get('workspace', '.'), workspace=data.get('workspace', '.'),
system_prompt=data.get('system_prompt', 'You are a helpful coding assistant.'), system_prompt=data.get('system_prompt', 'You are a helpful coding assistant.'),
base_url=data.get('base_url', None) base_url=base_url
) )
def to_dict(self) -> Dict[str, Any]: def to_dict(self) -> Dict[str, Any]:

View File

@ -4,9 +4,12 @@ Anthropic Claude provider using httpx
import httpx import httpx
import json import json
import logging
from typing import Dict, List, Any, Optional from typing import Dict, List, Any, Optional
from .base import BaseProvider from .base import BaseProvider
logger = logging.getLogger("picogent.anthropic")
class AnthropicProvider(BaseProvider): class AnthropicProvider(BaseProvider):
"""Anthropic Claude provider using direct API calls""" """Anthropic Claude provider using direct API calls"""
@ -42,6 +45,10 @@ class AnthropicProvider(BaseProvider):
if tools: if tools:
payload["tools"] = tools payload["tools"] = tools
logger.info(f"POST {self.base_url}/messages | model={self.model} | key={self.api_key[:8]}...{self.api_key[-4:]} (len={len(self.api_key)})")
logger.debug(f"Headers: x-api-key={self.api_key[:8]}..., anthropic-version={self.anthropic_version}")
logger.debug(f"Messages count: {len(messages)}, tools: {len(tools) if tools else 0}")
async with httpx.AsyncClient() as client: async with httpx.AsyncClient() as client:
response = await client.post( response = await client.post(
f"{self.base_url}/messages", f"{self.base_url}/messages",
@ -50,8 +57,10 @@ class AnthropicProvider(BaseProvider):
timeout=120.0 timeout=120.0
) )
logger.info(f"Response status: {response.status_code}")
if response.status_code != 200: if response.status_code != 200:
error_text = response.text error_text = response.text
logger.error(f"API error: {error_text}")
raise Exception(f"Anthropic API error {response.status_code}: {error_text}") raise Exception(f"Anthropic API error {response.status_code}: {error_text}")
result = response.json() result = response.json()