dreadnode 2.0.12__tar.gz → 2.0.14__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.
- {dreadnode-2.0.12 → dreadnode-2.0.14}/.gitignore +4 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/PKG-INFO +4 -4
- {dreadnode-2.0.12 → dreadnode-2.0.14}/README.md +3 -3
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/__init__.py +2 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/agents/agent.py +57 -9
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/agents/events.py +28 -16
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/agents/hooks.py +28 -7
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/agents/mcp/client.py +101 -5
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/agents/skills.py +109 -23
- dreadnode-2.0.14/dreadnode/agents/tool_resolution.py +56 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/agents/tools.py +100 -2
- dreadnode-2.0.14/dreadnode/airt/__init__.py +157 -0
- dreadnode-2.0.14/dreadnode/airt/adversarial_reasoning.py +352 -0
- dreadnode-2.0.14/dreadnode/airt/advpromptier.py +273 -0
- dreadnode-2.0.14/dreadnode/airt/alignment_faking.py +397 -0
- dreadnode-2.0.14/dreadnode/airt/analogy_escalation.py +351 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/analytics/classifier.py +7 -1
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/analytics/recommendations.py +74 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/analytics/types.py +6 -0
- dreadnode-2.0.14/dreadnode/airt/aprt_progressive.py +377 -0
- dreadnode-2.0.14/dreadnode/airt/attention_shifting.py +430 -0
- dreadnode-2.0.14/dreadnode/airt/autoredteamer.py +378 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/compliance/owasp_agentic.py +103 -19
- dreadnode-2.0.14/dreadnode/airt/cot_jailbreak.py +385 -0
- dreadnode-2.0.14/dreadnode/airt/echo_chamber.py +300 -0
- dreadnode-2.0.14/dreadnode/airt/genetic_persona.py +417 -0
- dreadnode-2.0.14/dreadnode/airt/goat_v2.py +385 -0
- dreadnode-2.0.14/dreadnode/airt/humor_bypass.py +400 -0
- dreadnode-2.0.14/dreadnode/airt/j2_meta.py +350 -0
- dreadnode-2.0.14/dreadnode/airt/jbdistill.py +379 -0
- dreadnode-2.0.14/dreadnode/airt/jbfuzz.py +385 -0
- dreadnode-2.0.14/dreadnode/airt/lrm_autonomous.py +405 -0
- dreadnode-2.0.14/dreadnode/airt/mapf.py +366 -0
- dreadnode-2.0.14/dreadnode/airt/nexus.py +357 -0
- dreadnode-2.0.14/dreadnode/airt/persona_hijack.py +356 -0
- dreadnode-2.0.14/dreadnode/airt/quantization_safety.py +289 -0
- dreadnode-2.0.14/dreadnode/airt/refusal_aware.py +330 -0
- dreadnode-2.0.14/dreadnode/airt/reward_hacking.py +310 -0
- dreadnode-2.0.14/dreadnode/airt/salami_slicing.py +332 -0
- dreadnode-2.0.14/dreadnode/airt/self_persuasion.py +365 -0
- dreadnode-2.0.14/dreadnode/airt/siren.py +353 -0
- dreadnode-2.0.14/dreadnode/airt/templatefuzz.py +385 -0
- dreadnode-2.0.14/dreadnode/airt/tmap_trajectory.py +378 -0
- dreadnode-2.0.14/dreadnode/airt/trojail.py +286 -0
- dreadnode-2.0.14/dreadnode/airt/watermark_removal.py +309 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/api/client.py +92 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/api/models.py +28 -1
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/cli/airt.py +12 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/cli/capability.py +10 -5
- dreadnode-2.0.14/dreadnode/app/cli/environment.py +450 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/cli/main.py +2 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/cli/templates/init/provision.sh +1 -1
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/cli/templates/init/solution.sh +1 -1
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/cli/templates/init/task-remote.yaml.tmpl +1 -1
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/cli/templates/init/task.yaml.tmpl +2 -2
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/cli/templates/init/teardown.sh +1 -1
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/cli/templates/init/verify.sh +1 -1
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/client/interactive.py +46 -6
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/client/managed_client.py +254 -30
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/client/models.py +28 -2
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/client/runtime_client.py +10 -4
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/main.py +43 -18
- dreadnode-2.0.14/dreadnode/app/paths.py +60 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/server/app.py +193 -48
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/server/capability_manager.py +145 -42
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/server/runtime_events.py +2 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/server/websocket.py +6 -2
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/server/worker_manager.py +149 -48
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/app.py +149 -11
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/capabilities_manager.py +47 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/command_dispatcher.py +26 -10
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/dreadnode.tcss +31 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/profile_manager.py +51 -9
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/screen_router.py +4 -1
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/screens/capabilities.py +219 -86
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/screens/console.py +4 -2
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/screens/runtimes.py +89 -4
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/screens/services.py +283 -17
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/sessions_manager.py +45 -8
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/turn_reducer.py +18 -3
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/widgets/__init__.py +2 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/widgets/conversation.py +121 -4
- dreadnode-2.0.14/dreadnode/app/tui/widgets/new_messages_pill.py +173 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/widgets/tool.py +52 -9
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/wire_events.py +6 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/builtin_capabilities/__init__.py +1 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/capabilities/capability.py +31 -4
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/capabilities/loader.py +55 -1
- dreadnode-2.0.14/dreadnode/capabilities/tool_rules.py +115 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/capabilities/worker.py +31 -2
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/capabilities/worker_runner.py +130 -32
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/core/__init__.py +8 -0
- dreadnode-2.0.14/dreadnode/core/environment.py +254 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/core/meta/config.py +4 -13
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/core/metric.py +2 -2
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/core/scorer.py +1 -1
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/core/task.py +1 -1
- dreadnode-2.0.14/dreadnode/core/templating.py +133 -0
- dreadnode-2.0.14/dreadnode/generators/caching.py +52 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/generators/generator/base.py +9 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/generators/generator/litellm_.py +15 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/generators/message.py +5 -2
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/packaging/oci.py +14 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/scorers/__init__.py +44 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/scorers/advanced_jailbreak_detection.py +168 -0
- dreadnode-2.0.14/dreadnode/scorers/attack_outcome.py +439 -0
- dreadnode-2.0.14/dreadnode/scorers/judge_ensemble.py +424 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/scorers/mcp_security.py +81 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/scorers/reasoning_security.py +92 -0
- dreadnode-2.0.14/dreadnode/scorers/structural_detection.py +385 -0
- dreadnode-2.0.14/dreadnode/scorers/supply_chain_detection.py +582 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/__init__.py +10 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/advanced_jailbreak.py +635 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/adversarial_suffix.py +128 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/agentic_workflow.py +201 -0
- dreadnode-2.0.14/dreadnode/transforms/backdoor_finetune.py +859 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/browser_agent_attacks.py +476 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/cipher.py +139 -0
- dreadnode-2.0.14/dreadnode/transforms/competitive_parity.py +997 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/encoding.py +170 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/image.py +4 -2
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/mcp_attacks.py +619 -0
- dreadnode-2.0.14/dreadnode/transforms/multi_agent_attacks.py +2674 -0
- dreadnode-2.0.14/dreadnode/transforms/multimodal_attacks.py +1283 -0
- dreadnode-2.0.14/dreadnode/transforms/persuasion.py +623 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/rag_poisoning.py +507 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/reasoning_attacks.py +889 -0
- dreadnode-2.0.14/dreadnode/transforms/structural_exploits.py +785 -0
- dreadnode-2.0.14/dreadnode/transforms/supply_chain.py +524 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/xml_tools.py +1 -1
- {dreadnode-2.0.12 → dreadnode-2.0.14}/pyproject.toml +1 -1
- dreadnode-2.0.12/dreadnode/airt/__init__.py +0 -70
- dreadnode-2.0.12/dreadnode/capabilities/tool_rules.py +0 -51
- dreadnode-2.0.12/dreadnode/core/environment.py +0 -67
- dreadnode-2.0.12/dreadnode/generators/caching.py +0 -42
- dreadnode-2.0.12/dreadnode/transforms/multi_agent_attacks.py +0 -1161
- dreadnode-2.0.12/dreadnode/transforms/persuasion.py +0 -312
- {dreadnode-2.0.12 → dreadnode-2.0.14}/LICENSE +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/__main__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/agents/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/agents/exceptions.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/agents/format.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/agents/mcp/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/agents/mcp/auth.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/agents/mcp/config.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/agents/mcp/server.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/agents/reactions.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/agents/stopping.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/agents/subagent.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/agents/trajectory.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/analytics/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/analytics/aggregator.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/analytics/compliance.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/analytics/engine.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/assessment.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/autodan_turbo.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/beast.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/compliance/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/compliance/atlas.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/compliance/nist.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/compliance/owasp.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/compliance/saif.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/constants.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/crescendo.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/data/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/data/assets/audio/adversarial_query.mp3 +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/data/assets/image/bomb.jpg +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/data/assets/image/meth.png +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/data/prompts/adversarial_benchmark_subset.csv +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/data/prompts/ai_safety.csv +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/data/rubrics/data_exfiltration.yaml +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/data/rubrics/goal_hijacking.yaml +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/data/rubrics/memory_poisoning.yaml +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/data/rubrics/privilege_escalation.yaml +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/data/rubrics/rce.yaml +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/data/rubrics/scope_creep.yaml +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/data/rubrics/tool_chaining.yaml +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/data/rubrics/tool_selection_safety.yaml +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/data/rubrics/unbounded_agency.yaml +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/data/rubrics/web_chatbot_security.yaml +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/data/templates/crescendo/variant_1.yaml +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/data/templates/crescendo/variant_2.yaml +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/data/templates/crescendo/variant_3.yaml +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/data/templates/crescendo/variant_4.yaml +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/data/templates/crescendo/variant_5.yaml +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/deep_inception.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/drattack.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/events.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/goat.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/gptfuzzer.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/image.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/multimodal.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/pair.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/prompt.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/rainbow.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/renellm.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/reporting/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/reporting/json_report.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/reporting/llm_summary.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/reporting/markdown.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/airt/tap.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/api/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/cli/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/cli/args.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/cli/dataset.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/cli/evaluation.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/cli/model.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/cli/optimize.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/cli/runtime.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/cli/sandbox.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/cli/shared.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/cli/task.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/cli/templates/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/cli/templates/init/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/cli/templates/init/challenge/Dockerfile +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/cli/templates/init/docker-compose.yaml +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/cli/train.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/cli/worlds.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/client/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/client/transports.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/config.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/env.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/model_catalog.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/print_mode.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/server/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/server/auth.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/server/model_resolution.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/server/prompt.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/server/prompt_registry.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/server/session_hydrator.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/server/session_persistence.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/server/session_policy.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/server/turn_coordinator.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/server/utils.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/auth_flow.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/commands.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/connection.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/error_handler.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/model_manager.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/model_variants.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/runtime_cache.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/screens/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/screens/auth.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/screens/base.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/screens/capability_docs.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/screens/connection_error.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/screens/environments.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/screens/evaluations.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/screens/model_picker.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/screens/models.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/screens/raw_spans.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/screens/sandboxes.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/screens/secrets.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/screens/sessions.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/screens/theme_showcase.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/screens/traces.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/screens/workspaces.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/spans_reader.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/theme.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/tool_format.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/turn_coordinator.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/turn_lifecycle.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/turn_state_phase.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/update_check.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/widgets/agent_dialog.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/widgets/agent_suggester.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/widgets/composer.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/widgets/context_bar.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/widgets/flash.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/widgets/header_bar.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/widgets/help_panel.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/widgets/mention_overlay.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/widgets/message_queue.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/widgets/overlay_mixin.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/widgets/permission_prompt.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/widgets/profile_dialog.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/widgets/prompt_info.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/widgets/session_sidebar.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/widgets/skills_dialog.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/widgets/slash_overlay.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/widgets/status_bar.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/widgets/throbber.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/widgets/tool_progress.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/widgets/tools_dialog.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/widgets/welcome.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/app/tui/widgets/whoami.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/builtin_capabilities/dreadnode/agents/dreadnode.md +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/builtin_capabilities/dreadnode/capability.yaml +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/SKILL.md +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/capability-components.md +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/capability-improvement.md +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/builtin_capabilities/dreadnode/skills/creating-capabilities/runtime-default-capability.md +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-cli/SKILL.md +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-cli/references/command-groups.md +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-cli/references/tui-crosswalk.md +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-runtime-reference/SKILL.md +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/builtin_capabilities/dreadnode/system-prompt.md +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/capabilities/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/capabilities/flags.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/capabilities/sync.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/capabilities/types.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/core/conditions.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/core/discovery.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/core/exceptions.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/core/execution.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/core/hook.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/core/judge.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/core/load.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/core/log.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/core/meta/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/core/meta/context.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/core/meta/hydrate.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/core/meta/introspect.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/core/object.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/core/serialization.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/core/stopping.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/core/transforms.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/core/types/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/core/types/audio.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/core/types/base.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/core/types/common.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/core/types/image.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/core/types/object_3d.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/core/types/table.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/core/types/text.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/core/types/video.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/core/util.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/datasets/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/datasets/dataset.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/datasets/hf.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/datasets/local.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/evaluations/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/evaluations/console.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/evaluations/evaluation.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/evaluations/events.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/evaluations/format.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/evaluations/result.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/evaluations/sample.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/generators/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/generators/chat.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/generators/data.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/generators/exceptions.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/generators/generator/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/generators/generator/http.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/generators/generator/transformers_.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/generators/generator/vllm_.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/generators/models.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/generators/parsing.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/generators/tokenizer/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/generators/tokenizer/base.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/generators/tokenizer/transformers_.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/generators/utils.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/models/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/models/hf.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/models/local.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/models/model.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/optimization/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/optimization/adapters/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/optimization/adapters/agent.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/optimization/adapters/stack.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/optimization/api.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/optimization/backends/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/optimization/backends/base.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/optimization/backends/gepa.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/optimization/collectors.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/optimization/config.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/optimization/console.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/optimization/events.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/optimization/format.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/optimization/jobs.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/optimization/result.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/optimization/sampler.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/optimization/sampling.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/optimization/search.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/optimization/stopping.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/optimization/study.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/optimization/trial.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/packaging/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/packaging/loader.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/packaging/manifest.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/packaging/package.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/packaging/task_validation.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/py.typed +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/samplers/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/samplers/boundary.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/samplers/fuzzing.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/samplers/graph.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/samplers/grid.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/samplers/image.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/samplers/mapelites.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/samplers/optuna.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/samplers/random.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/samplers/registry.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/samplers/strategy.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/scorers/agent_security.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/scorers/agentic.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/scorers/agentic_workflow.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/scorers/classification.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/scorers/consistency.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/scorers/contains.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/scorers/cosine_sim.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/scorers/credentials.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/scorers/crucible.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/scorers/documentation_security.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/scorers/exfiltration_detection.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/scorers/format.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/scorers/harm.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/scorers/ide_security.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/scorers/image.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/scorers/json.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/scorers/judge.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/scorers/length.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/scorers/lexical.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/scorers/memorization.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/scorers/multi_agent_security.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/scorers/pii.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/scorers/prompt_leak.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/scorers/readability.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/scorers/sentiment.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/scorers/similarity.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/storage/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/storage/providers.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/storage/session_store.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/storage/storage.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/tools/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/tools/_ripgrep.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/tools/apply_patch.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/tools/dreadnode_cli.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/tools/editing.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/tools/execute.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/tools/fetch.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/tools/glob.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/tools/grep.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/tools/interaction.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/tools/ls.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/tools/memory.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/tools/read.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/tools/report.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/tools/task.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/tools/think.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/tools/todo.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/tools/trajectory_search.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/tools/web_search.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/tools/write.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/tracing/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/tracing/constants.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/tracing/convert.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/tracing/exporter.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/tracing/exporters.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/tracing/span.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/tracing/spans.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/tracing/trace_converter.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/base.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/dpo.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/etl/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/etl/_common.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/etl/rl.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/etl/sft.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/etl/worlds.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/events.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/grpo.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/jobs.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/ppo.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/prime.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/ray/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/ray/async_trainer.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/ray/config.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/ray/coordinator.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/ray/distributed.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/ray/dpo.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/ray/experience.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/ray/fsdp2_learner.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/ray/inference.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/ray/learner.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/ray/multi_turn.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/ray/ppo.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/ray/reward_model.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/ray/rollout_env.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/ray/rollout_worker.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/ray/sft.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/ray/trainer.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/recipes.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/rewards/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/rewards/aggregator.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/rewards/functions.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/rewards/scorer_bridge.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/rewards/shaping.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/rewards/types.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/rollouts/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/rollouts/adapters.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/rollouts/orchestrator.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/rollouts/types.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/rollouts/worlds.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/serving/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/serving/vllm_client.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/sft.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/tinker/__init__.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/tinker/config.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/tinker/data.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/tinker/renderer.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/tinker/rl.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/tinker/trainer.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/tinker_sft.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/training/utils.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/agent_skill.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/audio.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/constitutional.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/document.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/documentation_poison.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/exfiltration.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/flip_attack.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/guardrail_bypass.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/ide_injection.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/injection.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/json_tools.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/language.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/logic_bomb.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/perturbation.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/pii_extraction.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/pythonic_tools.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/refine.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/response_steering.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/stylistic.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/substitution.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/swap.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/system_prompt_extraction.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/text.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/transforms/video.py +0 -0
- {dreadnode-2.0.12 → dreadnode-2.0.14}/dreadnode/version.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dreadnode
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.14
|
|
4
4
|
Summary: Dreadnode SDK
|
|
5
5
|
Project-URL: Homepage, https://dreadnode.io
|
|
6
6
|
Project-URL: Documentation, https://docs.dreadnode.io
|
|
@@ -384,9 +384,9 @@ uv sync --all-extras
|
|
|
384
384
|
|
|
385
385
|
## Documentation
|
|
386
386
|
|
|
387
|
-
- **[
|
|
388
|
-
- **[
|
|
389
|
-
- **[
|
|
387
|
+
- **[Getting started](https://docs.dreadnode.io/getting-started/overview/)** - Install, authenticate, first run
|
|
388
|
+
- **[Quickstart](https://docs.dreadnode.io/getting-started/quickstart/)** - End-to-end walkthrough
|
|
389
|
+
- **[SDK reference](https://docs.dreadnode.io/sdk/overview/)** - Complete SDK reference
|
|
390
390
|
|
|
391
391
|
## License
|
|
392
392
|
|
|
@@ -312,9 +312,9 @@ uv sync --all-extras
|
|
|
312
312
|
|
|
313
313
|
## Documentation
|
|
314
314
|
|
|
315
|
-
- **[
|
|
316
|
-
- **[
|
|
317
|
-
- **[
|
|
315
|
+
- **[Getting started](https://docs.dreadnode.io/getting-started/overview/)** - Install, authenticate, first run
|
|
316
|
+
- **[Quickstart](https://docs.dreadnode.io/getting-started/quickstart/)** - End-to-end walkthrough
|
|
317
|
+
- **[SDK reference](https://docs.dreadnode.io/sdk/overview/)** - Complete SDK reference
|
|
318
318
|
|
|
319
319
|
## License
|
|
320
320
|
|
|
@@ -166,6 +166,7 @@ __all__ = [
|
|
|
166
166
|
"tag",
|
|
167
167
|
"task",
|
|
168
168
|
"task_and_run",
|
|
169
|
+
"task_env",
|
|
169
170
|
"task_span",
|
|
170
171
|
"tool",
|
|
171
172
|
"tool_method",
|
|
@@ -260,6 +261,7 @@ __instance_methods__: list[str] = [
|
|
|
260
261
|
"task_span",
|
|
261
262
|
"run",
|
|
262
263
|
"task_and_run",
|
|
264
|
+
"task_env",
|
|
263
265
|
"scorer",
|
|
264
266
|
"evaluation",
|
|
265
267
|
"optimize_anything",
|
|
@@ -153,7 +153,7 @@ class Agent(Executor[AgentEvent, Trajectory]):
|
|
|
153
153
|
instructions: t.Annotated[str | None, AfterValidator(lambda x: dedent(x) if x else x)] = Config(
|
|
154
154
|
default=None
|
|
155
155
|
)
|
|
156
|
-
cache: caching.CacheMode | None = Config(default=
|
|
156
|
+
cache: caching.CacheMode | None = Config(default="latest", repr=False)
|
|
157
157
|
tools: list[Tool | Toolset] = Config(default_factory=list, validate_default=False)
|
|
158
158
|
tool_mode: ToolMode = Config(default="auto", repr=False)
|
|
159
159
|
hooks: list[Hook] = Config(default_factory=list, repr=False)
|
|
@@ -307,7 +307,8 @@ class Agent(Executor[AgentEvent, Trajectory]):
|
|
|
307
307
|
post_transforms.append(post_transform)
|
|
308
308
|
|
|
309
309
|
try:
|
|
310
|
-
|
|
310
|
+
if self.cache is not None and self.generator.supports_prompt_caching():
|
|
311
|
+
messages = caching.apply_cache_mode_to_messages(self.cache, [messages])[0]
|
|
311
312
|
logger.trace(f"Generating with model '{self.generator.model}'. Messages: {messages!r}")
|
|
312
313
|
|
|
313
314
|
generated = (await self.generator.generate_messages([messages], [params]))[0]
|
|
@@ -494,9 +495,18 @@ class Agent(Executor[AgentEvent, Trajectory]):
|
|
|
494
495
|
)
|
|
495
496
|
|
|
496
497
|
if not _is_context_length_error(error):
|
|
498
|
+
logger.debug(
|
|
499
|
+
"Overflow recovery: error not classified as context-length ({}: {}); skipping",
|
|
500
|
+
type(error).__name__,
|
|
501
|
+
str(error)[:200],
|
|
502
|
+
)
|
|
497
503
|
return None
|
|
498
504
|
|
|
499
505
|
if len(messages) <= 10:
|
|
506
|
+
logger.info(
|
|
507
|
+
"Overflow recovery: too few messages to compact ({} <= 10); skipping",
|
|
508
|
+
len(messages),
|
|
509
|
+
)
|
|
500
510
|
return None
|
|
501
511
|
|
|
502
512
|
work = list(messages)
|
|
@@ -504,6 +514,7 @@ class Agent(Executor[AgentEvent, Trajectory]):
|
|
|
504
514
|
|
|
505
515
|
summarizer = self._generator
|
|
506
516
|
if summarizer is None:
|
|
517
|
+
logger.warning("Overflow recovery: no summarizer generator available; skipping")
|
|
507
518
|
return None
|
|
508
519
|
|
|
509
520
|
# Cap summarizer input at ~60% of the model's token budget (~3 chars/token,
|
|
@@ -519,12 +530,27 @@ class Agent(Executor[AgentEvent, Trajectory]):
|
|
|
519
530
|
max_summarize_chars=max_summarize_chars,
|
|
520
531
|
)
|
|
521
532
|
if boundary == 0:
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
)
|
|
533
|
+
# Distinguish "no safe boundary exists" (neither a simple-assistant
|
|
534
|
+
# nor a complete tool-call group anywhere in the trajectory) from
|
|
535
|
+
# "boundaries exist but none fit the summarizer budget". Both
|
|
536
|
+
# currently return 0; telling them apart is the diagnostic split
|
|
537
|
+
# point ENG-6545 needs.
|
|
538
|
+
uncapped_boundary = find_summarization_boundary(work, min_messages_to_keep=10)
|
|
539
|
+
if uncapped_boundary == 0:
|
|
540
|
+
logger.info(
|
|
541
|
+
"Overflow recovery: no API-safe boundary in {} messages "
|
|
542
|
+
"(no simple-assistant or complete tool-call group); skipping",
|
|
543
|
+
len(work),
|
|
544
|
+
)
|
|
545
|
+
else:
|
|
546
|
+
logger.info(
|
|
547
|
+
"Overflow recovery: valid boundary at index {} exceeds summarizer "
|
|
548
|
+
"budget (messages={}, budget_tokens={}, max_chars={}); skipping",
|
|
549
|
+
uncapped_boundary,
|
|
550
|
+
len(work),
|
|
551
|
+
budget_tokens,
|
|
552
|
+
max_summarize_chars,
|
|
553
|
+
)
|
|
528
554
|
return None
|
|
529
555
|
|
|
530
556
|
to_summarize = work[:boundary]
|
|
@@ -578,7 +604,7 @@ class Agent(Executor[AgentEvent, Trajectory]):
|
|
|
578
604
|
async for event in self._dispatch(start_event):
|
|
579
605
|
yield event
|
|
580
606
|
|
|
581
|
-
tool = next((t for t in self.all_tools if t.
|
|
607
|
+
tool = next((t for t in self.all_tools if t.wire_name == tool_call.name), None)
|
|
582
608
|
|
|
583
609
|
if tool is None:
|
|
584
610
|
error_msg = f"Tool '{tool_call.name}' not found."
|
|
@@ -620,6 +646,14 @@ class Agent(Executor[AgentEvent, Trajectory]):
|
|
|
620
646
|
try:
|
|
621
647
|
message, stop = await tool.handle_tool_call(tool_call)
|
|
622
648
|
|
|
649
|
+
# Tools that catch their own exceptions (bash non-zero,
|
|
650
|
+
# @tool(catch=True), MCP isError) lift the failure into
|
|
651
|
+
# message.metadata. Surface it on ToolEnd so renderers can
|
|
652
|
+
# mark the call as errored without needing to parse XML
|
|
653
|
+
# out of the result body.
|
|
654
|
+
tool_error = message.metadata.get("error")
|
|
655
|
+
tool_error_type = message.metadata.get("error_type")
|
|
656
|
+
|
|
623
657
|
end_event = ToolEnd(
|
|
624
658
|
agent_id=self.agent_id,
|
|
625
659
|
agent_name=self.name,
|
|
@@ -627,11 +661,19 @@ class Agent(Executor[AgentEvent, Trajectory]):
|
|
|
627
661
|
result=message.content,
|
|
628
662
|
output_file=message.metadata.get("output_file"),
|
|
629
663
|
stop=stop,
|
|
664
|
+
error=tool_error,
|
|
665
|
+
error_type=tool_error_type,
|
|
630
666
|
)
|
|
631
667
|
async for event in self._dispatch(end_event):
|
|
632
668
|
yield event
|
|
633
669
|
end_event.emit(t_span) # Emit after dispatch - metrics attached
|
|
634
670
|
|
|
671
|
+
# ToolStep.error is typed for actual exceptions (uncaught
|
|
672
|
+
# errors that get re-raised). The metadata error string is
|
|
673
|
+
# already on ToolEnd.error above — don't double-emit it
|
|
674
|
+
# here, or Pydantic will reject the str input and the
|
|
675
|
+
# raised ValidationError will surface as a duplicate
|
|
676
|
+
# ToolError row in the TUI.
|
|
635
677
|
step_event = ToolStep(
|
|
636
678
|
agent_id=self.agent_id,
|
|
637
679
|
agent_name=self.name,
|
|
@@ -799,6 +841,12 @@ class Agent(Executor[AgentEvent, Trajectory]):
|
|
|
799
841
|
yield event
|
|
800
842
|
messages = recovered_messages
|
|
801
843
|
step_chat = await self._generate(messages)
|
|
844
|
+
if step_chat.failed and step_chat.error:
|
|
845
|
+
logger.warning(
|
|
846
|
+
"Overflow recovery: compacted regenerate also failed ({}: {})",
|
|
847
|
+
type(step_chat.error).__name__,
|
|
848
|
+
str(step_chat.error)[:200],
|
|
849
|
+
)
|
|
802
850
|
|
|
803
851
|
if step_chat.failed and step_chat.error:
|
|
804
852
|
from dreadnode.agents.hooks import _describe_generation_error
|
|
@@ -212,7 +212,7 @@ class AgentStart(AgentEvent):
|
|
|
212
212
|
|
|
213
213
|
goal = self.inputs.get("goal")
|
|
214
214
|
if goal is not None:
|
|
215
|
-
span.set_attribute(AGENT_ATTRIBUTE_GOAL, str(goal)
|
|
215
|
+
span.set_attribute(AGENT_ATTRIBUTE_GOAL, str(goal))
|
|
216
216
|
span.log_input(name="goal", value=goal)
|
|
217
217
|
|
|
218
218
|
if session_id := self.params.get("session_id"):
|
|
@@ -259,7 +259,7 @@ class AgentEnd(AgentEvent):
|
|
|
259
259
|
|
|
260
260
|
def emit(self, span: "TaskSpan") -> None:
|
|
261
261
|
if self.error:
|
|
262
|
-
span.log_output(name="error", value=str(self.error)
|
|
262
|
+
span.log_output(name="error", value=str(self.error))
|
|
263
263
|
|
|
264
264
|
super().emit(span)
|
|
265
265
|
|
|
@@ -338,11 +338,7 @@ class GenerationRetry(AgentEvent):
|
|
|
338
338
|
|
|
339
339
|
|
|
340
340
|
class AgentStalled(AgentEvent):
|
|
341
|
-
"""Event: The agent is stalled and there are no tool calls, or stop condition).
|
|
342
|
-
|
|
343
|
-
Attributes:
|
|
344
|
-
None
|
|
345
|
-
"""
|
|
341
|
+
"""Event: The agent is stalled and there are no tool calls, or stop condition)."""
|
|
346
342
|
|
|
347
343
|
def _get_data(self) -> dict[str, t.Any]:
|
|
348
344
|
return {"reason": "No tool calls and no stop condition met"}
|
|
@@ -516,16 +512,26 @@ class ToolStart(AgentEvent):
|
|
|
516
512
|
class ToolEnd(AgentEvent):
|
|
517
513
|
"""Event: A tool call has completed.
|
|
518
514
|
|
|
515
|
+
A non-empty ``error`` means the tool ran to completion but reported
|
|
516
|
+
a failure (e.g. bash non-zero exit, ``@tool(catch=True)`` swallowing
|
|
517
|
+
an exception, or an MCP server returning ``isError=true``). Uncaught
|
|
518
|
+
exceptions go through :class:`ToolError` instead.
|
|
519
|
+
|
|
519
520
|
Attributes:
|
|
520
521
|
tool_call: The tool call that was completed.
|
|
521
522
|
result: The result returned by the tool, if applicable.
|
|
522
523
|
stop: Whether this tool requested the agent to stop.
|
|
524
|
+
error: A failure message lifted from ``message.metadata['error']``.
|
|
525
|
+
error_type: Exception class name when the error was sourced from
|
|
526
|
+
an :class:`ErrorModel` carrying that metadata.
|
|
523
527
|
"""
|
|
524
528
|
|
|
525
529
|
tool_call: ToolCall
|
|
526
530
|
result: str | None = None
|
|
527
531
|
stop: bool = False
|
|
528
532
|
output_file: str | None = None
|
|
533
|
+
error: str | None = None
|
|
534
|
+
error_type: str | None = None
|
|
529
535
|
|
|
530
536
|
def _get_data(self) -> dict[str, t.Any]:
|
|
531
537
|
return {
|
|
@@ -533,9 +539,11 @@ class ToolEnd(AgentEvent):
|
|
|
533
539
|
"id": self.tool_call.id,
|
|
534
540
|
"name": self.tool_call.name,
|
|
535
541
|
},
|
|
536
|
-
"result": self.result
|
|
542
|
+
"result": self.result or None,
|
|
537
543
|
"output_file": self.output_file,
|
|
538
544
|
"stop": self.stop,
|
|
545
|
+
"error": self.error,
|
|
546
|
+
"error_type": self.error_type,
|
|
539
547
|
}
|
|
540
548
|
|
|
541
549
|
def __repr__(self) -> str:
|
|
@@ -545,11 +553,15 @@ class ToolEnd(AgentEvent):
|
|
|
545
553
|
def emit(self, span: "TaskSpan") -> None:
|
|
546
554
|
# Attributes
|
|
547
555
|
if self.result:
|
|
548
|
-
span.set_attribute(TOOL_ATTRIBUTE_RESULT, self.result
|
|
549
|
-
span.log_output("result", self.result
|
|
556
|
+
span.set_attribute(TOOL_ATTRIBUTE_RESULT, self.result)
|
|
557
|
+
span.log_output("result", self.result)
|
|
550
558
|
|
|
551
559
|
span.set_attribute(TOOL_ATTRIBUTE_STOPPED, self.stop)
|
|
552
560
|
|
|
561
|
+
if self.error:
|
|
562
|
+
span.set_attribute(TOOL_ATTRIBUTE_ERROR, self.error)
|
|
563
|
+
span.log_metric(f"tool/{self.tool_call.name}/error", 1)
|
|
564
|
+
|
|
553
565
|
super().emit(span)
|
|
554
566
|
|
|
555
567
|
def format_as_panel(self, *, truncate: bool = False) -> Panel:
|
|
@@ -591,7 +603,7 @@ class ToolError(AgentEvent):
|
|
|
591
603
|
|
|
592
604
|
def emit(self, span: "TaskSpan") -> None:
|
|
593
605
|
# Attributes
|
|
594
|
-
span.set_attribute(TOOL_ATTRIBUTE_ERROR, str(self.error)
|
|
606
|
+
span.set_attribute(TOOL_ATTRIBUTE_ERROR, str(self.error))
|
|
595
607
|
|
|
596
608
|
# Metrics
|
|
597
609
|
span.log_metric(f"tool/{self.tool_call.name}/error", 1)
|
|
@@ -666,7 +678,7 @@ class GenerationStep(AgentStep):
|
|
|
666
678
|
|
|
667
679
|
if self.messages:
|
|
668
680
|
last_msg = self.messages[-1]
|
|
669
|
-
content = str(last_msg.content)
|
|
681
|
+
content = str(last_msg.content) if last_msg.content else None
|
|
670
682
|
|
|
671
683
|
for tc in last_msg.tool_calls or []:
|
|
672
684
|
try:
|
|
@@ -721,7 +733,7 @@ class GenerationStep(AgentStep):
|
|
|
721
733
|
span.set_attribute(GENERATION_ATTRIBUTE_ROLE, last_msg.role)
|
|
722
734
|
|
|
723
735
|
if last_msg.content:
|
|
724
|
-
span.set_attribute(GENERATION_ATTRIBUTE_CONTENT, str(last_msg.content)
|
|
736
|
+
span.set_attribute(GENERATION_ATTRIBUTE_CONTENT, str(last_msg.content))
|
|
725
737
|
|
|
726
738
|
if last_msg.tool_calls:
|
|
727
739
|
span.set_attribute(
|
|
@@ -780,7 +792,7 @@ class GenerationStart(AgentEvent):
|
|
|
780
792
|
for m in self.messages:
|
|
781
793
|
msg: dict[str, t.Any] = {"role": m.role}
|
|
782
794
|
if m.content:
|
|
783
|
-
msg["content"] = str(m.content)
|
|
795
|
+
msg["content"] = str(m.content)
|
|
784
796
|
if m.tool_calls:
|
|
785
797
|
msg["tool_calls"] = [{"name": tc.name, "id": tc.id} for tc in m.tool_calls]
|
|
786
798
|
input_messages.append(msg)
|
|
@@ -806,7 +818,7 @@ class GenerationEnd(AgentStep):
|
|
|
806
818
|
|
|
807
819
|
if self.messages:
|
|
808
820
|
last_msg = self.messages[-1]
|
|
809
|
-
content = str(last_msg.content)
|
|
821
|
+
content = str(last_msg.content) if last_msg.content else None
|
|
810
822
|
|
|
811
823
|
for tc in last_msg.tool_calls or []:
|
|
812
824
|
try:
|
|
@@ -849,7 +861,7 @@ class GenerationEnd(AgentStep):
|
|
|
849
861
|
span.set_attribute(GENERATION_ATTRIBUTE_ROLE, last_msg.role)
|
|
850
862
|
|
|
851
863
|
if last_msg.content:
|
|
852
|
-
span.set_attribute(GENERATION_ATTRIBUTE_CONTENT, str(last_msg.content)
|
|
864
|
+
span.set_attribute(GENERATION_ATTRIBUTE_CONTENT, str(last_msg.content))
|
|
853
865
|
span.log_output(
|
|
854
866
|
name="generation",
|
|
855
867
|
value=last_msg.content,
|
|
@@ -243,8 +243,16 @@ def find_summarization_boundary(
|
|
|
243
243
|
|
|
244
244
|
Walks messages from the start and enumerates every safe split point that
|
|
245
245
|
leaves at least ``min_messages_to_keep`` messages in the "keep" portion.
|
|
246
|
-
A
|
|
247
|
-
|
|
246
|
+
A boundary is safe when both sides of the cut are API-valid chat
|
|
247
|
+
sequences — no orphaned ``tool_calls`` and no orphaned ``tool`` responses.
|
|
248
|
+
Two kinds of positions qualify:
|
|
249
|
+
|
|
250
|
+
- **After a simple assistant message** (no ``tool_calls``) — the natural
|
|
251
|
+
end of a complete conversational turn.
|
|
252
|
+
- **After a complete tool-call group** — every ``tool_call.id`` from a
|
|
253
|
+
preceding ``assistant`` message has a matching ``tool`` response. The
|
|
254
|
+
cut falls after the last matching tool response, so neither side has a
|
|
255
|
+
dangling tool call or result.
|
|
248
256
|
|
|
249
257
|
When ``max_summarize_chars`` is provided, returns the largest safe split
|
|
250
258
|
whose cumulative ``len(str(message))`` stays within the cap. This keeps
|
|
@@ -264,15 +272,28 @@ def find_summarization_boundary(
|
|
|
264
272
|
# (0, 0) is always a valid "no compaction" candidate.
|
|
265
273
|
candidates: list[tuple[int, int]] = [(0, 0)]
|
|
266
274
|
running_chars = 0
|
|
275
|
+
# Tool-call ids from the most recent assistant(tool_calls) that have not
|
|
276
|
+
# yet been resolved by matching tool responses. When empty, the preceding
|
|
277
|
+
# tool-call group is complete and the position is API-safe to cut at.
|
|
278
|
+
pending_tool_ids: set[str] = set()
|
|
267
279
|
for i, message in enumerate(messages):
|
|
268
280
|
if len(messages) - i <= min_messages_to_keep:
|
|
269
281
|
break
|
|
270
282
|
running_chars += len(str(message))
|
|
271
|
-
|
|
272
|
-
message, "tool_calls", None
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
283
|
+
if message.role == "assistant":
|
|
284
|
+
tool_calls = getattr(message, "tool_calls", None)
|
|
285
|
+
if tool_calls:
|
|
286
|
+
pending_tool_ids = {tc.id for tc in tool_calls}
|
|
287
|
+
elif not pending_tool_ids:
|
|
288
|
+
candidates.append((i + 1, running_chars))
|
|
289
|
+
elif (
|
|
290
|
+
message.role == "tool"
|
|
291
|
+
and getattr(message, "tool_call_id", None)
|
|
292
|
+
and message.tool_call_id in pending_tool_ids
|
|
293
|
+
):
|
|
294
|
+
pending_tool_ids.discard(message.tool_call_id)
|
|
295
|
+
if not pending_tool_ids:
|
|
296
|
+
candidates.append((i + 1, running_chars))
|
|
276
297
|
|
|
277
298
|
if max_summarize_chars is None:
|
|
278
299
|
return candidates[-1][0]
|
|
@@ -29,6 +29,8 @@ from dreadnode.agents.mcp.config import (
|
|
|
29
29
|
Transport,
|
|
30
30
|
)
|
|
31
31
|
from dreadnode.agents.tools import Tool
|
|
32
|
+
from dreadnode.app.paths import rotate_log
|
|
33
|
+
from dreadnode.generators.models import ErrorModel
|
|
32
34
|
|
|
33
35
|
if t.TYPE_CHECKING:
|
|
34
36
|
from mcp import ClientSession
|
|
@@ -44,20 +46,36 @@ class _StderrCapture:
|
|
|
44
46
|
letting it spill into the parent terminal. On connection failure the
|
|
45
47
|
buffered lines are included in the error message so users can see
|
|
46
48
|
why the server process crashed.
|
|
49
|
+
|
|
50
|
+
When a ``log_path`` is provided, each captured line is also tee'd to
|
|
51
|
+
disk so operators can ``tail -f`` the server's stderr — matching the
|
|
52
|
+
subprocess-worker convention under ``~/.dreadnode/logs/``.
|
|
47
53
|
"""
|
|
48
54
|
|
|
49
55
|
_MAX_LINES = 50
|
|
50
56
|
|
|
51
|
-
def __init__(
|
|
57
|
+
def __init__(
|
|
58
|
+
self,
|
|
59
|
+
read_fd: int,
|
|
60
|
+
exit_stack: AsyncExitStack,
|
|
61
|
+
*,
|
|
62
|
+
log_path: Path | None = None,
|
|
63
|
+
) -> None:
|
|
52
64
|
import os
|
|
53
65
|
import threading
|
|
54
66
|
|
|
55
67
|
self._lines: list[str] = []
|
|
56
68
|
self._read_file = os.fdopen(read_fd, "r")
|
|
69
|
+
self._log_file = self._open_log_file(log_path)
|
|
57
70
|
|
|
58
71
|
def _reader() -> None:
|
|
59
72
|
try:
|
|
60
73
|
for raw in self._read_file:
|
|
74
|
+
if self._log_file is not None:
|
|
75
|
+
# Don't let a disk-side failure break the in-memory
|
|
76
|
+
# buffer or the connection itself.
|
|
77
|
+
with contextlib.suppress(OSError):
|
|
78
|
+
self._log_file.write(raw)
|
|
61
79
|
line = raw.rstrip("\n")
|
|
62
80
|
if line:
|
|
63
81
|
logger.debug("MCP stderr: {}", line)
|
|
@@ -71,9 +89,36 @@ class _StderrCapture:
|
|
|
71
89
|
self._thread.start()
|
|
72
90
|
exit_stack.callback(self._close)
|
|
73
91
|
|
|
92
|
+
@staticmethod
|
|
93
|
+
def _open_log_file(log_path: Path | None) -> t.TextIO | None:
|
|
94
|
+
"""Open the stderr log file for writing, or ``None`` on failure.
|
|
95
|
+
|
|
96
|
+
Rotates the prior log to ``<path>.prev`` first, so a failed connect
|
|
97
|
+
leaves the previous session's stderr intact for diffing. Truncates
|
|
98
|
+
on open, line-buffered so ``tail -f`` reflects new output
|
|
99
|
+
immediately.
|
|
100
|
+
"""
|
|
101
|
+
if log_path is None:
|
|
102
|
+
return None
|
|
103
|
+
rotate_log(log_path)
|
|
104
|
+
try:
|
|
105
|
+
log_path.parent.mkdir(parents=True, exist_ok=True)
|
|
106
|
+
return log_path.open("w", buffering=1, encoding="utf-8", errors="replace")
|
|
107
|
+
except OSError as exc:
|
|
108
|
+
logger.warning(
|
|
109
|
+
"MCP stderr capture: failed to open log file '{}' ({}); keeping in-memory buffer only",
|
|
110
|
+
log_path,
|
|
111
|
+
exc,
|
|
112
|
+
)
|
|
113
|
+
return None
|
|
114
|
+
|
|
74
115
|
def _close(self) -> None:
|
|
75
116
|
with contextlib.suppress(OSError):
|
|
76
117
|
self._read_file.close()
|
|
118
|
+
if self._log_file is not None:
|
|
119
|
+
with contextlib.suppress(OSError):
|
|
120
|
+
self._log_file.close()
|
|
121
|
+
self._log_file = None
|
|
77
122
|
self._thread.join(timeout=1)
|
|
78
123
|
|
|
79
124
|
@property
|
|
@@ -156,6 +201,7 @@ class MCPClient:
|
|
|
156
201
|
*,
|
|
157
202
|
oauth: t.Any = None,
|
|
158
203
|
init_timeout: float = DEFAULT_INIT_TIMEOUT,
|
|
204
|
+
log_path: Path | None = None,
|
|
159
205
|
) -> None:
|
|
160
206
|
# Handle deprecated "sse" transport
|
|
161
207
|
if transport == "sse":
|
|
@@ -176,6 +222,9 @@ class MCPClient:
|
|
|
176
222
|
self._session = None
|
|
177
223
|
self._oauth_config = oauth
|
|
178
224
|
self._init_timeout = init_timeout
|
|
225
|
+
# Only meaningful for stdio transports — the stderr capture wires it
|
|
226
|
+
# into _StderrCapture on connect. HTTP transports ignore it.
|
|
227
|
+
self._log_path = log_path
|
|
179
228
|
self._stderr_capture: _StderrCapture | None = None
|
|
180
229
|
self._owner_task = None
|
|
181
230
|
self._shutdown_event = None
|
|
@@ -183,8 +232,13 @@ class MCPClient:
|
|
|
183
232
|
self._lifecycle_lock = None
|
|
184
233
|
|
|
185
234
|
@classmethod
|
|
186
|
-
def from_config(cls, config: ServerConfig) -> "MCPClient":
|
|
187
|
-
"""Create a client from a typed server config.
|
|
235
|
+
def from_config(cls, config: ServerConfig, *, log_path: Path | None = None) -> "MCPClient":
|
|
236
|
+
"""Create a client from a typed server config.
|
|
237
|
+
|
|
238
|
+
The SDK's MCP lifecycle manager passes ``log_path`` to tee stderr
|
|
239
|
+
under ``~/.dreadnode/logs/``. User-code callers of
|
|
240
|
+
:func:`dreadnode.agents.mcp` don't need to supply it.
|
|
241
|
+
"""
|
|
188
242
|
if isinstance(config, StdioServerConfig):
|
|
189
243
|
connection: StdioConnection = StdioConnection(
|
|
190
244
|
command=config.command,
|
|
@@ -192,7 +246,12 @@ class MCPClient:
|
|
|
192
246
|
cwd=config.cwd,
|
|
193
247
|
env=config.env,
|
|
194
248
|
)
|
|
195
|
-
return cls(
|
|
249
|
+
return cls(
|
|
250
|
+
"stdio",
|
|
251
|
+
connection,
|
|
252
|
+
init_timeout=config.init_timeout,
|
|
253
|
+
log_path=log_path,
|
|
254
|
+
)
|
|
196
255
|
|
|
197
256
|
# HttpServerConfig
|
|
198
257
|
connection_dict: dict[str, t.Any] = {
|
|
@@ -206,6 +265,7 @@ class MCPClient:
|
|
|
206
265
|
connection_dict,
|
|
207
266
|
oauth=config.oauth,
|
|
208
267
|
init_timeout=config.init_timeout,
|
|
268
|
+
log_path=log_path,
|
|
209
269
|
)
|
|
210
270
|
|
|
211
271
|
@property
|
|
@@ -217,6 +277,27 @@ class MCPClient:
|
|
|
217
277
|
"""Error message if status is FAILED or NEEDS_AUTH."""
|
|
218
278
|
return self._error
|
|
219
279
|
|
|
280
|
+
@property
|
|
281
|
+
def log_path(self) -> Path | None:
|
|
282
|
+
"""Path that stderr is tee'd to, or ``None`` if capture is in-memory only.
|
|
283
|
+
|
|
284
|
+
Only populated for stdio transports; HTTP transports don't spawn a
|
|
285
|
+
subprocess and have nothing to capture.
|
|
286
|
+
"""
|
|
287
|
+
return self._log_path
|
|
288
|
+
|
|
289
|
+
@property
|
|
290
|
+
def recent_stderr(self) -> list[str]:
|
|
291
|
+
"""Captured stderr lines from the subprocess, bounded by the ring buffer.
|
|
292
|
+
|
|
293
|
+
Mirrors :attr:`SubprocessWorkerRunner.recent_output` so the TUI can
|
|
294
|
+
render the same progressive-disclosure block for MCP servers and
|
|
295
|
+
workers. Empty for HTTP transports or before :meth:`connect` runs.
|
|
296
|
+
"""
|
|
297
|
+
if self._stderr_capture is None:
|
|
298
|
+
return []
|
|
299
|
+
return self._stderr_capture.last_lines
|
|
300
|
+
|
|
220
301
|
@property
|
|
221
302
|
def session(self) -> "ClientSession":
|
|
222
303
|
if self._session is None:
|
|
@@ -226,6 +307,21 @@ class MCPClient:
|
|
|
226
307
|
def _make_execute_on_server(self, tool_name: str) -> t.Callable[..., t.Any]:
|
|
227
308
|
async def execute_on_server(**kwargs: t.Any) -> t.Any:
|
|
228
309
|
result = await self.session.call_tool(tool_name, kwargs)
|
|
310
|
+
# Protocol-level failures (``isError=true``) are reported as a
|
|
311
|
+
# successful response carrying error content. Lift them into
|
|
312
|
+
# an ``ErrorModel`` so ``Tool.handle_tool_call`` routes the
|
|
313
|
+
# message through the same ``metadata['error']`` path used by
|
|
314
|
+
# ``@tool(catch=True)`` failures (e.g. bash non-zero exits).
|
|
315
|
+
if result.isError:
|
|
316
|
+
error_text = (
|
|
317
|
+
"\n".join(
|
|
318
|
+
content.text # ty: ignore[unresolved-attribute]
|
|
319
|
+
for content in result.content
|
|
320
|
+
if content.type == "text"
|
|
321
|
+
)
|
|
322
|
+
or f"MCP tool '{tool_name}' reported an error."
|
|
323
|
+
)
|
|
324
|
+
return ErrorModel(content=error_text, type="MCPToolError")
|
|
229
325
|
return _convert_mcp_result_to_message_parts(result)
|
|
230
326
|
|
|
231
327
|
return execute_on_server
|
|
@@ -333,7 +429,7 @@ class MCPClient:
|
|
|
333
429
|
read_fd, write_fd = os.pipe()
|
|
334
430
|
write_file = os.fdopen(write_fd, "w")
|
|
335
431
|
|
|
336
|
-
stderr_capture = _StderrCapture(read_fd, self._exit_stack)
|
|
432
|
+
stderr_capture = _StderrCapture(read_fd, self._exit_stack, log_path=self._log_path)
|
|
337
433
|
self._stderr_capture = stderr_capture
|
|
338
434
|
|
|
339
435
|
server_params = StdioServerParameters(**connection)
|