talkops-opscloud 0.3.0b7__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 (401) hide show
  1. {talkops_opscloud-0.3.0b7 → 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.0b7 → talkops_opscloud-0.3.0b9}/pyproject.toml +1 -1
  4. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/agent/factory.py +41 -10
  5. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/mcp/discovery.py +14 -4
  6. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/mcp/preload.py +51 -30
  7. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/mcp/session_manager.py +49 -28
  8. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/server_hooks.py +1 -1
  9. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/tool_filter.py +185 -98
  10. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/plugins/adapters/mcp.py +1 -1
  11. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/plugins/models.py +10 -0
  12. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/app.py +231 -10
  13. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/remote_client.py +42 -18
  14. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/textual_adapter.py +43 -12
  15. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/chat_input.py +48 -3
  16. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/messages.py +13 -0
  17. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_mcp.py +17 -0
  18. talkops_opscloud-0.3.0b9/tests/unit_tests/test_plugin_agent_skill_mcp_scoping.py +498 -0
  19. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_tool_filter.py +133 -0
  20. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_tui_app.py +141 -0
  21. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/uv.lock +1 -1
  22. talkops_opscloud-0.3.0b7/tests/unit_tests/test_plugin_agent_skill_mcp_scoping.py +0 -228
  23. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/.dockerignore +0 -0
  24. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/.env.example +0 -0
  25. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/.github/workflows/ci.yml +0 -0
  26. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/.github/workflows/release-pypi.yml +0 -0
  27. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/.gitignore +0 -0
  28. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/.python-version +0 -0
  29. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/LICENSE +0 -0
  30. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/README.md +0 -0
  31. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/assets/opscloud-banner.gif +0 -0
  32. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/docs/opscloud-docs/Configuration.md +0 -0
  33. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/docs/opscloud-docs/approval-mode.md +0 -0
  34. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/docs/opscloud-docs/cli-reference.md +0 -0
  35. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/docs/opscloud-docs/config.toml.md +0 -0
  36. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/docs/opscloud-docs/credentials.md +0 -0
  37. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/docs/opscloud-docs/goal-and-rubrics.md +0 -0
  38. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/docs/opscloud-docs/hooks.md +0 -0
  39. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/docs/opscloud-docs/mcp-tools.md +0 -0
  40. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/docs/opscloud-docs/memory-and-skills.md +0 -0
  41. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/docs/opscloud-docs/model-providers.md +0 -0
  42. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/docs/opscloud-docs/overview.md +0 -0
  43. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/docs/opscloud-docs/plugins.md +0 -0
  44. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/docs/opscloud-docs/quickstart.md +0 -0
  45. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/docs/opscloud-docs/remote-sandboxes.md +0 -0
  46. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/docs/opscloud-docs/subagents.md +0 -0
  47. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/scripts/install.sh +0 -0
  48. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/__init__.py +0 -0
  49. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/__main__.py +0 -0
  50. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/_constants.py +0 -0
  51. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/_debug.py +0 -0
  52. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/_debug_buffer.py +0 -0
  53. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/_textual_patches.py +0 -0
  54. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/_version.py +0 -0
  55. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/agent/__init__.py +0 -0
  56. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/agent/config.py +0 -0
  57. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/approval_mode.py +0 -0
  58. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/backend/__init__.py +0 -0
  59. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/backend/composite.py +0 -0
  60. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/backend/local.py +0 -0
  61. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/backend/registry.py +0 -0
  62. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/backend/sandbox_config.py +0 -0
  63. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/backend/sandbox_factory.py +0 -0
  64. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/built_in_skills/remember/SKILL.md +0 -0
  65. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/built_in_skills/skill-creator/SKILL.md +0 -0
  66. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/built_in_skills/skill-creator/scripts/init_skill.py +0 -0
  67. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/built_in_skills/skill-creator/scripts/quick_validate.py +0 -0
  68. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/cli/__init__.py +0 -0
  69. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/cli/commands/__init__.py +0 -0
  70. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/cli/commands/auth.py +0 -0
  71. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/cli/commands/doctor.py +0 -0
  72. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/cli/commands/mcp.py +0 -0
  73. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/cli/commands/threads.py +0 -0
  74. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/cli/interactive.py +0 -0
  75. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/cli/main.py +0 -0
  76. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/cli/non_interactive.py +0 -0
  77. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/cli/server_manager.py +0 -0
  78. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/__init__.py +0 -0
  79. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/_base.py +0 -0
  80. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/_guards.py +0 -0
  81. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/_router.py +0 -0
  82. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/_types.py +0 -0
  83. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/__init__.py +0 -0
  84. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/auth.py +0 -0
  85. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/bug.py +0 -0
  86. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/clear.py +0 -0
  87. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/cloud.py +0 -0
  88. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/compact.py +0 -0
  89. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/config_cmd.py +0 -0
  90. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/context.py +0 -0
  91. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/cost.py +0 -0
  92. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/doctor.py +0 -0
  93. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/effort.py +0 -0
  94. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/exit_cmd.py +0 -0
  95. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/fast.py +0 -0
  96. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/help_cmd.py +0 -0
  97. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/mcp.py +0 -0
  98. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/model.py +0 -0
  99. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/permissions.py +0 -0
  100. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/plugins.py +0 -0
  101. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/pool.py +0 -0
  102. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/resume.py +0 -0
  103. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/core/skills.py +0 -0
  104. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/power/__init__.py +0 -0
  105. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/power/agents.py +0 -0
  106. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/power/btw.py +0 -0
  107. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/power/copy.py +0 -0
  108. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/power/goal.py +0 -0
  109. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/power/loop.py +0 -0
  110. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/power/memory.py +0 -0
  111. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/power/review.py +0 -0
  112. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/power/rubric.py +0 -0
  113. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/power/runtime.py +0 -0
  114. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/power/skill_creator.py +0 -0
  115. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/power/skill_invoke.py +0 -0
  116. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/power/tasks.py +0 -0
  117. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/power/trace.py +0 -0
  118. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/power/ui_toggles.py +0 -0
  119. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/power/version.py +0 -0
  120. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/commands/registry.py +0 -0
  121. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/config/__init__.py +0 -0
  122. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/config/adapters/__init__.py +0 -0
  123. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/config/adapters/postgres.py +0 -0
  124. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/config/adapters/sqlite.py +0 -0
  125. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/config/aws.py +0 -0
  126. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/config/cloud_profiles.py +0 -0
  127. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/config/env_vars.py +0 -0
  128. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/config/langsmith.py +0 -0
  129. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/config/manifest.py +0 -0
  130. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/config/metadata.py +0 -0
  131. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/config/paths.py +0 -0
  132. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/config/plugins.py +0 -0
  133. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/config/settings.py +0 -0
  134. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/config/store.py +0 -0
  135. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/config/store_factory.py +0 -0
  136. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/config/toml_config.py +0 -0
  137. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/editor.py +0 -0
  138. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/exceptions.py +0 -0
  139. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/file_ops.py +0 -0
  140. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/hooks/__init__.py +0 -0
  141. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/hooks/env.py +0 -0
  142. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/hooks/interrupt.py +0 -0
  143. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/hooks/models/__init__.py +0 -0
  144. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/hooks/models/adapters.py +0 -0
  145. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/hooks/models/config.py +0 -0
  146. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/hooks/models/domain.py +0 -0
  147. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/hooks/models/transport.py +0 -0
  148. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/hooks/tools.py +0 -0
  149. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/input.py +0 -0
  150. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/integrations/__init__.py +0 -0
  151. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/integrations/base.py +0 -0
  152. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/integrations/content_filter.py +0 -0
  153. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/integrations/event_bus.py +0 -0
  154. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/integrations/hooks.py +0 -0
  155. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/integrations/identity.py +0 -0
  156. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/integrations/notifications.py +0 -0
  157. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/integrations/stream_bridge.py +0 -0
  158. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/integrations/thread_store.py +0 -0
  159. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/json_types.py +0 -0
  160. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/mcp/__init__.py +0 -0
  161. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/mcp/config.py +0 -0
  162. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/mcp/mcp_info.py +0 -0
  163. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/mcp/middleware.py +0 -0
  164. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/mcp/raw_config.py +0 -0
  165. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/mcp/semantic_profiler.py +0 -0
  166. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/mcp/trust.py +0 -0
  167. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/memory/__init__.py +0 -0
  168. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/memory/branch.py +0 -0
  169. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/memory/guard.py +0 -0
  170. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/memory/onboarding.py +0 -0
  171. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/memory/registry.py +0 -0
  172. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/memory/store.py +0 -0
  173. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/__init__.py +0 -0
  174. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/_repository_bounds.py +0 -0
  175. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/ask_user.py +0 -0
  176. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/auto_mode.py +0 -0
  177. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/auto_mode_hitl.py +0 -0
  178. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/compaction.py +0 -0
  179. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/configurable_model.py +0 -0
  180. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/cost_tracking.py +0 -0
  181. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/glm_stall_recovery.py +0 -0
  182. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/goal_criteria.py +0 -0
  183. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/goal_state_notice.py +0 -0
  184. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/goal_tools.py +0 -0
  185. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/headless_mcp_guard.py +0 -0
  186. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/jev_model_router.py +0 -0
  187. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/local_context.py +0 -0
  188. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/mcp_context.py +0 -0
  189. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/mcp_middleware.py +0 -0
  190. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/memory_guard.py +0 -0
  191. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/model_retry.py +0 -0
  192. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/registry.py +0 -0
  193. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/reliable_rubric.py +0 -0
  194. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/resume_state.py +0 -0
  195. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/shell_allow_list.py +0 -0
  196. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/skills.py +0 -0
  197. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/subagent_artifacts.py +0 -0
  198. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/subagent_telemetry.py +0 -0
  199. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/subagents.py +0 -0
  200. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/middleware/unified_system_message.py +0 -0
  201. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/model/__init__.py +0 -0
  202. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/model/config.py +0 -0
  203. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/model/factory.py +0 -0
  204. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/model/pool.py +0 -0
  205. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/model/reasoning.py +0 -0
  206. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/offload.py +0 -0
  207. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/output.py +0 -0
  208. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/plugins/__init__.py +0 -0
  209. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/plugins/_json.py +0 -0
  210. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/plugins/adapters/__init__.py +0 -0
  211. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/plugins/adapters/agents.py +0 -0
  212. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/plugins/adapters/commands.py +0 -0
  213. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/plugins/adapters/skills.py +0 -0
  214. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/plugins/commands_cli.py +0 -0
  215. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/plugins/discovery.py +0 -0
  216. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/plugins/manifest.py +0 -0
  217. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/plugins/marketplace.py +0 -0
  218. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/plugins/project_plugins.py +0 -0
  219. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/plugins/protocol.py +0 -0
  220. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/plugins/store.py +0 -0
  221. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/plugins/substitution.py +0 -0
  222. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/project_utils.py +0 -0
  223. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/prompts/__init__.py +0 -0
  224. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/prompts/system.py +0 -0
  225. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/prompts/templates/system_prompt.md +0 -0
  226. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/prompts/types.py +0 -0
  227. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/rubrics/__init__.py +0 -0
  228. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/rubrics/evaluator.py +0 -0
  229. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/rubrics/evidence_extractor.py +0 -0
  230. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/rubrics/generator.py +0 -0
  231. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/rubrics/jev_compiler.py +0 -0
  232. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/rubrics/jev_grader.py +0 -0
  233. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/rubrics/middleware.py +0 -0
  234. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/schema/__init__.py +0 -0
  235. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/schema/interrupts.py +0 -0
  236. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/security/__init__.py +0 -0
  237. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/security/approval_mode.py +0 -0
  238. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/security/approval_mode_source.py +0 -0
  239. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/security/cli_ast_evaluator.py +0 -0
  240. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/security/jev_classifier.py +0 -0
  241. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/security/shell_safety.py +0 -0
  242. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/security/unicode_security.py +0 -0
  243. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/security/url_validation.py +0 -0
  244. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/server/__init__.py +0 -0
  245. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/server/_server_config.py +0 -0
  246. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/server/server.py +0 -0
  247. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/server/server_graph.py +0 -0
  248. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/skills/__init__.py +0 -0
  249. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/skills/commands.py +0 -0
  250. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/skills/invocation.py +0 -0
  251. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/skills/load.py +0 -0
  252. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/skills/loader.py +0 -0
  253. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/skills/merge.py +0 -0
  254. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/skills/registry.py +0 -0
  255. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/skills/sources.py +0 -0
  256. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/skills/trust.py +0 -0
  257. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/state/__init__.py +0 -0
  258. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/state/base.py +0 -0
  259. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/state/cloud_context.py +0 -0
  260. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/state/goal_channels.py +0 -0
  261. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/state/goal_state_limits.py +0 -0
  262. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/state/resume_state.py +0 -0
  263. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/state/service_context.py +0 -0
  264. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/state/session.py +0 -0
  265. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/state/state_migration.py +0 -0
  266. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/subagents/__init__.py +0 -0
  267. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/subagents/loader.py +0 -0
  268. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/subagents/subagents_parser.py +0 -0
  269. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/subagents/types.py +0 -0
  270. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/tools/__init__.py +0 -0
  271. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/tools/catalog.py +0 -0
  272. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/tools/display.py +0 -0
  273. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/tools/fetch_url.py +0 -0
  274. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/tools/goal_tools.py +0 -0
  275. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/tools/registry.py +0 -0
  276. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/tools/thread.py +0 -0
  277. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/tools/web_search.py +0 -0
  278. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/__init__.py +0 -0
  279. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/app.tcss +0 -0
  280. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/clipboard.py +0 -0
  281. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/command_registry.py +0 -0
  282. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/message_store.py +0 -0
  283. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/permission_store.py +0 -0
  284. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/preferences.py +0 -0
  285. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/prompt_manager.py +0 -0
  286. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/theme.py +0 -0
  287. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/ui_help.py +0 -0
  288. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/__init__.py +0 -0
  289. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/_ask_user_types.py +0 -0
  290. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/_copy_spans.py +0 -0
  291. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/_inline_prompt.py +0 -0
  292. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/_js_eval_display.py +0 -0
  293. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/_links.py +0 -0
  294. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/_tool_stream.py +0 -0
  295. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/agent_selector.py +0 -0
  296. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/approval.py +0 -0
  297. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/ask_user.py +0 -0
  298. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/auth.py +0 -0
  299. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/auth_manager.py +0 -0
  300. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/auto_mode_notice.py +0 -0
  301. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/autocomplete.py +0 -0
  302. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/cloud_selector.py +0 -0
  303. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/config_manager.py +0 -0
  304. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/debug_console.py +0 -0
  305. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/devops_renderers.py +0 -0
  306. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/diff.py +0 -0
  307. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/effort_selector.py +0 -0
  308. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/goal_review.py +0 -0
  309. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/goal_status.py +0 -0
  310. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/infra_panel.py +0 -0
  311. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/install_confirm.py +0 -0
  312. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/loading.py +0 -0
  313. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/mcp_viewer.py +0 -0
  314. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/model_selector.py +0 -0
  315. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/notification_center.py +0 -0
  316. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/notification_settings.py +0 -0
  317. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/operation_card.py +0 -0
  318. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/permissions_manager.py +0 -0
  319. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/plugin_manager.py +0 -0
  320. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/pool_selector.py +0 -0
  321. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/preamble.py +0 -0
  322. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/skills_viewer.py +0 -0
  323. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/status.py +0 -0
  324. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/subagent_panel.py +0 -0
  325. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/theme_selector.py +0 -0
  326. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/thread_selector.py +0 -0
  327. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/toast.py +0 -0
  328. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/tool_display.py +0 -0
  329. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/tool_renderers.py +0 -0
  330. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/tool_widgets.py +0 -0
  331. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/welcome.py +0 -0
  332. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/ui/widgets/welcome_popup.py +0 -0
  333. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/utils/__init__.py +0 -0
  334. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/utils/cost_estimation.py +0 -0
  335. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/utils/git.py +0 -0
  336. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/utils/logger.py +0 -0
  337. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/utils/session_stats.py +0 -0
  338. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/src/opscloud/utils/startup_error.py +0 -0
  339. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/__init__.py +0 -0
  340. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/conftest.py +0 -0
  341. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/evals/__init__.py +0 -0
  342. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/evals/datasets/aws_cloud_ops.yaml +0 -0
  343. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/evals/evaluators/__init__.py +0 -0
  344. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/evals/evaluators/output_evaluator.py +0 -0
  345. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/evals/evaluators/trajectory_evaluator.py +0 -0
  346. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/evals/runners/test_eval_runner.py +0 -0
  347. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/integration_tests/test_agent_lifecycle.py +0 -0
  348. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/integration_tests/test_server_lifecycle.py +0 -0
  349. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_agent_factory.py +0 -0
  350. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_approval_widget.py +0 -0
  351. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_ask_user.py +0 -0
  352. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_ast_evaluator.py +0 -0
  353. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_backend.py +0 -0
  354. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_chat_input_responsiveness.py +0 -0
  355. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_checkpointer.py +0 -0
  356. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_claude_opus_reasoning.py +0 -0
  357. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_cli_enhancements.py +0 -0
  358. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_cli_rubric.py +0 -0
  359. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_cloud_command.py +0 -0
  360. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_commands.py +0 -0
  361. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_config.py +0 -0
  362. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_cost_tracking.py +0 -0
  363. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_default_marketplace.py +0 -0
  364. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_goal_criteria.py +0 -0
  365. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_goal_state_limits.py +0 -0
  366. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_goal_state_notice.py +0 -0
  367. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_grader_tools.py +0 -0
  368. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_hitl.py +0 -0
  369. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_integrations_and_hooks.py +0 -0
  370. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_interrupt_schemas.py +0 -0
  371. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_jev_model_router.py +0 -0
  372. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_jev_rubrics.py +0 -0
  373. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_local_context.py +0 -0
  374. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_logging.py +0 -0
  375. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_mcp_middleware.py +0 -0
  376. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_mcp_viewer_and_command.py +0 -0
  377. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_memory.py +0 -0
  378. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_memory_enhancements.py +0 -0
  379. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_middleware_stack.py +0 -0
  380. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_model_providers.py +0 -0
  381. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_model_retry.py +0 -0
  382. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_plugin_manager_search.py +0 -0
  383. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_plugins.py +0 -0
  384. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_pool_persistence.py +0 -0
  385. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_project_plugins.py +0 -0
  386. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_prompts_and_schema.py +0 -0
  387. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_reliable_rubric.py +0 -0
  388. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_reload_restart.py +0 -0
  389. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_resume_state.py +0 -0
  390. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_resumed_thread_latency_fix.py +0 -0
  391. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_rubrics.py +0 -0
  392. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_security.py +0 -0
  393. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_server.py +0 -0
  394. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_server_hooks.py +0 -0
  395. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_skill_creator.py +0 -0
  396. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_skills.py +0 -0
  397. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_state.py +0 -0
  398. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_subagents.py +0 -0
  399. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_tools.py +0 -0
  400. {talkops_opscloud-0.3.0b7 → talkops_opscloud-0.3.0b9}/tests/unit_tests/test_utils.py +0 -0
  401. {talkops_opscloud-0.3.0b7 → 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.0b7
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.0b7"
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"
@@ -415,9 +415,9 @@ def _subagent_cli_middleware(
415
415
 
416
416
  server_keys: list[str] = []
417
417
  if mcp_config:
418
- server_keys.extend(mcp_config.keys())
418
+ server_keys.extend(str(k) for k in mcp_config.keys())
419
419
  if mcp_server_info:
420
- server_keys.extend(getattr(s, "name", str(s)) for s in mcp_server_info)
420
+ server_keys.extend(str(getattr(s, "name", s)) for s in mcp_server_info)
421
421
 
422
422
  if allowed_tools or capabilities:
423
423
  middleware.append(
@@ -603,13 +603,16 @@ def create_opscloud_agent(
603
603
 
604
604
  # 5. MCP Discovery
605
605
  mcp_tools_list: list[BaseTool] = []
606
- cached_infos: list[Any] | None = None
607
- mcp_configs: dict[str, Any] | None = None
606
+ cached_infos: list[Any] | None = kwargs.get("mcp_server_info")
607
+ mcp_configs: dict[str, Any] | None = kwargs.get("mcp_config")
608
608
  if mcp_tools is not None:
609
609
  mcp_tools_list = list(mcp_tools)
610
610
  all_tools.extend(mcp_tools)
611
+ if mcp_configs is None:
612
+ mcp_configs = discover_mcp_configs(project_scope_root)
611
613
  else:
612
- mcp_configs = discover_mcp_configs(project_scope_root)
614
+ if mcp_configs is None:
615
+ mcp_configs = discover_mcp_configs(project_scope_root)
613
616
  from opscloud.mcp.preload import (
614
617
  get_cached_mcp_server_infos,
615
618
  preload_mcp_metadata,
@@ -707,6 +710,7 @@ def create_opscloud_agent(
707
710
  from deepagents.middleware.subagents import GENERAL_PURPOSE_SUBAGENT, SubAgent
708
711
 
709
712
  compiled_subagents: list[SubAgent] = []
713
+ base_subagent_tools = [t for t in all_tools if t not in mcp_tools_list]
710
714
  for name, subagent_meta in subagent_by_name.items():
711
715
  model_spec = subagent_meta.get("model")
712
716
  has_explicit_model = bool(model_spec)
@@ -723,6 +727,18 @@ def create_opscloud_agent(
723
727
  subagent_path = subagent_meta.get("path")
724
728
  custom_mw = subagent_meta.get("middleware")
725
729
 
730
+ # Build per-subagent MCP config and tools for this subagent
731
+ from opscloud.plugins.adapters.mcp import prepare_subagent_mcp
732
+
733
+ servers, subagent_mcp_tools, sub_mcp_server_infos = prepare_subagent_mcp(
734
+ subagent_name, subagent_meta, project_scope_root
735
+ )
736
+
737
+ if subagent_mcp_tools:
738
+ subagent_dict["tools"] = [*base_subagent_tools, *subagent_mcp_tools]
739
+ else:
740
+ subagent_dict["tools"] = list(base_subagent_tools)
741
+
726
742
  sub_middleware = _subagent_cli_middleware(
727
743
  has_explicit_model=has_explicit_model,
728
744
  assistant_id=assistant_id,
@@ -738,6 +754,9 @@ def create_opscloud_agent(
738
754
  worktree_root=effective_cwd,
739
755
  subagent_path=subagent_path if subagent_path else None,
740
756
  custom_middleware=custom_mw if isinstance(custom_mw, list) else None,
757
+ mcp_server_info=sub_mcp_server_infos or None,
758
+ mcp_config=servers or None,
759
+ mcp_tools=subagent_mcp_tools or None,
741
760
  backend=composite_backend,
742
761
  model=active_model,
743
762
  )
@@ -748,9 +767,10 @@ def create_opscloud_agent(
748
767
 
749
768
  compiled_subagents.append(cast(SubAgent, subagent_dict))
750
769
  logger.info(
751
- "Registered declarative subagent '%s'",
770
+ "Compiled subagent '%s' (tools: %d)",
752
771
  subagent_name,
753
- extra={"subagent": subagent_name},
772
+ len(subagent_dict.get("tools", [])),
773
+ extra={"subagent": subagent_name, "tools_count": len(subagent_dict.get("tools", []))},
754
774
  )
755
775
 
756
776
  if not any(sub.get("name") == GENERAL_PURPOSE_SUBAGENT["name"] for sub in compiled_subagents):
@@ -773,6 +793,7 @@ def create_opscloud_agent(
773
793
  "name": gp_name,
774
794
  "description": gp_description,
775
795
  "system_prompt": gp_system_prompt,
796
+ "tools": list(base_subagent_tools),
776
797
  "middleware": gp_middleware,
777
798
  }
778
799
  if interrupt_on is not None:
@@ -832,12 +853,22 @@ def create_opscloud_agent(
832
853
  agent_middleware.append(AskUserMiddleware())
833
854
 
834
855
  # 10.5 MCP tool arguments and error handling
835
- if mcp_tools_list:
836
- if cached_infos or mcp_configs:
856
+ if mcp_tools_list or cached_infos or mcp_configs:
857
+ mcp_cfg_for_mw = mcp_configs
858
+ if not mcp_cfg_for_mw and not cached_infos and mcp_tools_list:
859
+ synth_cfg: dict[str, Any] = {}
860
+ for t in mcp_tools_list:
861
+ srv = getattr(t, "metadata", {}).get("_mcp_server") if isinstance(getattr(t, "metadata", None), dict) else None
862
+ if srv and srv not in synth_cfg:
863
+ synth_cfg[srv] = {"command": "custom", "args": []}
864
+ if synth_cfg:
865
+ mcp_cfg_for_mw = synth_cfg
866
+
867
+ if cached_infos or mcp_cfg_for_mw:
837
868
  from opscloud.middleware.mcp_context import MCPContextMiddleware
838
869
 
839
870
  agent_middleware.append(
840
- MCPContextMiddleware(mcp_server_info=cached_infos, mcp_config=mcp_configs)
871
+ MCPContextMiddleware(mcp_server_info=cached_infos, mcp_config=mcp_cfg_for_mw)
841
872
  )
842
873
  agent_middleware.append(MCPToolMiddleware())
843
874
 
@@ -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(
@@ -919,7 +919,7 @@ def _mcp_server_from_tool(tool: object | None) -> str | None:
919
919
  metadata = getattr(tool, "metadata", None)
920
920
  if not isinstance(metadata, Mapping):
921
921
  return None
922
- for key in ("mcp_server", "mcp_server_name", "server_name"):
922
+ for key in ("_mcp_server", "mcp_server", "mcp_server_name", "server_name"):
923
923
  value = metadata.get(key)
924
924
  if isinstance(value, str) and value:
925
925
  return value