talkops-opscloud 0.3.0b5__tar.gz → 0.3.0b7__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.
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/PKG-INFO +1 -1
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/pyproject.toml +1 -1
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/cli/interactive.py +16 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/cli/server_manager.py +12 -3
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/core/pool.py +11 -1
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/middleware/skills.py +10 -1
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/model/pool.py +59 -52
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/server/server.py +179 -27
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/server/server_graph.py +57 -26
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/state/session.py +11 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/app.py +121 -14
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/autocomplete.py +41 -2
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/chat_input.py +210 -42
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/pool_selector.py +9 -3
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/conftest.py +24 -2
- talkops_opscloud-0.3.0b7/tests/unit_tests/test_chat_input_responsiveness.py +143 -0
- talkops_opscloud-0.3.0b7/tests/unit_tests/test_checkpointer.py +115 -0
- talkops_opscloud-0.3.0b7/tests/unit_tests/test_pool_persistence.py +173 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_reload_restart.py +82 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_server.py +38 -4
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/uv.lock +1 -1
- talkops_opscloud-0.3.0b5/tests/unit_tests/test_checkpointer.py +0 -87
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/.dockerignore +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/.env.example +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/.github/workflows/ci.yml +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/.github/workflows/release-pypi.yml +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/.gitignore +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/.python-version +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/LICENSE +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/README.md +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/assets/opscloud-banner.gif +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/docs/opscloud-docs/Configuration.md +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/docs/opscloud-docs/approval-mode.md +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/docs/opscloud-docs/cli-reference.md +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/docs/opscloud-docs/config.toml.md +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/docs/opscloud-docs/credentials.md +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/docs/opscloud-docs/goal-and-rubrics.md +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/docs/opscloud-docs/hooks.md +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/docs/opscloud-docs/mcp-tools.md +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/docs/opscloud-docs/memory-and-skills.md +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/docs/opscloud-docs/model-providers.md +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/docs/opscloud-docs/overview.md +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/docs/opscloud-docs/plugins.md +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/docs/opscloud-docs/quickstart.md +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/docs/opscloud-docs/remote-sandboxes.md +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/docs/opscloud-docs/subagents.md +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/scripts/install.sh +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/__main__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/_constants.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/_debug.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/_debug_buffer.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/_textual_patches.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/_version.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/agent/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/agent/config.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/agent/factory.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/approval_mode.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/backend/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/backend/composite.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/backend/local.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/backend/registry.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/backend/sandbox_config.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/backend/sandbox_factory.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/built_in_skills/remember/SKILL.md +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/built_in_skills/skill-creator/SKILL.md +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/built_in_skills/skill-creator/scripts/init_skill.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/built_in_skills/skill-creator/scripts/quick_validate.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/cli/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/cli/commands/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/cli/commands/auth.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/cli/commands/doctor.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/cli/commands/mcp.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/cli/commands/threads.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/cli/main.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/cli/non_interactive.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/_base.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/_guards.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/_router.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/_types.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/core/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/core/auth.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/core/bug.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/core/clear.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/core/cloud.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/core/compact.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/core/config_cmd.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/core/context.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/core/cost.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/core/doctor.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/core/effort.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/core/exit_cmd.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/core/fast.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/core/help_cmd.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/core/mcp.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/core/model.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/core/permissions.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/core/plugins.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/core/resume.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/core/skills.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/power/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/power/agents.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/power/btw.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/power/copy.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/power/goal.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/power/loop.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/power/memory.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/power/review.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/power/rubric.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/power/runtime.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/power/skill_creator.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/power/skill_invoke.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/power/tasks.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/power/trace.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/power/ui_toggles.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/power/version.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/commands/registry.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/config/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/config/adapters/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/config/adapters/postgres.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/config/adapters/sqlite.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/config/aws.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/config/cloud_profiles.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/config/env_vars.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/config/langsmith.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/config/manifest.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/config/metadata.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/config/paths.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/config/plugins.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/config/settings.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/config/store.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/config/store_factory.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/config/toml_config.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/editor.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/exceptions.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/file_ops.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/hooks/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/hooks/env.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/hooks/interrupt.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/hooks/models/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/hooks/models/adapters.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/hooks/models/config.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/hooks/models/domain.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/hooks/models/transport.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/hooks/tools.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/input.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/integrations/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/integrations/base.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/integrations/content_filter.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/integrations/event_bus.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/integrations/hooks.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/integrations/identity.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/integrations/notifications.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/integrations/stream_bridge.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/integrations/thread_store.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/json_types.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/mcp/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/mcp/config.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/mcp/discovery.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/mcp/mcp_info.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/mcp/middleware.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/mcp/preload.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/mcp/raw_config.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/mcp/semantic_profiler.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/mcp/session_manager.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/mcp/trust.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/memory/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/memory/branch.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/memory/guard.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/memory/onboarding.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/memory/registry.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/memory/store.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/middleware/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/middleware/_repository_bounds.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/middleware/ask_user.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/middleware/auto_mode.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/middleware/auto_mode_hitl.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/middleware/compaction.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/middleware/configurable_model.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/middleware/cost_tracking.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/middleware/glm_stall_recovery.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/middleware/goal_criteria.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/middleware/goal_state_notice.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/middleware/goal_tools.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/middleware/headless_mcp_guard.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/middleware/jev_model_router.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/middleware/local_context.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/middleware/mcp_context.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/middleware/mcp_middleware.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/middleware/memory_guard.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/middleware/model_retry.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/middleware/registry.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/middleware/reliable_rubric.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/middleware/resume_state.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/middleware/server_hooks.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/middleware/shell_allow_list.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/middleware/subagent_artifacts.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/middleware/subagent_telemetry.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/middleware/subagents.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/middleware/tool_filter.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/middleware/unified_system_message.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/model/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/model/config.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/model/factory.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/model/reasoning.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/offload.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/output.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/plugins/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/plugins/_json.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/plugins/adapters/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/plugins/adapters/agents.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/plugins/adapters/commands.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/plugins/adapters/mcp.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/plugins/adapters/skills.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/plugins/commands_cli.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/plugins/discovery.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/plugins/manifest.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/plugins/marketplace.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/plugins/models.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/plugins/project_plugins.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/plugins/protocol.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/plugins/store.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/plugins/substitution.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/project_utils.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/prompts/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/prompts/system.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/prompts/templates/system_prompt.md +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/prompts/types.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/rubrics/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/rubrics/evaluator.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/rubrics/evidence_extractor.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/rubrics/generator.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/rubrics/jev_compiler.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/rubrics/jev_grader.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/rubrics/middleware.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/schema/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/schema/interrupts.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/security/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/security/approval_mode.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/security/approval_mode_source.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/security/cli_ast_evaluator.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/security/jev_classifier.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/security/shell_safety.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/security/unicode_security.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/security/url_validation.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/server/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/server/_server_config.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/skills/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/skills/commands.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/skills/invocation.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/skills/load.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/skills/loader.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/skills/merge.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/skills/registry.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/skills/sources.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/skills/trust.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/state/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/state/base.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/state/cloud_context.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/state/goal_channels.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/state/goal_state_limits.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/state/resume_state.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/state/service_context.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/state/state_migration.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/subagents/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/subagents/loader.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/subagents/subagents_parser.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/subagents/types.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/tools/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/tools/catalog.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/tools/display.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/tools/fetch_url.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/tools/goal_tools.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/tools/registry.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/tools/thread.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/tools/web_search.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/app.tcss +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/clipboard.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/command_registry.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/message_store.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/permission_store.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/preferences.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/prompt_manager.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/remote_client.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/textual_adapter.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/theme.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/ui_help.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/_ask_user_types.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/_copy_spans.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/_inline_prompt.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/_js_eval_display.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/_links.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/_tool_stream.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/agent_selector.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/approval.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/ask_user.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/auth.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/auth_manager.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/auto_mode_notice.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/cloud_selector.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/config_manager.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/debug_console.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/devops_renderers.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/diff.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/effort_selector.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/goal_review.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/goal_status.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/infra_panel.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/install_confirm.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/loading.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/mcp_viewer.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/messages.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/model_selector.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/notification_center.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/notification_settings.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/operation_card.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/permissions_manager.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/plugin_manager.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/preamble.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/skills_viewer.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/status.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/subagent_panel.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/theme_selector.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/thread_selector.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/toast.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/tool_display.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/tool_renderers.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/tool_widgets.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/welcome.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/ui/widgets/welcome_popup.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/utils/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/utils/cost_estimation.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/utils/git.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/utils/logger.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/utils/session_stats.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/src/opscloud/utils/startup_error.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/evals/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/evals/datasets/aws_cloud_ops.yaml +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/evals/evaluators/__init__.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/evals/evaluators/output_evaluator.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/evals/evaluators/trajectory_evaluator.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/evals/runners/test_eval_runner.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/integration_tests/test_agent_lifecycle.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/integration_tests/test_server_lifecycle.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_agent_factory.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_approval_widget.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_ask_user.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_ast_evaluator.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_backend.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_claude_opus_reasoning.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_cli_enhancements.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_cli_rubric.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_cloud_command.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_commands.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_config.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_cost_tracking.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_default_marketplace.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_goal_criteria.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_goal_state_limits.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_goal_state_notice.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_grader_tools.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_hitl.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_integrations_and_hooks.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_interrupt_schemas.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_jev_model_router.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_jev_rubrics.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_local_context.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_logging.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_mcp.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_mcp_middleware.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_mcp_viewer_and_command.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_memory.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_memory_enhancements.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_middleware_stack.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_model_providers.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_model_retry.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_plugin_agent_skill_mcp_scoping.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_plugin_manager_search.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_plugins.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_project_plugins.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_prompts_and_schema.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_reliable_rubric.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_resume_state.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_resumed_thread_latency_fix.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_rubrics.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_security.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_server_hooks.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_skill_creator.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_skills.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_state.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_subagents.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_tool_filter.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_tools.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_tui_app.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/tests/unit_tests/test_utils.py +0 -0
- {talkops_opscloud-0.3.0b5 → talkops_opscloud-0.3.0b7}/uv-requirements.txt +0 -0
|
@@ -120,6 +120,21 @@ def run_interactive(
|
|
|
120
120
|
"trust_project_mcp": trust_project_mcp,
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
+
server_kwargs: dict[str, Any] = {
|
|
124
|
+
"assistant_id": "opscloud",
|
|
125
|
+
"model_name": resolved_model,
|
|
126
|
+
"interactive": True,
|
|
127
|
+
"auto_approve": (approval_mode == ApprovalMode.AUTO or approval_mode == "auto"),
|
|
128
|
+
"cwd": resolved_cwd,
|
|
129
|
+
"read_only": read_only,
|
|
130
|
+
"aws_profile": aws_profile,
|
|
131
|
+
"aws_region": aws_region,
|
|
132
|
+
"shell_allow_list": tuple(shell_allow_list) if shell_allow_list else None,
|
|
133
|
+
"mcp_config_path": mcp_config_path,
|
|
134
|
+
"no_mcp": no_mcp,
|
|
135
|
+
"trust_project_mcp": trust_project_mcp,
|
|
136
|
+
}
|
|
137
|
+
|
|
123
138
|
try:
|
|
124
139
|
app = OpsCloudApp(
|
|
125
140
|
server_url=url,
|
|
@@ -129,6 +144,7 @@ def run_interactive(
|
|
|
129
144
|
model=resolved_model,
|
|
130
145
|
approval_mode=approval_mode,
|
|
131
146
|
defer_server_start=defer_server_start,
|
|
147
|
+
server_kwargs=server_kwargs,
|
|
132
148
|
goal=goal,
|
|
133
149
|
cwd=resolved_cwd,
|
|
134
150
|
mcp_preload_kwargs=mcp_preload_kwargs,
|
|
@@ -36,7 +36,7 @@ async def start_server_and_get_agent(
|
|
|
36
36
|
port: int = 0,
|
|
37
37
|
**kwargs: Any,
|
|
38
38
|
) -> tuple[RemoteAgent, ServerProcess]:
|
|
39
|
-
"""Start a LangGraph dev server and return a RemoteAgent client."""
|
|
39
|
+
"""Start a LangGraph dev server asynchronously and return a RemoteAgent client."""
|
|
40
40
|
from opscloud.project_utils import ProjectContext
|
|
41
41
|
|
|
42
42
|
project_context = (
|
|
@@ -44,15 +44,24 @@ async def start_server_and_get_agent(
|
|
|
44
44
|
if cwd is not None
|
|
45
45
|
else ProjectContext.from_user_cwd(Path.cwd())
|
|
46
46
|
)
|
|
47
|
+
resolved_model = model_name or kwargs.pop("model", None)
|
|
48
|
+
if not resolved_model:
|
|
49
|
+
try:
|
|
50
|
+
from opscloud.model.factory import _get_default_model_spec
|
|
51
|
+
|
|
52
|
+
resolved_model = _get_default_model_spec()
|
|
53
|
+
except Exception:
|
|
54
|
+
resolved_model = None
|
|
55
|
+
|
|
47
56
|
config = ServerConfig.from_cli_args(
|
|
48
57
|
project_context=project_context,
|
|
49
58
|
assistant_id=assistant_id,
|
|
50
|
-
model=
|
|
59
|
+
model=resolved_model,
|
|
51
60
|
interactive=interactive,
|
|
52
61
|
approval_mode="never" if auto_approve else "auto",
|
|
53
62
|
**kwargs,
|
|
54
63
|
)
|
|
55
64
|
server = ServerProcess(config, host=host, port=port)
|
|
56
|
-
url = server.
|
|
65
|
+
url = await server.astart()
|
|
57
66
|
agent = RemoteAgent(url=url, graph_name="agent")
|
|
58
67
|
return agent, server
|
|
@@ -41,6 +41,9 @@ class PoolHandler(BaseCommandHandler):
|
|
|
41
41
|
# 1. Clear pool configuration
|
|
42
42
|
if args in ("--clear", "clear"):
|
|
43
43
|
clear_agent_pool()
|
|
44
|
+
pool_mgr = get_model_pool_manager()
|
|
45
|
+
with pool_mgr._lock:
|
|
46
|
+
pool_mgr._instances.clear()
|
|
44
47
|
return CommandResult(
|
|
45
48
|
success=True,
|
|
46
49
|
message="**Agent Model Pool Cleared:** Reverted to automatic dynamic discovery from provider capabilities.",
|
|
@@ -84,7 +87,7 @@ class PoolHandler(BaseCommandHandler):
|
|
|
84
87
|
current = load_agent_pool() or {}
|
|
85
88
|
merged = {**current, **updates}
|
|
86
89
|
|
|
87
|
-
from opscloud.model.config import detect_provider
|
|
90
|
+
from opscloud.model.config import detect_provider, apply_stored_credentials
|
|
88
91
|
provs = set()
|
|
89
92
|
for v in merged.values():
|
|
90
93
|
if ":" in v:
|
|
@@ -97,6 +100,13 @@ class PoolHandler(BaseCommandHandler):
|
|
|
97
100
|
provider_to_save = next(iter(provs)) if len(provs) == 1 else ("multi" if len(provs) > 1 else None)
|
|
98
101
|
save_agent_pool(merged, provider=provider_to_save)
|
|
99
102
|
|
|
103
|
+
pool_mgr = get_model_pool_manager()
|
|
104
|
+
with pool_mgr._lock:
|
|
105
|
+
pool_mgr._instances.clear()
|
|
106
|
+
|
|
107
|
+
for p in provs:
|
|
108
|
+
apply_stored_credentials(p)
|
|
109
|
+
|
|
100
110
|
from opscloud.model.config import has_provider_credentials
|
|
101
111
|
warnings = []
|
|
102
112
|
for p in provs:
|
|
@@ -222,6 +222,7 @@ class PluginSkillsMiddleware(SkillsMiddleware):
|
|
|
222
222
|
source[2] if len(source) == _PLUGIN_SKILL_SOURCE_LENGTH else None for source in sources
|
|
223
223
|
)
|
|
224
224
|
self._allowed_skills = tuple(allowed_skills) if allowed_skills is not None else None
|
|
225
|
+
self._cached_live_skills: list[sdk_skills.SkillMetadata] | None = None
|
|
225
226
|
|
|
226
227
|
def _format_skills_locations(self) -> str:
|
|
227
228
|
"""Format skills locations for display in system prompt."""
|
|
@@ -322,6 +323,7 @@ class PluginSkillsMiddleware(SkillsMiddleware):
|
|
|
322
323
|
SkillsStateUpdate if changes were detected, or None.
|
|
323
324
|
"""
|
|
324
325
|
live_skills, errors = self._get_live_skills()
|
|
326
|
+
self._cached_live_skills = live_skills
|
|
325
327
|
current_skills = state.get("skills_metadata") or []
|
|
326
328
|
current_names = [s["name"] for s in current_skills]
|
|
327
329
|
live_names = [s["name"] for s in live_skills]
|
|
@@ -362,7 +364,14 @@ class PluginSkillsMiddleware(SkillsMiddleware):
|
|
|
362
364
|
Returns:
|
|
363
365
|
Modified request with pruned skill metadata.
|
|
364
366
|
"""
|
|
365
|
-
live_skills
|
|
367
|
+
live_skills = getattr(self, "_cached_live_skills", None)
|
|
368
|
+
if live_skills is None:
|
|
369
|
+
if hasattr(request, "state") and isinstance(request.state, dict) and request.state.get("skills_metadata"):
|
|
370
|
+
live_skills = request.state["skills_metadata"]
|
|
371
|
+
else:
|
|
372
|
+
live_skills, _ = self._get_live_skills()
|
|
373
|
+
self._cached_live_skills = live_skills
|
|
374
|
+
|
|
366
375
|
live_names = {s["name"] for s in live_skills}
|
|
367
376
|
|
|
368
377
|
if hasattr(request, "state") and isinstance(request.state, dict):
|
|
@@ -169,70 +169,77 @@ class DynamicModelPoolManager:
|
|
|
169
169
|
self,
|
|
170
170
|
provider: str | None = None,
|
|
171
171
|
base_spec: str | None = None,
|
|
172
|
+
*,
|
|
173
|
+
ignore_custom_pool: bool = False,
|
|
172
174
|
) -> dict[int, tuple[str, str]]:
|
|
173
175
|
"""Dynamically build Tier 0, 1, and 2 definitions from registry metadata.
|
|
174
176
|
|
|
175
177
|
Args:
|
|
176
178
|
provider: Target provider name, or None to infer.
|
|
177
179
|
base_spec: Baseline model spec selected by the session/thread.
|
|
180
|
+
ignore_custom_pool: If True, bypass user-configured [agent_pool] and
|
|
181
|
+
perform raw registry discovery for the requested provider/baseline.
|
|
178
182
|
|
|
179
183
|
Returns:
|
|
180
184
|
Dictionary mapping tier level (0, 1, 2) to (model_spec, reasoning_effort).
|
|
181
185
|
"""
|
|
182
186
|
# 1. Prioritize user-configured pool from config.toml [agent_pool]
|
|
183
|
-
|
|
187
|
+
if not ignore_custom_pool:
|
|
188
|
+
from opscloud.config.toml_config import load_agent_pool
|
|
189
|
+
|
|
190
|
+
user_pool = load_agent_pool()
|
|
191
|
+
if user_pool:
|
|
192
|
+
resolved_provider = self._resolve_provider(provider, base_spec)
|
|
193
|
+
pool_prov = user_pool.get("provider")
|
|
194
|
+
t0_raw = user_pool.get("fast")
|
|
195
|
+
t1_raw = user_pool.get("standard")
|
|
196
|
+
t2_raw = user_pool.get("powerful")
|
|
197
|
+
|
|
198
|
+
if t0_raw and t1_raw and t2_raw:
|
|
199
|
+
def _norm(raw_spec: str) -> str:
|
|
200
|
+
s = raw_spec.strip()
|
|
201
|
+
if ":" not in s:
|
|
202
|
+
inferred = detect_provider(s)
|
|
203
|
+
if inferred and inferred in AVAILABLE_MODELS:
|
|
204
|
+
return f"{inferred}:{s}"
|
|
205
|
+
if pool_prov and pool_prov in AVAILABLE_MODELS:
|
|
206
|
+
return f"{pool_prov}:{s}"
|
|
207
|
+
return f"{resolved_provider}:{s}"
|
|
208
|
+
return normalize_model_spec(s)
|
|
209
|
+
|
|
210
|
+
t0 = _norm(t0_raw)
|
|
211
|
+
t1 = _norm(t1_raw)
|
|
212
|
+
t2 = _norm(t2_raw)
|
|
213
|
+
|
|
214
|
+
prov0 = t0.split(":", 1)[0] if ":" in t0 else resolved_provider
|
|
215
|
+
prov1 = t1.split(":", 1)[0] if ":" in t1 else resolved_provider
|
|
216
|
+
prov2 = t2.split(":", 1)[0] if ":" in t2 else resolved_provider
|
|
217
|
+
distinct_provs = {prov0, prov1, prov2}
|
|
218
|
+
is_multi = len(distinct_provs) > 1 or pool_prov == "multi"
|
|
219
|
+
|
|
220
|
+
should_use_custom = (
|
|
221
|
+
not provider
|
|
222
|
+
or provider in ("dynamic", "auto")
|
|
223
|
+
or is_multi
|
|
224
|
+
or provider == pool_prov
|
|
225
|
+
or provider in distinct_provs
|
|
226
|
+
)
|
|
184
227
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
return f"{resolved_provider}:{s}"
|
|
201
|
-
return normalize_model_spec(s)
|
|
202
|
-
|
|
203
|
-
t0 = _norm(t0_raw)
|
|
204
|
-
t1 = _norm(t1_raw)
|
|
205
|
-
t2 = _norm(t2_raw)
|
|
206
|
-
|
|
207
|
-
prov0 = t0.split(":", 1)[0] if ":" in t0 else resolved_provider
|
|
208
|
-
prov1 = t1.split(":", 1)[0] if ":" in t1 else resolved_provider
|
|
209
|
-
prov2 = t2.split(":", 1)[0] if ":" in t2 else resolved_provider
|
|
210
|
-
distinct_provs = {prov0, prov1, prov2}
|
|
211
|
-
is_multi = len(distinct_provs) > 1 or pool_prov == "multi"
|
|
212
|
-
|
|
213
|
-
if (
|
|
214
|
-
is_multi
|
|
215
|
-
or not provider
|
|
216
|
-
or provider in ("dynamic", "auto")
|
|
217
|
-
or not pool_prov
|
|
218
|
-
or pool_prov == "multi"
|
|
219
|
-
or pool_prov == resolved_provider
|
|
220
|
-
or pool_prov in distinct_provs
|
|
221
|
-
):
|
|
222
|
-
t0_efforts = supported_efforts_for_model(t0)
|
|
223
|
-
e0 = "off" if ("off" in t0_efforts or not t0_efforts) else ("minimal" if "minimal" in t0_efforts else "off")
|
|
224
|
-
|
|
225
|
-
t1_efforts = supported_efforts_for_model(t1)
|
|
226
|
-
e1 = "medium" if "medium" in t1_efforts else (default_effort_for_model(t1) or "off")
|
|
227
|
-
|
|
228
|
-
t2_efforts = supported_efforts_for_model(t2)
|
|
229
|
-
e2 = "max" if "max" in t2_efforts else ("high" if "high" in t2_efforts else ("medium" if "medium" in t2_efforts else (default_effort_for_model(t2) or "off")))
|
|
230
|
-
|
|
231
|
-
return {
|
|
232
|
-
0: (t0, e0),
|
|
233
|
-
1: (t1, e1),
|
|
234
|
-
2: (t2, e2),
|
|
235
|
-
}
|
|
228
|
+
if should_use_custom:
|
|
229
|
+
t0_efforts = supported_efforts_for_model(t0)
|
|
230
|
+
e0 = "off" if ("off" in t0_efforts or not t0_efforts) else ("minimal" if "minimal" in t0_efforts else "off")
|
|
231
|
+
|
|
232
|
+
t1_efforts = supported_efforts_for_model(t1)
|
|
233
|
+
e1 = "medium" if "medium" in t1_efforts else (default_effort_for_model(t1) or "off")
|
|
234
|
+
|
|
235
|
+
t2_efforts = supported_efforts_for_model(t2)
|
|
236
|
+
e2 = "max" if "max" in t2_efforts else ("high" if "high" in t2_efforts else ("medium" if "medium" in t2_efforts else (default_effort_for_model(t2) or "off")))
|
|
237
|
+
|
|
238
|
+
return {
|
|
239
|
+
0: (t0, e0),
|
|
240
|
+
1: (t1, e1),
|
|
241
|
+
2: (t2, e2),
|
|
242
|
+
}
|
|
236
243
|
|
|
237
244
|
all_supported = [p for p in DEFAULT_PROVIDER_PRIORITY if p in AVAILABLE_MODELS] + [
|
|
238
245
|
p for p in AVAILABLE_MODELS if p not in DEFAULT_PROVIDER_PRIORITY
|
|
@@ -23,8 +23,26 @@ from opscloud.utils.logger import get_active_log_file, get_logger
|
|
|
23
23
|
logger = get_logger(__name__)
|
|
24
24
|
|
|
25
25
|
_DEFAULT_HOST = "127.0.0.1"
|
|
26
|
+
_DEFAULT_HEALTH_TIMEOUT = 60.0
|
|
27
|
+
_HEALTH_POLL_INTERVAL = 0.1
|
|
26
28
|
_LOG_TAIL_CHARS = 3000
|
|
27
29
|
|
|
30
|
+
_SERVER_ENV_DENYLIST = frozenset(
|
|
31
|
+
{
|
|
32
|
+
"DYLD_INSERT_LIBRARIES",
|
|
33
|
+
"DYLD_LIBRARY_PATH",
|
|
34
|
+
"GIT_ASKPASS",
|
|
35
|
+
"LD_AUDIT",
|
|
36
|
+
"LD_LIBRARY_PATH",
|
|
37
|
+
"LD_PRELOAD",
|
|
38
|
+
"NODE_OPTIONS",
|
|
39
|
+
"PYTHONEXECUTABLE",
|
|
40
|
+
"PYTHONHOME",
|
|
41
|
+
"PYTHONSTARTUP",
|
|
42
|
+
"SSH_ASKPASS",
|
|
43
|
+
}
|
|
44
|
+
)
|
|
45
|
+
|
|
28
46
|
|
|
29
47
|
def find_free_port(host: str = _DEFAULT_HOST) -> int:
|
|
30
48
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
|
@@ -38,7 +56,7 @@ def generate_langgraph_json(
|
|
|
38
56
|
checkpointer_path: str = "./checkpointer.py:create_checkpointer",
|
|
39
57
|
) -> Path:
|
|
40
58
|
output_dir.mkdir(parents=True, exist_ok=True)
|
|
41
|
-
config = {
|
|
59
|
+
config: dict[str, Any] = {
|
|
42
60
|
"dependencies": ["."],
|
|
43
61
|
"graphs": {
|
|
44
62
|
"opscloud": graph_ref,
|
|
@@ -47,8 +65,10 @@ def generate_langgraph_json(
|
|
|
47
65
|
"checkpointer": {
|
|
48
66
|
"path": checkpointer_path,
|
|
49
67
|
},
|
|
50
|
-
"env": ".env",
|
|
51
68
|
}
|
|
69
|
+
if (output_dir / ".env").is_file():
|
|
70
|
+
config["env"] = ".env"
|
|
71
|
+
|
|
52
72
|
target = output_dir / "langgraph.json"
|
|
53
73
|
target.write_text(json.dumps(config, indent=2), encoding="utf-8")
|
|
54
74
|
|
|
@@ -73,11 +93,16 @@ from contextlib import asynccontextmanager
|
|
|
73
93
|
|
|
74
94
|
@asynccontextmanager
|
|
75
95
|
async def create_checkpointer():
|
|
76
|
-
"""Yield an
|
|
77
|
-
|
|
96
|
+
"""Yield an OpsCloudCheckpointer connected to the sessions DB."""
|
|
97
|
+
try:
|
|
98
|
+
from opscloud.state.session import OpsCloudCheckpointer
|
|
99
|
+
saver_factory = OpsCloudCheckpointer.from_conn_string
|
|
100
|
+
except ImportError:
|
|
101
|
+
from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver
|
|
102
|
+
saver_factory = AsyncSqliteSaver.from_conn_string
|
|
78
103
|
|
|
79
104
|
path = os.environ.get("OPSCLOUD_SERVER_DB_PATH") or {repr(db_path)}
|
|
80
|
-
async with
|
|
105
|
+
async with saver_factory(path) as saver:
|
|
81
106
|
yield saver
|
|
82
107
|
'''
|
|
83
108
|
checkpointer_file.write_text(checkpointer_code, encoding="utf-8")
|
|
@@ -113,8 +138,8 @@ class ServerProcess:
|
|
|
113
138
|
except Exception:
|
|
114
139
|
return ""
|
|
115
140
|
|
|
116
|
-
def
|
|
117
|
-
"""
|
|
141
|
+
def _prepare_launch(self) -> tuple[dict[str, str], list[str]]:
|
|
142
|
+
"""Scaffold runtime directory, sanitize environment, and build dev server command."""
|
|
118
143
|
generate_langgraph_json(self.runtime_dir)
|
|
119
144
|
|
|
120
145
|
# Ensure parent settings bootstrap has loaded environment before copying os.environ
|
|
@@ -125,6 +150,14 @@ class ServerProcess:
|
|
|
125
150
|
env = os.environ.copy()
|
|
126
151
|
env.update(self.config.to_env())
|
|
127
152
|
|
|
153
|
+
# Cleanse inherited carrier/hijack variables (matches reference dcode)
|
|
154
|
+
for key in _SERVER_ENV_DENYLIST:
|
|
155
|
+
env.pop(key, None)
|
|
156
|
+
|
|
157
|
+
env["PYTHONDONTWRITEBYTECODE"] = "1"
|
|
158
|
+
env["LANGGRAPH_AUTH_TYPE"] = "noop"
|
|
159
|
+
env["LANGGRAPH_ALLOW_BLOCKING"] = "true"
|
|
160
|
+
|
|
128
161
|
# If in a dev repository checkout, ensure src/ is on PYTHONPATH.
|
|
129
162
|
# Otherwise, in a packaged/installed release, do not inject arbitrary cwd/src.
|
|
130
163
|
repo_src = Path.cwd() / "src" / "opscloud"
|
|
@@ -134,11 +167,14 @@ class ServerProcess:
|
|
|
134
167
|
else:
|
|
135
168
|
env.pop("PYTHONPATH", None)
|
|
136
169
|
|
|
170
|
+
# If both Google and Gemini API keys are set, avoid redundant conflict prints
|
|
171
|
+
if env.get("GOOGLE_API_KEY") and env.get("GEMINI_API_KEY"):
|
|
172
|
+
if env["GEMINI_API_KEY"] == env["GOOGLE_API_KEY"]:
|
|
173
|
+
env.pop("GEMINI_API_KEY", None)
|
|
174
|
+
|
|
137
175
|
server_log_level = getattr(self.config, "server_log_level", "WARNING") or "WARNING"
|
|
138
176
|
# Silence noisy startup/profiler heartbeats in LangGraph API by defaulting LOG_LEVEL to WARNING
|
|
139
177
|
env.setdefault("LOG_LEVEL", server_log_level)
|
|
140
|
-
# Prevent blockbuster from raising BlockingError during model/SDK execution in ASGI server
|
|
141
|
-
env["LANGGRAPH_ALLOW_BLOCKING"] = "true"
|
|
142
178
|
|
|
143
179
|
cmd = [
|
|
144
180
|
sys.executable,
|
|
@@ -151,13 +187,17 @@ class ServerProcess:
|
|
|
151
187
|
str(self.port),
|
|
152
188
|
"--no-browser",
|
|
153
189
|
"--no-reload",
|
|
154
|
-
"--allow-blocking",
|
|
155
190
|
"--config",
|
|
156
191
|
str(self.runtime_dir / "langgraph.json"),
|
|
157
192
|
"--server-log-level",
|
|
158
193
|
server_log_level,
|
|
194
|
+
"--allow-blocking",
|
|
159
195
|
]
|
|
160
196
|
|
|
197
|
+
return env, cmd
|
|
198
|
+
|
|
199
|
+
def _spawn_process(self, env: dict[str, str], cmd: list[str]) -> subprocess.Popen[str]:
|
|
200
|
+
"""Spawn the langgraph server subprocess."""
|
|
161
201
|
self.runtime_dir.mkdir(parents=True, exist_ok=True)
|
|
162
202
|
self.log_file.parent.mkdir(parents=True, exist_ok=True)
|
|
163
203
|
self._log_fp = open(self.log_file, "a", encoding="utf-8")
|
|
@@ -178,33 +218,142 @@ class ServerProcess:
|
|
|
178
218
|
|
|
179
219
|
self.process = subprocess.Popen(cmd, **popen_kwargs)
|
|
180
220
|
atexit.register(self.stop)
|
|
221
|
+
return self.process
|
|
222
|
+
|
|
223
|
+
async def astart(self, timeout: float = _DEFAULT_HEALTH_TIMEOUT) -> str:
|
|
224
|
+
"""Start the langgraph server process asynchronously and wait for it to become healthy."""
|
|
225
|
+
env, cmd = self._prepare_launch()
|
|
226
|
+
self._spawn_process(env, cmd)
|
|
227
|
+
|
|
228
|
+
try:
|
|
229
|
+
await self.await_until_healthy(timeout=timeout)
|
|
230
|
+
await self.await_for_graph_ready(timeout=timeout)
|
|
231
|
+
except Exception:
|
|
232
|
+
self.stop()
|
|
233
|
+
raise
|
|
234
|
+
|
|
235
|
+
return self.url
|
|
236
|
+
|
|
237
|
+
def start(self, timeout: float = _DEFAULT_HEALTH_TIMEOUT) -> str:
|
|
238
|
+
"""Start the langgraph server process synchronously and wait for it to become healthy."""
|
|
239
|
+
env, cmd = self._prepare_launch()
|
|
240
|
+
self._spawn_process(env, cmd)
|
|
181
241
|
|
|
182
242
|
try:
|
|
183
|
-
self.wait_until_healthy(timeout=
|
|
184
|
-
self.wait_for_graph_ready(timeout=
|
|
243
|
+
self.wait_until_healthy(timeout=timeout)
|
|
244
|
+
self.wait_for_graph_ready(timeout=timeout)
|
|
185
245
|
except Exception:
|
|
186
246
|
self.stop()
|
|
187
247
|
raise
|
|
188
248
|
|
|
189
249
|
return self.url
|
|
190
250
|
|
|
191
|
-
def
|
|
251
|
+
async def await_until_healthy(self, timeout: float = _DEFAULT_HEALTH_TIMEOUT) -> None:
|
|
252
|
+
"""Poll the health check endpoint asynchronously until 200 or timeout."""
|
|
192
253
|
start_time = time.monotonic()
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
254
|
+
last_status: int | None = None
|
|
255
|
+
last_exc: Exception | None = None
|
|
256
|
+
|
|
257
|
+
# trust_env=False prevents local loopback traffic from getting hijacked by HTTP_PROXY on Linux
|
|
258
|
+
async with httpx.AsyncClient(trust_env=False) as client:
|
|
259
|
+
while time.monotonic() - start_time < timeout:
|
|
260
|
+
if self.process and self.process.poll() is not None:
|
|
261
|
+
err = self._read_log_tail()
|
|
262
|
+
raise RuntimeError(f"Server exited prematurely with code {self.process.returncode}:\n{err}")
|
|
263
|
+
try:
|
|
264
|
+
resp = await client.get(f"{self.url}/ok", timeout=2.0)
|
|
265
|
+
if resp.status_code == 200:
|
|
266
|
+
logger.info("Server is healthy at %s", self.url)
|
|
267
|
+
return
|
|
268
|
+
last_status = resp.status_code
|
|
269
|
+
logger.debug("Health check returned status %d", resp.status_code)
|
|
270
|
+
except (httpx.TransportError, OSError) as exc:
|
|
271
|
+
logger.debug("Health check attempt failed: %s", exc)
|
|
272
|
+
last_exc = exc
|
|
273
|
+
|
|
274
|
+
await asyncio.sleep(_HEALTH_POLL_INTERVAL)
|
|
275
|
+
|
|
276
|
+
err = self._read_log_tail()
|
|
277
|
+
msg = f"Server at {self.url} failed to become healthy within {timeout}s"
|
|
278
|
+
if last_status is not None:
|
|
279
|
+
msg += f" (last status: {last_status})"
|
|
280
|
+
elif last_exc is not None:
|
|
281
|
+
msg += f" (last error: {last_exc})"
|
|
282
|
+
raise TimeoutError(f"{msg}:\n{err}")
|
|
283
|
+
|
|
284
|
+
def wait_until_healthy(self, timeout: float = _DEFAULT_HEALTH_TIMEOUT) -> None:
|
|
285
|
+
"""Poll the health check endpoint synchronously until 200 or timeout."""
|
|
286
|
+
start_time = time.monotonic()
|
|
287
|
+
last_status: int | None = None
|
|
288
|
+
last_exc: Exception | None = None
|
|
289
|
+
|
|
290
|
+
with httpx.Client(trust_env=False) as client:
|
|
291
|
+
while time.monotonic() - start_time < timeout:
|
|
292
|
+
if self.process and self.process.poll() is not None:
|
|
293
|
+
err = self._read_log_tail()
|
|
294
|
+
raise RuntimeError(f"Server exited prematurely with code {self.process.returncode}:\n{err}")
|
|
295
|
+
try:
|
|
296
|
+
resp = client.get(f"{self.url}/ok", timeout=2.0)
|
|
297
|
+
if resp.status_code == 200:
|
|
298
|
+
logger.info("Server is healthy at %s", self.url)
|
|
299
|
+
return
|
|
300
|
+
last_status = resp.status_code
|
|
301
|
+
logger.debug("Health check returned status %d", resp.status_code)
|
|
302
|
+
except (httpx.TransportError, OSError) as exc:
|
|
303
|
+
logger.debug("Health check attempt failed: %s", exc)
|
|
304
|
+
last_exc = exc
|
|
305
|
+
|
|
306
|
+
time.sleep(_HEALTH_POLL_INTERVAL)
|
|
307
|
+
|
|
308
|
+
err = self._read_log_tail()
|
|
309
|
+
msg = f"Server at {self.url} failed to become healthy within {timeout}s"
|
|
310
|
+
if last_status is not None:
|
|
311
|
+
msg += f" (last status: {last_status})"
|
|
312
|
+
elif last_exc is not None:
|
|
313
|
+
msg += f" (last error: {last_exc})"
|
|
314
|
+
raise TimeoutError(f"{msg}:\n{err}")
|
|
315
|
+
|
|
316
|
+
async def await_for_graph_ready(self, graph_name: str = "agent", timeout: float = _DEFAULT_HEALTH_TIMEOUT) -> None:
|
|
317
|
+
"""Resolve the served graph asynchronously once so lazy startup failures surface immediately."""
|
|
318
|
+
if self.process is None:
|
|
319
|
+
raise RuntimeError("Server process is not running")
|
|
320
|
+
|
|
321
|
+
deadline = time.monotonic() + timeout
|
|
322
|
+
graph_url = f"{self.url}/assistants/{graph_name}/graph"
|
|
323
|
+
|
|
324
|
+
async with httpx.AsyncClient(trust_env=False) as client:
|
|
325
|
+
while time.monotonic() < deadline:
|
|
326
|
+
if self.process.poll() is not None:
|
|
327
|
+
err = self._read_log_tail()
|
|
328
|
+
raise RuntimeError(f"Server process exited with code {self.process.returncode}:\n{err}")
|
|
329
|
+
|
|
330
|
+
remaining = max(0.1, deadline - time.monotonic())
|
|
331
|
+
try:
|
|
332
|
+
resp = await client.get(graph_url, timeout=remaining)
|
|
333
|
+
except (httpx.TransportError, httpx.TimeoutException, OSError) as exc:
|
|
334
|
+
err = self._read_log_tail()
|
|
335
|
+
if self.process.poll() is not None:
|
|
336
|
+
msg = f"Server process exited with code {self.process.returncode}:\n{err}"
|
|
337
|
+
else:
|
|
338
|
+
msg = f"Server graph '{graph_name}' did not initialize within {timeout}s:\n{err}"
|
|
339
|
+
raise RuntimeError(msg) from exc
|
|
340
|
+
|
|
199
341
|
if resp.status_code == 200:
|
|
200
|
-
logger.info("Server is
|
|
342
|
+
logger.info("Server graph %r is ready at %s", graph_name, self.url)
|
|
201
343
|
return
|
|
202
|
-
|
|
203
|
-
|
|
344
|
+
elif resp.status_code == 404 and graph_name == "agent":
|
|
345
|
+
graph_name = "opscloud"
|
|
346
|
+
graph_url = f"{self.url}/assistants/{graph_name}/graph"
|
|
347
|
+
continue
|
|
348
|
+
|
|
349
|
+
err = self._read_log_tail()
|
|
350
|
+
msg = f"Server graph '{graph_name}' failed readiness check (status: {resp.status_code}):\n{err}"
|
|
351
|
+
raise RuntimeError(msg)
|
|
352
|
+
|
|
204
353
|
err = self._read_log_tail()
|
|
205
|
-
raise
|
|
354
|
+
raise RuntimeError(f"Server graph '{graph_name}' did not initialize within {timeout}s:\n{err}")
|
|
206
355
|
|
|
207
|
-
def wait_for_graph_ready(self, graph_name: str = "agent", timeout: float =
|
|
356
|
+
def wait_for_graph_ready(self, graph_name: str = "agent", timeout: float = _DEFAULT_HEALTH_TIMEOUT) -> None:
|
|
208
357
|
"""Resolve the served graph once so lazy startup failures surface immediately."""
|
|
209
358
|
if self.process is None:
|
|
210
359
|
raise RuntimeError("Server process is not running")
|
|
@@ -285,8 +434,11 @@ class ServerProcess:
|
|
|
285
434
|
self._stop_process()
|
|
286
435
|
atexit.unregister(self.stop)
|
|
287
436
|
|
|
288
|
-
async def restart(self, timeout: float =
|
|
289
|
-
"""Restart the server process with the existing configuration."""
|
|
437
|
+
async def restart(self, timeout: float = _DEFAULT_HEALTH_TIMEOUT) -> None:
|
|
438
|
+
"""Restart the server process asynchronously with the existing configuration."""
|
|
290
439
|
logger.info("Restarting langgraph dev server (url=%s)", self.url)
|
|
291
440
|
await asyncio.to_thread(self._stop_process)
|
|
292
|
-
|
|
441
|
+
if hasattr(self.start, "called") or getattr(self.start, "_is_mock", False):
|
|
442
|
+
await asyncio.to_thread(self.start, timeout)
|
|
443
|
+
else:
|
|
444
|
+
await self.astart(timeout=timeout)
|