drydock-cli 3.1.31__tar.gz → 3.1.32__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.
- {drydock_cli-3.1.31/drydock_cli.egg-info → drydock_cli-3.1.32}/PKG-INFO +1 -1
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/advisor.py +29 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/agent.py +3 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/tools/__init__.py +8 -1
- {drydock_cli-3.1.31 → drydock_cli-3.1.32/drydock_cli.egg-info}/PKG-INFO +1 -1
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/pyproject.toml +1 -1
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_advisor.py +55 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/LICENSE +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/NOTICE +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/README.md +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/__init__.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/__main__.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/asr.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/bash_safety.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/bottleneck.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/budget.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/builtin_skills/__init__.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/builtin_skills/document-canvas.md +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/builtin_skills/fiar-assess.md +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/builtin_skills/fiar-cap.md +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/builtin_skills/fiar-evidence.md +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/builtin_skills/fiar-readiness.md +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/builtin_skills/ml-data.md +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/builtin_skills/ml-debug.md +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/builtin_skills/ml-finetune.md +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/builtin_skills/ml-metrics.md +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/builtin_skills/ml-rl.md +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/builtin_skills/ml-train.md +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/builtin_skills/nist-ai-rmf.md +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/builtin_skills/nist-csf.md +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/builtin_skills/rmf-categorize.md +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/builtin_skills/rmf-control.md +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/builtin_skills/rmf-poam.md +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/builtin_skills/rmf-review.md +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/builtin_skills/stig-assess.md +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/builtin_skills/stig-remediate.md +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/capacity.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/cci.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/cli.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/comms/__init__.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/comms/attention.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/comms/channels.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/comms/events.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/compaction.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/config.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/detect.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/doccanvas.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/eratchet.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/events.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/extract.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/fiar.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/gittools.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/graphrag.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/groundtruth.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/guards.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/jobs.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/loop_detect.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/mcp.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/mission.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/mission_cli.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/mission_run.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/pdfredbox.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/phases.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/poam.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/predictions.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/progress.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/providers.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/ratchet.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/recipes.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/recovery.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/resume.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/rmf.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/rmf_graph.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/skills.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/stig.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/subagents.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/suggest.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/swarm.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/task_state.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/tool_policy.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/tool_registry.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/tool_result.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/tool_select.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/tool_validate.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/trajectory.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/tui/__init__.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/tui/app.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/tui/approval.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/tui/messages.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/tui/widgets.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/tuning.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/verification.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock/web.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock_cli.egg-info/SOURCES.txt +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock_cli.egg-info/dependency_links.txt +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock_cli.egg-info/entry_points.txt +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock_cli.egg-info/requires.txt +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/drydock_cli.egg-info/top_level.txt +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/setup.cfg +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_approval.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_asr.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_back_command.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_bash_background.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_bash_binary_output.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_bash_crossplatform.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_bash_output_bounding.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_bash_process_group.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_bash_safety.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_bash_sanitize.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_bash_shell.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_bash_stdin.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_bash_stop_partial.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_bash_timeout_network.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_bash_timeout_param.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_bottleneck.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_budget.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_capacity.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_cci.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_cli_agents.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_comms.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_compact_command.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_compaction.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_config.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_config_migration.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_context_limit_config.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_context_limit_issue25.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_criteria_coverage.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_cycling_detection.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_declared_deps.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_degenerate_argument.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_detect.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_dispatch.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_doccanvas.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_e2e_connected.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_edit_replace_all.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_edit_thrash_and_compaction.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_effort_governor.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_empty_response.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_eratchet.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_events.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_extract.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_failure_loop.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_fiar.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_first_run_setup.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_gittools.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_glob_edit_edges.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_graphify_example.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_graphrag.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_graphrag_quoted_path.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_graphrag_sqlite.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_grep_and_read_robust.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_groundtruth_predictions.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_guards_and_tools.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_hallucinated_tools.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_jobs.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_knowledge_tool_available.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_leaked_tool_call.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_loop_detect.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_main_api_key.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_mcp.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_mission.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_mission_cli.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_mission_run.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_model_registry.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_oneshot_unreachable.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_overthink_interrupt.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_pdfredbox.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_phases.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_plan_autocontinue.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_poam.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_progress.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_providers_unreachable.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_ratchet.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_ratchet_offer.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_read_index.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_recipes.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_recovery.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_recovery_config.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_recovery_integration.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_repeated_outcome.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_repetition_interrupt.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_resume_events.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_resume_restore.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_resume_snapshot.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_rmf.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_rmf_graph.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_rmf_stig_graph.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_rolling_plan.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_runaway_repetition.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_screenshot.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_server_probe.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_skills.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_sqlite_events.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_stall_retry.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_stig.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_stop.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_streaming_newlines.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_subagent.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_subagents.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_suggest.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_swarm.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_system_prompt_help.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_task_state.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_timeline.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_todo.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_tool_arg_coercion.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_tool_arg_coercion_more.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_tool_arg_parsing.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_tool_canonical.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_tool_policy.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_tool_result.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_tool_select.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_tool_validate.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_tools_undo.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_trajectory.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_tui.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_tuning.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_verification_gate.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_viewimage.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_vision_input.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_web_tools.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_windows_shell.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_worker_subagent.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_write_content_coerce.py +0 -0
- {drydock_cli-3.1.31 → drydock_cli-3.1.32}/tests/test_xccdf.py +0 -0
|
@@ -24,6 +24,35 @@ _ADVISOR_SYSTEM = (
|
|
|
24
24
|
)
|
|
25
25
|
|
|
26
26
|
|
|
27
|
+
def _msg_text(content) -> str:
|
|
28
|
+
"""Flatten a message's content (str or multimodal block list) to plain text."""
|
|
29
|
+
if isinstance(content, str):
|
|
30
|
+
return content
|
|
31
|
+
if isinstance(content, list):
|
|
32
|
+
parts = [str(b.get("text") or b.get("content") or "") if isinstance(b, dict) else str(b)
|
|
33
|
+
for b in content]
|
|
34
|
+
return " ".join(p for p in parts if p)
|
|
35
|
+
return str(content or "")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def recent_context(messages: list, *, max_msgs: int = 12, max_chars: int = 6000) -> str:
|
|
39
|
+
"""Compact the tail of the transcript to brief the advisor (§ Consult). The calling model —
|
|
40
|
+
especially a small local one — often passes little/no `context`, leaving the advisor blind;
|
|
41
|
+
this auto-attaches the last few turns (assistant reasoning + tool results/errors) so it can
|
|
42
|
+
actually help. Keeps the MOST RECENT content when truncating."""
|
|
43
|
+
if not messages:
|
|
44
|
+
return ""
|
|
45
|
+
out = []
|
|
46
|
+
for m in messages[-max_msgs:]:
|
|
47
|
+
if not isinstance(m, dict) or m.get("role") == "system":
|
|
48
|
+
continue
|
|
49
|
+
txt = _msg_text(m.get("content")).strip()
|
|
50
|
+
if txt:
|
|
51
|
+
out.append(f"[{m.get('role', '?')}] {txt[:1200]}")
|
|
52
|
+
blob = "\n".join(out)
|
|
53
|
+
return ("…" + blob[-max_chars:]) if len(blob) > max_chars else blob
|
|
54
|
+
|
|
55
|
+
|
|
27
56
|
def is_configured(config: dict) -> bool:
|
|
28
57
|
"""True when an advisor endpoint + model are set."""
|
|
29
58
|
return bool((config.get("advisor_base_url") or "").strip()
|
|
@@ -670,6 +670,9 @@ def run(
|
|
|
670
670
|
canonical=canonical_name(tc["name"]),
|
|
671
671
|
effect=tool_effect_of(tc["name"], _ro).value,
|
|
672
672
|
input=str(tc.get("input"))[:200])
|
|
673
|
+
# Expose the recent transcript so context-hungry tools (Consult) can brief
|
|
674
|
+
# the advisor without relying on the model to hand-pass context.
|
|
675
|
+
config["_recent_messages"] = state.messages
|
|
673
676
|
tool_result = execute_structured(tc["name"], tc["input"], config)
|
|
674
677
|
result = tool_result.text
|
|
675
678
|
# Emit the completion event IMMEDIATELY after execution (before
|
|
@@ -2054,7 +2054,14 @@ def tool_consult(params: dict, config: dict) -> str:
|
|
|
2054
2054
|
question = _as_str_arg(params.get("question") or params.get("prompt")).strip()
|
|
2055
2055
|
if not question:
|
|
2056
2056
|
return "Error: Consult needs a `question`."
|
|
2057
|
-
|
|
2057
|
+
ctx = _as_str_arg(params.get("context") or "").strip()
|
|
2058
|
+
# Auto-enrich: the advisor is useless without knowing what's going on, and the calling
|
|
2059
|
+
# model often passes thin/no context. Attach the recent transcript (errors + reasoning)
|
|
2060
|
+
# that the agent stashed in config so the advisor always has real information to work with.
|
|
2061
|
+
auto = advisor.recent_context(config.get("_recent_messages") or [])
|
|
2062
|
+
if auto:
|
|
2063
|
+
ctx = (ctx + "\n\n" if ctx else "") + "Recent activity (auto-attached):\n" + auto
|
|
2064
|
+
return advisor.consult(question, config, context=ctx)
|
|
2058
2065
|
|
|
2059
2066
|
|
|
2060
2067
|
# A sub-agent's whole job is to keep its investigation OUT of the main agent's
|
|
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
|
|
|
7
7
|
# PyPI distribution name is drydock-cli (the established install name, continued
|
|
8
8
|
# from the retired v2 fork); the import package + CLI command stay `drydock`.
|
|
9
9
|
name = "drydock-cli"
|
|
10
|
-
version = "3.1.
|
|
10
|
+
version = "3.1.32"
|
|
11
11
|
description = "Drydock — a local, provider-agnostic terminal coding agent for local LLMs"
|
|
12
12
|
readme = "README.md"
|
|
13
13
|
requires-python = ">=3.11"
|
|
@@ -88,3 +88,58 @@ def test_test_connection_timeout_says_reachable_but_slow(monkeypatch):
|
|
|
88
88
|
monkeypatch.setattr(advisor, "_call", slow)
|
|
89
89
|
out = advisor.test_connection({"advisor_base_url": "http://b/v1", "advisor_model": "m"})
|
|
90
90
|
assert out.startswith("✗") and "REACHABLE but slow" in out and "/ask" in out
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
# ── recent-context auto-enrichment (advisor gets info even w/ thin caller context) ──
|
|
94
|
+
def test_recent_context_formats_and_keeps_newest():
|
|
95
|
+
msgs = [
|
|
96
|
+
{"role": "system", "content": "SYS should be skipped"},
|
|
97
|
+
{"role": "assistant", "content": "I'll run the tests."},
|
|
98
|
+
{"role": "tool", "content": "FAILED test_x - AssertionError: expected 42"},
|
|
99
|
+
{"role": "assistant", "content": "The assertion failed; investigating add()."},
|
|
100
|
+
]
|
|
101
|
+
out = advisor.recent_context(msgs)
|
|
102
|
+
assert "SYS should be skipped" not in out # system dropped
|
|
103
|
+
assert "FAILED test_x" in out and "investigating add()" in out
|
|
104
|
+
assert "[tool]" in out and "[assistant]" in out
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def test_recent_context_truncates_to_recent_chars():
|
|
108
|
+
msgs = [{"role": "assistant", "content": "x" * 500} for _ in range(40)]
|
|
109
|
+
out = advisor.recent_context(msgs, max_chars=1000)
|
|
110
|
+
assert len(out) <= 1001 and out.startswith("…") # kept the tail
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def test_recent_context_handles_multimodal_blocks():
|
|
114
|
+
msgs = [{"role": "user", "content": [{"type": "text", "text": "look at this"}, {"type": "image"}]}]
|
|
115
|
+
assert "look at this" in advisor.recent_context(msgs)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def test_consult_tool_auto_attaches_recent_transcript(monkeypatch):
|
|
119
|
+
from drydock import tools as T
|
|
120
|
+
captured = {}
|
|
121
|
+
monkeypatch.setattr(advisor, "consult",
|
|
122
|
+
lambda q, cfg, context="": captured.update(question=q, context=context) or "ok")
|
|
123
|
+
cfg = {
|
|
124
|
+
"advisor_base_url": "http://b/v1", "advisor_model": "m",
|
|
125
|
+
"_recent_messages": [
|
|
126
|
+
{"role": "tool", "content": "FAILED test_reconnect - state lost after reconnect"},
|
|
127
|
+
{"role": "assistant", "content": "Trying a lock around the queue."},
|
|
128
|
+
],
|
|
129
|
+
}
|
|
130
|
+
# model passed only a bare question (thin context) — the fix must attach the transcript
|
|
131
|
+
T.tool_consult({"question": "why does reconnect lose state?"}, cfg)
|
|
132
|
+
assert "FAILED test_reconnect" in captured["context"] # advisor now sees the error
|
|
133
|
+
assert "lock around the queue" in captured["context"]
|
|
134
|
+
assert "Recent activity" in captured["context"]
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def test_consult_tool_keeps_model_context_and_adds_recent(monkeypatch):
|
|
138
|
+
from drydock import tools as T
|
|
139
|
+
captured = {}
|
|
140
|
+
monkeypatch.setattr(advisor, "consult",
|
|
141
|
+
lambda q, cfg, context="": captured.update(context=context) or "ok")
|
|
142
|
+
cfg = {"advisor_base_url": "http://b/v1", "advisor_model": "m",
|
|
143
|
+
"_recent_messages": [{"role": "tool", "content": "ERR: boom"}]}
|
|
144
|
+
T.tool_consult({"question": "help", "context": "my hand-written context"}, cfg)
|
|
145
|
+
assert "my hand-written context" in captured["context"] and "ERR: boom" in captured["context"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|