feat: docs and ui tweaks

This commit is contained in:
DESKTOP-RTLN3BA\$punk 2026-07-06 19:26:35 -07:00
parent 64f2b4a6eb
commit 271a21aee6
103 changed files with 2161 additions and 2625 deletions

View file

@ -25,6 +25,7 @@ from app.agents.chat.multi_agent_chat.shared.permissions.middleware.core import
PermissionMiddleware,
)
from app.agents.chat.multi_agent_chat.subagents.shared.subagent_builder import (
append_today_utc,
pack_subagent,
)
@ -104,6 +105,35 @@ async def test_subagent_recovers_when_primary_llm_fails():
assert final.content == "recovered via fallback"
def test_packed_subagent_prompt_carries_todays_utc_date():
"""Subagents must inherit the main agent's clock, not guess the date."""
from datetime import UTC, datetime
today = datetime.now(UTC).date().isoformat()
result = pack_subagent(
name="date_test",
description="test",
system_prompt="be helpful",
tools=[],
ruleset=Ruleset(origin="date_test", rules=[]),
dependencies={"flags": AgentFeatureFlags()},
)
prompt = result.spec["system_prompt"]
assert prompt.startswith("be helpful")
assert f"Today (UTC): {today}" in prompt
def test_append_today_utc_is_idempotent_shape():
"""Helper appends exactly one dated line and preserves the original body."""
from datetime import UTC, datetime
today = datetime.now(UTC).date().isoformat()
out = append_today_utc("body")
assert out == f"body\n\nToday (UTC): {today}\n"
def _extract_permission_mw(spec) -> PermissionMiddleware:
"""Find the lone PermissionMiddleware in a subagent's middleware list."""
matches = [m for m in spec["middleware"] if isinstance(m, PermissionMiddleware)]

View file

@ -0,0 +1,52 @@
"""Allowlist filtering in ``_load_http_mcp_tools``.
Covers the fallback added after Notion renamed its MCP tools ("notion-"
prefix) and a stale allowlist silently disabled the connector: when the
allowlist matches zero advertised tools, load everything (HITL-gated)
instead of nothing.
"""
from datetime import UTC, datetime
from app.agents.chat.multi_agent_chat.shared.tools.mcp.cache import (
CachedMCPTools,
)
from app.agents.chat.multi_agent_chat.shared.tools.mcp.tool import (
_load_http_mcp_tools,
)
_CACHED = CachedMCPTools(
discovered_at=datetime.now(UTC),
tools=[
{"name": "notion-search", "description": "search", "input_schema": {}},
{"name": "notion-update-page", "description": "write", "input_schema": {}},
],
)
_SERVER_CONFIG = {"url": "https://example.com/mcp", "headers": {}}
async def test_allowlist_match_filters_and_flags_readonly():
tools = await _load_http_mcp_tools(
1,
"Notion",
_SERVER_CONFIG,
allowed_tools=["notion-search"],
readonly_tools=frozenset({"notion-search"}),
cached_tools=_CACHED,
)
assert [t.name for t in tools] == ["notion-search"]
assert tools[0].metadata["hitl"] is False
async def test_stale_allowlist_falls_back_to_all_tools_hitl_gated():
tools = await _load_http_mcp_tools(
1,
"Notion",
_SERVER_CONFIG,
allowed_tools=["search", "update-page"], # server renamed everything
readonly_tools=frozenset({"search"}),
cached_tools=_CACHED,
)
assert sorted(t.name for t in tools) == ["notion-search", "notion-update-page"]
# Renamed tools match no readonly entry -> every tool requires approval.
assert all(t.metadata["hitl"] is True for t in tools)

View file

@ -123,6 +123,41 @@ async def test_capabilities_endpoint_lists_verbs_with_input_schema(monkeypatch):
assert "properties" in entry["output_schema"]
@pytest.mark.asyncio
async def test_capabilities_endpoint_exposes_live_pricing(monkeypatch):
"""Billed verbs report their per-item rate; free verbs report an empty list."""
from app.capabilities.core.types import BillingUnit
from app.config import config
monkeypatch.setattr(config, "PLATFORM_SCRAPE_BILLING_ENABLED", True)
monkeypatch.setattr(config, "YOUTUBE_MICROS_PER_VIDEO", 2500)
billed = Capability(
name="test.billed",
description="Billed verb for tests.",
input_schema=_EchoInput,
output_schema=_EchoOutput,
executor=_echo_executor,
billing_unit=BillingUnit.YOUTUBE_VIDEO,
)
app = _build_app([_ECHO, billed], monkeypatch)
async with _client(app) as client:
resp = await client.get("/api/v1/workspaces/7/scrapers/capabilities")
assert resp.status_code == 200
by_name = {entry["name"]: entry for entry in resp.json()}
assert by_name["test.echo"]["pricing"] == []
assert by_name["test.billed"]["pricing"] == [
{"unit": "video", "micros_per_unit": 2500}
]
# Rates are read live: a config retune shows up without a router rebuild.
monkeypatch.setattr(config, "PLATFORM_SCRAPE_BILLING_ENABLED", False)
async with _client(app) as client:
resp = await client.get("/api/v1/workspaces/7/scrapers/capabilities")
assert resp.json()[1]["pricing"] == []
@pytest.mark.asyncio
async def test_over_budget_is_blocked_before_the_executor(monkeypatch):
from app.capabilities.core.access import rest

View file

@ -344,6 +344,9 @@ def test_validate_connector_config_invalid():
"SEARXNG_API",
"LINKUP_API",
"BAIDU_SEARCH_API",
"YOUTUBE_CONNECTOR",
"WEBCRAWLER_CONNECTOR",
"ELASTICSEARCH_CONNECTOR",
],
)
def test_raise_if_connector_deprecated_blocks(connector_type):