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,195 @@
|
|
|
1
|
+
"""
|
|
2
|
+
runtime/loader.py — 工具运行时框架进程级初始化入口
|
|
3
|
+
|
|
4
|
+
职责:
|
|
5
|
+
进程级一次性初始化,组装框架核心组件(pipeline / policy / registry)并统一管理工具注册。
|
|
6
|
+
loader 只负责注册 RuntimeTool,不构造 StructuredTool。
|
|
7
|
+
StructuredTool 构造由 factory(create_loop_agent)在 graph 构建时负责,
|
|
8
|
+
通过 create_loop_agent(loader=...) 在构图时调用 to_langchain_tools() 构造 StructuredTool。
|
|
9
|
+
|
|
10
|
+
policy_config 用于构造 DefaultPolicyEngine,在 register() 时自动注入给每个工具。
|
|
11
|
+
工具无需手动传入 policy,由 loader 统一治理。
|
|
12
|
+
|
|
13
|
+
装配路径:
|
|
14
|
+
ToolRuntimeLoader(policy_config=...) 构造
|
|
15
|
+
→ DefaultPolicyEngine(policy_config)
|
|
16
|
+
→ register(tool): 只存储 RuntimeTool,注入 policy
|
|
17
|
+
→ 传入 create_loop_agent(loader=loader, ...)
|
|
18
|
+
→ factory 内部调用 loader._registry.to_langchain_tools() 构造 StructuredTool
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
from typing import TYPE_CHECKING, Any
|
|
24
|
+
|
|
25
|
+
from langchain_core.tools import BaseTool
|
|
26
|
+
|
|
27
|
+
from .adapter import LangChainAdapter
|
|
28
|
+
from .base import RuntimeTool
|
|
29
|
+
from .pipeline import ToolExecutorPipeline, ToolOutputManager
|
|
30
|
+
from .policy import DefaultPolicyEngine, PolicyEngine, ToolPolicyConfig
|
|
31
|
+
from .registry import RuntimeToolRegistry
|
|
32
|
+
from .resolvers import PermissionResolver
|
|
33
|
+
from .session_store import AgentSessionStore
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class ToolRuntimeLoader:
|
|
37
|
+
"""
|
|
38
|
+
工具运行时进程级装配入口。
|
|
39
|
+
|
|
40
|
+
policy_config: 策略配置,构造 DefaultPolicyEngine 并自动注入给所有注册工具。
|
|
41
|
+
为 None 时不注入 policy(工具默认 allow,适用于开发/测试模式)。
|
|
42
|
+
policy_engine: 直接传入自定义 PolicyEngine 实例(优先于 policy_config)。
|
|
43
|
+
output_manager: 工具输出大小管控器,为 None 时使用默认配置。
|
|
44
|
+
headless: 是否处于无交互(headless)模式。
|
|
45
|
+
True — check_permissions 返回 ask 时自动降级为 deny(API 调用、CI、批处理场景)。
|
|
46
|
+
False — check_permissions 返回 ask 时抛出 PermissionAskInterrupt(交互场景,默认)。
|
|
47
|
+
对应 CC 的 shouldAvoidPermissionPrompts / isNonInteractiveSession。
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
def __init__(
|
|
51
|
+
self,
|
|
52
|
+
*,
|
|
53
|
+
policy_config: ToolPolicyConfig | None = None,
|
|
54
|
+
policy_engine: PolicyEngine | None = None,
|
|
55
|
+
output_manager: ToolOutputManager | None = None,
|
|
56
|
+
headless: bool = False,
|
|
57
|
+
permission_resolver: PermissionResolver | None = None,
|
|
58
|
+
) -> None:
|
|
59
|
+
self._headless = headless
|
|
60
|
+
self._permission_resolver = permission_resolver
|
|
61
|
+
self._pipeline = ToolExecutorPipeline(
|
|
62
|
+
output_manager=output_manager,
|
|
63
|
+
headless=headless,
|
|
64
|
+
permission_resolver=permission_resolver,
|
|
65
|
+
)
|
|
66
|
+
self._adapter = LangChainAdapter()
|
|
67
|
+
self._registry = RuntimeToolRegistry(
|
|
68
|
+
pipeline=self._pipeline,
|
|
69
|
+
adapter=self._adapter,
|
|
70
|
+
)
|
|
71
|
+
# 优先使用外部传入的 policy_engine;其次从 policy_config 构造;否则为 None
|
|
72
|
+
if policy_engine is not None:
|
|
73
|
+
self._policy: PolicyEngine | None = policy_engine
|
|
74
|
+
elif policy_config is not None:
|
|
75
|
+
self._policy = DefaultPolicyEngine(policy_config)
|
|
76
|
+
else:
|
|
77
|
+
self._policy = None
|
|
78
|
+
|
|
79
|
+
def register(self, tool: RuntimeTool) -> "ToolRuntimeLoader":
|
|
80
|
+
"""
|
|
81
|
+
注册工具并自动注入 PolicyEngine。
|
|
82
|
+
|
|
83
|
+
注入规则:
|
|
84
|
+
- 工具已有 _policy(初始化时手动传入)→ 不覆盖,保留工具自己的 policy
|
|
85
|
+
- 工具无 _policy(_policy is None)→ 注入 loader 的统一 policy
|
|
86
|
+
这允许个别工具使用专属 policy,其余工具统一受 loader policy 保护。
|
|
87
|
+
"""
|
|
88
|
+
if self._policy is not None and getattr(tool, "_policy", None) is None:
|
|
89
|
+
tool._policy = self._policy
|
|
90
|
+
self._registry.register(tool)
|
|
91
|
+
return self
|
|
92
|
+
|
|
93
|
+
def register_default_tools(
|
|
94
|
+
self,
|
|
95
|
+
*,
|
|
96
|
+
workspace_root: str,
|
|
97
|
+
agent_home: str = ".langchain_agentx",
|
|
98
|
+
include_agent: bool = True,
|
|
99
|
+
include_skill: bool = False,
|
|
100
|
+
agent_registry: Any | None = None,
|
|
101
|
+
) -> "ToolRuntimeLoader":
|
|
102
|
+
"""
|
|
103
|
+
注册默认工具集(Read/Grep/Glob/Bash + 可选 Agent/Skill)。
|
|
104
|
+
|
|
105
|
+
用于打通默认工具装配链路,避免每个调用方重复手写 register 序列。
|
|
106
|
+
"""
|
|
107
|
+
from pathlib import Path
|
|
108
|
+
|
|
109
|
+
from langchain_agentx.tools.bash import BashRuntimeTool
|
|
110
|
+
from langchain_agentx.tools.glob import GlobRuntimeTool
|
|
111
|
+
from langchain_agentx.tools.grep import GrepRuntimeTool
|
|
112
|
+
from langchain_agentx.tools.read import ReadRuntimeTool
|
|
113
|
+
from langchain_agentx.tools.ripgrep_plugin_exclusions import PluginCacheGlobExclusions
|
|
114
|
+
from langchain_agentx.tool_runtime.state_bridge import ToolStateBridge
|
|
115
|
+
from langchain_agentx.workspace.config import AgentWorkspaceConfig
|
|
116
|
+
|
|
117
|
+
self.register(ReadRuntimeTool())
|
|
118
|
+
default_tool_state_bridge = ToolStateBridge()
|
|
119
|
+
wr = Path(workspace_root).resolve()
|
|
120
|
+
cfg = AgentWorkspaceConfig(workspace_root=wr, agent_home=agent_home)
|
|
121
|
+
plugin_ex = PluginCacheGlobExclusions(
|
|
122
|
+
cache_root=str(cfg.plugin_cache_dir.resolve()),
|
|
123
|
+
)
|
|
124
|
+
self.register(
|
|
125
|
+
GrepRuntimeTool(
|
|
126
|
+
workspace_root=str(wr),
|
|
127
|
+
plugin_cache_glob_exclusions=plugin_ex,
|
|
128
|
+
)
|
|
129
|
+
)
|
|
130
|
+
self.register(
|
|
131
|
+
GlobRuntimeTool(
|
|
132
|
+
workspace_root=str(wr),
|
|
133
|
+
plugin_cache_glob_exclusions=plugin_ex,
|
|
134
|
+
state_bridge=default_tool_state_bridge,
|
|
135
|
+
)
|
|
136
|
+
)
|
|
137
|
+
self.register(BashRuntimeTool())
|
|
138
|
+
|
|
139
|
+
if include_agent:
|
|
140
|
+
from langchain_agentx.tools.agent import AgentRuntimeTool
|
|
141
|
+
|
|
142
|
+
self.register(AgentRuntimeTool(registry=agent_registry))
|
|
143
|
+
|
|
144
|
+
if include_skill:
|
|
145
|
+
from langchain_agentx.tools.skill import SkillRuntimeTool
|
|
146
|
+
|
|
147
|
+
self.register(
|
|
148
|
+
SkillRuntimeTool(
|
|
149
|
+
workspace_root=workspace_root,
|
|
150
|
+
agent_home=agent_home,
|
|
151
|
+
)
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
return self
|
|
155
|
+
|
|
156
|
+
def create_session(self, session_id: str | None = None) -> AgentSessionStore:
|
|
157
|
+
return AgentSessionStore(session_id=session_id)
|
|
158
|
+
|
|
159
|
+
def fork_with_tools(self, tools: list[RuntimeTool]) -> "ToolRuntimeLoader":
|
|
160
|
+
"""
|
|
161
|
+
基于当前 loader 派生一个子 loader(共享 policy/headless 语义),并注册给定工具集。
|
|
162
|
+
|
|
163
|
+
目的:为 subagent 组装“过滤后的工具池”而不丢失权限/管控语义。
|
|
164
|
+
"""
|
|
165
|
+
child = ToolRuntimeLoader(
|
|
166
|
+
policy_engine=self._policy,
|
|
167
|
+
headless=self._headless,
|
|
168
|
+
permission_resolver=self._permission_resolver,
|
|
169
|
+
)
|
|
170
|
+
for t in tools:
|
|
171
|
+
child.register(t)
|
|
172
|
+
return child
|
|
173
|
+
|
|
174
|
+
def set_permission_resolver(
|
|
175
|
+
self,
|
|
176
|
+
permission_resolver: PermissionResolver | None,
|
|
177
|
+
) -> None:
|
|
178
|
+
"""更新 loader 与 pipeline 的 permission_resolver。"""
|
|
179
|
+
self._permission_resolver = permission_resolver
|
|
180
|
+
self._pipeline.set_permission_resolver(permission_resolver)
|
|
181
|
+
|
|
182
|
+
@property
|
|
183
|
+
def registry(self) -> RuntimeToolRegistry:
|
|
184
|
+
return self._registry
|
|
185
|
+
|
|
186
|
+
@property
|
|
187
|
+
def pipeline(self) -> ToolExecutorPipeline:
|
|
188
|
+
return self._pipeline
|
|
189
|
+
|
|
190
|
+
@property
|
|
191
|
+
def adapter(self) -> LangChainAdapter:
|
|
192
|
+
return self._adapter
|
|
193
|
+
|
|
194
|
+
def __repr__(self) -> str:
|
|
195
|
+
return f"<ToolRuntimeLoader tools={list(self._registry._tools.keys())}>"
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
"""
|
|
2
|
+
runtime/models.py — 工具运行时框架核心数据模型
|
|
3
|
+
|
|
4
|
+
职责:
|
|
5
|
+
定义框架内部所有稳定的数据契约(Named Spec),包括:
|
|
6
|
+
- ToolExecutionContext:运行时归一化上下文,隔离 LangGraph 底层依赖
|
|
7
|
+
- ToolResultEnvelope:工具执行统一内部结果协议,分离模型可见输出与内部数据
|
|
8
|
+
- ValidationResult:输入语义校验结果(失败时告知模型,模型可修正重试)
|
|
9
|
+
- AuthorizationDecision:权限授权决策(失败时策略拒绝,不可绕过)
|
|
10
|
+
- ToolErrorInfo / ToolHint / ToolArtifact:辅助结构
|
|
11
|
+
|
|
12
|
+
与 CC 对比:
|
|
13
|
+
CC Tool.ts 中 ToolUseContext 是一个大而全的上下文对象,包含 abortController、
|
|
14
|
+
readFileState、getAppState、messages 等大量 UI/应用层字段。
|
|
15
|
+
本框架的 ToolExecutionContext 只保留框架稳定依赖的最小字段集,
|
|
16
|
+
UI/应用层依赖由 LangChainAdapter 在边界处消费,不透传到工具内部。
|
|
17
|
+
协作取消:``cancel_event`` 对应 CC ``AbortSignal``(由上层 ``set()`` 终止 ripgrep 等子进程)。
|
|
18
|
+
|
|
19
|
+
CC 的 ValidationResult / PermissionResult 是 TypeScript union type。
|
|
20
|
+
本框架用 dataclass 实现等价语义,保持 Python 风格。
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
import threading
|
|
26
|
+
import time
|
|
27
|
+
from dataclasses import dataclass, field
|
|
28
|
+
from typing import TYPE_CHECKING, Any, Literal, MutableMapping
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
from .session_store import AgentSessionStore
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# ---------------------------------------------------------------------------
|
|
35
|
+
# ToolExecutionContext
|
|
36
|
+
# ---------------------------------------------------------------------------
|
|
37
|
+
|
|
38
|
+
@dataclass
|
|
39
|
+
class ToolExecutionContext:
|
|
40
|
+
"""
|
|
41
|
+
运行时归一化上下文。
|
|
42
|
+
|
|
43
|
+
由 LangChainAdapter.build_tool_execution_context() 从 RunnableConfig 构造,
|
|
44
|
+
隔离 LangGraph / RunnableConfig 等底层依赖,工具内部只依赖此对象。
|
|
45
|
+
|
|
46
|
+
字段来源:
|
|
47
|
+
tool_name — RuntimeTool.name
|
|
48
|
+
tool_call_id — RunnableConfig.configurable["tool_call_id"]
|
|
49
|
+
input_args — 归一化后的输入 dict
|
|
50
|
+
state — LangGraph state 引用(工具可读写)
|
|
51
|
+
now_ts — pipeline 入口时间戳
|
|
52
|
+
thread_id — RunnableConfig.configurable.get("thread_id")
|
|
53
|
+
run_id — RunnableConfig.configurable.get("run_id")
|
|
54
|
+
actor — 当前版本固定 "agent"
|
|
55
|
+
tool_flags — 工具行为标志(由 LangChainAdapter 从 RuntimeTool 类属性注入)
|
|
56
|
+
{"is_read_only": bool, "is_destructive": bool}
|
|
57
|
+
PolicyEngine 从此处读取读写属性,不污染 input_data。
|
|
58
|
+
|
|
59
|
+
父 loop 控制面(由 LangChainAdapter 从 RunnableConfig.configurable["loop_config"] 填充,工具层只读):
|
|
60
|
+
model — 父 loop 当前模型,子代理继承的 SSOT;对应 CC options.mainLoopModel
|
|
61
|
+
来源:AgentLoopConfig.model
|
|
62
|
+
available_tools — 父工具池视图,子代理工具池组装的基础;对应 CC options.tools
|
|
63
|
+
来源:AgentLoopConfig.available_tools
|
|
64
|
+
agent_id — 当前 agent ID,用于日志与追踪;对应 CC agentId
|
|
65
|
+
来源:state["agent_id"]
|
|
66
|
+
agent_depth — 嵌套深度,防止无限递归;对应 CC queryTracking.depth
|
|
67
|
+
来源:state["agent_depth"]
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
tool_name: str
|
|
71
|
+
tool_call_id: str | None
|
|
72
|
+
input_args: dict[str, Any]
|
|
73
|
+
state: MutableMapping[str, Any]
|
|
74
|
+
now_ts: float = field(default_factory=time.time)
|
|
75
|
+
thread_id: str | None = None
|
|
76
|
+
run_id: str | None = None
|
|
77
|
+
session_id: str | None = None
|
|
78
|
+
conversation_session_id: str | None = None
|
|
79
|
+
actor: Literal["agent", "human", "system"] = "agent"
|
|
80
|
+
session_store: AgentSessionStore | None = field(default=None)
|
|
81
|
+
tool_loader: Any | None = None
|
|
82
|
+
tool_registry: Any | None = None
|
|
83
|
+
tool_flags: dict[str, Any] = field(default_factory=dict)
|
|
84
|
+
"""
|
|
85
|
+
工具行为标志,由 LangChainAdapter.build_tool_execution_context() 注入。
|
|
86
|
+
标准键:
|
|
87
|
+
is_read_only — 对应 RuntimeTool.is_read_only
|
|
88
|
+
is_destructive — 对应 RuntimeTool.is_destructive
|
|
89
|
+
PolicyEngine.authorize() 从此处读取,避免污染 input_data。
|
|
90
|
+
"""
|
|
91
|
+
# 父 loop 控制面
|
|
92
|
+
model: Any | None = None
|
|
93
|
+
available_tools: list[Any] = field(default_factory=list)
|
|
94
|
+
agent_id: str | None = None
|
|
95
|
+
agent_depth: int = 0
|
|
96
|
+
workspace_root: str | None = None
|
|
97
|
+
agent_home: str = ".langchain_agentx"
|
|
98
|
+
cwd: str | None = None # 工具执行时的路径基准(CC 对照:getCwd())
|
|
99
|
+
trace_enabled: bool = True
|
|
100
|
+
cancel_event: threading.Event | None = None
|
|
101
|
+
"""可选;由 ``RunnableConfig.configurable[\"cancel_event\"]`` 注入。set 后 Grep/Glob 应中断 rg。"""
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
# ---------------------------------------------------------------------------
|
|
105
|
+
# 辅助结构
|
|
106
|
+
# ---------------------------------------------------------------------------
|
|
107
|
+
|
|
108
|
+
@dataclass
|
|
109
|
+
class ToolErrorInfo:
|
|
110
|
+
"""工具执行错误细节,附在 ToolResultEnvelope.error 上。"""
|
|
111
|
+
|
|
112
|
+
message: str
|
|
113
|
+
code: str | None = None
|
|
114
|
+
exception_type: str | None = None
|
|
115
|
+
traceback: str | None = None
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
@dataclass
|
|
119
|
+
class ToolHint:
|
|
120
|
+
"""
|
|
121
|
+
下一步操作提示,面向模型。
|
|
122
|
+
|
|
123
|
+
例如:ReadRuntimeTool 在文件被截断时提示模型用更大的 offset 继续读取。
|
|
124
|
+
suggested_action 可携带建议的工具调用参数,提高模型遵从率。
|
|
125
|
+
"""
|
|
126
|
+
|
|
127
|
+
message: str
|
|
128
|
+
suggested_action: dict[str, Any] | None = None
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
@dataclass
|
|
132
|
+
class ToolArtifact:
|
|
133
|
+
"""
|
|
134
|
+
工具产出的文件 / 媒体引用。
|
|
135
|
+
|
|
136
|
+
对应 CC 的 content_and_artifact response_format,
|
|
137
|
+
模块 5 起可用于承载 Bash 图片输出等结构化媒体结果。
|
|
138
|
+
"""
|
|
139
|
+
|
|
140
|
+
uri: str
|
|
141
|
+
media_type: str
|
|
142
|
+
description: str | None = None
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
@dataclass
|
|
146
|
+
class ToolContentBlock:
|
|
147
|
+
"""
|
|
148
|
+
结构化结果块(P1 协议升级)。
|
|
149
|
+
|
|
150
|
+
type:
|
|
151
|
+
- text: 普通文本
|
|
152
|
+
- image: 图片(结合 artifact uri)
|
|
153
|
+
- status: 状态信息(task/sandbox)
|
|
154
|
+
- reference: 大输出文件引用
|
|
155
|
+
"""
|
|
156
|
+
|
|
157
|
+
type: Literal["text", "image", "status", "reference"]
|
|
158
|
+
text: str | None = None
|
|
159
|
+
uri: str | None = None
|
|
160
|
+
media_type: str | None = None
|
|
161
|
+
meta: dict[str, Any] | None = None
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
# ---------------------------------------------------------------------------
|
|
165
|
+
# ToolResultEnvelope
|
|
166
|
+
# ---------------------------------------------------------------------------
|
|
167
|
+
|
|
168
|
+
@dataclass
|
|
169
|
+
class ToolResultEnvelope:
|
|
170
|
+
"""
|
|
171
|
+
工具运行时统一内部结果协议。
|
|
172
|
+
|
|
173
|
+
框架内部始终使用此结构传递工具执行结果。
|
|
174
|
+
LangChainAdapter.envelope_to_tool_output() 负责将其映射为
|
|
175
|
+
LangChain ToolMessage.content 字符串,meta 默认不进入模型上下文。
|
|
176
|
+
|
|
177
|
+
字段说明:
|
|
178
|
+
status — ok / blocked / error
|
|
179
|
+
tool_name — 工具名
|
|
180
|
+
summary — 面向模型的简短结论(必须进入模型上下文)
|
|
181
|
+
payload — 主体数据(经映射后进入模型)
|
|
182
|
+
artifacts — 文件/媒体引用(v1 预留,默认 None)
|
|
183
|
+
hints — 下一步提示(进入模型)
|
|
184
|
+
meta — 审计/性能信息(不进入模型)
|
|
185
|
+
error — 错误细节(error 场景必须填写)
|
|
186
|
+
truncated — 输出是否被 ToolOutputManager 截断
|
|
187
|
+
overflow_file — 超大输出的持久化文件路径(截断时填写,告知模型)
|
|
188
|
+
"""
|
|
189
|
+
|
|
190
|
+
status: Literal["ok", "blocked", "error"]
|
|
191
|
+
tool_name: str
|
|
192
|
+
summary: str
|
|
193
|
+
payload: dict[str, Any] | str | None = None
|
|
194
|
+
blocks: list[ToolContentBlock] | None = None
|
|
195
|
+
artifacts: list[ToolArtifact] | None = None
|
|
196
|
+
hints: list[ToolHint] | None = None
|
|
197
|
+
meta: dict[str, Any] | None = None
|
|
198
|
+
error: ToolErrorInfo | None = None
|
|
199
|
+
truncated: bool = False
|
|
200
|
+
overflow_file: str | None = None
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
# ---------------------------------------------------------------------------
|
|
204
|
+
# ValidationResult
|
|
205
|
+
# ---------------------------------------------------------------------------
|
|
206
|
+
|
|
207
|
+
@dataclass
|
|
208
|
+
class ValidationResult:
|
|
209
|
+
"""
|
|
210
|
+
输入语义校验结果,由 RuntimeTool.validate_input() 返回。
|
|
211
|
+
|
|
212
|
+
ok=False 时,pipeline 短路并生成 status="error" 的 envelope。
|
|
213
|
+
模型会收到 message,可据此修正输入后重试。
|
|
214
|
+
|
|
215
|
+
与 CC 对比:
|
|
216
|
+
CC validateInput 返回 ValidationResult = { result: "success" } | { result: "error", message }
|
|
217
|
+
本框架等价语义,额外增加 code(稳定错误码)和 normalized_input(校验阶段回写归一化输入)。
|
|
218
|
+
"""
|
|
219
|
+
|
|
220
|
+
ok: bool
|
|
221
|
+
message: str | None = None
|
|
222
|
+
code: str | None = None
|
|
223
|
+
normalized_input: dict[str, Any] | None = None
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
# ---------------------------------------------------------------------------
|
|
227
|
+
# AuthorizationDecision
|
|
228
|
+
# ---------------------------------------------------------------------------
|
|
229
|
+
|
|
230
|
+
@dataclass
|
|
231
|
+
class AuthorizationDecision:
|
|
232
|
+
"""
|
|
233
|
+
权限授权决策,由 RuntimeTool.check_permissions() 返回。
|
|
234
|
+
|
|
235
|
+
behavior 语义:
|
|
236
|
+
"allow" — 放行,继续执行
|
|
237
|
+
"deny" — 策略拒绝,pipeline 短路返回 status="blocked" envelope,不可绕过
|
|
238
|
+
"ask" — 需要人工确认(HITL):
|
|
239
|
+
· headless 模式(ToolRuntimeLoader(headless=True)):pipeline 自动降级为 deny
|
|
240
|
+
· 交互模式:pipeline 抛出 PermissionAskInterrupt,
|
|
241
|
+
由 LangGraph checkpointer + HumanInTheLoopMiddleware 处理
|
|
242
|
+
|
|
243
|
+
ask_prompt: 展示给用户的确认提示文本(headless 时忽略)。
|
|
244
|
+
updated_input: 策略层在授权时回写修正后的输入(如路径规范化),
|
|
245
|
+
对应 CC PermissionAllowDecision.updatedInput。
|
|
246
|
+
metadata: 可选结构化扩展(如 bash 攻防 rule_code、审计快照),便于观测与 UI 对齐 CC。
|
|
247
|
+
|
|
248
|
+
与 CC 对比:
|
|
249
|
+
CC checkPermissions 返回 PermissionResult,包含 allow / ask / deny / passthrough。
|
|
250
|
+
本框架 v1.5 实现 allow / deny / ask 三种行为:
|
|
251
|
+
- headless=True 时 ask → deny(对应 CC shouldAvoidPermissionPrompts)
|
|
252
|
+
- headless=False 时 ask → PermissionAskInterrupt(对应 CC HITL race)
|
|
253
|
+
"""
|
|
254
|
+
|
|
255
|
+
behavior: Literal["allow", "deny", "ask"]
|
|
256
|
+
message: str | None = None
|
|
257
|
+
policy_id: str | None = None
|
|
258
|
+
updated_input: dict[str, Any] | None = None
|
|
259
|
+
ask_prompt: str | None = None
|
|
260
|
+
metadata: dict[str, Any] | None = None
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""
|
|
2
|
+
tool_runtime/permission_context.py — 会话级工具权限上下文
|
|
3
|
+
|
|
4
|
+
职责:在 AgentSessionStore 上管理 skill 触发的 auto-approved 工具窗口(pending/active)。
|
|
5
|
+
在整体链路中的位置:SkillRuntimeTool 写入 pending;模型调用前轮转为 active;PolicyEngine 消费。
|
|
6
|
+
CC 对照:allowedTools 进入 alwaysAllowRules,并在局部会话上下文生效。
|
|
7
|
+
当前裁剪范围:v1 单轮窗口语义(pending -> active),不实现多层嵌套栈。
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from collections.abc import Iterable
|
|
13
|
+
|
|
14
|
+
from .session_store import AgentSessionStore
|
|
15
|
+
|
|
16
|
+
_PENDING_KEY = "tool_scope.auto_approved.pending"
|
|
17
|
+
_ACTIVE_KEY = "tool_scope.auto_approved.active"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _normalize_names(names: Iterable[str]) -> list[str]:
|
|
21
|
+
result: list[str] = []
|
|
22
|
+
seen_lower: set[str] = set()
|
|
23
|
+
for name in names:
|
|
24
|
+
n = str(name).strip()
|
|
25
|
+
lower = n.lower()
|
|
26
|
+
if not n or lower in seen_lower:
|
|
27
|
+
continue
|
|
28
|
+
seen_lower.add(lower)
|
|
29
|
+
result.append(n)
|
|
30
|
+
return result
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def set_pending_auto_approved_tools(
|
|
34
|
+
session_store: AgentSessionStore | None,
|
|
35
|
+
tool_names: Iterable[str],
|
|
36
|
+
) -> None:
|
|
37
|
+
if session_store is None:
|
|
38
|
+
return
|
|
39
|
+
names = _normalize_names(tool_names)
|
|
40
|
+
if not names:
|
|
41
|
+
return
|
|
42
|
+
session_store.cache_permission(_PENDING_KEY, names)
|
|
43
|
+
session_store.append_audit(
|
|
44
|
+
{
|
|
45
|
+
"event": "tool_scope_pending_updated",
|
|
46
|
+
"pending_auto_approved": names,
|
|
47
|
+
}
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def rotate_auto_approved_window(session_store: AgentSessionStore | None) -> None:
|
|
52
|
+
"""模型调用前轮转权限窗口:pending -> active,旧 active 自动清空。"""
|
|
53
|
+
if session_store is None:
|
|
54
|
+
return
|
|
55
|
+
pending = session_store.get_cached_permission(_PENDING_KEY)
|
|
56
|
+
pending_names = _normalize_names(pending if isinstance(pending, list) else [])
|
|
57
|
+
prev_active = get_active_auto_approved_tools(session_store)
|
|
58
|
+
session_store.cache_permission(_ACTIVE_KEY, pending_names)
|
|
59
|
+
session_store.cache_permission(_PENDING_KEY, [])
|
|
60
|
+
session_store.append_audit(
|
|
61
|
+
{
|
|
62
|
+
"event": "tool_scope_window_rotated",
|
|
63
|
+
"previous_active": sorted(prev_active),
|
|
64
|
+
"active_auto_approved": pending_names,
|
|
65
|
+
}
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def get_active_auto_approved_tools(
|
|
70
|
+
session_store: AgentSessionStore | None,
|
|
71
|
+
) -> set[str]:
|
|
72
|
+
if session_store is None:
|
|
73
|
+
return set()
|
|
74
|
+
active = session_store.get_cached_permission(_ACTIVE_KEY)
|
|
75
|
+
if not isinstance(active, list):
|
|
76
|
+
return set()
|
|
77
|
+
return set(_normalize_names(active))
|
|
78
|
+
|