Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .claude/rules/development-workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ This rule provides code style guidelines and project conventions for the StackOn

- Full type annotations required for all public APIs
- Use Python 3.11+ typing features
- Run `just mypy` to verify type correctness
- Strict mypy configuration is enforced
- Run `just ty` to verify type correctness
- Strict ty configuration is enforced

## Pre-commit Hooks

Pre-commit hooks are configured for:

- ruff linting
- mypy type checking
- ty type checking

Run `just install` to set up hooks.

Expand All @@ -36,7 +36,7 @@ Run `just install` to set up hooks.
just install # Install dependencies and pre-commit hooks
just lint # Run ruff linting
just lint-fix # Auto-fix linting issues
just mypy # Run type checking
just ty # Run type checking
just test # Run all tests
just test-tools # Run tool-specific tests
just test-examples # Run example tests
Expand All @@ -48,7 +48,7 @@ just test-examples # Run example tests
- Use `.yaml` extension instead of `.yml` for YAML files
- Keep file names concise but meaningful

## Import Organisation
## Import Organization

- Standard library imports first
- Third-party imports second
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ jobs:
- name: Run Lint
run: nix develop --command just lint

- name: Run Mypy
run: nix develop --command just mypy
- name: Run Ty
run: nix develop --command just ty

- name: Run Tests
run: nix develop --command just test
10 changes: 5 additions & 5 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
| **no-relative-imports** | `**/*.py` | Enforce absolute imports in Python files |
| **package-installation** | `**/pyproject.toml` | UV package management standards |
| **uv-scripts** | `scripts/**/*.py` | Utility script standards with UV |
| **examples-standards** | `examples/**/*` | Example requirements and organisation |
| **examples-standards** | `examples/**/*` | Example requirements and organization |

## Project Overview

Expand All @@ -33,7 +33,7 @@ just install # Install dependencies and pre-commit hooks
# Code quality
just lint # Run ruff linting
just lint-fix # Auto-fix linting issues
just mypy # Run type checking
just ty # Run type checking

# Testing
just test # Run all tests
Expand Down Expand Up @@ -88,7 +88,7 @@ toolset = StackOneToolSet(
### Type Safety

- Full type annotations required (Python 3.11+)
- Strict mypy configuration
- Strict ty configuration
- Use generics for better IDE support

### Testing
Expand All @@ -100,7 +100,7 @@ toolset = StackOneToolSet(
## Important Considerations

1. **Dependencies**: See `package-installation` rule for uv dependency management
2. **Pre-commit**: Hooks configured for ruff and mypy - run on all commits
2. **Pre-commit**: Hooks configured for ruff and ty - run on all commits
3. **Python Version**: Requires Python >=3.11
4. **Error Handling**: Custom exceptions (`StackOneError`, `StackOneAPIError`)
5. **File Uploads**: Binary parameters auto-detected from OpenAPI specs
Expand All @@ -114,7 +114,7 @@ toolset = StackOneToolSet(
2. Parser automatically converts to tool definitions
3. Test with `make test-tools`

### Modifying Tool Behaviour
### Modifying Tool Behavior

- Core execution logic in `StackOneTool.execute()` method
- HTTP configuration via `ExecuteConfig` class
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ The Nix development environment includes:

- Python with uv package manager
- Automatic dependency installation
- Git hooks (treefmt + mypy) auto-configured
- Git hooks (treefmt + ty) auto-configured
- Consistent environment across all platforms

### Using pip/uv
Expand Down
8 changes: 4 additions & 4 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,16 @@

# Git hooks configuration
pre-commit = {
check.enable = false; # Skip check in flake (mypy needs Python env)
check.enable = false; # Skip check in flake (ty needs Python env)
settings.hooks = {
treefmt = {
enable = true;
package = config.treefmt.build.wrapper;
};
mypy = {
ty = {
enable = true;
name = "mypy";
entry = "${pkgs.uv}/bin/uv run mypy";
name = "ty";
entry = "${pkgs.uv}/bin/uv run ty check";
files = "^stackone_ai/";
language = "system";
types = [ "python" ];
Expand Down
4 changes: 2 additions & 2 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ test-examples:
uv run pytest examples

# Run type checking
mypy:
uv run mypy stackone_ai
ty:
uv run ty check stackone_ai

# Run typos spell checker
typos:
Expand Down
31 changes: 1 addition & 30 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,14 @@ examples = [

[dependency-groups]
dev = [
"mypy>=1.15.0",
"pytest>=8.3.4",
"pytest-asyncio>=0.25.3",
"pytest-cov>=6.0.0",
"pytest-snapshot>=0.9.0",
"responses>=0.25.8",
"ruff>=0.9.6",
"stackone-ai",
"types-requests>=2.31.0.20240311",
"ty>=0.0.3",
]

[tool.pytest.ini_options]
Expand Down Expand Up @@ -95,31 +94,3 @@ select = [
"C4", # flake8-comprehensions
"UP", # pyupgrade
]

[tool.mypy]
python_version = "3.10"
disallow_untyped_defs = true
disallow_incomplete_defs = true
check_untyped_defs = true
disallow_untyped_decorators = true
no_implicit_optional = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_return_any = true
warn_unreachable = true
exclude = [
"^.venv/",
]

[[tool.mypy.overrides]]
module = "bm25s"
ignore_missing_imports = true

[[tool.mypy.overrides]]
module = "langgraph.*"
ignore_missing_imports = true

[[tool.mypy.overrides]]
module = "mcp.*"
ignore_missing_imports = true
ignore_errors = true
18 changes: 5 additions & 13 deletions stackone_ai/integrations/langgraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,16 @@
from __future__ import annotations

from collections.abc import Sequence
from typing import TYPE_CHECKING, Any
from typing import Any

from langchain_core.tools import BaseTool

from stackone_ai.models import Tools

if TYPE_CHECKING: # pragma: no cover - only for typing
try:
from langgraph.prebuilt import ToolNode
except Exception: # pragma: no cover

class ToolNode: # type: ignore[no-redef]
pass


def _ensure_langgraph() -> None:
try:
from langgraph import prebuilt as _ # noqa: F401
from langgraph import prebuilt as _ # noqa: F401 # ty: ignore[unresolved-import]
except Exception as e: # pragma: no cover
raise ImportError(
"LangGraph is not installed. Install with `pip install langgraph` or "
Expand All @@ -53,7 +45,7 @@ def to_tool_node(tools: Tools | Sequence[BaseTool], **kwargs: Any) -> Any:
for inclusion in a graph.
"""
_ensure_langgraph()
from langgraph.prebuilt import ToolNode # local import with helpful error
from langgraph.prebuilt import ToolNode # ty: ignore[unresolved-import]

langchain_tools = _to_langchain_tools(tools)
return ToolNode(langchain_tools, **kwargs)
Expand All @@ -66,7 +58,7 @@ def to_tool_executor(tools: Tools | Sequence[BaseTool], **kwargs: Any) -> Any:
This function now returns a ToolNode for compatibility.
"""
_ensure_langgraph()
from langgraph.prebuilt import ToolNode # local import with helpful error
from langgraph.prebuilt import ToolNode # ty: ignore[unresolved-import]

langchain_tools = _to_langchain_tools(tools)
return ToolNode(langchain_tools, **kwargs)
Expand All @@ -89,6 +81,6 @@ def create_react_agent(llm: Any, tools: Tools | Sequence[BaseTool], **kwargs: An
`Tools` collection from this SDK.
"""
_ensure_langgraph()
from langgraph.prebuilt import create_react_agent as _create
from langgraph.prebuilt import create_react_agent as _create # ty: ignore[unresolved-import]

return _create(llm, _to_langchain_tools(tools), **kwargs)
4 changes: 2 additions & 2 deletions stackone_ai/meta_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def __init__(self, tools: list[StackOneTool], hybrid_alpha: float | None = None)

# Create BM25 index
self.bm25_retriever = bm25s.BM25()
corpus_tokens = bm25s.tokenize(corpus, stemmer=None, show_progress=False)
corpus_tokens = bm25s.tokenize(corpus, stemmer=None, show_progress=False) # ty: ignore[invalid-argument-type]
self.bm25_retriever.index(corpus_tokens)

# Create TF-IDF index
Expand All @@ -108,7 +108,7 @@ def search(self, query: str, limit: int = 5, min_score: float = 0.0) -> list[Met
fetch_limit = max(50, limit)

# Tokenize query for BM25
query_tokens = bm25s.tokenize([query], stemmer=None, show_progress=False)
query_tokens = bm25s.tokenize([query], stemmer=None, show_progress=False) # ty: ignore[invalid-argument-type]

# Search with BM25
bm25_results, bm25_scores = self.bm25_retriever.retrieve(
Expand Down
2 changes: 1 addition & 1 deletion stackone_ai/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ def to_langchain(self) -> BaseTool:
class StackOneLangChainTool(BaseTool):
name: str = parent_tool.name
description: str = parent_tool.description
args_schema: type[BaseModel] = schema_class
args_schema: type[BaseModel] = schema_class # ty: ignore[invalid-assignment]
func = staticmethod(parent_tool.execute) # Required by CrewAI

def _run(self, **kwargs: Any) -> Any:
Expand Down
6 changes: 3 additions & 3 deletions stackone_ai/toolset.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,9 @@ def _build_auth_header(api_key: str) -> str:

def _fetch_mcp_tools(endpoint: str, headers: dict[str, str]) -> list[_McpToolDefinition]:
try:
from mcp import types as mcp_types
from mcp.client.session import ClientSession
from mcp.client.streamable_http import streamablehttp_client
from mcp import types as mcp_types # ty: ignore[unresolved-import]
from mcp.client.session import ClientSession # ty: ignore[unresolved-import]
from mcp.client.streamable_http import streamablehttp_client # ty: ignore[unresolved-import]
except ImportError as exc: # pragma: no cover - depends on optional extra
raise ToolsetConfigError(
"MCP dependencies are required for fetch_tools. Install with 'pip install \"stackone-ai[mcp]\"'."
Expand Down
Loading
Loading