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,225 @@
|
|
|
1
|
+
"""
|
|
2
|
+
发往 LLM 前的 tool 消息管线修复(对齐 Claude Code `ensureToolResultPairing` 的 LangChain 子集)。
|
|
3
|
+
|
|
4
|
+
实例(消息序列在干什么)
|
|
5
|
+
------------------------
|
|
6
|
+
|
|
7
|
+
下面用简写:AI = AIMessage(含 tool_calls),T = ToolMessage(对应一次 tool 结果)。
|
|
8
|
+
|
|
9
|
+
**例 A — 同一条对话里 `call_id` 出现两次(压缩/重放后常见)**
|
|
10
|
+
|
|
11
|
+
修复前::
|
|
12
|
+
|
|
13
|
+
AI(call_id=foo) → T(foo) → AI(call_id=foo 又写一遍) → T(foo)
|
|
14
|
+
|
|
15
|
+
问题:第二次 AI 再声明 `foo`,提供商常报「tool_use id 必须唯一」。
|
|
16
|
+
|
|
17
|
+
修复后::
|
|
18
|
+
|
|
19
|
+
AI(call_id=foo) → T(foo) → AI(第二次不再带 foo) → 紧跟的那条 T(foo) 因对不上本轮 tool_calls,当孤儿删掉
|
|
20
|
+
|
|
21
|
+
(结果里只保留「第一轮」的 AI→T 配对,避免 id 重复上送 API。)
|
|
22
|
+
|
|
23
|
+
**例 B — 同一次工具结果来了两遍(同一 `call_id` 两条 T)**
|
|
24
|
+
|
|
25
|
+
修复前::
|
|
26
|
+
|
|
27
|
+
AI(call_id=bar) → T(bar, 内容A) → T(bar, 内容B)
|
|
28
|
+
|
|
29
|
+
修复后:只保留**最后一条** T(bar)(内容B)。
|
|
30
|
+
|
|
31
|
+
**例 C — AI 叫了工具但没等到结果(中断/丢消息)**
|
|
32
|
+
|
|
33
|
+
修复前::
|
|
34
|
+
|
|
35
|
+
AI(call_id=baz) → (没有 T(baz))
|
|
36
|
+
|
|
37
|
+
修复后:在 T 的位置**补一条 synthetic ToolMessage(baz)**,让下一轮模型调用合法,不 400。
|
|
38
|
+
|
|
39
|
+
**好处(为何放在 invoke 前,而不是靠提示词):**
|
|
40
|
+
- 提供商/SDK 对「同一 tool_call_id 重复」「tool_result 无对应 tool_use」「重复 tool_result」
|
|
41
|
+
往往直接 400;这是**协议约束**,与模型是否“注意”某段 System 提示无关。
|
|
42
|
+
- 在绑定模型调用前做一次确定性清洗,可避免因压缩/重放/中断导致的会话卡死,属于 **Harness 工程**,
|
|
43
|
+
而不是对模型的软劝导。
|
|
44
|
+
|
|
45
|
+
本模块只做 LangChain `AIMessage.tool_calls` + `ToolMessage` 序列可表达的修复:
|
|
46
|
+
- 跨多条 assistant 消息按**首次出现**保留 `tool_call_id`,后续重复从 `tool_calls` 中剔除;
|
|
47
|
+
- 紧跟某条 `AIMessage` 的连续 `ToolMessage` 中,同一 `tool_call_id` **只保留最后一条**;
|
|
48
|
+
- 剔除不属于当前轮 `tool_calls` 的孤儿 `ToolMessage`;
|
|
49
|
+
- 对仍缺少 `ToolMessage` 的 `tool_call`,追加与 `orphan_tool_results` 一致的 synthetic 占位。
|
|
50
|
+
|
|
51
|
+
不修改图状态:仅作用于本次 `invoke/ainvoke` 使用的消息列表副本,每次进模型都会再修一遍,
|
|
52
|
+
因此无需把修复结果写回 checkpoint 也能持续生效。
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
from __future__ import annotations
|
|
56
|
+
|
|
57
|
+
from copy import deepcopy
|
|
58
|
+
from typing import Any
|
|
59
|
+
|
|
60
|
+
from langchain_core.messages import AIMessage, ToolMessage
|
|
61
|
+
|
|
62
|
+
from .orphan_tool_results import synthetic_tool_messages_for_orphan_tool_calls
|
|
63
|
+
|
|
64
|
+
_DEFAULT_SYNTHETIC = (
|
|
65
|
+
"[Tool transcript repair: missing tool result; synthetic placeholder.]"
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _tool_call_id(tc: Any) -> str | None:
|
|
70
|
+
if isinstance(tc, dict):
|
|
71
|
+
tid = tc.get("id")
|
|
72
|
+
return str(tid) if tid is not None and str(tid) != "" else None
|
|
73
|
+
tid = getattr(tc, "id", None)
|
|
74
|
+
return str(tid) if tid is not None and str(tid) != "" else None
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _tool_call_name(tc: Any) -> str:
|
|
78
|
+
if isinstance(tc, dict):
|
|
79
|
+
n = tc.get("name")
|
|
80
|
+
return str(n) if n else "unknown_tool"
|
|
81
|
+
n = getattr(tc, "name", None)
|
|
82
|
+
return str(n) if n else "unknown_tool"
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _normalize_tool_call_dict(tc: Any) -> dict[str, Any]:
|
|
86
|
+
if isinstance(tc, dict):
|
|
87
|
+
return deepcopy(tc)
|
|
88
|
+
tid = _tool_call_id(tc)
|
|
89
|
+
return {
|
|
90
|
+
"name": _tool_call_name(tc),
|
|
91
|
+
"args": getattr(tc, "args", {}) or {},
|
|
92
|
+
"id": tid or "",
|
|
93
|
+
"type": "tool_call",
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _copy_ai_with_tool_calls(m: AIMessage, new_calls: list[dict[str, Any]]) -> AIMessage:
|
|
98
|
+
if hasattr(m, "model_copy"):
|
|
99
|
+
try:
|
|
100
|
+
return m.model_copy(update={"tool_calls": new_calls})
|
|
101
|
+
except Exception:
|
|
102
|
+
pass
|
|
103
|
+
kwargs: dict[str, Any] = {"content": m.content, "tool_calls": new_calls}
|
|
104
|
+
for key in ("additional_kwargs", "response_metadata", "usage_metadata", "id", "name"):
|
|
105
|
+
if hasattr(m, key):
|
|
106
|
+
kwargs[key] = getattr(m, key)
|
|
107
|
+
return AIMessage(**kwargs)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def repair_messages_for_llm_invoke(
|
|
111
|
+
messages: list[Any],
|
|
112
|
+
*,
|
|
113
|
+
synthetic_content_template: str = _DEFAULT_SYNTHETIC,
|
|
114
|
+
) -> tuple[list[Any], dict[str, Any]]:
|
|
115
|
+
"""返回 (修复后的消息列表, 统计信息)。输入不会被原地修改。"""
|
|
116
|
+
stats: dict[str, Any] = {
|
|
117
|
+
"repaired": False,
|
|
118
|
+
"dropped_duplicate_ai_tool_calls": 0,
|
|
119
|
+
"deduped_tool_messages": 0,
|
|
120
|
+
"dropped_orphan_tool_messages": 0,
|
|
121
|
+
"added_synthetic_tool_messages": 0,
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if not messages:
|
|
125
|
+
return [], stats
|
|
126
|
+
|
|
127
|
+
out: list[Any] = []
|
|
128
|
+
seen_global_ids: set[str] = set()
|
|
129
|
+
i = 0
|
|
130
|
+
n = len(messages)
|
|
131
|
+
|
|
132
|
+
while i < n:
|
|
133
|
+
m = messages[i]
|
|
134
|
+
if isinstance(m, AIMessage) and getattr(m, "tool_calls", None):
|
|
135
|
+
raw_calls = list(m.tool_calls)
|
|
136
|
+
new_calls: list[dict[str, Any]] = []
|
|
137
|
+
for tc in raw_calls:
|
|
138
|
+
tid = _tool_call_id(tc)
|
|
139
|
+
if not tid:
|
|
140
|
+
continue
|
|
141
|
+
if tid in seen_global_ids:
|
|
142
|
+
stats["dropped_duplicate_ai_tool_calls"] += 1
|
|
143
|
+
stats["repaired"] = True
|
|
144
|
+
continue
|
|
145
|
+
seen_global_ids.add(tid)
|
|
146
|
+
new_calls.append(_normalize_tool_call_dict(tc))
|
|
147
|
+
|
|
148
|
+
ai2 = _copy_ai_with_tool_calls(m, new_calls)
|
|
149
|
+
out.append(ai2)
|
|
150
|
+
i += 1
|
|
151
|
+
|
|
152
|
+
batch: list[ToolMessage] = []
|
|
153
|
+
while i < n and isinstance(messages[i], ToolMessage):
|
|
154
|
+
batch.append(messages[i])
|
|
155
|
+
i += 1
|
|
156
|
+
|
|
157
|
+
last_by_id: dict[str, ToolMessage] = {}
|
|
158
|
+
for tm in batch:
|
|
159
|
+
raw_tid = getattr(tm, "tool_call_id", None)
|
|
160
|
+
if raw_tid is None:
|
|
161
|
+
stats["dropped_orphan_tool_messages"] += 1
|
|
162
|
+
stats["repaired"] = True
|
|
163
|
+
continue
|
|
164
|
+
tid = str(raw_tid)
|
|
165
|
+
if tid in last_by_id:
|
|
166
|
+
stats["deduped_tool_messages"] += 1
|
|
167
|
+
stats["repaired"] = True
|
|
168
|
+
last_by_id[tid] = tm
|
|
169
|
+
|
|
170
|
+
valid_ids = {tid for tid in (_tool_call_id(tc) for tc in new_calls) if tid}
|
|
171
|
+
|
|
172
|
+
for tm in batch:
|
|
173
|
+
raw_tid = getattr(tm, "tool_call_id", None)
|
|
174
|
+
if raw_tid is None:
|
|
175
|
+
continue
|
|
176
|
+
if str(raw_tid) not in valid_ids:
|
|
177
|
+
stats["dropped_orphan_tool_messages"] += 1
|
|
178
|
+
stats["repaired"] = True
|
|
179
|
+
|
|
180
|
+
ordered_tool_messages: list[ToolMessage] = []
|
|
181
|
+
for tc in new_calls:
|
|
182
|
+
tid = _tool_call_id(tc)
|
|
183
|
+
if not tid or tid not in valid_ids:
|
|
184
|
+
continue
|
|
185
|
+
if tid not in last_by_id:
|
|
186
|
+
continue
|
|
187
|
+
ordered_tool_messages.append(last_by_id[tid])
|
|
188
|
+
|
|
189
|
+
result_ids = {
|
|
190
|
+
str(tm.tool_call_id)
|
|
191
|
+
for tm in ordered_tool_messages
|
|
192
|
+
if getattr(tm, "tool_call_id", None) is not None
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
for tm in ordered_tool_messages:
|
|
196
|
+
out.append(tm)
|
|
197
|
+
|
|
198
|
+
pending_dicts: list[dict[str, Any]] = []
|
|
199
|
+
for tc in new_calls:
|
|
200
|
+
tid = _tool_call_id(tc)
|
|
201
|
+
if tid and tid not in result_ids:
|
|
202
|
+
pending_dicts.append({"id": tid, "name": _tool_call_name(tc)})
|
|
203
|
+
if pending_dicts:
|
|
204
|
+
synth = synthetic_tool_messages_for_orphan_tool_calls(
|
|
205
|
+
pending_tool_calls=pending_dicts,
|
|
206
|
+
content_template=synthetic_content_template,
|
|
207
|
+
)
|
|
208
|
+
out.extend(synth)
|
|
209
|
+
stats["added_synthetic_tool_messages"] += len(synth)
|
|
210
|
+
stats["repaired"] = True
|
|
211
|
+
continue
|
|
212
|
+
|
|
213
|
+
if isinstance(m, ToolMessage):
|
|
214
|
+
stats["dropped_orphan_tool_messages"] += 1
|
|
215
|
+
stats["repaired"] = True
|
|
216
|
+
i += 1
|
|
217
|
+
continue
|
|
218
|
+
|
|
219
|
+
out.append(m)
|
|
220
|
+
i += 1
|
|
221
|
+
|
|
222
|
+
return out, stats
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
__all__ = ["repair_messages_for_llm_invoke"]
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""loop.prompt — 系统提示词管理。
|
|
2
|
+
|
|
3
|
+
提供三层能力:
|
|
4
|
+
1. Section 注册表(sections.py)— 段的定义、记忆化、解析
|
|
5
|
+
2. 优先级链(builder.py)— override → base → sections → append
|
|
6
|
+
3. 内置 section 工厂(builtin.py)— 环境信息、语言偏好、时间、Git 安全等
|
|
7
|
+
4. 压缩提示词(compact.py)— 上下文压缩用的提示词模板与格式化
|
|
8
|
+
|
|
9
|
+
公开 API:
|
|
10
|
+
# 核心机制
|
|
11
|
+
SystemPromptSection — 段数据类
|
|
12
|
+
section() — 创建 session 级缓存的提示词段
|
|
13
|
+
volatile_section() — 创建每轮重算的提示词段
|
|
14
|
+
resolve_sections() — 解析段列表,返回文本列表
|
|
15
|
+
build_effective_system_prompt() — 优先级链构建器
|
|
16
|
+
|
|
17
|
+
# 内置 section 工厂
|
|
18
|
+
env_section() — 环境信息(OS/Python/工作目录)
|
|
19
|
+
language_section() — 语言偏好
|
|
20
|
+
time_section() — 当前时间(volatile)
|
|
21
|
+
token_budget_section() — Token 预算提示
|
|
22
|
+
git_safety_section() — Git 安全红线(禁止 force-push 等危险操作)
|
|
23
|
+
tool_routing_guard_section() — 专用工具优先(系统级冗余强化)
|
|
24
|
+
actions_safety_section() — 高风险动作确认与可逆性优先
|
|
25
|
+
failure_diagnosis_section() — 失败后先诊断,不盲重试
|
|
26
|
+
task_execution_baseline_section() — 任务执行基线(先读后改、忠实汇报)
|
|
27
|
+
get_coding_sections() — 编码场景推荐 section 组合
|
|
28
|
+
tools_summary_section() — 工具列表摘要(volatile)
|
|
29
|
+
|
|
30
|
+
# 压缩提示词
|
|
31
|
+
get_compact_prompt() — 全量压缩提示词
|
|
32
|
+
get_partial_compact_prompt() — 部分压缩提示词
|
|
33
|
+
build_autocompact_llm_instruction_prompt() — 按类型选择压缩提示词
|
|
34
|
+
format_compact_summary() — 格式化压缩摘要
|
|
35
|
+
get_compact_user_summary_message() — 用户续写消息包装
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
from .builder import build_effective_system_prompt
|
|
39
|
+
from .builtin import (
|
|
40
|
+
env_section,
|
|
41
|
+
actions_safety_section,
|
|
42
|
+
failure_diagnosis_section,
|
|
43
|
+
get_coding_sections,
|
|
44
|
+
git_safety_section,
|
|
45
|
+
language_section,
|
|
46
|
+
task_execution_baseline_section,
|
|
47
|
+
time_section,
|
|
48
|
+
token_budget_section,
|
|
49
|
+
tool_routing_guard_section,
|
|
50
|
+
tools_summary_section,
|
|
51
|
+
)
|
|
52
|
+
from .compact import (
|
|
53
|
+
AutocompactLlmPromptKind,
|
|
54
|
+
PartialCompactDirection,
|
|
55
|
+
build_autocompact_llm_instruction_prompt,
|
|
56
|
+
format_compact_summary,
|
|
57
|
+
get_compact_prompt,
|
|
58
|
+
get_compact_user_summary_message,
|
|
59
|
+
get_partial_compact_prompt,
|
|
60
|
+
)
|
|
61
|
+
from .sections import (
|
|
62
|
+
SystemPromptSection,
|
|
63
|
+
resolve_sections,
|
|
64
|
+
section,
|
|
65
|
+
volatile_section,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
__all__ = [
|
|
69
|
+
# 核心机制
|
|
70
|
+
"SystemPromptSection",
|
|
71
|
+
"section",
|
|
72
|
+
"volatile_section",
|
|
73
|
+
"resolve_sections",
|
|
74
|
+
"build_effective_system_prompt",
|
|
75
|
+
# 内置 section 工厂
|
|
76
|
+
"actions_safety_section",
|
|
77
|
+
"env_section",
|
|
78
|
+
"failure_diagnosis_section",
|
|
79
|
+
"get_coding_sections",
|
|
80
|
+
"git_safety_section",
|
|
81
|
+
"language_section",
|
|
82
|
+
"task_execution_baseline_section",
|
|
83
|
+
"time_section",
|
|
84
|
+
"token_budget_section",
|
|
85
|
+
"tool_routing_guard_section",
|
|
86
|
+
"tools_summary_section",
|
|
87
|
+
# 压缩提示词
|
|
88
|
+
"AutocompactLlmPromptKind",
|
|
89
|
+
"PartialCompactDirection",
|
|
90
|
+
"get_compact_prompt",
|
|
91
|
+
"get_partial_compact_prompt",
|
|
92
|
+
"build_autocompact_llm_instruction_prompt",
|
|
93
|
+
"format_compact_summary",
|
|
94
|
+
"get_compact_user_summary_message",
|
|
95
|
+
]
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""系统提示词优先级链构建器。
|
|
2
|
+
|
|
3
|
+
对标 Claude Code:
|
|
4
|
+
buildEffectiveSystemPrompt() → build_effective_system_prompt()
|
|
5
|
+
|
|
6
|
+
优先级(从高到低):
|
|
7
|
+
1. override_system_prompt — 存在时直接返回,完全忽略其他所有来源
|
|
8
|
+
2. system_prompt — 基础提示词
|
|
9
|
+
3. dynamic_sections — session 级动态段(按列表顺序追加)
|
|
10
|
+
4. append_system_prompt — 追加在最后
|
|
11
|
+
|
|
12
|
+
注意:override 存在时,append_system_prompt 同样被忽略(与 CC 行为一致)。
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from .sections import SystemPromptSection, resolve_sections
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def build_effective_system_prompt(
|
|
21
|
+
*,
|
|
22
|
+
system_prompt: str | None,
|
|
23
|
+
override_system_prompt: str | None,
|
|
24
|
+
append_system_prompt: str | None,
|
|
25
|
+
dynamic_sections: list[SystemPromptSection],
|
|
26
|
+
section_cache: dict[str, str | None],
|
|
27
|
+
) -> str | None:
|
|
28
|
+
"""构建当前轮次实际生效的系统提示词字符串。
|
|
29
|
+
|
|
30
|
+
优先级规则:
|
|
31
|
+
1. override 存在 → 直接返回,其余全部忽略(含 append)。
|
|
32
|
+
2. 否则:base + sections + append 按顺序拼接,段间以双换行分隔。
|
|
33
|
+
3. 全部为空 → 返回 None(不注入系统消息)。
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
system_prompt: 基础提示词字符串(已由 factory 从 str|SystemMessage 转换)。
|
|
37
|
+
override_system_prompt: 最高优先级覆盖提示词,存在时完全替换其他来源。
|
|
38
|
+
append_system_prompt: 追加在有效提示词末尾的字符串(override 时不追加)。
|
|
39
|
+
dynamic_sections: session 级动态段列表,由 resolve_sections 解析。
|
|
40
|
+
section_cache: 来自 AgentState.section_cache,session 生命周期,
|
|
41
|
+
函数内部通过 resolve_sections 原地更新。
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
最终的系统提示词字符串,或 None(不注入任何系统消息)。
|
|
45
|
+
"""
|
|
46
|
+
# 优先级 1:override 直接返回
|
|
47
|
+
if override_system_prompt is not None:
|
|
48
|
+
return override_system_prompt
|
|
49
|
+
|
|
50
|
+
# 优先级 2-3:解析动态 sections(session 级记忆化)
|
|
51
|
+
section_texts = resolve_sections(dynamic_sections, section_cache)
|
|
52
|
+
|
|
53
|
+
# 优先级 4:拼装 base + sections + append
|
|
54
|
+
parts: list[str] = []
|
|
55
|
+
if system_prompt:
|
|
56
|
+
parts.append(system_prompt)
|
|
57
|
+
parts.extend(section_texts)
|
|
58
|
+
if append_system_prompt:
|
|
59
|
+
parts.append(append_system_prompt)
|
|
60
|
+
|
|
61
|
+
return "\n\n".join(parts) if parts else None
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
"""内置 SystemPromptSection 工厂函数。
|
|
2
|
+
|
|
3
|
+
提供框架级常用 section,供 create_loop_agent 与容器层组合使用。
|
|
4
|
+
|
|
5
|
+
设计原则:
|
|
6
|
+
- 每个工厂函数返回一个 SystemPromptSection
|
|
7
|
+
- volatile=False 的 section 在 session 内只计算一次(环境信息、语言偏好等)
|
|
8
|
+
- volatile=True 的 section 每轮重算(当前时间、动态工具列表等)
|
|
9
|
+
- 所有文本内容写在代码中(暂不引入 templates/ 目录)
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import platform
|
|
15
|
+
from datetime import datetime
|
|
16
|
+
from typing import TYPE_CHECKING
|
|
17
|
+
|
|
18
|
+
from .sections import SystemPromptSection, section, volatile_section
|
|
19
|
+
|
|
20
|
+
if TYPE_CHECKING:
|
|
21
|
+
from typing import Any
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def env_section() -> SystemPromptSection:
|
|
25
|
+
"""环境信息 section(session 级缓存)。
|
|
26
|
+
|
|
27
|
+
包含:操作系统、Python 版本、工作目录。
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def compute() -> str:
|
|
31
|
+
import os
|
|
32
|
+
|
|
33
|
+
return f"""# Environment
|
|
34
|
+
You have been invoked in the following environment:
|
|
35
|
+
- Platform: {platform.system().lower()}
|
|
36
|
+
- OS Version: {platform.platform()}
|
|
37
|
+
- Python: {platform.python_version()}
|
|
38
|
+
- Working Directory: {os.getcwd()}"""
|
|
39
|
+
|
|
40
|
+
return section(name="env_info", compute=compute)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def language_section(lang: str = "en") -> SystemPromptSection:
|
|
44
|
+
"""语言偏好 section(session 级缓存)。
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
lang: 语言代码("en" / "zh" / "ja" 等)
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
def compute() -> str | None:
|
|
51
|
+
if lang == "en":
|
|
52
|
+
return None # 默认英文,不注入额外提示
|
|
53
|
+
if lang == "zh":
|
|
54
|
+
return "# Language\nRespond in Simplified Chinese (简体中文) unless the user explicitly requests another language."
|
|
55
|
+
if lang == "ja":
|
|
56
|
+
return "# Language\nRespond in Japanese (日本語) unless the user explicitly requests another language."
|
|
57
|
+
# 其他语言可按需扩展
|
|
58
|
+
return f"# Language\nRespond in {lang} unless the user explicitly requests another language."
|
|
59
|
+
|
|
60
|
+
return section(name="language", compute=compute)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def time_section() -> SystemPromptSection:
|
|
64
|
+
"""当前时间 section(volatile,每轮重算)。
|
|
65
|
+
|
|
66
|
+
用于需要时间感知的场景(如日志分析、时间敏感任务)。
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
def compute() -> str:
|
|
70
|
+
now = datetime.now()
|
|
71
|
+
return f"""# Current Time
|
|
72
|
+
Current date and time: {now.strftime('%Y-%m-%d %H:%M:%S')}"""
|
|
73
|
+
|
|
74
|
+
return volatile_section(
|
|
75
|
+
name="current_time",
|
|
76
|
+
compute=compute,
|
|
77
|
+
reason="时间每轮变化,不能缓存",
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def token_budget_section(limit: int) -> SystemPromptSection:
|
|
82
|
+
"""Token 预算提示 section(session 级缓存)。
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
limit: Token 预算上限
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
def compute() -> str:
|
|
89
|
+
return f"""# Token Budget
|
|
90
|
+
You have a token budget of approximately {limit:,} tokens for this conversation. Be concise and efficient in your responses."""
|
|
91
|
+
|
|
92
|
+
return section(name="token_budget", compute=compute)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def git_safety_section() -> SystemPromptSection:
|
|
96
|
+
"""Git 安全红线 section(session 级缓存)。
|
|
97
|
+
|
|
98
|
+
说明:
|
|
99
|
+
- 该 section 仅提供规则文本,不负责决定是否注入。
|
|
100
|
+
- 是否启用由调用方在 dynamic_sections 装配阶段决定(例如编码模式下启用)。
|
|
101
|
+
"""
|
|
102
|
+
|
|
103
|
+
def compute() -> str:
|
|
104
|
+
return """# Git Safety Protocol
|
|
105
|
+
When using git-related commands, follow these safety constraints:
|
|
106
|
+
- NEVER update git config unless the user explicitly requests it.
|
|
107
|
+
- NEVER run destructive commands (e.g. push --force, reset --hard, checkout --, restore ., clean -f, branch -D) unless the user explicitly requests them.
|
|
108
|
+
- NEVER skip hooks or signing checks (--no-verify, --no-gpg-sign, etc.) unless the user explicitly requests it.
|
|
109
|
+
- NEVER force-push to main/master; warn the user if they request it.
|
|
110
|
+
- Prefer creating a new commit instead of amending. If pre-commit hooks fail, fix issues and create a new commit rather than amending a previous commit.
|
|
111
|
+
- Prefer safer alternatives before destructive operations."""
|
|
112
|
+
|
|
113
|
+
return section(name="git_safety", compute=compute)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def tool_routing_guard_section() -> SystemPromptSection:
|
|
117
|
+
"""系统级工具路由护栏 section(session 级缓存)。
|
|
118
|
+
|
|
119
|
+
作用:对 Bash 工具描述中的“专用工具优先”规则做冗余强化(defense in depth)。
|
|
120
|
+
"""
|
|
121
|
+
|
|
122
|
+
def compute() -> str:
|
|
123
|
+
return """# Dedicated Tool Routing (Critical)
|
|
124
|
+
Do NOT use bash when a relevant dedicated tool is available.
|
|
125
|
+
Using dedicated tools improves user reviewability and execution safety.
|
|
126
|
+
|
|
127
|
+
- To read files, use read_file instead of cat/head/tail.
|
|
128
|
+
- To search file content, use grep instead of grep/rg via bash.
|
|
129
|
+
- To search files by pattern, use glob instead of find/ls.
|
|
130
|
+
- Reserve bash primarily for terminal operations that require shell execution (e.g., git/gh/system commands)."""
|
|
131
|
+
|
|
132
|
+
return section(name="tool_routing_guard", compute=compute)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def actions_safety_section() -> SystemPromptSection:
|
|
136
|
+
"""高风险操作确认与可逆性优先 section(session 级缓存)。"""
|
|
137
|
+
|
|
138
|
+
def compute() -> str:
|
|
139
|
+
return """# Executing Actions With Care
|
|
140
|
+
Carefully consider reversibility and blast radius before acting.
|
|
141
|
+
|
|
142
|
+
- Prefer local and reversible actions by default.
|
|
143
|
+
- For risky or hard-to-reverse actions, confirm with the user before proceeding.
|
|
144
|
+
- Do not use destructive commands as shortcuts when blocked; diagnose root causes first.
|
|
145
|
+
- If you encounter unexpected state, investigate before deleting or overwriting."""
|
|
146
|
+
|
|
147
|
+
return section(name="actions_safety", compute=compute)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def failure_diagnosis_section() -> SystemPromptSection:
|
|
151
|
+
"""失败诊断优先 section(session 级缓存)。"""
|
|
152
|
+
|
|
153
|
+
def compute() -> str:
|
|
154
|
+
return """# Failure Diagnosis
|
|
155
|
+
If an approach fails, diagnose why before switching tactics.
|
|
156
|
+
|
|
157
|
+
- Read the error and verify assumptions.
|
|
158
|
+
- Do not blindly retry the exact same failing action.
|
|
159
|
+
- Prefer a focused fix over broad destructive workarounds."""
|
|
160
|
+
|
|
161
|
+
return section(name="failure_diagnosis", compute=compute)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def task_execution_baseline_section() -> SystemPromptSection:
|
|
165
|
+
"""任务执行基线 section(session 级缓存)。"""
|
|
166
|
+
|
|
167
|
+
def compute() -> str:
|
|
168
|
+
return """# Task Execution Baseline
|
|
169
|
+
- Understand first: read relevant files and existing patterns before changing code.
|
|
170
|
+
- Keep scope tight: avoid adding features or abstractions beyond the request.
|
|
171
|
+
- Report outcomes faithfully: if checks fail, say they fail; if not run, say not run."""
|
|
172
|
+
|
|
173
|
+
return section(name="task_execution_baseline", compute=compute)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def get_coding_sections() -> list[SystemPromptSection]:
|
|
177
|
+
"""编码场景推荐 section 组合(仅返回列表,是否注入由调用方决定)。"""
|
|
178
|
+
return [
|
|
179
|
+
tool_routing_guard_section(),
|
|
180
|
+
git_safety_section(),
|
|
181
|
+
actions_safety_section(),
|
|
182
|
+
failure_diagnosis_section(),
|
|
183
|
+
task_execution_baseline_section(),
|
|
184
|
+
]
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def tools_summary_section(tools: list[Any]) -> SystemPromptSection:
|
|
188
|
+
"""工具列表摘要 section(volatile,工具可能动态变化)。
|
|
189
|
+
|
|
190
|
+
Args:
|
|
191
|
+
tools: 当前可用的工具列表
|
|
192
|
+
"""
|
|
193
|
+
|
|
194
|
+
def compute() -> str:
|
|
195
|
+
tool_names = [getattr(t, "name", str(t)) for t in tools]
|
|
196
|
+
return f"""# Available Tools
|
|
197
|
+
You have access to the following tools: {', '.join(tool_names)}"""
|
|
198
|
+
|
|
199
|
+
return volatile_section(
|
|
200
|
+
name="tools_summary",
|
|
201
|
+
compute=compute,
|
|
202
|
+
reason="工具列表可能在 session 中动态变化(Skill 激活/MCP 加载)",
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
__all__ = [
|
|
207
|
+
"actions_safety_section",
|
|
208
|
+
"env_section",
|
|
209
|
+
"failure_diagnosis_section",
|
|
210
|
+
"get_coding_sections",
|
|
211
|
+
"git_safety_section",
|
|
212
|
+
"language_section",
|
|
213
|
+
"task_execution_baseline_section",
|
|
214
|
+
"time_section",
|
|
215
|
+
"token_budget_section",
|
|
216
|
+
"tool_routing_guard_section",
|
|
217
|
+
"tools_summary_section",
|
|
218
|
+
]
|