[Haik]: Fixed all pydantic instance attribute violations

This commit is contained in:
haikdc
2026-04-17 23:34:15 -07:00
parent e5ba3412f2
commit dbfa1a3c7d
16 changed files with 101 additions and 24 deletions
+16 -1
View File
@@ -11,5 +11,20 @@
"python.analysis.diagnosticSeverityOverrides": {
"reportMissingTypeStubs": "none"
},
"eslint.workingDirectories": ["frontend"]
"eslint.workingDirectories": [
"frontend"
],
"cursorpyright.analysis.diagnosticSeverityOverrides": {
"reportMissingTypeStubs": "none"
},
"cursorpyright.analysis.exclude": [
"backend/.venv",
"backend/uv-bin",
"backend/data",
"backend/tests"
],
"cursorpyright.analysis.include": [
"backend"
],
"cursorpyright.analysis.typeCheckingMode": "strict"
}
@@ -9,8 +9,6 @@ Heavy logic lives in sibling modules:
- session_store on-disk persistence, history, message copying
"""
from __future__ import annotations
import asyncio
import logging
import os
@@ -18,6 +16,8 @@ from datetime import datetime
from typing import Optional
from uuid import uuid4
from pydantic import InstanceOf
from backend.apps.agents.models import AgentConfig, AgentSession, Message
from backend.apps.agents.manager.ws_manager import ws_manager
from backend.apps.agents.execution.prompt_builder import resolve_mode
@@ -47,7 +47,7 @@ os.environ.setdefault("CLAUDE_CODE_STREAM_CLOSE_TIMEOUT", "3600000")
class AgentManager:
def __init__(self):
self.sessions: dict[str, AgentSession] = {}
self.tasks: dict[str, asyncio.Task] = {}
self.tasks: dict[str, InstanceOf[asyncio.Task]] = {}
async def launch_agent(self, config: AgentConfig) -> AgentSession:
session_id = uuid4().hex
+4 -1
View File
@@ -5,6 +5,9 @@ import logging
import platform
from contextlib import asynccontextmanager
from datetime import datetime
from typing import Optional
from pydantic import InstanceOf
from backend.config.Apps import SubApp
from backend.apps.analytics.collector import init as init_collector, shutdown as shutdown_collector, record, identify
@@ -22,7 +25,7 @@ logger = logging.getLogger(__name__)
APP_VERSION = "1.0.20"
_heartbeat_task: asyncio.Task | None = None
_heartbeat_task: Optional[InstanceOf[asyncio.Task]] = None
async def _heartbeat_loop():
+2 -1
View File
@@ -7,6 +7,7 @@ import time
from contextlib import asynccontextmanager
from typing import Optional
from pydantic import InstanceOf
import httpx
from fastapi import Query
from backend.config.Apps import SubApp
@@ -24,7 +25,7 @@ GITHUB_CONCURRENT = 10
_cache: dict[str, dict] = {}
_cache_updated_at: float = 0
_refresh_task: Optional[asyncio.Task] = None
_refresh_task: Optional[InstanceOf[asyncio.Task]] = None
_stars_cache: dict[str, int] = {}
@@ -3,12 +3,13 @@ from fastapi import WebSocket
from typing import List
from typeguard import typechecked
from pydantic import BaseModel, Field
from pydantic import InstanceOf
class FrontendBroadcaster(BaseModel):
"""Singleton WebSocket connection pool for broadcasting to dashboard clients."""
p_connections: List[WebSocket] = Field(default_factory=list)
p_connections: List[InstanceOf[WebSocket]] = Field(default_factory=list)
@typechecked
async def connect(self, ws: WebSocket) -> None:
@@ -1,6 +1,6 @@
import asyncio
from typing import Callable, Awaitable, Dict
from pydantic import BaseModel, Field
from pydantic import BaseModel, Field, InstanceOf
from typeguard import typechecked
class FutureBridge(BaseModel):
@@ -10,7 +10,7 @@ class FutureBridge(BaseModel):
block until the frontend responds (or timeout).
"""
p_pending: Dict[str, asyncio.Future] = Field(default_factory=dict)
p_pending: Dict[str, InstanceOf[asyncio.Future]] = Field(default_factory=dict)
# TODO: add better type specing for the output of this function
@typechecked
+2 -2
View File
@@ -6,7 +6,7 @@ Separated from models.py to keep schema classes small and data separate.
from backend.apps.modes.Mode import Mode
from typing import List
from backend.config.paths import DB_ROOT
from backend.apps.app_builder.app_builder import APP_BUILDER_WORKSPACE_DIR
from backend.apps.app_builder.app_builder import APP_BUILDER_CONTENT_DIR
import os
SKILLS_WORKSPACE: str = os.path.join(DB_ROOT, "skills")
@@ -75,7 +75,7 @@ BUILTIN_MODES: List[Mode] = [
is_builtin=True,
icon="view_quilt",
color="#f472b6",
default_folder=APP_BUILDER_WORKSPACE_DIR,
default_folder=APP_BUILDER_CONTENT_DIR,
),
Mode(
id="skill-builder",
@@ -3,10 +3,11 @@ from typing import Optional
import httpx
from backend.apps.skills.parse_frontmatter import parse_frontmatter
from typeguard import typechecked
from pydantic import InstanceOf
@typechecked
async def fetch_one_skill(
client: httpx.AsyncClient,
client: InstanceOf[httpx.AsyncClient],
sem: asyncio.Semaphore,
folder: str,
plugin_name: str,
@@ -1,10 +1,11 @@
import httpx
from typeguard import typechecked
from pydantic import InstanceOf
@typechecked
async def fetch_skill_paths(
client: httpx.AsyncClient,
client: InstanceOf[httpx.AsyncClient],
manifest_url: str
) -> list[tuple[str, str]]:
@@ -8,7 +8,7 @@ ensure-task, HTTP client) lives in one place.
import asyncio
from typing import ClassVar, Optional
from pydantic import BaseModel, Field
from pydantic import BaseModel, Field, InstanceOf
from typeguard import typechecked
from backend.apps.subscriptions.NineRouter.helpers.NineRouterProcess.NineRouterProcess import NineRouterProcess
@@ -19,7 +19,7 @@ class NineRouter(BaseModel):
p_instance: ClassVar[Optional["NineRouter"]] = None
p_process: NineRouterProcess = Field(default_factory=NineRouterProcess)
p_client: NineRouterClient = Field(default_factory=NineRouterClient)
p_ensure_task: Optional[asyncio.Task] = None
p_ensure_task: Optional[InstanceOf[asyncio.Task]] = None
@classmethod
def get(cls) -> "NineRouter":
@@ -1,7 +1,7 @@
"""HTTP client for 9Router's REST API."""
import httpx
from pydantic import Field, BaseModel
from pydantic import Field, BaseModel, InstanceOf
from typeguard import typechecked
from backend.apps.subscriptions.NineRouter.helpers.constants import NINE_ROUTER_API, NINE_ROUTER_V1
@@ -9,7 +9,7 @@ from backend.ports import NINE_ROUTER_PORT
class NineRouterClient(BaseModel):
p_http: httpx.AsyncClient = Field(default_factory=httpx.AsyncClient(timeout=15.0))
p_http: InstanceOf[httpx.AsyncClient] = Field(default_factory=lambda: httpx.AsyncClient(timeout=15.0))
async def aclose(self) -> None:
await self.p_http.aclose()
@@ -12,7 +12,7 @@ import threading
from typing import Optional
import httpx
from pydantic import Field, BaseModel
from pydantic import Field, BaseModel, InstanceOf
from typeguard import typechecked
from backend.ports import NINE_ROUTER_PORT
@@ -25,7 +25,7 @@ P_THIS_DIR: str = os.path.dirname(os.path.abspath(__file__))
class NineRouterProcess(BaseModel):
p_process: Optional[subprocess.Popen] = Field(default=None)
p_process: Optional[InstanceOf[subprocess.Popen]] = Field(default=None)
@typechecked
def is_running(self) -> bool:
+2 -2
View File
@@ -43,7 +43,7 @@ class Agent(BaseModel):
toolkit: Optional[Toolkit] = Field(default=None, exclude=True)
on_event: Optional[EventCallback] = Field(default=None, exclude=True)
task: Optional[asyncio.Task] = None
task: Optional[InstanceOf[asyncio.Task]] = None
lock: InstanceOf[asyncio.Lock] = Field(default_factory=asyncio.Lock)
@typechecked
@@ -96,7 +96,7 @@ class Agent(BaseModel):
session_id=self.session_id, status="waiting_approval",
))
future: asyncio.Future = asyncio.get_event_loop().create_future()
future: InstanceOf[asyncio.Future] = asyncio.get_event_loop().create_future()
try:
await self.emit(ApprovalRequestEvent(
session_id=self.session_id,
+2 -2
View File
@@ -1,6 +1,6 @@
import asyncio
from pydantic import BaseModel, Field
from pydantic import BaseModel, Field, InstanceOf
from typing import Annotated, Any, Dict, Literal, Optional, Union, Callable, Awaitable
from backend.core.shared_structs.agent.Message.Message import AnyMessage
@@ -74,7 +74,7 @@ class ApprovalRequestEvent(BaseModel):
request_id: str
tool_name: str
tool_input: Dict[str, Any]
future: asyncio.Future = Field(exclude=True)
future: InstanceOf[asyncio.Future] = Field(exclude=True)
AnyEvent = Annotated[
+1 -1
View File
@@ -1,6 +1,6 @@
{
"backend": {
"dev": 8324,
"dev": 8326,
"prod": 8325
},
"frontend": {
+55
View File
@@ -0,0 +1,55 @@
#!/usr/bin/env bash
set -euo pipefail
# --- Args ---
if [ $# -ne 2 ]; then
echo -e "\033[1;31mError: exactly 2 arguments required\033[0m"
echo -e "\033[0;90mUsage: bash push.sh Name \"commit message\"\033[0m"
exit 1
fi
NAME="$1"
MESSAGE="$2"
# --- Helpers ---
banner() {
local msg="$1"
local len=${#msg}
local border=$(printf '═%.0s' $(seq 1 $((len + 4))))
echo ""
echo -e "\033[1;36m╔${border}╗\033[0m"
echo -e "\033[1;36m║ \033[1;33m${msg}\033[1;36m ║\033[0m"
echo -e "\033[1;36m╚${border}╝\033[0m"
echo ""
}
gate() {
local prompt="${1:?gate requires a prompt argument}"
while true; do
read -rp $'\033[1;35m► '"${prompt}"$' [Y/n] \033[0m' yn
case "${yn:-Y}" in
[Yy]*) return 0 ;;
[Nn]*) echo -e "\033[1;31m✗ Aborted.\033[0m"; exit 1 ;;
*) echo "Please answer y or n." ;;
esac
done
}
# --- Workflow ---
banner "git status"
git status
gate "Stage all changes?"
banner "git add ."
git add .
git status
gate "Commit these changes?"
banner "git commit -m \"[${NAME}]: ${MESSAGE}\""
git commit -m "[${NAME}]: ${MESSAGE}"
gate "Push to remote?"
banner "git push"
git push
banner "All changes pushed successfully ✓"