deepagents-code 0.1.58__tar.gz → 0.1.59__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/CHANGELOG.md +22 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/PKG-INFO +7 -7
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/THREAT_MODEL.md +24 -1
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/_ask_user_types.py +225 -31
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/_build_info.py +1 -1
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/_env_vars.py +12 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/_session_stats.py +90 -6
- deepagents_code-0.1.59/deepagents_code/_tool_errors.py +20 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/_tool_stream.py +297 -137
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/_version.py +1 -1
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/agent.py +88 -14
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/app.py +413 -536
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/ask_user.py +20 -24
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/auto_mode.py +33 -3
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/client/commands/config.py +281 -29
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/client/non_interactive.py +7 -1
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/cold_cache.py +19 -6
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/config.py +233 -69
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/config_manifest.py +555 -366
- deepagents_code-0.1.59/deepagents_code/configuration/__init__.py +42 -0
- deepagents_code-0.1.59/deepagents_code/configuration/paths.py +161 -0
- deepagents_code-0.1.59/deepagents_code/configuration/providers.py +523 -0
- deepagents_code-0.1.59/deepagents_code/configuration/resolver.py +593 -0
- deepagents_code-0.1.59/deepagents_code/configuration/service.py +736 -0
- deepagents_code-0.1.59/deepagents_code/configuration/types.py +87 -0
- deepagents_code-0.1.59/deepagents_code/configuration/writer.py +147 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/doctor.py +38 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/integrations/sandbox_config.py +76 -25
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/main.py +276 -5
- deepagents_code-0.1.59/deepagents_code/mcp_disabled.py +510 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/mcp_tools.py +11 -1
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/model_config.py +812 -178
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/server_graph.py +5 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/sessions.py +4 -2
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/terminal_escape.py +11 -2
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/theme.py +40 -16
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/textual_adapter.py +4 -1
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/ask_user.py +31 -28
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/auth.py +31 -15
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/auto_mode_notice.py +13 -12
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/messages.py +183 -12
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/model_selector.py +3 -4
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/notification_center.py +8 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/status.py +62 -27
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/yolo_mode_notice.py +2 -2
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/update_check.py +190 -113
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/pyproject.toml +6 -6
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/conftest.py +49 -1
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test__tool_stream.py +244 -10
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_agent.py +42 -1
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_app.py +238 -188
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_ask_user_middleware.py +300 -23
- deepagents_code-0.1.59/tests/unit_tests/test_ask_user_types.py +422 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_auto_mode.py +209 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_charset.py +3 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_cold_cache.py +16 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_config.py +14 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_config_manifest.py +256 -5
- deepagents_code-0.1.59/tests/unit_tests/test_configuration.py +3152 -0
- deepagents_code-0.1.59/tests/unit_tests/test_configuration_resolution.py +499 -0
- deepagents_code-0.1.59/tests/unit_tests/test_configuration_resolver.py +215 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_end_to_end.py +52 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_main.py +163 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_mcp_disabled.py +48 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_model_config.py +25 -6
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_non_interactive.py +137 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_sandbox_config.py +23 -2
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_server_graph.py +9 -7
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_session_stats.py +244 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_terminal_escape.py +10 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_theme.py +12 -1
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_threads_resume.py +1 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_update_check.py +86 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/test_textual_adapter.py +16 -11
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_ask_user.py +143 -46
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_auth_widgets.py +67 -91
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_messages.py +150 -4
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_model_selector.py +8 -9
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_notification_center.py +23 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_status.py +83 -39
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_thread_selector.py +21 -0
- deepagents_code-0.1.59/tests/unit_tests/tui/widgets/test_yolo_mode_notice.py +8 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/uv.lock +17 -17
- deepagents_code-0.1.58/deepagents_code/mcp_disabled.py +0 -212
- deepagents_code-0.1.58/tests/unit_tests/test_ask_user_types.py +0 -118
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/.gitignore +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/AGENTS.md +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/ARCHITECTURE.md +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/COMMANDS.md +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/DEVELOPMENT.md +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/HOOKS.md +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/LICENSE +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/Makefile +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/PRICING.md +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/README.md +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/__init__.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/__main__.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/_cli_context.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/_constants.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/_debug.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/_debug_buffer.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/_dep_floor_check.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/_fake_models.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/_git.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/_glm_5p2_profile.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/_invocation.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/_markdown.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/_paths.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/_repository_bounds.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/_server_config.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/_startup_error.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/_testing_models.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/_textual_patches.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/_tracing.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/acp.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/app.tcss +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/approval_mode.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/auth_display.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/auth_store.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/built_in_skills/__init__.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/built_in_skills/deepagents-thread-inspector/SKILL.md +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/built_in_skills/deepagents-thread-inspector/scripts/inspect_sessions.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/built_in_skills/remember/SKILL.md +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/built_in_skills/skill-creator/SKILL.md +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/built_in_skills/skill-creator/scripts/init_skill.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/built_in_skills/skill-creator/scripts/quick_validate.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/bundled_prices.README.md +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/bundled_prices.json +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/client/__init__.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/client/commands/__init__.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/client/commands/auth.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/client/commands/extras.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/client/commands/mcp.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/client/commands/tools.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/client/launch/__init__.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/client/launch/server.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/client/launch/server_manager.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/client/remote_client.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/clipboard.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/command_registry.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/configurable_model.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/cost_tracking.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/default_agent_prompt.md +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/diff_utils.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/editor.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/event_bus.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/extras_info.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/file_ops.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/formatting.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/goal_rubric.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/goal_state_notice.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/goal_tools.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/hooks/__init__.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/hooks/capabilities.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/hooks/client.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/hooks/client_lifecycle.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/hooks/context.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/hooks/engine.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/hooks/env.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/hooks/envelope.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/hooks/interrupt.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/hooks/legacy.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/hooks/loading.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/hooks/manager.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/hooks/migration.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/hooks/models/__init__.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/hooks/models/adapters.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/hooks/models/config.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/hooks/models/domain.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/hooks/models/transport.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/hooks/models/wire.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/hooks/permissions.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/hooks/presenter.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/hooks/projection.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/hooks/reducer.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/hooks/runner.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/hooks/runtime.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/hooks/server_middleware.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/hooks/snapshot.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/hooks/tools.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/hooks/transcript.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/hooks/trust.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/hooks/validate_terminal_sequence.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/input.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/integrations/__init__.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/integrations/openai_codex.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/integrations/sandbox_factory.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/integrations/sandbox_provider.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/integrations/sandbox_registry.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/iterm_cursor_guide.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/json_types.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/local_context.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/managed_tools.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/mcp_auth.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/mcp_config.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/mcp_login_service.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/mcp_oauth_ui.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/mcp_providers/__init__.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/mcp_providers/_registry.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/mcp_providers/base.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/mcp_providers/github.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/mcp_providers/slack.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/media_utils.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/memory_guard.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/notifications.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/offload.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/offload_middleware.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/onboarding.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/output.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/paste_collapse.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/plugins/__init__.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/plugins/_json.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/plugins/adapters/__init__.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/plugins/adapters/hooks.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/plugins/adapters/mcp.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/plugins/adapters/skills.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/plugins/adapters/skills_middleware.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/plugins/commands_cli.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/plugins/discovery.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/plugins/manifest.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/plugins/marketplace.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/plugins/models.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/plugins/store.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/plugins/substitution.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/project_utils.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/py.typed +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/reasoning_effort.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/reliable_rubric.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/resume_state.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/skills/__init__.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/skills/commands.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/skills/invocation.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/skills/load.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/skills/merge.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/skills/trust.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/state_migration.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/subagents.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/system_prompt.md +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/terminal_capabilities.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tool_catalog.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tool_display.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tools.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/__init__.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/modals/__init__.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/modals/cold_cache.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/modals/plugin_manager/__init__.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/modals/plugin_manager/content.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/modals/plugin_manager/models.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/modals/plugin_manager/plugin_manager.tcss +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/modals/plugin_manager/state.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/modals/plugin_manager/tabs.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/modals/resume_compact.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/screens/__init__.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/__init__.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/_copy_spans.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/_inline_prompt.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/_js_eval_display.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/_links.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/_paste_textarea.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/agent_selector.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/approval.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/autocomplete.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/chat_input.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/codex_auth.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/context_usage.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/cwd_switch.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/debug_console.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/diff.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/effort_selector.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/goal_review.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/goal_status.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/history.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/install_confirm.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/launch_init.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/loading.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/mcp_login.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/mcp_reconnect.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/mcp_viewer.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/message_store.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/notification_detail.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/notification_settings.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/restart_prompt.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/skill_trust.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/startup_tip.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/subagent_panel.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/theme_selector.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/thread_agent_switch.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/thread_selector.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/tool_renderers.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/tool_widgets.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/update_available.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/update_confirm.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/update_progress.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/tui/widgets/welcome.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/ui.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/deepagents_code/unicode_security.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/examples/skills/arxiv-search/SKILL.md +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/examples/skills/arxiv-search/arxiv_search.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/examples/skills/langgraph-docs/SKILL.md +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/examples/skills/skill-creator/SKILL.md +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/examples/skills/skill-creator/scripts/init_skill.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/examples/skills/skill-creator/scripts/quick_validate.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/examples/skills/web-research/SKILL.md +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/hatch_build.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/images/tui.png +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/scripts/check_imports.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/scripts/debug_server.sh +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/scripts/generate_commands_catalog.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/scripts/install.sh +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/README.md +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/integration_tests/__init__.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/integration_tests/benchmarks/__init__.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/integration_tests/benchmarks/test_codspeed_import_benchmarks.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/integration_tests/benchmarks/test_local_context_benchmarks.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/integration_tests/benchmarks/test_startup_benchmarks.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/integration_tests/conftest.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/integration_tests/test_acp_mode.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/integration_tests/test_auto_approve_remote.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/integration_tests/test_compact_resume.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/integration_tests/test_goal_criteria_remote.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/integration_tests/test_offload_server_side.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/integration_tests/test_sandbox_factory.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/integration_tests/test_sandbox_operations.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/__init__.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/client/__init__.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/client/commands/__init__.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/client/commands/test_auth.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/client/commands/test_extras.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/client/commands/test_mcp.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/client/commands/test_tools.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/data/coding_agent_v1_validator.json +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/hooks/__init__.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/hooks/models/__init__.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/hooks/models/test_models.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/hooks/test_client_lifecycle.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/hooks/test_configuration.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/hooks/test_engine.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/hooks/test_execution.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/hooks/test_manager.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/hooks/test_presenter.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/hooks/test_server_lifecycle.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/hooks/test_transcript.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/hooks/test_trust.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/plugins/__init__.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/plugins/test_marketplace.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/plugins/test_plugin_hooks.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/plugins/test_plugins_p0.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/plugins/test_store.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/skills/__init__.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/skills/test_commands.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/skills/test_load.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/skills/test_merge.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/skills/test_skill_trust.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/skills/test_skills_json.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/skills/test_thread_inspector.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/smoke_tests/__init__.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/smoke_tests/conftest.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/smoke_tests/snapshots/system_prompt_interactive_local.md +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/smoke_tests/test_system_prompt.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_acp.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_agent_friendly.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_approval_mode.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_args.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_auth_display.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_auth_store.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_auth_web_search_restart.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_clipboard.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_coding_agent_metadata.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_command_registry.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_compact_tool.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_config_recursion_limit.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_configurable_model.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_cost_tracking.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_cursor_blink.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_cursor_style.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_debug.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_debug_buffer.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_debug_console.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_dep_floor_check.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_diff_utils.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_doctor.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_editor.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_env_vars.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_event_bus.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_exception_handling.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_extras_info.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_file_ops.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_formatting.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_git.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_glm_5p2_profile.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_goal_criteria_client.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_goal_rubric.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_goal_state_notice.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_goal_state_persistence.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_goal_tools.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_hatch_build.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_hooks.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_imports.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_input_parsing.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_install_command.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_install_script.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_invocation.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_iterm_cursor_guide.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_json_types.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_local_context.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_main_acp_mode.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_main_args.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_managed_tools.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_mcp_auth.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_mcp_config.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_mcp_login_service.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_mcp_oauth_ui.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_mcp_tools.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_media_utils.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_memory_guard.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_model_switch.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_notifications.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_offload.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_onboarding.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_openai_codex_integration.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_output.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_paths.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_reasoning_effort.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_reliable_rubric.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_reload.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_remote_client.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_repository_bounds.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_resume_state.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_rubric_cli.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_sandbox_factory.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_sandbox_provider.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_sandbox_registry.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_server.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_server_config.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_server_helpers.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_server_manager.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_sessions.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_shell_allow_list.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_skill_invocation.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_startup_blocking.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_startup_fast_paths.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_state_migration.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_subagents.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_terminal_capabilities.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_terminal_progress_preference.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_textual_patches.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_tool_catalog.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_tool_display.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_tracing.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_tracing_replicas.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_transcript_virtualization.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_ui.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_unicode_security.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/test_version.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tools/__init__.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tools/test_current_thread.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tools/test_fetch_url.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tools/test_tool_arg_schemas.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/__init__.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/modals/__init__.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/modals/plugin_manager/__init__.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/modals/plugin_manager/test_structure.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/modals/test_cold_cache.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/test_subagent_stream.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/__init__.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_agent_selector.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_approval.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_auto_mode_notice.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_autocomplete.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_chat_input.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_copy_spans.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_cwd_switch.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_diff.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_goal_review.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_history.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_inline_prompt.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_install_confirm.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_launch_init.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_links.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_loading.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_mcp_login_modal.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_mcp_reconnect.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_mcp_viewer.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_message_store.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_notification_detail.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_notification_settings.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_restart_prompt.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_skill_trust_screen.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_startup_tip.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_subagent_panel.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_thread_agent_switch.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_tool_renderers.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_update_available.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_update_confirm.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_update_progress.py +0 -0
- {deepagents_code-0.1.58 → deepagents_code-0.1.59}/tests/unit_tests/tui/widgets/test_welcome.py +0 -0
|
@@ -2,6 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
# Deep Agents Code Changelog
|
|
4
4
|
|
|
5
|
+
## [0.1.59](https://github.com/langchain-ai/deepagents/compare/deepagents-code==0.1.58...deepagents-code==0.1.59) (2026-08-20)
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
|
|
9
|
+
- Added support for `managed_config.toml` configuration ([#5604](https://github.com/langchain-ai/deepagents/issues/5604))
|
|
10
|
+
- Multi-select `ask_user` answers are now encoded as JSON arrays ([#5660](https://github.com/langchain-ai/deepagents/issues/5660))
|
|
11
|
+
- Made teardown usage stats configurable ([#5696](https://github.com/langchain-ai/deepagents/issues/5696))
|
|
12
|
+
- Footer pickers now open on click ([#5674](https://github.com/langchain-ai/deepagents/issues/5674))
|
|
13
|
+
- Replaced Gemini 3.6 Flash with Gemini 3.7 Flash ([#5681](https://github.com/langchain-ai/deepagents/issues/5681))
|
|
14
|
+
|
|
15
|
+
### Bug fixes
|
|
16
|
+
|
|
17
|
+
- Made tool argument validation errors recoverable ([#5659](https://github.com/langchain-ai/deepagents/issues/5659))
|
|
18
|
+
- Improved streaming performance for tool-call arguments to run in linear time ([#5712](https://github.com/langchain-ai/deepagents/issues/5712))
|
|
19
|
+
- Fixed durable-mask config resolution with ranked resolver behavior ([#5672](https://github.com/langchain-ai/deepagents/issues/5672))
|
|
20
|
+
- Skipped background sync in Apple Terminal ([#5666](https://github.com/langchain-ai/deepagents/issues/5666))
|
|
21
|
+
- Hid thread IDs when tracing is disabled ([#5692](https://github.com/langchain-ai/deepagents/issues/5692))
|
|
22
|
+
- Kept installed providers visible in `/auth` ([#5689](https://github.com/langchain-ai/deepagents/issues/5689))
|
|
23
|
+
- Preloaded the auth UI before notification handoff ([#5697](https://github.com/langchain-ai/deepagents/issues/5697))
|
|
24
|
+
- Updated and clarified UI copy across Auto mode, YOLO hints, classifier notices, `/tokens`, line-number toggles, review failures, onboarding Tavily cancellation, and OpenAI subscription login labels ([#5685](https://github.com/langchain-ai/deepagents/issues/5685), [#5694](https://github.com/langchain-ai/deepagents/issues/5694), [#5684](https://github.com/langchain-ai/deepagents/issues/5684), [#5687](https://github.com/langchain-ai/deepagents/issues/5687), [#5680](https://github.com/langchain-ai/deepagents/issues/5680), [#5688](https://github.com/langchain-ai/deepagents/issues/5688), [#5686](https://github.com/langchain-ai/deepagents/issues/5686), [#5691](https://github.com/langchain-ai/deepagents/issues/5691), [#5693](https://github.com/langchain-ai/deepagents/issues/5693))
|
|
25
|
+
- Removed the `Muse Spark 1.1` recommendation ([#5683](https://github.com/langchain-ai/deepagents/issues/5683))
|
|
26
|
+
|
|
5
27
|
## [0.1.58](https://github.com/langchain-ai/deepagents/compare/deepagents-code==0.1.57...deepagents-code==0.1.58) (2026-08-19)
|
|
6
28
|
|
|
7
29
|
### Breaking Changes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: deepagents-code
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.59
|
|
4
4
|
Summary: Terminal coding agent built on the Deep Agents SDK - works with any model, with persistent memory, customizable skills, subagents, and approval controls.
|
|
5
5
|
Project-URL: Homepage, https://www.langchain.com/dcode
|
|
6
6
|
Project-URL: Documentation, https://docs.langchain.com/oss/deepagents/code/overview
|
|
@@ -30,16 +30,16 @@ Requires-Python: <4.0,>=3.12
|
|
|
30
30
|
Requires-Dist: aiosqlite<1.0.0,>=0.22.1
|
|
31
31
|
Requires-Dist: anyio<5.0.0,>=4.14.2
|
|
32
32
|
Requires-Dist: deepagents-acp<1.0.0,>=0.0.10
|
|
33
|
-
Requires-Dist: deepagents==0.7.
|
|
33
|
+
Requires-Dist: deepagents==0.7.8
|
|
34
34
|
Requires-Dist: filelock<3.30,>=3.29.7
|
|
35
|
-
Requires-Dist: genai-prices<0.2.0,>=0.1.
|
|
35
|
+
Requires-Dist: genai-prices<0.2.0,>=0.1.4
|
|
36
36
|
Requires-Dist: httpx<1.0.0,>=0.28.1
|
|
37
|
-
Requires-Dist: langchain-anthropic<2.0.0,>=1.6.
|
|
37
|
+
Requires-Dist: langchain-anthropic<2.0.0,>=1.6.1
|
|
38
38
|
Requires-Dist: langchain-google-genai<5.0.0,>=4.3.4
|
|
39
39
|
Requires-Dist: langchain-mcp-adapters<1.0.0,>=0.3.2
|
|
40
40
|
Requires-Dist: langchain-openai<2.0.0,>=1.6.0
|
|
41
41
|
Requires-Dist: langchain-quickjs<0.4.0,>=0.3.4
|
|
42
|
-
Requires-Dist: langchain<2.0.0,>=1.3.
|
|
42
|
+
Requires-Dist: langchain<2.0.0,>=1.3.16
|
|
43
43
|
Requires-Dist: langgraph-checkpoint-sqlite<4.0.0,>=3.1.1
|
|
44
44
|
Requires-Dist: langgraph-cli[inmem]<1.0.0,>=0.4.31
|
|
45
45
|
Requires-Dist: langgraph-runtime-inmem<1.0.0,>=0.32.6
|
|
@@ -66,7 +66,7 @@ Provides-Extra: agentcore
|
|
|
66
66
|
Requires-Dist: langchain-agentcore-codeinterpreter<1.0.0,>=0.0.5; extra == 'agentcore'
|
|
67
67
|
Provides-Extra: all-providers
|
|
68
68
|
Requires-Dist: aiohttp<3.15.0,>=3.14.3; extra == 'all-providers'
|
|
69
|
-
Requires-Dist: langchain-anthropic<2.0.0,>=1.6.
|
|
69
|
+
Requires-Dist: langchain-anthropic<2.0.0,>=1.6.1; extra == 'all-providers'
|
|
70
70
|
Requires-Dist: langchain-aws<2.0.0,>=1.7.2; extra == 'all-providers'
|
|
71
71
|
Requires-Dist: langchain-baseten<1.0.0,>=0.2.3; extra == 'all-providers'
|
|
72
72
|
Requires-Dist: langchain-cohere<1.0.0,>=0.6.0; extra == 'all-providers'
|
|
@@ -94,7 +94,7 @@ Requires-Dist: langchain-modal>=0.0.5; extra == 'all-sandboxes'
|
|
|
94
94
|
Requires-Dist: langchain-runloop>=0.0.6; extra == 'all-sandboxes'
|
|
95
95
|
Requires-Dist: langchain-vercel-sandbox>=0.0.1; extra == 'all-sandboxes'
|
|
96
96
|
Provides-Extra: anthropic
|
|
97
|
-
Requires-Dist: langchain-anthropic<2.0.0,>=1.6.
|
|
97
|
+
Requires-Dist: langchain-anthropic<2.0.0,>=1.6.1; extra == 'anthropic'
|
|
98
98
|
Provides-Extra: baseten
|
|
99
99
|
Requires-Dist: langchain-baseten<1.0.0,>=0.2.3; extra == 'baseten'
|
|
100
100
|
Provides-Extra: bedrock
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
6. The LangGraph dev server subprocess binds to `127.0.0.1` by default (`client/launch/server.py:_DEFAULT_HOST`) and is ephemeral — started and stopped per CLI session.
|
|
51
51
|
7. `DA_SERVER_*` environment variables are readable only by the CLI process and its child server subprocess (OS process isolation assumption).
|
|
52
52
|
8. Users who set `class_path` in `config.toml` accept the same trust model as `pyproject.toml` build scripts — they control their own machine.
|
|
53
|
+
9. Administrators deploy and protect the fixed `managed_config.toml` path with operating-system controls; the CLI does not validate its owner or mode and never writes it.
|
|
53
54
|
|
|
54
55
|
---
|
|
55
56
|
|
|
@@ -129,7 +130,7 @@
|
|
|
129
130
|
| C6 | Hook Runtime | Fires subprocess commands on agent lifecycle events | framework-controlled | No³ | `hooks.runtime.HooksRuntime`, `hooks.runner.run_command_handler` |
|
|
130
131
|
| C7 | Sandbox Integration | Creates/destroys remote sandboxes (Daytona, LangSmith, Modal, Runloop, AgentCore) | framework-controlled | No⁴ | `integrations.sandbox_factory.create_sandbox` |
|
|
131
132
|
| C8 | Session Persistence | SQLite checkpoint store for LangGraph thread state | framework-controlled | Yes | `sessions.get_db_path`, `sessions.generate_thread_id` |
|
|
132
|
-
| C9 | Configuration System | TOML
|
|
133
|
+
| C9 | Configuration System | Managed/user TOML, env vars, `AGENTS.md` system prompts, model config | administrator/user-controlled | N/A | `configuration`, `config.settings`, `model_config.ModelConfig`, fixed managed path, `~/.deepagents/config.toml` |
|
|
133
134
|
| C10 | Unicode/URL Safety | Detects hidden Unicode, checks URL domain spoofing for approval UI warnings | framework-controlled | Yes | `unicode_security.detect_dangerous_unicode`, `unicode_security.check_url_safety` |
|
|
134
135
|
| C11 | LangGraph Dev Server | Subprocess running `langgraph dev` with `LANGGRAPH_AUTH_TYPE=noop`; managed by `ServerProcess` | framework-controlled | Yes⁵ | `client.launch.server.ServerProcess.start`, `client.launch.server.generate_langgraph_json`, `client.launch.server_manager.start_server_and_get_agent` |
|
|
135
136
|
| C12 | Remote Agent Client | HTTP+SSE client wrapping `RemoteGraph`; connects to C11 on localhost | framework-controlled | Yes⁵ | `client.remote_client.RemoteAgent.astream`, `client.remote_client.RemoteAgent.aget_state` |
|
|
@@ -207,6 +208,7 @@
|
|
|
207
208
|
| TB9 | LocalContextMiddleware → Host Env | Bash detect script output (git info, project files, Makefile) injected into system prompt | Script is framework-generated static code; 30s timeout; exit-code check | Content of Makefile, pyproject.toml, git branch names, directory listing |
|
|
208
209
|
| TB10 | RemoteAgent → LangGraph Dev Server | CLI communicates with agent via HTTP+SSE on localhost | Server bound to `127.0.0.1` (`client/launch/server.py:_DEFAULT_HOST`); ephemeral per session | No authentication (`LANGGRAPH_AUTH_TYPE=noop`); any localhost process can reach the API |
|
|
209
210
|
| TB11 | Config File → Code Execution | `class_path` in `config.toml` triggers `importlib.import_module()`; project/global `.env` values are loaded into the process environment and can reach Bash startup hooks | Format validation (`module:ClassName`); `issubclass(BaseChatModel)` check; dotenv loading denies shell startup / environment-hijack keys (`BASH_ENV`, `ENV`) | Module-level side effects execute during import; user controls config file; project files in the working directory influence execution |
|
|
211
|
+
| TB12 | Managed Config → Runtime | A fixed administrator-deployed TOML file overrides CLI, environment, and user preferences | Fixed non-redirectable path; the CLI never writes the file; fail-closed startup for every command except diagnostics; typed resolution; diagnostics remain available | Filesystem ownership/mode and privileged deployment are outside the CLI; a host administrator can weaken or strengthen policy |
|
|
210
212
|
|
|
211
213
|
### Boundary Details
|
|
212
214
|
|
|
@@ -261,6 +263,26 @@
|
|
|
261
263
|
- **Inside (dotenv)**: `config._load_dotenv` loads project and global `.env` values with `override=False` and drops shell startup / environment-hijack keys (`BASH_ENV`, `ENV`, and related) so a project `.env` cannot register a script that Bash would source at startup. The preview path (`_preview_dotenv_environ`) applies the same denylist so a dry-run config change cannot report a value a real reload would reject.
|
|
262
264
|
- **Outside (dotenv)**: All other `.env` keys are applied to the process environment, and any project file in the working directory (`.env`, `Makefile`, build scripts) can still influence execution. See T12.
|
|
263
265
|
|
|
266
|
+
#### TB12: Managed Config → Runtime
|
|
267
|
+
|
|
268
|
+
- **Inside**: The resolver reads one fixed OS path. The writer rejects that path, so the managed source is read-only by guard and not only by convention. Valid managed values take the highest precedence. The rules are:
|
|
269
|
+
- Tables deep-merge. Deny lists union. An explicit managed allow or trust list replaces lower-precedence grants.
|
|
270
|
+
- A managed scalar replaces a colliding user table at any depth, so a user cannot defeat policy by changing the shape of a key. This holds on the top-level merge and inside a structured table: both apply the manifest validator, so the effective value and the audited provenance agree.
|
|
271
|
+
- A wrong-typed managed scalar is skipped, and the lower-precedence value stays in effect.
|
|
272
|
+
- Inside a structured table (`[models.providers]`, `[themes]`, `[async_subagents]`, `[sandboxes.providers]`, `[ui.terminal_themes]`, `[threads.columns]`) the dedicated typed reader validates instead. A wrong-typed managed leaf there can displace a valid user leaf, after which the reader falls back to the built-in default.
|
|
273
|
+
- An enforced key whose managed value cannot be applied stops every command except the diagnostics listed below. It also blocks `/reload`. Skipping it would leave the user's CLI flag or environment variable in force. The enforced keys are `startup.mode`, `startup.yolo_switcher`, `shell.allow_list`, `skills.extra_allowed_dirs`, `interpreter.enable_interpreter`, `interpreter.ptc`, `interpreter.ptc_acknowledge_unsafe`, `models.auto_classifier`, `runtime.recursion_limit`, `sandboxes.default`, and `tracing.langsmith_redact`.
|
|
274
|
+
- Three conditions make an enforced key unapplicable: a wrong-typed value, a `runtime.recursion_limit` outside its bounds, and a key made unreachable by a scalar ancestor (`startup = "manual"` in place of `[startup]` and `mode`). A managed `[sandboxes].default` that names an unavailable backend stops a sandboxed launch.
|
|
275
|
+
- A scalar at a known section is rejected for the same reason, so it cannot replace the user's whole section. `[effort]` is included, although it has no manifest option.
|
|
276
|
+
- Any other rejected managed value is ignored, and `dcode doctor` and `dcode config` name it. An ignored key is never silent.
|
|
277
|
+
- A missing file is accepted and applies no policy.
|
|
278
|
+
- A present unreadable, undecodable, or syntactically corrupt file blocks every command except `--help`, `--version`, `help`, `config`, `doctor`, and `auth path`. It also blocks `/reload`.
|
|
279
|
+
- On Windows, a ProgramData directory that cannot be read from the registry blocks the same commands. The path would be a guess, and an empty read at a guessed path does not prove that no policy is deployed. Reporting it as a missing file made every managed setting silently inert on a host whose ProgramData is relocated.
|
|
280
|
+
- A failed `/reload` keeps the last snapshot that parsed cleanly, so policy is never dropped mid-session.
|
|
281
|
+
- An unusable user `config.toml` drops only the user layer, so managed policy still applies.
|
|
282
|
+
- A deny list that cannot be read is treated as denying everything, never as empty. This covers a managed `[mcp].disabled_servers` that is neither an array of names nor a comma-separated string, and a `[mcp]` section that is not a table. A managed `[mcp].enabled_project_server_approvals` that is not an array is treated the same way: the key is present, so policy means to narrow access, and reading its presence as absence would keep both the user's approvals and the `DEEPAGENTS_CODE_DANGEROUSLY_ENABLE_PROJECT_MCP_SERVERS` bypass in force.
|
|
283
|
+
- **Outside**: Ownership, permission-mode validation, privileged installation, and `sudo` policy are deployment responsibilities. Anyone who can replace the administrator-managed file can control model, sandbox, interpreter, MCP trust, and other supported runtime settings. On macOS, note that stock `/Library/Application Support` is group-writable by `admin`, so any admin-group member can create the file and grant themselves policy. Deployments that rely on this boundary must tighten ownership and mode on the `dcode` directory.
|
|
284
|
+
- **Crossing mechanism**: Synchronous local file read through `configuration.TomlFileProvider`, followed by typed resolution and CLI/server startup gates.
|
|
285
|
+
|
|
264
286
|
---
|
|
265
287
|
|
|
266
288
|
## Data Flows
|
|
@@ -292,6 +314,7 @@
|
|
|
292
314
|
| DF23 | C9 Config | C17 Model Config | `class_path` string from `config.toml` | — | TB11 | TOML parse → importlib |
|
|
293
315
|
| DF24 | C5 MCP Config | MCP Subprocess | `env` dict from `.mcp.json` forwarded to stdio subprocess | DC1 | TB4 | subprocess environment |
|
|
294
316
|
| DF25 | C3 Agent | C7 Sandbox | Conversation messages for offload | DC5 | TB6 | `backend.awrite()` |
|
|
317
|
+
| DF26 | Administrator | C9 Config | Managed TOML policy | DC1 | TB12 | Fixed local file read |
|
|
295
318
|
|
|
296
319
|
### Flow Details
|
|
297
320
|
|
|
@@ -11,6 +11,7 @@ side produces it and which reads it.
|
|
|
11
11
|
|
|
12
12
|
from __future__ import annotations
|
|
13
13
|
|
|
14
|
+
import json
|
|
14
15
|
from typing import Annotated, Literal, NotRequired, assert_never, get_args
|
|
15
16
|
|
|
16
17
|
from pydantic import Field
|
|
@@ -61,23 +62,97 @@ same as being *rendered* as a choice list: the TUI has its own exhaustive
|
|
|
61
62
|
dispatch in `_QuestionWidget.compose`.
|
|
62
63
|
"""
|
|
63
64
|
|
|
64
|
-
MULTI_SELECT_ANSWER_SEPARATOR = ", "
|
|
65
|
-
"""Separator joining the selected values of a `multi_select` answer."""
|
|
66
65
|
|
|
67
|
-
|
|
68
|
-
"""
|
|
66
|
+
def encode_multi_select_answer(values: list[str]) -> str:
|
|
67
|
+
"""Encode the selected values of a `multi_select` answer for the wire.
|
|
69
68
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
69
|
+
The answer stays one string so `answers: list[str]` keeps one slot per
|
|
70
|
+
question, positionally matched. JSON is self-delimiting, so values carrying
|
|
71
|
+
commas, quotes, or newlines round-trip exactly.
|
|
72
|
+
|
|
73
|
+
The encoding is opaque to a consumer that only moves the answer around. A
|
|
74
|
+
consumer that tests whether the user answered at all must go through
|
|
75
|
+
`ask_user_answer_is_empty`: an unselected `multi_select` encodes as the
|
|
76
|
+
*truthy* string `[]`, so a bare `.strip()` reads it as answered.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
values: Selected values — toggled predefined choices in choice-list
|
|
80
|
+
order, then custom Other values in slot order.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
The values as a JSON array, e.g. `["a", "b"]`. An empty selection
|
|
84
|
+
encodes as `[]`. The result never contains a line feed or carriage
|
|
85
|
+
return, so it cannot split a blank-line-separated transcript block.
|
|
86
|
+
`ensure_ascii=False` does pass U+2028 and U+2029 through literally, so
|
|
87
|
+
do not read this as "the result is a single line to every consumer" —
|
|
88
|
+
the guarantee is about the block separator only.
|
|
89
|
+
"""
|
|
90
|
+
return json.dumps(values, ensure_ascii=False)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def decode_multi_select_answer(raw: str) -> list[str] | None:
|
|
94
|
+
"""Decode a `multi_select` answer produced by `encode_multi_select_answer`.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
raw: The raw answer string for a `multi_select` question. Must already
|
|
98
|
+
be a `str`: a non-string raises `TypeError` out of `json.loads`
|
|
99
|
+
rather than returning `None`. Every call site establishes that
|
|
100
|
+
first — `_parse_answers` coerces non-string answers,
|
|
101
|
+
`_validated_ask_user_answers` checks `isinstance(answer, str)`, and
|
|
102
|
+
the display path passes a slice of the transcript.
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
The selected values, or `None` when `raw` is not a JSON array of
|
|
106
|
+
strings. Callers choose the policy for `None`; the one thing none of
|
|
107
|
+
them may do is fall back to splitting on `", "`, which mis-splits a
|
|
108
|
+
value that contains a comma.
|
|
109
|
+
"""
|
|
110
|
+
try:
|
|
111
|
+
decoded = json.loads(raw)
|
|
112
|
+
except (json.JSONDecodeError, RecursionError):
|
|
113
|
+
return None
|
|
114
|
+
if not isinstance(decoded, list) or not all(
|
|
115
|
+
isinstance(value, str) for value in decoded
|
|
116
|
+
):
|
|
117
|
+
return None
|
|
118
|
+
return decoded
|
|
74
119
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
`
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
120
|
+
|
|
121
|
+
def ask_user_answer_is_empty(answer: str, question_type: object) -> bool:
|
|
122
|
+
"""Return whether an `ask_user` answer counts as "no answer".
|
|
123
|
+
|
|
124
|
+
The single definition of emptiness for an answer, shared by the TUI (which
|
|
125
|
+
blocks submitting a required question) and by the Auto authorization path
|
|
126
|
+
(which keeps unanswered questions out of the consent evidence). Both sides
|
|
127
|
+
must agree: an answer the TUI accepts as empty must not read as consent
|
|
128
|
+
evidence downstream.
|
|
129
|
+
|
|
130
|
+
A bare `.strip()` is wrong for `multi_select`, whose empty encoding is the
|
|
131
|
+
truthy string `[]`. Every other type is empty when it is blank.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
answer: The raw answer string for the question.
|
|
135
|
+
question_type: The paired question's `type`. Anything other than
|
|
136
|
+
`'multi_select'` — including a malformed or missing type — takes the
|
|
137
|
+
blank test.
|
|
138
|
+
|
|
139
|
+
Returns:
|
|
140
|
+
`True` when the question has no substantive answer.
|
|
141
|
+
"""
|
|
142
|
+
if question_type == "multi_select":
|
|
143
|
+
# A malformed encoding counts as empty, which is the fail-closed side of
|
|
144
|
+
# both call sites: the TUI re-prompts a *required* question (an optional
|
|
145
|
+
# one submits unchanged), and Auto withholds the answer from the consent
|
|
146
|
+
# evidence rather than passing an undecodable string to the classifier.
|
|
147
|
+
#
|
|
148
|
+
# This makes emptiness asymmetric across types for the `(cancelled)` and
|
|
149
|
+
# `(error: ...)` placeholders, which are not JSON: on a `multi_select`
|
|
150
|
+
# they read as empty and are withheld from the evidence, while the same
|
|
151
|
+
# placeholder on a `text` question becomes a row. Withholding is the
|
|
152
|
+
# safe direction, so the asymmetry is acceptable — but it is real, and a
|
|
153
|
+
# future caller counting answered questions across types will see it.
|
|
154
|
+
return not decode_multi_select_answer(answer)
|
|
155
|
+
return not answer.strip()
|
|
81
156
|
|
|
82
157
|
|
|
83
158
|
class Choice(TypedDict):
|
|
@@ -88,7 +163,11 @@ class Choice(TypedDict):
|
|
|
88
163
|
Field(
|
|
89
164
|
description=(
|
|
90
165
|
"The display label for this choice. Also the text returned as "
|
|
91
|
-
"the answer when this choice is selected."
|
|
166
|
+
"the answer when this choice is selected. A 'multi_select' answer "
|
|
167
|
+
"is a JSON array, so a value may contain commas, quotes, and "
|
|
168
|
+
"newlines; JSON escaping keeps it exact. A 'multiple_choice' "
|
|
169
|
+
"value is returned on its own with no escaping, so keep that "
|
|
170
|
+
"one to a single line."
|
|
92
171
|
)
|
|
93
172
|
),
|
|
94
173
|
]
|
|
@@ -108,10 +187,9 @@ class Question(TypedDict):
|
|
|
108
187
|
"one or more predefined options. Both choice types always append an "
|
|
109
188
|
"'Other' free-form option automatically; multi-select can accept "
|
|
110
189
|
"multiple custom Other values (filling one reveals another). A "
|
|
111
|
-
"'multi_select' answer comes back as the selected
|
|
112
|
-
|
|
113
|
-
"is selected on an optional question the answer is
|
|
114
|
-
"string."
|
|
190
|
+
"'multi_select' answer comes back as a JSON array of the selected "
|
|
191
|
+
'values (including any custom Other text), e.g. ["a", "b"]; if '
|
|
192
|
+
"nothing is selected on an optional question the answer is []."
|
|
115
193
|
)
|
|
116
194
|
),
|
|
117
195
|
]
|
|
@@ -124,9 +202,10 @@ class Question(TypedDict):
|
|
|
124
202
|
"Options for 'multiple_choice' and 'multi_select' questions. "
|
|
125
203
|
"Every choice needs a non-empty 'value'. An 'Other' free-form "
|
|
126
204
|
"option is always appended automatically for both types; "
|
|
127
|
-
"multi-select may collect multiple custom Other values. "
|
|
128
|
-
"'multi_select'
|
|
129
|
-
"
|
|
205
|
+
"multi-select may collect multiple custom Other values. A "
|
|
206
|
+
"'multi_select' answer is a JSON array of the selected "
|
|
207
|
+
"values, so values (including custom Other text) may "
|
|
208
|
+
"contain commas, quotes, and newlines."
|
|
130
209
|
)
|
|
131
210
|
),
|
|
132
211
|
]
|
|
@@ -170,6 +249,10 @@ MAX_ASK_USER_AUTHORIZATION_ANSWER_CHARS = 4000
|
|
|
170
249
|
# These limits bound the receipt-anchored question/answer evidence copied into
|
|
171
250
|
# Auto's classifier prompt. Questions are model-generated and otherwise have no
|
|
172
251
|
# schema length constraint, so they must not be able to exhaust that context.
|
|
252
|
+
# The answer budget is measured on the answer as it travels the wire, which for
|
|
253
|
+
# `multi_select` is the JSON encoding: escaping and quoting count toward the
|
|
254
|
+
# limit, so a selection can cross it while its decoded values would not.
|
|
255
|
+
# Crossing it withholds the receipt, which is the fail-closed direction.
|
|
173
256
|
MAX_ASK_USER_AUTHORIZATION_QUESTION_CHARS = 4000
|
|
174
257
|
MAX_ASK_USER_AUTHORIZATION_QUESTION_TOTAL_CHARS = 8000
|
|
175
258
|
|
|
@@ -205,6 +288,20 @@ AskUserWidgetResult = AskUserAnswered | AskUserCancelled
|
|
|
205
288
|
"""Discriminated union for the ask_user widget Future result."""
|
|
206
289
|
|
|
207
290
|
|
|
291
|
+
ASK_USER_NOTHING_SELECTED = "(nothing selected)"
|
|
292
|
+
"""Display-only placeholder for a `multi_select` the user left unselected.
|
|
293
|
+
|
|
294
|
+
Distinct from `ASK_USER_NO_ANSWER`, which marks a *missing* answer: this one
|
|
295
|
+
marks an answer that arrived and selected nothing. Only
|
|
296
|
+
`render_ask_user_transcript_for_display` produces it, and only for a human — the
|
|
297
|
+
transcript the model reads keeps the `[]` encoding.
|
|
298
|
+
|
|
299
|
+
In-band like the other placeholders, so a `multi_select` value spelled
|
|
300
|
+
`(nothing selected)` renders indistinguishably from an empty selection. The
|
|
301
|
+
result feeds no trust decision, so this costs legibility in a corner case
|
|
302
|
+
rather than correctness.
|
|
303
|
+
"""
|
|
304
|
+
|
|
208
305
|
ASK_USER_NO_ANSWER = "(no answer)"
|
|
209
306
|
"""Placeholder for a question with no positionally matching answer.
|
|
210
307
|
|
|
@@ -327,15 +424,25 @@ def format_ask_user_transcript(questions: list[Question], answers: list[str]) ->
|
|
|
327
424
|
r"""Render questions and answers as the `Q:`/`A:` transcript.
|
|
328
425
|
|
|
329
426
|
This is the text the `ask_user` tool returns to the model and persists in the
|
|
330
|
-
thread. The TUI renders that authoritative text literally
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
427
|
+
thread. The TUI renders that authoritative text literally, except for the
|
|
428
|
+
display-only re-render in `render_ask_user_transcript_for_display`, which
|
|
429
|
+
anchors on the known question text and gives up rather than guess.
|
|
430
|
+
|
|
431
|
+
Answers of every type are interpolated unescaped, so the encoding is not
|
|
432
|
+
unambiguously decodable: an answer containing a blank line followed by a
|
|
433
|
+
literal `Q: <text>\nA:` header is indistinguishable from a real block
|
|
434
|
+
boundary. Only the model reads it that way today. Any future decoder must
|
|
435
|
+
anchor on the known question text rather than on a generic `Q: ` pattern,
|
|
436
|
+
or a crafted answer can fabricate an extra question/answer pair.
|
|
437
|
+
|
|
438
|
+
For an answer `encode_multi_select_answer` produced, the JSON encoding does
|
|
439
|
+
close the hazard above: no encoded value can carry a raw line feed, so it
|
|
440
|
+
cannot fabricate a block boundary. This function cannot *rely* on that,
|
|
441
|
+
because it does not validate answers and not every answer is encoded — the
|
|
442
|
+
cancel and error paths in `_parse_answers` substitute `(cancelled)` and
|
|
443
|
+
`(error: ...)` placeholders for every question whatever its type, and a
|
|
444
|
+
non-TUI client resuming the interrupt can put arbitrary text in a
|
|
445
|
+
`multi_select` slot.
|
|
339
446
|
|
|
340
447
|
Args:
|
|
341
448
|
questions: Questions that were asked. Callers must pass questions whose
|
|
@@ -354,3 +461,90 @@ def format_ask_user_transcript(questions: list[Question], answers: list[str]) ->
|
|
|
354
461
|
for i, question in enumerate(questions)
|
|
355
462
|
]
|
|
356
463
|
return "\n\n".join(blocks)
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
def render_ask_user_transcript_for_display(
|
|
467
|
+
questions: list[Question], transcript: str
|
|
468
|
+
) -> str | None:
|
|
469
|
+
r"""Re-render a transcript with `multi_select` answers unpacked for a human.
|
|
470
|
+
|
|
471
|
+
The transcript is built for the model, where a `multi_select` answer is a
|
|
472
|
+
JSON array. A person reading the same text sees the quoting and, worse, sees
|
|
473
|
+
a multi-line custom answer flattened to a literal `\n`. This unpacks those
|
|
474
|
+
answers back to one value per line, leaving every other answer untouched.
|
|
475
|
+
|
|
476
|
+
Recovering the answers means splitting the transcript, which
|
|
477
|
+
`format_ask_user_transcript` warns is not unambiguously decodable. So this
|
|
478
|
+
anchors on the known question text, the mitigation that docstring
|
|
479
|
+
prescribes, and gives up rather than guessing: a transcript that does not
|
|
480
|
+
match the questions exactly returns `None` and must be rendered literally.
|
|
481
|
+
An answer may itself contain a later `Q: ...` block verbatim (pasting
|
|
482
|
+
transcript-like text into a text answer is legitimate), so a separator must
|
|
483
|
+
be unique to be trusted — with duplicates, the first occurrence would
|
|
484
|
+
swallow the real blocks into the wrong answer and misattribute the rest.
|
|
485
|
+
The result is display-only and feeds no trust decision.
|
|
486
|
+
|
|
487
|
+
Two things this deliberately does not do. It does not reject trailing
|
|
488
|
+
content: the last answer runs to the end of the transcript, so junk appended
|
|
489
|
+
after the final block is indistinguishable from answer text and is
|
|
490
|
+
re-emitted verbatim. And it does not handle three or more identically worded
|
|
491
|
+
questions — their shared anchor makes the separator non-unique, so a
|
|
492
|
+
perfectly well-formed transcript falls back to literal rendering. Both are
|
|
493
|
+
display-only outcomes.
|
|
494
|
+
|
|
495
|
+
Args:
|
|
496
|
+
questions: The questions that produced `transcript`, in order.
|
|
497
|
+
transcript: Output of `format_ask_user_transcript` for those questions.
|
|
498
|
+
|
|
499
|
+
Returns:
|
|
500
|
+
The re-rendered transcript, or `None` when `transcript` does not parse
|
|
501
|
+
as exactly these questions — including when no answer needed
|
|
502
|
+
unpacking, so the caller keeps its literal rendering. The two
|
|
503
|
+
cases share one sentinel because the caller wants the same literal
|
|
504
|
+
rendering either way. A caller that wants to report an unexpected
|
|
505
|
+
`None` should first check that a `multi_select` is present at all,
|
|
506
|
+
which is what the TUI row does.
|
|
507
|
+
"""
|
|
508
|
+
if not questions:
|
|
509
|
+
return None
|
|
510
|
+
anchors = [f"Q: {question.get('question', '')}\nA: " for question in questions]
|
|
511
|
+
answers: list[str] = []
|
|
512
|
+
position = 0
|
|
513
|
+
for index, anchor in enumerate(anchors):
|
|
514
|
+
if not transcript.startswith(anchor, position):
|
|
515
|
+
return None
|
|
516
|
+
position += len(anchor)
|
|
517
|
+
if index + 1 == len(anchors):
|
|
518
|
+
# The final answer runs to the end, so there is nothing left to
|
|
519
|
+
# check: trailing junk cannot be told apart from answer text.
|
|
520
|
+
answers.append(transcript[position:])
|
|
521
|
+
break
|
|
522
|
+
separator = f"\n\n{anchors[index + 1]}"
|
|
523
|
+
end = transcript.find(separator, position)
|
|
524
|
+
# `end` indexes the first of the two newlines, so `end + 2` is the `Q`
|
|
525
|
+
# of the next anchor. Re-searching from there cannot re-find this match,
|
|
526
|
+
# and cannot miss one that overlaps it: an occurrence starting at
|
|
527
|
+
# `end + 1` would need `transcript[end + 2]` to be a newline, and it is
|
|
528
|
+
# the `Q`. So the check establishes exactly one separator ahead.
|
|
529
|
+
if end == -1 or transcript.find(separator, end + 2) != -1:
|
|
530
|
+
return None
|
|
531
|
+
answers.append(transcript[position:end])
|
|
532
|
+
position = end + 2
|
|
533
|
+
|
|
534
|
+
changed = False
|
|
535
|
+
blocks: list[str] = []
|
|
536
|
+
for question, answer in zip(questions, answers, strict=True):
|
|
537
|
+
rendered = answer
|
|
538
|
+
if question.get("type") == "multi_select":
|
|
539
|
+
values = decode_multi_select_answer(answer)
|
|
540
|
+
if values is not None:
|
|
541
|
+
# One per line, so a value that itself spans lines stays
|
|
542
|
+
# legible. This trades away distinguishability: `["a", "b"]` and
|
|
543
|
+
# `["a\nb"]` render identically. Legibility is the point here and
|
|
544
|
+
# nothing downstream parses the result, so the trade is fine.
|
|
545
|
+
rendered = "\n".join(values) if values else ASK_USER_NOTHING_SELECTED
|
|
546
|
+
changed = changed or rendered != answer
|
|
547
|
+
blocks.append(f"Q: {question.get('question', '')}\nA: {rendered}")
|
|
548
|
+
if not changed:
|
|
549
|
+
return None
|
|
550
|
+
return "\n\n".join(blocks)
|
|
@@ -528,6 +528,18 @@ Defaults to enabled; set to a falsy value (`0`, `false`, `no`, `off`, or empty)
|
|
|
528
528
|
to suppress the success toast while still opening URLs normally.
|
|
529
529
|
"""
|
|
530
530
|
|
|
531
|
+
SHOW_USAGE_STATS = "DEEPAGENTS_CODE_SHOW_USAGE_STATS"
|
|
532
|
+
"""Print the session usage-statistics table when a session ends.
|
|
533
|
+
|
|
534
|
+
Defaults to enabled; set to a falsy value (`0`, `false`, `no`, `off`, or empty)
|
|
535
|
+
to suppress the table. Applies to both the TUI teardown and the headless
|
|
536
|
+
`-x`/`--execute` run, which is why the option carries an env var at all: a CI
|
|
537
|
+
runner can set one, but rarely has a `~/.deepagents/config.toml` to edit.
|
|
538
|
+
|
|
539
|
+
Suppressing only the table is narrower than `--quiet`, which silences the rest
|
|
540
|
+
of the headless teardown output too.
|
|
541
|
+
"""
|
|
542
|
+
|
|
531
543
|
SPLASH_SHOW_CWD = "DEEPAGENTS_CODE_SPLASH_SHOW_CWD"
|
|
532
544
|
"""Show the working-directory row in the startup welcome banner when enabled.
|
|
533
545
|
|
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
"""Lightweight session statistics, token formatting, and usage-table rendering.
|
|
2
2
|
|
|
3
|
-
Holds `SessionStats`/`ModelStats`, the `format_token_count` formatter,
|
|
4
|
-
`print_usage_table` (which imports `rich.table` lazily)
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
`
|
|
3
|
+
Holds `SessionStats`/`ModelStats`, the `format_token_count` formatter,
|
|
4
|
+
`print_usage_table` (which imports `rich.table` lazily), and
|
|
5
|
+
`usage_table_enabled`, which decides whether that table is rendered at all.
|
|
6
|
+
The module is intentionally kept free of heavy top-level dependencies (no
|
|
7
|
+
pydantic, no config, no widget imports) so that `app.py` can import
|
|
8
|
+
`SessionStats` and `format_token_count` at module level without pulling in the
|
|
9
|
+
full `textual_adapter` dependency tree — hence the deferred `config_manifest`
|
|
10
|
+
import inside `usage_table_enabled` rather than at the top.
|
|
9
11
|
"""
|
|
10
12
|
|
|
11
13
|
from __future__ import annotations
|
|
12
14
|
|
|
13
15
|
import logging
|
|
14
16
|
import math
|
|
17
|
+
import sys
|
|
15
18
|
from collections.abc import Mapping
|
|
16
19
|
from dataclasses import dataclass, field, replace
|
|
17
20
|
from decimal import ROUND_CEILING, Decimal
|
|
@@ -24,6 +27,9 @@ if TYPE_CHECKING:
|
|
|
24
27
|
|
|
25
28
|
logger = logging.getLogger(__name__)
|
|
26
29
|
|
|
30
|
+
_warned_usage_stats_rejections: set[str] = set()
|
|
31
|
+
"""Rejection reasons already reported by `_warn_rejected_usage_stats_value`."""
|
|
32
|
+
|
|
27
33
|
SpinnerStatus = (
|
|
28
34
|
Literal[
|
|
29
35
|
"Thinking",
|
|
@@ -969,6 +975,84 @@ def _recorded_cost(cost_usd: float, priced_request_count: int) -> str:
|
|
|
969
975
|
return format_cost(cost_usd) if priced_request_count else "—"
|
|
970
976
|
|
|
971
977
|
|
|
978
|
+
def _warn_rejected_usage_stats_value(reason: str) -> None:
|
|
979
|
+
"""Report a rejected `show_usage_stats` value on stderr.
|
|
980
|
+
|
|
981
|
+
Every other rejection in this codebase is logged and left there, which is
|
|
982
|
+
right for an option that falls through to a cosmetic default. This one can
|
|
983
|
+
fall through to *showing the table* — the single outcome the user was
|
|
984
|
+
trying to prevent — and the log has no reader outside the TUI Debug
|
|
985
|
+
Console, so a quoted `"false"` or a bare `no` would otherwise look exactly
|
|
986
|
+
like never having set the option. `dcode config set` does not exist, so
|
|
987
|
+
hand-edited TOML is the only input path and typos are the expected case.
|
|
988
|
+
|
|
989
|
+
Both call sites are at teardown, where stderr is a plain stream rather than
|
|
990
|
+
a live interface, so this cannot land on top of the TUI.
|
|
991
|
+
|
|
992
|
+
The line states only the rejection, not the outcome: the resolver reports
|
|
993
|
+
rejections at or above the winning tier, so when a stronger source cleanly
|
|
994
|
+
disables the table the outcome half would contradict what the user sees.
|
|
995
|
+
|
|
996
|
+
Deduped per reason rather than per process: resolving once per session is
|
|
997
|
+
the norm, but `dcode config` walks the whole manifest, and a line repeated
|
|
998
|
+
verbatim reads as two separate problems. Two *different* reasons — managed
|
|
999
|
+
config and the user file both rejected — really are two problems and both
|
|
1000
|
+
print.
|
|
1001
|
+
|
|
1002
|
+
Args:
|
|
1003
|
+
reason: Rejection text from the resolver.
|
|
1004
|
+
"""
|
|
1005
|
+
if reason in _warned_usage_stats_rejections:
|
|
1006
|
+
return
|
|
1007
|
+
_warned_usage_stats_rejections.add(reason)
|
|
1008
|
+
print(f"Warning: {reason}", file=sys.stderr) # noqa: T201
|
|
1009
|
+
logger.warning("%s", reason)
|
|
1010
|
+
|
|
1011
|
+
|
|
1012
|
+
def usage_table_enabled() -> bool:
|
|
1013
|
+
"""Return whether the session usage table should be rendered.
|
|
1014
|
+
|
|
1015
|
+
Controlled by `[ui].show_usage_stats` or `DEEPAGENTS_CODE_SHOW_USAGE_STATS`.
|
|
1016
|
+
Both the TUI teardown and the headless run call this rather than resolving
|
|
1017
|
+
the option themselves, so the key and its fallback pair are written once
|
|
1018
|
+
and the two surfaces cannot disagree about the default.
|
|
1019
|
+
|
|
1020
|
+
Fails open: both callers are at teardown, where an exception would cost far
|
|
1021
|
+
more than the table is worth, so a broad catch is warranted for a leaf,
|
|
1022
|
+
cosmetic decision with a safe default — provided it is logged rather than
|
|
1023
|
+
swallowed. The call sites document what an escape would actually break.
|
|
1024
|
+
|
|
1025
|
+
`BlockingError` is excluded from that fail-open, matching
|
|
1026
|
+
`configurable_model._resolve_openai_prompt_cache_key_enabled`: it signals
|
|
1027
|
+
blocking I/O on the event loop, which is a real regression rather than a
|
|
1028
|
+
config hiccup, and this is called directly from the async headless
|
|
1029
|
+
teardown. It is matched by class name because `blockbuster` is not a
|
|
1030
|
+
runtime dependency of this package.
|
|
1031
|
+
|
|
1032
|
+
The `config_manifest` import is deliberately outside the `try`, so an
|
|
1033
|
+
`ImportError` propagates instead of being reported as a config failure.
|
|
1034
|
+
|
|
1035
|
+
Returns:
|
|
1036
|
+
Whether to render the table.
|
|
1037
|
+
"""
|
|
1038
|
+
from deepagents_code.config_manifest import load_bool_display_preference
|
|
1039
|
+
|
|
1040
|
+
try:
|
|
1041
|
+
return load_bool_display_preference(
|
|
1042
|
+
"display.show_usage_stats",
|
|
1043
|
+
fallback=True,
|
|
1044
|
+
on_rejected=_warn_rejected_usage_stats_value,
|
|
1045
|
+
)
|
|
1046
|
+
except Exception as exc:
|
|
1047
|
+
if any(cls.__name__ == "BlockingError" for cls in type(exc).__mro__):
|
|
1048
|
+
raise
|
|
1049
|
+
logger.warning(
|
|
1050
|
+
"Could not resolve display.show_usage_stats; showing the table",
|
|
1051
|
+
exc_info=True,
|
|
1052
|
+
)
|
|
1053
|
+
return True
|
|
1054
|
+
|
|
1055
|
+
|
|
972
1056
|
def print_usage_table(
|
|
973
1057
|
stats: SessionStats,
|
|
974
1058
|
wall_time: float,
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""Exception type for tool arguments the model authored incorrectly.
|
|
2
|
+
|
|
3
|
+
Lives in its own module so both the tools that raise it and the agent wiring
|
|
4
|
+
that recovers from it can import it without a circular import.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ToolArgumentError(ValueError):
|
|
11
|
+
"""A tool rejected arguments the model authored.
|
|
12
|
+
|
|
13
|
+
Raise this only when the model can fix the call by rewriting its arguments.
|
|
14
|
+
`create_cli_agent` wires a `ToolErrorMiddleware` that turns this into an
|
|
15
|
+
error `ToolMessage` the model can retry from. Every other exception, plain
|
|
16
|
+
`ValueError` included, stays fatal.
|
|
17
|
+
|
|
18
|
+
Subclasses `ValueError` so existing callers that catch `ValueError` around
|
|
19
|
+
tool argument validation keep working.
|
|
20
|
+
"""
|