dreadnode 2.0.11__tar.gz → 2.0.12__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.11 → dreadnode-2.0.12}/PKG-INFO +2 -1
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/agents/agent.py +32 -6
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/agents/hooks.py +69 -4
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/api/client.py +92 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/api/models.py +37 -2
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/cli/airt.py +14 -2
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/cli/args.py +24 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/cli/capability.py +64 -19
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/cli/main.py +11 -2
- dreadnode-2.0.12/dreadnode/app/cli/runtime.py +470 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/cli/task.py +132 -51
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/cli/templates/init/verify.sh +1 -1
- dreadnode-2.0.12/dreadnode/app/client/__init__.py +1 -0
- dreadnode-2.0.12/dreadnode/app/client/interactive.py +541 -0
- dreadnode-2.0.12/dreadnode/app/client/managed_client.py +396 -0
- dreadnode-2.0.12/dreadnode/app/client/models.py +190 -0
- dreadnode-2.0.12/dreadnode/app/client/runtime_client.py +742 -0
- dreadnode-2.0.12/dreadnode/app/client/transports.py +436 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/config.py +54 -0
- dreadnode-2.0.12/dreadnode/app/env.py +66 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/main.py +37 -14
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/print_mode.py +30 -25
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/server/app.py +1096 -1393
- dreadnode-2.0.12/dreadnode/app/server/auth.py +66 -0
- dreadnode-2.0.12/dreadnode/app/server/capability_manager.py +772 -0
- dreadnode-2.0.12/dreadnode/app/server/model_resolution.py +125 -0
- dreadnode-2.0.12/dreadnode/app/server/prompt_registry.py +153 -0
- dreadnode-2.0.12/dreadnode/app/server/runtime_events.py +503 -0
- dreadnode-2.0.12/dreadnode/app/server/session_hydrator.py +216 -0
- dreadnode-2.0.12/dreadnode/app/server/session_persistence.py +351 -0
- dreadnode-2.0.12/dreadnode/app/server/session_policy.py +426 -0
- dreadnode-2.0.12/dreadnode/app/server/turn_coordinator.py +183 -0
- dreadnode-2.0.12/dreadnode/app/server/websocket.py +731 -0
- dreadnode-2.0.12/dreadnode/app/server/worker_manager.py +517 -0
- dreadnode-2.0.12/dreadnode/app/tui/app.py +3948 -0
- dreadnode-2.0.12/dreadnode/app/tui/auth_flow.py +195 -0
- dreadnode-2.0.12/dreadnode/app/tui/capabilities_manager.py +388 -0
- dreadnode-2.0.12/dreadnode/app/tui/command_dispatcher.py +754 -0
- dreadnode-2.0.12/dreadnode/app/tui/commands.py +79 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/connection.py +33 -30
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/dreadnode.tcss +83 -333
- dreadnode-2.0.12/dreadnode/app/tui/error_handler.py +175 -0
- dreadnode-2.0.12/dreadnode/app/tui/model_manager.py +704 -0
- dreadnode-2.0.12/dreadnode/app/tui/profile_manager.py +1127 -0
- dreadnode-2.0.12/dreadnode/app/tui/screen_router.py +282 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/screens/__init__.py +2 -2
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/screens/auth.py +5 -3
- dreadnode-2.0.12/dreadnode/app/tui/screens/base.py +257 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/screens/capabilities.py +264 -68
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/screens/runtimes.py +62 -59
- dreadnode-2.0.12/dreadnode/app/tui/screens/services.py +700 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/screens/sessions.py +122 -56
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/screens/workspaces.py +44 -47
- dreadnode-2.0.12/dreadnode/app/tui/sessions_manager.py +1625 -0
- dreadnode-2.0.12/dreadnode/app/tui/tool_format.py +311 -0
- dreadnode-2.0.12/dreadnode/app/tui/turn_coordinator.py +642 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/turn_lifecycle.py +25 -1
- dreadnode-2.0.12/dreadnode/app/tui/turn_reducer.py +348 -0
- dreadnode-2.0.12/dreadnode/app/tui/turn_state_phase.py +62 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/widgets/__init__.py +0 -2
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/widgets/agent_suggester.py +1 -1
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/widgets/composer.py +3 -1
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/widgets/context_bar.py +14 -0
- dreadnode-2.0.12/dreadnode/app/tui/widgets/conversation.py +476 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/widgets/help_panel.py +2 -1
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/widgets/tool.py +1 -1
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/widgets/tools_dialog.py +7 -15
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/widgets/welcome.py +1 -0
- dreadnode-2.0.12/dreadnode/app/tui/wire_events.py +464 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/builtin_capabilities/dreadnode/skills/dreadnode-runtime-reference/SKILL.md +3 -5
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/capabilities/__init__.py +2 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/capabilities/capability.py +72 -1
- dreadnode-2.0.12/dreadnode/capabilities/flags.py +299 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/capabilities/loader.py +438 -11
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/capabilities/sync.py +1 -1
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/capabilities/types.py +32 -1
- dreadnode-2.0.12/dreadnode/capabilities/worker.py +268 -0
- dreadnode-2.0.12/dreadnode/capabilities/worker_runner.py +588 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/core/exceptions.py +4 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/generators/generator/litellm_.py +66 -1
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/optimization/jobs.py +1 -2
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/packaging/manifest.py +3 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/packaging/oci.py +48 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/packaging/task_validation.py +97 -4
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/storage/storage.py +132 -6
- dreadnode-2.0.12/dreadnode/tracing/exporter.py +66 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/pyproject.toml +2 -1
- dreadnode-2.0.11/dreadnode/app/cli/runtime.py +0 -55
- dreadnode-2.0.11/dreadnode/app/server/auth.py +0 -53
- dreadnode-2.0.11/dreadnode/app/tui/app.py +0 -5159
- dreadnode-2.0.11/dreadnode/app/tui/client.py +0 -1010
- dreadnode-2.0.11/dreadnode/app/tui/commands.py +0 -505
- dreadnode-2.0.11/dreadnode/app/tui/event_contract.py +0 -342
- dreadnode-2.0.11/dreadnode/app/tui/screens/base.py +0 -108
- dreadnode-2.0.11/dreadnode/app/tui/screens/mcp.py +0 -493
- dreadnode-2.0.11/dreadnode/app/tui/turn_reducer.py +0 -294
- dreadnode-2.0.11/dreadnode/app/tui/widgets/conversation.py +0 -332
- dreadnode-2.0.11/dreadnode/skills/__init__.py +0 -27
- dreadnode-2.0.11/dreadnode/tracing/exporter.py +0 -23
- {dreadnode-2.0.11 → dreadnode-2.0.12}/.gitignore +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/LICENSE +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/README.md +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/__main__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/agents/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/agents/events.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/agents/exceptions.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/agents/format.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/agents/mcp/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/agents/mcp/auth.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/agents/mcp/client.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/agents/mcp/config.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/agents/mcp/server.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/agents/reactions.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/agents/skills.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/agents/stopping.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/agents/subagent.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/agents/tools.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/agents/trajectory.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/analytics/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/analytics/aggregator.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/analytics/classifier.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/analytics/compliance.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/analytics/engine.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/analytics/recommendations.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/analytics/types.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/assessment.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/autodan_turbo.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/beast.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/compliance/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/compliance/atlas.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/compliance/nist.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/compliance/owasp.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/compliance/owasp_agentic.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/compliance/saif.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/constants.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/crescendo.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/data/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/data/assets/audio/adversarial_query.mp3 +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/data/assets/image/bomb.jpg +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/data/assets/image/meth.png +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/data/prompts/adversarial_benchmark_subset.csv +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/data/prompts/ai_safety.csv +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/data/rubrics/data_exfiltration.yaml +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/data/rubrics/goal_hijacking.yaml +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/data/rubrics/memory_poisoning.yaml +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/data/rubrics/privilege_escalation.yaml +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/data/rubrics/rce.yaml +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/data/rubrics/scope_creep.yaml +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/data/rubrics/tool_chaining.yaml +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/data/rubrics/tool_selection_safety.yaml +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/data/rubrics/unbounded_agency.yaml +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/data/rubrics/web_chatbot_security.yaml +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/data/templates/crescendo/variant_1.yaml +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/data/templates/crescendo/variant_2.yaml +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/data/templates/crescendo/variant_3.yaml +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/data/templates/crescendo/variant_4.yaml +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/data/templates/crescendo/variant_5.yaml +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/deep_inception.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/drattack.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/events.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/goat.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/gptfuzzer.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/image.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/multimodal.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/pair.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/prompt.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/rainbow.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/renellm.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/reporting/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/reporting/json_report.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/reporting/llm_summary.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/reporting/markdown.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/airt/tap.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/api/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/cli/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/cli/dataset.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/cli/evaluation.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/cli/model.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/cli/optimize.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/cli/sandbox.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/cli/shared.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/cli/templates/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/cli/templates/init/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/cli/templates/init/challenge/Dockerfile +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/cli/templates/init/docker-compose.yaml +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/cli/templates/init/provision.sh +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/cli/templates/init/solution.sh +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/cli/templates/init/task-remote.yaml.tmpl +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/cli/templates/init/task.yaml.tmpl +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/cli/templates/init/teardown.sh +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/cli/train.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/cli/worlds.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/model_catalog.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/server/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/server/prompt.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/server/utils.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/model_variants.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/runtime_cache.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/screens/capability_docs.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/screens/connection_error.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/screens/console.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/screens/environments.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/screens/evaluations.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/screens/model_picker.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/screens/models.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/screens/raw_spans.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/screens/sandboxes.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/screens/secrets.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/screens/theme_showcase.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/screens/traces.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/spans_reader.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/theme.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/update_check.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/widgets/agent_dialog.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/widgets/flash.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/widgets/header_bar.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/widgets/mention_overlay.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/widgets/message_queue.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/widgets/overlay_mixin.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/widgets/permission_prompt.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/widgets/profile_dialog.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/widgets/prompt_info.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/widgets/session_sidebar.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/widgets/skills_dialog.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/widgets/slash_overlay.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/widgets/status_bar.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/widgets/throbber.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/widgets/tool_progress.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/app/tui/widgets/whoami.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/builtin_capabilities/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/builtin_capabilities/dreadnode/agents/dreadnode.md +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/builtin_capabilities/dreadnode/capability.yaml +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12/dreadnode/builtin_capabilities}/dreadnode/skills/creating-capabilities/SKILL.md +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12/dreadnode/builtin_capabilities}/dreadnode/skills/creating-capabilities/capability-components.md +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12/dreadnode/builtin_capabilities}/dreadnode/skills/creating-capabilities/capability-improvement.md +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12/dreadnode/builtin_capabilities}/dreadnode/skills/creating-capabilities/runtime-default-capability.md +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12/dreadnode/builtin_capabilities}/dreadnode/skills/dreadnode-cli/SKILL.md +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12/dreadnode/builtin_capabilities}/dreadnode/skills/dreadnode-cli/references/command-groups.md +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12/dreadnode/builtin_capabilities}/dreadnode/skills/dreadnode-cli/references/tui-crosswalk.md +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/builtin_capabilities/dreadnode/system-prompt.md +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/capabilities/tool_rules.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/core/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/core/conditions.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/core/discovery.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/core/environment.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/core/execution.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/core/hook.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/core/judge.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/core/load.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/core/log.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/core/meta/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/core/meta/config.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/core/meta/context.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/core/meta/hydrate.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/core/meta/introspect.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/core/metric.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/core/object.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/core/scorer.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/core/serialization.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/core/stopping.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/core/task.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/core/transforms.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/core/types/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/core/types/audio.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/core/types/base.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/core/types/common.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/core/types/image.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/core/types/object_3d.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/core/types/table.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/core/types/text.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/core/types/video.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/core/util.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/datasets/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/datasets/dataset.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/datasets/hf.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/datasets/local.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/evaluations/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/evaluations/console.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/evaluations/evaluation.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/evaluations/events.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/evaluations/format.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/evaluations/result.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/evaluations/sample.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/generators/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/generators/caching.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/generators/chat.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/generators/data.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/generators/exceptions.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/generators/generator/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/generators/generator/base.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/generators/generator/http.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/generators/generator/transformers_.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/generators/generator/vllm_.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/generators/message.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/generators/models.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/generators/parsing.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/generators/tokenizer/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/generators/tokenizer/base.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/generators/tokenizer/transformers_.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/generators/utils.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/models/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/models/hf.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/models/local.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/models/model.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/optimization/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/optimization/adapters/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/optimization/adapters/agent.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/optimization/adapters/stack.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/optimization/api.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/optimization/backends/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/optimization/backends/base.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/optimization/backends/gepa.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/optimization/collectors.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/optimization/config.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/optimization/console.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/optimization/events.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/optimization/format.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/optimization/result.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/optimization/sampler.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/optimization/sampling.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/optimization/search.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/optimization/stopping.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/optimization/study.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/optimization/trial.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/packaging/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/packaging/loader.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/packaging/package.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/py.typed +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/samplers/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/samplers/boundary.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/samplers/fuzzing.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/samplers/graph.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/samplers/grid.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/samplers/image.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/samplers/mapelites.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/samplers/optuna.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/samplers/random.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/samplers/registry.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/samplers/strategy.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/scorers/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/scorers/advanced_jailbreak_detection.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/scorers/agent_security.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/scorers/agentic.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/scorers/agentic_workflow.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/scorers/classification.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/scorers/consistency.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/scorers/contains.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/scorers/cosine_sim.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/scorers/credentials.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/scorers/crucible.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/scorers/documentation_security.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/scorers/exfiltration_detection.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/scorers/format.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/scorers/harm.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/scorers/ide_security.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/scorers/image.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/scorers/json.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/scorers/judge.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/scorers/length.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/scorers/lexical.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/scorers/mcp_security.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/scorers/memorization.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/scorers/multi_agent_security.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/scorers/pii.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/scorers/prompt_leak.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/scorers/readability.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/scorers/reasoning_security.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/scorers/sentiment.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/scorers/similarity.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/storage/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/storage/providers.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/storage/session_store.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/tools/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/tools/_ripgrep.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/tools/apply_patch.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/tools/dreadnode_cli.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/tools/editing.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/tools/execute.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/tools/fetch.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/tools/glob.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/tools/grep.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/tools/interaction.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/tools/ls.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/tools/memory.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/tools/read.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/tools/report.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/tools/task.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/tools/think.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/tools/todo.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/tools/trajectory_search.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/tools/web_search.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/tools/write.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/tracing/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/tracing/constants.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/tracing/convert.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/tracing/exporters.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/tracing/span.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/tracing/spans.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/tracing/trace_converter.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/base.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/dpo.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/etl/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/etl/_common.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/etl/rl.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/etl/sft.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/etl/worlds.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/events.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/grpo.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/jobs.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/ppo.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/prime.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/ray/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/ray/async_trainer.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/ray/config.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/ray/coordinator.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/ray/distributed.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/ray/dpo.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/ray/experience.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/ray/fsdp2_learner.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/ray/inference.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/ray/learner.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/ray/multi_turn.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/ray/ppo.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/ray/reward_model.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/ray/rollout_env.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/ray/rollout_worker.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/ray/sft.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/ray/trainer.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/recipes.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/rewards/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/rewards/aggregator.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/rewards/functions.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/rewards/scorer_bridge.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/rewards/shaping.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/rewards/types.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/rollouts/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/rollouts/adapters.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/rollouts/orchestrator.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/rollouts/types.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/rollouts/worlds.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/serving/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/serving/vllm_client.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/sft.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/tinker/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/tinker/config.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/tinker/data.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/tinker/renderer.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/tinker/rl.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/tinker/trainer.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/tinker_sft.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/training/utils.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/__init__.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/advanced_jailbreak.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/adversarial_suffix.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/agent_skill.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/agentic_workflow.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/audio.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/browser_agent_attacks.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/cipher.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/constitutional.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/document.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/documentation_poison.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/encoding.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/exfiltration.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/flip_attack.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/guardrail_bypass.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/ide_injection.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/image.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/injection.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/json_tools.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/language.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/logic_bomb.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/mcp_attacks.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/multi_agent_attacks.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/persuasion.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/perturbation.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/pii_extraction.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/pythonic_tools.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/rag_poisoning.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/reasoning_attacks.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/refine.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/response_steering.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/stylistic.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/substitution.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/swap.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/system_prompt_extraction.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/text.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/video.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/dreadnode/transforms/xml_tools.py +0 -0
- {dreadnode-2.0.11 → dreadnode-2.0.12}/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.12
|
|
4
4
|
Summary: Dreadnode SDK
|
|
5
5
|
Project-URL: Homepage, https://dreadnode.io
|
|
6
6
|
Project-URL: Documentation, https://docs.dreadnode.io
|
|
@@ -10,6 +10,7 @@ Requires-Python: <3.14,>=3.11
|
|
|
10
10
|
Requires-Dist: aiofiles<25.0.0,>=24.1.0
|
|
11
11
|
Requires-Dist: art<7.0.0,>=6.5
|
|
12
12
|
Requires-Dist: coolname<3.0.0,>=2.2.0
|
|
13
|
+
Requires-Dist: croniter<7.0.0,>=6.0.0
|
|
13
14
|
Requires-Dist: cyclopts>=4.2.0
|
|
14
15
|
Requires-Dist: datasets>=4.5.0
|
|
15
16
|
Requires-Dist: fastapi>=0.115.0
|
|
@@ -487,6 +487,7 @@ class Agent(Executor[AgentEvent, Trajectory]):
|
|
|
487
487
|
than via hook indirection.
|
|
488
488
|
"""
|
|
489
489
|
from dreadnode.agents.hooks import (
|
|
490
|
+
_get_model_context_budget,
|
|
490
491
|
_is_context_length_error,
|
|
491
492
|
find_summarization_boundary,
|
|
492
493
|
summarize_conversation,
|
|
@@ -501,19 +502,38 @@ class Agent(Executor[AgentEvent, Trajectory]):
|
|
|
501
502
|
work = list(messages)
|
|
502
503
|
system_message: Message | None = work.pop(0) if work and work[0].role == "system" else None
|
|
503
504
|
|
|
504
|
-
|
|
505
|
+
summarizer = self._generator
|
|
506
|
+
if summarizer is None:
|
|
507
|
+
return None
|
|
508
|
+
|
|
509
|
+
# Cap summarizer input at ~60% of the model's token budget (~3 chars/token,
|
|
510
|
+
# conservative to prefer over-truncating on code/JSON-heavy content).
|
|
511
|
+
# This keeps the recovery call itself from overflowing the same provider
|
|
512
|
+
# context that triggered recovery.
|
|
513
|
+
budget_tokens = _get_model_context_budget(summarizer)
|
|
514
|
+
max_summarize_chars = int(budget_tokens * 0.6 * 3)
|
|
515
|
+
|
|
516
|
+
boundary = find_summarization_boundary(
|
|
517
|
+
work,
|
|
518
|
+
min_messages_to_keep=10,
|
|
519
|
+
max_summarize_chars=max_summarize_chars,
|
|
520
|
+
)
|
|
505
521
|
if boundary == 0:
|
|
522
|
+
logger.info(
|
|
523
|
+
"Overflow recovery: no safe summarization window fits summarizer budget "
|
|
524
|
+
"(budget_tokens={}, max_chars={})",
|
|
525
|
+
budget_tokens,
|
|
526
|
+
max_summarize_chars,
|
|
527
|
+
)
|
|
506
528
|
return None
|
|
507
529
|
|
|
508
530
|
to_summarize = work[:boundary]
|
|
509
531
|
to_keep = work[boundary:]
|
|
510
532
|
|
|
511
|
-
summarizer = self._generator
|
|
512
|
-
if summarizer is None:
|
|
513
|
-
return None
|
|
514
|
-
|
|
515
533
|
logger.info(
|
|
516
|
-
|
|
534
|
+
"Overflow recovery: summarizing {} messages, keeping {}",
|
|
535
|
+
len(to_summarize),
|
|
536
|
+
len(to_keep),
|
|
517
537
|
)
|
|
518
538
|
|
|
519
539
|
try:
|
|
@@ -781,6 +801,12 @@ class Agent(Executor[AgentEvent, Trajectory]):
|
|
|
781
801
|
step_chat = await self._generate(messages)
|
|
782
802
|
|
|
783
803
|
if step_chat.failed and step_chat.error:
|
|
804
|
+
from dreadnode.agents.hooks import _describe_generation_error
|
|
805
|
+
|
|
806
|
+
logger.error(
|
|
807
|
+
"Generation step failed: {}",
|
|
808
|
+
_describe_generation_error(step_chat.error),
|
|
809
|
+
)
|
|
784
810
|
error_event = GenerationError(
|
|
785
811
|
agent_id=self.agent_id,
|
|
786
812
|
agent_name=self.name,
|
|
@@ -80,6 +80,9 @@ CONTEXT_LENGTH_ERROR_PATTERNS = [
|
|
|
80
80
|
"token limit",
|
|
81
81
|
"maximum context length",
|
|
82
82
|
"is too long",
|
|
83
|
+
"chunk too big",
|
|
84
|
+
"prompt is too long",
|
|
85
|
+
"too many tokens",
|
|
83
86
|
]
|
|
84
87
|
|
|
85
88
|
|
|
@@ -193,32 +196,94 @@ def _is_context_length_error(error: BaseException) -> bool:
|
|
|
193
196
|
return any(pattern in error_str for pattern in CONTEXT_LENGTH_ERROR_PATTERNS)
|
|
194
197
|
|
|
195
198
|
|
|
199
|
+
def _describe_generation_error(error: BaseException) -> dict[str, t.Any]:
|
|
200
|
+
"""Best-effort structured dump of a generation error for diagnostic logs.
|
|
201
|
+
|
|
202
|
+
Returns a dict of litellm-known attributes when present. Never raises:
|
|
203
|
+
attribute access that fails is silently omitted, so callers can log the
|
|
204
|
+
result safely even for hostile or malformed exception objects.
|
|
205
|
+
|
|
206
|
+
Intended for one-per-failure diagnostic logging at the generation error
|
|
207
|
+
site. Presence flags are included for fields whose *content* is not
|
|
208
|
+
itself safe to log (raw bodies may be arbitrary length); they tell a
|
|
209
|
+
future debugger whether structured data exists to look at without
|
|
210
|
+
dumping it into every log line.
|
|
211
|
+
"""
|
|
212
|
+
fields: dict[str, t.Any] = {"type": type(error).__name__}
|
|
213
|
+
|
|
214
|
+
with contextlib.suppress(Exception):
|
|
215
|
+
msg = str(error)
|
|
216
|
+
if msg:
|
|
217
|
+
fields["message"] = msg if len(msg) <= 500 else msg[:500] + "...<truncated>"
|
|
218
|
+
|
|
219
|
+
for attr in ("status_code", "llm_provider", "model", "request_id"):
|
|
220
|
+
with contextlib.suppress(Exception):
|
|
221
|
+
val = getattr(error, attr, None)
|
|
222
|
+
if val is not None:
|
|
223
|
+
fields[attr] = val
|
|
224
|
+
|
|
225
|
+
with contextlib.suppress(Exception):
|
|
226
|
+
fields["has_body"] = bool(getattr(error, "body", None))
|
|
227
|
+
|
|
228
|
+
with contextlib.suppress(Exception):
|
|
229
|
+
resp = getattr(error, "response", None)
|
|
230
|
+
if resp is not None:
|
|
231
|
+
text = getattr(resp, "text", "") or ""
|
|
232
|
+
fields["has_response_text"] = bool(text)
|
|
233
|
+
|
|
234
|
+
return fields
|
|
235
|
+
|
|
236
|
+
|
|
196
237
|
def find_summarization_boundary(
|
|
197
238
|
messages: list[Message],
|
|
198
239
|
min_messages_to_keep: int = 10,
|
|
240
|
+
max_summarize_chars: int | None = None,
|
|
199
241
|
) -> int:
|
|
200
242
|
"""Find a clean message boundary for summarization.
|
|
201
243
|
|
|
202
|
-
Walks messages from the start and
|
|
244
|
+
Walks messages from the start and enumerates every safe split point that
|
|
203
245
|
leaves at least ``min_messages_to_keep`` messages in the "keep" portion.
|
|
204
246
|
A safe boundary is after a simple assistant message (no tool calls) —
|
|
205
247
|
this is the natural end of a complete conversational turn.
|
|
206
248
|
|
|
249
|
+
When ``max_summarize_chars`` is provided, returns the largest safe split
|
|
250
|
+
whose cumulative ``len(str(message))`` stays within the cap. This keeps
|
|
251
|
+
the summarizer call from overflowing the same provider context that
|
|
252
|
+
triggered recovery. ``str(message)`` is exactly what the summarizer
|
|
253
|
+
receives (see ``Agent._try_overflow_recovery``) so the cap and the actual
|
|
254
|
+
serialized input measure the same string — including elision of image
|
|
255
|
+
URLs (``ContentImageUrl.__str__``) and tool-call arguments
|
|
256
|
+
(``ToolCall.__str__``).
|
|
257
|
+
|
|
207
258
|
Returns:
|
|
208
259
|
Index splitting ``messages[:boundary]`` (to summarize) from
|
|
209
260
|
``messages[boundary:]`` (to keep). Returns ``0`` when no valid
|
|
210
261
|
boundary exists.
|
|
211
262
|
"""
|
|
212
|
-
|
|
263
|
+
# Enumerate every safe boundary with its cumulative serialized char count.
|
|
264
|
+
# (0, 0) is always a valid "no compaction" candidate.
|
|
265
|
+
candidates: list[tuple[int, int]] = [(0, 0)]
|
|
266
|
+
running_chars = 0
|
|
213
267
|
for i, message in enumerate(messages):
|
|
214
268
|
if len(messages) - i <= min_messages_to_keep:
|
|
215
269
|
break
|
|
270
|
+
running_chars += len(str(message))
|
|
216
271
|
is_simple_assistant = message.role == "assistant" and not getattr(
|
|
217
272
|
message, "tool_calls", None
|
|
218
273
|
)
|
|
219
274
|
if is_simple_assistant:
|
|
220
|
-
|
|
221
|
-
|
|
275
|
+
candidates.append((i + 1, running_chars))
|
|
276
|
+
|
|
277
|
+
if max_summarize_chars is None:
|
|
278
|
+
return candidates[-1][0]
|
|
279
|
+
|
|
280
|
+
# Cumulative sizes are monotonic in boundary order, so the largest
|
|
281
|
+
# boundary whose size fits the cap is the best match. Walk candidates
|
|
282
|
+
# from latest to earliest and return the first that fits.
|
|
283
|
+
for boundary, size in reversed(candidates):
|
|
284
|
+
if size <= max_summarize_chars:
|
|
285
|
+
return boundary
|
|
286
|
+
return 0
|
|
222
287
|
|
|
223
288
|
|
|
224
289
|
def _get_model_context_budget(model_or_generator: "str | Generator | None") -> int:
|
|
@@ -36,6 +36,7 @@ from dreadnode.app.api.models import (
|
|
|
36
36
|
UserSecretsList,
|
|
37
37
|
Workspace,
|
|
38
38
|
)
|
|
39
|
+
from dreadnode.core.exceptions import InsufficientCreditsError
|
|
39
40
|
from dreadnode.version import VERSION
|
|
40
41
|
|
|
41
42
|
|
|
@@ -109,6 +110,11 @@ class ApiClient:
|
|
|
109
110
|
else:
|
|
110
111
|
return f"{response.status_code}: {detail}"
|
|
111
112
|
|
|
113
|
+
@staticmethod
|
|
114
|
+
def _is_credit_related_429(detail: str) -> bool:
|
|
115
|
+
lowered = detail.lower()
|
|
116
|
+
return "credit" in lowered
|
|
117
|
+
|
|
112
118
|
def _request(
|
|
113
119
|
self,
|
|
114
120
|
method: str,
|
|
@@ -141,6 +147,11 @@ class ApiClient:
|
|
|
141
147
|
response = self._request(method, path, params, json_data, data, headers)
|
|
142
148
|
if response.status_code == 401:
|
|
143
149
|
raise AuthenticationError(self._get_error_message(response))
|
|
150
|
+
if response.status_code == 429:
|
|
151
|
+
error_message = self._get_error_message(response)
|
|
152
|
+
detail = error_message.split(": ", 1)[1] if ": " in error_message else error_message
|
|
153
|
+
if self._is_credit_related_429(detail):
|
|
154
|
+
raise InsufficientCreditsError(detail)
|
|
144
155
|
try:
|
|
145
156
|
response.raise_for_status()
|
|
146
157
|
except httpx.HTTPStatusError as e:
|
|
@@ -1086,6 +1097,64 @@ class ApiClient:
|
|
|
1086
1097
|
)
|
|
1087
1098
|
return t.cast("dict[str, t.Any]", response.json())
|
|
1088
1099
|
|
|
1100
|
+
def create_runtime(
|
|
1101
|
+
self,
|
|
1102
|
+
org: str,
|
|
1103
|
+
workspace: str,
|
|
1104
|
+
project: str | None = None,
|
|
1105
|
+
*,
|
|
1106
|
+
key: str | None = None,
|
|
1107
|
+
name: str | None = None,
|
|
1108
|
+
description: str | None = None,
|
|
1109
|
+
config: dict[str, t.Any] | None = None,
|
|
1110
|
+
) -> dict[str, t.Any]:
|
|
1111
|
+
"""POST /org/{org}/ws/{workspace}/runtimes - Ensure a runtime exists."""
|
|
1112
|
+
payload: dict[str, t.Any] = {}
|
|
1113
|
+
if project is not None:
|
|
1114
|
+
payload["project"] = project
|
|
1115
|
+
if key is not None:
|
|
1116
|
+
payload["key"] = key
|
|
1117
|
+
if name is not None:
|
|
1118
|
+
payload["name"] = name
|
|
1119
|
+
if description is not None:
|
|
1120
|
+
payload["description"] = description
|
|
1121
|
+
if config is not None:
|
|
1122
|
+
payload["config"] = config
|
|
1123
|
+
response = self.request(
|
|
1124
|
+
"POST",
|
|
1125
|
+
f"/org/{org}/ws/{workspace}/runtimes",
|
|
1126
|
+
json_data=payload,
|
|
1127
|
+
)
|
|
1128
|
+
return t.cast("dict[str, t.Any]", response.json())
|
|
1129
|
+
|
|
1130
|
+
def get_runtime_config(
|
|
1131
|
+
self,
|
|
1132
|
+
org: str,
|
|
1133
|
+
workspace: str,
|
|
1134
|
+
runtime_id: str,
|
|
1135
|
+
) -> dict[str, t.Any]:
|
|
1136
|
+
"""GET /org/{org}/ws/{workspace}/runtimes/{runtime_id}/config - Get runtime config."""
|
|
1137
|
+
response = self.request(
|
|
1138
|
+
"GET",
|
|
1139
|
+
f"/org/{org}/ws/{workspace}/runtimes/{runtime_id}/config",
|
|
1140
|
+
)
|
|
1141
|
+
return t.cast("dict[str, t.Any]", response.json())
|
|
1142
|
+
|
|
1143
|
+
def update_runtime_config(
|
|
1144
|
+
self,
|
|
1145
|
+
org: str,
|
|
1146
|
+
workspace: str,
|
|
1147
|
+
runtime_id: str,
|
|
1148
|
+
config: dict[str, t.Any],
|
|
1149
|
+
) -> dict[str, t.Any]:
|
|
1150
|
+
"""PUT /org/{org}/ws/{workspace}/runtimes/{runtime_id}/config - Replace runtime config."""
|
|
1151
|
+
response = self.request(
|
|
1152
|
+
"PUT",
|
|
1153
|
+
f"/org/{org}/ws/{workspace}/runtimes/{runtime_id}/config",
|
|
1154
|
+
json_data={"config": config},
|
|
1155
|
+
)
|
|
1156
|
+
return t.cast("dict[str, t.Any]", response.json())
|
|
1157
|
+
|
|
1089
1158
|
def pause_runtime(self, org: str, workspace: str, runtime_id: str) -> dict[str, t.Any]:
|
|
1090
1159
|
"""POST /org/{org}/ws/{workspace}/runtimes/{runtime_id}/pause - Pause a runtime."""
|
|
1091
1160
|
response = self.request(
|
|
@@ -1722,6 +1791,23 @@ class ApiClient:
|
|
|
1722
1791
|
)
|
|
1723
1792
|
return t.cast("dict[str, t.Any]", response.json())
|
|
1724
1793
|
|
|
1794
|
+
def set_runtime_capability_flags(
|
|
1795
|
+
self,
|
|
1796
|
+
org: str,
|
|
1797
|
+
workspace: str,
|
|
1798
|
+
runtime_id: str,
|
|
1799
|
+
binding_id: str,
|
|
1800
|
+
*,
|
|
1801
|
+
flags: dict[str, bool | None],
|
|
1802
|
+
) -> dict[str, t.Any]:
|
|
1803
|
+
"""PATCH /org/{org}/ws/{workspace}/runtimes/{runtime_id}/capabilities/{binding_id}."""
|
|
1804
|
+
response = self.request(
|
|
1805
|
+
"PATCH",
|
|
1806
|
+
f"/org/{org}/ws/{workspace}/runtimes/{runtime_id}/capabilities/{binding_id}",
|
|
1807
|
+
json_data={"flags": flags},
|
|
1808
|
+
)
|
|
1809
|
+
return t.cast("dict[str, t.Any]", response.json())
|
|
1810
|
+
|
|
1725
1811
|
def update_runtime_capability(
|
|
1726
1812
|
self,
|
|
1727
1813
|
org: str,
|
|
@@ -1881,6 +1967,7 @@ class ApiClient:
|
|
|
1881
1967
|
title: str | None = None,
|
|
1882
1968
|
message_count: int = 0,
|
|
1883
1969
|
project_id: str | None = None,
|
|
1970
|
+
runtime_id: str | None = None,
|
|
1884
1971
|
) -> dict[str, t.Any]:
|
|
1885
1972
|
"""POST /org/{org}/ws/{workspace}/sessions - Create or save a session."""
|
|
1886
1973
|
payload: dict[str, t.Any] = {
|
|
@@ -1894,6 +1981,8 @@ class ApiClient:
|
|
|
1894
1981
|
payload["title"] = title
|
|
1895
1982
|
if project_id is not None:
|
|
1896
1983
|
payload["project_id"] = project_id
|
|
1984
|
+
if runtime_id is not None:
|
|
1985
|
+
payload["runtime_id"] = runtime_id
|
|
1897
1986
|
response = self.request("POST", f"/org/{org}/ws/{workspace}/sessions", json_data=payload)
|
|
1898
1987
|
return t.cast("dict[str, t.Any]", response.json())
|
|
1899
1988
|
|
|
@@ -2500,6 +2589,7 @@ class ApiClient:
|
|
|
2500
2589
|
*,
|
|
2501
2590
|
name: str,
|
|
2502
2591
|
project_id: str,
|
|
2592
|
+
runtime_id: str | None = None,
|
|
2503
2593
|
description: str | None = None,
|
|
2504
2594
|
session_id: str | None = None,
|
|
2505
2595
|
target_model: str | None = None,
|
|
@@ -2517,6 +2607,8 @@ class ApiClient:
|
|
|
2517
2607
|
payload["description"] = description
|
|
2518
2608
|
if session_id is not None:
|
|
2519
2609
|
payload["session_id"] = session_id
|
|
2610
|
+
if runtime_id is not None:
|
|
2611
|
+
payload["runtime_id"] = runtime_id
|
|
2520
2612
|
if target_model is not None:
|
|
2521
2613
|
payload["target_model"] = target_model
|
|
2522
2614
|
if attacker_model is not None:
|
|
@@ -792,6 +792,9 @@ class SessionInfo(BaseModel):
|
|
|
792
792
|
agent: str | None = None
|
|
793
793
|
title: str | None = None
|
|
794
794
|
preview: str | None = None
|
|
795
|
+
policy_name: str = "interactive"
|
|
796
|
+
policy_is_autonomous: bool = False
|
|
797
|
+
policy_display_label: str = ""
|
|
795
798
|
|
|
796
799
|
|
|
797
800
|
class SessionMessage(BaseModel):
|
|
@@ -814,6 +817,7 @@ class SessionCreateRequest(BaseModel):
|
|
|
814
817
|
default=None,
|
|
815
818
|
validation_alias="generateParamsExtra",
|
|
816
819
|
)
|
|
820
|
+
policy: str | dict[str, t.Any] | None = None
|
|
817
821
|
|
|
818
822
|
model_config = ConfigDict(populate_by_name=True)
|
|
819
823
|
|
|
@@ -823,6 +827,13 @@ class SessionCreateRequest(BaseModel):
|
|
|
823
827
|
return _normalize_default_agent_fields(data)
|
|
824
828
|
|
|
825
829
|
|
|
830
|
+
class SessionEventPublishRequest(BaseModel):
|
|
831
|
+
"""Request body for publishing an event into a session's event bus."""
|
|
832
|
+
|
|
833
|
+
kind: str
|
|
834
|
+
payload: dict[str, t.Any] = Field(default_factory=dict)
|
|
835
|
+
|
|
836
|
+
|
|
826
837
|
class SessionRestoreRequest(BaseModel):
|
|
827
838
|
"""Request body for restoring a server-side session runtime."""
|
|
828
839
|
|
|
@@ -882,9 +893,9 @@ class CapabilityAgentInfo(BaseModel):
|
|
|
882
893
|
class ComponentStatusInfo(BaseModel):
|
|
883
894
|
"""Component-level load/runtime status."""
|
|
884
895
|
|
|
885
|
-
kind: t.Literal["agent", "tool", "hook", "skill", "mcp_server", "capability", "check"]
|
|
896
|
+
kind: t.Literal["agent", "tool", "hook", "skill", "mcp_server", "capability", "check", "worker"]
|
|
886
897
|
name: str
|
|
887
|
-
status: t.Literal["ok", "error", "degraded"]
|
|
898
|
+
status: t.Literal["ok", "error", "degraded", "stopped", "gated_off", "enabled_failed"]
|
|
888
899
|
error: str | None = None
|
|
889
900
|
detail: str | None = None
|
|
890
901
|
# MCP-specific optional fields
|
|
@@ -892,6 +903,20 @@ class ComponentStatusInfo(BaseModel):
|
|
|
892
903
|
capability: str | None = None
|
|
893
904
|
transport: str | None = None
|
|
894
905
|
tool_count: int | None = None
|
|
906
|
+
# Gate-eligible components (MCP server / worker): flag names that would
|
|
907
|
+
# satisfy the when: predicate. Present when status is gated_off so the
|
|
908
|
+
# TUI can tell operators which flag to flip (CAP-FLAG-014).
|
|
909
|
+
when: list[str] | None = None
|
|
910
|
+
|
|
911
|
+
|
|
912
|
+
class FlagInfo(BaseModel):
|
|
913
|
+
"""Resolved flag state exposed by the local runtime."""
|
|
914
|
+
|
|
915
|
+
name: str
|
|
916
|
+
description: str
|
|
917
|
+
default: bool
|
|
918
|
+
effective: bool
|
|
919
|
+
source: t.Literal["default", "binding", "env", "cli"]
|
|
895
920
|
|
|
896
921
|
|
|
897
922
|
class CapabilityInfo(BaseModel):
|
|
@@ -911,6 +936,7 @@ class CapabilityInfo(BaseModel):
|
|
|
911
936
|
enabled: bool = True
|
|
912
937
|
binding_id: str | None = None
|
|
913
938
|
update_available: str | None = None
|
|
939
|
+
flags: list[FlagInfo] = []
|
|
914
940
|
components: list[ComponentStatusInfo] = []
|
|
915
941
|
dependencies: dict[str, t.Any] | None = None
|
|
916
942
|
checks: list[dict[str, t.Any]] | None = None
|
|
@@ -945,6 +971,15 @@ class ToolInfo(BaseModel):
|
|
|
945
971
|
name: str
|
|
946
972
|
description: str = ""
|
|
947
973
|
capability: str = ""
|
|
974
|
+
parameters_schema: dict[str, t.Any] | None = None
|
|
975
|
+
"""JSON Schema for the tool's parameters, if available.
|
|
976
|
+
|
|
977
|
+
Populated for first-class :class:`dreadnode.agents.tools.Tool`
|
|
978
|
+
instances and MCP tools; ``None`` for synthetic session-scoped
|
|
979
|
+
entries (``load_skill``, ``spawn_agent``) where no schema applies.
|
|
980
|
+
The TUI uses this to register per-tool display hints — without it,
|
|
981
|
+
unknown tools fall back to the generic first-string-arg heuristic.
|
|
982
|
+
"""
|
|
948
983
|
|
|
949
984
|
|
|
950
985
|
class ToolsResponse(BaseModel):
|
|
@@ -70,7 +70,14 @@ def _summarize_report(p: dict[str, t.Any]) -> str:
|
|
|
70
70
|
def create(
|
|
71
71
|
*,
|
|
72
72
|
name: str,
|
|
73
|
-
project_id:
|
|
73
|
+
project_id: t.Annotated[
|
|
74
|
+
str | None,
|
|
75
|
+
cyclopts.Parameter(help="Project ID. Defaults to the active project scope."),
|
|
76
|
+
] = None,
|
|
77
|
+
runtime_id: t.Annotated[
|
|
78
|
+
str | None,
|
|
79
|
+
cyclopts.Parameter(help="Runtime ID. Required when the project has multiple runtimes."),
|
|
80
|
+
] = None,
|
|
74
81
|
description: t.Annotated[str | None, cyclopts.Parameter(help="Assessment description")] = None,
|
|
75
82
|
session_id: t.Annotated[str | None, cyclopts.Parameter(help="Session ID to associate")] = None,
|
|
76
83
|
target_config: t.Annotated[
|
|
@@ -91,11 +98,16 @@ def create(
|
|
|
91
98
|
) -> None:
|
|
92
99
|
"""Create a new AIRT assessment."""
|
|
93
100
|
api, profile = platform.connect()
|
|
101
|
+
resolved_project_id = project_id or profile.project_id
|
|
102
|
+
if resolved_project_id is None:
|
|
103
|
+
raise ValueError("Project ID required. Pass --project-id or set an active project scope.")
|
|
104
|
+
|
|
94
105
|
payload = api.create_airt_assessment(
|
|
95
106
|
profile.org_key,
|
|
96
107
|
profile.workspace_key,
|
|
97
108
|
name=name,
|
|
98
|
-
project_id=
|
|
109
|
+
project_id=resolved_project_id,
|
|
110
|
+
runtime_id=runtime_id,
|
|
99
111
|
description=description,
|
|
100
112
|
session_id=session_id,
|
|
101
113
|
target_config=_parse_json_object_option(target_config, field_name="--target-config"),
|
|
@@ -199,6 +199,15 @@ class TuiArgs(PlatformScopeArgs):
|
|
|
199
199
|
help="Enable specific capability (repeatable, exclusive)",
|
|
200
200
|
),
|
|
201
201
|
] = None
|
|
202
|
+
capability_flags: t.Annotated[
|
|
203
|
+
list[str] | None,
|
|
204
|
+
cyclopts.Parameter(
|
|
205
|
+
name="--capability-flag",
|
|
206
|
+
group=TUI_GROUP,
|
|
207
|
+
negative_iterable=(),
|
|
208
|
+
help="Override capability flag (repeatable, format: capability.flag=true|false)",
|
|
209
|
+
),
|
|
210
|
+
] = None
|
|
202
211
|
prompt: t.Annotated[
|
|
203
212
|
str | None,
|
|
204
213
|
cyclopts.Parameter(
|
|
@@ -222,3 +231,18 @@ class TuiArgs(PlatformScopeArgs):
|
|
|
222
231
|
help="Headless mode: execute --prompt, print response to stdout, exit",
|
|
223
232
|
),
|
|
224
233
|
] = False
|
|
234
|
+
auto: t.Annotated[
|
|
235
|
+
bool,
|
|
236
|
+
cyclopts.Parameter(
|
|
237
|
+
group=TUI_GROUP,
|
|
238
|
+
negative=(),
|
|
239
|
+
help="Launch in autonomous mode: the agent runs without human prompts, bounded by --max-steps",
|
|
240
|
+
),
|
|
241
|
+
] = False
|
|
242
|
+
max_steps: t.Annotated[
|
|
243
|
+
int | None,
|
|
244
|
+
cyclopts.Parameter(
|
|
245
|
+
group=TUI_GROUP,
|
|
246
|
+
help="Step budget for autonomous mode (defaults to 30)",
|
|
247
|
+
),
|
|
248
|
+
] = None
|
|
@@ -259,6 +259,50 @@ def _summarize_capability(p: dict[str, t.Any]) -> str:
|
|
|
259
259
|
return f"[cyan]{name}[/cyan]@[dim]{version}[/dim] {_visibility_markup(visibility)}{suffix}"
|
|
260
260
|
|
|
261
261
|
|
|
262
|
+
def _download_capability_files(
|
|
263
|
+
api: t.Any,
|
|
264
|
+
org: str,
|
|
265
|
+
name: str,
|
|
266
|
+
version: str,
|
|
267
|
+
dest: Path,
|
|
268
|
+
) -> None:
|
|
269
|
+
"""Download capability files to *dest*, trying bundle then file-by-file."""
|
|
270
|
+
from loguru import logger
|
|
271
|
+
|
|
272
|
+
from dreadnode.capabilities.sync import _extract_tar_to_dir
|
|
273
|
+
|
|
274
|
+
# Fast path: single tar.gz bundle download
|
|
275
|
+
bundle_ok = False
|
|
276
|
+
try:
|
|
277
|
+
data = api.download_capability_bundle(org, name, version)
|
|
278
|
+
_extract_tar_to_dir(data, dest)
|
|
279
|
+
bundle_ok = True
|
|
280
|
+
except Exception:
|
|
281
|
+
logger.debug(
|
|
282
|
+
"Bundle download unavailable for {}/{}@{}, falling back to file-by-file",
|
|
283
|
+
org,
|
|
284
|
+
name,
|
|
285
|
+
version,
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
if bundle_ok:
|
|
289
|
+
return
|
|
290
|
+
|
|
291
|
+
# Slow path: fetch manifest and download each file individually
|
|
292
|
+
detail = api.get_capability(org, name, version)
|
|
293
|
+
file_manifest = detail.get("file_manifest", [])
|
|
294
|
+
if not file_manifest:
|
|
295
|
+
raise RuntimeError(f"Capability {org}/{name}@{version} has no downloadable files")
|
|
296
|
+
|
|
297
|
+
dest.mkdir(parents=True, exist_ok=True)
|
|
298
|
+
for entry in file_manifest:
|
|
299
|
+
file_path = entry["path"]
|
|
300
|
+
content = api.get_capability_file(org, name, version, file_path)
|
|
301
|
+
file_dest = dest / file_path
|
|
302
|
+
file_dest.parent.mkdir(parents=True, exist_ok=True)
|
|
303
|
+
file_dest.write_bytes(content if isinstance(content, bytes) else content.encode())
|
|
304
|
+
|
|
305
|
+
|
|
262
306
|
# ---------------------------------------------------------------------------
|
|
263
307
|
# push
|
|
264
308
|
# ---------------------------------------------------------------------------
|
|
@@ -429,36 +473,37 @@ def info(
|
|
|
429
473
|
def pull(
|
|
430
474
|
ref: str,
|
|
431
475
|
*,
|
|
432
|
-
|
|
476
|
+
output: t.Annotated[Path | None, cyclopts.Parameter(name="--output", alias="-o")] = None,
|
|
477
|
+
force: t.Annotated[bool, cyclopts.Parameter(negative=())] = False,
|
|
433
478
|
platform: PlatformArgs = PlatformArgs(),
|
|
434
479
|
) -> None:
|
|
435
|
-
"""Download a capability to
|
|
480
|
+
"""Download a capability to a local directory.
|
|
436
481
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
482
|
+
Fetches the capability from the registry and writes it to disk.
|
|
483
|
+
Defaults to a folder named after the capability in the current
|
|
484
|
+
directory. Use ``--output`` to choose a different destination.
|
|
485
|
+
|
|
486
|
+
This does **not** install or activate the capability — use
|
|
487
|
+
``install`` for that.
|
|
440
488
|
|
|
441
489
|
Args:
|
|
442
490
|
ref: Capability to pull (e.g. my-cap, my-cap@1.0.0, or acme/my-cap).
|
|
443
|
-
|
|
491
|
+
output: Destination directory. Defaults to ./<capability-name>.
|
|
492
|
+
force: Overwrite the destination if it already exists.
|
|
444
493
|
"""
|
|
445
|
-
dn = configured_dreadnode(platform)
|
|
446
|
-
_api, profile = platform.connect()
|
|
447
|
-
parsed = ArtifactRef.parse(ref, profile.org_key)
|
|
448
494
|
|
|
449
|
-
|
|
450
|
-
|
|
495
|
+
api, profile = platform.connect()
|
|
496
|
+
parsed = ensure_version(api, "capability", ArtifactRef.parse(ref, profile.org_key))
|
|
451
497
|
|
|
452
|
-
|
|
498
|
+
dest = (output or Path.cwd() / parsed.name).resolve()
|
|
453
499
|
|
|
454
|
-
if
|
|
455
|
-
|
|
500
|
+
if dest.exists():
|
|
501
|
+
if not force:
|
|
502
|
+
raise FileExistsError(f"{dest} already exists — use --force to overwrite")
|
|
503
|
+
shutil.rmtree(dest)
|
|
456
504
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
console.print(f"Pulled {display} to {result.dest}")
|
|
460
|
-
else:
|
|
461
|
-
console.print(f"Pulled {display}")
|
|
505
|
+
_download_capability_files(api, parsed.org, parsed.name, parsed.version, dest)
|
|
506
|
+
print_success(f"Pulled {parsed.format()} to {dest}")
|
|
462
507
|
|
|
463
508
|
|
|
464
509
|
# ---------------------------------------------------------------------------
|
|
@@ -148,6 +148,12 @@ def create_app(tui_args: TuiArgs) -> "DreadnodeTextualApp":
|
|
|
148
148
|
except Exception:
|
|
149
149
|
profile = None
|
|
150
150
|
|
|
151
|
+
initial_policy: dict[str, t.Any] | None = None
|
|
152
|
+
if tui_args.auto:
|
|
153
|
+
initial_policy = {"name": "headless"}
|
|
154
|
+
if tui_args.max_steps is not None:
|
|
155
|
+
initial_policy["max_steps"] = tui_args.max_steps
|
|
156
|
+
|
|
151
157
|
return DreadnodeTextualApp(
|
|
152
158
|
profile=profile,
|
|
153
159
|
platform_url=platform_url,
|
|
@@ -158,7 +164,9 @@ def create_app(tui_args: TuiArgs) -> "DreadnodeTextualApp":
|
|
|
158
164
|
initial_prompt=tui_args.prompt,
|
|
159
165
|
capabilities_dirs=tui_args.capabilities_dirs,
|
|
160
166
|
capabilities=tui_args.capabilities,
|
|
167
|
+
capability_flags=tui_args.capability_flags,
|
|
161
168
|
system_prompt=tui_args.system_prompt,
|
|
169
|
+
initial_policy=initial_policy,
|
|
162
170
|
)
|
|
163
171
|
|
|
164
172
|
|
|
@@ -188,6 +196,7 @@ def _run_print(tui_args: TuiArgs) -> None:
|
|
|
188
196
|
agent=tui_args.agent,
|
|
189
197
|
capabilities_dirs=tui_args.capabilities_dirs,
|
|
190
198
|
capabilities=tui_args.capabilities,
|
|
199
|
+
capability_flags=tui_args.capability_flags,
|
|
191
200
|
system_prompt=tui_args.system_prompt,
|
|
192
201
|
server_url=tui_args.runtime_server,
|
|
193
202
|
platform_url=tui_args.server,
|
|
@@ -234,7 +243,7 @@ def login(
|
|
|
234
243
|
) -> None:
|
|
235
244
|
"""Authenticate with the Dreadnode platform."""
|
|
236
245
|
from dreadnode.app.config import DEFAULT_PLATFORM_URL
|
|
237
|
-
from dreadnode.app.tui.
|
|
246
|
+
from dreadnode.app.tui.auth_flow import _login_with_api_key
|
|
238
247
|
|
|
239
248
|
server_url = (server or DEFAULT_PLATFORM_URL).rstrip("/")
|
|
240
249
|
|
|
@@ -286,7 +295,7 @@ def _login_with_device_code(
|
|
|
286
295
|
import httpx
|
|
287
296
|
|
|
288
297
|
from dreadnode.app.api.client import ApiClient
|
|
289
|
-
from dreadnode.app.tui.
|
|
298
|
+
from dreadnode.app.tui.auth_flow import _login_with_api_key
|
|
290
299
|
|
|
291
300
|
api = ApiClient(server_url)
|
|
292
301
|
payload = api.create_device_code()
|