add skyvern sdk (#1741)

This commit is contained in:
LawyZheng 2025-02-07 02:48:13 +08:00 committed by GitHub
parent cd64639faa
commit 73a69edbbc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 651 additions and 4 deletions

311
poetry.lock generated
View file

@ -550,6 +550,21 @@ files = [
{file = "backoff-2.2.1.tar.gz", hash = "sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba"},
]
[[package]]
name = "backports-tarfile"
version = "1.2.0"
description = "Backport of CPython tarfile module"
optional = false
python-versions = ">=3.8"
files = [
{file = "backports.tarfile-1.2.0-py3-none-any.whl", hash = "sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34"},
{file = "backports_tarfile-1.2.0.tar.gz", hash = "sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991"},
]
[package.extras]
docs = ["furo", "jaraco.packaging (>=9.3)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
testing = ["jaraco.test", "pytest (!=8.0.*)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)"]
[[package]]
name = "beautifulsoup4"
version = "4.12.3"
@ -626,6 +641,29 @@ urllib3 = {version = ">=1.25.4,<2.2.0 || >2.2.0,<3", markers = "python_version >
[package.extras]
crt = ["awscrt (==0.19.19)"]
[[package]]
name = "build"
version = "1.2.2.post1"
description = "A simple, correct Python build frontend"
optional = false
python-versions = ">=3.8"
files = [
{file = "build-1.2.2.post1-py3-none-any.whl", hash = "sha256:1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5"},
{file = "build-1.2.2.post1.tar.gz", hash = "sha256:b36993e92ca9375a219c99e606a122ff365a760a2d4bba0caa09bd5278b608b7"},
]
[package.dependencies]
colorama = {version = "*", markers = "os_name == \"nt\""}
packaging = ">=19.1"
pyproject_hooks = "*"
[package.extras]
docs = ["furo (>=2023.08.17)", "sphinx (>=7.0,<8.0)", "sphinx-argparse-cli (>=1.5)", "sphinx-autodoc-typehints (>=1.10)", "sphinx-issues (>=3.0.0)"]
test = ["build[uv,virtualenv]", "filelock (>=3)", "pytest (>=6.2.4)", "pytest-cov (>=2.12)", "pytest-mock (>=2)", "pytest-rerunfailures (>=9.1)", "pytest-xdist (>=1.34)", "setuptools (>=42.0.0)", "setuptools (>=56.0.0)", "setuptools (>=56.0.0)", "setuptools (>=67.8.0)", "wheel (>=0.36.0)"]
typing = ["build[uv]", "importlib-metadata (>=5.1)", "mypy (>=1.9.0,<1.10.0)", "tomli", "typing-extensions (>=3.7.4.3)"]
uv = ["uv (>=0.1.18)"]
virtualenv = ["virtualenv (>=20.0.35)"]
[[package]]
name = "bytecode"
version = "0.16.0"
@ -1196,6 +1234,17 @@ idna = ["idna (>=3.7)"]
trio = ["trio (>=0.23)"]
wmi = ["wmi (>=1.5.1)"]
[[package]]
name = "docutils"
version = "0.21.2"
description = "Docutils -- Python Documentation Utilities"
optional = false
python-versions = ">=3.9"
files = [
{file = "docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2"},
{file = "docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f"},
]
[[package]]
name = "ecdsa"
version = "0.19.0"
@ -1855,6 +1904,25 @@ files = [
[package.dependencies]
pyreadline3 = {version = "*", markers = "sys_platform == \"win32\" and python_version >= \"3.8\""}
[[package]]
name = "id"
version = "1.5.0"
description = "A tool for generating OIDC identities"
optional = false
python-versions = ">=3.8"
files = [
{file = "id-1.5.0-py3-none-any.whl", hash = "sha256:f1434e1cef91f2cbb8a4ec64663d5a23b9ed43ef44c4c957d02583d61714c658"},
{file = "id-1.5.0.tar.gz", hash = "sha256:292cb8a49eacbbdbce97244f47a97b4c62540169c976552e497fd57df0734c1d"},
]
[package.dependencies]
requests = "*"
[package.extras]
dev = ["build", "bump (>=1.3.2)", "id[lint,test]"]
lint = ["bandit", "interrogate", "mypy", "ruff (<0.8.2)", "types-requests"]
test = ["coverage[toml]", "pretend", "pytest", "pytest-cov"]
[[package]]
name = "identify"
version = "2.6.2"
@ -2036,6 +2104,64 @@ files = [
[package.extras]
colors = ["colorama (>=0.4.6)"]
[[package]]
name = "jaraco-classes"
version = "3.4.0"
description = "Utility functions for Python class constructs"
optional = false
python-versions = ">=3.8"
files = [
{file = "jaraco.classes-3.4.0-py3-none-any.whl", hash = "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790"},
{file = "jaraco.classes-3.4.0.tar.gz", hash = "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd"},
]
[package.dependencies]
more-itertools = "*"
[package.extras]
docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)"]
[[package]]
name = "jaraco-context"
version = "6.0.1"
description = "Useful decorators and context managers"
optional = false
python-versions = ">=3.8"
files = [
{file = "jaraco.context-6.0.1-py3-none-any.whl", hash = "sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4"},
{file = "jaraco_context-6.0.1.tar.gz", hash = "sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3"},
]
[package.dependencies]
"backports.tarfile" = {version = "*", markers = "python_version < \"3.12\""}
[package.extras]
doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
test = ["portend", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)"]
[[package]]
name = "jaraco-functools"
version = "4.1.0"
description = "Functools like those found in stdlib"
optional = false
python-versions = ">=3.8"
files = [
{file = "jaraco.functools-4.1.0-py3-none-any.whl", hash = "sha256:ad159f13428bc4acbf5541ad6dec511f91573b90fba04df61dafa2a1231cf649"},
{file = "jaraco_functools-4.1.0.tar.gz", hash = "sha256:70f7e0e2ae076498e212562325e805204fc092d7b4c17e0e86c959e249701a9d"},
]
[package.dependencies]
more-itertools = "*"
[package.extras]
check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"]
cover = ["pytest-cov"]
doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
enabler = ["pytest-enabler (>=2.2)"]
test = ["jaraco.classes", "pytest (>=6,!=8.1.*)"]
type = ["pytest-mypy"]
[[package]]
name = "jedi"
version = "0.19.2"
@ -2055,6 +2181,21 @@ docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alab
qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"]
testing = ["Django", "attrs", "colorama", "docopt", "pytest (<9.0.0)"]
[[package]]
name = "jeepney"
version = "0.8.0"
description = "Low-level, pure Python DBus protocol wrapper."
optional = false
python-versions = ">=3.7"
files = [
{file = "jeepney-0.8.0-py3-none-any.whl", hash = "sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755"},
{file = "jeepney-0.8.0.tar.gz", hash = "sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806"},
]
[package.extras]
test = ["async-timeout", "pytest", "pytest-asyncio (>=0.17)", "pytest-trio", "testpath", "trio"]
trio = ["async_generator", "trio"]
[[package]]
name = "jinja2"
version = "3.1.4"
@ -2460,6 +2601,35 @@ files = [
{file = "jupyterlab_widgets-3.0.13.tar.gz", hash = "sha256:a2966d385328c1942b683a8cd96b89b8dd82c8b8f81dda902bb2bc06d46f5bed"},
]
[[package]]
name = "keyring"
version = "25.6.0"
description = "Store and access your passwords safely."
optional = false
python-versions = ">=3.9"
files = [
{file = "keyring-25.6.0-py3-none-any.whl", hash = "sha256:552a3f7af126ece7ed5c89753650eec89c7eaae8617d0aa4d9ad2b75111266bd"},
{file = "keyring-25.6.0.tar.gz", hash = "sha256:0b39998aa941431eb3d9b0d4b2460bc773b9df6fed7621c2dfb291a7e0187a66"},
]
[package.dependencies]
importlib_metadata = {version = ">=4.11.4", markers = "python_version < \"3.12\""}
"jaraco.classes" = "*"
"jaraco.context" = "*"
"jaraco.functools" = "*"
jeepney = {version = ">=0.4.2", markers = "sys_platform == \"linux\""}
pywin32-ctypes = {version = ">=0.2.0", markers = "sys_platform == \"win32\""}
SecretStorage = {version = ">=3.2", markers = "sys_platform == \"linux\""}
[package.extras]
check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"]
completion = ["shtab (>=1.1.0)"]
cover = ["pytest-cov"]
doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
enabler = ["pytest-enabler (>=2.2)"]
test = ["pyfakefs", "pytest (>=6,!=8.1.*)"]
type = ["pygobject-stubs", "pytest-mypy", "shtab", "types-pywin32"]
[[package]]
name = "lark-parser"
version = "0.7.8"
@ -2685,6 +2855,17 @@ files = [
{file = "monotonic-1.6.tar.gz", hash = "sha256:3a55207bcfed53ddd5c5bae174524062935efed17792e9de2ad0205ce9ad63f7"},
]
[[package]]
name = "more-itertools"
version = "10.6.0"
description = "More routines for operating on iterables, beyond itertools"
optional = false
python-versions = ">=3.9"
files = [
{file = "more-itertools-10.6.0.tar.gz", hash = "sha256:2cd7fad1009c31cc9fb6a035108509e6547547a7a738374f10bd49a09eb3ee3b"},
{file = "more_itertools-10.6.0-py3-none-any.whl", hash = "sha256:6eb054cb4b6db1473f6e15fcc676a08e4732548acd47c708f0e179c2c7c01e89"},
]
[[package]]
name = "mpmath"
version = "1.3.0"
@ -2957,6 +3138,39 @@ files = [
{file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"},
]
[[package]]
name = "nh3"
version = "0.2.20"
description = "Python binding to Ammonia HTML sanitizer Rust crate"
optional = false
python-versions = ">=3.8"
files = [
{file = "nh3-0.2.20-cp313-cp313t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e1061a4ab6681f6bdf72b110eea0c4e1379d57c9de937db3be4202f7ad6043db"},
{file = "nh3-0.2.20-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb4254b1dac4a1ee49919a5b3f1caf9803ea8dada1816d9e8289e63d3cd0dd9a"},
{file = "nh3-0.2.20-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0ae9cbd713524cdb81e64663d0d6aae26f678db9f2cd9db0bf162606f1f9f20c"},
{file = "nh3-0.2.20-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e1f7370b4e14cc03f5ae141ef30a1caf81fa5787711f80be9081418dd9eb79d2"},
{file = "nh3-0.2.20-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:ac4d27dc836a476efffc6eb661994426b8b805c951b29c9cf2ff36bc9ad58bc5"},
{file = "nh3-0.2.20-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:4fd2e9248725ebcedac3997a8d3da0d90a12a28c9179c6ba51f1658938ac30d0"},
{file = "nh3-0.2.20-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f7d564871833ddbe54df3aa59053b1110729d3a800cb7628ae8f42adb3d75208"},
{file = "nh3-0.2.20-cp313-cp313t-win32.whl", hash = "sha256:d2a176fd4306b6f0f178a3f67fac91bd97a3a8d8fafb771c9b9ef675ba5c8886"},
{file = "nh3-0.2.20-cp313-cp313t-win_amd64.whl", hash = "sha256:6ed834c68452a600f517dd3e1534dbfaff1f67f98899fecf139a055a25d99150"},
{file = "nh3-0.2.20-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:76e2f603b30c02ff6456b233a83fc377dedab6a50947b04e960a6b905637b776"},
{file = "nh3-0.2.20-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:181063c581defe683bd4bb78188ac9936d208aebbc74c7f7c16b6a32ae2ebb38"},
{file = "nh3-0.2.20-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:231addb7643c952cd6d71f1c8702d703f8fe34afcb20becb3efb319a501a12d7"},
{file = "nh3-0.2.20-cp38-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:1b9a8340a0aab991c68a5ca938d35ef4a8a3f4bf1b455da8855a40bee1fa0ace"},
{file = "nh3-0.2.20-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:10317cd96fe4bbd4eb6b95f3920b71c902157ad44fed103fdcde43e3b8ee8be6"},
{file = "nh3-0.2.20-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8698db4c04b140800d1a1cd3067fda399e36e1e2b8fc1fe04292a907350a3e9b"},
{file = "nh3-0.2.20-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3eb04b9c3deb13c3a375ea39fd4a3c00d1f92e8fb2349f25f1e3e4506751774b"},
{file = "nh3-0.2.20-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:92f3f1c4f47a2c6f3ca7317b1d5ced05bd29556a75d3a4e2715652ae9d15c05d"},
{file = "nh3-0.2.20-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ddefa9fd6794a87e37d05827d299d4b53a3ec6f23258101907b96029bfef138a"},
{file = "nh3-0.2.20-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:ce3731c8f217685d33d9268362e5b4f770914e922bba94d368ab244a59a6c397"},
{file = "nh3-0.2.20-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:09f037c02fc2c43b211ff1523de32801dcfb0918648d8e651c36ef890f1731ec"},
{file = "nh3-0.2.20-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:813f1c8012dd64c990514b795508abb90789334f76a561fa0fd4ca32d2275330"},
{file = "nh3-0.2.20-cp38-abi3-win32.whl", hash = "sha256:47b2946c0e13057855209daeffb45dc910bd0c55daf10190bb0b4b60e2999784"},
{file = "nh3-0.2.20-cp38-abi3-win_amd64.whl", hash = "sha256:da87573f03084edae8eb87cfe811ec338606288f81d333c07d2a9a0b9b976c0b"},
{file = "nh3-0.2.20.tar.gz", hash = "sha256:9705c42d7ff88a0bea546c82d7fe5e59135e3d3f057e485394f491248a1f8ed5"},
]
[[package]]
name = "nodeenv"
version = "1.9.1"
@ -4066,6 +4280,17 @@ docs = ["myst_parser", "sphinx", "sphinx_rtd_theme"]
full = ["Pillow (>=8.0.0)", "cryptography"]
image = ["Pillow (>=8.0.0)"]
[[package]]
name = "pyproject-hooks"
version = "1.2.0"
description = "Wrappers to call pyproject.toml-based build backend hooks."
optional = false
python-versions = ">=3.7"
files = [
{file = "pyproject_hooks-1.2.0-py3-none-any.whl", hash = "sha256:9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913"},
{file = "pyproject_hooks-1.2.0.tar.gz", hash = "sha256:1e859bd5c40fae9448642dd871adf459e5e2084186e8d2c2a79a824c970da1f8"},
]
[[package]]
name = "pyreadline3"
version = "3.5.4"
@ -4232,6 +4457,17 @@ files = [
{file = "pywin32-308-cp39-cp39-win_amd64.whl", hash = "sha256:71b3322d949b4cc20776436a9c9ba0eeedcbc9c650daa536df63f0ff111bb920"},
]
[[package]]
name = "pywin32-ctypes"
version = "0.2.3"
description = "A (partial) reimplementation of pywin32 using ctypes/cffi"
optional = false
python-versions = ">=3.6"
files = [
{file = "pywin32-ctypes-0.2.3.tar.gz", hash = "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755"},
{file = "pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8"},
]
[[package]]
name = "pywinpty"
version = "2.0.14"
@ -4430,6 +4666,25 @@ files = [
[package.dependencies]
cffi = {version = "*", markers = "implementation_name == \"pypy\""}
[[package]]
name = "readme-renderer"
version = "44.0"
description = "readme_renderer is a library for rendering readme descriptions for Warehouse"
optional = false
python-versions = ">=3.9"
files = [
{file = "readme_renderer-44.0-py3-none-any.whl", hash = "sha256:2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151"},
{file = "readme_renderer-44.0.tar.gz", hash = "sha256:8712034eabbfa6805cacf1402b4eeb2a73028f72d1166d6f5cb7f9c047c5d1e1"},
]
[package.dependencies]
docutils = ">=0.21.2"
nh3 = ">=0.2.14"
Pygments = ">=2.5.1"
[package.extras]
md = ["cmarkgfm (>=0.8.0)"]
[[package]]
name = "redis"
version = "5.2.0"
@ -4629,6 +4884,20 @@ files = [
[package.dependencies]
six = "*"
[[package]]
name = "rfc3986"
version = "2.0.0"
description = "Validating URI References per RFC 3986"
optional = false
python-versions = ">=3.7"
files = [
{file = "rfc3986-2.0.0-py2.py3-none-any.whl", hash = "sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd"},
{file = "rfc3986-2.0.0.tar.gz", hash = "sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c"},
]
[package.extras]
idna2008 = ["idna"]
[[package]]
name = "rfc3986-validator"
version = "0.1.1"
@ -4789,6 +5058,21 @@ botocore = ">=1.33.2,<2.0a.0"
[package.extras]
crt = ["botocore[crt] (>=1.33.2,<2.0a.0)"]
[[package]]
name = "secretstorage"
version = "3.3.3"
description = "Python bindings to FreeDesktop.org Secret Service API"
optional = false
python-versions = ">=3.6"
files = [
{file = "SecretStorage-3.3.3-py3-none-any.whl", hash = "sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99"},
{file = "SecretStorage-3.3.3.tar.gz", hash = "sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77"},
]
[package.dependencies]
cryptography = ">=2.0"
jeepney = ">=0.6"
[[package]]
name = "selenium"
version = "4.26.1"
@ -5476,6 +5760,31 @@ files = [
trio = ">=0.11"
wsproto = ">=0.14"
[[package]]
name = "twine"
version = "6.1.0"
description = "Collection of utilities for publishing packages on PyPI"
optional = false
python-versions = ">=3.8"
files = [
{file = "twine-6.1.0-py3-none-any.whl", hash = "sha256:a47f973caf122930bf0fbbf17f80b83bc1602c9ce393c7845f289a3001dc5384"},
{file = "twine-6.1.0.tar.gz", hash = "sha256:be324f6272eff91d07ee93f251edf232fc647935dd585ac003539b42404a8dbd"},
]
[package.dependencies]
id = "*"
keyring = {version = ">=15.1", markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\""}
packaging = ">=24.0"
readme-renderer = ">=35.0"
requests = ">=2.20"
requests-toolbelt = ">=0.8.0,<0.9.0 || >0.9.0"
rfc3986 = ">=1.4.0"
rich = ">=12.0.0"
urllib3 = ">=1.26.0"
[package.extras]
keyring = ["keyring (>=15.1)"]
[[package]]
name = "typer"
version = "0.9.4"
@ -6193,4 +6502,4 @@ type = ["pytest-mypy"]
[metadata]
lock-version = "2.0"
python-versions = "^3.11,<3.12"
content-hash = "f57d0d18c10e49fd5cb243bf508dff8069b8422fcd5831cb8133184e1b52cb4e"
content-hash = "1183d0728a6986cf1585dd516163c710fe14648b2bb12928b7db7eb99c9027d6"

View file

@ -1,10 +1,10 @@
[tool.poetry]
name = "skyvern"
version = "0.1.0"
version = "0.1.55"
description = ""
authors = ["Skyvern AI <info@skyvern.com>"]
readme = "README.md"
packages = [{ include = "skyvern" }]
packages = [{ include = "skyvern" }, { include = "alembic" }]
[tool.poetry.dependencies]
python = "^3.11,<3.12"
@ -76,6 +76,8 @@ snoop = "^0.4.3"
rich = {extras = ["jupyter"], version = "^13.7.0"}
fpdf = "^1.7.2"
pypdf = "^5.0.1"
twine = "^6.1.0"
build = "^1.2.2.post1"
[build-system]
@ -129,3 +131,6 @@ skip = ["webeye/actions/__init__.py", "forge/sdk/__init__.py"]
[tool.mypy]
plugins = "sqlalchemy.ext.mypy.plugin"
[tool.poetry.scripts]
skyvern = "skyvern.cli.commands:app"

144
skyvern/agent/local.py Normal file
View file

@ -0,0 +1,144 @@
from dotenv import load_dotenv
from skyvern.agent.parameter import TaskV1Request, TaskV2Request
from skyvern.forge import app
from skyvern.forge.sdk.core import security, skyvern_context
from skyvern.forge.sdk.core.skyvern_context import SkyvernContext
from skyvern.forge.sdk.db.enums import OrganizationAuthTokenType
from skyvern.forge.sdk.schemas.observers import ObserverTask, ObserverTaskStatus
from skyvern.forge.sdk.schemas.organizations import Organization
from skyvern.forge.sdk.schemas.tasks import TaskResponse, TaskStatus
from skyvern.forge.sdk.services import observer_service
from skyvern.forge.sdk.services.org_auth_token_service import API_KEY_LIFETIME
from skyvern.forge.sdk.workflow.models.workflow import WorkflowRunStatus
from skyvern.utils import migrate_db
class Agent:
def __init__(self) -> None:
load_dotenv(".env")
migrate_db()
async def _get_organization(self) -> Organization:
organization = await app.DATABASE.get_organization_by_domain("skyvern.local")
if not organization:
organization = await app.DATABASE.create_organization(
organization_name="Skyvern-local",
domain="skyvern.local",
max_steps_per_run=10,
max_retries_per_step=3,
)
api_key = security.create_access_token(
organization.organization_id,
expires_delta=API_KEY_LIFETIME,
)
# generate OrganizationAutoToken
await app.DATABASE.create_org_auth_token(
organization_id=organization.organization_id,
token=api_key,
token_type=OrganizationAuthTokenType.api,
)
return organization
async def run_task_v1(self, task_request: TaskV1Request) -> TaskResponse:
organization = await self._get_organization()
org_auth_token = await app.DATABASE.get_valid_org_auth_token(
organization_id=organization.organization_id,
token_type=OrganizationAuthTokenType.api,
)
created_task = await app.agent.create_task(task_request, organization.organization_id)
skyvern_context.set(
SkyvernContext(
organization_id=organization.organization_id,
task_id=created_task.task_id,
max_steps_override=task_request.max_steps,
)
)
step = await app.DATABASE.create_step(
created_task.task_id,
order=0,
retry_index=0,
organization_id=organization.organization_id,
)
updated_task = await app.DATABASE.update_task(
created_task.task_id,
status=TaskStatus.running,
organization_id=organization.organization_id,
)
step, _, _ = await app.agent.execute_step(
organization=organization,
task=updated_task,
step=step,
api_key=org_auth_token.token if org_auth_token else None,
)
refreshed_task = await app.DATABASE.get_task(created_task.task_id, organization.organization_id)
if refreshed_task:
updated_task = refreshed_task
failure_reason: str | None = None
if updated_task.status == TaskStatus.failed and (step.output or updated_task.failure_reason):
failure_reason = ""
if updated_task.failure_reason:
failure_reason += updated_task.failure_reason or ""
if step.output is not None and step.output.actions_and_results is not None:
action_results_string: list[str] = []
for action, results in step.output.actions_and_results:
if len(results) == 0:
continue
if results[-1].success:
continue
action_results_string.append(f"{action.action_type} action failed.")
if len(action_results_string) > 0:
failure_reason += "(Exceptions: " + str(action_results_string) + ")"
return await app.agent.build_task_response(
task=updated_task, last_step=step, failure_reason=failure_reason, need_browser_log=True
)
async def run_task_v2(self, task_request: TaskV2Request) -> ObserverTask:
organization = await self._get_organization()
observer_task = await observer_service.initialize_observer_task(
organization=organization,
user_prompt=task_request.user_prompt,
user_url=str(task_request.url) if task_request.url else None,
totp_identifier=task_request.totp_identifier,
totp_verification_url=task_request.totp_verification_url,
webhook_callback_url=task_request.webhook_callback_url,
proxy_location=task_request.proxy_location,
publish_workflow=task_request.publish_workflow,
)
if not observer_task.workflow_run_id:
raise Exception("Observer cruise missing workflow run id")
# mark observer cruise as queued
await app.DATABASE.update_observer_cruise(
observer_cruise_id=observer_task.observer_cruise_id,
status=ObserverTaskStatus.queued,
organization_id=organization.organization_id,
)
await app.DATABASE.update_workflow_run(
workflow_run_id=observer_task.workflow_run_id,
status=WorkflowRunStatus.queued,
)
await observer_service.run_observer_task(
organization=organization,
observer_cruise_id=observer_task.observer_cruise_id,
max_iterations_override=task_request.max_iterations,
)
refreshed_observer_task = await app.DATABASE.get_observer_cruise(
observer_cruise_id=observer_task.observer_cruise_id, organization_id=organization.organization_id
)
if refreshed_observer_task:
return refreshed_observer_task
return observer_task

View file

@ -0,0 +1,10 @@
from skyvern.forge.sdk.schemas.observers import ObserverTaskRequest
from skyvern.forge.sdk.schemas.tasks import TaskRequest
class TaskV1Request(TaskRequest):
max_steps: int = 10
class TaskV2Request(ObserverTaskRequest):
max_iterations: int = 10

43
skyvern/agent/remote.py Normal file
View file

@ -0,0 +1,43 @@
import httpx
from skyvern.agent.parameter import TaskV1Request, TaskV2Request
from skyvern.forge.sdk.schemas.observers import ObserverTask
from skyvern.forge.sdk.schemas.tasks import CreateTaskResponse, TaskResponse
class RemoteAgent:
def __init__(self, api_key: str, endpoint: str = "https://api.skyvern.com"):
self.endpoint = endpoint
self.api_key = api_key
self.client = httpx.AsyncClient(
headers={
"Content-Type": "application/json",
"x-api-key": self.api_key,
}
)
async def run_task_v1(self, task: TaskV1Request) -> CreateTaskResponse:
url = f"{self.endpoint}/api/v1/tasks"
payload = task.model_dump_json()
headers = {"x_max_steps_override": str(task.max_steps)}
response = await self.client.post(url, headers=headers, data=payload)
return CreateTaskResponse.model_validate(response.json())
async def run_task_v2(self, task: TaskV2Request) -> ObserverTask:
url = f"{self.endpoint}/api/v2/tasks"
payload = task.model_dump_json()
headers = {"x_max_iterations_override": str(task.max_iterations)}
response = await self.client.post(url, headers=headers, data=payload)
return ObserverTask.model_validate(response.json())
async def get_task_v1(self, task_id: str) -> TaskResponse:
"""Get a task by id."""
url = f"{self.endpoint}/api/v1/tasks/{task_id}"
response = await self.client.get(url)
return TaskResponse.model_validate(response.json())
async def get_task_v2(self, task_id: str) -> ObserverTask:
"""Get a task by id."""
url = f"{self.endpoint}/api/v2/tasks/{task_id}"
response = await self.client.get(url)
return ObserverTask.model_validate(response.json())

126
skyvern/cli/commands.py Normal file
View file

@ -0,0 +1,126 @@
import shutil
import subprocess
import time
from typing import Optional
import typer
from skyvern.utils import migrate_db
app = typer.Typer()
def command_exists(command: str) -> bool:
return shutil.which(command) is not None
def run_command(command: str, check: bool = True) -> tuple[Optional[str], Optional[int]]:
try:
result = subprocess.run(command, shell=True, check=check, capture_output=True, text=True)
return result.stdout.strip(), result.returncode
except subprocess.CalledProcessError as e:
return None, e.returncode
def is_postgres_running() -> bool:
if command_exists("pg_isready"):
result = run_command("pg_isready")
return result is not None and "accepting connections" in result
return False
def database_exists(dbname: str, user: str) -> bool:
check_db_command = f'psql {dbname} -U {user} -c "\\q"'
return run_command(check_db_command, check=False) is not None
def create_database_and_user() -> None:
print("Creating database user and database...")
run_command("createuser skyvern")
run_command("createdb skyvern -O skyvern")
print("Database and user created successfully.")
def is_docker_running() -> bool:
if not command_exists("docker"):
return False
_, code = run_command("docker info", check=False)
return code == 0
def is_postgres_running_in_docker() -> bool:
_, code = run_command("docker ps | grep -q postgresql-container", check=False)
return code == 0
def is_postgres_container_exists() -> bool:
_, code = run_command("docker ps -a | grep -q postgresql-container", check=False)
return code == 0
def setup_postgresql() -> None:
print("Setting up PostgreSQL...")
if command_exists("psql") and is_postgres_running():
print("PostgreSQL is already running locally.")
if database_exists("skyvern", "skyvern"):
print("Database and user exist.")
else:
create_database_and_user()
return
if not is_docker_running():
print("Docker is not running or not installed. Please install or start Docker and try again.")
exit(1)
if is_postgres_running_in_docker():
print("PostgreSQL is already running in a Docker container.")
else:
print("Attempting to install PostgreSQL via Docker...")
if not is_postgres_container_exists():
run_command(
"docker run --name postgresql-container -e POSTGRES_HOST_AUTH_METHOD=trust -d -p 5432:5432 postgres:14"
)
else:
run_command("docker start postgresql-container")
print("PostgreSQL has been installed and started using Docker.")
print("Waiting for PostgreSQL to start...")
time.sleep(20)
_, code = run_command('docker exec postgresql-container psql -U postgres -c "\\du" | grep -q skyvern', check=False)
if code == 0:
print("Database user exists.")
else:
print("Creating database user...")
run_command("docker exec postgresql-container createuser -U postgres skyvern")
_, code = run_command(
"docker exec postgresql-container psql -U postgres -lqt | cut -d \\| -f 1 | grep -qw skyvern", check=False
)
if code == 0:
print("Database exists.")
else:
print("Creating database...")
run_command("docker exec postgresql-container createdb -U postgres skyvern -O skyvern")
print("Database and user created successfully.")
@app.command(name="init")
def init(
openai_api_key: str = typer.Option(..., help="The OpenAI API key"),
log_level: str = typer.Option("CRITICAL", help="The log level"),
) -> None:
setup_postgresql()
# Generate .env file
with open(".env", "w") as env_file:
env_file.write("ENABLE_OPENAI=true\n")
env_file.write(f"OPENAI_API_KEY={openai_api_key}\n")
env_file.write(f"LOG_LEVEL={log_level}\n")
env_file.write("ARTIFACT_STORAGE_PATH=./artifacts\n")
print(".env file created with the parameters provided.")
@app.command(name="migrate")
def migrate() -> None:
migrate_db()

View file

@ -11,7 +11,7 @@ class Settings(BaseSettings):
BROWSER_TYPE: str = "chromium-headful"
MAX_SCRAPING_RETRIES: int = 0
VIDEO_PATH: str | None = None
VIDEO_PATH: str | None = "./video"
HAR_PATH: str | None = "./har"
LOG_PATH: str = "./log"
TEMP_PATH: str = "./temp"

10
skyvern/utils/__init__.py Normal file
View file

@ -0,0 +1,10 @@
from alembic import command
from alembic.config import Config
from skyvern.constants import REPO_ROOT_DIR
def migrate_db() -> None:
alembic_cfg = Config()
path = f"{REPO_ROOT_DIR}/alembic"
alembic_cfg.set_main_option("script_location", path)
command.upgrade(alembic_cfg, "head")