langchain-agentx-python 0.1__py3-none-any.whl
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.
- langchain_agentx/__init__.py +46 -0
- langchain_agentx/command/__init__.py +28 -0
- langchain_agentx/command/builtin/__init__.py +25 -0
- langchain_agentx/command/builtin/clear.py +33 -0
- langchain_agentx/command/builtin/compact.py +33 -0
- langchain_agentx/command/builtin/memory.py +37 -0
- langchain_agentx/command/builtin/reload_plugins.py +42 -0
- langchain_agentx/command/context.py +30 -0
- langchain_agentx/command/dispatcher.py +183 -0
- langchain_agentx/command/registry.py +110 -0
- langchain_agentx/command/result.py +25 -0
- langchain_agentx/command/types.py +41 -0
- langchain_agentx/config/__init__.py +14 -0
- langchain_agentx/loop/__init__.py +47 -0
- langchain_agentx/loop/config/__init__.py +20 -0
- langchain_agentx/loop/config/agent_config.py +66 -0
- langchain_agentx/loop/config/agent_loop_config.py +72 -0
- langchain_agentx/loop/config/model_context_resolver.py +105 -0
- langchain_agentx/loop/config/runtime_settings.py +50 -0
- langchain_agentx/loop/config/token_estimator.py +133 -0
- langchain_agentx/loop/context/__init__.py +66 -0
- langchain_agentx/loop/context/blocking_guard.py +97 -0
- langchain_agentx/loop/context/compaction_service.py +60 -0
- langchain_agentx/loop/context/message_utils.py +56 -0
- langchain_agentx/loop/context/pipeline.py +127 -0
- langchain_agentx/loop/context/settings.py +103 -0
- langchain_agentx/loop/context/stages/__init__.py +29 -0
- langchain_agentx/loop/context/stages/autocompact.py +140 -0
- langchain_agentx/loop/context/stages/base.py +32 -0
- langchain_agentx/loop/context/stages/collapse.py +76 -0
- langchain_agentx/loop/context/stages/microcompact.py +76 -0
- langchain_agentx/loop/context/stages/noop.py +33 -0
- langchain_agentx/loop/context/stages/snip.py +71 -0
- langchain_agentx/loop/context/stages/tool_result_budget.py +69 -0
- langchain_agentx/loop/context/types.py +79 -0
- langchain_agentx/loop/exit/__init__.py +1 -0
- langchain_agentx/loop/exit/exit_logic.py +320 -0
- langchain_agentx/loop/exit/reason_codes.py +39 -0
- langchain_agentx/loop/graph/__init__.py +5 -0
- langchain_agentx/loop/graph/builtin_loop_control.py +197 -0
- langchain_agentx/loop/graph/factory.py +1409 -0
- langchain_agentx/loop/graph/graph_edges.py +820 -0
- langchain_agentx/loop/hook/__init__.py +48 -0
- langchain_agentx/loop/hook/async_hook_runner.py +62 -0
- langchain_agentx/loop/hook/config.py +280 -0
- langchain_agentx/loop/hook/engine.py +321 -0
- langchain_agentx/loop/hook/executors/__init__.py +9 -0
- langchain_agentx/loop/hook/executors/agent.py +107 -0
- langchain_agentx/loop/hook/executors/command.py +230 -0
- langchain_agentx/loop/hook/executors/http.py +114 -0
- langchain_agentx/loop/hook/executors/prompt.py +92 -0
- langchain_agentx/loop/hook/graph_wiring.py +134 -0
- langchain_agentx/loop/hook/registry.py +262 -0
- langchain_agentx/loop/hook/trust.py +43 -0
- langchain_agentx/loop/hook/types.py +110 -0
- langchain_agentx/loop/injection/__init__.py +13 -0
- langchain_agentx/loop/injection/dedup.py +74 -0
- langchain_agentx/loop/loop_abort.py +36 -0
- langchain_agentx/loop/model/__init__.py +1 -0
- langchain_agentx/loop/model/model_node.py +648 -0
- langchain_agentx/loop/model/model_nodes.py +661 -0
- langchain_agentx/loop/model/orphan_tool_results.py +38 -0
- langchain_agentx/loop/model/retrier.py +307 -0
- langchain_agentx/loop/model/retry_bridge.py +58 -0
- langchain_agentx/loop/model/retry_events.py +35 -0
- langchain_agentx/loop/model/retry_policy.py +56 -0
- langchain_agentx/loop/model/schema_and_format.py +153 -0
- langchain_agentx/loop/model/tool_and_model_binding.py +227 -0
- langchain_agentx/loop/model/tool_call_degradation_corrector.py +443 -0
- langchain_agentx/loop/model/tool_transcript_guard.py +225 -0
- langchain_agentx/loop/prompt/__init__.py +95 -0
- langchain_agentx/loop/prompt/builder.py +61 -0
- langchain_agentx/loop/prompt/builtin.py +218 -0
- langchain_agentx/loop/prompt/compact.py +408 -0
- langchain_agentx/loop/prompt/sections.py +120 -0
- langchain_agentx/loop/runtime/__init__.py +19 -0
- langchain_agentx/loop/runtime/context.py +34 -0
- langchain_agentx/loop/runtime/context_factory.py +107 -0
- langchain_agentx/loop/runtime/subagent_execution_paths.py +68 -0
- langchain_agentx/loop/subagent/__init__.py +53 -0
- langchain_agentx/loop/subagent/async_runner.py +215 -0
- langchain_agentx/loop/subagent/context.py +209 -0
- langchain_agentx/loop/subagent/fork_worktree_notice.py +25 -0
- langchain_agentx/loop/subagent/graph.py +72 -0
- langchain_agentx/loop/subagent/orchestrator.py +391 -0
- langchain_agentx/loop/subagent/progress.py +30 -0
- langchain_agentx/loop/subagent/prompt.py +52 -0
- langchain_agentx/loop/subagent/runner.py +504 -0
- langchain_agentx/loop/subagent/transcript.py +172 -0
- langchain_agentx/memory/__init__.py +2 -0
- langchain_agentx/memory/instruction/__init__.py +12 -0
- langchain_agentx/memory/instruction/loader.py +325 -0
- langchain_agentx/memory/instruction/resolver.py +24 -0
- langchain_agentx/memory/instruction/runtime.py +83 -0
- langchain_agentx/memory/instruction/sections.py +83 -0
- langchain_agentx/memory/instruction/types.py +59 -0
- langchain_agentx/memory/memdir/__init__.py +77 -0
- langchain_agentx/memory/memdir/age.py +36 -0
- langchain_agentx/memory/memdir/agent_memory.py +380 -0
- langchain_agentx/memory/memdir/extractor.py +309 -0
- langchain_agentx/memory/memdir/loader.py +187 -0
- langchain_agentx/memory/memdir/paths.py +63 -0
- langchain_agentx/memory/memdir/recall.py +45 -0
- langchain_agentx/memory/memdir/runtime.py +43 -0
- langchain_agentx/memory/memdir/scan.py +135 -0
- langchain_agentx/memory/memdir/types.py +104 -0
- langchain_agentx/memory/session/__init__.py +76 -0
- langchain_agentx/memory/session/compact_bridge.py +208 -0
- langchain_agentx/memory/session/prompts.py +172 -0
- langchain_agentx/memory/session/session_memory.py +282 -0
- langchain_agentx/observability/__init__.py +67 -0
- langchain_agentx/observability/evaluation/__init__.py +17 -0
- langchain_agentx/observability/evaluation/checkers/__init__.py +18 -0
- langchain_agentx/observability/evaluation/checkers/base.py +34 -0
- langchain_agentx/observability/evaluation/checkers/compaction.py +38 -0
- langchain_agentx/observability/evaluation/checkers/degradation.py +50 -0
- langchain_agentx/observability/evaluation/checkers/exit_quality.py +42 -0
- langchain_agentx/observability/evaluation/checkers/session_memory.py +45 -0
- langchain_agentx/observability/evaluation/checkers/tool_behavior.py +53 -0
- langchain_agentx/observability/evaluation/retention_scheduler.py +67 -0
- langchain_agentx/observability/evaluation/service.py +102 -0
- langchain_agentx/observability/evaluation/state.py +32 -0
- langchain_agentx/observability/evaluation/store.py +258 -0
- langchain_agentx/observability/events/__init__.py +15 -0
- langchain_agentx/observability/events/langchain_agentx_event_adapter.py +832 -0
- langchain_agentx/observability/logging/__init__.py +15 -0
- langchain_agentx/observability/logging/debug_burst.py +95 -0
- langchain_agentx/observability/logging/logging_config.py +178 -0
- langchain_agentx/observability/logging/logging_contract.py +65 -0
- langchain_agentx/observability/replay/__init__.py +35 -0
- langchain_agentx/observability/replay/cli.py +91 -0
- langchain_agentx/observability/replay/service.py +83 -0
- langchain_agentx/observability/replay/store.py +278 -0
- langchain_agentx/observability/replay/ui.py +47 -0
- langchain_agentx/observability/trace/__init__.py +25 -0
- langchain_agentx/observability/trace/collector.py +560 -0
- langchain_agentx/observability/trace/event_emitter.py +183 -0
- langchain_agentx/observability/trace/hook_event_emitter.py +49 -0
- langchain_agentx/observability/trace/models.py +144 -0
- langchain_agentx/observability/trace/sqlite_store.py +873 -0
- langchain_agentx/observability/trace/trace_callback.py +295 -0
- langchain_agentx/observability/trace/trace_lifecycle_collector.py +114 -0
- langchain_agentx/plugin/__init__.py +26 -0
- langchain_agentx/plugin/builtin.py +53 -0
- langchain_agentx/plugin/config.py +113 -0
- langchain_agentx/plugin/loader.py +386 -0
- langchain_agentx/plugin/manifest.py +154 -0
- langchain_agentx/plugin/registries.py +211 -0
- langchain_agentx/plugin/types.py +142 -0
- langchain_agentx/provider/__init__.py +27 -0
- langchain_agentx/provider/anthropic.py +121 -0
- langchain_agentx/provider/compatible_chat_openai.py +86 -0
- langchain_agentx/provider/env.py +45 -0
- langchain_agentx/provider/model_profile.py +156 -0
- langchain_agentx/provider/openai.py +89 -0
- langchain_agentx/session/__init__.py +17 -0
- langchain_agentx/session/agent_session.py +320 -0
- langchain_agentx/session/conversation_factory.py +87 -0
- langchain_agentx/session/conversation_recovery.py +156 -0
- langchain_agentx/session/conversation_session.py +198 -0
- langchain_agentx/session/factory.py +143 -0
- langchain_agentx/session/protocol.py +25 -0
- langchain_agentx/task_runtime/__init__.py +113 -0
- langchain_agentx/task_runtime/core/__init__.py +51 -0
- langchain_agentx/task_runtime/core/ids.py +33 -0
- langchain_agentx/task_runtime/core/interfaces.py +115 -0
- langchain_agentx/task_runtime/core/notification_priority.py +19 -0
- langchain_agentx/task_runtime/core/types.py +136 -0
- langchain_agentx/task_runtime/integrations/__init__.py +33 -0
- langchain_agentx/task_runtime/integrations/loop_adapter.py +91 -0
- langchain_agentx/task_runtime/integrations/loop_integration.py +61 -0
- langchain_agentx/task_runtime/integrations/prefetch_providers.py +108 -0
- langchain_agentx/task_runtime/integrations/provider_factory.py +103 -0
- langchain_agentx/task_runtime/integrations/queued_command_provider.py +184 -0
- langchain_agentx/task_runtime/integrations/sqlite_queued_command_provider.py +338 -0
- langchain_agentx/task_runtime/integrations/tool_use_summary_provider.py +254 -0
- langchain_agentx/task_runtime/orchestrator/__init__.py +5 -0
- langchain_agentx/task_runtime/orchestrator/runtime.py +386 -0
- langchain_agentx/task_runtime/output/__init__.py +5 -0
- langchain_agentx/task_runtime/output/sink.py +64 -0
- langchain_agentx/task_runtime/policy/__init__.py +11 -0
- langchain_agentx/task_runtime/policy/withhold_visibility.py +32 -0
- langchain_agentx/task_runtime/queue/__init__.py +5 -0
- langchain_agentx/task_runtime/queue/in_memory.py +55 -0
- langchain_agentx/task_runtime/skill_prefetch/__init__.py +4 -0
- langchain_agentx/task_runtime/skill_prefetch/attachments.py +46 -0
- langchain_agentx/task_runtime/skill_prefetch/models.py +37 -0
- langchain_agentx/task_runtime/skill_prefetch/provider.py +344 -0
- langchain_agentx/task_runtime/store/__init__.py +6 -0
- langchain_agentx/task_runtime/store/in_memory.py +81 -0
- langchain_agentx/task_runtime/store/sqlite_store.py +281 -0
- langchain_agentx/task_runtime/tasks/__init__.py +76 -0
- langchain_agentx/task_runtime/tasks/ai_analysis/__init__.py +15 -0
- langchain_agentx/task_runtime/tasks/ai_analysis/base.py +41 -0
- langchain_agentx/task_runtime/tasks/ai_analysis/evaluation.py +67 -0
- langchain_agentx/task_runtime/tasks/ai_analysis/registry.py +36 -0
- langchain_agentx/task_runtime/tasks/ai_analysis/scheduler.py +70 -0
- langchain_agentx/task_runtime/tasks/base/__init__.py +6 -0
- langchain_agentx/task_runtime/tasks/base/contracts.py +24 -0
- langchain_agentx/task_runtime/tasks/custom/__init__.py +7 -0
- langchain_agentx/task_runtime/tasks/custom/executor.py +60 -0
- langchain_agentx/task_runtime/tasks/custom/notification.py +7 -0
- langchain_agentx/task_runtime/tasks/custom/semantics.py +13 -0
- langchain_agentx/task_runtime/tasks/custom/spec.py +33 -0
- langchain_agentx/task_runtime/tasks/dream_task/__init__.py +15 -0
- langchain_agentx/task_runtime/tasks/dream_task/executor.py +61 -0
- langchain_agentx/task_runtime/tasks/dream_task/notification.py +19 -0
- langchain_agentx/task_runtime/tasks/dream_task/semantics.py +13 -0
- langchain_agentx/task_runtime/tasks/dream_task/spec.py +35 -0
- langchain_agentx/task_runtime/tasks/dream_task/state.py +17 -0
- langchain_agentx/task_runtime/tasks/in_process_teammate/__init__.py +12 -0
- langchain_agentx/task_runtime/tasks/in_process_teammate/executor.py +36 -0
- langchain_agentx/task_runtime/tasks/in_process_teammate/notification.py +25 -0
- langchain_agentx/task_runtime/tasks/in_process_teammate/semantics.py +13 -0
- langchain_agentx/task_runtime/tasks/in_process_teammate/spec.py +63 -0
- langchain_agentx/task_runtime/tasks/local_agent/__init__.py +14 -0
- langchain_agentx/task_runtime/tasks/local_agent/executor.py +33 -0
- langchain_agentx/task_runtime/tasks/local_agent/notification.py +21 -0
- langchain_agentx/task_runtime/tasks/local_agent/runner.py +43 -0
- langchain_agentx/task_runtime/tasks/local_agent/semantics.py +13 -0
- langchain_agentx/task_runtime/tasks/local_agent/spec.py +31 -0
- langchain_agentx/task_runtime/tasks/local_bash/__init__.py +13 -0
- langchain_agentx/task_runtime/tasks/local_bash/executor.py +95 -0
- langchain_agentx/task_runtime/tasks/local_bash/notification.py +22 -0
- langchain_agentx/task_runtime/tasks/local_bash/semantics.py +13 -0
- langchain_agentx/task_runtime/tasks/local_bash/spec.py +55 -0
- langchain_agentx/task_runtime/tasks/remote_agent/__init__.py +19 -0
- langchain_agentx/task_runtime/tasks/remote_agent/backend.py +76 -0
- langchain_agentx/task_runtime/tasks/remote_agent/executor.py +37 -0
- langchain_agentx/task_runtime/tasks/remote_agent/notification.py +22 -0
- langchain_agentx/task_runtime/tasks/remote_agent/semantics.py +13 -0
- langchain_agentx/task_runtime/tasks/remote_agent/spec.py +34 -0
- langchain_agentx/task_runtime/tasks/trace_cleanup/__init__.py +19 -0
- langchain_agentx/task_runtime/tasks/trace_cleanup/bootstrap.py +95 -0
- langchain_agentx/task_runtime/tasks/trace_cleanup/executor.py +66 -0
- langchain_agentx/task_runtime/tasks/trace_cleanup/scheduler.py +169 -0
- langchain_agentx/tool_runtime/__init__.py +90 -0
- langchain_agentx/tool_runtime/adapter.py +365 -0
- langchain_agentx/tool_runtime/base.py +319 -0
- langchain_agentx/tool_runtime/errors.py +190 -0
- langchain_agentx/tool_runtime/identical_call_cache.py +110 -0
- langchain_agentx/tool_runtime/loader.py +195 -0
- langchain_agentx/tool_runtime/models.py +260 -0
- langchain_agentx/tool_runtime/permission_context.py +78 -0
- langchain_agentx/tool_runtime/pipeline.py +621 -0
- langchain_agentx/tool_runtime/policy.py +447 -0
- langchain_agentx/tool_runtime/registry.py +81 -0
- langchain_agentx/tool_runtime/resolvers/__init__.py +27 -0
- langchain_agentx/tool_runtime/resolvers/agent_session.py +125 -0
- langchain_agentx/tool_runtime/resolvers/background.py +32 -0
- langchain_agentx/tool_runtime/resolvers/base.py +20 -0
- langchain_agentx/tool_runtime/resolvers/conversation.py +22 -0
- langchain_agentx/tool_runtime/resolvers/workflow.py +73 -0
- langchain_agentx/tool_runtime/session_store.py +132 -0
- langchain_agentx/tool_runtime/smoke_test_runtime.py +294 -0
- langchain_agentx/tool_runtime/state_bridge.py +164 -0
- langchain_agentx/tools/__init__.py +26 -0
- langchain_agentx/tools/agent/__init__.py +9 -0
- langchain_agentx/tools/agent/backend.py +53 -0
- langchain_agentx/tools/agent/built_in/__init__.py +19 -0
- langchain_agentx/tools/agent/built_in/agentx_guide.py +65 -0
- langchain_agentx/tools/agent/built_in/explore.py +80 -0
- langchain_agentx/tools/agent/built_in/general.py +57 -0
- langchain_agentx/tools/agent/built_in/plan.py +89 -0
- langchain_agentx/tools/agent/built_in/statusline_setup.py +64 -0
- langchain_agentx/tools/agent/built_in/verification.py +120 -0
- langchain_agentx/tools/agent/builtin_subagent_loader.py +89 -0
- langchain_agentx/tools/agent/cwd_resolution.py +119 -0
- langchain_agentx/tools/agent/limits.py +26 -0
- langchain_agentx/tools/agent/loader.py +270 -0
- langchain_agentx/tools/agent/models.py +85 -0
- langchain_agentx/tools/agent/prompt.py +120 -0
- langchain_agentx/tools/agent/registry/__init__.py +18 -0
- langchain_agentx/tools/agent/registry/config.py +29 -0
- langchain_agentx/tools/agent/registry/registry.py +47 -0
- langchain_agentx/tools/agent/scope.py +137 -0
- langchain_agentx/tools/agent/tool.py +256 -0
- langchain_agentx/tools/bash/__init__.py +9 -0
- langchain_agentx/tools/bash/ast_security.py +571 -0
- langchain_agentx/tools/bash/backend.py +1447 -0
- langchain_agentx/tools/bash/bash_hardening.py +734 -0
- langchain_agentx/tools/bash/bash_runtime_contract.py +41 -0
- langchain_agentx/tools/bash/cwd_reporter.py +95 -0
- langchain_agentx/tools/bash/limits.py +71 -0
- langchain_agentx/tools/bash/mode_validation.py +282 -0
- langchain_agentx/tools/bash/models.py +131 -0
- langchain_agentx/tools/bash/observability.py +148 -0
- langchain_agentx/tools/bash/output_utils.py +200 -0
- langchain_agentx/tools/bash/path_security.py +2429 -0
- langchain_agentx/tools/bash/prompt.py +68 -0
- langchain_agentx/tools/bash/read_only_validation.py +589 -0
- langchain_agentx/tools/bash/result_presenter.py +324 -0
- langchain_agentx/tools/bash/sandbox_decision.py +133 -0
- langchain_agentx/tools/bash/security.py +311 -0
- langchain_agentx/tools/bash/sed_edit_parser.py +243 -0
- langchain_agentx/tools/bash/sed_validation.py +163 -0
- langchain_agentx/tools/bash/semantics.py +111 -0
- langchain_agentx/tools/bash/session_manager.py +205 -0
- langchain_agentx/tools/bash/session_runtime.py +290 -0
- langchain_agentx/tools/bash/shell_locator.py +191 -0
- langchain_agentx/tools/bash/task_runtime.py +91 -0
- langchain_agentx/tools/bash/tool.py +939 -0
- langchain_agentx/tools/bash/windows_shell_quoting.py +45 -0
- langchain_agentx/tools/glob/__init__.py +9 -0
- langchain_agentx/tools/glob/models.py +57 -0
- langchain_agentx/tools/glob/pagination.py +30 -0
- langchain_agentx/tools/glob/prompt.py +24 -0
- langchain_agentx/tools/glob/rg_list_backend.py +139 -0
- langchain_agentx/tools/glob/rg_pattern.py +44 -0
- langchain_agentx/tools/glob/tool.py +327 -0
- langchain_agentx/tools/grep/__init__.py +7 -0
- langchain_agentx/tools/grep/backend.py +375 -0
- langchain_agentx/tools/grep/models.py +127 -0
- langchain_agentx/tools/grep/prompt.py +30 -0
- langchain_agentx/tools/grep/rg_subprocess_controller.py +114 -0
- langchain_agentx/tools/grep/tool.py +475 -0
- langchain_agentx/tools/read/__init__.py +9 -0
- langchain_agentx/tools/read/backend.py +415 -0
- langchain_agentx/tools/read/limits.py +67 -0
- langchain_agentx/tools/read/models.py +156 -0
- langchain_agentx/tools/read/prompt.py +73 -0
- langchain_agentx/tools/read/tool.py +494 -0
- langchain_agentx/tools/ripgrep_plugin_exclusions.py +137 -0
- langchain_agentx/tools/skill/__init__.py +4 -0
- langchain_agentx/tools/skill/argument_substitution.py +80 -0
- langchain_agentx/tools/skill/loader.py +196 -0
- langchain_agentx/tools/skill/models.py +88 -0
- langchain_agentx/tools/skill/policy.py +80 -0
- langchain_agentx/tools/skill/prompt.py +35 -0
- langchain_agentx/tools/skill/tool.py +222 -0
- langchain_agentx/utils/__init__.py +0 -0
- langchain_agentx/utils/cwd.py +124 -0
- langchain_agentx/utils/host_platform.py +112 -0
- langchain_agentx/utils/path_hierarchy.py +48 -0
- langchain_agentx/utils/path_user_input.py +66 -0
- langchain_agentx/utils/rg_executable.py +18 -0
- langchain_agentx/utils/subprocess_text.py +101 -0
- langchain_agentx/utils/temp_paths.py +77 -0
- langchain_agentx/utils/unc_path.py +25 -0
- langchain_agentx/utils/win_reserved_paths.py +51 -0
- langchain_agentx/workflow/__init__.py +7 -0
- langchain_agentx/workflow/base.py +97 -0
- langchain_agentx/workflow/batch.py +55 -0
- langchain_agentx/workflow/dag.py +54 -0
- langchain_agentx/workspace/__init__.py +13 -0
- langchain_agentx/workspace/config.py +140 -0
- langchain_agentx/workspace/path_key_normalizer.py +30 -0
- langchain_agentx/workspace/resolver.py +74 -0
- langchain_agentx/workspace/validators.py +41 -0
- langchain_agentx_python-0.1.dist-info/LICENSE +201 -0
- langchain_agentx_python-0.1.dist-info/METADATA +513 -0
- langchain_agentx_python-0.1.dist-info/RECORD +354 -0
- langchain_agentx_python-0.1.dist-info/WHEEL +5 -0
- langchain_agentx_python-0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""
|
|
2
|
+
tasks/local_bash/executor.py — LOCAL_BASH 执行器
|
|
3
|
+
|
|
4
|
+
职责:
|
|
5
|
+
解析输入、``subprocess.run`` 执行、返回 ``TaskExecutionResult``。
|
|
6
|
+
|
|
7
|
+
与 CC 对比:
|
|
8
|
+
CC ``LocalShellTask`` 含输出文件、stall watchdog、kill 等;本仓库最小实现仅覆盖
|
|
9
|
+
「一次 shell 执行 → 终态摘要」,长驻/monitor 等分期扩展。
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import subprocess
|
|
15
|
+
from typing import TYPE_CHECKING, Optional
|
|
16
|
+
|
|
17
|
+
from ...core.interfaces import TaskExecutor
|
|
18
|
+
from ...core.types import TaskExecutionResult, TaskStatus
|
|
19
|
+
|
|
20
|
+
from .spec import LocalBashTaskInput
|
|
21
|
+
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from ...output.sink import TaskOutputSink
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class LocalBashExecutor(TaskExecutor):
|
|
27
|
+
"""本地 shell 执行器:输入经 ``LocalBashTaskInput.from_mapping`` 校验。"""
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
*,
|
|
32
|
+
default_timeout_sec: int = 30,
|
|
33
|
+
output_sink: Optional["TaskOutputSink"] = None,
|
|
34
|
+
) -> None:
|
|
35
|
+
self._default_timeout_sec = default_timeout_sec
|
|
36
|
+
self._output_sink = output_sink
|
|
37
|
+
|
|
38
|
+
def execute(self, record) -> TaskExecutionResult:
|
|
39
|
+
try:
|
|
40
|
+
parsed = LocalBashTaskInput.from_mapping(dict(record.input or {}))
|
|
41
|
+
except ValueError as e:
|
|
42
|
+
return TaskExecutionResult(
|
|
43
|
+
status=TaskStatus.FAILED,
|
|
44
|
+
summary=str(e),
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
timeout_sec = (
|
|
48
|
+
parsed.timeout_sec
|
|
49
|
+
if parsed.timeout_sec is not None
|
|
50
|
+
else self._default_timeout_sec
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
try:
|
|
54
|
+
# shell=True:不适用 TextSubprocessRunner(其拒绝 shell);显式 UTF-8 与 CC/遥测对齐。
|
|
55
|
+
completed = subprocess.run(
|
|
56
|
+
parsed.command,
|
|
57
|
+
shell=True,
|
|
58
|
+
cwd=parsed.cwd,
|
|
59
|
+
text=True,
|
|
60
|
+
encoding="utf-8",
|
|
61
|
+
errors="replace",
|
|
62
|
+
capture_output=True,
|
|
63
|
+
timeout=timeout_sec,
|
|
64
|
+
check=False,
|
|
65
|
+
)
|
|
66
|
+
except subprocess.TimeoutExpired:
|
|
67
|
+
return TaskExecutionResult(
|
|
68
|
+
status=TaskStatus.FAILED,
|
|
69
|
+
summary=f"Command timed out after {timeout_sec}s",
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
out_blob = (completed.stdout or "") + (
|
|
73
|
+
"\n" if (completed.stdout and completed.stderr) else ""
|
|
74
|
+
) + (completed.stderr or "")
|
|
75
|
+
if self._output_sink is not None and out_blob:
|
|
76
|
+
self._output_sink.append(record.task_id, out_blob)
|
|
77
|
+
|
|
78
|
+
if completed.returncode == 0:
|
|
79
|
+
stdout = (completed.stdout or "").strip()
|
|
80
|
+
summary = stdout[:300] if stdout else "Command completed"
|
|
81
|
+
return TaskExecutionResult(
|
|
82
|
+
status=TaskStatus.COMPLETED,
|
|
83
|
+
summary=summary,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
stderr = (completed.stderr or "").strip()
|
|
87
|
+
summary = (
|
|
88
|
+
stderr[:300]
|
|
89
|
+
if stderr
|
|
90
|
+
else f"Command failed with exit code {completed.returncode}"
|
|
91
|
+
)
|
|
92
|
+
return TaskExecutionResult(
|
|
93
|
+
status=TaskStatus.FAILED,
|
|
94
|
+
summary=summary,
|
|
95
|
+
)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""
|
|
2
|
+
tasks/local_bash/notification.py — 终态摘要格式(OOP)
|
|
3
|
+
|
|
4
|
+
职责:
|
|
5
|
+
封装与 CC UI/通知折叠相关的摘要前缀与格式化,便于单测锚定。
|
|
6
|
+
|
|
7
|
+
与 CC 对比:
|
|
8
|
+
``LocalShellTask.tsx`` 中 ``BACKGROUND_BASH_SUMMARY_PREFIX``、
|
|
9
|
+
``enqueueShellNotification`` 对 completed/failed/killed 的展示逻辑;
|
|
10
|
+
此处仅保留可移植的最小前缀与拼接规则。
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class LocalBashNotificationFormatter:
|
|
15
|
+
"""CC: ``BACKGROUND_BASH_SUMMARY_PREFIX = 'Background command '``"""
|
|
16
|
+
|
|
17
|
+
BACKGROUND_BASH_SUMMARY_PREFIX = "Background command "
|
|
18
|
+
|
|
19
|
+
@classmethod
|
|
20
|
+
def format_terminal(cls, *, description: str, status: str) -> str:
|
|
21
|
+
desc = (description or "").strip() or "(no description)"
|
|
22
|
+
return f"{cls.BACKGROUND_BASH_SUMMARY_PREFIX}\"{desc}\" [{status}]"
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""tasks/local_bash/semantics.py — ``TaskSemanticContract`` 绑定。"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from ...core.types import TaskStatus, TaskType
|
|
6
|
+
from ..base.contracts import TaskSemanticContract
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
LOCAL_BASH_SEMANTIC = TaskSemanticContract(
|
|
10
|
+
task_type=TaskType.LOCAL_BASH,
|
|
11
|
+
terminal_statuses=(TaskStatus.COMPLETED, TaskStatus.FAILED, TaskStatus.STOPPED),
|
|
12
|
+
summary_prefix="local_bash",
|
|
13
|
+
)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""
|
|
2
|
+
tasks/local_bash/spec.py — LOCAL_BASH 输入契约(OOP)
|
|
3
|
+
|
|
4
|
+
职责:
|
|
5
|
+
将未信任的 ``dict`` 解析为冻结的输入值对象;校验失败抛 ``ValueError``,
|
|
6
|
+
由 ``TaskExecutor.execute`` 转为 ``TaskExecutionResult(FAILED)``。
|
|
7
|
+
|
|
8
|
+
与 CC 对比:
|
|
9
|
+
CC 侧 ``LocalShellSpawnInput`` / guards(``BashTaskKind``)在 TS 中结构化;
|
|
10
|
+
本仓库用 ``LocalBashTaskInput.from_mapping`` 做等价入口,避免业务层散落魔法 key。
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from dataclasses import dataclass
|
|
16
|
+
from typing import Any, Mapping
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass(frozen=True)
|
|
20
|
+
class LocalBashTaskInput:
|
|
21
|
+
"""进程内 shell 任务输入(对齐 CC LocalShellTask 最小字段)。"""
|
|
22
|
+
|
|
23
|
+
command: str
|
|
24
|
+
cwd: str | None = None
|
|
25
|
+
timeout_sec: int | None = None
|
|
26
|
+
kind: str | None = None
|
|
27
|
+
|
|
28
|
+
@classmethod
|
|
29
|
+
def from_mapping(cls, raw: Mapping[str, Any]) -> LocalBashTaskInput:
|
|
30
|
+
command = str(raw.get("command") or "").strip()
|
|
31
|
+
if not command:
|
|
32
|
+
raise ValueError("LOCAL_BASH requires non-empty 'command'")
|
|
33
|
+
cwd_raw = raw.get("cwd")
|
|
34
|
+
cwd = str(cwd_raw).strip() if cwd_raw not in (None, "") else None
|
|
35
|
+
timeout_raw = raw.get("timeout_sec")
|
|
36
|
+
if timeout_raw is None:
|
|
37
|
+
timeout_sec = None
|
|
38
|
+
else:
|
|
39
|
+
timeout_sec = int(timeout_raw)
|
|
40
|
+
if timeout_sec <= 0:
|
|
41
|
+
raise ValueError("timeout_sec must be positive when set")
|
|
42
|
+
kind_raw = raw.get("kind")
|
|
43
|
+
kind = str(kind_raw).strip().lower() if kind_raw is not None else None
|
|
44
|
+
return cls(command=command, cwd=cwd, timeout_sec=timeout_sec, kind=kind)
|
|
45
|
+
|
|
46
|
+
def to_executor_mapping(self) -> dict[str, Any]:
|
|
47
|
+
"""供 ``TaskSpec.input`` 序列化;仅包含执行器消费的键。"""
|
|
48
|
+
out: dict[str, Any] = {"command": self.command}
|
|
49
|
+
if self.cwd is not None:
|
|
50
|
+
out["cwd"] = self.cwd
|
|
51
|
+
if self.timeout_sec is not None:
|
|
52
|
+
out["timeout_sec"] = self.timeout_sec
|
|
53
|
+
if self.kind is not None:
|
|
54
|
+
out["kind"] = self.kind
|
|
55
|
+
return out
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""REMOTE_AGENT 语义包(CC ``RemoteAgentTask``)。"""
|
|
2
|
+
|
|
3
|
+
from .backend import (
|
|
4
|
+
ImmediateRemoteAgentBackend,
|
|
5
|
+
RecordingRemoteAgentBackend,
|
|
6
|
+
RemoteAgentSessionBackend,
|
|
7
|
+
)
|
|
8
|
+
from .executor import RemoteAgentExecutor
|
|
9
|
+
from .semantics import REMOTE_AGENT_SEMANTIC
|
|
10
|
+
from .spec import RemoteAgentTaskInput
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"ImmediateRemoteAgentBackend",
|
|
14
|
+
"RecordingRemoteAgentBackend",
|
|
15
|
+
"RemoteAgentExecutor",
|
|
16
|
+
"RemoteAgentSessionBackend",
|
|
17
|
+
"REMOTE_AGENT_SEMANTIC",
|
|
18
|
+
"RemoteAgentTaskInput",
|
|
19
|
+
]
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""
|
|
2
|
+
tasks/remote_agent/backend.py — 远程会话命令后端(CC poll/send 语义)
|
|
3
|
+
|
|
4
|
+
职责:
|
|
5
|
+
将 ``session_id + command`` 的执行与 executor 解耦,便于接入 **HTTP / teleport**
|
|
6
|
+
等实现;默认 ``ImmediateRemoteAgentBackend`` 无 I/O,用于 CI 与单测。
|
|
7
|
+
|
|
8
|
+
与 CC 对比:
|
|
9
|
+
CC ``RemoteAgentTask`` 轮询 ``pollRemoteSessionEvents`` 并下发 command;
|
|
10
|
+
此处用 ``run_command`` 抽象一次「投递命令 → 终态结果」,真轮询可在实现内循环。
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from typing import Protocol, runtime_checkable
|
|
16
|
+
|
|
17
|
+
from ...core.types import TaskExecutionResult, TaskStatus
|
|
18
|
+
from .notification import RemoteAgentNotificationFormatter
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@runtime_checkable
|
|
22
|
+
class RemoteAgentSessionBackend(Protocol):
|
|
23
|
+
def run_command(
|
|
24
|
+
self,
|
|
25
|
+
*,
|
|
26
|
+
session_id: str,
|
|
27
|
+
command: str,
|
|
28
|
+
remote_task_type: str,
|
|
29
|
+
) -> TaskExecutionResult:
|
|
30
|
+
...
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class ImmediateRemoteAgentBackend:
|
|
34
|
+
"""无网络:命令立即视为成功,摘要与 CC 展示串对齐。"""
|
|
35
|
+
|
|
36
|
+
def run_command(
|
|
37
|
+
self,
|
|
38
|
+
*,
|
|
39
|
+
session_id: str,
|
|
40
|
+
command: str,
|
|
41
|
+
remote_task_type: str,
|
|
42
|
+
) -> TaskExecutionResult:
|
|
43
|
+
summary = RemoteAgentNotificationFormatter.format_command_completion(
|
|
44
|
+
session_id=session_id,
|
|
45
|
+
command=command,
|
|
46
|
+
remote_task_type=remote_task_type,
|
|
47
|
+
)
|
|
48
|
+
return TaskExecutionResult(status=TaskStatus.COMPLETED, summary=summary)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class RecordingRemoteAgentBackend:
|
|
52
|
+
"""包装另一后端并记录调用,便于测试与调试。"""
|
|
53
|
+
|
|
54
|
+
def __init__(self, inner: RemoteAgentSessionBackend | None = None) -> None:
|
|
55
|
+
self._inner = inner or ImmediateRemoteAgentBackend()
|
|
56
|
+
self.calls: list[dict[str, str]] = []
|
|
57
|
+
|
|
58
|
+
def run_command(
|
|
59
|
+
self,
|
|
60
|
+
*,
|
|
61
|
+
session_id: str,
|
|
62
|
+
command: str,
|
|
63
|
+
remote_task_type: str,
|
|
64
|
+
) -> TaskExecutionResult:
|
|
65
|
+
self.calls.append(
|
|
66
|
+
{
|
|
67
|
+
"session_id": session_id,
|
|
68
|
+
"command": command,
|
|
69
|
+
"remote_task_type": remote_task_type,
|
|
70
|
+
}
|
|
71
|
+
)
|
|
72
|
+
return self._inner.run_command(
|
|
73
|
+
session_id=session_id,
|
|
74
|
+
command=command,
|
|
75
|
+
remote_task_type=remote_task_type,
|
|
76
|
+
)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""
|
|
2
|
+
tasks/remote_agent/executor.py — REMOTE_AGENT 执行器
|
|
3
|
+
|
|
4
|
+
职责:
|
|
5
|
+
校验输入后委托 ``RemoteAgentSessionBackend.run_command``;默认
|
|
6
|
+
``ImmediateRemoteAgentBackend`` 无网络。生产接入 HTTP/teleport 时替换 backend。
|
|
7
|
+
|
|
8
|
+
与 CC 对比:
|
|
9
|
+
CC ``pollRemoteSessionEvents`` + 命令下发;此处将一轮「投递命令 → 结果」收口到
|
|
10
|
+
backend,轮询可在 ``HttpRemoteAgentBackend`` 等实现内完成。
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from typing import Optional
|
|
16
|
+
|
|
17
|
+
from ...core.interfaces import TaskExecutor
|
|
18
|
+
from ...core.types import TaskExecutionResult, TaskStatus
|
|
19
|
+
|
|
20
|
+
from .backend import ImmediateRemoteAgentBackend, RemoteAgentSessionBackend
|
|
21
|
+
from .spec import RemoteAgentTaskInput
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class RemoteAgentExecutor(TaskExecutor):
|
|
25
|
+
def __init__(self, backend: Optional[RemoteAgentSessionBackend] = None) -> None:
|
|
26
|
+
self._backend: RemoteAgentSessionBackend = backend or ImmediateRemoteAgentBackend()
|
|
27
|
+
|
|
28
|
+
def execute(self, record) -> TaskExecutionResult:
|
|
29
|
+
try:
|
|
30
|
+
parsed = RemoteAgentTaskInput.from_mapping(dict(record.input or {}))
|
|
31
|
+
except ValueError as e:
|
|
32
|
+
return TaskExecutionResult(status=TaskStatus.FAILED, summary=str(e))
|
|
33
|
+
return self._backend.run_command(
|
|
34
|
+
session_id=parsed.session_id,
|
|
35
|
+
command=parsed.command,
|
|
36
|
+
remote_task_type=parsed.remote_task_type,
|
|
37
|
+
)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""
|
|
2
|
+
tasks/remote_agent/notification.py — 终态摘要(OOP)
|
|
3
|
+
|
|
4
|
+
与 CC 对比:
|
|
5
|
+
CC 在 poll 完成时生成可展示的 notification 文本;本类仅提供占位格式化。
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class RemoteAgentNotificationFormatter:
|
|
10
|
+
@classmethod
|
|
11
|
+
def format_command_completion(
|
|
12
|
+
cls,
|
|
13
|
+
*,
|
|
14
|
+
session_id: str,
|
|
15
|
+
command: str,
|
|
16
|
+
remote_task_type: str,
|
|
17
|
+
) -> str:
|
|
18
|
+
excerpt = command[:160]
|
|
19
|
+
return (
|
|
20
|
+
f"Remote agent command completed: session={session_id} "
|
|
21
|
+
f"type={remote_task_type} cmd={excerpt!r}"
|
|
22
|
+
)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""tasks/remote_agent/semantics.py — 语义契约绑定。"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from ...core.types import TaskStatus, TaskType
|
|
6
|
+
from ..base.contracts import TaskSemanticContract
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
REMOTE_AGENT_SEMANTIC = TaskSemanticContract(
|
|
10
|
+
task_type=TaskType.REMOTE_AGENT,
|
|
11
|
+
terminal_statuses=(TaskStatus.COMPLETED, TaskStatus.FAILED, TaskStatus.STOPPED),
|
|
12
|
+
summary_prefix="remote_agent",
|
|
13
|
+
)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""
|
|
2
|
+
tasks/remote_agent/spec.py — REMOTE_AGENT 输入契约(OOP)
|
|
3
|
+
|
|
4
|
+
职责:
|
|
5
|
+
描述远程会话类任务的最小输入;.teleport / poll 等网络行为不在 spec 内实现。
|
|
6
|
+
|
|
7
|
+
与 CC 对比:
|
|
8
|
+
``RemoteAgentTask.tsx`` 中 ``sessionId``、``command``、``remoteTaskType``、
|
|
9
|
+
``RemoteAgentTaskState``;本仓库用 ``RemoteAgentTaskInput.from_mapping`` 对齐命名,
|
|
10
|
+
真轮询与元数据持久化在 executor 分期接入。
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from dataclasses import dataclass
|
|
16
|
+
from typing import Any, Mapping
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass(frozen=True)
|
|
20
|
+
class RemoteAgentTaskInput:
|
|
21
|
+
session_id: str
|
|
22
|
+
command: str
|
|
23
|
+
remote_task_type: str = "remote-agent"
|
|
24
|
+
|
|
25
|
+
@classmethod
|
|
26
|
+
def from_mapping(cls, raw: Mapping[str, Any]) -> RemoteAgentTaskInput:
|
|
27
|
+
sid = str(raw.get("session_id") or raw.get("sessionId") or "").strip()
|
|
28
|
+
cmd = str(raw.get("command") or "").strip()
|
|
29
|
+
if not sid:
|
|
30
|
+
raise ValueError("REMOTE_AGENT requires 'session_id'")
|
|
31
|
+
if not cmd:
|
|
32
|
+
raise ValueError("REMOTE_AGENT requires non-empty 'command'")
|
|
33
|
+
rtt = str(raw.get("remote_task_type") or raw.get("remoteTaskType") or "remote-agent").strip()
|
|
34
|
+
return cls(session_id=sid, command=cmd, remote_task_type=rtt or "remote-agent")
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""
|
|
2
|
+
trace_cleanup — Trace 数据清理后台任务(OB-D10 Phase 1)
|
|
3
|
+
|
|
4
|
+
职责:
|
|
5
|
+
导出 TraceCleanupTask;import 本包时注册 ``trace.cleanup`` 到 BackgroundAiTaskRegistry。
|
|
6
|
+
|
|
7
|
+
链路位置:
|
|
8
|
+
由 ``langchain_agentx.task_runtime.tasks.ai_analysis`` 包加载时一并 import,保证 registry 侧载。
|
|
9
|
+
|
|
10
|
+
当前裁剪范围:
|
|
11
|
+
不含 create_agent / loop 挂载(Phase 4);不含 ``cleanup_by_size``(OB-D10 Phase 5)。
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
from .executor import TraceCleanupTask
|
|
17
|
+
from .scheduler import TraceCleanupScheduler
|
|
18
|
+
|
|
19
|
+
__all__ = ["TraceCleanupTask", "TraceCleanupScheduler"]
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""
|
|
2
|
+
trace_cleanup/bootstrap.py — create_loop_agent 侧清理调度启动
|
|
3
|
+
|
|
4
|
+
职责:
|
|
5
|
+
在图已 ``compile`` 后,若存在运行中 asyncio 循环,则 ``create_task(TraceCleanupScheduler.start())``。
|
|
6
|
+
|
|
7
|
+
链路位置:
|
|
8
|
+
可由应用在 **async 上下文** 内显式调用;是否从 ``create_loop_agent`` 挂载由产品决定(当前 factory 未接线)。
|
|
9
|
+
|
|
10
|
+
当前裁剪范围:
|
|
11
|
+
不解析 YAML;参数由 ``create_loop_agent`` 关键字传入;无 event loop 时仅打日志不抛错。
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import asyncio
|
|
17
|
+
import logging
|
|
18
|
+
from typing import Any
|
|
19
|
+
|
|
20
|
+
logger = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class _NoopCompiledGraph:
|
|
24
|
+
"""TraceCleanupTask 不调用 invoke,仅占位满足 BaseWorkflow 契约。"""
|
|
25
|
+
|
|
26
|
+
async def ainvoke(self, *args: Any, **kwargs: Any) -> dict[str, Any]:
|
|
27
|
+
return {"messages": []}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _noop_graph_factory(**kwargs: Any) -> _NoopCompiledGraph:
|
|
31
|
+
return _NoopCompiledGraph()
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def try_start_trace_cleanup_after_compile(
|
|
35
|
+
builder: Any,
|
|
36
|
+
*,
|
|
37
|
+
poll_interval: float,
|
|
38
|
+
failed_days: int,
|
|
39
|
+
normal_days: int,
|
|
40
|
+
enable_file_lock: bool,
|
|
41
|
+
marker_cooldown_seconds: float | None,
|
|
42
|
+
cleanup_diagnostic_reports: bool,
|
|
43
|
+
) -> None:
|
|
44
|
+
"""在 **当前线程** 存在运行中 event loop 时启动 ``TraceCleanupScheduler``,否则打 warning。"""
|
|
45
|
+
wiring = getattr(builder, "_hook_graph_wiring", None)
|
|
46
|
+
if wiring is None:
|
|
47
|
+
logger.warning("trace cleanup: LoopGraphBuilder 缺少 _hook_graph_wiring,跳过启动")
|
|
48
|
+
return
|
|
49
|
+
try:
|
|
50
|
+
loop = asyncio.get_running_loop()
|
|
51
|
+
except RuntimeError:
|
|
52
|
+
logger.warning(
|
|
53
|
+
"enable_trace_cleanup=True 但当前线程无运行中的 asyncio 事件循环,未启动 "
|
|
54
|
+
"TraceCleanupScheduler;请在 async 内创建 agent 或自行 ``asyncio.create_task(scheduler.start())``"
|
|
55
|
+
)
|
|
56
|
+
return
|
|
57
|
+
|
|
58
|
+
import langchain_agentx.task_runtime.tasks.ai_analysis # noqa: F401 — registry 侧载
|
|
59
|
+
|
|
60
|
+
from langchain_agentx.observability.evaluation.store import EvaluationStore
|
|
61
|
+
from langchain_agentx.observability.trace.sqlite_store import SqliteTraceStore
|
|
62
|
+
from langchain_agentx.task_runtime.tasks.ai_analysis.registry import registry
|
|
63
|
+
|
|
64
|
+
from .scheduler import TraceCleanupScheduler
|
|
65
|
+
|
|
66
|
+
trace_store = SqliteTraceStore.from_env()
|
|
67
|
+
eval_store = EvaluationStore.from_env()
|
|
68
|
+
cleanup_config: dict[str, Any] = {
|
|
69
|
+
"failed_days": int(failed_days),
|
|
70
|
+
"normal_days": int(normal_days),
|
|
71
|
+
"cleanup_diagnostic_reports": bool(cleanup_diagnostic_reports),
|
|
72
|
+
}
|
|
73
|
+
scheduler = TraceCleanupScheduler(
|
|
74
|
+
trace_store=trace_store,
|
|
75
|
+
evaluation_store=eval_store,
|
|
76
|
+
registry=registry,
|
|
77
|
+
poll_interval=float(poll_interval),
|
|
78
|
+
cleanup_config=cleanup_config,
|
|
79
|
+
enable_file_lock=bool(enable_file_lock),
|
|
80
|
+
marker_cooldown_seconds=marker_cooldown_seconds,
|
|
81
|
+
task_factory_kwargs={
|
|
82
|
+
"graph_factory": _noop_graph_factory,
|
|
83
|
+
"hook_engine": wiring.hook_engine,
|
|
84
|
+
},
|
|
85
|
+
)
|
|
86
|
+
loop.create_task(scheduler.start())
|
|
87
|
+
logger.info(
|
|
88
|
+
"TraceCleanupScheduler 已提交到事件循环 poll_interval=%s failed_days=%s normal_days=%s",
|
|
89
|
+
poll_interval,
|
|
90
|
+
failed_days,
|
|
91
|
+
normal_days,
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
__all__ = ["try_start_trace_cleanup_after_compile", "_noop_graph_factory"]
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""
|
|
2
|
+
trace_cleanup/executor.py — TraceCleanupTask
|
|
3
|
+
|
|
4
|
+
职责:
|
|
5
|
+
单次执行 trace session 分层保留清理(调用 SqliteTraceStore.cleanup_sessions_by_retention)。
|
|
6
|
+
|
|
7
|
+
链路位置:
|
|
8
|
+
由 TraceCleanupScheduler(Phase 2)或测试/脚本通过 registry.get("trace.cleanup") 构造并 run()。
|
|
9
|
+
|
|
10
|
+
当前裁剪范围:
|
|
11
|
+
``cleanup_diagnostic_reports=False`` 时不删诊断报告(§4.1 Q1=A 默认);不实现 cleanup_by_size(Q3 延后)。
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import logging
|
|
17
|
+
from typing import Any
|
|
18
|
+
|
|
19
|
+
from langchain_agentx.observability.evaluation.store import EvaluationStore
|
|
20
|
+
from langchain_agentx.observability.trace.sqlite_store import SqliteTraceStore
|
|
21
|
+
|
|
22
|
+
from ..ai_analysis.base import BackgroundAiTask
|
|
23
|
+
from ..ai_analysis.registry import registry
|
|
24
|
+
|
|
25
|
+
logger = logging.getLogger(__name__)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class TraceCleanupTask(BackgroundAiTask):
|
|
29
|
+
"""清理过期 trace session(retention 策略由参数传入)。"""
|
|
30
|
+
|
|
31
|
+
def __init__(
|
|
32
|
+
self,
|
|
33
|
+
trace_store: SqliteTraceStore,
|
|
34
|
+
evaluation_store: EvaluationStore,
|
|
35
|
+
**workflow_kwargs: Any,
|
|
36
|
+
) -> None:
|
|
37
|
+
super().__init__(**workflow_kwargs)
|
|
38
|
+
self._trace_store = trace_store
|
|
39
|
+
self._evaluation_store = evaluation_store
|
|
40
|
+
|
|
41
|
+
async def _execute(
|
|
42
|
+
self,
|
|
43
|
+
*,
|
|
44
|
+
failed_days: int = 180,
|
|
45
|
+
normal_days: int = 30,
|
|
46
|
+
cleanup_diagnostic_reports: bool = False,
|
|
47
|
+
**_: Any,
|
|
48
|
+
) -> dict[str, int]:
|
|
49
|
+
deleted_sessions = self._trace_store.cleanup_sessions_by_retention(
|
|
50
|
+
failed_days=int(failed_days),
|
|
51
|
+
normal_days=int(normal_days),
|
|
52
|
+
)
|
|
53
|
+
deleted_reports = 0
|
|
54
|
+
if cleanup_diagnostic_reports:
|
|
55
|
+
deleted_reports = self._evaluation_store.cleanup_old_reports(days=int(failed_days))
|
|
56
|
+
out: dict[str, int] = {
|
|
57
|
+
"deleted_sessions": int(deleted_sessions),
|
|
58
|
+
"deleted_reports": int(deleted_reports),
|
|
59
|
+
}
|
|
60
|
+
logger.info("TraceCleanupTask 完成: %s", out)
|
|
61
|
+
return out
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
registry.register("trace.cleanup", TraceCleanupTask)
|
|
65
|
+
|
|
66
|
+
__all__ = ["TraceCleanupTask"]
|