sycommon-python-lib 0.2.5a1__tar.gz → 0.2.5a3__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.
Potentially problematic release.
This version of sycommon-python-lib might be problematic. Click here for more details.
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/PKG-INFO +1 -1
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/pyproject.toml +1 -1
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/agent/deep_agent.py +3 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/agent/mcp/tool_loader.py +59 -9
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/agent/sandbox/http_sandbox_backend.py +42 -9
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/auth/__init__.py +23 -0
- sycommon_python_lib-0.2.5a3/src/sycommon/auth/oa_cache.py +95 -0
- sycommon_python_lib-0.2.5a3/src/sycommon/auth/oa_crypto.py +60 -0
- sycommon_python_lib-0.2.5a3/src/sycommon/auth/oa_service.py +201 -0
- sycommon_python_lib-0.2.5a3/src/sycommon/tests/test_minimax_reasoning.py +290 -0
- sycommon_python_lib-0.2.5a3/src/sycommon/tests/test_oa_login.py +229 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon_python_lib.egg-info/PKG-INFO +1 -1
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon_python_lib.egg-info/SOURCES.txt +5 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/README.md +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/setup.cfg +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/cli.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/core/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/core/console.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/core/models.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/core/project.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/core/utils.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/agent/README.md.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/agent/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/agent/agent/__init__.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/agent/agent/main_agent.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/agent/agent/nodes/__init__.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/agent/agent/nodes/example_node.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/agent/agent/states/__init__.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/agent/agent/states/agent_state.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/agent/api/__init__.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/agent/api/query.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/agent/api/sse/__init__.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/agent/api/sse/agent.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/agent/app.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/agent/client/__init__.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/agent/db/__init__.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/agent/db/model/__init__.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/agent/db/model/entity.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/agent/db/service.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/agent/model/__init__.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/agent/model/parse.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/agent/tools/__init__.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/agent/tools/mq.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/base/.env.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/base/.gitignore.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/base/Dockerfile.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/base/README.md.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/base/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/base/app.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/base/app.yaml.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/base/client/FileServiceClient.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/base/client/__init__.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/base/model/__init__.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/base/model/file_info.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/base/requirements.txt.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/cli/README.md.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/cli/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/cli/app.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/cli/commands/__init__.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/cli/commands/hello.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/cli/pyproject.toml.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/cli/tools/__init__.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/web/README.md.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/web/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/web/api/__init__.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/web/api/echo.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/web/api/sse/__init__.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/web/api/sse/echo.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/web/app.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/web/client/__init__.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/web/model/__init__.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/web/tools/__init__.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/command/templates/web/tools/mq.py.tpl +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/nexus/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/__main__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/agents/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/agents/factory.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/agents/prompts.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/cdp/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/cdp/browser.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/cdp/capabilities/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/cdp/capabilities/console.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/cdp/capabilities/dom.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/cdp/capabilities/network.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/cdp/capabilities/page_errors.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/cdp/capabilities/performance.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/cdp/capabilities/screenshot.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/cdp/client.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/cdp/protocol.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/cdp/repl.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/cli.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/commands/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/commands/cdp_cmd.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/commands/chat_cmd.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/commands/create_cmd.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/commands/evaluate_cmd.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/commands/init_cmd.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/commands/memory_cmd.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/commands/resume_cmd.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/commands/rollback_cmd.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/commands/run_cmd.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/core/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/core/backend.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/core/config.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/core/display.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/core/git_integration.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/core/llm.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/core/state.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/evaluate/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/evaluate/api_evaluator.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/memory/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/memory/compressor.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/memory/full.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/memory/hot.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/memory/manager.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/memory/warm.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/mode/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/mode/create.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/mode/optimize.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/models/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/models/config_models.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/rl/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/rl/baseline_tests.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/rl/checkpoint.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/rl/convergence.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/rl/diagnosis.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/rl/engine.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/rl/environment.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/rl/experience.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/rl/harness_prompts.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/rl/history.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/rl/optimization_logger.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/rl/pre_validation.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/rl/reward.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/rl/strategy_bandit.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/rl/strategy_generator.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/rl/strategy_prompts.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycli/skills/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/agent/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/agent/agent_manager.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/agent/chat_events.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/agent/mcp/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/agent/mcp/models.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/agent/multi_agent_team.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/agent/sandbox/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/agent/sandbox/file_ops.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/agent/sandbox/minio_sync.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/agent/sandbox/sandbox_pool.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/agent/sandbox/sandbox_recovery.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/agent/sandbox/session.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/agent/summarization_utils.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/auth/ldap_service.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/auth/wecom_ldap_service.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/config/Config.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/config/DatabaseConfig.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/config/ElasticsearchConfig.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/config/EmbeddingConfig.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/config/LLMConfig.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/config/LangfuseConfig.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/config/MQConfig.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/config/PgConfig.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/config/RedisConfig.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/config/RerankerConfig.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/config/SentryConfig.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/config/XxlJobConfig.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/config/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/database/async_base_db_service.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/database/async_database_service.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/database/base_db_service.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/database/database_service.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/database/elasticsearch_service.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/database/pg_checkpoint_service.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/database/redis_service.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/database/token_usage_db_service.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/health/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/health/health_check.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/health/metrics.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/health/ping.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/heartbeat_process/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/heartbeat_process/heartbeat_config.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/heartbeat_process/heartbeat_process_manager.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/heartbeat_process/heartbeat_process_worker.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/llm/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/llm/embedding.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/llm/get_llm.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/llm/llm_logger.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/llm/llm_tokens.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/llm/llm_with_token_tracking.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/llm/native_with_fallback_runnable.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/llm/output_fixing_runnable.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/llm/struct_token.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/llm/sy_langfuse.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/llm/token_usage_es_service.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/llm/token_usage_mysql_service.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/llm/usage_token.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/logging/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/logging/async_sql_logger.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/logging/kafka_log.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/logging/logger_levels.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/logging/logger_wrapper.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/logging/process_logger.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/logging/sql_logger.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/middleware/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/middleware/background_execution.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/middleware/context.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/middleware/cors.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/middleware/docs.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/middleware/exception.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/middleware/middleware.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/middleware/monitor_memory.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/middleware/mq.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/middleware/sandbox.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/middleware/timeout.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/middleware/token_tracking.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/middleware/tool_result_truncation.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/middleware/traceid.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/models/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/models/base_http.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/models/log.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/models/mqlistener_config.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/models/mqmsg_model.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/models/mqsend_config.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/models/sandbox.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/models/sso_user.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/models/token_usage.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/models/token_usage_mysql.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/models/xxljob_handler_config.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/notice/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/notice/uvicorn_monitor.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/notice/wecom_message.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/rabbitmq/process_pool_consumer.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/rabbitmq/rabbitmq_client.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/rabbitmq/rabbitmq_pool.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/rabbitmq/rabbitmq_service.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/rabbitmq/rabbitmq_service_client_manager.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/rabbitmq/rabbitmq_service_connection_monitor.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/rabbitmq/rabbitmq_service_consumer_manager.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/rabbitmq/rabbitmq_service_core.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/rabbitmq/rabbitmq_service_producer_manager.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/sentry/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/sentry/sy_sentry.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/services.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/sse/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/sse/event.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/sse/sse.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/synacos/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/synacos/example.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/synacos/example2.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/synacos/feign.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/synacos/feign_client.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/synacos/nacos_client_base.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/synacos/nacos_config_manager.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/synacos/nacos_heartbeat_manager.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/synacos/nacos_service.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/synacos/nacos_service_discovery.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/synacos/nacos_service_registration.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/synacos/param.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/tests/deep_agent_server.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/tests/test_deep_agent.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/tests/test_email.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/tests/test_mq.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/tests/test_real_summarization.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/tests/test_summarization_config.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/tests/test_summarization_real.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/tools/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/tools/async_utils.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/tools/docs.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/tools/env.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/tools/merge_headers.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/tools/snowflake.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/tools/syemail.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/tools/timing.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/xxljob/__init__.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/xxljob/xxljob_service.py +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon_python_lib.egg-info/dependency_links.txt +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon_python_lib.egg-info/entry_points.txt +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon_python_lib.egg-info/requires.txt +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon_python_lib.egg-info/top_level.txt +0 -0
- {sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/tests/test_sycli.py +0 -0
{sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/agent/deep_agent.py
RENAMED
|
@@ -484,6 +484,9 @@ class DeepAgent:
|
|
|
484
484
|
SYLogger.warning(f"[DeepAgent] Token 兜底统计失败: {te}")
|
|
485
485
|
|
|
486
486
|
event = ChatEventBuilder.done()
|
|
487
|
+
if total_input_tokens > 0 or total_output_tokens > 0:
|
|
488
|
+
event.data["input_tokens"] = total_input_tokens
|
|
489
|
+
event.data["output_tokens"] = total_output_tokens
|
|
487
490
|
if on_event:
|
|
488
491
|
await on_event(event)
|
|
489
492
|
yield event
|
{sycommon_python_lib-0.2.5a1 → sycommon_python_lib-0.2.5a3}/src/sycommon/agent/mcp/tool_loader.py
RENAMED
|
@@ -72,8 +72,36 @@ def wrap_tool_with_error_handler(
|
|
|
72
72
|
return tool
|
|
73
73
|
|
|
74
74
|
|
|
75
|
+
def _make_user_id_interceptor(user_id: str):
|
|
76
|
+
"""创建 MCP 工具调用拦截器,注入 X-User-Id 和 X-OA-Session-Id header"""
|
|
77
|
+
from langchain_mcp_adapters.interceptors import MCPToolCallRequest, MCPToolCallResult
|
|
78
|
+
from typing import Callable, Awaitable
|
|
79
|
+
|
|
80
|
+
async def inject_user_id(
|
|
81
|
+
request: MCPToolCallRequest,
|
|
82
|
+
handler: Callable[[MCPToolCallRequest], Awaitable[MCPToolCallResult]],
|
|
83
|
+
) -> MCPToolCallResult:
|
|
84
|
+
headers = dict(request.headers or {})
|
|
85
|
+
headers["X-User-Id"] = user_id
|
|
86
|
+
|
|
87
|
+
# 自动获取 OA session_id 注入 header
|
|
88
|
+
try:
|
|
89
|
+
from sycommon.auth.oa_cache import oa_login_with_cache
|
|
90
|
+
success, _, session_id = await oa_login_with_cache(user_id)
|
|
91
|
+
if success and session_id:
|
|
92
|
+
headers["X-OA-Session-Id"] = session_id
|
|
93
|
+
except Exception:
|
|
94
|
+
pass
|
|
95
|
+
|
|
96
|
+
request = request.override(headers=headers)
|
|
97
|
+
return await handler(request)
|
|
98
|
+
|
|
99
|
+
return inject_user_id
|
|
100
|
+
|
|
101
|
+
|
|
75
102
|
async def load_mcp_tools(
|
|
76
103
|
configs: List[MCPServerConfig],
|
|
104
|
+
user_id: str = None,
|
|
77
105
|
on_tool_success: Optional[Callable[[str, str], Awaitable[None]]] = None,
|
|
78
106
|
on_tool_error: Optional[Callable[[str, str, str], Awaitable[None]]] = None,
|
|
79
107
|
on_batch_available: Optional[Callable[[str, list], Awaitable[None]]] = None,
|
|
@@ -85,6 +113,7 @@ async def load_mcp_tools(
|
|
|
85
113
|
|
|
86
114
|
Args:
|
|
87
115
|
configs: MCP 服务器配置列表(仅 enabled 的会被处理)
|
|
116
|
+
user_id: 当前用户 ID,通过 interceptor 注入到每次 MCP 工具调用的 header 中
|
|
88
117
|
on_tool_success: 单个工具调用成功回调
|
|
89
118
|
on_tool_error: 单个工具调用失败回调
|
|
90
119
|
on_batch_available: 服务器连接成功后批量标记工具可用回调 (config_id, tool_names)
|
|
@@ -94,10 +123,16 @@ async def load_mcp_tools(
|
|
|
94
123
|
if not enabled_configs:
|
|
95
124
|
return []
|
|
96
125
|
|
|
126
|
+
# 构建 interceptor 链
|
|
127
|
+
interceptors = []
|
|
128
|
+
if user_id:
|
|
129
|
+
interceptors.append(_make_user_id_interceptor(user_id))
|
|
130
|
+
|
|
97
131
|
all_tools = []
|
|
98
132
|
for config in enabled_configs:
|
|
99
133
|
try:
|
|
100
134
|
from langchain_mcp_adapters.client import MultiServerMCPClient
|
|
135
|
+
from langchain_mcp_adapters.tools import load_mcp_tools as _load_tools
|
|
101
136
|
|
|
102
137
|
key = sanitize_name(config.name)
|
|
103
138
|
client_config = {
|
|
@@ -109,22 +144,37 @@ async def load_mcp_tools(
|
|
|
109
144
|
}
|
|
110
145
|
|
|
111
146
|
client = MultiServerMCPClient(client_config)
|
|
112
|
-
|
|
147
|
+
session = await client.session_for(key)
|
|
148
|
+
await session.initialize()
|
|
149
|
+
|
|
150
|
+
from langchain_mcp_adapters.tools import _list_all_tools
|
|
151
|
+
raw_tools = await _list_all_tools(session)
|
|
113
152
|
|
|
114
153
|
original_names = []
|
|
115
|
-
for tool in
|
|
154
|
+
for tool in raw_tools:
|
|
116
155
|
original_name = tool.name
|
|
117
156
|
original_names.append(original_name)
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
157
|
+
|
|
158
|
+
# 使用 convert_mcp_tool_to_langchain_tool 带 interceptors
|
|
159
|
+
from langchain_mcp_adapters.tools import convert_mcp_tool_to_langchain_tool
|
|
160
|
+
lc_tool = convert_mcp_tool_to_langchain_tool(
|
|
161
|
+
session,
|
|
162
|
+
tool,
|
|
163
|
+
connection=client_config[key],
|
|
164
|
+
tool_interceptors=interceptors if interceptors else None,
|
|
165
|
+
server_name=config.name,
|
|
166
|
+
tool_name_prefix=False,
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
lc_tool.name = f"mcp__{key}__{original_name}"
|
|
170
|
+
if lc_tool.description and not lc_tool.description.startswith("[MCP"):
|
|
171
|
+
lc_tool.description = f"[MCP:{config.name}] {lc_tool.description}"
|
|
121
172
|
wrap_tool_with_error_handler(
|
|
122
|
-
|
|
173
|
+
lc_tool, config.id, config.name, original_name,
|
|
123
174
|
on_tool_success=on_tool_success,
|
|
124
175
|
on_tool_error=on_tool_error,
|
|
125
176
|
)
|
|
126
|
-
|
|
127
|
-
all_tools.extend(tools)
|
|
177
|
+
all_tools.append(lc_tool)
|
|
128
178
|
|
|
129
179
|
if on_batch_available:
|
|
130
180
|
try:
|
|
@@ -132,7 +182,7 @@ async def load_mcp_tools(
|
|
|
132
182
|
except Exception as e:
|
|
133
183
|
SYLogger.warning(f"[MCP] 写入工具状态失败: {e}")
|
|
134
184
|
|
|
135
|
-
SYLogger.info(f"[MCP] 服务器 '{config.name}' 加载了 {len(
|
|
185
|
+
SYLogger.info(f"[MCP] 服务器 '{config.name}' 加载了 {len(raw_tools)} 个工具")
|
|
136
186
|
|
|
137
187
|
except Exception as e:
|
|
138
188
|
SYLogger.warning(f"[MCP] 服务器 '{config.name}' ({config.server_url}) 连接失败,跳过: {e}")
|
|
@@ -110,6 +110,10 @@ class HTTPSandboxBackend(FileOperationsMixin, SandboxBackendProtocol):
|
|
|
110
110
|
self._auto_sync = auto_sync
|
|
111
111
|
self._synced = False
|
|
112
112
|
self._workspace_verified = False
|
|
113
|
+
self._local_mode: Optional[bool] = None
|
|
114
|
+
|
|
115
|
+
# Token authentication
|
|
116
|
+
self._token = os.environ.get("SANDBOX_TOKEN", "")
|
|
113
117
|
|
|
114
118
|
# Nacos 配置(用于故障转移)
|
|
115
119
|
self._nacos_service_name = nacos_service_name
|
|
@@ -309,6 +313,16 @@ class HTTPSandboxBackend(FileOperationsMixin, SandboxBackendProtocol):
|
|
|
309
313
|
finally:
|
|
310
314
|
self._in_failover = False
|
|
311
315
|
|
|
316
|
+
def _build_headers(self) -> dict:
|
|
317
|
+
"""Build common headers for all requests (trace ID + token auth)."""
|
|
318
|
+
headers = {}
|
|
319
|
+
trace_id = SYLogger.get_trace_id()
|
|
320
|
+
if trace_id:
|
|
321
|
+
headers["x-traceid-header"] = str(trace_id)
|
|
322
|
+
if self._token:
|
|
323
|
+
headers["X-Sandbox-Token"] = self._token
|
|
324
|
+
return headers
|
|
325
|
+
|
|
312
326
|
def _post_sync_with_failover(self, endpoint: str, data: dict, timeout: int = None) -> dict:
|
|
313
327
|
"""带故障转移的同步 POST 请求"""
|
|
314
328
|
actual_timeout = timeout if timeout is not None else self._timeout
|
|
@@ -320,10 +334,7 @@ class HTTPSandboxBackend(FileOperationsMixin, SandboxBackendProtocol):
|
|
|
320
334
|
http_timeout = actual_timeout + 30
|
|
321
335
|
max_retries = 3
|
|
322
336
|
|
|
323
|
-
|
|
324
|
-
headers = {}
|
|
325
|
-
if trace_id:
|
|
326
|
-
headers["x-traceid-header"] = str(trace_id)
|
|
337
|
+
headers = self._build_headers()
|
|
327
338
|
|
|
328
339
|
url = f"{self._base_url}{endpoint}"
|
|
329
340
|
SYLogger.info(f"[Sandbox] POST 请求开始: {url}, timeout={http_timeout}s, command_timeout={actual_timeout}s")
|
|
@@ -376,6 +387,8 @@ class HTTPSandboxBackend(FileOperationsMixin, SandboxBackendProtocol):
|
|
|
376
387
|
headers = {"Content-Type": "application/json"}
|
|
377
388
|
if trace_id:
|
|
378
389
|
headers["x-traceid-header"] = str(trace_id)
|
|
390
|
+
if self._token:
|
|
391
|
+
headers["X-Sandbox-Token"] = self._token
|
|
379
392
|
|
|
380
393
|
url = f"{self._base_url}{endpoint}"
|
|
381
394
|
SYLogger.info(f"[Sandbox] Async POST 请求开始: {url}, timeout={http_timeout}s")
|
|
@@ -1275,10 +1288,7 @@ class HTTPSandboxBackend(FileOperationsMixin, SandboxBackendProtocol):
|
|
|
1275
1288
|
|
|
1276
1289
|
def health_check(self, timeout: int = 10) -> dict:
|
|
1277
1290
|
"""健康检查(快速检查,默认10秒超时)"""
|
|
1278
|
-
|
|
1279
|
-
headers = {}
|
|
1280
|
-
if trace_id:
|
|
1281
|
-
headers["x-traceid-header"] = str(trace_id)
|
|
1291
|
+
headers = self._build_headers()
|
|
1282
1292
|
|
|
1283
1293
|
url = f"{self._base_url}{SANDBOX_API_PREFIX}/health"
|
|
1284
1294
|
SYLogger.info(f"[Sandbox] 健康检查: {url}, timeout={timeout}s")
|
|
@@ -1299,11 +1309,12 @@ class HTTPSandboxBackend(FileOperationsMixin, SandboxBackendProtocol):
|
|
|
1299
1309
|
async def ahealth_check(self, timeout: int = 10) -> dict:
|
|
1300
1310
|
"""异步健康检查"""
|
|
1301
1311
|
try:
|
|
1312
|
+
headers = self._build_headers()
|
|
1302
1313
|
url = f"{self._base_url}{SANDBOX_API_PREFIX}/health"
|
|
1303
1314
|
timeout_obj = aiohttp.ClientTimeout(total=timeout)
|
|
1304
1315
|
connector = aiohttp.TCPConnector(ssl=_SSL_CONTEXT)
|
|
1305
1316
|
async with aiohttp.ClientSession(connector=connector) as session:
|
|
1306
|
-
async with session.get(url, timeout=timeout_obj) as resp:
|
|
1317
|
+
async with session.get(url, headers=headers, timeout=timeout_obj) as resp:
|
|
1307
1318
|
resp.raise_for_status()
|
|
1308
1319
|
result = await resp.json()
|
|
1309
1320
|
SYLogger.info(f"[Sandbox] 异步健康检查成功: {result}")
|
|
@@ -1320,3 +1331,25 @@ class HTTPSandboxBackend(FileOperationsMixin, SandboxBackendProtocol):
|
|
|
1320
1331
|
except Exception as e:
|
|
1321
1332
|
SYLogger.warning(f"[Sandbox] 沙箱不可用: {e}")
|
|
1322
1333
|
return False
|
|
1334
|
+
|
|
1335
|
+
def is_local_mode(self) -> bool:
|
|
1336
|
+
"""检查沙箱是否运行在 LocalMode(本地直接访问文件系统,跳过上传/同步)"""
|
|
1337
|
+
if self._local_mode is not None:
|
|
1338
|
+
return self._local_mode
|
|
1339
|
+
try:
|
|
1340
|
+
result = self.health_check(timeout=5)
|
|
1341
|
+
self._local_mode = result.get("mode") == "local"
|
|
1342
|
+
except Exception:
|
|
1343
|
+
self._local_mode = False
|
|
1344
|
+
return self._local_mode
|
|
1345
|
+
|
|
1346
|
+
async def ais_local_mode(self) -> bool:
|
|
1347
|
+
"""异步检查沙箱是否运行在 LocalMode"""
|
|
1348
|
+
if self._local_mode is not None:
|
|
1349
|
+
return self._local_mode
|
|
1350
|
+
try:
|
|
1351
|
+
result = await self.ahealth_check(timeout=5)
|
|
1352
|
+
self._local_mode = result.get("mode") == "local"
|
|
1353
|
+
except Exception:
|
|
1354
|
+
self._local_mode = False
|
|
1355
|
+
return self._local_mode
|
|
@@ -34,6 +34,20 @@ from sycommon.auth.wecom_ldap_service import (
|
|
|
34
34
|
LDAPFullUser,
|
|
35
35
|
)
|
|
36
36
|
|
|
37
|
+
from sycommon.auth.oa_service import (
|
|
38
|
+
OAConfig,
|
|
39
|
+
OAAuthService,
|
|
40
|
+
OAUser,
|
|
41
|
+
OAAuthResult,
|
|
42
|
+
)
|
|
43
|
+
from sycommon.auth.oa_cache import (
|
|
44
|
+
set_oa_credential,
|
|
45
|
+
get_oa_credential,
|
|
46
|
+
delete_oa_credential,
|
|
47
|
+
has_oa_credential,
|
|
48
|
+
oa_login_with_cache,
|
|
49
|
+
)
|
|
50
|
+
|
|
37
51
|
__all__ = [
|
|
38
52
|
"LDAPConfig",
|
|
39
53
|
"LDAPAuthService",
|
|
@@ -43,4 +57,13 @@ __all__ = [
|
|
|
43
57
|
"WeComLDAPService",
|
|
44
58
|
"WeComLDAPUser",
|
|
45
59
|
"LDAPFullUser",
|
|
60
|
+
"OAConfig",
|
|
61
|
+
"OAAuthService",
|
|
62
|
+
"OAUser",
|
|
63
|
+
"OAAuthResult",
|
|
64
|
+
"set_oa_credential",
|
|
65
|
+
"get_oa_credential",
|
|
66
|
+
"delete_oa_credential",
|
|
67
|
+
"has_oa_credential",
|
|
68
|
+
"oa_login_with_cache",
|
|
46
69
|
]
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""OA 凭据 Redis 缓存服务
|
|
2
|
+
|
|
3
|
+
加密存储用户 LDAP 凭据到 Redis,供 OA 登录使用。
|
|
4
|
+
每次写入覆盖旧值。
|
|
5
|
+
OA session_id 也缓存到 Redis,避免重复登录。
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Optional
|
|
9
|
+
|
|
10
|
+
from sycommon.auth.oa_crypto import encrypt_credential, decrypt_credential
|
|
11
|
+
from sycommon.logging.kafka_log import SYLogger
|
|
12
|
+
|
|
13
|
+
_CRED_PREFIX = "digital_work:oa_credential"
|
|
14
|
+
_SESSION_PREFIX = "digital_work:oa_session"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _cred_key(user_id: str) -> str:
|
|
18
|
+
return f"{_CRED_PREFIX}:{user_id}"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _session_key(user_id: str) -> str:
|
|
22
|
+
return f"{_SESSION_PREFIX}:{user_id}"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
async def set_oa_credential(user_id: str, login_id: str, password: str) -> None:
|
|
26
|
+
"""加密存储 LDAP 凭据到 Redis(覆盖)"""
|
|
27
|
+
from sycommon.database.redis_service import RedisService
|
|
28
|
+
encrypted = encrypt_credential({"login_id": login_id, "password": password})
|
|
29
|
+
await RedisService.set(_cred_key(user_id), encrypted)
|
|
30
|
+
SYLogger.info(f"[OA] 已缓存用户 {user_id} 的 LDAP 凭据")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
async def get_oa_credential(user_id: str) -> Optional[dict]:
|
|
34
|
+
"""从 Redis 读取并解密 LDAP 凭据"""
|
|
35
|
+
from sycommon.database.redis_service import RedisService
|
|
36
|
+
raw = await RedisService.get(_cred_key(user_id))
|
|
37
|
+
if not raw:
|
|
38
|
+
return None
|
|
39
|
+
return decrypt_credential(raw)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
async def delete_oa_credential(user_id: str) -> None:
|
|
43
|
+
"""删除 Redis 中的 LDAP 凭据和 session"""
|
|
44
|
+
from sycommon.database.redis_service import RedisService
|
|
45
|
+
await RedisService.delete(_cred_key(user_id))
|
|
46
|
+
await RedisService.delete(_session_key(user_id))
|
|
47
|
+
SYLogger.info(f"[OA] 已删除用户 {user_id} 的 LDAP 凭据")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
async def has_oa_credential(user_id: str) -> bool:
|
|
51
|
+
"""检查用户是否已有缓存的 LDAP 凭据"""
|
|
52
|
+
from sycommon.database.redis_service import RedisService
|
|
53
|
+
raw = await RedisService.get(_cred_key(user_id))
|
|
54
|
+
return raw is not None
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
async def set_oa_session(user_id: str, session_id: str) -> None:
|
|
58
|
+
"""缓存 OA session_id 到 Redis(30 分钟过期,与 OA 服务端保持一致)"""
|
|
59
|
+
from sycommon.database.redis_service import RedisService
|
|
60
|
+
await RedisService.set(_session_key(user_id), session_id, ex=1800)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
async def get_cached_oa_session(user_id: str) -> Optional[str]:
|
|
64
|
+
"""获取缓存的 OA session_id(可能已过期)"""
|
|
65
|
+
from sycommon.database.redis_service import RedisService
|
|
66
|
+
return await RedisService.get(_session_key(user_id))
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
async def oa_login_with_cache(user_id: str) -> tuple[bool, str, Optional[str]]:
|
|
70
|
+
"""从 Redis 获取 OA session,过期则重新登录。
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
(success, message, session_id)
|
|
74
|
+
"""
|
|
75
|
+
# 优先使用缓存的 session
|
|
76
|
+
cached_session = await get_cached_oa_session(user_id)
|
|
77
|
+
if cached_session:
|
|
78
|
+
return True, "OA session有效", cached_session
|
|
79
|
+
|
|
80
|
+
# 缓存过期,重新登录
|
|
81
|
+
cred = await get_oa_credential(user_id)
|
|
82
|
+
if not cred:
|
|
83
|
+
return False, "NEED_OA_AUTH", None
|
|
84
|
+
|
|
85
|
+
from sycommon.auth.oa_service import OAConfig, OAAuthService
|
|
86
|
+
config = OAConfig(login_id=cred["login_id"], password=cred["password"])
|
|
87
|
+
result = await OAAuthService(config).login()
|
|
88
|
+
|
|
89
|
+
if result.success:
|
|
90
|
+
await set_oa_session(user_id, result.user.session_id)
|
|
91
|
+
SYLogger.info(f"[OA] 用户 {user_id} 登录成功")
|
|
92
|
+
return True, "OA登录成功", result.user.session_id
|
|
93
|
+
else:
|
|
94
|
+
SYLogger.warning(f"[OA] 用户 {user_id} 登录失败: {result.error}")
|
|
95
|
+
return False, f"OA登录失败: {result.error}", None
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""OA 凭据加密工具
|
|
2
|
+
|
|
3
|
+
使用 AES-256-GCM 加密 LDAP 凭据,密钥从 Nacos 配置或环境变量读取。
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import base64
|
|
7
|
+
import json
|
|
8
|
+
import os
|
|
9
|
+
from typing import Optional
|
|
10
|
+
|
|
11
|
+
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
|
|
12
|
+
|
|
13
|
+
from sycommon.logging.kafka_log import SYLogger
|
|
14
|
+
|
|
15
|
+
NONCE_SIZE = 12
|
|
16
|
+
_ENV_KEY = "OA_CREDENTIAL_ENCRYPT_KEY"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _get_key() -> bytes:
|
|
20
|
+
"""获取加密密钥(优先环境变量,其次 Nacos 配置)"""
|
|
21
|
+
b64 = os.environ.get(_ENV_KEY)
|
|
22
|
+
if not b64:
|
|
23
|
+
try:
|
|
24
|
+
from sycommon.config.Config import Config
|
|
25
|
+
b64 = Config().config.get("llm", {}).get("OA", {}).get("credential_encrypt_key", "")
|
|
26
|
+
except Exception:
|
|
27
|
+
pass
|
|
28
|
+
if not b64:
|
|
29
|
+
raise ValueError(
|
|
30
|
+
f"未配置 OA 凭据加密密钥,请设置环境变量 {_ENV_KEY} 或 Nacos 配置 OA.credential_encrypt_key"
|
|
31
|
+
)
|
|
32
|
+
key = base64.b64decode(b64)
|
|
33
|
+
if len(key) != 32:
|
|
34
|
+
raise ValueError("加密密钥长度必须为 32 字节 (AES-256)")
|
|
35
|
+
return key
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def encrypt_credential(data: dict) -> str:
|
|
39
|
+
"""加密凭据字典,返回 base64 编码的密文"""
|
|
40
|
+
key = _get_key()
|
|
41
|
+
plaintext = json.dumps(data, ensure_ascii=False).encode("utf-8")
|
|
42
|
+
aesgcm = AESGCM(key)
|
|
43
|
+
nonce = os.urandom(NONCE_SIZE)
|
|
44
|
+
ciphertext = aesgcm.encrypt(nonce, plaintext, None)
|
|
45
|
+
return base64.b64encode(nonce + ciphertext).decode("ascii")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def decrypt_credential(raw: str) -> Optional[dict]:
|
|
49
|
+
"""解密 base64 编码的密文,返回凭据字典"""
|
|
50
|
+
try:
|
|
51
|
+
key = _get_key()
|
|
52
|
+
blob = base64.b64decode(raw)
|
|
53
|
+
nonce = blob[:NONCE_SIZE]
|
|
54
|
+
ciphertext = blob[NONCE_SIZE:]
|
|
55
|
+
aesgcm = AESGCM(key)
|
|
56
|
+
plaintext = aesgcm.decrypt(nonce, ciphertext, None)
|
|
57
|
+
return json.loads(plaintext)
|
|
58
|
+
except Exception as e:
|
|
59
|
+
SYLogger.error(f"[OA] 凭据解密失败: {e}")
|
|
60
|
+
return None
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"""
|
|
2
|
+
OA 登录服务
|
|
3
|
+
|
|
4
|
+
提供基于 SOAP 协议的 OA 系统登录认证功能。
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import asyncio
|
|
8
|
+
from typing import Optional
|
|
9
|
+
from pydantic import BaseModel
|
|
10
|
+
|
|
11
|
+
from sycommon.logging.kafka_log import SYLogger
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class OAConfig(BaseModel):
|
|
15
|
+
"""OA 配置"""
|
|
16
|
+
|
|
17
|
+
base_url: str = "https://oa.syholdings.com"
|
|
18
|
+
doc_service: Optional[str] = None
|
|
19
|
+
login_id: str = ""
|
|
20
|
+
password: str = ""
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def doc_service_url(self) -> str:
|
|
24
|
+
if self.doc_service:
|
|
25
|
+
return self.doc_service
|
|
26
|
+
return f"{self.base_url}/services/DocService"
|
|
27
|
+
|
|
28
|
+
@classmethod
|
|
29
|
+
def from_config(cls) -> "OAConfig":
|
|
30
|
+
from sycommon.config.Config import Config
|
|
31
|
+
|
|
32
|
+
oa_config = Config().config.get("OA", {})
|
|
33
|
+
return cls(
|
|
34
|
+
base_url=oa_config.get("base_url", "https://oa.syholdings.com"),
|
|
35
|
+
doc_service=oa_config.get("doc_service"),
|
|
36
|
+
login_id=oa_config.get("login_id", ""),
|
|
37
|
+
password=oa_config.get("password", ""),
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class OAUser(BaseModel):
|
|
42
|
+
"""OA 用户信息"""
|
|
43
|
+
|
|
44
|
+
session_id: Optional[str] = None
|
|
45
|
+
login_id: str
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class OAAuthResult(BaseModel):
|
|
49
|
+
"""OA 登录结果"""
|
|
50
|
+
|
|
51
|
+
success: bool
|
|
52
|
+
user: Optional[OAUser] = None
|
|
53
|
+
error: Optional[str] = None
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class OAAuthService:
|
|
57
|
+
"""OA 认证服务
|
|
58
|
+
|
|
59
|
+
使用示例::
|
|
60
|
+
|
|
61
|
+
config = OAConfig(
|
|
62
|
+
base_url="https://oa.syholdings.com",
|
|
63
|
+
login_id="username",
|
|
64
|
+
password="password",
|
|
65
|
+
)
|
|
66
|
+
service = OAAuthService(config)
|
|
67
|
+
result = await service.login()
|
|
68
|
+
if result.success:
|
|
69
|
+
print(f"登录成功, session: {result.user.session_id}")
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
def __init__(self, config: OAConfig):
|
|
73
|
+
self.config = config
|
|
74
|
+
|
|
75
|
+
def _build_login_xml(self, login_id: Optional[str] = None,
|
|
76
|
+
password: Optional[str] = None) -> str:
|
|
77
|
+
"""构建登录 SOAP 请求体"""
|
|
78
|
+
lid = login_id or self.config.login_id
|
|
79
|
+
pwd = password or self.config.password
|
|
80
|
+
return f"""<?xml version="1.0" encoding="UTF-8"?>
|
|
81
|
+
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
|
|
82
|
+
xmlns:doc="http://localhost/services/DocService">
|
|
83
|
+
<soapenv:Body>
|
|
84
|
+
<doc:login>
|
|
85
|
+
<doc:in0>{lid}</doc:in0>
|
|
86
|
+
<doc:in1>{pwd}</doc:in1>
|
|
87
|
+
<doc:in2>2</doc:in2>
|
|
88
|
+
<doc:in3>127.0.0.1</doc:in3>
|
|
89
|
+
</doc:login>
|
|
90
|
+
</soapenv:Body>
|
|
91
|
+
</soapenv:Envelope>"""
|
|
92
|
+
|
|
93
|
+
def _parse_login_response(self, response_text: str) -> OAAuthResult:
|
|
94
|
+
"""解析登录响应"""
|
|
95
|
+
import xml.etree.ElementTree as ET
|
|
96
|
+
|
|
97
|
+
try:
|
|
98
|
+
root = ET.fromstring(response_text)
|
|
99
|
+
except ET.ParseError as e:
|
|
100
|
+
SYLogger.error(f"[OA] 响应 XML 解析失败: {e}")
|
|
101
|
+
return OAAuthResult(success=False, error=f"XML 解析失败: {e}")
|
|
102
|
+
|
|
103
|
+
# SOAP 命名空间
|
|
104
|
+
ns = {
|
|
105
|
+
"soapenv": "http://schemas.xmlsoap.org/soap/envelope/",
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
body = root.find("soapenv:Body", ns)
|
|
109
|
+
if body is None:
|
|
110
|
+
return OAAuthResult(success=False, error="响应缺少 Body")
|
|
111
|
+
|
|
112
|
+
# 查找登录返回值(可能是 loginReturn 或 out)
|
|
113
|
+
login_return = None
|
|
114
|
+
for child in body:
|
|
115
|
+
for sub in child:
|
|
116
|
+
if sub.tag.endswith("loginReturn") or sub.tag.endswith("out"):
|
|
117
|
+
login_return = sub
|
|
118
|
+
break
|
|
119
|
+
|
|
120
|
+
if login_return is None:
|
|
121
|
+
return OAAuthResult(success=False, error="响应缺少 loginReturn")
|
|
122
|
+
|
|
123
|
+
session_id = login_return.text
|
|
124
|
+
|
|
125
|
+
if not session_id:
|
|
126
|
+
return OAAuthResult(success=False, error="登录返回空 session")
|
|
127
|
+
|
|
128
|
+
SYLogger.info(f"[OA] 用户 {self.config.login_id} 登录成功")
|
|
129
|
+
return OAAuthResult(
|
|
130
|
+
success=True,
|
|
131
|
+
user=OAUser(session_id=session_id, login_id=self.config.login_id),
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
async def login(self, login_id: Optional[str] = None,
|
|
135
|
+
password: Optional[str] = None) -> OAAuthResult:
|
|
136
|
+
"""执行 OA 登录
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
login_id: 登录账号(可选,默认使用配置中的账号)
|
|
140
|
+
password: 登录密码(可选,默认使用配置中的密码)
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
OAAuthResult: 登录结果
|
|
144
|
+
"""
|
|
145
|
+
try:
|
|
146
|
+
result = await asyncio.get_event_loop().run_in_executor(
|
|
147
|
+
None,
|
|
148
|
+
self._login_sync,
|
|
149
|
+
login_id,
|
|
150
|
+
password,
|
|
151
|
+
)
|
|
152
|
+
return result
|
|
153
|
+
except Exception as e:
|
|
154
|
+
SYLogger.error(f"[OA] 登录异常: {e}")
|
|
155
|
+
return OAAuthResult(success=False, error=str(e))
|
|
156
|
+
|
|
157
|
+
def _login_sync(self, login_id: Optional[str],
|
|
158
|
+
password: Optional[str]) -> OAAuthResult:
|
|
159
|
+
"""同步执行 OA 登录"""
|
|
160
|
+
import urllib.request
|
|
161
|
+
import urllib.error
|
|
162
|
+
|
|
163
|
+
soap_xml = self._build_login_xml(login_id, password)
|
|
164
|
+
|
|
165
|
+
headers = {
|
|
166
|
+
"Content-Type": "text/xml; charset=UTF-8",
|
|
167
|
+
"SOAPAction": "",
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
req = urllib.request.Request(
|
|
171
|
+
self.config.doc_service_url,
|
|
172
|
+
data=soap_xml.encode("utf-8"),
|
|
173
|
+
headers=headers,
|
|
174
|
+
method="POST",
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
try:
|
|
178
|
+
# 禁用 SSL 验证(OA 可能使用自签名证书)
|
|
179
|
+
import ssl
|
|
180
|
+
ctx = ssl.create_default_context()
|
|
181
|
+
ctx.check_hostname = False
|
|
182
|
+
ctx.verify_mode = ssl.CERT_NONE
|
|
183
|
+
|
|
184
|
+
with urllib.request.urlopen(req, context=ctx, timeout=15) as resp:
|
|
185
|
+
response_text = resp.read().decode("utf-8")
|
|
186
|
+
|
|
187
|
+
return self._parse_login_response(response_text)
|
|
188
|
+
|
|
189
|
+
except urllib.error.HTTPError as e:
|
|
190
|
+
body = e.read().decode("utf-8", errors="replace")
|
|
191
|
+
SYLogger.error(f"[OA] HTTP 错误 {e.code}: {body[:500]}")
|
|
192
|
+
return OAAuthResult(
|
|
193
|
+
success=False,
|
|
194
|
+
error=f"HTTP {e.code}: {body[:200]}",
|
|
195
|
+
)
|
|
196
|
+
except urllib.error.URLError as e:
|
|
197
|
+
SYLogger.error(f"[OA] 连接失败: {e.reason}")
|
|
198
|
+
return OAAuthResult(success=False, error=f"连接失败: {e.reason}")
|
|
199
|
+
except Exception as e:
|
|
200
|
+
SYLogger.error(f"[OA] 登录请求异常: {e}")
|
|
201
|
+
return OAAuthResult(success=False, error=str(e))
|