Core changes: - Add @defgroup/@ingroup to 1791 C2+ contracts (555 files) for HCA 128× pre-training DSA grouping - Add §0.1 Pre-Training Frequency matrix to semantics-core - Add §VIII Attention Architecture rules (ATTN_1-4) with MLA/CSA/HCA/DSA mechanics - Add @defgroup/@ingroup to canonical syntax (§II) and all contract examples Agent prompts (5 files): - Add ZERO-STATE RATIONALE with MLA/CSA/HCA/DSA compression mechanics - Add pre-training note: @RATIONALE/@REJECTED are in-context learned tags - svelte-coder: add missing #region contract, fix Svelte rule violations - python-coder/fullstack-coder: honor function contracts from speckit plan - qa-tester: add attention compliance audit (P3 ATTN_1-4 checks) Skills (6 files): - Translate all axiom_config descriptions to English - Fix doc_dirs to index .opencode/ and .specify/ - Deduplicate 5× complexity_rules → single global_tags catalog - Reduce semantics-svelte 591→485 lines (remove duplicate code blocks) - Fix semantics-testing: 'Short IDs' → 'Short hierarchical IDs' - Fix all examples: flat IDs → hierarchical Domain.Name format - Fix Svelte examples: replace raw Tailwind + <button> with semantic tokens + /ui Speckit workflow (commands + templates): - speckit.plan: add Function-Level Contracts for C3+ with @PRE/@POST/@TEST_EDGE - speckit.plan: add Attention Compliance Gate (ATTN_1-4 before contract generation) - speckit.tasks: add function contract inlining format (constraints in task description) - speckit.specify: load semantics-core for spec density rules - spec-template: add #region contract, @SEMANTICS grouping, hierarchical IDs - ux-reference-template: add #region wrapper - plan-template: add attention gate, @defgroup/@ingroup guidance - tasks-template: add attention audit + rebuild + orphan check tasks - constitution.md: translate to English, add Principle VIII (attention-optimized contracts) Reference modules rewritten (hierarchical IDs + full contracts): - Auth.Jwt: 6 child contracts with @RATIONALE/@REJECTED/@TEST_EDGE - Api.Auth: 5 endpoints with @TEST_EDGE + molecular CoT markers - Migration.Model: @defgroup Migration with 18 @ACTION + 6 @INVARIANT Scripts: - add_defgroup_ingroup.py: zero-risk additive @ingroup migration (1791 insertions) - migrate_hierarchical.py: flat→hierarchical ID dry-run analysis (792 contracts) - merge_prompts.py: merge all prompts/skills/commands into one review file Config: - axiom_config.yaml: 749→395 lines (-47%), English, doc_dirs include prompts - Fix test_datasets.py import collision (rename → test_datasets_routes.py) - Fix test_preview.py: SupersetClient→get_superset_client, AsyncMock, logger f-string
123 lines
4.2 KiB
Python
123 lines
4.2 KiB
Python
# #region AssistantToolSearchDashboards [C:3] [TYPE Module] [SEMANTICS assistant, tool, dashboards, search]
|
||
# @defgroup AssistantApi Module group.
|
||
# @BRIEF Handler for the "search_dashboards" tool — search and list dashboards from an environment.
|
||
# @LAYER API
|
||
# @RELATION DEPENDS_ON -> [AssistantToolRegistry]
|
||
# @RELATION DEPENDS_ON -> [SupersetClient]
|
||
|
||
from __future__ import annotations
|
||
|
||
from typing import Any
|
||
|
||
from sqlalchemy.orm import Session
|
||
|
||
from src.core.config_manager import ConfigManager
|
||
from src.core.logger import belief_scope, logger
|
||
from src.core.superset_client import SupersetClient
|
||
from src.core.task_manager import TaskManager
|
||
from src.schemas.auth import User
|
||
|
||
from ._resolvers import _resolve_env_id
|
||
from ._schemas import AssistantAction
|
||
from ._tool_registry import assistant_tool
|
||
|
||
|
||
# #region handle_search_dashboards [C:3] [TYPE Function]
|
||
# @ingroup AssistantApi
|
||
@assistant_tool(
|
||
operation="search_dashboards",
|
||
domain="dashboards",
|
||
description="Search and list dashboards by name/id from an environment. Shows id, title, and URL for each dashboard.",
|
||
optional_entities=["environment", "search", "page", "page_size"],
|
||
risk_level="safe",
|
||
requires_confirmation=False,
|
||
)
|
||
@belief_scope("search_dashboards")
|
||
async def handle_search_dashboards(
|
||
intent: dict[str, Any],
|
||
current_user: User,
|
||
task_manager: TaskManager,
|
||
config_manager: ConfigManager,
|
||
db: Session,
|
||
) -> tuple[str, str | None, list[AssistantAction]]:
|
||
"""Search and list dashboards from an environment."""
|
||
entities = intent.get("entities", {})
|
||
env_token = entities.get("environment")
|
||
search = entities.get("search")
|
||
page = int(entities.get("page", 1))
|
||
page_size = min(int(entities.get("page_size", 20)), 100)
|
||
|
||
env_id = _resolve_env_id(env_token, config_manager)
|
||
|
||
if not env_id:
|
||
# Show available environments if none specified
|
||
envs = config_manager.get_environments()
|
||
if not envs:
|
||
return ("Нет доступных окружений.", None, [])
|
||
env_list = "\n".join(f"- {e.id} ({e.name})" for e in envs)
|
||
return (
|
||
f"Укажите окружение. Доступные:\n{env_list}\n\n"
|
||
f"Пример: `покажи дашборды из окружения dev`",
|
||
None,
|
||
[],
|
||
)
|
||
|
||
env_map = {e.id: e for e in config_manager.get_environments()}
|
||
env = env_map.get(env_id)
|
||
if not env:
|
||
return (f"Окружение {env_id} не найдено.", None, [])
|
||
|
||
client = SupersetClient(env)
|
||
all_dashboards = await client.get_dashboards_summary(require_slug=True)
|
||
|
||
# Filter by search term
|
||
if search:
|
||
search_lower = search.lower()
|
||
filtered = [
|
||
d
|
||
for d in all_dashboards
|
||
if search_lower in str(d.get("id", ""))
|
||
or search_lower in str(d.get("title", "")).lower()
|
||
or search_lower in str(d.get("slug", "")).lower()
|
||
]
|
||
else:
|
||
filtered = list(all_dashboards)
|
||
|
||
total = len(filtered)
|
||
start = (page - 1) * page_size
|
||
page_items = filtered[start : start + page_size]
|
||
|
||
if not page_items:
|
||
if search:
|
||
return (
|
||
f"Дашборды по запросу «{search}» в окружении {env.name} не найдены.",
|
||
None,
|
||
[],
|
||
)
|
||
return (f"В окружении {env.name} нет дашбордов.", None, [])
|
||
|
||
lines = [f"📊 Дашборды в окружении **{env.name}** ({total} всего):"]
|
||
for d in page_items:
|
||
title = d.get("title", "Без названия")
|
||
did = d.get("id", "?")
|
||
slug = d.get("slug", "")
|
||
slug_str = f" ({slug})" if slug else ""
|
||
lines.append(f"- #{did} {title}{slug_str}")
|
||
|
||
if start + page_size < total:
|
||
lines.append(f"\n... и ещё {total - start - page_size}")
|
||
|
||
actions = [
|
||
AssistantAction(
|
||
type="open_route",
|
||
label=f"Открыть дашборды в {env.name}",
|
||
target=f"/dashboards?env_id={env_id}",
|
||
)
|
||
]
|
||
|
||
return ("\n".join(lines), None, actions)
|
||
|
||
|
||
# #endregion handle_search_dashboards
|
||
# #endregion AssistantToolSearchDashboards
|