diff --git a/echo/.vscode/sessions.json b/echo/.vscode/sessions.json index 7a0e3b91..c330c33e 100644 --- a/echo/.vscode/sessions.json +++ b/echo/.vscode/sessions.json @@ -1,68 +1,68 @@ { "$schema": "https://cdn.statically.io/gh/nguyenngoclongdev/cdn/main/schema/v11/terminal-keeper.json", - "theme": "tribe", "active": "default", "keepExistingTerminals": false, "sessions": { "default": [ { "autoExecuteCommands": true, - "name": "server", - "icon": "server", "commands": [ "cd server", "./run.sh" - ] + ], + "icon": "server", + "name": "server" }, [ { "autoExecuteCommands": true, - "name": "workers", - "icon": "gear", "commands": [ "cd server", "./run-worker.sh" - ] + ], + "icon": "gear", + "name": "workers" }, { "autoExecuteCommands": true, - "name": "workers-cpu", - "icon": "gear", "commands": [ "cd server", "./run-worker-cpu.sh" - ] + ], + "icon": "gear", + "name": "workers-cpu" }, { "autoExecuteCommands": true, - "name": "scheduler", - "icon": "clock", "commands": [ "cd server", "./run-scheduler.sh" - ] + ], + "icon": "clock", + "name": "scheduler" } ], [ { "autoExecuteCommands": true, - "name": "admin-dashboard", - "icon": "browser", "commands": [ "cd frontend", "pnpm run dev" - ] + ], + "icon": "browser", + "name": "admin-dashboard" }, { "autoExecuteCommands": true, - "name": "participant-portal", - "icon": "browser", "commands": [ "cd frontend", "pnpm run participant:dev" - ] + ], + "icon": "browser", + "name": "participant-portal" } ] ] - } + }, + "theme": "tribe" } \ No newline at end of file diff --git a/echo/AGENTS.md b/echo/AGENTS.md index 050c5064..479df426 100644 --- a/echo/AGENTS.md +++ b/echo/AGENTS.md @@ -158,6 +158,8 @@ bash echo/server/scripts/agentic/latest_runs.sh --chat-id --limit 1 | `frontend/src/config.ts` | Frontend feature flags | | `server/dembrane/settings.py` | Backend configuration | | `docs/frontend_translations.md` | Translation workflow | +| `docs/branching_and_releases.md` | Branching strategy, release process, hotfixes | +| `docs/database_migrations.md` | Directus data migration steps | ## Code Style @@ -165,28 +167,85 @@ bash echo/server/scripts/agentic/latest_runs.sh --chat-id --limit 1 - Backend: Python 3.11+, FastAPI, Pydantic - Use existing patterns in the codebase as reference -## Dev Notes +## Branching Strategy & Deployment -### Recent Changes (testing branch) -- Copy guide enforcement: "context limit" → "selection too large" -- Translations updated for all 6 languages -- Suggestions use faster model (`TEXT_FAST` instead of `MULTI_MODAL_PRO`) -- Stream status shows inline under "Thinking..." instead of toast -- Webhooks (conversation-level notifications) +See [docs/branching_and_releases.md](docs/branching_and_releases.md) for the full guide including hotfix process, release checklist, and ASCII diagrams. -### Tech Debt / Known Issues +Quick reference: +- **Feature flow**: branch off `main` → (optional) merge to `testing` → PR to `main` → auto-deploys to Echo Next +- **Releases**: tagged from `main` every ~2 weeks → auto-deploys to production +- **Hotfixes**: branch off release tag → fix → new release → cherry-pick into main +- **Project management**: Linear (`ECHO-xxx` tickets, two-week cycles) +- **GitOps**: `dembrane/echo-gitops` (Terraform + Helm + Argo CD) + +## Architecture Notes + +### High-Level Stack + +``` +Frontend (React/Vite/Mantine) → Backend API (FastAPI) → Directus (headless CMS/DB) + ↕ ↕ + Dramatiq Workers PostgreSQL + (gevent + standard) + ↕ + Redis (pub/sub, task broker, caching) + ↕ + Agent Service (LangGraph, port 8001) +``` + +- **Directus** is the data layer — all collections (projects, conversations, reports, etc.) live there +- **FastAPI** handles API routes, SSE streaming, and orchestration +- **Dramatiq** handles background work: transcription, summarization, report generation +- **Redis** is used for task brokering, pub/sub (SSE progress), and caching +- **LiteLLM** routes all LLM calls with automatic failover between deployments + +### Report Generation Pipeline + +Report generation runs **synchronously** in Dramatiq network-queue workers (no asyncio — this was a deliberate choice after recurring event-loop corruption bugs): + +1. Fetch conversations for the project +2. Fan-out summarization of individual conversations via `dramatiq.group()` +3. Poll Redis for group completion +4. Refetch conversations with summaries +5. Fetch full transcripts via `gevent.pool.Pool` (concurrent I/O) +6. Build prompt with token budget management +7. Call LLM via `router_completion()` (sync litellm, uses `MULTI_MODAL_PRO`) + +Key files: +- `server/dembrane/report_generation.py` — main pipeline +- `server/dembrane/report_events.py` — Redis pub/sub for real-time SSE progress +- `server/prompt_templates/system_report.{lang}.jinja` — per-language prompt templates (written IN the target language) + +### BFF Pattern + +Backend For Frontend endpoints under `/bff/` aggregate data the frontend needs in a single call. This is the preferred pattern over having the frontend make multiple Directus SDK calls directly. + +Example: `/bff/projects/home` bundles pinned projects, paginated project list, search results, and admin info into one response. + +### Transcription Pipeline + +Two-step process: +1. **AssemblyAI** (`universal-3-pro`) for raw speech-to-text — supports en, es, pt, fr, de, it. Dutch ("nl") requires `universal-2` fallback. +2. **Gemini correction** — fixes transcripts, normalizes hotwords, PII redaction, adds recording feedback + +Production uses webhook mode (`ASSEMBLYAI_WEBHOOK_URL`); polling is only a fallback path. + +### Agent Service + +The `agent/` directory contains the agentic chat service (LangGraph-based). It runs as a separate FastAPI service on port 8001. Agentic chat streams via `POST /api/agentic/runs/{run_id}/stream` — no Dramatiq dispatch. See `agent/README.md`. + +## Tech Debt / Known Issues - Some mypy errors in `llm_router.py` and `settings.py` (pre-existing, non-blocking) -## Deployment Process +## Deployment Checklist -### Merging to Main (for echo-next environment) +### Before Merging to Main -1. **Compare branches**: `git log main..testing --oneline` -2. **Check for new env vars**: Look for new `Field()` definitions in `settings.py` and new exports in `config.ts` -3. **Update deployment env vars** if needed (see checklist below) -4. **Push Directus schema** if there were database changes -5. **Create PR**: `testing` → `main` -6. **Deploy** after merge +1. **Check for new env vars**: Look for new `Field()` definitions in `settings.py` and new exports in `config.ts` +2. **Update deployment env vars** if needed (see checklist below) +3. **Push Directus schema** if there were database changes (see `docs/database_migrations.md`) +4. **Create PR** from feature branch to `main` +5. After merge → auto-deploys to Echo Next ### Environment Variables Checklist @@ -225,4 +284,4 @@ LLM__MULTI_MODAL_FAST_2__GCP_SA_JSON=${GCP_SA_JSON} LLM__MULTI_MODAL_FAST_2__VERTEX_LOCATION=europe-west1 ``` -Model groups: `TEXT_FAST`, `MULTI_MODAL_PRO`, `MULTI_MODAL_FAST` +Model groups: `MULTI_MODAL_PRO` (Gemini 2.5 Pro — chat, reports, transcript correction), `MULTI_MODAL_FAST` (Gemini 2.5 Flash — suggestions, verification, lightweight tasks), `TEXT_FAST` (Azure GPT-4.1 — being deprecated) diff --git a/echo/agent/README.md b/echo/agent/README.md index 10c14ccd..d0e562e1 100644 --- a/echo/agent/README.md +++ b/echo/agent/README.md @@ -12,8 +12,9 @@ Isolated CopilotKit/LangGraph runtime for Agentic Chat. ```bash cd echo/agent -cp .env.sample .env -# set GEMINI_API_KEY in .env +# configure Vertex auth via one of: +# - VERTEX_PROJECT + VERTEX_LOCATION + VERTEX_CREDENTIALS / GCP_SA_JSON +# - Application Default Credentials (ADC) uv sync uv run uvicorn main:app --host 0.0.0.0 --port 8001 --reload ``` @@ -35,3 +36,5 @@ docker run --rm -p 8001:8001 --env-file .env echo-agent:local - This service is intentionally scoped to one purpose: agentic chat execution. - Auth, persistence, and notifications should be owned by `echo/server` gateway routes. +- Default model is Vertex Anthropic Claude Opus 4.6 via `LLM_MODEL=claude-opus-4-6`. +- Default Vertex location is `europe-west1` because that is the working Europe region for the current project setup. diff --git a/echo/agent/agent.py b/echo/agent/agent.py index 959696c5..5d73976b 100644 --- a/echo/agent/agent.py +++ b/echo/agent/agent.py @@ -1,11 +1,11 @@ from logging import getLogger +import importlib import re from typing import Any, Callable from copilotkit.langgraph import CopilotKitState from langchain_core.messages import HumanMessage, SystemMessage from langchain_core.tools import tool -from langchain_google_genai import ChatGoogleGenerativeAI from langgraph.checkpoint.memory import MemorySaver from langgraph.graph import END, StateGraph from langgraph.prebuilt import ToolNode @@ -14,6 +14,7 @@ from settings import get_settings logger = getLogger("agent") +VERTEX_AUTH_SCOPES = ["https://www.googleapis.com/auth/cloud-platform"] SYSTEM_PROMPT = """You are the Dembrane Echo assistant — a friendly, conversational AI that helps \ users explore and understand their project's conversation data. @@ -64,7 +65,9 @@ ## Citation policy (when citing project data) - Ground all claims in actual transcript/summary content from tool results. - Provide exact quotes when you have transcripts: "[Participant Name]: quoted text" \ -tagged as [conversation_id:]. +tagged as [conversation_id:;chunk_id:] when chunk ids are available. +- If you only have conversation-level evidence without an exact transcript chunk, cite as \ +[conversation_id:]. - Use quotes to support your points, but don't overwhelm with citations. - When working from summaries only (no transcript retrieved), say so and suggest \ you can retrieve the full transcript if they want exact wording. @@ -92,14 +95,38 @@ ) -def _build_llm() -> ChatGoogleGenerativeAI: +def _build_llm() -> Any: settings = get_settings() - if not settings.gemini_api_key: - raise ValueError("GEMINI_API_KEY is required") - - return ChatGoogleGenerativeAI( - model=settings.llm_model, - google_api_key=settings.gemini_api_key, + try: + vertex_model_garden_module = importlib.import_module( + "langchain_google_vertexai.model_garden" + ) + google_service_account = importlib.import_module("google.oauth2.service_account") + except ModuleNotFoundError as exc: + raise RuntimeError( + "Vertex AI Anthropic dependencies are missing. Install " + "langchain-google-vertexai, anthropic[vertex], and google-auth " + "in the agent environment." + ) from exc + chat_anthropic_vertex = getattr( + vertex_model_garden_module, "ChatAnthropicVertex" + ) + credentials = None + credentials_payload = settings.vertex_credentials or settings.gcp_sa_json + project = settings.vertex_project or None + if credentials_payload: + credentials = google_service_account.Credentials.from_service_account_info( + credentials_payload, + scopes=VERTEX_AUTH_SCOPES, + ) + if not project: + project = credentials_payload.get("project_id") + + return chat_anthropic_vertex( + model_name=settings.llm_model, + project=project, + location=settings.vertex_location, + credentials=credentials, ) @@ -210,66 +237,6 @@ def _keyword_guardrail_result( }, } - def _build_snippet( - *, - line: str, - offset: int, - needle_length: int, - context_window: int = 80, - ) -> str: - start = max(0, offset - context_window) - end = min(len(line), offset + needle_length + context_window) - snippet = line[start:end].strip() - if not snippet: - snippet = line.strip() - if start > 0 and snippet: - snippet = f"...{snippet}" - if end < len(line) and snippet: - snippet = f"{snippet}..." - return snippet - - def _grep_transcript_snippets( - *, - transcript: str, - query: str, - limit: int, - ) -> list[dict[str, Any]]: - normalized_query = query.strip().lower() - if not normalized_query: - return [] - - matches: list[dict[str, Any]] = [] - lines = transcript.splitlines() or [transcript] - - for line_index, line in enumerate(lines): - if not isinstance(line, str): - continue - - lowered = line.lower() - search_offset = 0 - while True: - match_offset = lowered.find(normalized_query, search_offset) - if match_offset < 0: - break - - matches.append( - { - "line_index": line_index, - "offset": match_offset, - "snippet": _build_snippet( - line=line, - offset=match_offset, - needle_length=len(normalized_query), - ), - } - ) - if len(matches) >= limit: - return matches - - search_offset = match_offset + max(1, len(normalized_query)) - - return matches - def _create_echo_client() -> EchoClient: if echo_client_factory: return echo_client_factory(bearer_token) @@ -307,6 +274,7 @@ def _normalize_project_conversation( "started_at": raw.get("startedAt") or raw.get("started_at"), "last_chunk_at": raw.get("lastChunkAt") or raw.get("last_chunk_at"), "summary": raw.get("summary"), + "matches": raw.get("matches") if isinstance(raw.get("matches"), list) else [], } def _cache_project_conversations(conversations: list[dict[str, Any]]) -> None: @@ -562,15 +530,31 @@ async def grepConvoSnippets(conversation_id: str, query: str, limit: int = 8) -> client = _create_echo_client() try: - transcript = await client.get_conversation_transcript(conversation_id) + payload = await client.list_project_conversations( + project_id=project_id, + limit=1, + conversation_id=conversation_id, + transcript_query=normalized_query, + ) finally: await client.close() - matches = _grep_transcript_snippets( - transcript=transcript, - query=normalized_query, - limit=normalized_limit, + conversations = _extract_project_conversations( + payload, + fallback_project_id=project_id, ) + if conversations: + _cache_project_conversations(conversations) + + matches: list[dict[str, Any]] = [] + for candidate in conversations: + if candidate.get("conversation_id") != conversation_id: + continue + candidate_matches = candidate.get("matches") + if isinstance(candidate_matches, list): + matches = candidate_matches[:normalized_limit] + break + return { "project_id": project_id, "conversation_id": conversation_id, diff --git a/echo/agent/echo_client.py b/echo/agent/echo_client.py index 20b8f23a..74b3d35a 100644 --- a/echo/agent/echo_client.py +++ b/echo/agent/echo_client.py @@ -38,6 +38,7 @@ class AgentProjectConversation(TypedDict, total=False): summary: Optional[str] started_at: Optional[str] last_chunk_at: Optional[str] + matches: list[dict[str, Optional[str]]] class AgentProjectConversationsResponse(TypedDict, total=False): diff --git a/echo/agent/pyproject.toml b/echo/agent/pyproject.toml index 7ed31478..30d79cdb 100644 --- a/echo/agent/pyproject.toml +++ b/echo/agent/pyproject.toml @@ -6,7 +6,8 @@ requires-python = ">=3.11" dependencies = [ "copilotkit>=0.1.77", "langgraph>=0.2", - "langchain-google-genai>=2.0", + "langchain-google-vertexai>=3.2.2", + "anthropic[vertex]>=0.49.0", "fastapi>=0.115", "uvicorn[standard]>=0.30", "httpx>=0.27", diff --git a/echo/agent/settings.py b/echo/agent/settings.py index 392ec0b0..77e6a7b7 100644 --- a/echo/agent/settings.py +++ b/echo/agent/settings.py @@ -1,13 +1,22 @@ from functools import lru_cache +import json +from typing import Any, Optional from pydantic import Field +from pydantic import field_validator from pydantic_settings import BaseSettings class Settings(BaseSettings): echo_api_url: str = Field(default="http://localhost:8000/api", alias="ECHO_API_URL") - gemini_api_key: str = Field(default="", alias="GEMINI_API_KEY") - llm_model: str = Field(default="gemini-3-pro-preview", alias="LLM_MODEL") + llm_model: str = Field(default="claude-opus-4-6", alias="LLM_MODEL") + vertex_project: str = Field(default="", alias="VERTEX_PROJECT") + vertex_location: str = Field(default="europe-west1", alias="VERTEX_LOCATION") + vertex_credentials: Optional[dict[str, Any]] = Field( + default=None, + alias="VERTEX_CREDENTIALS", + ) + gcp_sa_json: Optional[dict[str, Any]] = Field(default=None, alias="GCP_SA_JSON") agent_graph_recursion_limit: int = Field( default=80, alias="AGENT_GRAPH_RECURSION_LIMIT", @@ -21,6 +30,19 @@ class Config: env_file = ".env" extra = "ignore" + @field_validator("vertex_credentials", "gcp_sa_json", mode="before") + @classmethod + def parse_json_blob(cls, value: Optional[Any]) -> Optional[dict[str, Any]]: + if value in (None, "", b""): + return None + if isinstance(value, dict): + return value + if isinstance(value, str): + parsed = json.loads(value) + if isinstance(parsed, dict): + return parsed + raise ValueError("Expected a JSON object") + @lru_cache(maxsize=1) def get_settings() -> Settings: diff --git a/echo/agent/tests/test_agent_graph.py b/echo/agent/tests/test_agent_graph.py index f987e4bd..ff045cb6 100644 --- a/echo/agent/tests/test_agent_graph.py +++ b/echo/agent/tests/test_agent_graph.py @@ -1,7 +1,8 @@ import pytest from langchain_core.messages import AIMessage, HumanMessage -from agent import POST_NUDGE_CONTINUATION_SYSTEM_PROMPT, create_agent_graph +import agent +from agent import POST_NUDGE_CONTINUATION_SYSTEM_PROMPT, _build_llm, create_agent_graph class FakeLLM: @@ -72,6 +73,176 @@ def _count_corrective_retry_invocations(invocations: list[list[object]]) -> int: return count +def test_build_llm_prefers_explicit_vertex_credentials(monkeypatch, tmp_path): + class _FakeChatAnthropicVertex: + def __init__(self, **kwargs) -> None: + self.kwargs = kwargs + + class _FakeCredentialsFactory: + calls: list[dict[str, object]] = [] + + @classmethod + def from_service_account_info(cls, value, scopes=None): + cls.calls.append( + { + "scopes": scopes, + "value": value, + } + ) + return {"credentials": value, "scopes": scopes} + + class _FakeVertexModelGardenModule: + ChatAnthropicVertex = _FakeChatAnthropicVertex + + class _FakeServiceAccountModule: + Credentials = _FakeCredentialsFactory + + def _fake_import(name: str): + if name == "langchain_google_vertexai.model_garden": + return _FakeVertexModelGardenModule + if name == "google.oauth2.service_account": + return _FakeServiceAccountModule + raise ModuleNotFoundError(name) + + monkeypatch.chdir(tmp_path) + agent.get_settings.cache_clear() + monkeypatch.setenv("LLM_MODEL", "claude-opus-4-6") + monkeypatch.setenv("VERTEX_PROJECT", "vertex-project") + monkeypatch.setenv("VERTEX_LOCATION", "europe-west4") + monkeypatch.setenv("VERTEX_CREDENTIALS", '{"type":"service_account","project_id":"explicit"}') + monkeypatch.setenv("GCP_SA_JSON", '{"type":"service_account","project_id":"fallback"}') + monkeypatch.setattr(agent.importlib, "import_module", _fake_import) + + llm = _build_llm() + + assert isinstance(llm, _FakeChatAnthropicVertex) + assert llm.kwargs["model_name"] == "claude-opus-4-6" + assert llm.kwargs["project"] == "vertex-project" + assert llm.kwargs["location"] == "europe-west4" + assert llm.kwargs["credentials"] == { + "credentials": { + "type": "service_account", + "project_id": "explicit", + }, + "scopes": ["https://www.googleapis.com/auth/cloud-platform"], + } + assert _FakeCredentialsFactory.calls == [ + { + "scopes": ["https://www.googleapis.com/auth/cloud-platform"], + "value": { + "type": "service_account", + "project_id": "explicit", + }, + } + ] + agent.get_settings.cache_clear() + + +def test_build_llm_uses_adc_when_no_explicit_credentials(monkeypatch, tmp_path): + class _FakeChatAnthropicVertex: + def __init__(self, **kwargs) -> None: + self.kwargs = kwargs + + class _FakeVertexModelGardenModule: + ChatAnthropicVertex = _FakeChatAnthropicVertex + + class _FakeServiceAccountModule: + class Credentials: + @classmethod + def from_service_account_info(cls, value): + raise AssertionError(f"Unexpected explicit credentials: {value}") + + def _fake_import(name: str): + if name == "langchain_google_vertexai.model_garden": + return _FakeVertexModelGardenModule + if name == "google.oauth2.service_account": + return _FakeServiceAccountModule + raise ModuleNotFoundError(name) + + monkeypatch.chdir(tmp_path) + agent.get_settings.cache_clear() + monkeypatch.delenv("VERTEX_CREDENTIALS", raising=False) + monkeypatch.setenv("GCP_SA_JSON", "") + monkeypatch.setenv("LLM_MODEL", "claude-opus-4-6") + monkeypatch.setenv("VERTEX_PROJECT", "vertex-project") + monkeypatch.setenv("VERTEX_LOCATION", "us-central1") + monkeypatch.setattr(agent.importlib, "import_module", _fake_import) + + llm = _build_llm() + + assert isinstance(llm, _FakeChatAnthropicVertex) + assert llm.kwargs["credentials"] is None + assert llm.kwargs["model_name"] == "claude-opus-4-6" + assert llm.kwargs["project"] == "vertex-project" + assert llm.kwargs["location"] == "us-central1" + agent.get_settings.cache_clear() + + +def test_build_llm_falls_back_to_service_account_project_id(monkeypatch, tmp_path): + class _FakeChatAnthropicVertex: + def __init__(self, **kwargs) -> None: + self.kwargs = kwargs + + class _FakeVertexModelGardenModule: + ChatAnthropicVertex = _FakeChatAnthropicVertex + + class _FakeCredentialsFactory: + calls: list[dict[str, str]] = [] + + @classmethod + def from_service_account_info(cls, value, scopes=None): + cls.calls.append( + { + "scopes": scopes, + "value": value, + } + ) + return {"credentials": value, "scopes": scopes} + + class _FakeServiceAccountModule: + Credentials = _FakeCredentialsFactory + + def _fake_import(name: str): + if name == "langchain_google_vertexai.model_garden": + return _FakeVertexModelGardenModule + if name == "google.oauth2.service_account": + return _FakeServiceAccountModule + raise ModuleNotFoundError(name) + + monkeypatch.chdir(tmp_path) + agent.get_settings.cache_clear() + monkeypatch.setenv("VERTEX_PROJECT", "") + monkeypatch.delenv("VERTEX_CREDENTIALS", raising=False) + monkeypatch.setenv("LLM_MODEL", "claude-opus-4-6") + monkeypatch.setenv("VERTEX_LOCATION", "us-central1") + monkeypatch.setenv("GCP_SA_JSON", '{"type":"service_account","project_id":"sa-project"}') + monkeypatch.setattr(agent.importlib, "import_module", _fake_import) + + llm = _build_llm() + + assert isinstance(llm, _FakeChatAnthropicVertex) + assert llm.kwargs["model_name"] == "claude-opus-4-6" + assert llm.kwargs["project"] == "sa-project" + assert llm.kwargs["location"] == "us-central1" + assert llm.kwargs["credentials"] == { + "credentials": { + "type": "service_account", + "project_id": "sa-project", + }, + "scopes": ["https://www.googleapis.com/auth/cloud-platform"], + } + assert _FakeCredentialsFactory.calls == [ + { + "scopes": ["https://www.googleapis.com/auth/cloud-platform"], + "value": { + "type": "service_account", + "project_id": "sa-project", + }, + } + ] + agent.get_settings.cache_clear() + + @pytest.mark.asyncio async def test_create_agent_graph_uses_mocked_llm_deterministically(): graph = create_agent_graph( diff --git a/echo/agent/tests/test_agent_tools.py b/echo/agent/tests/test_agent_tools.py index 0e5188b6..b693f8ff 100644 --- a/echo/agent/tests/test_agent_tools.py +++ b/echo/agent/tests/test_agent_tools.py @@ -128,6 +128,7 @@ def test_system_prompt_contains_conversational_and_research_directives(): assert "analysis guidelines" in prompt # Citation policy still anchors output quality assert '"[participant name]: quoted text"' in prompt + assert "[conversation_id:;chunk_id:]" in SYSTEM_PROMPT assert "[conversation_id:]" in SYSTEM_PROMPT assert "working from summaries only" in prompt assert "retrieve the full transcript" in prompt @@ -522,11 +523,35 @@ async def test_grep_convo_snippets_returns_matches_for_in_scope_conversation(): } ] }, - transcripts={ - "conv-1": "Minority representation matters for trust.\n" - "Some participants discussed representation gaps in media.\n" - "Other topics were unrelated.", + project_conversations_payload_by_transcript_query={ + "representation": { + "project_id": "project-1", + "count": 1, + "conversations": [ + { + "conversation_id": "conv-1", + "participant_name": "Alice", + "status": "done", + "summary": "summary one", + "started_at": "2026-01-01T00:00:00Z", + "last_chunk_at": "2026-01-01T01:00:00Z", + "matches": [ + { + "chunk_id": "chunk-1", + "timestamp": "2026-01-01T00:10:00Z", + "snippet": "Minority representation matters for trust.", + }, + { + "chunk_id": "chunk-2", + "timestamp": "2026-01-01T00:20:00Z", + "snippet": "Some participants discussed representation gaps in media.", + }, + ], + } + ], + } }, + transcripts={}, ) create_agent_graph( @@ -544,7 +569,11 @@ async def test_grep_convo_snippets_returns_matches_for_in_scope_conversation(): assert result["project_id"] == "project-1" assert result["conversation_id"] == "conv-1" assert result["count"] == 2 - assert result["matches"][0]["snippet"] + assert result["matches"][0] == { + "chunk_id": "chunk-1", + "timestamp": "2026-01-01T00:10:00Z", + "snippet": "Minority representation matters for trust.", + } assert factory.instances[-1].closed is True @@ -562,7 +591,24 @@ async def test_grep_convo_snippets_returns_empty_matches_when_no_hits(): } ] }, - transcripts={"conv-1": "No relevant term in this transcript."}, + project_conversations_payload_by_transcript_query={ + "representation": { + "project_id": "project-1", + "count": 1, + "conversations": [ + { + "conversation_id": "conv-1", + "participant_name": "Alice", + "status": "done", + "summary": "summary one", + "started_at": "2026-01-01T00:00:00Z", + "last_chunk_at": "2026-01-01T01:00:00Z", + "matches": [], + } + ], + } + }, + transcripts={}, ) create_agent_graph( diff --git a/echo/agent/tests/test_settings.py b/echo/agent/tests/test_settings.py index 85383df1..a311cac5 100644 --- a/echo/agent/tests/test_settings.py +++ b/echo/agent/tests/test_settings.py @@ -1,19 +1,32 @@ from settings import get_settings -def test_settings_reads_env(monkeypatch): +def test_settings_reads_env(monkeypatch, tmp_path): + monkeypatch.chdir(tmp_path) get_settings.cache_clear() monkeypatch.setenv("ECHO_API_URL", "http://example.test/api") - monkeypatch.setenv("GEMINI_API_KEY", "test-key") - monkeypatch.setenv("LLM_MODEL", "gemini-test") + monkeypatch.setenv("LLM_MODEL", "claude-opus-4-6") + monkeypatch.setenv("VERTEX_PROJECT", "vertex-project") + monkeypatch.setenv("VERTEX_LOCATION", "europe-west4") + monkeypatch.setenv("VERTEX_CREDENTIALS", '{"type":"service_account","project_id":"vertex-project"}') + monkeypatch.setenv("GCP_SA_JSON", '{"type":"service_account","project_id":"fallback-project"}') monkeypatch.setenv("AGENT_GRAPH_RECURSION_LIMIT", "64") monkeypatch.setenv("AGENT_CORS_ORIGINS", "http://localhost:1111,http://localhost:2222") settings = get_settings() assert settings.echo_api_url == "http://example.test/api" - assert settings.gemini_api_key == "test-key" - assert settings.llm_model == "gemini-test" + assert settings.llm_model == "claude-opus-4-6" + assert settings.vertex_project == "vertex-project" + assert settings.vertex_location == "europe-west4" + assert settings.vertex_credentials == { + "type": "service_account", + "project_id": "vertex-project", + } + assert settings.gcp_sa_json == { + "type": "service_account", + "project_id": "fallback-project", + } assert settings.agent_graph_recursion_limit == 64 assert settings.agent_cors_origins == "http://localhost:1111,http://localhost:2222" diff --git a/echo/agent/uv.lock b/echo/agent/uv.lock index 88377b72..be79c388 100644 --- a/echo/agent/uv.lock +++ b/echo/agent/uv.lock @@ -1,6 +1,11 @@ version = 1 revision = 3 requires-python = ">=3.11" +resolution-markers = [ + "python_full_version >= '3.14'", + "python_full_version == '3.13.*'", + "python_full_version < '3.13'", +] [[package]] name = "ag-ui-langgraph" @@ -44,6 +49,30 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, ] +[[package]] +name = "anthropic" +version = "0.85.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "distro" }, + { name = "docstring-parser" }, + { name = "httpx" }, + { name = "jiter" }, + { name = "pydantic" }, + { name = "sniffio" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c5/08/c620a0eb8625539a8ea9f5a6e06f13d131be0bc8b5b714c235d4b25dd1b5/anthropic-0.85.0.tar.gz", hash = "sha256:d45b2f38a1efb1a5d15515a426b272179a0d18783efa2bb4c3925fa773eb50b9", size = 542034, upload-time = "2026-03-16T17:00:44.324Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/5a/9d85b85686d5cdd79f5488c8667e668d7920d06a0a1a1beb454a5b77b2db/anthropic-0.85.0-py3-none-any.whl", hash = "sha256:b4f54d632877ed7b7b29c6d9ba7299d5e21c4c92ae8de38947e9d862bff74adf", size = 458237, upload-time = "2026-03-16T17:00:45.877Z" }, +] + +[package.optional-dependencies] +vertex = [ + { name = "google-auth", extra = ["requests"] }, +] + [[package]] name = "anyio" version = "4.12.1" @@ -57,6 +86,59 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592, upload-time = "2026-01-06T11:45:19.497Z" }, ] +[[package]] +name = "bottleneck" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/14/d8/6d641573e210768816023a64966d66463f2ce9fc9945fa03290c8a18f87c/bottleneck-1.6.0.tar.gz", hash = "sha256:028d46ee4b025ad9ab4d79924113816f825f62b17b87c9e1d0d8ce144a4a0e31", size = 104311, upload-time = "2025-09-08T16:30:38.617Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/96/9d51012d729f97de1e75aad986f3ba50956742a40fc99cbab4c2aa896c1c/bottleneck-1.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:69ef4514782afe39db2497aaea93b1c167ab7ab3bc5e3930500ef9cf11841db7", size = 100400, upload-time = "2025-09-08T16:29:44.464Z" }, + { url = "https://files.pythonhosted.org/packages/16/f4/4fcbebcbc42376a77e395a6838575950587e5eb82edf47d103f8daa7ba22/bottleneck-1.6.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:727363f99edc6dc83d52ed28224d4cb858c07a01c336c7499c0c2e5dd4fd3e4a", size = 375920, upload-time = "2025-09-08T16:29:45.52Z" }, + { url = "https://files.pythonhosted.org/packages/36/13/7fa8cdc41cbf2dfe0540f98e1e0caf9ffbd681b1a0fc679a91c2698adaf9/bottleneck-1.6.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:847671a9e392220d1dfd2ff2524b4d61ec47b2a36ea78e169d2aa357fd9d933a", size = 367922, upload-time = "2025-09-08T16:29:46.743Z" }, + { url = "https://files.pythonhosted.org/packages/13/7d/dccfa4a2792c1bdc0efdde8267e527727e517df1ff0d4976b84e0268c2f9/bottleneck-1.6.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:daef2603ab7b4ec4f032bb54facf5fa92dacd3a264c2fd9677c9fc22bcb5a245", size = 361379, upload-time = "2025-09-08T16:29:48.042Z" }, + { url = "https://files.pythonhosted.org/packages/93/42/21c0fad823b71c3a8904cbb847ad45136d25573a2d001a9cff48d3985fab/bottleneck-1.6.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:fc7f09bda980d967f2e9f1a746eda57479f824f66de0b92b9835c431a8c922d4", size = 371911, upload-time = "2025-09-08T16:29:49.366Z" }, + { url = "https://files.pythonhosted.org/packages/3b/b0/830ff80f8c74577d53034c494639eac7a0ffc70935c01ceadfbe77f590c2/bottleneck-1.6.0-cp311-cp311-win32.whl", hash = "sha256:1f78bad13ad190180f73cceb92d22f4101bde3d768f4647030089f704ae7cac7", size = 107831, upload-time = "2025-09-08T16:29:51.397Z" }, + { url = "https://files.pythonhosted.org/packages/6f/42/01d4920b0aa51fba503f112c90714547609bbe17b6ecfc1c7ae1da3183df/bottleneck-1.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:8f2adef59fdb9edf2983fe3a4c07e5d1b677c43e5669f4711da2c3daad8321ad", size = 113358, upload-time = "2025-09-08T16:29:52.602Z" }, + { url = "https://files.pythonhosted.org/packages/8d/72/7e3593a2a3dd69ec831a9981a7b1443647acb66a5aec34c1620a5f7f8498/bottleneck-1.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3bb16a16a86a655fdbb34df672109a8a227bb5f9c9cf5bb8ae400a639bc52fa3", size = 100515, upload-time = "2025-09-08T16:29:55.141Z" }, + { url = "https://files.pythonhosted.org/packages/b5/d4/e7bbea08f4c0f0bab819d38c1a613da5f194fba7b19aae3e2b3a27e78886/bottleneck-1.6.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0fbf5d0787af9aee6cef4db9cdd14975ce24bd02e0cc30155a51411ebe2ff35f", size = 377451, upload-time = "2025-09-08T16:29:56.718Z" }, + { url = "https://files.pythonhosted.org/packages/fe/80/a6da430e3b1a12fd85f9fe90d3ad8fe9a527ecb046644c37b4b3f4baacfc/bottleneck-1.6.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d08966f4a22384862258940346a72087a6f7cebb19038fbf3a3f6690ee7fd39f", size = 368303, upload-time = "2025-09-08T16:29:57.834Z" }, + { url = "https://files.pythonhosted.org/packages/30/11/abd30a49f3251f4538430e5f876df96f2b39dabf49e05c5836820d2c31fe/bottleneck-1.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:604f0b898b43b7bc631c564630e936a8759d2d952641c8b02f71e31dbcd9deaa", size = 361232, upload-time = "2025-09-08T16:29:59.104Z" }, + { url = "https://files.pythonhosted.org/packages/1d/ac/1c0e09d8d92b9951f675bd42463ce76c3c3657b31c5bf53ca1f6dd9eccff/bottleneck-1.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d33720bad761e642abc18eda5f188ff2841191c9f63f9d0c052245decc0faeb9", size = 373234, upload-time = "2025-09-08T16:30:00.488Z" }, + { url = "https://files.pythonhosted.org/packages/fb/ea/382c572ae3057ba885d484726bb63629d1f63abedf91c6cd23974eb35a9b/bottleneck-1.6.0-cp312-cp312-win32.whl", hash = "sha256:a1e5907ec2714efbe7075d9207b58c22ab6984a59102e4ecd78dced80dab8374", size = 108020, upload-time = "2025-09-08T16:30:01.773Z" }, + { url = "https://files.pythonhosted.org/packages/48/ad/d71da675eef85ac153eef5111ca0caa924548c9591da00939bcabba8de8e/bottleneck-1.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:81e3822499f057a917b7d3972ebc631ac63c6bbcc79ad3542a66c4c40634e3a6", size = 113493, upload-time = "2025-09-08T16:30:02.872Z" }, + { url = "https://files.pythonhosted.org/packages/97/1a/e117cd5ff7056126d3291deb29ac8066476e60b852555b95beb3fc9d62a0/bottleneck-1.6.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d015de414ca016ebe56440bdf5d3d1204085080527a3c51f5b7b7a3e704fe6fd", size = 100521, upload-time = "2025-09-08T16:30:03.89Z" }, + { url = "https://files.pythonhosted.org/packages/bd/22/05555a9752357e24caa1cd92324d1a7fdde6386aab162fcc451f8f8eedc2/bottleneck-1.6.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:456757c9525b0b12356f472e38020ed4b76b18375fd76e055f8d33fb62956f5e", size = 377719, upload-time = "2025-09-08T16:30:05.135Z" }, + { url = "https://files.pythonhosted.org/packages/11/ee/76593af47097d9633109bed04dbcf2170707dd84313ca29f436f9234bc51/bottleneck-1.6.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c65254d51b6063c55f6272f175e867e2078342ae75f74be29d6612e9627b2c0", size = 368577, upload-time = "2025-09-08T16:30:06.387Z" }, + { url = "https://files.pythonhosted.org/packages/f9/f7/4dcacaf637d2b8d89ea746c74159adda43858d47358978880614c3fa4391/bottleneck-1.6.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a172322895fbb79c6127474f1b0db0866895f0b804a18d5c6b841fea093927fe", size = 361441, upload-time = "2025-09-08T16:30:07.613Z" }, + { url = "https://files.pythonhosted.org/packages/05/34/21eb1eb1c42cb7be2872d0647c292fc75768d14e1f0db66bf907b24b2464/bottleneck-1.6.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d5e81b642eb0d5a5bf00312598d7ed142d389728b694322a118c26813f3d1fa9", size = 373416, upload-time = "2025-09-08T16:30:08.899Z" }, + { url = "https://files.pythonhosted.org/packages/48/cb/7957ff40367a151139b5f1854616bf92e578f10804d226fbcdecfd73aead/bottleneck-1.6.0-cp313-cp313-win32.whl", hash = "sha256:543d3a89d22880cd322e44caff859af6c0489657bf9897977d1f5d3d3f77299c", size = 108029, upload-time = "2025-09-08T16:30:09.909Z" }, + { url = "https://files.pythonhosted.org/packages/90/a8/735df4156fa5595501d5d96a6ee102f49c13d2ce9e2a287ad51806bc3ba0/bottleneck-1.6.0-cp313-cp313-win_amd64.whl", hash = "sha256:48a44307d604ceb81e256903e5d57d3adb96a461b1d3c6a69baa2c67e823bd36", size = 113497, upload-time = "2025-09-08T16:30:10.82Z" }, + { url = "https://files.pythonhosted.org/packages/c7/5c/8c1260df8ade7cebc2a8af513a27082b5e36aa4a5fb762d56ea6d969d893/bottleneck-1.6.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:547e6715115867c4657c9ae8cc5ddac1fec8fdad66690be3a322a7488721b06b", size = 101606, upload-time = "2025-09-08T16:30:11.935Z" }, + { url = "https://files.pythonhosted.org/packages/ce/ea/f03e2944e91ee962922c834ed21e5be6d067c8395681f5dc6c67a0a26853/bottleneck-1.6.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5e4a4a6e05b6f014c307969129e10d1a0afd18f3a2c127b085532a4a76677aef", size = 391804, upload-time = "2025-09-08T16:30:13.13Z" }, + { url = "https://files.pythonhosted.org/packages/0b/58/2b356b8a81eb97637dccee6cf58237198dd828890e38be9afb4e5e58e38e/bottleneck-1.6.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2baae0d1589b4a520b2f9cf03528c0c8b20717b3f05675e212ec2200cf628f12", size = 383443, upload-time = "2025-09-08T16:30:14.318Z" }, + { url = "https://files.pythonhosted.org/packages/55/52/cf7d09ed3736ad0d50c624787f9b580ae3206494d95cc0f4814b93eef728/bottleneck-1.6.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2e407139b322f01d8d5b6b2e8091b810f48a25c7fa5c678cfcdc420dfe8aea0a", size = 375458, upload-time = "2025-09-08T16:30:15.379Z" }, + { url = "https://files.pythonhosted.org/packages/c4/e9/7c87a34a24e339860064f20fac49f6738e94f1717bc8726b9c47705601d8/bottleneck-1.6.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1adefb89b92aba6de9c6ea871d99bcd29d519f4fb012cc5197917813b4fc2c7f", size = 386384, upload-time = "2025-09-08T16:30:17.012Z" }, + { url = "https://files.pythonhosted.org/packages/59/57/db51855e18a47671801180be748939b4c9422a0544849af1919116346b5f/bottleneck-1.6.0-cp313-cp313t-win32.whl", hash = "sha256:64b8690393494074923780f6abdf5f5577d844b9d9689725d1575a936e74e5f0", size = 109448, upload-time = "2025-09-08T16:30:18.076Z" }, + { url = "https://files.pythonhosted.org/packages/bd/1e/683c090b624f13a5bf88a0be2241dc301e98b2fb72a45812a7ae6e456cc4/bottleneck-1.6.0-cp313-cp313t-win_amd64.whl", hash = "sha256:cb67247f65dcdf62af947c76c6c8b77d9f0ead442cac0edbaa17850d6da4e48d", size = 115190, upload-time = "2025-09-08T16:30:19.106Z" }, + { url = "https://files.pythonhosted.org/packages/77/e2/eb7c08964a3f3c4719f98795ccd21807ee9dd3071a0f9ad652a5f19196ff/bottleneck-1.6.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:98f1d789042511a0f042b3bdcd2903e8567e956d3aa3be189cce3746daeb8550", size = 100544, upload-time = "2025-09-08T16:30:20.22Z" }, + { url = "https://files.pythonhosted.org/packages/99/ec/c6f3be848f37689f481797ce7d9807d5f69a199d7fc0e46044f9b708c468/bottleneck-1.6.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1fad24c99e39ad7623fc2a76d37feb26bd32e4dd170885edf4dbf4bfce2199a3", size = 378315, upload-time = "2025-09-08T16:30:21.409Z" }, + { url = "https://files.pythonhosted.org/packages/bf/8f/2d6600836e2ea8f14fcefac592dc83497e5b88d381470c958cb9cdf88706/bottleneck-1.6.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:643e61e50a6f993debc399b495a1609a55b3bd76b057e433e4089505d9f605c7", size = 368978, upload-time = "2025-09-08T16:30:23.458Z" }, + { url = "https://files.pythonhosted.org/packages/9b/b5/bf72b49f5040212873b985feef5050015645e0a02204b591e1d265fc522a/bottleneck-1.6.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa668efbe4c6b200524ea0ebd537212da9b9801287138016fdf64119d6fcf201", size = 362074, upload-time = "2025-09-08T16:30:24.71Z" }, + { url = "https://files.pythonhosted.org/packages/1d/c8/c4891a0604eb680031390182c6e264247e3a9a8d067d654362245396fadf/bottleneck-1.6.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9f7dd35262e89e28fedd79d45022394b1fa1aceb61d2e747c6d6842e50546daa", size = 374019, upload-time = "2025-09-08T16:30:26.438Z" }, + { url = "https://files.pythonhosted.org/packages/e6/2d/ed096f8d1b9147e84914045dd89bc64e3c32eee49b862d1e20d573a9ab0d/bottleneck-1.6.0-cp314-cp314-win32.whl", hash = "sha256:bd90bec3c470b7fdfafc2fbdcd7a1c55a4e57b5cdad88d40eea5bc9bab759bf1", size = 110173, upload-time = "2025-09-08T16:30:27.521Z" }, + { url = "https://files.pythonhosted.org/packages/33/70/1414acb6ae378a15063cfb19a0a39d69d1b6baae1120a64d2b069902549b/bottleneck-1.6.0-cp314-cp314-win_amd64.whl", hash = "sha256:b43b6d36a62ffdedc6368cf9a708e4d0a30d98656c2b5f33d88894e1bcfd6857", size = 115899, upload-time = "2025-09-08T16:30:28.524Z" }, + { url = "https://files.pythonhosted.org/packages/4e/ed/4570b5d8c1c85ce3c54963ebc37472231ed54f0b0d8dbb5dde14303f775f/bottleneck-1.6.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:53296707a8e195b5dcaa804b714bd222b5e446bd93cd496008122277eb43fa87", size = 101615, upload-time = "2025-09-08T16:30:29.556Z" }, + { url = "https://files.pythonhosted.org/packages/2d/93/c148faa07ae91f266be1f3fad1fde95aa2449e12937f3f3df2dd720b86e0/bottleneck-1.6.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d6df19cc48a83efd70f6d6874332aa31c3f5ca06a98b782449064abbd564cf0e", size = 392411, upload-time = "2025-09-08T16:30:31.186Z" }, + { url = "https://files.pythonhosted.org/packages/6e/1c/e6ad221d345a059e7efb2ad1d46a22d9fdae0486faef70555766e1123966/bottleneck-1.6.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96bb3a52cb3c0aadfedce3106f93ab940a49c9d35cd4ed612e031f6deb27e80f", size = 384022, upload-time = "2025-09-08T16:30:32.364Z" }, + { url = "https://files.pythonhosted.org/packages/4f/40/5b15c01eb8c59d59bc84c94d01d3d30797c961f10ec190f53c27e05d62ab/bottleneck-1.6.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d1db9e831b69d5595b12e79aeb04cb02873db35576467c8dd26cdc1ee6b74581", size = 376004, upload-time = "2025-09-08T16:30:33.731Z" }, + { url = "https://files.pythonhosted.org/packages/74/f6/cb228f5949553a5c01d1d5a3c933f0216d78540d9e0bf8dd4343bb449681/bottleneck-1.6.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:4dd7ac619570865fcb7a0e8925df418005f076286ad2c702dd0f447231d7a055", size = 386909, upload-time = "2025-09-08T16:30:34.973Z" }, + { url = "https://files.pythonhosted.org/packages/09/9a/425065c37a67a9120bf53290371579b83d05bf46f3212cce65d8c01d470a/bottleneck-1.6.0-cp314-cp314t-win32.whl", hash = "sha256:7fb694165df95d428fe00b98b9ea7d126ef786c4a4b7d43ae2530248396cadcb", size = 111636, upload-time = "2025-09-08T16:30:36.044Z" }, + { url = "https://files.pythonhosted.org/packages/ad/23/c41006e42909ec5114a8961818412310aa54646d1eae0495dbff3598a095/bottleneck-1.6.0-cp314-cp314t-win_amd64.whl", hash = "sha256:174b80930ce82bd8456c67f1abb28a5975c68db49d254783ce2cb6983b4fea40", size = 117611, upload-time = "2025-09-08T16:30:37.055Z" }, +] + [[package]] name = "certifi" version = "2026.1.4" @@ -315,15 +397,25 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" }, ] +[[package]] +name = "docstring-parser" +version = "0.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/9d/c3b43da9515bd270df0f80548d9944e389870713cc1fe2b8fb35fe2bcefd/docstring_parser-0.17.0.tar.gz", hash = "sha256:583de4a309722b3315439bb31d64ba3eebada841f2e2cee23b99df001434c912", size = 27442, upload-time = "2025-07-21T07:35:01.868Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/55/e2/2537ebcff11c1ee1ff17d8d0b6f4db75873e3b0fb32c2d4a2ee31ecb310a/docstring_parser-0.17.0-py3-none-any.whl", hash = "sha256:cf2569abd23dce8099b300f9b4fa8191e9582dda731fd533daf54c4551658708", size = 36896, upload-time = "2025-07-21T07:35:00.684Z" }, +] + [[package]] name = "echo-agent" version = "0.1.0" source = { virtual = "." } dependencies = [ + { name = "anthropic", extra = ["vertex"] }, { name = "copilotkit" }, { name = "fastapi" }, { name = "httpx" }, - { name = "langchain-google-genai" }, + { name = "langchain-google-vertexai" }, { name = "langgraph" }, { name = "pydantic" }, { name = "pydantic-settings" }, @@ -335,10 +427,11 @@ dependencies = [ [package.metadata] requires-dist = [ + { name = "anthropic", extras = ["vertex"], specifier = ">=0.49.0" }, { name = "copilotkit", specifier = ">=0.1.77" }, { name = "fastapi", specifier = ">=0.115" }, { name = "httpx", specifier = ">=0.27" }, - { name = "langchain-google-genai", specifier = ">=2.0" }, + { name = "langchain-google-vertexai", specifier = ">=3.2.2" }, { name = "langgraph", specifier = ">=0.2" }, { name = "pydantic", specifier = ">=2.0" }, { name = "pydantic-settings", specifier = ">=2.0" }, @@ -363,12 +456,25 @@ wheels = [ ] [[package]] -name = "filetype" -version = "1.2.0" +name = "google-api-core" +version = "2.30.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bb/29/745f7d30d47fe0f251d3ad3dc2978a23141917661998763bebb6da007eb1/filetype-1.2.0.tar.gz", hash = "sha256:66b56cd6474bf41d8c54660347d37afcc3f7d1970648de365c102ef77548aadb", size = 998020, upload-time = "2022-11-02T17:34:04.141Z" } +dependencies = [ + { name = "google-auth" }, + { name = "googleapis-common-protos" }, + { name = "proto-plus" }, + { name = "protobuf" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/22/98/586ec94553b569080caef635f98a3723db36a38eac0e3d7eb3ea9d2e4b9a/google_api_core-2.30.0.tar.gz", hash = "sha256:02edfa9fab31e17fc0befb5f161b3bf93c9096d99aed584625f38065c511ad9b", size = 176959, upload-time = "2026-02-18T20:28:11.926Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/18/79/1b8fa1bb3568781e84c9200f951c735f3f157429f44be0495da55894d620/filetype-1.2.0-py2.py3-none-any.whl", hash = "sha256:7ce71b6880181241cf7ac8697a2f1eb6a8bd9b429f7ad6d27b8db9ba5f1c2d25", size = 19970, upload-time = "2022-11-02T17:34:01.425Z" }, + { url = "https://files.pythonhosted.org/packages/45/27/09c33d67f7e0dcf06d7ac17d196594e66989299374bfb0d4331d1038e76b/google_api_core-2.30.0-py3-none-any.whl", hash = "sha256:80be49ee937ff9aba0fd79a6eddfde35fe658b9953ab9b79c57dd7061afa8df5", size = 173288, upload-time = "2026-02-18T20:28:10.367Z" }, +] + +[package.optional-dependencies] +grpc = [ + { name = "grpcio" }, + { name = "grpcio-status" }, ] [[package]] @@ -390,6 +496,140 @@ requests = [ { name = "requests" }, ] +[[package]] +name = "google-cloud-aiplatform" +version = "1.141.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "docstring-parser" }, + { name = "google-api-core", extra = ["grpc"] }, + { name = "google-auth" }, + { name = "google-cloud-bigquery" }, + { name = "google-cloud-resource-manager" }, + { name = "google-cloud-storage" }, + { name = "google-genai" }, + { name = "packaging" }, + { name = "proto-plus" }, + { name = "protobuf" }, + { name = "pydantic" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ac/dc/1209c7aab43bd7233cf631165a3b1b4284d22fc7fe7387c66228d07868ab/google_cloud_aiplatform-1.141.0.tar.gz", hash = "sha256:e3b1cdb28865dd862aac9c685dfc5ac076488705aba0a5354016efadcddd59c6", size = 10152688, upload-time = "2026-03-10T22:20:08.692Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/fc/428af69a69ff2e477e7f5e12d227b31fe5790f1a8234aacd54297f49c836/google_cloud_aiplatform-1.141.0-py2.py3-none-any.whl", hash = "sha256:6bd25b4d514c40b8181ca703e1b313ad6d0454ab8006fc9907fb3e9f672f31d1", size = 8358409, upload-time = "2026-03-10T22:20:04.871Z" }, +] + +[[package]] +name = "google-cloud-bigquery" +version = "3.40.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core", extra = ["grpc"] }, + { name = "google-auth" }, + { name = "google-cloud-core" }, + { name = "google-resumable-media" }, + { name = "packaging" }, + { name = "python-dateutil" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/11/0c/153ee546c288949fcc6794d58811ab5420f3ecad5fa7f9e73f78d9512a6e/google_cloud_bigquery-3.40.1.tar.gz", hash = "sha256:75afcfb6e007238fe1deefb2182105249321145ff921784fe7b1de2b4ba24506", size = 511761, upload-time = "2026-02-12T18:44:18.958Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/f5/081cf5b90adfe524ae0d671781b0d497a75a0f2601d075af518828e22d8f/google_cloud_bigquery-3.40.1-py3-none-any.whl", hash = "sha256:9082a6b8193aba87bed6a2c79cf1152b524c99bb7e7ac33a785e333c09eac868", size = 262018, upload-time = "2026-02-12T18:44:16.913Z" }, +] + +[[package]] +name = "google-cloud-core" +version = "2.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core" }, + { name = "google-auth" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a6/03/ef0bc99d0e0faf4fdbe67ac445e18cdaa74824fd93cd069e7bb6548cb52d/google_cloud_core-2.5.0.tar.gz", hash = "sha256:7c1b7ef5c92311717bd05301aa1a91ffbc565673d3b0b4163a52d8413a186963", size = 36027, upload-time = "2025-10-29T23:17:39.513Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/89/20/bfa472e327c8edee00f04beecc80baeddd2ab33ee0e86fd7654da49d45e9/google_cloud_core-2.5.0-py3-none-any.whl", hash = "sha256:67d977b41ae6c7211ee830c7912e41003ea8194bff15ae7d72fd6f51e57acabc", size = 29469, upload-time = "2025-10-29T23:17:38.548Z" }, +] + +[[package]] +name = "google-cloud-resource-manager" +version = "1.16.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core", extra = ["grpc"] }, + { name = "google-auth" }, + { name = "grpc-google-iam-v1" }, + { name = "grpcio" }, + { name = "proto-plus" }, + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4e/7f/db00b2820475793a52958dc55fe9ec2eb8e863546e05fcece9b921f86ebe/google_cloud_resource_manager-1.16.0.tar.gz", hash = "sha256:cc938f87cc36c2672f062b1e541650629e0d954c405a4dac35ceedee70c267c3", size = 459840, upload-time = "2026-01-15T13:04:07.726Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/ff/4b28bcc791d9d7e4ac8fea00fbd90ccb236afda56746a3b4564d2ae45df3/google_cloud_resource_manager-1.16.0-py3-none-any.whl", hash = "sha256:fb9a2ad2b5053c508e1c407ac31abfd1a22e91c32876c1892830724195819a28", size = 400218, upload-time = "2026-01-15T13:02:47.378Z" }, +] + +[[package]] +name = "google-cloud-storage" +version = "3.10.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core" }, + { name = "google-auth" }, + { name = "google-cloud-core" }, + { name = "google-crc32c" }, + { name = "google-resumable-media" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7a/e3/747759eebc72e420c25903d6bc231d0ceb110b66ac7e6ee3f350417152cd/google_cloud_storage-3.10.0.tar.gz", hash = "sha256:1aeebf097c27d718d84077059a28d7e87f136f3700212215f1ceeae1d1c5d504", size = 17309829, upload-time = "2026-03-18T15:54:11.875Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/29/e2/d58442f4daee5babd9255cf492a1f3d114357164072f8339a22a3ad460a2/google_cloud_storage-3.10.0-py3-none-any.whl", hash = "sha256:0072e7783b201e45af78fd9779894cdb6bec2bf922ee932f3fcc16f8bce9b9a3", size = 324382, upload-time = "2026-03-18T15:54:10.091Z" }, +] + +[[package]] +name = "google-cloud-vectorsearch" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core", extra = ["grpc"] }, + { name = "google-auth" }, + { name = "grpcio" }, + { name = "proto-plus" }, + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ee/8f/c30e0bbf19f57702fb8c87833285d37c61e310bc27c5965a2c06812b516e/google_cloud_vectorsearch-0.7.0.tar.gz", hash = "sha256:d30a18d66848f1aa6a215ba933a02c0b7b7c8ad943b9d80244a44e0e060544f0", size = 405338, upload-time = "2026-03-09T20:42:32.664Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/ae/839b1127aab19c8508c30116faf4a6303be39c9f1af8f3e61065a8a8708f/google_cloud_vectorsearch-0.7.0-py3-none-any.whl", hash = "sha256:0ba9adf3a0725e07c3a604387b9ebd65f09a6d881d8ca3d2310b0b82a5e2bc02", size = 344356, upload-time = "2026-03-09T20:42:30.608Z" }, +] + +[[package]] +name = "google-crc32c" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/03/41/4b9c02f99e4c5fb477122cd5437403b552873f014616ac1d19ac8221a58d/google_crc32c-1.8.0.tar.gz", hash = "sha256:a428e25fb7691024de47fecfbff7ff957214da51eddded0da0ae0e0f03a2cf79", size = 14192, upload-time = "2025-12-16T00:35:25.142Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/ef/21ccfaab3d5078d41efe8612e0ed0bfc9ce22475de074162a91a25f7980d/google_crc32c-1.8.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:014a7e68d623e9a4222d663931febc3033c5c7c9730785727de2a81f87d5bab8", size = 31298, upload-time = "2025-12-16T00:20:32.241Z" }, + { url = "https://files.pythonhosted.org/packages/c5/b8/f8413d3f4b676136e965e764ceedec904fe38ae8de0cdc52a12d8eb1096e/google_crc32c-1.8.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:86cfc00fe45a0ac7359e5214a1704e51a99e757d0272554874f419f79838c5f7", size = 30872, upload-time = "2025-12-16T00:33:58.785Z" }, + { url = "https://files.pythonhosted.org/packages/f6/fd/33aa4ec62b290477181c55bb1c9302c9698c58c0ce9a6ab4874abc8b0d60/google_crc32c-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:19b40d637a54cb71e0829179f6cb41835f0fbd9e8eb60552152a8b52c36cbe15", size = 33243, upload-time = "2025-12-16T00:40:21.46Z" }, + { url = "https://files.pythonhosted.org/packages/71/03/4820b3bd99c9653d1a5210cb32f9ba4da9681619b4d35b6a052432df4773/google_crc32c-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:17446feb05abddc187e5441a45971b8394ea4c1b6efd88ab0af393fd9e0a156a", size = 33608, upload-time = "2025-12-16T00:40:22.204Z" }, + { url = "https://files.pythonhosted.org/packages/7c/43/acf61476a11437bf9733fb2f70599b1ced11ec7ed9ea760fdd9a77d0c619/google_crc32c-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:71734788a88f551fbd6a97be9668a0020698e07b2bf5b3aa26a36c10cdfb27b2", size = 34439, upload-time = "2025-12-16T00:35:20.458Z" }, + { url = "https://files.pythonhosted.org/packages/e9/5f/7307325b1198b59324c0fa9807cafb551afb65e831699f2ce211ad5c8240/google_crc32c-1.8.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:4b8286b659c1335172e39563ab0a768b8015e88e08329fa5321f774275fc3113", size = 31300, upload-time = "2025-12-16T00:21:56.723Z" }, + { url = "https://files.pythonhosted.org/packages/21/8e/58c0d5d86e2220e6a37befe7e6a94dd2f6006044b1a33edf1ff6d9f7e319/google_crc32c-1.8.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:2a3dc3318507de089c5384cc74d54318401410f82aa65b2d9cdde9d297aca7cb", size = 30867, upload-time = "2025-12-16T00:38:31.302Z" }, + { url = "https://files.pythonhosted.org/packages/ce/a9/a780cc66f86335a6019f557a8aaca8fbb970728f0efd2430d15ff1beae0e/google_crc32c-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:14f87e04d613dfa218d6135e81b78272c3b904e2a7053b841481b38a7d901411", size = 33364, upload-time = "2025-12-16T00:40:22.96Z" }, + { url = "https://files.pythonhosted.org/packages/21/3f/3457ea803db0198c9aaca2dd373750972ce28a26f00544b6b85088811939/google_crc32c-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cb5c869c2923d56cb0c8e6bcdd73c009c36ae39b652dbe46a05eb4ef0ad01454", size = 33740, upload-time = "2025-12-16T00:40:23.96Z" }, + { url = "https://files.pythonhosted.org/packages/df/c0/87c2073e0c72515bb8733d4eef7b21548e8d189f094b5dad20b0ecaf64f6/google_crc32c-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:3cc0c8912038065eafa603b238abf252e204accab2a704c63b9e14837a854962", size = 34437, upload-time = "2025-12-16T00:35:21.395Z" }, + { url = "https://files.pythonhosted.org/packages/d1/db/000f15b41724589b0e7bc24bc7a8967898d8d3bc8caf64c513d91ef1f6c0/google_crc32c-1.8.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:3ebb04528e83b2634857f43f9bb8ef5b2bbe7f10f140daeb01b58f972d04736b", size = 31297, upload-time = "2025-12-16T00:23:20.709Z" }, + { url = "https://files.pythonhosted.org/packages/d7/0d/8ebed0c39c53a7e838e2a486da8abb0e52de135f1b376ae2f0b160eb4c1a/google_crc32c-1.8.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:450dc98429d3e33ed2926fc99ee81001928d63460f8538f21a5d6060912a8e27", size = 30867, upload-time = "2025-12-16T00:43:14.628Z" }, + { url = "https://files.pythonhosted.org/packages/ce/42/b468aec74a0354b34c8cbf748db20d6e350a68a2b0912e128cabee49806c/google_crc32c-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3b9776774b24ba76831609ffbabce8cdf6fa2bd5e9df37b594221c7e333a81fa", size = 33344, upload-time = "2025-12-16T00:40:24.742Z" }, + { url = "https://files.pythonhosted.org/packages/1c/e8/b33784d6fc77fb5062a8a7854e43e1e618b87d5ddf610a88025e4de6226e/google_crc32c-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:89c17d53d75562edfff86679244830599ee0a48efc216200691de8b02ab6b2b8", size = 33694, upload-time = "2025-12-16T00:40:25.505Z" }, + { url = "https://files.pythonhosted.org/packages/92/b1/d3cbd4d988afb3d8e4db94ca953df429ed6db7282ed0e700d25e6c7bfc8d/google_crc32c-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:57a50a9035b75643996fbf224d6661e386c7162d1dfdab9bc4ca790947d1007f", size = 34435, upload-time = "2025-12-16T00:35:22.107Z" }, + { url = "https://files.pythonhosted.org/packages/21/88/8ecf3c2b864a490b9e7010c84fd203ec8cf3b280651106a3a74dd1b0ca72/google_crc32c-1.8.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:e6584b12cb06796d285d09e33f63309a09368b9d806a551d8036a4207ea43697", size = 31301, upload-time = "2025-12-16T00:24:48.527Z" }, + { url = "https://files.pythonhosted.org/packages/36/c6/f7ff6c11f5ca215d9f43d3629163727a272eabc356e5c9b2853df2bfe965/google_crc32c-1.8.0-cp314-cp314-macosx_12_0_x86_64.whl", hash = "sha256:f4b51844ef67d6cf2e9425983274da75f18b1597bb2c998e1c0a0e8d46f8f651", size = 30868, upload-time = "2025-12-16T00:48:12.163Z" }, + { url = "https://files.pythonhosted.org/packages/56/15/c25671c7aad70f8179d858c55a6ae8404902abe0cdcf32a29d581792b491/google_crc32c-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b0d1a7afc6e8e4635564ba8aa5c0548e3173e41b6384d7711a9123165f582de2", size = 33381, upload-time = "2025-12-16T00:40:26.268Z" }, + { url = "https://files.pythonhosted.org/packages/42/fa/f50f51260d7b0ef5d4898af122d8a7ec5a84e2984f676f746445f783705f/google_crc32c-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8b3f68782f3cbd1bce027e48768293072813469af6a61a86f6bb4977a4380f21", size = 33734, upload-time = "2025-12-16T00:40:27.028Z" }, + { url = "https://files.pythonhosted.org/packages/08/a5/7b059810934a09fb3ccb657e0843813c1fee1183d3bc2c8041800374aa2c/google_crc32c-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:d511b3153e7011a27ab6ee6bb3a5404a55b994dc1a7322c0b87b29606d9790e2", size = 34878, upload-time = "2025-12-16T00:35:23.142Z" }, + { url = "https://files.pythonhosted.org/packages/52/c5/c171e4d8c44fec1422d801a6d2e5d7ddabd733eeda505c79730ee9607f07/google_crc32c-1.8.0-pp311-pypy311_pp73-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:87fa445064e7db928226b2e6f0d5304ab4cd0339e664a4e9a25029f384d9bb93", size = 28615, upload-time = "2025-12-16T00:40:29.298Z" }, + { url = "https://files.pythonhosted.org/packages/9c/97/7d75fe37a7a6ed171a2cf17117177e7aab7e6e0d115858741b41e9dd4254/google_crc32c-1.8.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f639065ea2042d5c034bf258a9f085eaa7af0cd250667c0635a3118e8f92c69c", size = 28800, upload-time = "2025-12-16T00:40:30.322Z" }, +] + [[package]] name = "google-genai" version = "1.62.0" @@ -411,6 +651,114 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/09/5f/4645d8a28c6e431d0dd6011003a852563f3da7037d36af53154925b099fd/google_genai-1.62.0-py3-none-any.whl", hash = "sha256:4c3daeff3d05fafee4b9a1a31f9c07f01bc22051081aa58b4d61f58d16d1bcc0", size = 724166, upload-time = "2026-02-04T22:48:39.956Z" }, ] +[[package]] +name = "google-resumable-media" +version = "2.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-crc32c" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/64/d7/520b62a35b23038ff005e334dba3ffc75fcf583bee26723f1fd8fd4b6919/google_resumable_media-2.8.0.tar.gz", hash = "sha256:f1157ed8b46994d60a1bc432544db62352043113684d4e030ee02e77ebe9a1ae", size = 2163265, upload-time = "2025-11-17T15:38:06.659Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1f/0b/93afde9cfe012260e9fe1522f35c9b72d6ee222f316586b1f23ecf44d518/google_resumable_media-2.8.0-py3-none-any.whl", hash = "sha256:dd14a116af303845a8d932ddae161a26e86cc229645bc98b39f026f9b1717582", size = 81340, upload-time = "2025-11-17T15:38:05.594Z" }, +] + +[[package]] +name = "googleapis-common-protos" +version = "1.73.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/99/96/a0205167fa0154f4a542fd6925bdc63d039d88dab3588b875078107e6f06/googleapis_common_protos-1.73.0.tar.gz", hash = "sha256:778d07cd4fbeff84c6f7c72102f0daf98fa2bfd3fa8bea426edc545588da0b5a", size = 147323, upload-time = "2026-03-06T21:53:09.727Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/28/23eea8acd65972bbfe295ce3666b28ac510dfcb115fac089d3edb0feb00a/googleapis_common_protos-1.73.0-py3-none-any.whl", hash = "sha256:dfdaaa2e860f242046be561e6d6cb5c5f1541ae02cfbcb034371aadb2942b4e8", size = 297578, upload-time = "2026-03-06T21:52:33.933Z" }, +] + +[package.optional-dependencies] +grpc = [ + { name = "grpcio" }, +] + +[[package]] +name = "grpc-google-iam-v1" +version = "0.14.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "googleapis-common-protos", extra = ["grpc"] }, + { name = "grpcio" }, + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/76/1e/1011451679a983f2f5c6771a1682542ecb027776762ad031fd0d7129164b/grpc_google_iam_v1-0.14.3.tar.gz", hash = "sha256:879ac4ef33136c5491a6300e27575a9ec760f6cdf9a2518798c1b8977a5dc389", size = 23745, upload-time = "2025-10-15T21:14:53.318Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4a/bd/330a1bbdb1afe0b96311249e699b6dc9cfc17916394fd4503ac5aca2514b/grpc_google_iam_v1-0.14.3-py3-none-any.whl", hash = "sha256:7a7f697e017a067206a3dfef44e4c634a34d3dee135fe7d7a4613fe3e59217e6", size = 32690, upload-time = "2025-10-15T21:14:51.72Z" }, +] + +[[package]] +name = "grpcio" +version = "1.78.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/8a/3d098f35c143a89520e568e6539cc098fcd294495910e359889ce8741c84/grpcio-1.78.0.tar.gz", hash = "sha256:7382b95189546f375c174f53a5fa873cef91c4b8005faa05cc5b3beea9c4f1c5", size = 12852416, upload-time = "2026-02-06T09:57:18.093Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/86/c7/d0b780a29b0837bf4ca9580904dfb275c1fc321ded7897d620af7047ec57/grpcio-1.78.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:2777b783f6c13b92bd7b716667452c329eefd646bfb3f2e9dabea2e05dbd34f6", size = 5951525, upload-time = "2026-02-06T09:55:01.989Z" }, + { url = "https://files.pythonhosted.org/packages/c5/b1/96920bf2ee61df85a9503cb6f733fe711c0ff321a5a697d791b075673281/grpcio-1.78.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:9dca934f24c732750389ce49d638069c3892ad065df86cb465b3fa3012b70c9e", size = 11830418, upload-time = "2026-02-06T09:55:04.462Z" }, + { url = "https://files.pythonhosted.org/packages/83/0c/7c1528f098aeb75a97de2bae18c530f56959fb7ad6c882db45d9884d6edc/grpcio-1.78.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:459ab414b35f4496138d0ecd735fed26f1318af5e52cb1efbc82a09f0d5aa911", size = 6524477, upload-time = "2026-02-06T09:55:07.111Z" }, + { url = "https://files.pythonhosted.org/packages/8d/52/e7c1f3688f949058e19a011c4e0dec973da3d0ae5e033909677f967ae1f4/grpcio-1.78.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:082653eecbdf290e6e3e2c276ab2c54b9e7c299e07f4221872380312d8cf395e", size = 7198266, upload-time = "2026-02-06T09:55:10.016Z" }, + { url = "https://files.pythonhosted.org/packages/e5/61/8ac32517c1e856677282c34f2e7812d6c328fa02b8f4067ab80e77fdc9c9/grpcio-1.78.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:85f93781028ec63f383f6bc90db785a016319c561cc11151fbb7b34e0d012303", size = 6730552, upload-time = "2026-02-06T09:55:12.207Z" }, + { url = "https://files.pythonhosted.org/packages/bd/98/b8ee0158199250220734f620b12e4a345955ac7329cfd908d0bf0fda77f0/grpcio-1.78.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f12857d24d98441af6a1d5c87442d624411db486f7ba12550b07788f74b67b04", size = 7304296, upload-time = "2026-02-06T09:55:15.044Z" }, + { url = "https://files.pythonhosted.org/packages/bd/0f/7b72762e0d8840b58032a56fdbd02b78fc645b9fa993d71abf04edbc54f4/grpcio-1.78.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5397fff416b79e4b284959642a4e95ac4b0f1ece82c9993658e0e477d40551ec", size = 8288298, upload-time = "2026-02-06T09:55:17.276Z" }, + { url = "https://files.pythonhosted.org/packages/24/ae/ae4ce56bc5bb5caa3a486d60f5f6083ac3469228faa734362487176c15c5/grpcio-1.78.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:fbe6e89c7ffb48518384068321621b2a69cab509f58e40e4399fdd378fa6d074", size = 7730953, upload-time = "2026-02-06T09:55:19.545Z" }, + { url = "https://files.pythonhosted.org/packages/b5/6e/8052e3a28eb6a820c372b2eb4b5e32d195c661e137d3eca94d534a4cfd8a/grpcio-1.78.0-cp311-cp311-win32.whl", hash = "sha256:6092beabe1966a3229f599d7088b38dfc8ffa1608b5b5cdda31e591e6500f856", size = 4076503, upload-time = "2026-02-06T09:55:21.521Z" }, + { url = "https://files.pythonhosted.org/packages/08/62/f22c98c5265dfad327251fa2f840b591b1df5f5e15d88b19c18c86965b27/grpcio-1.78.0-cp311-cp311-win_amd64.whl", hash = "sha256:1afa62af6e23f88629f2b29ec9e52ec7c65a7176c1e0a83292b93c76ca882558", size = 4799767, upload-time = "2026-02-06T09:55:24.107Z" }, + { url = "https://files.pythonhosted.org/packages/4e/f4/7384ed0178203d6074446b3c4f46c90a22ddf7ae0b3aee521627f54cfc2a/grpcio-1.78.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:f9ab915a267fc47c7e88c387a3a28325b58c898e23d4995f765728f4e3dedb97", size = 5913985, upload-time = "2026-02-06T09:55:26.832Z" }, + { url = "https://files.pythonhosted.org/packages/81/ed/be1caa25f06594463f685b3790b320f18aea49b33166f4141bfdc2bfb236/grpcio-1.78.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3f8904a8165ab21e07e58bf3e30a73f4dffc7a1e0dbc32d51c61b5360d26f43e", size = 11811853, upload-time = "2026-02-06T09:55:29.224Z" }, + { url = "https://files.pythonhosted.org/packages/24/a7/f06d151afc4e64b7e3cc3e872d331d011c279aaab02831e40a81c691fb65/grpcio-1.78.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:859b13906ce098c0b493af92142ad051bf64c7870fa58a123911c88606714996", size = 6475766, upload-time = "2026-02-06T09:55:31.825Z" }, + { url = "https://files.pythonhosted.org/packages/8a/a8/4482922da832ec0082d0f2cc3a10976d84a7424707f25780b82814aafc0a/grpcio-1.78.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:b2342d87af32790f934a79c3112641e7b27d63c261b8b4395350dad43eff1dc7", size = 7170027, upload-time = "2026-02-06T09:55:34.7Z" }, + { url = "https://files.pythonhosted.org/packages/54/bf/f4a3b9693e35d25b24b0b39fa46d7d8a3c439e0a3036c3451764678fec20/grpcio-1.78.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:12a771591ae40bc65ba67048fa52ef4f0e6db8279e595fd349f9dfddeef571f9", size = 6690766, upload-time = "2026-02-06T09:55:36.902Z" }, + { url = "https://files.pythonhosted.org/packages/c7/b9/521875265cc99fe5ad4c5a17010018085cae2810a928bf15ebe7d8bcd9cc/grpcio-1.78.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:185dea0d5260cbb2d224c507bf2a5444d5abbb1fa3594c1ed7e4c709d5eb8383", size = 7266161, upload-time = "2026-02-06T09:55:39.824Z" }, + { url = "https://files.pythonhosted.org/packages/05/86/296a82844fd40a4ad4a95f100b55044b4f817dece732bf686aea1a284147/grpcio-1.78.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:51b13f9aed9d59ee389ad666b8c2214cc87b5de258fa712f9ab05f922e3896c6", size = 8253303, upload-time = "2026-02-06T09:55:42.353Z" }, + { url = "https://files.pythonhosted.org/packages/f3/e4/ea3c0caf5468537f27ad5aab92b681ed7cc0ef5f8c9196d3fd42c8c2286b/grpcio-1.78.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fd5f135b1bd58ab088930b3c613455796dfa0393626a6972663ccdda5b4ac6ce", size = 7698222, upload-time = "2026-02-06T09:55:44.629Z" }, + { url = "https://files.pythonhosted.org/packages/d7/47/7f05f81e4bb6b831e93271fb12fd52ba7b319b5402cbc101d588f435df00/grpcio-1.78.0-cp312-cp312-win32.whl", hash = "sha256:94309f498bcc07e5a7d16089ab984d42ad96af1d94b5a4eb966a266d9fcabf68", size = 4066123, upload-time = "2026-02-06T09:55:47.644Z" }, + { url = "https://files.pythonhosted.org/packages/ad/e7/d6914822c88aa2974dbbd10903d801a28a19ce9cd8bad7e694cbbcf61528/grpcio-1.78.0-cp312-cp312-win_amd64.whl", hash = "sha256:9566fe4ababbb2610c39190791e5b829869351d14369603702e890ef3ad2d06e", size = 4797657, upload-time = "2026-02-06T09:55:49.86Z" }, + { url = "https://files.pythonhosted.org/packages/05/a9/8f75894993895f361ed8636cd9237f4ab39ef87fd30db17467235ed1c045/grpcio-1.78.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:ce3a90455492bf8bfa38e56fbbe1dbd4f872a3d8eeaf7337dc3b1c8aa28c271b", size = 5920143, upload-time = "2026-02-06T09:55:52.035Z" }, + { url = "https://files.pythonhosted.org/packages/55/06/0b78408e938ac424100100fd081189451b472236e8a3a1f6500390dc4954/grpcio-1.78.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:2bf5e2e163b356978b23652c4818ce4759d40f4712ee9ec5a83c4be6f8c23a3a", size = 11803926, upload-time = "2026-02-06T09:55:55.494Z" }, + { url = "https://files.pythonhosted.org/packages/88/93/b59fe7832ff6ae3c78b813ea43dac60e295fa03606d14d89d2e0ec29f4f3/grpcio-1.78.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8f2ac84905d12918e4e55a16da17939eb63e433dc11b677267c35568aa63fc84", size = 6478628, upload-time = "2026-02-06T09:55:58.533Z" }, + { url = "https://files.pythonhosted.org/packages/ed/df/e67e3734527f9926b7d9c0dde6cd998d1d26850c3ed8eeec81297967ac67/grpcio-1.78.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:b58f37edab4a3881bc6c9bca52670610e0c9ca14e2ea3cf9debf185b870457fb", size = 7173574, upload-time = "2026-02-06T09:56:01.786Z" }, + { url = "https://files.pythonhosted.org/packages/a6/62/cc03fffb07bfba982a9ec097b164e8835546980aec25ecfa5f9c1a47e022/grpcio-1.78.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:735e38e176a88ce41840c21bb49098ab66177c64c82426e24e0082500cc68af5", size = 6692639, upload-time = "2026-02-06T09:56:04.529Z" }, + { url = "https://files.pythonhosted.org/packages/bf/9a/289c32e301b85bdb67d7ec68b752155e674ee3ba2173a1858f118e399ef3/grpcio-1.78.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2045397e63a7a0ee7957c25f7dbb36ddc110e0cfb418403d110c0a7a68a844e9", size = 7268838, upload-time = "2026-02-06T09:56:08.397Z" }, + { url = "https://files.pythonhosted.org/packages/0e/79/1be93f32add280461fa4773880196572563e9c8510861ac2da0ea0f892b6/grpcio-1.78.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a9f136fbafe7ccf4ac7e8e0c28b31066e810be52d6e344ef954a3a70234e1702", size = 8251878, upload-time = "2026-02-06T09:56:10.914Z" }, + { url = "https://files.pythonhosted.org/packages/65/65/793f8e95296ab92e4164593674ae6291b204bb5f67f9d4a711489cd30ffa/grpcio-1.78.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:748b6138585379c737adc08aeffd21222abbda1a86a0dca2a39682feb9196c20", size = 7695412, upload-time = "2026-02-06T09:56:13.593Z" }, + { url = "https://files.pythonhosted.org/packages/1c/9f/1e233fe697ecc82845942c2822ed06bb522e70d6771c28d5528e4c50f6a4/grpcio-1.78.0-cp313-cp313-win32.whl", hash = "sha256:271c73e6e5676afe4fc52907686670c7cea22ab2310b76a59b678403ed40d670", size = 4064899, upload-time = "2026-02-06T09:56:15.601Z" }, + { url = "https://files.pythonhosted.org/packages/4d/27/d86b89e36de8a951501fb06a0f38df19853210f341d0b28f83f4aa0ffa08/grpcio-1.78.0-cp313-cp313-win_amd64.whl", hash = "sha256:f2d4e43ee362adfc05994ed479334d5a451ab7bc3f3fee1b796b8ca66895acb4", size = 4797393, upload-time = "2026-02-06T09:56:17.882Z" }, + { url = "https://files.pythonhosted.org/packages/29/f2/b56e43e3c968bfe822fa6ce5bca10d5c723aa40875b48791ce1029bb78c7/grpcio-1.78.0-cp314-cp314-linux_armv7l.whl", hash = "sha256:e87cbc002b6f440482b3519e36e1313eb5443e9e9e73d6a52d43bd2004fcfd8e", size = 5920591, upload-time = "2026-02-06T09:56:20.758Z" }, + { url = "https://files.pythonhosted.org/packages/5d/81/1f3b65bd30c334167bfa8b0d23300a44e2725ce39bba5b76a2460d85f745/grpcio-1.78.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:c41bc64626db62e72afec66b0c8a0da76491510015417c127bfc53b2fe6d7f7f", size = 11813685, upload-time = "2026-02-06T09:56:24.315Z" }, + { url = "https://files.pythonhosted.org/packages/0e/1c/bbe2f8216a5bd3036119c544d63c2e592bdf4a8ec6e4a1867592f4586b26/grpcio-1.78.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8dfffba826efcf366b1e3ccc37e67afe676f290e13a3b48d31a46739f80a8724", size = 6487803, upload-time = "2026-02-06T09:56:27.367Z" }, + { url = "https://files.pythonhosted.org/packages/16/5c/a6b2419723ea7ddce6308259a55e8e7593d88464ce8db9f4aa857aba96fa/grpcio-1.78.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:74be1268d1439eaaf552c698cdb11cd594f0c49295ae6bb72c34ee31abbe611b", size = 7173206, upload-time = "2026-02-06T09:56:29.876Z" }, + { url = "https://files.pythonhosted.org/packages/df/1e/b8801345629a415ea7e26c83d75eb5dbe91b07ffe5210cc517348a8d4218/grpcio-1.78.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:be63c88b32e6c0f1429f1398ca5c09bc64b0d80950c8bb7807d7d7fb36fb84c7", size = 6693826, upload-time = "2026-02-06T09:56:32.305Z" }, + { url = "https://files.pythonhosted.org/packages/34/84/0de28eac0377742679a510784f049738a80424b17287739fc47d63c2439e/grpcio-1.78.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:3c586ac70e855c721bda8f548d38c3ca66ac791dc49b66a8281a1f99db85e452", size = 7277897, upload-time = "2026-02-06T09:56:34.915Z" }, + { url = "https://files.pythonhosted.org/packages/ca/9c/ad8685cfe20559a9edb66f735afdcb2b7d3de69b13666fdfc542e1916ebd/grpcio-1.78.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:35eb275bf1751d2ffbd8f57cdbc46058e857cf3971041521b78b7db94bdaf127", size = 8252404, upload-time = "2026-02-06T09:56:37.553Z" }, + { url = "https://files.pythonhosted.org/packages/3c/05/33a7a4985586f27e1de4803887c417ec7ced145ebd069bc38a9607059e2b/grpcio-1.78.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:207db540302c884b8848036b80db352a832b99dfdf41db1eb554c2c2c7800f65", size = 7696837, upload-time = "2026-02-06T09:56:40.173Z" }, + { url = "https://files.pythonhosted.org/packages/73/77/7382241caf88729b106e49e7d18e3116216c778e6a7e833826eb96de22f7/grpcio-1.78.0-cp314-cp314-win32.whl", hash = "sha256:57bab6deef2f4f1ca76cc04565df38dc5713ae6c17de690721bdf30cb1e0545c", size = 4142439, upload-time = "2026-02-06T09:56:43.258Z" }, + { url = "https://files.pythonhosted.org/packages/48/b2/b096ccce418882fbfda4f7496f9357aaa9a5af1896a9a7f60d9f2b275a06/grpcio-1.78.0-cp314-cp314-win_amd64.whl", hash = "sha256:dce09d6116df20a96acfdbf85e4866258c3758180e8c49845d6ba8248b6d0bbb", size = 4929852, upload-time = "2026-02-06T09:56:45.885Z" }, +] + +[[package]] +name = "grpcio-status" +version = "1.78.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "googleapis-common-protos" }, + { name = "grpcio" }, + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8a/cd/89ce482a931b543b92cdd9b2888805518c4620e0094409acb8c81dd4610a/grpcio_status-1.78.0.tar.gz", hash = "sha256:a34cfd28101bfea84b5aa0f936b4b423019e9213882907166af6b3bddc59e189", size = 13808, upload-time = "2026-02-06T10:01:48.034Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/8a/1241ec22c41028bddd4a052ae9369267b4475265ad0ce7140974548dc3fa/grpcio_status-1.78.0-py3-none-any.whl", hash = "sha256:b492b693d4bf27b47a6c32590701724f1d3b9444b36491878fb71f6208857f34", size = 14523, upload-time = "2026-02-06T10:01:32.584Z" }, +] + [[package]] name = "h11" version = "0.16.0" @@ -484,6 +832,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, ] +[[package]] +name = "httpx-sse" +version = "0.4.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/4c/751061ffa58615a32c31b2d82e8482be8dd4a89154f003147acee90f2be9/httpx_sse-0.4.3.tar.gz", hash = "sha256:9b1ed0127459a66014aec3c56bebd93da3c1bc8bb6618c8082039a44889a755d", size = 15943, upload-time = "2025-10-10T21:48:22.271Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl", hash = "sha256:0ac1c9fe3c0afad2e0ebb25a934a59f4c7823b60792691f779fad2c5568830fc", size = 8960, upload-time = "2025-10-10T21:48:21.158Z" }, +] + [[package]] name = "idna" version = "3.11" @@ -502,6 +859,91 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, ] +[[package]] +name = "jiter" +version = "0.13.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0d/5e/4ec91646aee381d01cdb9974e30882c9cd3b8c5d1079d6b5ff4af522439a/jiter-0.13.0.tar.gz", hash = "sha256:f2839f9c2c7e2dffc1bc5929a510e14ce0a946be9365fd1219e7ef342dae14f4", size = 164847, upload-time = "2026-02-02T12:37:56.441Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/71/29/499f8c9eaa8a16751b1c0e45e6f5f1761d180da873d417996cc7bddc8eef/jiter-0.13.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ea026e70a9a28ebbdddcbcf0f1323128a8db66898a06eaad3a4e62d2f554d096", size = 311157, upload-time = "2026-02-02T12:35:37.758Z" }, + { url = "https://files.pythonhosted.org/packages/50/f6/566364c777d2ab450b92100bea11333c64c38d32caf8dc378b48e5b20c46/jiter-0.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:66aa3e663840152d18cc8ff1e4faad3dd181373491b9cfdc6004b92198d67911", size = 319729, upload-time = "2026-02-02T12:35:39.246Z" }, + { url = "https://files.pythonhosted.org/packages/73/dd/560f13ec5e4f116d8ad2658781646cca91b617ae3b8758d4a5076b278f70/jiter-0.13.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3524798e70655ff19aec58c7d05adb1f074fecff62da857ea9be2b908b6d701", size = 354766, upload-time = "2026-02-02T12:35:40.662Z" }, + { url = "https://files.pythonhosted.org/packages/7c/0d/061faffcfe94608cbc28a0d42a77a74222bdf5055ccdbe5fd2292b94f510/jiter-0.13.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ec7e287d7fbd02cb6e22f9a00dd9c9cd504c40a61f2c61e7e1f9690a82726b4c", size = 362587, upload-time = "2026-02-02T12:35:42.025Z" }, + { url = "https://files.pythonhosted.org/packages/92/c9/c66a7864982fd38a9773ec6e932e0398d1262677b8c60faecd02ffb67bf3/jiter-0.13.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:47455245307e4debf2ce6c6e65a717550a0244231240dcf3b8f7d64e4c2f22f4", size = 487537, upload-time = "2026-02-02T12:35:43.459Z" }, + { url = "https://files.pythonhosted.org/packages/6c/86/84eb4352cd3668f16d1a88929b5888a3fe0418ea8c1dfc2ad4e7bf6e069a/jiter-0.13.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ee9da221dca6e0429c2704c1b3655fe7b025204a71d4d9b73390c759d776d165", size = 373717, upload-time = "2026-02-02T12:35:44.928Z" }, + { url = "https://files.pythonhosted.org/packages/6e/09/9fe4c159358176f82d4390407a03f506a8659ed13ca3ac93a843402acecf/jiter-0.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24ab43126d5e05f3d53a36a8e11eb2f23304c6c1117844aaaf9a0aa5e40b5018", size = 362683, upload-time = "2026-02-02T12:35:46.636Z" }, + { url = "https://files.pythonhosted.org/packages/c9/5e/85f3ab9caca0c1d0897937d378b4a515cae9e119730563572361ea0c48ae/jiter-0.13.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9da38b4fedde4fb528c740c2564628fbab737166a0e73d6d46cb4bb5463ff411", size = 392345, upload-time = "2026-02-02T12:35:48.088Z" }, + { url = "https://files.pythonhosted.org/packages/12/4c/05b8629ad546191939e6f0c2f17e29f542a398f4a52fb987bc70b6d1eb8b/jiter-0.13.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0b34c519e17658ed88d5047999a93547f8889f3c1824120c26ad6be5f27b6cf5", size = 517775, upload-time = "2026-02-02T12:35:49.482Z" }, + { url = "https://files.pythonhosted.org/packages/4d/88/367ea2eb6bc582c7052e4baf5ddf57ebe5ab924a88e0e09830dfb585c02d/jiter-0.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d2a6394e6af690d462310a86b53c47ad75ac8c21dc79f120714ea449979cb1d3", size = 551325, upload-time = "2026-02-02T12:35:51.104Z" }, + { url = "https://files.pythonhosted.org/packages/f3/12/fa377ffb94a2f28c41afaed093e0d70cfe512035d5ecb0cad0ae4792d35e/jiter-0.13.0-cp311-cp311-win32.whl", hash = "sha256:0f0c065695f616a27c920a56ad0d4fc46415ef8b806bf8fc1cacf25002bd24e1", size = 204709, upload-time = "2026-02-02T12:35:52.467Z" }, + { url = "https://files.pythonhosted.org/packages/cb/16/8e8203ce92f844dfcd3d9d6a5a7322c77077248dbb12da52d23193a839cd/jiter-0.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:0733312953b909688ae3c2d58d043aa040f9f1a6a75693defed7bc2cc4bf2654", size = 204560, upload-time = "2026-02-02T12:35:53.925Z" }, + { url = "https://files.pythonhosted.org/packages/44/26/97cc40663deb17b9e13c3a5cf29251788c271b18ee4d262c8f94798b8336/jiter-0.13.0-cp311-cp311-win_arm64.whl", hash = "sha256:5d9b34ad56761b3bf0fbe8f7e55468704107608512350962d3317ffd7a4382d5", size = 189608, upload-time = "2026-02-02T12:35:55.304Z" }, + { url = "https://files.pythonhosted.org/packages/2e/30/7687e4f87086829955013ca12a9233523349767f69653ebc27036313def9/jiter-0.13.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0a2bd69fc1d902e89925fc34d1da51b2128019423d7b339a45d9e99c894e0663", size = 307958, upload-time = "2026-02-02T12:35:57.165Z" }, + { url = "https://files.pythonhosted.org/packages/c3/27/e57f9a783246ed95481e6749cc5002a8a767a73177a83c63ea71f0528b90/jiter-0.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f917a04240ef31898182f76a332f508f2cc4b57d2b4d7ad2dbfebbfe167eb505", size = 318597, upload-time = "2026-02-02T12:35:58.591Z" }, + { url = "https://files.pythonhosted.org/packages/cf/52/e5719a60ac5d4d7c5995461a94ad5ef962a37c8bf5b088390e6fad59b2ff/jiter-0.13.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1e2b199f446d3e82246b4fd9236d7cb502dc2222b18698ba0d986d2fecc6152", size = 348821, upload-time = "2026-02-02T12:36:00.093Z" }, + { url = "https://files.pythonhosted.org/packages/61/db/c1efc32b8ba4c740ab3fc2d037d8753f67685f475e26b9d6536a4322bcdd/jiter-0.13.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04670992b576fa65bd056dbac0c39fe8bd67681c380cb2b48efa885711d9d726", size = 364163, upload-time = "2026-02-02T12:36:01.937Z" }, + { url = "https://files.pythonhosted.org/packages/55/8a/fb75556236047c8806995671a18e4a0ad646ed255276f51a20f32dceaeec/jiter-0.13.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5a1aff1fbdb803a376d4d22a8f63f8e7ccbce0b4890c26cc7af9e501ab339ef0", size = 483709, upload-time = "2026-02-02T12:36:03.41Z" }, + { url = "https://files.pythonhosted.org/packages/7e/16/43512e6ee863875693a8e6f6d532e19d650779d6ba9a81593ae40a9088ff/jiter-0.13.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b3fb8c2053acaef8580809ac1d1f7481a0a0bdc012fd7f5d8b18fb696a5a089", size = 370480, upload-time = "2026-02-02T12:36:04.791Z" }, + { url = "https://files.pythonhosted.org/packages/f8/4c/09b93e30e984a187bc8aaa3510e1ec8dcbdcd71ca05d2f56aac0492453aa/jiter-0.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bdaba7d87e66f26a2c45d8cbadcbfc4bf7884182317907baf39cfe9775bb4d93", size = 360735, upload-time = "2026-02-02T12:36:06.994Z" }, + { url = "https://files.pythonhosted.org/packages/1a/1b/46c5e349019874ec5dfa508c14c37e29864ea108d376ae26d90bee238cd7/jiter-0.13.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7b88d649135aca526da172e48083da915ec086b54e8e73a425ba50999468cc08", size = 391814, upload-time = "2026-02-02T12:36:08.368Z" }, + { url = "https://files.pythonhosted.org/packages/15/9e/26184760e85baee7162ad37b7912797d2077718476bf91517641c92b3639/jiter-0.13.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e404ea551d35438013c64b4f357b0474c7abf9f781c06d44fcaf7a14c69ff9e2", size = 513990, upload-time = "2026-02-02T12:36:09.993Z" }, + { url = "https://files.pythonhosted.org/packages/e9/34/2c9355247d6debad57a0a15e76ab1566ab799388042743656e566b3b7de1/jiter-0.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1f4748aad1b4a93c8bdd70f604d0f748cdc0e8744c5547798acfa52f10e79228", size = 548021, upload-time = "2026-02-02T12:36:11.376Z" }, + { url = "https://files.pythonhosted.org/packages/ac/4a/9f2c23255d04a834398b9c2e0e665382116911dc4d06b795710503cdad25/jiter-0.13.0-cp312-cp312-win32.whl", hash = "sha256:0bf670e3b1445fc4d31612199f1744f67f889ee1bbae703c4b54dc097e5dd394", size = 203024, upload-time = "2026-02-02T12:36:12.682Z" }, + { url = "https://files.pythonhosted.org/packages/09/ee/f0ae675a957ae5a8f160be3e87acea6b11dc7b89f6b7ab057e77b2d2b13a/jiter-0.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:15db60e121e11fe186c0b15236bd5d18381b9ddacdcf4e659feb96fc6c969c92", size = 205424, upload-time = "2026-02-02T12:36:13.93Z" }, + { url = "https://files.pythonhosted.org/packages/1b/02/ae611edf913d3cbf02c97cdb90374af2082c48d7190d74c1111dde08bcdd/jiter-0.13.0-cp312-cp312-win_arm64.whl", hash = "sha256:41f92313d17989102f3cb5dd533a02787cdb99454d494344b0361355da52fcb9", size = 186818, upload-time = "2026-02-02T12:36:15.308Z" }, + { url = "https://files.pythonhosted.org/packages/91/9c/7ee5a6ff4b9991e1a45263bfc46731634c4a2bde27dfda6c8251df2d958c/jiter-0.13.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1f8a55b848cbabf97d861495cd65f1e5c590246fabca8b48e1747c4dfc8f85bf", size = 306897, upload-time = "2026-02-02T12:36:16.748Z" }, + { url = "https://files.pythonhosted.org/packages/7c/02/be5b870d1d2be5dd6a91bdfb90f248fbb7dcbd21338f092c6b89817c3dbf/jiter-0.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f556aa591c00f2c45eb1b89f68f52441a016034d18b65da60e2d2875bbbf344a", size = 317507, upload-time = "2026-02-02T12:36:18.351Z" }, + { url = "https://files.pythonhosted.org/packages/da/92/b25d2ec333615f5f284f3a4024f7ce68cfa0604c322c6808b2344c7f5d2b/jiter-0.13.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7e1d61da332ec412350463891923f960c3073cf1aae93b538f0bb4c8cd46efb", size = 350560, upload-time = "2026-02-02T12:36:19.746Z" }, + { url = "https://files.pythonhosted.org/packages/be/ec/74dcb99fef0aca9fbe56b303bf79f6bd839010cb18ad41000bf6cc71eec0/jiter-0.13.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3097d665a27bc96fd9bbf7f86178037db139f319f785e4757ce7ccbf390db6c2", size = 363232, upload-time = "2026-02-02T12:36:21.243Z" }, + { url = "https://files.pythonhosted.org/packages/1b/37/f17375e0bb2f6a812d4dd92d7616e41917f740f3e71343627da9db2824ce/jiter-0.13.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d01ecc3a8cbdb6f25a37bd500510550b64ddf9f7d64a107d92f3ccb25035d0f", size = 483727, upload-time = "2026-02-02T12:36:22.688Z" }, + { url = "https://files.pythonhosted.org/packages/77/d2/a71160a5ae1a1e66c1395b37ef77da67513b0adba73b993a27fbe47eb048/jiter-0.13.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ed9bbc30f5d60a3bdf63ae76beb3f9db280d7f195dfcfa61af792d6ce912d159", size = 370799, upload-time = "2026-02-02T12:36:24.106Z" }, + { url = "https://files.pythonhosted.org/packages/01/99/ed5e478ff0eb4e8aa5fd998f9d69603c9fd3f32de3bd16c2b1194f68361c/jiter-0.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98fbafb6e88256f4454de33c1f40203d09fc33ed19162a68b3b257b29ca7f663", size = 359120, upload-time = "2026-02-02T12:36:25.519Z" }, + { url = "https://files.pythonhosted.org/packages/16/be/7ffd08203277a813f732ba897352797fa9493faf8dc7995b31f3d9cb9488/jiter-0.13.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5467696f6b827f1116556cb0db620440380434591e93ecee7fd14d1a491b6daa", size = 390664, upload-time = "2026-02-02T12:36:26.866Z" }, + { url = "https://files.pythonhosted.org/packages/d1/84/e0787856196d6d346264d6dcccb01f741e5f0bd014c1d9a2ebe149caf4f3/jiter-0.13.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:2d08c9475d48b92892583df9da592a0e2ac49bcd41fae1fec4f39ba6cf107820", size = 513543, upload-time = "2026-02-02T12:36:28.217Z" }, + { url = "https://files.pythonhosted.org/packages/65/50/ecbd258181c4313cf79bca6c88fb63207d04d5bf5e4f65174114d072aa55/jiter-0.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:aed40e099404721d7fcaf5b89bd3b4568a4666358bcac7b6b15c09fb6252ab68", size = 547262, upload-time = "2026-02-02T12:36:29.678Z" }, + { url = "https://files.pythonhosted.org/packages/27/da/68f38d12e7111d2016cd198161b36e1f042bd115c169255bcb7ec823a3bf/jiter-0.13.0-cp313-cp313-win32.whl", hash = "sha256:36ebfbcffafb146d0e6ffb3e74d51e03d9c35ce7c625c8066cdbfc7b953bdc72", size = 200630, upload-time = "2026-02-02T12:36:31.808Z" }, + { url = "https://files.pythonhosted.org/packages/25/65/3bd1a972c9a08ecd22eb3b08a95d1941ebe6938aea620c246cf426ae09c2/jiter-0.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:8d76029f077379374cf0dbc78dbe45b38dec4a2eb78b08b5194ce836b2517afc", size = 202602, upload-time = "2026-02-02T12:36:33.679Z" }, + { url = "https://files.pythonhosted.org/packages/15/fe/13bd3678a311aa67686bb303654792c48206a112068f8b0b21426eb6851e/jiter-0.13.0-cp313-cp313-win_arm64.whl", hash = "sha256:bb7613e1a427cfcb6ea4544f9ac566b93d5bf67e0d48c787eca673ff9c9dff2b", size = 185939, upload-time = "2026-02-02T12:36:35.065Z" }, + { url = "https://files.pythonhosted.org/packages/49/19/a929ec002ad3228bc97ca01dbb14f7632fffdc84a95ec92ceaf4145688ae/jiter-0.13.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fa476ab5dd49f3bf3a168e05f89358c75a17608dbabb080ef65f96b27c19ab10", size = 316616, upload-time = "2026-02-02T12:36:36.579Z" }, + { url = "https://files.pythonhosted.org/packages/52/56/d19a9a194afa37c1728831e5fb81b7722c3de18a3109e8f282bfc23e587a/jiter-0.13.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ade8cb6ff5632a62b7dbd4757d8c5573f7a2e9ae285d6b5b841707d8363205ef", size = 346850, upload-time = "2026-02-02T12:36:38.058Z" }, + { url = "https://files.pythonhosted.org/packages/36/4a/94e831c6bf287754a8a019cb966ed39ff8be6ab78cadecf08df3bb02d505/jiter-0.13.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9950290340acc1adaded363edd94baebcee7dabdfa8bee4790794cd5cfad2af6", size = 358551, upload-time = "2026-02-02T12:36:39.417Z" }, + { url = "https://files.pythonhosted.org/packages/a2/ec/a4c72c822695fa80e55d2b4142b73f0012035d9fcf90eccc56bc060db37c/jiter-0.13.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2b4972c6df33731aac0742b64fd0d18e0a69bc7d6e03108ce7d40c85fd9e3e6d", size = 201950, upload-time = "2026-02-02T12:36:40.791Z" }, + { url = "https://files.pythonhosted.org/packages/b6/00/393553ec27b824fbc29047e9c7cd4a3951d7fbe4a76743f17e44034fa4e4/jiter-0.13.0-cp313-cp313t-win_arm64.whl", hash = "sha256:701a1e77d1e593c1b435315ff625fd071f0998c5f02792038a5ca98899261b7d", size = 185852, upload-time = "2026-02-02T12:36:42.077Z" }, + { url = "https://files.pythonhosted.org/packages/6e/f5/f1997e987211f6f9bd71b8083047b316208b4aca0b529bb5f8c96c89ef3e/jiter-0.13.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:cc5223ab19fe25e2f0bf2643204ad7318896fe3729bf12fde41b77bfc4fafff0", size = 308804, upload-time = "2026-02-02T12:36:43.496Z" }, + { url = "https://files.pythonhosted.org/packages/cd/8f/5482a7677731fd44881f0204981ce2d7175db271f82cba2085dd2212e095/jiter-0.13.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9776ebe51713acf438fd9b4405fcd86893ae5d03487546dae7f34993217f8a91", size = 318787, upload-time = "2026-02-02T12:36:45.071Z" }, + { url = "https://files.pythonhosted.org/packages/f3/b9/7257ac59778f1cd025b26a23c5520a36a424f7f1b068f2442a5b499b7464/jiter-0.13.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:879e768938e7b49b5e90b7e3fecc0dbec01b8cb89595861fb39a8967c5220d09", size = 353880, upload-time = "2026-02-02T12:36:47.365Z" }, + { url = "https://files.pythonhosted.org/packages/c3/87/719eec4a3f0841dad99e3d3604ee4cba36af4419a76f3cb0b8e2e691ad67/jiter-0.13.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:682161a67adea11e3aae9038c06c8b4a9a71023228767477d683f69903ebc607", size = 366702, upload-time = "2026-02-02T12:36:48.871Z" }, + { url = "https://files.pythonhosted.org/packages/d2/65/415f0a75cf6921e43365a1bc227c565cb949caca8b7532776e430cbaa530/jiter-0.13.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a13b68cd1cd8cc9de8f244ebae18ccb3e4067ad205220ef324c39181e23bbf66", size = 486319, upload-time = "2026-02-02T12:36:53.006Z" }, + { url = "https://files.pythonhosted.org/packages/54/a2/9e12b48e82c6bbc6081fd81abf915e1443add1b13d8fc586e1d90bb02bb8/jiter-0.13.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87ce0f14c6c08892b610686ae8be350bf368467b6acd5085a5b65441e2bf36d2", size = 372289, upload-time = "2026-02-02T12:36:54.593Z" }, + { url = "https://files.pythonhosted.org/packages/4e/c1/e4693f107a1789a239c759a432e9afc592366f04e901470c2af89cfd28e1/jiter-0.13.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c365005b05505a90d1c47856420980d0237adf82f70c4aff7aebd3c1cc143ad", size = 360165, upload-time = "2026-02-02T12:36:56.112Z" }, + { url = "https://files.pythonhosted.org/packages/17/08/91b9ea976c1c758240614bd88442681a87672eebc3d9a6dde476874e706b/jiter-0.13.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1317fdffd16f5873e46ce27d0e0f7f4f90f0cdf1d86bf6abeaea9f63ca2c401d", size = 389634, upload-time = "2026-02-02T12:36:57.495Z" }, + { url = "https://files.pythonhosted.org/packages/18/23/58325ef99390d6d40427ed6005bf1ad54f2577866594bcf13ce55675f87d/jiter-0.13.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:c05b450d37ba0c9e21c77fef1f205f56bcee2330bddca68d344baebfc55ae0df", size = 514933, upload-time = "2026-02-02T12:36:58.909Z" }, + { url = "https://files.pythonhosted.org/packages/5b/25/69f1120c7c395fd276c3996bb8adefa9c6b84c12bb7111e5c6ccdcd8526d/jiter-0.13.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:775e10de3849d0631a97c603f996f518159272db00fdda0a780f81752255ee9d", size = 548842, upload-time = "2026-02-02T12:37:00.433Z" }, + { url = "https://files.pythonhosted.org/packages/18/05/981c9669d86850c5fbb0d9e62bba144787f9fba84546ba43d624ee27ef29/jiter-0.13.0-cp314-cp314-win32.whl", hash = "sha256:632bf7c1d28421c00dd8bbb8a3bac5663e1f57d5cd5ed962bce3c73bf62608e6", size = 202108, upload-time = "2026-02-02T12:37:01.718Z" }, + { url = "https://files.pythonhosted.org/packages/8d/96/cdcf54dd0b0341db7d25413229888a346c7130bd20820530905fdb65727b/jiter-0.13.0-cp314-cp314-win_amd64.whl", hash = "sha256:f22ef501c3f87ede88f23f9b11e608581c14f04db59b6a801f354397ae13739f", size = 204027, upload-time = "2026-02-02T12:37:03.075Z" }, + { url = "https://files.pythonhosted.org/packages/fb/f9/724bcaaab7a3cd727031fe4f6995cb86c4bd344909177c186699c8dec51a/jiter-0.13.0-cp314-cp314-win_arm64.whl", hash = "sha256:07b75fe09a4ee8e0c606200622e571e44943f47254f95e2436c8bdcaceb36d7d", size = 187199, upload-time = "2026-02-02T12:37:04.414Z" }, + { url = "https://files.pythonhosted.org/packages/62/92/1661d8b9fd6a3d7a2d89831db26fe3c1509a287d83ad7838831c7b7a5c7e/jiter-0.13.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:964538479359059a35fb400e769295d4b315ae61e4105396d355a12f7fef09f0", size = 318423, upload-time = "2026-02-02T12:37:05.806Z" }, + { url = "https://files.pythonhosted.org/packages/4f/3b/f77d342a54d4ebcd128e520fc58ec2f5b30a423b0fd26acdfc0c6fef8e26/jiter-0.13.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e104da1db1c0991b3eaed391ccd650ae8d947eab1480c733e5a3fb28d4313e40", size = 351438, upload-time = "2026-02-02T12:37:07.189Z" }, + { url = "https://files.pythonhosted.org/packages/76/b3/ba9a69f0e4209bd3331470c723c2f5509e6f0482e416b612431a5061ed71/jiter-0.13.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0e3a5f0cde8ff433b8e88e41aa40131455420fb3649a3c7abdda6145f8cb7202", size = 364774, upload-time = "2026-02-02T12:37:08.579Z" }, + { url = "https://files.pythonhosted.org/packages/b3/16/6cdb31fa342932602458dbb631bfbd47f601e03d2e4950740e0b2100b570/jiter-0.13.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:57aab48f40be1db920a582b30b116fe2435d184f77f0e4226f546794cedd9cf0", size = 487238, upload-time = "2026-02-02T12:37:10.066Z" }, + { url = "https://files.pythonhosted.org/packages/ed/b1/956cc7abaca8d95c13aa8d6c9b3f3797241c246cd6e792934cc4c8b250d2/jiter-0.13.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7772115877c53f62beeb8fd853cab692dbc04374ef623b30f997959a4c0e7e95", size = 372892, upload-time = "2026-02-02T12:37:11.656Z" }, + { url = "https://files.pythonhosted.org/packages/26/c4/97ecde8b1e74f67b8598c57c6fccf6df86ea7861ed29da84629cdbba76c4/jiter-0.13.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1211427574b17b633cfceba5040de8081e5abf114f7a7602f73d2e16f9fdaa59", size = 360309, upload-time = "2026-02-02T12:37:13.244Z" }, + { url = "https://files.pythonhosted.org/packages/4b/d7/eabe3cf46715854ccc80be2cd78dd4c36aedeb30751dbf85a1d08c14373c/jiter-0.13.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7beae3a3d3b5212d3a55d2961db3c292e02e302feb43fce6a3f7a31b90ea6dfe", size = 389607, upload-time = "2026-02-02T12:37:14.881Z" }, + { url = "https://files.pythonhosted.org/packages/df/2d/03963fc0804e6109b82decfb9974eb92df3797fe7222428cae12f8ccaa0c/jiter-0.13.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:e5562a0f0e90a6223b704163ea28e831bd3a9faa3512a711f031611e6b06c939", size = 514986, upload-time = "2026-02-02T12:37:16.326Z" }, + { url = "https://files.pythonhosted.org/packages/f6/6c/8c83b45eb3eb1c1e18d841fe30b4b5bc5619d781267ca9bc03e005d8fd0a/jiter-0.13.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:6c26a424569a59140fb51160a56df13f438a2b0967365e987889186d5fc2f6f9", size = 548756, upload-time = "2026-02-02T12:37:17.736Z" }, + { url = "https://files.pythonhosted.org/packages/47/66/eea81dfff765ed66c68fd2ed8c96245109e13c896c2a5015c7839c92367e/jiter-0.13.0-cp314-cp314t-win32.whl", hash = "sha256:24dc96eca9f84da4131cdf87a95e6ce36765c3b156fc9ae33280873b1c32d5f6", size = 201196, upload-time = "2026-02-02T12:37:19.101Z" }, + { url = "https://files.pythonhosted.org/packages/ff/32/4ac9c7a76402f8f00d00842a7f6b83b284d0cf7c1e9d4227bc95aa6d17fa/jiter-0.13.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0a8d76c7524087272c8ae913f5d9d608bd839154b62c4322ef65723d2e5bb0b8", size = 204215, upload-time = "2026-02-02T12:37:20.495Z" }, + { url = "https://files.pythonhosted.org/packages/f9/8e/7def204fea9f9be8b3c21a6f2dd6c020cf56c7d5ff753e0e23ed7f9ea57e/jiter-0.13.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2c26cf47e2cad140fa23b6d58d435a7c0161f5c514284802f25e87fddfe11024", size = 187152, upload-time = "2026-02-02T12:37:22.124Z" }, + { url = "https://files.pythonhosted.org/packages/79/b3/3c29819a27178d0e461a8571fb63c6ae38be6dc36b78b3ec2876bbd6a910/jiter-0.13.0-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b1cbfa133241d0e6bdab48dcdc2604e8ba81512f6bbd68ec3e8e1357dd3c316c", size = 307016, upload-time = "2026-02-02T12:37:42.755Z" }, + { url = "https://files.pythonhosted.org/packages/eb/ae/60993e4b07b1ac5ebe46da7aa99fdbb802eb986c38d26e3883ac0125c4e0/jiter-0.13.0-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:db367d8be9fad6e8ebbac4a7578b7af562e506211036cba2c06c3b998603c3d2", size = 305024, upload-time = "2026-02-02T12:37:44.774Z" }, + { url = "https://files.pythonhosted.org/packages/77/fa/2227e590e9cf98803db2811f172b2d6460a21539ab73006f251c66f44b14/jiter-0.13.0-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45f6f8efb2f3b0603092401dc2df79fa89ccbc027aaba4174d2d4133ed661434", size = 339337, upload-time = "2026-02-02T12:37:46.668Z" }, + { url = "https://files.pythonhosted.org/packages/2d/92/015173281f7eb96c0ef580c997da8ef50870d4f7f4c9e03c845a1d62ae04/jiter-0.13.0-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:597245258e6ad085d064780abfb23a284d418d3e61c57362d9449c6c7317ee2d", size = 346395, upload-time = "2026-02-02T12:37:48.09Z" }, + { url = "https://files.pythonhosted.org/packages/80/60/e50fa45dd7e2eae049f0ce964663849e897300433921198aef94b6ffa23a/jiter-0.13.0-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:3d744a6061afba08dd7ae375dcde870cffb14429b7477e10f67e9e6d68772a0a", size = 305169, upload-time = "2026-02-02T12:37:50.376Z" }, + { url = "https://files.pythonhosted.org/packages/d2/73/a009f41c5eed71c49bec53036c4b33555afcdee70682a18c6f66e396c039/jiter-0.13.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:ff732bd0a0e778f43d5009840f20b935e79087b4dc65bd36f1cd0f9b04b8ff7f", size = 303808, upload-time = "2026-02-02T12:37:52.092Z" }, + { url = "https://files.pythonhosted.org/packages/c4/10/528b439290763bff3d939268085d03382471b442f212dca4ff5f12802d43/jiter-0.13.0-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab44b178f7981fcaea7e0a5df20e773c663d06ffda0198f1a524e91b2fde7e59", size = 337384, upload-time = "2026-02-02T12:37:53.582Z" }, + { url = "https://files.pythonhosted.org/packages/67/8a/a342b2f0251f3dac4ca17618265d93bf244a2a4d089126e81e4c1056ac50/jiter-0.13.0-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bb00b6d26db67a05fe3e12c76edc75f32077fb51deed13822dc648fa373bc19", size = 343768, upload-time = "2026-02-02T12:37:55.055Z" }, +] + [[package]] name = "jsonpatch" version = "1.33" @@ -557,18 +999,48 @@ wheels = [ ] [[package]] -name = "langchain-google-genai" -version = "4.2.0" +name = "langchain-google-vertexai" +version = "3.2.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "filetype" }, - { name = "google-genai" }, + { name = "bottleneck" }, + { name = "google-cloud-aiplatform" }, + { name = "google-cloud-storage" }, + { name = "google-cloud-vectorsearch" }, + { name = "httpx" }, + { name = "httpx-sse" }, { name = "langchain-core" }, + { name = "langchain-tests" }, + { name = "numexpr" }, + { name = "pyarrow" }, { name = "pydantic" }, + { name = "validators" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d8/0b/eae2305e207574dc633983a8a82a745e0ede1bce1f3a9daff24d2341fadc/langchain_google_genai-4.2.0.tar.gz", hash = "sha256:9a8d9bfc35354983ed29079cefff53c3e7c9c2a44b6ba75cc8f13a0cf8b55c33", size = 277361, upload-time = "2026-01-13T20:41:17.63Z" } +sdist = { url = "https://files.pythonhosted.org/packages/81/36/6924d8321f661733c15685738d525de30b4dee5f0b288545f0a525ddf4e6/langchain_google_vertexai-3.2.2.tar.gz", hash = "sha256:089200b44e0002ef0a571243bf19cd6897446e8b5d17b7c3a8e6579820cda3a7", size = 375968, upload-time = "2026-01-30T18:29:13.229Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/22/51/39942c0083139652494bb354dddf0ed397703a4882302f7b48aeca531c96/langchain_google_genai-4.2.0-py3-none-any.whl", hash = "sha256:856041aaafceff65a4ef0d5acf5731f2db95229ff041132af011aec51e8279d9", size = 66452, upload-time = "2026-01-13T20:41:16.296Z" }, + { url = "https://files.pythonhosted.org/packages/b6/d9/3adf09ff844a6d5c9dad9fe9ad6a032b706a1184eae71caa4c89bb470cbd/langchain_google_vertexai-3.2.2-py3-none-any.whl", hash = "sha256:aee8ea79f5aa19da74058e3905c78e0d3b882d5bc9eaf8549d92c13a5c458fda", size = 113381, upload-time = "2026-01-30T18:29:12.13Z" }, +] + +[[package]] +name = "langchain-tests" +version = "1.1.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "httpx" }, + { name = "langchain-core" }, + { name = "numpy" }, + { name = "pytest" }, + { name = "pytest-asyncio" }, + { name = "pytest-benchmark" }, + { name = "pytest-codspeed" }, + { name = "pytest-recording" }, + { name = "pytest-socket" }, + { name = "syrupy" }, + { name = "vcrpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/21/94/e626a40c14a5bc7b60563446a23330a06654d0b1e3804109ed792ca0c638/langchain_tests-1.1.5.tar.gz", hash = "sha256:add75c24ea4aacb5f4efa02670fcceee5d5276848586f724e90135da6d3e070e", size = 154114, upload-time = "2026-02-18T16:08:31.745Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/2c/c7641310171ed49d1e603c56ce38a9f3e157c23257b226f69ce5cb6a7428/langchain_tests-1.1.5-py3-none-any.whl", hash = "sha256:535429fb31d17a6cf8d7f61a3f81013a650f090c0f57b4daf1a03be7771d61ff", size = 55731, upload-time = "2026-02-18T16:08:30.811Z" }, ] [[package]] @@ -647,6 +1119,165 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ce/87/6f2b008a456b4f5fd0fb1509bb7e1e9368c1a0c9641a535f224a9ddc10f3/langsmith-0.7.1-py3-none-any.whl", hash = "sha256:92cfa54253d35417184c297ad25bfd921d95f15d60a1ca75f14d4e7acd152a29", size = 322515, upload-time = "2026-02-10T01:55:22.531Z" }, ] +[[package]] +name = "markdown-it-py" +version = "4.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, +] + +[[package]] +name = "numexpr" +version = "2.14.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cb/2f/fdba158c9dbe5caca9c3eca3eaffffb251f2fb8674bf8e2d0aed5f38d319/numexpr-2.14.1.tar.gz", hash = "sha256:4be00b1086c7b7a5c32e31558122b7b80243fe098579b170967da83f3152b48b", size = 119400, upload-time = "2025-10-13T16:17:27.351Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b2/a3/67999bdd1ed1f938d38f3fedd4969632f2f197b090e50505f7cc1fa82510/numexpr-2.14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2d03fcb4644a12f70a14d74006f72662824da5b6128bf1bcd10cc3ed80e64c34", size = 163195, upload-time = "2025-10-13T16:16:31.212Z" }, + { url = "https://files.pythonhosted.org/packages/25/95/d64f680ea1fc56d165457287e0851d6708800f9fcea346fc1b9957942ee6/numexpr-2.14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2773ee1133f77009a1fc2f34fe236f3d9823779f5f75450e183137d49f00499f", size = 152088, upload-time = "2025-10-13T16:16:33.186Z" }, + { url = "https://files.pythonhosted.org/packages/0e/7f/3bae417cb13ae08afd86d08bb0301c32440fe0cae4e6262b530e0819aeda/numexpr-2.14.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ebe4980f9494b9f94d10d2e526edc29e72516698d3bf95670ba79415492212a4", size = 451126, upload-time = "2025-10-13T16:13:22.248Z" }, + { url = "https://files.pythonhosted.org/packages/4c/1a/edbe839109518364ac0bd9e918cf874c755bb2c128040e920f198c494263/numexpr-2.14.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2a381e5e919a745c9503bcefffc1c7f98c972c04ec58fc8e999ed1a929e01ba6", size = 442012, upload-time = "2025-10-13T16:14:51.416Z" }, + { url = "https://files.pythonhosted.org/packages/66/b1/be4ce99bff769a5003baddac103f34681997b31d4640d5a75c0e8ed59c78/numexpr-2.14.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d08856cfc1b440eb1caaa60515235369654321995dd68eb9377577392020f6cb", size = 1415975, upload-time = "2025-10-13T16:13:26.088Z" }, + { url = "https://files.pythonhosted.org/packages/e7/33/b33b8fdc032a05d9ebb44a51bfcd4b92c178a2572cd3e6c1b03d8a4b45b2/numexpr-2.14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03130afa04edf83a7b590d207444f05a00363c9b9ea5d81c0f53b1ea13fad55a", size = 1464683, upload-time = "2025-10-13T16:14:58.87Z" }, + { url = "https://files.pythonhosted.org/packages/d0/b2/ddcf0ac6cf0a1d605e5aecd4281507fd79a9628a67896795ab2e975de5df/numexpr-2.14.1-cp311-cp311-win32.whl", hash = "sha256:db78fa0c9fcbaded3ae7453faf060bd7a18b0dc10299d7fcd02d9362be1213ed", size = 166838, upload-time = "2025-10-13T16:17:06.765Z" }, + { url = "https://files.pythonhosted.org/packages/64/72/4ca9bd97b2eb6dce9f5e70a3b6acec1a93e1fb9b079cb4cba2cdfbbf295d/numexpr-2.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:e9b2f957798c67a2428be96b04bce85439bed05efe78eb78e4c2ca43737578e7", size = 160069, upload-time = "2025-10-13T16:17:08.752Z" }, + { url = "https://files.pythonhosted.org/packages/9d/20/c473fc04a371f5e2f8c5749e04505c13e7a8ede27c09e9f099b2ad6f43d6/numexpr-2.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:91ebae0ab18c799b0e6b8c5a8d11e1fa3848eb4011271d99848b297468a39430", size = 162790, upload-time = "2025-10-13T16:16:34.903Z" }, + { url = "https://files.pythonhosted.org/packages/45/93/b6760dd1904c2a498e5f43d1bb436f59383c3ddea3815f1461dfaa259373/numexpr-2.14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:47041f2f7b9e69498fb311af672ba914a60e6e6d804011caacb17d66f639e659", size = 152196, upload-time = "2025-10-13T16:16:36.593Z" }, + { url = "https://files.pythonhosted.org/packages/72/94/cc921e35593b820521e464cbbeaf8212bbdb07f16dc79fe283168df38195/numexpr-2.14.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d686dfb2c1382d9e6e0ee0b7647f943c1886dba3adbf606c625479f35f1956c1", size = 452468, upload-time = "2025-10-13T16:13:29.531Z" }, + { url = "https://files.pythonhosted.org/packages/d9/43/560e9ba23c02c904b5934496486d061bcb14cd3ebba2e3cf0e2dccb6c22b/numexpr-2.14.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eee6d4fbbbc368e6cdd0772734d6249128d957b3b8ad47a100789009f4de7083", size = 443631, upload-time = "2025-10-13T16:15:02.473Z" }, + { url = "https://files.pythonhosted.org/packages/7b/6c/78f83b6219f61c2c22d71ab6e6c2d4e5d7381334c6c29b77204e59edb039/numexpr-2.14.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3a2839efa25f3c8d4133252ea7342d8f81226c7c4dda81f97a57e090b9d87a48", size = 1417670, upload-time = "2025-10-13T16:13:33.464Z" }, + { url = "https://files.pythonhosted.org/packages/0e/bb/1ccc9dcaf46281568ce769888bf16294c40e98a5158e4b16c241de31d0d3/numexpr-2.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9f9137f1351b310436662b5dc6f4082a245efa8950c3b0d9008028df92fefb9b", size = 1466212, upload-time = "2025-10-13T16:15:12.828Z" }, + { url = "https://files.pythonhosted.org/packages/31/9f/203d82b9e39dadd91d64bca55b3c8ca432e981b822468dcef41a4418626b/numexpr-2.14.1-cp312-cp312-win32.whl", hash = "sha256:36f8d5c1bd1355df93b43d766790f9046cccfc1e32b7c6163f75bcde682cda07", size = 166996, upload-time = "2025-10-13T16:17:10.369Z" }, + { url = "https://files.pythonhosted.org/packages/1f/67/ffe750b5452eb66de788c34e7d21ec6d886abb4d7c43ad1dc88ceb3d998f/numexpr-2.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:fdd886f4b7dbaf167633ee396478f0d0aa58ea2f9e7ccc3c6431019623e8d68f", size = 160187, upload-time = "2025-10-13T16:17:11.974Z" }, + { url = "https://files.pythonhosted.org/packages/73/b4/9f6d637fd79df42be1be29ee7ba1f050fab63b7182cb922a0e08adc12320/numexpr-2.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:09078ba73cffe94745abfbcc2d81ab8b4b4e9d7bfbbde6cac2ee5dbf38eee222", size = 162794, upload-time = "2025-10-13T16:16:38.291Z" }, + { url = "https://files.pythonhosted.org/packages/35/ae/d58558d8043de0c49f385ea2fa789e3cfe4d436c96be80200c5292f45f15/numexpr-2.14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dce0b5a0447baa7b44bc218ec2d7dcd175b8eee6083605293349c0c1d9b82fb6", size = 152203, upload-time = "2025-10-13T16:16:39.907Z" }, + { url = "https://files.pythonhosted.org/packages/13/65/72b065f9c75baf8f474fd5d2b768350935989d4917db1c6c75b866d4067c/numexpr-2.14.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:06855053de7a3a8425429bd996e8ae3c50b57637ad3e757e0fa0602a7874be30", size = 455860, upload-time = "2025-10-13T16:13:35.811Z" }, + { url = "https://files.pythonhosted.org/packages/fc/f9/c9457652dfe28e2eb898372da2fe786c6db81af9540c0f853ee04a0699cc/numexpr-2.14.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05f9366d23a2e991fd5a8b5e61a17558f028ba86158a4552f8f239b005cdf83c", size = 446574, upload-time = "2025-10-13T16:15:17.367Z" }, + { url = "https://files.pythonhosted.org/packages/b6/99/8d3879c4d67d3db5560cf2de65ce1778b80b75f6fa415eb5c3e7bd37ba27/numexpr-2.14.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c5f1b1605695778896534dfc6e130d54a65cd52be7ed2cd0cfee3981fd676bf5", size = 1417306, upload-time = "2025-10-13T16:13:42.813Z" }, + { url = "https://files.pythonhosted.org/packages/ea/05/6bddac9f18598ba94281e27a6943093f7d0976544b0cb5d92272c64719bd/numexpr-2.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a4ba71db47ea99c659d88ee6233fa77b6dc83392f1d324e0c90ddf617ae3f421", size = 1466145, upload-time = "2025-10-13T16:15:27.464Z" }, + { url = "https://files.pythonhosted.org/packages/24/5d/cbeb67aca0c5a76ead13df7e8bd8dd5e0d49145f90da697ba1d9f07005b0/numexpr-2.14.1-cp313-cp313-win32.whl", hash = "sha256:638dce8320f4a1483d5ca4fda69f60a70ed7e66be6e68bc23fb9f1a6b78a9e3b", size = 166996, upload-time = "2025-10-13T16:17:13.803Z" }, + { url = "https://files.pythonhosted.org/packages/cc/23/9281bceaeb282cead95f0aa5f7f222ffc895670ea689cc1398355f6e3001/numexpr-2.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:9fdcd4735121658a313f878fd31136d1bfc6a5b913219e7274e9fca9f8dac3bb", size = 160189, upload-time = "2025-10-13T16:17:15.417Z" }, + { url = "https://files.pythonhosted.org/packages/f3/76/7aac965fd93a56803cbe502aee2adcad667253ae34b0badf6c5af7908b6c/numexpr-2.14.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:557887ad7f5d3c2a40fd7310e50597045a68e66b20a77b3f44d7bc7608523b4b", size = 163524, upload-time = "2025-10-13T16:16:42.213Z" }, + { url = "https://files.pythonhosted.org/packages/58/65/79d592d5e63fbfab3b59a60c386853d9186a44a3fa3c87ba26bdc25b6195/numexpr-2.14.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:af111c8fe6fc55d15e4c7cab11920fc50740d913636d486545b080192cd0ad73", size = 152919, upload-time = "2025-10-13T16:16:44.229Z" }, + { url = "https://files.pythonhosted.org/packages/84/78/3c8335f713d4aeb99fa758d7c62f0be1482d4947ce5b508e2052bb7aeee9/numexpr-2.14.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:33265294376e7e2ae4d264d75b798a915d2acf37b9dd2b9405e8b04f84d05cfc", size = 465972, upload-time = "2025-10-13T16:13:45.061Z" }, + { url = "https://files.pythonhosted.org/packages/35/81/9ee5f69b811e8f18746c12d6f71848617684edd3161927f95eee7a305631/numexpr-2.14.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:83647d846d3eeeb9a9255311236135286728b398d0d41d35dedb532dca807fe9", size = 456953, upload-time = "2025-10-13T16:15:31.186Z" }, + { url = "https://files.pythonhosted.org/packages/6d/39/9b8bc6e294d85cbb54a634e47b833e9f3276a8bdf7ce92aa808718a0212d/numexpr-2.14.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6e575fd3ad41ddf3355d0c7ef6bd0168619dc1779a98fe46693cad5e95d25e6e", size = 1426199, upload-time = "2025-10-13T16:13:48.231Z" }, + { url = "https://files.pythonhosted.org/packages/1e/ce/0d4fcd31ab49319740d934fba1734d7dad13aa485532ca754e555ca16c8b/numexpr-2.14.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:67ea4771029ce818573b1998f5ca416bd255156feea017841b86176a938f7d19", size = 1474214, upload-time = "2025-10-13T16:15:38.893Z" }, + { url = "https://files.pythonhosted.org/packages/b7/47/b2a93cbdb3ba4e009728ad1b9ef1550e2655ea2c86958ebaf03b9615f275/numexpr-2.14.1-cp313-cp313t-win32.whl", hash = "sha256:15015d47d3d1487072d58c0e7682ef2eb608321e14099c39d52e2dd689483611", size = 167676, upload-time = "2025-10-13T16:17:17.351Z" }, + { url = "https://files.pythonhosted.org/packages/86/99/ee3accc589ed032eea68e12172515ed96a5568534c213ad109e1f4411df1/numexpr-2.14.1-cp313-cp313t-win_amd64.whl", hash = "sha256:94c711f6d8f17dfb4606842b403699603aa591ab9f6bf23038b488ea9cfb0f09", size = 161096, upload-time = "2025-10-13T16:17:19.174Z" }, + { url = "https://files.pythonhosted.org/packages/ac/36/9db78dfbfdfa1f8bf0872993f1a334cdd8fca5a5b6567e47dcb128bcb7c2/numexpr-2.14.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ede79f7ff06629f599081de644546ce7324f1581c09b0ac174da88a470d39c21", size = 162848, upload-time = "2025-10-13T16:16:46.216Z" }, + { url = "https://files.pythonhosted.org/packages/13/c1/a5c78ae637402c5550e2e0ba175275d2515d432ec28af0cdc23c9b476e65/numexpr-2.14.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2eac7a5a2f70b3768c67056445d1ceb4ecd9b853c8eda9563823b551aeaa5082", size = 152270, upload-time = "2025-10-13T16:16:47.92Z" }, + { url = "https://files.pythonhosted.org/packages/9a/ed/aabd8678077848dd9a751c5558c2057839f5a09e2a176d8dfcd0850ee00e/numexpr-2.14.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5aedf38d4c0c19d3cecfe0334c3f4099fb496f54c146223d30fa930084bc8574", size = 455918, upload-time = "2025-10-13T16:13:50.338Z" }, + { url = "https://files.pythonhosted.org/packages/88/e1/3db65117f02cdefb0e5e4c440daf1c30beb45051b7f47aded25b7f4f2f34/numexpr-2.14.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:439ec4d57b853792ebe5456e3160312281c3a7071ecac5532ded3278ede614de", size = 446512, upload-time = "2025-10-13T16:15:42.313Z" }, + { url = "https://files.pythonhosted.org/packages/9a/fb/7ceb9ee55b5f67e4a3e4d73d5af4c7e37e3c9f37f54bee90361b64b17e3f/numexpr-2.14.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e23b87f744e04e302d82ac5e2189ae20a533566aec76a46885376e20b0645bf8", size = 1417845, upload-time = "2025-10-13T16:13:53.836Z" }, + { url = "https://files.pythonhosted.org/packages/45/2d/9b5764d0eafbbb2889288f80de773791358acf6fad1a55767538d8b79599/numexpr-2.14.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:44f84e0e5af219dbb62a081606156420815890e041b87252fbcea5df55214c4c", size = 1466211, upload-time = "2025-10-13T16:15:48.985Z" }, + { url = "https://files.pythonhosted.org/packages/5d/21/204db708eccd71aa8bc55bcad55bc0fc6c5a4e01ad78e14ee5714a749386/numexpr-2.14.1-cp314-cp314-win32.whl", hash = "sha256:1f1a5e817c534539351aa75d26088e9e1e0ef1b3a6ab484047618a652ccc4fc3", size = 168835, upload-time = "2025-10-13T16:17:20.82Z" }, + { url = "https://files.pythonhosted.org/packages/4f/3e/d83e9401a1c3449a124f7d4b3fb44084798e0d30f7c11e60712d9b94cf11/numexpr-2.14.1-cp314-cp314-win_amd64.whl", hash = "sha256:587c41509bc373dfb1fe6086ba55a73147297247bedb6d588cda69169fc412f2", size = 162608, upload-time = "2025-10-13T16:17:22.228Z" }, + { url = "https://files.pythonhosted.org/packages/7f/d6/ec947806bb57836d6379a8c8a253c2aeaa602b12fef2336bfd2462bb4ed5/numexpr-2.14.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:ec368819502b64f190c3f71be14a304780b5935c42aae5bf22c27cc2cbba70b5", size = 163525, upload-time = "2025-10-13T16:16:50.133Z" }, + { url = "https://files.pythonhosted.org/packages/0d/77/048f30dcf661a3d52963a88c29b52b6d5ce996d38e9313a56a922451c1e0/numexpr-2.14.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7e87f6d203ac57239de32261c941e9748f9309cbc0da6295eabd0c438b920d3a", size = 152917, upload-time = "2025-10-13T16:16:52.055Z" }, + { url = "https://files.pythonhosted.org/packages/9e/d3/956a13e628d722d649fbf2fded615134a308c082e122a48bad0e90a99ce9/numexpr-2.14.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dd72d8c2a165fe45ea7650b16eb8cc1792a94a722022006bb97c86fe51fd2091", size = 466242, upload-time = "2025-10-13T16:13:55.795Z" }, + { url = "https://files.pythonhosted.org/packages/d6/dd/abe848678d82486940892f2cacf39e82eec790e8930d4d713d3f9191063b/numexpr-2.14.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:70d80fcb418a54ca208e9a38e58ddc425c07f66485176b261d9a67c7f2864f73", size = 457149, upload-time = "2025-10-13T16:15:52.036Z" }, + { url = "https://files.pythonhosted.org/packages/fd/bb/797b583b5fb9da5700a5708ca6eb4f889c94d81abb28de4d642c0f4b3258/numexpr-2.14.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:edea2f20c2040df8b54ee8ca8ebda63de9545b2112872466118e9df4d0ae99f3", size = 1426493, upload-time = "2025-10-13T16:13:59.244Z" }, + { url = "https://files.pythonhosted.org/packages/77/c4/0519ab028fdc35e3e7ee700def7f2b4631b175cd9e1202bd7966c1695c33/numexpr-2.14.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:790447be6879a6c51b9545f79612d24c9ea0a41d537a84e15e6a8ddef0b6268e", size = 1474413, upload-time = "2025-10-13T16:15:59.211Z" }, + { url = "https://files.pythonhosted.org/packages/d4/4a/33044878c8f4a75213cfe9c11d4c02058bb710a7a063fe14f362e8de1077/numexpr-2.14.1-cp314-cp314t-win32.whl", hash = "sha256:538961096c2300ea44240209181e31fae82759d26b51713b589332b9f2a4117e", size = 169502, upload-time = "2025-10-13T16:17:23.829Z" }, + { url = "https://files.pythonhosted.org/packages/41/a2/5a1a2c72528b429337f49911b18c302ecd36eeab00f409147e1aa4ae4519/numexpr-2.14.1-cp314-cp314t-win_amd64.whl", hash = "sha256:a40b350cd45b4446076fa11843fa32bbe07024747aeddf6d467290bf9011b392", size = 163589, upload-time = "2025-10-13T16:17:25.696Z" }, +] + +[[package]] +name = "numpy" +version = "2.4.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/10/8b/c265f4823726ab832de836cdd184d0986dcf94480f81e8739692a7ac7af2/numpy-2.4.3.tar.gz", hash = "sha256:483a201202b73495f00dbc83796c6ae63137a9bdade074f7648b3e32613412dd", size = 20727743, upload-time = "2026-03-09T07:58:53.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f9/51/5093a2df15c4dc19da3f79d1021e891f5dcf1d9d1db6ba38891d5590f3fe/numpy-2.4.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:33b3bf58ee84b172c067f56aeadc7ee9ab6de69c5e800ab5b10295d54c581adb", size = 16957183, upload-time = "2026-03-09T07:55:57.774Z" }, + { url = "https://files.pythonhosted.org/packages/b5/7c/c061f3de0630941073d2598dc271ac2f6cbcf5c83c74a5870fea07488333/numpy-2.4.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8ba7b51e71c05aa1f9bc3641463cd82308eab40ce0d5c7e1fd4038cbf9938147", size = 14968734, upload-time = "2026-03-09T07:56:00.494Z" }, + { url = "https://files.pythonhosted.org/packages/ef/27/d26c85cbcd86b26e4f125b0668e7a7c0542d19dd7d23ee12e87b550e95b5/numpy-2.4.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:a1988292870c7cb9d0ebb4cc96b4d447513a9644801de54606dc7aabf2b7d920", size = 5475288, upload-time = "2026-03-09T07:56:02.857Z" }, + { url = "https://files.pythonhosted.org/packages/2b/09/3c4abbc1dcd8010bf1a611d174c7aa689fc505585ec806111b4406f6f1b1/numpy-2.4.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:23b46bb6d8ecb68b58c09944483c135ae5f0e9b8d8858ece5e4ead783771d2a9", size = 6805253, upload-time = "2026-03-09T07:56:04.53Z" }, + { url = "https://files.pythonhosted.org/packages/21/bc/e7aa3f6817e40c3f517d407742337cbb8e6fc4b83ce0b55ab780c829243b/numpy-2.4.3-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a016db5c5dba78fa8fe9f5d80d6708f9c42ab087a739803c0ac83a43d686a470", size = 15969479, upload-time = "2026-03-09T07:56:06.638Z" }, + { url = "https://files.pythonhosted.org/packages/78/51/9f5d7a41f0b51649ddf2f2320595e15e122a40610b233d51928dd6c92353/numpy-2.4.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:715de7f82e192e8cae5a507a347d97ad17598f8e026152ca97233e3666daaa71", size = 16901035, upload-time = "2026-03-09T07:56:09.405Z" }, + { url = "https://files.pythonhosted.org/packages/64/6e/b221dd847d7181bc5ee4857bfb026182ef69499f9305eb1371cbb1aea626/numpy-2.4.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2ddb7919366ee468342b91dea2352824c25b55814a987847b6c52003a7c97f15", size = 17325657, upload-time = "2026-03-09T07:56:12.067Z" }, + { url = "https://files.pythonhosted.org/packages/eb/b8/8f3fd2da596e1063964b758b5e3c970aed1949a05200d7e3d46a9d46d643/numpy-2.4.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a315e5234d88067f2d97e1f2ef670a7569df445d55400f1e33d117418d008d52", size = 18635512, upload-time = "2026-03-09T07:56:14.629Z" }, + { url = "https://files.pythonhosted.org/packages/5c/24/2993b775c37e39d2f8ab4125b44337ab0b2ba106c100980b7c274a22bee7/numpy-2.4.3-cp311-cp311-win32.whl", hash = "sha256:2b3f8d2c4589b1a2028d2a770b0fc4d1f332fb5e01521f4de3199a896d158ddd", size = 6238100, upload-time = "2026-03-09T07:56:17.243Z" }, + { url = "https://files.pythonhosted.org/packages/76/1d/edccf27adedb754db7c4511d5eac8b83f004ae948fe2d3509e8b78097d4c/numpy-2.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:77e76d932c49a75617c6d13464e41203cd410956614d0a0e999b25e9e8d27eec", size = 12609816, upload-time = "2026-03-09T07:56:19.089Z" }, + { url = "https://files.pythonhosted.org/packages/92/82/190b99153480076c8dce85f4cfe7d53ea84444145ffa54cb58dcd460d66b/numpy-2.4.3-cp311-cp311-win_arm64.whl", hash = "sha256:eb610595dd91560905c132c709412b512135a60f1851ccbd2c959e136431ff67", size = 10485757, upload-time = "2026-03-09T07:56:21.753Z" }, + { url = "https://files.pythonhosted.org/packages/a9/ed/6388632536f9788cea23a3a1b629f25b43eaacd7d7377e5d6bc7b9deb69b/numpy-2.4.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:61b0cbabbb6126c8df63b9a3a0c4b1f44ebca5e12ff6997b80fcf267fb3150ef", size = 16669628, upload-time = "2026-03-09T07:56:24.252Z" }, + { url = "https://files.pythonhosted.org/packages/74/1b/ee2abfc68e1ce728b2958b6ba831d65c62e1b13ce3017c13943f8f9b5b2e/numpy-2.4.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7395e69ff32526710748f92cd8c9849b361830968ea3e24a676f272653e8983e", size = 14696872, upload-time = "2026-03-09T07:56:26.991Z" }, + { url = "https://files.pythonhosted.org/packages/ba/d1/780400e915ff5638166f11ca9dc2c5815189f3d7cf6f8759a1685e586413/numpy-2.4.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:abdce0f71dcb4a00e4e77f3faf05e4616ceccfe72ccaa07f47ee79cda3b7b0f4", size = 5203489, upload-time = "2026-03-09T07:56:29.414Z" }, + { url = "https://files.pythonhosted.org/packages/0b/bb/baffa907e9da4cc34a6e556d6d90e032f6d7a75ea47968ea92b4858826c4/numpy-2.4.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:48da3a4ee1336454b07497ff7ec83903efa5505792c4e6d9bf83d99dc07a1e18", size = 6550814, upload-time = "2026-03-09T07:56:32.225Z" }, + { url = "https://files.pythonhosted.org/packages/7b/12/8c9f0c6c95f76aeb20fc4a699c33e9f827fa0d0f857747c73bb7b17af945/numpy-2.4.3-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:32e3bef222ad6b052280311d1d60db8e259e4947052c3ae7dd6817451fc8a4c5", size = 15666601, upload-time = "2026-03-09T07:56:34.461Z" }, + { url = "https://files.pythonhosted.org/packages/bd/79/cc665495e4d57d0aa6fbcc0aa57aa82671dfc78fbf95fe733ed86d98f52a/numpy-2.4.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e7dd01a46700b1967487141a66ac1a3cf0dd8ebf1f08db37d46389401512ca97", size = 16621358, upload-time = "2026-03-09T07:56:36.852Z" }, + { url = "https://files.pythonhosted.org/packages/a8/40/b4ecb7224af1065c3539f5ecfff879d090de09608ad1008f02c05c770cb3/numpy-2.4.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:76f0f283506c28b12bba319c0fab98217e9f9b54e6160e9c79e9f7348ba32e9c", size = 17016135, upload-time = "2026-03-09T07:56:39.337Z" }, + { url = "https://files.pythonhosted.org/packages/f7/b1/6a88e888052eed951afed7a142dcdf3b149a030ca59b4c71eef085858e43/numpy-2.4.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:737f630a337364665aba3b5a77e56a68cc42d350edd010c345d65a3efa3addcc", size = 18345816, upload-time = "2026-03-09T07:56:42.31Z" }, + { url = "https://files.pythonhosted.org/packages/f3/8f/103a60c5f8c3d7fc678c19cd7b2476110da689ccb80bc18050efbaeae183/numpy-2.4.3-cp312-cp312-win32.whl", hash = "sha256:26952e18d82a1dbbc2f008d402021baa8d6fc8e84347a2072a25e08b46d698b9", size = 5960132, upload-time = "2026-03-09T07:56:44.851Z" }, + { url = "https://files.pythonhosted.org/packages/d7/7c/f5ee1bf6ed888494978046a809df2882aad35d414b622893322df7286879/numpy-2.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:65f3c2455188f09678355f5cae1f959a06b778bc66d535da07bf2ef20cd319d5", size = 12316144, upload-time = "2026-03-09T07:56:47.057Z" }, + { url = "https://files.pythonhosted.org/packages/71/46/8d1cb3f7a00f2fb6394140e7e6623696e54c6318a9d9691bb4904672cf42/numpy-2.4.3-cp312-cp312-win_arm64.whl", hash = "sha256:2abad5c7fef172b3377502bde47892439bae394a71bc329f31df0fd829b41a9e", size = 10220364, upload-time = "2026-03-09T07:56:49.849Z" }, + { url = "https://files.pythonhosted.org/packages/b6/d0/1fe47a98ce0df229238b77611340aff92d52691bcbc10583303181abf7fc/numpy-2.4.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b346845443716c8e542d54112966383b448f4a3ba5c66409771b8c0889485dd3", size = 16665297, upload-time = "2026-03-09T07:56:52.296Z" }, + { url = "https://files.pythonhosted.org/packages/27/d9/4e7c3f0e68dfa91f21c6fb6cf839bc829ec920688b1ce7ec722b1a6202fb/numpy-2.4.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2629289168f4897a3c4e23dc98d6f1731f0fc0fe52fb9db19f974041e4cc12b9", size = 14691853, upload-time = "2026-03-09T07:56:54.992Z" }, + { url = "https://files.pythonhosted.org/packages/3a/66/bd096b13a87549683812b53ab211e6d413497f84e794fb3c39191948da97/numpy-2.4.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:bb2e3cf95854233799013779216c57e153c1ee67a0bf92138acca0e429aefaee", size = 5198435, upload-time = "2026-03-09T07:56:57.184Z" }, + { url = "https://files.pythonhosted.org/packages/a2/2f/687722910b5a5601de2135c891108f51dfc873d8e43c8ed9f4ebb440b4a2/numpy-2.4.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:7f3408ff897f8ab07a07fbe2823d7aee6ff644c097cc1f90382511fe982f647f", size = 6546347, upload-time = "2026-03-09T07:56:59.531Z" }, + { url = "https://files.pythonhosted.org/packages/bf/ec/7971c4e98d86c564750393fab8d7d83d0a9432a9d78bb8a163a6dc59967a/numpy-2.4.3-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:decb0eb8a53c3b009b0962378065589685d66b23467ef5dac16cbe818afde27f", size = 15664626, upload-time = "2026-03-09T07:57:01.385Z" }, + { url = "https://files.pythonhosted.org/packages/7e/eb/7daecbea84ec935b7fc732e18f532073064a3816f0932a40a17f3349185f/numpy-2.4.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d5f51900414fc9204a0e0da158ba2ac52b75656e7dce7e77fb9f84bfa343b4cc", size = 16608916, upload-time = "2026-03-09T07:57:04.008Z" }, + { url = "https://files.pythonhosted.org/packages/df/58/2a2b4a817ffd7472dca4421d9f0776898b364154e30c95f42195041dc03b/numpy-2.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6bd06731541f89cdc01b261ba2c9e037f1543df7472517836b78dfb15bd6e476", size = 17015824, upload-time = "2026-03-09T07:57:06.347Z" }, + { url = "https://files.pythonhosted.org/packages/4a/ca/627a828d44e78a418c55f82dd4caea8ea4a8ef24e5144d9e71016e52fb40/numpy-2.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:22654fe6be0e5206f553a9250762c653d3698e46686eee53b399ab90da59bd92", size = 18334581, upload-time = "2026-03-09T07:57:09.114Z" }, + { url = "https://files.pythonhosted.org/packages/cd/c0/76f93962fc79955fcba30a429b62304332345f22d4daec1cb33653425643/numpy-2.4.3-cp313-cp313-win32.whl", hash = "sha256:d71e379452a2f670ccb689ec801b1218cd3983e253105d6e83780967e899d687", size = 5958618, upload-time = "2026-03-09T07:57:11.432Z" }, + { url = "https://files.pythonhosted.org/packages/b1/3c/88af0040119209b9b5cb59485fa48b76f372c73068dbf9254784b975ac53/numpy-2.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:0a60e17a14d640f49146cb38e3f105f571318db7826d9b6fef7e4dce758faecd", size = 12312824, upload-time = "2026-03-09T07:57:13.586Z" }, + { url = "https://files.pythonhosted.org/packages/58/ce/3d07743aced3d173f877c3ef6a454c2174ba42b584ab0b7e6d99374f51ed/numpy-2.4.3-cp313-cp313-win_arm64.whl", hash = "sha256:c9619741e9da2059cd9c3f206110b97583c7152c1dc9f8aafd4beb450ac1c89d", size = 10221218, upload-time = "2026-03-09T07:57:16.183Z" }, + { url = "https://files.pythonhosted.org/packages/62/09/d96b02a91d09e9d97862f4fc8bfebf5400f567d8eb1fe4b0cc4795679c15/numpy-2.4.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:7aa4e54f6469300ebca1d9eb80acd5253cdfa36f2c03d79a35883687da430875", size = 14819570, upload-time = "2026-03-09T07:57:18.564Z" }, + { url = "https://files.pythonhosted.org/packages/b5/ca/0b1aba3905fdfa3373d523b2b15b19029f4f3031c87f4066bd9d20ef6c6b/numpy-2.4.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:d1b90d840b25874cf5cd20c219af10bac3667db3876d9a495609273ebe679070", size = 5326113, upload-time = "2026-03-09T07:57:21.052Z" }, + { url = "https://files.pythonhosted.org/packages/c0/63/406e0fd32fcaeb94180fd6a4c41e55736d676c54346b7efbce548b94a914/numpy-2.4.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:a749547700de0a20a6718293396ec237bb38218049cfce788e08fcb716e8cf73", size = 6646370, upload-time = "2026-03-09T07:57:22.804Z" }, + { url = "https://files.pythonhosted.org/packages/b6/d0/10f7dc157d4b37af92720a196be6f54f889e90dcd30dce9dc657ed92c257/numpy-2.4.3-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:94f3c4a151a2e529adf49c1d54f0f57ff8f9b233ee4d44af623a81553ab86368", size = 15723499, upload-time = "2026-03-09T07:57:24.693Z" }, + { url = "https://files.pythonhosted.org/packages/66/f1/d1c2bf1161396629701bc284d958dc1efa3a5a542aab83cf11ee6eb4cba5/numpy-2.4.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22c31dc07025123aedf7f2db9e91783df13f1776dc52c6b22c620870dc0fab22", size = 16657164, upload-time = "2026-03-09T07:57:27.676Z" }, + { url = "https://files.pythonhosted.org/packages/1a/be/cca19230b740af199ac47331a21c71e7a3d0ba59661350483c1600d28c37/numpy-2.4.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:148d59127ac95979d6f07e4d460f934ebdd6eed641db9c0db6c73026f2b2101a", size = 17081544, upload-time = "2026-03-09T07:57:30.664Z" }, + { url = "https://files.pythonhosted.org/packages/b9/c5/9602b0cbb703a0936fb40f8a95407e8171935b15846de2f0776e08af04c7/numpy-2.4.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a97cbf7e905c435865c2d939af3d93f99d18eaaa3cabe4256f4304fb51604349", size = 18380290, upload-time = "2026-03-09T07:57:33.763Z" }, + { url = "https://files.pythonhosted.org/packages/ed/81/9f24708953cd30be9ee36ec4778f4b112b45165812f2ada4cc5ea1c1f254/numpy-2.4.3-cp313-cp313t-win32.whl", hash = "sha256:be3b8487d725a77acccc9924f65fd8bce9af7fac8c9820df1049424a2115af6c", size = 6082814, upload-time = "2026-03-09T07:57:36.491Z" }, + { url = "https://files.pythonhosted.org/packages/e2/9e/52f6eaa13e1a799f0ab79066c17f7016a4a8ae0c1aefa58c82b4dab690b4/numpy-2.4.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1ec84fd7c8e652b0f4aaaf2e6e9cc8eaa9b1b80a537e06b2e3a2fb176eedcb26", size = 12452673, upload-time = "2026-03-09T07:57:38.281Z" }, + { url = "https://files.pythonhosted.org/packages/c4/04/b8cece6ead0b30c9fbd99bb835ad7ea0112ac5f39f069788c5558e3b1ab2/numpy-2.4.3-cp313-cp313t-win_arm64.whl", hash = "sha256:120df8c0a81ebbf5b9020c91439fccd85f5e018a927a39f624845be194a2be02", size = 10290907, upload-time = "2026-03-09T07:57:40.747Z" }, + { url = "https://files.pythonhosted.org/packages/70/ae/3936f79adebf8caf81bd7a599b90a561334a658be4dcc7b6329ebf4ee8de/numpy-2.4.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:5884ce5c7acfae1e4e1b6fde43797d10aa506074d25b531b4f54bde33c0c31d4", size = 16664563, upload-time = "2026-03-09T07:57:43.817Z" }, + { url = "https://files.pythonhosted.org/packages/9b/62/760f2b55866b496bb1fa7da2a6db076bef908110e568b02fcfc1422e2a3a/numpy-2.4.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:297837823f5bc572c5f9379b0c9f3a3365f08492cbdc33bcc3af174372ebb168", size = 14702161, upload-time = "2026-03-09T07:57:46.169Z" }, + { url = "https://files.pythonhosted.org/packages/32/af/a7a39464e2c0a21526fb4fb76e346fb172ebc92f6d1c7a07c2c139cc17b1/numpy-2.4.3-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:a111698b4a3f8dcbe54c64a7708f049355abd603e619013c346553c1fd4ca90b", size = 5208738, upload-time = "2026-03-09T07:57:48.506Z" }, + { url = "https://files.pythonhosted.org/packages/29/8c/2a0cf86a59558fa078d83805589c2de490f29ed4fb336c14313a161d358a/numpy-2.4.3-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:4bd4741a6a676770e0e97fe9ab2e51de01183df3dcbcec591d26d331a40de950", size = 6543618, upload-time = "2026-03-09T07:57:50.591Z" }, + { url = "https://files.pythonhosted.org/packages/aa/b8/612ce010c0728b1c363fa4ea3aa4c22fe1c5da1de008486f8c2f5cb92fae/numpy-2.4.3-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:54f29b877279d51e210e0c80709ee14ccbbad647810e8f3d375561c45ef613dd", size = 15680676, upload-time = "2026-03-09T07:57:52.34Z" }, + { url = "https://files.pythonhosted.org/packages/a9/7e/4f120ecc54ba26ddf3dc348eeb9eb063f421de65c05fc961941798feea18/numpy-2.4.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:679f2a834bae9020f81534671c56fd0cc76dd7e5182f57131478e23d0dc59e24", size = 16613492, upload-time = "2026-03-09T07:57:54.91Z" }, + { url = "https://files.pythonhosted.org/packages/2c/86/1b6020db73be330c4b45d5c6ee4295d59cfeef0e3ea323959d053e5a6909/numpy-2.4.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d84f0f881cb2225c2dfd7f78a10a5645d487a496c6668d6cc39f0f114164f3d0", size = 17031789, upload-time = "2026-03-09T07:57:57.641Z" }, + { url = "https://files.pythonhosted.org/packages/07/3a/3b90463bf41ebc21d1b7e06079f03070334374208c0f9a1f05e4ae8455e7/numpy-2.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d213c7e6e8d211888cc359bab7199670a00f5b82c0978b9d1c75baf1eddbeac0", size = 18339941, upload-time = "2026-03-09T07:58:00.577Z" }, + { url = "https://files.pythonhosted.org/packages/a8/74/6d736c4cd962259fd8bae9be27363eb4883a2f9069763747347544c2a487/numpy-2.4.3-cp314-cp314-win32.whl", hash = "sha256:52077feedeff7c76ed7c9f1a0428558e50825347b7545bbb8523da2cd55c547a", size = 6007503, upload-time = "2026-03-09T07:58:03.331Z" }, + { url = "https://files.pythonhosted.org/packages/48/39/c56ef87af669364356bb011922ef0734fc49dad51964568634c72a009488/numpy-2.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:0448e7f9caefb34b4b7dd2b77f21e8906e5d6f0365ad525f9f4f530b13df2afc", size = 12444915, upload-time = "2026-03-09T07:58:06.353Z" }, + { url = "https://files.pythonhosted.org/packages/9d/1f/ab8528e38d295fd349310807496fabb7cf9fe2e1f70b97bc20a483ea9d4a/numpy-2.4.3-cp314-cp314-win_arm64.whl", hash = "sha256:b44fd60341c4d9783039598efadd03617fa28d041fc37d22b62d08f2027fa0e7", size = 10494875, upload-time = "2026-03-09T07:58:08.734Z" }, + { url = "https://files.pythonhosted.org/packages/e6/ef/b7c35e4d5ef141b836658ab21a66d1a573e15b335b1d111d31f26c8ef80f/numpy-2.4.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0a195f4216be9305a73c0e91c9b026a35f2161237cf1c6de9b681637772ea657", size = 14822225, upload-time = "2026-03-09T07:58:11.034Z" }, + { url = "https://files.pythonhosted.org/packages/cd/8d/7730fa9278cf6648639946cc816e7cc89f0d891602584697923375f801ed/numpy-2.4.3-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:cd32fbacb9fd1bf041bf8e89e4576b6f00b895f06d00914820ae06a616bdfef7", size = 5328769, upload-time = "2026-03-09T07:58:13.67Z" }, + { url = "https://files.pythonhosted.org/packages/47/01/d2a137317c958b074d338807c1b6a383406cdf8b8e53b075d804cc3d211d/numpy-2.4.3-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:2e03c05abaee1f672e9d67bc858f300b5ccba1c21397211e8d77d98350972093", size = 6649461, upload-time = "2026-03-09T07:58:15.912Z" }, + { url = "https://files.pythonhosted.org/packages/5c/34/812ce12bc0f00272a4b0ec0d713cd237cb390666eb6206323d1cc9cedbb2/numpy-2.4.3-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7d1ce23cce91fcea443320a9d0ece9b9305d4368875bab09538f7a5b4131938a", size = 15725809, upload-time = "2026-03-09T07:58:17.787Z" }, + { url = "https://files.pythonhosted.org/packages/25/c0/2aed473a4823e905e765fee3dc2cbf504bd3e68ccb1150fbdabd5c39f527/numpy-2.4.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c59020932feb24ed49ffd03704fbab89f22aa9c0d4b180ff45542fe8918f5611", size = 16655242, upload-time = "2026-03-09T07:58:20.476Z" }, + { url = "https://files.pythonhosted.org/packages/f2/c8/7e052b2fc87aa0e86de23f20e2c42bd261c624748aa8efd2c78f7bb8d8c6/numpy-2.4.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9684823a78a6cd6ad7511fc5e25b07947d1d5b5e2812c93fe99d7d4195130720", size = 17080660, upload-time = "2026-03-09T07:58:23.067Z" }, + { url = "https://files.pythonhosted.org/packages/f3/3d/0876746044db2adcb11549f214d104f2e1be00f07a67edbb4e2812094847/numpy-2.4.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0200b25c687033316fb39f0ff4e3e690e8957a2c3c8d22499891ec58c37a3eb5", size = 18380384, upload-time = "2026-03-09T07:58:25.839Z" }, + { url = "https://files.pythonhosted.org/packages/07/12/8160bea39da3335737b10308df4f484235fd297f556745f13092aa039d3b/numpy-2.4.3-cp314-cp314t-win32.whl", hash = "sha256:5e10da9e93247e554bb1d22f8edc51847ddd7dde52d85ce31024c1b4312bfba0", size = 6154547, upload-time = "2026-03-09T07:58:28.289Z" }, + { url = "https://files.pythonhosted.org/packages/42/f3/76534f61f80d74cc9cdf2e570d3d4eeb92c2280a27c39b0aaf471eda7b48/numpy-2.4.3-cp314-cp314t-win_amd64.whl", hash = "sha256:45f003dbdffb997a03da2d1d0cb41fbd24a87507fb41605c0420a3db5bd4667b", size = 12633645, upload-time = "2026-03-09T07:58:30.384Z" }, + { url = "https://files.pythonhosted.org/packages/1f/b6/7c0d4334c15983cec7f92a69e8ce9b1e6f31857e5ee3a413ac424e6bd63d/numpy-2.4.3-cp314-cp314t-win_arm64.whl", hash = "sha256:4d382735cecd7bcf090172489a525cd7d4087bc331f7df9f60ddc9a296cf208e", size = 10565454, upload-time = "2026-03-09T07:58:33.031Z" }, + { url = "https://files.pythonhosted.org/packages/64/e4/4dab9fb43c83719c29241c535d9e07be73bea4bc0c6686c5816d8e1b6689/numpy-2.4.3-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c6b124bfcafb9e8d3ed09130dbee44848c20b3e758b6bbf006e641778927c028", size = 16834892, upload-time = "2026-03-09T07:58:35.334Z" }, + { url = "https://files.pythonhosted.org/packages/c9/29/f8b6d4af90fed3dfda84ebc0df06c9833d38880c79ce954e5b661758aa31/numpy-2.4.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:76dbb9d4e43c16cf9aa711fcd8de1e2eeb27539dcefb60a1d5e9f12fae1d1ed8", size = 14893070, upload-time = "2026-03-09T07:58:37.7Z" }, + { url = "https://files.pythonhosted.org/packages/9a/04/a19b3c91dbec0a49269407f15d5753673a09832daed40c45e8150e6fa558/numpy-2.4.3-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:29363fbfa6f8ee855d7569c96ce524845e3d726d6c19b29eceec7dd555dab152", size = 5399609, upload-time = "2026-03-09T07:58:39.853Z" }, + { url = "https://files.pythonhosted.org/packages/79/34/4d73603f5420eab89ea8a67097b31364bf7c30f811d4dd84b1659c7476d9/numpy-2.4.3-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:bc71942c789ef415a37f0d4eab90341425a00d538cd0642445d30b41023d3395", size = 6714355, upload-time = "2026-03-09T07:58:42.365Z" }, + { url = "https://files.pythonhosted.org/packages/58/ad/1100d7229bb248394939a12a8074d485b655e8ed44207d328fdd7fcebc7b/numpy-2.4.3-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7e58765ad74dcebd3ef0208a5078fba32dc8ec3578fe84a604432950cd043d79", size = 15800434, upload-time = "2026-03-09T07:58:44.837Z" }, + { url = "https://files.pythonhosted.org/packages/0c/fd/16d710c085d28ba4feaf29ac60c936c9d662e390344f94a6beaa2ac9899b/numpy-2.4.3-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e236dbda4e1d319d681afcbb136c0c4a8e0f1a5c58ceec2adebb547357fe857", size = 16729409, upload-time = "2026-03-09T07:58:47.972Z" }, + { url = "https://files.pythonhosted.org/packages/57/a7/b35835e278c18b85206834b3aa3abe68e77a98769c59233d1f6300284781/numpy-2.4.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:4b42639cdde6d24e732ff823a3fa5b701d8acad89c4142bc1d0bd6dc85200ba5", size = 12504685, upload-time = "2026-03-09T07:58:50.525Z" }, +] + [[package]] name = "orjson" version = "3.11.7" @@ -790,6 +1421,92 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, ] +[[package]] +name = "proto-plus" +version = "1.27.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3a/02/8832cde80e7380c600fbf55090b6ab7b62bd6825dbedde6d6657c15a1f8e/proto_plus-1.27.1.tar.gz", hash = "sha256:912a7460446625b792f6448bade9e55cd4e41e6ac10e27009ef71a7f317fa147", size = 56929, upload-time = "2026-02-02T17:34:49.035Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/79/ac273cbbf744691821a9cca88957257f41afe271637794975ca090b9588b/proto_plus-1.27.1-py3-none-any.whl", hash = "sha256:e4643061f3a4d0de092d62aa4ad09fa4756b2cbb89d4627f3985018216f9fefc", size = 50480, upload-time = "2026-02-02T17:34:47.339Z" }, +] + +[[package]] +name = "protobuf" +version = "6.33.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/25/7c72c307aafc96fa87062aa6291d9f7c94836e43214d43722e86037aac02/protobuf-6.33.5.tar.gz", hash = "sha256:6ddcac2a081f8b7b9642c09406bc6a4290128fce5f471cddd165960bb9119e5c", size = 444465, upload-time = "2026-01-29T21:51:33.494Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b1/79/af92d0a8369732b027e6d6084251dd8e782c685c72da161bd4a2e00fbabb/protobuf-6.33.5-cp310-abi3-win32.whl", hash = "sha256:d71b040839446bac0f4d162e758bea99c8251161dae9d0983a3b88dee345153b", size = 425769, upload-time = "2026-01-29T21:51:21.751Z" }, + { url = "https://files.pythonhosted.org/packages/55/75/bb9bc917d10e9ee13dee8607eb9ab963b7cf8be607c46e7862c748aa2af7/protobuf-6.33.5-cp310-abi3-win_amd64.whl", hash = "sha256:3093804752167bcab3998bec9f1048baae6e29505adaf1afd14a37bddede533c", size = 437118, upload-time = "2026-01-29T21:51:24.022Z" }, + { url = "https://files.pythonhosted.org/packages/a2/6b/e48dfc1191bc5b52950246275bf4089773e91cb5ba3592621723cdddca62/protobuf-6.33.5-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:a5cb85982d95d906df1e2210e58f8e4f1e3cdc088e52c921a041f9c9a0386de5", size = 427766, upload-time = "2026-01-29T21:51:25.413Z" }, + { url = "https://files.pythonhosted.org/packages/4e/b1/c79468184310de09d75095ed1314b839eb2f72df71097db9d1404a1b2717/protobuf-6.33.5-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:9b71e0281f36f179d00cbcb119cb19dec4d14a81393e5ea220f64b286173e190", size = 324638, upload-time = "2026-01-29T21:51:26.423Z" }, + { url = "https://files.pythonhosted.org/packages/c5/f5/65d838092fd01c44d16037953fd4c2cc851e783de9b8f02b27ec4ffd906f/protobuf-6.33.5-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:8afa18e1d6d20af15b417e728e9f60f3aa108ee76f23c3b2c07a2c3b546d3afd", size = 339411, upload-time = "2026-01-29T21:51:27.446Z" }, + { url = "https://files.pythonhosted.org/packages/9b/53/a9443aa3ca9ba8724fdfa02dd1887c1bcd8e89556b715cfbacca6b63dbec/protobuf-6.33.5-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:cbf16ba3350fb7b889fca858fb215967792dc125b35c7976ca4818bee3521cf0", size = 323465, upload-time = "2026-01-29T21:51:28.925Z" }, + { url = "https://files.pythonhosted.org/packages/57/bf/2086963c69bdac3d7cff1cc7ff79b8ce5ea0bec6797a017e1be338a46248/protobuf-6.33.5-py3-none-any.whl", hash = "sha256:69915a973dd0f60f31a08b8318b73eab2bd6a392c79184b3612226b0a3f8ec02", size = 170687, upload-time = "2026-01-29T21:51:32.557Z" }, +] + +[[package]] +name = "py-cpuinfo" +version = "9.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/37/a8/d832f7293ebb21690860d2e01d8115e5ff6f2ae8bbdc953f0eb0fa4bd2c7/py-cpuinfo-9.0.0.tar.gz", hash = "sha256:3cdbbf3fac90dc6f118bfd64384f309edeadd902d7c8fb17f02ffa1fc3f49690", size = 104716, upload-time = "2022-10-25T20:38:06.303Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/a9/023730ba63db1e494a271cb018dcd361bd2c917ba7004c3e49d5daf795a2/py_cpuinfo-9.0.0-py3-none-any.whl", hash = "sha256:859625bc251f64e21f077d099d4162689c762b5d6a4c3c97553d56241c9674d5", size = 22335, upload-time = "2022-10-25T20:38:27.636Z" }, +] + +[[package]] +name = "pyarrow" +version = "22.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/30/53/04a7fdc63e6056116c9ddc8b43bc28c12cdd181b85cbeadb79278475f3ae/pyarrow-22.0.0.tar.gz", hash = "sha256:3d600dc583260d845c7d8a6db540339dd883081925da2bd1c5cb808f720b3cd9", size = 1151151, upload-time = "2025-10-24T12:30:00.762Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/b7/18f611a8cdc43417f9394a3ccd3eace2f32183c08b9eddc3d17681819f37/pyarrow-22.0.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:3e294c5eadfb93d78b0763e859a0c16d4051fc1c5231ae8956d61cb0b5666f5a", size = 34272022, upload-time = "2025-10-24T10:04:28.973Z" }, + { url = "https://files.pythonhosted.org/packages/26/5c/f259e2526c67eb4b9e511741b19870a02363a47a35edbebc55c3178db22d/pyarrow-22.0.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:69763ab2445f632d90b504a815a2a033f74332997052b721002298ed6de40f2e", size = 35995834, upload-time = "2025-10-24T10:04:35.467Z" }, + { url = "https://files.pythonhosted.org/packages/50/8d/281f0f9b9376d4b7f146913b26fac0aa2829cd1ee7e997f53a27411bbb92/pyarrow-22.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:b41f37cabfe2463232684de44bad753d6be08a7a072f6a83447eeaf0e4d2a215", size = 45030348, upload-time = "2025-10-24T10:04:43.366Z" }, + { url = "https://files.pythonhosted.org/packages/f5/e5/53c0a1c428f0976bf22f513d79c73000926cb00b9c138d8e02daf2102e18/pyarrow-22.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:35ad0f0378c9359b3f297299c3309778bb03b8612f987399a0333a560b43862d", size = 47699480, upload-time = "2025-10-24T10:04:51.486Z" }, + { url = "https://files.pythonhosted.org/packages/95/e1/9dbe4c465c3365959d183e6345d0a8d1dc5b02ca3f8db4760b3bc834cf25/pyarrow-22.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8382ad21458075c2e66a82a29d650f963ce51c7708c7c0ff313a8c206c4fd5e8", size = 48011148, upload-time = "2025-10-24T10:04:59.585Z" }, + { url = "https://files.pythonhosted.org/packages/c5/b4/7caf5d21930061444c3cf4fa7535c82faf5263e22ce43af7c2759ceb5b8b/pyarrow-22.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1a812a5b727bc09c3d7ea072c4eebf657c2f7066155506ba31ebf4792f88f016", size = 50276964, upload-time = "2025-10-24T10:05:08.175Z" }, + { url = "https://files.pythonhosted.org/packages/ae/f3/cec89bd99fa3abf826f14d4e53d3d11340ce6f6af4d14bdcd54cd83b6576/pyarrow-22.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:ec5d40dd494882704fb876c16fa7261a69791e784ae34e6b5992e977bd2e238c", size = 28106517, upload-time = "2025-10-24T10:05:14.314Z" }, + { url = "https://files.pythonhosted.org/packages/af/63/ba23862d69652f85b615ca14ad14f3bcfc5bf1b99ef3f0cd04ff93fdad5a/pyarrow-22.0.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:bea79263d55c24a32b0d79c00a1c58bb2ee5f0757ed95656b01c0fb310c5af3d", size = 34211578, upload-time = "2025-10-24T10:05:21.583Z" }, + { url = "https://files.pythonhosted.org/packages/b1/d0/f9ad86fe809efd2bcc8be32032fa72e8b0d112b01ae56a053006376c5930/pyarrow-22.0.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:12fe549c9b10ac98c91cf791d2945e878875d95508e1a5d14091a7aaa66d9cf8", size = 35989906, upload-time = "2025-10-24T10:05:29.485Z" }, + { url = "https://files.pythonhosted.org/packages/b4/a8/f910afcb14630e64d673f15904ec27dd31f1e009b77033c365c84e8c1e1d/pyarrow-22.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:334f900ff08ce0423407af97e6c26ad5d4e3b0763645559ece6fbf3747d6a8f5", size = 45021677, upload-time = "2025-10-24T10:05:38.274Z" }, + { url = "https://files.pythonhosted.org/packages/13/95/aec81f781c75cd10554dc17a25849c720d54feafb6f7847690478dcf5ef8/pyarrow-22.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:c6c791b09c57ed76a18b03f2631753a4960eefbbca80f846da8baefc6491fcfe", size = 47726315, upload-time = "2025-10-24T10:05:47.314Z" }, + { url = "https://files.pythonhosted.org/packages/bb/d4/74ac9f7a54cfde12ee42734ea25d5a3c9a45db78f9def949307a92720d37/pyarrow-22.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c3200cb41cdbc65156e5f8c908d739b0dfed57e890329413da2748d1a2cd1a4e", size = 47990906, upload-time = "2025-10-24T10:05:58.254Z" }, + { url = "https://files.pythonhosted.org/packages/2e/71/fedf2499bf7a95062eafc989ace56572f3343432570e1c54e6599d5b88da/pyarrow-22.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ac93252226cf288753d8b46280f4edf3433bf9508b6977f8dd8526b521a1bbb9", size = 50306783, upload-time = "2025-10-24T10:06:08.08Z" }, + { url = "https://files.pythonhosted.org/packages/68/ed/b202abd5a5b78f519722f3d29063dda03c114711093c1995a33b8e2e0f4b/pyarrow-22.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:44729980b6c50a5f2bfcc2668d36c569ce17f8b17bccaf470c4313dcbbf13c9d", size = 27972883, upload-time = "2025-10-24T10:06:14.204Z" }, + { url = "https://files.pythonhosted.org/packages/a6/d6/d0fac16a2963002fc22c8fa75180a838737203d558f0ed3b564c4a54eef5/pyarrow-22.0.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:e6e95176209257803a8b3d0394f21604e796dadb643d2f7ca21b66c9c0b30c9a", size = 34204629, upload-time = "2025-10-24T10:06:20.274Z" }, + { url = "https://files.pythonhosted.org/packages/c6/9c/1d6357347fbae062ad3f17082f9ebc29cc733321e892c0d2085f42a2212b/pyarrow-22.0.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:001ea83a58024818826a9e3f89bf9310a114f7e26dfe404a4c32686f97bd7901", size = 35985783, upload-time = "2025-10-24T10:06:27.301Z" }, + { url = "https://files.pythonhosted.org/packages/ff/c0/782344c2ce58afbea010150df07e3a2f5fdad299cd631697ae7bd3bac6e3/pyarrow-22.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:ce20fe000754f477c8a9125543f1936ea5b8867c5406757c224d745ed033e691", size = 45020999, upload-time = "2025-10-24T10:06:35.387Z" }, + { url = "https://files.pythonhosted.org/packages/1b/8b/5362443737a5307a7b67c1017c42cd104213189b4970bf607e05faf9c525/pyarrow-22.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e0a15757fccb38c410947df156f9749ae4a3c89b2393741a50521f39a8cf202a", size = 47724601, upload-time = "2025-10-24T10:06:43.551Z" }, + { url = "https://files.pythonhosted.org/packages/69/4d/76e567a4fc2e190ee6072967cb4672b7d9249ac59ae65af2d7e3047afa3b/pyarrow-22.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cedb9dd9358e4ea1d9bce3665ce0797f6adf97ff142c8e25b46ba9cdd508e9b6", size = 48001050, upload-time = "2025-10-24T10:06:52.284Z" }, + { url = "https://files.pythonhosted.org/packages/01/5e/5653f0535d2a1aef8223cee9d92944cb6bccfee5cf1cd3f462d7cb022790/pyarrow-22.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:252be4a05f9d9185bb8c18e83764ebcfea7185076c07a7a662253af3a8c07941", size = 50307877, upload-time = "2025-10-24T10:07:02.405Z" }, + { url = "https://files.pythonhosted.org/packages/2d/f8/1d0bd75bf9328a3b826e24a16e5517cd7f9fbf8d34a3184a4566ef5a7f29/pyarrow-22.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:a4893d31e5ef780b6edcaf63122df0f8d321088bb0dee4c8c06eccb1ca28d145", size = 27977099, upload-time = "2025-10-24T10:08:07.259Z" }, + { url = "https://files.pythonhosted.org/packages/90/81/db56870c997805bf2b0f6eeeb2d68458bf4654652dccdcf1bf7a42d80903/pyarrow-22.0.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:f7fe3dbe871294ba70d789be16b6e7e52b418311e166e0e3cba9522f0f437fb1", size = 34336685, upload-time = "2025-10-24T10:07:11.47Z" }, + { url = "https://files.pythonhosted.org/packages/1c/98/0727947f199aba8a120f47dfc229eeb05df15bcd7a6f1b669e9f882afc58/pyarrow-22.0.0-cp313-cp313t-macosx_12_0_x86_64.whl", hash = "sha256:ba95112d15fd4f1105fb2402c4eab9068f0554435e9b7085924bcfaac2cc306f", size = 36032158, upload-time = "2025-10-24T10:07:18.626Z" }, + { url = "https://files.pythonhosted.org/packages/96/b4/9babdef9c01720a0785945c7cf550e4acd0ebcd7bdd2e6f0aa7981fa85e2/pyarrow-22.0.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:c064e28361c05d72eed8e744c9605cbd6d2bb7481a511c74071fd9b24bc65d7d", size = 44892060, upload-time = "2025-10-24T10:07:26.002Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ca/2f8804edd6279f78a37062d813de3f16f29183874447ef6d1aadbb4efa0f/pyarrow-22.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:6f9762274496c244d951c819348afbcf212714902742225f649cf02823a6a10f", size = 47504395, upload-time = "2025-10-24T10:07:34.09Z" }, + { url = "https://files.pythonhosted.org/packages/b9/f0/77aa5198fd3943682b2e4faaf179a674f0edea0d55d326d83cb2277d9363/pyarrow-22.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a9d9ffdc2ab696f6b15b4d1f7cec6658e1d788124418cb30030afbae31c64746", size = 48066216, upload-time = "2025-10-24T10:07:43.528Z" }, + { url = "https://files.pythonhosted.org/packages/79/87/a1937b6e78b2aff18b706d738c9e46ade5bfcf11b294e39c87706a0089ac/pyarrow-22.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ec1a15968a9d80da01e1d30349b2b0d7cc91e96588ee324ce1b5228175043e95", size = 50288552, upload-time = "2025-10-24T10:07:53.519Z" }, + { url = "https://files.pythonhosted.org/packages/60/ae/b5a5811e11f25788ccfdaa8f26b6791c9807119dffcf80514505527c384c/pyarrow-22.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:bba208d9c7decf9961998edf5c65e3ea4355d5818dd6cd0f6809bec1afb951cc", size = 28262504, upload-time = "2025-10-24T10:08:00.932Z" }, + { url = "https://files.pythonhosted.org/packages/bd/b0/0fa4d28a8edb42b0a7144edd20befd04173ac79819547216f8a9f36f9e50/pyarrow-22.0.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:9bddc2cade6561f6820d4cd73f99a0243532ad506bc510a75a5a65a522b2d74d", size = 34224062, upload-time = "2025-10-24T10:08:14.101Z" }, + { url = "https://files.pythonhosted.org/packages/0f/a8/7a719076b3c1be0acef56a07220c586f25cd24de0e3f3102b438d18ae5df/pyarrow-22.0.0-cp314-cp314-macosx_12_0_x86_64.whl", hash = "sha256:e70ff90c64419709d38c8932ea9fe1cc98415c4f87ea8da81719e43f02534bc9", size = 35990057, upload-time = "2025-10-24T10:08:21.842Z" }, + { url = "https://files.pythonhosted.org/packages/89/3c/359ed54c93b47fb6fe30ed16cdf50e3f0e8b9ccfb11b86218c3619ae50a8/pyarrow-22.0.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:92843c305330aa94a36e706c16209cd4df274693e777ca47112617db7d0ef3d7", size = 45068002, upload-time = "2025-10-24T10:08:29.034Z" }, + { url = "https://files.pythonhosted.org/packages/55/fc/4945896cc8638536ee787a3bd6ce7cec8ec9acf452d78ec39ab328efa0a1/pyarrow-22.0.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:6dda1ddac033d27421c20d7a7943eec60be44e0db4e079f33cc5af3b8280ccde", size = 47737765, upload-time = "2025-10-24T10:08:38.559Z" }, + { url = "https://files.pythonhosted.org/packages/cd/5e/7cb7edeb2abfaa1f79b5d5eb89432356155c8426f75d3753cbcb9592c0fd/pyarrow-22.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:84378110dd9a6c06323b41b56e129c504d157d1a983ce8f5443761eb5256bafc", size = 48048139, upload-time = "2025-10-24T10:08:46.784Z" }, + { url = "https://files.pythonhosted.org/packages/88/c6/546baa7c48185f5e9d6e59277c4b19f30f48c94d9dd938c2a80d4d6b067c/pyarrow-22.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:854794239111d2b88b40b6ef92aa478024d1e5074f364033e73e21e3f76b25e0", size = 50314244, upload-time = "2025-10-24T10:08:55.771Z" }, + { url = "https://files.pythonhosted.org/packages/3c/79/755ff2d145aafec8d347bf18f95e4e81c00127f06d080135dfc86aea417c/pyarrow-22.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:b883fe6fd85adad7932b3271c38ac289c65b7337c2c132e9569f9d3940620730", size = 28757501, upload-time = "2025-10-24T10:09:59.891Z" }, + { url = "https://files.pythonhosted.org/packages/0e/d2/237d75ac28ced3147912954e3c1a174df43a95f4f88e467809118a8165e0/pyarrow-22.0.0-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:7a820d8ae11facf32585507c11f04e3f38343c1e784c9b5a8b1da5c930547fe2", size = 34355506, upload-time = "2025-10-24T10:09:02.953Z" }, + { url = "https://files.pythonhosted.org/packages/1e/2c/733dfffe6d3069740f98e57ff81007809067d68626c5faef293434d11bd6/pyarrow-22.0.0-cp314-cp314t-macosx_12_0_x86_64.whl", hash = "sha256:c6ec3675d98915bf1ec8b3c7986422682f7232ea76cad276f4c8abd5b7319b70", size = 36047312, upload-time = "2025-10-24T10:09:10.334Z" }, + { url = "https://files.pythonhosted.org/packages/7c/2b/29d6e3782dc1f299727462c1543af357a0f2c1d3c160ce199950d9ca51eb/pyarrow-22.0.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:3e739edd001b04f654b166204fc7a9de896cf6007eaff33409ee9e50ceaff754", size = 45081609, upload-time = "2025-10-24T10:09:18.61Z" }, + { url = "https://files.pythonhosted.org/packages/8d/42/aa9355ecc05997915af1b7b947a7f66c02dcaa927f3203b87871c114ba10/pyarrow-22.0.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:7388ac685cab5b279a41dfe0a6ccd99e4dbf322edfb63e02fc0443bf24134e91", size = 47703663, upload-time = "2025-10-24T10:09:27.369Z" }, + { url = "https://files.pythonhosted.org/packages/ee/62/45abedde480168e83a1de005b7b7043fd553321c1e8c5a9a114425f64842/pyarrow-22.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f633074f36dbc33d5c05b5dc75371e5660f1dbf9c8b1d95669def05e5425989c", size = 48066543, upload-time = "2025-10-24T10:09:34.908Z" }, + { url = "https://files.pythonhosted.org/packages/84/e9/7878940a5b072e4f3bf998770acafeae13b267f9893af5f6d4ab3904b67e/pyarrow-22.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:4c19236ae2402a8663a2c8f21f1870a03cc57f0bef7e4b6eb3238cc82944de80", size = 50288838, upload-time = "2025-10-24T10:09:44.394Z" }, + { url = "https://files.pythonhosted.org/packages/7b/03/f335d6c52b4a4761bcc83499789a1e2e16d9d201a58c327a9b5cc9a41bd9/pyarrow-22.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0c34fe18094686194f204a3b1787a27456897d8a2d62caf84b61e8dfbc0252ae", size = 29185594, upload-time = "2025-10-24T10:09:53.111Z" }, +] + [[package]] name = "pyasn1" version = "0.6.2" @@ -984,6 +1701,80 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e5/35/f8b19922b6a25bc0880171a2f1a003eaeb93657475193ab516fd87cac9da/pytest_asyncio-1.3.0-py3-none-any.whl", hash = "sha256:611e26147c7f77640e6d0a92a38ed17c3e9848063698d5c93d5aa7aa11cebff5", size = 15075, upload-time = "2025-11-10T16:07:45.537Z" }, ] +[[package]] +name = "pytest-benchmark" +version = "5.2.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "py-cpuinfo" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/24/34/9f732b76456d64faffbef6232f1f9dbec7a7c4999ff46282fa418bd1af66/pytest_benchmark-5.2.3.tar.gz", hash = "sha256:deb7317998a23c650fd4ff76e1230066a76cb45dcece0aca5607143c619e7779", size = 341340, upload-time = "2025-11-09T18:48:43.215Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/33/29/e756e715a48959f1c0045342088d7ca9762a2f509b945f362a316e9412b7/pytest_benchmark-5.2.3-py3-none-any.whl", hash = "sha256:bc839726ad20e99aaa0d11a127445457b4219bdb9e80a1afc4b51da7f96b0803", size = 45255, upload-time = "2025-11-09T18:48:39.765Z" }, +] + +[[package]] +name = "pytest-codspeed" +version = "4.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi" }, + { name = "pytest" }, + { name = "rich" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/98/ab/eca41967d11c95392829a8b4bfa9220a51cffc4a33ec4653358000356918/pytest_codspeed-4.3.0.tar.gz", hash = "sha256:5230d9d65f39063a313ed1820df775166227ec5c20a1122968f85653d5efee48", size = 124745, upload-time = "2026-02-09T15:23:34.745Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/15/ec0ac1f022173b3134c9638f2a35f21fbb3142c75da066d9e49e5a8bb4bd/pytest_codspeed-4.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dbeff1eb2f2e36df088658b556fa993e6937bf64ffb07406de4db16fd2b26874", size = 347076, upload-time = "2026-02-09T15:23:19.989Z" }, + { url = "https://files.pythonhosted.org/packages/a5/e8/1fe375794ad02b7835f378a7bcfa8fbac9acadefe600a782a7c4a7064db7/pytest_codspeed-4.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:878aad5e4bb7b401ad8d82f3af5186030cd2bd0d0446782e10dabb9db8827466", size = 342215, upload-time = "2026-02-09T15:23:20.954Z" }, + { url = "https://files.pythonhosted.org/packages/09/58/50df94e9a78e1c77818a492c90557eeb1309af025120c9a21e6375950c52/pytest_codspeed-4.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:527a3a02eaa3e4d4583adc4ba2327eef79628f3e1c682a4b959439551a72588e", size = 347395, upload-time = "2026-02-09T15:23:21.986Z" }, + { url = "https://files.pythonhosted.org/packages/e4/56/7dfbd3eefd112a14e6fb65f9ff31dacf2e9c381cb94b27332b81d2b13f8d/pytest_codspeed-4.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9858c2a6e1f391d5696757e7b6e9484749a7376c46f8b4dd9aebf093479a9667", size = 342625, upload-time = "2026-02-09T15:23:23.035Z" }, + { url = "https://files.pythonhosted.org/packages/7f/53/7255f6a25bc56ff1745b254b21545dfe0be2268f5b91ce78f7e8a908f0ad/pytest_codspeed-4.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:34f2fd8497456eefbd325673f677ea80d93bb1bc08a578c1fa43a09cec3d1879", size = 347325, upload-time = "2026-02-09T15:23:23.998Z" }, + { url = "https://files.pythonhosted.org/packages/2e/f8/82ae570d8b9ad30f33c9d4002a7a1b2740de0e090540c69a28e4f711ebe2/pytest_codspeed-4.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:df6a36a2a9da1406bc50428437f657f0bd8c842ae54bee5fb3ad30e01d50c0f5", size = 342558, upload-time = "2026-02-09T15:23:25.656Z" }, + { url = "https://files.pythonhosted.org/packages/b3/e1/55cfe9474f91d174c7a4b04d257b5fc6d4d06f3d3680f2da672ee59ccc10/pytest_codspeed-4.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bec30f4fc9c4973143cd80f0d33fa780e9fa3e01e4dbe8cedf229e72f1212c62", size = 347383, upload-time = "2026-02-09T15:23:26.68Z" }, + { url = "https://files.pythonhosted.org/packages/7f/3b/8fd781d959bbe789b3de8ce4c50d5706a684a0df377147dfb27b200c20c1/pytest_codspeed-4.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e6584e641cadf27d894ae90b87c50377232a97cbfd76ee0c7ecd0c056fa3f7f4", size = 342481, upload-time = "2026-02-09T15:23:27.686Z" }, + { url = "https://files.pythonhosted.org/packages/bb/0c/368045133c6effa2c665b1634b7b8a9c88b307f877fa31f1f8df47885b51/pytest_codspeed-4.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:df0d1f6ea594f29b745c634d66d5f5f1caa1c3abd2af82fea49d656038e8fc77", size = 353680, upload-time = "2026-02-09T15:23:28.726Z" }, + { url = "https://files.pythonhosted.org/packages/59/21/e543abcd72244294e25ae88ec3a9311ade24d6913f8c8f42569d671700bc/pytest_codspeed-4.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a2f5bb6d8898bea7db45e3c8b916ee48e36905b929477bb511b79c5a3ccacda4", size = 347888, upload-time = "2026-02-09T15:23:30.443Z" }, + { url = "https://files.pythonhosted.org/packages/55/d9/b8a53c20cf5b41042c205bb9d36d37da00418d30fd1a94bf9eb147820720/pytest_codspeed-4.3.0-py3-none-any.whl", hash = "sha256:05baff2a61dc9f3e92b92b9c2ab5fb45d9b802438f5373073f5766a91319ed7a", size = 125224, upload-time = "2026-02-09T15:23:33.774Z" }, +] + +[[package]] +name = "pytest-recording" +version = "0.13.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, + { name = "vcrpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/32/9c/f4027c5f1693847b06d11caf4b4f6bb09f22c1581ada4663877ec166b8c6/pytest_recording-0.13.4.tar.gz", hash = "sha256:568d64b2a85992eec4ae0a419c855d5fd96782c5fb016784d86f18053792768c", size = 26576, upload-time = "2025-05-08T10:41:11.231Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/42/c2/ce34735972cc42d912173e79f200fe66530225190c06655c5632a9d88f1e/pytest_recording-0.13.4-py3-none-any.whl", hash = "sha256:ad49a434b51b1c4f78e85b1e6b74fdcc2a0a581ca16e52c798c6ace971f7f439", size = 13723, upload-time = "2025-05-08T10:41:09.684Z" }, +] + +[[package]] +name = "pytest-socket" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/05/ff/90c7e1e746baf3d62ce864c479fd53410b534818b9437413903596f81580/pytest_socket-0.7.0.tar.gz", hash = "sha256:71ab048cbbcb085c15a4423b73b619a8b35d6a307f46f78ea46be51b1b7e11b3", size = 12389, upload-time = "2024-01-28T20:17:23.177Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/19/58/5d14cb5cb59409e491ebe816c47bf81423cd03098ea92281336320ae5681/pytest_socket-0.7.0-py3-none-any.whl", hash = "sha256:7e0f4642177d55d317bbd58fc68c6bd9048d6eadb2d46a89307fa9221336ce45", size = 6754, upload-time = "2024-01-28T20:17:22.105Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + [[package]] name = "python-dotenv" version = "1.2.1" @@ -1075,6 +1866,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06", size = 54481, upload-time = "2023-05-01T04:11:28.427Z" }, ] +[[package]] +name = "rich" +version = "14.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b3/c6/f3b320c27991c46f43ee9d856302c70dc2d0fb2dba4842ff739d5f46b393/rich-14.3.3.tar.gz", hash = "sha256:b8daa0b9e4eef54dd8cf7c86c03713f53241884e814f4e2f5fb342fe520f639b", size = 230582, upload-time = "2026-02-19T17:23:12.474Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/14/25/b208c5683343959b670dc001595f2f3737e051da617f66c31f7c4fa93abc/rich-14.3.3-py3-none-any.whl", hash = "sha256:793431c1f8619afa7d3b52b2cdec859562b950ea0d4b6b505397612db8d5362d", size = 310458, upload-time = "2026-02-19T17:23:13.732Z" }, +] + [[package]] name = "rsa" version = "4.9.1" @@ -1087,6 +1891,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696, upload-time = "2025-04-16T09:51:17.142Z" }, ] +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + [[package]] name = "sniffio" version = "1.3.1" @@ -1108,6 +1921,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8b/0c/9d30a4ebeb6db2b25a841afbb80f6ef9a854fc3b41be131d249a977b4959/starlette-0.46.2-py3-none-any.whl", hash = "sha256:595633ce89f8ffa71a015caed34a5b2dc1c0cdb3f0f1fbd1e69339cf2abeec35", size = 72037, upload-time = "2025-04-13T13:56:16.21Z" }, ] +[[package]] +name = "syrupy" +version = "5.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2e/b0/24bca682d6a6337854be37f242d116cceeda9942571d5804c44bc1bdd427/syrupy-5.1.0.tar.gz", hash = "sha256:df543c7aa50d3cf1246e83d58fe490afe5f7dab7b41e74ecc0d8d23ae19bd4b8", size = 50495, upload-time = "2026-01-25T14:53:06.2Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/70/cf880c3b95a6034ef673e74b369941b42315c01f1554a5637a4f8b911009/syrupy-5.1.0-py3-none-any.whl", hash = "sha256:95162d2b05e61ed3e13f117b88dfab7c58bd6f90e66ebbf918e8a77114ad51c5", size = 51658, upload-time = "2026-01-25T14:53:05.105Z" }, +] + [[package]] name = "tenacity" version = "9.1.4" @@ -1247,6 +2072,28 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e4/16/c1fd27e9549f3c4baf1dc9c20c456cd2f822dbf8de9f463824b0c0357e06/uvloop-0.22.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6cde23eeda1a25c75b2e07d39970f3374105d5eafbaab2a4482be82f272d5a5e", size = 4296730, upload-time = "2025-10-16T22:17:00.744Z" }, ] +[[package]] +name = "validators" +version = "0.35.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/53/66/a435d9ae49850b2f071f7ebd8119dd4e84872b01630d6736761e6e7fd847/validators-0.35.0.tar.gz", hash = "sha256:992d6c48a4e77c81f1b4daba10d16c3a9bb0dbb79b3a19ea847ff0928e70497a", size = 73399, upload-time = "2025-05-01T05:42:06.7Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/6e/3e955517e22cbdd565f2f8b2e73d52528b14b8bcfdb04f62466b071de847/validators-0.35.0-py3-none-any.whl", hash = "sha256:e8c947097eae7892cb3d26868d637f79f47b4a0554bc6b80065dfe5aac3705dd", size = 44712, upload-time = "2025-05-01T05:42:04.203Z" }, +] + +[[package]] +name = "vcrpy" +version = "8.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyyaml" }, + { name = "wrapt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b3/07/bcfd5ebd7cb308026ab78a353e091bd699593358be49197d39d004e5ad83/vcrpy-8.1.1.tar.gz", hash = "sha256:58e3053e33b423f3594031cb758c3f4d1df931307f1e67928e30cf352df7709f", size = 85770, upload-time = "2026-01-04T19:22:03.886Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/d7/f79b05a5d728f8786876a7d75dfb0c5cae27e428081b2d60152fb52f155f/vcrpy-8.1.1-py3-none-any.whl", hash = "sha256:2d16f31ad56493efb6165182dd99767207031b0da3f68b18f975545ede8ac4b9", size = 42445, upload-time = "2026-01-04T19:22:02.532Z" }, +] + [[package]] name = "watchfiles" version = "1.1.1" @@ -1376,6 +2223,81 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, ] +[[package]] +name = "wrapt" +version = "2.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2e/64/925f213fdcbb9baeb1530449ac71a4d57fc361c053d06bf78d0c5c7cd80c/wrapt-2.1.2.tar.gz", hash = "sha256:3996a67eecc2c68fd47b4e3c564405a5777367adfd9b8abb58387b63ee83b21e", size = 81678, upload-time = "2026-03-06T02:53:25.134Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/81/60c4471fce95afa5922ca09b88a25f03c93343f759aae0f31fb4412a85c7/wrapt-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:96159a0ee2b0277d44201c3b5be479a9979cf154e8c82fa5df49586a8e7679bb", size = 60666, upload-time = "2026-03-06T02:52:58.934Z" }, + { url = "https://files.pythonhosted.org/packages/6b/be/80e80e39e7cb90b006a0eaf11c73ac3a62bbfb3068469aec15cc0bc795de/wrapt-2.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:98ba61833a77b747901e9012072f038795de7fc77849f1faa965464f3f87ff2d", size = 61601, upload-time = "2026-03-06T02:53:00.487Z" }, + { url = "https://files.pythonhosted.org/packages/b0/be/d7c88cd9293c859fc74b232abdc65a229bb953997995d6912fc85af18323/wrapt-2.1.2-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:767c0dbbe76cae2a60dd2b235ac0c87c9cccf4898aef8062e57bead46b5f6894", size = 114057, upload-time = "2026-03-06T02:52:44.08Z" }, + { url = "https://files.pythonhosted.org/packages/ea/25/36c04602831a4d685d45a93b3abea61eca7fe35dab6c842d6f5d570ef94a/wrapt-2.1.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c691a6bc752c0cc4711cc0c00896fcd0f116abc253609ef64ef930032821842", size = 116099, upload-time = "2026-03-06T02:54:56.74Z" }, + { url = "https://files.pythonhosted.org/packages/5c/4e/98a6eb417ef551dc277bec1253d5246b25003cf36fdf3913b65cb7657a56/wrapt-2.1.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f3b7d73012ea75aee5844de58c88f44cf62d0d62711e39da5a82824a7c4626a8", size = 112457, upload-time = "2026-03-06T02:53:52.842Z" }, + { url = "https://files.pythonhosted.org/packages/cb/a6/a6f7186a5297cad8ec53fd7578533b28f795fdf5372368c74bd7e6e9841c/wrapt-2.1.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:577dff354e7acd9d411eaf4bfe76b724c89c89c8fc9b7e127ee28c5f7bcb25b6", size = 115351, upload-time = "2026-03-06T02:53:32.684Z" }, + { url = "https://files.pythonhosted.org/packages/97/6f/06e66189e721dbebd5cf20e138acc4d1150288ce118462f2fcbff92d38db/wrapt-2.1.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:3d7b6fd105f8b24e5bd23ccf41cb1d1099796524bcc6f7fbb8fe576c44befbc9", size = 111748, upload-time = "2026-03-06T02:53:08.455Z" }, + { url = "https://files.pythonhosted.org/packages/ef/43/4808b86f499a51370fbdbdfa6cb91e9b9169e762716456471b619fca7a70/wrapt-2.1.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:866abdbf4612e0b34764922ef8b1c5668867610a718d3053d59e24a5e5fcfc15", size = 113783, upload-time = "2026-03-06T02:53:02.02Z" }, + { url = "https://files.pythonhosted.org/packages/91/2c/a3f28b8fa7ac2cefa01cfcaca3471f9b0460608d012b693998cd61ef43df/wrapt-2.1.2-cp311-cp311-win32.whl", hash = "sha256:5a0a0a3a882393095573344075189eb2d566e0fd205a2b6414e9997b1b800a8b", size = 57977, upload-time = "2026-03-06T02:53:27.844Z" }, + { url = "https://files.pythonhosted.org/packages/3f/c3/2b1c7bd07a27b1db885a2fab469b707bdd35bddf30a113b4917a7e2139d2/wrapt-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:64a07a71d2730ba56f11d1a4b91f7817dc79bc134c11516b75d1921a7c6fcda1", size = 60336, upload-time = "2026-03-06T02:54:28.104Z" }, + { url = "https://files.pythonhosted.org/packages/ec/5c/76ece7b401b088daa6503d6264dd80f9a727df3e6042802de9a223084ea2/wrapt-2.1.2-cp311-cp311-win_arm64.whl", hash = "sha256:b89f095fe98bc12107f82a9f7d570dc83a0870291aeb6b1d7a7d35575f55d98a", size = 58756, upload-time = "2026-03-06T02:53:16.319Z" }, + { url = "https://files.pythonhosted.org/packages/4c/b6/1db817582c49c7fcbb7df6809d0f515af29d7c2fbf57eb44c36e98fb1492/wrapt-2.1.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ff2aad9c4cda28a8f0653fc2d487596458c2a3f475e56ba02909e950a9efa6a9", size = 61255, upload-time = "2026-03-06T02:52:45.663Z" }, + { url = "https://files.pythonhosted.org/packages/a2/16/9b02a6b99c09227c93cd4b73acc3678114154ec38da53043c0ddc1fba0dc/wrapt-2.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6433ea84e1cfacf32021d2a4ee909554ade7fd392caa6f7c13f1f4bf7b8e8748", size = 61848, upload-time = "2026-03-06T02:53:48.728Z" }, + { url = "https://files.pythonhosted.org/packages/af/aa/ead46a88f9ec3a432a4832dfedb84092fc35af2d0ba40cd04aea3889f247/wrapt-2.1.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c20b757c268d30d6215916a5fa8461048d023865d888e437fab451139cad6c8e", size = 121433, upload-time = "2026-03-06T02:54:40.328Z" }, + { url = "https://files.pythonhosted.org/packages/3a/9f/742c7c7cdf58b59085a1ee4b6c37b013f66ac33673a7ef4aaed5e992bc33/wrapt-2.1.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79847b83eb38e70d93dc392c7c5b587efe65b3e7afcc167aa8abd5d60e8761c8", size = 123013, upload-time = "2026-03-06T02:53:26.58Z" }, + { url = "https://files.pythonhosted.org/packages/e8/44/2c3dd45d53236b7ed7c646fcf212251dc19e48e599debd3926b52310fafb/wrapt-2.1.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f8fba1bae256186a83d1875b2b1f4e2d1242e8fac0f58ec0d7e41b26967b965c", size = 117326, upload-time = "2026-03-06T02:53:11.547Z" }, + { url = "https://files.pythonhosted.org/packages/74/e2/b17d66abc26bd96f89dec0ecd0ef03da4a1286e6ff793839ec431b9fae57/wrapt-2.1.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e3d3b35eedcf5f7d022291ecd7533321c4775f7b9cd0050a31a68499ba45757c", size = 121444, upload-time = "2026-03-06T02:54:09.5Z" }, + { url = "https://files.pythonhosted.org/packages/3c/62/e2977843fdf9f03daf1586a0ff49060b1b2fc7ff85a7ea82b6217c1ae36e/wrapt-2.1.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:6f2c5390460de57fa9582bc8a1b7a6c86e1a41dfad74c5225fc07044c15cc8d1", size = 116237, upload-time = "2026-03-06T02:54:03.884Z" }, + { url = "https://files.pythonhosted.org/packages/88/dd/27fc67914e68d740bce512f11734aec08696e6b17641fef8867c00c949fc/wrapt-2.1.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7dfa9f2cf65d027b951d05c662cc99ee3bd01f6e4691ed39848a7a5fffc902b2", size = 120563, upload-time = "2026-03-06T02:53:20.412Z" }, + { url = "https://files.pythonhosted.org/packages/ec/9f/b750b3692ed2ef4705cb305bd68858e73010492b80e43d2a4faa5573cbe7/wrapt-2.1.2-cp312-cp312-win32.whl", hash = "sha256:eba8155747eb2cae4a0b913d9ebd12a1db4d860fc4c829d7578c7b989bd3f2f0", size = 58198, upload-time = "2026-03-06T02:53:37.732Z" }, + { url = "https://files.pythonhosted.org/packages/8e/b2/feecfe29f28483d888d76a48f03c4c4d8afea944dbee2b0cd3380f9df032/wrapt-2.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:1c51c738d7d9faa0b3601708e7e2eda9bf779e1b601dce6c77411f2a1b324a63", size = 60441, upload-time = "2026-03-06T02:52:47.138Z" }, + { url = "https://files.pythonhosted.org/packages/44/e1/e328f605d6e208547ea9fd120804fcdec68536ac748987a68c47c606eea8/wrapt-2.1.2-cp312-cp312-win_arm64.whl", hash = "sha256:c8e46ae8e4032792eb2f677dbd0d557170a8e5524d22acc55199f43efedd39bf", size = 58836, upload-time = "2026-03-06T02:53:22.053Z" }, + { url = "https://files.pythonhosted.org/packages/4c/7a/d936840735c828b38d26a854e85d5338894cda544cb7a85a9d5b8b9c4df7/wrapt-2.1.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787fd6f4d67befa6fe2abdffcbd3de2d82dfc6fb8a6d850407c53332709d030b", size = 61259, upload-time = "2026-03-06T02:53:41.922Z" }, + { url = "https://files.pythonhosted.org/packages/5e/88/9a9b9a90ac8ca11c2fdb6a286cb3a1fc7dd774c00ed70929a6434f6bc634/wrapt-2.1.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4bdf26e03e6d0da3f0e9422fd36bcebf7bc0eeb55fdf9c727a09abc6b9fe472e", size = 61851, upload-time = "2026-03-06T02:52:48.672Z" }, + { url = "https://files.pythonhosted.org/packages/03/a9/5b7d6a16fd6533fed2756900fc8fc923f678179aea62ada6d65c92718c00/wrapt-2.1.2-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bbac24d879aa22998e87f6b3f481a5216311e7d53c7db87f189a7a0266dafffb", size = 121446, upload-time = "2026-03-06T02:54:14.013Z" }, + { url = "https://files.pythonhosted.org/packages/45/bb/34c443690c847835cfe9f892be78c533d4f32366ad2888972c094a897e39/wrapt-2.1.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:16997dfb9d67addc2e3f41b62a104341e80cac52f91110dece393923c0ebd5ca", size = 123056, upload-time = "2026-03-06T02:54:10.829Z" }, + { url = "https://files.pythonhosted.org/packages/93/b9/ff205f391cb708f67f41ea148545f2b53ff543a7ac293b30d178af4d2271/wrapt-2.1.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:162e4e2ba7542da9027821cb6e7c5e068d64f9a10b5f15512ea28e954893a267", size = 117359, upload-time = "2026-03-06T02:53:03.623Z" }, + { url = "https://files.pythonhosted.org/packages/1f/3d/1ea04d7747825119c3c9a5e0874a40b33594ada92e5649347c457d982805/wrapt-2.1.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f29c827a8d9936ac320746747a016c4bc66ef639f5cd0d32df24f5eacbf9c69f", size = 121479, upload-time = "2026-03-06T02:53:45.844Z" }, + { url = "https://files.pythonhosted.org/packages/78/cc/ee3a011920c7a023b25e8df26f306b2484a531ab84ca5c96260a73de76c0/wrapt-2.1.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:a9dd9813825f7ecb018c17fd147a01845eb330254dff86d3b5816f20f4d6aaf8", size = 116271, upload-time = "2026-03-06T02:54:46.356Z" }, + { url = "https://files.pythonhosted.org/packages/98/fd/e5ff7ded41b76d802cf1191288473e850d24ba2e39a6ec540f21ae3b57cb/wrapt-2.1.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6f8dbdd3719e534860d6a78526aafc220e0241f981367018c2875178cf83a413", size = 120573, upload-time = "2026-03-06T02:52:50.163Z" }, + { url = "https://files.pythonhosted.org/packages/47/c5/242cae3b5b080cd09bacef0591691ba1879739050cc7c801ff35c8886b66/wrapt-2.1.2-cp313-cp313-win32.whl", hash = "sha256:5c35b5d82b16a3bc6e0a04349b606a0582bc29f573786aebe98e0c159bc48db6", size = 58205, upload-time = "2026-03-06T02:53:47.494Z" }, + { url = "https://files.pythonhosted.org/packages/12/69/c358c61e7a50f290958809b3c61ebe8b3838ea3e070d7aac9814f95a0528/wrapt-2.1.2-cp313-cp313-win_amd64.whl", hash = "sha256:f8bc1c264d8d1cf5b3560a87bbdd31131573eb25f9f9447bb6252b8d4c44a3a1", size = 60452, upload-time = "2026-03-06T02:53:30.038Z" }, + { url = "https://files.pythonhosted.org/packages/8e/66/c8a6fcfe321295fd8c0ab1bd685b5a01462a9b3aa2f597254462fc2bc975/wrapt-2.1.2-cp313-cp313-win_arm64.whl", hash = "sha256:3beb22f674550d5634642c645aba4c72a2c66fb185ae1aebe1e955fae5a13baf", size = 58842, upload-time = "2026-03-06T02:52:52.114Z" }, + { url = "https://files.pythonhosted.org/packages/da/55/9c7052c349106e0b3f17ae8db4b23a691a963c334de7f9dbd60f8f74a831/wrapt-2.1.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0fc04bc8664a8bc4c8e00b37b5355cffca2535209fba1abb09ae2b7c76ddf82b", size = 63075, upload-time = "2026-03-06T02:53:19.108Z" }, + { url = "https://files.pythonhosted.org/packages/09/a8/ce7b4006f7218248dd71b7b2b732d0710845a0e49213b18faef64811ffef/wrapt-2.1.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a9b9d50c9af998875a1482a038eb05755dfd6fe303a313f6a940bb53a83c3f18", size = 63719, upload-time = "2026-03-06T02:54:33.452Z" }, + { url = "https://files.pythonhosted.org/packages/e4/e5/2ca472e80b9e2b7a17f106bb8f9df1db11e62101652ce210f66935c6af67/wrapt-2.1.2-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2d3ff4f0024dd224290c0eabf0240f1bfc1f26363431505fb1b0283d3b08f11d", size = 152643, upload-time = "2026-03-06T02:52:42.721Z" }, + { url = "https://files.pythonhosted.org/packages/36/42/30f0f2cefca9d9cbf6835f544d825064570203c3e70aa873d8ae12e23791/wrapt-2.1.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3278c471f4468ad544a691b31bb856374fbdefb7fee1a152153e64019379f015", size = 158805, upload-time = "2026-03-06T02:54:25.441Z" }, + { url = "https://files.pythonhosted.org/packages/bb/67/d08672f801f604889dcf58f1a0b424fe3808860ede9e03affc1876b295af/wrapt-2.1.2-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a8914c754d3134a3032601c6984db1c576e6abaf3fc68094bb8ab1379d75ff92", size = 145990, upload-time = "2026-03-06T02:53:57.456Z" }, + { url = "https://files.pythonhosted.org/packages/68/a7/fd371b02e73babec1de6ade596e8cd9691051058cfdadbfd62a5898f3295/wrapt-2.1.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:ff95d4264e55839be37bafe1536db2ab2de19da6b65f9244f01f332b5286cfbf", size = 155670, upload-time = "2026-03-06T02:54:55.309Z" }, + { url = "https://files.pythonhosted.org/packages/86/2d/9fe0095dfdb621009f40117dcebf41d7396c2c22dca6eac779f4c007b86c/wrapt-2.1.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:76405518ca4e1b76fbb1b9f686cff93aebae03920cc55ceeec48ff9f719c5f67", size = 144357, upload-time = "2026-03-06T02:54:24.092Z" }, + { url = "https://files.pythonhosted.org/packages/0e/b6/ec7b4a254abbe4cde9fa15c5d2cca4518f6b07d0f1b77d4ee9655e30280e/wrapt-2.1.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c0be8b5a74c5824e9359b53e7e58bef71a729bacc82e16587db1c4ebc91f7c5a", size = 150269, upload-time = "2026-03-06T02:53:31.268Z" }, + { url = "https://files.pythonhosted.org/packages/6e/6b/2fabe8ebf148f4ee3c782aae86a795cc68ffe7d432ef550f234025ce0cfa/wrapt-2.1.2-cp313-cp313t-win32.whl", hash = "sha256:f01277d9a5fc1862f26f7626da9cf443bebc0abd2f303f41c5e995b15887dabd", size = 59894, upload-time = "2026-03-06T02:54:15.391Z" }, + { url = "https://files.pythonhosted.org/packages/ca/fb/9ba66fc2dedc936de5f8073c0217b5d4484e966d87723415cc8262c5d9c2/wrapt-2.1.2-cp313-cp313t-win_amd64.whl", hash = "sha256:84ce8f1c2104d2f6daa912b1b5b039f331febfeee74f8042ad4e04992bd95c8f", size = 63197, upload-time = "2026-03-06T02:54:41.943Z" }, + { url = "https://files.pythonhosted.org/packages/c0/1c/012d7423c95d0e337117723eb8ecf73c622ce15a97847e84cf3f8f26cd7e/wrapt-2.1.2-cp313-cp313t-win_arm64.whl", hash = "sha256:a93cd767e37faeddbe07d8fc4212d5cba660af59bdb0f6372c93faaa13e6e679", size = 60363, upload-time = "2026-03-06T02:54:48.093Z" }, + { url = "https://files.pythonhosted.org/packages/39/25/e7ea0b417db02bb796182a5316398a75792cd9a22528783d868755e1f669/wrapt-2.1.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:1370e516598854e5b4366e09ce81e08bfe94d42b0fd569b88ec46cc56d9164a9", size = 61418, upload-time = "2026-03-06T02:53:55.706Z" }, + { url = "https://files.pythonhosted.org/packages/ec/0f/fa539e2f6a770249907757eaeb9a5ff4deb41c026f8466c1c6d799088a9b/wrapt-2.1.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6de1a3851c27e0bd6a04ca993ea6f80fc53e6c742ee1601f486c08e9f9b900a9", size = 61914, upload-time = "2026-03-06T02:52:53.37Z" }, + { url = "https://files.pythonhosted.org/packages/53/37/02af1867f5b1441aaeda9c82deed061b7cd1372572ddcd717f6df90b5e93/wrapt-2.1.2-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:de9f1a2bbc5ac7f6012ec24525bdd444765a2ff64b5985ac6e0692144838542e", size = 120417, upload-time = "2026-03-06T02:54:30.74Z" }, + { url = "https://files.pythonhosted.org/packages/c3/b7/0138a6238c8ba7476c77cf786a807f871672b37f37a422970342308276e7/wrapt-2.1.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:970d57ed83fa040d8b20c52fe74a6ae7e3775ae8cff5efd6a81e06b19078484c", size = 122797, upload-time = "2026-03-06T02:54:51.539Z" }, + { url = "https://files.pythonhosted.org/packages/e1/ad/819ae558036d6a15b7ed290d5b14e209ca795dd4da9c58e50c067d5927b0/wrapt-2.1.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3969c56e4563c375861c8df14fa55146e81ac11c8db49ea6fb7f2ba58bc1ff9a", size = 117350, upload-time = "2026-03-06T02:54:37.651Z" }, + { url = "https://files.pythonhosted.org/packages/8b/2d/afc18dc57a4600a6e594f77a9ae09db54f55ba455440a54886694a84c71b/wrapt-2.1.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:57d7c0c980abdc5f1d98b11a2aa3bb159790add80258c717fa49a99921456d90", size = 121223, upload-time = "2026-03-06T02:54:35.221Z" }, + { url = "https://files.pythonhosted.org/packages/b9/5b/5ec189b22205697bc56eb3b62aed87a1e0423e9c8285d0781c7a83170d15/wrapt-2.1.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:776867878e83130c7a04237010463372e877c1c994d449ca6aaafeab6aab2586", size = 116287, upload-time = "2026-03-06T02:54:19.654Z" }, + { url = "https://files.pythonhosted.org/packages/f7/2d/f84939a7c9b5e6cdd8a8d0f6a26cabf36a0f7e468b967720e8b0cd2bdf69/wrapt-2.1.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:fab036efe5464ec3291411fabb80a7a39e2dd80bae9bcbeeca5087fdfa891e19", size = 119593, upload-time = "2026-03-06T02:54:16.697Z" }, + { url = "https://files.pythonhosted.org/packages/0b/fe/ccd22a1263159c4ac811ab9374c061bcb4a702773f6e06e38de5f81a1bdc/wrapt-2.1.2-cp314-cp314-win32.whl", hash = "sha256:e6ed62c82ddf58d001096ae84ce7f833db97ae2263bff31c9b336ba8cfe3f508", size = 58631, upload-time = "2026-03-06T02:53:06.498Z" }, + { url = "https://files.pythonhosted.org/packages/65/0a/6bd83be7bff2e7efaac7b4ac9748da9d75a34634bbbbc8ad077d527146df/wrapt-2.1.2-cp314-cp314-win_amd64.whl", hash = "sha256:467e7c76315390331c67073073d00662015bb730c566820c9ca9b54e4d67fd04", size = 60875, upload-time = "2026-03-06T02:53:50.252Z" }, + { url = "https://files.pythonhosted.org/packages/6c/c0/0b3056397fe02ff80e5a5d72d627c11eb885d1ca78e71b1a5c1e8c7d45de/wrapt-2.1.2-cp314-cp314-win_arm64.whl", hash = "sha256:da1f00a557c66225d53b095a97eace0fc5349e3bfda28fa34ffae238978ee575", size = 59164, upload-time = "2026-03-06T02:53:59.128Z" }, + { url = "https://files.pythonhosted.org/packages/71/ed/5d89c798741993b2371396eb9d4634f009ff1ad8a6c78d366fe2883ea7a6/wrapt-2.1.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:62503ffbc2d3a69891cf29beeaccdb4d5e0a126e2b6a851688d4777e01428dbb", size = 63163, upload-time = "2026-03-06T02:52:54.873Z" }, + { url = "https://files.pythonhosted.org/packages/c6/8c/05d277d182bf36b0a13d6bd393ed1dec3468a25b59d01fba2dd70fe4d6ae/wrapt-2.1.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c7e6cd120ef837d5b6f860a6ea3745f8763805c418bb2f12eeb1fa6e25f22d22", size = 63723, upload-time = "2026-03-06T02:52:56.374Z" }, + { url = "https://files.pythonhosted.org/packages/f4/27/6c51ec1eff4413c57e72d6106bb8dec6f0c7cdba6503d78f0fa98767bcc9/wrapt-2.1.2-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3769a77df8e756d65fbc050333f423c01ae012b4f6731aaf70cf2bef61b34596", size = 152652, upload-time = "2026-03-06T02:53:23.79Z" }, + { url = "https://files.pythonhosted.org/packages/db/4c/d7dd662d6963fc7335bfe29d512b02b71cdfa23eeca7ab3ac74a67505deb/wrapt-2.1.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a76d61a2e851996150ba0f80582dd92a870643fa481f3b3846f229de88caf044", size = 158807, upload-time = "2026-03-06T02:53:35.742Z" }, + { url = "https://files.pythonhosted.org/packages/b4/4d/1e5eea1a78d539d346765727422976676615814029522c76b87a95f6bcdd/wrapt-2.1.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6f97edc9842cf215312b75fe737ee7c8adda75a89979f8e11558dfff6343cc4b", size = 146061, upload-time = "2026-03-06T02:52:57.574Z" }, + { url = "https://files.pythonhosted.org/packages/89/bc/62cabea7695cd12a288023251eeefdcb8465056ddaab6227cb78a2de005b/wrapt-2.1.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:4006c351de6d5007aa33a551f600404ba44228a89e833d2fadc5caa5de8edfbf", size = 155667, upload-time = "2026-03-06T02:53:39.422Z" }, + { url = "https://files.pythonhosted.org/packages/e9/99/6f2888cd68588f24df3a76572c69c2de28287acb9e1972bf0c83ce97dbc1/wrapt-2.1.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:a9372fc3639a878c8e7d87e1556fa209091b0a66e912c611e3f833e2c4202be2", size = 144392, upload-time = "2026-03-06T02:54:22.41Z" }, + { url = "https://files.pythonhosted.org/packages/40/51/1dfc783a6c57971614c48e361a82ca3b6da9055879952587bc99fe1a7171/wrapt-2.1.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3144b027ff30cbd2fca07c0a87e67011adb717eb5f5bd8496325c17e454257a3", size = 150296, upload-time = "2026-03-06T02:54:07.848Z" }, + { url = "https://files.pythonhosted.org/packages/6c/38/cbb8b933a0201076c1f64fc42883b0023002bdc14a4964219154e6ff3350/wrapt-2.1.2-cp314-cp314t-win32.whl", hash = "sha256:3b8d15e52e195813efe5db8cec156eebe339aaf84222f4f4f051a6c01f237ed7", size = 60539, upload-time = "2026-03-06T02:54:00.594Z" }, + { url = "https://files.pythonhosted.org/packages/82/dd/e5176e4b241c9f528402cebb238a36785a628179d7d8b71091154b3e4c9e/wrapt-2.1.2-cp314-cp314t-win_amd64.whl", hash = "sha256:08ffa54146a7559f5b8df4b289b46d963a8e74ed16ba3687f99896101a3990c5", size = 63969, upload-time = "2026-03-06T02:54:39Z" }, + { url = "https://files.pythonhosted.org/packages/5c/99/79f17046cf67e4a95b9987ea129632ba8bcec0bc81f3fb3d19bdb0bd60cd/wrapt-2.1.2-cp314-cp314t-win_arm64.whl", hash = "sha256:72aaa9d0d8e4ed0e2e98019cea47a21f823c9dd4b43c7b77bba6679ffcca6a00", size = 60554, upload-time = "2026-03-06T02:53:14.132Z" }, + { url = "https://files.pythonhosted.org/packages/1a/c7/8528ac2dfa2c1e6708f647df7ae144ead13f0a31146f43c7264b4942bf12/wrapt-2.1.2-py3-none-any.whl", hash = "sha256:b8fd6fa2b2c4e7621808f8c62e8317f4aae56e59721ad933bac5239d913cf0e8", size = 43993, upload-time = "2026-03-06T02:53:12.905Z" }, +] + [[package]] name = "xxhash" version = "3.6.0" diff --git a/echo/cookies.txt b/echo/cookies.txt new file mode 100644 index 00000000..c31d9899 --- /dev/null +++ b/echo/cookies.txt @@ -0,0 +1,4 @@ +# Netscape HTTP Cookie File +# https://curl.se/docs/http-cookies.html +# This file was generated by libcurl! Edit at your own risk. + diff --git a/echo/cypress/cypress.env.json b/echo/cypress/cypress.env.json index e2b5ffe7..3cb5943d 100644 --- a/echo/cypress/cypress.env.json +++ b/echo/cypress/cypress.env.json @@ -36,5 +36,13 @@ "email": "charugundla.vipul6009@gmail.com", "password": "test@1234" } + }, + "local": { + "dashboardUrl": "http://127.0.0.1:5173/", + "portalUrl": "http://127.0.0.1:5174/", + "auth": { + "email": "charugundla.vipul6009@gmail.com", + "password": "test@1234" + } } -} \ No newline at end of file +} diff --git a/echo/cypress/cypress/downloads/merged-c73ccb37-8d3b-42e0-a51e-3edf8e20469b-eaa71516-0fcf-49e5-b9a7-3d45f4b5c4a6.mp3 b/echo/cypress/cypress/downloads/merged-c73ccb37-8d3b-42e0-a51e-3edf8e20469b-eaa71516-0fcf-49e5-b9a7-3d45f4b5c4a6.mp3 deleted file mode 100644 index 0723154d..00000000 Binary files a/echo/cypress/cypress/downloads/merged-c73ccb37-8d3b-42e0-a51e-3edf8e20469b-eaa71516-0fcf-49e5-b9a7-3d45f4b5c4a6.mp3 and /dev/null differ diff --git a/echo/cypress/cypress/downloads/transcript-1771916490192 b/echo/cypress/cypress/downloads/transcript-1771916490192 deleted file mode 100644 index 462f87a0..00000000 --- a/echo/cypress/cypress/downloads/transcript-1771916490192 +++ /dev/null @@ -1 +0,0 @@ -Hey, everybody. My name is Chris Nash. It's a new year, which means it's time for a new podcast. Now, unlike all of your other favorite podcasts, this one will only take one minute of your time. Every time, all the time. Sometimes it'll be just me. Other times it'll be just you. Seriously, submit stuff, your opinions, videos. I want to know what you have to say. I want to share what you have to say. Other times, I'll be joined by excellent guests like Cameron Hart of the Tournamental Podcast. Hey, Nash, that one minute podcast idea. Don't do it. It's a terrible idea. Swell. Some episodes will be really funny. Other episodes will be really serious. But I guarantee that every episode will be the best minute of your day. Warning. Depending on your preferences, one minute podcast may be the worst minute of your day. \ No newline at end of file diff --git a/echo/cypress/cypress/screenshots/04-create-edit-delete-project.cy.js/Project Create, Edit, and Delete Flow -- should create a project, edit its name and portal settings, verify changes, and delete it (failed).png b/echo/cypress/cypress/screenshots/04-create-edit-delete-project.cy.js/Project Create, Edit, and Delete Flow -- should create a project, edit its name and portal settings, verify changes, and delete it (failed).png deleted file mode 100644 index d6c065b8..00000000 Binary files a/echo/cypress/cypress/screenshots/04-create-edit-delete-project.cy.js/Project Create, Edit, and Delete Flow -- should create a project, edit its name and portal settings, verify changes, and delete it (failed).png and /dev/null differ diff --git a/echo/cypress/cypress/screenshots/30-report-lifecycle.cy.js/Report Lifecycle Flow -- creates a project and generates a report draft (failed).png b/echo/cypress/cypress/screenshots/30-report-lifecycle.cy.js/Report Lifecycle Flow -- creates a project and generates a report draft (failed).png deleted file mode 100644 index 9f51dd2e..00000000 Binary files a/echo/cypress/cypress/screenshots/30-report-lifecycle.cy.js/Report Lifecycle Flow -- creates a project and generates a report draft (failed).png and /dev/null differ diff --git a/echo/cypress/e2e/suites/36-agentic-chat-local.cy.js b/echo/cypress/e2e/suites/36-agentic-chat-local.cy.js new file mode 100644 index 00000000..bf7e7a5d --- /dev/null +++ b/echo/cypress/e2e/suites/36-agentic-chat-local.cy.js @@ -0,0 +1,436 @@ +const projectId = "project-e2e"; +const chatId = "chat-e2e"; +const runId = "run-e2e"; +const directusBaseUrl = "http://localhost:8055"; +const transcriptConversationId = "96adf4c3-290e-4eb6-876e-987610996fd5"; +const transcriptChunkId = "chunk-e2e-1"; + +const project = { + default_conversation_title: "Conversation", + id: projectId, + is_conversation_allowed: true, + language: "en-US", + name: "Agentic E2E Project", + tags: [], +}; + +const chat = { + chat_mode: "agentic", + date_created: "2026-03-18T19:00:00.000Z", + date_updated: "2026-03-18T19:00:00.000Z", + id: chatId, + name: "Agentic QA Chat", + project_id: projectId, +}; + +const user = { + disable_create_project: false, + email: "agentic-e2e@dembrane.test", + first_name: "Agentic", + id: "user-e2e", + legal_basis: null, + privacy_policy_url: null, + tfa_secret: null, + whitelabel_logo: null, +}; + +const chatContext = { + auto_select_bool: false, + chat_mode: "agentic", + conversation_id_list: [], + conversations: [], + locked_conversation_id_list: [], + messages: [], +}; + +const extractToolQuery = (message) => { + if (message.includes("Putin")) { + return "Putin oligarch control loyalty sanctions wealth"; + } + if (message.includes("clear sky")) return "clear sky sunny day"; + if (message.includes("comes after six")) return "comes after six"; + if (message.includes("opposite of cold")) return "opposite of cold"; + return "project conversations"; +}; + +const buildToolStartPayload = (query) => ({ + data: { + input: { + conversation_id: transcriptConversationId, + keywords: query, + limit: 3, + }, + }, + name: "grepConvoSnippets", +}); + +const buildToolEndPayload = (query) => ({ + data: { + input: { + conversation_id: transcriptConversationId, + keywords: query, + limit: 3, + }, + output: { + kwargs: { + content: JSON.stringify({ + conversation_id: transcriptConversationId, + count: 1, + matches: [ + { + chunk_id: transcriptChunkId, + snippet: + "The discussion describes how wealth and political loyalty reinforce one another.", + }, + ], + query, + }), + }, + }, + }, + name: "grepConvoSnippets", +}); + +const nextTimestamp = (seq) => + new Date(Date.UTC(2026, 2, 18, 19, 0, seq)).toISOString(); + +describe("Agentic chat local smoke", () => { + it("keeps tool rows compact, merges tool lifecycle rows, shows live status, renders transcript chips, scrolls to the newest reply, and restores history after reload", () => { + let run = null; + const events = []; + let nextSeq = 0; + let pendingTurn = null; + let hydrateMode = false; + + const pushEvent = (eventType, payload) => { + nextSeq += 1; + const event = { + event_type: eventType, + id: nextSeq, + payload, + project_agentic_run_id: runId, + seq: nextSeq, + timestamp: nextTimestamp(nextSeq), + }; + events.push(event); + return event; + }; + + const buildReply = (message) => { + if (message.includes("Putin")) { + return `The transcript ties wealth to political loyalty [conversation_id:${transcriptConversationId};chunk_id:${transcriptChunkId}]`; + } + if (message.includes("clear sky")) return "blue"; + if (message.includes("comes after six")) return "seven"; + if (message.includes("opposite of cold")) return "hot"; + return "There are 0 conversations in this project."; + }; + + const beginTurn = (message) => { + const query = extractToolQuery(message); + const assistantReply = buildReply(message); + pushEvent("user.message", { content: message }); + pushEvent("on_tool_start", buildToolStartPayload(query)); + pendingTurn = { + assistantReply, + query, + }; + run = { + completed_at: null, + directus_user_id: user.id, + id: runId, + last_event_seq: nextSeq, + latest_error: null, + latest_error_code: null, + latest_output: null, + project_chat_id: chatId, + project_id: projectId, + started_at: nextTimestamp(1), + status: "running", + }; + return run; + }; + + const completeTurn = () => { + if (!pendingTurn) return []; + + const streamedEvents = [ + pushEvent("on_tool_end", buildToolEndPayload(pendingTurn.query)), + pushEvent("assistant.message", { content: pendingTurn.assistantReply }), + ]; + + run = { + ...run, + completed_at: nextTimestamp(nextSeq), + last_event_seq: nextSeq, + latest_output: pendingTurn.assistantReply, + status: "completed", + }; + pendingTurn = null; + return streamedEvents; + }; + + cy.intercept("POST", `${directusBaseUrl}/auth/refresh*`, { + body: { + data: { + access_token: "token-e2e", + expires: 3600, + refresh_token: "refresh-e2e", + }, + }, + statusCode: 200, + }); + + cy.intercept("GET", `${directusBaseUrl}/users/me*`, { + body: { data: user }, + statusCode: 200, + }); + + cy.intercept("GET", `${directusBaseUrl}/items/project/${projectId}*`, { + body: { data: project }, + statusCode: 200, + }); + + cy.intercept("GET", `${directusBaseUrl}/items/project_chat/${chatId}*`, { + body: { data: chat }, + statusCode: 200, + }); + + cy.intercept("GET", `${directusBaseUrl}/items/project_chat_message*`, { + body: { data: [] }, + statusCode: 200, + }); + + cy.intercept("GET", `${directusBaseUrl}/items/project_chat*`, (req) => { + if (Object.keys(req.query).some((key) => key.includes("aggregate"))) { + req.reply({ + body: { data: [{ count: "1" }] }, + statusCode: 200, + }); + return; + } + + req.reply({ + body: { data: [chat] }, + statusCode: 200, + }); + }); + + cy.intercept("GET", `${directusBaseUrl}/items/conversation*`, (req) => { + if (Object.keys(req.query).some((key) => key.includes("aggregate"))) { + req.reply({ + body: { data: [{ count: "0" }] }, + statusCode: 200, + }); + return; + } + + req.reply({ + body: { data: [] }, + statusCode: 200, + }); + }); + + cy.intercept("GET", `${directusBaseUrl}/items/announcement*`, { + body: { data: [] }, + statusCode: 200, + }); + + cy.intercept("GET", `${directusBaseUrl}/items/announcement_activity*`, { + body: { data: [] }, + statusCode: 200, + }); + + cy.intercept("GET", `**/api/chats/${chatId}/context`, { + body: chatContext, + statusCode: 200, + }); + + cy.intercept("POST", "**/api/agentic/runs", (req) => { + beginTurn(req.body.message); + req.reply({ + body: run, + statusCode: 200, + }); + }); + + cy.intercept("POST", `**/api/agentic/runs/${runId}/messages`, (req) => { + beginTurn(req.body.message); + req.reply({ + body: run, + statusCode: 200, + }); + }); + + cy.intercept("GET", `**/api/agentic/runs/${runId}`, (req) => { + req.reply({ + body: run ?? { + completed_at: null, + directus_user_id: user.id, + id: runId, + last_event_seq: 0, + latest_error: null, + latest_error_code: null, + latest_output: null, + project_chat_id: chatId, + project_id: projectId, + started_at: null, + status: "completed", + }, + delay: hydrateMode ? 250 : 0, + statusCode: 200, + }); + }); + + cy.intercept("GET", `**/api/agentic/runs/${runId}/events*`, (req) => { + const afterSeq = Number(req.query.after_seq ?? 0); + const filteredEvents = events.filter((event) => event.seq > afterSeq); + const pageSize = hydrateMode ? 3 : filteredEvents.length; + const page = filteredEvents.slice(0, pageSize); + const nextSeqValue = + page.length > 0 ? page[page.length - 1].seq : afterSeq; + + req.reply({ + body: { + done: + page.length === 0 || + page[page.length - 1].seq === events[events.length - 1]?.seq, + events: page, + next_seq: nextSeqValue, + run_id: runId, + status: run?.status ?? "completed", + }, + delay: hydrateMode ? 350 : 0, + statusCode: 200, + }); + }); + + cy.intercept("POST", `**/api/agentic/runs/${runId}/stream*`, (req) => { + const streamedEvents = completeTurn(); + const body = streamedEvents + .map((event) => `event: message\ndata: ${JSON.stringify(event)}\n\n`) + .join(""); + + req.reply({ + body, + delay: 400, + headers: { + "content-type": "text/event-stream", + }, + statusCode: 200, + }); + }); + + cy.viewport(1440, 600); + cy.visit(`/en-US/projects/${projectId}/chats/${chatId}`); + + cy.get('[data-testid="chat-interface"]').should("be.visible"); + cy.get('[data-testid="chat-title"]').should("contain.text", chat.name); + + cy.get('[data-testid="chat-input-textarea"]') + .should("be.visible") + .type( + 'Find the transcript excerpt about "Putin oligarch control loyalty sanctions wealth" and answer in one short sentence.', + ); + cy.get('[data-testid="chat-send-button"]').click(); + + cy.get('[data-testid="agentic-run-indicator"]') + .should("be.visible") + .and( + "contain.text", + 'Search transcript for "Putin oligarch control loyalty sanctions wealth"', + ); + cy.get('[data-testid^="agentic-tool-row-"]') + .should("have.length", 1) + .first() + .then(($row) => { + expect($row.outerHeight()).to.be.lessThan(96); + expect($row.text()).to.include( + 'Search transcript for "Putin oligarch control loyalty sanctions wealth"', + ); + expect($row.text()).not.to.include("Query:"); + expect($row.text()).not.to.include("Conversation:"); + }); + cy.contains("Raw data").should("not.exist"); + cy.get('[data-testid^="agentic-tool-raw-toggle-"]') + .first() + .click({ force: true }); + cy.get('[data-testid^="agentic-tool-raw-panel-"]') + .first() + .should("be.visible"); + cy.get('[data-testid="agentic-transcript-link"]', { timeout: 10000 }) + .should("be.visible") + .and("contain.text", "transcript excerpt") + .and("have.attr", "href") + .and("include", `#chunk-${transcriptChunkId}`); + cy.get('[data-testid="agentic-transcript-link"]') + .first() + .should("have.attr", "title", "Open transcript"); + cy.get('[data-testid="agentic-run-indicator"]').should("not.exist"); + cy.contains("The transcript ties wealth to political loyalty").should( + "exist", + ); + + cy.get('[data-testid="chat-input-textarea"]') + .clear() + .type( + "What color is a clear sky on a sunny day? Reply with one lowercase word only.", + ); + cy.get('[data-testid="chat-send-button"]').click(); + cy.contains(/\bblue\b/).should("be.visible"); + + cy.get('[data-testid="chat-input-textarea"]') + .clear() + .type("What comes after six? Reply with one lowercase word only."); + cy.get('[data-testid="chat-send-button"]').click(); + cy.contains(/\bseven\b/).should("be.visible"); + + cy.get('[data-testid="chat-input-textarea"]') + .clear() + .type( + "What is the opposite of cold? Reply with one lowercase word only.", + ); + cy.get('[data-testid="chat-send-button"]').click(); + cy.contains(/\bhot\b/) + .should("be.visible") + .then(($reply) => { + const rect = $reply[0].getBoundingClientRect(); + expect(rect.bottom).to.be.lessThan( + Cypress.config("viewportHeight") - 16, + ); + }); + + cy.get('[data-testid^="agentic-tool-row-"]') + .its("length") + .as("toolCountBefore"); + cy.then(() => { + hydrateMode = true; + }); + cy.reload(); + + cy.get('[data-testid="chat-interface"]', { timeout: 60000 }).should( + "be.visible", + ); + cy.get('[data-testid="agentic-chat-loading"]', { timeout: 60000 }).should( + "be.visible", + ); + cy.get('[data-testid="agentic-chat-loading"]', { timeout: 60000 }).should( + "not.exist", + ); + cy.get('[data-testid="agentic-transcript-link"]', { + timeout: 60000, + }).should("be.visible"); + cy.contains("The transcript ties wealth to political loyalty", { + timeout: 60000, + }).should("be.visible"); + cy.contains(/\bblue\b/, { timeout: 60000 }).should("be.visible"); + cy.contains(/\bseven\b/, { timeout: 60000 }).should("be.visible"); + cy.contains(/\bhot\b/, { timeout: 60000 }).should("be.visible"); + cy.get("@toolCountBefore").then((toolCountBefore) => { + cy.get('[data-testid^="agentic-tool-row-"]', { timeout: 60000 }).should( + "have.length", + toolCountBefore, + ); + }); + }); +}); diff --git a/echo/cypress/support/functions/report/index.js b/echo/cypress/support/functions/report/index.js index eabdc10e..094da3a6 100644 --- a/echo/cypress/support/functions/report/index.js +++ b/echo/cypress/support/functions/report/index.js @@ -43,15 +43,23 @@ export const generateReport = (langCode = 'en') => { // ============= Report Actions ============= /** - * Clicks the share button (mobile) + * Opens the report actions menu (three-dot menu) + */ +const openReportActionsMenu = () => { + cy.get('[data-testid="report-actions-menu"]').should('be.visible').click(); +}; + +/** + * Clicks the share button (in actions menu dropdown) */ export const shareReport = () => { cy.log('Sharing Report'); + openReportActionsMenu(); cy.get('[data-testid="report-share-button"]').should('be.visible').click(); }; /** - * Copies the report link + * Copies the report link (inline icon button, only when published) */ export const copyReportLink = () => { cy.log('Copying Report Link'); @@ -59,10 +67,11 @@ export const copyReportLink = () => { }; /** - * Prints the report + * Prints the report (in actions menu dropdown, only when published) */ export const printReport = () => { cy.log('Printing Report'); + openReportActionsMenu(); cy.get('[data-testid="report-print-button"]').should('be.visible').click(); }; diff --git a/echo/directus/sync/collections/folders.json b/echo/directus/sync/collections/folders.json index de17c519..2032803c 100644 --- a/echo/directus/sync/collections/folders.json +++ b/echo/directus/sync/collections/folders.json @@ -8,5 +8,10 @@ "name": "Public", "parent": null, "_syncId": "74232676-80e7-4f8c-8012-c0d59e6d0a24" + }, + { + "name": "avatars", + "parent": null, + "_syncId": "da1c3f3e-4398-4dda-950e-9123c0873fbb" } ] diff --git a/echo/directus/sync/collections/operations.json b/echo/directus/sync/collections/operations.json index df2d31c5..c169726e 100644 --- a/echo/directus/sync/collections/operations.json +++ b/echo/directus/sync/collections/operations.json @@ -79,7 +79,7 @@ "resolve": null, "reject": null, "flow": "17703446-fef0-49e9-bdc4-385db1311137", - "_syncId": "84c38ea6-5d15-429f-8c24-9485d54ba7be" + "_syncId": "615a54cd-a72e-41ad-9403-9577c80280d6" }, { "name": "Email Send Operation Failed Dutch", @@ -93,7 +93,7 @@ "resolve": null, "reject": null, "flow": "17703446-fef0-49e9-bdc4-385db1311137", - "_syncId": "615a54cd-a72e-41ad-9403-9577c80280d6" + "_syncId": "84c38ea6-5d15-429f-8c24-9485d54ba7be" }, { "name": "failed", @@ -107,7 +107,7 @@ "resolve": null, "reject": null, "flow": "17703446-fef0-49e9-bdc4-385db1311137", - "_syncId": "eb6f8253-647f-4fb1-9010-e93594ba065e" + "_syncId": "8d8d787a-dbc4-44f9-9ab4-28e3f3d5f31c" }, { "name": "failed", @@ -121,7 +121,7 @@ "resolve": null, "reject": null, "flow": "17703446-fef0-49e9-bdc4-385db1311137", - "_syncId": "8d8d787a-dbc4-44f9-9ab4-28e3f3d5f31c" + "_syncId": "eb6f8253-647f-4fb1-9010-e93594ba065e" }, { "name": "Filter Emails", @@ -132,10 +132,10 @@ "options": { "code": "module.exports = async function(data) {\n\n const submissions = data.get_all_participants;\n \n // Filter submissions to only include those where email_opt_in is true\n const filteredSubmissions = submissions.filter(sub => sub.email_opt_in === true);\n\n // Create an array with email, project_id and an email_opt_out token for each submission\n const result = filteredSubmissions.map(sub => ({\n project_name: data.project_data[0].name || '',\n\t\tdefault_conversation_title: data.project_data[0].default_conversation_title || '',\n\t\tconversation_name: sub.conversation_id.participant_name || '',\n email: sub.email,\n project_id: sub.project_id || '',\n token: sub.email_opt_out_token,\n language: data.check_report_language[0].language || 'empty',\n ADMIN_BASE_URL: \"{{ $env.ADMIN_BASE_URL }}\" || \"http://localhost:5173\",\n PARTICIPANT_BASE_URL: \"{{ $env.PARTICIPANT_BASE_URL }}\" || \"http://localhost:5174\", \n }));\n \n return result;\n};" }, - "resolve": "e101f00d-2fb8-4f40-9e0e-4d24da5bb1e9", + "resolve": "b8144cee-59f6-40d9-a849-dd0c639e4e31", "reject": null, "flow": "ec4e7ea5-72de-4365-b66f-d8f11b549495", - "_syncId": "efb3982e-5703-4c07-8982-a6e1b5218e4a" + "_syncId": "ca1ffbc5-cfce-4fb4-8f15-c128ea407d41" }, { "name": "Filter Emails", @@ -146,10 +146,10 @@ "options": { "code": "module.exports = async function(data) {\n\n const submissions = data.get_all_participants;\n \n // Filter submissions to only include those where email_opt_in is true\n const filteredSubmissions = submissions.filter(sub => sub.email_opt_in === true);\n\n // Create an array with email, project_id and an email_opt_out token for each submission\n const result = filteredSubmissions.map(sub => ({\n project_name: data.project_data[0].name || '',\n\t\tdefault_conversation_title: data.project_data[0].default_conversation_title || '',\n\t\tconversation_name: sub.conversation_id.participant_name || '',\n email: sub.email,\n project_id: sub.project_id || '',\n token: sub.email_opt_out_token,\n language: data.check_report_language[0].language || 'empty',\n ADMIN_BASE_URL: \"{{ $env.ADMIN_BASE_URL }}\" || \"http://localhost:5173\",\n PARTICIPANT_BASE_URL: \"{{ $env.PARTICIPANT_BASE_URL }}\" || \"http://localhost:5174\", \n }));\n \n return result;\n};" }, - "resolve": "b8144cee-59f6-40d9-a849-dd0c639e4e31", + "resolve": "e101f00d-2fb8-4f40-9e0e-4d24da5bb1e9", "reject": null, "flow": "ec4e7ea5-72de-4365-b66f-d8f11b549495", - "_syncId": "ca1ffbc5-cfce-4fb4-8f15-c128ea407d41" + "_syncId": "efb3982e-5703-4c07-8982-a6e1b5218e4a" }, { "name": "log environment vars", @@ -213,7 +213,7 @@ "resolve": null, "reject": null, "flow": "ec4e7ea5-72de-4365-b66f-d8f11b549495", - "_syncId": "e8274ad4-5844-42cd-8a6b-d40d08cf83d3" + "_syncId": "84852456-3f3a-4906-be94-8b750159883b" }, { "name": "Report Not Published", @@ -227,7 +227,7 @@ "resolve": null, "reject": null, "flow": "ec4e7ea5-72de-4365-b66f-d8f11b549495", - "_syncId": "84852456-3f3a-4906-be94-8b750159883b" + "_syncId": "e8274ad4-5844-42cd-8a6b-d40d08cf83d3" }, { "name": "Send Email Dutch", @@ -256,9 +256,9 @@ ] }, "resolve": null, - "reject": "615a54cd-a72e-41ad-9403-9577c80280d6", + "reject": "84c38ea6-5d15-429f-8c24-9485d54ba7be", "flow": "17703446-fef0-49e9-bdc4-385db1311137", - "_syncId": "ea78ec02-364d-4f18-80f8-ea5ac4c787ed" + "_syncId": "34fb6ee5-2813-484a-a1cc-f97de097509b" }, { "name": "Send Email Dutch", @@ -287,9 +287,9 @@ ] }, "resolve": null, - "reject": "84c38ea6-5d15-429f-8c24-9485d54ba7be", + "reject": "615a54cd-a72e-41ad-9403-9577c80280d6", "flow": "17703446-fef0-49e9-bdc4-385db1311137", - "_syncId": "34fb6ee5-2813-484a-a1cc-f97de097509b" + "_syncId": "ea78ec02-364d-4f18-80f8-ea5ac4c787ed" }, { "name": "Send Email English", @@ -318,9 +318,9 @@ ] }, "resolve": null, - "reject": "920bd181-b2a2-4f0d-94dc-3b1a08c3f4ef", + "reject": "2b24450b-6a2e-4452-aba1-9814d17fef42", "flow": "17703446-fef0-49e9-bdc4-385db1311137", - "_syncId": "3dbf2ea1-17f8-4bde-aa89-43278fe9a00f" + "_syncId": "9390ed2f-7dc6-4a6a-83da-2d87d478261d" }, { "name": "Send Email English", @@ -349,9 +349,9 @@ ] }, "resolve": null, - "reject": "2b24450b-6a2e-4452-aba1-9814d17fef42", + "reject": "920bd181-b2a2-4f0d-94dc-3b1a08c3f4ef", "flow": "17703446-fef0-49e9-bdc4-385db1311137", - "_syncId": "9390ed2f-7dc6-4a6a-83da-2d87d478261d" + "_syncId": "3dbf2ea1-17f8-4bde-aa89-43278fe9a00f" }, { "name": "Trigger Email Flow", diff --git a/echo/directus/sync/collections/policies.json b/echo/directus/sync/collections/policies.json index 5687fce3..1dff0924 100644 --- a/echo/directus/sync/collections/policies.json +++ b/echo/directus/sync/collections/policies.json @@ -11,6 +11,10 @@ { "role": "_sync_default_admin_role", "sort": 1 + }, + { + "role": null, + "sort": null } ], "_syncId": "_sync_default_admin_policy" diff --git a/echo/directus/sync/snapshot/collections/prompt_template.json b/echo/directus/sync/snapshot/collections/prompt_template.json new file mode 100644 index 00000000..d9eb5314 --- /dev/null +++ b/echo/directus/sync/snapshot/collections/prompt_template.json @@ -0,0 +1,28 @@ +{ + "collection": "prompt_template", + "meta": { + "accountability": "all", + "archive_app_filter": true, + "archive_field": null, + "archive_value": null, + "collapse": "open", + "collection": "prompt_template", + "color": null, + "display_template": null, + "group": null, + "hidden": false, + "icon": null, + "item_duplication_fields": null, + "note": null, + "preview_url": null, + "singleton": false, + "sort": null, + "sort_field": null, + "translations": null, + "unarchive_value": null, + "versioning": false + }, + "schema": { + "name": "prompt_template" + } +} diff --git a/echo/directus/sync/snapshot/collections/prompt_template_preference.json b/echo/directus/sync/snapshot/collections/prompt_template_preference.json new file mode 100644 index 00000000..e3034b06 --- /dev/null +++ b/echo/directus/sync/snapshot/collections/prompt_template_preference.json @@ -0,0 +1,28 @@ +{ + "collection": "prompt_template_preference", + "meta": { + "accountability": "all", + "archive_app_filter": true, + "archive_field": null, + "archive_value": null, + "collapse": "open", + "collection": "prompt_template_preference", + "color": null, + "display_template": null, + "group": null, + "hidden": false, + "icon": null, + "item_duplication_fields": null, + "note": null, + "preview_url": null, + "singleton": false, + "sort": null, + "sort_field": null, + "translations": null, + "unarchive_value": null, + "versioning": false + }, + "schema": { + "name": "prompt_template_preference" + } +} diff --git a/echo/directus/sync/snapshot/collections/prompt_template_rating.json b/echo/directus/sync/snapshot/collections/prompt_template_rating.json new file mode 100644 index 00000000..f70534d8 --- /dev/null +++ b/echo/directus/sync/snapshot/collections/prompt_template_rating.json @@ -0,0 +1,28 @@ +{ + "collection": "prompt_template_rating", + "meta": { + "accountability": "all", + "archive_app_filter": true, + "archive_field": null, + "archive_value": null, + "collapse": "open", + "collection": "prompt_template_rating", + "color": null, + "display_template": null, + "group": null, + "hidden": false, + "icon": null, + "item_duplication_fields": null, + "note": null, + "preview_url": null, + "singleton": false, + "sort": null, + "sort_field": null, + "translations": null, + "unarchive_value": null, + "versioning": false + }, + "schema": { + "name": "prompt_template_rating" + } +} diff --git a/echo/directus/sync/snapshot/fields/directus_users/hide_ai_suggestions.json b/echo/directus/sync/snapshot/fields/directus_users/hide_ai_suggestions.json new file mode 100644 index 00000000..d9732e7b --- /dev/null +++ b/echo/directus/sync/snapshot/fields/directus_users/hide_ai_suggestions.json @@ -0,0 +1,46 @@ +{ + "collection": "directus_users", + "field": "hide_ai_suggestions", + "type": "boolean", + "meta": { + "collection": "directus_users", + "conditions": null, + "display": null, + "display_options": null, + "field": "hide_ai_suggestions", + "group": null, + "hidden": false, + "interface": "boolean", + "note": null, + "options": null, + "readonly": false, + "required": false, + "searchable": true, + "sort": 8, + "special": [ + "cast-boolean" + ], + "translations": null, + "validation": null, + "validation_message": null, + "width": "full" + }, + "schema": { + "name": "hide_ai_suggestions", + "table": "directus_users", + "data_type": "boolean", + "default_value": false, + "max_length": null, + "numeric_precision": null, + "numeric_scale": null, + "is_nullable": true, + "is_unique": false, + "is_indexed": false, + "is_primary_key": false, + "is_generated": false, + "generation_expression": null, + "has_auto_increment": false, + "foreign_key_table": null, + "foreign_key_column": null + } +} diff --git a/echo/directus/sync/snapshot/fields/project/pin_order.json b/echo/directus/sync/snapshot/fields/project/pin_order.json new file mode 100644 index 00000000..7d6fbff3 --- /dev/null +++ b/echo/directus/sync/snapshot/fields/project/pin_order.json @@ -0,0 +1,44 @@ +{ + "collection": "project", + "field": "pin_order", + "type": "integer", + "meta": { + "collection": "project", + "conditions": null, + "display": null, + "display_options": null, + "field": "pin_order", + "group": null, + "hidden": false, + "interface": "input", + "note": null, + "options": null, + "readonly": false, + "required": false, + "searchable": true, + "sort": 36, + "special": null, + "translations": null, + "validation": null, + "validation_message": null, + "width": "full" + }, + "schema": { + "name": "pin_order", + "table": "project", + "data_type": "integer", + "default_value": null, + "max_length": null, + "numeric_precision": 32, + "numeric_scale": 0, + "is_nullable": true, + "is_unique": false, + "is_indexed": false, + "is_primary_key": false, + "is_generated": false, + "generation_expression": null, + "has_auto_increment": false, + "foreign_key_table": null, + "foreign_key_column": null + } +} diff --git a/echo/directus/sync/snapshot/fields/project_report/scheduled_at.json b/echo/directus/sync/snapshot/fields/project_report/scheduled_at.json new file mode 100644 index 00000000..c237433e --- /dev/null +++ b/echo/directus/sync/snapshot/fields/project_report/scheduled_at.json @@ -0,0 +1,46 @@ +{ + "collection": "project_report", + "field": "scheduled_at", + "type": "timestamp", + "meta": { + "collection": "project_report", + "conditions": null, + "display": null, + "display_options": null, + "field": "scheduled_at", + "group": null, + "hidden": false, + "interface": "datetime", + "note": null, + "options": { + "includeSeconds": true + }, + "readonly": false, + "required": false, + "searchable": true, + "sort": 14, + "special": null, + "translations": null, + "validation": null, + "validation_message": null, + "width": "full" + }, + "schema": { + "name": "scheduled_at", + "table": "project_report", + "data_type": "timestamp with time zone", + "default_value": null, + "max_length": null, + "numeric_precision": null, + "numeric_scale": null, + "is_nullable": true, + "is_unique": false, + "is_indexed": false, + "is_primary_key": false, + "is_generated": false, + "generation_expression": null, + "has_auto_increment": false, + "foreign_key_table": null, + "foreign_key_column": null + } +} diff --git a/echo/directus/sync/snapshot/fields/project_report/status.json b/echo/directus/sync/snapshot/fields/project_report/status.json index 595a1cfd..51096b21 100644 --- a/echo/directus/sync/snapshot/fields/project_report/status.json +++ b/echo/directus/sync/snapshot/fields/project_report/status.json @@ -53,6 +53,18 @@ "color": "var(--theme--primary)", "text": "$t:published", "value": "published" + }, + { + "text": "draft", + "value": "draft" + }, + { + "text": "cancelled", + "value": "cancelled" + }, + { + "text": "scheduled", + "value": "scheduled" } ] }, diff --git a/echo/directus/sync/snapshot/fields/project_report/user_instructions.json b/echo/directus/sync/snapshot/fields/project_report/user_instructions.json new file mode 100644 index 00000000..d377f6d2 --- /dev/null +++ b/echo/directus/sync/snapshot/fields/project_report/user_instructions.json @@ -0,0 +1,44 @@ +{ + "collection": "project_report", + "field": "user_instructions", + "type": "text", + "meta": { + "collection": "project_report", + "conditions": null, + "display": null, + "display_options": null, + "field": "user_instructions", + "group": null, + "hidden": false, + "interface": "input-multiline", + "note": null, + "options": null, + "readonly": false, + "required": false, + "searchable": true, + "sort": 13, + "special": null, + "translations": null, + "validation": null, + "validation_message": null, + "width": "full" + }, + "schema": { + "name": "user_instructions", + "table": "project_report", + "data_type": "text", + "default_value": null, + "max_length": null, + "numeric_precision": null, + "numeric_scale": null, + "is_nullable": true, + "is_unique": false, + "is_indexed": false, + "is_primary_key": false, + "is_generated": false, + "generation_expression": null, + "has_auto_increment": false, + "foreign_key_table": null, + "foreign_key_column": null + } +} diff --git a/echo/directus/sync/snapshot/fields/prompt_template/content.json b/echo/directus/sync/snapshot/fields/prompt_template/content.json new file mode 100644 index 00000000..8494cd8d --- /dev/null +++ b/echo/directus/sync/snapshot/fields/prompt_template/content.json @@ -0,0 +1,44 @@ +{ + "collection": "prompt_template", + "field": "content", + "type": "text", + "meta": { + "collection": "prompt_template", + "conditions": null, + "display": null, + "display_options": null, + "field": "content", + "group": null, + "hidden": false, + "interface": "input-multiline", + "note": null, + "options": null, + "readonly": false, + "required": true, + "searchable": true, + "sort": 6, + "special": null, + "translations": null, + "validation": null, + "validation_message": null, + "width": "full" + }, + "schema": { + "name": "content", + "table": "prompt_template", + "data_type": "text", + "default_value": null, + "max_length": null, + "numeric_precision": null, + "numeric_scale": null, + "is_nullable": true, + "is_unique": false, + "is_indexed": false, + "is_primary_key": false, + "is_generated": false, + "generation_expression": null, + "has_auto_increment": false, + "foreign_key_table": null, + "foreign_key_column": null + } +} diff --git a/echo/directus/sync/snapshot/fields/prompt_template/date_created.json b/echo/directus/sync/snapshot/fields/prompt_template/date_created.json new file mode 100644 index 00000000..51785417 --- /dev/null +++ b/echo/directus/sync/snapshot/fields/prompt_template/date_created.json @@ -0,0 +1,48 @@ +{ + "collection": "prompt_template", + "field": "date_created", + "type": "timestamp", + "meta": { + "collection": "prompt_template", + "conditions": null, + "display": "datetime", + "display_options": { + "relative": true + }, + "field": "date_created", + "group": null, + "hidden": true, + "interface": "datetime", + "note": null, + "options": null, + "readonly": true, + "required": false, + "searchable": true, + "sort": 3, + "special": [ + "date-created" + ], + "translations": null, + "validation": null, + "validation_message": null, + "width": "half" + }, + "schema": { + "name": "date_created", + "table": "prompt_template", + "data_type": "timestamp with time zone", + "default_value": null, + "max_length": null, + "numeric_precision": null, + "numeric_scale": null, + "is_nullable": true, + "is_unique": false, + "is_indexed": false, + "is_primary_key": false, + "is_generated": false, + "generation_expression": null, + "has_auto_increment": false, + "foreign_key_table": null, + "foreign_key_column": null + } +} diff --git a/echo/directus/sync/snapshot/fields/prompt_template/date_updated.json b/echo/directus/sync/snapshot/fields/prompt_template/date_updated.json new file mode 100644 index 00000000..937e5877 --- /dev/null +++ b/echo/directus/sync/snapshot/fields/prompt_template/date_updated.json @@ -0,0 +1,48 @@ +{ + "collection": "prompt_template", + "field": "date_updated", + "type": "timestamp", + "meta": { + "collection": "prompt_template", + "conditions": null, + "display": "datetime", + "display_options": { + "relative": true + }, + "field": "date_updated", + "group": null, + "hidden": true, + "interface": "datetime", + "note": null, + "options": null, + "readonly": true, + "required": false, + "searchable": true, + "sort": 4, + "special": [ + "date-updated" + ], + "translations": null, + "validation": null, + "validation_message": null, + "width": "half" + }, + "schema": { + "name": "date_updated", + "table": "prompt_template", + "data_type": "timestamp with time zone", + "default_value": null, + "max_length": null, + "numeric_precision": null, + "numeric_scale": null, + "is_nullable": true, + "is_unique": false, + "is_indexed": false, + "is_primary_key": false, + "is_generated": false, + "generation_expression": null, + "has_auto_increment": false, + "foreign_key_table": null, + "foreign_key_column": null + } +} diff --git a/echo/directus/sync/snapshot/fields/prompt_template/description.json b/echo/directus/sync/snapshot/fields/prompt_template/description.json new file mode 100644 index 00000000..cf239761 --- /dev/null +++ b/echo/directus/sync/snapshot/fields/prompt_template/description.json @@ -0,0 +1,44 @@ +{ + "collection": "prompt_template", + "field": "description", + "type": "text", + "meta": { + "collection": "prompt_template", + "conditions": null, + "display": null, + "display_options": null, + "field": "description", + "group": null, + "hidden": false, + "interface": "input-multiline", + "note": null, + "options": null, + "readonly": false, + "required": false, + "searchable": true, + "sort": 10, + "special": null, + "translations": null, + "validation": null, + "validation_message": null, + "width": "full" + }, + "schema": { + "name": "description", + "table": "prompt_template", + "data_type": "text", + "default_value": null, + "max_length": null, + "numeric_precision": null, + "numeric_scale": null, + "is_nullable": true, + "is_unique": false, + "is_indexed": false, + "is_primary_key": false, + "is_generated": false, + "generation_expression": null, + "has_auto_increment": false, + "foreign_key_table": null, + "foreign_key_column": null + } +} diff --git a/echo/directus/sync/snapshot/fields/prompt_template/icon.json b/echo/directus/sync/snapshot/fields/prompt_template/icon.json new file mode 100644 index 00000000..ed766fa0 --- /dev/null +++ b/echo/directus/sync/snapshot/fields/prompt_template/icon.json @@ -0,0 +1,44 @@ +{ + "collection": "prompt_template", + "field": "icon", + "type": "string", + "meta": { + "collection": "prompt_template", + "conditions": null, + "display": null, + "display_options": null, + "field": "icon", + "group": null, + "hidden": false, + "interface": "input", + "note": null, + "options": null, + "readonly": false, + "required": false, + "searchable": true, + "sort": 7, + "special": null, + "translations": null, + "validation": null, + "validation_message": null, + "width": "full" + }, + "schema": { + "name": "icon", + "table": "prompt_template", + "data_type": "character varying", + "default_value": null, + "max_length": 50, + "numeric_precision": null, + "numeric_scale": null, + "is_nullable": true, + "is_unique": false, + "is_indexed": false, + "is_primary_key": false, + "is_generated": false, + "generation_expression": null, + "has_auto_increment": false, + "foreign_key_table": null, + "foreign_key_column": null + } +} diff --git a/echo/directus/sync/snapshot/fields/prompt_template/id.json b/echo/directus/sync/snapshot/fields/prompt_template/id.json new file mode 100644 index 00000000..453fb88e --- /dev/null +++ b/echo/directus/sync/snapshot/fields/prompt_template/id.json @@ -0,0 +1,46 @@ +{ + "collection": "prompt_template", + "field": "id", + "type": "uuid", + "meta": { + "collection": "prompt_template", + "conditions": null, + "display": null, + "display_options": null, + "field": "id", + "group": null, + "hidden": true, + "interface": "input", + "note": null, + "options": null, + "readonly": true, + "required": false, + "searchable": true, + "sort": 1, + "special": [ + "uuid" + ], + "translations": null, + "validation": null, + "validation_message": null, + "width": "full" + }, + "schema": { + "name": "id", + "table": "prompt_template", + "data_type": "uuid", + "default_value": null, + "max_length": null, + "numeric_precision": null, + "numeric_scale": null, + "is_nullable": false, + "is_unique": true, + "is_indexed": false, + "is_primary_key": true, + "is_generated": false, + "generation_expression": null, + "has_auto_increment": false, + "foreign_key_table": null, + "foreign_key_column": null + } +} diff --git a/echo/directus/sync/snapshot/fields/prompt_template/is_anonymous.json b/echo/directus/sync/snapshot/fields/prompt_template/is_anonymous.json new file mode 100644 index 00000000..e07a694f --- /dev/null +++ b/echo/directus/sync/snapshot/fields/prompt_template/is_anonymous.json @@ -0,0 +1,46 @@ +{ + "collection": "prompt_template", + "field": "is_anonymous", + "type": "boolean", + "meta": { + "collection": "prompt_template", + "conditions": null, + "display": null, + "display_options": null, + "field": "is_anonymous", + "group": null, + "hidden": false, + "interface": "boolean", + "note": null, + "options": null, + "readonly": false, + "required": false, + "searchable": true, + "sort": 13, + "special": [ + "cast-boolean" + ], + "translations": null, + "validation": null, + "validation_message": null, + "width": "full" + }, + "schema": { + "name": "is_anonymous", + "table": "prompt_template", + "data_type": "boolean", + "default_value": null, + "max_length": null, + "numeric_precision": null, + "numeric_scale": null, + "is_nullable": true, + "is_unique": false, + "is_indexed": false, + "is_primary_key": false, + "is_generated": false, + "generation_expression": null, + "has_auto_increment": false, + "foreign_key_table": null, + "foreign_key_column": null + } +} diff --git a/echo/directus/sync/snapshot/fields/prompt_template/is_public.json b/echo/directus/sync/snapshot/fields/prompt_template/is_public.json new file mode 100644 index 00000000..8c77842e --- /dev/null +++ b/echo/directus/sync/snapshot/fields/prompt_template/is_public.json @@ -0,0 +1,46 @@ +{ + "collection": "prompt_template", + "field": "is_public", + "type": "boolean", + "meta": { + "collection": "prompt_template", + "conditions": null, + "display": null, + "display_options": null, + "field": "is_public", + "group": null, + "hidden": false, + "interface": "boolean", + "note": null, + "options": null, + "readonly": false, + "required": false, + "searchable": true, + "sort": 9, + "special": [ + "cast-boolean" + ], + "translations": null, + "validation": null, + "validation_message": null, + "width": "full" + }, + "schema": { + "name": "is_public", + "table": "prompt_template", + "data_type": "boolean", + "default_value": false, + "max_length": null, + "numeric_precision": null, + "numeric_scale": null, + "is_nullable": true, + "is_unique": false, + "is_indexed": false, + "is_primary_key": false, + "is_generated": false, + "generation_expression": null, + "has_auto_increment": false, + "foreign_key_table": null, + "foreign_key_column": null + } +} diff --git a/echo/directus/sync/snapshot/fields/prompt_template/language.json b/echo/directus/sync/snapshot/fields/prompt_template/language.json new file mode 100644 index 00000000..39ee0464 --- /dev/null +++ b/echo/directus/sync/snapshot/fields/prompt_template/language.json @@ -0,0 +1,44 @@ +{ + "collection": "prompt_template", + "field": "language", + "type": "string", + "meta": { + "collection": "prompt_template", + "conditions": null, + "display": null, + "display_options": null, + "field": "language", + "group": null, + "hidden": false, + "interface": "input", + "note": null, + "options": null, + "readonly": false, + "required": false, + "searchable": true, + "sort": 12, + "special": null, + "translations": null, + "validation": null, + "validation_message": null, + "width": "full" + }, + "schema": { + "name": "language", + "table": "prompt_template", + "data_type": "character varying", + "default_value": null, + "max_length": 255, + "numeric_precision": null, + "numeric_scale": null, + "is_nullable": true, + "is_unique": false, + "is_indexed": false, + "is_primary_key": false, + "is_generated": false, + "generation_expression": null, + "has_auto_increment": false, + "foreign_key_table": null, + "foreign_key_column": null + } +} diff --git a/echo/directus/sync/snapshot/fields/prompt_template/sort.json b/echo/directus/sync/snapshot/fields/prompt_template/sort.json new file mode 100644 index 00000000..619f9bc8 --- /dev/null +++ b/echo/directus/sync/snapshot/fields/prompt_template/sort.json @@ -0,0 +1,44 @@ +{ + "collection": "prompt_template", + "field": "sort", + "type": "integer", + "meta": { + "collection": "prompt_template", + "conditions": null, + "display": null, + "display_options": null, + "field": "sort", + "group": null, + "hidden": false, + "interface": "input", + "note": null, + "options": null, + "readonly": false, + "required": false, + "searchable": true, + "sort": 8, + "special": null, + "translations": null, + "validation": null, + "validation_message": null, + "width": "full" + }, + "schema": { + "name": "sort", + "table": "prompt_template", + "data_type": "integer", + "default_value": null, + "max_length": null, + "numeric_precision": 32, + "numeric_scale": 0, + "is_nullable": true, + "is_unique": false, + "is_indexed": false, + "is_primary_key": false, + "is_generated": false, + "generation_expression": null, + "has_auto_increment": false, + "foreign_key_table": null, + "foreign_key_column": null + } +} diff --git a/echo/directus/sync/snapshot/fields/prompt_template/tags.json b/echo/directus/sync/snapshot/fields/prompt_template/tags.json new file mode 100644 index 00000000..2a2d5061 --- /dev/null +++ b/echo/directus/sync/snapshot/fields/prompt_template/tags.json @@ -0,0 +1,44 @@ +{ + "collection": "prompt_template", + "field": "tags", + "type": "text", + "meta": { + "collection": "prompt_template", + "conditions": null, + "display": null, + "display_options": null, + "field": "tags", + "group": null, + "hidden": false, + "interface": "input-multiline", + "note": null, + "options": null, + "readonly": false, + "required": false, + "searchable": true, + "sort": 11, + "special": null, + "translations": null, + "validation": null, + "validation_message": null, + "width": "full" + }, + "schema": { + "name": "tags", + "table": "prompt_template", + "data_type": "text", + "default_value": null, + "max_length": null, + "numeric_precision": null, + "numeric_scale": null, + "is_nullable": true, + "is_unique": false, + "is_indexed": false, + "is_primary_key": false, + "is_generated": false, + "generation_expression": null, + "has_auto_increment": false, + "foreign_key_table": null, + "foreign_key_column": null + } +} diff --git a/echo/directus/sync/snapshot/fields/prompt_template/title.json b/echo/directus/sync/snapshot/fields/prompt_template/title.json new file mode 100644 index 00000000..6d2017dd --- /dev/null +++ b/echo/directus/sync/snapshot/fields/prompt_template/title.json @@ -0,0 +1,44 @@ +{ + "collection": "prompt_template", + "field": "title", + "type": "string", + "meta": { + "collection": "prompt_template", + "conditions": null, + "display": null, + "display_options": null, + "field": "title", + "group": null, + "hidden": false, + "interface": "input", + "note": null, + "options": null, + "readonly": false, + "required": true, + "searchable": true, + "sort": 5, + "special": null, + "translations": null, + "validation": null, + "validation_message": null, + "width": "full" + }, + "schema": { + "name": "title", + "table": "prompt_template", + "data_type": "character varying", + "default_value": null, + "max_length": 200, + "numeric_precision": null, + "numeric_scale": null, + "is_nullable": false, + "is_unique": false, + "is_indexed": false, + "is_primary_key": false, + "is_generated": false, + "generation_expression": null, + "has_auto_increment": false, + "foreign_key_table": null, + "foreign_key_column": null + } +} diff --git a/echo/directus/sync/snapshot/fields/prompt_template/user_created.json b/echo/directus/sync/snapshot/fields/prompt_template/user_created.json new file mode 100644 index 00000000..b3e68dfa --- /dev/null +++ b/echo/directus/sync/snapshot/fields/prompt_template/user_created.json @@ -0,0 +1,48 @@ +{ + "collection": "prompt_template", + "field": "user_created", + "type": "uuid", + "meta": { + "collection": "prompt_template", + "conditions": null, + "display": "user", + "display_options": null, + "field": "user_created", + "group": null, + "hidden": true, + "interface": "select-dropdown-m2o", + "note": null, + "options": { + "template": "{{avatar}} {{first_name}} {{last_name}}" + }, + "readonly": true, + "required": false, + "searchable": true, + "sort": 2, + "special": [ + "user-created" + ], + "translations": null, + "validation": null, + "validation_message": null, + "width": "half" + }, + "schema": { + "name": "user_created", + "table": "prompt_template", + "data_type": "uuid", + "default_value": null, + "max_length": null, + "numeric_precision": null, + "numeric_scale": null, + "is_nullable": true, + "is_unique": false, + "is_indexed": false, + "is_primary_key": false, + "is_generated": false, + "generation_expression": null, + "has_auto_increment": false, + "foreign_key_table": "directus_users", + "foreign_key_column": "id" + } +} diff --git a/echo/directus/sync/snapshot/fields/prompt_template_preference/date_created.json b/echo/directus/sync/snapshot/fields/prompt_template_preference/date_created.json new file mode 100644 index 00000000..cbb38b73 --- /dev/null +++ b/echo/directus/sync/snapshot/fields/prompt_template_preference/date_created.json @@ -0,0 +1,48 @@ +{ + "collection": "prompt_template_preference", + "field": "date_created", + "type": "timestamp", + "meta": { + "collection": "prompt_template_preference", + "conditions": null, + "display": "datetime", + "display_options": { + "relative": true + }, + "field": "date_created", + "group": null, + "hidden": true, + "interface": "datetime", + "note": null, + "options": null, + "readonly": true, + "required": false, + "searchable": true, + "sort": 3, + "special": [ + "date-created" + ], + "translations": null, + "validation": null, + "validation_message": null, + "width": "half" + }, + "schema": { + "name": "date_created", + "table": "prompt_template_preference", + "data_type": "timestamp with time zone", + "default_value": null, + "max_length": null, + "numeric_precision": null, + "numeric_scale": null, + "is_nullable": true, + "is_unique": false, + "is_indexed": false, + "is_primary_key": false, + "is_generated": false, + "generation_expression": null, + "has_auto_increment": false, + "foreign_key_table": null, + "foreign_key_column": null + } +} diff --git a/echo/directus/sync/snapshot/fields/prompt_template_preference/id.json b/echo/directus/sync/snapshot/fields/prompt_template_preference/id.json new file mode 100644 index 00000000..dd78fcc3 --- /dev/null +++ b/echo/directus/sync/snapshot/fields/prompt_template_preference/id.json @@ -0,0 +1,46 @@ +{ + "collection": "prompt_template_preference", + "field": "id", + "type": "uuid", + "meta": { + "collection": "prompt_template_preference", + "conditions": null, + "display": null, + "display_options": null, + "field": "id", + "group": null, + "hidden": true, + "interface": "input", + "note": null, + "options": null, + "readonly": true, + "required": false, + "searchable": true, + "sort": 1, + "special": [ + "uuid" + ], + "translations": null, + "validation": null, + "validation_message": null, + "width": "full" + }, + "schema": { + "name": "id", + "table": "prompt_template_preference", + "data_type": "uuid", + "default_value": null, + "max_length": null, + "numeric_precision": null, + "numeric_scale": null, + "is_nullable": false, + "is_unique": true, + "is_indexed": false, + "is_primary_key": true, + "is_generated": false, + "generation_expression": null, + "has_auto_increment": false, + "foreign_key_table": null, + "foreign_key_column": null + } +} diff --git a/echo/directus/sync/snapshot/fields/prompt_template_preference/prompt_template_id.json b/echo/directus/sync/snapshot/fields/prompt_template_preference/prompt_template_id.json new file mode 100644 index 00000000..461d1c05 --- /dev/null +++ b/echo/directus/sync/snapshot/fields/prompt_template_preference/prompt_template_id.json @@ -0,0 +1,48 @@ +{ + "collection": "prompt_template_preference", + "field": "prompt_template_id", + "type": "uuid", + "meta": { + "collection": "prompt_template_preference", + "conditions": null, + "display": null, + "display_options": null, + "field": "prompt_template_id", + "group": null, + "hidden": false, + "interface": "select-dropdown-m2o", + "note": null, + "options": { + "template": "{{title}}" + }, + "readonly": false, + "required": false, + "searchable": true, + "sort": 6, + "special": [ + "m2o" + ], + "translations": null, + "validation": null, + "validation_message": null, + "width": "full" + }, + "schema": { + "name": "prompt_template_id", + "table": "prompt_template_preference", + "data_type": "uuid", + "default_value": null, + "max_length": null, + "numeric_precision": null, + "numeric_scale": null, + "is_nullable": true, + "is_unique": false, + "is_indexed": false, + "is_primary_key": false, + "is_generated": false, + "generation_expression": null, + "has_auto_increment": false, + "foreign_key_table": "prompt_template", + "foreign_key_column": "id" + } +} diff --git a/echo/directus/sync/snapshot/fields/prompt_template_preference/sort.json b/echo/directus/sync/snapshot/fields/prompt_template_preference/sort.json new file mode 100644 index 00000000..25ebccbb --- /dev/null +++ b/echo/directus/sync/snapshot/fields/prompt_template_preference/sort.json @@ -0,0 +1,44 @@ +{ + "collection": "prompt_template_preference", + "field": "sort", + "type": "integer", + "meta": { + "collection": "prompt_template_preference", + "conditions": null, + "display": null, + "display_options": null, + "field": "sort", + "group": null, + "hidden": false, + "interface": "input", + "note": null, + "options": null, + "readonly": false, + "required": false, + "searchable": true, + "sort": 7, + "special": null, + "translations": null, + "validation": null, + "validation_message": null, + "width": "full" + }, + "schema": { + "name": "sort", + "table": "prompt_template_preference", + "data_type": "integer", + "default_value": null, + "max_length": null, + "numeric_precision": 32, + "numeric_scale": 0, + "is_nullable": true, + "is_unique": false, + "is_indexed": false, + "is_primary_key": false, + "is_generated": false, + "generation_expression": null, + "has_auto_increment": false, + "foreign_key_table": null, + "foreign_key_column": null + } +} diff --git a/echo/directus/sync/snapshot/fields/prompt_template_preference/static_template_id.json b/echo/directus/sync/snapshot/fields/prompt_template_preference/static_template_id.json new file mode 100644 index 00000000..37a971b8 --- /dev/null +++ b/echo/directus/sync/snapshot/fields/prompt_template_preference/static_template_id.json @@ -0,0 +1,44 @@ +{ + "collection": "prompt_template_preference", + "field": "static_template_id", + "type": "string", + "meta": { + "collection": "prompt_template_preference", + "conditions": null, + "display": null, + "display_options": null, + "field": "static_template_id", + "group": null, + "hidden": false, + "interface": "input", + "note": null, + "options": null, + "readonly": false, + "required": false, + "searchable": true, + "sort": 5, + "special": null, + "translations": null, + "validation": null, + "validation_message": null, + "width": "full" + }, + "schema": { + "name": "static_template_id", + "table": "prompt_template_preference", + "data_type": "character varying", + "default_value": null, + "max_length": 100, + "numeric_precision": null, + "numeric_scale": null, + "is_nullable": true, + "is_unique": false, + "is_indexed": false, + "is_primary_key": false, + "is_generated": false, + "generation_expression": null, + "has_auto_increment": false, + "foreign_key_table": null, + "foreign_key_column": null + } +} diff --git a/echo/directus/sync/snapshot/fields/prompt_template_preference/template_type.json b/echo/directus/sync/snapshot/fields/prompt_template_preference/template_type.json new file mode 100644 index 00000000..fae89fca --- /dev/null +++ b/echo/directus/sync/snapshot/fields/prompt_template_preference/template_type.json @@ -0,0 +1,44 @@ +{ + "collection": "prompt_template_preference", + "field": "template_type", + "type": "string", + "meta": { + "collection": "prompt_template_preference", + "conditions": null, + "display": null, + "display_options": null, + "field": "template_type", + "group": null, + "hidden": false, + "interface": "input", + "note": null, + "options": null, + "readonly": false, + "required": true, + "searchable": true, + "sort": 4, + "special": null, + "translations": null, + "validation": null, + "validation_message": null, + "width": "full" + }, + "schema": { + "name": "template_type", + "table": "prompt_template_preference", + "data_type": "character varying", + "default_value": null, + "max_length": 100, + "numeric_precision": null, + "numeric_scale": null, + "is_nullable": false, + "is_unique": false, + "is_indexed": false, + "is_primary_key": false, + "is_generated": false, + "generation_expression": null, + "has_auto_increment": false, + "foreign_key_table": null, + "foreign_key_column": null + } +} diff --git a/echo/directus/sync/snapshot/fields/prompt_template_preference/user_created.json b/echo/directus/sync/snapshot/fields/prompt_template_preference/user_created.json new file mode 100644 index 00000000..4df92e93 --- /dev/null +++ b/echo/directus/sync/snapshot/fields/prompt_template_preference/user_created.json @@ -0,0 +1,48 @@ +{ + "collection": "prompt_template_preference", + "field": "user_created", + "type": "uuid", + "meta": { + "collection": "prompt_template_preference", + "conditions": null, + "display": "user", + "display_options": null, + "field": "user_created", + "group": null, + "hidden": true, + "interface": "select-dropdown-m2o", + "note": null, + "options": { + "template": "{{avatar}} {{first_name}} {{last_name}}" + }, + "readonly": true, + "required": false, + "searchable": true, + "sort": 2, + "special": [ + "user-created" + ], + "translations": null, + "validation": null, + "validation_message": null, + "width": "half" + }, + "schema": { + "name": "user_created", + "table": "prompt_template_preference", + "data_type": "uuid", + "default_value": null, + "max_length": null, + "numeric_precision": null, + "numeric_scale": null, + "is_nullable": true, + "is_unique": false, + "is_indexed": false, + "is_primary_key": false, + "is_generated": false, + "generation_expression": null, + "has_auto_increment": false, + "foreign_key_table": "directus_users", + "foreign_key_column": "id" + } +} diff --git a/echo/directus/sync/snapshot/fields/prompt_template_rating/chat_message_id.json b/echo/directus/sync/snapshot/fields/prompt_template_rating/chat_message_id.json new file mode 100644 index 00000000..3db86d4c --- /dev/null +++ b/echo/directus/sync/snapshot/fields/prompt_template_rating/chat_message_id.json @@ -0,0 +1,48 @@ +{ + "collection": "prompt_template_rating", + "field": "chat_message_id", + "type": "uuid", + "meta": { + "collection": "prompt_template_rating", + "conditions": null, + "display": null, + "display_options": null, + "field": "chat_message_id", + "group": null, + "hidden": false, + "interface": "select-dropdown-m2o", + "note": null, + "options": { + "enableLink": true + }, + "readonly": false, + "required": false, + "searchable": true, + "sort": 8, + "special": [ + "m2o" + ], + "translations": null, + "validation": null, + "validation_message": null, + "width": "full" + }, + "schema": { + "name": "chat_message_id", + "table": "prompt_template_rating", + "data_type": "uuid", + "default_value": null, + "max_length": null, + "numeric_precision": null, + "numeric_scale": null, + "is_nullable": true, + "is_unique": false, + "is_indexed": false, + "is_primary_key": false, + "is_generated": false, + "generation_expression": null, + "has_auto_increment": false, + "foreign_key_table": "project_chat_message", + "foreign_key_column": "id" + } +} diff --git a/echo/directus/sync/snapshot/fields/prompt_template_rating/date_created.json b/echo/directus/sync/snapshot/fields/prompt_template_rating/date_created.json new file mode 100644 index 00000000..66497b80 --- /dev/null +++ b/echo/directus/sync/snapshot/fields/prompt_template_rating/date_created.json @@ -0,0 +1,48 @@ +{ + "collection": "prompt_template_rating", + "field": "date_created", + "type": "timestamp", + "meta": { + "collection": "prompt_template_rating", + "conditions": null, + "display": "datetime", + "display_options": { + "relative": true + }, + "field": "date_created", + "group": null, + "hidden": true, + "interface": "datetime", + "note": null, + "options": null, + "readonly": true, + "required": false, + "searchable": true, + "sort": 3, + "special": [ + "date-created" + ], + "translations": null, + "validation": null, + "validation_message": null, + "width": "half" + }, + "schema": { + "name": "date_created", + "table": "prompt_template_rating", + "data_type": "timestamp with time zone", + "default_value": null, + "max_length": null, + "numeric_precision": null, + "numeric_scale": null, + "is_nullable": true, + "is_unique": false, + "is_indexed": false, + "is_primary_key": false, + "is_generated": false, + "generation_expression": null, + "has_auto_increment": false, + "foreign_key_table": null, + "foreign_key_column": null + } +} diff --git a/echo/directus/sync/snapshot/fields/prompt_template_rating/date_updated.json b/echo/directus/sync/snapshot/fields/prompt_template_rating/date_updated.json new file mode 100644 index 00000000..0cfe9684 --- /dev/null +++ b/echo/directus/sync/snapshot/fields/prompt_template_rating/date_updated.json @@ -0,0 +1,48 @@ +{ + "collection": "prompt_template_rating", + "field": "date_updated", + "type": "timestamp", + "meta": { + "collection": "prompt_template_rating", + "conditions": null, + "display": "datetime", + "display_options": { + "relative": true + }, + "field": "date_updated", + "group": null, + "hidden": true, + "interface": "datetime", + "note": null, + "options": null, + "readonly": true, + "required": false, + "searchable": true, + "sort": 5, + "special": [ + "date-updated" + ], + "translations": null, + "validation": null, + "validation_message": null, + "width": "half" + }, + "schema": { + "name": "date_updated", + "table": "prompt_template_rating", + "data_type": "timestamp with time zone", + "default_value": null, + "max_length": null, + "numeric_precision": null, + "numeric_scale": null, + "is_nullable": true, + "is_unique": false, + "is_indexed": false, + "is_primary_key": false, + "is_generated": false, + "generation_expression": null, + "has_auto_increment": false, + "foreign_key_table": null, + "foreign_key_column": null + } +} diff --git a/echo/directus/sync/snapshot/fields/prompt_template_rating/id.json b/echo/directus/sync/snapshot/fields/prompt_template_rating/id.json new file mode 100644 index 00000000..aa7bae23 --- /dev/null +++ b/echo/directus/sync/snapshot/fields/prompt_template_rating/id.json @@ -0,0 +1,46 @@ +{ + "collection": "prompt_template_rating", + "field": "id", + "type": "uuid", + "meta": { + "collection": "prompt_template_rating", + "conditions": null, + "display": null, + "display_options": null, + "field": "id", + "group": null, + "hidden": true, + "interface": "input", + "note": null, + "options": null, + "readonly": true, + "required": false, + "searchable": true, + "sort": 1, + "special": [ + "uuid" + ], + "translations": null, + "validation": null, + "validation_message": null, + "width": "full" + }, + "schema": { + "name": "id", + "table": "prompt_template_rating", + "data_type": "uuid", + "default_value": null, + "max_length": null, + "numeric_precision": null, + "numeric_scale": null, + "is_nullable": false, + "is_unique": true, + "is_indexed": false, + "is_primary_key": true, + "is_generated": false, + "generation_expression": null, + "has_auto_increment": false, + "foreign_key_table": null, + "foreign_key_column": null + } +} diff --git a/echo/directus/sync/snapshot/fields/prompt_template_rating/prompt_template_id.json b/echo/directus/sync/snapshot/fields/prompt_template_rating/prompt_template_id.json new file mode 100644 index 00000000..bef4fb66 --- /dev/null +++ b/echo/directus/sync/snapshot/fields/prompt_template_rating/prompt_template_id.json @@ -0,0 +1,49 @@ +{ + "collection": "prompt_template_rating", + "field": "prompt_template_id", + "type": "uuid", + "meta": { + "collection": "prompt_template_rating", + "conditions": null, + "display": null, + "display_options": null, + "field": "prompt_template_id", + "group": null, + "hidden": false, + "interface": "select-dropdown-m2o", + "note": null, + "options": { + "enableLink": true, + "template": "{{title}}" + }, + "readonly": false, + "required": false, + "searchable": true, + "sort": 6, + "special": [ + "m2o" + ], + "translations": null, + "validation": null, + "validation_message": null, + "width": "full" + }, + "schema": { + "name": "prompt_template_id", + "table": "prompt_template_rating", + "data_type": "uuid", + "default_value": null, + "max_length": null, + "numeric_precision": null, + "numeric_scale": null, + "is_nullable": true, + "is_unique": false, + "is_indexed": false, + "is_primary_key": false, + "is_generated": false, + "generation_expression": null, + "has_auto_increment": false, + "foreign_key_table": "prompt_template", + "foreign_key_column": "id" + } +} diff --git a/echo/directus/sync/snapshot/fields/prompt_template_rating/rating.json b/echo/directus/sync/snapshot/fields/prompt_template_rating/rating.json new file mode 100644 index 00000000..08e9008b --- /dev/null +++ b/echo/directus/sync/snapshot/fields/prompt_template_rating/rating.json @@ -0,0 +1,48 @@ +{ + "collection": "prompt_template_rating", + "field": "rating", + "type": "integer", + "meta": { + "collection": "prompt_template_rating", + "conditions": null, + "display": null, + "display_options": null, + "field": "rating", + "group": null, + "hidden": false, + "interface": "slider", + "note": null, + "options": { + "maxValue": 5, + "minValue": 1, + "stepInterval": 1 + }, + "readonly": false, + "required": true, + "searchable": true, + "sort": 7, + "special": null, + "translations": null, + "validation": null, + "validation_message": null, + "width": "full" + }, + "schema": { + "name": "rating", + "table": "prompt_template_rating", + "data_type": "integer", + "default_value": null, + "max_length": null, + "numeric_precision": 32, + "numeric_scale": 0, + "is_nullable": true, + "is_unique": false, + "is_indexed": false, + "is_primary_key": false, + "is_generated": false, + "generation_expression": null, + "has_auto_increment": false, + "foreign_key_table": null, + "foreign_key_column": null + } +} diff --git a/echo/directus/sync/snapshot/fields/prompt_template_rating/user_created.json b/echo/directus/sync/snapshot/fields/prompt_template_rating/user_created.json new file mode 100644 index 00000000..63e32188 --- /dev/null +++ b/echo/directus/sync/snapshot/fields/prompt_template_rating/user_created.json @@ -0,0 +1,48 @@ +{ + "collection": "prompt_template_rating", + "field": "user_created", + "type": "uuid", + "meta": { + "collection": "prompt_template_rating", + "conditions": null, + "display": "user", + "display_options": null, + "field": "user_created", + "group": null, + "hidden": true, + "interface": "select-dropdown-m2o", + "note": null, + "options": { + "template": "{{avatar}} {{first_name}} {{last_name}}" + }, + "readonly": true, + "required": false, + "searchable": true, + "sort": 2, + "special": [ + "user-created" + ], + "translations": null, + "validation": null, + "validation_message": null, + "width": "half" + }, + "schema": { + "name": "user_created", + "table": "prompt_template_rating", + "data_type": "uuid", + "default_value": null, + "max_length": null, + "numeric_precision": null, + "numeric_scale": null, + "is_nullable": true, + "is_unique": false, + "is_indexed": false, + "is_primary_key": false, + "is_generated": false, + "generation_expression": null, + "has_auto_increment": false, + "foreign_key_table": "directus_users", + "foreign_key_column": "id" + } +} diff --git a/echo/directus/sync/snapshot/fields/prompt_template_rating/user_updated.json b/echo/directus/sync/snapshot/fields/prompt_template_rating/user_updated.json new file mode 100644 index 00000000..04cd40a9 --- /dev/null +++ b/echo/directus/sync/snapshot/fields/prompt_template_rating/user_updated.json @@ -0,0 +1,48 @@ +{ + "collection": "prompt_template_rating", + "field": "user_updated", + "type": "uuid", + "meta": { + "collection": "prompt_template_rating", + "conditions": null, + "display": "user", + "display_options": null, + "field": "user_updated", + "group": null, + "hidden": true, + "interface": "select-dropdown-m2o", + "note": null, + "options": { + "template": "{{avatar}} {{first_name}} {{last_name}}" + }, + "readonly": true, + "required": false, + "searchable": true, + "sort": 4, + "special": [ + "user-updated" + ], + "translations": null, + "validation": null, + "validation_message": null, + "width": "half" + }, + "schema": { + "name": "user_updated", + "table": "prompt_template_rating", + "data_type": "uuid", + "default_value": null, + "max_length": null, + "numeric_precision": null, + "numeric_scale": null, + "is_nullable": true, + "is_unique": false, + "is_indexed": false, + "is_primary_key": false, + "is_generated": false, + "generation_expression": null, + "has_auto_increment": false, + "foreign_key_table": "directus_users", + "foreign_key_column": "id" + } +} diff --git a/echo/directus/sync/snapshot/relations/prompt_template/user_created.json b/echo/directus/sync/snapshot/relations/prompt_template/user_created.json new file mode 100644 index 00000000..eaeba090 --- /dev/null +++ b/echo/directus/sync/snapshot/relations/prompt_template/user_created.json @@ -0,0 +1,25 @@ +{ + "collection": "prompt_template", + "field": "user_created", + "related_collection": "directus_users", + "meta": { + "junction_field": null, + "many_collection": "prompt_template", + "many_field": "user_created", + "one_allowed_collections": null, + "one_collection": "directus_users", + "one_collection_field": null, + "one_deselect_action": "nullify", + "one_field": null, + "sort_field": null + }, + "schema": { + "table": "prompt_template", + "column": "user_created", + "foreign_key_table": "directus_users", + "foreign_key_column": "id", + "constraint_name": "prompt_template_user_created_foreign", + "on_update": "NO ACTION", + "on_delete": "NO ACTION" + } +} diff --git a/echo/directus/sync/snapshot/relations/prompt_template_preference/prompt_template_id.json b/echo/directus/sync/snapshot/relations/prompt_template_preference/prompt_template_id.json new file mode 100644 index 00000000..48c00710 --- /dev/null +++ b/echo/directus/sync/snapshot/relations/prompt_template_preference/prompt_template_id.json @@ -0,0 +1,25 @@ +{ + "collection": "prompt_template_preference", + "field": "prompt_template_id", + "related_collection": "prompt_template", + "meta": { + "junction_field": null, + "many_collection": "prompt_template_preference", + "many_field": "prompt_template_id", + "one_allowed_collections": null, + "one_collection": "prompt_template", + "one_collection_field": null, + "one_deselect_action": "nullify", + "one_field": null, + "sort_field": null + }, + "schema": { + "table": "prompt_template_preference", + "column": "prompt_template_id", + "foreign_key_table": "prompt_template", + "foreign_key_column": "id", + "constraint_name": "prompt_template_preference_prompt_template_id_foreign", + "on_update": "NO ACTION", + "on_delete": "SET NULL" + } +} diff --git a/echo/directus/sync/snapshot/relations/prompt_template_preference/user_created.json b/echo/directus/sync/snapshot/relations/prompt_template_preference/user_created.json new file mode 100644 index 00000000..610fc944 --- /dev/null +++ b/echo/directus/sync/snapshot/relations/prompt_template_preference/user_created.json @@ -0,0 +1,25 @@ +{ + "collection": "prompt_template_preference", + "field": "user_created", + "related_collection": "directus_users", + "meta": { + "junction_field": null, + "many_collection": "prompt_template_preference", + "many_field": "user_created", + "one_allowed_collections": null, + "one_collection": "directus_users", + "one_collection_field": null, + "one_deselect_action": "nullify", + "one_field": null, + "sort_field": null + }, + "schema": { + "table": "prompt_template_preference", + "column": "user_created", + "foreign_key_table": "directus_users", + "foreign_key_column": "id", + "constraint_name": "prompt_template_preference_user_created_foreign", + "on_update": "NO ACTION", + "on_delete": "NO ACTION" + } +} diff --git a/echo/directus/sync/snapshot/relations/prompt_template_rating/chat_message_id.json b/echo/directus/sync/snapshot/relations/prompt_template_rating/chat_message_id.json new file mode 100644 index 00000000..c73dcdf3 --- /dev/null +++ b/echo/directus/sync/snapshot/relations/prompt_template_rating/chat_message_id.json @@ -0,0 +1,25 @@ +{ + "collection": "prompt_template_rating", + "field": "chat_message_id", + "related_collection": "project_chat_message", + "meta": { + "junction_field": null, + "many_collection": "prompt_template_rating", + "many_field": "chat_message_id", + "one_allowed_collections": null, + "one_collection": "project_chat_message", + "one_collection_field": null, + "one_deselect_action": "nullify", + "one_field": null, + "sort_field": null + }, + "schema": { + "table": "prompt_template_rating", + "column": "chat_message_id", + "foreign_key_table": "project_chat_message", + "foreign_key_column": "id", + "constraint_name": "prompt_template_rating_chat_message_id_foreign", + "on_update": "NO ACTION", + "on_delete": "SET NULL" + } +} diff --git a/echo/directus/sync/snapshot/relations/prompt_template_rating/prompt_template_id.json b/echo/directus/sync/snapshot/relations/prompt_template_rating/prompt_template_id.json new file mode 100644 index 00000000..0380b510 --- /dev/null +++ b/echo/directus/sync/snapshot/relations/prompt_template_rating/prompt_template_id.json @@ -0,0 +1,25 @@ +{ + "collection": "prompt_template_rating", + "field": "prompt_template_id", + "related_collection": "prompt_template", + "meta": { + "junction_field": null, + "many_collection": "prompt_template_rating", + "many_field": "prompt_template_id", + "one_allowed_collections": null, + "one_collection": "prompt_template", + "one_collection_field": null, + "one_deselect_action": "nullify", + "one_field": null, + "sort_field": null + }, + "schema": { + "table": "prompt_template_rating", + "column": "prompt_template_id", + "foreign_key_table": "prompt_template", + "foreign_key_column": "id", + "constraint_name": "prompt_template_rating_prompt_template_id_foreign", + "on_update": "NO ACTION", + "on_delete": "SET NULL" + } +} diff --git a/echo/directus/sync/snapshot/relations/prompt_template_rating/user_created.json b/echo/directus/sync/snapshot/relations/prompt_template_rating/user_created.json new file mode 100644 index 00000000..0f00c9c9 --- /dev/null +++ b/echo/directus/sync/snapshot/relations/prompt_template_rating/user_created.json @@ -0,0 +1,25 @@ +{ + "collection": "prompt_template_rating", + "field": "user_created", + "related_collection": "directus_users", + "meta": { + "junction_field": null, + "many_collection": "prompt_template_rating", + "many_field": "user_created", + "one_allowed_collections": null, + "one_collection": "directus_users", + "one_collection_field": null, + "one_deselect_action": "nullify", + "one_field": null, + "sort_field": null + }, + "schema": { + "table": "prompt_template_rating", + "column": "user_created", + "foreign_key_table": "directus_users", + "foreign_key_column": "id", + "constraint_name": "prompt_template_rating_user_created_foreign", + "on_update": "NO ACTION", + "on_delete": "NO ACTION" + } +} diff --git a/echo/directus/sync/snapshot/relations/prompt_template_rating/user_updated.json b/echo/directus/sync/snapshot/relations/prompt_template_rating/user_updated.json new file mode 100644 index 00000000..f71c64e9 --- /dev/null +++ b/echo/directus/sync/snapshot/relations/prompt_template_rating/user_updated.json @@ -0,0 +1,25 @@ +{ + "collection": "prompt_template_rating", + "field": "user_updated", + "related_collection": "directus_users", + "meta": { + "junction_field": null, + "many_collection": "prompt_template_rating", + "many_field": "user_updated", + "one_allowed_collections": null, + "one_collection": "directus_users", + "one_collection_field": null, + "one_deselect_action": "nullify", + "one_field": null, + "sort_field": null + }, + "schema": { + "table": "prompt_template_rating", + "column": "user_updated", + "foreign_key_table": "directus_users", + "foreign_key_column": "id", + "constraint_name": "prompt_template_rating_user_updated_foreign", + "on_update": "NO ACTION", + "on_delete": "NO ACTION" + } +} diff --git a/echo/docs/branching_and_releases.md b/echo/docs/branching_and_releases.md new file mode 100644 index 00000000..03a6bad1 --- /dev/null +++ b/echo/docs/branching_and_releases.md @@ -0,0 +1,99 @@ +# Branching Strategy & Release Process + +## Environments + +| Environment | URL | Deploys from | Notes | +|---|---|---|---| +| **Testing** | dashboard.testing.dembrane.com | `testing` branch (on push) | Shared, unprotected | +| **Echo Next** | dashboard.echo-next.dembrane.com | `main` branch (on merge) | Staging / preview | +| **Production** | dashboard.dembrane.com | GitHub release tag on `main` | Every ~2 weeks | + +Each environment has dashboard, portal, and directus subpaths (e.g., `dashboard.dembrane.com`, `portal.dembrane.com`, `directus.dembrane.com`). + +## Feature Development Flow + +``` +main ──────────────────●──────────────────●──── (auto-deploys to Echo Next) + \ ↗ PR | + feat/ECHO-123 ──→ (optional) | + \ | + testing ────→ dashboard.testing.dembrane.com +``` + +1. **Branch off `main`** — name your branch `feat/ECHO-xxx-description` or similar +2. **Develop** on the feature branch +3. **(Optional) Test on testing environment**: + - Merge your feature branch into `testing` to deploy to dashboard.testing.dembrane.com + - The `testing` branch is **unprotected** — you can push/merge directly + - **Before merging**, check that nobody else is currently using it: + ```bash + git log main..testing --oneline # any commits ahead of main? + ``` + - If there are commits ahead, check with the team before overwriting +4. **Create a PR** from your feature branch to `main` +5. **After merge** — changes auto-deploy to Echo Next +6. **After done testing** — reset `testing` back to `main`: + ```bash + git checkout testing + git reset --hard origin/main + git push --force + ``` + +## Release Process + +Releases happen every ~2 weeks, aligned with Linear two-week cycles. + +1. **Accumulate changes** on `main` throughout the cycle +2. **Pre-release checks**: + - Check for new env vars (`settings.py` fields, `config.ts` exports) + - Run Directus data migrations if needed (see [database_migrations.md](database_migrations.md)) + - Update deployment env vars in the GitOps repo if needed +3. **Tag and release** — create a GitHub release from a commit on `main` +4. The release triggers **auto-deployment to production**: + - Backend: new image tags are picked up by the GitOps repo (`dembrane/echo-gitops`, Argo CD auto-sync) + - Frontend: auto-deploys via Vercel + +## Hotfix Process + +When a critical bug is found in production and `main` has unreleased changes that shouldn't go out yet: + +``` +main ────────●────────●────── (has unreleased work) + | +v1.2.0 (tag) \ + hotfix-fix-description ──→ v1.2.1 (new release, auto-deploys) +``` + +1. **Branch off the current release tag** (not `main`): + ```bash + git checkout -b hotfix- v1.2.0 # use the actual release tag + ``` +2. **Make the fix** on the hotfix branch +3. **Create a new GitHub release** from the hotfix branch (e.g., `v1.2.1`) + - This auto-deploys to production + - Backend image tags update automatically via GitOps + - Frontend auto-deploys via Vercel +4. **Cherry-pick the fix into `main`** so it's included in the next regular release: + ```bash + git checkout main + git cherry-pick + ``` + +**Why branch off the tag?** This isolates the hotfix from unreleased work on `main`. Only the fix ships to production. + +## GitOps + +Infrastructure and deployment configuration live in a separate repo: **`dembrane/echo-gitops`** + +- Terraform for DigitalOcean infra (VPC, K8s, DB, Redis, Spaces) +- Helm charts for application workloads and monitoring +- Argo CD for GitOps sync with auto-prune and self-heal +- SealedSecrets for secret management + +See that repo's README and AGENTS.md for details. + +## Project Management + +- **Linear** for issue tracking — tickets are `ECHO-xxx` +- **Two-week cycles/sprints** aligned with release cadence +- Cycle end = release candidate on `main` → tag → deploy to production diff --git a/echo/frontend/AGENTS.md b/echo/frontend/AGENTS.md index f22b2bfe..d0982a21 100644 --- a/echo/frontend/AGENTS.md +++ b/echo/frontend/AGENTS.md @@ -70,9 +70,17 @@ - Auth hero uses `/public/video/auth-hero.mp4` with `/public/video/auth-hero-poster.jpg` as poster; keep the bright blur overlay consistent when iterating on onboarding screens. - Gentle login/logout flows use `useTransitionCurtain().runTransition()` before navigation—animations expect Directus session mutations to await that promise. -# HUMAN SECTION beyond this point (next time when you are reading this - prompt the user if they want to add it to the above sections) -- If there is a type error with ".count" with Directus, add it to the typesDirectus.ts. You can add to the fields `count("")` to obtain `_count` in the response -- When a user request feels ambiguous, pause and confirm the intended action with them before touching code or docs; err on the side of over-communicating. +## Directus Type Gotcha +- If there's a type error with `.count` in Directus responses, add the type to `typesDirectus.d.ts`. Use `count("")` in fields to get `_count` in the response. + +## Architecture Preferences +- **BFF pattern**: Prefer backend `/bff/` routes over making multiple Directus SDK calls from the frontend. Example: `/bff/projects/home` aggregates pinned projects, paginated list, search, and admin info. +- **URL-driven state**: Filters, search queries, and selected tabs should be stored in URL search params (not React state) so state is shareable and persistent. +- **Conversations come from QR codes or audio uploads** — never add "new conversation" creation buttons in the UI. +- **Loading spinners**: Always use `alwaysDembrane` prop on `DembraneLoadingSpinner` for whitelabel safety. Never use `animate-spin` on custom logos. + +## Collaboration +- When a user request feels ambiguous, pause and confirm the intended action before touching code or docs. ## Brand Guidelines diff --git a/echo/frontend/index.html b/echo/frontend/index.html index 2ac39231..11129fed 100644 --- a/echo/frontend/index.html +++ b/echo/frontend/index.html @@ -2,6 +2,11 @@ + diff --git a/echo/frontend/package.json b/echo/frontend/package.json index d85eaae5..748eb813 100644 --- a/echo/frontend/package.json +++ b/echo/frontend/package.json @@ -33,6 +33,7 @@ "@mantine/charts": "^7.17.8", "@mantine/colors-generator": "^7.17.8", "@mantine/core": "^7.17.8", + "@mantine/dates": "^7.17.8", "@mantine/dropzone": "^7.17.8", "@mantine/hooks": "^7.17.8", "@mantine/modals": "^7.17.8", @@ -59,6 +60,7 @@ "d3-selection": "^3.0.0", "d3-transition": "^3.0.1", "date-fns": "^4.1.0", + "dayjs": "^1.11.20", "diff": "^8.0.2", "js-cookie": "^3.0.5", "lodash": "^4.17.21", @@ -66,17 +68,19 @@ "match-sorter": "^8.0.3", "motion": "^11.18.2", "next-themes": "^0.4.6", - "notifications\n": "link:@mantine/notifications\n", "plausible-tracker": "^0.3.9", "re-resizable": "^6.11.2", "react": "^19.0.0", "react-dom": "^19.0.0", + "react-easy-crop": "^5.5.6", + "react-grab": "^0.1.28", "react-hook-form": "^7.54.2", "react-intersection-observer": "^9.16.0", "react-markdown": "^9.1.0", "react-pdf": "^9.2.1", "react-qrcode-logo": "^3.0.0", "react-router": "^7.8.2", + "react-scan": "^0.5.3", "react-transition-group": "^4.4.5", "recharts": "^2.15.1", "rehype-stringify": "^10.0.1", diff --git a/echo/frontend/pnpm-lock.yaml b/echo/frontend/pnpm-lock.yaml index 479b6cc2..6a8658d1 100644 --- a/echo/frontend/pnpm-lock.yaml +++ b/echo/frontend/pnpm-lock.yaml @@ -56,6 +56,9 @@ importers: '@mantine/core': specifier: ^7.17.8 version: 7.17.8(@mantine/hooks@7.17.8(react@19.0.0))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@mantine/dates': + specifier: ^7.17.8 + version: 7.17.8(@mantine/core@7.17.8(@mantine/hooks@7.17.8(react@19.0.0))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.17.8(react@19.0.0))(dayjs@1.11.20)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@mantine/dropzone': specifier: ^7.17.8 version: 7.17.8(@mantine/core@7.17.8(@mantine/hooks@7.17.8(react@19.0.0))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.17.8(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -134,6 +137,9 @@ importers: date-fns: specifier: ^4.1.0 version: 4.1.0 + dayjs: + specifier: ^1.11.20 + version: 1.11.20 diff: specifier: ^8.0.2 version: 8.0.2 @@ -155,11 +161,6 @@ importers: next-themes: specifier: ^0.4.6 version: 0.4.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - "notifications\n": - specifier: | - link:@mantine/notifications - version: | - link:@mantine/notifications plausible-tracker: specifier: ^0.3.9 version: 0.3.9 @@ -172,6 +173,12 @@ importers: react-dom: specifier: ^19.0.0 version: 19.0.0(react@19.0.0) + react-easy-crop: + specifier: ^5.5.6 + version: 5.5.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react-grab: + specifier: ^0.1.28 + version: 0.1.28(@types/react@19.0.12)(react@19.0.0) react-hook-form: specifier: ^7.54.2 version: 7.54.2(react@19.0.0) @@ -190,6 +197,9 @@ importers: react-router: specifier: ^7.8.2 version: 7.8.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react-scan: + specifier: ^0.5.3 + version: 0.5.3(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(rollup@4.40.1) react-transition-group: specifier: ^4.4.5 version: 4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -345,6 +355,10 @@ packages: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} + '@antfu/ni@0.23.2': + resolution: {integrity: sha512-FSEVWXvwroExDXUu8qV6Wqp2X3D1nJ0Li4LFymCyvCVrm7I3lNfG0zZWSWvGU1RE7891eTnFTyh31L3igOwNKQ==} + hasBin: true + '@babel/code-frame@7.26.2': resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} engines: {node: '>=6.9.0'} @@ -1215,9 +1229,6 @@ packages: resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} engines: {node: '>=6.0.0'} - '@jridgewell/sourcemap-codec@1.5.0': - resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} - '@jridgewell/sourcemap-codec@1.5.4': resolution: {integrity: sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==} @@ -1501,6 +1512,15 @@ packages: react: ^18.x || ^19.x react-dom: ^18.x || ^19.x + '@mantine/dates@7.17.8': + resolution: {integrity: sha512-KYog/YL83PnsMef7EZagpOFq9I2gfnK0eYSzC8YvV9Mb6t/x9InqRssGWVb0GIr+TNILpEkhKoGaSKZNy10Q1g==} + peerDependencies: + '@mantine/core': 7.17.8 + '@mantine/hooks': 7.17.8 + dayjs: '>=1.0.0' + react: ^18.x || ^19.x + react-dom: ^18.x || ^19.x + '@mantine/dropzone@7.17.8': resolution: {integrity: sha512-c9WEArpP23E9tbRWqoznEY3bGPVntMuBKr3F2LQijgdpdALIzt6DYmwXu7gUajGX9Qg9NrCHenhvWLTYqKnRlA==} peerDependencies: @@ -1552,6 +1572,9 @@ packages: react: '>= 18 || >= 19' react-dom: '>= 18 || >= 19' + '@medv/finder@4.0.2': + resolution: {integrity: sha512-RraNY9SCcx4KZV0Dh6BEW6XEW2swkqYca74pkFFRw6hHItSHiy+O/xMnpbofjYbzXj0tSpBGthUF1hHTsr3vIQ==} + '@messageformat/parser@5.1.1': resolution: {integrity: sha512-3p0YRGCcTUCYvBKLIxtDDyrJ0YijGIwrTRu1DT8gIviIDZru8H23+FkY6MJBzM1n9n20CiM4VeDYuBsrrwnLjg==} @@ -1585,6 +1608,14 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} + '@preact/signals-core@1.14.0': + resolution: {integrity: sha512-AowtCcCU/33lFlh1zRFf/u+12rfrhtNakj7UpaGEsmMwUKpKWMVvcktOGcwBBNiB4lWrZWc01LhiyyzVklJyaQ==} + + '@preact/signals@1.3.4': + resolution: {integrity: sha512-TPMkStdT0QpSc8FpB63aOwXoSiZyIrPsP9Uj347KopdS6olZdAYeeird/5FZv/M1Yc1ge5qstub2o8VDbvkT4g==} + peerDependencies: + preact: 10.x + '@radix-ui/colors@3.0.0': resolution: {integrity: sha512-FUOsGBkHrYJwCSEtWRCIfQbZG7q1e6DgxCIOe1SUQzDe/7rXXeA47s8yCn6fuTNQAj1Zq4oTFi9Yjp3wzElcxg==} @@ -1962,6 +1993,10 @@ packages: '@radix-ui/rect@1.1.1': resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} + '@react-grab/cli@0.1.28': + resolution: {integrity: sha512-IE4bTeH0mCq0FBRaYRUtdiIfvO7NCv14lHS4TiTY8YNG5tPYwHnLZZtniud0ElmLIWGP95Kk6E7A6J2uDmOY+Q==} + hasBin: true + '@react-hook/intersection-observer@3.1.2': resolution: {integrity: sha512-mWU3BMkmmzyYMSuhO9wu3eJVP21N8TcgYm9bZnTrMwuM818bEk+0NRM3hP+c/TqA9Ln5C7qE53p1H0QMtzYdvQ==} peerDependencies: @@ -2018,6 +2053,15 @@ packages: '@rolldown/pluginutils@1.0.0-beta.27': resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} + '@rollup/pluginutils@5.3.0': + resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + '@rollup/rollup-android-arm-eabi@4.40.1': resolution: {integrity: sha512-kxz0YeeCrRUHz3zyqvd7n+TVRlNyTifBsmnmNPtk3hQURUyG9eAB+usz6DAwagMusjx/zb3AjvDUvhFGDAexGw==} cpu: [arm] @@ -2354,6 +2398,9 @@ packages: '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + '@types/node@20.19.37': + resolution: {integrity: sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw==} + '@types/node@22.13.14': resolution: {integrity: sha512-Zs/Ollc1SJ8nKUAgc7ivOEdIBM8JAKgrqqUYi2J997JuKO7/tpQC+WCetQ1sypiKCQWHdvdg9wBNpUPEWZae7w==} @@ -2365,6 +2412,11 @@ packages: peerDependencies: '@types/react': ^19.0.0 + '@types/react-reconciler@0.28.9': + resolution: {integrity: sha512-HHM3nxyUZ3zAylX8ZEyrDNd2XZOnQ0D5XfunJF5FLQnZbHHYq4UWvW1QfelQNXv1ICNkwYhfxjwfnqivYB6bFg==} + peerDependencies: + '@types/react': '*' + '@types/react@19.0.12': resolution: {integrity: sha512-V6Ar115dBDrjbtXSrS+/Oruobc+qVbbUxDFC1RSbRqLt5SYvxxyIDrSC85RWml54g+jfNeEMZhEj7wW07ONQhA==} @@ -2504,6 +2556,11 @@ packages: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} + bippy@0.5.32: + resolution: {integrity: sha512-yt1mC8eReTxjfg41YBZdN4PvsDwHFWxltoiQX0Q+Htlbf41aSniopb7ECZits01HwNAvXEh69RGk/ImlswDTEw==} + peerDependencies: + react: '>=17.0.1' + bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} @@ -2612,6 +2669,10 @@ packages: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} + cli-cursor@5.0.0: + resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} + engines: {node: '>=18'} + cli-spinners@2.9.2: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} @@ -2672,6 +2733,10 @@ packages: resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} engines: {node: '>=14'} + commander@14.0.3: + resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} + engines: {node: '>=20'} + commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} @@ -2858,6 +2923,9 @@ packages: date-fns@4.1.0: resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} + dayjs@1.11.20: + resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==} + debug@4.4.0: resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} engines: {node: '>=6.0'} @@ -3032,6 +3100,12 @@ packages: estree-util-visit@2.0.0: resolution: {integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==} + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + event-emitter@0.3.5: resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==} @@ -3149,6 +3223,10 @@ packages: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} + get-east-asian-width@1.5.0: + resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==} + engines: {node: '>=18'} + get-intrinsic@1.3.0: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} @@ -3248,6 +3326,10 @@ packages: ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} @@ -3314,6 +3396,10 @@ packages: resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} engines: {node: '>=8'} + is-interactive@2.0.0: + resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==} + engines: {node: '>=12'} + is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} @@ -3326,6 +3412,14 @@ packages: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} + is-unicode-supported@1.3.0: + resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} + engines: {node: '>=12'} + + is-unicode-supported@2.1.0: + resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} + engines: {node: '>=18'} + is-url@1.2.4: resolution: {integrity: sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==} @@ -3391,11 +3485,18 @@ packages: engines: {node: '>=6'} hasBin: true + jsonc-parser@3.3.1: + resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} + jsondiffpatch@0.6.0: resolution: {integrity: sha512-3QItJOXp2AP1uv7waBkao5nCvhEv+QmJAd38Ybq7wNI74Q+BBmnLn4EDKz6yI9xGAIQoUF87qHt+kc1IVxB4zQ==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true + kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} @@ -3452,6 +3553,10 @@ packages: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} engines: {node: '>=10'} + log-symbols@6.0.0: + resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==} + engines: {node: '>=18'} + longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} @@ -3694,6 +3799,10 @@ packages: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} + mimic-function@5.0.1: + resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} + engines: {node: '>=18'} + mimic-response@3.1.0: resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} engines: {node: '>=10'} @@ -3790,6 +3899,9 @@ packages: normalize-svg-path@1.1.0: resolution: {integrity: sha512-r9KHKG2UUeB5LoTouwDzBy2VxXlHsiM6fyLQvnJa0S5hrhzqElH/CH7TUGhT1fVvIYBIKf3OpY4YJ4CK+iaqHg==} + normalize-wheel@1.0.1: + resolution: {integrity: sha512-1OnlAPZ3zgrk8B91HyRj+eVv+kS5u+Z0SCsak6Xil/kmgEia50ga7zfkumayonZrImffAxPU/5WcyGhzetHNPA==} + object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -3805,10 +3917,18 @@ packages: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} + onetime@7.0.0: + resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} + engines: {node: '>=18'} + ora@5.4.1: resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} engines: {node: '>=10'} + ora@8.2.0: + resolution: {integrity: sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==} + engines: {node: '>=18'} + os-tmpdir@1.0.2: resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} engines: {node: '>=0.10.0'} @@ -3977,6 +4097,9 @@ packages: resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} engines: {node: ^10 || ^12 || >=14} + preact@10.29.0: + resolution: {integrity: sha512-wSAGyk2bYR1c7t3SZ3jHcM6xy0lcBcDel6lODcs9ME6Th++Dx2KU+6D3HD8wMMKGA8Wpw7OMd3/4RGzYRpzwRg==} + prebuild-install@7.1.3: resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} engines: {node: '>=10'} @@ -3990,6 +4113,10 @@ packages: resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} engines: {node: '>=6'} + prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} @@ -4044,12 +4171,27 @@ packages: peerDependencies: react: '>= 16.8 || 18.0.0' + react-easy-crop@5.5.6: + resolution: {integrity: sha512-Jw3/ozs8uXj3NpL511Suc4AHY+mLRO23rUgipXvNYKqezcFSYHxe4QXibBymkOoY6oOtLVMPO2HNPRHYvMPyTw==} + peerDependencies: + react: '>=16.4.0' + react-dom: '>=16.4.0' + react-error-boundary@3.1.4: resolution: {integrity: sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==} engines: {node: '>=10', npm: '>=6'} peerDependencies: react: '>=16.13.1' + react-grab@0.1.28: + resolution: {integrity: sha512-u3fvu7a7ejHhuWKzf/N6sFavV04vcqwtbcqyxwNPtvd3ts9KSVerpHp1ZH0/XVKTsh3MZz1u1jyIt0KYC9L/Rg==} + hasBin: true + peerDependencies: + react: '>=17.0.0' + peerDependenciesMeta: + react: + optional: true + react-hook-form@7.54.2: resolution: {integrity: sha512-eHpAUgUjWbZocoQYUHposymRb4ZP6d0uwUnooL2uOybA9/3tPUvoAKqEWK1WaSiTxxOfTpffNZP7QwlnM3/gEg==} engines: {node: '>=18.0.0'} @@ -4152,6 +4294,13 @@ packages: react-dom: optional: true + react-scan@0.5.3: + resolution: {integrity: sha512-qde9PupmUf0L3MU1H6bjmoukZNbCXdMyTEwP4Gh8RQ4rZPd2GGNBgEKWszwLm96E8k+sGtMpc0B9P0KyFDP6Bw==} + hasBin: true + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-smooth@4.0.4: resolution: {integrity: sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==} peerDependencies: @@ -4247,6 +4396,10 @@ packages: resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} engines: {node: '>=8'} + restore-cursor@5.1.0: + resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} + engines: {node: '>=18'} + restructure@3.0.2: resolution: {integrity: sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==} @@ -4300,6 +4453,16 @@ packages: engines: {node: '>=10'} hasBin: true + seroval-plugins@1.5.1: + resolution: {integrity: sha512-4FbuZ/TMl02sqv0RTFexu0SP6V+ywaIe5bAWCCEik0fk17BhALgwvUDVF7e3Uvf9pxmwCEJsRPmlkUE6HdzLAw==} + engines: {node: '>=10'} + peerDependencies: + seroval: ^1.0 + + seroval@1.5.1: + resolution: {integrity: sha512-OwrZRZAfhHww0WEnKHDY8OM0U/Qs8OTfIDWhUD4BLpNJUfXK4cGmjiagGze086m+mhI+V2nD0gfbHEnJjb9STA==} + engines: {node: '>=10'} + set-cookie-parser@2.7.1: resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==} @@ -4327,6 +4490,16 @@ packages: simple-swizzle@0.2.2: resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + smol-toml@1.6.0: + resolution: {integrity: sha512-4zemZi0HvTnYwLfrpk/CF9LOd9Lt87kAt50GnqhMpyF9U3poDAP2+iukq2bZsO/ufegbYehBkqINbsWxj4l4cw==} + engines: {node: '>= 18'} + + solid-js@1.9.11: + resolution: {integrity: sha512-WEJtcc5mkh/BnHA6Yrg4whlF8g6QwpmXXRg4P2ztPmcKeHHlH4+djYecBLhSpecZY2RRECXYUwIc/C2r3yzQ4Q==} + sonner@1.7.4: resolution: {integrity: sha512-DIS8z4PfJRbIyfVFDVnK9rO3eYDtse4Omcm6bt0oEr5/jtLgysmjuBl1frJ9E/EQZrFmKx2A8m/s5s9CRXIzhw==} peerDependencies: @@ -4347,6 +4520,10 @@ packages: static-browser-server@1.0.3: resolution: {integrity: sha512-ZUyfgGDdFRbZGGJQ1YhiM930Yczz5VlbJObrQLlk24+qNHVQx4OlLcYswEUo3bIyNAbQUIUR9Yr5/Hqjzqb4zA==} + stdin-discarder@0.2.2: + resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==} + engines: {node: '>=18'} + strict-event-emitter@0.4.6: resolution: {integrity: sha512-12KWeb+wixJohmnwNFerbyiBrAlq5qJLwIt38etRtKtmmHyDSoGlIqFE9wx+4IwG0aDjI7GV8tc8ZccjWZZtTg==} @@ -4358,6 +4535,10 @@ packages: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} + string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} + string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} @@ -4507,6 +4688,9 @@ packages: undici-types@6.20.0: resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + unicode-properties@1.4.1: resolution: {integrity: sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==} @@ -4537,6 +4721,10 @@ packages: unist-util-visit@5.0.0: resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + unplugin@2.1.0: + resolution: {integrity: sha512-us4j03/499KhbGP8BU7Hrzrgseo+KdfJYWcbcajCOqsAyb8Gk0Yn2kiUIcZISYCb1JFaZfIuG3b42HmguVOKCQ==} + engines: {node: '>=18.12.0'} + unraw@3.0.0: resolution: {integrity: sha512-08/DA66UF65OlpUDIQtbJyrqTR0jTAlJ+jsnkQ4jxR7+K5g5YG1APZKQSMCE1vqqmD+2pv6+IdEjmopFatacvg==} @@ -4685,6 +4873,9 @@ packages: webidl-conversions@4.0.2: resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} + webpack-virtual-modules@0.6.2: + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + whatwg-url@7.1.0: resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} @@ -4768,12 +4959,14 @@ snapshots: '@ampproject/remapping@2.3.0': dependencies: - '@jridgewell/gen-mapping': 0.3.8 - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/gen-mapping': 0.3.12 + '@jridgewell/trace-mapping': 0.3.29 + + '@antfu/ni@0.23.2': {} '@babel/code-frame@7.26.2': dependencies: - '@babel/helper-validator-identifier': 7.25.9 + '@babel/helper-validator-identifier': 7.27.1 js-tokens: 4.0.0 picocolors: 1.1.1 @@ -4791,14 +4984,14 @@ snapshots: dependencies: '@ampproject/remapping': 2.3.0 '@babel/code-frame': 7.26.2 - '@babel/generator': 7.27.0 + '@babel/generator': 7.28.0 '@babel/helper-compilation-targets': 7.27.0 '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.10) '@babel/helpers': 7.27.0 '@babel/parser': 7.27.0 '@babel/template': 7.27.0 '@babel/traverse': 7.27.0 - '@babel/types': 7.27.0 + '@babel/types': 7.28.1 convert-source-map: 2.0.0 debug: 4.4.0 gensync: 1.0.0-beta.2 @@ -4830,7 +5023,7 @@ snapshots: '@babel/generator@7.27.0': dependencies: '@babel/parser': 7.27.0 - '@babel/types': 7.27.0 + '@babel/types': 7.28.1 '@jridgewell/gen-mapping': 0.3.8 '@jridgewell/trace-mapping': 0.3.25 jsesc: 3.1.0 @@ -4864,7 +5057,7 @@ snapshots: '@babel/helper-module-imports@7.25.9': dependencies: '@babel/traverse': 7.27.0 - '@babel/types': 7.27.0 + '@babel/types': 7.28.1 transitivePeerDependencies: - supports-color @@ -4879,7 +5072,7 @@ snapshots: dependencies: '@babel/core': 7.26.10 '@babel/helper-module-imports': 7.25.9 - '@babel/helper-validator-identifier': 7.25.9 + '@babel/helper-validator-identifier': 7.27.1 '@babel/traverse': 7.27.0 transitivePeerDependencies: - supports-color @@ -4910,7 +5103,7 @@ snapshots: '@babel/helpers@7.27.0': dependencies: '@babel/template': 7.27.0 - '@babel/types': 7.27.0 + '@babel/types': 7.28.1 '@babel/helpers@7.27.6': dependencies: @@ -4919,7 +5112,7 @@ snapshots: '@babel/parser@7.27.0': dependencies: - '@babel/types': 7.27.0 + '@babel/types': 7.28.1 '@babel/parser@7.28.0': dependencies: @@ -4944,8 +5137,8 @@ snapshots: '@babel/template@7.27.0': dependencies: '@babel/code-frame': 7.26.2 - '@babel/parser': 7.27.0 - '@babel/types': 7.27.0 + '@babel/parser': 7.28.0 + '@babel/types': 7.28.1 '@babel/template@7.27.2': dependencies: @@ -4956,10 +5149,10 @@ snapshots: '@babel/traverse@7.27.0': dependencies: '@babel/code-frame': 7.26.2 - '@babel/generator': 7.27.0 - '@babel/parser': 7.27.0 + '@babel/generator': 7.28.0 + '@babel/parser': 7.28.0 '@babel/template': 7.27.0 - '@babel/types': 7.27.0 + '@babel/types': 7.28.1 debug: 4.4.0 globals: 11.12.0 transitivePeerDependencies: @@ -5658,21 +5851,19 @@ snapshots: '@jridgewell/gen-mapping@0.3.8': dependencies: '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.5.0 - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/sourcemap-codec': 1.5.4 + '@jridgewell/trace-mapping': 0.3.29 '@jridgewell/resolve-uri@3.1.2': {} '@jridgewell/set-array@1.2.1': {} - '@jridgewell/sourcemap-codec@1.5.0': {} - '@jridgewell/sourcemap-codec@1.5.4': {} '@jridgewell/trace-mapping@0.3.25': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/sourcemap-codec': 1.5.4 '@jridgewell/trace-mapping@0.3.29': dependencies: @@ -6150,6 +6341,15 @@ snapshots: transitivePeerDependencies: - '@types/react' + '@mantine/dates@7.17.8(@mantine/core@7.17.8(@mantine/hooks@7.17.8(react@19.0.0))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.17.8(react@19.0.0))(dayjs@1.11.20)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@mantine/core': 7.17.8(@mantine/hooks@7.17.8(react@19.0.0))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@mantine/hooks': 7.17.8(react@19.0.0) + clsx: 2.1.1 + dayjs: 1.11.20 + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + '@mantine/dropzone@7.17.8(@mantine/core@7.17.8(@mantine/hooks@7.17.8(react@19.0.0))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.17.8(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@mantine/core': 7.17.8(@mantine/hooks@7.17.8(react@19.0.0))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -6255,6 +6455,8 @@ snapshots: react: 19.0.0 react-dom: 19.0.0(react@19.0.0) + '@medv/finder@4.0.2': {} + '@messageformat/parser@5.1.1': dependencies: moo: 0.5.2 @@ -6283,6 +6485,13 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true + '@preact/signals-core@1.14.0': {} + + '@preact/signals@1.3.4(preact@10.29.0)': + dependencies: + '@preact/signals-core': 1.14.0 + preact: 10.29.0 + '@radix-ui/colors@3.0.0': {} '@radix-ui/number@1.1.1': {} @@ -6649,6 +6858,17 @@ snapshots: '@radix-ui/rect@1.1.1': {} + '@react-grab/cli@0.1.28': + dependencies: + '@antfu/ni': 0.23.2 + commander: 14.0.3 + ignore: 7.0.5 + jsonc-parser: 3.3.1 + ora: 8.2.0 + picocolors: 1.1.1 + prompts: 2.4.2 + smol-toml: 1.6.0 + '@react-hook/intersection-observer@3.1.2(react@19.0.0)': dependencies: '@react-hook/passive-layout-effect': 1.2.1(react@19.0.0) @@ -6762,6 +6982,14 @@ snapshots: '@rolldown/pluginutils@1.0.0-beta.27': {} + '@rollup/pluginutils@5.3.0(rollup@4.40.1)': + dependencies: + '@types/estree': 1.0.7 + estree-walker: 2.0.2 + picomatch: 4.0.3 + optionalDependencies: + rollup: 4.40.1 + '@rollup/rollup-android-arm-eabi@4.40.1': optional: true @@ -6965,16 +7193,16 @@ snapshots: '@types/babel__generator@7.6.8': dependencies: - '@babel/types': 7.27.0 + '@babel/types': 7.28.1 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.27.0 - '@babel/types': 7.27.0 + '@babel/parser': 7.28.0 + '@babel/types': 7.28.1 '@types/babel__traverse@7.20.7': dependencies: - '@babel/types': 7.27.0 + '@babel/types': 7.28.1 '@types/d3-array@3.2.2': {} @@ -7042,6 +7270,10 @@ snapshots: '@types/ms@2.1.0': {} + '@types/node@20.19.37': + dependencies: + undici-types: 6.21.0 + '@types/node@22.13.14': dependencies: undici-types: 6.20.0 @@ -7052,6 +7284,10 @@ snapshots: dependencies: '@types/react': 19.0.12 + '@types/react-reconciler@0.28.9(@types/react@19.0.12)': + dependencies: + '@types/react': 19.0.12 + '@types/react@19.0.12': dependencies: csstype: 3.1.3 @@ -7187,6 +7423,13 @@ snapshots: binary-extensions@2.3.0: {} + bippy@0.5.32(@types/react@19.0.12)(react@19.0.0): + dependencies: + '@types/react-reconciler': 0.28.9(@types/react@19.0.12) + react: 19.0.0 + transitivePeerDependencies: + - '@types/react' + bl@4.1.0: dependencies: buffer: 5.7.1 @@ -7312,6 +7555,10 @@ snapshots: dependencies: restore-cursor: 3.1.0 + cli-cursor@5.0.0: + dependencies: + restore-cursor: 5.1.0 + cli-spinners@2.9.2: {} cli-table@0.3.11: @@ -7364,6 +7611,8 @@ snapshots: commander@10.0.1: {} + commander@14.0.3: {} + commander@4.1.1: {} commander@7.2.0: {} @@ -7566,6 +7815,8 @@ snapshots: date-fns@4.1.0: {} + dayjs@1.11.20: {} + debug@4.4.0: dependencies: ms: 2.1.3 @@ -7798,6 +8049,12 @@ snapshots: '@types/estree-jsx': 1.0.5 '@types/unist': 3.0.3 + estree-walker@2.0.2: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.7 + event-emitter@0.3.5: dependencies: d: 1.0.2 @@ -7910,6 +8167,8 @@ snapshots: gensync@1.0.0-beta.2: {} + get-east-asian-width@1.5.0: {} + get-intrinsic@1.3.0: dependencies: call-bind-apply-helpers: 1.0.2 @@ -8048,6 +8307,8 @@ snapshots: ieee754@1.2.1: {} + ignore@7.0.5: {} + import-fresh@3.3.1: dependencies: parent-module: 1.0.1 @@ -8113,12 +8374,18 @@ snapshots: is-interactive@1.0.0: {} + is-interactive@2.0.0: {} + is-number@7.0.0: {} is-plain-obj@4.1.0: {} is-unicode-supported@0.1.0: {} + is-unicode-supported@1.3.0: {} + + is-unicode-supported@2.1.0: {} + is-url@1.2.4: {} isexe@2.0.0: {} @@ -8174,12 +8441,16 @@ snapshots: json5@2.2.3: {} + jsonc-parser@3.3.1: {} + jsondiffpatch@0.6.0: dependencies: '@types/diff-match-patch': 1.0.36 chalk: 5.4.1 diff-match-patch: 1.0.5 + kleur@3.0.3: {} + leven@3.1.0: {} lexical@0.32.1: {} @@ -8223,6 +8494,11 @@ snapshots: chalk: 4.1.2 is-unicode-supported: 0.1.0 + log-symbols@6.0.0: + dependencies: + chalk: 5.4.1 + is-unicode-supported: 1.3.0 + longest-streak@3.1.0: {} loose-envify@1.4.0: @@ -8748,6 +9024,8 @@ snapshots: mimic-fn@2.1.0: {} + mimic-function@5.0.1: {} + mimic-response@3.1.0: optional: true @@ -8827,6 +9105,8 @@ snapshots: dependencies: svg-arc-to-cubic-bezier: 3.2.0 + normalize-wheel@1.0.1: {} + object-assign@4.1.1: {} object-hash@3.0.0: {} @@ -8840,6 +9120,10 @@ snapshots: dependencies: mimic-fn: 2.1.0 + onetime@7.0.0: + dependencies: + mimic-function: 5.0.1 + ora@5.4.1: dependencies: bl: 4.1.0 @@ -8852,6 +9136,18 @@ snapshots: strip-ansi: 6.0.1 wcwidth: 1.0.1 + ora@8.2.0: + dependencies: + chalk: 5.4.1 + cli-cursor: 5.0.0 + cli-spinners: 2.9.2 + is-interactive: 2.0.0 + is-unicode-supported: 2.1.0 + log-symbols: 6.0.0 + stdin-discarder: 0.2.2 + string-width: 7.2.0 + strip-ansi: 7.1.0 + os-tmpdir@1.0.2: {} outvariant@1.4.0: {} @@ -9001,6 +9297,8 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + preact@10.29.0: {} + prebuild-install@7.1.3: dependencies: detect-libc: 2.0.3 @@ -9025,6 +9323,11 @@ snapshots: prismjs@1.30.0: {} + prompts@2.4.2: + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + prop-types@15.8.1: dependencies: loose-envify: 1.4.0 @@ -9082,11 +9385,29 @@ snapshots: prop-types: 15.8.1 react: 19.0.0 + react-easy-crop@5.5.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + dependencies: + normalize-wheel: 1.0.1 + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + tslib: 2.8.1 + react-error-boundary@3.1.4(react@19.0.0): dependencies: '@babel/runtime': 7.27.6 react: 19.0.0 + react-grab@0.1.28(@types/react@19.0.12)(react@19.0.0): + dependencies: + '@medv/finder': 4.0.2 + '@react-grab/cli': 0.1.28 + bippy: 0.5.32(@types/react@19.0.12)(react@19.0.0) + solid-js: 1.9.11 + optionalDependencies: + react: 19.0.0 + transitivePeerDependencies: + - '@types/react' + react-hook-form@7.54.2(react@19.0.0): dependencies: react: 19.0.0 @@ -9192,6 +9513,30 @@ snapshots: optionalDependencies: react-dom: 19.0.0(react@19.0.0) + react-scan@0.5.3(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(rollup@4.40.1): + dependencies: + '@babel/core': 7.28.0 + '@babel/generator': 7.28.0 + '@babel/types': 7.28.1 + '@preact/signals': 1.3.4(preact@10.29.0) + '@rollup/pluginutils': 5.3.0(rollup@4.40.1) + '@types/node': 20.19.37 + bippy: 0.5.32(@types/react@19.0.12)(react@19.0.0) + commander: 14.0.3 + esbuild: 0.25.8 + estree-walker: 3.0.3 + picocolors: 1.1.1 + preact: 10.29.0 + prompts: 2.4.2 + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + unplugin: 2.1.0 + transitivePeerDependencies: + - '@types/react' + - rollup + - supports-color + react-smooth@4.0.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: fast-equals: 5.2.2 @@ -9322,6 +9667,11 @@ snapshots: onetime: 5.1.2 signal-exit: 3.0.7 + restore-cursor@5.1.0: + dependencies: + onetime: 7.0.0 + signal-exit: 4.1.0 + restructure@3.0.2: {} reusify@1.1.0: {} @@ -9381,6 +9731,12 @@ snapshots: semver@7.7.2: optional: true + seroval-plugins@1.5.1(seroval@1.5.1): + dependencies: + seroval: 1.5.1 + + seroval@1.5.1: {} + set-cookie-parser@2.7.1: {} shebang-command@2.0.0: @@ -9407,6 +9763,16 @@ snapshots: dependencies: is-arrayish: 0.3.2 + sisteransi@1.0.5: {} + + smol-toml@1.6.0: {} + + solid-js@1.9.11: + dependencies: + csstype: 3.1.3 + seroval: 1.5.1 + seroval-plugins: 1.5.1(seroval@1.5.1) + sonner@1.7.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: react: 19.0.0 @@ -9427,6 +9793,8 @@ snapshots: mime-db: 1.54.0 outvariant: 1.4.0 + stdin-discarder@0.2.2: {} + strict-event-emitter@0.4.6: {} string-width@4.2.3: @@ -9441,6 +9809,12 @@ snapshots: emoji-regex: 9.2.2 strip-ansi: 7.1.0 + string-width@7.2.0: + dependencies: + emoji-regex: 10.4.0 + get-east-asian-width: 1.5.0 + strip-ansi: 7.1.0 + string_decoder@1.3.0: dependencies: safe-buffer: 5.2.1 @@ -9609,6 +9983,8 @@ snapshots: undici-types@6.20.0: {} + undici-types@6.21.0: {} + unicode-properties@1.4.1: dependencies: base64-js: 1.5.1 @@ -9660,6 +10036,12 @@ snapshots: unist-util-is: 6.0.0 unist-util-visit-parents: 6.0.1 + unplugin@2.1.0: + dependencies: + acorn: 8.14.1 + webpack-virtual-modules: 0.6.2 + optional: true + unraw@3.0.0: {} update-browserslist-db@1.1.3(browserslist@4.24.4): @@ -9789,6 +10171,9 @@ snapshots: webidl-conversions@4.0.2: {} + webpack-virtual-modules@0.6.2: + optional: true + whatwg-url@7.1.0: dependencies: lodash.sortby: 4.7.0 diff --git a/echo/frontend/src/App.tsx b/echo/frontend/src/App.tsx index 3ca64694..0fb5e7ea 100644 --- a/echo/frontend/src/App.tsx +++ b/echo/frontend/src/App.tsx @@ -1,8 +1,10 @@ import "@fontsource-variable/space-grotesk"; import "@mantine/core/styles.css"; +import "@mantine/dates/styles.css"; import "@mantine/dropzone/styles.css"; import { MantineProvider } from "@mantine/core"; +import { DatesProvider } from "@mantine/dates"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; import { useEffect } from "react"; @@ -81,13 +83,15 @@ export const App = () => { {/* */} - - - - - - - + + + + + + + + + ); diff --git a/echo/frontend/src/components/announcement/AnnouncementDrawerHeader.tsx b/echo/frontend/src/components/announcement/AnnouncementDrawerHeader.tsx index 59863527..0faa6d0d 100644 --- a/echo/frontend/src/components/announcement/AnnouncementDrawerHeader.tsx +++ b/echo/frontend/src/components/announcement/AnnouncementDrawerHeader.tsx @@ -1,7 +1,7 @@ import { t } from "@lingui/core/macro"; import { Trans } from "@lingui/react/macro"; import { ActionIcon, Button, Group, Stack, Text } from "@mantine/core"; -import { IconX } from "@tabler/icons-react"; +import { X } from "@phosphor-icons/react"; import { testId } from "@/lib/testUtils"; import { useUnreadAnnouncements } from "./hooks"; @@ -30,7 +30,7 @@ export const AnnouncementDrawerHeader = ({ className="focus:outline-none" {...testId("announcement-close-drawer-button")} > - + diff --git a/echo/frontend/src/components/announcement/AnnouncementIcon.tsx b/echo/frontend/src/components/announcement/AnnouncementIcon.tsx index dc0a9844..409166b2 100644 --- a/echo/frontend/src/components/announcement/AnnouncementIcon.tsx +++ b/echo/frontend/src/components/announcement/AnnouncementIcon.tsx @@ -1,8 +1,7 @@ -import { ActionIcon, Box, Group, Indicator, Loader } from "@mantine/core"; +import { ActionIcon, Box, Group, Indicator, Loader, Text } from "@mantine/core"; import { FlagBannerIcon } from "@phosphor-icons/react"; import { useAnnouncementDrawer } from "@/components/announcement/hooks"; import { getTranslatedContent } from "@/components/announcement/hooks/useProcessedAnnouncements"; -import { Markdown } from "@/components/common/Markdown"; import { useLanguage } from "@/hooks/useLanguage"; import { testId } from "@/lib/testUtils"; import { useLatestAnnouncement, useUnreadAnnouncements } from "./hooks"; @@ -15,20 +14,18 @@ export const AnnouncementIcon = () => { const { data: unreadCount, isLoading: isLoadingUnread } = useUnreadAnnouncements(); - // Get latest urgent announcement message - const message = latestAnnouncement - ? getTranslatedContent(latestAnnouncement as Announcement, language).message + const title = latestAnnouncement + ? getTranslatedContent(latestAnnouncement as Announcement, language).title : ""; - // Check if the latest announcement is unread const isUnread = latestAnnouncement ? !latestAnnouncement.activity?.some( (activity: AnnouncementActivity) => activity.read === true, ) : false; - const showMessage = - isUnread && message && latestAnnouncement?.level === "info"; + const showPreview = + isUnread && title && latestAnnouncement?.level === "info"; const isLoading = isLoadingLatest || isLoadingUnread; @@ -69,13 +66,15 @@ export const AnnouncementIcon = () => { - {showMessage && ( + {showPreview && ( - + + {title} + )} diff --git a/echo/frontend/src/components/announcement/AnnouncementItem.tsx b/echo/frontend/src/components/announcement/AnnouncementItem.tsx index 1a1761d1..d838b4cb 100644 --- a/echo/frontend/src/components/announcement/AnnouncementItem.tsx +++ b/echo/frontend/src/components/announcement/AnnouncementItem.tsx @@ -9,11 +9,11 @@ import { useMantineTheme, } from "@mantine/core"; import { - IconAlertTriangle, - IconChevronDown, - IconChevronUp, - IconInfoCircle, -} from "@tabler/icons-react"; + CaretDown, + CaretUp, + Info, + WarningCircle, +} from "@phosphor-icons/react"; import { forwardRef, useEffect, useRef, useState } from "react"; import { Markdown } from "@/components/common/Markdown"; import { testId } from "@/lib/testUtils"; @@ -31,14 +31,13 @@ type Announcement = { interface AnnouncementItemProps { announcement: Announcement; - onMarkAsRead: (id: string) => void; index: number; } export const AnnouncementItem = forwardRef< HTMLDivElement, AnnouncementItemProps ->(({ announcement, onMarkAsRead, index }, ref) => { +>(({ announcement, index }, ref) => { const theme = useMantineTheme(); const [showMore, setShowMore] = useState(false); const [showReadMoreButton, setShowReadMoreButton] = useState(false); @@ -65,24 +64,24 @@ export const AnnouncementItem = forwardRef< > - { - - {announcement.level === "urgent" ? ( - - ) : ( - - )} - - } + + {announcement.level === "urgent" ? ( + + ) : ( + + )} +
- + + {announcement.title} +
@@ -90,7 +89,6 @@ export const AnnouncementItem = forwardRef< {formatDate(announcement.created_at)} - {/* this part needs a second look */} {!announcement.read && (
)} - {/* this part needs a second look */} @@ -113,8 +110,8 @@ export const AnnouncementItem = forwardRef< /> - - {showReadMoreButton && ( + {showReadMoreButton && ( + - )} - - - {!announcement.read && ( - - )} - - + + )} diff --git a/echo/frontend/src/components/announcement/Announcements.tsx b/echo/frontend/src/components/announcement/Announcements.tsx index 3a76a2c1..13e2b1e3 100644 --- a/echo/frontend/src/components/announcement/Announcements.tsx +++ b/echo/frontend/src/components/announcement/Announcements.tsx @@ -1,9 +1,25 @@ import { Trans } from "@lingui/react/macro"; -import { Box, Center, Loader, ScrollArea, Stack, Text } from "@mantine/core"; -import { useEffect, useState } from "react"; +import { + Box, + Center, + Collapse, + Divider, + Group, + Loader, + ScrollArea, + Stack, + Text, + ThemeIcon, + UnstyledButton, +} from "@mantine/core"; +import { CaretDown, CaretUp, Sparkle } from "@phosphor-icons/react"; +import { useEffect, useRef, useState } from "react"; import { useInView } from "react-intersection-observer"; import { useAnnouncementDrawer } from "@/components/announcement/hooks"; -import { useProcessedAnnouncements } from "@/components/announcement/hooks/useProcessedAnnouncements"; +import { + useProcessedAnnouncements, + useWhatsNewProcessed, +} from "@/components/announcement/hooks/useProcessedAnnouncements"; import { useLanguage } from "@/hooks/useLanguage"; import { analytics } from "@/lib/analytics"; import { AnalyticsEvents as events } from "@/lib/analyticsEvents"; @@ -13,18 +29,20 @@ import { AnnouncementDrawerHeader } from "./AnnouncementDrawerHeader"; import { AnnouncementErrorState } from "./AnnouncementErrorState"; import { AnnouncementItem } from "./AnnouncementItem"; import { AnnouncementSkeleton } from "./AnnouncementSkeleton"; +import { WhatsNewItem } from "./WhatsNewItem"; import { useInfiniteAnnouncements, useMarkAllAsReadMutation, - useMarkAsReadMutation, + useWhatsNewAnnouncements, } from "./hooks"; export const Announcements = () => { const { isOpen, close } = useAnnouncementDrawer(); const { language } = useLanguage(); - const markAsReadMutation = useMarkAsReadMutation(); const markAllAsReadMutation = useMarkAllAsReadMutation(); const [openedOnce, setOpenedOnce] = useState(false); + const [whatsNewExpanded, setWhatsNewExpanded] = useState(false); + const autoReadTimerRef = useRef | null>(null); const { ref: loadMoreRef, inView } = useInView(); @@ -40,6 +58,24 @@ export const Announcements = () => { } }, [isOpen, openedOnce]); + // Auto-mark all as read after 1 second when drawer opens + useEffect(() => { + if (isOpen) { + autoReadTimerRef.current = setTimeout(() => { + markAllAsReadMutation.mutate(); + }, 1000); + } + + return () => { + if (autoReadTimerRef.current) { + clearTimeout(autoReadTimerRef.current); + autoReadTimerRef.current = null; + } + }; + // Only trigger on isOpen changes, not on mutation reference changes + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isOpen]); + const { data: announcementsData, fetchNextPage, @@ -55,7 +91,11 @@ export const Announcements = () => { }, }); - // Flatten all announcements from all pages, with type safety + const { data: whatsNewData } = useWhatsNewAnnouncements({ + enabled: openedOnce, + }); + + // Flatten all announcements from all pages const allAnnouncements = announcementsData?.pages.flatMap( (page) => (page as { announcements: Announcement[] }).announcements, @@ -67,6 +107,15 @@ export const Announcements = () => { language, ); + // Only show unread announcements (read ones are hidden) + const unreadAnnouncements = processedAnnouncements.filter((a) => !a.read); + + // Process "What's new" announcements + const whatsNewAnnouncements = useWhatsNewProcessed( + whatsNewData ?? [], + language, + ); + // Load more announcements when user scrolls to bottom useEffect(() => { if (inView && hasNextPage && !isFetchingNextPage) { @@ -74,12 +123,6 @@ export const Announcements = () => { } }, [inView, hasNextPage, isFetchingNextPage, fetchNextPage]); - const handleMarkAsRead = async (id: string) => { - markAsReadMutation.mutate({ - announcementId: id, - }); - }; - const handleMarkAllAsRead = async () => { markAllAsReadMutation.mutate(); }; @@ -124,7 +167,8 @@ export const Announcements = () => { /> ) : isLoading ? ( - ) : processedAnnouncements.length === 0 ? ( + ) : unreadAnnouncements.length === 0 && + whatsNewAnnouncements.length === 0 ? ( No announcements available @@ -132,24 +176,74 @@ export const Announcements = () => { ) : ( <> - {processedAnnouncements.map((announcement, index) => ( + {/* Unread announcements */} + {unreadAnnouncements.map((announcement, index) => ( ))} + {isFetchingNextPage && (
)} + + {/* Release notes under "View earlier" */} + {whatsNewAnnouncements.length > 0 && ( + <> + + setWhatsNewExpanded(!whatsNewExpanded) + } + > + + + + Release notes + + {whatsNewExpanded ? ( + + ) : ( + + )} + + + } + labelPosition="left" + /> + + + + {whatsNewAnnouncements.map((announcement) => ( + + ))} + + + + )} )} diff --git a/echo/frontend/src/components/announcement/TopAnnouncementBar.tsx b/echo/frontend/src/components/announcement/TopAnnouncementBar.tsx index d7ab3b27..d6c5675d 100644 --- a/echo/frontend/src/components/announcement/TopAnnouncementBar.tsx +++ b/echo/frontend/src/components/announcement/TopAnnouncementBar.tsx @@ -2,27 +2,23 @@ import { ActionIcon, Box, Group, + Text, ThemeIcon, - useMantineTheme, } from "@mantine/core"; -import { IconAlertTriangle, IconX } from "@tabler/icons-react"; +import { WarningCircle, X } from "@phosphor-icons/react"; import { useEffect, useState } from "react"; import { useAnnouncementDrawer } from "@/components/announcement/hooks"; import { getTranslatedContent } from "@/components/announcement/hooks/useProcessedAnnouncements"; -import { Markdown } from "@/components/common/Markdown"; import { useLanguage } from "@/hooks/useLanguage"; import { useLatestAnnouncement, useMarkAsReadMutation } from "./hooks"; export function TopAnnouncementBar() { - const theme = useMantineTheme(); const { data: announcement, isLoading } = useLatestAnnouncement(); const markAsReadMutation = useMarkAsReadMutation(); const [isClosed, setIsClosed] = useState(false); const { open } = useAnnouncementDrawer(); const { language } = useLanguage(); - // Check if the announcement has been read by the current user - // Directus already filters activity data for the current user const isRead = announcement?.activity?.some( (activity: AnnouncementActivity) => activity.read === true, ); @@ -51,7 +47,6 @@ export function TopAnnouncementBar() { ); }, [isLoading, announcement, isClosed, isRead]); - // Only show if we have an urgent announcement, it's not closed, and it's not read if ( isLoading || !announcement || @@ -71,7 +66,6 @@ export function TopAnnouncementBar() { e.stopPropagation(); setIsClosed(true); - // Mark announcement as read if (announcement.id) { markAsReadMutation.mutate({ announcementId: announcement.id, @@ -83,10 +77,15 @@ export function TopAnnouncementBar() { open(); }; + const bgColor = + announcement.level === "urgent" + ? "rgba(255, 209, 102, 0.15)" + : "var(--mantine-color-blue-0)"; + return ( @@ -96,9 +95,11 @@ export function TopAnnouncementBar() { color={announcement.level === "urgent" ? "orange" : "blue"} radius="xl" > - + - + + {title} + - + ); diff --git a/echo/frontend/src/components/announcement/WhatsNewItem.tsx b/echo/frontend/src/components/announcement/WhatsNewItem.tsx new file mode 100644 index 00000000..a6ecf3c8 --- /dev/null +++ b/echo/frontend/src/components/announcement/WhatsNewItem.tsx @@ -0,0 +1,67 @@ +import { + Box, + Collapse, + Group, + Stack, + Text, + ThemeIcon, + UnstyledButton, +} from "@mantine/core"; +import { CaretDown, CaretRight, Sparkle } from "@phosphor-icons/react"; +import { useState } from "react"; +import { Markdown } from "@/components/common/Markdown"; +import { testId } from "@/lib/testUtils"; +import type { ProcessedAnnouncement } from "./hooks/useProcessedAnnouncements"; +import { useFormatDate } from "./utils/dateUtils"; + +interface WhatsNewItemProps { + announcement: ProcessedAnnouncement; +} + +export const WhatsNewItem = ({ announcement }: WhatsNewItemProps) => { + const [expanded, setExpanded] = useState(false); + const formatDate = useFormatDate(); + + return ( + + setExpanded(!expanded)} + w="100%" + > + + {expanded ? ( + + ) : ( + + )} + + + + + {announcement.title} + + + {formatDate(announcement.created_at)} + + + + + + + + + + + ); +}; diff --git a/echo/frontend/src/components/announcement/hooks/index.ts b/echo/frontend/src/components/announcement/hooks/index.ts index 81f31eac..d73b5826 100644 --- a/echo/frontend/src/components/announcement/hooks/index.ts +++ b/echo/frontend/src/components/announcement/hooks/index.ts @@ -1,4 +1,4 @@ -import { aggregate, createItems, type Query, readItems } from "@directus/sdk"; +import { createItems, type Query, readItems } from "@directus/sdk"; import { t } from "@lingui/core/macro"; import * as Sentry from "@sentry/react"; import { @@ -420,64 +420,108 @@ export const useUnreadAnnouncements = () => { const { data: currentUser } = useCurrentUser(); return useQuery({ - enabled: !!currentUser?.id, // Only run query if user is logged in + enabled: !!currentUser?.id, queryFn: async () => { try { - // If no user is logged in, return 0 if (!currentUser?.id) { return 0; } const unreadAnnouncements = await directus.request( - aggregate("announcement", { - aggregate: { count: "*" }, - query: { - filter: { - _or: [ - { - expires_at: { - _gte: new Date().toISOString(), + readItems("announcement", { + fields: ["id"], + filter: { + _and: [ + { + activity: { + _none: { + user_id: { + _eq: currentUser.id, + }, }, }, - { - expires_at: { - _null: true, + }, + { + _or: [ + { + expires_at: { + _gte: new Date().toISOString(), + }, }, - }, - ], - }, + { + expires_at: { + _null: true, + }, + }, + ], + }, + ], }, }), ); - const activities = await directus.request( - aggregate("announcement_activity", { - aggregate: { count: "*" }, - query: { - filter: { - _and: [ - { - user_id: { _eq: currentUser.id }, + return unreadAnnouncements.length; + } catch (error) { + Sentry.captureException(error); + console.error("Error fetching unread announcements count:", error); + throw error; + } + }, + queryKey: ["announcements", "unread", currentUser?.id], + retry: 2, + staleTime: 1000 * 60 * 5, // 5 minutes + }); +}; + +export const useWhatsNewAnnouncements = ({ + enabled = true, +}: { + enabled?: boolean; +} = {}) => { + const { data: currentUser } = useCurrentUser(); + + return useQuery({ + enabled, + queryFn: async () => { + try { + const response: Announcement[] = await directus.request( + readItems("announcement", { + deep: { + activity: { + _filter: { + user_id: { + _eq: currentUser?.id, }, - ], + }, }, }, + fields: [ + "id", + "created_at", + "expires_at", + "level", + { + translations: ["id", "languages_code", "title", "message"], + }, + { + activity: ["id", "user_id", "announcement_activity", "read"], + }, + ], + sort: ["-created_at"], + limit: 50, }), ); - const count = - Number.parseInt(unreadAnnouncements?.[0]?.count?.toString() ?? "0") - - Number.parseInt(activities?.[0]?.count?.toString() ?? "0"); - return Math.max(0, count); + return response; } catch (error) { Sentry.captureException(error); - console.error("Error fetching unread announcements count:", error); + console.error("Error fetching what's new announcements:", error); throw error; } }, - queryKey: ["announcements", "unread", currentUser?.id], + queryKey: ["announcements", "whats-new"], retry: 2, - staleTime: 1000 * 60 * 5, // 5 minutes + staleTime: 1000 * 60 * 5, }); }; diff --git a/echo/frontend/src/components/announcement/hooks/useProcessedAnnouncements.ts b/echo/frontend/src/components/announcement/hooks/useProcessedAnnouncements.ts index 716c9c86..60708920 100644 --- a/echo/frontend/src/components/announcement/hooks/useProcessedAnnouncements.ts +++ b/echo/frontend/src/components/announcement/hooks/useProcessedAnnouncements.ts @@ -20,25 +20,73 @@ export const getTranslatedContent = ( }; }; -// @FIXME: this doesn't need to be a hook, it can be a simple function, memo for a .find is overkill +export const isWhatsNew = (announcement: Announcement): boolean => { + const enTranslation = announcement.translations?.find( + (t) => (t as AnnouncementTranslation).languages_code === "en-US", + ); + const title = + (enTranslation as AnnouncementTranslation)?.title?.toLowerCase() || ""; + return title.includes("new features") || title.startsWith("new:"); +}; + +export interface ProcessedAnnouncement { + id: string; + created_at: string | Date | null | undefined; + expires_at?: string | Date | null | undefined; + level: "info" | "urgent"; + title: string; + message: string; + read: boolean; +} + +function processAnnouncement( + announcement: Announcement, + language: string, +): ProcessedAnnouncement { + const { title, message } = getTranslatedContent(announcement, language); + return { + created_at: announcement.created_at, + expires_at: announcement.expires_at, + id: announcement.id, + level: announcement.level as "info" | "urgent", + message, + read: + (announcement.activity?.[0] as AnnouncementActivity)?.read || false, + title, + }; +} + +function sortByDateDesc(a: ProcessedAnnouncement, b: ProcessedAnnouncement) { + const dateA = a.created_at ? new Date(a.created_at).getTime() : 0; + const dateB = b.created_at ? new Date(b.created_at).getTime() : 0; + return dateB - dateA; +} + export function useProcessedAnnouncements( announcements: Announcement[], language: string, ) { return useMemo(() => { - return announcements.map((announcement) => { - const { title, message } = getTranslatedContent(announcement, language); - - return { - created_at: announcement.created_at, - expires_at: announcement.expires_at, - id: announcement.id, - level: announcement.level as "info" | "urgent", - message, - read: - (announcement.activity?.[0] as AnnouncementActivity)?.read || false, - title, - }; + const processed = announcements + .filter((a) => !isWhatsNew(a)) + .map((a) => processAnnouncement(a, language)); + + // Sort: unread first, then by date descending + return processed.sort((a, b) => { + if (a.read !== b.read) return a.read ? 1 : -1; + return sortByDateDesc(a, b); }); }, [announcements, language]); } + +export function useWhatsNewProcessed( + announcements: Announcement[], + language: string, +) { + return useMemo(() => { + return announcements + .filter((a) => isWhatsNew(a)) + .map((a) => processAnnouncement(a, language)) + .sort(sortByDateDesc); + }, [announcements, language]); +} diff --git a/echo/frontend/src/components/auth/hooks/index.ts b/echo/frontend/src/components/auth/hooks/index.ts index c15e19c4..bf6a2b4c 100644 --- a/echo/frontend/src/components/auth/hooks/index.ts +++ b/echo/frontend/src/components/auth/hooks/index.ts @@ -1,7 +1,6 @@ import { passwordRequest, passwordReset, - readUser, registerUser, registerUserVerify, } from "@directus/sdk"; @@ -9,7 +8,7 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { useEffect, useRef } from "react"; import { useLocation, useSearchParams } from "react-router"; import { toast } from "@/components/common/Toaster"; -import { ADMIN_BASE_URL } from "@/config"; +import { ADMIN_BASE_URL, API_BASE_URL } from "@/config"; import { useI18nNavigate } from "@/hooks/useI18nNavigate"; import { directus } from "@/lib/directus"; import { throwWithMessage } from "../utils/errorUtils"; @@ -21,22 +20,14 @@ export const useCurrentUser = ({ } = {}) => useQuery({ enabled, - queryFn: () => { + queryFn: async () => { try { - return directus.request( - readUser("me", { - fields: [ - "id", - "first_name", - "email", - "disable_create_project", - "tfa_secret", - "whitelabel_logo", - "legal_basis", - "privacy_policy_url", - ], - }), + const response = await fetch( + `${API_BASE_URL}/user-settings/me`, + { credentials: "include" }, ); + if (!response.ok) return null; + return response.json(); } catch (_error) { return null; } diff --git a/echo/frontend/src/components/chat/AgenticChatPanel.tsx b/echo/frontend/src/components/chat/AgenticChatPanel.tsx index 85b32adf..a3dd8bff 100644 --- a/echo/frontend/src/components/chat/AgenticChatPanel.tsx +++ b/echo/frontend/src/components/chat/AgenticChatPanel.tsx @@ -1,19 +1,34 @@ import { t } from "@lingui/core/macro"; import { Trans } from "@lingui/react/macro"; import { + ActionIcon, Alert, Box, Button, + Collapse, Divider, Group, Loader, + Paper, + Skeleton, Stack, Text, Textarea, Title, + Tooltip, } from "@mantine/core"; -import { IconAlertCircle, IconPlayerStop, IconSend } from "@tabler/icons-react"; +import { ErrorBoundary } from "@sentry/react"; +import { + IconAlertCircle, + IconBraces, + IconPlayerStop, + IconSend, +} from "@tabler/icons-react"; +import { useQueryClient } from "@tanstack/react-query"; +import { formatDate } from "date-fns"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { useElementOnScreen } from "@/hooks/useElementOnScreen"; +import { useLanguage } from "@/hooks/useLanguage"; import type { AgenticRunEvent, AgenticRunEventsResponse, @@ -27,14 +42,19 @@ import { stopAgenticRun, streamAgenticRun, } from "@/lib/api"; -import { Markdown } from "../common/Markdown"; +import { testId } from "@/lib/testUtils"; +import { CopyRichTextIconButton } from "../common/CopyRichTextIconButton"; +import { ScrollToBottomButton } from "../common/ScrollToBottom"; import { toast } from "../common/Toaster"; import { extractTopLevelToolActivity, type ToolActivity, } from "./agenticToolActivity"; -import { ChatMessage } from "./ChatMessage"; +import { ChatAccordionItemMenu, ChatModeIndicator } from "./ChatAccordion"; +import { ChatHistoryMessage } from "./ChatHistoryMessage"; import { ChatTemplatesMenu } from "./ChatTemplatesMenu"; +import { formatMessage } from "./chatUtils"; +import { useChat as useProjectChat } from "./hooks"; type AgenticChatPanelProps = { chatId: string; @@ -43,8 +63,10 @@ type AgenticChatPanelProps = { type RenderMessage = { id: string; - role: "user" | "assistant" | "dembrane"; + role: "user" | "assistant"; content: string; + timestamp: string; + sortSeq: number; }; type TimelineItem = @@ -55,6 +77,10 @@ type TimelineItem = kind: "tool"; }); +type HistoryLikeMessage = ChatHistory[number] & { + createdAt: string; +}; + const storageKeyForChat = (chatId: string) => `agentic-run:${chatId}`; const isTerminalStatus = (status: AgenticRunStatus | null) => @@ -69,7 +95,58 @@ const asObject = (value: unknown): Record | null => { return null; }; -const toMessage = (event: AgenticRunEvent): RenderMessage | null => { +const AGENTIC_REFERENCE_PATTERN = + /\[conversation_id:([^;\]\s]+)(?:;chunk_id:([^\]\s]+))?\]/g; + +const buildTranscriptLink = ({ + chunkId, + conversationId, + language, + projectId, +}: { + chunkId?: string; + conversationId: string; + language: string; + projectId: string; +}) => { + const encodedConversationId = encodeURIComponent(conversationId); + const hash = chunkId ? `#chunk-${encodeURIComponent(chunkId)}` : ""; + return `/${language}/projects/${projectId}/conversation/${encodedConversationId}/transcript${hash}`; +}; + +const enrichAgenticContent = ({ + content, + language, + projectId, +}: { + content: string; + language: string; + projectId: string; +}) => + content.replace( + AGENTIC_REFERENCE_PATTERN, + (_match, conversationIdRaw: string, chunkIdRaw?: string) => { + const conversationId = conversationIdRaw.trim(); + const chunkId = chunkIdRaw?.trim(); + const label = chunkId ? t`transcript excerpt` : t`transcript`; + return `[${label}](${buildTranscriptLink({ + chunkId, + conversationId, + language, + projectId, + })})`; + }, + ); + +const toMessage = ({ + event, + language, + projectId, +}: { + event: AgenticRunEvent; + language: string; + projectId: string; +}): RenderMessage | null => { const payload = asObject(event.payload); const content = @@ -84,18 +161,36 @@ const toMessage = (event: AgenticRunEvent): RenderMessage | null => { } if (event.event_type === "user.message" && content) { - return { content, id: `u-${event.seq}`, role: "user" }; + return { + content: enrichAgenticContent({ content, language, projectId }), + id: `u-${event.seq}`, + role: "user", + sortSeq: event.seq, + timestamp: event.timestamp, + }; } if (event.event_type === "assistant.message" && content) { - return { content, id: `a-${event.seq}`, role: "assistant" }; + return { + content: enrichAgenticContent({ content, language, projectId }), + id: `a-${event.seq}`, + role: "assistant", + sortSeq: event.seq, + timestamp: event.timestamp, + }; } if (event.event_type === "run.failed" || event.event_type === "run.timeout") { return { - content: content ?? "Agent run failed", - id: `s-${event.seq}`, - role: "dembrane", + content: enrichAgenticContent({ + content: content ?? t`Agent run failed`, + language, + projectId, + }), + id: `a-${event.seq}`, + role: "assistant", + sortSeq: event.seq, + timestamp: event.timestamp, }; } @@ -113,11 +208,13 @@ const toMessage = (event: AgenticRunEvent): RenderMessage | null => { ? nestedError.message : typeof data?.message === "string" ? data.message - : "Agent run failed"; + : t`Agent run failed`; return { content: errorMessage, id: `e-${event.seq}`, - role: "dembrane", + role: "assistant", + sortSeq: event.seq, + timestamp: event.timestamp, }; } @@ -126,26 +223,54 @@ const toMessage = (event: AgenticRunEvent): RenderMessage | null => { const TOOL_STATUS_META: Record< ToolActivity["status"], - { badgeClass: string; label: string } + { dotClass: string; label: string; textClass: string } > = { completed: { - badgeClass: "border-emerald-300 bg-emerald-100 text-emerald-800", - label: "✓", + dotClass: "bg-emerald-500", + label: t`Done`, + textClass: "text-emerald-700", }, error: { - badgeClass: "border-red-300 bg-red-100 text-red-800", - label: "Error", + dotClass: "bg-red-500", + label: t`Error`, + textClass: "text-red-700", }, running: { - badgeClass: "border-amber-300 bg-amber-100 text-amber-800", - label: "Running", + dotClass: "bg-amber-500", + label: t`Running`, + textClass: "text-amber-700", }, }; +const toHistoryMessage = (message: RenderMessage): HistoryLikeMessage => + ({ + _original: { + added_conversations: [], + chat_message_metadata: [], + date_created: message.timestamp, + date_updated: message.timestamp, + id: message.id, + message_from: message.role === "user" ? "User" : "assistant", + project_chat_id: null, + template_key: null, + text: message.content, + tokens_count: null, + used_conversations: [], + } as ProjectChatMessage, + content: message.content, + createdAt: message.timestamp, + id: message.id, + metadata: [], + role: message.role, + }) as HistoryLikeMessage; + export const AgenticChatPanel = ({ chatId, projectId, }: AgenticChatPanelProps) => { + const { iso639_1, language } = useLanguage(); + const queryClient = useQueryClient(); + const chatQuery = useProjectChat(chatId); const [runId, setRunId] = useState(null); const [runStatus, setRunStatus] = useState(null); const [afterSeq, setAfterSeq] = useState(0); @@ -155,43 +280,64 @@ export const AgenticChatPanel = ({ const [isSubmitting, setIsSubmitting] = useState(false); const [isStopping, setIsStopping] = useState(false); const [isStreaming, setIsStreaming] = useState(false); + const [isHydratingStoredRun, setIsHydratingStoredRun] = useState(false); const [streamFailureCount, setStreamFailureCount] = useState(0); const [error, setError] = useState(null); + const [expandedToolIds, setExpandedToolIds] = useState< + Record + >({}); const streamAbortRef = useRef(null); + const [scrollTargetRef, isVisible] = useElementOnScreen({ + root: null, + rootMargin: "-83px", + threshold: 0.1, + }); const timeline = useMemo(() => { const sorted = [...events].sort((a, b) => a.seq - b.seq); - const byId = new Map(); - const orderedIds: string[] = []; - - const upsertItem = (item: TimelineItem) => { - if (!byId.has(item.id)) { - orderedIds.push(item.id); - } - byId.set(item.id, item); - }; + const items: TimelineItem[] = []; for (const event of sorted) { - const topLevelMessage = toMessage(event); + const topLevelMessage = toMessage({ + event, + language, + projectId, + }); if (topLevelMessage) { - upsertItem({ + items.push({ ...topLevelMessage, kind: "message", }); } + } - for (const activity of extractTopLevelToolActivity(event)) { - upsertItem({ - ...activity, - kind: "tool", - }); - } + for (const activity of extractTopLevelToolActivity(sorted)) { + items.push({ + ...activity, + kind: "tool", + }); } - return orderedIds - .map((id) => byId.get(id)) - .filter((item): item is TimelineItem => item !== undefined); - }, [events]); + return items.sort((left, right) => left.sortSeq - right.sortSeq); + }, [events, language, projectId]); + + const historyMessages = useMemo( + () => + timeline + .filter( + (item): item is Extract => + item.kind === "message", + ) + .map(toHistoryMessage), + [timeline], + ); + + const computedChatForCopy = useMemo(() => { + const messagesList = historyMessages.map((message) => + formatMessage(message, "User", "Dembrane"), + ); + return messagesList.join("\n\n\n\n"); + }, [historyMessages]); const mergeEvents = useCallback((incoming: AgenticRunEvent[]) => { if (incoming.length === 0) return; @@ -217,6 +363,54 @@ export const AgenticChatPanel = ({ [mergeEvents], ); + const loadAllEvents = useCallback( + async ( + targetRunId: string, + fromSeq: number, + ): Promise => { + const collected: AgenticRunEvent[] = []; + let cursor = fromSeq; + let latestPayload: AgenticRunEventsResponse | null = null; + + for (let page = 0; page < 100; page += 1) { + const payload = await getAgenticRunEvents(targetRunId, cursor); + latestPayload = payload; + + if (payload.events.length === 0) { + break; + } + + collected.push(...payload.events); + + const lastEventSeq = + payload.events[payload.events.length - 1]?.seq ?? cursor; + const nextCursor = Math.max(cursor, payload.next_seq, lastEventSeq); + if (nextCursor <= cursor) { + break; + } + cursor = nextCursor; + } + + if (!latestPayload) { + const payload = await getAgenticRunEvents(targetRunId, fromSeq); + mergeEvents(payload.events); + setAfterSeq(payload.next_seq); + setRunStatus(payload.status); + return payload; + } + + mergeEvents(collected); + setAfterSeq(cursor); + setRunStatus(latestPayload.status); + return { + ...latestPayload, + events: collected, + next_seq: cursor, + }; + }, + [mergeEvents], + ); + const stopStream = useCallback(() => { if (streamAbortRef.current) { streamAbortRef.current.abort(); @@ -257,7 +451,7 @@ export const AgenticChatPanel = ({ setStreamFailureCount((count) => { const next = count + 1; if (next >= 2) { - setError("Live stream interrupted. Falling back to polling."); + setError(t`Live stream interrupted. Falling back to polling.`); } return next; }); @@ -281,7 +475,7 @@ export const AgenticChatPanel = ({ [mergeEvents, stopStream], ); - // biome-ignore lint/correctness/useExhaustiveDependencies: Reset panel state whenever chatId changes. + // biome-ignore lint/correctness/useExhaustiveDependencies: reset panel state whenever chatId changes. useEffect(() => { stopStream(); setRunId(null); @@ -292,7 +486,9 @@ export const AgenticChatPanel = ({ setTemplateKey(null); setIsStopping(false); setIsSubmitting(false); + setIsHydratingStoredRun(false); setStreamFailureCount(0); + setExpandedToolIds({}); }, [chatId, stopStream]); useEffect(() => { @@ -302,26 +498,31 @@ export const AgenticChatPanel = ({ if (!storedRunId) return; let active = true; + setIsHydratingStoredRun(true); (async () => { try { const run = await getAgenticRun(storedRunId); if (!active) return; setRunId(storedRunId); setRunStatus(run.status); - const payload = await refreshEvents(storedRunId, 0); + const payload = await loadAllEvents(storedRunId, 0); if (!active) return; if (!isTerminalStatus(payload.status)) { void startStream(storedRunId, payload.next_seq); } } catch { window.localStorage.removeItem(key); + } finally { + if (active) { + setIsHydratingStoredRun(false); + } } })(); return () => { active = false; }; - }, [chatId, refreshEvents, startStream]); + }, [chatId, loadAllEvents, startStream]); useEffect(() => { if (!runId || !runStatus || isTerminalStatus(runStatus)) return; @@ -356,12 +557,38 @@ export const AgenticChatPanel = ({ } }, [runStatus, stopStream]); + const scrollToBottom = useCallback( + (behavior: ScrollBehavior = "smooth") => { + window.requestAnimationFrame(() => { + scrollTargetRef.current?.scrollIntoView({ + behavior, + block: "end", + }); + }); + }, + [scrollTargetRef], + ); + + useEffect(() => { + if (timeline.length === 0) return; + scrollToBottom("smooth"); + }, [timeline.length, scrollToBottom]); + useEffect(() => { return () => { stopStream(); }; }, [stopStream]); + const invalidateChatQueries = useCallback(() => { + void queryClient.invalidateQueries({ + queryKey: ["chats", chatId], + }); + void queryClient.invalidateQueries({ + queryKey: ["projects", projectId, "chats"], + }); + }, [chatId, projectId, queryClient]); + const handleTemplateSelect = ({ content, key, @@ -406,9 +633,11 @@ export const AgenticChatPanel = ({ try { let targetRunId = runId; + const nextLanguage = iso639_1 ?? "en"; if (!targetRunId) { const created = await createAgenticRun({ + language: nextLanguage, message, project_chat_id: chatId, project_id: projectId, @@ -417,24 +646,29 @@ export const AgenticChatPanel = ({ setRunId(targetRunId); setRunStatus(created.status); window.localStorage.setItem(storageKeyForChat(chatId), targetRunId); + invalidateChatQueries(); const payload = await refreshEvents(targetRunId, 0); if (!isTerminalStatus(payload.status)) { void startStream(targetRunId, payload.next_seq); } } else { - const updated = await appendAgenticRunMessage(targetRunId, message); + const updated = await appendAgenticRunMessage(targetRunId, { + language: nextLanguage, + message, + }); setRunStatus(updated.status); + invalidateChatQueries(); const payload = await refreshEvents(targetRunId, afterSeq); if (!isTerminalStatus(payload.status)) { void startStream(targetRunId, payload.next_seq); } } } catch (submitError) { - const message = + const nextError = submitError instanceof Error ? submitError.message - : "Failed to submit agentic message"; - setError(message); + : t`Failed to submit agentic message`; + setError(nextError); } finally { setIsSubmitting(false); } @@ -447,53 +681,90 @@ export const AgenticChatPanel = ({ try { await stopAgenticRun(runId); } catch (stopError) { - const message = - stopError instanceof Error ? stopError.message : "Failed to stop run"; - setError(message); + const nextError = + stopError instanceof Error ? stopError.message : t`Failed to stop run`; + setError(nextError); } finally { setIsStopping(false); } }; const isRunInFlight = isInFlightStatus(runStatus); + const chatTitle = chatQuery.data?.name ?? t`Chat`; + const liveToolActivity = useMemo( + () => + [...timeline] + .reverse() + .find( + (item): item is Extract => + item.kind === "tool" && item.status === "running", + ), + [timeline], + ); + const liveRunStatusText = + liveToolActivity?.headline ?? t`Agent is working...`; + const showExistingChatLoading = isHydratingStoredRun && timeline.length === 0; + const toggleToolDetails = useCallback((toolId: string) => { + setExpandedToolIds((previous) => ({ + ...previous, + [toolId]: !previous[toolId], + })); + }, []); return ( - + - - - <Trans>Agentic Chat</Trans> - + + + + {chatTitle} + + + + + + + {chatQuery.data && ( + + )} + + + + {runStatus && ( Run status: {runStatus} )} - {isRunInFlight && ( - - )} + {isRunInFlight && ( + + )} - - + + {error && ( )} - - - {timeline.length === 0 && ( + {showExistingChatLoading && ( + + + - Send a message to start an agentic run. + Loading this chat... - )} - {timeline.map((item) => { - if (item.kind === "message") { - return ( - - - - ); - } + + + + + + + + + + + + + + + + + + + + + + )} - const statusMeta = TOOL_STATUS_META[item.status]; - const hasRawData = - item.rawInput || item.rawOutput || item.rawError; - const showStatusBadge = item.status !== "running"; - - return ( - - -
- - - - {item.headline} - - {showStatusBadge && ( - + Send a message to start an agentic run. + + )} + + {timeline.map((item) => { + if (item.kind === "message") { + return ( +
+ +
+ ); + } + + const statusMeta = TOOL_STATUS_META[item.status]; + const hasRawData = item.rawInput || item.rawOutput || item.rawError; + const isExpanded = Boolean(expandedToolIds[item.id]); + + return ( +
+ + + + + + + + + {statusMeta.label} + + + {formatDate(new Date(item.timestamp), "h:mm a")} + + {hasRawData && ( + + toggleToolDetails(item.id)} + {...testId( + `agentic-tool-raw-toggle-${item.id}`, + )} > - {statusMeta.label} - - )} - -
- {(item.summaryLines.length > 0 || hasRawData) && ( - - {item.summaryLines.map((line) => ( + + + + )} + + + + + {item.rawInput && ( + + + Input + - {line} + {item.rawInput} - ))} - {hasRawData && ( -
- - Raw data - - - {item.rawInput && ( - - - Input - - - {item.rawInput} - - - )} - {item.rawOutput && ( - - - Output - - - {item.rawOutput} - - - )} - {item.rawError && ( - - - Error - - - {item.rawError} - - - )} - -
- )} -
- )} -
-
-
- ); - })} -
-
+
+ )} + {item.rawOutput && ( + + + Output + + + {item.rawOutput} + + + )} + {item.rawError && ( + + + Error + + + {item.rawError} + + + )} +
+ +
+ + +
+ ); + })}
+