sycommon-python-lib 0.2.5a37__tar.gz → 0.2.5a39__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 (296) hide show
  1. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/PKG-INFO +1 -1
  2. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/pyproject.toml +1 -1
  3. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/agent/deep_agent.py +33 -17
  4. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/agent/multi_agent_team.py +13 -8
  5. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/agent/sandbox/file_ops.py +21 -0
  6. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/agent/sandbox/http_sandbox_backend.py +128 -25
  7. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/agent/sandbox/minio_sync.py +45 -3
  8. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/auth/wecom_ldap_service.py +87 -3
  9. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon_python_lib.egg-info/PKG-INFO +1 -1
  10. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/README.md +0 -0
  11. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/setup.cfg +0 -0
  12. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/__init__.py +0 -0
  13. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/cli.py +0 -0
  14. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/core/__init__.py +0 -0
  15. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/core/console.py +0 -0
  16. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/core/models.py +0 -0
  17. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/core/project.py +0 -0
  18. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/core/utils.py +0 -0
  19. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/__init__.py +0 -0
  20. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/agent/README.md.tpl +0 -0
  21. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/agent/__init__.py +0 -0
  22. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/agent/agent/__init__.py.tpl +0 -0
  23. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/agent/agent/main_agent.py.tpl +0 -0
  24. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/agent/agent/nodes/__init__.py.tpl +0 -0
  25. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/agent/agent/nodes/example_node.py.tpl +0 -0
  26. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/agent/agent/states/__init__.py.tpl +0 -0
  27. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/agent/agent/states/agent_state.py.tpl +0 -0
  28. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/agent/api/__init__.py.tpl +0 -0
  29. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/agent/api/query.py.tpl +0 -0
  30. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/agent/api/sse/__init__.py.tpl +0 -0
  31. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/agent/api/sse/agent.py.tpl +0 -0
  32. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/agent/app.py.tpl +0 -0
  33. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/agent/client/__init__.py.tpl +0 -0
  34. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/agent/db/__init__.py.tpl +0 -0
  35. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/agent/db/model/__init__.py.tpl +0 -0
  36. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/agent/db/model/entity.py.tpl +0 -0
  37. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/agent/db/service.py.tpl +0 -0
  38. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/agent/model/__init__.py.tpl +0 -0
  39. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/agent/model/parse.py.tpl +0 -0
  40. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/agent/tools/__init__.py.tpl +0 -0
  41. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/agent/tools/mq.py.tpl +0 -0
  42. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/base/.env.tpl +0 -0
  43. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/base/.gitignore.tpl +0 -0
  44. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/base/Dockerfile.tpl +0 -0
  45. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/base/README.md.tpl +0 -0
  46. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/base/__init__.py +0 -0
  47. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/base/app.py.tpl +0 -0
  48. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/base/app.yaml.tpl +0 -0
  49. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/base/client/FileServiceClient.py.tpl +0 -0
  50. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/base/client/__init__.py.tpl +0 -0
  51. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/base/model/__init__.py.tpl +0 -0
  52. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/base/model/file_info.py.tpl +0 -0
  53. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/base/requirements.txt.tpl +0 -0
  54. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/cli/README.md.tpl +0 -0
  55. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/cli/__init__.py +0 -0
  56. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/cli/app.py.tpl +0 -0
  57. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/cli/commands/__init__.py.tpl +0 -0
  58. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/cli/commands/hello.py.tpl +0 -0
  59. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/cli/pyproject.toml.tpl +0 -0
  60. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/cli/tools/__init__.py.tpl +0 -0
  61. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/web/README.md.tpl +0 -0
  62. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/web/__init__.py +0 -0
  63. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/web/api/__init__.py.tpl +0 -0
  64. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/web/api/echo.py.tpl +0 -0
  65. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/web/api/sse/__init__.py.tpl +0 -0
  66. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/web/api/sse/echo.py.tpl +0 -0
  67. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/web/app.py.tpl +0 -0
  68. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/web/client/__init__.py.tpl +0 -0
  69. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/web/model/__init__.py.tpl +0 -0
  70. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/web/tools/__init__.py.tpl +0 -0
  71. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/command/templates/web/tools/mq.py.tpl +0 -0
  72. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/nexus/__init__.py +0 -0
  73. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/__init__.py +0 -0
  74. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/__main__.py +0 -0
  75. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/agents/__init__.py +0 -0
  76. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/agents/factory.py +0 -0
  77. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/agents/prompts.py +0 -0
  78. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/cdp/__init__.py +0 -0
  79. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/cdp/browser.py +0 -0
  80. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/cdp/capabilities/__init__.py +0 -0
  81. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/cdp/capabilities/console.py +0 -0
  82. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/cdp/capabilities/dom.py +0 -0
  83. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/cdp/capabilities/network.py +0 -0
  84. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/cdp/capabilities/page_errors.py +0 -0
  85. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/cdp/capabilities/performance.py +0 -0
  86. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/cdp/capabilities/screenshot.py +0 -0
  87. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/cdp/client.py +0 -0
  88. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/cdp/protocol.py +0 -0
  89. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/cdp/repl.py +0 -0
  90. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/cli.py +0 -0
  91. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/commands/__init__.py +0 -0
  92. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/commands/cdp_cmd.py +0 -0
  93. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/commands/chat_cmd.py +0 -0
  94. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/commands/create_cmd.py +0 -0
  95. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/commands/evaluate_cmd.py +0 -0
  96. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/commands/init_cmd.py +0 -0
  97. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/commands/memory_cmd.py +0 -0
  98. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/commands/resume_cmd.py +0 -0
  99. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/commands/rollback_cmd.py +0 -0
  100. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/commands/run_cmd.py +0 -0
  101. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/core/__init__.py +0 -0
  102. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/core/backend.py +0 -0
  103. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/core/config.py +0 -0
  104. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/core/display.py +0 -0
  105. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/core/git_integration.py +0 -0
  106. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/core/llm.py +0 -0
  107. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/core/state.py +0 -0
  108. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/evaluate/__init__.py +0 -0
  109. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/evaluate/api_evaluator.py +0 -0
  110. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/memory/__init__.py +0 -0
  111. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/memory/compressor.py +0 -0
  112. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/memory/full.py +0 -0
  113. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/memory/hot.py +0 -0
  114. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/memory/manager.py +0 -0
  115. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/memory/warm.py +0 -0
  116. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/mode/__init__.py +0 -0
  117. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/mode/create.py +0 -0
  118. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/mode/optimize.py +0 -0
  119. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/models/__init__.py +0 -0
  120. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/models/config_models.py +0 -0
  121. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/rl/__init__.py +0 -0
  122. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/rl/baseline_tests.py +0 -0
  123. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/rl/checkpoint.py +0 -0
  124. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/rl/convergence.py +0 -0
  125. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/rl/diagnosis.py +0 -0
  126. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/rl/engine.py +0 -0
  127. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/rl/environment.py +0 -0
  128. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/rl/experience.py +0 -0
  129. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/rl/harness_prompts.py +0 -0
  130. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/rl/history.py +0 -0
  131. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/rl/optimization_logger.py +0 -0
  132. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/rl/pre_validation.py +0 -0
  133. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/rl/reward.py +0 -0
  134. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/rl/strategy_bandit.py +0 -0
  135. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/rl/strategy_generator.py +0 -0
  136. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/rl/strategy_prompts.py +0 -0
  137. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycli/skills/__init__.py +0 -0
  138. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/__init__.py +0 -0
  139. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/agent/__init__.py +0 -0
  140. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/agent/agent_manager.py +0 -0
  141. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/agent/chat_events.py +0 -0
  142. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/agent/mcp/__init__.py +0 -0
  143. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/agent/mcp/models.py +0 -0
  144. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/agent/mcp/tool_loader.py +0 -0
  145. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/agent/sandbox/__init__.py +0 -0
  146. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/agent/sandbox/sandbox_pool.py +0 -0
  147. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/agent/sandbox/sandbox_recovery.py +0 -0
  148. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/agent/sandbox/session.py +0 -0
  149. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/agent/summarization_utils.py +0 -0
  150. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/auth/__init__.py +0 -0
  151. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/auth/ldap_service.py +0 -0
  152. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/auth/oa_cache.py +0 -0
  153. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/auth/oa_crypto.py +0 -0
  154. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/auth/oa_service.py +0 -0
  155. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/config/Config.py +0 -0
  156. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/config/DatabaseConfig.py +0 -0
  157. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/config/ElasticsearchConfig.py +0 -0
  158. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/config/EmbeddingConfig.py +0 -0
  159. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/config/LLMConfig.py +0 -0
  160. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/config/LangfuseConfig.py +0 -0
  161. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/config/MQConfig.py +0 -0
  162. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/config/PgConfig.py +0 -0
  163. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/config/RedisConfig.py +0 -0
  164. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/config/RerankerConfig.py +0 -0
  165. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/config/SentryConfig.py +0 -0
  166. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/config/XxlJobConfig.py +0 -0
  167. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/config/__init__.py +0 -0
  168. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/database/async_base_db_service.py +0 -0
  169. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/database/async_database_service.py +0 -0
  170. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/database/base_db_service.py +0 -0
  171. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/database/database_service.py +0 -0
  172. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/database/elasticsearch_service.py +0 -0
  173. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/database/pg_checkpoint_service.py +0 -0
  174. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/database/redis_service.py +0 -0
  175. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/database/token_usage_db_service.py +0 -0
  176. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/health/__init__.py +0 -0
  177. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/health/health_check.py +0 -0
  178. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/health/metrics.py +0 -0
  179. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/health/ping.py +0 -0
  180. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/heartbeat_process/__init__.py +0 -0
  181. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/heartbeat_process/heartbeat_config.py +0 -0
  182. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/heartbeat_process/heartbeat_process_manager.py +0 -0
  183. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/heartbeat_process/heartbeat_process_worker.py +0 -0
  184. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/llm/__init__.py +0 -0
  185. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/llm/embedding.py +0 -0
  186. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/llm/get_llm.py +0 -0
  187. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/llm/llm_logger.py +0 -0
  188. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/llm/llm_tokens.py +0 -0
  189. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/llm/llm_with_token_tracking.py +0 -0
  190. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/llm/native_with_fallback_runnable.py +0 -0
  191. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/llm/output_fixing_runnable.py +0 -0
  192. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/llm/struct_token.py +0 -0
  193. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/llm/sy_langfuse.py +0 -0
  194. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/llm/tiktoken_cache/9b5ad71b2ce5302211f9c61530b329a4922fc6a4 +0 -0
  195. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/llm/tiktoken_cache/fb374d419588a4632f3f557e76b4b70aebbca790 +0 -0
  196. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/llm/token_usage_es_service.py +0 -0
  197. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/llm/token_usage_mysql_service.py +0 -0
  198. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/llm/token_utils.py +0 -0
  199. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/llm/usage_token.py +0 -0
  200. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/logging/__init__.py +0 -0
  201. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/logging/async_sql_logger.py +0 -0
  202. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/logging/kafka_log.py +0 -0
  203. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/logging/logger_levels.py +0 -0
  204. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/logging/logger_wrapper.py +0 -0
  205. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/logging/process_logger.py +0 -0
  206. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/logging/sql_logger.py +0 -0
  207. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/mcp_server/__init__.py +0 -0
  208. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/mcp_server/server.py +0 -0
  209. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/middleware/__init__.py +0 -0
  210. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/middleware/context.py +0 -0
  211. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/middleware/cors.py +0 -0
  212. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/middleware/docs.py +0 -0
  213. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/middleware/exception.py +0 -0
  214. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/middleware/middleware.py +0 -0
  215. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/middleware/monitor_memory.py +0 -0
  216. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/middleware/mq.py +0 -0
  217. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/middleware/sandbox.py +0 -0
  218. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/middleware/timeout.py +0 -0
  219. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/middleware/token_tracking.py +0 -0
  220. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/middleware/tool_result_truncation.py +0 -0
  221. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/middleware/traceid.py +0 -0
  222. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/models/__init__.py +0 -0
  223. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/models/base_http.py +0 -0
  224. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/models/log.py +0 -0
  225. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/models/mcp_server_config.py +0 -0
  226. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/models/mqlistener_config.py +0 -0
  227. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/models/mqmsg_model.py +0 -0
  228. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/models/mqsend_config.py +0 -0
  229. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/models/sandbox.py +0 -0
  230. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/models/sso_user.py +0 -0
  231. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/models/token_usage.py +0 -0
  232. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/models/token_usage_mysql.py +0 -0
  233. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/models/xxljob_handler_config.py +0 -0
  234. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/notice/__init__.py +0 -0
  235. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/notice/uvicorn_monitor.py +0 -0
  236. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/notice/wecom_message.py +0 -0
  237. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/rabbitmq/process_pool_consumer.py +0 -0
  238. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/rabbitmq/rabbitmq_client.py +0 -0
  239. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/rabbitmq/rabbitmq_pool.py +0 -0
  240. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/rabbitmq/rabbitmq_service.py +0 -0
  241. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/rabbitmq/rabbitmq_service_client_manager.py +0 -0
  242. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/rabbitmq/rabbitmq_service_connection_monitor.py +0 -0
  243. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/rabbitmq/rabbitmq_service_consumer_manager.py +0 -0
  244. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/rabbitmq/rabbitmq_service_core.py +0 -0
  245. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/rabbitmq/rabbitmq_service_producer_manager.py +0 -0
  246. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/sentry/__init__.py +0 -0
  247. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/sentry/sy_sentry.py +0 -0
  248. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/services.py +0 -0
  249. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/sse/__init__.py +0 -0
  250. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/sse/event.py +0 -0
  251. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/sse/sse.py +0 -0
  252. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/synacos/__init__.py +0 -0
  253. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/synacos/example.py +0 -0
  254. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/synacos/example2.py +0 -0
  255. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/synacos/feign.py +0 -0
  256. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/synacos/feign_client.py +0 -0
  257. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/synacos/nacos_client_base.py +0 -0
  258. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/synacos/nacos_config_manager.py +0 -0
  259. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/synacos/nacos_heartbeat_manager.py +0 -0
  260. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/synacos/nacos_service.py +0 -0
  261. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/synacos/nacos_service_discovery.py +0 -0
  262. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/synacos/nacos_service_registration.py +0 -0
  263. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/synacos/param.py +0 -0
  264. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/tests/deep_agent_server.py +0 -0
  265. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/tests/test_consumer_loss_rootcause.py +0 -0
  266. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/tests/test_consumer_recovery.py +0 -0
  267. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/tests/test_deep_agent.py +0 -0
  268. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/tests/test_dynamic_max_tokens.py +0 -0
  269. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/tests/test_email.py +0 -0
  270. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/tests/test_encoding_cache.py +0 -0
  271. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/tests/test_fix_verification.py +0 -0
  272. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/tests/test_mcp_server.py +0 -0
  273. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/tests/test_minimax_reasoning.py +0 -0
  274. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/tests/test_mq.py +0 -0
  275. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/tests/test_oa_login.py +0 -0
  276. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/tests/test_real_summarization.py +0 -0
  277. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/tests/test_summarization_config.py +0 -0
  278. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/tests/test_summarization_real.py +0 -0
  279. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/tests/test_summary_leak_e2e.py +0 -0
  280. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/tools/__init__.py +0 -0
  281. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/tools/async_utils.py +0 -0
  282. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/tools/docs.py +0 -0
  283. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/tools/env.py +0 -0
  284. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/tools/merge_headers.py +0 -0
  285. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/tools/snowflake.py +0 -0
  286. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/tools/syemail.py +0 -0
  287. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/tools/timing.py +0 -0
  288. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/xxljob/__init__.py +0 -0
  289. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon/xxljob/xxljob_service.py +0 -0
  290. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon_python_lib.egg-info/SOURCES.txt +0 -0
  291. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon_python_lib.egg-info/dependency_links.txt +0 -0
  292. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon_python_lib.egg-info/entry_points.txt +0 -0
  293. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon_python_lib.egg-info/requires.txt +0 -0
  294. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/src/sycommon_python_lib.egg-info/top_level.txt +0 -0
  295. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/tests/test_asyncio_logging.py +0 -0
  296. {sycommon_python_lib-0.2.5a37 → sycommon_python_lib-0.2.5a39}/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.5a37
3
+ Version: 0.2.5a39
4
4
  Summary: Add your description here
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sycommon-python-lib"
3
- version = "0.2.5a37"
3
+ version = "0.2.5a39"
4
4
  description = "Add your description here"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -762,13 +762,10 @@ class DeepAgent:
762
762
 
763
763
  # 发送 tool_call 事件,前端根据 tool_call_id 更新
764
764
  tc_id = existing_tc["id"]
765
- if tc_id:
765
+ if tc_id and tc_id not in seen_tool_call_ids:
766
766
  current_args = existing_tc["args"]
767
- # 只有以下情况才发送:
768
- # 1. 首次出现(args 为空,先发一个占位)
769
- # 2. args 解析成功(有实质更新)
770
767
  is_first = not existing_tc.get("_sent")
771
- if is_first or args_parsed:
768
+ if is_first:
772
769
  event = ChatEventBuilder.tool_call(
773
770
  name=existing_tc["name"],
774
771
  args=current_args,
@@ -777,6 +774,7 @@ class DeepAgent:
777
774
  agent=DEFAULT_AGENT_NAME,
778
775
  )
779
776
  existing_tc["_sent"] = True
777
+ seen_tool_call_ids.add(tc_id)
780
778
  if on_event:
781
779
  await on_event(event)
782
780
  yield event
@@ -788,6 +786,9 @@ class DeepAgent:
788
786
  tc_id = tc.get("id", "")
789
787
  if not tc_id:
790
788
  continue
789
+ if tc_id in seen_tool_call_ids:
790
+ continue
791
+ seen_tool_call_ids.add(tc_id)
791
792
 
792
793
  tc_name = tc.get("name", "unknown")
793
794
  tc_args = tc.get("args", {})
@@ -1237,7 +1238,11 @@ async def _sync_skills_to_sandbox(
1237
1238
  skills_dir: str,
1238
1239
  backend: HTTPSandboxBackend,
1239
1240
  ) -> None:
1240
- """同步 skills 到沙箱(按版本检查,版本不一致则覆盖)"""
1241
+ """同步 skills SKILL.md 到沙箱(按版本检查,版本不一致则覆盖)
1242
+
1243
+ 只同步 SKILL.md 文件,不同步 scripts/ 等大目录。
1244
+ scripts/ 在 agent 实际调用时由 HTTPSandboxBackend._lazy_sync_skill_from_path 按需同步。
1245
+ """
1241
1246
  if not os.path.isdir(skills_dir):
1242
1247
  return
1243
1248
 
@@ -1291,9 +1296,15 @@ async def _sync_skills_to_sandbox(
1291
1296
  f"[DeepAgent] 删除旧版技能失败: {skill_name}, {e}")
1292
1297
  continue
1293
1298
 
1294
- await backend.async_sync_dirs([(src, f"/skills/{skill_name}")])
1295
- SYLogger.info(
1296
- f"[DeepAgent] 同步技能到沙箱: {skill_name} v{local_version}")
1299
+ # 只同步 SKILL.md(不再同步整个目录)
1300
+ if os.path.isfile(local_skill_md):
1301
+ with open(local_skill_md, "rb") as f:
1302
+ content = f.read()
1303
+ await backend.aupload_files([
1304
+ (f"/skills/{skill_name}/SKILL.md", content)
1305
+ ])
1306
+ SYLogger.info(
1307
+ f"[DeepAgent] 同步技能元数据到沙箱: {skill_name} v{local_version} (仅 SKILL.md)")
1297
1308
  except Exception as e:
1298
1309
  SYLogger.warning(f"[DeepAgent] 技能同步失败: {e}")
1299
1310
 
@@ -1303,16 +1314,14 @@ async def _create_sandbox_backend(
1303
1314
  config: AgentConfig,
1304
1315
  project_root: Path,
1305
1316
  ) -> HTTPSandboxBackend:
1306
- """创建并同步沙箱后端"""
1307
- sync_dirs = []
1317
+ """创建并同步沙箱后端
1308
1318
 
1309
- if config.skills_dir:
1310
- skills_dir = Path(config.skills_dir)
1311
- else:
1312
- skills_dir = project_root / "skills"
1313
- skills_dir.mkdir(parents=True, exist_ok=True)
1314
- sync_dirs.append((str(skills_dir), "/skills"))
1319
+ 注意:skills 目录不再通过 sync_dirs 全量同步,
1320
+ 而是由 _sync_skills_to_sandbox() 做版本感知的增量同步。
1321
+ """
1322
+ sync_dirs = []
1315
1323
 
1324
+ # skills 不再通过 sync_dirs 全量同步,改由 _sync_skills_to_sandbox() 按版本增量同步
1316
1325
  if config.memory_dir:
1317
1326
  memory_dir = Path(config.memory_dir)
1318
1327
  else:
@@ -1320,12 +1329,19 @@ async def _create_sandbox_backend(
1320
1329
  memory_dir.mkdir(parents=True, exist_ok=True)
1321
1330
  sync_dirs.append((str(memory_dir), "/memory"))
1322
1331
 
1332
+ # 确定 skills_dir,传递给沙箱后端用于懒同步
1333
+ if config.skills_dir:
1334
+ skills_dir_for_backend = str(Path(config.skills_dir))
1335
+ else:
1336
+ skills_dir_for_backend = str(project_root / "skills")
1337
+
1323
1338
  sandbox_backend = HTTPSandboxBackend.from_nacos(
1324
1339
  service_name=config.sandbox_service_name,
1325
1340
  user_id=user_id,
1326
1341
  timeout=config.sandbox_timeout,
1327
1342
  sync_dirs=sync_dirs,
1328
1343
  auto_sync=True,
1344
+ skills_dir=skills_dir_for_backend,
1329
1345
  )
1330
1346
 
1331
1347
  try:
@@ -655,16 +655,14 @@ async def _create_sandbox_backend_for_team(
655
655
  config: TeamConfig,
656
656
  project_root: Path,
657
657
  ) -> HTTPSandboxBackend:
658
- """创建并同步沙箱后端(团队版本)"""
659
- sync_dirs = []
658
+ """创建并同步沙箱后端(团队版本)
660
659
 
661
- if config.skills_dir:
662
- skills_dir = Path(config.skills_dir)
663
- else:
664
- skills_dir = project_root / "skills"
665
- skills_dir.mkdir(parents=True, exist_ok=True)
666
- sync_dirs.append((str(skills_dir), "/skills"))
660
+ 注意:skills 目录不再通过 sync_dirs 全量同步,
661
+ 而是由 _sync_skills_to_sandbox() 做版本感知的增量同步。
662
+ """
663
+ sync_dirs = []
667
664
 
665
+ # skills 不再通过 sync_dirs 全量同步,改由 _sync_skills_to_sandbox() 按版本增量同步
668
666
  if config.memory_dir:
669
667
  memory_dir = Path(config.memory_dir)
670
668
  else:
@@ -672,6 +670,12 @@ async def _create_sandbox_backend_for_team(
672
670
  memory_dir.mkdir(parents=True, exist_ok=True)
673
671
  sync_dirs.append((str(memory_dir), "/memory"))
674
672
 
673
+ # 确定 skills_dir,传递给沙箱后端用于懒同步
674
+ if config.skills_dir:
675
+ skills_dir_for_backend = str(Path(config.skills_dir))
676
+ else:
677
+ skills_dir_for_backend = str(project_root / "skills")
678
+
675
679
  sandbox_backend = HTTPSandboxBackend.from_nacos(
676
680
  service_name=config.sandbox_service_name,
677
681
  user_id=user_id,
@@ -679,6 +683,7 @@ async def _create_sandbox_backend_for_team(
679
683
  sync_dirs=sync_dirs,
680
684
  auto_sync=True,
681
685
  version=get_env_var('VERSION') or None,
686
+ skills_dir=skills_dir_for_backend,
682
687
  )
683
688
 
684
689
  # 健康检查
@@ -182,6 +182,7 @@ class FileOperationsMixin:
182
182
  def ls(self: "HTTPSandboxBackend", path: str) -> LsResult:
183
183
  """列出目录内容"""
184
184
  try:
185
+ self._lazy_sync_skill_from_path_sync(path)
185
186
  self._ensure_synced_sync()
186
187
  SYLogger.info(f"[Sandbox] 列出目录: {path}")
187
188
  result = self._post_sync(f"{SANDBOX_API_PREFIX}/ls", {
@@ -198,6 +199,7 @@ class FileOperationsMixin:
198
199
  async def als(self: "HTTPSandboxBackend", path: str, *, timeout: int = None) -> LsResult:
199
200
  """异步列出目录内容"""
200
201
  try:
202
+ await self._lazy_sync_skill_from_path(path)
201
203
  await self._ensure_synced_async()
202
204
  SYLogger.info(f"[Sandbox] 异步列出目录: {path}")
203
205
  result = await self._post_async_with_failover(f"{SANDBOX_API_PREFIX}/ls", {
@@ -221,6 +223,9 @@ class FileOperationsMixin:
221
223
  ) -> ReadResult:
222
224
  """读取文件内容"""
223
225
  try:
226
+ # 按需懒同步:检测是否读取 skill 资源
227
+ self._lazy_sync_skill_from_path_sync(file_path)
228
+
224
229
  self._ensure_synced_sync()
225
230
  SYLogger.info(
226
231
  f"[Sandbox] 读取文件: {file_path} (offset={offset}, limit={limit})")
@@ -256,6 +261,9 @@ class FileOperationsMixin:
256
261
  ) -> ReadResult:
257
262
  """异步读取文件内容"""
258
263
  try:
264
+ # 按需懒同步:检测是否读取 skill 资源
265
+ await self._lazy_sync_skill_from_path(file_path)
266
+
259
267
  await self._ensure_synced_async()
260
268
  SYLogger.info(
261
269
  f"[Sandbox] 异步读取文件: {file_path} (offset={offset}, limit={limit})")
@@ -302,6 +310,7 @@ class FileOperationsMixin:
302
310
  /conversation_history/ 路径)。设为 False 时,文件已存在返回错误。
303
311
  """
304
312
  try:
313
+ self._lazy_sync_skill_from_path_sync(file_path)
305
314
  self._ensure_synced_sync()
306
315
  SYLogger.info(f"[Sandbox] 写入文件: {file_path} ({len(content)} 字符)")
307
316
  result = self._post_sync(f"{SANDBOX_API_PREFIX}/write", {
@@ -340,6 +349,7 @@ class FileOperationsMixin:
340
349
  timeout: 请求超时时间。
341
350
  """
342
351
  try:
352
+ await self._lazy_sync_skill_from_path(file_path)
343
353
  await self._ensure_synced_async()
344
354
  SYLogger.info(f"[Sandbox] 异步写入文件: {file_path} ({len(content)} 字符)")
345
355
  result = await self._post_async_with_failover(f"{SANDBOX_API_PREFIX}/write", {
@@ -374,6 +384,7 @@ class FileOperationsMixin:
374
384
  ) -> EditResult:
375
385
  """编辑文件"""
376
386
  try:
387
+ self._lazy_sync_skill_from_path_sync(file_path)
377
388
  self._ensure_synced_sync()
378
389
  result = self._post_sync(f"{SANDBOX_API_PREFIX}/edit", {
379
390
  "file_path": file_path,
@@ -402,6 +413,7 @@ class FileOperationsMixin:
402
413
  ) -> EditResult:
403
414
  """异步编辑文件"""
404
415
  try:
416
+ await self._lazy_sync_skill_from_path(file_path)
405
417
  await self._ensure_synced_async()
406
418
  result = await self._post_async_with_failover(f"{SANDBOX_API_PREFIX}/edit", {
407
419
  "file_path": file_path,
@@ -424,6 +436,7 @@ class FileOperationsMixin:
424
436
  def glob(self: "HTTPSandboxBackend", pattern: str, path: str | None = None) -> GlobResult:
425
437
  """glob 搜索文件"""
426
438
  try:
439
+ self._lazy_sync_skill_from_path_sync(path or "/")
427
440
  self._ensure_synced_sync()
428
441
  result = self._post_sync(f"{SANDBOX_API_PREFIX}/glob", {
429
442
  "pattern": pattern,
@@ -439,6 +452,7 @@ class FileOperationsMixin:
439
452
  async def aglob(self: "HTTPSandboxBackend", pattern: str, path: str | None = None, *, timeout: int = None) -> GlobResult:
440
453
  """异步 glob 搜索文件"""
441
454
  try:
455
+ await self._lazy_sync_skill_from_path(path or "/")
442
456
  await self._ensure_synced_async()
443
457
  result = await self._post_async_with_failover(f"{SANDBOX_API_PREFIX}/glob", {
444
458
  "pattern": pattern,
@@ -456,6 +470,7 @@ class FileOperationsMixin:
456
470
  def tree(self: "HTTPSandboxBackend", path: str = "/", max_depth: int = 30, max_files: int = 0) -> TreeResult:
457
471
  """以树形结构展示目录"""
458
472
  try:
473
+ self._lazy_sync_skill_from_path_sync(path)
459
474
  self._ensure_synced_sync()
460
475
  SYLogger.info(f"[Sandbox] tree: {path}")
461
476
  result = self._post_sync(f"{SANDBOX_API_PREFIX}/tree", {
@@ -476,6 +491,7 @@ class FileOperationsMixin:
476
491
  async def atree(self: "HTTPSandboxBackend", path: str = "/", max_depth: int = 30, max_files: int = 0, *, timeout: int = None) -> TreeResult:
477
492
  """异步以树形结构展示目录"""
478
493
  try:
494
+ await self._lazy_sync_skill_from_path(path)
479
495
  await self._ensure_synced_async()
480
496
  SYLogger.info(f"[Sandbox] 异步 tree: {path}")
481
497
  result = await self._post_async_with_failover(f"{SANDBOX_API_PREFIX}/tree", {
@@ -501,6 +517,7 @@ class FileOperationsMixin:
501
517
  ) -> GrepResult:
502
518
  """搜索文件内容"""
503
519
  try:
520
+ self._lazy_sync_skill_from_path_sync(path or "/")
504
521
  self._ensure_synced_sync()
505
522
  result = self._post_sync(f"{SANDBOX_API_PREFIX}/grep", {
506
523
  "pattern": pattern,
@@ -534,6 +551,7 @@ class FileOperationsMixin:
534
551
  ) -> GrepResult:
535
552
  """异步搜索文件内容"""
536
553
  try:
554
+ await self._lazy_sync_skill_from_path(path or "/")
537
555
  await self._ensure_synced_async()
538
556
  result = await self._post_async_with_failover(f"{SANDBOX_API_PREFIX}/grep", {
539
557
  "pattern": pattern,
@@ -564,6 +582,7 @@ class FileOperationsMixin:
564
582
  ) -> DeleteResult:
565
583
  """删除文件或文件夹"""
566
584
  try:
585
+ self._lazy_sync_skill_from_path_sync(path)
567
586
  self._ensure_synced_sync()
568
587
  SYLogger.info(f"[Sandbox] 删除: {path} (recursive={recursive})")
569
588
  result = self._post_sync(f"{SANDBOX_API_PREFIX}/delete", {
@@ -593,6 +612,7 @@ class FileOperationsMixin:
593
612
  ) -> DeleteResult:
594
613
  """异步删除文件或文件夹"""
595
614
  try:
615
+ await self._lazy_sync_skill_from_path(path)
596
616
  await self._ensure_synced_async()
597
617
  SYLogger.info(f"[Sandbox] 异步删除: {path} (recursive={recursive})")
598
618
  result = await self._post_async_with_failover(f"{SANDBOX_API_PREFIX}/delete", {
@@ -618,6 +638,7 @@ class FileOperationsMixin:
618
638
  async def astat(self: "HTTPSandboxBackend", path: str, *, timeout: int = None) -> "StatResult":
619
639
  """异步检查文件或目录状态"""
620
640
  try:
641
+ await self._lazy_sync_skill_from_path(path)
621
642
  await self._ensure_synced_async()
622
643
  SYLogger.info(f"[Sandbox] 异步查询文件状态: {path}")
623
644
  result = await self._post_async_with_failover(f"{SANDBOX_API_PREFIX}/stat", {
@@ -14,7 +14,7 @@ import sys
14
14
  import tempfile
15
15
  import threading
16
16
  import requests
17
- from pathlib import Path
17
+ from pathlib import Path, PurePosixPath
18
18
  from typing import Optional, List
19
19
 
20
20
  import aiohttp
@@ -126,6 +126,7 @@ class HTTPSandboxBackend(FileOperationsMixin, SandboxBackendProtocol):
126
126
  nacos_group: str = "DEFAULT_GROUP",
127
127
  token: str = None,
128
128
  env: dict[str, str] = None,
129
+ skills_dir: str = None,
129
130
  ):
130
131
  """
131
132
  初始化 HTTP 沙箱后端
@@ -139,6 +140,7 @@ class HTTPSandboxBackend(FileOperationsMixin, SandboxBackendProtocol):
139
140
  nacos_service_name: Nacos 服务名(用于故障转移时重新发现服务)
140
141
  nacos_group: Nacos 服务分组
141
142
  env: 注入到沙箱的环境变量字典,每次执行命令时自动前置 export
143
+ skills_dir: 本地 skills 目录路径,用于 execute 时按需懒同步 scripts/
142
144
  """
143
145
  self._base_url = base_url.rstrip("/")
144
146
  self._user_id = user_id.lower().replace(" ", "") if user_id else user_id
@@ -149,6 +151,10 @@ class HTTPSandboxBackend(FileOperationsMixin, SandboxBackendProtocol):
149
151
  self._workspace_verified = False
150
152
  self._local_mode: Optional[bool] = None
151
153
 
154
+ # Skills 懒同步:记录本地 skills 目录,访问时按需同步整个 skill 子目录
155
+ self._skills_dir = skills_dir
156
+ self._synced_skills: set[str] = set() # 已完整同步的 skill 名称
157
+
152
158
  # Token authentication: instance-level > env var
153
159
  self._token = token if token is not None else os.environ.get(
154
160
  "SANDBOX_TOKEN", "")
@@ -244,6 +250,7 @@ class HTTPSandboxBackend(FileOperationsMixin, SandboxBackendProtocol):
244
250
  auto_sync: bool = False,
245
251
  load_balance: bool = True,
246
252
  env: dict[str, str] = None,
253
+ skills_dir: str = None,
247
254
  ) -> "HTTPSandboxBackend":
248
255
  """
249
256
  从 Nacos 服务发现创建后端实例
@@ -257,6 +264,7 @@ class HTTPSandboxBackend(FileOperationsMixin, SandboxBackendProtocol):
257
264
  sync_dirs: 要同步的目录列表 [(本地路径, 沙箱路径), ...]
258
265
  auto_sync: 是否在首次文件操作时自动同步
259
266
  load_balance: 是否基于 user_id 进行负载均衡(默认 True)
267
+ skills_dir: 本地 skills 目录路径,用于 execute 时按需懒同步 scripts/
260
268
 
261
269
  Returns:
262
270
  HTTPSandboxBackend 实例
@@ -279,6 +287,7 @@ class HTTPSandboxBackend(FileOperationsMixin, SandboxBackendProtocol):
279
287
  sync_dirs=sync_dirs,
280
288
  auto_sync=auto_sync,
281
289
  env=env,
290
+ skills_dir=skills_dir,
282
291
  )
283
292
 
284
293
  from sycommon.synacos.nacos_service import NacosService
@@ -330,6 +339,7 @@ class HTTPSandboxBackend(FileOperationsMixin, SandboxBackendProtocol):
330
339
  nacos_service_name=service_name,
331
340
  nacos_group=group,
332
341
  env=env,
342
+ skills_dir=skills_dir,
333
343
  )
334
344
 
335
345
  @classmethod
@@ -344,17 +354,22 @@ class HTTPSandboxBackend(FileOperationsMixin, SandboxBackendProtocol):
344
354
  auto_sync: bool = False,
345
355
  load_balance: bool = True,
346
356
  env: dict[str, str] = None,
357
+ skills_dir: str = None,
347
358
  ) -> "HTTPSandboxBackend":
348
359
  """异步从 Nacos 服务发现创建后端实例"""
349
360
  return await asyncio.to_thread(
350
361
  cls.from_nacos,
351
- service_name, user_id, group, version, timeout, sync_dirs, auto_sync, load_balance, env,
362
+ service_name, user_id, group, version, timeout, sync_dirs, auto_sync, load_balance, env, skills_dir,
352
363
  )
353
364
 
354
365
  # ============== 内部方法 - 同步版本 ==============
355
366
 
356
367
  def _refresh_from_nacos_and_switch_sync(self) -> bool:
357
- """从 Nacos 重新获取服务实例并切换(同步版本)"""
368
+ """从 Nacos 重新获取服务实例并切换(同步版本)
369
+
370
+ 优先从 MinIO 恢复用户文件到新沙箱,避免沙箱间互相迁移脏数据。
371
+ 只有 MinIO 不可用时才尝试从旧沙箱拉取。
372
+ """
358
373
  # 防止递归:如果在故障转移过程中再次调用,直接返回 False
359
374
  if getattr(self, '_in_failover', False):
360
375
  SYLogger.warning("[Sandbox] 已在故障转移过程中,跳过重复调用")
@@ -399,33 +414,40 @@ class HTTPSandboxBackend(FileOperationsMixin, SandboxBackendProtocol):
399
414
  old_url = self._base_url
400
415
  SYLogger.info(f"[Sandbox] 准备切换服务: {old_url} -> {new_url}")
401
416
 
402
- # 1. 先从旧服务下载工作空间文件
403
- workspace_files = []
404
- try:
405
- sync_result = self._sync_workspace_sync()
406
- workspace_files = sync_result.get("files", [])
407
- SYLogger.info(
408
- f"[Sandbox] 从旧服务获取 {len(workspace_files)} 个工作空间文件")
409
- except Exception as e:
410
- SYLogger.warning(f"[Sandbox] 获取工作空间文件失败: {e}")
411
-
412
- # 2. 切换到新服务
417
+ # 1. 切换到新服务
413
418
  self._base_url = new_url
414
419
  self._synced = False
415
420
 
416
- # 3. 同步配置的目录到新服务
421
+ # 2. 同步配置的目录到新服务(skills, memory 等本地文件)
417
422
  if self._sync_dirs:
418
423
  SYLogger.info(f"[Sandbox] 重新同步配置目录到新服务...")
419
424
  self._sync_sync()
420
425
 
421
- # 4. 上传工作空间文件到新服务
422
- if workspace_files:
423
- SYLogger.info(
424
- f"[Sandbox] 上传 {len(workspace_files)} 个工作空间文件到新服务...")
425
- upload_result = self._upload_workspace_files_sync(
426
- workspace_files)
426
+ # 3. 优先从 MinIO 恢复用户工作空间文件
427
+ workspace_restored = False
428
+ try:
429
+ from sycommon.agent.sandbox.minio_sync import MinioSyncService
430
+ minio = MinioSyncService()
431
+ if minio.is_available():
432
+ SYLogger.info(
433
+ f"[Sandbox] 从 MinIO 恢复用户文件到新沙箱...")
434
+ import asyncio
435
+ loop = asyncio.new_event_loop()
436
+ try:
437
+ restored = loop.run_until_complete(
438
+ minio.restore_from_minio(self, self._user_id))
439
+ workspace_restored = restored > 0
440
+ SYLogger.info(
441
+ f"[Sandbox] MinIO 恢复完成: {restored} 个文件")
442
+ finally:
443
+ loop.close()
444
+ except Exception as e:
445
+ SYLogger.warning(
446
+ f"[Sandbox] MinIO 恢复失败: {e}")
447
+
448
+ if not workspace_restored:
427
449
  SYLogger.info(
428
- f"[Sandbox] 工作空间迁移完成: 成功 {upload_result['success']}, 失败 {upload_result['failed']}")
450
+ f"[Sandbox] MinIO 无可用数据,新沙箱将从空工作空间开始")
429
451
 
430
452
  SYLogger.info(f"[Sandbox] 服务切换完成: {old_url} -> {new_url}")
431
453
  return True
@@ -702,9 +724,17 @@ class HTTPSandboxBackend(FileOperationsMixin, SandboxBackendProtocol):
702
724
  )
703
725
 
704
726
  async def aexecute(self, command: str, *, timeout: int = None) -> ExecuteResponse:
705
- """异步执行 shell 命令(服务端负责路径隔离和目录初始化)"""
727
+ """异步执行 shell 命令(服务端负责路径隔离和目录初始化)
728
+
729
+ 如果命令引用了 /skills/<name>/ 下的资源,
730
+ 会自动按需同步该 skill 的整个目录到沙箱。
731
+ """
706
732
  command = self._inject_env(command)
707
733
  SYLogger.info(f"[Sandbox] aexecute 开始: command={command}")
734
+
735
+ # 按需懒同步:检测命令中是否引用了 skill 资源
736
+ await self._lazy_sync_skill_from_path(command)
737
+
708
738
  await self._ensure_synced_async()
709
739
  SYLogger.info(f"[Sandbox] _ensure_synced_async 完成,开始执行命令: {command}")
710
740
  try:
@@ -728,6 +758,79 @@ class HTTPSandboxBackend(FileOperationsMixin, SandboxBackendProtocol):
728
758
  truncated=False
729
759
  )
730
760
 
761
+ async def _lazy_sync_skill_from_path(self, path: str) -> None:
762
+ """从文件路径中检测是否访问了 skill 资源,按需同步整个 skill 目录
763
+
764
+ 检测路径中是否包含 /skills/<name>/ 模式(不限 scripts/,覆盖
765
+ assets/、references/ 及任意自定义子目录)。
766
+ 如果该 skill 尚未同步,则上传整个 skill 目录到沙箱。
767
+ """
768
+ if not self._skills_dir:
769
+ return
770
+
771
+ import re
772
+ # 匹配 /skills/<skill_name>/ 或 skills/<skill_name>/
773
+ match = re.search(r'/skills/([a-zA-Z0-9_\-]+)/', path)
774
+ if not match:
775
+ match = re.search(r'(?:^|\s|")skills/([a-zA-Z0-9_\-]+)/', path)
776
+ if not match:
777
+ return
778
+
779
+ skill_name = match.group(1)
780
+ if skill_name in self._synced_skills:
781
+ return
782
+
783
+ skill_dir = os.path.join(self._skills_dir, skill_name)
784
+ if not os.path.isdir(skill_dir):
785
+ self._synced_skills.add(skill_name)
786
+ return
787
+
788
+ try:
789
+ await self.async_sync_dirs([
790
+ (skill_dir, f"/skills/{skill_name}")
791
+ ])
792
+ self._synced_skills.add(skill_name)
793
+ SYLogger.info(
794
+ f"[Sandbox] 懒同步技能目录: {skill_name}/")
795
+ except Exception as e:
796
+ SYLogger.warning(
797
+ f"[Sandbox] 懒同步技能目录失败: {skill_name}, {e}")
798
+
799
+ def _lazy_sync_skill_from_path_sync(self, path: str) -> None:
800
+ """同步版本的懒同步(在同步文件操作中调用)
801
+
802
+ 内部使用 asyncio.run_coroutine_threadsafe 或回退到同步上传。
803
+ """
804
+ if not self._skills_dir:
805
+ return
806
+
807
+ import re
808
+ match = re.search(r'/skills/([a-zA-Z0-9_\-]+)/', path)
809
+ if not match:
810
+ match = re.search(r'(?:^|\s|")skills/([a-zA-Z0-9_\-]+)/', path)
811
+ if not match:
812
+ return
813
+
814
+ skill_name = match.group(1)
815
+ if skill_name in self._synced_skills:
816
+ return
817
+
818
+ skill_dir = os.path.join(self._skills_dir, skill_name)
819
+ if not os.path.isdir(skill_dir):
820
+ self._synced_skills.add(skill_name)
821
+ return
822
+
823
+ try:
824
+ # 同步版本直接调用同步上传方法
825
+ self._upload_directory_sync(
826
+ skill_dir, f"/skills/{skill_name}", mode="full")
827
+ self._synced_skills.add(skill_name)
828
+ SYLogger.info(
829
+ f"[Sandbox] 懒同步技能目录(sync): {skill_name}/")
830
+ except Exception as e:
831
+ SYLogger.warning(
832
+ f"[Sandbox] 懒同步技能目录失败(sync): {skill_name}, {e}")
833
+
731
834
  async def _sync_async(self, *, timeout: int = None) -> dict:
732
835
  """同步目录(异步版本)
733
836
 
@@ -855,7 +958,7 @@ class HTTPSandboxBackend(FileOperationsMixin, SandboxBackendProtocol):
855
958
 
856
959
  local_file = Path(root) / file
857
960
  relative_path = local_file.relative_to(local_path)
858
- sandbox_path = str(Path(remote_path) / relative_path)
961
+ sandbox_path = str(PurePosixPath(remote_path) / relative_path.as_posix())
859
962
  result.append((sandbox_path, local_file))
860
963
  return result
861
964
 
@@ -1236,7 +1339,7 @@ class HTTPSandboxBackend(FileOperationsMixin, SandboxBackendProtocol):
1236
1339
 
1237
1340
  local_file = Path(root) / file
1238
1341
  relative_path = local_file.relative_to(local_path)
1239
- sandbox_path = str(Path(remote_path) / relative_path)
1342
+ sandbox_path = str(PurePosixPath(remote_path) / relative_path.as_posix())
1240
1343
  files_to_upload.append((sandbox_path, local_file))
1241
1344
 
1242
1345
  SYLogger.info(f"[Sandbox] 准备上传 {len(files_to_upload)} 个文件到沙箱")
@@ -218,6 +218,19 @@ class MinioSyncService(metaclass=SingletonMeta):
218
218
  """异步删除 MinIO 中指定前缀下的所有对象"""
219
219
  return await asyncio.to_thread(self.remove_prefix, prefix)
220
220
 
221
+ async def cleanup_user_history(self, user_id: str) -> None:
222
+ """清理用户沙箱对话历史和工具缓存(沙箱 + MinIO 双删)
223
+
224
+ 用于新建会话/重置对话时,确保沙箱和 MinIO 中的
225
+ conversation_history 和 large_tool_results 都被清除,
226
+ 避免 restore_from_minio 把旧文件同步回来。
227
+ """
228
+ uid = user_id.lower().replace(" ", "")
229
+ await asyncio.gather(
230
+ self.aremove_prefix(f"{uid}/current/conversation_history/"),
231
+ self.aremove_prefix(f"{uid}/current/large_tool_results/"),
232
+ )
233
+
221
234
  # ============== 查找最近副本 ==============
222
235
 
223
236
  def find_latest_object_key(self, user_id: str, file_path: str) -> Optional[str]:
@@ -303,7 +316,10 @@ class MinioSyncService(metaclass=SingletonMeta):
303
316
  async def sync_sandbox_to_minio(self, sandbox_backend, user_id: str) -> int:
304
317
  """扫描沙箱目录,增量同步文件到 MinIO
305
318
 
306
- 存储到 {user_id}/current/ 目录,只上传新增或修改的文件。
319
+ 存储到 {user_id}/current/ 目录:
320
+ - 上传新增或修改的文件
321
+ - 删除 MinIO 中存在但沙箱中已不存在的文件(双向同步)
322
+
307
323
  max_files=0 表示不限制,tree 返回全部文件。
308
324
  下载/上传采用并发(每批 CONCURRENT_BATCH 个),避免串行太慢。
309
325
 
@@ -329,6 +345,13 @@ class MinioSyncService(metaclass=SingletonMeta):
329
345
 
330
346
  sandbox_files = self.collect_sandbox_files(tree_result)
331
347
  if not sandbox_files:
348
+ # 沙箱为空,清理 MinIO 中该用户的所有文件
349
+ try:
350
+ removed = await self.aremove_prefix(f"{user_id.lower()}/current/")
351
+ if removed > 0:
352
+ SYLogger.info(f"[MinIO] 沙箱为空,清理 MinIO: user={user_id}, removed={removed}")
353
+ except Exception as e:
354
+ SYLogger.warning(f"[MinIO] 沙箱为空时清理 MinIO 失败: {e}")
332
355
  return 0
333
356
 
334
357
  # 2. 确定存储目录
@@ -353,17 +376,36 @@ class MinioSyncService(metaclass=SingletonMeta):
353
376
  SYLogger.warning(f"[MinIO] 列出已有副本失败,将全量上传: {e}")
354
377
 
355
378
  # 4. 找出需要同步的文件(新增的不在 MinIO 中)
379
+ sandbox_file_set = set(sandbox_files)
356
380
  changed_files = [
357
381
  fp for fp in sandbox_files if fp not in existing_objects]
358
382
 
383
+ # 5. 找出需要删除的文件(MinIO 中存在但沙箱中已不存在)
384
+ deleted_files = [
385
+ fp for fp in existing_objects if fp not in sandbox_file_set]
386
+
387
+ # 删除 MinIO 中的孤立文件
388
+ if deleted_files:
389
+ removed_count = 0
390
+ for fp in deleted_files:
391
+ try:
392
+ object_key = f"{prefix}{fp}"
393
+ await self.aremove_object(object_key)
394
+ removed_count += 1
395
+ except Exception as e:
396
+ SYLogger.warning(f"[MinIO] 删除孤立文件失败: {fp}, {e}")
397
+ if removed_count > 0:
398
+ SYLogger.info(
399
+ f"[MinIO] 清理孤立文件: user={user_id}, removed={removed_count}")
400
+
359
401
  if not changed_files:
360
- SYLogger.info(f"[MinIO] 所有文件均无变化,跳过同步: user={user_id}")
402
+ SYLogger.info(f"[MinIO] 所有文件均无变化: user={user_id}")
361
403
  return 0
362
404
 
363
405
  SYLogger.info(
364
406
  f"[MinIO] 检测到 {len(changed_files)} 个文件有变化: user={user_id}")
365
407
 
366
- # 5. 并发下载并上传变化文件
408
+ # 6. 并发下载并上传变化文件
367
409
  synced = await self._sync_batch(sandbox_backend, changed_files, existing_objects, prefix)
368
410
 
369
411
  SYLogger.info(