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,156 @@
|
|
|
1
|
+
"""
|
|
2
|
+
session/conversation_recovery.py — 会话恢复入口编排。
|
|
3
|
+
|
|
4
|
+
职责:
|
|
5
|
+
从 transcript store 读取并清洗消息,重建为可用于 resume 的 BaseMessage 链。
|
|
6
|
+
|
|
7
|
+
链路位置:
|
|
8
|
+
为 AgentSession/ConversationSession 提供恢复前置能力。
|
|
9
|
+
|
|
10
|
+
当前裁剪范围:
|
|
11
|
+
覆盖 compact 边界定位、unresolved tool_use 过滤、空白 assistant 过滤。
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
from dataclasses import dataclass, field
|
|
17
|
+
from typing import Any
|
|
18
|
+
|
|
19
|
+
from langchain_core.messages import AIMessage, BaseMessage, HumanMessage, SystemMessage, ToolMessage
|
|
20
|
+
|
|
21
|
+
from ..loop.subagent.transcript import SubagentTranscriptStore
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class CompactBoundaryLocator:
|
|
26
|
+
"""定位最后一个 compact_boundary 之后的恢复起点。"""
|
|
27
|
+
|
|
28
|
+
def find_resume_start(self, records: list[dict[str, Any]]) -> int:
|
|
29
|
+
last_boundary = -1
|
|
30
|
+
for idx, record in enumerate(records):
|
|
31
|
+
if record.get("type") == "compact_boundary":
|
|
32
|
+
last_boundary = idx
|
|
33
|
+
if last_boundary < 0:
|
|
34
|
+
return 0
|
|
35
|
+
return last_boundary + 1
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@dataclass
|
|
39
|
+
class RecoveryMessageFilter:
|
|
40
|
+
"""恢复前消息过滤器。"""
|
|
41
|
+
|
|
42
|
+
def filter_records(self, records: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
|
43
|
+
resolved_tool_ids = self._collect_resolved_tool_ids(records)
|
|
44
|
+
kept: list[dict[str, Any]] = []
|
|
45
|
+
valid_ai_tool_ids: set[str] = set()
|
|
46
|
+
for record in records:
|
|
47
|
+
record_type = str(record.get("type", ""))
|
|
48
|
+
if record_type == "compact_boundary":
|
|
49
|
+
continue
|
|
50
|
+
if self._is_blank_assistant(record):
|
|
51
|
+
continue
|
|
52
|
+
if self._is_unresolved_tool_use(record, resolved_tool_ids):
|
|
53
|
+
continue
|
|
54
|
+
if record_type in {"ai", "assistant"}:
|
|
55
|
+
for tool_call_id in self._extract_tool_call_ids(record):
|
|
56
|
+
valid_ai_tool_ids.add(tool_call_id)
|
|
57
|
+
if record_type in {"tool", "tool_result"}:
|
|
58
|
+
call_id = str(record.get("tool_call_id", ""))
|
|
59
|
+
if call_id and call_id not in valid_ai_tool_ids:
|
|
60
|
+
continue
|
|
61
|
+
kept.append(record)
|
|
62
|
+
return kept
|
|
63
|
+
|
|
64
|
+
def _collect_resolved_tool_ids(self, records: list[dict[str, Any]]) -> set[str]:
|
|
65
|
+
resolved: set[str] = set()
|
|
66
|
+
for record in records:
|
|
67
|
+
record_type = str(record.get("type", ""))
|
|
68
|
+
if record_type not in {"tool", "tool_result"}:
|
|
69
|
+
continue
|
|
70
|
+
call_id = str(record.get("tool_call_id", ""))
|
|
71
|
+
if call_id:
|
|
72
|
+
resolved.add(call_id)
|
|
73
|
+
return resolved
|
|
74
|
+
|
|
75
|
+
def _is_unresolved_tool_use(self, record: dict[str, Any], resolved_ids: set[str]) -> bool:
|
|
76
|
+
record_type = str(record.get("type", ""))
|
|
77
|
+
if record_type not in {"ai", "assistant"}:
|
|
78
|
+
return False
|
|
79
|
+
tool_call_ids = self._extract_tool_call_ids(record)
|
|
80
|
+
if not tool_call_ids:
|
|
81
|
+
return False
|
|
82
|
+
return any(tool_call_id not in resolved_ids for tool_call_id in tool_call_ids)
|
|
83
|
+
|
|
84
|
+
@staticmethod
|
|
85
|
+
def _extract_tool_call_ids(record: dict[str, Any]) -> list[str]:
|
|
86
|
+
tool_calls = record.get("tool_calls")
|
|
87
|
+
if not isinstance(tool_calls, list):
|
|
88
|
+
return []
|
|
89
|
+
ids: list[str] = []
|
|
90
|
+
for call in tool_calls:
|
|
91
|
+
if not isinstance(call, dict):
|
|
92
|
+
continue
|
|
93
|
+
call_id = call.get("id")
|
|
94
|
+
if isinstance(call_id, str) and call_id:
|
|
95
|
+
ids.append(call_id)
|
|
96
|
+
return ids
|
|
97
|
+
|
|
98
|
+
@staticmethod
|
|
99
|
+
def _is_blank_assistant(record: dict[str, Any]) -> bool:
|
|
100
|
+
record_type = str(record.get("type", ""))
|
|
101
|
+
if record_type not in {"ai", "assistant"}:
|
|
102
|
+
return False
|
|
103
|
+
content = record.get("content")
|
|
104
|
+
if isinstance(content, str):
|
|
105
|
+
return content.strip() == ""
|
|
106
|
+
return False
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@dataclass
|
|
110
|
+
class SessionRecoveryLoader:
|
|
111
|
+
"""恢复加载器:读取 -> 定位 -> 过滤 -> 反序列化。"""
|
|
112
|
+
|
|
113
|
+
boundary_locator: CompactBoundaryLocator = field(default_factory=CompactBoundaryLocator)
|
|
114
|
+
message_filter: RecoveryMessageFilter = field(default_factory=RecoveryMessageFilter)
|
|
115
|
+
|
|
116
|
+
def load_session_messages(
|
|
117
|
+
self,
|
|
118
|
+
transcript_store: SubagentTranscriptStore,
|
|
119
|
+
session_id: str,
|
|
120
|
+
) -> list[BaseMessage]:
|
|
121
|
+
raw = transcript_store.read_transcript(session_id)
|
|
122
|
+
start_index = self.boundary_locator.find_resume_start(raw)
|
|
123
|
+
tail = raw[start_index:]
|
|
124
|
+
filtered = self.message_filter.filter_records(tail)
|
|
125
|
+
return [self._deserialize_record(record) for record in filtered]
|
|
126
|
+
|
|
127
|
+
def _deserialize_record(self, record: dict[str, Any]) -> BaseMessage:
|
|
128
|
+
record_type = str(record.get("type") or record.get("role") or "")
|
|
129
|
+
content = record.get("content", "")
|
|
130
|
+
normalized_content = content if isinstance(content, str) else str(content)
|
|
131
|
+
if record_type in {"human", "user"}:
|
|
132
|
+
return HumanMessage(content=normalized_content)
|
|
133
|
+
if record_type in {"system"}:
|
|
134
|
+
return SystemMessage(content=normalized_content)
|
|
135
|
+
if record_type in {"tool", "tool_result"}:
|
|
136
|
+
tool_call_id = str(record.get("tool_call_id", "recovered-tool-call"))
|
|
137
|
+
name = str(record.get("name", "tool"))
|
|
138
|
+
return ToolMessage(content=normalized_content, tool_call_id=tool_call_id, name=name)
|
|
139
|
+
return AIMessage(content=normalized_content)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def load_session_messages(
|
|
143
|
+
transcript_store: SubagentTranscriptStore,
|
|
144
|
+
session_id: str,
|
|
145
|
+
) -> list[BaseMessage]:
|
|
146
|
+
"""便捷函数:使用默认 loader 恢复消息。"""
|
|
147
|
+
return SessionRecoveryLoader().load_session_messages(transcript_store, session_id)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
__all__ = [
|
|
151
|
+
"CompactBoundaryLocator",
|
|
152
|
+
"RecoveryMessageFilter",
|
|
153
|
+
"SessionRecoveryLoader",
|
|
154
|
+
"load_session_messages",
|
|
155
|
+
]
|
|
156
|
+
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"""
|
|
2
|
+
session/conversation_session.py — 对话窗口级 Session 容器。
|
|
3
|
+
|
|
4
|
+
职责:
|
|
5
|
+
管理单个对话窗口生命周期(session_start/end),每次请求新建 graph。
|
|
6
|
+
|
|
7
|
+
链路位置:
|
|
8
|
+
作为 Web/IM 对话场景的外层容器,与 AgentSession 并列。
|
|
9
|
+
|
|
10
|
+
当前裁剪范围:
|
|
11
|
+
覆盖最小生命周期与 run_turn 入口;memory manager 可选注入。
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import inspect
|
|
17
|
+
import logging
|
|
18
|
+
from typing import Any, Callable
|
|
19
|
+
|
|
20
|
+
from langchain_core.messages import HumanMessage
|
|
21
|
+
from langgraph.graph.state import CompiledStateGraph
|
|
22
|
+
|
|
23
|
+
from ..command import CommandContext, CommandDispatcher, CommandRegistry
|
|
24
|
+
from ..command.builtin import (
|
|
25
|
+
make_clear_command,
|
|
26
|
+
make_compact_command,
|
|
27
|
+
make_memory_command,
|
|
28
|
+
make_reload_plugins_command,
|
|
29
|
+
)
|
|
30
|
+
from ..loop.context.compaction_service import default_loop_context_compaction
|
|
31
|
+
from ..loop.context.message_utils import total_estimated_tokens_for_messages
|
|
32
|
+
from ..loop.hook.types import HookContext, HookEvent
|
|
33
|
+
from ..memory.memdir.agent_memory import drain_pending_agent_memory_extraction
|
|
34
|
+
from ..memory.memdir.extractor import drain_pending_extraction
|
|
35
|
+
from ..plugin.loader import PluginLoader
|
|
36
|
+
from ..plugin.registries import AgentRegistry, CommandRegistry as PluginCommandRegistry, SkillRegistry
|
|
37
|
+
from ..plugin.types import PluginLoadResult
|
|
38
|
+
from ..workspace.config import AgentWorkspaceConfig
|
|
39
|
+
|
|
40
|
+
logger = logging.getLogger(__name__)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class ConversationSession:
|
|
44
|
+
"""对话窗口级 session 容器。graph 每次请求新建,不复用。"""
|
|
45
|
+
|
|
46
|
+
def __init__(
|
|
47
|
+
self,
|
|
48
|
+
graph_factory: Callable[..., CompiledStateGraph],
|
|
49
|
+
conversation_id: str,
|
|
50
|
+
workspace_cfg: AgentWorkspaceConfig,
|
|
51
|
+
hook_engine: Any,
|
|
52
|
+
plugin_loader: PluginLoader | None = None,
|
|
53
|
+
initial_messages: list[Any] | None = None,
|
|
54
|
+
) -> None:
|
|
55
|
+
self._graph_factory = graph_factory
|
|
56
|
+
self._conversation_id = conversation_id
|
|
57
|
+
self._workspace_cfg = workspace_cfg
|
|
58
|
+
self._hook_engine = hook_engine
|
|
59
|
+
self._messages: list[Any] = list(initial_messages or [])
|
|
60
|
+
self._container_type = "conversation"
|
|
61
|
+
self._session_memory_manager: Any | None = None
|
|
62
|
+
self._skill_registry = SkillRegistry()
|
|
63
|
+
self._command_registry = PluginCommandRegistry()
|
|
64
|
+
self._agent_registry = AgentRegistry()
|
|
65
|
+
self._runtime_command_registry = CommandRegistry()
|
|
66
|
+
self._register_builtin_commands()
|
|
67
|
+
self._dispatcher = CommandDispatcher(
|
|
68
|
+
self._runtime_command_registry,
|
|
69
|
+
plugin_command_registry=self._command_registry,
|
|
70
|
+
)
|
|
71
|
+
self._plugin_loader: PluginLoader | None
|
|
72
|
+
if not workspace_cfg.plugins_enabled:
|
|
73
|
+
self._plugin_loader = None
|
|
74
|
+
else:
|
|
75
|
+
self._plugin_loader = plugin_loader or PluginLoader(
|
|
76
|
+
workspace_config=workspace_cfg,
|
|
77
|
+
hook_engine=hook_engine,
|
|
78
|
+
skill_registry=self._skill_registry,
|
|
79
|
+
command_registry=self._command_registry,
|
|
80
|
+
agent_registry=self._agent_registry,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
async def __aenter__(self) -> "ConversationSession":
|
|
84
|
+
if self._plugin_loader is not None:
|
|
85
|
+
load_result = await self._plugin_loader.load_all(container_type="conversation")
|
|
86
|
+
load_result.log_errors(logger)
|
|
87
|
+
await self._execute_hook(HookEvent.SESSION_START)
|
|
88
|
+
return self
|
|
89
|
+
|
|
90
|
+
async def __aexit__(self, *_) -> None:
|
|
91
|
+
if self._session_memory_manager is not None:
|
|
92
|
+
await self._session_memory_manager.drain(timeout=30.0)
|
|
93
|
+
await drain_pending_extraction(timeout_ms=60_000)
|
|
94
|
+
await drain_pending_agent_memory_extraction(timeout_ms=60_000)
|
|
95
|
+
await self._execute_hook(HookEvent.SESSION_END)
|
|
96
|
+
if self._plugin_loader is not None:
|
|
97
|
+
await self._plugin_loader.unload_all()
|
|
98
|
+
|
|
99
|
+
async def run_turn(self, user_input: str) -> dict[str, Any]:
|
|
100
|
+
"""每次用户请求调用一次,graph 每次新建。"""
|
|
101
|
+
appended_message = HumanMessage(content=user_input)
|
|
102
|
+
self._messages.append(appended_message)
|
|
103
|
+
graph = self._graph_factory(
|
|
104
|
+
session_id=self._conversation_id,
|
|
105
|
+
container_type="conversation",
|
|
106
|
+
)
|
|
107
|
+
try:
|
|
108
|
+
result = await graph.ainvoke(
|
|
109
|
+
{
|
|
110
|
+
"messages": list(self._messages),
|
|
111
|
+
"_session_id": self._conversation_id,
|
|
112
|
+
}
|
|
113
|
+
)
|
|
114
|
+
except Exception:
|
|
115
|
+
# 回滚本轮 append,避免异常路径消息重复累积。
|
|
116
|
+
if self._messages and self._messages[-1] is appended_message:
|
|
117
|
+
self._messages.pop()
|
|
118
|
+
raise
|
|
119
|
+
if isinstance(result, dict) and isinstance(result.get("messages"), list):
|
|
120
|
+
self._messages = list(result["messages"])
|
|
121
|
+
return dict(result) if isinstance(result, dict) else {"result": result}
|
|
122
|
+
|
|
123
|
+
@property
|
|
124
|
+
def conversation_id(self) -> str:
|
|
125
|
+
return self._conversation_id
|
|
126
|
+
|
|
127
|
+
@property
|
|
128
|
+
def dispatcher(self) -> CommandDispatcher:
|
|
129
|
+
return self._dispatcher
|
|
130
|
+
|
|
131
|
+
def clear_context(self) -> None:
|
|
132
|
+
self._messages.clear()
|
|
133
|
+
|
|
134
|
+
async def compact_context(self) -> tuple[int, int]:
|
|
135
|
+
before_tokens = total_estimated_tokens_for_messages(self._messages, num_chars_per_token=4)
|
|
136
|
+
patch = default_loop_context_compaction().run({"messages": self._messages})
|
|
137
|
+
if isinstance(patch.get("messages"), list):
|
|
138
|
+
self._messages = list(patch["messages"])
|
|
139
|
+
after_tokens = total_estimated_tokens_for_messages(self._messages, num_chars_per_token=4)
|
|
140
|
+
return before_tokens, after_tokens
|
|
141
|
+
|
|
142
|
+
async def reload_plugins(self) -> PluginLoadResult:
|
|
143
|
+
if self._plugin_loader is None:
|
|
144
|
+
return PluginLoadResult(enabled=[], errors=[])
|
|
145
|
+
result = await self._plugin_loader.reload(container_type=self._container_type)
|
|
146
|
+
result.log_errors(logger)
|
|
147
|
+
return result
|
|
148
|
+
|
|
149
|
+
def get_memory_summary(self, sub_cmd: str = "show") -> str:
|
|
150
|
+
memory_path = self._workspace_cfg.session_memory_path(self._conversation_id)
|
|
151
|
+
if sub_cmd == "clear":
|
|
152
|
+
if memory_path.exists():
|
|
153
|
+
memory_path.unlink()
|
|
154
|
+
return "记忆已清除"
|
|
155
|
+
if not memory_path.exists():
|
|
156
|
+
return "(暂无记忆摘要)"
|
|
157
|
+
content = memory_path.read_text(encoding="utf-8").strip()
|
|
158
|
+
return content or "(暂无记忆摘要)"
|
|
159
|
+
|
|
160
|
+
def _build_context(self) -> CommandContext:
|
|
161
|
+
return CommandContext(
|
|
162
|
+
session_id=self._conversation_id,
|
|
163
|
+
session=self,
|
|
164
|
+
workspace_cfg=self._workspace_cfg,
|
|
165
|
+
hook_engine=self._hook_engine,
|
|
166
|
+
plugin_loader=self._plugin_loader,
|
|
167
|
+
extra={"container_type": self._container_type},
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
async def dispatch_command(self, user_input: str):
|
|
171
|
+
return await self._dispatcher.dispatch(user_input, self._build_context())
|
|
172
|
+
|
|
173
|
+
def list_commands(self) -> list[dict[str, object]]:
|
|
174
|
+
return self._runtime_command_registry.list_for_help()
|
|
175
|
+
|
|
176
|
+
async def _execute_hook(self, event: HookEvent) -> None:
|
|
177
|
+
ctx = HookContext(event=event, state={}, session_id=self._conversation_id)
|
|
178
|
+
execute_async = getattr(self._hook_engine, "execute_async", None)
|
|
179
|
+
if callable(execute_async):
|
|
180
|
+
async_out = execute_async(ctx)
|
|
181
|
+
if inspect.isawaitable(async_out):
|
|
182
|
+
await async_out
|
|
183
|
+
return
|
|
184
|
+
execute = getattr(self._hook_engine, "execute", None)
|
|
185
|
+
if not callable(execute):
|
|
186
|
+
return
|
|
187
|
+
out = execute(ctx)
|
|
188
|
+
if inspect.isawaitable(out):
|
|
189
|
+
await out
|
|
190
|
+
|
|
191
|
+
def _register_builtin_commands(self) -> None:
|
|
192
|
+
self._runtime_command_registry.register(make_clear_command())
|
|
193
|
+
self._runtime_command_registry.register(make_compact_command())
|
|
194
|
+
self._runtime_command_registry.register(make_memory_command())
|
|
195
|
+
self._runtime_command_registry.register(make_reload_plugins_command())
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
__all__ = ["ConversationSession"]
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"""
|
|
2
|
+
session/factory.py — AgentSession 入口工厂。
|
|
3
|
+
|
|
4
|
+
职责:
|
|
5
|
+
统一组装 AgentSession 所需的 graph_factory、workspace 配置与 session 级 hook_engine。
|
|
6
|
+
|
|
7
|
+
链路位置:
|
|
8
|
+
作为上层应用(CLI/示例)创建 AgentSession 的便捷入口,底层仍复用 create_loop_agent。
|
|
9
|
+
|
|
10
|
+
当前裁剪范围:
|
|
11
|
+
仅覆盖 session 级基础参数透传,不包含应用层交互循环。
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import json
|
|
17
|
+
from dataclasses import replace
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from typing import Any
|
|
20
|
+
from uuid import uuid4
|
|
21
|
+
|
|
22
|
+
from langchain_core.language_models.chat_models import BaseChatModel
|
|
23
|
+
|
|
24
|
+
from ..loop.graph.factory import create_loop_agent
|
|
25
|
+
from ..loop.hook import HookEngine, HooksConfigSnapshot, HookRegistry, WorkspaceTrustChecker
|
|
26
|
+
from ..loop.subagent.transcript import SubagentTranscriptStore
|
|
27
|
+
from ..workspace import resolve_agent_workspace_config
|
|
28
|
+
from .agent_session import AgentSession
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def create_agent_session(
|
|
32
|
+
model: str | BaseChatModel,
|
|
33
|
+
*,
|
|
34
|
+
session_id: str | None = None,
|
|
35
|
+
workspace_root: str | Path | None = None,
|
|
36
|
+
agent_home: str = ".langchain_agentx",
|
|
37
|
+
hooks: HookRegistry | None = None,
|
|
38
|
+
hook_engine: Any | None = None,
|
|
39
|
+
workspace_trust_prompter: Any | None = None,
|
|
40
|
+
transcript_writer: SubagentTranscriptStore | None = None,
|
|
41
|
+
container_type: str = "interactive",
|
|
42
|
+
enable_trace: bool = True,
|
|
43
|
+
**loop_kwargs: Any,
|
|
44
|
+
) -> AgentSession:
|
|
45
|
+
"""创建默认走 graph_factory 注入路径的 AgentSession。"""
|
|
46
|
+
resolved_session_id = session_id or f"session-{uuid4().hex}"
|
|
47
|
+
workspace_cfg = resolve_agent_workspace_config(
|
|
48
|
+
workspace_root=workspace_root or Path.cwd(),
|
|
49
|
+
agent_home=agent_home,
|
|
50
|
+
)
|
|
51
|
+
workspace_trust_accepted = _resolve_workspace_trust_accepted(
|
|
52
|
+
workspace_cfg=workspace_cfg,
|
|
53
|
+
workspace_trust_prompter=workspace_trust_prompter,
|
|
54
|
+
)
|
|
55
|
+
workspace_cfg = replace(
|
|
56
|
+
workspace_cfg,
|
|
57
|
+
workspace_trust_accepted=workspace_trust_accepted,
|
|
58
|
+
)
|
|
59
|
+
if hook_engine is None:
|
|
60
|
+
snapshot = hooks.build_snapshot() if hooks is not None else HooksConfigSnapshot()
|
|
61
|
+
hook_engine = HookEngine(
|
|
62
|
+
snapshot,
|
|
63
|
+
trust_checker=WorkspaceTrustChecker(
|
|
64
|
+
headless=_is_headless_container(container_type),
|
|
65
|
+
workspace_trust_accepted=workspace_cfg.workspace_trust_accepted,
|
|
66
|
+
),
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
def _graph_factory(
|
|
70
|
+
active_files_getter: Any = None,
|
|
71
|
+
container_type: str = container_type,
|
|
72
|
+
**_ignored: Any,
|
|
73
|
+
):
|
|
74
|
+
return create_loop_agent(
|
|
75
|
+
model,
|
|
76
|
+
session_id=resolved_session_id,
|
|
77
|
+
workspace_root=workspace_cfg.workspace_root,
|
|
78
|
+
agent_home=workspace_cfg.agent_home,
|
|
79
|
+
workspace_trust_accepted=workspace_cfg.workspace_trust_accepted,
|
|
80
|
+
hooks=hooks,
|
|
81
|
+
active_files_getter=active_files_getter,
|
|
82
|
+
container_type=container_type,
|
|
83
|
+
enable_trace=enable_trace,
|
|
84
|
+
**loop_kwargs,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
return AgentSession(
|
|
88
|
+
graph=None,
|
|
89
|
+
graph_factory=_graph_factory,
|
|
90
|
+
session_id=resolved_session_id,
|
|
91
|
+
workspace_cfg=workspace_cfg,
|
|
92
|
+
hook_engine=hook_engine,
|
|
93
|
+
transcript_writer=transcript_writer,
|
|
94
|
+
container_type=container_type,
|
|
95
|
+
enable_trace=enable_trace,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
__all__ = ["create_agent_session"]
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _resolve_workspace_trust_accepted(
|
|
103
|
+
*,
|
|
104
|
+
workspace_cfg,
|
|
105
|
+
workspace_trust_prompter: Any | None,
|
|
106
|
+
) -> bool:
|
|
107
|
+
persisted = _read_workspace_trust_flag(workspace_cfg)
|
|
108
|
+
if persisted:
|
|
109
|
+
return True
|
|
110
|
+
if workspace_cfg.workspace_trust_accepted:
|
|
111
|
+
return True
|
|
112
|
+
if workspace_trust_prompter is None:
|
|
113
|
+
return False
|
|
114
|
+
accepted = bool(workspace_trust_prompter(workspace_cfg))
|
|
115
|
+
if accepted:
|
|
116
|
+
_write_workspace_trust_flag(workspace_cfg, accepted=True)
|
|
117
|
+
return accepted
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _workspace_config_json_path(workspace_cfg) -> Path:
|
|
121
|
+
return workspace_cfg.workspace_config_path
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def _read_workspace_trust_flag(workspace_cfg) -> bool:
|
|
125
|
+
path = _workspace_config_json_path(workspace_cfg)
|
|
126
|
+
if not path.exists():
|
|
127
|
+
return False
|
|
128
|
+
try:
|
|
129
|
+
data = json.loads(path.read_text(encoding="utf-8"))
|
|
130
|
+
except Exception:
|
|
131
|
+
return False
|
|
132
|
+
return bool(data.get("workspace_trust_accepted"))
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _write_workspace_trust_flag(workspace_cfg, *, accepted: bool) -> None:
|
|
136
|
+
path = _workspace_config_json_path(workspace_cfg)
|
|
137
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
138
|
+
payload = {"workspace_trust_accepted": bool(accepted)}
|
|
139
|
+
path.write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8")
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def _is_headless_container(container_type: str) -> bool:
|
|
143
|
+
return container_type in {"background", "batch", "worker", "sdk"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""
|
|
2
|
+
session/protocol.py — LoopContainer 协议定义。
|
|
3
|
+
|
|
4
|
+
职责:
|
|
5
|
+
约束外层生命周期容器的最小异步上下文接口(on_start/on_end)。
|
|
6
|
+
|
|
7
|
+
链路位置:
|
|
8
|
+
由 AgentSession 与后续 Workflow 基类共同实现,用于统一生命周期语义。
|
|
9
|
+
|
|
10
|
+
当前裁剪范围:
|
|
11
|
+
仅定义 Protocol,不包含任何容器实现逻辑。
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
from typing import Protocol, Self, runtime_checkable
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@runtime_checkable
|
|
20
|
+
class LoopContainer(Protocol):
|
|
21
|
+
async def __aenter__(self) -> Self: ...
|
|
22
|
+
async def __aexit__(self, *_) -> None: ...
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
__all__ = ["LoopContainer"]
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""Task runtime package.
|
|
2
|
+
|
|
3
|
+
Shared task scheduling primitives for loop and tools.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .core.interfaces import TaskExecutor
|
|
7
|
+
from .orchestrator.runtime import DefaultTaskRuntime
|
|
8
|
+
from .queue.in_memory import InMemoryTaskCommandQueue
|
|
9
|
+
from .store.in_memory import InMemoryTaskStore
|
|
10
|
+
from .store.sqlite_store import SqliteTaskStore
|
|
11
|
+
from .tasks import (
|
|
12
|
+
CUSTOM_SEMANTIC,
|
|
13
|
+
CustomTaskExecutor,
|
|
14
|
+
DREAM_TASK_SEMANTIC,
|
|
15
|
+
DefaultLocalAgentRunner,
|
|
16
|
+
DreamTaskExecutor,
|
|
17
|
+
IN_PROCESS_TEAMMATE_SEMANTIC,
|
|
18
|
+
ImmediateRemoteAgentBackend,
|
|
19
|
+
InProcessTeammateExecutor,
|
|
20
|
+
LOCAL_AGENT_SEMANTIC,
|
|
21
|
+
LOCAL_BASH_SEMANTIC,
|
|
22
|
+
LocalAgentExecutor,
|
|
23
|
+
LocalAgentRunner,
|
|
24
|
+
LocalBashExecutor,
|
|
25
|
+
RecordingRemoteAgentBackend,
|
|
26
|
+
REMOTE_AGENT_SEMANTIC,
|
|
27
|
+
RemoteAgentExecutor,
|
|
28
|
+
RemoteAgentSessionBackend,
|
|
29
|
+
)
|
|
30
|
+
from .integrations import (
|
|
31
|
+
InMemoryQueuedCommandProvider,
|
|
32
|
+
MemoryPrefetchProvider,
|
|
33
|
+
QueuedCommandEnvelope,
|
|
34
|
+
QueuedCommandProvider,
|
|
35
|
+
SqliteQueuedCommandProvider,
|
|
36
|
+
SkillPrefetchProvider,
|
|
37
|
+
ToolUseSummaryProvider,
|
|
38
|
+
ProviderFactoryConfig,
|
|
39
|
+
ProviderBundle,
|
|
40
|
+
build_provider_bundle,
|
|
41
|
+
decode_provider_batch_id,
|
|
42
|
+
encode_provider_batch_id,
|
|
43
|
+
)
|
|
44
|
+
from .core.types import (
|
|
45
|
+
QueuePriority,
|
|
46
|
+
ReservedNotificationBatch,
|
|
47
|
+
TaskExecutionResult,
|
|
48
|
+
TaskNotificationEnvelope,
|
|
49
|
+
TaskRecord,
|
|
50
|
+
TaskRuntimeEvent,
|
|
51
|
+
TaskRuntimeEventType,
|
|
52
|
+
TaskScope,
|
|
53
|
+
TaskSpec,
|
|
54
|
+
TaskStatus,
|
|
55
|
+
TaskType,
|
|
56
|
+
)
|
|
57
|
+
from .output import InMemoryTaskOutputSink, TaskOutputSink
|
|
58
|
+
from .policy import (
|
|
59
|
+
DEFAULT_WITHHOLD_TASK_EVENT_POLICY,
|
|
60
|
+
WithholdTaskEventPolicy,
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
__all__ = [
|
|
64
|
+
"QueuedCommandProvider",
|
|
65
|
+
"encode_provider_batch_id",
|
|
66
|
+
"decode_provider_batch_id",
|
|
67
|
+
"DefaultTaskRuntime",
|
|
68
|
+
"InMemoryTaskStore",
|
|
69
|
+
"SqliteTaskStore",
|
|
70
|
+
"InMemoryTaskCommandQueue",
|
|
71
|
+
"TaskExecutor",
|
|
72
|
+
"LocalBashExecutor",
|
|
73
|
+
"LOCAL_BASH_SEMANTIC",
|
|
74
|
+
"DefaultLocalAgentRunner",
|
|
75
|
+
"LocalAgentExecutor",
|
|
76
|
+
"LocalAgentRunner",
|
|
77
|
+
"LOCAL_AGENT_SEMANTIC",
|
|
78
|
+
"InProcessTeammateExecutor",
|
|
79
|
+
"IN_PROCESS_TEAMMATE_SEMANTIC",
|
|
80
|
+
"ImmediateRemoteAgentBackend",
|
|
81
|
+
"RecordingRemoteAgentBackend",
|
|
82
|
+
"RemoteAgentExecutor",
|
|
83
|
+
"RemoteAgentSessionBackend",
|
|
84
|
+
"REMOTE_AGENT_SEMANTIC",
|
|
85
|
+
"CustomTaskExecutor",
|
|
86
|
+
"CUSTOM_SEMANTIC",
|
|
87
|
+
"DreamTaskExecutor",
|
|
88
|
+
"DREAM_TASK_SEMANTIC",
|
|
89
|
+
"TaskType",
|
|
90
|
+
"TaskStatus",
|
|
91
|
+
"QueuePriority",
|
|
92
|
+
"TaskScope",
|
|
93
|
+
"TaskSpec",
|
|
94
|
+
"TaskRecord",
|
|
95
|
+
"TaskNotificationEnvelope",
|
|
96
|
+
"ReservedNotificationBatch",
|
|
97
|
+
"TaskExecutionResult",
|
|
98
|
+
"TaskRuntimeEvent",
|
|
99
|
+
"TaskRuntimeEventType",
|
|
100
|
+
"InMemoryQueuedCommandProvider",
|
|
101
|
+
"QueuedCommandEnvelope",
|
|
102
|
+
"SqliteQueuedCommandProvider",
|
|
103
|
+
"MemoryPrefetchProvider",
|
|
104
|
+
"SkillPrefetchProvider",
|
|
105
|
+
"ToolUseSummaryProvider",
|
|
106
|
+
"ProviderFactoryConfig",
|
|
107
|
+
"ProviderBundle",
|
|
108
|
+
"build_provider_bundle",
|
|
109
|
+
"InMemoryTaskOutputSink",
|
|
110
|
+
"TaskOutputSink",
|
|
111
|
+
"WithholdTaskEventPolicy",
|
|
112
|
+
"DEFAULT_WITHHOLD_TASK_EVENT_POLICY",
|
|
113
|
+
]
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""Core domain types and protocols for task_runtime."""
|
|
2
|
+
|
|
3
|
+
from .ids import (
|
|
4
|
+
new_notification_command_id,
|
|
5
|
+
new_reserved_batch_id,
|
|
6
|
+
new_run_id,
|
|
7
|
+
new_task_id,
|
|
8
|
+
)
|
|
9
|
+
from .interfaces import (
|
|
10
|
+
TaskCommandQueue,
|
|
11
|
+
TaskExecutor,
|
|
12
|
+
TaskRuntime,
|
|
13
|
+
TaskStore,
|
|
14
|
+
)
|
|
15
|
+
from .notification_priority import notification_priority_for_terminal_status
|
|
16
|
+
from .types import (
|
|
17
|
+
QueuePriority,
|
|
18
|
+
ReservedNotificationBatch,
|
|
19
|
+
TaskExecutionResult,
|
|
20
|
+
TaskNotificationEnvelope,
|
|
21
|
+
TaskRecord,
|
|
22
|
+
TaskRuntimeEvent,
|
|
23
|
+
TaskRuntimeEventType,
|
|
24
|
+
TaskScope,
|
|
25
|
+
TaskSpec,
|
|
26
|
+
TaskStatus,
|
|
27
|
+
TaskType,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
__all__ = [
|
|
31
|
+
"new_notification_command_id",
|
|
32
|
+
"new_reserved_batch_id",
|
|
33
|
+
"new_run_id",
|
|
34
|
+
"new_task_id",
|
|
35
|
+
"notification_priority_for_terminal_status",
|
|
36
|
+
"QueuePriority",
|
|
37
|
+
"ReservedNotificationBatch",
|
|
38
|
+
"TaskCommandQueue",
|
|
39
|
+
"TaskExecutionResult",
|
|
40
|
+
"TaskExecutor",
|
|
41
|
+
"TaskNotificationEnvelope",
|
|
42
|
+
"TaskRecord",
|
|
43
|
+
"TaskRuntime",
|
|
44
|
+
"TaskRuntimeEvent",
|
|
45
|
+
"TaskRuntimeEventType",
|
|
46
|
+
"TaskScope",
|
|
47
|
+
"TaskSpec",
|
|
48
|
+
"TaskStatus",
|
|
49
|
+
"TaskStore",
|
|
50
|
+
"TaskType",
|
|
51
|
+
]
|