Skip to content

Commit 9a1179d

Browse files
authored
Python SDK for AgentFS (#83)
Generate python SDK based on the Typescript SDK which uses latest `pyturso` package This PR updates release.yml workflow and require `PYPI_API_TOKEN` secrets to be set for the repository
2 parents 05bc2f1 + 1a17e68 commit 9a1179d

28 files changed

Lines changed: 4146 additions & 0 deletions
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
---
2+
allowed-tools: Bash(git commit:*), Bash(git add:*), Bash(git status:*), Bash(mkdir:*), Bash(uv:*), Read, Edit(sdk/python/**), Write(sdk/python/**), Edit(.github/workflows/python.yml), Write(.github/workflows/python.yml), Write(.github/workflows/release.yml), Edit(.github/workflows/release.yml)
3+
argument-hint: [ts-change-sha-commit]
4+
description: Generate Python SDK for agentfs based on the Typescript SDK
5+
---
6+
7+
## Dev rules
8+
9+
- COMMIT your changes in the end with detailed message with the motivation of changes and traces of your actions
10+
- USE `uv` with `--directory sdk/python` command in order to avoid `cd` to the subdirectory
11+
- ALWAYS USE pathes relative to the project root
12+
- DO NOT EVER `cd` into the directories - tool permissions will not be validated properly
13+
- USE ONLY SIMPLE "ls", "grep", "find", "cat" Bash commands and native Claude Code tools - otherwise permission will be blocked
14+
15+
## Context
16+
17+
- You must generate Python SDK with the API similar to the current Typescript SDK located at ../../sdk/typescript
18+
- The package name is `agentfs-sdk` and import path must be `agentfs_sdk`
19+
- You must transfer all tests from Typescript SDK to the Python
20+
- Last time, python sdk was updated based on the comment $1
21+
- If value is "unspecified" then regenerate SDK from scratch
22+
- If value is set - FOCUS on the diff between the current state and specified commit hash
23+
- The primary changes are in the Typescript SDK but changes outside of it also can contribute to the process
24+
- For example, command prompt in .claude directory influence process heavily
25+
- Use `turso.aio` python package which provide API similar to `aiosqlite`
26+
- Use simple setup with builtin uv ruff formatter
27+
- Use pytest for testing
28+
- Use ty for type checking
29+
- Maintain CI for linting and checking at .github/workflows/python.yml similar to the TS workflow at .github/workflows/typescript.yml
30+
- Maintain CI for publishing the Python package to the PyPI in the .github/workflows/release.yml
31+
- Use `PYPI_API_TOKEN` secret
32+
33+
```py
34+
class Connection:
35+
def __init__(self, connector: Callable[[], BlockingConnection]) -> None:
36+
async def close(self) -> None:
37+
def __await__(self):
38+
async def __aenter__(self) -> "Connection":
39+
async def __aexit__(self, exc_type, exc, tb) -> None:
40+
def cursor(self, factory: Optional[Callable[[BlockingConnection], BlockingCursor]] = None) -> "Cursor":
41+
async def execute(self, sql: str, parameters: Sequence[Any] | Mapping[str, Any] = ()) -> "Cursor":
42+
async def executemany(self, sql: str, parameters: Iterable[Sequence[Any] | Mapping[str, Any]]) -> "Cursor":
43+
async def executescript(self, sql_script: str) -> "Cursor":
44+
async def commit(self) -> None:
45+
async def rollback(self) -> None:
46+
class Cursor:
47+
async def close(self) -> None:
48+
# named parameters not supported at the moment
49+
async def execute(self, sql: str, parameters: Sequence[Any] | Mapping[str, Any] = ()) -> "Cursor":
50+
async def executemany(self, sql: str, parameters: Iterable[Sequence[Any] | Mapping[str, Any]]) -> "Cursor":
51+
async def executescript(self, sql_script: str) -> "Cursor":
52+
async def fetchone(self) -> Any:
53+
async def fetchmany(self, size: Optional[int] = None) -> list[Any]:
54+
async def fetchall(self) -> list[Any]:
55+
async def __aenter__(self) -> "Cursor":
56+
async def __aexit__(self, exc_type, exc, tb) -> None:
57+
58+
# as Connection is awaitable - caller can use await connect(...)
59+
def connect(database: str) -> Connection:
60+
```
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
allowed-tools: Bash(git commit:*), Bash(git add:*), Bash(git status:*), Bash(mkdir:*), Bash(uv:*), Read, Edit(sdk/python/**), Write(sdk/python/**), Bash(grep:*), Bash(sed:*)
3+
argument-hint: [prompt]
4+
description: Command to refactor Python SDK
5+
---
6+
7+
## Dev rules
8+
9+
- COMMIT your changes in the end with detailed message with the motivation of changes and traces of your actions
10+
- USE `uv` with `--directory sdk/python` command in order to avoid `cd` to the subdirectory
11+
- ALWAYS USE pathes relative to the project root
12+
- DO NOT EVER `cd` into the directories - tool permissions will not be validated properly
13+
- USE ONLY SIMPLE "ls", "grep", "find", "cat" Bash commands and native Claude Code tools - otherwise permission will be blocked
14+
- FORMAT AND TEST code with uv
15+
16+
## Task
17+
18+
$1
19+
20+
## Context
21+
22+
- You must refactor Python SDK with the API similar to the current Typescript SDK located at ../../sdk/typescript
23+
- The Python API should be similar to the Typescript one if possible - so inspect Typescript code before introducing any breaking change in the PUBLIC API

.devcontainer/Dockerfile

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
FROM node:20
2+
3+
ARG TZ
4+
ARG CLAUDE_CODE_VERSION
5+
ARG GIT_DELTA_VERSION
6+
ARG ZSH_IN_DOCKER_VERSION
7+
ARG RUST_VERSION
8+
ARG PYTHON_VERSION
9+
10+
ENV TZ="$TZ"
11+
12+
# Install build dependencies needed for further installations
13+
RUN apt-get update && apt-get install -y --no-install-recommends \
14+
wget \
15+
curl \
16+
ca-certificates \
17+
build-essential \
18+
pkg-config \
19+
gnupg2 \
20+
python${PYTHON_VERSION}-dev \
21+
sudo \
22+
&& apt-get clean && rm -rf /var/lib/apt/lists/*
23+
24+
# Ensure default node user has access to /usr/local/share
25+
RUN mkdir -p /usr/local/share/npm-global && \
26+
chown -R node:node /usr/local/share
27+
28+
ARG USERNAME=node
29+
30+
# Persist bash history.
31+
RUN SNIPPET="export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhistory/.bash_history" \
32+
&& mkdir /commandhistory \
33+
&& touch /commandhistory/.bash_history \
34+
&& chown -R $USERNAME /commandhistory
35+
36+
# Set `DEVCONTAINER` environment variable to help with orientation
37+
ENV DEVCONTAINER=true
38+
39+
# Create workspace and config directories and set permissions
40+
RUN mkdir -p /workspace /home/node/.claude && \
41+
chown -R node:node /workspace /home/node/.claude
42+
43+
WORKDIR /workspace
44+
45+
RUN ARCH=$(dpkg --print-architecture) && \
46+
wget "https://github.com/dandavison/delta/releases/download/${GIT_DELTA_VERSION}/git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb" && \
47+
sudo dpkg -i "git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb" && \
48+
rm "git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb"
49+
50+
# Set up non-root user
51+
USER node
52+
53+
# Install Rust
54+
ENV RUSTUP_HOME=/home/node/.rustup \
55+
CARGO_HOME=/home/node/.cargo
56+
ENV PATH=$PATH:/home/node/.cargo/bin
57+
58+
RUN curl https://sh.rustup.rs -sSf | sh -s -- \
59+
-y \
60+
--default-toolchain ${RUST_VERSION} \
61+
--profile minimal \
62+
&& rustup component add rustfmt clippy
63+
64+
# Install Python
65+
66+
ENV UV_HOME=/home/node/.uv
67+
ENV PATH=$PATH:/home/node/.cargo/bin:/home/node/.local/bin
68+
69+
RUN curl -Ls https://astral.sh/uv/install.sh | sh
70+
RUN uv python install ${PYTHON_VERSION}
71+
72+
# Check installation
73+
74+
RUN rustc --version \
75+
&& cargo --version \
76+
&& uv --version
77+
78+
# Install global packages
79+
ENV NPM_CONFIG_PREFIX=/usr/local/share/npm-global
80+
ENV PATH=$PATH:/usr/local/share/npm-global/bin
81+
82+
# Set the default shell to zsh rather than sh
83+
ENV SHELL=/bin/zsh
84+
85+
# Set the default editor and visual
86+
ENV EDITOR=vim
87+
ENV VISUAL=vim
88+
89+
# Switch back to root to install runtime dependencies
90+
USER root
91+
92+
# Install runtime dependencies for final image
93+
RUN apt-get update && apt-get install -y --no-install-recommends \
94+
traceroute \
95+
iputils-ping \
96+
sqlite3 \
97+
less \
98+
git \
99+
procps \
100+
fzf \
101+
zsh \
102+
man-db \
103+
unzip \
104+
gh \
105+
iptables \
106+
ipset \
107+
iproute2 \
108+
dnsutils \
109+
aggregate \
110+
jq \
111+
nano \
112+
vim \
113+
&& apt-get clean && rm -rf /var/lib/apt/lists/*
114+
115+
# Switch back to node user
116+
USER node
117+
118+
# Default powerline10k theme
119+
RUN sh -c "$(wget -O- https://github.com/deluan/zsh-in-docker/releases/download/v${ZSH_IN_DOCKER_VERSION}/zsh-in-docker.sh)" -- \
120+
-p git \
121+
-p fzf \
122+
-a "source /usr/share/doc/fzf/examples/key-bindings.zsh" \
123+
-a "source /usr/share/doc/fzf/examples/completion.zsh" \
124+
-a "export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhistory/.bash_history" \
125+
-x
126+
127+
# Install Claude
128+
RUN npm install -g @anthropic-ai/claude-code@${CLAUDE_CODE_VERSION}

.devcontainer/Dockerfile.squid

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
FROM ubuntu/squid:latest
2+
RUN apt-get update && apt-get install -y netcat-openbsd && rm -rf /var/lib/apt/lists/*

.devcontainer/devcontainer.json

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{
2+
"name": "agentfs sandbox",
3+
"dockerComposeFile": ["docker-compose.yml"],
4+
"service": "agentfs",
5+
"remoteUser": "node",
6+
"workspaceFolder": "/workspace",
7+
"waitFor": "postStartCommand",
8+
"customizations": {
9+
"vscode": {
10+
"extensions": [
11+
"anthropic.claude-code",
12+
"eamodio.gitlens",
13+
14+
// Rust
15+
"rust-lang.rust-analyzer",
16+
17+
// Python
18+
"ms-python.python",
19+
"ms-python.vscode-pylance",
20+
21+
// JavaScript / TypeScript
22+
"dbaeumer.vscode-eslint",
23+
"esbenp.prettier-vscode",
24+
"ms-vscode.vscode-typescript-next"
25+
],
26+
"settings": {
27+
"editor.formatOnSave": true,
28+
"editor.defaultFormatter": "esbenp.prettier-vscode",
29+
"editor.codeActionsOnSave": {
30+
"source.fixAll.eslint": "explicit"
31+
},
32+
"terminal.integrated.defaultProfile.linux": "zsh",
33+
"terminal.integrated.profiles.linux": {
34+
"bash": {
35+
"path": "bash",
36+
"icon": "terminal-bash"
37+
},
38+
"zsh": {
39+
"path": "zsh"
40+
}
41+
}
42+
}
43+
}
44+
}
45+
}

.devcontainer/docker-compose.yml

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
version: "3.9"
2+
3+
services:
4+
proxy:
5+
build:
6+
context: .
7+
dockerfile: Dockerfile.squid
8+
networks: [sandbox, egress]
9+
volumes:
10+
- ./squid.conf:/etc/squid/squid.conf:ro
11+
healthcheck:
12+
test: ["CMD", "nc", "-z", "127.0.0.1", "3128"]
13+
interval: 1s
14+
timeout: 5s
15+
retries: 10
16+
start_period: 1s
17+
agentfs:
18+
depends_on:
19+
proxy:
20+
condition: service_healthy
21+
build:
22+
context: .
23+
dockerfile: Dockerfile
24+
args:
25+
TZ: ${TZ:-America/Los_Angeles}
26+
CLAUDE_CODE_VERSION: "latest"
27+
GIT_DELTA_VERSION: "0.18.2"
28+
ZSH_IN_DOCKER_VERSION: "1.2.0"
29+
GO_VERSION: "1.24.10"
30+
RUST_VERSION: "1.88.0"
31+
PYTHON_VERSION: "3.11"
32+
environment:
33+
NODE_OPTIONS: "--max-old-space-size=4096"
34+
CLAUDE_CONFIG_DIR: "/home/node/.claude"
35+
POWERLEVEL9K_DISABLE_GITSTATUS: "true"
36+
HTTP_PROXY: "http://proxy:3128"
37+
HTTPS_PROXY: "http://proxy:3128"
38+
ALL_PROXY: "http://proxy:3128"
39+
NO_PROXY: "localhost,127.0.0.1"
40+
networks: [sandbox]
41+
volumes:
42+
- ..:/workspace:delegated
43+
- claude-code-bashhistory:/commandhistory
44+
- claude-code-config:/home/node/.claude
45+
46+
cap_add:
47+
- NET_ADMIN
48+
- NET_RAW
49+
50+
init: true
51+
tty: true
52+
53+
volumes:
54+
claude-code-bashhistory:
55+
claude-code-config:
56+
networks:
57+
sandbox:
58+
internal: true
59+
egress:
60+
driver: bridge

.devcontainer/squid.conf

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
http_port 3128
2+
3+
# DNS
4+
dns_v4_first on
5+
6+
# Allowed domains
7+
acl allowed dstdomain \
8+
.pythonhosted.org \
9+
.pypi.org \
10+
.crates.io \
11+
.npmjs.org \
12+
.github.com \
13+
.githubusercontent.com \
14+
.go.dev \
15+
.golang.org \
16+
.anthropic.com \
17+
.openai.com \
18+
.sentry.io \
19+
.statsig.com \
20+
.visualstudio.com \
21+
.windows.net
22+
23+
# Allow HTTPS CONNECT only to allowed domains
24+
acl SSL_ports port 443
25+
acl Safe_ports port 80 443
26+
acl CONNECT method CONNECT
27+
28+
http_access deny !Safe_ports
29+
http_access deny CONNECT !SSL_ports
30+
http_access allow allowed
31+
http_access deny all
32+
33+
# Logging
34+
access_log stdio:/var/log/squid/access.log

0 commit comments

Comments
 (0)