mirror of
https://github.com/Skyvern-AI/skyvern.git
synced 2025-09-02 02:30:07 +00:00
add skyvern sdk (#1741)
This commit is contained in:
parent
cd64639faa
commit
73a69edbbc
8 changed files with 651 additions and 4 deletions
311
poetry.lock
generated
311
poetry.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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
144
skyvern/agent/local.py
Normal 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
|
10
skyvern/agent/parameter.py
Normal file
10
skyvern/agent/parameter.py
Normal 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
43
skyvern/agent/remote.py
Normal 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
126
skyvern/cli/commands.py
Normal 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()
|
|
@ -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
10
skyvern/utils/__init__.py
Normal 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")
|
Loading…
Add table
Reference in a new issue