mukulcore 0.1.0__tar.gz

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.
Files changed (87) hide show
  1. mukulcore-0.1.0/LICENSE +20 -0
  2. mukulcore-0.1.0/PKG-INFO +13 -0
  3. mukulcore-0.1.0/README.md +3 -0
  4. mukulcore-0.1.0/mukulcore/__init__.py +7 -0
  5. mukulcore-0.1.0/mukulcore/agents/__init__.py +1 -0
  6. mukulcore-0.1.0/mukulcore/agents/base_agent.py +14 -0
  7. mukulcore-0.1.0/mukulcore/agents/critic.py +10 -0
  8. mukulcore-0.1.0/mukulcore/agents/planner.py +10 -0
  9. mukulcore-0.1.0/mukulcore/agents/researcher.py +10 -0
  10. mukulcore-0.1.0/mukulcore/agents/writer.py +10 -0
  11. mukulcore-0.1.0/mukulcore/ai/__init__.py +1 -0
  12. mukulcore-0.1.0/mukulcore/ai/embeddings.py +8 -0
  13. mukulcore-0.1.0/mukulcore/ai/llm.py +11 -0
  14. mukulcore-0.1.0/mukulcore/ai/markdown.py +6 -0
  15. mukulcore-0.1.0/mukulcore/ai/memory.py +16 -0
  16. mukulcore-0.1.0/mukulcore/ai/parser.py +10 -0
  17. mukulcore-0.1.0/mukulcore/ai/prompts.py +8 -0
  18. mukulcore-0.1.0/mukulcore/ai/templates.py +6 -0
  19. mukulcore-0.1.0/mukulcore/ai/tokenizer.py +6 -0
  20. mukulcore-0.1.0/mukulcore/api/__init__.py +1 -0
  21. mukulcore-0.1.0/mukulcore/api/auth.py +6 -0
  22. mukulcore-0.1.0/mukulcore/api/client.py +8 -0
  23. mukulcore-0.1.0/mukulcore/api/requests.py +11 -0
  24. mukulcore-0.1.0/mukulcore/api/responses.py +11 -0
  25. mukulcore-0.1.0/mukulcore/cli/__init__.py +1 -0
  26. mukulcore-0.1.0/mukulcore/cli/doctor.py +6 -0
  27. mukulcore-0.1.0/mukulcore/cli/init.py +6 -0
  28. mukulcore-0.1.0/mukulcore/cli/main.py +6 -0
  29. mukulcore-0.1.0/mukulcore/config/__init__.py +1 -0
  30. mukulcore-0.1.0/mukulcore/config/constants.py +4 -0
  31. mukulcore-0.1.0/mukulcore/config/env.py +8 -0
  32. mukulcore-0.1.0/mukulcore/config/settings.py +17 -0
  33. mukulcore-0.1.0/mukulcore/database/__init__.py +1 -0
  34. mukulcore-0.1.0/mukulcore/database/mongodb.py +6 -0
  35. mukulcore-0.1.0/mukulcore/database/postgres.py +6 -0
  36. mukulcore-0.1.0/mukulcore/database/sqlite.py +9 -0
  37. mukulcore-0.1.0/mukulcore/database/vectorstore.py +8 -0
  38. mukulcore-0.1.0/mukulcore/decorators/__init__.py +1 -0
  39. mukulcore-0.1.0/mukulcore/decorators/cache.py +20 -0
  40. mukulcore-0.1.0/mukulcore/decorators/retry.py +29 -0
  41. mukulcore-0.1.0/mukulcore/decorators/singleton.py +19 -0
  42. mukulcore-0.1.0/mukulcore/decorators/timer.py +22 -0
  43. mukulcore-0.1.0/mukulcore/decorators/validate.py +16 -0
  44. mukulcore-0.1.0/mukulcore/exceptions/__init__.py +8 -0
  45. mukulcore-0.1.0/mukulcore/exceptions/ai.py +5 -0
  46. mukulcore-0.1.0/mukulcore/exceptions/api.py +5 -0
  47. mukulcore-0.1.0/mukulcore/exceptions/graph.py +5 -0
  48. mukulcore-0.1.0/mukulcore/exceptions/validation.py +5 -0
  49. mukulcore-0.1.0/mukulcore/graph/__init__.py +1 -0
  50. mukulcore-0.1.0/mukulcore/graph/checkpoint.py +8 -0
  51. mukulcore-0.1.0/mukulcore/graph/edges.py +6 -0
  52. mukulcore-0.1.0/mukulcore/graph/nodes.py +8 -0
  53. mukulcore-0.1.0/mukulcore/graph/state.py +11 -0
  54. mukulcore-0.1.0/mukulcore/graph/workflow.py +8 -0
  55. mukulcore-0.1.0/mukulcore/logging/__init__.py +5 -0
  56. mukulcore-0.1.0/mukulcore/logging/file_logger.py +15 -0
  57. mukulcore-0.1.0/mukulcore/logging/formatter.py +10 -0
  58. mukulcore-0.1.0/mukulcore/logging/logger.py +15 -0
  59. mukulcore-0.1.0/mukulcore/models/__init__.py +1 -0
  60. mukulcore-0.1.0/mukulcore/models/base.py +10 -0
  61. mukulcore-0.1.0/mukulcore/models/requests.py +10 -0
  62. mukulcore-0.1.0/mukulcore/models/responses.py +10 -0
  63. mukulcore-0.1.0/mukulcore/tools/__init__.py +1 -0
  64. mukulcore-0.1.0/mukulcore/tools/calculator.py +6 -0
  65. mukulcore-0.1.0/mukulcore/tools/csv_tool.py +10 -0
  66. mukulcore-0.1.0/mukulcore/tools/filesystem.py +8 -0
  67. mukulcore-0.1.0/mukulcore/tools/github.py +6 -0
  68. mukulcore-0.1.0/mukulcore/tools/pdf.py +6 -0
  69. mukulcore-0.1.0/mukulcore/tools/search.py +6 -0
  70. mukulcore-0.1.0/mukulcore/tools/web.py +6 -0
  71. mukulcore-0.1.0/mukulcore/utils/__init__.py +5 -0
  72. mukulcore-0.1.0/mukulcore/utils/file_utils.py +10 -0
  73. mukulcore-0.1.0/mukulcore/utils/json_utils.py +17 -0
  74. mukulcore-0.1.0/mukulcore/version.py +3 -0
  75. mukulcore-0.1.0/mukulcore.egg-info/PKG-INFO +13 -0
  76. mukulcore-0.1.0/mukulcore.egg-info/SOURCES.txt +85 -0
  77. mukulcore-0.1.0/mukulcore.egg-info/dependency_links.txt +1 -0
  78. mukulcore-0.1.0/mukulcore.egg-info/top_level.txt +1 -0
  79. mukulcore-0.1.0/pyproject.toml +14 -0
  80. mukulcore-0.1.0/setup.cfg +4 -0
  81. mukulcore-0.1.0/tests/test_agents.py +6 -0
  82. mukulcore-0.1.0/tests/test_graph.py +7 -0
  83. mukulcore-0.1.0/tests/test_json.py +11 -0
  84. mukulcore-0.1.0/tests/test_json_utils.py +11 -0
  85. mukulcore-0.1.0/tests/test_logger.py +6 -0
  86. mukulcore-0.1.0/tests/test_retry.py +17 -0
  87. mukulcore-0.1.0/tests/test_tools.py +5 -0
@@ -0,0 +1,20 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 mukulcore
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TO USE, THE SOFTWARE OR OTHER
20
+ DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,13 @@
1
+ Metadata-Version: 2.4
2
+ Name: mukulcore
3
+ Version: 0.1.0
4
+ Summary: A small utility package
5
+ Author: mukulcore
6
+ Requires-Python: >=3.9
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Dynamic: license-file
10
+
11
+ # mukulcore
12
+
13
+ A small utility package with logging, retry, JSON, file, and config helpers.
@@ -0,0 +1,3 @@
1
+ # mukulcore
2
+
3
+ A small utility package with logging, retry, JSON, file, and config helpers.
@@ -0,0 +1,7 @@
1
+ """
2
+ MukulCore
3
+
4
+ A Python toolkit for AI Engineers.
5
+ """
6
+
7
+ from .version import __version__
@@ -0,0 +1 @@
1
+ """Agents package."""
@@ -0,0 +1,14 @@
1
+ """Base agent abstraction."""
2
+
3
+ from typing import Any
4
+
5
+
6
+ class BaseAgent:
7
+ """Simple base class for agents."""
8
+
9
+ def __init__(self, name: str) -> None:
10
+ self.name = name
11
+
12
+ def run(self, task: str, **kwargs: Any) -> str:
13
+ """Execute a task and return a string result."""
14
+ return f"{self.name}: {task}"
@@ -0,0 +1,10 @@
1
+ """Critic agent."""
2
+
3
+ from .base_agent import BaseAgent
4
+
5
+
6
+ class CriticAgent(BaseAgent):
7
+ """Agent for critique tasks."""
8
+
9
+ def __init__(self) -> None:
10
+ super().__init__("critic")
@@ -0,0 +1,10 @@
1
+ """Planner agent."""
2
+
3
+ from .base_agent import BaseAgent
4
+
5
+
6
+ class PlannerAgent(BaseAgent):
7
+ """Agent for planning tasks."""
8
+
9
+ def __init__(self) -> None:
10
+ super().__init__("planner")
@@ -0,0 +1,10 @@
1
+ """Researcher agent."""
2
+
3
+ from .base_agent import BaseAgent
4
+
5
+
6
+ class ResearcherAgent(BaseAgent):
7
+ """Agent for research tasks."""
8
+
9
+ def __init__(self) -> None:
10
+ super().__init__("researcher")
@@ -0,0 +1,10 @@
1
+ """Writer agent."""
2
+
3
+ from .base_agent import BaseAgent
4
+
5
+
6
+ class WriterAgent(BaseAgent):
7
+ """Agent for writing tasks."""
8
+
9
+ def __init__(self) -> None:
10
+ super().__init__("writer")
@@ -0,0 +1 @@
1
+ """AI package."""
@@ -0,0 +1,8 @@
1
+ """Embedding helpers."""
2
+
3
+ from typing import List
4
+
5
+
6
+ def embed_text(text: str) -> List[float]:
7
+ """Return a simple placeholder embedding."""
8
+ return [float(len(text)), float(sum(ord(ch) for ch in text) % 100)]
@@ -0,0 +1,11 @@
1
+ """Simple LLM abstraction interface."""
2
+
3
+ from typing import Any
4
+
5
+
6
+ class BaseLLM:
7
+ """Base class for LLM integrations."""
8
+
9
+ def generate(self, prompt: str, **kwargs: Any) -> str:
10
+ """Generate a response from a prompt."""
11
+ return prompt
@@ -0,0 +1,6 @@
1
+ """Markdown helpers."""
2
+
3
+
4
+ def to_markdown(text: str) -> str:
5
+ """Wrap text as a markdown paragraph."""
6
+ return f"{text}\n"
@@ -0,0 +1,16 @@
1
+ """Simple memory store."""
2
+
3
+ from typing import Any, Dict
4
+
5
+
6
+ class MemoryStore:
7
+ """Store key/value pairs in memory."""
8
+
9
+ def __init__(self) -> None:
10
+ self._store: Dict[str, Any] = {}
11
+
12
+ def set(self, key: str, value: Any) -> None:
13
+ self._store[key] = value
14
+
15
+ def get(self, key: str, default: Any = None) -> Any:
16
+ return self._store.get(key, default)
@@ -0,0 +1,10 @@
1
+ """Output parsing helpers."""
2
+
3
+ from typing import Any
4
+
5
+
6
+ def parse_json(text: str) -> Any:
7
+ """Parse JSON from a string."""
8
+ import json
9
+
10
+ return json.loads(text)
@@ -0,0 +1,8 @@
1
+ """Prompt management utilities."""
2
+
3
+ from pathlib import Path
4
+
5
+
6
+ def load_prompt(path: str | Path) -> str:
7
+ """Load a prompt from disk."""
8
+ return Path(path).read_text(encoding="utf-8")
@@ -0,0 +1,6 @@
1
+ """Template helpers."""
2
+
3
+
4
+ def render(template: str, **values: str) -> str:
5
+ """Render a basic template string."""
6
+ return template.format(**values)
@@ -0,0 +1,6 @@
1
+ """Tokenization helpers."""
2
+
3
+
4
+ def tokenize(text: str) -> list[str]:
5
+ """Split text into tokens."""
6
+ return text.split()
@@ -0,0 +1 @@
1
+ """API package."""
@@ -0,0 +1,6 @@
1
+ """Authentication helpers."""
2
+
3
+
4
+ def get_auth_header(token: str) -> dict[str, str]:
5
+ """Return a bearer token header."""
6
+ return {"Authorization": f"Bearer {token}"}
@@ -0,0 +1,8 @@
1
+ """API client placeholder."""
2
+
3
+
4
+ class APIClient:
5
+ """Minimal API client stub."""
6
+
7
+ def __init__(self, base_url: str = "") -> None:
8
+ self.base_url = base_url
@@ -0,0 +1,11 @@
1
+ """API request models."""
2
+
3
+ from dataclasses import dataclass
4
+
5
+
6
+ @dataclass
7
+ class APIRequest:
8
+ """Simple request payload."""
9
+
10
+ method: str = "GET"
11
+ url: str = ""
@@ -0,0 +1,11 @@
1
+ """API response models."""
2
+
3
+ from dataclasses import dataclass
4
+
5
+
6
+ @dataclass
7
+ class APIResponse:
8
+ """Simple response payload."""
9
+
10
+ status_code: int = 200
11
+ body: str = ""
@@ -0,0 +1 @@
1
+ """CLI package."""
@@ -0,0 +1,6 @@
1
+ """CLI doctor command."""
2
+
3
+
4
+ def doctor() -> str:
5
+ """Return a health-check message."""
6
+ return "Everything looks healthy"
@@ -0,0 +1,6 @@
1
+ """Initialize the package from the CLI."""
2
+
3
+
4
+ def init_project() -> str:
5
+ """Return a setup message."""
6
+ return "Project initialized"
@@ -0,0 +1,6 @@
1
+ """CLI entry point."""
2
+
3
+
4
+ def main() -> None:
5
+ """Print a welcome message."""
6
+ print("mukulcore CLI")
@@ -0,0 +1 @@
1
+ """Configuration package."""
@@ -0,0 +1,4 @@
1
+ """Common constants."""
2
+
3
+ DEFAULT_TIMEOUT = 30
4
+ DEFAULT_RETRIES = 3
@@ -0,0 +1,8 @@
1
+ """Environment helpers."""
2
+
3
+ import os
4
+
5
+
6
+ def get_env(name: str, default: str | None = None) -> str | None:
7
+ """Return an environment variable value."""
8
+ return os.getenv(name, default)
@@ -0,0 +1,17 @@
1
+ """Pydantic-based settings helpers."""
2
+
3
+ from typing import Optional
4
+
5
+ try:
6
+ from pydantic import BaseModel
7
+ except ImportError: # pragma: no cover
8
+ class BaseModel: # type: ignore
9
+ pass
10
+
11
+
12
+ class Settings(BaseModel):
13
+ """Simple application settings container."""
14
+
15
+ app_name: str = "mukulcore"
16
+ debug: bool = False
17
+ api_key: Optional[str] = None
@@ -0,0 +1 @@
1
+ """Database package."""
@@ -0,0 +1,6 @@
1
+ """MongoDB helpers."""
2
+
3
+
4
+ def get_connection_string(host: str, db: str) -> str:
5
+ """Create a simple MongoDB connection string."""
6
+ return f"mongodb://{host}/{db}"
@@ -0,0 +1,6 @@
1
+ """PostgreSQL helpers."""
2
+
3
+
4
+ def get_connection_string(host: str, db: str, user: str, password: str) -> str:
5
+ """Create a simple PostgreSQL connection string."""
6
+ return f"postgresql://{user}:{password}@{host}/{db}"
@@ -0,0 +1,9 @@
1
+ """SQLite helpers."""
2
+
3
+ import sqlite3
4
+ from pathlib import Path
5
+
6
+
7
+ def connect(path: str | Path) -> sqlite3.Connection:
8
+ """Connect to a SQLite database."""
9
+ return sqlite3.connect(str(path))
@@ -0,0 +1,8 @@
1
+ """Vector store helpers."""
2
+
3
+ from typing import List, Tuple
4
+
5
+
6
+ def create_index(items: List[Tuple[str, List[float]]]) -> List[Tuple[str, List[float]]]:
7
+ """Return the provided items as a simple index."""
8
+ return items
@@ -0,0 +1 @@
1
+ """Decorators package."""
@@ -0,0 +1,20 @@
1
+ """Caching decorator."""
2
+
3
+ from functools import wraps
4
+ from typing import Any, Callable, Dict, TypeVar
5
+
6
+ T = TypeVar("T")
7
+
8
+
9
+ def cache(func: Callable[..., T]) -> Callable[..., T]:
10
+ """Cache the result of a function for repeated calls."""
11
+ cache_store: Dict[tuple, Any] = {}
12
+
13
+ @wraps(func)
14
+ def wrapper(*args, **kwargs) -> T:
15
+ key = (args, tuple(sorted(kwargs.items())))
16
+ if key not in cache_store:
17
+ cache_store[key] = func(*args, **kwargs)
18
+ return cache_store[key]
19
+
20
+ return wrapper
@@ -0,0 +1,29 @@
1
+ """Retry helpers."""
2
+
3
+ import time
4
+ from functools import wraps
5
+ from typing import Callable, TypeVar
6
+
7
+ T = TypeVar("T")
8
+
9
+
10
+ def retry(max_attempts: int = 3, delay: float = 0.1):
11
+ """Retry a function a few times on failure."""
12
+
13
+ def decorator(func: Callable[..., T]) -> Callable[..., T]:
14
+ @wraps(func)
15
+ def wrapper(*args, **kwargs) -> T:
16
+ last_error = None
17
+ for attempt in range(1, max_attempts + 1):
18
+ try:
19
+ return func(*args, **kwargs)
20
+ except Exception as exc: # pragma: no cover - simple helper
21
+ last_error = exc
22
+ if attempt == max_attempts:
23
+ raise
24
+ time.sleep(delay)
25
+ raise last_error
26
+
27
+ return wrapper
28
+
29
+ return decorator
@@ -0,0 +1,19 @@
1
+ """Singleton decorator."""
2
+
3
+ from functools import wraps
4
+ from typing import Callable, TypeVar
5
+
6
+ T = TypeVar("T")
7
+
8
+
9
+ def singleton(cls: type[T]) -> type[T]:
10
+ """Ensure a class only has one instance."""
11
+ instances = {}
12
+
13
+ @wraps(cls)
14
+ def wrapper(*args, **kwargs) -> T:
15
+ if cls not in instances:
16
+ instances[cls] = cls(*args, **kwargs)
17
+ return instances[cls]
18
+
19
+ return wrapper
@@ -0,0 +1,22 @@
1
+ """Timer decorator."""
2
+
3
+ import time
4
+ from functools import wraps
5
+ from typing import Callable, TypeVar
6
+
7
+ T = TypeVar("T")
8
+
9
+
10
+ def timer(func: Callable[..., T]) -> Callable[..., T]:
11
+ """Measure the execution time of a function."""
12
+
13
+ @wraps(func)
14
+ def wrapper(*args, **kwargs) -> T:
15
+ start = time.perf_counter()
16
+ try:
17
+ return func(*args, **kwargs)
18
+ finally:
19
+ elapsed = time.perf_counter() - start
20
+ print(f"{func.__name__} took {elapsed:.4f}s")
21
+
22
+ return wrapper
@@ -0,0 +1,16 @@
1
+ """Validation decorator."""
2
+
3
+ from functools import wraps
4
+ from typing import Callable, TypeVar
5
+
6
+ T = TypeVar("T")
7
+
8
+
9
+ def validate(func: Callable[..., T]) -> Callable[..., T]:
10
+ """Placeholder validator decorator."""
11
+
12
+ @wraps(func)
13
+ def wrapper(*args, **kwargs) -> T:
14
+ return func(*args, **kwargs)
15
+
16
+ return wrapper
@@ -0,0 +1,8 @@
1
+ """Exceptions package."""
2
+
3
+ from .ai import AIError
4
+ from .api import APIError
5
+ from .graph import GraphError
6
+ from .validation import ValidationError
7
+
8
+ __all__ = ["AIError", "APIError", "GraphError", "ValidationError"]
@@ -0,0 +1,5 @@
1
+ """AI-related exceptions."""
2
+
3
+
4
+ class AIError(Exception):
5
+ """Raised for AI-related failures."""
@@ -0,0 +1,5 @@
1
+ """API-related exceptions."""
2
+
3
+
4
+ class APIError(Exception):
5
+ """Raised for API-related failures."""
@@ -0,0 +1,5 @@
1
+ """Graph-related exceptions."""
2
+
3
+
4
+ class GraphError(Exception):
5
+ """Raised for workflow graph failures."""
@@ -0,0 +1,5 @@
1
+ """Validation-related exceptions."""
2
+
3
+
4
+ class ValidationError(Exception):
5
+ """Raised for validation failures."""
@@ -0,0 +1 @@
1
+ """Graph package."""
@@ -0,0 +1,8 @@
1
+ """Checkpoint helpers."""
2
+
3
+ from pathlib import Path
4
+
5
+
6
+ def save_checkpoint(path: str | Path, data: str) -> None:
7
+ """Save a checkpoint string to disk."""
8
+ Path(path).write_text(data, encoding="utf-8")
@@ -0,0 +1,6 @@
1
+ """Graph edges."""
2
+
3
+ from typing import Callable
4
+
5
+
6
+ Edge = Callable[[dict], dict]
@@ -0,0 +1,8 @@
1
+ """Graph nodes."""
2
+
3
+ from .state import GraphState
4
+
5
+
6
+ def simple_node(state: GraphState) -> GraphState:
7
+ """Return the state unchanged."""
8
+ return state
@@ -0,0 +1,11 @@
1
+ """Workflow state definitions."""
2
+
3
+ from dataclasses import dataclass, field
4
+ from typing import Any, Dict
5
+
6
+
7
+ @dataclass
8
+ class GraphState:
9
+ """Simple state container for graph workflows."""
10
+
11
+ data: Dict[str, Any] = field(default_factory=dict)
@@ -0,0 +1,8 @@
1
+ """Workflow orchestration helpers."""
2
+
3
+ from .state import GraphState
4
+
5
+
6
+ def run_workflow(initial_state: GraphState) -> GraphState:
7
+ """Run a simple workflow."""
8
+ return initial_state
@@ -0,0 +1,5 @@
1
+ """Logging package."""
2
+
3
+ from .logger import get_logger
4
+
5
+ __all__ = ["get_logger"]
@@ -0,0 +1,15 @@
1
+ """File-based logging helper."""
2
+
3
+ import logging
4
+ from pathlib import Path
5
+
6
+
7
+ def create_file_logger(name: str, path: str | Path) -> logging.Logger:
8
+ """Create a logger that writes to a file."""
9
+ logger = logging.getLogger(name)
10
+ logger.setLevel(logging.INFO)
11
+ handler = logging.FileHandler(path)
12
+ handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s"))
13
+ logger.addHandler(handler)
14
+ logger.propagate = False
15
+ return logger
@@ -0,0 +1,10 @@
1
+ """Custom formatter helpers."""
2
+
3
+ import logging
4
+
5
+
6
+ class JsonFormatter(logging.Formatter):
7
+ """Minimal JSON-like formatter for log records."""
8
+
9
+ def format(self, record: logging.LogRecord) -> str:
10
+ return f'{{"level": "{record.levelname}", "message": "{record.getMessage()}"}}'
@@ -0,0 +1,15 @@
1
+ """Logging helpers."""
2
+
3
+ import logging
4
+
5
+
6
+ def get_logger(name: str = "mukulcore") -> logging.Logger:
7
+ """Create or retrieve a logger instance."""
8
+ logger = logging.getLogger(name)
9
+ if not logger.handlers:
10
+ handler = logging.StreamHandler()
11
+ handler.setFormatter(logging.Formatter("%(levelname)s:%(name)s:%(message)s"))
12
+ logger.addHandler(handler)
13
+ logger.setLevel(logging.INFO)
14
+ logger.propagate = False
15
+ return logger
@@ -0,0 +1 @@
1
+ """Data models package."""
@@ -0,0 +1,10 @@
1
+ """Base model definitions."""
2
+
3
+ from dataclasses import dataclass
4
+
5
+
6
+ @dataclass
7
+ class BaseModel:
8
+ """Minimal base model."""
9
+
10
+ id: str | None = None
@@ -0,0 +1,10 @@
1
+ """Request model definitions."""
2
+
3
+ from dataclasses import dataclass
4
+
5
+
6
+ @dataclass
7
+ class RequestModel:
8
+ """Simple request container."""
9
+
10
+ prompt: str = ""
@@ -0,0 +1,10 @@
1
+ """Response model definitions."""
2
+
3
+ from dataclasses import dataclass
4
+
5
+
6
+ @dataclass
7
+ class ResponseModel:
8
+ """Simple response container."""
9
+
10
+ output: str = ""
@@ -0,0 +1 @@
1
+ """Tools package."""
@@ -0,0 +1,6 @@
1
+ """Calculator tool placeholder."""
2
+
3
+
4
+ def add(a: float, b: float) -> float:
5
+ """Add two numbers."""
6
+ return a + b
@@ -0,0 +1,10 @@
1
+ """CSV helper placeholder."""
2
+
3
+ import csv
4
+ from pathlib import Path
5
+
6
+
7
+ def read_csv(path: str | Path) -> list[dict[str, str]]:
8
+ """Read a CSV file into a list of rows."""
9
+ with Path(path).open(newline="", encoding="utf-8") as handle:
10
+ return list(csv.DictReader(handle))
@@ -0,0 +1,8 @@
1
+ """Filesystem tool placeholder."""
2
+
3
+ from pathlib import Path
4
+
5
+
6
+ def read_text(path: str | Path) -> str:
7
+ """Read text from a file."""
8
+ return Path(path).read_text(encoding="utf-8")
@@ -0,0 +1,6 @@
1
+ """GitHub tool placeholder."""
2
+
3
+
4
+ def repo_info(owner: str, repo: str) -> dict[str, str]:
5
+ """Return placeholder repository metadata."""
6
+ return {"owner": owner, "repo": repo}
@@ -0,0 +1,6 @@
1
+ """PDF helper placeholder."""
2
+
3
+
4
+ def extract_text(path: str) -> str:
5
+ """Return a placeholder extraction result."""
6
+ return f"pdf:{path}"
@@ -0,0 +1,6 @@
1
+ """Search tool placeholder."""
2
+
3
+
4
+ def search(query: str) -> list[str]:
5
+ """Return a placeholder search result."""
6
+ return [query]
@@ -0,0 +1,6 @@
1
+ """Web tool placeholder."""
2
+
3
+
4
+ def fetch(url: str) -> str:
5
+ """Return a placeholder response for a URL."""
6
+ return f"fetched {url}"
@@ -0,0 +1,5 @@
1
+ """Top-level package for mukulcore."""
2
+
3
+ from ..version import __version__
4
+
5
+ __all__ = ["__version__"]
@@ -0,0 +1,10 @@
1
+ """File system utility helpers."""
2
+
3
+ from pathlib import Path
4
+
5
+
6
+ def ensure_parent_dir(path: str | Path) -> Path:
7
+ """Create the parent directory for a file path if needed."""
8
+ path = Path(path)
9
+ path.parent.mkdir(parents=True, exist_ok=True)
10
+ return path
@@ -0,0 +1,17 @@
1
+ """JSON utility helpers."""
2
+
3
+ import json
4
+ from pathlib import Path
5
+ from typing import Any
6
+
7
+
8
+ def load_json(path: str | Path) -> Any:
9
+ """Load JSON data from a file."""
10
+ with Path(path).open("r", encoding="utf-8") as handle:
11
+ return json.load(handle)
12
+
13
+
14
+ def dump_json(path: str | Path, data: Any) -> None:
15
+ """Write JSON data to a file."""
16
+ with Path(path).open("w", encoding="utf-8") as handle:
17
+ json.dump(data, handle, indent=2)
@@ -0,0 +1,3 @@
1
+ """Package version information."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,13 @@
1
+ Metadata-Version: 2.4
2
+ Name: mukulcore
3
+ Version: 0.1.0
4
+ Summary: A small utility package
5
+ Author: mukulcore
6
+ Requires-Python: >=3.9
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Dynamic: license-file
10
+
11
+ # mukulcore
12
+
13
+ A small utility package with logging, retry, JSON, file, and config helpers.
@@ -0,0 +1,85 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ mukulcore/__init__.py
5
+ mukulcore/version.py
6
+ mukulcore.egg-info/PKG-INFO
7
+ mukulcore.egg-info/SOURCES.txt
8
+ mukulcore.egg-info/dependency_links.txt
9
+ mukulcore.egg-info/top_level.txt
10
+ mukulcore/agents/__init__.py
11
+ mukulcore/agents/base_agent.py
12
+ mukulcore/agents/critic.py
13
+ mukulcore/agents/planner.py
14
+ mukulcore/agents/researcher.py
15
+ mukulcore/agents/writer.py
16
+ mukulcore/ai/__init__.py
17
+ mukulcore/ai/embeddings.py
18
+ mukulcore/ai/llm.py
19
+ mukulcore/ai/markdown.py
20
+ mukulcore/ai/memory.py
21
+ mukulcore/ai/parser.py
22
+ mukulcore/ai/prompts.py
23
+ mukulcore/ai/templates.py
24
+ mukulcore/ai/tokenizer.py
25
+ mukulcore/api/__init__.py
26
+ mukulcore/api/auth.py
27
+ mukulcore/api/client.py
28
+ mukulcore/api/requests.py
29
+ mukulcore/api/responses.py
30
+ mukulcore/cli/__init__.py
31
+ mukulcore/cli/doctor.py
32
+ mukulcore/cli/init.py
33
+ mukulcore/cli/main.py
34
+ mukulcore/config/__init__.py
35
+ mukulcore/config/constants.py
36
+ mukulcore/config/env.py
37
+ mukulcore/config/settings.py
38
+ mukulcore/database/__init__.py
39
+ mukulcore/database/mongodb.py
40
+ mukulcore/database/postgres.py
41
+ mukulcore/database/sqlite.py
42
+ mukulcore/database/vectorstore.py
43
+ mukulcore/decorators/__init__.py
44
+ mukulcore/decorators/cache.py
45
+ mukulcore/decorators/retry.py
46
+ mukulcore/decorators/singleton.py
47
+ mukulcore/decorators/timer.py
48
+ mukulcore/decorators/validate.py
49
+ mukulcore/exceptions/__init__.py
50
+ mukulcore/exceptions/ai.py
51
+ mukulcore/exceptions/api.py
52
+ mukulcore/exceptions/graph.py
53
+ mukulcore/exceptions/validation.py
54
+ mukulcore/graph/__init__.py
55
+ mukulcore/graph/checkpoint.py
56
+ mukulcore/graph/edges.py
57
+ mukulcore/graph/nodes.py
58
+ mukulcore/graph/state.py
59
+ mukulcore/graph/workflow.py
60
+ mukulcore/logging/__init__.py
61
+ mukulcore/logging/file_logger.py
62
+ mukulcore/logging/formatter.py
63
+ mukulcore/logging/logger.py
64
+ mukulcore/models/__init__.py
65
+ mukulcore/models/base.py
66
+ mukulcore/models/requests.py
67
+ mukulcore/models/responses.py
68
+ mukulcore/tools/__init__.py
69
+ mukulcore/tools/calculator.py
70
+ mukulcore/tools/csv_tool.py
71
+ mukulcore/tools/filesystem.py
72
+ mukulcore/tools/github.py
73
+ mukulcore/tools/pdf.py
74
+ mukulcore/tools/search.py
75
+ mukulcore/tools/web.py
76
+ mukulcore/utils/__init__.py
77
+ mukulcore/utils/file_utils.py
78
+ mukulcore/utils/json_utils.py
79
+ tests/test_agents.py
80
+ tests/test_graph.py
81
+ tests/test_json.py
82
+ tests/test_json_utils.py
83
+ tests/test_logger.py
84
+ tests/test_retry.py
85
+ tests/test_tools.py
@@ -0,0 +1 @@
1
+ mukulcore
@@ -0,0 +1,14 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "mukulcore"
7
+ version = "0.1.0"
8
+ description = "A small utility package"
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ authors = [{ name = "mukulcore" }]
12
+
13
+ [tool.pytest.ini_options]
14
+ testpaths = ["tests"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,6 @@
1
+ from mukulcore.agents.researcher import ResearcherAgent
2
+
3
+
4
+ def test_agent_runs():
5
+ agent = ResearcherAgent()
6
+ assert agent.run("collect data") == "researcher: collect data"
@@ -0,0 +1,7 @@
1
+ from mukulcore.graph.state import GraphState
2
+ from mukulcore.graph.workflow import run_workflow
3
+
4
+
5
+ def test_run_workflow_returns_initial_state():
6
+ state = GraphState(data={"step": 1})
7
+ assert run_workflow(state) == state
@@ -0,0 +1,11 @@
1
+ from pathlib import Path
2
+
3
+ from mukulcore.utils.json_utils import dump_json, load_json
4
+
5
+
6
+ def test_json_round_trip(tmp_path: Path):
7
+ path = tmp_path / "data.json"
8
+ payload = {"hello": "world"}
9
+
10
+ dump_json(path, payload)
11
+ assert load_json(path) == payload
@@ -0,0 +1,11 @@
1
+ from pathlib import Path
2
+
3
+ from mukulcore.utils.json_utils import dump_json, load_json
4
+
5
+
6
+ def test_json_round_trip(tmp_path: Path):
7
+ path = tmp_path / "data.json"
8
+ payload = {"hello": "world"}
9
+
10
+ dump_json(path, payload)
11
+ assert load_json(path) == payload
@@ -0,0 +1,6 @@
1
+ from mukulcore.logger import get_logger
2
+
3
+
4
+ def test_get_logger_returns_logger():
5
+ logger = get_logger("test")
6
+ assert logger.name == "test"
@@ -0,0 +1,17 @@
1
+ from mukulcore.decorators.retry import retry
2
+
3
+
4
+ @retry(max_attempts=2, delay=0.0)
5
+ def flaky_function():
6
+ if flaky_function.calls == 0:
7
+ flaky_function.calls += 1
8
+ raise ValueError("fail")
9
+ flaky_function.calls += 1
10
+ return "ok"
11
+
12
+
13
+ flaky_function.calls = 0
14
+
15
+
16
+ def test_retry_succeeds_after_retry():
17
+ assert flaky_function() == "ok"
@@ -0,0 +1,5 @@
1
+ from mukulcore.tools.calculator import add
2
+
3
+
4
+ def test_addition():
5
+ assert add(2, 3) == 5