diff --git a/poetry.lock b/poetry.lock index 3ce8f58..12b0f2c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. [[package]] name = "annotated-types" @@ -14,30 +14,6 @@ files = [ [package.dependencies] typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.9\""} -[[package]] -name = "anthropic" -version = "0.47.2" -description = "The official Python library for the anthropic API" -optional = false -python-versions = ">=3.8" -files = [ - {file = "anthropic-0.47.2-py3-none-any.whl", hash = "sha256:61b712a56308fce69f04d92ba0230ab2bc187b5bce17811d400843a8976bb67f"}, - {file = "anthropic-0.47.2.tar.gz", hash = "sha256:452f4ca0c56ffab8b6ce9928bf8470650f88106a7001b250895eb65c54cfa44c"}, -] - -[package.dependencies] -anyio = ">=3.5.0,<5" -distro = ">=1.7.0,<2" -httpx = ">=0.23.0,<1" -jiter = ">=0.4.0,<1" -pydantic = ">=1.9.0,<3" -sniffio = "*" -typing-extensions = ">=4.10,<5" - -[package.extras] -bedrock = ["boto3 (>=1.28.57)", "botocore (>=1.31.57)"] -vertex = ["google-auth (>=2,<3)"] - [[package]] name = "anyio" version = "4.5.2" @@ -82,17 +58,6 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] -[[package]] -name = "distro" -version = "1.9.0" -description = "Distro - an OS platform information API" -optional = false -python-versions = ">=3.6" -files = [ - {file = "distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2"}, - {file = "distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed"}, -] - [[package]] name = "exceptiongroup" version = "1.2.2" @@ -107,92 +72,6 @@ files = [ [package.extras] test = ["pytest (>=6)"] -[[package]] -name = "greenlet" -version = "3.1.1" -description = "Lightweight in-process concurrent programming" -optional = false -python-versions = ">=3.7" -files = [ - {file = "greenlet-3.1.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:0bbae94a29c9e5c7e4a2b7f0aae5c17e8e90acbfd3bf6270eeba60c39fce3563"}, - {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fde093fb93f35ca72a556cf72c92ea3ebfda3d79fc35bb19fbe685853869a83"}, - {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:36b89d13c49216cadb828db8dfa6ce86bbbc476a82d3a6c397f0efae0525bdd0"}, - {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94b6150a85e1b33b40b1464a3f9988dcc5251d6ed06842abff82e42632fac120"}, - {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93147c513fac16385d1036b7e5b102c7fbbdb163d556b791f0f11eada7ba65dc"}, - {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:da7a9bff22ce038e19bf62c4dd1ec8391062878710ded0a845bcf47cc0200617"}, - {file = "greenlet-3.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b2795058c23988728eec1f36a4e5e4ebad22f8320c85f3587b539b9ac84128d7"}, - {file = "greenlet-3.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ed10eac5830befbdd0c32f83e8aa6288361597550ba669b04c48f0f9a2c843c6"}, - {file = "greenlet-3.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:77c386de38a60d1dfb8e55b8c1101d68c79dfdd25c7095d51fec2dd800892b80"}, - {file = "greenlet-3.1.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:e4d333e558953648ca09d64f13e6d8f0523fa705f51cae3f03b5983489958c70"}, - {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09fc016b73c94e98e29af67ab7b9a879c307c6731a2c9da0db5a7d9b7edd1159"}, - {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d5e975ca70269d66d17dd995dafc06f1b06e8cb1ec1e9ed54c1d1e4a7c4cf26e"}, - {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b2813dc3de8c1ee3f924e4d4227999285fd335d1bcc0d2be6dc3f1f6a318ec1"}, - {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e347b3bfcf985a05e8c0b7d462ba6f15b1ee1c909e2dcad795e49e91b152c383"}, - {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e8f8c9cb53cdac7ba9793c276acd90168f416b9ce36799b9b885790f8ad6c0a"}, - {file = "greenlet-3.1.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:62ee94988d6b4722ce0028644418d93a52429e977d742ca2ccbe1c4f4a792511"}, - {file = "greenlet-3.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1776fd7f989fc6b8d8c8cb8da1f6b82c5814957264d1f6cf818d475ec2bf6395"}, - {file = "greenlet-3.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:48ca08c771c268a768087b408658e216133aecd835c0ded47ce955381105ba39"}, - {file = "greenlet-3.1.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:4afe7ea89de619adc868e087b4d2359282058479d7cfb94970adf4b55284574d"}, - {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f406b22b7c9a9b4f8aa9d2ab13d6ae0ac3e85c9a809bd590ad53fed2bf70dc79"}, - {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c3a701fe5a9695b238503ce5bbe8218e03c3bcccf7e204e455e7462d770268aa"}, - {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2846930c65b47d70b9d178e89c7e1a69c95c1f68ea5aa0a58646b7a96df12441"}, - {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99cfaa2110534e2cf3ba31a7abcac9d328d1d9f1b95beede58294a60348fba36"}, - {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1443279c19fca463fc33e65ef2a935a5b09bb90f978beab37729e1c3c6c25fe9"}, - {file = "greenlet-3.1.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b7cede291382a78f7bb5f04a529cb18e068dd29e0fb27376074b6d0317bf4dd0"}, - {file = "greenlet-3.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:23f20bb60ae298d7d8656c6ec6db134bca379ecefadb0b19ce6f19d1f232a942"}, - {file = "greenlet-3.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:7124e16b4c55d417577c2077be379514321916d5790fa287c9ed6f23bd2ffd01"}, - {file = "greenlet-3.1.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:05175c27cb459dcfc05d026c4232f9de8913ed006d42713cb8a5137bd49375f1"}, - {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:935e943ec47c4afab8965954bf49bfa639c05d4ccf9ef6e924188f762145c0ff"}, - {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:667a9706c970cb552ede35aee17339a18e8f2a87a51fba2ed39ceeeb1004798a"}, - {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b8a678974d1f3aa55f6cc34dc480169d58f2e6d8958895d68845fa4ab566509e"}, - {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efc0f674aa41b92da8c49e0346318c6075d734994c3c4e4430b1c3f853e498e4"}, - {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0153404a4bb921f0ff1abeb5ce8a5131da56b953eda6e14b88dc6bbc04d2049e"}, - {file = "greenlet-3.1.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:275f72decf9932639c1c6dd1013a1bc266438eb32710016a1c742df5da6e60a1"}, - {file = "greenlet-3.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c4aab7f6381f38a4b42f269057aee279ab0fc7bf2e929e3d4abfae97b682a12c"}, - {file = "greenlet-3.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:b42703b1cf69f2aa1df7d1030b9d77d3e584a70755674d60e710f0af570f3761"}, - {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1695e76146579f8c06c1509c7ce4dfe0706f49c6831a817ac04eebb2fd02011"}, - {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7876452af029456b3f3549b696bb36a06db7c90747740c5302f74a9e9fa14b13"}, - {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ead44c85f8ab905852d3de8d86f6f8baf77109f9da589cb4fa142bd3b57b475"}, - {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8320f64b777d00dd7ccdade271eaf0cad6636343293a25074cc5566160e4de7b"}, - {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6510bf84a6b643dabba74d3049ead221257603a253d0a9873f55f6a59a65f822"}, - {file = "greenlet-3.1.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:04b013dc07c96f83134b1e99888e7a79979f1a247e2a9f59697fa14b5862ed01"}, - {file = "greenlet-3.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:411f015496fec93c1c8cd4e5238da364e1da7a124bcb293f085bf2860c32c6f6"}, - {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47da355d8687fd65240c364c90a31569a133b7b60de111c255ef5b606f2ae291"}, - {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:98884ecf2ffb7d7fe6bd517e8eb99d31ff7855a840fa6d0d63cd07c037f6a981"}, - {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1d4aeb8891338e60d1ab6127af1fe45def5259def8094b9c7e34690c8858803"}, - {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db32b5348615a04b82240cc67983cb315309e88d444a288934ee6ceaebcad6cc"}, - {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dcc62f31eae24de7f8dce72134c8651c58000d3b1868e01392baea7c32c247de"}, - {file = "greenlet-3.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1d3755bcb2e02de341c55b4fca7a745a24a9e7212ac953f6b3a48d117d7257aa"}, - {file = "greenlet-3.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b8da394b34370874b4572676f36acabac172602abf054cbc4ac910219f3340af"}, - {file = "greenlet-3.1.1-cp37-cp37m-win32.whl", hash = "sha256:a0dfc6c143b519113354e780a50381508139b07d2177cb6ad6a08278ec655798"}, - {file = "greenlet-3.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:54558ea205654b50c438029505def3834e80f0869a70fb15b871c29b4575ddef"}, - {file = "greenlet-3.1.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:346bed03fe47414091be4ad44786d1bd8bef0c3fcad6ed3dee074a032ab408a9"}, - {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dfc59d69fc48664bc693842bd57acfdd490acafda1ab52c7836e3fc75c90a111"}, - {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d21e10da6ec19b457b82636209cbe2331ff4306b54d06fa04b7c138ba18c8a81"}, - {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:37b9de5a96111fc15418819ab4c4432e4f3c2ede61e660b1e33971eba26ef9ba"}, - {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ef9ea3f137e5711f0dbe5f9263e8c009b7069d8a1acea822bd5e9dae0ae49c8"}, - {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85f3ff71e2e60bd4b4932a043fbbe0f499e263c628390b285cb599154a3b03b1"}, - {file = "greenlet-3.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:95ffcf719966dd7c453f908e208e14cde192e09fde6c7186c8f1896ef778d8cd"}, - {file = "greenlet-3.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:03a088b9de532cbfe2ba2034b2b85e82df37874681e8c470d6fb2f8c04d7e4b7"}, - {file = "greenlet-3.1.1-cp38-cp38-win32.whl", hash = "sha256:8b8b36671f10ba80e159378df9c4f15c14098c4fd73a36b9ad715f057272fbef"}, - {file = "greenlet-3.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:7017b2be767b9d43cc31416aba48aab0d2309ee31b4dbf10a1d38fb7972bdf9d"}, - {file = "greenlet-3.1.1-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:396979749bd95f018296af156201d6211240e7a23090f50a8d5d18c370084dc3"}, - {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca9d0ff5ad43e785350894d97e13633a66e2b50000e8a183a50a88d834752d42"}, - {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f6ff3b14f2df4c41660a7dec01045a045653998784bf8cfcb5a525bdffffbc8f"}, - {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94ebba31df2aa506d7b14866fed00ac141a867e63143fe5bca82a8e503b36437"}, - {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73aaad12ac0ff500f62cebed98d8789198ea0e6f233421059fa68a5aa7220145"}, - {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:63e4844797b975b9af3a3fb8f7866ff08775f5426925e1e0bbcfe7932059a12c"}, - {file = "greenlet-3.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7939aa3ca7d2a1593596e7ac6d59391ff30281ef280d8632fa03d81f7c5f955e"}, - {file = "greenlet-3.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d0028e725ee18175c6e422797c407874da24381ce0690d6b9396c204c7f7276e"}, - {file = "greenlet-3.1.1-cp39-cp39-win32.whl", hash = "sha256:5e06afd14cbaf9e00899fae69b24a32f2196c19de08fcb9f4779dd4f004e5e7c"}, - {file = "greenlet-3.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:3319aa75e0e0639bc15ff54ca327e8dc7a6fe404003496e3c6925cd3142e0e22"}, - {file = "greenlet-3.1.1.tar.gz", hash = "sha256:4ce3ac6cdb6adf7946475d7ef31777c26d94bccc377e070a7986bd2d5c515467"}, -] - -[package.extras] -docs = ["Sphinx", "furo"] -test = ["objgraph", "psutil"] - [[package]] name = "h11" version = "0.14.0" @@ -274,91 +153,6 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] -[[package]] -name = "jiter" -version = "0.8.2" -description = "Fast iterable JSON parser." -optional = false -python-versions = ">=3.8" -files = [ - {file = "jiter-0.8.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:ca8577f6a413abe29b079bc30f907894d7eb07a865c4df69475e868d73e71c7b"}, - {file = "jiter-0.8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b25bd626bde7fb51534190c7e3cb97cee89ee76b76d7585580e22f34f5e3f393"}, - {file = "jiter-0.8.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5c826a221851a8dc028eb6d7d6429ba03184fa3c7e83ae01cd6d3bd1d4bd17d"}, - {file = "jiter-0.8.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d35c864c2dff13dfd79fb070fc4fc6235d7b9b359efe340e1261deb21b9fcb66"}, - {file = "jiter-0.8.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f557c55bc2b7676e74d39d19bcb8775ca295c7a028246175d6a8b431e70835e5"}, - {file = "jiter-0.8.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:580ccf358539153db147e40751a0b41688a5ceb275e6f3e93d91c9467f42b2e3"}, - {file = "jiter-0.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af102d3372e917cffce49b521e4c32c497515119dc7bd8a75665e90a718bbf08"}, - {file = "jiter-0.8.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cadcc978f82397d515bb2683fc0d50103acff2a180552654bb92d6045dec2c49"}, - {file = "jiter-0.8.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ba5bdf56969cad2019d4e8ffd3f879b5fdc792624129741d3d83fc832fef8c7d"}, - {file = "jiter-0.8.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3b94a33a241bee9e34b8481cdcaa3d5c2116f575e0226e421bed3f7a6ea71cff"}, - {file = "jiter-0.8.2-cp310-cp310-win32.whl", hash = "sha256:6e5337bf454abddd91bd048ce0dca5134056fc99ca0205258766db35d0a2ea43"}, - {file = "jiter-0.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:4a9220497ca0cb1fe94e3f334f65b9b5102a0b8147646118f020d8ce1de70105"}, - {file = "jiter-0.8.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:2dd61c5afc88a4fda7d8b2cf03ae5947c6ac7516d32b7a15bf4b49569a5c076b"}, - {file = "jiter-0.8.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a6c710d657c8d1d2adbbb5c0b0c6bfcec28fd35bd6b5f016395f9ac43e878a15"}, - {file = "jiter-0.8.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9584de0cd306072635fe4b89742bf26feae858a0683b399ad0c2509011b9dc0"}, - {file = "jiter-0.8.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5a90a923338531b7970abb063cfc087eebae6ef8ec8139762007188f6bc69a9f"}, - {file = "jiter-0.8.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d21974d246ed0181558087cd9f76e84e8321091ebfb3a93d4c341479a736f099"}, - {file = "jiter-0.8.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:32475a42b2ea7b344069dc1e81445cfc00b9d0e3ca837f0523072432332e9f74"}, - {file = "jiter-0.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b9931fd36ee513c26b5bf08c940b0ac875de175341cbdd4fa3be109f0492586"}, - {file = "jiter-0.8.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ce0820f4a3a59ddced7fce696d86a096d5cc48d32a4183483a17671a61edfddc"}, - {file = "jiter-0.8.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8ffc86ae5e3e6a93765d49d1ab47b6075a9c978a2b3b80f0f32628f39caa0c88"}, - {file = "jiter-0.8.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5127dc1abd809431172bc3fbe8168d6b90556a30bb10acd5ded41c3cfd6f43b6"}, - {file = "jiter-0.8.2-cp311-cp311-win32.whl", hash = "sha256:66227a2c7b575720c1871c8800d3a0122bb8ee94edb43a5685aa9aceb2782d44"}, - {file = "jiter-0.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:cde031d8413842a1e7501e9129b8e676e62a657f8ec8166e18a70d94d4682855"}, - {file = "jiter-0.8.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:e6ec2be506e7d6f9527dae9ff4b7f54e68ea44a0ef6b098256ddf895218a2f8f"}, - {file = "jiter-0.8.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76e324da7b5da060287c54f2fabd3db5f76468006c811831f051942bf68c9d44"}, - {file = "jiter-0.8.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:180a8aea058f7535d1c84183c0362c710f4750bef66630c05f40c93c2b152a0f"}, - {file = "jiter-0.8.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:025337859077b41548bdcbabe38698bcd93cfe10b06ff66617a48ff92c9aec60"}, - {file = "jiter-0.8.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ecff0dc14f409599bbcafa7e470c00b80f17abc14d1405d38ab02e4b42e55b57"}, - {file = "jiter-0.8.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ffd9fee7d0775ebaba131f7ca2e2d83839a62ad65e8e02fe2bd8fc975cedeb9e"}, - {file = "jiter-0.8.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14601dcac4889e0a1c75ccf6a0e4baf70dbc75041e51bcf8d0e9274519df6887"}, - {file = "jiter-0.8.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:92249669925bc1c54fcd2ec73f70f2c1d6a817928480ee1c65af5f6b81cdf12d"}, - {file = "jiter-0.8.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e725edd0929fa79f8349ab4ec7f81c714df51dc4e991539a578e5018fa4a7152"}, - {file = "jiter-0.8.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bf55846c7b7a680eebaf9c3c48d630e1bf51bdf76c68a5f654b8524335b0ad29"}, - {file = "jiter-0.8.2-cp312-cp312-win32.whl", hash = "sha256:7efe4853ecd3d6110301665a5178b9856be7e2a9485f49d91aa4d737ad2ae49e"}, - {file = "jiter-0.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:83c0efd80b29695058d0fd2fa8a556490dbce9804eac3e281f373bbc99045f6c"}, - {file = "jiter-0.8.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:ca1f08b8e43dc3bd0594c992fb1fd2f7ce87f7bf0d44358198d6da8034afdf84"}, - {file = "jiter-0.8.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5672a86d55416ccd214c778efccf3266b84f87b89063b582167d803246354be4"}, - {file = "jiter-0.8.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58dc9bc9767a1101f4e5e22db1b652161a225874d66f0e5cb8e2c7d1c438b587"}, - {file = "jiter-0.8.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:37b2998606d6dadbb5ccda959a33d6a5e853252d921fec1792fc902351bb4e2c"}, - {file = "jiter-0.8.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ab9a87f3784eb0e098f84a32670cfe4a79cb6512fd8f42ae3d0709f06405d18"}, - {file = "jiter-0.8.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:79aec8172b9e3c6d05fd4b219d5de1ac616bd8da934107325a6c0d0e866a21b6"}, - {file = "jiter-0.8.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:711e408732d4e9a0208008e5892c2966b485c783cd2d9a681f3eb147cf36c7ef"}, - {file = "jiter-0.8.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:653cf462db4e8c41995e33d865965e79641ef45369d8a11f54cd30888b7e6ff1"}, - {file = "jiter-0.8.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:9c63eaef32b7bebac8ebebf4dabebdbc6769a09c127294db6babee38e9f405b9"}, - {file = "jiter-0.8.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:eb21aaa9a200d0a80dacc7a81038d2e476ffe473ffdd9c91eb745d623561de05"}, - {file = "jiter-0.8.2-cp313-cp313-win32.whl", hash = "sha256:789361ed945d8d42850f919342a8665d2dc79e7e44ca1c97cc786966a21f627a"}, - {file = "jiter-0.8.2-cp313-cp313-win_amd64.whl", hash = "sha256:ab7f43235d71e03b941c1630f4b6e3055d46b6cb8728a17663eaac9d8e83a865"}, - {file = "jiter-0.8.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b426f72cd77da3fec300ed3bc990895e2dd6b49e3bfe6c438592a3ba660e41ca"}, - {file = "jiter-0.8.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2dd880785088ff2ad21ffee205e58a8c1ddabc63612444ae41e5e4b321b39c0"}, - {file = "jiter-0.8.2-cp313-cp313t-win_amd64.whl", hash = "sha256:3ac9f578c46f22405ff7f8b1f5848fb753cc4b8377fbec8470a7dc3997ca7566"}, - {file = "jiter-0.8.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:9e1fa156ee9454642adb7e7234a383884452532bc9d53d5af2d18d98ada1d79c"}, - {file = "jiter-0.8.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0cf5dfa9956d96ff2efb0f8e9c7d055904012c952539a774305aaaf3abdf3d6c"}, - {file = "jiter-0.8.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e52bf98c7e727dd44f7c4acb980cb988448faeafed8433c867888268899b298b"}, - {file = "jiter-0.8.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a2ecaa3c23e7a7cf86d00eda3390c232f4d533cd9ddea4b04f5d0644faf642c5"}, - {file = "jiter-0.8.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:08d4c92bf480e19fc3f2717c9ce2aa31dceaa9163839a311424b6862252c943e"}, - {file = "jiter-0.8.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:99d9a1eded738299ba8e106c6779ce5c3893cffa0e32e4485d680588adae6db8"}, - {file = "jiter-0.8.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d20be8b7f606df096e08b0b1b4a3c6f0515e8dac296881fe7461dfa0fb5ec817"}, - {file = "jiter-0.8.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d33f94615fcaf872f7fd8cd98ac3b429e435c77619777e8a449d9d27e01134d1"}, - {file = "jiter-0.8.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:317b25e98a35ffec5c67efe56a4e9970852632c810d35b34ecdd70cc0e47b3b6"}, - {file = "jiter-0.8.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fc9043259ee430ecd71d178fccabd8c332a3bf1e81e50cae43cc2b28d19e4cb7"}, - {file = "jiter-0.8.2-cp38-cp38-win32.whl", hash = "sha256:fc5adda618205bd4678b146612ce44c3cbfdee9697951f2c0ffdef1f26d72b63"}, - {file = "jiter-0.8.2-cp38-cp38-win_amd64.whl", hash = "sha256:cd646c827b4f85ef4a78e4e58f4f5854fae0caf3db91b59f0d73731448a970c6"}, - {file = "jiter-0.8.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:e41e75344acef3fc59ba4765df29f107f309ca9e8eace5baacabd9217e52a5ee"}, - {file = "jiter-0.8.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f22b16b35d5c1df9dfd58843ab2cd25e6bf15191f5a236bed177afade507bfc"}, - {file = "jiter-0.8.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7200b8f7619d36aa51c803fd52020a2dfbea36ffec1b5e22cab11fd34d95a6d"}, - {file = "jiter-0.8.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:70bf4c43652cc294040dbb62256c83c8718370c8b93dd93d934b9a7bf6c4f53c"}, - {file = "jiter-0.8.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f9d471356dc16f84ed48768b8ee79f29514295c7295cb41e1133ec0b2b8d637d"}, - {file = "jiter-0.8.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:859e8eb3507894093d01929e12e267f83b1d5f6221099d3ec976f0c995cb6bd9"}, - {file = "jiter-0.8.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaa58399c01db555346647a907b4ef6d4f584b123943be6ed5588c3f2359c9f4"}, - {file = "jiter-0.8.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8f2d5ed877f089862f4c7aacf3a542627c1496f972a34d0474ce85ee7d939c27"}, - {file = "jiter-0.8.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:03c9df035d4f8d647f8c210ddc2ae0728387275340668fb30d2421e17d9a0841"}, - {file = "jiter-0.8.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8bd2a824d08d8977bb2794ea2682f898ad3d8837932e3a74937e93d62ecbb637"}, - {file = "jiter-0.8.2-cp39-cp39-win32.whl", hash = "sha256:ca29b6371ebc40e496995c94b988a101b9fbbed48a51190a4461fcb0a68b4a36"}, - {file = "jiter-0.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:1c0dfbd1be3cbefc7510102370d86e35d1d53e5a93d48519688b1bf0f761160a"}, - {file = "jiter-0.8.2.tar.gz", hash = "sha256:cd73d3e740666d0e639f678adb176fad25c1bcbdae88d8d7b857e1783bb4212d"}, -] - [[package]] name = "mypy" version = "1.0.1" @@ -427,26 +221,6 @@ files = [ {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, ] -[[package]] -name = "playwright" -version = "1.48.0" -description = "A high-level API to automate web browsers" -optional = false -python-versions = ">=3.8" -files = [ - {file = "playwright-1.48.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:082bce2739f1078acc7d0734da8cc0e23eb91b7fae553f3316d733276f09a6b1"}, - {file = "playwright-1.48.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7da2eb51a19c7f3b523e9faa9d98e7af92e52eb983a099979ea79c9668e3cbf7"}, - {file = "playwright-1.48.0-py3-none-macosx_11_0_universal2.whl", hash = "sha256:115b988d1da322358b77bc3bf2d3cc90f8c881e691461538e7df91614c4833c9"}, - {file = "playwright-1.48.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:8dabb80e62f667fe2640a8b694e26a7b884c0b4803f7514a3954fc849126227b"}, - {file = "playwright-1.48.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ff8303409ebed76bed4c3d655340320b768817d900ba208b394fdd7d7939a5c"}, - {file = "playwright-1.48.0-py3-none-win32.whl", hash = "sha256:85598c360c590076d4f435525be991246d74a905b654ac19d26eab7ed9b98b2d"}, - {file = "playwright-1.48.0-py3-none-win_amd64.whl", hash = "sha256:e0e87b0c4dc8fce83c725dd851aec37bc4e882bb225ec8a96bd83cf32d4f1623"}, -] - -[package.dependencies] -greenlet = "3.1.1" -pyee = "12.0.0" - [[package]] name = "pluggy" version = "1.5.0" @@ -594,23 +368,6 @@ files = [ [package.dependencies] typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" -[[package]] -name = "pyee" -version = "12.0.0" -description = "A rough port of Node.js's EventEmitter to Python with a few tricks of its own" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pyee-12.0.0-py3-none-any.whl", hash = "sha256:7b14b74320600049ccc7d0e0b1becd3b4bd0a03c745758225e31a59f4095c990"}, - {file = "pyee-12.0.0.tar.gz", hash = "sha256:c480603f4aa2927d4766eb41fa82793fe60a82cbfdb8d688e0d08c55a534e145"}, -] - -[package.dependencies] -typing-extensions = "*" - -[package.extras] -dev = ["black", "build", "flake8", "flake8-black", "isort", "jupyter-console", "mkdocs", "mkdocs-include-markdown-plugin", "mkdocstrings[python]", "pytest", "pytest-asyncio", "pytest-trio", "sphinx", "toml", "tox", "trio", "trio", "trio-typing", "twine", "twisted", "validate-pyproject[all]"] - [[package]] name = "pytest" version = "7.4.4" @@ -780,4 +537,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "afd12abd07590f9897eb7e414c5b497477e5fd6e31bfb4390cac050339717ccd" +content-hash = "6f6c191c1028d17a97fdfa84cedfd3cef94b5d63d98b8c1d333b3398eeea9055" diff --git a/pyproject.toml b/pyproject.toml index d5715c1..56d4bed 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "scrapybara" -version = "2.2.9" +version = "2.3.0" description = "" readme = "README.md" authors = [] @@ -32,9 +32,7 @@ Repository = 'https://github.com/scrapybara/scrapybara-python' [tool.poetry.dependencies] python = "^3.8" -anthropic = "^0.47.2" httpx = ">=0.21.2" -playwright = "^1.48.0" pydantic = ">= 1.9.2" pydantic-core = "^2.18.2" typing_extensions = ">= 4.0.0" diff --git a/reference.md b/reference.md index a8e0763..90ff350 100644 --- a/reference.md +++ b/reference.md @@ -336,13 +336,16 @@ client.instance.get_stream_url( ```python from scrapybara import Scrapybara +from scrapybara.instance import Request_MoveMouse client = Scrapybara( api_key="YOUR_API_KEY", ) client.instance.computer( instance_id="instance_id", - action="key", + request=Request_MoveMouse( + coordinates=[1], + ), ) ``` @@ -367,23 +370,7 @@ client.instance.computer(
-**action:** `Action` - -
-
- -
-
- -**coordinate:** `typing.Optional[typing.Sequence[int]]` - -
-
- -
-
- -**text:** `typing.Optional[str]` +**request:** `Request`
diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..f502f1b --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +httpx>=0.21.2 +pydantic>= 1.9.2 +pydantic-core==^2.18.2 +typing_extensions>= 4.0.0 diff --git a/src/scrapybara/__init__.py b/src/scrapybara/__init__.py index 5311076..a892df8 100644 --- a/src/scrapybara/__init__.py +++ b/src/scrapybara/__init__.py @@ -2,15 +2,23 @@ from .types import ( AuthStateResponse, + BashResponse, BrowserAuthenticateResponse, BrowserGetCdpUrlResponse, + Button, CellType, + ClickMouseAction, + ClickMouseActionClickType, + ComputerResponse, DeploymentConfigInstanceType, + DragMouseAction, + EditResponse, EnvGetResponse, EnvResponse, ExecuteCellRequest, FileDownloadResponse, FileReadResponse, + GetCursorPositionAction, GetInstanceResponse, GetInstanceResponseInstanceType, HttpValidationError, @@ -18,37 +26,62 @@ InstanceScreenshotResponse, KernelInfo, ModifyBrowserAuthResponse, + MoveMouseAction, Notebook, NotebookCell, + PressKeyAction, SaveBrowserAuthResponse, + ScrollAction, StartBrowserResponse, Status, StopBrowserResponse, StopInstanceResponse, + TakeScreenshotAction, + TypeTextAction, ValidationError, ValidationErrorLocItem, + WaitAction, ) from .errors import UnprocessableEntityError from . import browser, code, env, file, instance, notebook from .client import AsyncScrapybara, Scrapybara from .environment import ScrapybaraEnvironment -from .instance import Action, Command +from .instance import ( + Command, + Request, + Request_ClickMouse, + Request_DragMouse, + Request_GetCursorPosition, + Request_MoveMouse, + Request_PressKey, + Request_Scroll, + Request_TakeScreenshot, + Request_TypeText, + Request_Wait, +) from .version import __version__ __all__ = [ - "Action", "AsyncScrapybara", "AuthStateResponse", + "BashResponse", "BrowserAuthenticateResponse", "BrowserGetCdpUrlResponse", + "Button", "CellType", + "ClickMouseAction", + "ClickMouseActionClickType", "Command", + "ComputerResponse", "DeploymentConfigInstanceType", + "DragMouseAction", + "EditResponse", "EnvGetResponse", "EnvResponse", "ExecuteCellRequest", "FileDownloadResponse", "FileReadResponse", + "GetCursorPositionAction", "GetInstanceResponse", "GetInstanceResponseInstanceType", "HttpValidationError", @@ -56,18 +89,34 @@ "InstanceScreenshotResponse", "KernelInfo", "ModifyBrowserAuthResponse", + "MoveMouseAction", "Notebook", "NotebookCell", + "PressKeyAction", + "Request", + "Request_ClickMouse", + "Request_DragMouse", + "Request_GetCursorPosition", + "Request_MoveMouse", + "Request_PressKey", + "Request_Scroll", + "Request_TakeScreenshot", + "Request_TypeText", + "Request_Wait", "SaveBrowserAuthResponse", "Scrapybara", "ScrapybaraEnvironment", + "ScrollAction", "StartBrowserResponse", "Status", "StopBrowserResponse", "StopInstanceResponse", + "TakeScreenshotAction", + "TypeTextAction", "UnprocessableEntityError", "ValidationError", "ValidationErrorLocItem", + "WaitAction", "__version__", "browser", "code", diff --git a/src/scrapybara/anthropic/__init__.py b/src/scrapybara/anthropic/__init__.py index 847c4d1..7c54d8e 100644 --- a/src/scrapybara/anthropic/__init__.py +++ b/src/scrapybara/anthropic/__init__.py @@ -1,18 +1,10 @@ -from typing import Literal, Optional, TypedDict, Any, Dict -from anthropic.types.beta import ( - BetaToolComputerUse20241022Param, - BetaToolTextEditor20241022Param, - BetaToolBash20241022Param, -) -import asyncio +from typing import Literal, Optional + from pydantic import Field -from ..client import BaseInstance, UbuntuInstance from ..types.act import Model -from .base import BaseAnthropicTool, CLIResult, ToolError, ToolResult -# New: universal act API class Anthropic(Model): """Model adapter for Anthropic. @@ -37,179 +29,3 @@ def __init__( api_key: Optional[str] = None, ) -> None: super().__init__(provider="anthropic", name=name, api_key=api_key) - - -# Legacy: Anthropic SDK-compatible tools -class ComputerToolOptions(TypedDict): - display_height_px: int - display_width_px: int - display_number: Optional[int] - - -class ComputerTool(BaseAnthropicTool): - """A computer interaction tool that allows the agent to control mouse and keyboard. - - Available for Ubuntu, Browser, and Windows instances.""" - - api_type: Literal["computer_20241022"] = "computer_20241022" - name: Literal["computer"] = "computer" - width: int = 1024 - height: int = 768 - display_num: Optional[int] = 1 - _instance: BaseInstance - - def __init__(self, instance: BaseInstance): - self._instance = instance - super().__init__() - - @property - def options(self) -> ComputerToolOptions: - return { - "display_width_px": self.width, - "display_height_px": self.height, - "display_number": self.display_num, - } - - def to_params(self) -> BetaToolComputerUse20241022Param: - return { - "name": self.name, - "type": self.api_type, - "display_width_px": self.width, - "display_height_px": self.height, - "display_number": self.display_num, - } - - async def __call__(self, **kwargs: Any) -> ToolResult: - action = kwargs.pop("action") - coordinate = kwargs.pop("coordinate", None) - text = kwargs.pop("text", None) - - try: - loop = asyncio.get_event_loop() - result = await loop.run_in_executor( - None, - lambda: self._instance.computer( - action=action, - coordinate=tuple(coordinate) if coordinate else None, - text=text, - ), - ) - return CLIResult( - output=result.get("output") if result else "", - error=result.get("error") if result else None, - base64_image=result.get("base64_image") if result else None, - system=result.get("system") if result else None, - ) - except Exception as e: - raise ToolError(str(e)) from None - - -class EditTool(BaseAnthropicTool): - """A filesystem editor tool that allows the agent to view, create, and edit files. - - Available for Ubuntu instances.""" - - api_type: Literal["text_editor_20241022"] = "text_editor_20241022" - name: Literal["str_replace_editor"] = "str_replace_editor" - _instance: UbuntuInstance - - def __init__(self, instance: UbuntuInstance): - self._instance = instance - super().__init__() - - def to_params(self) -> BetaToolTextEditor20241022Param: - return { - "name": self.name, - "type": self.api_type, - } - - async def __call__(self, **kwargs: Any) -> ToolResult: - command = kwargs.pop("command") - path = kwargs.pop("path") - file_text = kwargs.pop("file_text", None) - view_range = kwargs.pop("view_range", None) - old_str = kwargs.pop("old_str", None) - new_str = kwargs.pop("new_str", None) - insert_line = kwargs.pop("insert_line", None) - try: - loop = asyncio.get_event_loop() - result = await loop.run_in_executor( - None, - lambda: self._instance.edit( - command=command, - path=path, - file_text=file_text, - view_range=view_range, - old_str=old_str, - new_str=new_str, - insert_line=insert_line, - ), - ) - return CLIResult( - output=result.get("output") if result else "", - error=result.get("error") if result else None, - base64_image=result.get("base64_image") if result else None, - system=result.get("system") if result else None, - ) - except Exception as e: - raise ToolError(str(e)) from None - - -class BashTool(BaseAnthropicTool): - """A shell execution tool that allows the agent to run bash commands. - - Available for Ubuntu instances.""" - - api_type: Literal["bash_20241022"] = "bash_20241022" - name: Literal["bash"] = "bash" - _instance: UbuntuInstance - - def __init__(self, instance: UbuntuInstance): - self._instance = instance - super().__init__() - - def to_params(self) -> BetaToolBash20241022Param: - return { - "name": self.name, - "type": self.api_type, - } - - async def __call__(self, **kwargs: Any) -> ToolResult: - command = kwargs.pop("command") - restart = kwargs.pop("restart", False) - try: - loop = asyncio.get_event_loop() - result = await loop.run_in_executor( - None, - lambda: self._instance.bash(command=command, restart=restart), - ) - return CLIResult( - output=result.get("output") if result else "", - error=result.get("error") if result else None, - base64_image=result.get("base64_image") if result else None, - system=result.get("system") if result else None, - ) - except Exception as e: - raise ToolError(str(e)) from None - - -class ToolCollection: - """A collection of anthropic-defined tools.""" - - def __init__(self, *tools): - self.tools = tools - self.tool_map = {tool.to_params()["name"]: tool for tool in tools} - - def to_params(self) -> list: - return [tool.to_params() for tool in self.tools] - - async def run(self, *, name: str, tool_input: Dict[str, Any]) -> ToolResult: - tool = self.tool_map.get(name) - if not tool: - return ToolResult(error=f"Tool {name} not found") - try: - r = await tool(**tool_input) - return r if r else ToolResult() - except Exception as e: - print(f"Error running tool {name}: {e}") - return ToolResult(error=str(e)) diff --git a/src/scrapybara/anthropic/base.py b/src/scrapybara/anthropic/base.py deleted file mode 100644 index c10e978..0000000 --- a/src/scrapybara/anthropic/base.py +++ /dev/null @@ -1,69 +0,0 @@ -from abc import ABCMeta, abstractmethod -from dataclasses import dataclass, fields, replace -from typing import Any, Optional - -from anthropic.types.beta import BetaToolUnionParam - - -class BaseAnthropicTool(metaclass=ABCMeta): - """Abstract base class for Anthropic-defined tools.""" - - @abstractmethod - def __call__(self, **kwargs) -> Any: - """Executes the tool with the given arguments.""" - ... - - @abstractmethod - def to_params( - self, - ) -> BetaToolUnionParam: - raise NotImplementedError - - -@dataclass(frozen=True) -class ToolResult: - """Represents the result of a tool execution.""" - - output: Optional[str] = None - error: Optional[str] = None - base64_image: Optional[str] = None - system: Optional[str] = None - - def __bool__(self): - return any(getattr(self, field.name) for field in fields(self)) - - def __add__(self, other: "ToolResult"): - def combine_fields( - field: Optional[str], other_field: Optional[str], concatenate: bool = True - ) -> Optional[str]: - if field and other_field: - if concatenate: - return field + other_field - raise ValueError("Cannot combine tool results") - return field or other_field - - return ToolResult( - output=combine_fields(self.output, other.output), - error=combine_fields(self.error, other.error), - base64_image=combine_fields(self.base64_image, other.base64_image, False), - system=combine_fields(self.system, other.system), - ) - - def replace(self, **kwargs): - """Returns a new ToolResult with the given fields replaced.""" - return replace(self, **kwargs) - - -class CLIResult(ToolResult): - """A ToolResult that can be rendered as a CLI output.""" - - -class ToolFailure(ToolResult): - """A ToolResult that represents a failure.""" - - -class ToolError(Exception): - """Raised when a tool encounters an error.""" - - def __init__(self, message): - self.message = message diff --git a/src/scrapybara/client.py b/src/scrapybara/client.py index eaaae73..446f2b6 100644 --- a/src/scrapybara/client.py +++ b/src/scrapybara/client.py @@ -12,6 +12,8 @@ Generator, Callable, AsyncGenerator, + Literal, + overload, ) import typing import os @@ -25,9 +27,13 @@ from .core.request_options import RequestOptions from .core.api_error import ApiError from .types import ( + Action, AuthStateResponse, BrowserAuthenticateResponse, BrowserGetCdpUrlResponse, + Button, + ClickMouseActionClickType, + ComputerResponse, CellType, EnvGetResponse, EnvResponse, @@ -45,6 +51,7 @@ StopInstanceResponse, ModifyBrowserAuthResponse, ) + from .types.act import ( SingleActRequest, SingleActResponse, @@ -64,7 +71,18 @@ TokenUsage, ) from .base_client import BaseClient, AsyncBaseClient -from .instance.types import Action, Command +from .instance.types import ( + Command, + Request_MoveMouse, + Request_ClickMouse, + Request_DragMouse, + Request_Scroll, + Request_PressKey, + Request_TypeText, + Request_Wait, + Request_TakeScreenshot, + Request_GetCursorPosition, +) OMIT = typing.cast(typing.Any, ...) SchemaT = TypeVar("SchemaT", bound=BaseModel) @@ -628,19 +646,148 @@ def get_stream_url( self.id, request_options=request_options ) + @overload + def computer( + self, + *, + action: Literal["move_mouse"], + coordinates: List[int], + hold_keys: Optional[List[str]] = None, + request_options: Optional[RequestOptions] = None, + ) -> ComputerResponse: ... + + @overload + def computer( + self, + *, + action: Literal["click_mouse"], + button: Button, + click_type: Optional[ClickMouseActionClickType] = None, + coordinates: Optional[List[int]] = None, + num_clicks: Optional[int] = None, + hold_keys: Optional[List[str]] = None, + request_options: Optional[RequestOptions] = None, + ) -> ComputerResponse: ... + + @overload + def computer( + self, + *, + action: Literal["drag_mouse"], + path: List[List[int]], + hold_keys: Optional[List[str]] = None, + request_options: Optional[RequestOptions] = None, + ) -> ComputerResponse: ... + + @overload + def computer( + self, + *, + action: Literal["scroll"], + coordinates: List[int], + delta_x: Optional[float] = None, + delta_y: Optional[float] = None, + hold_keys: Optional[List[str]] = None, + request_options: Optional[RequestOptions] = None, + ) -> ComputerResponse: ... + + @overload + def computer( + self, + *, + action: Literal["press_key"], + keys: List[str], + duration: Optional[float] = None, + request_options: Optional[RequestOptions] = None, + ) -> ComputerResponse: ... + + @overload + def computer( + self, + *, + action: Literal["type_text"], + text: str, + hold_keys: Optional[List[str]] = None, + request_options: Optional[RequestOptions] = None, + ) -> ComputerResponse: ... + + @overload + def computer( + self, + *, + action: Literal["wait"], + duration: float, + request_options: Optional[RequestOptions] = None, + ) -> ComputerResponse: ... + + @overload + def computer( + self, + *, + action: Literal["take_screenshot"], + request_options: Optional[RequestOptions] = None, + ) -> ComputerResponse: ... + + @overload + def computer( + self, + *, + action: Literal["get_cursor_position"], + request_options: Optional[RequestOptions] = None, + ) -> ComputerResponse: ... + def computer( self, *, action: Action, - coordinate: Optional[Sequence[int]] = OMIT, - text: Optional[str] = OMIT, + button: Optional[Button] = None, + click_type: Optional[ClickMouseActionClickType] = None, + coordinates: Optional[List[int]] = None, + delta_x: Optional[float] = None, + delta_y: Optional[float] = None, + num_clicks: Optional[int] = None, + hold_keys: Optional[List[str]] = None, + path: Optional[List[List[int]]] = None, + keys: Optional[List[str]] = None, + text: Optional[str] = None, + duration: Optional[float] = None, request_options: Optional[RequestOptions] = None, - ) -> Optional[Any]: + ) -> ComputerResponse: + request: Any = None + + if action == "move_mouse": + request = Request_MoveMouse(coordinates=coordinates, hold_keys=hold_keys) + elif action == "click_mouse": + request = Request_ClickMouse( + button=button, + click_type=click_type, + coordinates=coordinates, + num_clicks=num_clicks, + hold_keys=hold_keys, + ) + elif action == "drag_mouse": + request = Request_DragMouse(path=path, hold_keys=hold_keys) + elif action == "scroll": + request = Request_Scroll( + coordinates=coordinates, + delta_x=delta_x, + delta_y=delta_y, + hold_keys=hold_keys, + ) + elif action == "press_key": + request = Request_PressKey(keys=keys, duration=duration) + elif action == "type_text": + request = Request_TypeText(text=text, hold_keys=hold_keys) + elif action == "wait": + request = Request_Wait(duration=duration) + elif action == "take_screenshot": + request = Request_TakeScreenshot() + elif action == "get_cursor_position": + request = Request_GetCursorPosition() + return self._client.instance.computer( self.id, - action=action, - coordinate=coordinate, - text=text, + request=request, request_options=request_options, ) @@ -807,19 +954,148 @@ async def get_stream_url( self.id, request_options=request_options ) + @overload + async def computer( + self, + *, + action: Literal["move_mouse"], + coordinates: List[int], + hold_keys: Optional[List[str]] = None, + request_options: Optional[RequestOptions] = None, + ) -> ComputerResponse: ... + + @overload + async def computer( + self, + *, + action: Literal["click_mouse"], + button: Button, + click_type: Optional[ClickMouseActionClickType] = None, + coordinates: Optional[List[int]] = None, + num_clicks: Optional[int] = None, + hold_keys: Optional[List[str]] = None, + request_options: Optional[RequestOptions] = None, + ) -> ComputerResponse: ... + + @overload + async def computer( + self, + *, + action: Literal["drag_mouse"], + path: List[List[int]], + hold_keys: Optional[List[str]] = None, + request_options: Optional[RequestOptions] = None, + ) -> ComputerResponse: ... + + @overload + async def computer( + self, + *, + action: Literal["scroll"], + coordinates: List[int], + delta_x: Optional[float] = None, + delta_y: Optional[float] = None, + hold_keys: Optional[List[str]] = None, + request_options: Optional[RequestOptions] = None, + ) -> ComputerResponse: ... + + @overload + async def computer( + self, + *, + action: Literal["press_key"], + keys: List[str], + duration: Optional[float] = None, + request_options: Optional[RequestOptions] = None, + ) -> ComputerResponse: ... + + @overload + async def computer( + self, + *, + action: Literal["type_text"], + text: str, + hold_keys: Optional[List[str]] = None, + request_options: Optional[RequestOptions] = None, + ) -> ComputerResponse: ... + + @overload + async def computer( + self, + *, + action: Literal["wait"], + duration: float, + request_options: Optional[RequestOptions] = None, + ) -> ComputerResponse: ... + + @overload + async def computer( + self, + *, + action: Literal["take_screenshot"], + request_options: Optional[RequestOptions] = None, + ) -> ComputerResponse: ... + + @overload + async def computer( + self, + *, + action: Literal["get_cursor_position"], + request_options: Optional[RequestOptions] = None, + ) -> ComputerResponse: ... + async def computer( self, *, action: Action, - coordinate: Optional[Sequence[int]] = OMIT, - text: Optional[str] = OMIT, + button: Optional[Button] = None, + click_type: Optional[ClickMouseActionClickType] = None, + coordinates: Optional[List[int]] = None, + delta_x: Optional[float] = None, + delta_y: Optional[float] = None, + num_clicks: Optional[int] = None, + hold_keys: Optional[List[str]] = None, + path: Optional[List[List[int]]] = None, + keys: Optional[List[str]] = None, + text: Optional[str] = None, + duration: Optional[float] = None, request_options: Optional[RequestOptions] = None, - ) -> Optional[Any]: + ) -> ComputerResponse: + request: Any = None + + if action == "move_mouse": + request = Request_MoveMouse(coordinates=coordinates, hold_keys=hold_keys) + elif action == "click_mouse": + request = Request_ClickMouse( + button=button, + click_type=click_type, + coordinates=coordinates, + num_clicks=num_clicks, + hold_keys=hold_keys, + ) + elif action == "drag_mouse": + request = Request_DragMouse(path=path, hold_keys=hold_keys) + elif action == "scroll": + request = Request_Scroll( + coordinates=coordinates, + delta_x=delta_x, + delta_y=delta_y, + hold_keys=hold_keys, + ) + elif action == "press_key": + request = Request_PressKey(keys=keys, duration=duration) + elif action == "type_text": + request = Request_TypeText(text=text, hold_keys=hold_keys) + elif action == "wait": + request = Request_Wait(duration=duration) + elif action == "take_screenshot": + request = Request_TakeScreenshot() + elif action == "get_cursor_position": + request = Request_GetCursorPosition() + return await self._client.instance.computer( self.id, - action=action, - coordinate=coordinate, - text=text, + request=request, request_options=request_options, ) diff --git a/src/scrapybara/core/client_wrapper.py b/src/scrapybara/core/client_wrapper.py index 53ce88b..1c86f52 100644 --- a/src/scrapybara/core/client_wrapper.py +++ b/src/scrapybara/core/client_wrapper.py @@ -16,7 +16,7 @@ def get_headers(self) -> typing.Dict[str, str]: headers: typing.Dict[str, str] = { "X-Fern-Language": "Python", "X-Fern-SDK-Name": "scrapybara", - "X-Fern-SDK-Version": "2.2.9", + "X-Fern-SDK-Version": "2.3.0", } headers["x-api-key"] = self.api_key return headers diff --git a/src/scrapybara/core/http_client.py b/src/scrapybara/core/http_client.py index 1a1a131..275a54c 100644 --- a/src/scrapybara/core/http_client.py +++ b/src/scrapybara/core/http_client.py @@ -85,8 +85,8 @@ def _retry_timeout(response: httpx.Response, retries: int) -> float: def _should_retry(response: httpx.Response) -> bool: - retriable_400s = [429, 408, 409] - return response.status_code >= 500 or response.status_code in retriable_400s + retryable_400s = [429, 408, 409] + return response.status_code >= 500 or response.status_code in retryable_400s def remove_omit_from_dict( @@ -183,7 +183,7 @@ def request( files: typing.Optional[typing.Dict[str, typing.Optional[typing.Union[File, typing.List[File]]]]] = None, headers: typing.Optional[typing.Dict[str, typing.Any]] = None, request_options: typing.Optional[RequestOptions] = None, - retries: int = 0, + retries: int = 2, omit: typing.Optional[typing.Any] = None, ) -> httpx.Response: base_url = self.get_base_url(base_url) @@ -269,7 +269,7 @@ def stream( files: typing.Optional[typing.Dict[str, typing.Optional[typing.Union[File, typing.List[File]]]]] = None, headers: typing.Optional[typing.Dict[str, typing.Any]] = None, request_options: typing.Optional[RequestOptions] = None, - retries: int = 0, + retries: int = 2, omit: typing.Optional[typing.Any] = None, ) -> typing.Iterator[httpx.Response]: base_url = self.get_base_url(base_url) @@ -359,7 +359,7 @@ async def request( files: typing.Optional[typing.Dict[str, typing.Optional[typing.Union[File, typing.List[File]]]]] = None, headers: typing.Optional[typing.Dict[str, typing.Any]] = None, request_options: typing.Optional[RequestOptions] = None, - retries: int = 0, + retries: int = 2, omit: typing.Optional[typing.Any] = None, ) -> httpx.Response: base_url = self.get_base_url(base_url) @@ -445,7 +445,7 @@ async def stream( files: typing.Optional[typing.Dict[str, typing.Optional[typing.Union[File, typing.List[File]]]]] = None, headers: typing.Optional[typing.Dict[str, typing.Any]] = None, request_options: typing.Optional[RequestOptions] = None, - retries: int = 0, + retries: int = 2, omit: typing.Optional[typing.Any] = None, ) -> typing.AsyncIterator[httpx.Response]: base_url = self.get_base_url(base_url) diff --git a/src/scrapybara/core/pydantic_utilities.py b/src/scrapybara/core/pydantic_utilities.py index ee8f0e4..ca1f479 100644 --- a/src/scrapybara/core/pydantic_utilities.py +++ b/src/scrapybara/core/pydantic_utilities.py @@ -79,7 +79,7 @@ def to_jsonable_with_fallback( class UniversalBaseModel(pydantic.BaseModel): if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - # Allow fields begining with `model_` to be used in the model + # Allow fields beginning with `model_` to be used in the model protected_namespaces=(), ) # type: ignore # Pydantic v2 @@ -128,7 +128,7 @@ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: Override the default dict method to `exclude_unset` by default. This function patches `exclude_unset` to work include fields within non-None default values. """ - # Note: the logic here is multi-plexed given the levers exposed in Pydantic V1 vs V2 + # Note: the logic here is multiplexed given the levers exposed in Pydantic V1 vs V2 # Pydantic V1's .dict can be extremely slow, so we do not want to call it twice. # # We'd ideally do the same for Pydantic V2, but it shells out to a library to serialize models diff --git a/src/scrapybara/instance/__init__.py b/src/scrapybara/instance/__init__.py index d6b3225..2908d87 100644 --- a/src/scrapybara/instance/__init__.py +++ b/src/scrapybara/instance/__init__.py @@ -1,5 +1,29 @@ # This file was auto-generated by Fern from our API Definition. -from .types import Action, Command +from .types import ( + Command, + Request, + Request_ClickMouse, + Request_DragMouse, + Request_GetCursorPosition, + Request_MoveMouse, + Request_PressKey, + Request_Scroll, + Request_TakeScreenshot, + Request_TypeText, + Request_Wait, +) -__all__ = ["Action", "Command"] +__all__ = [ + "Command", + "Request", + "Request_ClickMouse", + "Request_DragMouse", + "Request_GetCursorPosition", + "Request_MoveMouse", + "Request_PressKey", + "Request_Scroll", + "Request_TakeScreenshot", + "Request_TypeText", + "Request_Wait", +] diff --git a/src/scrapybara/instance/client.py b/src/scrapybara/instance/client.py index 17ed202..78e8799 100644 --- a/src/scrapybara/instance/client.py +++ b/src/scrapybara/instance/client.py @@ -11,8 +11,12 @@ from json.decoder import JSONDecodeError from ..core.api_error import ApiError from ..types.instance_get_stream_url_response import InstanceGetStreamUrlResponse -from .types.action import Action +from .types.request import Request +from ..types.computer_response import ComputerResponse +from ..core.serialization import convert_and_respect_annotation_metadata +from ..types.bash_response import BashResponse from .types.command import Command +from ..types.edit_response import EditResponse from ..types.stop_instance_response import StopInstanceResponse from ..types.get_instance_response import GetInstanceResponse from ..core.client_wrapper import AsyncClientWrapper @@ -138,65 +142,51 @@ def get_stream_url( raise ApiError(status_code=_response.status_code, body=_response_json) def computer( - self, - instance_id: str, - *, - action: Action, - coordinate: typing.Optional[typing.Sequence[int]] = OMIT, - text: typing.Optional[str] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> typing.Optional[typing.Any]: + self, instance_id: str, *, request: Request, request_options: typing.Optional[RequestOptions] = None + ) -> ComputerResponse: """ Parameters ---------- instance_id : str - action : Action - - coordinate : typing.Optional[typing.Sequence[int]] - - text : typing.Optional[str] + request : Request request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - typing.Optional[typing.Any] + ComputerResponse Successful Response Examples -------- from scrapybara import Scrapybara + from scrapybara.instance import Request_MoveMouse client = Scrapybara( api_key="YOUR_API_KEY", ) client.instance.computer( instance_id="instance_id", - action="key", + request=Request_MoveMouse( + coordinates=[1], + ), ) """ _response = self._client_wrapper.httpx_client.request( f"v1/instance/{jsonable_encoder(instance_id)}/computer", method="POST", - json={ - "action": action, - "coordinate": coordinate, - "text": text, - }, - headers={ - "content-type": "application/json", - }, + json=convert_and_respect_annotation_metadata(object_=request, annotation=Request, direction="write"), request_options=request_options, omit=OMIT, ) try: if 200 <= _response.status_code < 300: return typing.cast( - typing.Optional[typing.Any], + ComputerResponse, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=ComputerResponse, # type: ignore object_=_response.json(), ), ) @@ -222,7 +212,7 @@ def bash( command: typing.Optional[str] = OMIT, restart: typing.Optional[bool] = OMIT, request_options: typing.Optional[RequestOptions] = None, - ) -> typing.Optional[typing.Any]: + ) -> BashResponse: """ Parameters ---------- @@ -237,7 +227,7 @@ def bash( Returns ------- - typing.Optional[typing.Any] + BashResponse Successful Response Examples @@ -267,9 +257,9 @@ def bash( try: if 200 <= _response.status_code < 300: return typing.cast( - typing.Optional[typing.Any], + BashResponse, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=BashResponse, # type: ignore object_=_response.json(), ), ) @@ -300,7 +290,7 @@ def edit( new_str: typing.Optional[str] = OMIT, insert_line: typing.Optional[int] = OMIT, request_options: typing.Optional[RequestOptions] = None, - ) -> typing.Optional[typing.Any]: + ) -> EditResponse: """ Parameters ---------- @@ -325,7 +315,7 @@ def edit( Returns ------- - typing.Optional[typing.Any] + EditResponse Successful Response Examples @@ -362,9 +352,9 @@ def edit( try: if 200 <= _response.status_code < 300: return typing.cast( - typing.Optional[typing.Any], + EditResponse, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=EditResponse, # type: ignore object_=_response.json(), ), ) @@ -694,31 +684,21 @@ async def main() -> None: raise ApiError(status_code=_response.status_code, body=_response_json) async def computer( - self, - instance_id: str, - *, - action: Action, - coordinate: typing.Optional[typing.Sequence[int]] = OMIT, - text: typing.Optional[str] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> typing.Optional[typing.Any]: + self, instance_id: str, *, request: Request, request_options: typing.Optional[RequestOptions] = None + ) -> ComputerResponse: """ Parameters ---------- instance_id : str - action : Action - - coordinate : typing.Optional[typing.Sequence[int]] - - text : typing.Optional[str] + request : Request request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - typing.Optional[typing.Any] + ComputerResponse Successful Response Examples @@ -726,6 +706,7 @@ async def computer( import asyncio from scrapybara import AsyncScrapybara + from scrapybara.instance import Request_MoveMouse client = AsyncScrapybara( api_key="YOUR_API_KEY", @@ -735,7 +716,9 @@ async def computer( async def main() -> None: await client.instance.computer( instance_id="instance_id", - action="key", + request=Request_MoveMouse( + coordinates=[1], + ), ) @@ -744,23 +727,16 @@ async def main() -> None: _response = await self._client_wrapper.httpx_client.request( f"v1/instance/{jsonable_encoder(instance_id)}/computer", method="POST", - json={ - "action": action, - "coordinate": coordinate, - "text": text, - }, - headers={ - "content-type": "application/json", - }, + json=convert_and_respect_annotation_metadata(object_=request, annotation=Request, direction="write"), request_options=request_options, omit=OMIT, ) try: if 200 <= _response.status_code < 300: return typing.cast( - typing.Optional[typing.Any], + ComputerResponse, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=ComputerResponse, # type: ignore object_=_response.json(), ), ) @@ -786,7 +762,7 @@ async def bash( command: typing.Optional[str] = OMIT, restart: typing.Optional[bool] = OMIT, request_options: typing.Optional[RequestOptions] = None, - ) -> typing.Optional[typing.Any]: + ) -> BashResponse: """ Parameters ---------- @@ -801,7 +777,7 @@ async def bash( Returns ------- - typing.Optional[typing.Any] + BashResponse Successful Response Examples @@ -839,9 +815,9 @@ async def main() -> None: try: if 200 <= _response.status_code < 300: return typing.cast( - typing.Optional[typing.Any], + BashResponse, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=BashResponse, # type: ignore object_=_response.json(), ), ) @@ -872,7 +848,7 @@ async def edit( new_str: typing.Optional[str] = OMIT, insert_line: typing.Optional[int] = OMIT, request_options: typing.Optional[RequestOptions] = None, - ) -> typing.Optional[typing.Any]: + ) -> EditResponse: """ Parameters ---------- @@ -897,7 +873,7 @@ async def edit( Returns ------- - typing.Optional[typing.Any] + EditResponse Successful Response Examples @@ -942,9 +918,9 @@ async def main() -> None: try: if 200 <= _response.status_code < 300: return typing.cast( - typing.Optional[typing.Any], + EditResponse, parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore + type_=EditResponse, # type: ignore object_=_response.json(), ), ) diff --git a/src/scrapybara/instance/types/__init__.py b/src/scrapybara/instance/types/__init__.py index 59c4cd2..f6da6bb 100644 --- a/src/scrapybara/instance/types/__init__.py +++ b/src/scrapybara/instance/types/__init__.py @@ -1,6 +1,29 @@ # This file was auto-generated by Fern from our API Definition. -from .action import Action from .command import Command +from .request import ( + Request, + Request_ClickMouse, + Request_DragMouse, + Request_GetCursorPosition, + Request_MoveMouse, + Request_PressKey, + Request_Scroll, + Request_TakeScreenshot, + Request_TypeText, + Request_Wait, +) -__all__ = ["Action", "Command"] +__all__ = [ + "Command", + "Request", + "Request_ClickMouse", + "Request_DragMouse", + "Request_GetCursorPosition", + "Request_MoveMouse", + "Request_PressKey", + "Request_Scroll", + "Request_TakeScreenshot", + "Request_TypeText", + "Request_Wait", +] diff --git a/src/scrapybara/instance/types/action.py b/src/scrapybara/instance/types/action.py deleted file mode 100644 index f3fa17f..0000000 --- a/src/scrapybara/instance/types/action.py +++ /dev/null @@ -1,21 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -Action = typing.Union[ - typing.Literal[ - "key", - "type", - "mouse_move", - "left_click", - "left_click_drag", - "right_click", - "middle_click", - "double_click", - "screenshot", - "cursor_position", - "scroll", - "wait", - ], - typing.Any, -] diff --git a/src/scrapybara/instance/types/request.py b/src/scrapybara/instance/types/request.py new file mode 100644 index 0000000..bf94fec --- /dev/null +++ b/src/scrapybara/instance/types/request.py @@ -0,0 +1,157 @@ +# This file was auto-generated by Fern from our API Definition. + +from __future__ import annotations +from ...core.pydantic_utilities import UniversalBaseModel +import typing +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic +from ...types.button import Button +from ...types.click_mouse_action_click_type import ClickMouseActionClickType + + +class Request_MoveMouse(UniversalBaseModel): + action: typing.Literal["move_mouse"] = "move_mouse" + coordinates: typing.List[int] + hold_keys: typing.Optional[typing.List[str]] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +class Request_ClickMouse(UniversalBaseModel): + action: typing.Literal["click_mouse"] = "click_mouse" + button: Button + click_type: typing.Optional[ClickMouseActionClickType] = None + coordinates: typing.Optional[typing.List[int]] = None + num_clicks: typing.Optional[int] = None + hold_keys: typing.Optional[typing.List[str]] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +class Request_DragMouse(UniversalBaseModel): + action: typing.Literal["drag_mouse"] = "drag_mouse" + path: typing.List[typing.List[int]] + hold_keys: typing.Optional[typing.List[str]] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +class Request_Scroll(UniversalBaseModel): + action: typing.Literal["scroll"] = "scroll" + coordinates: typing.List[int] + delta_x: typing.Optional[float] = None + delta_y: typing.Optional[float] = None + hold_keys: typing.Optional[typing.List[str]] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +class Request_PressKey(UniversalBaseModel): + action: typing.Literal["press_key"] = "press_key" + keys: typing.List[str] + duration: typing.Optional[float] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +class Request_TypeText(UniversalBaseModel): + action: typing.Literal["type_text"] = "type_text" + text: str + hold_keys: typing.Optional[typing.List[str]] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +class Request_Wait(UniversalBaseModel): + action: typing.Literal["wait"] = "wait" + duration: float + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +class Request_TakeScreenshot(UniversalBaseModel): + action: typing.Literal["take_screenshot"] = "take_screenshot" + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +class Request_GetCursorPosition(UniversalBaseModel): + action: typing.Literal["get_cursor_position"] = "get_cursor_position" + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +Request = typing.Union[ + Request_MoveMouse, + Request_ClickMouse, + Request_DragMouse, + Request_Scroll, + Request_PressKey, + Request_TypeText, + Request_Wait, + Request_TakeScreenshot, + Request_GetCursorPosition, +] diff --git a/src/scrapybara/tools/__init__.py b/src/scrapybara/tools/__init__.py index 340c88d..7efd2cf 100644 --- a/src/scrapybara/tools/__init__.py +++ b/src/scrapybara/tools/__init__.py @@ -1,34 +1,32 @@ -import base64 -import json -from typing import Any, Literal, Optional, Sequence, Tuple, Union +from typing import Any, List, Optional, Tuple from pydantic import BaseModel, Field -from playwright.sync_api import sync_playwright -from ..types.tool import Tool -from ..client import BaseInstance, UbuntuInstance, BrowserInstance -from ..instance.types import Action, Command - - -def image_result(base64: str) -> str: - """Return an image result that is interpretable by the model.""" - return json.dumps( - { - "output": "", - "error": "", - "base64_image": base64, - "system": None, - } - ) +from ..types import Action, Button, ClickMouseActionClickType, Tool +from ..client import BaseInstance, UbuntuInstance +from ..instance.types import Command class ComputerToolParameters(BaseModel): """Parameters for computer interaction commands.""" action: Action = Field(description="The computer action to execute") - coordinate: Optional[Sequence[int]] = Field( - None, description="Coordinates for mouse actions" + button: Optional[Button] = Field(None, description="The button to click") + click_type: Optional[ClickMouseActionClickType] = Field( + None, description="The type of click to perform" ) - text: Optional[str] = Field(None, description="Text for keyboard actions") + coordinates: Optional[List[int]] = Field( + None, description="The coordinates to move to" + ) + delta_x: Optional[float] = Field(None, description="The x delta to move") + delta_y: Optional[float] = Field(None, description="The y delta to move") + num_clicks: Optional[int] = Field( + None, description="The number of clicks to perform" + ) + hold_keys: Optional[List[str]] = Field(None, description="The keys to hold") + path: Optional[List[List[int]]] = Field(None, description="The path to move to") + keys: Optional[List[str]] = Field(None, description="The keys to press") + text: Optional[str] = Field(None, description="The text to type") + duration: Optional[float] = Field(None, description="The duration to wait") class ComputerTool(Tool): @@ -48,11 +46,73 @@ def __init__(self, instance: BaseInstance) -> None: def __call__(self, **kwargs: Any) -> Any: params = ComputerToolParameters.model_validate(kwargs) - return self._instance.computer( - action=params.action, - coordinate=tuple(params.coordinate) if params.coordinate else None, - text=params.text, - ) + + if params.action == "move_mouse": + if not params.coordinates: + raise ValueError("coordinates is required for move_mouse action") + return self._instance.computer( + action=params.action, + coordinates=params.coordinates, + hold_keys=params.hold_keys, + ) + elif params.action == "click_mouse": + if not params.button: + raise ValueError("button is required for click_mouse action") + return self._instance.computer( + action=params.action, + button=params.button, + click_type=params.click_type, + coordinates=params.coordinates, + num_clicks=params.num_clicks, + hold_keys=params.hold_keys, + ) + elif params.action == "drag_mouse": + if not params.path: + raise ValueError("path is required for drag_mouse action") + return self._instance.computer( + action=params.action, + path=params.path, + hold_keys=params.hold_keys, + ) + elif params.action == "scroll": + if not params.coordinates: + raise ValueError("coordinates is required for scroll action") + return self._instance.computer( + action=params.action, + coordinates=params.coordinates, + delta_x=params.delta_x, + delta_y=params.delta_y, + hold_keys=params.hold_keys, + ) + elif params.action == "press_key": + if not params.keys: + raise ValueError("keys is required for press_key action") + return self._instance.computer( + action=params.action, + keys=params.keys, + duration=params.duration, + ) + elif params.action == "type_text": + if not params.text: + raise ValueError("text is required for type_text action") + return self._instance.computer( + action=params.action, + text=params.text, + hold_keys=params.hold_keys, + ) + elif params.action == "wait": + if params.duration is None: + raise ValueError("duration is required for wait action") + return self._instance.computer( + action=params.action, + duration=params.duration, + ) + elif params.action == "take_screenshot": + return self._instance.computer(action=params.action) + elif params.action == "get_cursor_position": + return self._instance.computer(action=params.action) + else: + raise ValueError(f"Unknown action: {params.action}") class EditToolParameters(BaseModel): @@ -128,160 +188,3 @@ def __init__(self, instance: UbuntuInstance) -> None: def __call__(self, **kwargs: Any) -> Any: params = BashToolParameters.model_validate(kwargs) return self._instance.bash(command=params.command, restart=params.restart) - - -class BrowserToolParameters(BaseModel): - """Parameters for browser interaction commands.""" - - command: Literal[ - "go_to", # Navigate to a URL - "get_html", # Get current page HTML - "evaluate", # Run JavaScript code - "click", # Click on an element - "type", # Type into an element - "screenshot", # Take a screenshot - "get_text", # Get text content of element - "get_attribute", # Get attribute of element - ] = Field( - description="The browser command to execute. Required parameters per command:\n" - "- go_to: requires 'url'\n" - "- evaluate: requires 'code'\n" - "- click: requires 'selector'\n" - "- type: requires 'selector' and 'text'\n" - "- get_text: requires 'selector'\n" - "- get_attribute: requires 'selector' and 'attribute'\n" - "- get_html: no additional parameters\n" - "- screenshot: no additional parameters" - ) - url: Optional[str] = Field( - None, description="URL for go_to command (required for go_to)" - ) - selector: Optional[str] = Field( - None, - description="CSS selector for element operations (required for click, type, get_text, get_attribute)", - ) - code: Optional[str] = Field( - None, description="JavaScript code for evaluate command (required for evaluate)" - ) - text: Optional[str] = Field( - None, description="Text to type for type command (required for type)" - ) - timeout: Optional[int] = Field( - 30000, description="Timeout in milliseconds for operations" - ) - attribute: Optional[str] = Field( - None, - description="Attribute name for get_attribute command (required for get_attribute)", - ) - - -class BrowserTool(Tool): - """A browser interaction tool that allows the agent to interact with a browser. - - Available for Ubuntu and Browser instances.""" - - _instance: Union[UbuntuInstance, BrowserInstance] - - def __init__(self, instance: Union[UbuntuInstance, BrowserInstance]) -> None: - super().__init__( - name="browser", - description="Interact with a browser for web scraping and automation", - parameters=BrowserToolParameters, - ) - self._instance = instance - - def __call__(self, **kwargs: Any) -> Any: - params = BrowserToolParameters.model_validate(kwargs) - command = params.command - url = params.url - selector = params.selector - code = params.code - text = params.text - timeout = params.timeout or 30000 - attribute = params.attribute - - # Get CDP URL based on instance type - if isinstance(self._instance, UbuntuInstance): - cdp_url = self._instance.browser.get_cdp_url().cdp_url - else: - cdp_url = self._instance.get_cdp_url().cdp_url - - if cdp_url is None: - raise ValueError("CDP URL is not available, start the browser first") - - with sync_playwright() as playwright: - browser = playwright.chromium.connect_over_cdp(cdp_url) - context = browser.contexts[0] - if not context.pages: - page = context.new_page() - else: - page = context.pages[0] - - try: - if command == "go_to": - if not url: - raise ValueError("URL is required for go_to command") - page.goto(url, timeout=timeout) - return True - - elif command == "get_html": - try: - return page.evaluate("() => document.documentElement.outerHTML") - except Exception: - # If page is navigating, just return what we can get - return page.evaluate("() => document.documentElement.innerHTML") - - elif command == "evaluate": - if not code: - raise ValueError("Code is required for evaluate command") - return page.evaluate(code) - - elif command == "click": - if not selector: - raise ValueError("Selector is required for click command") - page.click(selector, timeout=timeout) - return True - - elif command == "type": - if not selector: - raise ValueError("Selector is required for type command") - if not text: - raise ValueError("Text is required for type command") - page.type(selector, text, timeout=timeout) - return True - - elif command == "screenshot": - return image_result( - base64.b64encode(page.screenshot(type="png")).decode("utf-8") - ) - - elif command == "get_text": - if not selector: - raise ValueError("Selector is required for get_text command") - element = page.wait_for_selector(selector, timeout=timeout) - if element is None: - raise ValueError(f"Element not found: {selector}") - return element.text_content() - - elif command == "get_attribute": - if not selector: - raise ValueError( - "Selector is required for get_attribute command" - ) - if not attribute: - raise ValueError( - "Attribute is required for get_attribute command" - ) - element = page.wait_for_selector(selector, timeout=timeout) - if element is None: - raise ValueError(f"Element not found: {selector}") - return element.get_attribute(attribute) - - else: - raise ValueError(f"Unknown command: {command}") - - except Exception as e: - raise ValueError(f"Browser command failed: {str(e)}") - - finally: - browser.close() diff --git a/src/scrapybara/types/__init__.py b/src/scrapybara/types/__init__.py index 59c6a92..5179743 100644 --- a/src/scrapybara/types/__init__.py +++ b/src/scrapybara/types/__init__.py @@ -1,13 +1,22 @@ +from typing import Literal from .auth_state_response import AuthStateResponse +from .bash_response import BashResponse from .browser_authenticate_response import BrowserAuthenticateResponse from .browser_get_cdp_url_response import BrowserGetCdpUrlResponse +from .button import Button from .cell_type import CellType +from .click_mouse_action import ClickMouseAction +from .click_mouse_action_click_type import ClickMouseActionClickType +from .computer_response import ComputerResponse from .deployment_config_instance_type import DeploymentConfigInstanceType +from .drag_mouse_action import DragMouseAction +from .edit_response import EditResponse from .env_get_response import EnvGetResponse from .env_response import EnvResponse from .execute_cell_request import ExecuteCellRequest from .file_download_response import FileDownloadResponse from .file_read_response import FileReadResponse +from .get_cursor_position_action import GetCursorPositionAction from .get_instance_response import GetInstanceResponse from .get_instance_response_instance_type import GetInstanceResponseInstanceType from .http_validation_error import HttpValidationError @@ -15,15 +24,21 @@ from .instance_screenshot_response import InstanceScreenshotResponse from .kernel_info import KernelInfo from .modify_browser_auth_response import ModifyBrowserAuthResponse +from .move_mouse_action import MoveMouseAction from .notebook import Notebook from .notebook_cell import NotebookCell +from .press_key_action import PressKeyAction from .save_browser_auth_response import SaveBrowserAuthResponse +from .scroll_action import ScrollAction from .start_browser_response import StartBrowserResponse from .status import Status from .stop_browser_response import StopBrowserResponse from .stop_instance_response import StopInstanceResponse +from .take_screenshot_action import TakeScreenshotAction +from .type_text_action import TypeTextAction from .validation_error import ValidationError from .validation_error_loc_item import ValidationErrorLocItem +from .wait_action import WaitAction from .act import ( TextPart, ImagePart, @@ -42,47 +57,74 @@ ) from .tool import Tool, ApiTool +Action = Literal[ + "move_mouse", + "click_mouse", + "drag_mouse", + "scroll", + "press_key", + "type_text", + "wait", + "take_screenshot", + "get_cursor_position", +] + __all__ = [ + "ActResponse", + "Action", + "ApiTool", + "AssistantMessage", "AuthStateResponse", + "BashResponse", "BrowserAuthenticateResponse", "BrowserGetCdpUrlResponse", + "Button", "CellType", + "ClickMouseAction", + "ClickMouseActionClickType", + "ComputerResponse", "DeploymentConfigInstanceType", + "DragMouseAction", + "EditResponse", "EnvGetResponse", "EnvResponse", "ExecuteCellRequest", "FileDownloadResponse", "FileReadResponse", + "GetCursorPositionAction", "GetInstanceResponse", "GetInstanceResponseInstanceType", "HttpValidationError", + "ImagePart", "InstanceGetStreamUrlResponse", "InstanceScreenshotResponse", "KernelInfo", + "Message", + "Model", "ModifyBrowserAuthResponse", + "MoveMouseAction", "Notebook", "NotebookCell", + "PressKeyAction", "SaveBrowserAuthResponse", + "ScrollAction", + "SingleActRequest", + "SingleActResponse", "StartBrowserResponse", "Status", + "Step", "StopBrowserResponse", "StopInstanceResponse", - "ValidationError", - "ValidationErrorLocItem", + "TakeScreenshotAction", "TextPart", - "ImagePart", + "Tool", "ToolCallPart", - "ToolResultPart", - "UserMessage", - "AssistantMessage", "ToolMessage", - "Message", - "Model", - "SingleActRequest", + "ToolResultPart", "TokenUsage", - "SingleActResponse", - "Step", - "ActResponse", - "Tool", - "ApiTool", + "TypeTextAction", + "UserMessage", + "ValidationError", + "ValidationErrorLocItem", + "WaitAction", ] diff --git a/src/scrapybara/types/bash_response.py b/src/scrapybara/types/bash_response.py new file mode 100644 index 0000000..1b3829b --- /dev/null +++ b/src/scrapybara/types/bash_response.py @@ -0,0 +1,28 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +import typing_extensions +from ..core.serialization import FieldMetadata +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class BashResponse(UniversalBaseModel): + """ + Response model for bash actions. + """ + + output: typing.Optional[str] = None + error: typing.Optional[str] = None + base_64_image: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="base64_image")] = None + system: typing.Optional[str] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/scrapybara/types/button.py b/src/scrapybara/types/button.py new file mode 100644 index 0000000..032f76b --- /dev/null +++ b/src/scrapybara/types/button.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +Button = typing.Union[typing.Literal["left", "right", "middle", "back", "forward"], typing.Any] diff --git a/src/scrapybara/types/click_mouse_action.py b/src/scrapybara/types/click_mouse_action.py new file mode 100644 index 0000000..fdb5b8a --- /dev/null +++ b/src/scrapybara/types/click_mouse_action.py @@ -0,0 +1,25 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +from .button import Button +import typing +from .click_mouse_action_click_type import ClickMouseActionClickType +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class ClickMouseAction(UniversalBaseModel): + button: Button + click_type: typing.Optional[ClickMouseActionClickType] = None + coordinates: typing.Optional[typing.List[int]] = None + num_clicks: typing.Optional[int] = None + hold_keys: typing.Optional[typing.List[str]] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/scrapybara/types/click_mouse_action_click_type.py b/src/scrapybara/types/click_mouse_action_click_type.py new file mode 100644 index 0000000..7b6d146 --- /dev/null +++ b/src/scrapybara/types/click_mouse_action_click_type.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +ClickMouseActionClickType = typing.Union[typing.Literal["down", "up", "click"], typing.Any] diff --git a/src/scrapybara/types/computer_response.py b/src/scrapybara/types/computer_response.py new file mode 100644 index 0000000..176eaa7 --- /dev/null +++ b/src/scrapybara/types/computer_response.py @@ -0,0 +1,28 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +import typing_extensions +from ..core.serialization import FieldMetadata +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class ComputerResponse(UniversalBaseModel): + """ + Response model for computer actions. + """ + + output: typing.Optional[str] = None + error: typing.Optional[str] = None + base_64_image: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="base64_image")] = None + system: typing.Optional[str] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/scrapybara/types/drag_mouse_action.py b/src/scrapybara/types/drag_mouse_action.py new file mode 100644 index 0000000..354caec --- /dev/null +++ b/src/scrapybara/types/drag_mouse_action.py @@ -0,0 +1,20 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class DragMouseAction(UniversalBaseModel): + path: typing.List[typing.List[int]] + hold_keys: typing.Optional[typing.List[str]] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/scrapybara/types/edit_response.py b/src/scrapybara/types/edit_response.py new file mode 100644 index 0000000..7650b2f --- /dev/null +++ b/src/scrapybara/types/edit_response.py @@ -0,0 +1,28 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +import typing_extensions +from ..core.serialization import FieldMetadata +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class EditResponse(UniversalBaseModel): + """ + Response model for edit actions. + """ + + output: typing.Optional[str] = None + error: typing.Optional[str] = None + base_64_image: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="base64_image")] = None + system: typing.Optional[str] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/scrapybara/types/get_cursor_position_action.py b/src/scrapybara/types/get_cursor_position_action.py new file mode 100644 index 0000000..177164f --- /dev/null +++ b/src/scrapybara/types/get_cursor_position_action.py @@ -0,0 +1,17 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import typing +import pydantic + + +class GetCursorPositionAction(UniversalBaseModel): + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/scrapybara/types/move_mouse_action.py b/src/scrapybara/types/move_mouse_action.py new file mode 100644 index 0000000..66e0335 --- /dev/null +++ b/src/scrapybara/types/move_mouse_action.py @@ -0,0 +1,20 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class MoveMouseAction(UniversalBaseModel): + coordinates: typing.List[int] + hold_keys: typing.Optional[typing.List[str]] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/scrapybara/types/press_key_action.py b/src/scrapybara/types/press_key_action.py new file mode 100644 index 0000000..432eea0 --- /dev/null +++ b/src/scrapybara/types/press_key_action.py @@ -0,0 +1,20 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class PressKeyAction(UniversalBaseModel): + keys: typing.List[str] + duration: typing.Optional[float] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/scrapybara/types/scroll_action.py b/src/scrapybara/types/scroll_action.py new file mode 100644 index 0000000..b03bf80 --- /dev/null +++ b/src/scrapybara/types/scroll_action.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class ScrollAction(UniversalBaseModel): + coordinates: typing.List[int] + delta_x: typing.Optional[float] = None + delta_y: typing.Optional[float] = None + hold_keys: typing.Optional[typing.List[str]] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/scrapybara/types/status.py b/src/scrapybara/types/status.py index 3fb3c9c..0c98034 100644 --- a/src/scrapybara/types/status.py +++ b/src/scrapybara/types/status.py @@ -2,4 +2,4 @@ import typing -Status = typing.Union[typing.Literal["deploying", "running", "paused", "terminated", "error"], typing.Any] +Status = typing.Union[typing.Literal["deploying", "running", "paused", "terminated", "error", "warm_pool"], typing.Any] diff --git a/src/scrapybara/types/take_screenshot_action.py b/src/scrapybara/types/take_screenshot_action.py new file mode 100644 index 0000000..fdbc5d3 --- /dev/null +++ b/src/scrapybara/types/take_screenshot_action.py @@ -0,0 +1,17 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import typing +import pydantic + + +class TakeScreenshotAction(UniversalBaseModel): + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/scrapybara/types/type_text_action.py b/src/scrapybara/types/type_text_action.py new file mode 100644 index 0000000..6bf9e52 --- /dev/null +++ b/src/scrapybara/types/type_text_action.py @@ -0,0 +1,20 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class TypeTextAction(UniversalBaseModel): + text: str + hold_keys: typing.Optional[typing.List[str]] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/scrapybara/types/wait_action.py b/src/scrapybara/types/wait_action.py new file mode 100644 index 0000000..23e1131 --- /dev/null +++ b/src/scrapybara/types/wait_action.py @@ -0,0 +1,19 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import typing +import pydantic + + +class WaitAction(UniversalBaseModel): + duration: float + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/tests/custom/test_client.py b/tests/custom/test_client.py index 951c749..894c531 100644 --- a/tests/custom/test_client.py +++ b/tests/custom/test_client.py @@ -110,6 +110,8 @@ def test_windows() -> None: assert response.output.combined_valuation is not None windows_instance.stop() + +@pytest.mark.skip() def test_ubuntu_thinking() -> None: _check_api_key() client = Scrapybara() @@ -144,6 +146,7 @@ def test_ubuntu_thinking() -> None: ubuntu_instance.stop() +@pytest.mark.skip() def test_browser_thinking() -> None: _check_api_key() client = Scrapybara()