deepagents-code 0.1.32__tar.gz → 0.1.33__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.32 → deepagents_code-0.1.33}/CHANGELOG.md +13 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/PKG-INFO +5 -5
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/THREAT_MODEL.md +1 -1
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/_build_info.py +1 -1
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/_env_vars.py +36 -0
- deepagents_code-0.1.33/deepagents_code/_fake_models.py +66 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/_testing_models.py +22 -34
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/_version.py +1 -1
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/agent.py +16 -9
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/app.py +180 -2
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/config.py +55 -8
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/config_manifest.py +44 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/input.py +198 -12
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/main.py +91 -8
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/mcp_disabled.py +52 -22
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/mcp_tools.py +262 -65
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/media_utils.py +137 -3
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/model_config.py +243 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/non_interactive.py +6 -1
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/skills/commands.py +172 -2
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/skills/invocation.py +9 -0
- deepagents_code-0.1.33/deepagents_code/skills/trust.py +547 -0
- deepagents_code-0.1.33/deepagents_code/tool_catalog.py +354 -0
- deepagents_code-0.1.33/deepagents_code/tools_commands.py +402 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/ui.py +49 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/chat_input.py +76 -5
- deepagents_code-0.1.33/deepagents_code/widgets/skill_trust.py +131 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/pyproject.toml +4 -4
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/skills/test_commands.py +287 -0
- deepagents_code-0.1.33/tests/unit_tests/skills/test_skill_trust.py +528 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_chat_input.py +198 -1
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_main.py +221 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_mcp_disabled.py +59 -2
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_mcp_tools.py +462 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_media_utils.py +369 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_model_config.py +323 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_non_interactive.py +58 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_reload.py +205 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_skill_invocation.py +407 -4
- deepagents_code-0.1.33/tests/unit_tests/test_skill_trust_screen.py +78 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_startup_fast_paths.py +1 -0
- deepagents_code-0.1.33/tests/unit_tests/test_tool_catalog.py +334 -0
- deepagents_code-0.1.33/tests/unit_tests/test_tools_commands.py +527 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/uv.lock +6 -6
- deepagents_code-0.1.32/deepagents_code/tools_commands.py +0 -191
- deepagents_code-0.1.32/tests/unit_tests/test_tools_commands.py +0 -144
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/.gitignore +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/AGENTS.md +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/ARCHITECTURE.md +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/COMMANDS.md +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/DEVELOPMENT.md +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/Makefile +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/README.md +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/__init__.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/__main__.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/_ask_user_types.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/_cli_context.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/_constants.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/_debug.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/_git.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/_paths.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/_server_config.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/_session_stats.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/_startup_error.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/_textual_patches.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/_tool_stream.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/app.tcss +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/approval_mode.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/ask_user.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/auth_commands.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/auth_display.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/auth_store.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/built_in_skills/__init__.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/built_in_skills/remember/SKILL.md +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/built_in_skills/skill-creator/SKILL.md +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/built_in_skills/skill-creator/scripts/init_skill.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/built_in_skills/skill-creator/scripts/quick_validate.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/clipboard.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/command_registry.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/config_commands.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/configurable_model.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/default_agent_prompt.md +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/doctor.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/editor.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/event_bus.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/extras_info.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/file_ops.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/formatting.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/goal_rubric.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/goal_tools.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/hooks.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/integrations/__init__.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/integrations/openai_codex.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/integrations/sandbox_config.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/integrations/sandbox_factory.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/integrations/sandbox_provider.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/integrations/sandbox_registry.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/iterm_cursor_guide.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/local_context.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/managed_tools.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/mcp_auth.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/mcp_commands.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/mcp_login_service.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/mcp_oauth_ui.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/mcp_providers/__init__.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/mcp_providers/_registry.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/mcp_providers/base.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/mcp_providers/github.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/mcp_providers/slack.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/mcp_trust.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/memory_guard.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/notifications.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/offload.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/onboarding.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/output.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/paste_collapse.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/project_utils.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/py.typed +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/reasoning_effort.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/remote_client.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/resume_state.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/server.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/server_graph.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/server_manager.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/sessions.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/skills/__init__.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/skills/load.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/state_migration.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/subagents.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/system_prompt.md +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/terminal_capabilities.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/terminal_escape.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/textual_adapter.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/theme.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/tool_display.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/tools.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/unicode_security.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/update_check.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/__init__.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/_js_eval_display.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/_links.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/agent_selector.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/approval.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/ask_user.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/auth.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/autocomplete.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/codex_auth.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/cwd_switch.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/diff.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/effort_selector.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/goal_review.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/history.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/install_confirm.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/launch_init.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/loading.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/mcp_login.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/mcp_reconnect.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/mcp_viewer.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/message_store.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/messages.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/model_selector.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/notification_center.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/notification_detail.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/notification_settings.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/restart_prompt.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/status.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/subagent_panel.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/theme_selector.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/thread_selector.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/tool_renderers.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/tool_widgets.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/update_available.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/update_confirm.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/update_progress.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/deepagents_code/widgets/welcome.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/examples/skills/arxiv-search/SKILL.md +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/examples/skills/arxiv-search/arxiv_search.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/examples/skills/langgraph-docs/SKILL.md +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/examples/skills/skill-creator/SKILL.md +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/examples/skills/skill-creator/scripts/init_skill.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/examples/skills/skill-creator/scripts/quick_validate.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/examples/skills/web-research/SKILL.md +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/hatch_build.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/images/tui.png +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/scripts/check_imports.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/scripts/debug_server.sh +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/scripts/generate_commands_catalog.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/scripts/install.sh +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/README.md +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/integration_tests/__init__.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/integration_tests/benchmarks/__init__.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/integration_tests/benchmarks/test_codspeed_import_benchmarks.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/integration_tests/benchmarks/test_startup_benchmarks.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/integration_tests/conftest.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/integration_tests/test_acp_mode.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/integration_tests/test_auto_approve_remote.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/integration_tests/test_compact_resume.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/integration_tests/test_sandbox_factory.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/integration_tests/test_sandbox_operations.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/__init__.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/conftest.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/data/coding_agent_v1_validator.json +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/skills/__init__.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/skills/test_load.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/skills/test_skills_json.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/smoke_tests/__init__.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/smoke_tests/conftest.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/smoke_tests/snapshots/system_prompt_interactive_local.md +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/smoke_tests/test_system_prompt.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test__tool_stream.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_agent.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_agent_friendly.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_agent_selector.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_app.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_approval.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_approval_mode.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_args.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_ask_user.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_ask_user_middleware.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_auth_commands.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_auth_display.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_auth_store.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_auth_widgets.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_autocomplete.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_charset.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_clipboard.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_coding_agent_metadata.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_command_registry.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_compact_tool.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_config.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_config_manifest.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_configurable_model.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_cursor_blink.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_cwd_switch.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_debug.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_doctor.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_editor.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_end_to_end.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_env_vars.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_event_bus.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_exception_handling.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_extras_info.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_file_ops.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_formatting.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_git.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_goal_review.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_goal_rubric.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_goal_tools.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_hatch_build.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_history.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_hooks.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_imports.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_input_parsing.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_install_command.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_install_confirm.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_install_script.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_iterm_cursor_guide.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_launch_init.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_links.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_loading.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_local_context.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_main_acp_mode.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_main_args.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_managed_tools.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_mcp_auth.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_mcp_commands.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_mcp_login_modal.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_mcp_login_service.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_mcp_oauth_ui.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_mcp_reconnect.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_mcp_trust.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_mcp_viewer.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_memory_guard.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_message_store.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_messages.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_model_selector.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_model_switch.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_notification_center.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_notification_detail.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_notifications.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_offload.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_offload_dict_messages.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_onboarding.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_openai_codex_integration.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_output.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_paths.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_reasoning_effort.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_remote_client.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_restart_prompt.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_resume_state.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_rubric_cli.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_sandbox_config.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_sandbox_factory.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_sandbox_provider.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_sandbox_registry.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_server.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_server_config.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_server_graph.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_server_helpers.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_server_manager.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_session_stats.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_sessions.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_shell_allow_list.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_state_migration.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_status.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_subagent_panel.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_subagent_stream.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_subagents.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_terminal_capabilities.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_terminal_escape.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_terminal_progress_preference.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_textual_adapter.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_textual_patches.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_theme.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_thread_selector.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_tool_display.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_tool_renderers.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_tracing_replicas.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_ui.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_unicode_security.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_update_available.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_update_check.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_update_confirm.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_update_progress.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_version.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/test_welcome.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/tools/__init__.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/tools/test_current_thread.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/tools/test_fetch_url.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/widgets/__init__.py +0 -0
- {deepagents_code-0.1.32 → deepagents_code-0.1.33}/tests/unit_tests/widgets/test_diff.py +0 -0
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
# Deep Agents Code Changelog
|
|
4
4
|
|
|
5
|
+
## [0.1.33](https://github.com/langchain-ai/deepagents/compare/deepagents-code==0.1.32...deepagents-code==0.1.33) (2026-07-06)
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
|
|
9
|
+
* In-the-moment trust prompt for symlinked skills ([#4200](https://github.com/langchain-ai/deepagents/issues/4200)) ([a4431e4](https://github.com/langchain-ai/deepagents/commit/a4431e4339348431e91533cb2b177259ab94b083))
|
|
10
|
+
* Selective per-server project MCP trust ([#4507](https://github.com/langchain-ai/deepagents/issues/4507)) ([aaa22a9](https://github.com/langchain-ai/deepagents/commit/aaa22a9340cb3d2c8e9ce1a921957d0a9121da20))
|
|
11
|
+
* Add `dcode tools list` command ([#4461](https://github.com/langchain-ai/deepagents/issues/4461)) ([1402d0e](https://github.com/langchain-ai/deepagents/commit/1402d0e735a1580503f240457c77db76fcd779d7))
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* Strip media placeholders from model-facing message text ([#4462](https://github.com/langchain-ai/deepagents/issues/4462)) ([aa0ae36](https://github.com/langchain-ai/deepagents/commit/aa0ae36b00df6411a9200610a9075ef2dc28b1af))
|
|
16
|
+
* Re-apply theme preference on `/reload` ([#4514](https://github.com/langchain-ai/deepagents/issues/4514)) ([5d1c392](https://github.com/langchain-ai/deepagents/commit/5d1c3928f7ca0ea97f28fd4d34ae1a4ee885e888))
|
|
17
|
+
|
|
5
18
|
## [0.1.32](https://github.com/langchain-ai/deepagents/compare/deepagents-code==0.1.31...deepagents-code==0.1.32) (2026-07-06)
|
|
6
19
|
|
|
7
20
|
### Features
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deepagents-code
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.33
|
|
4
4
|
Summary: Terminal interface for Deep Agents - interactive AI agent with file operations, shell access, and sub-agent capabilities.
|
|
5
5
|
Project-URL: Homepage, https://docs.langchain.com/oss/python/deepagents/overview
|
|
6
6
|
Project-URL: Documentation, https://reference.langchain.com/python/deepagents/
|
|
@@ -27,10 +27,10 @@ Classifier: Topic :: Terminals
|
|
|
27
27
|
Requires-Python: <4.0,>=3.11
|
|
28
28
|
Requires-Dist: aiosqlite<1.0.0,>=0.22.1
|
|
29
29
|
Requires-Dist: deepagents-acp<1.0.0,>=0.0.8
|
|
30
|
-
Requires-Dist: deepagents==0.7.
|
|
30
|
+
Requires-Dist: deepagents==0.7.0a4
|
|
31
31
|
Requires-Dist: httpx<1.0.0,>=0.28.1
|
|
32
32
|
Requires-Dist: langchain-anthropic<2.0.0,>=1.4.7
|
|
33
|
-
Requires-Dist: langchain-google-genai<5.0.0,>=4.2.
|
|
33
|
+
Requires-Dist: langchain-google-genai<5.0.0,>=4.2.7
|
|
34
34
|
Requires-Dist: langchain-mcp-adapters<1.0.0,>=0.3.0
|
|
35
35
|
Requires-Dist: langchain-openai<2.0.0,>=1.3.3
|
|
36
36
|
Requires-Dist: langchain-quickjs<0.4.0,>=0.3.2
|
|
@@ -67,7 +67,7 @@ Requires-Dist: langchain-baseten<1.0.0,>=0.2.1; extra == 'all-providers'
|
|
|
67
67
|
Requires-Dist: langchain-cohere<1.0.0,>=0.6.0; extra == 'all-providers'
|
|
68
68
|
Requires-Dist: langchain-deepseek<2.0.0,>=1.1.0; extra == 'all-providers'
|
|
69
69
|
Requires-Dist: langchain-fireworks<2.0.0,>=1.4.3; extra == 'all-providers'
|
|
70
|
-
Requires-Dist: langchain-google-genai<5.0.0,>=4.2.
|
|
70
|
+
Requires-Dist: langchain-google-genai<5.0.0,>=4.2.7; extra == 'all-providers'
|
|
71
71
|
Requires-Dist: langchain-google-vertexai<4.0.0,>=3.2.4; extra == 'all-providers'
|
|
72
72
|
Requires-Dist: langchain-groq<2.0.0,>=1.1.3; extra == 'all-providers'
|
|
73
73
|
Requires-Dist: langchain-huggingface<2.0.0,>=1.2.2; extra == 'all-providers'
|
|
@@ -102,7 +102,7 @@ Requires-Dist: langchain-deepseek<2.0.0,>=1.1.0; extra == 'deepseek'
|
|
|
102
102
|
Provides-Extra: fireworks
|
|
103
103
|
Requires-Dist: langchain-fireworks<2.0.0,>=1.4.3; extra == 'fireworks'
|
|
104
104
|
Provides-Extra: google-genai
|
|
105
|
-
Requires-Dist: langchain-google-genai<5.0.0,>=4.2.
|
|
105
|
+
Requires-Dist: langchain-google-genai<5.0.0,>=4.2.7; extra == 'google-genai'
|
|
106
106
|
Provides-Extra: groq
|
|
107
107
|
Requires-Dist: langchain-groq<2.0.0,>=1.1.3; extra == 'groq'
|
|
108
108
|
Provides-Extra: huggingface
|
|
@@ -232,7 +232,7 @@
|
|
|
232
232
|
|
|
233
233
|
#### TB4: MCP Config → Process / Network
|
|
234
234
|
|
|
235
|
-
- **Inside**: `mcp_tools._validate_server_config` validates JSON structure and field types. `mcp_trust.compute_config_fingerprint` computes SHA-256 over config file contents. Project-level stdio servers require trust approval (fingerprint prompt) unless `--trust-project-mcp` is set.
|
|
235
|
+
- **Inside**: `mcp_tools._validate_server_config` validates JSON structure and field types. `mcp_trust.compute_config_fingerprint` computes SHA-256 over config file contents. Project-level stdio servers require trust approval (fingerprint prompt) unless `--trust-project-mcp` is set. A user can selectively pre-approve or reject individual project servers by name via `[mcp].enabled_project_servers` / `disabled_project_servers` (or the `DEEPAGENTS_CODE_ENABLED_PROJECT_MCP_SERVERS` / `..._DISABLED_...` env vars); reject wins over approval and over full trust. These lists are read by `model_config.load_mcp_server_trust_lists` only from user-controlled sources — the user-level `~/.deepagents/config.toml`, the global `~/.deepagents/.env`, and shell-exported env — never from `.mcp.json` or any repo-committed file, so a committed config cannot self-approve its own servers. In particular, the env forms (`DEEPAGENTS_CODE_ENABLED_PROJECT_MCP_SERVERS` / `..._DISABLED_...`) are added to `config._PROJECT_DOTENV_DENIED_ENV_KEYS`, so a committed *project* `.env` cannot inject them into `os.environ` even though it is loaded at bootstrap. Enabled resolves env-over-TOML, but disabled *unions* TOML and env so a deny can never be silently emptied by the other source. If the user's `config.toml` exists but cannot be read or parsed, the loader fails closed (project configs are treated as untrusted and the error is surfaced) rather than proceeding with an empty deny list. Only allowlisted (or fully trusted) names survive into the merged config, so a non-allowlisted remote entry is never preflighted and its interpolated headers are never resolved. Note that the allow list binds by server *name*, not by fingerprint: an allowlisted name is loaded whatever definition the repo currently gives it, bypassing the fingerprint change-detection that re-prompts on full-config trust — so users should only allowlist names in repos they would otherwise trust.
|
|
236
236
|
- **Outside**: Stdio server `command`, `args`, and `env` fields are user-controlled strings passed directly to `StdioConnection`. The `env` dict from MCP config is forwarded without filtering — users can set arbitrary environment variables (including `PATH`, `LD_PRELOAD`, `PYTHONPATH`) for the MCP subprocess.
|
|
237
237
|
- **Crossing mechanism**: `subprocess.Popen` (via `langchain_mcp_adapters`) for stdio; HTTP/SSE for remote servers.
|
|
238
238
|
|
|
@@ -93,6 +93,42 @@ real PyPI release.
|
|
|
93
93
|
Any non-empty value enables the flag (including `"0"` or `"false"`).
|
|
94
94
|
"""
|
|
95
95
|
|
|
96
|
+
DISABLED_PROJECT_MCP_SERVERS = "DEEPAGENTS_CODE_DISABLED_PROJECT_MCP_SERVERS"
|
|
97
|
+
"""Comma-separated project MCP server names to always reject by name.
|
|
98
|
+
|
|
99
|
+
A user-level equivalent of `[mcp].disabled_project_servers`.
|
|
100
|
+
|
|
101
|
+
Rejection wins over approval: a name listed here is dropped even when it also
|
|
102
|
+
appears in `ENABLED_PROJECT_MCP_SERVERS` (or `[mcp].enabled_project_servers`)
|
|
103
|
+
and even when the project config is otherwise trusted. Unlike the enabled list,
|
|
104
|
+
this env var *unions* with (rather than replaces)
|
|
105
|
+
`[mcp].disabled_project_servers` — denies accumulate across sources, so neither
|
|
106
|
+
can silently empty a deny set in the other. This is process env the user
|
|
107
|
+
controls, not a repo file, so it does not weaken the user-level-only
|
|
108
|
+
trust boundary: a committed *project* `.env` is blocked from setting it
|
|
109
|
+
(see `config._PROJECT_DOTENV_DENIED_ENV_KEYS`); only the user's shell,
|
|
110
|
+
launch env, or global `~/.deepagents/.env` can.
|
|
111
|
+
"""
|
|
112
|
+
|
|
113
|
+
ENABLED_PROJECT_MCP_SERVERS = "DEEPAGENTS_CODE_ENABLED_PROJECT_MCP_SERVERS"
|
|
114
|
+
"""Comma-separated project MCP server names to pre-approve by name.
|
|
115
|
+
|
|
116
|
+
A user-level equivalent of `[mcp].enabled_project_servers`.
|
|
117
|
+
|
|
118
|
+
Servers named here load from an otherwise-untrusted project `.mcp.json` without
|
|
119
|
+
prompting (they are omitted from the interactive approval prompt), while
|
|
120
|
+
non-listed servers stay dropped. Like `DISABLED_PROJECT_MCP_SERVERS`, this is
|
|
121
|
+
user-controlled process env, not a repo file, so it does not weaken
|
|
122
|
+
the user-level-only trust boundary (a committed *project* `.env` cannot set it;
|
|
123
|
+
see `config._PROJECT_DOTENV_DENIED_ENV_KEYS`). This contract is name-based:
|
|
124
|
+
a project command or URL change under the same server name still matches.
|
|
125
|
+
|
|
126
|
+
When set, this replaces (takes precedence over) the
|
|
127
|
+
`[mcp].enabled_project_servers` TOML list.
|
|
128
|
+
(`DISABLED_PROJECT_MCP_SERVERS` instead *unions* with its TOML list, so a deny
|
|
129
|
+
is never silently emptied.)
|
|
130
|
+
"""
|
|
131
|
+
|
|
96
132
|
EXTERNAL_EVENT_SOCKET = "DEEPAGENTS_CODE_EXTERNAL_EVENT_SOCKET"
|
|
97
133
|
"""Enable the local Unix-socket external event listener.
|
|
98
134
|
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""Fake chat model base shared by integration tests and tool enumeration.
|
|
2
|
+
|
|
3
|
+
Holds the tool-binding base that both the local integration-test fakes
|
|
4
|
+
(`_testing_models`) and the `dcode tools list` tool-enumeration path
|
|
5
|
+
(`tool_catalog._CatalogModel`) build on. It lives in a use-neutral module — not
|
|
6
|
+
under a `_testing_`-prefixed name — so a production import path never depends on
|
|
7
|
+
something that reads as test-only and might be pruned or excluded from the wheel.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from typing import TYPE_CHECKING, Any
|
|
13
|
+
|
|
14
|
+
from langchain_core.language_models.fake_chat_models import GenericFakeChatModel
|
|
15
|
+
from pydantic import Field
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from collections.abc import Callable, Sequence
|
|
19
|
+
|
|
20
|
+
from langchain_core.language_models import LanguageModelInput
|
|
21
|
+
from langchain_core.messages import AIMessage
|
|
22
|
+
from langchain_core.runnables import Runnable
|
|
23
|
+
from langchain_core.tools import BaseTool
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
_TOOL_BINDING_MODEL_PROFILE: dict[str, Any] = {
|
|
27
|
+
"tool_calling": True,
|
|
28
|
+
"max_input_tokens": 8000,
|
|
29
|
+
}
|
|
30
|
+
"""Minimal capability profile the agent runtime reads while compiling a model.
|
|
31
|
+
|
|
32
|
+
Only `tool_calling` is load-bearing — the agent negotiates tool support at
|
|
33
|
+
setup. `max_input_tokens` is part of the profile surface but inert here: these
|
|
34
|
+
models are compiled to bind tools and are never invoked, so no token budget ever
|
|
35
|
+
applies. Defined once so both the integration-test fakes and
|
|
36
|
+
`tool_catalog._CatalogModel` share a single source of truth.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class _ToolBindingFakeModel(GenericFakeChatModel):
|
|
41
|
+
"""Base for fake chat models that must bind tools but are never invoked.
|
|
42
|
+
|
|
43
|
+
The agent runtime calls `model.bind_tools(schemas)` and reads `model.profile`
|
|
44
|
+
while compiling the graph, and a bare `GenericFakeChatModel` cannot be
|
|
45
|
+
compiled into an agent graph: it inherits `BaseChatModel.bind_tools`, which
|
|
46
|
+
raises `NotImplementedError`, and its `profile` is `None`, which breaks
|
|
47
|
+
capability negotiation. This base supplies a no-op `bind_tools` passthrough
|
|
48
|
+
and a minimal `profile`, leaving subclasses to add generation behavior
|
|
49
|
+
(tests) or nothing at all (tool enumeration).
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
# Required by `GenericFakeChatModel`, but subclasses never consume it.
|
|
53
|
+
messages: object = Field(default_factory=lambda: iter(()))
|
|
54
|
+
profile: dict[str, Any] | None = Field(
|
|
55
|
+
default_factory=lambda: dict(_TOOL_BINDING_MODEL_PROFILE)
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
def bind_tools(
|
|
59
|
+
self,
|
|
60
|
+
tools: Sequence[dict[str, Any] | type | Callable | BaseTool], # noqa: ARG002
|
|
61
|
+
*,
|
|
62
|
+
tool_choice: str | None = None, # noqa: ARG002
|
|
63
|
+
**kwargs: Any, # noqa: ARG002
|
|
64
|
+
) -> Runnable[LanguageModelInput, AIMessage]:
|
|
65
|
+
"""Return self so the agent can bind tool schemas without a real model."""
|
|
66
|
+
return self
|
|
@@ -1,21 +1,23 @@
|
|
|
1
|
-
"""Internal chat models
|
|
1
|
+
"""Internal fake chat models for local integration tests.
|
|
2
|
+
|
|
3
|
+
The tool-binding base these build on (`_fake_models._ToolBindingFakeModel`) is
|
|
4
|
+
factored out into a use-neutral module so the `dcode tools list` enumeration
|
|
5
|
+
path can reuse it without importing this test-named module.
|
|
6
|
+
"""
|
|
2
7
|
|
|
3
8
|
from __future__ import annotations
|
|
4
9
|
|
|
5
10
|
from typing import TYPE_CHECKING, Any
|
|
6
11
|
|
|
7
|
-
from langchain_core.language_models.fake_chat_models import GenericFakeChatModel
|
|
8
12
|
from langchain_core.messages import AIMessage, BaseMessage
|
|
9
13
|
from langchain_core.outputs import ChatGeneration, ChatResult
|
|
10
|
-
|
|
14
|
+
|
|
15
|
+
from deepagents_code._fake_models import _ToolBindingFakeModel
|
|
11
16
|
|
|
12
17
|
if TYPE_CHECKING:
|
|
13
|
-
from collections.abc import Callable
|
|
18
|
+
from collections.abc import Callable
|
|
14
19
|
|
|
15
20
|
from langchain_core.callbacks import CallbackManagerForLLMRun
|
|
16
|
-
from langchain_core.language_models import LanguageModelInput
|
|
17
|
-
from langchain_core.runnables import Runnable
|
|
18
|
-
from langchain_core.tools import BaseTool
|
|
19
21
|
|
|
20
22
|
|
|
21
23
|
# Prompt markers that drive `ToolCallingIntegrationChatModel`. Each marker is the
|
|
@@ -33,13 +35,13 @@ TOP_LEVEL_WRITE_CONTENT = "auto-approved"
|
|
|
33
35
|
SUBAGENT_WRITE_CONTENT = "auto-approved-subagent"
|
|
34
36
|
|
|
35
37
|
|
|
36
|
-
class DeterministicIntegrationChatModel(
|
|
38
|
+
class DeterministicIntegrationChatModel(_ToolBindingFakeModel):
|
|
37
39
|
"""Deterministic chat model for integration tests.
|
|
38
40
|
|
|
39
|
-
This subclasses
|
|
40
|
-
stays aligned with the core fake-chat-model test surface,
|
|
41
|
-
generation to remain prompt-driven and restart-safe for real
|
|
42
|
-
integration tests.
|
|
41
|
+
This subclasses `_ToolBindingFakeModel` (itself a `GenericFakeChatModel`) so
|
|
42
|
+
the implementation stays aligned with the core fake-chat-model test surface,
|
|
43
|
+
while overriding generation to remain prompt-driven and restart-safe for real
|
|
44
|
+
CLI server integration tests.
|
|
43
45
|
|
|
44
46
|
Why the existing `langchain_core` fakes cannot be reused here:
|
|
45
47
|
|
|
@@ -53,13 +55,15 @@ class DeterministicIntegrationChatModel(GenericFakeChatModel):
|
|
|
53
55
|
identical output regardless of process lifecycle.
|
|
54
56
|
|
|
55
57
|
2. The agent runtime calls `model.bind_tools(schemas)` during
|
|
56
|
-
initialization.
|
|
57
|
-
|
|
58
|
+
initialization. A bare `GenericFakeChatModel` inherits
|
|
59
|
+
`BaseChatModel.bind_tools`, which raises `NotImplementedError` in any
|
|
60
|
+
agent-loop context. The inherited `_ToolBindingFakeModel` supplies a
|
|
58
61
|
no-op passthrough.
|
|
59
62
|
|
|
60
63
|
3. The app server reads `model.profile` for capability negotiation (e.g.
|
|
61
|
-
`tool_calling`, `max_input_tokens`).
|
|
62
|
-
causing
|
|
64
|
+
`tool_calling`, `max_input_tokens`). A bare fake's `profile` is `None`,
|
|
65
|
+
causing silent misconfiguration at runtime. The inherited
|
|
66
|
+
`_ToolBindingFakeModel` supplies a minimal profile.
|
|
63
67
|
|
|
64
68
|
Additionally, the compact middleware issues summarization prompts mid-
|
|
65
69
|
conversation. A list-based model cannot distinguish these from normal user
|
|
@@ -68,24 +72,8 @@ class DeterministicIntegrationChatModel(GenericFakeChatModel):
|
|
|
68
72
|
"""
|
|
69
73
|
|
|
70
74
|
model: str = "fake"
|
|
71
|
-
#
|
|
72
|
-
|
|
73
|
-
profile: dict[str, Any] | None = Field(
|
|
74
|
-
default_factory=lambda: {
|
|
75
|
-
"tool_calling": True,
|
|
76
|
-
"max_input_tokens": 8000,
|
|
77
|
-
}
|
|
78
|
-
)
|
|
79
|
-
|
|
80
|
-
def bind_tools(
|
|
81
|
-
self,
|
|
82
|
-
tools: Sequence[dict[str, Any] | type | Callable | BaseTool], # noqa: ARG002
|
|
83
|
-
*,
|
|
84
|
-
tool_choice: str | None = None, # noqa: ARG002
|
|
85
|
-
**kwargs: Any, # noqa: ARG002
|
|
86
|
-
) -> Runnable[LanguageModelInput, AIMessage]:
|
|
87
|
-
"""Return self so the agent can bind tool schemas during tests."""
|
|
88
|
-
return self
|
|
75
|
+
# `messages`, `profile`, and the `bind_tools` passthrough are inherited from
|
|
76
|
+
# `_ToolBindingFakeModel`; this model adds only prompt-driven generation.
|
|
89
77
|
|
|
90
78
|
def _generate(
|
|
91
79
|
self,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# Keep the `x-release-please-version` annotation — release-please uses it to
|
|
4
4
|
# bump `__version__` in sync with `pyproject.toml` on every release PR.
|
|
5
|
-
__version__ = "0.1.
|
|
5
|
+
__version__ = "0.1.33" # x-release-please-version
|
|
6
6
|
|
|
7
7
|
DOCS_URL = "https://docs.langchain.com/oss/python/deepagents/code"
|
|
8
8
|
"""URL for `deepagents-code` documentation."""
|
|
@@ -1702,6 +1702,9 @@ def create_cli_agent(
|
|
|
1702
1702
|
)
|
|
1703
1703
|
raise ValueError(msg)
|
|
1704
1704
|
# Lazy import keeps `dcode -v` fast — see AGENTS.md startup-perf rule.
|
|
1705
|
+
from langchain_core._api import ( # noqa: PLC2701 # re-exported in _api.__all__
|
|
1706
|
+
suppress_langchain_beta_warning,
|
|
1707
|
+
)
|
|
1705
1708
|
from langchain_quickjs import CodeInterpreterMiddleware, PTCOption
|
|
1706
1709
|
|
|
1707
1710
|
ptc_names = _resolve_ptc_option(
|
|
@@ -1713,16 +1716,20 @@ def create_cli_agent(
|
|
|
1713
1716
|
ptc_option: PTCOption | None = (
|
|
1714
1717
|
cast("PTCOption", list(ptc_names)) if ptc_names is not None else None
|
|
1715
1718
|
)
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1719
|
+
# `CodeInterpreterMiddleware` is decorated `@beta()`, which emits a
|
|
1720
|
+
# `LangChainBetaWarning` on every instantiation. We intentionally use it
|
|
1721
|
+
# and the warning is not actionable for users, so suppress it.
|
|
1722
|
+
with suppress_langchain_beta_warning():
|
|
1723
|
+
agent_middleware.append(
|
|
1724
|
+
CodeInterpreterMiddleware(
|
|
1725
|
+
tool_name="js_eval",
|
|
1726
|
+
timeout=settings.interpreter_timeout_seconds,
|
|
1727
|
+
memory_limit=settings.interpreter_memory_limit_mb * 1024 * 1024,
|
|
1728
|
+
max_ptc_calls=settings.interpreter_max_ptc_calls,
|
|
1729
|
+
max_result_chars=settings.interpreter_max_result_chars,
|
|
1730
|
+
ptc=ptc_option,
|
|
1731
|
+
)
|
|
1724
1732
|
)
|
|
1725
|
-
)
|
|
1726
1733
|
|
|
1727
1734
|
# Local context middleware (git info, directory tree, etc.).
|
|
1728
1735
|
if isinstance(backend, (_ExecutableBackend, _AsyncExecutableBackend)):
|
|
@@ -279,6 +279,11 @@ def _create_model_with_deepagents_import_lock(
|
|
|
279
279
|
)
|
|
280
280
|
|
|
281
281
|
|
|
282
|
+
def _resolve_parent_dir(path: str | Path) -> str:
|
|
283
|
+
"""Return the resolved parent directory for a path."""
|
|
284
|
+
return str(Path(path).resolve().parent)
|
|
285
|
+
|
|
286
|
+
|
|
282
287
|
def _extra_is_ready(extra: str) -> bool | None:
|
|
283
288
|
"""Return whether all dependencies for `extra` are installed.
|
|
284
289
|
|
|
@@ -2786,6 +2791,13 @@ class DeepAgentsApp(App):
|
|
|
2786
2791
|
Built alongside `_discovered_skills`.
|
|
2787
2792
|
"""
|
|
2788
2793
|
|
|
2794
|
+
self._skill_trust_denied: set[str] = set()
|
|
2795
|
+
"""Resolved skill directories the user declined to trust this session.
|
|
2796
|
+
|
|
2797
|
+
Prevents re-prompting for the same untrusted location after a deny
|
|
2798
|
+
within a single run.
|
|
2799
|
+
"""
|
|
2800
|
+
|
|
2789
2801
|
# Media
|
|
2790
2802
|
# Lazily imported here to avoid pulling image dependencies into
|
|
2791
2803
|
# argument parsing paths.
|
|
@@ -9630,6 +9642,28 @@ class DeepAgentsApp(App):
|
|
|
9630
9642
|
theme_reload_ok = False
|
|
9631
9643
|
logger.warning("Failed to reload user themes", exc_info=True)
|
|
9632
9644
|
|
|
9645
|
+
# Re-resolve and apply the theme preference so a per-terminal or
|
|
9646
|
+
# global default saved by another session is picked up. This
|
|
9647
|
+
# re-syncs to on-disk config using the same resolution as startup
|
|
9648
|
+
# (env -> [ui.terminal_themes][TERM_PROGRAM] -> [ui].theme ->
|
|
9649
|
+
# default), which intentionally overrides an unsaved in-session
|
|
9650
|
+
# `/theme` choice. Guarded on the registry reload succeeding since
|
|
9651
|
+
# the target theme must be registered before it can be applied.
|
|
9652
|
+
theme_switched_to: str | None = None
|
|
9653
|
+
if theme_reload_ok:
|
|
9654
|
+
try:
|
|
9655
|
+
new_theme = _load_theme_preference()
|
|
9656
|
+
if new_theme != self.theme and new_theme in theme.get_registry():
|
|
9657
|
+
self.theme = new_theme
|
|
9658
|
+
self.sync_terminal_background()
|
|
9659
|
+
self.refresh_css(animate=False)
|
|
9660
|
+
theme_switched_to = new_theme
|
|
9661
|
+
except Exception:
|
|
9662
|
+
logger.warning(
|
|
9663
|
+
"Failed to re-apply theme preference on reload",
|
|
9664
|
+
exc_info=True,
|
|
9665
|
+
)
|
|
9666
|
+
|
|
9633
9667
|
# Re-discover skills so autocomplete reflects any new/removed
|
|
9634
9668
|
# skills. Run via the same exclusive-group worker used at
|
|
9635
9669
|
# startup so any in-flight startup discovery is cancelled
|
|
@@ -9655,6 +9689,10 @@ class DeepAgentsApp(App):
|
|
|
9655
9689
|
report += "\nModel config caches cleared."
|
|
9656
9690
|
if theme_reload_ok:
|
|
9657
9691
|
report += "\nTheme registry reloaded."
|
|
9692
|
+
if theme_switched_to is not None:
|
|
9693
|
+
entry = theme.get_registry().get(theme_switched_to)
|
|
9694
|
+
label = entry.label if entry is not None else theme_switched_to
|
|
9695
|
+
report += f"\nSwitched theme to {label}."
|
|
9658
9696
|
else:
|
|
9659
9697
|
report += (
|
|
9660
9698
|
"\nTheme registry reload failed. Check config.toml for errors."
|
|
@@ -9791,8 +9829,15 @@ class DeepAgentsApp(App):
|
|
|
9791
9829
|
normalized_name,
|
|
9792
9830
|
exc_info=True,
|
|
9793
9831
|
)
|
|
9794
|
-
await
|
|
9795
|
-
|
|
9832
|
+
content = await self._prompt_skill_trust_and_retry(
|
|
9833
|
+
normalized_name,
|
|
9834
|
+
skill_path,
|
|
9835
|
+
allowed_roots,
|
|
9836
|
+
fallback_error=str(exc),
|
|
9837
|
+
mount_error=_mount_error,
|
|
9838
|
+
)
|
|
9839
|
+
if content is None:
|
|
9840
|
+
return
|
|
9796
9841
|
except OSError as exc:
|
|
9797
9842
|
logger.warning(
|
|
9798
9843
|
"Filesystem error loading skill %r",
|
|
@@ -9842,6 +9887,139 @@ class DeepAgentsApp(App):
|
|
|
9842
9887
|
message_kwargs=envelope.message_kwargs,
|
|
9843
9888
|
)
|
|
9844
9889
|
|
|
9890
|
+
async def _prompt_skill_trust_and_retry(
|
|
9891
|
+
self,
|
|
9892
|
+
skill_name: str,
|
|
9893
|
+
skill_path: str | Path,
|
|
9894
|
+
allowed_roots: list[Path],
|
|
9895
|
+
*,
|
|
9896
|
+
fallback_error: str,
|
|
9897
|
+
mount_error: Callable[[str], Awaitable[None]],
|
|
9898
|
+
) -> str | None:
|
|
9899
|
+
"""Prompt to trust an out-of-bounds skill directory, then reload it.
|
|
9900
|
+
|
|
9901
|
+
Mirrors the MCP project-trust flow: when containment fails, the user is
|
|
9902
|
+
asked once to allow the resolved target directory. Allowing persists the
|
|
9903
|
+
decision, extends the in-session containment allowlist, and retries the
|
|
9904
|
+
read. Denying (or a prior deny this session) shows the original error.
|
|
9905
|
+
|
|
9906
|
+
Args:
|
|
9907
|
+
skill_name: Normalized skill name, for messaging.
|
|
9908
|
+
skill_path: Path to the skill's `SKILL.md`.
|
|
9909
|
+
allowed_roots: Containment roots to extend on approval.
|
|
9910
|
+
fallback_error: Original `PermissionError` message to show on deny.
|
|
9911
|
+
mount_error: Callback to surface an error in the chat log.
|
|
9912
|
+
|
|
9913
|
+
Returns:
|
|
9914
|
+
The skill content on approval and successful reload, or `None` when
|
|
9915
|
+
the user declined or the retry failed (an error was mounted).
|
|
9916
|
+
"""
|
|
9917
|
+
from deepagents_code.skills.load import load_skill_content
|
|
9918
|
+
from deepagents_code.skills.trust import trust_skill_dir
|
|
9919
|
+
from deepagents_code.widgets.skill_trust import SkillTrustScreen
|
|
9920
|
+
|
|
9921
|
+
try:
|
|
9922
|
+
target_dir = await asyncio.to_thread(_resolve_parent_dir, skill_path)
|
|
9923
|
+
except (OSError, RuntimeError):
|
|
9924
|
+
# Resolving the skill path can fail (e.g. a symlink loop introduced
|
|
9925
|
+
# in the window after the first containment check raised). Fail
|
|
9926
|
+
# closed with the original error rather than letting the worker
|
|
9927
|
+
# exception escape unhandled — this mirrors the retry block below,
|
|
9928
|
+
# which already guards its own resolve.
|
|
9929
|
+
logger.warning(
|
|
9930
|
+
"Could not resolve skill path %r for the trust prompt; refusing",
|
|
9931
|
+
skill_path,
|
|
9932
|
+
exc_info=True,
|
|
9933
|
+
)
|
|
9934
|
+
await mount_error(fallback_error)
|
|
9935
|
+
return None
|
|
9936
|
+
|
|
9937
|
+
if target_dir in self._skill_trust_denied:
|
|
9938
|
+
await mount_error(fallback_error)
|
|
9939
|
+
return None
|
|
9940
|
+
|
|
9941
|
+
try:
|
|
9942
|
+
allowed = await self._push_screen_wait(
|
|
9943
|
+
SkillTrustScreen(skill_name, target_dir)
|
|
9944
|
+
)
|
|
9945
|
+
except Exception:
|
|
9946
|
+
# This runs inside `_invoke_skill`'s `except PermissionError` block,
|
|
9947
|
+
# so an error escaping the modal push would not be caught by that
|
|
9948
|
+
# method's sibling handlers and would surface as an unhandled worker
|
|
9949
|
+
# crash. Fail closed: treat a modal failure as a deny.
|
|
9950
|
+
logger.warning(
|
|
9951
|
+
"Skill trust prompt failed to display for %s; refusing",
|
|
9952
|
+
target_dir,
|
|
9953
|
+
exc_info=True,
|
|
9954
|
+
)
|
|
9955
|
+
self._skill_trust_denied.add(target_dir)
|
|
9956
|
+
await mount_error(fallback_error)
|
|
9957
|
+
return None
|
|
9958
|
+
if not allowed:
|
|
9959
|
+
self._skill_trust_denied.add(target_dir)
|
|
9960
|
+
await mount_error(fallback_error)
|
|
9961
|
+
return None
|
|
9962
|
+
|
|
9963
|
+
if not await asyncio.to_thread(trust_skill_dir, target_dir):
|
|
9964
|
+
# The modal told the user this location would be remembered for
|
|
9965
|
+
# future sessions. Persisting failed (read-only/full `.state`), so
|
|
9966
|
+
# surface that: we honor the approval this session, but they will be
|
|
9967
|
+
# asked again next launch. Logging alone would silently break that
|
|
9968
|
+
# promise.
|
|
9969
|
+
logger.warning("Could not persist skill trust for %s", target_dir)
|
|
9970
|
+
self.notify(
|
|
9971
|
+
"Approved for this session, but the decision could not be "
|
|
9972
|
+
"saved — you may be asked again next time.",
|
|
9973
|
+
severity="warning",
|
|
9974
|
+
markup=False,
|
|
9975
|
+
)
|
|
9976
|
+
|
|
9977
|
+
target_path = Path(target_dir)
|
|
9978
|
+
for roots in (allowed_roots, self._skill_allowed_roots):
|
|
9979
|
+
if target_path not in roots:
|
|
9980
|
+
roots.append(target_path)
|
|
9981
|
+
|
|
9982
|
+
def _retry() -> str | None:
|
|
9983
|
+
return load_skill_content(str(skill_path), allowed_roots=allowed_roots)
|
|
9984
|
+
|
|
9985
|
+
try:
|
|
9986
|
+
content = await asyncio.to_thread(_retry)
|
|
9987
|
+
except PermissionError:
|
|
9988
|
+
# Containment failed *after* the target dir was allowlisted, so the
|
|
9989
|
+
# skill path must now resolve somewhere else — a symlink swap during
|
|
9990
|
+
# the prompt window. Refuse and flag it distinctly from a plain read
|
|
9991
|
+
# error. (PermissionError is an OSError subclass, so this must come
|
|
9992
|
+
# first.)
|
|
9993
|
+
logger.warning(
|
|
9994
|
+
"Skill %r resolved outside the approved directory on retry "
|
|
9995
|
+
"(target may have changed since approval); refusing",
|
|
9996
|
+
skill_name,
|
|
9997
|
+
exc_info=True,
|
|
9998
|
+
)
|
|
9999
|
+
await mount_error(
|
|
10000
|
+
f"Could not load skill: {skill_name}. Its location changed "
|
|
10001
|
+
"after you approved it, so it was not read.",
|
|
10002
|
+
)
|
|
10003
|
+
return None
|
|
10004
|
+
except OSError:
|
|
10005
|
+
logger.warning(
|
|
10006
|
+
"Retry load failed for skill %r after trust",
|
|
10007
|
+
skill_name,
|
|
10008
|
+
exc_info=True,
|
|
10009
|
+
)
|
|
10010
|
+
await mount_error(
|
|
10011
|
+
f"Could not load skill: {skill_name} after granting trust.",
|
|
10012
|
+
)
|
|
10013
|
+
return None
|
|
10014
|
+
|
|
10015
|
+
if content is None:
|
|
10016
|
+
await mount_error(
|
|
10017
|
+
f"Could not read content for skill: {skill_name}. "
|
|
10018
|
+
"Check that the SKILL.md file exists, is readable, "
|
|
10019
|
+
"and is saved as UTF-8.",
|
|
10020
|
+
)
|
|
10021
|
+
return content
|
|
10022
|
+
|
|
9845
10023
|
async def _handle_skill_command(self, command: str) -> None:
|
|
9846
10024
|
"""Handle a `/skill:<name>` command by loading and invoking a skill.
|
|
9847
10025
|
|