Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
6 changes: 2 additions & 4 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,9 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.9", "3.10", "3.13"]
python-version: ["3.11", "3.13"]
include:
- python-version: "3.9"
sync-extras: "--all-extras --no-extra mcp"
- python-version: "3.10"
- python-version: "3.11"
sync-extras: "--all-extras"
- python-version: "3.13"
sync-extras: "--all-extras"
Comment on lines +37 to 42
Copy link

Copilot AI Dec 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CI matrix tests Python 3.11 and 3.13, but skips Python 3.12. This is unusual and might be unintentional. Consider adding Python 3.12 to the matrix to ensure compatibility with all supported versions listed in the project classifiers (3.11, 3.12, 3.13).

Copilot uses AI. Check for mistakes.
Expand Down
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ StackOne AI provides a unified interface for accessing various SaaS tools throug

## Requirements

- Python 3.10+ (MCP extra required for `fetch_tools()`)
- Python 3.11+

## Installation

Expand Down Expand Up @@ -265,12 +265,10 @@ _ = app.invoke({"messages": [("user", "Get employee with id emp123") ]})
</details>

<details>
<summary>CrewAI Integration (Python 3.10+)</summary>
<summary>CrewAI Integration</summary>

CrewAI uses LangChain tools natively, making integration seamless:

> **Note**: CrewAI requires Python 3.10+. Install with `pip install 'stackone-ai[mcp,examples]'`

```python
from crewai import Agent, Crew, Task
from stackone_ai import StackOneToolSet
Expand Down
12 changes: 4 additions & 8 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "stackone-ai"
version = "0.3.4"
description = "agents performing actions on your SaaS"
readme = "README.md"
requires-python = ">=3.9"
requires-python = ">=3.11"
authors = [
{ name = "StackOne", email = "[email protected]" }
]
Expand All @@ -12,8 +12,6 @@ classifiers = [
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
Expand All @@ -26,7 +24,6 @@ dependencies = [
"bm25s>=0.2.2",
"numpy>=1.24.0",
"typing-extensions>=4.0.0",
"eval-type-backport; python_version<'3.10'", # TODO: Remove when Python 3.9 support is dropped
]

[build-system]
Expand All @@ -43,12 +40,11 @@ packages = ["stackone_ai"]
"py.typed" = "py.typed"

[project.optional-dependencies]
# TODO: Remove python_version conditions when Python 3.9 support is dropped
mcp = [
"mcp>=1.3.0; python_version>='3.10'",
"mcp>=1.3.0",
]
examples = [
"crewai>=0.102.0; python_version>='3.10'",
"crewai>=0.102.0",
"langchain-openai>=0.3.6",
"langgraph>=0.2.0",
"openai>=1.63.2",
Expand Down Expand Up @@ -82,7 +78,7 @@ markers = [

[tool.ruff]
line-length = 110
target-version = "py39"
target-version = "py311"

[tool.ruff.lint]
select = [
Expand Down
2 changes: 1 addition & 1 deletion stackone_ai/meta_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ def search(self, query: str, limit: int = 5, min_score: float = 0.0) -> list[Met
score_map: dict[str, dict[str, float]] = {}

# Add BM25 scores
for idx, score in zip(bm25_results[0], bm25_scores[0]):
for idx, score in zip(bm25_results[0], bm25_scores[0], strict=True):
tool_name = self.tool_names[idx]
# Normalize BM25 score to 0-1 range
normalized_score = float(1 / (1 + np.exp(-score / 10)))
Expand Down
12 changes: 4 additions & 8 deletions stackone_ai/models.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
# TODO: Remove when Python 3.9 support is dropped
from __future__ import annotations

import base64
import json
import logging
from collections.abc import Sequence
from datetime import datetime, timezone
from datetime import UTC, datetime
from enum import Enum
from typing import Annotated, Any, ClassVar, cast
from typing import Annotated, Any, ClassVar, TypeAlias, cast
from urllib.parse import quote

import httpx
from langchain_core.tools import BaseTool
from pydantic import BaseModel, BeforeValidator, Field, PrivateAttr

# TODO: Remove when Python 3.9 support is dropped
from typing_extensions import TypeAlias

# Type aliases for common types
JsonDict: TypeAlias = dict[str, Any]
Headers: TypeAlias = dict[str, str]
Expand Down Expand Up @@ -200,7 +196,7 @@ def execute(
StackOneAPIError: If the API request fails
ValueError: If the arguments are invalid
"""
datetime.now(timezone.utc)
datetime.now(UTC)
feedback_options: JsonDict = {}
result_payload: JsonDict | None = None
response_status: int | None = None
Expand Down Expand Up @@ -270,7 +266,7 @@ def execute(
status = "error"
raise StackOneError(f"Request failed: {exc}") from exc
finally:
datetime.now(timezone.utc)
datetime.now(UTC)
metadata: JsonDict = {
"http_method": self._execute_config.method,
"url": url_used,
Expand Down
2 changes: 1 addition & 1 deletion stackone_ai/utils/tfidf_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ def build(self, corpus: list[TfidfDocument]) -> None:

# Build document vectors
self.docs = []
for doc, tokens in zip(corpus, docs_tokens):
for doc, tokens in zip(corpus, docs_tokens, strict=True):
# Compute term frequency (TF)
tf: dict[int, int] = {}
for token in tokens:
Expand Down
Loading