sycommon-python-lib 0.2.1b5__tar.gz → 0.2.1b6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (212) hide show
  1. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/PKG-INFO +4 -4
  2. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/pyproject.toml +4 -4
  3. sycommon_python_lib-0.2.1b6/src/sycli/cdp/__init__.py +1 -0
  4. sycommon_python_lib-0.2.1b6/src/sycli/cdp/browser.py +214 -0
  5. sycommon_python_lib-0.2.1b6/src/sycli/cdp/capabilities/__init__.py +1 -0
  6. sycommon_python_lib-0.2.1b6/src/sycli/cdp/capabilities/console.py +85 -0
  7. sycommon_python_lib-0.2.1b6/src/sycli/cdp/capabilities/dom.py +53 -0
  8. sycommon_python_lib-0.2.1b6/src/sycli/cdp/capabilities/network.py +119 -0
  9. sycommon_python_lib-0.2.1b6/src/sycli/cdp/capabilities/page_errors.py +91 -0
  10. sycommon_python_lib-0.2.1b6/src/sycli/cdp/capabilities/performance.py +67 -0
  11. sycommon_python_lib-0.2.1b6/src/sycli/cdp/capabilities/screenshot.py +61 -0
  12. sycommon_python_lib-0.2.1b6/src/sycli/cdp/client.py +148 -0
  13. sycommon_python_lib-0.2.1b6/src/sycli/cdp/protocol.py +133 -0
  14. sycommon_python_lib-0.2.1b6/src/sycli/cdp/repl.py +267 -0
  15. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/cli.py +52 -0
  16. sycommon_python_lib-0.2.1b6/src/sycli/commands/cdp_cmd.py +271 -0
  17. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/llm/llm_tokens.py +8 -0
  18. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon_python_lib.egg-info/PKG-INFO +4 -4
  19. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon_python_lib.egg-info/SOURCES.txt +13 -0
  20. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon_python_lib.egg-info/requires.txt +3 -3
  21. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/README.md +0 -0
  22. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/setup.cfg +0 -0
  23. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/command/__init__.py +0 -0
  24. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/command/cli.py +0 -0
  25. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/command/core/__init__.py +0 -0
  26. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/command/core/console.py +0 -0
  27. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/command/core/models.py +0 -0
  28. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/command/core/project.py +0 -0
  29. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/command/core/utils.py +0 -0
  30. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/command/templates/__init__.py +0 -0
  31. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/command/templates/agent/__init__.py +0 -0
  32. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/command/templates/base/__init__.py +0 -0
  33. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/command/templates/web/__init__.py +0 -0
  34. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/__init__.py +0 -0
  35. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/__main__.py +0 -0
  36. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/agents/__init__.py +0 -0
  37. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/agents/factory.py +0 -0
  38. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/agents/prompts.py +0 -0
  39. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/commands/__init__.py +0 -0
  40. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/commands/chat_cmd.py +0 -0
  41. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/commands/create_cmd.py +0 -0
  42. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/commands/evaluate_cmd.py +0 -0
  43. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/commands/init_cmd.py +0 -0
  44. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/commands/memory_cmd.py +0 -0
  45. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/commands/resume_cmd.py +0 -0
  46. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/commands/rollback_cmd.py +0 -0
  47. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/commands/run_cmd.py +0 -0
  48. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/core/__init__.py +0 -0
  49. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/core/backend.py +0 -0
  50. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/core/config.py +0 -0
  51. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/core/display.py +0 -0
  52. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/core/git_integration.py +0 -0
  53. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/core/llm.py +0 -0
  54. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/core/state.py +0 -0
  55. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/evaluate/__init__.py +0 -0
  56. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/evaluate/api_evaluator.py +0 -0
  57. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/memory/__init__.py +0 -0
  58. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/memory/compressor.py +0 -0
  59. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/memory/full.py +0 -0
  60. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/memory/hot.py +0 -0
  61. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/memory/manager.py +0 -0
  62. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/memory/warm.py +0 -0
  63. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/mode/__init__.py +0 -0
  64. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/mode/create.py +0 -0
  65. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/mode/optimize.py +0 -0
  66. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/models/__init__.py +0 -0
  67. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/models/config_models.py +0 -0
  68. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/rl/__init__.py +0 -0
  69. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/rl/convergence.py +0 -0
  70. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/rl/diagnosis.py +0 -0
  71. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/rl/engine.py +0 -0
  72. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/rl/environment.py +0 -0
  73. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/rl/experience.py +0 -0
  74. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/rl/harness_prompts.py +0 -0
  75. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/rl/history.py +0 -0
  76. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/rl/pre_validation.py +0 -0
  77. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/rl/reward.py +0 -0
  78. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/rl/strategy_bandit.py +0 -0
  79. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/rl/strategy_generator.py +0 -0
  80. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/rl/strategy_prompts.py +0 -0
  81. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycli/skills/__init__.py +0 -0
  82. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/__init__.py +0 -0
  83. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/agent/__init__.py +0 -0
  84. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/agent/agent_manager.py +0 -0
  85. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/agent/chat_events.py +0 -0
  86. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/agent/deep_agent.py +0 -0
  87. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/agent/multi_agent_team.py +0 -0
  88. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/agent/sandbox/__init__.py +0 -0
  89. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/agent/sandbox/file_ops.py +0 -0
  90. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/agent/sandbox/http_sandbox_backend.py +0 -0
  91. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/agent/sandbox/sandbox_pool.py +0 -0
  92. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/agent/sandbox/sandbox_recovery.py +0 -0
  93. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/agent/sandbox/session.py +0 -0
  94. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/auth/__init__.py +0 -0
  95. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/auth/ldap_service.py +0 -0
  96. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/config/Config.py +0 -0
  97. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/config/DatabaseConfig.py +0 -0
  98. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/config/ElasticsearchConfig.py +0 -0
  99. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/config/EmbeddingConfig.py +0 -0
  100. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/config/LLMConfig.py +0 -0
  101. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/config/LangfuseConfig.py +0 -0
  102. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/config/MQConfig.py +0 -0
  103. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/config/RedisConfig.py +0 -0
  104. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/config/RerankerConfig.py +0 -0
  105. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/config/SentryConfig.py +0 -0
  106. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/config/XxlJobConfig.py +0 -0
  107. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/config/__init__.py +0 -0
  108. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/database/async_base_db_service.py +0 -0
  109. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/database/async_database_service.py +0 -0
  110. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/database/base_db_service.py +0 -0
  111. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/database/database_service.py +0 -0
  112. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/database/elasticsearch_service.py +0 -0
  113. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/database/redis_service.py +0 -0
  114. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/database/token_usage_db_service.py +0 -0
  115. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/health/__init__.py +0 -0
  116. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/health/health_check.py +0 -0
  117. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/health/metrics.py +0 -0
  118. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/health/ping.py +0 -0
  119. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/heartbeat_process/__init__.py +0 -0
  120. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/heartbeat_process/heartbeat_config.py +0 -0
  121. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/heartbeat_process/heartbeat_process_manager.py +0 -0
  122. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/heartbeat_process/heartbeat_process_worker.py +0 -0
  123. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/llm/__init__.py +0 -0
  124. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/llm/embedding.py +0 -0
  125. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/llm/get_llm.py +0 -0
  126. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/llm/llm_logger.py +0 -0
  127. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/llm/llm_with_token_tracking.py +0 -0
  128. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/llm/native_with_fallback_runnable.py +0 -0
  129. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/llm/output_fixing_runnable.py +0 -0
  130. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/llm/struct_token.py +0 -0
  131. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/llm/sy_langfuse.py +0 -0
  132. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/llm/token_usage_es_service.py +0 -0
  133. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/llm/token_usage_mysql_service.py +0 -0
  134. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/llm/usage_token.py +0 -0
  135. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/logging/__init__.py +0 -0
  136. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/logging/async_sql_logger.py +0 -0
  137. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/logging/kafka_log.py +0 -0
  138. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/logging/logger_levels.py +0 -0
  139. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/logging/logger_wrapper.py +0 -0
  140. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/logging/process_logger.py +0 -0
  141. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/logging/sql_logger.py +0 -0
  142. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/middleware/__init__.py +0 -0
  143. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/middleware/background_execution.py +0 -0
  144. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/middleware/context.py +0 -0
  145. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/middleware/cors.py +0 -0
  146. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/middleware/docs.py +0 -0
  147. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/middleware/exception.py +0 -0
  148. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/middleware/middleware.py +0 -0
  149. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/middleware/monitor_memory.py +0 -0
  150. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/middleware/mq.py +0 -0
  151. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/middleware/sandbox.py +0 -0
  152. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/middleware/timeout.py +0 -0
  153. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/middleware/token_tracking.py +0 -0
  154. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/middleware/traceid.py +0 -0
  155. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/models/__init__.py +0 -0
  156. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/models/base_http.py +0 -0
  157. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/models/log.py +0 -0
  158. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/models/mqlistener_config.py +0 -0
  159. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/models/mqmsg_model.py +0 -0
  160. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/models/mqsend_config.py +0 -0
  161. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/models/sandbox.py +0 -0
  162. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/models/sso_user.py +0 -0
  163. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/models/token_usage.py +0 -0
  164. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/models/token_usage_mysql.py +0 -0
  165. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/models/xxljob_handler_config.py +0 -0
  166. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/notice/__init__.py +0 -0
  167. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/notice/uvicorn_monitor.py +0 -0
  168. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/rabbitmq/process_pool_consumer.py +0 -0
  169. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/rabbitmq/rabbitmq_client.py +0 -0
  170. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/rabbitmq/rabbitmq_pool.py +0 -0
  171. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/rabbitmq/rabbitmq_service.py +0 -0
  172. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/rabbitmq/rabbitmq_service_client_manager.py +0 -0
  173. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/rabbitmq/rabbitmq_service_connection_monitor.py +0 -0
  174. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/rabbitmq/rabbitmq_service_consumer_manager.py +0 -0
  175. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/rabbitmq/rabbitmq_service_core.py +0 -0
  176. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/rabbitmq/rabbitmq_service_producer_manager.py +0 -0
  177. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/sentry/__init__.py +0 -0
  178. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/sentry/sy_sentry.py +0 -0
  179. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/services.py +0 -0
  180. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/sse/__init__.py +0 -0
  181. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/sse/event.py +0 -0
  182. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/sse/sse.py +0 -0
  183. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/synacos/__init__.py +0 -0
  184. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/synacos/example.py +0 -0
  185. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/synacos/example2.py +0 -0
  186. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/synacos/feign.py +0 -0
  187. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/synacos/feign_client.py +0 -0
  188. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/synacos/nacos_client_base.py +0 -0
  189. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/synacos/nacos_config_manager.py +0 -0
  190. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/synacos/nacos_heartbeat_manager.py +0 -0
  191. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/synacos/nacos_service.py +0 -0
  192. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/synacos/nacos_service_discovery.py +0 -0
  193. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/synacos/nacos_service_registration.py +0 -0
  194. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/synacos/param.py +0 -0
  195. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/tests/deep_agent_server.py +0 -0
  196. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/tests/test_deep_agent.py +0 -0
  197. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/tests/test_email.py +0 -0
  198. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/tests/test_mq.py +0 -0
  199. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/tools/__init__.py +0 -0
  200. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/tools/async_utils.py +0 -0
  201. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/tools/docs.py +0 -0
  202. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/tools/env.py +0 -0
  203. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/tools/merge_headers.py +0 -0
  204. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/tools/snowflake.py +0 -0
  205. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/tools/syemail.py +0 -0
  206. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/tools/timing.py +0 -0
  207. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/xxljob/__init__.py +0 -0
  208. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon/xxljob/xxljob_service.py +0 -0
  209. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon_python_lib.egg-info/dependency_links.txt +0 -0
  210. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon_python_lib.egg-info/entry_points.txt +0 -0
  211. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/src/sycommon_python_lib.egg-info/top_level.txt +0 -0
  212. {sycommon_python_lib-0.2.1b5 → sycommon_python_lib-0.2.1b6}/tests/test_sycli.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sycommon-python-lib
3
- Version: 0.2.1b5
3
+ Version: 0.2.1b6
4
4
  Summary: Add your description here
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -9,7 +9,7 @@ Requires-Dist: aiohttp>=3.13.5
9
9
  Requires-Dist: aiomysql>=0.3.2
10
10
  Requires-Dist: anyio>=4.12.1
11
11
  Requires-Dist: decorator>=5.2.1
12
- Requires-Dist: deepagents>=0.5.1
12
+ Requires-Dist: deepagents>=0.5.2
13
13
  Requires-Dist: elasticsearch>=9.3.0
14
14
  Requires-Dist: fastapi>=0.135.3
15
15
  Requires-Dist: jinja2>=3.1.6
@@ -17,7 +17,7 @@ Requires-Dist: kafka-python>=2.3.1
17
17
  Requires-Dist: langchain>=1.2.15
18
18
  Requires-Dist: langchain-core>=1.2.28
19
19
  Requires-Dist: langchain-openai>=1.1.11
20
- Requires-Dist: langfuse>=4.1.0
20
+ Requires-Dist: langfuse>=4.2.0
21
21
  Requires-Dist: langgraph>=1.1.6
22
22
  Requires-Dist: langgraph-checkpoint-redis>=0.4.0
23
23
  Requires-Dist: ldap3>=2.9.1
@@ -28,7 +28,7 @@ Requires-Dist: psutil>=7.2.2
28
28
  Requires-Dist: pyxxl>=0.4.6
29
29
  Requires-Dist: pydantic>=2.12.5
30
30
  Requires-Dist: python-dotenv>=1.2.2
31
- Requires-Dist: python-multipart>=0.0.24
31
+ Requires-Dist: python-multipart>=0.0.26
32
32
  Requires-Dist: pyyaml>=6.0.3
33
33
  Requires-Dist: redis>=7.3.0
34
34
  Requires-Dist: sentry-sdk[fastapi]>=2.57.0
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sycommon-python-lib"
3
- version = "0.2.1b5"
3
+ version = "0.2.1b6"
4
4
  description = "Add your description here"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -10,7 +10,7 @@ dependencies = [
10
10
  "aiomysql>=0.3.2",
11
11
  "anyio>=4.12.1",
12
12
  "decorator>=5.2.1",
13
- "deepagents>=0.5.1",
13
+ "deepagents>=0.5.2",
14
14
  "elasticsearch>=9.3.0",
15
15
  "fastapi>=0.135.3",
16
16
  "jinja2>=3.1.6",
@@ -18,7 +18,7 @@ dependencies = [
18
18
  "langchain>=1.2.15",
19
19
  "langchain-core>=1.2.28",
20
20
  "langchain-openai>=1.1.11",
21
- "langfuse>=4.1.0",
21
+ "langfuse>=4.2.0",
22
22
  "langgraph>=1.1.6",
23
23
  "langgraph-checkpoint-redis>=0.4.0",
24
24
  "ldap3>=2.9.1",
@@ -29,7 +29,7 @@ dependencies = [
29
29
  "pyxxl>=0.4.6",
30
30
  "pydantic>=2.12.5",
31
31
  "python-dotenv>=1.2.2",
32
- "python-multipart>=0.0.24",
32
+ "python-multipart>=0.0.26",
33
33
  "pyyaml>=6.0.3",
34
34
  "redis>=7.3.0",
35
35
  "sentry-sdk[fastapi]>=2.57.0",
@@ -0,0 +1 @@
1
+ """sycli CDP — Chrome DevTools Protocol debugging support."""
@@ -0,0 +1,214 @@
1
+ """Browser launcher — find and start Chrome/Chromium with remote debugging.
2
+
3
+ Supports macOS, Linux, and Windows. Uses a temporary user data directory
4
+ and cleans up the process tree on termination.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import asyncio
10
+ import logging
11
+ import os
12
+ import platform
13
+ import shutil
14
+ import subprocess
15
+ import tempfile
16
+ from pathlib import Path
17
+
18
+ import aiohttp
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+ # Platform-specific Chrome search paths
23
+ _CHROME_PATHS: dict[str, list[str]] = {
24
+ "Darwin": [
25
+ "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
26
+ "/Applications/Chromium.app/Contents/MacOS/Chromium",
27
+ "/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary",
28
+ ],
29
+ "Linux": [
30
+ "/usr/bin/google-chrome",
31
+ "/usr/bin/google-chrome-stable",
32
+ "/usr/bin/chromium-browser",
33
+ "/usr/bin/chromium",
34
+ "/snap/bin/chromium",
35
+ ],
36
+ "Windows": [
37
+ os.path.expandvars(r"%ProgramFiles%\Google\Chrome\Application\chrome.exe"),
38
+ os.path.expandvars(r"%ProgramFiles(x86)%\Google\Chrome\Application\chrome.exe"),
39
+ os.path.expandvars(r"%LocalAppData%\Google\Chrome\Application\chrome.exe"),
40
+ ],
41
+ }
42
+
43
+
44
+ class BrowserProcess:
45
+ """Manages a launched Chrome subprocess."""
46
+
47
+ def __init__(self, process: subprocess.Popen, port: int, user_data_dir: str) -> None:
48
+ self.process = process
49
+ self.port = port
50
+ self.user_data_dir = user_data_dir
51
+
52
+ async def wait_for_ready(self, timeout: float = 10.0) -> None:
53
+ """Poll the /json/version endpoint until Chrome is ready."""
54
+ import time
55
+ deadline = time.monotonic() + timeout
56
+ while time.monotonic() < deadline:
57
+ try:
58
+ async with aiohttp.ClientSession() as session:
59
+ async with session.get(
60
+ f"http://localhost:{self.port}/json/version",
61
+ timeout=aiohttp.ClientTimeout(total=2),
62
+ ) as resp:
63
+ if resp.status == 200:
64
+ return
65
+ except Exception:
66
+ pass
67
+ await asyncio.sleep(0.2)
68
+ raise TimeoutError(f"Chrome did not become ready on port {self.port} within {timeout}s")
69
+
70
+ async def terminate(self) -> None:
71
+ """Terminate the Chrome process and clean up."""
72
+ if self.process.poll() is None:
73
+ try:
74
+ import psutil
75
+ parent = psutil.Process(self.process.pid)
76
+ children = parent.children(recursive=True)
77
+ for child in children:
78
+ try:
79
+ child.terminate()
80
+ except psutil.NoSuchProcess:
81
+ pass
82
+ self.process.terminate()
83
+ try:
84
+ self.process.wait(timeout=5)
85
+ except subprocess.TimeoutExpired:
86
+ self.process.kill()
87
+ except ImportError:
88
+ self.process.terminate()
89
+ try:
90
+ self.process.wait(timeout=5)
91
+ except subprocess.TimeoutExpired:
92
+ self.process.kill()
93
+
94
+ # Clean up temp directory
95
+ if self.user_data_dir and os.path.exists(self.user_data_dir):
96
+ try:
97
+ shutil.rmtree(self.user_data_dir, ignore_errors=True)
98
+ except Exception:
99
+ pass
100
+
101
+
102
+ class BrowserLauncher:
103
+ """Find and launch Chrome/Chromium with remote debugging enabled."""
104
+
105
+ @staticmethod
106
+ def find_chrome() -> str | None:
107
+ """Return the path to a Chrome/Chromium executable, or None."""
108
+ system = platform.system()
109
+ paths = _CHROME_PATHS.get(system, [])
110
+
111
+ for path in paths:
112
+ if os.path.isfile(path):
113
+ return path
114
+
115
+ # Fallback to PATH lookup
116
+ for name in ("google-chrome", "google-chrome-stable", "chromium-browser", "chromium", "chrome"):
117
+ found = shutil.which(name)
118
+ if found:
119
+ return found
120
+
121
+ return None
122
+
123
+ @staticmethod
124
+ async def launch(
125
+ port: int = 0,
126
+ headless: bool = True,
127
+ extra_args: list[str] | None = None,
128
+ ) -> BrowserProcess:
129
+ """Launch Chrome and return a BrowserProcess handle.
130
+
131
+ Args:
132
+ port: Remote debugging port. 0 = auto-select an available port.
133
+ headless: Run in headless mode.
134
+ extra_args: Additional Chrome command-line arguments.
135
+ """
136
+ chrome_path = BrowserLauncher.find_chrome()
137
+ if not chrome_path:
138
+ raise FileNotFoundError(
139
+ "Chrome/Chromium not found. Install Chrome or use --port to connect "
140
+ "to an existing browser with --remote-debugging-port."
141
+ )
142
+
143
+ # Auto-select port if 0
144
+ if port == 0:
145
+ import socket
146
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
147
+ s.bind(("", 0))
148
+ port = s.getsockname()[1]
149
+
150
+ user_data_dir = tempfile.mkdtemp(prefix="sycli-cdp-")
151
+
152
+ args = [
153
+ chrome_path,
154
+ f"--remote-debugging-port={port}",
155
+ f"--user-data-dir={user_data_dir}",
156
+ "--disable-gpu",
157
+ "--no-sandbox",
158
+ "--disable-dev-shm-usage",
159
+ "--disable-extensions",
160
+ "--disable-background-networking",
161
+ "--disable-sync",
162
+ "--no-first-run",
163
+ "--disable-default-apps",
164
+ ]
165
+
166
+ if headless:
167
+ args.append("--headless=new")
168
+
169
+ if extra_args:
170
+ args.extend(extra_args)
171
+
172
+ logger.debug("Launching Chrome: %s", " ".join(args))
173
+
174
+ process = subprocess.Popen(
175
+ args,
176
+ stdout=subprocess.DEVNULL,
177
+ stderr=subprocess.PIPE,
178
+ )
179
+
180
+ bp = BrowserProcess(process, port, user_data_dir)
181
+ await bp.wait_for_ready()
182
+ return bp
183
+
184
+
185
+ async def discover_ws_url(port: int, target_id: str | None = None) -> str | None:
186
+ """Query /json endpoint to find a page's WebSocket debugger URL."""
187
+ try:
188
+ async with aiohttp.ClientSession() as session:
189
+ async with session.get(
190
+ f"http://localhost:{port}/json",
191
+ timeout=aiohttp.ClientTimeout(total=5),
192
+ ) as resp:
193
+ if resp.status != 200:
194
+ return None
195
+ targets = await resp.json()
196
+ if not isinstance(targets, list):
197
+ return None
198
+
199
+ if target_id:
200
+ for t in targets:
201
+ if t.get("id") == target_id:
202
+ return t.get("webSocketDebuggerUrl")
203
+
204
+ # Default: first page target
205
+ for t in targets:
206
+ if t.get("type") == "page":
207
+ return t.get("webSocketDebuggerUrl")
208
+
209
+ # Fallback: any target
210
+ if targets:
211
+ return targets[0].get("webSocketDebuggerUrl")
212
+ except Exception:
213
+ return None
214
+ return None
@@ -0,0 +1 @@
1
+ """CDP capability modules for browser debugging."""
@@ -0,0 +1,85 @@
1
+ """Console capability — capture Runtime console events and exceptions."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import time
7
+ from typing import Any
8
+
9
+ from sycli.cdp.client import CDPClient
10
+ from sycli.cdp.protocol import enable_runtime, evaluate_js
11
+
12
+
13
+ async def capture_console(
14
+ client: CDPClient,
15
+ duration: float = 5.0,
16
+ evaluate: str | None = None,
17
+ ) -> list[dict[str, Any]]:
18
+ """Capture console logs for a duration.
19
+
20
+ Args:
21
+ client: Connected CDP client.
22
+ duration: How long to capture (seconds).
23
+ evaluate: Optional JS expression to evaluate after enabling console capture.
24
+
25
+ Returns:
26
+ List of console entries: {"type", "args", "timestamp", "text"}.
27
+ """
28
+ entries: list[dict[str, Any]] = []
29
+
30
+ def on_console_api(params: dict) -> None:
31
+ args = params.get("args", [])
32
+ text = " ".join(_arg_to_str(a) for a in args)
33
+ entries.append({
34
+ "type": params.get("type", "log"),
35
+ "args": [_arg_summary(a) for a in args],
36
+ "text": text,
37
+ "timestamp": params.get("timestamp", 0),
38
+ })
39
+
40
+ def on_exception(params: dict) -> None:
41
+ detail = params.get("exceptionDetails", {})
42
+ exc = detail.get("exception", {})
43
+ entries.append({
44
+ "type": "exception",
45
+ "text": exc.get("description", detail.get("text", "Unknown exception")),
46
+ "args": [],
47
+ "timestamp": params.get("timestamp", 0),
48
+ "url": detail.get("url", ""),
49
+ "line": detail.get("lineNumber", -1),
50
+ "column": detail.get("columnNumber", -1),
51
+ })
52
+
53
+ client.on_event("Runtime.consoleAPICalled", on_console_api)
54
+ client.on_event("Runtime.exceptionThrown", on_exception)
55
+ await enable_runtime(client)
56
+
57
+ if evaluate:
58
+ await evaluate_js(client, evaluate)
59
+
60
+ await asyncio.sleep(duration)
61
+
62
+ client.remove_event_handler("Runtime.consoleAPICalled", on_console_api)
63
+ client.remove_event_handler("Runtime.exceptionThrown", on_exception)
64
+
65
+ return entries
66
+
67
+
68
+ def _arg_to_str(arg: dict) -> str:
69
+ """Convert a CDP RemoteObject to a readable string."""
70
+ if "value" in arg:
71
+ import json
72
+ v = arg["value"]
73
+ return json.dumps(v, ensure_ascii=False) if isinstance(v, (dict, list)) else str(v)
74
+ if "description" in arg:
75
+ return arg["description"]
76
+ return arg.get("type", "undefined")
77
+
78
+
79
+ def _arg_summary(arg: dict) -> dict:
80
+ """Summarize a CDP RemoteObject for structured output."""
81
+ return {
82
+ "type": arg.get("type"),
83
+ "value": arg.get("value"),
84
+ "description": arg.get("description"),
85
+ }
@@ -0,0 +1,53 @@
1
+ """DOM capability — query and inspect DOM elements."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from sycli.cdp.client import CDPClient
8
+ from sycli.cdp.protocol import (
9
+ enable_dom,
10
+ enable_page,
11
+ get_document,
12
+ get_outer_html,
13
+ query_selector,
14
+ )
15
+
16
+
17
+ async def query_dom(
18
+ client: CDPClient,
19
+ selector: str,
20
+ ) -> dict[str, Any]:
21
+ """Query a DOM element by CSS selector.
22
+
23
+ Args:
24
+ client: Connected CDP client.
25
+ selector: CSS selector string.
26
+
27
+ Returns:
28
+ Dict with "selector", "node_id", "outer_html".
29
+ """
30
+ await enable_page(client)
31
+ await enable_dom(client)
32
+
33
+ doc = await get_document(client)
34
+ root_node_id = doc.get("root", {}).get("nodeId", 0)
35
+
36
+ result = await query_selector(client, root_node_id, selector)
37
+ node_id = result.get("nodeId", 0)
38
+
39
+ if node_id == 0:
40
+ return {
41
+ "selector": selector,
42
+ "node_id": 0,
43
+ "outer_html": None,
44
+ "found": False,
45
+ }
46
+
47
+ html_result = await get_outer_html(client, node_id)
48
+ return {
49
+ "selector": selector,
50
+ "node_id": node_id,
51
+ "outer_html": html_result.get("outerHTML", ""),
52
+ "found": True,
53
+ }
@@ -0,0 +1,119 @@
1
+ """Network capability — capture HTTP request/response traffic."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ from typing import Any
7
+
8
+ from sycli.cdp.client import CDPClient
9
+ from sycli.cdp.protocol import (
10
+ disable_network,
11
+ enable_network,
12
+ get_response_body,
13
+ )
14
+
15
+
16
+ async def capture_network(
17
+ client: CDPClient,
18
+ duration: float = 10.0,
19
+ url_filter: str | None = None,
20
+ include_body: bool = False,
21
+ ) -> list[dict[str, Any]]:
22
+ """Capture network requests for a duration.
23
+
24
+ Args:
25
+ client: Connected CDP client.
26
+ duration: How long to capture (seconds).
27
+ url_filter: Optional URL substring filter.
28
+ include_body: Fetch response bodies for text responses.
29
+
30
+ Returns:
31
+ List of network entries with request/response info.
32
+ """
33
+ entries: dict[str, dict[str, Any]] = {}
34
+
35
+ def on_request(params: dict) -> None:
36
+ req = params.get("request", {})
37
+ rid = params.get("requestId", "")
38
+ entries[rid] = {
39
+ "request_id": rid,
40
+ "method": req.get("method", ""),
41
+ "url": req.get("url", ""),
42
+ "headers": req.get("headers", {}),
43
+ "request_type": params.get("type", ""),
44
+ "timestamp": params.get("timestamp", 0),
45
+ "status": None,
46
+ "mime_type": None,
47
+ "size": None,
48
+ "timing": None,
49
+ "body": None,
50
+ "failed": False,
51
+ "error_text": None,
52
+ }
53
+
54
+ def on_response(params: dict) -> None:
55
+ rid = params.get("requestId", "")
56
+ resp = params.get("response", {})
57
+ if rid in entries:
58
+ entries[rid]["status"] = resp.get("status")
59
+ entries[rid]["mime_type"] = resp.get("mimeType", "")
60
+ entries[rid]["size"] = resp.get("encodedDataLength") or resp.get("content", {}).get("size")
61
+ entries[rid]["timing"] = resp.get("timing")
62
+
63
+ def on_loading_finished(params: dict) -> None:
64
+ rid = params.get("requestId", "")
65
+ if rid in entries:
66
+ entries[rid]["size"] = params.get("encodedDataLength", entries[rid]["size"])
67
+
68
+ def on_loading_failed(params: dict) -> None:
69
+ rid = params.get("requestId", "")
70
+ if rid in entries:
71
+ entries[rid]["failed"] = True
72
+ entries[rid]["error_text"] = params.get("errorText", "")
73
+ entries[rid]["canceled"] = params.get("canceled", False)
74
+
75
+ # Enable network BEFORE any page activity
76
+ client.on_event("Network.requestWillBeSent", on_request)
77
+ client.on_event("Network.responseReceived", on_response)
78
+ client.on_event("Network.loadingFinished", on_loading_finished)
79
+ client.on_event("Network.loadingFailed", on_loading_failed)
80
+ await enable_network(client)
81
+
82
+ # If page is already loaded, reload to capture traffic
83
+ try:
84
+ from sycli.cdp.protocol import enable_page
85
+ await enable_page(client)
86
+ await client.send("Page.reload", {"ignoreCache": True})
87
+ except Exception:
88
+ pass
89
+
90
+ await asyncio.sleep(duration)
91
+
92
+ try:
93
+ await disable_network(client)
94
+ except Exception:
95
+ pass
96
+
97
+ # Fetch response bodies if requested
98
+ results = list(entries.values())
99
+ if include_body:
100
+ for entry in results:
101
+ if entry["failed"] or entry["status"] is None:
102
+ continue
103
+ mime = (entry.get("mime_type") or "").lower()
104
+ if any(t in mime for t in ("text", "json", "javascript", "html", "xml", "css")):
105
+ try:
106
+ body_result = await get_response_body(client, entry["request_id"])
107
+ body = body_result.get("body", "")
108
+ if body_result.get("base64Encoded"):
109
+ import base64
110
+ body = base64.b64decode(body).decode("utf-8", errors="replace")
111
+ entry["body"] = body[:10000] # Truncate large bodies
112
+ except Exception:
113
+ pass
114
+
115
+ # Apply URL filter
116
+ if url_filter:
117
+ results = [e for e in results if url_filter in e.get("url", "")]
118
+
119
+ return results
@@ -0,0 +1,91 @@
1
+ """Page errors capability — capture JS exceptions, window.onerror, and log entries."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ from typing import Any
7
+
8
+ from sycli.cdp.client import CDPClient
9
+ from sycli.cdp.protocol import enable_log, enable_page, enable_runtime
10
+
11
+
12
+ async def capture_errors(
13
+ client: CDPClient,
14
+ duration: float = 5.0,
15
+ ) -> list[dict[str, Any]]:
16
+ """Capture page errors for a duration.
17
+
18
+ Listens for Runtime.exceptionThrown, Page.windowOnError (via Runtime.evaluate),
19
+ and Log.entryAdded events.
20
+
21
+ Args:
22
+ client: Connected CDP client.
23
+ duration: How long to capture (seconds).
24
+
25
+ Returns:
26
+ List of error entries with type, message, url, line, column, stack.
27
+ """
28
+ errors: list[dict[str, Any]] = []
29
+
30
+ def on_exception(params: dict) -> None:
31
+ detail = params.get("exceptionDetails", {})
32
+ exc = detail.get("exception", {})
33
+ errors.append({
34
+ "type": "exception",
35
+ "message": exc.get("description", detail.get("text", "")),
36
+ "url": detail.get("url", ""),
37
+ "line": detail.get("lineNumber", -1),
38
+ "column": detail.get("columnNumber", -1),
39
+ "stack": _format_stack(detail.get("stackTrace", {})),
40
+ })
41
+
42
+ def on_log_entry(params: dict) -> None:
43
+ entry = params.get("entry", {})
44
+ if entry.get("level") in ("error", "warning"):
45
+ errors.append({
46
+ "type": f"log_{entry.get('level', 'unknown')}",
47
+ "message": entry.get("text", ""),
48
+ "url": entry.get("url", ""),
49
+ "line": entry.get("lineNumber", -1),
50
+ "source": entry.get("source", ""),
51
+ "stack": _format_stack(entry.get("stackTrace", {})),
52
+ })
53
+
54
+ client.on_event("Runtime.exceptionThrown", on_exception)
55
+ client.on_event("Log.entryAdded", on_log_entry)
56
+
57
+ await enable_page(client)
58
+ await enable_runtime(client)
59
+ await enable_log(client)
60
+
61
+ # Install window.onerror handler
62
+ await client.send("Runtime.evaluate", {
63
+ "expression": (
64
+ "window.onerror = function(msg, url, line, col, error) {"
65
+ " console.error('[window.onerror]', msg, url, line, col);"
66
+ "};"
67
+ ),
68
+ "returnByValue": True,
69
+ })
70
+
71
+ await asyncio.sleep(duration)
72
+
73
+ client.remove_event_handler("Runtime.exceptionThrown", on_exception)
74
+ client.remove_event_handler("Log.entryAdded", on_log_entry)
75
+
76
+ return errors
77
+
78
+
79
+ def _format_stack(stack_trace: dict) -> str:
80
+ """Format a CDP StackTrace object into a readable string."""
81
+ frames = stack_trace.get("callFrames", [])
82
+ if not frames:
83
+ return ""
84
+ lines = []
85
+ for f in frames:
86
+ name = f.get("functionName", "<anonymous>")
87
+ url = f.get("url", "")
88
+ line = f.get("lineNumber", -1)
89
+ col = f.get("columnNumber", -1)
90
+ lines.append(f" at {name} ({url}:{line}:{col})")
91
+ return "\n".join(lines)