wizelit-sdk 0.1.23__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,148 @@
1
+ from sqlalchemy import text
2
+ from sqlalchemy.ext.asyncio import (
3
+ create_async_engine,
4
+ async_sessionmaker,
5
+ AsyncSession,
6
+ AsyncEngine
7
+ )
8
+ from contextlib import asynccontextmanager
9
+ from typing import AsyncGenerator, Optional
10
+ import logging
11
+ import os
12
+
13
+ from wizelit_sdk.models.base import BaseModel
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+ class DatabaseManager:
18
+ """Singleton database manager with connection pooling."""
19
+
20
+ DATABASE_URL: str = ""
21
+ POOL_SIZE: int = 5
22
+ MAX_OVERFLOW: int = 10
23
+ POOL_TIMEOUT: int = 30
24
+ POOL_RECYCLE: int = 3600
25
+ ECHO_SQL: bool = False
26
+
27
+ _instance = None
28
+
29
+ def __new__(cls):
30
+ if cls._instance is None:
31
+ cls._instance = super().__new__(cls)
32
+ cls._instance._initialized = False
33
+ return cls._instance
34
+
35
+ def __init__(
36
+ self,
37
+ username: Optional[str] = None,
38
+ password: Optional[str] = None,
39
+ host: Optional[str] = None,
40
+ port: Optional[str] = None,
41
+ database: Optional[str] = None,
42
+ ):
43
+ if self._initialized:
44
+ return
45
+
46
+ # Use provided values or fall back to environment variables
47
+ USERNAME = username or os.getenv("POSTGRES_USER")
48
+ PASSWORD = password or os.getenv("POSTGRES_PASSWORD")
49
+ HOST = host or os.getenv("POSTGRES_HOST")
50
+ PORT = port or os.getenv("POSTGRES_PORT")
51
+ DATABASE = database or os.getenv("POSTGRES_DB")
52
+ self.DATABASE_URL = f"postgresql+asyncpg://{USERNAME}:{PASSWORD}@{HOST}:{PORT}/{DATABASE}"
53
+
54
+ # Create async engine
55
+ self.engine: AsyncEngine = create_async_engine(
56
+ self.DATABASE_URL,
57
+ pool_size=self.POOL_SIZE,
58
+ max_overflow=self.MAX_OVERFLOW,
59
+ pool_timeout=self.POOL_TIMEOUT,
60
+ pool_recycle=self.POOL_RECYCLE,
61
+ echo=self.ECHO_SQL,
62
+ pool_pre_ping=True,
63
+ )
64
+
65
+ # Create async session factory
66
+ self.async_session_factory = async_sessionmaker(
67
+ self.engine,
68
+ class_=AsyncSession,
69
+ expire_on_commit=False,
70
+ autoflush=False,
71
+ autocommit=False,
72
+ )
73
+
74
+ self._initialized = True
75
+ logger.info("Database manager initialized")
76
+
77
+ async def init_db(self, drop_existing: bool = False):
78
+ """
79
+ Initialize database tables.
80
+
81
+ Args:
82
+ drop_existing: If True, drops all existing tables before creating
83
+ """
84
+ try:
85
+ async with self.engine.begin() as conn:
86
+ if drop_existing:
87
+ logger.warning("Dropping all existing tables")
88
+ await conn.run_sync(BaseModel.metadata.drop_all)
89
+
90
+ await conn.run_sync(BaseModel.metadata.create_all)
91
+
92
+ logger.info("Database tables initialized successfully")
93
+
94
+ except Exception as e:
95
+ logger.error(f"Failed to initialize database: {e}")
96
+ raise
97
+
98
+ @asynccontextmanager
99
+ async def get_session(self) -> AsyncGenerator[AsyncSession, None]:
100
+ """
101
+ Async context manager for database sessions.
102
+
103
+ Usage:
104
+ async with db_manager.get_session() as session:
105
+ user = await session.get(User, user_id)
106
+ await session.commit()
107
+ """
108
+ session = self.async_session_factory()
109
+ try:
110
+ yield session
111
+ await session.commit()
112
+ except Exception as e:
113
+ await session.rollback()
114
+ logger.error(f"Session error: {e}")
115
+ raise
116
+ finally:
117
+ await session.close()
118
+
119
+ async def get_db(self) -> AsyncGenerator[AsyncSession, None]:
120
+ """
121
+ Dependency injection for FastAPI/similar frameworks.
122
+
123
+ Usage:
124
+ @app.get("/users")
125
+ async def get_users(db: AsyncSession = Depends(db_manager.get_db)):
126
+ result = await db.execute(select(User))
127
+ return result.scalars().all()
128
+ """
129
+ session = self.async_session_factory()
130
+ try:
131
+ yield session
132
+ finally:
133
+ await session.close()
134
+
135
+ async def close(self):
136
+ """Dispose of the engine and close all connections."""
137
+ await self.engine.dispose()
138
+ logger.info("Database connections closed")
139
+
140
+ async def health_check(self) -> bool:
141
+ """Check if database connection is healthy."""
142
+ try:
143
+ async with self.get_session() as session:
144
+ await session.execute(text("SELECT 1"))
145
+ return True
146
+ except Exception as e:
147
+ logger.error(f"Health check failed: {e}")
148
+ return False
@@ -0,0 +1,4 @@
1
+ from .base import BaseModel
2
+ from .job import JobModel, JobLogModel, JobStatus
3
+
4
+ __all__ = ["BaseModel", "JobModel", "JobLogModel", "JobStatus"]
@@ -0,0 +1,25 @@
1
+ from sqlalchemy.ext.declarative import declarative_base
2
+ from sqlalchemy import Column
3
+ from sqlalchemy.dialects.postgresql import UUID
4
+ import uuid
5
+ from datetime import datetime
6
+
7
+ Base = declarative_base()
8
+
9
+ class TimestampMixin:
10
+ """Mixin for models that need timestamp functionality."""
11
+
12
+ @staticmethod
13
+ def get_timestamp():
14
+ return datetime.utcnow().isoformat()
15
+
16
+
17
+ class BaseModel(Base):
18
+ """Abstract base model with common functionality."""
19
+ __abstract__ = True
20
+
21
+ id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
22
+
23
+ def to_dict(self):
24
+ """Convert model to dictionary."""
25
+ return {c.name: getattr(self, c.name) for c in self.__table__.columns}
@@ -0,0 +1,72 @@
1
+ """
2
+ Job and JobLog models for persistent storage of job execution data.
3
+ """
4
+ from sqlalchemy import Column, String, Text, DateTime, Integer, ForeignKey, Index
5
+ from sqlalchemy.dialects.postgresql import JSONB
6
+ from sqlalchemy.orm import relationship
7
+ from datetime import datetime
8
+ import enum
9
+
10
+ from wizelit_sdk.models.base import BaseModel
11
+
12
+
13
+
14
+ class JobStatus(str, enum.Enum):
15
+ """Enumeration of possible job statuses."""
16
+ RUNNING = "running"
17
+ COMPLETED = "completed"
18
+ FAILED = "failed"
19
+
20
+
21
+ class JobModel(BaseModel):
22
+ """
23
+ Persistent storage for job execution data.
24
+ Tracks status, results, and errors for long-running jobs.
25
+ """
26
+ __tablename__ = "jobs"
27
+
28
+ id = Column(String(64), primary_key=True) # JOB-xxxxx
29
+ status = Column(String(20), default=JobStatus.RUNNING.value, nullable=False)
30
+ result = Column(JSONB, nullable=True) # JSON result for completed jobs
31
+ error = Column(Text, nullable=True) # Error message for failed jobs
32
+ created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
33
+ updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
34
+
35
+ # Relationship to logs
36
+ logs = relationship("JobLogModel", back_populates="job", cascade="all, delete-orphan")
37
+
38
+ # Index for faster queries
39
+ __table_args__ = (
40
+ Index('idx_job_status', 'status'),
41
+ Index('idx_job_created_at', 'created_at'),
42
+ )
43
+
44
+ def __repr__(self):
45
+ return f"<JobModel(id={self.id}, status={self.status})>"
46
+
47
+
48
+ class JobLogModel(BaseModel):
49
+ """
50
+ Persistent storage for individual job log entries.
51
+ Captures timestamped log messages with severity levels.
52
+ """
53
+ __tablename__ = "job_logs"
54
+
55
+ id = Column(Integer, primary_key=True, autoincrement=True)
56
+ job_id = Column(String(64), ForeignKey("jobs.id", ondelete="CASCADE"), nullable=False)
57
+ message = Column(Text, nullable=False)
58
+ level = Column(String(20), nullable=False) # INFO, ERROR, WARNING, DEBUG
59
+ timestamp = Column(DateTime, default=datetime.utcnow, nullable=False)
60
+
61
+ # Relationship to job
62
+ job = relationship("JobModel", back_populates="logs")
63
+
64
+ # Indexes for faster queries
65
+ __table_args__ = (
66
+ Index('idx_job_log_job_id', 'job_id'),
67
+ Index('idx_job_log_timestamp', 'timestamp'),
68
+ Index('idx_job_log_job_id_timestamp', 'job_id', 'timestamp'),
69
+ )
70
+
71
+ def __repr__(self):
72
+ return f"<JobLogModel(id={self.id}, job_id={self.job_id}, level={self.level})>"
@@ -0,0 +1,111 @@
1
+ Metadata-Version: 2.4
2
+ Name: wizelit-sdk
3
+ Version: 0.1.23
4
+ Summary: Wizelit Agent Wrapper - Internal utility package
5
+ Author-email: Your Name <your.email@company.com>
6
+ Requires-Python: >=3.10
7
+ Requires-Dist: asyncpg>=0.26.0
8
+ Requires-Dist: fastmcp>=0.1.0
9
+ Requires-Dist: redis>=4.5.0
10
+ Requires-Dist: sqlalchemy>=1.4
11
+ Requires-Dist: typing-extensions>=4.0.0
12
+ Provides-Extra: dev
13
+ Requires-Dist: black>=22.0.0; extra == 'dev'
14
+ Requires-Dist: build>=1.0.0; extra == 'dev'
15
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
16
+ Requires-Dist: ruff>=0.1.0; extra == 'dev'
17
+ Provides-Extra: streaming
18
+ Requires-Dist: redis>=4.5.0; extra == 'streaming'
19
+ Description-Content-Type: text/markdown
20
+
21
+ # wizelit-sdk
22
+
23
+ Internal utility package for Wizelit Agent operations.
24
+
25
+ ## Installation
26
+
27
+ ### Install from Git Repository
28
+
29
+ ```bash
30
+ # Install latest version from main branch
31
+ uv pip install git+https://github.com/your-org/wizelit-sdk.git
32
+
33
+ # Install specific version
34
+ uv pip install git+https://github.com/your-org/wizelit-sdk.git@v0.1.0
35
+
36
+ # Install with SSH (Recommended for Private Repos)
37
+ uv pip install git+ssh://git@github.com/your-org/wizelit-sdk.git@v0.1.0
38
+ ```
39
+
40
+ ### Add to pyproject.toml
41
+
42
+ ```toml
43
+ [project]
44
+ dependencies = [
45
+ "wizelit-sdk @ git+ssh://git@github.com/your-org/wizelit-sdk.git@v0.1.0"
46
+ ]
47
+ ```
48
+
49
+ ## Usage
50
+
51
+ ```python
52
+ from wizelit_agent_wrapper import your_module
53
+
54
+ # Use the wrapper
55
+ result = your_module.function()
56
+ ```
57
+
58
+ ## Development
59
+
60
+ ### Setup Development Environment
61
+
62
+ ```bash
63
+ # Clone repository
64
+ git clone https://github.com/your-org/wizelit-sdk.git
65
+ cd wizelit-sdk
66
+
67
+ # Set up environment
68
+ make setup
69
+
70
+ # Activate virtual environment
71
+ source .venv/bin/activate # Windows: .venv\Scripts\activate
72
+
73
+ # Install in development mode
74
+ make install-dev
75
+ ```
76
+
77
+ ### Available Make Commands
78
+
79
+ ```bash
80
+ make setup # Set up development environment
81
+ make install-dev # Install in development mode
82
+ make test # Run tests
83
+ make format # Format code with black
84
+ make lint # Lint code with ruff
85
+ make check # Run tests and linting
86
+ make clean # Clean build artifacts
87
+ make build # Build package
88
+ make release # Create new release (interactive)
89
+ make tag VERSION=x.x.x # Create specific version tag
90
+ make push # Push code and tags
91
+ make version # Show current version
92
+ make versions # List all available versions
93
+ ```
94
+
95
+ ## Contributing
96
+
97
+ 1. Create a feature branch
98
+ 2. Make your changes
99
+ 3. Run tests and linting: `make check`
100
+ 4. Commit your changes
101
+ 5. Push and create a pull request
102
+
103
+ ## Versioning
104
+
105
+ We use [Semantic Versioning](https://semver.org/):
106
+ - **MAJOR** version for incompatible API changes
107
+ - **MINOR** version for new functionality (backward compatible)
108
+ - **PATCH** version for bug fixes
109
+
110
+ See [CHANGELOG.md](CHANGELOG.md) for version history.
111
+
@@ -0,0 +1,13 @@
1
+ wizelit_sdk/__init__.py,sha256=6UyHRL8Wu0CAWHIErlmDZFxqI_BZwsco_DWnoMr_H6A,485
2
+ wizelit_sdk/database.py,sha256=39Vu5A8CV7u7ItIwRgrkAugD9UqNbG5vQrCsMOgTamc,4631
3
+ wizelit_sdk/agent_wrapper/__init__.py,sha256=q4xsoiAyI_KM9TSL9rFfxPzGrONJt3GF6MlEx6vDkis,321
4
+ wizelit_sdk/agent_wrapper/agent_wrapper.py,sha256=r1N47KT4Sh6Gudt6ZEFNXvDDD8g4kOkuwTm19K9Np9c,22644
5
+ wizelit_sdk/agent_wrapper/job.py,sha256=Vvmm6eTX1cbXpFuwPMLaom6hEgdk3ovitnaj9d9p02o,13804
6
+ wizelit_sdk/agent_wrapper/streaming.py,sha256=f0VV3IzGAlfQY_cw2OHgxWjvM16Hs42_b700EUX2QpY,6633
7
+ wizelit_sdk/agent_wrapper/utils.py,sha256=OUihj3Kk6uI0y7bDr_L_YQs33vSK0GAJRl0c4km4DNs,951
8
+ wizelit_sdk/models/__init__.py,sha256=UB7nfHoE6hGcjfzy7w8AmuKVmYrTg9wIgGjG8GWziJ0,143
9
+ wizelit_sdk/models/base.py,sha256=aEPGMZVczKnlWz4Ps99e_xI5TcuSV3DxCigRMU5BnhE,704
10
+ wizelit_sdk/models/job.py,sha256=P68Vb1k77Z_Tha4dE0GzrLPa0LJrnMCxyYMENZyD7Kc,2480
11
+ wizelit_sdk-0.1.23.dist-info/METADATA,sha256=ta0J_LwnCa4NGBO2q-v0c23_G-b-SfK6Okhhzr-3zjM,2778
12
+ wizelit_sdk-0.1.23.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
13
+ wizelit_sdk-0.1.23.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.28.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any