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
46 changes: 10 additions & 36 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,58 +2,32 @@ name: Publish Python Package

on:
push:
branches: [main]
tags:
- 'v*' # Triggers on tags like v1.0, v2.3.4

jobs:
deploy:
runs-on: ubuntu-latest
environment: pypi
permissions:
contents: write
id-token: write
id-token: write # Required for PyPI publishing

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.13"

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install build twine
- name: Install uv
uses: astral-sh/setup-uv@v6

- name: Configure Git
- name: Install dependencies and build
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"

- name: Bump version and create tag
run: |
# Get the current version from pyproject.toml
current_version=$(grep '^version = ' pyproject.toml | sed -e 's/version = "//' -e 's/"//')

# Increment the patch version (e.g., 0.1.0 -> 0.1.1)
new_version=$(echo $current_version | awk -F. '{$NF = $NF + 1;} 1' | sed 's/ /./g')

# Update pyproject.toml with the new version
sed -i "s/version = \"$current_version\"/version = \"$new_version\"/" pyproject.toml

# Commit and tag the new version
git add pyproject.toml
git commit -m "chore(release): version $new_version"
git tag "v$new_version"
git push
git push --tags

- name: Build package
run: python -m build
uv sync --all-extras
uv build

- name: Publish package to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_API_TOKEN }}
uses: pypa/gh-action-pypi-publish@release/v1
25 changes: 8 additions & 17 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@ jobs:
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install uv
uses: astral-sh/setup-uv@v3
uses: astral-sh/setup-uv@v6

- name: Install dependencies
run: |
uv sync --dev
uv sync --all-extras

- name: Lint and format check with ruff
run: |
Expand All @@ -39,39 +39,30 @@ jobs:

- name: Test with pytest
run: |
uv run pytest --cov=src/agentvisa --cov-report=xml --cov-report=term-missing

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: ./coverage.xml
flags: unittests
name: codecov-umbrella
fail_ci_if_error: false
uv run pytest

# Separate job for testing on different OS
test-os:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
os: [windows-latest, macos-latest]
python-version: ["3.13"]

steps:
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install uv
uses: astral-sh/setup-uv@v3
uses: astral-sh/setup-uv@v6

- name: Install dependencies
run: |
uv sync --dev
uv sync --all-extras

- name: Test with pytest
run: |
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ clean: ## Clean build artifacts
find . -type f -name "*.pyc" -delete

build: clean ## Build package
python -m build
uv build

publish: build ## Publish to PyPI
twine upload dist/*
Expand Down
127 changes: 93 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# agentvisa-python
# AgentVisa Python SDK

[![Tests](https://github.com/your-org/agentvisa-python/workflows/Tests/badge.svg)](https://github.com/your-org/agentvisa-python/actions)
[![Tests](https://github.com/AgentVisa/agentvisa-python/workflows/Tests/badge.svg)](https://github.com/AgentVisa/agentvisa-python/actions)
[![PyPI version](https://badge.fury.io/py/agentvisa.svg)](https://badge.fury.io/py/agentvisa)
[![Python Support](https://img.shields.io/pypi/pyversions/agentvisa.svg)](https://pypi.org/project/agentvisa/)

The official Python SDK for the [AgentVisa API](https://agentvisa.dev). Simple, fast, and reliable.
The official Python SDK for the [AgentVisa API](https://agentvisa.dev).

## Quick Start

Expand All @@ -18,12 +18,12 @@ import agentvisa
# Initialize the SDK
agentvisa.init(api_key="your-api-key")

# Create a delegation
# Create a delegation (type defaults to "ephemeral")
delegation = agentvisa.create_delegation(
end_user_identifier="user123",
scopes=["read", "write"]
scopes=["read", "write"],
)
print(f"Created delegation: {delegation['id']}")
print(f"Credential: {delegation['credential'][:12]}... (agent_id={delegation['agent_id']})")
```

## Installation
Expand All @@ -40,7 +40,7 @@ uv add agentvisa

## Authentication

Get your API key from the [AgentVisa Dashboard](https://dashboard.agentvisa.dev).
Get your API key from the [AgentVisa Dashboard](https://agentvisa.dev/dashboard).

```python
import agentvisa
Expand All @@ -64,7 +64,8 @@ agentvisa.init(api_key="your-api-key")
delegation = agentvisa.create_delegation(
end_user_identifier="user123",
scopes=["read", "write", "admin"],
expires_in=7200 # 2 hours
expires_in=7200, # 2 hours
metadata={"description": "Test agent"},
)
```

Expand All @@ -86,23 +87,92 @@ delegation = client.delegations.create(
)
```

### Custom Base URL
## Integrating with LangChain

You can easily secure LangChain agents by creating a custom tool that wraps AgentVisa. This ensures that every time an agent needs to perform a privileged action, it acquires a fresh, scoped, short-lived credential tied to the end-user.

This example shows how to create a secure "email sending" tool.

### 1. Create the AgentVisa-powered Tool

The tool's `_run` method will call `agentvisa.create_delegation` to get a secure token just before it performs its action.

```python
from agentvisa import AgentVisaClient
from langchain.tools import BaseTool
import agentvisa

# For development or enterprise installations
client = AgentVisaClient(
api_key="your-api-key",
base_url="https://your-instance.agentvisa.dev/v1"
# Initialize AgentVisa once in your application
agentvisa.init(api_key="your-api-key")

class SecureEmailTool(BaseTool):
name = "send_email"
description = "Use this tool to send an email."

def _run(self, to: str, subject: str, body: str, user_id: str):
"""Sends an email securely using an AgentVisa token."""

# 1. Get a short-lived, scoped credential from AgentVisa
try:
delegation = agentvisa.create_delegation(
end_user_identifier=user_id,
scopes=["send:email"]
)
token = delegation.get("credential")
print(f"Successfully acquired AgentVisa for user '{user_id}' with scope 'send:email'")
except Exception as e:
return f"Error: Could not acquire AgentVisa. {e}"

# 2. Use the token to call your internal, secure email API
# Your internal API would verify this token before sending the email.
print(f"Calling internal email service with token: {token[:15]}...")
# response = requests.post(
# "https://internal-api.yourcompany.com/send-email",
# headers={"Authorization": f"Bearer {token}"},
# json={"to": to, "subject": subject, "body": body}
# )

# For this example, we'll simulate a successful call
return "Email sent successfully."

async def _arun(self, to: str, subject: str, body: str, user_id: str):
# LangChain requires an async implementation for tools
raise NotImplementedError("SecureEmailTool does not support async")
```

### 2. Add the Tool to your Agent

Now, you can provide this tool to your LangChain agent. When the agent decides to use the `send_email` tool, it will automatically generate a new, auditable AgentVisa.

```python
from langchain.agents import initialize_agent, AgentType
from langchain.chat_models import ChatOpenAI

# Initialize your LLM
llm = ChatOpenAI(model_name="gpt-4o", temperature=0)

# Create an instance of your secure tool
tools = [SecureEmailTool()]

# Initialize the agent
agent = initialize_agent(
tools,
llm,
agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
verbose=True
)

# Run the agent
# The agent will correctly parse the user_id and pass it to the tool
agent.run("Please send an email to team@example.com with the subject 'Project Update' and body 'The new feature is live.' for user_id 'user_anne'.")
```

This pattern provides the perfect combination of LangChain's powerful reasoning capabilities with AgentVisa's secure, auditable credentialing system.

## API Reference

### Delegations

#### `create_delegation(end_user_identifier, scopes, expires_in=3600)`
#### `create_delegation(end_user_identifier, scopes, expires_in=3600, *, delegation_type="ephemeral", metadata=None, timeout=15)`

Create a new agent delegation.

Expand All @@ -112,7 +182,8 @@ Create a new agent delegation.
- `expires_in` (int): Expiration time in seconds (default: 3600)

**Returns:**
Dict containing delegation details including `id`, `token`, and `expires_at`.
Dict containing delegation details including `agent_id`, `credential`, and `expires_at`.
For backward compatibility the dict also includes aliases: `id` mirrors `agent_id`, and `token` mirrors `credential`.

**Example:**
```python
Expand Down Expand Up @@ -152,22 +223,11 @@ cd agentvisa-python
make install
```

### Testing

```bash
make test
```

### Linting

```bash
make lint
```

### Type Checking
### Check the code
Run all checks (format, lint, typecheck, test)

```bash
make typecheck
make check
```

## Contributing
Expand All @@ -182,10 +242,9 @@ make typecheck

## Support

- [Documentation](https://docs.agentvisa.dev)
- [API Reference](https://docs.agentvisa.dev/api)
- [Issues](https://github.com/your-org/agentvisa-python/issues)
- [Discord Community](https://discord.gg/agentvisa)
- [Documentation](https://agentvisa.dev/docs)
- [Issues](https://github.com/AgentVisa/agentvisa-python/issues)
- [Discord Community](https://discord.gg/ZupkwFbvqC)

## License

Expand Down
13 changes: 3 additions & 10 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ version = "0.1.0"
description = "The official Python SDK for the AgentVisa API."
readme = "README.md"
authors = [
{ name = "Chris Clapham", email = "chris.jim.clapham@outlook.com" }
{ name = "Chris Clapham", email = "chris@agentvisa.dev" }
]
license = { text = "MIT" }
requires-python = ">=3.13"
dependencies = [
"requests>=2.25.0"
"requests>=2.25.0",
"pydantic>=2.5"
]
keywords = ["agentvisa", "api", "sdk", "agent", "delegation"]
classifiers = [
Expand Down Expand Up @@ -100,11 +101,3 @@ strict_equality = true
[[tool.mypy.overrides]]
module = "tests.*"
disallow_untyped_defs = false

[dependency-groups]
dev = [
"pytest>=8.4.1",
"responses>=0.25.7",
]


Loading
Loading