Skip to content

Commit 9968096

Browse files
authored
Merge branch 'main' into fix-mock
2 parents 7ad3f54 + ffea23b commit 9968096

File tree

11 files changed

+737
-59
lines changed

11 files changed

+737
-59
lines changed

.claude/rules/nix-workflow.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# Nix Workflow
2+
3+
This rule provides guidance on Nix usage in the StackOne AI Python SDK.
4+
5+
## Development Environment
6+
7+
The project uses `flake.nix` with flake-parts to define the development environment. Enter it with `nix develop`.
8+
9+
### Adding Development Tools
10+
11+
To add a new tool to the development environment, add it to `buildInputs` in `flake.nix`:
12+
13+
```nix
14+
devShells.default = pkgs.mkShellNoCC {
15+
buildInputs = with pkgs; [
16+
uv
17+
ty
18+
just
19+
nixfmt-rfc-style
20+
21+
# your new tool here
22+
new-tool
23+
];
24+
};
25+
```
26+
27+
### Treefmt and Git Hooks
28+
29+
The flake includes:
30+
31+
- **treefmt-nix**: Unified formatting (nixfmt, ruff, oxfmt)
32+
- **git-hooks.nix**: Pre-commit hooks (gitleaks, treefmt, ty)
33+
34+
These are automatically installed when entering the dev shell.
35+
36+
## CI Workflow
37+
38+
CI uses `nix profile install` via the `.github/actions/setup-nix/action.yaml` composite action.
39+
40+
### Adding Tools to CI Jobs
41+
42+
Specify tools in the `tools` input of the setup-nix action:
43+
44+
```yaml
45+
- name: Setup Nix
46+
uses: ./.github/actions/setup-nix
47+
with:
48+
tools: uv ty just bun pnpm_10
49+
```
50+
51+
The action installs packages using:
52+
53+
```bash
54+
nix profile install --inputs-from . nixpkgs#tool1 nixpkgs#tool2
55+
```
56+
57+
### CI Tool Configuration
58+
59+
- **Default tools**: `uv ty just` (defined in action.yaml)
60+
- **Skip uv sync**: Set `skip-uv-sync: 'true'` for jobs that don't need Python dependencies
61+
62+
### Example: Adding a New Tool to CI Job
63+
64+
```yaml
65+
ci:
66+
runs-on: ubuntu-latest
67+
steps:
68+
- name: Checkout repository
69+
uses: actions/checkout@v4
70+
with:
71+
submodules: true
72+
- name: Setup Nix
73+
uses: ./.github/actions/setup-nix
74+
with:
75+
tools: uv ty just new-tool
76+
- name: Run Lint
77+
run: just lint
78+
```
79+
80+
## Notes
81+
82+
- The project uses flake-parts for modular flake configuration
83+
- Git submodules are initialised automatically in dev shell and CI
84+
- MCP mock server dependencies (pnpm) are installed for testing
Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
name: "Setup Nix"
2-
description: "Install Nix and configure Cachix"
2+
description: "Install Nix and configure cache"
3+
inputs:
4+
tools:
5+
description: 'Space-separated list of nixpkgs packages to install (e.g., "uv ty just")'
6+
required: false
7+
default: "uv ty just"
8+
skip-uv-sync:
9+
description: "Skip uv sync step (useful for jobs that do not need Python dependencies)"
10+
required: false
11+
default: "false"
312
runs:
413
using: "composite"
514
steps:
@@ -8,12 +17,34 @@ runs:
817
with:
918
github_access_token: ${{ github.token }}
1019

11-
- name: Setup Cachix (numtide)
12-
uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
13-
with:
14-
name: numtide
15-
authToken: ""
20+
- name: Install tools from nixpkgs
21+
shell: bash
22+
run: |
23+
tools="${{ inputs.tools }}"
24+
packages=""
25+
for tool in $tools; do
26+
packages="$packages nixpkgs#$tool"
27+
done
28+
nix profile install --inputs-from . $packages
29+
30+
- name: Initialise git submodules
31+
if: inputs.skip-uv-sync != 'true'
32+
shell: bash
33+
run: |
34+
# Only initialise if submodules exist but are not yet checked out
35+
if [ -f .gitmodules ] && [ ! -f vendor/stackone-ai-node/package.json ]; then
36+
git submodule update --init --recursive
37+
fi
38+
39+
- name: Install Python dependencies
40+
if: inputs.skip-uv-sync != 'true'
41+
shell: bash
42+
run: uv sync --all-extras
1643

17-
- name: Load Nix development environment
44+
- name: Install MCP mock server dependencies
45+
if: inputs.skip-uv-sync != 'true'
1846
shell: bash
19-
run: nix develop --command true
47+
run: |
48+
if [ -f vendor/stackone-ai-node/package.json ]; then
49+
cd vendor/stackone-ai-node && pnpm install --frozen-lockfile
50+
fi

.github/workflows/ci.yaml

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,18 @@ jobs:
2626

2727
- name: Setup Nix
2828
uses: ./.github/actions/setup-nix
29+
with:
30+
tools: gitleaks
31+
skip-uv-sync: "true"
2932

3033
- name: Run Gitleaks
31-
run: nix develop --command just gitleaks
34+
run: gitleaks detect --source . --config .gitleaks.toml
3235

3336
ci:
3437
runs-on: ubuntu-latest
3538
strategy:
3639
matrix:
37-
python-version: ["3.11", "3.13"]
38-
include:
39-
- python-version: "3.11"
40-
sync-extras: "--all-extras"
41-
- python-version: "3.13"
42-
sync-extras: "--all-extras"
40+
python-version: ["3.10", "3.11", "3.12", "3.13"]
4341
steps:
4442
- name: Checkout repository
4543
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
@@ -48,18 +46,17 @@ jobs:
4846

4947
- name: Setup Nix
5048
uses: ./.github/actions/setup-nix
51-
52-
- name: Install dependencies
53-
run: nix develop --command just install ${{ matrix.sync-extras }}
49+
with:
50+
tools: uv ty just bun pnpm_10 typescript-go
5451

5552
- name: Run Lint
56-
run: nix develop --command just lint
53+
run: just lint
5754

5855
- name: Run Ty
59-
run: nix develop --command just ty
56+
run: just ty
6057

6158
- name: Run Tests
62-
run: nix develop --command just test
59+
run: just test
6360

6461
coverage:
6562
runs-on: ubuntu-latest
@@ -72,12 +69,11 @@ jobs:
7269

7370
- name: Setup Nix
7471
uses: ./.github/actions/setup-nix
75-
76-
- name: Install dependencies
77-
run: nix develop --command just install --all-extras
72+
with:
73+
tools: uv just bun pnpm_10 typescript-go
7874

7975
- name: Run Tests with Coverage
80-
run: nix develop --command just coverage
76+
run: just coverage
8177

8278
- name: Create Coverage Badge
8379
uses: jaywcjlove/coverage-badges-cli@4e8975aa2628e3329126e7eee36724d07ed86fda # v2.2.0

.github/workflows/nix-flake.yaml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@ jobs:
2626
- name: Checkout repository
2727
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
2828

29-
- name: Setup Nix
30-
uses: ./.github/actions/setup-nix
29+
- name: Install Nix
30+
uses: cachix/install-nix-action@0b0e072294b088b73964f1d72dfdac0951439dbd # v31.8.4
31+
with:
32+
github_access_token: ${{ github.token }}
3133

3234
- name: Check flake
33-
run: nix flake check --all-systems --show-trace
35+
run: nix flake check --all-systems --print-build-logs --show-trace

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
1515
| **git-workflow** | All files | Commit conventions, branch strategy, PR guidelines |
1616
| **development-workflow** | All files | Code style, file naming, project conventions |
1717
| **release-please-standards** | All files | Release versioning with release-please |
18+
| **nix-workflow** | All files | Nix development environment and CI configuration |
1819
| **no-relative-imports** | `**/*.py` | Enforce absolute imports in Python files |
1920
| **package-installation** | `**/pyproject.toml` | UV package management standards |
2021
| **uv-scripts** | `scripts/**/*.py` | Utility script standards with UV |

flake.lock

Lines changed: 12 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flake.nix

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@
8989
};
9090
};
9191

92-
devShells.default = pkgs.mkShell {
92+
devShells.default = pkgs.mkShellNoCC {
9393
buildInputs = with pkgs; [
9494
uv
9595
ty

pyproject.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name = "stackone-ai"
33
version = "2.0.0"
44
description = "agents performing actions on your SaaS"
55
readme = "README.md"
6-
requires-python = ">=3.11"
6+
requires-python = ">=3.10"
77
authors = [
88
{ name = "StackOne", email = "support@stackone.com" }
99
]
@@ -12,6 +12,7 @@ classifiers = [
1212
"Intended Audience :: Developers",
1313
"License :: OSI Approved :: MIT License",
1414
"Programming Language :: Python :: 3",
15+
"Programming Language :: Python :: 3.10",
1516
"Programming Language :: Python :: 3.11",
1617
"Programming Language :: Python :: 3.12",
1718
"Programming Language :: Python :: 3.13",
@@ -77,7 +78,7 @@ markers = [
7778

7879
[tool.ruff]
7980
line-length = 110
80-
target-version = "py311"
81+
target-version = "py310"
8182

8283
[tool.ruff.lint]
8384
select = [

stackone_ai/integrations/langgraph.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
def _ensure_langgraph() -> None:
2525
try:
26-
from langgraph import prebuilt as _ # noqa: F401 # ty: ignore[unresolved-import]
26+
from langgraph import prebuilt as _ # noqa: F401
2727
except Exception as e: # pragma: no cover
2828
raise ImportError(
2929
"LangGraph is not installed. Install with `pip install langgraph` or "
@@ -45,7 +45,7 @@ def to_tool_node(tools: Tools | Sequence[BaseTool], **kwargs: Any) -> Any:
4545
for inclusion in a graph.
4646
"""
4747
_ensure_langgraph()
48-
from langgraph.prebuilt import ToolNode # ty: ignore[unresolved-import]
48+
from langgraph.prebuilt import ToolNode
4949

5050
langchain_tools = _to_langchain_tools(tools)
5151
return ToolNode(langchain_tools, **kwargs)
@@ -58,7 +58,7 @@ def to_tool_executor(tools: Tools | Sequence[BaseTool], **kwargs: Any) -> Any:
5858
This function now returns a ToolNode for compatibility.
5959
"""
6060
_ensure_langgraph()
61-
from langgraph.prebuilt import ToolNode # ty: ignore[unresolved-import]
61+
from langgraph.prebuilt import ToolNode
6262

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

86-
return _create(llm, _to_langchain_tools(tools), **kwargs)
86+
return _create(llm, _to_langchain_tools(tools), **kwargs) # ty: ignore[deprecated]

stackone_ai/models.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import json
55
import logging
66
from collections.abc import Sequence
7-
from datetime import UTC, datetime
7+
from datetime import datetime, timezone
88
from enum import Enum
99
from typing import Annotated, Any, ClassVar, TypeAlias, cast
1010
from urllib.parse import quote
@@ -196,7 +196,7 @@ def execute(
196196
StackOneAPIError: If the API request fails
197197
ValueError: If the arguments are invalid
198198
"""
199-
datetime.now(UTC)
199+
datetime.now(timezone.utc)
200200
feedback_options: JsonDict = {}
201201
result_payload: JsonDict | None = None
202202
response_status: int | None = None
@@ -266,7 +266,7 @@ def execute(
266266
status = "error"
267267
raise StackOneError(f"Request failed: {exc}") from exc
268268
finally:
269-
datetime.now(UTC)
269+
datetime.now(timezone.utc)
270270
metadata: JsonDict = {
271271
"http_method": self._execute_config.method,
272272
"url": url_used,

0 commit comments

Comments
 (0)