ha-mcp-dev 7.4.1.dev445__tar.gz → 7.4.1.dev446__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.
- {ha_mcp_dev-7.4.1.dev445/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.4.1.dev446}/PKG-INFO +2 -1
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/pyproject.toml +4 -1
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/config.py +31 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/errors.py +8 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/server.py +13 -1
- ha_mcp_dev-7.4.1.dev446/src/ha_mcp/tools/tools_code.py +1293 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/transforms/categorized_search.py +25 -2
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446/src/ha_mcp_dev.egg-info}/PKG-INFO +2 -1
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp_dev.egg-info/SOURCES.txt +1 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp_dev.egg-info/requires.txt +1 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/LICENSE +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/MANIFEST.in +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/README.md +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/setup.cfg +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/__init__.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/__main__.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/_pypi_marker +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/_version.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/auth/__init__.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/auth/consent_form.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/auth/provider.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/client/__init__.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/client/rest_client.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/client/websocket_client.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/client/websocket_listener.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/py.typed +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/settings_ui.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/smoke_test.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/__init__.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/backup.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/best_practice_checker.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/device_control.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/enhanced.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/helpers.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/reference_validator.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/registry.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/smart_search.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_addons.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_areas.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_blueprints.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_bug_report.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_calendar.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_camera.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_categories.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_config_automations.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_config_entry_flow.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_energy.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_entities.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_filesystem.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_groups.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_hacs.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_history.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_integrations.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_labels.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_mcp_component.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_registry.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_resources.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_search.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_service.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_services.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_system.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_todo.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_traces.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_updates.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_utility.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/tools_zones.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/tools/util_helpers.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/transforms/__init__.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/utils/__init__.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/utils/config_hash.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/utils/data_paths.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/utils/domain_handlers.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/utils/fuzzy_search.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/utils/operation_manager.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/utils/python_sandbox.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp/utils/usage_logger.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/tests/__init__.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/tests/test_constants.py +0 -0
- {ha_mcp_dev-7.4.1.dev445 → ha_mcp_dev-7.4.1.dev446}/tests/test_env_manager.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ha-mcp-dev
|
|
3
|
-
Version: 7.4.1.
|
|
3
|
+
Version: 7.4.1.dev446
|
|
4
4
|
Summary: Home Assistant MCP Server - Complete control of Home Assistant through MCP
|
|
5
5
|
Author-email: Julien <github@qc-h.net>
|
|
6
6
|
License: MIT
|
|
@@ -25,6 +25,7 @@ Requires-Dist: python-dotenv==1.2.2
|
|
|
25
25
|
Requires-Dist: truststore==0.10.4
|
|
26
26
|
Requires-Dist: websockets==16.0
|
|
27
27
|
Requires-Dist: cryptography==47.0.0
|
|
28
|
+
Requires-Dist: pydantic-monty==0.0.9
|
|
28
29
|
Dynamic: license-file
|
|
29
30
|
|
|
30
31
|
> **Breaking change (v7.3.0):** `ha_config_set_yaml` has been moved to [beta](docs/beta.md).
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ha-mcp-dev"
|
|
7
|
-
version = "7.4.1.
|
|
7
|
+
version = "7.4.1.dev446"
|
|
8
8
|
description = "Home Assistant MCP Server - Complete control of Home Assistant through MCP"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.13,<3.14"
|
|
@@ -31,6 +31,7 @@ dependencies = [
|
|
|
31
31
|
"truststore==0.10.4",
|
|
32
32
|
"websockets==16.0",
|
|
33
33
|
"cryptography==47.0.0",
|
|
34
|
+
"pydantic-monty==0.0.9",
|
|
34
35
|
]
|
|
35
36
|
|
|
36
37
|
[project.urls]
|
|
@@ -76,6 +77,8 @@ explicit_package_bases = true
|
|
|
76
77
|
module = [
|
|
77
78
|
"fastmcp.*",
|
|
78
79
|
"jq",
|
|
80
|
+
"pydantic_monty",
|
|
81
|
+
"pydantic_monty.*",
|
|
79
82
|
]
|
|
80
83
|
ignore_missing_imports = true
|
|
81
84
|
|
|
@@ -113,6 +113,37 @@ class Settings(BaseSettings):
|
|
|
113
113
|
# supervisor UI rejects out-of-range values before they reach env vars.
|
|
114
114
|
tool_search_max_results: int = Field(5, ge=2, le=10, alias="TOOL_SEARCH_MAX_RESULTS")
|
|
115
115
|
|
|
116
|
+
# Code Mode — sandboxed Python execution via pydantic-monty.
|
|
117
|
+
# Provides an "escape hatch" tool (ha_manage_custom_tool) that lets LLMs write
|
|
118
|
+
# custom one-off Python code when no existing tool covers the request.
|
|
119
|
+
# Disabled by default due to the inherent risk of LLM-generated code.
|
|
120
|
+
# Range bounds reject zero/negative values that would silently break the
|
|
121
|
+
# tool and clamp upper bounds at sane safety margins (5 min wall-clock,
|
|
122
|
+
# 256 MB memory, 10k recursion, 10k API/tool calls per execution).
|
|
123
|
+
enable_code_mode: bool = Field(False, alias="ENABLE_CODE_MODE")
|
|
124
|
+
code_mode_max_duration: float = Field(
|
|
125
|
+
30.0, ge=1.0, le=300.0, alias="CODE_MODE_MAX_DURATION"
|
|
126
|
+
)
|
|
127
|
+
code_mode_max_memory: int = Field(
|
|
128
|
+
10_485_760, ge=1_048_576, le=268_435_456, alias="CODE_MODE_MAX_MEMORY"
|
|
129
|
+
) # 10 MB default; 1 MB floor, 256 MB ceiling
|
|
130
|
+
code_mode_max_recursion: int = Field(
|
|
131
|
+
100, ge=1, le=10_000, alias="CODE_MODE_MAX_RECURSION"
|
|
132
|
+
)
|
|
133
|
+
code_mode_max_invocations: int = Field(
|
|
134
|
+
100, ge=1, le=10_000, alias="CODE_MODE_MAX_INVOCATIONS"
|
|
135
|
+
)
|
|
136
|
+
# Path to a JSON file for persisting saved custom tools across restarts.
|
|
137
|
+
# Empty string disables persistence (saved tools live in process memory
|
|
138
|
+
# and are lost on restart). The addon sets this to /data/saved_tools.json
|
|
139
|
+
# by default so saved tools survive addon restarts (the /data directory
|
|
140
|
+
# is mapped per-addon by Supervisor and is preserved across addon
|
|
141
|
+
# updates).
|
|
142
|
+
code_mode_saved_tools_path: str = Field(
|
|
143
|
+
"", alias="CODE_MODE_SAVED_TOOLS_PATH"
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
|
|
116
147
|
@property
|
|
117
148
|
def env_file_name(self) -> str:
|
|
118
149
|
"""Get the current environment file name."""
|
|
@@ -81,6 +81,14 @@ class ErrorCode(StrEnum):
|
|
|
81
81
|
# Component errors
|
|
82
82
|
COMPONENT_NOT_INSTALLED = "COMPONENT_NOT_INSTALLED"
|
|
83
83
|
|
|
84
|
+
# Code-mode sandbox errors. The sandbox is a separate execution
|
|
85
|
+
# context; runtime failures inside it map cleanly to one of these
|
|
86
|
+
# three buckets so the LLM can self-recover instead of seeing every
|
|
87
|
+
# failure as INTERNAL_ERROR.
|
|
88
|
+
SANDBOX_LIMIT_EXCEEDED = "SANDBOX_LIMIT_EXCEEDED"
|
|
89
|
+
SANDBOX_SYNTAX_UNSUPPORTED = "SANDBOX_SYNTAX_UNSUPPORTED"
|
|
90
|
+
SANDBOX_RUNTIME_ERROR = "SANDBOX_RUNTIME_ERROR"
|
|
91
|
+
|
|
84
92
|
|
|
85
93
|
# Default suggestions for common error codes
|
|
86
94
|
DEFAULT_SUGGESTIONS: dict[ErrorCode, list[str]] = {
|
|
@@ -590,6 +590,11 @@ class HomeAssistantSmartMCPServer(EnhancedToolsMixin):
|
|
|
590
590
|
)
|
|
591
591
|
pinned.extend(getattr(self, "_skill_tool_names", []))
|
|
592
592
|
|
|
593
|
+
# Pin code mode tool so it gets individual permission gating
|
|
594
|
+
# rather than being hidden behind the BM25 search proxy.
|
|
595
|
+
if self.settings.enable_code_mode:
|
|
596
|
+
pinned.append("ha_manage_custom_tool")
|
|
597
|
+
|
|
593
598
|
# The client may not support resources or server instructions — add
|
|
594
599
|
# skills hint to the search tool description (the one place the LLM
|
|
595
600
|
# is guaranteed to see).
|
|
@@ -609,12 +614,19 @@ class HomeAssistantSmartMCPServer(EnhancedToolsMixin):
|
|
|
609
614
|
max_results=self.settings.tool_search_max_results,
|
|
610
615
|
always_visible=pinned,
|
|
611
616
|
search_tool_description=description,
|
|
617
|
+
# Pinned tools must be excluded from the proxy's
|
|
618
|
+
# category sets when code mode is on; otherwise sandbox
|
|
619
|
+
# code can launder a recursive ``ha_manage_custom_tool``
|
|
620
|
+
# invocation through ``ha_call_write_tool``. See the
|
|
621
|
+
# docstring on ``_rebuild_category_cache``.
|
|
622
|
+
enable_code_mode=self.settings.enable_code_mode,
|
|
612
623
|
)
|
|
613
624
|
)
|
|
614
625
|
logger.info(
|
|
615
|
-
"Tool search transform applied (%d pinned tools, max_results=%d)",
|
|
626
|
+
"Tool search transform applied (%d pinned tools, max_results=%d, code_mode=%s)",
|
|
616
627
|
len(pinned),
|
|
617
628
|
self.settings.tool_search_max_results,
|
|
629
|
+
self.settings.enable_code_mode,
|
|
618
630
|
)
|
|
619
631
|
except Exception:
|
|
620
632
|
logger.exception("Failed to apply tool search transform")
|