mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-08-31 00:03:01 +03:00
refactor: remove remaining dead code
This commit is contained in:
@@ -145,14 +145,9 @@ class _FakeChannel:
|
|||||||
class _FakeInteractionResponse:
|
class _FakeInteractionResponse:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.messages: list[dict] = []
|
self.messages: list[dict] = []
|
||||||
self._done = False
|
|
||||||
|
|
||||||
async def send_message(self, content: str, *, ephemeral: bool = False) -> None:
|
async def send_message(self, content: str, *, ephemeral: bool = False) -> None:
|
||||||
self.messages.append({"content": content, "ephemeral": ephemeral})
|
self.messages.append({"content": content, "ephemeral": ephemeral})
|
||||||
self._done = True
|
|
||||||
|
|
||||||
def is_done(self) -> bool:
|
|
||||||
return self._done
|
|
||||||
|
|
||||||
|
|
||||||
def _make_interaction(
|
def _make_interaction(
|
||||||
|
|||||||
@@ -53,7 +53,6 @@ class MattermostConfig(Base):
|
|||||||
include_thread_context: bool = True
|
include_thread_context: bool = True
|
||||||
thread_context_limit: int = 20
|
thread_context_limit: int = 20
|
||||||
streaming: bool = True
|
streaming: bool = True
|
||||||
streaming_max_chars: int = 16000
|
|
||||||
react_emoji: str = "eyes"
|
react_emoji: str = "eyes"
|
||||||
done_emoji: str = "white_check_mark"
|
done_emoji: str = "white_check_mark"
|
||||||
send_progress: bool = True
|
send_progress: bool = True
|
||||||
@@ -106,7 +105,6 @@ class MattermostChannel(BaseChannel):
|
|||||||
self._ws_task: asyncio.Task[None] | None = None
|
self._ws_task: asyncio.Task[None] | None = None
|
||||||
self._self_id: str | None = None
|
self._self_id: str | None = None
|
||||||
self._self_username: str | None = None
|
self._self_username: str | None = None
|
||||||
self._self_email: str | None = None
|
|
||||||
self._usernames: dict[str, str] = {}
|
self._usernames: dict[str, str] = {}
|
||||||
self._user_emails: dict[str, str] = {}
|
self._user_emails: dict[str, str] = {}
|
||||||
self._channel_types: dict[str, str] = {}
|
self._channel_types: dict[str, str] = {}
|
||||||
@@ -138,7 +136,6 @@ class MattermostChannel(BaseChannel):
|
|||||||
me = cast(dict[str, Any], resp.json())
|
me = cast(dict[str, Any], resp.json())
|
||||||
self._self_id = me.get("id")
|
self._self_id = me.get("id")
|
||||||
self._self_username = me.get("username")
|
self._self_username = me.get("username")
|
||||||
self._self_email = me.get("email", "")
|
|
||||||
self.logger.info("bot @{} connected", self._self_username)
|
self.logger.info("bot @{} connected", self._self_username)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error("Failed to identify bot user: {}", e)
|
self.logger.error("Failed to identify bot user: {}", e)
|
||||||
|
|||||||
@@ -31,8 +31,6 @@ class _FakeHTTPClient:
|
|||||||
self.delete_calls: list[dict[str, Any]] = []
|
self.delete_calls: list[dict[str, Any]] = []
|
||||||
self._get_responses: dict[str, Any] = {}
|
self._get_responses: dict[str, Any] = {}
|
||||||
self._post_responses: dict[str, Any] = {}
|
self._post_responses: dict[str, Any] = {}
|
||||||
self._put_responses: dict[str, Any] = {}
|
|
||||||
self._delete_status: int | None = None
|
|
||||||
|
|
||||||
def _req(self, method: str, path: str) -> httpx.Request:
|
def _req(self, method: str, path: str) -> httpx.Request:
|
||||||
return httpx.Request(method, f"https://chat.example.com{path}")
|
return httpx.Request(method, f"https://chat.example.com{path}")
|
||||||
@@ -46,12 +44,6 @@ class _FakeHTTPClient:
|
|||||||
def set_post_response(self, path: str, data: Any) -> None:
|
def set_post_response(self, path: str, data: Any) -> None:
|
||||||
self._post_responses[path] = data
|
self._post_responses[path] = data
|
||||||
|
|
||||||
def set_put_response(self, path: str, data: Any) -> None:
|
|
||||||
self._put_responses[path] = data
|
|
||||||
|
|
||||||
def set_delete_status(self, status: int) -> None:
|
|
||||||
self._delete_status = status
|
|
||||||
|
|
||||||
async def get(self, path: str, **kwargs) -> httpx.Response:
|
async def get(self, path: str, **kwargs) -> httpx.Response:
|
||||||
self.get_calls.append({"path": path, **kwargs})
|
self.get_calls.append({"path": path, **kwargs})
|
||||||
data = self._get_responses.get(path, {"id": "resp_" + path.split("/")[-1]})
|
data = self._get_responses.get(path, {"id": "resp_" + path.split("/")[-1]})
|
||||||
@@ -71,13 +63,11 @@ class _FakeHTTPClient:
|
|||||||
|
|
||||||
async def put(self, path: str, *, json: dict[str, Any] | None = None, **kwargs) -> httpx.Response:
|
async def put(self, path: str, *, json: dict[str, Any] | None = None, **kwargs) -> httpx.Response:
|
||||||
self.put_calls.append({"path": path, "json": json})
|
self.put_calls.append({"path": path, "json": json})
|
||||||
data = self._put_responses.get(path, {"id": path.split("/")[-1]})
|
return self._resp(200, {"id": path.split("/")[-1]}, "PUT", path)
|
||||||
return self._resp(200, data, "PUT", path)
|
|
||||||
|
|
||||||
async def delete(self, path: str, **kwargs) -> httpx.Response:
|
async def delete(self, path: str, **kwargs) -> httpx.Response:
|
||||||
self.delete_calls.append({"path": path})
|
self.delete_calls.append({"path": path})
|
||||||
status = self._delete_status if self._delete_status is not None else 200
|
return self._resp(200, {}, "DELETE", path)
|
||||||
return self._resp(status, {}, "DELETE", path)
|
|
||||||
|
|
||||||
async def aclose(self) -> None:
|
async def aclose(self) -> None:
|
||||||
pass
|
pass
|
||||||
@@ -119,7 +109,6 @@ def test_config_defaults():
|
|||||||
assert config.server_url == ""
|
assert config.server_url == ""
|
||||||
assert config.token == ""
|
assert config.token == ""
|
||||||
assert config.streaming is True
|
assert config.streaming is True
|
||||||
assert config.streaming_max_chars == 16000
|
|
||||||
assert config.send_tool_hints is True
|
assert config.send_tool_hints is True
|
||||||
assert config.dm.enabled is True
|
assert config.dm.enabled is True
|
||||||
assert config.dm.policy == "open"
|
assert config.dm.policy == "open"
|
||||||
@@ -150,7 +139,6 @@ def test_config_camelcase_aliases():
|
|||||||
"serverUrl": "https://mm.example.com",
|
"serverUrl": "https://mm.example.com",
|
||||||
"token": "abc123",
|
"token": "abc123",
|
||||||
"allowFromMatchMode": "username",
|
"allowFromMatchMode": "username",
|
||||||
"streamingMaxChars": 8000,
|
|
||||||
"replyInThread": False,
|
"replyInThread": False,
|
||||||
"sendToolHints": False,
|
"sendToolHints": False,
|
||||||
}
|
}
|
||||||
@@ -158,7 +146,6 @@ def test_config_camelcase_aliases():
|
|||||||
assert config.server_url == "https://mm.example.com"
|
assert config.server_url == "https://mm.example.com"
|
||||||
assert config.token == "abc123"
|
assert config.token == "abc123"
|
||||||
assert config.allow_from_match_mode == "username"
|
assert config.allow_from_match_mode == "username"
|
||||||
assert config.streaming_max_chars == 8000
|
|
||||||
assert config.reply_in_thread is False
|
assert config.reply_in_thread is False
|
||||||
assert config.send_tool_hints is False
|
assert config.send_tool_hints is False
|
||||||
|
|
||||||
@@ -194,7 +181,6 @@ async def test_start_identifies_bot():
|
|||||||
|
|
||||||
assert channel._self_id == "botuserid123"
|
assert channel._self_id == "botuserid123"
|
||||||
assert channel._self_username == "nanobot"
|
assert channel._self_username == "nanobot"
|
||||||
assert channel._self_email == "bot@example.com"
|
|
||||||
assert not start_task.done()
|
assert not start_task.done()
|
||||||
user_me_calls = [c for c in fake.get_calls[calls_before:] if "/api/v4/users/me" in c["path"]]
|
user_me_calls = [c for c in fake.get_calls[calls_before:] if "/api/v4/users/me" in c["path"]]
|
||||||
assert len(user_me_calls) == 1
|
assert len(user_me_calls) == 1
|
||||||
|
|||||||
@@ -277,7 +277,7 @@ class MochatChannel(BaseChannel):
|
|||||||
self.config: MochatConfig = config
|
self.config: MochatConfig = config
|
||||||
self._http: httpx.AsyncClient | None = None
|
self._http: httpx.AsyncClient | None = None
|
||||||
self._socket: Any = None
|
self._socket: Any = None
|
||||||
self._ws_connected = self._ws_ready = False
|
self._ws_ready = False
|
||||||
|
|
||||||
self._state_dir = get_runtime_subdir("mochat")
|
self._state_dir = get_runtime_subdir("mochat")
|
||||||
self._cursor_path = self._state_dir / "session_cursors.json"
|
self._cursor_path = self._state_dir / "session_cursors.json"
|
||||||
@@ -346,7 +346,7 @@ class MochatChannel(BaseChannel):
|
|||||||
if self._http:
|
if self._http:
|
||||||
await self._http.aclose()
|
await self._http.aclose()
|
||||||
self._http = None
|
self._http = None
|
||||||
self._ws_connected = self._ws_ready = False
|
self._ws_ready = False
|
||||||
|
|
||||||
async def send(self, msg: OutboundMessage) -> None:
|
async def send(self, msg: OutboundMessage) -> None:
|
||||||
"""Send outbound message to session or panel."""
|
"""Send outbound message to session or panel."""
|
||||||
@@ -422,7 +422,7 @@ class MochatChannel(BaseChannel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
async def connect() -> None:
|
async def connect() -> None:
|
||||||
self._ws_connected, self._ws_ready = True, False
|
self._ws_ready = False
|
||||||
self.logger.info("websocket connected")
|
self.logger.info("websocket connected")
|
||||||
subscribed = await self._subscribe_all()
|
subscribed = await self._subscribe_all()
|
||||||
self._ws_ready = subscribed
|
self._ws_ready = subscribed
|
||||||
@@ -431,7 +431,7 @@ class MochatChannel(BaseChannel):
|
|||||||
async def disconnect() -> None:
|
async def disconnect() -> None:
|
||||||
if not self._running:
|
if not self._running:
|
||||||
return
|
return
|
||||||
self._ws_connected = self._ws_ready = False
|
self._ws_ready = False
|
||||||
self.logger.warning("websocket disconnected")
|
self.logger.warning("websocket disconnected")
|
||||||
await self._ensure_fallback_workers()
|
await self._ensure_fallback_workers()
|
||||||
|
|
||||||
|
|||||||
@@ -363,13 +363,6 @@ def test_reported_daily_brief_pattern():
|
|||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
def _resolve_chunk_styles(text: str, max_len: int) -> tuple[list[str], list[list[str]]]:
|
|
||||||
"""Helper: full markdown → signal pipeline, including chunking."""
|
|
||||||
plain, styles = _markdown_to_signal(text)
|
|
||||||
chunks = split_message(plain, max_len) if plain else [""]
|
|
||||||
return chunks, _partition_styles(plain, chunks, styles)
|
|
||||||
|
|
||||||
|
|
||||||
def test_partition_styles_single_chunk_passthrough():
|
def test_partition_styles_single_chunk_passthrough():
|
||||||
plain, styles = _markdown_to_signal("**bold** plain *it*")
|
plain, styles = _markdown_to_signal("**bold** plain *it*")
|
||||||
parts = _partition_styles(plain, [plain], styles)
|
parts = _partition_styles(plain, [plain], styles)
|
||||||
|
|||||||
@@ -69,7 +69,6 @@ class SlackConfig(Base):
|
|||||||
webhook_path: str = "/slack/events"
|
webhook_path: str = "/slack/events"
|
||||||
bot_token: str = ""
|
bot_token: str = ""
|
||||||
app_token: str = ""
|
app_token: str = ""
|
||||||
user_token_read_only: bool = True
|
|
||||||
reply_in_thread: bool = True
|
reply_in_thread: bool = True
|
||||||
react_emoji: str = "eyes"
|
react_emoji: str = "eyes"
|
||||||
done_emoji: str = "white_check_mark"
|
done_emoji: str = "white_check_mark"
|
||||||
|
|||||||
@@ -1244,39 +1244,6 @@ async def test_pairing_routes_require_token_and_approve_or_deny(
|
|||||||
assert "Missing pairing code" in missing_code.text
|
assert "Missing pairing code" in missing_code.text
|
||||||
|
|
||||||
|
|
||||||
def test_api_service_settings_read_api_key_from_webui_payload(bus: MagicMock) -> None:
|
|
||||||
channel = _ch(bus)
|
|
||||||
request = _FakeReq(path="/api/settings/api-service/start")
|
|
||||||
setattr(
|
|
||||||
request,
|
|
||||||
"_nanobot_webui_mutation_payload",
|
|
||||||
{"host": "0.0.0.0", "port": 8900, "timeout": 120, "api_key": "secret-token"},
|
|
||||||
)
|
|
||||||
|
|
||||||
query = channel.gateway.http.settings_routes._parse_api_service_settings_query(request)
|
|
||||||
|
|
||||||
assert query == {
|
|
||||||
"host": ["0.0.0.0"],
|
|
||||||
"port": ["8900"],
|
|
||||||
"timeout": ["120"],
|
|
||||||
"api_key": ["secret-token"],
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def test_api_service_settings_reject_non_string_api_key(bus: MagicMock) -> None:
|
|
||||||
from nanobot.webui.settings_api import WebUISettingsError
|
|
||||||
|
|
||||||
channel = _ch(bus)
|
|
||||||
request = _FakeReq(path="/api/settings/api-service/start")
|
|
||||||
setattr(
|
|
||||||
request,
|
|
||||||
"_nanobot_webui_mutation_payload",
|
|
||||||
{"host": "127.0.0.1", "api_key": 123},
|
|
||||||
)
|
|
||||||
|
|
||||||
with pytest.raises(WebUISettingsError, match="API key must be a string"):
|
|
||||||
channel.gateway.http.settings_routes._parse_api_service_settings_query(request)
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_nanobot_feature_remote_install_requires_opt_in(
|
async def test_nanobot_feature_remote_install_requires_opt_in(
|
||||||
bus: MagicMock,
|
bus: MagicMock,
|
||||||
|
|||||||
@@ -202,12 +202,6 @@ class WsTestClient:
|
|||||||
assert msg.event == "delta", f"Expected 'delta' event, got '{msg.event}'"
|
assert msg.event == "delta", f"Expected 'delta' event, got '{msg.event}'"
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
async def recv_stream_end(self, timeout: float = 10.0) -> WsMessage:
|
|
||||||
"""Receive and validate a 'stream_end' event."""
|
|
||||||
msg = await self.recv(timeout)
|
|
||||||
assert msg.event == "stream_end", f"Expected 'stream_end' event, got '{msg.event}'"
|
|
||||||
return msg
|
|
||||||
|
|
||||||
async def collect_stream(self, timeout: float = 10.0) -> list[WsMessage]:
|
async def collect_stream(self, timeout: float = 10.0) -> list[WsMessage]:
|
||||||
"""Collect all deltas and the final stream_end into a list."""
|
"""Collect all deltas and the final stream_end into a list."""
|
||||||
messages: list[WsMessage] = []
|
messages: list[WsMessage] = []
|
||||||
@@ -232,10 +226,6 @@ class WsTestClient:
|
|||||||
"""Send a JSON frame."""
|
"""Send a JSON frame."""
|
||||||
await self.ws.send(json.dumps(data, ensure_ascii=False))
|
await self.ws.send(json.dumps(data, ensure_ascii=False))
|
||||||
|
|
||||||
async def send_content(self, content: str) -> None:
|
|
||||||
"""Send content in the preferred JSON format ``{"content": ...}``."""
|
|
||||||
await self.send_json({"content": content})
|
|
||||||
|
|
||||||
# -- Connection introspection -----------------------------------------
|
# -- Connection introspection -----------------------------------------
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|||||||
@@ -96,22 +96,6 @@ class ManagedProcessRuntime(Generic[_StartOptionsT]):
|
|||||||
# it; poll() both reaps it and reports the real lifecycle state.
|
# it; poll() both reaps it and reports the real lifecycle state.
|
||||||
self._owned_process: Any | None = None
|
self._owned_process: Any | None = None
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def refresh_state_pid(cls, *, paths: ProcessRuntimePaths) -> None:
|
|
||||||
"""Update a managed state file after the recorded process restarts."""
|
|
||||||
if not paths.state_path.exists():
|
|
||||||
return
|
|
||||||
try:
|
|
||||||
state = json.loads(paths.state_path.read_text(encoding="utf-8"))
|
|
||||||
except (json.JSONDecodeError, OSError):
|
|
||||||
return
|
|
||||||
state["pid"] = os.getpid()
|
|
||||||
runtime = cls(paths=paths)
|
|
||||||
state.pop("stable_identity", None)
|
|
||||||
state.update(runtime.process_identity_record(os.getpid()))
|
|
||||||
state["started_at"] = _utc_now()
|
|
||||||
runtime._write_state(state)
|
|
||||||
|
|
||||||
def start_background(self, options: _StartOptionsT) -> ProcessResult:
|
def start_background(self, options: _StartOptionsT) -> ProcessResult:
|
||||||
"""Start the configured command as a detached process."""
|
"""Start the configured command as a detached process."""
|
||||||
with self._lifecycle_lock():
|
with self._lifecycle_lock():
|
||||||
|
|||||||
@@ -685,15 +685,6 @@ class WebuiTurnCoordinator:
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
async def publish_run_status(
|
|
||||||
self,
|
|
||||||
msg: InboundMessage,
|
|
||||||
status: str,
|
|
||||||
*,
|
|
||||||
started_at: float | None = None,
|
|
||||||
) -> None:
|
|
||||||
await publish_turn_run_status(self.bus, msg, status, started_at=started_at)
|
|
||||||
|
|
||||||
async def handle_turn_end(
|
async def handle_turn_end(
|
||||||
self,
|
self,
|
||||||
msg: InboundMessage,
|
msg: InboundMessage,
|
||||||
|
|||||||
@@ -63,9 +63,6 @@ class GatewayTokenStore:
|
|||||||
self.api_tokens[token_value] = expiry
|
self.api_tokens[token_value] = expiry
|
||||||
return token_value
|
return token_value
|
||||||
|
|
||||||
def take_issued_token_if_valid(self, token_value: str | None) -> bool:
|
|
||||||
return self.take_issued_token_audience(token_value) is not None
|
|
||||||
|
|
||||||
def take_issued_token_audience(
|
def take_issued_token_audience(
|
||||||
self,
|
self,
|
||||||
token_value: str | None,
|
token_value: str | None,
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ from nanobot.webui.nanobot_features_api import (
|
|||||||
nanobot_features_payload,
|
nanobot_features_payload,
|
||||||
)
|
)
|
||||||
from nanobot.webui.settings_api import (
|
from nanobot.webui.settings_api import (
|
||||||
WebUISettingsError,
|
|
||||||
complete_oauth_provider,
|
complete_oauth_provider,
|
||||||
create_model_configuration,
|
create_model_configuration,
|
||||||
create_provider_settings,
|
create_provider_settings,
|
||||||
@@ -490,17 +489,6 @@ class WebUISettingsRouter:
|
|||||||
lambda: request_image_generation_reload(self.bus),
|
lambda: request_image_generation_reload(self.bus),
|
||||||
)
|
)
|
||||||
|
|
||||||
async def _apply_image_generation_runtime_change(
|
|
||||||
self,
|
|
||||||
payload: dict[str, Any],
|
|
||||||
) -> dict[str, Any]:
|
|
||||||
updated, restart_cleared = (
|
|
||||||
await self._apply_image_generation_runtime_change_result(payload)
|
|
||||||
)
|
|
||||||
if restart_cleared:
|
|
||||||
self._restart_sections.discard("image")
|
|
||||||
return updated
|
|
||||||
|
|
||||||
async def _reload_mcp_runtime(self) -> dict[str, Any]:
|
async def _reload_mcp_runtime(self) -> dict[str, Any]:
|
||||||
if self._mcp_reload is None:
|
if self._mcp_reload is None:
|
||||||
return {
|
return {
|
||||||
@@ -531,47 +519,9 @@ class WebUISettingsRouter:
|
|||||||
def _parse_mcp_settings_query(self, request: WsRequest) -> QueryParams:
|
def _parse_mcp_settings_query(self, request: WsRequest) -> QueryParams:
|
||||||
return self._query(request)
|
return self._query(request)
|
||||||
|
|
||||||
def _parse_provider_settings_query(self, request: WsRequest) -> QueryParams:
|
|
||||||
return self._query(request)
|
|
||||||
|
|
||||||
def _parse_api_service_settings_query(self, request: WsRequest) -> QueryParams:
|
|
||||||
payload = _mutation_payload(request)
|
|
||||||
if payload is not None:
|
|
||||||
api_key = payload.get("api_key")
|
|
||||||
if api_key is not None and not isinstance(api_key, str):
|
|
||||||
raise WebUISettingsError("API service API key must be a string")
|
|
||||||
return self._query(request)
|
|
||||||
|
|
||||||
def _api_runtime(self) -> ApiRuntime:
|
def _api_runtime(self) -> ApiRuntime:
|
||||||
return ApiRuntime(paths=api_runtime_paths(self.settings.config.path))
|
return ApiRuntime(paths=api_runtime_paths(self.settings.config.path))
|
||||||
|
|
||||||
def _api_service_payload(
|
|
||||||
self,
|
|
||||||
*,
|
|
||||||
last_action: str | None = None,
|
|
||||||
) -> dict[str, Any]:
|
|
||||||
return capability_domain.api_service_payload(
|
|
||||||
self.settings,
|
|
||||||
self._api_runtime(),
|
|
||||||
last_action=last_action,
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _masked_secret(value: str) -> str | None:
|
|
||||||
return capability_domain.masked_api_secret(value)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _api_runtime_message(message: str) -> str:
|
|
||||||
return capability_domain.api_runtime_message(message)
|
|
||||||
|
|
||||||
def _parse_channel_values(self, request: WsRequest) -> dict[str, Any]:
|
|
||||||
return self._system.parse_channel_values(
|
|
||||||
SettingsRequest(
|
|
||||||
query=self._query(request),
|
|
||||||
payload=_mutation_payload(request),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
def _save_channel_config_values(
|
def _save_channel_config_values(
|
||||||
self,
|
self,
|
||||||
name: str,
|
name: str,
|
||||||
@@ -610,17 +560,6 @@ class WebUISettingsRouter:
|
|||||||
allow_install=allow_install,
|
allow_install=allow_install,
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _feature_runtime_fallback(
|
|
||||||
payload: dict[str, Any],
|
|
||||||
*,
|
|
||||||
message: str,
|
|
||||||
) -> dict[str, Any]:
|
|
||||||
return system_domain.SystemSettingsHandler.feature_runtime_fallback(
|
|
||||||
payload,
|
|
||||||
message=message,
|
|
||||||
)
|
|
||||||
|
|
||||||
def _allow_feature_package_install(
|
def _allow_feature_package_install(
|
||||||
self,
|
self,
|
||||||
connection: Any,
|
connection: Any,
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ dependencies = [
|
|||||||
"pydantic-settings>=2.12.0,<3.0.0",
|
"pydantic-settings>=2.12.0,<3.0.0",
|
||||||
# Feishu's lark-oapi currently requires websockets<16; core supports 15 and 16.
|
# Feishu's lark-oapi currently requires websockets<16; core supports 15 and 16.
|
||||||
"websockets>=15.0,<17.0",
|
"websockets>=15.0,<17.0",
|
||||||
"websocket-client>=1.9.0,<2.0.0",
|
|
||||||
"httpx[socks]>=0.28.0,<1.0.0",
|
"httpx[socks]>=0.28.0,<1.0.0",
|
||||||
"ddgs>=9.5.5,<10.0.0",
|
"ddgs>=9.5.5,<10.0.0",
|
||||||
"oauth-cli-kit>=0.1.6,<1.0.0",
|
"oauth-cli-kit>=0.1.6,<1.0.0",
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { PickerMenu, type PickerMenuTheme } from "./picker-menu"
|
|||||||
|
|
||||||
export type CommandMenuTheme = PickerMenuTheme
|
export type CommandMenuTheme = PickerMenuTheme
|
||||||
|
|
||||||
export type TuiCommandAction =
|
type TuiCommandAction =
|
||||||
| "sessions"
|
| "sessions"
|
||||||
| "new-chat"
|
| "new-chat"
|
||||||
| "context"
|
| "context"
|
||||||
|
|||||||
+3
-3
@@ -29,14 +29,14 @@ export interface FileEditEvent {
|
|||||||
diff?: FileDiff
|
diff?: FileDiff
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FileDiff {
|
interface FileDiff {
|
||||||
format: "unified" | string
|
format: "unified" | string
|
||||||
context?: number
|
context?: number
|
||||||
truncated?: boolean
|
truncated?: boolean
|
||||||
text?: string
|
text?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MediaAttachment {
|
interface MediaAttachment {
|
||||||
kind: "image" | "video" | "file"
|
kind: "image" | "video" | "file"
|
||||||
url: string
|
url: string
|
||||||
name?: string
|
name?: string
|
||||||
@@ -225,7 +225,7 @@ export interface SessionContextSnapshot {
|
|||||||
lastUsage: TokenUsage | null
|
lastUsage: TokenUsage | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SessionMention {
|
interface SessionMention {
|
||||||
name: string
|
name: string
|
||||||
session_key: string
|
session_key: string
|
||||||
title?: string
|
title?: string
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { TFunction } from "i18next";
|
import type { TFunction } from "i18next";
|
||||||
|
|
||||||
export type ChannelFieldMessages = {
|
type ChannelFieldMessages = {
|
||||||
label: string;
|
label: string;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
help?: string;
|
help?: string;
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ export function CapabilityMentionToken({
|
|||||||
return <SessionMentionToken mention={segment.mention} label={segment.text} variant={variant} />;
|
return <SessionMentionToken mention={segment.mention} label={segment.text} variant={variant} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SessionMentionToken({
|
function SessionMentionToken({
|
||||||
mention,
|
mention,
|
||||||
label,
|
label,
|
||||||
variant,
|
variant,
|
||||||
@@ -172,7 +172,7 @@ export function SessionMentionToken({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function CliAppMentionToken({
|
function CliAppMentionToken({
|
||||||
app,
|
app,
|
||||||
label,
|
label,
|
||||||
variant,
|
variant,
|
||||||
@@ -229,7 +229,7 @@ export function CliAppMentionToken({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function McpPresetMentionToken({
|
function McpPresetMentionToken({
|
||||||
preset,
|
preset,
|
||||||
label,
|
label,
|
||||||
variant,
|
variant,
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ export function splitFilePath(path: string): { directory: string; name: string }
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fileKindForPath(path: string): FileReferenceKind {
|
function fileKindForPath(path: string): FileReferenceKind {
|
||||||
const normalized = path.toLowerCase();
|
const normalized = path.toLowerCase();
|
||||||
const name = normalized.split(/[\\/]/).pop() ?? normalized;
|
const name = normalized.split(/[\\/]/).pop() ?? normalized;
|
||||||
const ext = name.includes(".") ? name.split(".").pop() ?? "" : "";
|
const ext = name.includes(".") ? name.split(".").pop() ?? "" : "";
|
||||||
@@ -193,7 +193,7 @@ export function fileKindForPath(path: string): FileReferenceKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function FileReferenceIcon({ kind }: { kind: FileReferenceKind }) {
|
function FileReferenceIcon({ kind }: { kind: FileReferenceKind }) {
|
||||||
if (kind === "python") {
|
if (kind === "python") {
|
||||||
return (
|
return (
|
||||||
<svg
|
<svg
|
||||||
|
|||||||
@@ -967,7 +967,7 @@ interface ReasoningBubbleProps {
|
|||||||
hasBodyBelow: boolean;
|
hasBodyBelow: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ReasoningBubble({
|
function ReasoningBubble({
|
||||||
text,
|
text,
|
||||||
streaming,
|
streaming,
|
||||||
hasBodyBelow,
|
hasBodyBelow,
|
||||||
@@ -993,7 +993,7 @@ interface TraceGroupProps {
|
|||||||
* collapsed because tool traces are supporting evidence, not the answer.
|
* collapsed because tool traces are supporting evidence, not the answer.
|
||||||
* A single click expands the exact calls when the user wants details.
|
* A single click expands the exact calls when the user wants details.
|
||||||
*/
|
*/
|
||||||
export function TraceGroup({ message }: TraceGroupProps) {
|
function TraceGroup({ message }: TraceGroupProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const lines = message.traces ?? [message.content];
|
const lines = message.traces ?? [message.content];
|
||||||
const count = lines.length;
|
const count = lines.length;
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ export function ChannelLogo({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function channelDisplayName(feature: NanobotFeatureInfo): string {
|
function channelDisplayName(feature: NanobotFeatureInfo): string {
|
||||||
return channelUiPresentation(feature.name, feature.webui)?.displayName ?? feature.display_name;
|
return channelUiPresentation(feature.name, feature.webui)?.displayName ?? feature.display_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ export function ChannelSetupLinks({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ChannelOfficialLink({
|
function ChannelOfficialLink({
|
||||||
feature,
|
feature,
|
||||||
setup,
|
setup,
|
||||||
}: {
|
}: {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { Input } from "@/components/ui/input";
|
|||||||
import type { ChannelConfigField } from "@/components/settings/channels/catalog";
|
import type { ChannelConfigField } from "@/components/settings/channels/catalog";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
export function channelFieldValue(field: ChannelConfigField, values: Record<string, string>): string {
|
function channelFieldValue(field: ChannelConfigField, values: Record<string, string>): string {
|
||||||
return values[field.key] ?? field.defaultValue ?? field.options?.[0]?.value ?? "";
|
return values[field.key] ?? field.defaultValue ?? field.options?.[0]?.value ?? "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export type ChannelSetupPresentation = {
|
|||||||
presets?: ChannelProviderPreset[];
|
presets?: ChannelProviderPreset[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ChannelCatalogSetupPresentation = {
|
type ChannelCatalogSetupPresentation = {
|
||||||
mode?: "webui" | "credentials" | "connect";
|
mode?: "webui" | "credentials" | "connect";
|
||||||
command?: string;
|
command?: string;
|
||||||
docsUrl?: string;
|
docsUrl?: string;
|
||||||
@@ -38,15 +38,15 @@ export type ChannelCatalogSetupPresentation = {
|
|||||||
presets?: ChannelProviderPresetDefinition[];
|
presets?: ChannelProviderPresetDefinition[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ChannelFieldPresentation = {
|
type ChannelFieldPresentation = {
|
||||||
key: string;
|
key: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ChannelSetupActionDefinition = Omit<ChannelSetupAction, "label">;
|
type ChannelSetupActionDefinition = Omit<ChannelSetupAction, "label">;
|
||||||
|
|
||||||
export type ChannelProviderPresetDefinition = Omit<ChannelProviderPreset, "label">;
|
export type ChannelProviderPresetDefinition = Omit<ChannelProviderPreset, "label">;
|
||||||
|
|
||||||
export type ChannelSetupAction = {
|
type ChannelSetupAction = {
|
||||||
id: string;
|
id: string;
|
||||||
label: string;
|
label: string;
|
||||||
url?: string;
|
url?: string;
|
||||||
@@ -72,7 +72,7 @@ export type ChannelConfigField = {
|
|||||||
options?: ChannelConfigOption[];
|
options?: ChannelConfigOption[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ChannelConfigOption = {
|
type ChannelConfigOption = {
|
||||||
value: string;
|
value: string;
|
||||||
label: string;
|
label: string;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export type SettingsSectionKey =
|
|||||||
| "runtime"
|
| "runtime"
|
||||||
| "advanced";
|
| "advanced";
|
||||||
|
|
||||||
export type PendingRestartSection = "runtime" | "browser" | "image";
|
type PendingRestartSection = "runtime" | "browser" | "image";
|
||||||
export type PendingRestartSections = Record<PendingRestartSection, boolean>;
|
export type PendingRestartSections = Record<PendingRestartSection, boolean>;
|
||||||
|
|
||||||
export type RestartAwarePayload = {
|
export type RestartAwarePayload = {
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ import type { CliAppInfo, McpPresetInfo, ToolProgressEvent, UIFileEdit, UIMessag
|
|||||||
|
|
||||||
const ACTIVITY_SCROLL_NEAR_BOTTOM_PX = 24;
|
const ACTIVITY_SCROLL_NEAR_BOTTOM_PX = 24;
|
||||||
|
|
||||||
export { isAgentActivityMember, isReasoningOnlyAssistant };
|
export { isAgentActivityMember };
|
||||||
|
|
||||||
interface ActivityCounts {
|
interface ActivityCounts {
|
||||||
reasoningSteps: number;
|
reasoningSteps: number;
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ function FileEditRow({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hasVisibleDiffStats(edit: Pick<FileEditSummary, "added" | "deleted">): boolean {
|
function hasVisibleDiffStats(edit: Pick<FileEditSummary, "added" | "deleted">): boolean {
|
||||||
return edit.added > 0 || edit.deleted > 0;
|
return edit.added > 0 || edit.deleted > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { compactActivityPath, redactActivityText } from "./activity-text";
|
|||||||
export type GenericToolStatus = "running" | "done" | "error";
|
export type GenericToolStatus = "running" | "done" | "error";
|
||||||
export type ToolFamily = "content-search" | "file-search" | "list" | "read" | "memory" | "generic";
|
export type ToolFamily = "content-search" | "file-search" | "list" | "read" | "memory" | "generic";
|
||||||
|
|
||||||
export interface ToolField {
|
interface ToolField {
|
||||||
key:
|
key:
|
||||||
| "query"
|
| "query"
|
||||||
| "pattern"
|
| "pattern"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { displayWebHost, formatCompactWebUrl, parseSafeActivityHttpUrl } from ".
|
|||||||
export type WebSearchStatus = "running" | "done" | "error";
|
export type WebSearchStatus = "running" | "done" | "error";
|
||||||
export type WebSearchTarget = "web" | "x";
|
export type WebSearchTarget = "web" | "x";
|
||||||
|
|
||||||
export interface WebSearchSource {
|
interface WebSearchSource {
|
||||||
title: string;
|
title: string;
|
||||||
href: string;
|
href: string;
|
||||||
host: string;
|
host: string;
|
||||||
|
|||||||
@@ -26,13 +26,13 @@ export function userPromptAnchors(messages: UIMessage[]): PromptAnchor[] {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function promptLabel(content: string, index: number): string {
|
function promptLabel(content: string, index: number): string {
|
||||||
const text = content.replace(/\s+/g, " ").trim();
|
const text = content.replace(/\s+/g, " ").trim();
|
||||||
if (!text) return `Prompt ${index + 1}`;
|
if (!text) return `Prompt ${index + 1}`;
|
||||||
return truncatePreview(text, 80);
|
return truncatePreview(text, 80);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function promptPreview(content: string, index: number): string {
|
function promptPreview(content: string, index: number): string {
|
||||||
const text = compactPreview(content);
|
const text = compactPreview(content);
|
||||||
if (!text) return `Prompt ${index + 1}`;
|
if (!text) return `Prompt ${index + 1}`;
|
||||||
return truncatePreview(text, 320);
|
return truncatePreview(text, 320);
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ const buttonVariants = cva(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
export interface ButtonProps
|
interface ButtonProps
|
||||||
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||||
VariantProps<typeof buttonVariants> {
|
VariantProps<typeof buttonVariants> {
|
||||||
asChild?: boolean;
|
asChild?: boolean;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import * as React from "react";
|
|||||||
import { formControlFocusClassName } from "@/components/ui/form-control";
|
import { formControlFocusClassName } from "@/components/ui/form-control";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
export type InputProps = React.InputHTMLAttributes<HTMLInputElement>;
|
type InputProps = React.InputHTMLAttributes<HTMLInputElement>;
|
||||||
|
|
||||||
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||||
({ className, type, ...props }, ref) => {
|
({ className, type, ...props }, ref) => {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import * as React from "react";
|
|||||||
import { formControlFocusClassName } from "@/components/ui/form-control";
|
import { formControlFocusClassName } from "@/components/ui/form-control";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
export type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;
|
type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;
|
||||||
|
|
||||||
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
||||||
({ className, ...props }, ref) => {
|
({ className, ...props }, ref) => {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export type {
|
|||||||
|
|
||||||
export const MAX_WORKBENCH_PANES = 4;
|
export const MAX_WORKBENCH_PANES = 4;
|
||||||
|
|
||||||
export const WORKBENCH_LAYOUTS = [
|
const WORKBENCH_LAYOUTS = [
|
||||||
"columns",
|
"columns",
|
||||||
"rows",
|
"rows",
|
||||||
"grid",
|
"grid",
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ import type { WebUIIngressLimits } from "@/lib/types";
|
|||||||
* - ``ready`` — ``dataUrl`` available; safe to submit
|
* - ``ready`` — ``dataUrl`` available; safe to submit
|
||||||
* - ``error`` — validation / decode failure; chip shows inline error
|
* - ``error`` — validation / decode failure; chip shows inline error
|
||||||
*/
|
*/
|
||||||
export type AttachmentStatus = "encoding" | "ready" | "error";
|
type AttachmentStatus = "encoding" | "ready" | "error";
|
||||||
export type AttachmentKind = "image" | "file";
|
export type AttachmentKind = "image" | "file";
|
||||||
|
|
||||||
export interface AttachedAttachment {
|
interface AttachedAttachment {
|
||||||
id: string;
|
id: string;
|
||||||
kind: AttachmentKind;
|
kind: AttachmentKind;
|
||||||
file: File;
|
file: File;
|
||||||
@@ -32,7 +32,7 @@ export interface AttachedAttachment {
|
|||||||
|
|
||||||
export type AttachedImage = AttachedAttachment;
|
export type AttachedImage = AttachedAttachment;
|
||||||
|
|
||||||
export interface RestoredReadyAttachment {
|
interface RestoredReadyAttachment {
|
||||||
dataUrl: string;
|
dataUrl: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
kind?: AttachmentKind;
|
kind?: AttachmentKind;
|
||||||
@@ -55,8 +55,8 @@ export type AttachmentError =
|
|||||||
| "io"; // file read failed at the browser layer
|
| "io"; // file read failed at the browser layer
|
||||||
|
|
||||||
export const MAX_ATTACHMENTS_PER_MESSAGE = 4;
|
export const MAX_ATTACHMENTS_PER_MESSAGE = 4;
|
||||||
export const MAX_ATTACHMENT_BYTES = 6 * 1024 * 1024;
|
const MAX_ATTACHMENT_BYTES = 6 * 1024 * 1024;
|
||||||
export const MAX_TOTAL_ATTACHMENT_BYTES = 24 * 1024 * 1024;
|
const MAX_TOTAL_ATTACHMENT_BYTES = 24 * 1024 * 1024;
|
||||||
|
|
||||||
/** MIME whitelist — mirrors the server's and the ``<input accept>`` attr. */
|
/** MIME whitelist — mirrors the server's and the ``<input accept>`` attr. */
|
||||||
const ACCEPTED_IMAGE_MIMES: ReadonlySet<string> = new Set([
|
const ACCEPTED_IMAGE_MIMES: ReadonlySet<string> = new Set([
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { acceptedAttachmentKind } from "@/hooks/useAttachedImages";
|
|||||||
* - Plain text pasted alongside attachments is *not* consumed by this helper,
|
* - Plain text pasted alongside attachments is *not* consumed by this helper,
|
||||||
* so the caller can still let the textarea receive it naturally.
|
* so the caller can still let the textarea receive it naturally.
|
||||||
*/
|
*/
|
||||||
export function extractImageFilesFromPaste(
|
function extractImageFilesFromPaste(
|
||||||
event: ClipboardEvent | React.ClipboardEvent,
|
event: ClipboardEvent | React.ClipboardEvent,
|
||||||
): File[] {
|
): File[] {
|
||||||
const clipboard = (event as ClipboardEvent).clipboardData
|
const clipboard = (event as ClipboardEvent).clipboardData
|
||||||
@@ -27,7 +27,7 @@ export function extractImageFilesFromPaste(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Extract dropped attachment files, mirroring ``extractImageFilesFromPaste``. */
|
/** Extract dropped attachment files, mirroring ``extractImageFilesFromPaste``. */
|
||||||
export function extractImageFilesFromDrop(
|
function extractImageFilesFromDrop(
|
||||||
event: DragEvent | React.DragEvent,
|
event: DragEvent | React.DragEvent,
|
||||||
): File[] {
|
): File[] {
|
||||||
const dt = (event as DragEvent).dataTransfer
|
const dt = (event as DragEvent).dataTransfer
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { normalizeWorkbenchState } from "@/components/workbench/workbench-model"
|
|||||||
import { fetchSidebarState } from "@/lib/api";
|
import { fetchSidebarState } from "@/lib/api";
|
||||||
import type { ChatSummary, SidebarStatePayload } from "@/lib/types";
|
import type { ChatSummary, SidebarStatePayload } from "@/lib/types";
|
||||||
|
|
||||||
export const DEFAULT_SIDEBAR_STATE: SidebarStatePayload = {
|
const DEFAULT_SIDEBAR_STATE: SidebarStatePayload = {
|
||||||
schema_version: 1,
|
schema_version: 1,
|
||||||
pinned_keys: [],
|
pinned_keys: [],
|
||||||
archived_keys: [],
|
archived_keys: [],
|
||||||
@@ -74,7 +74,7 @@ function boolMap(value: unknown): Record<string, boolean> {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function normalizeSidebarState(raw: unknown): SidebarStatePayload {
|
function normalizeSidebarState(raw: unknown): SidebarStatePayload {
|
||||||
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
||||||
return { ...DEFAULT_SIDEBAR_STATE, view: { ...DEFAULT_SIDEBAR_STATE.view } };
|
return { ...DEFAULT_SIDEBAR_STATE, view: { ...DEFAULT_SIDEBAR_STATE.view } };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ export function normalizeLocale(
|
|||||||
return baseMatch?.code ?? defaultLocale;
|
return baseMatch?.code ?? defaultLocale;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function readStoredLocale(): SupportedLocale | null {
|
function readStoredLocale(): SupportedLocale | null {
|
||||||
if (typeof window === "undefined") return null;
|
if (typeof window === "undefined") return null;
|
||||||
try {
|
try {
|
||||||
const raw = window.localStorage.getItem(LOCALE_STORAGE_KEY);
|
const raw = window.localStorage.getItem(LOCALE_STORAGE_KEY);
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import {
|
|||||||
applyDocumentLocale,
|
applyDocumentLocale,
|
||||||
defaultLocale,
|
defaultLocale,
|
||||||
fallbackLocale,
|
fallbackLocale,
|
||||||
LOCALE_STORAGE_KEY,
|
|
||||||
normalizeLocale,
|
normalizeLocale,
|
||||||
persistLocale,
|
persistLocale,
|
||||||
resolveInitialLocale,
|
resolveInitialLocale,
|
||||||
@@ -47,7 +46,7 @@ export function currentLocale(): SupportedLocale {
|
|||||||
return normalizeLocale(i18n.resolvedLanguage ?? i18n.language ?? defaultLocale);
|
return normalizeLocale(i18n.resolvedLanguage ?? i18n.language ?? defaultLocale);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function loadLocaleResources(
|
async function loadLocaleResources(
|
||||||
locale: SupportedLocale,
|
locale: SupportedLocale,
|
||||||
): Promise<LocaleResource> {
|
): Promise<LocaleResource> {
|
||||||
const existing = resourcePromises.get(locale);
|
const existing = resourcePromises.get(locale);
|
||||||
@@ -131,5 +130,4 @@ function syncLocaleSideEffects(language: string) {
|
|||||||
persistLocale(locale);
|
persistLocale(locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
export { LOCALE_STORAGE_KEY };
|
|
||||||
export default i18n;
|
export default i18n;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ export type AnsiSegment = {
|
|||||||
style?: AnsiStyle;
|
style?: AnsiStyle;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type AnsiStyle = {
|
type AnsiStyle = {
|
||||||
backgroundColor?: string;
|
backgroundColor?: string;
|
||||||
color?: string;
|
color?: string;
|
||||||
fontStyle?: "italic";
|
fontStyle?: "italic";
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export const DEFAULT_HTTP_TIMEOUT_MS = 20_000;
|
const DEFAULT_HTTP_TIMEOUT_MS = 20_000;
|
||||||
|
|
||||||
export async function fetchWithTimeout(
|
export async function fetchWithTimeout(
|
||||||
input: RequestInfo | URL,
|
input: RequestInfo | URL,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
type EncodeResponse,
|
type EncodeResponse,
|
||||||
} from "@/workers/imageEncode.worker";
|
} from "@/workers/imageEncode.worker";
|
||||||
|
|
||||||
export type { EncodeResponse, EncodeSuccess, EncodeFailure } from "@/workers/imageEncode.worker";
|
export type { EncodeResponse, EncodeFailure } from "@/workers/imageEncode.worker";
|
||||||
|
|
||||||
type Pending = {
|
type Pending = {
|
||||||
resolve: (r: EncodeResponse) => void;
|
resolve: (r: EncodeResponse) => void;
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ interface PendingWebUIRequest extends PendingRequest<unknown> {
|
|||||||
serializedFrame: string;
|
serializedFrame: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WebUIMutationError extends Error {
|
class WebUIMutationError extends Error {
|
||||||
status: number;
|
status: number;
|
||||||
|
|
||||||
constructor(status: number, message: string) {
|
constructor(status: number, message: string) {
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ export function logoFallbackUrls(logoUrl: string | null | undefined): string[] {
|
|||||||
return urls;
|
return urls;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PROVIDER_BRAND_ALIASES: Record<string, string> = {
|
const PROVIDER_BRAND_ALIASES: Record<string, string> = {
|
||||||
brave_search: "brave",
|
brave_search: "brave",
|
||||||
byteplus_coding_plan: "byteplus",
|
byteplus_coding_plan: "byteplus",
|
||||||
mimo: "xiaomi_mimo",
|
mimo: "xiaomi_mimo",
|
||||||
@@ -137,7 +137,7 @@ export const PROVIDER_BRAND_ALIASES: Record<string, string> = {
|
|||||||
volcengine_coding_plan: "volcengine",
|
volcengine_coding_plan: "volcengine",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PROVIDER_LABEL_ALIASES: Record<string, string> = {
|
const PROVIDER_LABEL_ALIASES: Record<string, string> = {
|
||||||
brave_search: "Brave Search",
|
brave_search: "Brave Search",
|
||||||
byteplus_coding_plan: "BytePlus",
|
byteplus_coding_plan: "BytePlus",
|
||||||
minimaxAnthropic: "MiniMax",
|
minimaxAnthropic: "MiniMax",
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export interface RuntimeHost {
|
|||||||
exportDiagnostics?: () => Promise<string>;
|
exportDiagnostics?: () => Promise<string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HostRuntimeInfo {
|
interface HostRuntimeInfo {
|
||||||
surface: "native";
|
surface: "native";
|
||||||
app_version: string;
|
app_version: string;
|
||||||
engine_status: "starting" | "ready" | "restarting" | "stopped" | "crashed";
|
engine_status: "starting" | "ready" | "restarting" | "stopped" | "crashed";
|
||||||
@@ -23,7 +23,7 @@ export interface HostRuntimeInfo {
|
|||||||
engine_transport?: "unix_socket";
|
engine_transport?: "unix_socket";
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NanobotHostApi {
|
interface NanobotHostApi {
|
||||||
getRuntimeInfo?(): Promise<HostRuntimeInfo>;
|
getRuntimeInfo?(): Promise<HostRuntimeInfo>;
|
||||||
restartEngine?(): Promise<void>;
|
restartEngine?(): Promise<void>;
|
||||||
pickFolder?(): Promise<string | null>;
|
pickFolder?(): Promise<string | null>;
|
||||||
@@ -40,7 +40,7 @@ export interface NanobotHostApi {
|
|||||||
): () => void;
|
): () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type HostSocketEvent =
|
type HostSocketEvent =
|
||||||
| { id: string; type: "open" }
|
| { id: string; type: "open" }
|
||||||
| { data: string; id: string; type: "message" }
|
| { data: string; id: string; type: "message" }
|
||||||
| { id: string; message: string; type: "error" }
|
| { id: string; message: string; type: "error" }
|
||||||
|
|||||||
+27
-27
@@ -1,8 +1,8 @@
|
|||||||
export type Role = "user" | "assistant" | "tool" | "system";
|
type Role = "user" | "assistant" | "tool" | "system";
|
||||||
|
|
||||||
/** "trace" rows are intermediate agent breadcrumbs (tool-call hints,
|
/** "trace" rows are intermediate agent breadcrumbs (tool-call hints,
|
||||||
* progress pings) that should not be rendered as conversational replies. */
|
* progress pings) that should not be rendered as conversational replies. */
|
||||||
export type MessageKind = "message" | "trace";
|
type MessageKind = "message" | "trace";
|
||||||
|
|
||||||
export type UITurnPhase = "user" | "reasoning" | "activity" | "answer" | "complete";
|
export type UITurnPhase = "user" | "reasoning" | "activity" | "answer" | "complete";
|
||||||
export type MessageDeliveryStatus = "sending" | "accepted" | "failed";
|
export type MessageDeliveryStatus = "sending" | "accepted" | "failed";
|
||||||
@@ -37,7 +37,7 @@ export interface UIMediaAttachment {
|
|||||||
name?: string;
|
name?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UIMessageSource { kind: "cron" | "local_trigger" | "trigger" | string; label?: string; }
|
interface UIMessageSource { kind: "cron" | "local_trigger" | "trigger" | string; label?: string; }
|
||||||
|
|
||||||
export interface TurnUsage {
|
export interface TurnUsage {
|
||||||
prompt_tokens?: number;
|
prompt_tokens?: number;
|
||||||
@@ -144,7 +144,7 @@ export interface SessionHandle {
|
|||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UISessionMessage {
|
interface UISessionMessage {
|
||||||
message_id: string;
|
message_id: string;
|
||||||
session: SessionHandle;
|
session: SessionHandle;
|
||||||
}
|
}
|
||||||
@@ -226,14 +226,14 @@ export interface SkillSummary {
|
|||||||
unavailable_reason?: string;
|
unavailable_reason?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SkillRequirements {
|
interface SkillRequirements {
|
||||||
bins: string[];
|
bins: string[];
|
||||||
env: string[];
|
env: string[];
|
||||||
missing_bins: string[];
|
missing_bins: string[];
|
||||||
missing_env: string[];
|
missing_env: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SkillInstallOption {
|
interface SkillInstallOption {
|
||||||
id: string;
|
id: string;
|
||||||
kind: string;
|
kind: string;
|
||||||
label: string;
|
label: string;
|
||||||
@@ -303,7 +303,7 @@ export interface SkillInstallPayload extends SkillsPayload {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Structured UI blob on ``progress`` WS frames; channels may add more ``kind`` values later. */
|
/** Structured UI blob on ``progress`` WS frames; channels may add more ``kind`` values later. */
|
||||||
export interface AgentUIBlob {
|
interface AgentUIBlob {
|
||||||
kind: string;
|
kind: string;
|
||||||
data?: unknown;
|
data?: unknown;
|
||||||
}
|
}
|
||||||
@@ -455,16 +455,16 @@ export interface BootstrapResponse {
|
|||||||
runtime_capabilities?: RuntimeCapabilities;
|
runtime_capabilities?: RuntimeCapabilities;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WebUITransportLimits {
|
interface WebUITransportLimits {
|
||||||
max_frame_bytes: number;
|
max_frame_bytes: number;
|
||||||
envelope_reserve_bytes: number;
|
envelope_reserve_bytes: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WebUIMessageLimits {
|
interface WebUIMessageLimits {
|
||||||
max_text_bytes: number;
|
max_text_bytes: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WebUIAttachmentLimits {
|
interface WebUIAttachmentLimits {
|
||||||
max_count: number;
|
max_count: number;
|
||||||
max_file_bytes: number;
|
max_file_bytes: number;
|
||||||
max_total_bytes: number;
|
max_total_bytes: number;
|
||||||
@@ -477,8 +477,8 @@ export interface WebUIIngressLimits {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type RuntimeSurface = "browser" | "native";
|
export type RuntimeSurface = "browser" | "native";
|
||||||
export type RestartBehavior = "none" | "nextTurn" | "engineRestart" | "appRestart";
|
type RestartBehavior = "none" | "nextTurn" | "engineRestart" | "appRestart";
|
||||||
export type SettingsApplyStatus =
|
type SettingsApplyStatus =
|
||||||
| "idle"
|
| "idle"
|
||||||
| "pending"
|
| "pending"
|
||||||
| "applying"
|
| "applying"
|
||||||
@@ -492,7 +492,7 @@ export interface RuntimeCapabilities {
|
|||||||
can_export_diagnostics: boolean;
|
can_export_diagnostics: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProviderModelInfo {
|
interface ProviderModelInfo {
|
||||||
id: string;
|
id: string;
|
||||||
label?: string | null;
|
label?: string | null;
|
||||||
description?: string | null;
|
description?: string | null;
|
||||||
@@ -783,12 +783,12 @@ export interface ApiServicePayload {
|
|||||||
last_action?: "started" | "stopped" | string;
|
last_action?: "started" | "stopped" | string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AppPackageRef {
|
interface AppPackageRef {
|
||||||
manager: string;
|
manager: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AppCapability {
|
interface AppCapability {
|
||||||
type: "cli" | "mcp" | "skill" | string;
|
type: "cli" | "mcp" | "skill" | string;
|
||||||
entry_point?: string;
|
entry_point?: string;
|
||||||
package?: AppPackageRef;
|
package?: AppPackageRef;
|
||||||
@@ -806,20 +806,20 @@ export interface AppCapability {
|
|||||||
}>;
|
}>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AppPlan {
|
interface AppPlan {
|
||||||
supported: boolean;
|
supported: boolean;
|
||||||
strategy?: string;
|
strategy?: string;
|
||||||
managed_paths?: string[];
|
managed_paths?: string[];
|
||||||
verification?: string[];
|
verification?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AppTrust {
|
interface AppTrust {
|
||||||
registry: string;
|
registry: string;
|
||||||
level: string;
|
level: string;
|
||||||
review_status: string;
|
review_status: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AppManifest {
|
interface AppManifest {
|
||||||
schema: "agent-app.v1" | string;
|
schema: "agent-app.v1" | string;
|
||||||
id: string;
|
id: string;
|
||||||
display_name: string;
|
display_name: string;
|
||||||
@@ -935,7 +935,7 @@ export interface NanobotFeaturesPayload {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ChannelSetupStatus =
|
type ChannelSetupStatus =
|
||||||
| "connected"
|
| "connected"
|
||||||
| "configured"
|
| "configured"
|
||||||
| "needs_setup"
|
| "needs_setup"
|
||||||
@@ -943,9 +943,9 @@ export type ChannelSetupStatus =
|
|||||||
| "unsupported"
|
| "unsupported"
|
||||||
| string;
|
| string;
|
||||||
|
|
||||||
export type ChannelValidationCheckStatus = "pass" | "warn" | "fail" | "skipped" | string;
|
type ChannelValidationCheckStatus = "pass" | "warn" | "fail" | "skipped" | string;
|
||||||
|
|
||||||
export interface ChannelValidationCheck {
|
interface ChannelValidationCheck {
|
||||||
id: string;
|
id: string;
|
||||||
label: string;
|
label: string;
|
||||||
status: ChannelValidationCheckStatus;
|
status: ChannelValidationCheckStatus;
|
||||||
@@ -953,7 +953,7 @@ export interface ChannelValidationCheck {
|
|||||||
action_url?: string;
|
action_url?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ChannelIdentity {
|
interface ChannelIdentity {
|
||||||
name?: string;
|
name?: string;
|
||||||
workspace?: string;
|
workspace?: string;
|
||||||
account?: string;
|
account?: string;
|
||||||
@@ -993,7 +993,7 @@ export interface PairingPayload {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface McpPresetField {
|
interface McpPresetField {
|
||||||
name: string;
|
name: string;
|
||||||
label: string;
|
label: string;
|
||||||
secret: boolean;
|
secret: boolean;
|
||||||
@@ -1033,7 +1033,7 @@ export interface McpPresetInfo {
|
|||||||
manifest?: AppManifest;
|
manifest?: AppManifest;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type McpOAuthFlowStatus =
|
type McpOAuthFlowStatus =
|
||||||
| "starting"
|
| "starting"
|
||||||
| "authorization_required"
|
| "authorization_required"
|
||||||
| "connecting"
|
| "connecting"
|
||||||
@@ -1089,7 +1089,7 @@ export interface McpPresetsPayload {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ChannelConnectStatus = "pending" | "succeeded" | "expired" | "cancelled" | "failed";
|
type ChannelConnectStatus = "pending" | "succeeded" | "expired" | "cancelled" | "failed";
|
||||||
|
|
||||||
export interface ChannelConnectPayload {
|
export interface ChannelConnectPayload {
|
||||||
session_id: string;
|
session_id: string;
|
||||||
@@ -1234,7 +1234,7 @@ export type ConnectionStatus =
|
|||||||
| "closed"
|
| "closed"
|
||||||
| "error";
|
| "error";
|
||||||
|
|
||||||
export interface InboundTurnMetadata {
|
interface InboundTurnMetadata {
|
||||||
turn_id?: string;
|
turn_id?: string;
|
||||||
turn_phase?: UITurnPhase;
|
turn_phase?: UITurnPhase;
|
||||||
turn_seq?: number;
|
turn_seq?: number;
|
||||||
@@ -1430,7 +1430,7 @@ export interface OutboundMcpPresetMention {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Response shape for ``GET .../webui-thread`` (server-built transcript replay). */
|
/** Response shape for ``GET .../webui-thread`` (server-built transcript replay). */
|
||||||
export interface WebuiThreadPagePayload {
|
interface WebuiThreadPagePayload {
|
||||||
before_cursor?: string | null;
|
before_cursor?: string | null;
|
||||||
has_more_before?: boolean;
|
has_more_before?: boolean;
|
||||||
loaded_message_count?: number;
|
loaded_message_count?: number;
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export type EncodeInput = {
|
|||||||
file: File;
|
file: File;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type EncodeSuccess = {
|
type EncodeSuccess = {
|
||||||
id: string;
|
id: string;
|
||||||
ok: true;
|
ok: true;
|
||||||
dataUrl: string;
|
dataUrl: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user