talkops-opscloud 0.3.0b8__tar.gz → 0.3.0b9__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.
Files changed (400) hide show
  1. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/PKG-INFO +1 -1
  2. talkops_opscloud-0.3.0b9/docs/issues/MCP_PERFORMANCE_AND_CONTEXT_EXPLOSION_AUDIT.md +275 -0
  3. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/pyproject.toml +1 -1
  4. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/mcp/discovery.py +14 -4
  5. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/mcp/preload.py +51 -30
  6. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/mcp/session_manager.py +49 -28
  7. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/tool_filter.py +35 -1
  8. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/plugins/adapters/mcp.py +1 -1
  9. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/plugins/models.py +10 -0
  10. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_mcp.py +17 -0
  11. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_tool_filter.py +72 -0
  12. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/uv.lock +1 -1
  13. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/.dockerignore +0 -0
  14. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/.env.example +0 -0
  15. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/.github/workflows/ci.yml +0 -0
  16. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/.github/workflows/release-pypi.yml +0 -0
  17. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/.gitignore +0 -0
  18. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/.python-version +0 -0
  19. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/LICENSE +0 -0
  20. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/README.md +0 -0
  21. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/assets/opscloud-banner.gif +0 -0
  22. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/docs/opscloud-docs/Configuration.md +0 -0
  23. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/docs/opscloud-docs/approval-mode.md +0 -0
  24. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/docs/opscloud-docs/cli-reference.md +0 -0
  25. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/docs/opscloud-docs/config.toml.md +0 -0
  26. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/docs/opscloud-docs/credentials.md +0 -0
  27. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/docs/opscloud-docs/goal-and-rubrics.md +0 -0
  28. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/docs/opscloud-docs/hooks.md +0 -0
  29. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/docs/opscloud-docs/mcp-tools.md +0 -0
  30. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/docs/opscloud-docs/memory-and-skills.md +0 -0
  31. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/docs/opscloud-docs/model-providers.md +0 -0
  32. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/docs/opscloud-docs/overview.md +0 -0
  33. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/docs/opscloud-docs/plugins.md +0 -0
  34. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/docs/opscloud-docs/quickstart.md +0 -0
  35. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/docs/opscloud-docs/remote-sandboxes.md +0 -0
  36. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/docs/opscloud-docs/subagents.md +0 -0
  37. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/scripts/install.sh +0 -0
  38. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/__init__.py +0 -0
  39. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/__main__.py +0 -0
  40. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/_constants.py +0 -0
  41. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/_debug.py +0 -0
  42. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/_debug_buffer.py +0 -0
  43. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/_textual_patches.py +0 -0
  44. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/_version.py +0 -0
  45. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/agent/__init__.py +0 -0
  46. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/agent/config.py +0 -0
  47. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/agent/factory.py +0 -0
  48. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/approval_mode.py +0 -0
  49. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/backend/__init__.py +0 -0
  50. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/backend/composite.py +0 -0
  51. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/backend/local.py +0 -0
  52. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/backend/registry.py +0 -0
  53. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/backend/sandbox_config.py +0 -0
  54. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/backend/sandbox_factory.py +0 -0
  55. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/built_in_skills/remember/SKILL.md +0 -0
  56. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/built_in_skills/skill-creator/SKILL.md +0 -0
  57. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/built_in_skills/skill-creator/scripts/init_skill.py +0 -0
  58. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/built_in_skills/skill-creator/scripts/quick_validate.py +0 -0
  59. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/cli/__init__.py +0 -0
  60. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/cli/commands/__init__.py +0 -0
  61. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/cli/commands/auth.py +0 -0
  62. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/cli/commands/doctor.py +0 -0
  63. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/cli/commands/mcp.py +0 -0
  64. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/cli/commands/threads.py +0 -0
  65. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/cli/interactive.py +0 -0
  66. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/cli/main.py +0 -0
  67. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/cli/non_interactive.py +0 -0
  68. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/cli/server_manager.py +0 -0
  69. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/__init__.py +0 -0
  70. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/_base.py +0 -0
  71. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/_guards.py +0 -0
  72. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/_router.py +0 -0
  73. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/_types.py +0 -0
  74. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/__init__.py +0 -0
  75. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/auth.py +0 -0
  76. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/bug.py +0 -0
  77. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/clear.py +0 -0
  78. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/cloud.py +0 -0
  79. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/compact.py +0 -0
  80. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/config_cmd.py +0 -0
  81. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/context.py +0 -0
  82. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/cost.py +0 -0
  83. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/doctor.py +0 -0
  84. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/effort.py +0 -0
  85. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/exit_cmd.py +0 -0
  86. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/fast.py +0 -0
  87. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/help_cmd.py +0 -0
  88. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/mcp.py +0 -0
  89. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/model.py +0 -0
  90. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/permissions.py +0 -0
  91. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/plugins.py +0 -0
  92. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/pool.py +0 -0
  93. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/resume.py +0 -0
  94. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/skills.py +0 -0
  95. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/power/__init__.py +0 -0
  96. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/power/agents.py +0 -0
  97. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/power/btw.py +0 -0
  98. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/power/copy.py +0 -0
  99. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/power/goal.py +0 -0
  100. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/power/loop.py +0 -0
  101. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/power/memory.py +0 -0
  102. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/power/review.py +0 -0
  103. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/power/rubric.py +0 -0
  104. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/power/runtime.py +0 -0
  105. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/power/skill_creator.py +0 -0
  106. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/power/skill_invoke.py +0 -0
  107. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/power/tasks.py +0 -0
  108. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/power/trace.py +0 -0
  109. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/power/ui_toggles.py +0 -0
  110. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/power/version.py +0 -0
  111. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/registry.py +0 -0
  112. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/config/__init__.py +0 -0
  113. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/config/adapters/__init__.py +0 -0
  114. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/config/adapters/postgres.py +0 -0
  115. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/config/adapters/sqlite.py +0 -0
  116. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/config/aws.py +0 -0
  117. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/config/cloud_profiles.py +0 -0
  118. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/config/env_vars.py +0 -0
  119. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/config/langsmith.py +0 -0
  120. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/config/manifest.py +0 -0
  121. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/config/metadata.py +0 -0
  122. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/config/paths.py +0 -0
  123. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/config/plugins.py +0 -0
  124. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/config/settings.py +0 -0
  125. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/config/store.py +0 -0
  126. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/config/store_factory.py +0 -0
  127. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/config/toml_config.py +0 -0
  128. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/editor.py +0 -0
  129. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/exceptions.py +0 -0
  130. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/file_ops.py +0 -0
  131. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/hooks/__init__.py +0 -0
  132. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/hooks/env.py +0 -0
  133. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/hooks/interrupt.py +0 -0
  134. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/hooks/models/__init__.py +0 -0
  135. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/hooks/models/adapters.py +0 -0
  136. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/hooks/models/config.py +0 -0
  137. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/hooks/models/domain.py +0 -0
  138. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/hooks/models/transport.py +0 -0
  139. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/hooks/tools.py +0 -0
  140. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/input.py +0 -0
  141. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/integrations/__init__.py +0 -0
  142. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/integrations/base.py +0 -0
  143. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/integrations/content_filter.py +0 -0
  144. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/integrations/event_bus.py +0 -0
  145. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/integrations/hooks.py +0 -0
  146. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/integrations/identity.py +0 -0
  147. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/integrations/notifications.py +0 -0
  148. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/integrations/stream_bridge.py +0 -0
  149. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/integrations/thread_store.py +0 -0
  150. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/json_types.py +0 -0
  151. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/mcp/__init__.py +0 -0
  152. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/mcp/config.py +0 -0
  153. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/mcp/mcp_info.py +0 -0
  154. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/mcp/middleware.py +0 -0
  155. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/mcp/raw_config.py +0 -0
  156. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/mcp/semantic_profiler.py +0 -0
  157. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/mcp/trust.py +0 -0
  158. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/memory/__init__.py +0 -0
  159. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/memory/branch.py +0 -0
  160. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/memory/guard.py +0 -0
  161. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/memory/onboarding.py +0 -0
  162. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/memory/registry.py +0 -0
  163. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/memory/store.py +0 -0
  164. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/__init__.py +0 -0
  165. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/_repository_bounds.py +0 -0
  166. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/ask_user.py +0 -0
  167. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/auto_mode.py +0 -0
  168. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/auto_mode_hitl.py +0 -0
  169. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/compaction.py +0 -0
  170. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/configurable_model.py +0 -0
  171. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/cost_tracking.py +0 -0
  172. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/glm_stall_recovery.py +0 -0
  173. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/goal_criteria.py +0 -0
  174. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/goal_state_notice.py +0 -0
  175. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/goal_tools.py +0 -0
  176. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/headless_mcp_guard.py +0 -0
  177. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/jev_model_router.py +0 -0
  178. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/local_context.py +0 -0
  179. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/mcp_context.py +0 -0
  180. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/mcp_middleware.py +0 -0
  181. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/memory_guard.py +0 -0
  182. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/model_retry.py +0 -0
  183. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/registry.py +0 -0
  184. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/reliable_rubric.py +0 -0
  185. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/resume_state.py +0 -0
  186. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/server_hooks.py +0 -0
  187. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/shell_allow_list.py +0 -0
  188. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/skills.py +0 -0
  189. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/subagent_artifacts.py +0 -0
  190. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/subagent_telemetry.py +0 -0
  191. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/subagents.py +0 -0
  192. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/unified_system_message.py +0 -0
  193. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/model/__init__.py +0 -0
  194. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/model/config.py +0 -0
  195. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/model/factory.py +0 -0
  196. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/model/pool.py +0 -0
  197. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/model/reasoning.py +0 -0
  198. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/offload.py +0 -0
  199. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/output.py +0 -0
  200. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/plugins/__init__.py +0 -0
  201. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/plugins/_json.py +0 -0
  202. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/plugins/adapters/__init__.py +0 -0
  203. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/plugins/adapters/agents.py +0 -0
  204. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/plugins/adapters/commands.py +0 -0
  205. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/plugins/adapters/skills.py +0 -0
  206. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/plugins/commands_cli.py +0 -0
  207. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/plugins/discovery.py +0 -0
  208. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/plugins/manifest.py +0 -0
  209. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/plugins/marketplace.py +0 -0
  210. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/plugins/project_plugins.py +0 -0
  211. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/plugins/protocol.py +0 -0
  212. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/plugins/store.py +0 -0
  213. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/plugins/substitution.py +0 -0
  214. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/project_utils.py +0 -0
  215. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/prompts/__init__.py +0 -0
  216. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/prompts/system.py +0 -0
  217. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/prompts/templates/system_prompt.md +0 -0
  218. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/prompts/types.py +0 -0
  219. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/rubrics/__init__.py +0 -0
  220. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/rubrics/evaluator.py +0 -0
  221. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/rubrics/evidence_extractor.py +0 -0
  222. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/rubrics/generator.py +0 -0
  223. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/rubrics/jev_compiler.py +0 -0
  224. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/rubrics/jev_grader.py +0 -0
  225. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/rubrics/middleware.py +0 -0
  226. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/schema/__init__.py +0 -0
  227. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/schema/interrupts.py +0 -0
  228. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/security/__init__.py +0 -0
  229. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/security/approval_mode.py +0 -0
  230. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/security/approval_mode_source.py +0 -0
  231. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/security/cli_ast_evaluator.py +0 -0
  232. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/security/jev_classifier.py +0 -0
  233. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/security/shell_safety.py +0 -0
  234. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/security/unicode_security.py +0 -0
  235. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/security/url_validation.py +0 -0
  236. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/server/__init__.py +0 -0
  237. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/server/_server_config.py +0 -0
  238. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/server/server.py +0 -0
  239. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/server/server_graph.py +0 -0
  240. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/skills/__init__.py +0 -0
  241. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/skills/commands.py +0 -0
  242. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/skills/invocation.py +0 -0
  243. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/skills/load.py +0 -0
  244. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/skills/loader.py +0 -0
  245. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/skills/merge.py +0 -0
  246. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/skills/registry.py +0 -0
  247. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/skills/sources.py +0 -0
  248. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/skills/trust.py +0 -0
  249. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/state/__init__.py +0 -0
  250. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/state/base.py +0 -0
  251. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/state/cloud_context.py +0 -0
  252. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/state/goal_channels.py +0 -0
  253. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/state/goal_state_limits.py +0 -0
  254. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/state/resume_state.py +0 -0
  255. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/state/service_context.py +0 -0
  256. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/state/session.py +0 -0
  257. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/state/state_migration.py +0 -0
  258. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/subagents/__init__.py +0 -0
  259. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/subagents/loader.py +0 -0
  260. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/subagents/subagents_parser.py +0 -0
  261. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/subagents/types.py +0 -0
  262. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/tools/__init__.py +0 -0
  263. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/tools/catalog.py +0 -0
  264. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/tools/display.py +0 -0
  265. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/tools/fetch_url.py +0 -0
  266. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/tools/goal_tools.py +0 -0
  267. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/tools/registry.py +0 -0
  268. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/tools/thread.py +0 -0
  269. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/tools/web_search.py +0 -0
  270. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/__init__.py +0 -0
  271. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/app.py +0 -0
  272. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/app.tcss +0 -0
  273. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/clipboard.py +0 -0
  274. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/command_registry.py +0 -0
  275. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/message_store.py +0 -0
  276. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/permission_store.py +0 -0
  277. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/preferences.py +0 -0
  278. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/prompt_manager.py +0 -0
  279. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/remote_client.py +0 -0
  280. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/textual_adapter.py +0 -0
  281. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/theme.py +0 -0
  282. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/ui_help.py +0 -0
  283. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/__init__.py +0 -0
  284. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/_ask_user_types.py +0 -0
  285. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/_copy_spans.py +0 -0
  286. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/_inline_prompt.py +0 -0
  287. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/_js_eval_display.py +0 -0
  288. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/_links.py +0 -0
  289. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/_tool_stream.py +0 -0
  290. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/agent_selector.py +0 -0
  291. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/approval.py +0 -0
  292. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/ask_user.py +0 -0
  293. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/auth.py +0 -0
  294. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/auth_manager.py +0 -0
  295. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/auto_mode_notice.py +0 -0
  296. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/autocomplete.py +0 -0
  297. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/chat_input.py +0 -0
  298. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/cloud_selector.py +0 -0
  299. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/config_manager.py +0 -0
  300. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/debug_console.py +0 -0
  301. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/devops_renderers.py +0 -0
  302. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/diff.py +0 -0
  303. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/effort_selector.py +0 -0
  304. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/goal_review.py +0 -0
  305. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/goal_status.py +0 -0
  306. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/infra_panel.py +0 -0
  307. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/install_confirm.py +0 -0
  308. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/loading.py +0 -0
  309. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/mcp_viewer.py +0 -0
  310. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/messages.py +0 -0
  311. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/model_selector.py +0 -0
  312. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/notification_center.py +0 -0
  313. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/notification_settings.py +0 -0
  314. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/operation_card.py +0 -0
  315. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/permissions_manager.py +0 -0
  316. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/plugin_manager.py +0 -0
  317. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/pool_selector.py +0 -0
  318. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/preamble.py +0 -0
  319. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/skills_viewer.py +0 -0
  320. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/status.py +0 -0
  321. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/subagent_panel.py +0 -0
  322. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/theme_selector.py +0 -0
  323. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/thread_selector.py +0 -0
  324. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/toast.py +0 -0
  325. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/tool_display.py +0 -0
  326. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/tool_renderers.py +0 -0
  327. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/tool_widgets.py +0 -0
  328. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/welcome.py +0 -0
  329. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/welcome_popup.py +0 -0
  330. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/utils/__init__.py +0 -0
  331. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/utils/cost_estimation.py +0 -0
  332. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/utils/git.py +0 -0
  333. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/utils/logger.py +0 -0
  334. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/utils/session_stats.py +0 -0
  335. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/src/opscloud/utils/startup_error.py +0 -0
  336. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/__init__.py +0 -0
  337. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/conftest.py +0 -0
  338. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/evals/__init__.py +0 -0
  339. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/evals/datasets/aws_cloud_ops.yaml +0 -0
  340. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/evals/evaluators/__init__.py +0 -0
  341. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/evals/evaluators/output_evaluator.py +0 -0
  342. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/evals/evaluators/trajectory_evaluator.py +0 -0
  343. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/evals/runners/test_eval_runner.py +0 -0
  344. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/integration_tests/test_agent_lifecycle.py +0 -0
  345. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/integration_tests/test_server_lifecycle.py +0 -0
  346. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_agent_factory.py +0 -0
  347. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_approval_widget.py +0 -0
  348. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_ask_user.py +0 -0
  349. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_ast_evaluator.py +0 -0
  350. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_backend.py +0 -0
  351. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_chat_input_responsiveness.py +0 -0
  352. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_checkpointer.py +0 -0
  353. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_claude_opus_reasoning.py +0 -0
  354. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_cli_enhancements.py +0 -0
  355. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_cli_rubric.py +0 -0
  356. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_cloud_command.py +0 -0
  357. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_commands.py +0 -0
  358. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_config.py +0 -0
  359. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_cost_tracking.py +0 -0
  360. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_default_marketplace.py +0 -0
  361. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_goal_criteria.py +0 -0
  362. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_goal_state_limits.py +0 -0
  363. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_goal_state_notice.py +0 -0
  364. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_grader_tools.py +0 -0
  365. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_hitl.py +0 -0
  366. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_integrations_and_hooks.py +0 -0
  367. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_interrupt_schemas.py +0 -0
  368. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_jev_model_router.py +0 -0
  369. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_jev_rubrics.py +0 -0
  370. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_local_context.py +0 -0
  371. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_logging.py +0 -0
  372. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_mcp_middleware.py +0 -0
  373. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_mcp_viewer_and_command.py +0 -0
  374. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_memory.py +0 -0
  375. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_memory_enhancements.py +0 -0
  376. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_middleware_stack.py +0 -0
  377. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_model_providers.py +0 -0
  378. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_model_retry.py +0 -0
  379. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_plugin_agent_skill_mcp_scoping.py +0 -0
  380. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_plugin_manager_search.py +0 -0
  381. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_plugins.py +0 -0
  382. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_pool_persistence.py +0 -0
  383. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_project_plugins.py +0 -0
  384. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_prompts_and_schema.py +0 -0
  385. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_reliable_rubric.py +0 -0
  386. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_reload_restart.py +0 -0
  387. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_resume_state.py +0 -0
  388. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_resumed_thread_latency_fix.py +0 -0
  389. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_rubrics.py +0 -0
  390. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_security.py +0 -0
  391. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_server.py +0 -0
  392. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_server_hooks.py +0 -0
  393. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_skill_creator.py +0 -0
  394. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_skills.py +0 -0
  395. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_state.py +0 -0
  396. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_subagents.py +0 -0
  397. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_tools.py +0 -0
  398. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_tui_app.py +0 -0
  399. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_utils.py +0 -0
  400. {talkops_opscloud-0.3.0b8 → talkops_opscloud-0.3.0b9}/uv-requirements.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: talkops-opscloud
3
- Version: 0.3.0b8
3
+ Version: 0.3.0b9
4
4
  Summary: Extensible Terminal Multi-Agent Framework for Cloud Operations & DevOps Coding
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -0,0 +1,275 @@
1
+ # Engineering Issue & Architectural Audit: MCP Tool Schema Explosion & Extreme Latency in Plugin Skills Flow
2
+
3
+ **Issue ID:** `ISSUE-OPSCLOUD-MCP-001`
4
+ **Date:** October 8, 2026
5
+ **Severity:** **P0 — Blocker**
6
+ **Component:** Deep Agent Core / Subagent Flow / MCP Session Manager / Plugin Adapters
7
+ **Target Environments:** `src/opscloud` (OpsCloud Orchestrator) vs. `reference/dcode` (Reference Implementation)
8
+ **Authors:** AI Architecture & Core Systems Audit
9
+ **Audience:** Core Engineering Team, Agent Platform Engineers, DevOps & Infrastructure
10
+
11
+ ---
12
+
13
+ ## 1. Executive Summary & Impact Analysis
14
+
15
+ During testing of skill plugins equipped with MCP (Model Context Protocol) servers (e.g., `aws-containers@talkops-devops-plugins`), the Deep Agent experienced catastrophic response latency and token usage degradation:
16
+
17
+ * **OpsCloud Turn 1 Performance:** **315.79 seconds (5.22 minutes)** total turn duration, processing **211,300 input tokens** ($0.1531 cost) on a simple user command.
18
+ * **Reference `dcode` Performance:** **15.10s P50** across 4 turns (Turn 1: 0.73s, Turn 2: 25.39s [45.37K tokens], Turn 3: 15.09s [46.6K tokens], Turn 4: 40.15s [254.8K tokens]).
19
+ * **Discrepancy Ratio:** **~21x Latency Explosion**, **~4.7x Initial Prompt Context Explosion**.
20
+
21
+ ```
22
+ ┌───────────────────────────────────────────────────────────────────────────────┐
23
+ │ INITIAL TURN LATENCY & CONTEXT COMPARISON │
24
+ ├──────────────────┬─────────────────────────────┬──────────────────────────────┤
25
+ │ Metric │ OpsCloud (Current) │ reference/dcode (Benchmark) │
26
+ ├──────────────────┼─────────────────────────────┼──────────────────────────────┤
27
+ │ Turn 1 Latency │ 315.79s (5m 15s) ⚠️ BLOCKER │ 0.73s - 25.39s (P50: 15.10s) │
28
+ │ Turn 1 Tokens │ 211,300 tokens (Context full)│ ~45,370 tokens │
29
+ │ Tool Injection │ Eager / Global / Unscoped │ Scoped / Filtered │
30
+ │ Schema Strategy │ Recursive $ref Dereference │ Protocol Native (Compact) │
31
+ │ Session / Loop │ Ephemeral Thread Loop + Stdio│ Server Loop Router Client │
32
+ └──────────────────┴─────────────────────────────┴──────────────────────────────┘
33
+ ```
34
+
35
+ The system became completely unresponsive for 5+ minutes because **the entire LLM context window was inundated with over 211K tokens of recursively inlined JSON schemas for dozens of un-scoped Kubernetes/AWS tools**, which then had to be re-evaluated across every internal graph step over disjointed stdio subprocess loops.
36
+
37
+ ---
38
+
39
+ ## 2. Trace & Incident Evidence Breakdown
40
+
41
+ ### 2.1 OpsCloud Trace (Image 1: `media_1791459244211.png`)
42
+ * **Execution Status:** 1 Turn, Duration: **315.79s**, Context: **211.3K tokens**, Cost: **$0.1531**.
43
+ * **Observed Bound Tools:**
44
+ * Core: `create_temp_artifact`, `delete_temp_artifact`, `fetch_url`.
45
+ * Finch MCP: `plugin__aws-containers_ta_finch_build_container_ima_df47730a85e8`, `plugin__aws-containers_talkops-dev_finch_push_image_6b02bcde1560`, `plugin__aws-containers_talkop_finch_create_ecr_repo_a8f88f0a1f9f`.
46
+ * EKS / Kubernetes MCP: `plugin__aws-containers_talkops-d_list_k8s_resources_5aa672efc864`, `plugin__aws-containers_talkops-devops-_get_pod_logs_a03a76775bc1`, `plugin__aws-containers_talkops-devop_get_k8s_events_465d1e587238`, `plugin__aws-containers_talkops-de_list_api_versions_c0a261010b5e`, `plugin__aws-containers_talkops-_manage_k8s_resource_b877895269a7`, `plugin__aws-containers_talkops-devops-pl_apply_yaml_34e08bc5a89a`, `plugin__aws-containers_talkop_generate_app_manifest_555c8188f2bb`...
47
+ * **Symptom:** Every single tool from all MCP servers declared in the plugin was injected directly into the main agent's LLM prompt, expanding schemas recursively.
48
+
49
+ ### 2.2 Reference `dcode` Trace (Image 2: `media_1791459309416.png`)
50
+ * **Execution Status:** 4 Turns, P50: **15.10s**, Cost: **$0.1014**.
51
+ * Turn 1: **0.73s** (Goal initialization)
52
+ * Turn 2: **25.39s** (45.37K tokens)
53
+ * Turn 3: **15.09s** (46.6K tokens)
54
+ * Turn 4: **40.15s** (254.8K tokens after 4 rounds of conversation history accumulation)
55
+ * **Observed Bound Tools:**
56
+ * Core: `update_goal`, `ask_user`, `js_eval`, `create_temp_artifact`, `delete_temp_artifact`, `fetch_url`, `get_current_thread_id`.
57
+ * Compute MCP (`aws-compute`): Only 6 focused tools (`aws__get_regional_availa`, `aws__search_documentatio`, `aws__read_documentation`, `aws__retrieve_skill`, `aws__list_regions`, `aws__get_tasks`).
58
+ * **Symptom:** Fast execution, minimal initial token overhead, and precise tool availability.
59
+
60
+ ---
61
+
62
+ ## 3. Deep Root-Cause Analysis (Forensic Audit)
63
+
64
+ Our cross-codebase audit identified **5 compounding architectural flaws** in OpsCloud that do not exist in `reference/dcode`.
65
+
66
+ ---
67
+
68
+ ### Root Cause 1: Recursive `$ref` Dereferencing in `_clean_mcp_schema`
69
+ **Location:** [`src/opscloud/mcp/session_manager.py:68–85`](file:///Users/structbinary/Documents/work/talkops/opscloud/src/opscloud/mcp/session_manager.py#L68-L85)
70
+
71
+ #### What OpsCloud Does:
72
+ ```python
73
+ def _clean_mcp_schema(schema: Any) -> dict[str, Any]:
74
+ if not isinstance(schema, dict):
75
+ return {}
76
+
77
+ from langchain_core.utils.json_schema import dereference_refs
78
+
79
+ try:
80
+ resolved = dereference_refs(schema)
81
+ except Exception as exc:
82
+ logger.debug("Failed to dereference MCP schema refs: %s", exc)
83
+ resolved = schema
84
+
85
+ cleaned = dict(resolved) if isinstance(resolved, dict) else dict(schema)
86
+ for key in ("$schema", "$id", "$defs", "definitions", "additionalProperties"):
87
+ cleaned.pop(key, None)
88
+ ...
89
+ ```
90
+
91
+ #### Why This Explodes Context to 211.3K Tokens:
92
+ * When `awslabs.eks-mcp-server` loads, tools like `apply_yaml`, `manage_k8s_resource`, and `generate_app_manifest` define parameters that accept complete Kubernetes manifests.
93
+ * The underlying JSON schema contains deep OpenAPI definitions (`#/$defs/ObjectMeta`, `#/$defs/PodSpec`, `#/$defs/Container`, `#/$defs/EnvVar`, etc.) with multiple recursive and cross-referencing branches.
94
+ * `dereference_refs()` replaces every `{"$ref": ...}` pointer with a **deep, full copy** of the referenced definition.
95
+ * If a single schema references sub-models 15 times, inlining them causes exponential duplication. A single tool's schema grows from a compact 1.5KB reference graph into a **60KB–100KB JSON behemoth**.
96
+ * Multiplying this by 10+ Kubernetes tools in `aws-containers` results in **150,000+ tokens generated from tool schema definitions alone**.
97
+
98
+ #### What `reference/dcode` Does Differently:
99
+ **Location:** [`reference/dcode/mcp_tools.py:1514–1520`](file:///Users/structbinary/Documents/work/talkops/opscloud/reference/dcode/mcp_tools.py#L1514-L1520)
100
+ * `dcode` passes the raw MCP schema directly to `langchain.mcp.as_langchain_tool(routed_tool, client)`.
101
+ * It **never calls `dereference_refs`**. The schema remains compact and standard, allowing the LLM provider's API client to handle references natively without exponential duplication.
102
+
103
+ ---
104
+
105
+ ### Root Cause 2: Global Eager Tool Injection of Vertical Plugins into Main Coordinator Agent
106
+ **Locations:**
107
+ * [`src/opscloud/plugins/models.py:174–185`](file:///Users/structbinary/Documents/work/talkops/opscloud/src/opscloud/plugins/models.py#L174-L185)
108
+ * [`src/opscloud/plugins/adapters/mcp.py:200–203`](file:///Users/structbinary/Documents/work/talkops/opscloud/src/opscloud/plugins/adapters/mcp.py#L200-L203)
109
+ * [`src/opscloud/agent/factory.py:604–660`](file:///Users/structbinary/Documents/work/talkops/opscloud/src/opscloud/agent/factory.py#L604-L660)
110
+
111
+ #### The Fault Chain:
112
+ 1. In `src/opscloud/plugins/models.py`:
113
+ ```python
114
+ @property
115
+ def is_agent_plugin(self) -> bool:
116
+ """Return True if this plugin provides autonomous agents (agent-based plugin)."""
117
+ if self.inventory.agents:
118
+ ...
119
+ if self.root and isinstance(self.root, Path):
120
+ agents_dir = self.root / "agents"
121
+ return agents_dir.is_dir() and any(agents_dir.glob("*.md"))
122
+ return False
123
+ ```
124
+ 2. In `src/opscloud/plugins/adapters/mcp.py`:
125
+ ```python
126
+ def plugin_mcp_configs(plugins, *, include_subagents: bool = False):
127
+ for plugin in plugins:
128
+ if not include_subagents and plugin.is_agent_plugin:
129
+ continue # Dynamic subagent plugins isolate their own MCP servers
130
+ ```
131
+ 3. Vertical plugins (such as `aws-containers`, `aws-networking`, `aws-web-and-mobile`) and skill plugins do **not** define an `agents/*.md` directory. Therefore, `plugin.is_agent_plugin` evaluates to **`False`**.
132
+ 4. Consequently, when `factory.py` calls `discover_mcp_configs()` to build the **Main Coordinator Agent**, all MCP servers declared by `aws-containers` (`finch`, `eks`, `ecs`, `aws-mcp`) are treated as global coordinator tools!
133
+ 5. In `factory.py` lines 654–657:
134
+ ```python
135
+ discovered_tools = build_mcp_tools_from_server_infos(coordinator_infos, mcp_manager)
136
+ if discovered_tools:
137
+ mcp_tools_list.extend(discovered_tools)
138
+ all_tools.extend(discovered_tools) # <-- Injected into all_tools!
139
+ ```
140
+ 6. In `factory.py` line 1081:
141
+ ```python
142
+ graph = create_deep_agent(
143
+ model=active_model,
144
+ tools=all_tools, # <-- ALL vertical plugin tools bound to Main Agent!
145
+ ...
146
+ )
147
+ ```
148
+ 7. **The result:** The main agent is inundated with 40+ specialized container/Kubernetes tools that should have been isolated to a specialized subagent or dynamically mounted skill.
149
+
150
+ ---
151
+
152
+ ### Root Cause 3: `ToolFilterMiddleware` Does NOT Filter Tools from the Model Request
153
+ **Location:** [`src/opscloud/middleware/tool_filter.py:412–431`](file:///Users/structbinary/Documents/work/talkops/opscloud/src/opscloud/middleware/tool_filter.py#L412-L431)
154
+
155
+ #### The Missing Hook:
156
+ * `ToolFilterMiddleware` only implements:
157
+ - `wrap_tool_call(self, request: ToolCallRequest, handler)`
158
+ - `awrap_tool_call(self, request: ToolCallRequest, handler)`
159
+ * It **does not implement** `wrap_model_call`, `awrap_model_call`, or `modify_request`.
160
+ * In LangGraph / DeepAgents, `tools` are passed to `model.bind_tools(self.tools)`.
161
+ * Because `ToolFilterMiddleware` does not intercept the model call request to prune `request.tools`, **100% of all registered tools are sent in the system prompt / tool definitions to the LLM on every single turn**.
162
+ * The filter only functions as an execution-time authorization gate (blocking the tool *after* the LLM decides to call it). It provides **zero context-reduction benefits**.
163
+
164
+ ---
165
+
166
+ ### Root Cause 4: Multi-Step Compounding Turn Latency (315 Seconds TTFT)
167
+ * Processing **211,300 input tokens** on remote LLM endpoints (Gemini 2.5 / 3.7 Flash, Claude 3.5 Sonnet) incurs an extreme Time-To-First-Token (TTFT) penalty: ~30 to 70 seconds per call.
168
+ * When the agent runs an agentic step (e.g., executing a command or asking for user clarification), LangGraph's Pregel engine executes sequential model nodes (`model` -> `tools` -> `model` -> `tools` -> `model`).
169
+ * Because the tool schema footprint remains at 211K tokens, **each model call must re-send and the LLM must re-process the full 211K tokens**.
170
+ * 4 sequential steps × 75 seconds per step = **300+ seconds (5.22 minutes)**.
171
+
172
+ ---
173
+
174
+ ### Root Cause 5: Event Loop Mismatch & Stdio Process Locking/Churn
175
+ **Locations:**
176
+ * [`src/opscloud/agent/factory.py:643–646`](file:///Users/structbinary/Documents/work/talkops/opscloud/src/opscloud/agent/factory.py#L643-L646)
177
+ * [`src/opscloud/mcp/session_manager.py:530–547`](file:///Users/structbinary/Documents/work/talkops/opscloud/src/opscloud/mcp/session_manager.py#L530-L547)
178
+
179
+ #### Thread & Event Loop Lifecycles in OpsCloud:
180
+ 1. In `factory.py`:
181
+ ```python
182
+ if loop is not None and loop.is_running():
183
+ with concurrent.futures.ThreadPoolExecutor(max_workers=1) as pool:
184
+ new_infos = pool.submit(asyncio.run, preload_mcp_metadata(missing_configs)).result()
185
+ else:
186
+ new_infos = asyncio.run(preload_mcp_metadata(missing_configs))
187
+ ```
188
+ `asyncio.run()` creates a temporary event loop. Preloading connects via stdio, fetches tool names, and when `asyncio.run()` finishes, **that event loop is destroyed**. Any stdio pipes or process handles bound to that loop become dead or detached.
189
+ 2. Later, when an agent turn executes on the server's `uvloop`, `get_session(server_name)` finds that no live session exists for that loop and calls `connect_server()` to start a brand new stdio connection via `uvx`.
190
+ 3. Running multiple `uvx` instances (`uvx awslabs.eks-mcp-server@latest`, `uvx awslabs.finch-mcp-server@latest`, `uvx ecs-mcp-server`) concurrently causes:
191
+ - Python virtual environment creation / cache resolution latency for each `uvx` invocation.
192
+ - Stdio process blocking and mutex lock contention under `_get_server_lock(server_name)`.
193
+ - Thread stalls while waiting for child processes to initialize their IPC pipes.
194
+
195
+ #### What `reference/dcode` Does Differently:
196
+ **Locations:**
197
+ * [`reference/dcode/server_graph.py:161–168`](file:///Users/structbinary/Documents/work/talkops/opscloud/reference/dcode/server_graph.py#L161-L168)
198
+ * [`reference/dcode/mcp_tools.py:2247–2251`](file:///Users/structbinary/Documents/work/talkops/opscloud/reference/dcode/mcp_tools.py#L2247-L2251)
199
+ * `dcode` initializes a single, shared `MCPSessionManager` directly on the server's running event loop via `_get_mcp_session_manager()`.
200
+ * Backends are mounted onto a single FastMCP router client.
201
+ * Preflight and connection setup are executed concurrently with bounded concurrency:
202
+ ```python
203
+ preflight_results = await _gather_bounded(
204
+ [functools.partial(_preflight_and_connect, name, cfg) for name, cfg in server_items],
205
+ limit=_MCP_LOAD_CONCURRENCY,
206
+ )
207
+ ```
208
+ * All tools route through this unified client. There are no detached thread pools or orphaned event loops.
209
+
210
+ ---
211
+
212
+ ## 4. Architectural Comparison: OpsCloud vs. `dcode`
213
+
214
+ | Architectural Dimension | OpsCloud (`src/opscloud`) | Reference Implementation (`reference/dcode`) |
215
+ | :--- | :--- | :--- |
216
+ | **Tool Adapter Layer** | `langchain_mcp_adapters` with custom `StructuredTool` wrapping | `fastmcp.Client` + `langchain.mcp.as_langchain_tool` |
217
+ | **JSON Schema Handling** | **Recursive `dereference_refs()`** expanding all definitions inline | Native schema pass-through without ref dereferencing |
218
+ | **Plugin MCP Scoping** | Only checks `plugin.is_agent_plugin` (`agents/*.md`). Vertical/Skill plugins dump all tools to Main Agent | Strict config discovery; plugins inject scoped configs with user trust gating |
219
+ | **Model Prompt Filtering** | **None.** `ToolFilterMiddleware` only acts at tool execution time | `_apply_tool_filter` prunes tools before agent construction via `allowedTools`/`disabledTools` |
220
+ | **Session Lifetime** | Eager thread preloading with `asyncio.run()`, on-demand reconnect on separate `uvloop` | Singleton `MCPSessionManager` bound to server event loop |
221
+ | **Connection Pooling** | Separate `_MCPSessionEntry` per server with individual locks | Single unified FastMCP router client multiplexing all backends |
222
+ | **Teardown & Cleanup** | `session.invalidate()` per server | Bounded 5s teardown via `AsyncExitStack` |
223
+
224
+ ---
225
+
226
+ ## 5. Engineering Action Plan & Implementation Guidance
227
+
228
+ To permanently resolve this blocker and achieve the ~15s response latency of `reference/dcode`, the engineering team must implement the following four-phase remediation:
229
+
230
+ ### Phase 1: Eliminate Recursive Schema Expansion (Immediate Fix)
231
+ **Target:** [`src/opscloud/mcp/session_manager.py:68–103`](file:///Users/structbinary/Documents/work/talkops/opscloud/src/opscloud/mcp/session_manager.py#L68-L103)
232
+ 1. **Remove `dereference_refs()`**: Cease using `langchain_core.utils.json_schema.dereference_refs` on raw MCP tool schemas.
233
+ 2. **Schema Sanitization**: Instead of deep inlining, clean schemas by stripping provider-incompatible root keys (`$schema`, `$id`) while preserving local `$defs` or flattening top-level properties shallowly.
234
+ 3. **Verify Schemas**: Ensure parameters for tools like `apply_yaml` and `manage_k8s_resource` pass concise schemas to the model.
235
+
236
+ ### Phase 2: Restrict Plugin MCP Tool Scope to Subagents / Skills
237
+ **Target:** [`src/opscloud/plugins/adapters/mcp.py`](file:///Users/structbinary/Documents/work/talkops/opscloud/src/opscloud/plugins/adapters/mcp.py) & [`src/opscloud/agent/factory.py`](file:///Users/structbinary/Documents/work/talkops/opscloud/src/opscloud/agent/factory.py)
238
+ 1. **Update Plugin Classification**: Plugins that provide skills with MCP servers must not automatically dump their MCP tools into the Main Coordinator Agent (`all_tools`).
239
+ 2. **Scope Vertical Plugins**: Tools from vertical plugins (`aws-containers`, `aws-networking`, etc.) should only be attached to their respective specialized subagents or mounted when their specific skill is activated.
240
+ 3. **Main Agent Tool Budget**: Ensure the Main Coordinator Agent is initialized with only core tools (`fetch_url`, `web_search`, `read_file`, `run_command`, `task`, `ask_user`), keeping initial context below **15,000 tokens**.
241
+
242
+ ### Phase 3: Implement Model-Level Tool Filtering in `ToolFilterMiddleware`
243
+ **Target:** [`src/opscloud/middleware/tool_filter.py`](file:///Users/structbinary/Documents/work/talkops/opscloud/src/opscloud/middleware/tool_filter.py)
244
+ 1. Implement `wrap_model_call` and `awrap_model_call` (or `modify_request`):
245
+ ```python
246
+ async def awrap_model_call(
247
+ self,
248
+ request: ModelRequest,
249
+ handler: Callable[[ModelRequest], Awaitable[ModelResponse]],
250
+ ) -> ModelResponse:
251
+ if self._allowed_patterns and request.tools:
252
+ filtered_tools = [
253
+ t for t in request.tools
254
+ if self.is_tool_allowed(getattr(t, "name", str(t)), tool_obj=t)
255
+ ]
256
+ request = request.override(tools=filtered_tools)
257
+ return await handler(request)
258
+ ```
259
+ 2. This guarantees that subagents with restricted tool lists (e.g., `allowed_tools: ["aws-finops-*"]`) only send their authorized tools to the LLM prompt.
260
+
261
+ ### Phase 4: Align Session Lifecycle with `dcode` Pattern
262
+ **Target:** [`src/opscloud/mcp/session_manager.py`](file:///Users/structbinary/Documents/work/talkops/opscloud/src/opscloud/mcp/session_manager.py) & [`src/opscloud/server/server_graph.py`](file:///Users/structbinary/Documents/work/talkops/opscloud/src/opscloud/server/server_graph.py)
263
+ 1. **Bind Session Manager to Server Loop**: Ensure `MCPSessionManager` is instantiated on the server's primary event loop, eliminating cross-thread `asyncio.run()` preloading.
264
+ 2. **Router Client Multiplexing**: Adopt FastMCP router client mounting so all stdio/http transports share a single client context.
265
+ 3. **Graceful Subprocess Management**: Ensure bounded subprocess shutdown (5s timeout) to prevent dangling `uvx` / `docker` processes on server reload.
266
+
267
+ ---
268
+
269
+ ## 6. Verification & Acceptance Criteria
270
+
271
+ The fix will be considered complete and verified when:
272
+ 1. **Context Benchmark:** Turn 1 prompt context with `aws-containers` installed does not exceed **45,000 tokens** (comparable to `dcode`).
273
+ 2. **Latency Benchmark:** Turn 1 execution latency drops from **315 seconds to under 25 seconds** on the same test query.
274
+ 3. **No Schema Inlining Bloat:** Inspection of LangSmith tool definitions confirms that Kubernetes OpenAPI definitions are not duplicated into thousands of lines of JSON.
275
+ 4. **Subagent Isolation:** Tools from `aws-containers` only appear in turns where the container subagent/skill is explicitly dispatched.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "talkops-opscloud"
3
- version = "0.3.0b8"
3
+ version = "0.3.0b9"
4
4
  description = "Extensible Terminal Multi-Agent Framework for Cloud Operations & DevOps Coding"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -117,7 +117,11 @@ class MCPDiscovery:
117
117
  """
118
118
  self._store = store
119
119
 
120
- def discover(self, project_root: Path | None = None) -> dict[str, MCPServerConfig]:
120
+ def discover(
121
+ self,
122
+ project_root: Path | None = None,
123
+ include_subagents: bool = False,
124
+ ) -> dict[str, MCPServerConfig]:
121
125
  """Discover and merge MCP server configs across global, user, plugin, and project files.
122
126
 
123
127
  Precedence (lowest to highest):
@@ -158,7 +162,10 @@ class MCPDiscovery:
158
162
  try:
159
163
  from opscloud.plugins.adapters.mcp import discover_plugin_mcp_configs
160
164
 
161
- plugin_configs = discover_plugin_mcp_configs(project_dir=effective_project_root)
165
+ plugin_configs = discover_plugin_mcp_configs(
166
+ project_dir=effective_project_root,
167
+ include_subagents=include_subagents,
168
+ )
162
169
  if isinstance(plugin_configs, dict):
163
170
  for name, config in plugin_configs.items():
164
171
  if isinstance(config, dict):
@@ -224,6 +231,9 @@ class MCPDiscovery:
224
231
  return results
225
232
 
226
233
 
227
- def discover_mcp_configs(project_root: Path | None = None) -> dict[str, MCPServerConfig]:
234
+ def discover_mcp_configs(
235
+ project_root: Path | None = None,
236
+ include_subagents: bool = False,
237
+ ) -> dict[str, MCPServerConfig]:
228
238
  """Discover active MCP server configs from disk."""
229
- return MCPDiscovery().discover(project_root)
239
+ return MCPDiscovery().discover(project_root, include_subagents=include_subagents)
@@ -77,42 +77,63 @@ def _filter_tool_names(
77
77
  return True
78
78
 
79
79
 
80
- def _clean_mcp_schema(schema: Any) -> dict[str, Any]:
80
+ def _clean_mcp_schema(schema: Any, max_ref_depth: int = 3) -> dict[str, Any]:
81
81
  """Clean JSON Schema for compatibility with LLM provider tool schemas (Gemini, Anthropic, OpenAI).
82
82
 
83
- Dereferences all `$ref` pointers (such as `#/$defs/...` or `#/definitions/...`)
84
- using LangChain's `dereference_refs` so that referenced models (like PricingFilter)
85
- are inlined directly into properties before removing metadata keys.
83
+ Safely inlines local `$ref` pointers (such as `#/$defs/...` or `#/definitions/...`)
84
+ up to a bounded ref depth, strips provider-incompatible metadata keys (`$schema`, `$id`,
85
+ `additionalProperties`), and prevents recursive bloat or corrupted empty keys.
86
86
  """
87
87
  if not isinstance(schema, dict):
88
88
  return {}
89
89
 
90
- from langchain_core.utils.json_schema import dereference_refs
91
-
92
- try:
93
- resolved = dereference_refs(schema)
94
- except Exception as exc:
95
- logger.debug("Failed to dereference MCP schema refs: %s", exc)
96
- resolved = schema
97
-
98
- cleaned = dict(resolved) if isinstance(resolved, dict) else dict(schema)
99
- for key in ("$schema", "$id", "$defs", "definitions", "additionalProperties"):
100
- cleaned.pop(key, None)
101
-
102
- properties = cleaned.get("properties")
103
- if isinstance(properties, dict):
104
- new_props = {}
105
- for prop_name, prop_val in properties.items():
106
- if isinstance(prop_val, dict):
107
- p_clean = dict(prop_val)
108
- p_clean.pop("additionalProperties", None)
109
- p_clean.pop("$schema", None)
110
- new_props[prop_name] = p_clean
111
- else:
112
- new_props[prop_name] = prop_val
113
- cleaned["properties"] = new_props
114
-
115
- return cleaned
90
+ defs: dict[str, Any] = {}
91
+ if isinstance(schema.get("$defs"), dict):
92
+ defs.update(schema["$defs"])
93
+ if isinstance(schema.get("definitions"), dict):
94
+ defs.update(schema["definitions"])
95
+
96
+ def _resolve(node: Any, ref_depth: int, seen_refs: set[str]) -> Any:
97
+ if isinstance(node, dict):
98
+ if "$ref" in node:
99
+ ref = node["$ref"]
100
+ if (
101
+ ref_depth >= max_ref_depth
102
+ or not isinstance(ref, str)
103
+ or not ref.startswith("#/")
104
+ or ref in seen_refs
105
+ ):
106
+ return {"type": "object"}
107
+
108
+ parts = ref.lstrip("#/").split("/")
109
+ target = None
110
+ if len(parts) >= 2 and parts[0] in ("$defs", "definitions"):
111
+ target = defs.get(parts[1])
112
+ elif len(parts) == 1 and parts[0] in defs:
113
+ target = defs.get(parts[0])
114
+
115
+ if isinstance(target, dict):
116
+ merged = dict(target)
117
+ for k, v in node.items():
118
+ if k != "$ref":
119
+ merged[k] = v
120
+ return _resolve(merged, ref_depth + 1, seen_refs | {ref})
121
+ return {"type": "object"}
122
+
123
+ res = {}
124
+ for k, v in node.items():
125
+ if k in ("$schema", "$id", "additionalProperties", "$defs", "definitions"):
126
+ continue
127
+ res[k] = _resolve(v, ref_depth, seen_refs)
128
+ return res
129
+
130
+ if isinstance(node, list):
131
+ return [_resolve(item, ref_depth, seen_refs) for item in node]
132
+
133
+ return node
134
+
135
+ result = _resolve(schema, 0, set())
136
+ return result if isinstance(result, dict) else {}
116
137
 
117
138
 
118
139
  def _clean_stderr_diagnostic(stderr_text: str | None) -> str | None:
@@ -65,42 +65,63 @@ def _normalize_mcp_arguments(arguments: dict[str, Any], input_schema: Any) -> di
65
65
  return cleaned
66
66
 
67
67
 
68
- def _clean_mcp_schema(schema: Any) -> dict[str, Any]:
68
+ def _clean_mcp_schema(schema: Any, max_ref_depth: int = 3) -> dict[str, Any]:
69
69
  """Clean JSON Schema for compatibility with LLM provider tool schemas (Gemini, Anthropic, OpenAI).
70
70
 
71
- Dereferences all `$ref` pointers (such as `#/$defs/...` or `#/definitions/...`)
72
- using LangChain's `dereference_refs` so that referenced models (like PricingFilter)
73
- are inlined directly into properties before removing metadata keys.
71
+ Safely inlines local `$ref` pointers (such as `#/$defs/...` or `#/definitions/...`)
72
+ up to a bounded ref depth, strips provider-incompatible metadata keys (`$schema`, `$id`,
73
+ `additionalProperties`), and prevents recursive bloat or corrupted empty keys.
74
74
  """
75
75
  if not isinstance(schema, dict):
76
76
  return {}
77
77
 
78
- from langchain_core.utils.json_schema import dereference_refs
78
+ defs: dict[str, Any] = {}
79
+ if isinstance(schema.get("$defs"), dict):
80
+ defs.update(schema["$defs"])
81
+ if isinstance(schema.get("definitions"), dict):
82
+ defs.update(schema["definitions"])
83
+
84
+ def _resolve(node: Any, ref_depth: int, seen_refs: set[str]) -> Any:
85
+ if isinstance(node, dict):
86
+ if "$ref" in node:
87
+ ref = node["$ref"]
88
+ if (
89
+ ref_depth >= max_ref_depth
90
+ or not isinstance(ref, str)
91
+ or not ref.startswith("#/")
92
+ or ref in seen_refs
93
+ ):
94
+ return {"type": "object"}
95
+
96
+ parts = ref.lstrip("#/").split("/")
97
+ target = None
98
+ if len(parts) >= 2 and parts[0] in ("$defs", "definitions"):
99
+ target = defs.get(parts[1])
100
+ elif len(parts) == 1 and parts[0] in defs:
101
+ target = defs.get(parts[0])
102
+
103
+ if isinstance(target, dict):
104
+ merged = dict(target)
105
+ for k, v in node.items():
106
+ if k != "$ref":
107
+ merged[k] = v
108
+ return _resolve(merged, ref_depth + 1, seen_refs | {ref})
109
+ return {"type": "object"}
110
+
111
+ res = {}
112
+ for k, v in node.items():
113
+ if k in ("$schema", "$id", "additionalProperties", "$defs", "definitions"):
114
+ continue
115
+ res[k] = _resolve(v, ref_depth, seen_refs)
116
+ return res
79
117
 
80
- try:
81
- resolved = dereference_refs(schema)
82
- except Exception as exc:
83
- logger.debug("Failed to dereference MCP schema refs: %s", exc)
84
- resolved = schema
85
-
86
- cleaned = dict(resolved) if isinstance(resolved, dict) else dict(schema)
87
- for key in ("$schema", "$id", "$defs", "definitions", "additionalProperties"):
88
- cleaned.pop(key, None)
89
-
90
- properties = cleaned.get("properties")
91
- if isinstance(properties, dict):
92
- new_props = {}
93
- for prop_name, prop_val in properties.items():
94
- if isinstance(prop_val, dict):
95
- p_clean = dict(prop_val)
96
- p_clean.pop("additionalProperties", None)
97
- p_clean.pop("$schema", None)
98
- new_props[prop_name] = p_clean
99
- else:
100
- new_props[prop_name] = prop_val
101
- cleaned["properties"] = new_props
118
+ if isinstance(node, list):
119
+ return [_resolve(item, ref_depth, seen_refs) for item in node]
102
120
 
103
- return cleaned
121
+ return node
122
+
123
+ result = _resolve(schema, 0, set())
124
+ return result if isinstance(result, dict) else {}
104
125
 
105
126
 
106
127
  def _filter_tool_name(
@@ -6,7 +6,7 @@ from collections.abc import Callable, Mapping, Sequence
6
6
  import fnmatch
7
7
  from typing import Any
8
8
 
9
- from langchain.agents.middleware.types import AgentMiddleware
9
+ from langchain.agents.middleware.types import AgentMiddleware, ModelRequest
10
10
  from langchain_core.messages import ToolMessage
11
11
  from langgraph.prebuilt.tool_node import ToolCallRequest
12
12
 
@@ -429,6 +429,40 @@ class ToolFilterMiddleware(AgentMiddleware[Any, Any]):
429
429
  return err
430
430
  return await handler(request)
431
431
 
432
+ def wrap_model_call(
433
+ self,
434
+ request: ModelRequest[Any],
435
+ handler: Callable[[ModelRequest[Any]], Any],
436
+ ) -> Any:
437
+ """Prune unavailable tools from model request before sending to LLM."""
438
+ if self._allowed_patterns and request.tools:
439
+ filtered_tools = []
440
+ for t in request.tools:
441
+ raw_name = getattr(t, "name", None) if not isinstance(t, dict) else t.get("name")
442
+ name = str(raw_name) if raw_name is not None else ""
443
+ tool_obj = t if not isinstance(t, dict) else None
444
+ if name and self.is_tool_allowed(name, tool_obj=tool_obj):
445
+ filtered_tools.append(t)
446
+ request = request.override(tools=filtered_tools)
447
+ return handler(request)
448
+
449
+ async def awrap_model_call(
450
+ self,
451
+ request: ModelRequest[Any],
452
+ handler: Callable[[ModelRequest[Any]], Any],
453
+ ) -> Any:
454
+ """Asynchronously prune unavailable tools from model request before sending to LLM."""
455
+ if self._allowed_patterns and request.tools:
456
+ filtered_tools = []
457
+ for t in request.tools:
458
+ raw_name = getattr(t, "name", None) if not isinstance(t, dict) else t.get("name")
459
+ name = str(raw_name) if raw_name is not None else ""
460
+ tool_obj = t if not isinstance(t, dict) else None
461
+ if name and self.is_tool_allowed(name, tool_obj=tool_obj):
462
+ filtered_tools.append(t)
463
+ request = request.override(tools=filtered_tools)
464
+ return await handler(request)
465
+
432
466
 
433
467
  __all__ = [
434
468
  "ALWAYS_ALLOWED_SYSTEM_TOOLS",
@@ -199,7 +199,7 @@ def plugin_mcp_configs(
199
199
  configs: list[dict[str, Any]] = []
200
200
  for plugin in plugins:
201
201
  if not include_subagents and plugin.is_agent_plugin:
202
- continue # Dynamic subagent plugins isolate their own MCP servers
202
+ continue # Agent-based plugins isolate their MCP servers to their own subagents
203
203
 
204
204
  if plugin.data_dir is not None:
205
205
  try:
@@ -189,6 +189,16 @@ class PluginInstance:
189
189
  """Alias for is_agent_plugin."""
190
190
  return self.is_agent_plugin
191
191
 
192
+ @property
193
+ def is_partner_plugin(self) -> bool:
194
+ """Return True if plugin provides MCP tools and skills without autonomous agents."""
195
+ return not self.is_agent_plugin and bool(self.inventory.mcp_files or (self.manifest and self.manifest.inline_mcp))
196
+
197
+ @property
198
+ def is_vertical_plugin(self) -> bool:
199
+ """Return True if plugin provides specialized skills without agents or MCP servers."""
200
+ return not self.is_agent_plugin and not self.is_partner_plugin and bool(self.inventory.skills)
201
+
192
202
 
193
203
  def is_agent_plugin_dir(plugin_dir: Path) -> bool:
194
204
  """Return True if a plugin directory contains an agents/ component with markdown definitions."""
@@ -192,6 +192,23 @@ def test_clean_mcp_schema() -> None:
192
192
  assert "Field" in items_schema["properties"]
193
193
  assert "Value" in items_schema["properties"]
194
194
 
195
+ # Verify circular references and bounded recursion break safely without empty keys or infinite loop
196
+ circular_schema = {
197
+ "type": "object",
198
+ "properties": {"node": {"$ref": "#/$defs/Node"}},
199
+ "$defs": {
200
+ "Node": {
201
+ "type": "object",
202
+ "properties": {"child": {"$ref": "#/$defs/Node"}},
203
+ }
204
+ },
205
+ }
206
+ cleaned_circ = _clean_mcp_schema(circular_schema)
207
+ assert "$defs" not in cleaned_circ
208
+ assert "$ref" not in str(cleaned_circ)
209
+ assert "" not in cleaned_circ
210
+ assert cleaned_circ["properties"]["node"]["properties"]["child"] == {"type": "object"}
211
+
195
212
 
196
213
  def test_is_transient_session_error() -> None:
197
214
  assert _is_transient_session_error(BrokenPipeError()) is True