From b6b4cd0a4ce79d092f14d245815ced0ea4dc889e Mon Sep 17 00:00:00 2001 From: Sam Partee Date: Wed, 11 Jun 2025 16:48:17 -0700 Subject: [PATCH] =?UTF-8?q?=F0=9F=8F=97=EF=B8=8F=20Restructure:=20Multi-Pa?= =?UTF-8?q?ckage=20Architecture=20+=20uv=20Migration=20(#412)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### Overview Major restructuring from monolithic `arcade-ai` package to modular library architecture with standardized uv-based dependency management. ![arcade-ai Monorepo (2)](https://github.com/user-attachments/assets/25f102b0-bb87-4a04-9701-d227d05664b1) ### New Package Structure - **`arcade-tdk`** - Lightweight toolkit development kit (core decorators, auth) - **`arcade-core`** - Core execution engine and catalog functionality - **`arcade-serve`** - FastAPI/MCP server components - **`arcade-ai`** - Meta package that includes CLI functionality. Optionally include evals via the `evals` extra. Optionally include all packages via the `all` extra. ### Key Benefits - **Lighter Dependencies**: Toolkits now depend only on `arcade-tdk` (~2 deps) vs full `arcade-ai` (~30+ deps) - **Faster Builds**: uv provides 10-100x faster dependency resolution and installation - **Better Modularity**: Clear separation of concerns, consumers import only what they need - **Standard Tooling**: Eliminates custom poetry scripts, uses standard Python packaging ### Migration Impact - All 20 toolkits converted from poetry โ†’ uv with `arcade-tdk` dependencies plus `arcade-ai[evals]` and `arcade-serve` dev dependencies. When developing locally, devs should install toolkits via `make install-local`. - Modern Python 3.10+ type hints throughout - Standardized build system with hatchling backend - Enhanced Makefile with robust toolkit management commands - Removed `arcade dev` CLI command - Reduce the number of files created by `arcade new` and add an option to not generate a tests and evals folder. This foundation enables faster development cycles and cleaner dependency chains for the growing toolkit ecosystem. ### Todo After this PR is merged - [ ] Post-merge workflow(s) (release & publish containers, etc) - [ ] Release order plan. @EricGustin suggests releasing in the following order: 1. `arcade-core` version 0.1.0 2. `arcade-serve` version 0.1.0 and `arcade-tdk` version 0.1.0 3. `arcade-ai` version 2.0.0 4. Patch release for all toolkits (all changes in toolkits are internal refactors) - [ ] [Update docs](https://github.com/ArcadeAI/docs/pull/318) --------- Co-authored-by: Eric Gustin Co-authored-by: Eric Gustin <34000337+EricGustin@users.noreply.github.com> --- .github/actions/setup-uv-env/action.yml | 20 + .github/workflows/main.yml | 29 +- .github/workflows/test-toolkits.yml | 57 +- .pre-commit-config.yaml | 1 + .ruff.toml | 4 + .vscode/launch.json | 28 +- CONTRIBUTING.md | 37 +- Makefile | 224 ++++++-- README.md | 52 +- arcade/README.md | 13 - arcade/arcade/__init__.py | 3 - arcade/arcade/cli/launcher.py | 505 ------------------ arcade/arcade/cli/new.py | 143 ----- arcade/arcade/sdk/__init__.py | 14 - arcade/arcade/sdk/annotations/__init__.py | 3 - .../{{ toolkit_name }}/.editorconfig | 15 - .../actions/setup-poetry-env/action.yml | 39 -- .../.github/workflows/main.yml | 61 --- .../.github/workflows/publish-to-pypi.yml | 38 -- .../templates/{{ toolkit_name }}/.gitignore | 167 ------ .../.pre-commit-config.yaml | 19 - .../{{ toolkit_name }}/.prettierignore | 3 - .../{{ toolkit_name }}/.prettierrc.toml | 16 - .../templates/{{ toolkit_name }}/.ruff.toml | 45 -- .../templates/{{ toolkit_name }}/LICENSE | 22 - .../templates/{{ toolkit_name }}/Makefile | 59 -- .../templates/{{ toolkit_name }}/codecov.yaml | 10 - .../{{ toolkit_name }}/pyproject.toml | 40 -- .../templates/{{ toolkit_name }}/tox.ini | 17 - arcade/codecov.yaml | 11 - arcade/pyproject.toml | 88 --- arcade/tox.ini | 17 - examples/mcp/run_stdio.py | 5 +- .../serving-tools/modal/run-arcade-worker.py | 9 +- libs/arcade-cli/README.md | 28 + .../arcade-cli/arcade_cli}/__init__.py | 0 .../arcade-cli/arcade_cli}/authn.py | 2 +- libs/arcade-cli/arcade_cli/config.py | 104 ++++ .../arcade-cli/arcade_cli}/constants.py | 0 .../arcade-cli/arcade_cli}/deployment.py | 0 .../arcade-cli/arcade_cli}/display.py | 5 +- .../arcade-cli/arcade_cli}/main.py | 84 +-- libs/arcade-cli/arcade_cli/new.py | 219 ++++++++ .../arcade-cli/arcade_cli}/serve.py | 15 +- .../arcade-cli/arcade_cli}/show.py | 4 +- .../templates/{{ toolkit_name }}/Makefile | 46 ++ .../templates/{{ toolkit_name }}/README.md | 16 +- .../evals/eval_{{ toolkit_name }}.py | 6 +- .../{{ toolkit_name }}/pyproject.toml | 66 +++ .../{{ toolkit_name }}/tests/__init__.py | 0 .../tests/test_{{ toolkit_name }}.py | 2 +- .../{{ package_name }}/__init__.py | 0 .../{{ package_name }}/tools/__init__.py | 0 .../{{ package_name }}/tools/hello.py | 3 +- .../arcade-cli/arcade_cli}/utils.py | 44 +- .../arcade-cli/arcade_cli}/worker.py | 4 +- {arcade => libs/arcade-cli}/run_cli.py | 2 +- libs/arcade-core/README.md | 39 ++ libs/arcade-core/arcade_core/__init__.py | 2 + .../arcade-core/arcade_core}/annotations.py | 0 .../arcade-core/arcade_core}/auth.py | 0 .../arcade-core/arcade_core}/catalog.py | 12 +- .../arcade-core/arcade_core}/config.py | 2 +- .../arcade-core/arcade_core}/config_model.py | 0 .../arcade-core/arcade_core}/errors.py | 0 .../arcade-core/arcade_core}/executor.py | 6 +- .../arcade-core/arcade_core}/output.py | 4 +- .../arcade-core/arcade_core}/parse.py | 0 .../arcade-core/arcade_core}/py.typed | 0 .../arcade-core/arcade_core}/schema.py | 0 .../arcade-core/arcade_core}/telemetry.py | 0 .../arcade-core/arcade_core}/toolkit.py | 4 +- .../arcade-core/arcade_core}/utils.py | 0 .../arcade-core/arcade_core}/version.py | 0 libs/arcade-core/pyproject.toml | 65 +++ libs/arcade-evals/README.md | 86 +++ .../arcade-evals/arcade_evals}/__init__.py | 0 .../arcade-evals/arcade_evals}/critic.py | 5 +- libs/arcade-evals/arcade_evals/errors.py | 12 + .../arcade-evals/arcade_evals}/eval.py | 24 +- .../arcade-evals/arcade_evals/py.typed | 0 libs/arcade-serve/README.md | 70 +++ .../arcade-serve/arcade_serve}/__init__.py | 0 .../arcade_serve/core}/__init__.py | 0 .../arcade-serve/arcade_serve}/core/auth.py | 0 .../arcade-serve/arcade_serve}/core/base.py | 16 +- .../arcade-serve/arcade_serve}/core/common.py | 3 +- .../arcade_serve}/core/components.py | 2 +- .../arcade_serve}/fastapi/__init__.py | 0 .../arcade_serve}/fastapi/auth.py | 2 +- .../arcade_serve}/fastapi/worker.py | 8 +- .../arcade_serve}/mcp/__init__.py | 2 +- .../arcade-serve/arcade_serve}/mcp/convert.py | 2 +- .../arcade-serve/arcade_serve}/mcp/logging.py | 2 +- .../arcade_serve}/mcp/message_processor.py | 2 +- .../arcade-serve/arcade_serve}/mcp/server.py | 16 +- .../arcade-serve/arcade_serve}/mcp/stdio.py | 2 +- .../arcade-serve/arcade_serve}/mcp/types.py | 0 .../arcade-serve/arcade_serve/py.typed | 0 .../arcade-serve/arcade_serve}/utils.py | 0 libs/arcade-serve/pyproject.toml | 54 ++ libs/arcade-tdk/README.md | 58 ++ libs/arcade-tdk/arcade_tdk/__init__.py | 22 + .../arcade_tdk/annotations/__init__.py | 3 + .../arcade-tdk/arcade_tdk}/auth/__init__.py | 2 +- .../arcade-tdk/arcade_tdk}/errors.py | 10 +- .../arcade-tdk/arcade_tdk/py.typed | 0 .../arcade-tdk/arcade_tdk}/tool.py | 6 +- libs/arcade-tdk/arcade_tdk/utils.py | 10 + libs/arcade-tdk/pyproject.toml | 51 ++ libs/tests/__init__.py | 0 {arcade => libs}/tests/cli/test_dashboard.py | 19 +- {arcade => libs}/tests/cli/test_show.py | 6 +- {arcade => libs}/tests/cli/test_utils.py | 3 +- {arcade => libs}/tests/core/test_catalog.py | 15 +- {arcade => libs}/tests/core/test_executor.py | 11 +- {arcade => libs}/tests/core/test_output.py | 3 +- {arcade => libs}/tests/core/test_parse.py | 3 +- {arcade => libs}/tests/core/test_schema.py | 3 +- {arcade => libs}/tests/core/test_telemetry.py | 31 +- .../tests/core/utils/test_casing.py | 3 +- .../core/utils/test_is_strict_optional.py | 3 +- .../tests/core/utils/test_is_union.py | 3 +- .../tests/deployment/test_config.py | 3 +- .../test_files/env.secret.worker.toml | 0 .../deployment/test_files/full.worker.toml | 0 .../test_files/invalid.fields.worker.toml | 0 .../test_files/invalid.localfile.worker.toml | 0 .../test_files/invalid.secret.worker.toml | 0 .../invalid_toolkit/invalid_main.py | 0 .../test_files/mock_toolkit/mock_main.py | 0 .../test_files/mock_toolkit/pyproject.toml | 0 {arcade => libs}/tests/mcp/test_convert.py | 6 +- .../tests/mcp/test_message_processor.py | 5 +- {arcade => libs}/tests/mcp/test_server.py | 9 +- {arcade => libs}/tests/mcp/test_stdio.py | 2 +- {arcade => libs}/tests/sdk/test_eval.py | 7 +- .../tests/sdk/test_eval_critic.py | 7 +- .../tests/sdk/test_tool_decorator.py | 7 +- .../tests/tool/test_create_tool_definition.py | 13 +- .../test_create_tool_definition_errors.py | 9 +- .../tool/test_create_tool_definition_new.py | 5 +- .../test_create_tool_definition_pydantic.py | 9 +- ..._create_tool_definition_pydantic_errors.py | 7 +- .../tool/test_fully_qualified_tool_name.py | 2 +- .../tests/worker/test_worker_base.py | 13 +- .../tests/worker/test_worker_fastapi.py | 7 +- pyproject.toml | 152 ++++++ toolkits/asana/.pre-commit-config.yaml | 2 +- toolkits/asana/Makefile | 38 +- toolkits/asana/arcade_asana/exceptions.py | 2 +- toolkits/asana/arcade_asana/tools/projects.py | 4 +- toolkits/asana/arcade_asana/tools/tags.py | 6 +- toolkits/asana/arcade_asana/tools/tasks.py | 6 +- toolkits/asana/arcade_asana/tools/teams.py | 4 +- toolkits/asana/arcade_asana/tools/users.py | 4 +- .../asana/arcade_asana/tools/workspaces.py | 4 +- toolkits/asana/arcade_asana/utils.py | 4 +- toolkits/asana/conftest.py | 2 +- toolkits/asana/evals/eval_create_task.py | 6 +- toolkits/asana/evals/eval_projects.py | 6 +- toolkits/asana/evals/eval_tags.py | 6 +- toolkits/asana/evals/eval_tasks.py | 6 +- toolkits/asana/evals/eval_teams.py | 6 +- toolkits/asana/evals/eval_users.py | 6 +- toolkits/asana/evals/eval_workspaces.py | 6 +- toolkits/asana/pyproject.toml | 57 +- toolkits/asana/tests/test_utils.py | 2 +- toolkits/code_sandbox/.pre-commit-config.yaml | 2 +- toolkits/code_sandbox/Makefile | 43 +- .../arcade_code_sandbox/tools/e2b.py | 2 +- toolkits/code_sandbox/evals/eval_e2b.py | 4 +- toolkits/code_sandbox/pyproject.toml | 57 +- toolkits/code_sandbox/tests/test_e2b.py | 5 +- toolkits/confluence/.pre-commit-config.yaml | 2 +- toolkits/confluence/Makefile | 43 +- .../confluence/arcade_confluence/client.py | 11 +- .../arcade_confluence/tools/attachment.py | 4 +- .../arcade_confluence/tools/page.py | 6 +- .../arcade_confluence/tools/search.py | 4 +- .../arcade_confluence/tools/space.py | 4 +- .../confluence/arcade_confluence/utils.py | 2 +- toolkits/confluence/evals/critics.py | 2 +- toolkits/confluence/evals/eval_page.py | 7 +- toolkits/confluence/evals/eval_search.py | 6 +- toolkits/confluence/evals/eval_space.py | 6 +- toolkits/confluence/pyproject.toml | 55 +- toolkits/confluence/tests/test_client_v1.py | 2 +- toolkits/confluence/tests/test_utils.py | 2 +- toolkits/dropbox/.pre-commit-config.yaml | 2 +- toolkits/dropbox/Makefile | 38 +- toolkits/dropbox/arcade_dropbox/critics.py | 2 +- .../dropbox/arcade_dropbox/tools/browse.py | 6 +- .../dropbox/arcade_dropbox/tools/files.py | 6 +- toolkits/dropbox/conftest.py | 2 +- toolkits/dropbox/evals/eval_download_file.py | 4 +- toolkits/dropbox/evals/eval_list_items.py | 4 +- toolkits/dropbox/evals/eval_search.py | 4 +- toolkits/dropbox/pyproject.toml | 57 +- toolkits/github/.pre-commit-config.yaml | 2 +- toolkits/github/Makefile | 41 +- .../github/arcade_github/tools/activity.py | 4 +- toolkits/github/arcade_github/tools/issues.py | 4 +- .../arcade_github/tools/pull_requests.py | 6 +- .../arcade_github/tools/repositories.py | 4 +- toolkits/github/arcade_github/tools/utils.py | 2 +- toolkits/github/evals/eval_github_activity.py | 4 +- toolkits/github/evals/eval_github_issues.py | 4 +- .../github/evals/eval_github_pull_requests.py | 4 +- .../github/evals/eval_github_repositories.py | 4 +- toolkits/github/pyproject.toml | 56 +- toolkits/github/tests/test_activity.py | 2 +- toolkits/github/tests/test_issues.py | 2 +- toolkits/github/tests/test_pull_requests.py | 2 +- toolkits/github/tests/test_repositories.py | 2 +- toolkits/google/.pre-commit-config.yaml | 2 +- toolkits/google/Makefile | 43 +- toolkits/google/arcade_google/critics.py | 2 +- toolkits/google/arcade_google/exceptions.py | 2 +- .../google/arcade_google/tools/calendar.py | 6 +- .../google/arcade_google/tools/contacts.py | 4 +- toolkits/google/arcade_google/tools/docs.py | 4 +- toolkits/google/arcade_google/tools/drive.py | 4 +- .../google/arcade_google/tools/file_picker.py | 6 +- toolkits/google/arcade_google/tools/gmail.py | 6 +- toolkits/google/arcade_google/tools/sheets.py | 6 +- toolkits/google/arcade_google/utils.py | 4 +- .../google/evals/eval_calendar_free_slots.py | 4 +- toolkits/google/evals/eval_file_picker.py | 4 +- toolkits/google/evals/eval_google_calendar.py | 4 +- toolkits/google/evals/eval_google_contacts.py | 6 +- toolkits/google/evals/eval_google_docs.py | 4 +- toolkits/google/evals/eval_google_drive.py | 4 +- toolkits/google/evals/eval_google_gmail.py | 4 +- toolkits/google/evals/eval_google_sheets.py | 4 +- toolkits/google/pyproject.toml | 69 ++- toolkits/google/tests/test_calendar.py | 4 +- toolkits/google/tests/test_contacts.py | 2 +- toolkits/google/tests/test_docs.py | 2 +- toolkits/google/tests/test_drive.py | 2 +- toolkits/google/tests/test_file_picker.py | 3 +- toolkits/google/tests/test_gmail.py | 4 +- toolkits/google/tests/test_sheets_utils.py | 2 +- toolkits/hubspot/.pre-commit-config.yaml | 2 +- toolkits/hubspot/Makefile | 38 +- .../hubspot/arcade_hubspot/custom_critics.py | 2 +- toolkits/hubspot/arcade_hubspot/exceptions.py | 2 +- .../arcade_hubspot/tools/crm/companies.py | 4 +- .../arcade_hubspot/tools/crm/contacts.py | 4 +- toolkits/hubspot/conftest.py | 2 +- toolkits/hubspot/evals/eval_crm_companies.py | 4 +- toolkits/hubspot/evals/eval_crm_contacts.py | 4 +- toolkits/hubspot/pyproject.toml | 57 +- toolkits/jira/.pre-commit-config.yaml | 2 +- toolkits/jira/.ruff.toml | 6 +- toolkits/jira/Makefile | 38 +- toolkits/jira/arcade_jira/client.py | 28 +- toolkits/jira/arcade_jira/critics.py | 2 +- toolkits/jira/arcade_jira/exceptions.py | 2 +- .../jira/arcade_jira/tools/attachments.py | 10 +- toolkits/jira/arcade_jira/tools/comments.py | 10 +- toolkits/jira/arcade_jira/tools/issues.py | 8 +- toolkits/jira/arcade_jira/tools/labels.py | 4 +- toolkits/jira/arcade_jira/tools/priorities.py | 4 +- toolkits/jira/arcade_jira/tools/projects.py | 4 +- .../jira/arcade_jira/tools/transitions.py | 4 +- toolkits/jira/arcade_jira/tools/users.py | 10 +- toolkits/jira/arcade_jira/utils.py | 56 +- toolkits/jira/conftest.py | 5 +- .../jira/evals/eval_create_update_issues.py | 25 +- toolkits/jira/evals/eval_get_issues.py | 16 +- toolkits/jira/evals/eval_issue_types.py | 14 +- toolkits/jira/evals/eval_transitions.py | 4 +- toolkits/jira/pyproject.toml | 59 +- .../tests/test_find_priorities_by_project.py | 6 +- .../jira/tests/test_find_unique_issue_type.py | 4 +- .../jira/tests/test_find_unique_priority.py | 4 +- .../jira/tests/test_find_unique_project.py | 4 +- toolkits/jira/tests/test_find_unique_user.py | 4 +- .../jira/tests/test_pagination_helpers.py | 4 +- toolkits/linkedin/.pre-commit-config.yaml | 2 +- toolkits/linkedin/Makefile | 43 +- .../linkedin/arcade_linkedin/tools/share.py | 6 +- .../linkedin/arcade_linkedin/tools/utils.py | 4 +- toolkits/linkedin/conftest.py | 2 +- toolkits/linkedin/evals/eval_linkedin.py | 4 +- toolkits/linkedin/pyproject.toml | 57 +- toolkits/linkedin/tests/test_share.py | 2 +- toolkits/math/.pre-commit-config.yaml | 2 +- toolkits/math/Makefile | 43 +- toolkits/math/arcade_math/tools/arithmetic.py | 2 +- toolkits/math/arcade_math/tools/exponents.py | 2 +- .../math/arcade_math/tools/miscellaneous.py | 2 +- toolkits/math/arcade_math/tools/random.py | 2 +- toolkits/math/arcade_math/tools/rational.py | 2 +- toolkits/math/arcade_math/tools/rounding.py | 2 +- toolkits/math/arcade_math/tools/statistics.py | 2 +- .../math/arcade_math/tools/trigonometry.py | 2 +- toolkits/math/evals/eval_math_tools.py | 4 +- toolkits/math/pyproject.toml | 55 +- toolkits/math/tests/test_arithmetic.py | 2 +- toolkits/math/tests/test_exponents.py | 2 +- toolkits/math/tests/test_miscellaneous.py | 2 +- toolkits/math/tests/test_rational.py | 2 +- toolkits/microsoft/.pre-commit-config.yaml | 2 +- toolkits/microsoft/Makefile | 43 +- .../outlook_calendar/_utils.py | 2 +- .../outlook_calendar/tools/create_event.py | 4 +- .../outlook_calendar/tools/get_event.py | 4 +- .../tools/list_events_in_time_range.py | 4 +- .../arcade_microsoft/outlook_mail/_utils.py | 2 +- .../arcade_microsoft/outlook_mail/message.py | 4 +- .../outlook_mail/tools/read.py | 6 +- .../outlook_mail/tools/send.py | 4 +- .../outlook_mail/tools/write.py | 6 +- .../outlook_calendar/eval_create_event.py | 6 +- .../evals/outlook_calendar/eval_get_event.py | 4 +- .../eval_list_events_in_time_range.py | 6 +- .../microsoft/evals/outlook_mail/eval_read.py | 4 +- .../microsoft/evals/outlook_mail/eval_send.py | 6 +- .../evals/outlook_mail/eval_write.py | 6 +- toolkits/microsoft/pyproject.toml | 58 +- .../tests/outlook_calendar/test_utils.py | 2 +- toolkits/notion/.pre-commit-config.yaml | 2 +- toolkits/notion/Makefile | 43 +- .../block_to_markdown_converter.py | 2 +- .../arcade_notion_toolkit/tools/pages.py | 6 +- .../arcade_notion_toolkit/tools/search.py | 6 +- .../notion/arcade_notion_toolkit/utils.py | 2 +- toolkits/notion/conftest.py | 2 +- toolkits/notion/evals/eval_notion_pages.py | 4 +- toolkits/notion/evals/eval_notion_search.py | 4 +- toolkits/notion/pyproject.toml | 54 +- toolkits/reddit/.pre-commit-config.yaml | 2 +- toolkits/reddit/Makefile | 43 +- toolkits/reddit/arcade_reddit/tools/read.py | 6 +- toolkits/reddit/arcade_reddit/tools/submit.py | 4 +- toolkits/reddit/arcade_reddit/utils.py | 4 +- toolkits/reddit/evals/critics.py | 2 +- toolkits/reddit/evals/eval_reddit_read.py | 6 +- toolkits/reddit/evals/eval_reddit_submit.py | 7 +- toolkits/reddit/pyproject.toml | 52 +- toolkits/reddit/tests/test_utils.py | 2 +- toolkits/salesforce/.pre-commit-config.yaml | 2 +- toolkits/salesforce/Makefile | 43 +- .../arcade_salesforce/exceptions.py | 2 +- .../arcade_salesforce/tools/crm/account.py | 6 +- .../arcade_salesforce/tools/crm/contact.py | 6 +- toolkits/salesforce/conftest.py | 2 +- .../salesforce/evals/eval_create_contact.py | 6 +- .../salesforce/evals/eval_get_account_data.py | 6 +- toolkits/salesforce/pyproject.toml | 54 +- toolkits/search/.pre-commit-config.yaml | 2 +- toolkits/search/Makefile | 43 +- toolkits/search/arcade_search/exceptions.py | 2 +- .../arcade_search/tools/google_finance.py | 2 +- .../arcade_search/tools/google_flights.py | 2 +- .../arcade_search/tools/google_hotels.py | 2 +- .../search/arcade_search/tools/google_jobs.py | 2 +- .../search/arcade_search/tools/google_maps.py | 2 +- .../search/arcade_search/tools/google_news.py | 4 +- .../arcade_search/tools/google_search.py | 2 +- .../arcade_search/tools/google_shopping.py | 4 +- .../search/arcade_search/tools/walmart.py | 6 +- .../search/arcade_search/tools/youtube.py | 4 +- toolkits/search/arcade_search/utils.py | 4 +- toolkits/search/evals/eval_google_jobs.py | 4 +- .../evals/eval_google_maps_directions.py | 4 +- toolkits/search/evals/eval_google_search.py | 4 +- toolkits/search/pyproject.toml | 54 +- toolkits/search/tests/test_google_jobs.py | 3 +- .../tests/test_google_maps_directions.py | 3 +- toolkits/search/tests/test_google_search.py | 3 +- toolkits/search/tests/test_utils.py | 2 +- toolkits/slack/.pre-commit-config.yaml | 2 +- toolkits/slack/Makefile | 43 +- toolkits/slack/arcade_slack/critics.py | 2 +- toolkits/slack/arcade_slack/tools/chat.py | 6 +- toolkits/slack/arcade_slack/tools/users.py | 6 +- toolkits/slack/arcade_slack/utils.py | 6 +- toolkits/slack/conftest.py | 2 +- toolkits/slack/evals/eval_chat.py | 4 +- toolkits/slack/evals/eval_users.py | 4 +- toolkits/slack/pyproject.toml | 57 +- toolkits/slack/tests/test_chat.py | 2 +- toolkits/slack/tests/test_users.py | 2 +- toolkits/slack/tests/test_utils.py | 2 +- toolkits/spotify/.pre-commit-config.yaml | 2 +- toolkits/spotify/Makefile | 43 +- .../spotify/arcade_spotify/tools/player.py | 6 +- .../spotify/arcade_spotify/tools/search.py | 4 +- .../spotify/arcade_spotify/tools/tracks.py | 4 +- .../spotify/arcade_spotify/tools/utils.py | 2 +- toolkits/spotify/conftest.py | 2 +- toolkits/spotify/evals/eval_player.py | 4 +- toolkits/spotify/evals/eval_search.py | 4 +- toolkits/spotify/evals/eval_tracks.py | 4 +- toolkits/spotify/pyproject.toml | 54 +- toolkits/spotify/tests/test_player.py | 2 +- toolkits/spotify/tests/test_search.py | 2 +- toolkits/spotify/tests/test_tracks.py | 2 +- toolkits/stripe/.pre-commit-config.yaml | 2 +- toolkits/stripe/Makefile | 43 +- toolkits/stripe/_generate.py | 2 +- .../stripe/arcade_stripe/evals/eval_stripe.py | 12 +- toolkits/stripe/arcade_stripe/tools/stripe.py | 2 +- toolkits/stripe/pyproject.toml | 52 +- toolkits/web/.pre-commit-config.yaml | 2 +- toolkits/web/Makefile | 43 +- toolkits/web/arcade_web/tools/firecrawl.py | 2 +- toolkits/web/evals/eval_firecrawl.py | 4 +- toolkits/web/pyproject.toml | 54 +- toolkits/web/tests/test_firecrawl.py | 5 +- toolkits/x/.pre-commit-config.yaml | 2 +- toolkits/x/Makefile | 43 +- toolkits/x/arcade_x/tools/tweets.py | 6 +- toolkits/x/arcade_x/tools/users.py | 6 +- toolkits/x/arcade_x/tools/utils.py | 4 +- toolkits/x/conftest.py | 2 +- toolkits/x/evals/eval_x_tools.py | 4 +- toolkits/x/pyproject.toml | 55 +- toolkits/x/tests/test_tweets.py | 2 +- toolkits/x/tests/test_users.py | 2 +- toolkits/zoom/.pre-commit-config.yaml | 2 +- toolkits/zoom/Makefile | 43 +- toolkits/zoom/arcade_zoom/tools/meetings.py | 4 +- toolkits/zoom/arcade_zoom/tools/utils.py | 4 +- toolkits/zoom/pyproject.toml | 54 +- toolkits/zoom/tests/test_meetings.py | 2 +- 429 files changed, 3321 insertions(+), 3184 deletions(-) create mode 100644 .github/actions/setup-uv-env/action.yml delete mode 100644 arcade/README.md delete mode 100644 arcade/arcade/__init__.py delete mode 100644 arcade/arcade/cli/launcher.py delete mode 100644 arcade/arcade/cli/new.py delete mode 100644 arcade/arcade/sdk/__init__.py delete mode 100644 arcade/arcade/sdk/annotations/__init__.py delete mode 100644 arcade/arcade/templates/{{ toolkit_name }}/.editorconfig delete mode 100644 arcade/arcade/templates/{{ toolkit_name }}/.github/actions/setup-poetry-env/action.yml delete mode 100644 arcade/arcade/templates/{{ toolkit_name }}/.github/workflows/main.yml delete mode 100644 arcade/arcade/templates/{{ toolkit_name }}/.github/workflows/publish-to-pypi.yml delete mode 100644 arcade/arcade/templates/{{ toolkit_name }}/.gitignore delete mode 100644 arcade/arcade/templates/{{ toolkit_name }}/.pre-commit-config.yaml delete mode 100644 arcade/arcade/templates/{{ toolkit_name }}/.prettierignore delete mode 100644 arcade/arcade/templates/{{ toolkit_name }}/.prettierrc.toml delete mode 100644 arcade/arcade/templates/{{ toolkit_name }}/.ruff.toml delete mode 100644 arcade/arcade/templates/{{ toolkit_name }}/LICENSE delete mode 100644 arcade/arcade/templates/{{ toolkit_name }}/Makefile delete mode 100644 arcade/arcade/templates/{{ toolkit_name }}/codecov.yaml delete mode 100644 arcade/arcade/templates/{{ toolkit_name }}/pyproject.toml delete mode 100644 arcade/arcade/templates/{{ toolkit_name }}/tox.ini delete mode 100644 arcade/codecov.yaml delete mode 100644 arcade/pyproject.toml delete mode 100644 arcade/tox.ini create mode 100644 libs/arcade-cli/README.md rename {arcade/arcade/cli => libs/arcade-cli/arcade_cli}/__init__.py (100%) rename {arcade/arcade/cli => libs/arcade-cli/arcade_cli}/authn.py (99%) create mode 100644 libs/arcade-cli/arcade_cli/config.py rename {arcade/arcade/cli => libs/arcade-cli/arcade_cli}/constants.py (100%) rename {arcade/arcade/cli => libs/arcade-cli/arcade_cli}/deployment.py (100%) rename {arcade/arcade/cli => libs/arcade-cli/arcade_cli}/display.py (98%) rename {arcade/arcade/cli => libs/arcade-cli/arcade_cli}/main.py (93%) create mode 100644 libs/arcade-cli/arcade_cli/new.py rename {arcade/arcade/cli => libs/arcade-cli/arcade_cli}/serve.py (96%) rename {arcade/arcade/cli => libs/arcade-cli/arcade_cli}/show.py (92%) create mode 100644 libs/arcade-cli/arcade_cli/templates/{{ toolkit_name }}/Makefile rename {arcade/arcade => libs/arcade-cli/arcade_cli}/templates/{{ toolkit_name }}/README.md (85%) rename {arcade/arcade => libs/arcade-cli/arcade_cli}/templates/{{ toolkit_name }}/evals/eval_{{ toolkit_name }}.py (91%) create mode 100644 libs/arcade-cli/arcade_cli/templates/{{ toolkit_name }}/pyproject.toml rename {arcade/arcade => libs/arcade-cli/arcade_cli}/templates/{{ toolkit_name }}/tests/__init__.py (100%) rename {arcade/arcade => libs/arcade-cli/arcade_cli}/templates/{{ toolkit_name }}/tests/test_{{ toolkit_name }}.py (84%) rename {arcade/arcade => libs/arcade-cli/arcade_cli}/templates/{{ toolkit_name }}/{{ package_name }}/__init__.py (100%) rename {arcade/arcade => libs/arcade-cli/arcade_cli}/templates/{{ toolkit_name }}/{{ package_name }}/tools/__init__.py (100%) rename {arcade/arcade => libs/arcade-cli/arcade_cli}/templates/{{ toolkit_name }}/{{ package_name }}/tools/hello.py (85%) rename {arcade/arcade/cli => libs/arcade-cli/arcade_cli}/utils.py (94%) rename {arcade/arcade/cli => libs/arcade-cli/arcade_cli}/worker.py (99%) rename {arcade => libs/arcade-cli}/run_cli.py (88%) create mode 100644 libs/arcade-core/README.md create mode 100644 libs/arcade-core/arcade_core/__init__.py rename {arcade/arcade/core => libs/arcade-core/arcade_core}/annotations.py (100%) rename {arcade/arcade/core => libs/arcade-core/arcade_core}/auth.py (100%) rename {arcade/arcade/core => libs/arcade-core/arcade_core}/catalog.py (99%) rename {arcade/arcade/core => libs/arcade-core/arcade_core}/config.py (92%) rename {arcade/arcade/core => libs/arcade-core/arcade_core}/config_model.py (100%) rename {arcade/arcade/core => libs/arcade-core/arcade_core}/errors.py (100%) rename {arcade/arcade/core => libs/arcade-core/arcade_core}/executor.py (96%) rename {arcade/arcade/core => libs/arcade-core/arcade_core}/output.py (93%) rename {arcade/arcade/core => libs/arcade-core/arcade_core}/parse.py (100%) rename {arcade/arcade => libs/arcade-core/arcade_core}/py.typed (100%) rename {arcade/arcade/core => libs/arcade-core/arcade_core}/schema.py (100%) rename {arcade/arcade/core => libs/arcade-core/arcade_core}/telemetry.py (100%) rename {arcade/arcade/core => libs/arcade-core/arcade_core}/toolkit.py (98%) rename {arcade/arcade/core => libs/arcade-core/arcade_core}/utils.py (100%) rename {arcade/arcade/core => libs/arcade-core/arcade_core}/version.py (100%) create mode 100644 libs/arcade-core/pyproject.toml create mode 100644 libs/arcade-evals/README.md rename {arcade/arcade/sdk/eval => libs/arcade-evals/arcade_evals}/__init__.py (100%) rename {arcade/arcade/sdk/eval => libs/arcade-evals/arcade_evals}/critic.py (98%) create mode 100644 libs/arcade-evals/arcade_evals/errors.py rename {arcade/arcade/sdk/eval => libs/arcade-evals/arcade_evals}/eval.py (98%) rename arcade/arcade/worker/__init__.py => libs/arcade-evals/arcade_evals/py.typed (100%) create mode 100644 libs/arcade-serve/README.md rename {arcade/arcade/worker/core => libs/arcade-serve/arcade_serve}/__init__.py (100%) rename {arcade/tests => libs/arcade-serve/arcade_serve/core}/__init__.py (100%) rename {arcade/arcade/worker => libs/arcade-serve/arcade_serve}/core/auth.py (100%) rename {arcade/arcade/worker => libs/arcade-serve/arcade_serve}/core/base.py (96%) rename {arcade/arcade/worker => libs/arcade-serve/arcade_serve}/core/common.py (97%) rename {arcade/arcade/worker => libs/arcade-serve/arcade_serve}/core/components.py (98%) rename {arcade/arcade/worker => libs/arcade-serve/arcade_serve}/fastapi/__init__.py (100%) rename {arcade/arcade/worker => libs/arcade-serve/arcade_serve}/fastapi/auth.py (90%) rename {arcade/arcade/worker => libs/arcade-serve/arcade_serve}/fastapi/worker.py (93%) rename {arcade/arcade/worker => libs/arcade-serve/arcade_serve}/mcp/__init__.py (65%) rename {arcade/arcade/worker => libs/arcade-serve/arcade_serve}/mcp/convert.py (99%) rename {arcade/arcade/worker => libs/arcade-serve/arcade_serve}/mcp/logging.py (99%) rename {arcade/arcade/worker => libs/arcade-serve/arcade_serve}/mcp/message_processor.py (97%) rename {arcade/arcade/worker => libs/arcade-serve/arcade_serve}/mcp/server.py (97%) rename {arcade/arcade/worker => libs/arcade-serve/arcade_serve}/mcp/stdio.py (99%) rename {arcade/arcade/worker => libs/arcade-serve/arcade_serve}/mcp/types.py (100%) rename arcade/poetry.toml => libs/arcade-serve/arcade_serve/py.typed (100%) rename {arcade/arcade/worker => libs/arcade-serve/arcade_serve}/utils.py (100%) create mode 100644 libs/arcade-serve/pyproject.toml create mode 100644 libs/arcade-tdk/README.md create mode 100644 libs/arcade-tdk/arcade_tdk/__init__.py create mode 100644 libs/arcade-tdk/arcade_tdk/annotations/__init__.py rename {arcade/arcade/sdk => libs/arcade-tdk/arcade_tdk}/auth/__init__.py (94%) rename {arcade/arcade/sdk => libs/arcade-tdk/arcade_tdk}/errors.py (83%) rename arcade/tests/deployment/test_files/invalid_toolkit/invalid_main.py => libs/arcade-tdk/arcade_tdk/py.typed (100%) rename {arcade/arcade/sdk => libs/arcade-tdk/arcade_tdk}/tool.py (94%) create mode 100644 libs/arcade-tdk/arcade_tdk/utils.py create mode 100644 libs/arcade-tdk/pyproject.toml create mode 100644 libs/tests/__init__.py rename {arcade => libs}/tests/cli/test_dashboard.py (82%) rename {arcade => libs}/tests/cli/test_show.py (84%) rename {arcade => libs}/tests/cli/test_utils.py (99%) rename {arcade => libs}/tests/core/test_catalog.py (94%) rename {arcade => libs}/tests/core/test_executor.py (95%) rename {arcade => libs}/tests/core/test_output.py (97%) rename {arcade => libs}/tests/core/test_parse.py (95%) rename {arcade => libs}/tests/core/test_schema.py (99%) rename {arcade => libs}/tests/core/test_telemetry.py (85%) rename {arcade => libs}/tests/core/utils/test_casing.py (90%) rename {arcade => libs}/tests/core/utils/test_is_strict_optional.py (91%) rename {arcade => libs}/tests/core/utils/test_is_union.py (92%) rename {arcade => libs}/tests/deployment/test_config.py (99%) rename {arcade => libs}/tests/deployment/test_files/env.secret.worker.toml (100%) rename {arcade => libs}/tests/deployment/test_files/full.worker.toml (100%) rename {arcade => libs}/tests/deployment/test_files/invalid.fields.worker.toml (100%) rename {arcade => libs}/tests/deployment/test_files/invalid.localfile.worker.toml (100%) rename {arcade => libs}/tests/deployment/test_files/invalid.secret.worker.toml (100%) create mode 100644 libs/tests/deployment/test_files/invalid_toolkit/invalid_main.py rename {arcade => libs}/tests/deployment/test_files/mock_toolkit/mock_main.py (100%) rename {arcade => libs}/tests/deployment/test_files/mock_toolkit/pyproject.toml (100%) rename {arcade => libs}/tests/mcp/test_convert.py (90%) rename {arcade => libs}/tests/mcp/test_message_processor.py (91%) rename {arcade => libs}/tests/mcp/test_server.py (96%) rename {arcade => libs}/tests/mcp/test_stdio.py (92%) rename {arcade => libs}/tests/sdk/test_eval.py (98%) rename {arcade => libs}/tests/sdk/test_eval_critic.py (99%) rename {arcade => libs}/tests/sdk/test_tool_decorator.py (98%) rename {arcade => libs}/tests/tool/test_create_tool_definition.py (99%) rename {arcade => libs}/tests/tool/test_create_tool_definition_errors.py (96%) rename {arcade => libs}/tests/tool/test_create_tool_definition_new.py (96%) rename {arcade => libs}/tests/tool/test_create_tool_definition_pydantic.py (99%) rename {arcade => libs}/tests/tool/test_create_tool_definition_pydantic_errors.py (93%) rename {arcade => libs}/tests/tool/test_fully_qualified_tool_name.py (95%) rename {arcade => libs}/tests/worker/test_worker_base.py (96%) rename {arcade => libs}/tests/worker/test_worker_fastapi.py (97%) create mode 100644 pyproject.toml diff --git a/.github/actions/setup-uv-env/action.yml b/.github/actions/setup-uv-env/action.yml new file mode 100644 index 00000000..de15824f --- /dev/null +++ b/.github/actions/setup-uv-env/action.yml @@ -0,0 +1,20 @@ +name: "setup-uv-env" +description: "Composite action to setup the Python and uv environment." + +inputs: + python-version: + required: false + description: "The python version to use" + default: "3.11" + +runs: + using: "composite" + steps: + - name: Install uv + uses: astral-sh/setup-uv@v5 + with: + python-version: ${{ inputs.python-version }} + + - name: Install dependencies + run: uv sync --dev --extra all + shell: bash diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 07930e54..ad1d6e82 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -20,12 +20,12 @@ jobs: key: pre-commit-${{ hashFiles('.pre-commit-config.yaml') }} - name: Set up the environment - uses: ./.github/actions/setup-poetry-env + uses: ./.github/actions/setup-uv-env - name: Run checks run: make check - tox: + test: runs-on: ubuntu-latest strategy: matrix: @@ -35,30 +35,13 @@ jobs: - name: Check out uses: actions/checkout@v4 - - name: Set up python - uses: actions/setup-python@v5 + - name: Set up the environment + uses: ./.github/actions/setup-uv-env with: python-version: ${{ matrix.python-version }} - - name: Install Poetry - uses: snok/install-poetry@v1 - with: - version: 1.8.5 - - - name: Load cached venv - uses: actions/cache@v4 - with: - path: .tox - key: venv-${{ runner.os }}-${{ matrix.python-version }}-${{ hashFiles('arcade/poetry.lock') }} - - - name: Install tox - run: | - python -m pip install --upgrade pip - python -m pip install tox tox-gh-actions - - - name: Test with tox - run: cd arcade && tox - + - name: Test libs + run: make test - name: Upload coverage reports to Codecov with GitHub Action on Python 3.10 uses: codecov/codecov-action@v4.0.1 if: ${{ matrix.python-version == '3.10' }} diff --git a/.github/workflows/test-toolkits.yml b/.github/workflows/test-toolkits.yml index cb6ae072..f991452b 100644 --- a/.github/workflows/test-toolkits.yml +++ b/.github/workflows/test-toolkits.yml @@ -11,46 +11,43 @@ jobs: setup: runs-on: ubuntu-latest outputs: - tool_matrix: ${{ steps.dataStep.outputs.tools }} + tool_matrix: ${{ steps.get-toolkits.outputs.toolkits }} steps: - - name: Checkout code - uses: actions/checkout@v3 - with: - fetch-depth: 0 + - name: Check out + uses: actions/checkout@v4 - - name: Get Toolkits - id: dataStep + - name: Get toolkits + id: get-toolkits run: | - TARGETS=$(./.github/scripts/get_toolkits.sh) - echo "tools=$(jq -cn --argjson environments "$TARGETS" '{target: $environments}')" >> $GITHUB_OUTPUT + # Find all directories in toolkits/ that have a pyproject.toml + TOOLKITS=$(find toolkits -maxdepth 1 -type d -not -name "toolkits" -exec test -f {}/pyproject.toml \; -exec basename {} \; | jq -R -s -c 'split("\n")[:-1]') + echo "Found toolkits: $TOOLKITS" + echo "toolkits=$TOOLKITS" >> $GITHUB_OUTPUT test-toolkits: needs: setup runs-on: ubuntu-latest strategy: - matrix: ${{ fromJson(needs.setup.outputs.tool_matrix) }} + matrix: + toolkit: ${{ fromJson(needs.setup.outputs.tool_matrix) }} + fail-fast: true steps: - - run: echo ${{ matrix.target }} + - name: Check out + uses: actions/checkout@v4 - - name: Checkout code - uses: actions/checkout@v3 - with: - fetch-depth: 0 + - name: Set up the environment + uses: ./.github/actions/setup-uv-env - - name: Install Poetry - uses: snok/install-poetry@v1 - with: - version: 1.8.5 + - name: Install toolkit dependencies + working-directory: toolkits/${{ matrix.toolkit }} + run: uv pip install -e ".[dev]" - - uses: actions/setup-python@v5 - with: - python-version: '3.12' - cache: 'pip' + - name: Check toolkit + working-directory: toolkits/${{ matrix.toolkit }} + run: | + uv run --active pre-commit run -a + uv run --active mypy --config-file=pyproject.toml - - name: Test Toolkit - id: Test_Toolkit - working-directory: toolkits/${{ matrix.target }} - run: | - make install - make check - make test + - name: Test toolkit + working-directory: toolkits/${{ matrix.toolkit }} + run: uv run --active pytest -W ignore -v --cov=arcade_${{ matrix.toolkit }} --cov-report=xml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 273304f6..1d51e41f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,6 +5,7 @@ repos: - id: check-case-conflict - id: check-merge-conflict - id: check-toml + exclude: ".*/templates/.*" - id: check-yaml exclude: ".*/templates/.*" - id: end-of-file-fixer diff --git a/.ruff.toml b/.ruff.toml index 54915aae..477d663c 100644 --- a/.ruff.toml +++ b/.ruff.toml @@ -2,6 +2,10 @@ target-version = "py39" line-length = 100 fix = true +exclude = [ + "libs/arcade-cli/arcade_cli/templates/", +] + [lint] select = [ # flake8-2020 diff --git a/.vscode/launch.json b/.vscode/launch.json index 8547fbb6..1d76aeef 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,7 +5,7 @@ "name": "Debug `arcade workerup --no-auth`", "type": "debugpy", "request": "launch", - "program": "${workspaceFolder}/arcade/run_cli.py", + "program": "${workspaceFolder}/libs/arcade-cli/run_cli.py", "args": ["workerup", "--no-auth"], "console": "integratedTerminal", "jinja": true, @@ -16,34 +16,34 @@ "name": "Debug `arcade chat -d -h localhost`", "type": "debugpy", "request": "launch", - "program": "${workspaceFolder}/arcade/run_cli.py", + "program": "${workspaceFolder}/libs/arcade-cli/run_cli.py", "args": ["chat", "-d", "-h", "localhost"], "console": "integratedTerminal", "jinja": true, "justMyCode": true, "cwd": "${workspaceFolder}" }, - { - "name": "Debug `arcade dev`", - "type": "debugpy", - "request": "launch", - "program": "${workspaceFolder}/arcade/run_cli.py", - "args": ["dev"], - "console": "integratedTerminal", - "jinja": true, - "justMyCode": true, - "cwd": "${workspaceFolder}" - }, { "name": "Debug `arcade evals -d` on current file", "type": "debugpy", "request": "launch", - "program": "${workspaceFolder}/arcade/run_cli.py", + "program": "${workspaceFolder}/libs/arcade-cli/run_cli.py", "args": ["evals", "-d", "${fileDirname}", "-h", "localhost"], "console": "integratedTerminal", "jinja": true, "justMyCode": true, "cwd": "" + }, + { + "name": "Debug `arcade serve`", + "type": "debugpy", + "request": "launch", + "program": "${workspaceFolder}/libs/arcade-cli/run_cli.py", + "args": ["serve"], + "console": "integratedTerminal", + "jinja": true, + "justMyCode": true, + "cwd": "" } ] } diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9a001853..a106969b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -45,7 +45,7 @@ If you are proposing a new feature: # Get Started! Ready to contribute? Here's how to set up `arcade-ai` for local development. -Please note this documentation assumes you already have `poetry` and `Git` installed and ready to go. +Please note this documentation assumes you already have `uv` and `Git` installed and ready to go. 1. Fork the `arcade-ai` repo on GitHub. @@ -53,7 +53,7 @@ Please note this documentation assumes you already have `poetry` and `Git` insta ```bash cd -git clone git@github.com:YOUR_NAME/arcade-ai.git +git clone git@github.com:YOUR_GITHUB_USERNAME/arcade-ai.git ``` 3. Now we need to install the environment. Navigate into the directory @@ -62,25 +62,30 @@ git clone git@github.com:YOUR_NAME/arcade-ai.git cd arcade-ai ``` -If you are using `pyenv`, select a version to use locally. (See installed versions with `pyenv versions`) +Create your virtual environment ```bash -pyenv local +uv venv --python 3.11.6 ``` -Then, install and activate the environment with: +4. Install the development environment and dependencies: ```bash -poetry install -poetry shell +# Install all packages and development dependencies via uv workspace +uv sync --extra all --dev + +# Install pre-commit hooks for code quality +uv run pre-commit install ``` -4. Install pre-commit to run linters/formatters at commit time: +Or use the convenient Makefile command that does both: ```bash -poetry run pre-commit install +make install ``` +The uv workspace will automatically handle installing all lib packages in the correct dependency order. + 5. Create a branch for local development: ```bash @@ -89,7 +94,7 @@ git checkout -b name-of-your-bugfix-or-feature Now you can make your changes locally. -6. Don't forget to add test cases for your added functionality to the `tests` directory. +6. Don't forget to add test cases for your added functionality to the `libs/tests` directory. 7. When you're done making changes, check that your changes pass the formatting tests. @@ -103,15 +108,14 @@ Now, validate that all unit tests are passing: make test ``` -9. Before raising a pull request you should also run tox. - This will run the tests across different versions of Python: +8. You can also run tests for specific components: ```bash -tox +# Test all lib packages +make test ``` -This requires you to have multiple versions of python installed. -This step is also triggered in the CI/CD pipeline, so you could also choose to skip this step locally. +9. The CI/CD pipeline will run additional checks across different Python versions, so local testing with a single version is usually sufficient. 10. Commit your changes and push your branch to GitHub: @@ -129,8 +133,7 @@ Before you submit a pull request, check that it meets these guidelines: 1. The pull request should include tests. -2. If the pull request adds functionality, the docs should be updated. - Put your new functionality into a function with a docstring, and add the feature to the list in `README.md`. +2. If the pull request adds functionality, the [docs](https://github.com/ArcadeAI/docs) should be updated. 3. If making contributions to multiple toolkits (i.e. Google and Slack, etc.), submit a separate pull request for each. This helps us segregate the changes during the review process making it more efficient. diff --git a/Makefile b/Makefile index 123e1e54..e8a9be28 100644 --- a/Makefile +++ b/Makefile @@ -1,30 +1,64 @@ -VERSION ?= "0.1.0.dev0" +CLI_VERSION ?= "2.0.0" +TDK_VERSION ?= "2.0.0" +SERVE_VERSION ?= "2.0.0" +CORE_VERSION ?= "2.0.0" .PHONY: install -install: ## Install the poetry environment and install the pre-commit hooks - @echo "๐Ÿš€ Creating virtual environment using pyenv and poetry" - @cd arcade && poetry install --all-extras - @cd arcade && poetry run pre-commit install - +install: ## Install the uv environment and all packages with dependencies + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv workspace" + @uv sync --active --dev --extra all + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv workspace" .PHONY: install-toolkits install-toolkits: ## Install dependencies for all toolkits @echo "๐Ÿš€ Installing dependencies for all toolkits" - @for dir in toolkits/*/ ; do \ - echo "๐Ÿ“ฆ Installing dependencies for $$dir"; \ - (cd $$dir && poetry lock && poetry install); \ - done - + @failed=0; \ + successful=0; \ + for dir in toolkits/*/ ; do \ + if [ -d "$$dir" ] && [ -f "$$dir/pyproject.toml" ]; then \ + echo "๐Ÿ“ฆ Installing dependencies for $$dir"; \ + if (cd $$dir && uv pip install -e ".[dev]"); then \ + successful=$$((successful + 1)); \ + else \ + echo "โŒ Failed to install dependencies for $$dir"; \ + failed=$$((failed + 1)); \ + fi; \ + else \ + echo "โš ๏ธ Skipping $$dir (no pyproject.toml found)"; \ + fi; \ + done; \ + echo ""; \ + echo "๐Ÿ“Š Installation Summary:"; \ + echo " โœ… Successful: $$successful toolkits"; \ + echo " โŒ Failed: $$failed toolkits"; \ + if [ $$failed -gt 0 ]; then \ + echo ""; \ + echo "โš ๏ธ Some toolkit installations failed. Check the output above for details."; \ + exit 1; \ + else \ + echo ""; \ + echo "๐ŸŽ‰ All toolkit dependencies installed successfully!"; \ + fi .PHONY: check check: ## Run code quality tools. - @echo "๐Ÿš€ Checking Poetry lock file consistency with 'pyproject.toml': Running poetry check --lock" - @cd arcade && poetry check --lock @echo "๐Ÿš€ Linting code: Running pre-commit" - @cd arcade && poetry run pre-commit run -a - @echo "๐Ÿš€ Static type checking: Running mypy" - @cd arcade && poetry run mypy $(git ls-files '*.py') + @uv run pre-commit run -a + @echo "๐Ÿš€ Static type checking: Running mypy on libs" + @for lib in libs/arcade*/ ; do \ + echo "๐Ÿ” Type checking $$lib"; \ + (cd $$lib && uv run mypy . || true); \ + done +.PHONY: check-libs +check-libs: ## Run code quality tools for each lib package + @echo "๐Ÿš€ Running checks on each lib package" + @for lib in libs/arcade*/ ; do \ + echo "๐Ÿ› ๏ธ Checking lib $$lib"; \ + (cd $$lib && uv run pre-commit run -a || true); \ + (cd $$lib && uv run mypy . || true); \ + done .PHONY: check-toolkits check-toolkits: ## Run code quality tools for each toolkit that has a Makefile @@ -32,7 +66,7 @@ check-toolkits: ## Run code quality tools for each toolkit that has a Makefile @for dir in toolkits/*/ ; do \ if [ -f "$$dir/Makefile" ]; then \ echo "๐Ÿ› ๏ธ Checking toolkit $$dir"; \ - (cd "$$dir" && make check); \ + (cd "$$dir" && uv run --active pre-commit run -a && uv run --active mypy --config-file=pyproject.toml); \ else \ echo "๐Ÿ› ๏ธ Skipping toolkit $$dir (no Makefile found)"; \ fi; \ @@ -40,69 +74,129 @@ check-toolkits: ## Run code quality tools for each toolkit that has a Makefile .PHONY: test test: ## Test the code with pytest - @echo "๐Ÿš€ Testing code: Running pytest" - @cd arcade && poetry run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml + @echo "๐Ÿš€ Testing libs: Running pytest" + @uv run pytest -W ignore -v --cov=libs/tests --cov-config=pyproject.toml --cov-report=xml + +.PHONY: test-libs +test-libs: ## Test each lib package individually + @echo "๐Ÿš€ Testing each lib package" + @for lib in libs/arcade*/ ; do \ + echo "๐Ÿงช Testing $$lib"; \ + (cd $$lib && uv run pytest -W ignore -v || true); \ + done .PHONY: test-toolkits test-toolkits: ## Iterate over all toolkits and run pytest on each one @echo "๐Ÿš€ Testing code in toolkits: Running pytest" @for dir in toolkits/*/ ; do \ - (cd $$dir && poetry run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml || exit 1); \ + toolkit_name=$$(basename "$$dir"); \ + echo "๐Ÿงช Testing $$toolkit_name toolkit"; \ + (cd $$dir && uv run --active pytest -W ignore -v --cov=arcade_$$toolkit_name --cov-report=xml || exit 1); \ done .PHONY: coverage coverage: ## Generate coverage report @echo "coverage report" - @cd arcade && coverage report + @uv run coverage report @echo "Generating coverage report" - @cd arcade && coverage html + @uv run coverage html .PHONY: set-version -set-version: ## Set the version in the pyproject.toml file - @echo "๐Ÿš€ Setting version in pyproject.toml" - @cd arcade && poetry version $(VERSION) +set-version: ## Set the version in all lib pyproject.toml files + @echo "๐Ÿš€ Setting versions in all lib packages" + @echo "Setting arcade-ai version to $(CLI_VERSION)" + @sed -i.bak '/^\[project\]/,/^\[/ s/^version = .*/version = $(CLI_VERSION)/' pyproject.toml && rm pyproject.toml.bak + @echo "Setting libs/arcade-tdk version to $(TDK_VERSION)" + @cd libs/arcade-tdk && sed -i.bak '/^\[project\]/,/^\[/ s/^version = .*/version = $(TDK_VERSION)/' pyproject.toml && rm pyproject.toml.bak + @echo "Setting libs/arcade-serve version to $(SERVE_VERSION)" + @cd libs/arcade-serve && sed -i.bak '/^\[project\]/,/^\[/ s/^version = .*/version = $(SERVE_VERSION)/' pyproject.toml && rm pyproject.toml.bak + @echo "Setting libs/arcade-core version to $(CORE_VERSION)" + @cd libs/arcade-core && sed -i.bak '/^\[project\]/,/^\[/ s/^version = .*/version = $(CORE_VERSION)/' pyproject.toml && rm pyproject.toml.bak .PHONY: unset-version -unset-version: ## Set the version in the pyproject.toml file - @echo "๐Ÿš€ Setting version in pyproject.toml" - @cd arcade && poetry version 0.1.0 +unset-version: ## Reset version to 0.1.0 in all lib pyproject.toml files + @echo "๐Ÿš€ Resetting version to 0.1.0 in all lib packages" + @for lib in libs/arcade*/ ; do \ + if [ -f "$$lib/pyproject.toml" ]; then \ + echo "Resetting version in $$lib"; \ + (cd $$lib && sed -i.bak 's/version = "[^"]*"/version = "0.1.0"/' pyproject.toml && rm pyproject.toml.bak); \ + fi; \ + done .PHONY: build -build: clean-build ## Build wheel file using poetry - @echo "๐Ÿš€ Creating wheel file" - @cd arcade && poetry build +build: clean-build ## Build wheel files using uv + @echo "๐Ÿš€ Creating wheel files for all lib packages" + @for lib in libs/arcade*/ ; do \ + if [ -f "$$lib/pyproject.toml" ]; then \ + echo "๐Ÿ› ๏ธ Building $$lib"; \ + (cd $$lib && uv build); \ + fi; \ + done + +.PHONY: build-toolkits +build-toolkits: ## Build wheel files for all toolkits + @echo "๐Ÿš€ Creating wheel files for all toolkits" + @failed=0; \ + successful=0; \ + for dir in toolkits/*/ ; do \ + if [ -d "$$dir" ] && [ -f "$$dir/pyproject.toml" ]; then \ + toolkit_name=$$(basename "$$dir"); \ + echo "๐Ÿ› ๏ธ Building toolkit $$toolkit_name"; \ + if (cd $$dir && uv build); then \ + successful=$$((successful + 1)); \ + else \ + echo "โŒ Failed to build toolkit $$toolkit_name"; \ + failed=$$((failed + 1)); \ + fi; \ + else \ + echo "โš ๏ธ Skipping $$dir (no pyproject.toml found)"; \ + fi; \ + done; \ + echo ""; \ + echo "๐Ÿ“Š Build Summary:"; \ + echo " โœ… Successful: $$successful toolkits"; \ + echo " โŒ Failed: $$failed toolkits"; \ + if [ $$failed -gt 0 ]; then \ + echo ""; \ + echo "โš ๏ธ Some toolkit builds failed. Check the output above for details."; \ + exit 1; \ + else \ + echo ""; \ + echo "๐ŸŽ‰ All toolkit wheels built successfully!"; \ + fi .PHONY: clean-build clean-build: ## clean build artifacts - @cd arcade && rm -rf dist + @echo "๐Ÿ—‘๏ธ Cleaning build artifacts" + @for lib in libs/arcade*/ ; do \ + (cd $$lib && rm -rf dist); \ + done .PHONY: publish publish: ## publish a release to pypi. - @echo "๐Ÿš€ Publishing: Dry run." - @cd arcade && poetry config pypi-token.pypi $(PYPI_TOKEN) - @cd arcade && poetry publish --dry-run - @echo "๐Ÿš€ Publishing." - @cd arcade && poetry publish + @echo "๐Ÿš€ Publishing all lib packages to PyPI" + @for lib in libs/arcade*/ ; do \ + if [ -f "$$lib/pyproject.toml" ]; then \ + echo "๐Ÿ“ฆ Publishing $$lib"; \ + (cd $$lib && uv publish --token $(PYPI_TOKEN) || true); \ + fi; \ + done .PHONY: build-and-publish build-and-publish: build publish ## Build and publish. .PHONY: docker docker: ## Build and run the Docker container - @echo "๐Ÿš€ Building arcade and toolkit wheels..." + @echo "๐Ÿš€ Building lib packages and toolkit wheels..." @make full-dist - @echo "Writing requirements.txt" - @cd arcade && poetry export --output ../dist/requirements.txt @echo "๐Ÿš€ Building Docker image" @cd docker && make docker-build @cd docker && make docker-run .PHONY: docker-base docker-base: ## Build and run the Docker container - @echo "๐Ÿš€ Building arcade and toolkit wheels..." + @echo "๐Ÿš€ Building lib packages and toolkit wheels..." @make full-dist - @echo "Writing requirements.txt" - @cd arcade && poetry export --output ../dist/requirements.txt @echo "๐Ÿš€ Building Docker image" @cd docker && INSTALL_TOOLKITS=false make docker-build @cd docker && INSTALL_TOOLKITS=false make docker-run @@ -123,31 +217,42 @@ publish-ghcr: ## Publish to the GHCR .PHONY: full-dist full-dist: clean-dist ## Build all projects and copy wheels to ./dist - @echo " Building a full distribution with toolkits" + @echo "๐Ÿ› ๏ธ Building a full distribution with lib packages and toolkits" - @echo "Setting version to $(VERSION)" + @echo "Setting version to $(CLI_VERSION)" @make set-version - # @echo "๐Ÿ› ๏ธ Building all projects and copying wheels to ./dist" + @echo "๐Ÿ› ๏ธ Building all lib packages and copying wheels to ./dist" @mkdir -p dist - # Build the main arcade project - @echo "๐Ÿ› ๏ธ Building arcade project wheel..." - @cd arcade && poetry build + # Build all lib packages in dependency order + @for lib in arcade-core arcade-tdk arcade-serve ; do \ + echo "๐Ÿ› ๏ธ Building libs/$$lib wheel..."; \ + (cd libs/$$lib && uv build); \ + cp libs/$$lib/dist/*.whl dist/; \ + done - # Copy the main arcade project wheel to the dist directory - @cp arcade/dist/*.whl dist/ + @echo "๐Ÿ› ๏ธ Building all toolkit packages and copying wheels to ./dist" + @for dir in toolkits/*/ ; do \ + if [ -d "$$dir" ] && [ -f "$$dir/pyproject.toml" ]; then \ + toolkit_name=$$(basename "$$dir"); \ + echo "๐Ÿ› ๏ธ Building toolkit $$toolkit_name wheel..."; \ + (cd $$dir && uv build); \ + cp $$dir/dist/*.whl dist/; \ + fi; \ + done @echo "Reset version to default (0.1.0)" @make unset-version - .PHONY: clean-dist clean-dist: ## Clean all built distributions @echo "๐Ÿ—‘๏ธ Cleaning dist directory" @rm -rf dist - @echo "๐Ÿ—‘๏ธ Cleaning arcade/dist directory" - @rm -rf arcade/dist + @echo "๐Ÿ—‘๏ธ Cleaning libs/*/dist directories" + @for lib in libs/arcade*/ ; do \ + rm -rf "$$lib"/dist; \ + done @echo "๐Ÿ—‘๏ธ Cleaning toolkits/*/dist directory" @for toolkit_dir in toolkits/*; do \ if [ -d "$$toolkit_dir" ]; then \ @@ -155,11 +260,18 @@ clean-dist: ## Clean all built distributions fi; \ done +.PHONY: setup +setup: install ## Complete development setup (same as install) + +.PHONY: lint +lint: check ## Alias for check command + +.PHONY: clean +clean: clean-build clean-dist ## Clean all build and distribution artifacts + .PHONY: help help: @echo "๐Ÿ› ๏ธ Arcade Dev Commands:\n" @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' - - .DEFAULT_GOAL := help diff --git a/README.md b/README.md index 48c0d45c..91dc6b08 100644 --- a/README.md +++ b/README.md @@ -38,11 +38,17 @@ Quickstart โ€ข Contact Us -# Arcade Tool SDK +# Arcade AI Platform Arcade is a developer platform that lets you build, deploy, and manage tools for AI agents. -The Tool SDK makes it easy to create powerful, secure tools that your agents can use to interact with the world. +This repository contains the core Arcade libraries, organized as separate packages for maximum flexibility and modularity: + +- [**`arcade-core`**](libs/arcade-core) - Core platform functionality and schemas +- [**`arcade-tdk`**](libs/arcade-tdk) - Tool Development Kit with the `@tool` decorator +- [**`arcade-serve`**](libs/arcade-serve) - Serving infrastructure for workers and MCP servers +- [**`arcade-evals`**](libs/arcade-evals) - Evaluation framework for testing tool performance +- [**`arcade-cli`**](libs/arcade-cli) - Command-line interface for the Arcade platform ![diagram](https://github.com/user-attachments/assets/1a567e5f-d6b4-4b1e-9918-c401ad232ebb) @@ -54,6 +60,48 @@ _Pst. hey, you, give us a star if you like it!_ GitHub stars +## Quick Start + +### Installation + +For development, install all packages with dependencies using uv workspace: + +```bash +# Install all packages and dev dependencies +uv sync --extra all --dev + +# Or use the Makefile (includes pre-commit hooks) +make install +``` + +For production use, install individual packages as needed: + +```bash +pip install arcade-ai # CLI +pip install 'arcade-ai[evals]' # CLI + Evaluation framework +pip install 'arcade-ai[all]' # CLI + Serving infra + eval framework + TDK +pip install arcade_serve # Serving infrastructure +pip install arcade-tdk # Tool Development Kit +``` + +### Development + +Use the Makefile for standard tasks: + +```bash +# Run tests +make test + +# Run linting and type checking +make check + +# Build all packages +make build + +# See all available commands +make help +``` + ## Client Libraries - **[ArcadeAI/arcade-py](https://github.com/ArcadeAI/arcade-py):** diff --git a/arcade/README.md b/arcade/README.md deleted file mode 100644 index 6c33b982..00000000 --- a/arcade/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Arcade Python SDK and CLI - -[Arcade](https://arcade.dev?ref=pypi) provides developer-focused tooling and APIs designed to improve the capabilities of LLM applications and agents. - -By removing the complexity of connecting agentic applications with your users' data and services, Arcade enables developers to focus on building their agentic applications. - -To learn more, check out our -- [Website](https://arcade.dev?ref=pypi) -- [GitHub](https://github.com/ArcadeAI/arcade-ai) -- [Documentation](https://docs.arcade.dev) -- [Discord](https://discord.com/invite/GUZEMpEZ9p) -- [X](https://x.com/TryArcade) -- [LinkedIn](https://www.linkedin.com/company/arcade-ai) diff --git a/arcade/arcade/__init__.py b/arcade/arcade/__init__.py deleted file mode 100644 index eb04cb60..00000000 --- a/arcade/arcade/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from importlib.metadata import version as get_version - -__version__ = get_version("arcade-ai") diff --git a/arcade/arcade/cli/launcher.py b/arcade/arcade/cli/launcher.py deleted file mode 100644 index bae9f952..00000000 --- a/arcade/arcade/cli/launcher.py +++ /dev/null @@ -1,505 +0,0 @@ -import http.client -import io -import ipaddress -import logging -import os -import shutil -import signal -import socket -import subprocess -import sys -import threading -import time -from pathlib import Path -from typing import Callable - -from rich.console import Console - -console = Console(highlight=False) -logger = logging.getLogger(__name__) - -known_engine_config_locations = [ - "/etc/arcade-ai", - "/etc/arcade-engine", - "/opt/homebrew/etc/arcade-engine", -] - -if os.environ.get("HOMEBREW_REPOSITORY") is not None: - homebrew_home = os.path.join(os.environ["HOMEBREW_REPOSITORY"], "etc", "arcade-engine") - if homebrew_home not in known_engine_config_locations: - known_engine_config_locations.append(homebrew_home) - - -def start_servers( - worker_host: str, - worker_port: int, - engine_config: str | None, - engine_env: str | None = None, - debug: bool = False, -) -> None: - """ - Start the worker and engine servers. - - Args: - host: Host for the worker server. - port: Port for the worker server. - engine_config: Path to the engine configuration file. - engine_env: Path to the engine environment file. - debug: Whether to run in debug mode. - """ - # Validate host and port - worker_host = _validate_host(worker_host) - worker_port = _validate_port(worker_port) - - # Ensure engine_config is provided and validated - engine_config = _get_config_file(engine_config, default_filename="engine.yaml") - - # Ensure engine_env is provided or found and either way, validated - env_file = _get_config_file(engine_env, default_filename="engine.env", optional=True) - - # Prepare command-line arguments for the worker server and engine - worker_cmd = _build_worker_command(worker_host, worker_port, debug) - - # even if the user didn't pass an env file we may have found it in the default locations - engine_cmd = _build_engine_command(engine_config, engine_env=env_file if env_file else None) - - # Start and manage the processes - _manage_processes(worker_cmd, worker_host, worker_port, engine_cmd, debug=debug) - - -def _validate_host(host: str) -> str: - """ - Validates the host input. - - Args: - host: Host for the worker server. - - Returns: - The validated host as a string. - - Raises: - ValueError: If the host is invalid. - """ - try: - # Validate IP address - ipaddress.ip_address(host) - except ValueError: - # Optionally, validate hostname - if not host.isalnum() and "-" not in host and "." not in host: - console.print(f"โŒ Invalid host: {host}", style="bold red") - raise ValueError("Invalid host.") - return host - - -def _validate_port(port: int) -> int: - """ - Validates the port input. - - Args: - port: Port for the worker server. - - Returns: - The validated port as an integer. - - Raises: - ValueError: If the port is out of the valid range. - """ - if not (1 <= port <= 65535): - console.print(f"โŒ Invalid port: {port}", style="bold red") - raise ValueError("Invalid port.") - return port - - -def _get_config_file( - file_path: str | None, default_filename: str = "engine.yaml", optional: bool = False -) -> str | None: - """ - Resolves and validates the config file path from a set of candidate locations. - - If a file_path is provided, it is checked directly. - Otherwise, the following candidate locations are checked in order: - 1. Current working directory. - 2. User's home directory under .arcade. - 3. Known engine config locations. - - Args: - file_path: Optional path provided by the user. - default_filename: The default filename to look for. - optional: Whether the config file is optional. - - Returns: - The resolved config file path. None if the file is optional and not found. - - Raises: - RuntimeError: If the config file is not found and is not optional. - """ - if file_path: - candidate = Path(os.path.expanduser(file_path)).resolve() - if not candidate.is_file(): - console.print(f"โŒ Config file not found at {candidate}", style="bold red") - raise RuntimeError(f"Config file not found at {candidate}") - return str(candidate) - - # List of all config file path locations to check. - candidates = [ - Path(os.getcwd()) / default_filename, - Path.home() / ".arcade" / default_filename, - ] - candidates.extend(Path(path) / default_filename for path in known_engine_config_locations) - - # Find the first candidate that exists. - for candidate in candidates: - if candidate.is_file(): - console.print(f"Using config file at {candidate}", style="bold green") - return str(candidate) - - # No config file was found. Handle according to the optional flag. - if optional: - console.print( - f"โš ๏ธ Optional config file '{default_filename}' not found in any of the following locations:", - style="bold yellow", - ) - for i, candidate in enumerate(candidates, start=1): - console.print(f" {i}) {candidate}", style="bold yellow") - return None - - console.print( - f"โŒ Error: Required config file '{default_filename}' not found in any of the following locations:", - style="bold red", - ) - for i, candidate in enumerate(candidates, start=1): - console.print(f" {i}) {candidate}", style="bold red") - - console.print( - "\nTIP: Please install the Arcade Engine by following the instructions at:\n" - " https://docs.arcade.dev/home/install/local#install-the-engine\n", - style="bold green", - ) - raise RuntimeError(f"Config file '{default_filename}' not found.") - - -def _build_worker_command(host: str, port: int, debug: bool) -> list[str]: - """ - Builds the command to start the worker server. - - Args: - host: Host for the worker server. - port: Port for the worker server. - debug: Whether to run in debug mode. - - Returns: - The command as a list. - """ - # Expand full path to "arcade" executable - arcade_bin = shutil.which("arcade") - if not arcade_bin: - console.print( - "โŒ Arcade binary not found, please install with `pip install arcade-ai`", - style="bold red", - ) - sys.exit(1) - cmd = [ - arcade_bin, - "workerup", - "--host", - host, - "--port", - str(port), - ] - if debug: - cmd.append("--debug") - return cmd - - -def _build_engine_command(engine_config: str | None, engine_env: str | None = None) -> list[str]: - """ - Builds the command to start the engine. - - Args: - engine_config: Path to the engine configuration file. - engine_env: Path to the engine environment file. - - Returns: - The command as a list. - """ - # This should never happen, but we'll check regardless - if not engine_config: - console.print("โŒ Engine configuration file not found", style="bold red") - sys.exit(1) - - engine_bin = shutil.which("arcade-engine") - if not engine_bin: - console.print( - "โŒ Engine binary not found, refer to the installation guide at " - "https://docs.arcade.dev/guides/installation for how to install the engine", - style="bold red", - ) - sys.exit(1) - cmd = [ - engine_bin, - "-c", - engine_config, - ] - if engine_env: - cmd.append("-e") - cmd.append(engine_env) - - return cmd - - -def _manage_processes( - worker_cmd: list[str], - worker_host: str, - worker_port: int, - engine_cmd: list[str], - engine_env: dict[str, str] | None = None, - debug: bool = False, -) -> None: - """ - Manages the lifecycle of the worker and engine processes. - - Args: - worker_cmd: The command to start the worker server. - engine_cmd: The command to start the engine. - engine_env: Environment variables to set for the engine. - debug: Whether to run in debug mode. - """ - worker_process: subprocess.Popen | None = None - engine_process: subprocess.Popen | None = None - - def terminate_processes(exit_program: bool = False) -> None: - console.print("Terminating child processes...", style="bold yellow") - _terminate_process(worker_process) - _terminate_process(engine_process) - if exit_program: - sys.exit(0) - - _setup_signal_handlers(terminate_processes) - - retry_count = 0 - max_retries = 1 # Define the maximum number of retries - - while retry_count <= max_retries: - try: - # Start the worker server - console.print("Starting worker server...", style="bold green") - worker_process = _start_process("Worker", worker_cmd, debug=debug) - - _wait_for_healthy_worker(worker_process, worker_host, worker_port) - - # Start the engine - console.print("Starting engine...", style="bold green") - engine_process = _start_process("Engine", engine_cmd, env=engine_env, debug=debug) - - # Monitor processes - _monitor_processes(worker_process, engine_process) - - # If we reach here, one of the processes has exited - retry_count += 1 - console.print( - f"Processes exited. Retry {retry_count} of {max_retries}.", style="bold yellow" - ) - - if retry_count >= max_retries: - console.print(f"โŒ Exiting after {max_retries} retries", style="bold red") - terminate_processes(exit_program=True) - break # Exit the loop - - except Exception as e: - console.print(f"โŒ Exception occurred: {e}", style="bold red") - terminate_processes() - retry_count += 1 - if retry_count > max_retries: - console.print( - f"โŒ Exiting after {retry_count - 1} retries due to exceptions", - style="bold red", - ) - sys.exit(1) - break # Not strictly necessary, but good practice - - console.print("Exiting...", style="bold red") - sys.exit(1) - - -def _start_process( - name: str, cmd: list[str], env: dict[str, str] | None = None, debug: bool = False -) -> subprocess.Popen: - """ - Starts a subprocess and begins streaming its output. - - Args: - name: Name of the process. - cmd: Command to execute. - env: Environment variables to set for the process. - debug: Whether to run in debug mode. - Returns: - The subprocess.Popen object. - - Raises: - RuntimeError: If the process fails to start. - """ - _env = os.environ.copy() - if env: - _env.update(env) - - if debug: - _env["GIN_MODE"] = "debug" - else: - _env["GIN_MODE"] = "release" - - if name == "Worker": - _env["PYTHONUNBUFFERED"] = "1" - - try: - process = subprocess.Popen( # noqa: S603, RUF100 - cmd, - env=_env, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - universal_newlines=True, - bufsize=1, - shell=False, - ) - _stream_output(process, name) - return process # noqa: TRY300 - except Exception as e: - console.print(f"โŒ Failed to start {name}: {e}", style="bold red") - raise RuntimeError(f"Failed to start {name}") - - -def _wait_for_healthy_worker( - worker_process: subprocess.Popen, worker_host: str, worker_port: int -) -> None: - """Wait until an HTTP request to `host:port/worker/health` returns 200""" - - while worker_process.poll() is None: # Continue waiting UNLESS the worker process has exited - time.sleep(1) - try: - conn = http.client.HTTPConnection(worker_host, worker_port, timeout=1) - conn.request("GET", "/worker/health") - res = conn.getresponse() - if res.status == 200: - break - conn.close() - except (socket.gaierror, http.client.HTTPException, ConnectionRefusedError, TimeoutError): - pass # Handle expected exceptions gracefully - console.print("Waiting for worker to start...", style="bold yellow") - - time.sleep(1) # Wait just a little longer for everything to settle (discovered experimentally) - console.print("Worker is healthy", style="bold green") - - -def _stream_output(process: subprocess.Popen, name: str) -> None: - """ - Streams the output from a subprocess to the console. - - Args: - process: The subprocess.Popen object. - name: Name of the process. - """ - stdout_style = "green" if name == "Worker" else "#87CEFA" - - def stream(pipe: io.TextIOWrapper | None, style: str) -> None: - if pipe is None: - return - with pipe: - for line in iter(pipe.readline, ""): - line = line.rstrip() - - if "DEBUG" in line: - line = line.replace("DEBUG", "[#87CEFA]DEBUG[/#87CEFA]", 1) - if "INFO" in line: - line = line.replace("INFO", "[#109a10]INFO[/#109a10]", 1) - if "WARNING" in line: - line = line.replace("WARNING", "[#FFA500]WARNING[/#FFA500]", 1) - if "ERROR" in line: - line = line.replace("ERROR", "[#FF0000]ERROR[/#FF0000]", 1) - console.print(f"[{style}]{name}>[/{style}] {line}") - - threading.Thread(target=stream, args=(process.stdout, stdout_style), daemon=True).start() - threading.Thread(target=stream, args=(process.stderr, "red"), daemon=True).start() - - -def _monitor_processes(worker_process: subprocess.Popen, engine_process: subprocess.Popen) -> None: - """ - Monitors the worker and engine processes, restarts them if they exit. - - Args: - worker_process: The worker subprocess. - engine_process: The engine subprocess. - """ - - while True: - worker_status = worker_process.poll() - engine_status = engine_process.poll() - - if worker_status is not None or engine_status is not None: - if worker_status is not None: - console.print( - f"Worker process exited with code {worker_status}. Restarting both processes...", - style="bold red", - ) - if engine_status is not None: - console.print( - f"Engine process exited with code {engine_status}. Restarting both processes...", - style="bold red", - ) - _terminate_process(worker_process) - _terminate_process(engine_process) - time.sleep(1) - break # Exit to restart both processes - else: - time.sleep(1) - - -def _terminate_process(process: subprocess.Popen | None) -> None: - """ - Terminates a subprocess if it's running. - - Args: - process: The subprocess.Popen object. - """ - if process and process.poll() is None: - process.terminate() - try: - process.wait(timeout=5) - except subprocess.TimeoutExpired: - process.kill() - - -def _setup_signal_handlers(terminate_processes: Callable[[bool], None]) -> None: - """ - Setup signal handlers to handle process termination signals. - - Args: - terminate_processes: Function to call to terminate child processes. - """ - signals_to_handle = ["SIGINT", "SIGTERM", "SIGQUIT", "SIGHUP"] - - for sig_name in signals_to_handle: - sig = getattr(signal, sig_name, None) - if sig is None: - continue # Signal not available on this platform - try: - # Use a lambda to pass the terminate_processes function - signal.signal( - sig, - lambda signum, frame: _handle_signal(signum, terminate_processes), - ) - except (ValueError, RuntimeError): - # Signal handling not allowed in this thread or invalid signal - console.print(f"Warning: Cannot set handler for {sig_name}", style="bold yellow") - continue - - -def _handle_signal(signum: int, terminate_processes: Callable[[bool], None]) -> None: - """ - Handle received signal and terminate child processes. - - Args: - signum: The signal number received. - terminate_processes: Function to call to terminate child processes. - """ - signal_name = signal.Signals(signum).name - console.print(f"Received {signal_name}. Shutting down...", style="bold yellow") - terminate_processes(exit_program=True) # type: ignore[call-arg] diff --git a/arcade/arcade/cli/new.py b/arcade/arcade/cli/new.py deleted file mode 100644 index ba50fe76..00000000 --- a/arcade/arcade/cli/new.py +++ /dev/null @@ -1,143 +0,0 @@ -import re -import shutil -from datetime import datetime -from importlib.metadata import version as get_version -from pathlib import Path -from typing import Optional - -import typer -from jinja2 import Environment, FileSystemLoader, select_autoescape -from rich.console import Console - -from arcade.cli.deployment import ( - create_demo_deployment, -) - -console = Console() - -# Retrieve the installed version of arcade-ai -try: - ARCADE_VERSION = get_version("arcade-ai") -except Exception as e: - console.print(f"[red]Failed to get arcade-ai version: {e}[/red]") - ARCADE_VERSION = "0.0.0" # Default version if unable to fetch - -TEMPLATE_IGNORE_PATTERN = re.compile( - r"(__pycache__|\.DS_Store|Thumbs\.db|\.git|\.svn|\.hg|\.vscode|\.idea|build|dist|.*\.egg-info|.*\.pyc|.*\.pyo)$" -) - - -def ask_question(question: str, default: Optional[str] = None) -> str: - """ - Ask a question via input() and return the answer. - """ - answer = typer.prompt(question, default=default) - if not answer and default: - return default - return str(answer) - - -def render_template(env: Environment, template_string: str, context: dict) -> str: - """Render a template string with the given variables.""" - template = env.from_string(template_string) - return template.render(context) - - -def write_template(path: Path, content: str) -> None: - """Write content to a file.""" - path.write_text(content, encoding="utf-8") - - -def create_package(env: Environment, template_path: Path, output_path: Path, context: dict) -> None: - """Recursively create a new toolkit directory structure from jinja2 templates.""" - if TEMPLATE_IGNORE_PATTERN.match(template_path.name): - return - - try: - if template_path.is_dir(): - folder_name = render_template(env, template_path.name, context) - new_dir_path = output_path / folder_name - new_dir_path.mkdir(parents=True, exist_ok=True) - - for item in template_path.iterdir(): - create_package(env, item, new_dir_path, context) - - else: - # Render the file name - file_name = render_template(env, template_path.name, context) - with open(template_path, encoding="utf-8") as f: - content = f.read() - # Render the file content - content = render_template(env, content, context) - - write_template(output_path / file_name, content) - except Exception as e: - console.print(f"[red]Failed to create package: {e}[/red]") - raise - - -def remove_toolkit(toolkit_directory: Path, toolkit_name: str) -> None: - """Teardown logic for when creating a new toolkit fails.""" - toolkit_path = toolkit_directory / toolkit_name - if toolkit_path.exists(): - shutil.rmtree(toolkit_path) - - -def create_new_toolkit(output_directory: str) -> None: - """Create a new toolkit from a template with user input.""" - toolkit_directory = Path(output_directory) - while True: - name = ask_question("Name of the new toolkit?") - package_name = name if name.startswith("arcade_") else f"arcade_{name}" - - # Check for illegal characters in the toolkit name - if re.match(r"^[\w_]+$", package_name): - toolkit_name = package_name.replace("arcade_", "", 1) - - if (toolkit_directory / toolkit_name).exists(): - console.print(f"[red]Toolkit {toolkit_name} already exists.[/red]") - continue - break - else: - console.print( - "[red]Toolkit name contains illegal characters. " - "Only alphanumeric characters and underscores are allowed. " - "Please try again.[/red]" - ) - - toolkit_description = ask_question("Description of the toolkit?") - toolkit_author_name = ask_question("Github owner username?") - toolkit_author_email = ask_question("Author's email?") - - context = { - "package_name": package_name, - "toolkit_name": toolkit_name, - "toolkit_description": toolkit_description, - "toolkit_author_name": toolkit_author_name, - "toolkit_author_email": toolkit_author_email, - "arcade_version": f"^{ARCADE_VERSION}", - "creation_year": datetime.now().year, - } - template_directory = Path(__file__).parent.parent / "templates" / "{{ toolkit_name }}" - - env = Environment( - loader=FileSystemLoader(str(template_directory)), - autoescape=select_autoescape(["html", "xml"]), - ) - - try: - create_package(env, template_directory, toolkit_directory, context) - create_deployment(toolkit_directory, toolkit_name) - except Exception: - remove_toolkit(toolkit_directory, toolkit_name) - raise - - -def create_deployment(toolkit_directory: Path, toolkit_name: str) -> None: - worker_toml = toolkit_directory / "worker.toml" - if not worker_toml.exists(): - create_demo_deployment(worker_toml, toolkit_name) - else: - pass - # Disabled pending bug fix - # update_deployment_with_local_packages(worker_toml, toolkit_name) diff --git a/arcade/arcade/sdk/__init__.py b/arcade/arcade/sdk/__init__.py deleted file mode 100644 index 35132e9e..00000000 --- a/arcade/arcade/sdk/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -from arcade.core.catalog import ToolCatalog -from arcade.core.schema import ToolAuthorizationContext, ToolContext, ToolMetadataKey -from arcade.core.toolkit import Toolkit - -from .tool import tool - -__all__ = [ - "ToolAuthorizationContext", - "ToolCatalog", - "ToolContext", - "ToolMetadataKey", - "Toolkit", - "tool", -] diff --git a/arcade/arcade/sdk/annotations/__init__.py b/arcade/arcade/sdk/annotations/__init__.py deleted file mode 100644 index ff53692e..00000000 --- a/arcade/arcade/sdk/annotations/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from arcade.core.annotations import Inferrable - -__all__ = ["Inferrable"] diff --git a/arcade/arcade/templates/{{ toolkit_name }}/.editorconfig b/arcade/arcade/templates/{{ toolkit_name }}/.editorconfig deleted file mode 100644 index d6eca0eb..00000000 --- a/arcade/arcade/templates/{{ toolkit_name }}/.editorconfig +++ /dev/null @@ -1,15 +0,0 @@ -# Stop the editor from looking for .editorconfig files in the parent directories -root = true - -[*] -charset = utf-8 -insert_final_newline = true -end_of_line = lf -indent_style = space -indent_size = 4 -max_line_length = 100 # This is also set in .ruff.toml for ruff - -[*.{json,jsonc,yml,yaml}] -indent_style = space -indent_size = 2 # This is also set in .prettierrc.toml - diff --git a/arcade/arcade/templates/{{ toolkit_name }}/.github/actions/setup-poetry-env/action.yml b/arcade/arcade/templates/{{ toolkit_name }}/.github/actions/setup-poetry-env/action.yml deleted file mode 100644 index dd8d25a4..00000000 --- a/arcade/arcade/templates/{{ toolkit_name }}/.github/actions/setup-poetry-env/action.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: "setup-poetry-env"{% raw %} -description: "Composite action to setup the Python and poetry environment." - -inputs: - python-version: - required: false - description: "The python version to use" - default: "3.11" - -runs: - using: "composite" - steps: - - name: Set up python - uses: actions/setup-python@v5 - with: - python-version: ${{ inputs.python-version }} - - - name: Install Poetry - uses: snok/install-poetry@v1 - with: - version: 1.8.5 - virtualenvs-in-project: true - - - name: Generate poetry.lock - run: poetry lock --no-update - shell: bash - - - name: Load cached venv - id: cached-poetry-dependencies - uses: actions/cache@v4 - with: - path: .venv - key: venv-${{ runner.os }}-${{ inputs.python-version }}-${{ hashFiles('poetry.lock') }} - - - name: Install dependencies - if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' - run: poetry install --no-interaction --all-extras - shell: bash -{% endraw %} diff --git a/arcade/arcade/templates/{{ toolkit_name }}/.github/workflows/main.yml b/arcade/arcade/templates/{{ toolkit_name }}/.github/workflows/main.yml deleted file mode 100644 index ce8b873b..00000000 --- a/arcade/arcade/templates/{{ toolkit_name }}/.github/workflows/main.yml +++ /dev/null @@ -1,61 +0,0 @@ -name: Main{% raw %} - -on: - push: - branches: - - main - pull_request: - types: [opened, synchronize, reopened, ready_for_review] - -jobs: - quality: - runs-on: ubuntu-latest - steps: - - name: Check out - uses: actions/checkout@v4 - - - uses: actions/cache@v4 - with: - path: ~/.cache/pre-commit - key: pre-commit-${{ hashFiles('.pre-commit-config.yaml') }} - - - name: Set up the environment - uses: ./.github/actions/setup-poetry-env - - - name: Run checks - run: make check - - tox: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.10", "3.11", "3.12"] - fail-fast: false - steps: - - name: Check out - uses: actions/checkout@v4 - - - name: Set up python - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - - - name: Install Poetry - uses: snok/install-poetry@v1 - with: - version: 1.8.5 - - - name: Load cached venv - uses: actions/cache@v4 - with: - path: .tox - key: venv-${{ runner.os }}-${{ matrix.python-version }}-${{ hashFiles('poetry.lock') }} - - - name: Install tox - run: | - python -m pip install --upgrade pip - python -m pip install tox tox-gh-actions - - - name: Test with tox - run: tox -{% endraw %} diff --git a/arcade/arcade/templates/{{ toolkit_name }}/.github/workflows/publish-to-pypi.yml b/arcade/arcade/templates/{{ toolkit_name }}/.github/workflows/publish-to-pypi.yml deleted file mode 100644 index 6868b034..00000000 --- a/arcade/arcade/templates/{{ toolkit_name }}/.github/workflows/publish-to-pypi.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: Publish to PyPI - -on: - release: - types: [published] - -jobs: - pypi-publish: - name: Publish to PyPi - runs-on: ubuntu-latest - environment: - name: pypi - url: https://pypi.org/project/{{ package_name }} - permissions: - id-token: write - steps: - - name: Check out - uses: actions/checkout@v4 - - - name: Set up python - uses: actions/setup-python@v5 - with: - python-version: '3.12' - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install build twine - - - name: Build package - run: python -m build - - - name: Publish to PyPI - env: - TWINE_USERNAME: "__token__"{% raw %} - TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} - run: twine upload dist/* -{% endraw %} diff --git a/arcade/arcade/templates/{{ toolkit_name }}/.gitignore b/arcade/arcade/templates/{{ toolkit_name }}/.gitignore deleted file mode 100644 index 3843d043..00000000 --- a/arcade/arcade/templates/{{ toolkit_name }}/.gitignore +++ /dev/null @@ -1,167 +0,0 @@ -.DS_Store - -*.lock - -# From https://raw.githubusercontent.com/github/gitignore/main/Python.gitignore - -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -share/python-wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -*.py,cover -.hypothesis/ -.pytest_cache/ -cover/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py -db.sqlite3 -db.sqlite3-journal - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -.pybuilder/ -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -# For a library or package, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# .python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# poetry -# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control -poetry.lock - -# pdm -# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. -#pdm.lock -# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it -# in version control. -# https://pdm.fming.dev/#use-with-ide -.pdm.toml - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm -__pypackages__/ - -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# SageMath parsed files -*.sage.py - -# Environments -.env -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ - -# pytype static type analyzer -.pytype/ - -# Cython debug symbols -cython_debug/ - -# PyCharm -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ - diff --git a/arcade/arcade/templates/{{ toolkit_name }}/.pre-commit-config.yaml b/arcade/arcade/templates/{{ toolkit_name }}/.pre-commit-config.yaml deleted file mode 100644 index 9fcd4018..00000000 --- a/arcade/arcade/templates/{{ toolkit_name }}/.pre-commit-config.yaml +++ /dev/null @@ -1,19 +0,0 @@ -files: ^./ -repos: - - repo: https://github.com/pre-commit/pre-commit-hooks - rev: "v4.4.0" - hooks: - - id: check-case-conflict - - id: check-merge-conflict - - id: check-toml - - id: check-yaml - - id: end-of-file-fixer - - id: trailing-whitespace - - - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.6.7 - hooks: - - id: ruff - args: [--fix] - - id: ruff-format - diff --git a/arcade/arcade/templates/{{ toolkit_name }}/.prettierignore b/arcade/arcade/templates/{{ toolkit_name }}/.prettierignore deleted file mode 100644 index 7bc9c651..00000000 --- a/arcade/arcade/templates/{{ toolkit_name }}/.prettierignore +++ /dev/null @@ -1,3 +0,0 @@ -# Ignore Python files for Prettier -*.py - diff --git a/arcade/arcade/templates/{{ toolkit_name }}/.prettierrc.toml b/arcade/arcade/templates/{{ toolkit_name }}/.prettierrc.toml deleted file mode 100644 index 6532bbb1..00000000 --- a/arcade/arcade/templates/{{ toolkit_name }}/.prettierrc.toml +++ /dev/null @@ -1,16 +0,0 @@ -# See https://prettier.io/docs/en/configuration - -# Note: This prettier config is only for the non-python files in this repo. -# Python files are formatted with ruff and ignored in .prettierignore - -trailingComma = "es5" -tabWidth = 4 -semi = false -singleQuote = false - -[[overrides]] -files = [ "*.json", "*.jsonc", "*.yml", "*.yaml" ] - - [overrides.options] - tabWidth = 2 - diff --git a/arcade/arcade/templates/{{ toolkit_name }}/.ruff.toml b/arcade/arcade/templates/{{ toolkit_name }}/.ruff.toml deleted file mode 100644 index 421edfcf..00000000 --- a/arcade/arcade/templates/{{ toolkit_name }}/.ruff.toml +++ /dev/null @@ -1,45 +0,0 @@ -target-version = "py310" -line-length = 100 -fix = true - -[lint] -select = [ - # flake8-2020 - "YTT", - # flake8-bandit - "S", - # flake8-bugbear - "B", - # flake8-builtins - "A", - # flake8-comprehensions - "C4", - # flake8-debugger - "T10", - # flake8-simplify - "SIM", - # isort - "I", - # mccabe - "C90", - # pycodestyle - "E", "W", - # pyflakes - "F", - # pygrep-hooks - "PGH", - # pyupgrade - "UP", - # ruff - "RUF", - # tryceratops - "TRY", -] - -[lint.per-file-ignores] -"**/tests/*" = ["S101"] - -[format] -preview = true -skip-magic-trailing-comma = false - diff --git a/arcade/arcade/templates/{{ toolkit_name }}/LICENSE b/arcade/arcade/templates/{{ toolkit_name }}/LICENSE deleted file mode 100644 index 0e1b63bf..00000000 --- a/arcade/arcade/templates/{{ toolkit_name }}/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -MIT License - -Copyright (c) {{ creation_year }}, {{ toolkit_author_name }} - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/arcade/arcade/templates/{{ toolkit_name }}/Makefile b/arcade/arcade/templates/{{ toolkit_name }}/Makefile deleted file mode 100644 index 78d525d3..00000000 --- a/arcade/arcade/templates/{{ toolkit_name }}/Makefile +++ /dev/null @@ -1,59 +0,0 @@ -.PHONY: help - -help: - @echo "๐Ÿ› ๏ธ {{ toolkit_name }} Commands:\n" - @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' - -.PHONY: install -install: ## Install the poetry environment and install the pre-commit hooks - @echo "๐Ÿ“ฆ Checking if Poetry is installed" - @if ! command -v poetry >/dev/null 2>&1; then \ - echo "๐Ÿ“ฆ Poetry not found. Checking if pip is available"; \ - if ! command -v pip >/dev/null 2>&1; then \ - echo "โŒ pip is not installed. Please install pip first."; \ - exit 1; \ - fi; \ - echo "๐Ÿ“ฆ Installing Poetry with pip"; \ - pip install poetry==1.8.5; \ - else \ - echo "๐Ÿ“ฆ Poetry is already installed"; \ - fi - @echo "๐Ÿš€ Installing package in development mode with all extras" - poetry install --all-extras - -.PHONY: build -build: clean-build ## Build wheel file using poetry - @echo "๐Ÿš€ Creating wheel file" - poetry build - -.PHONY: clean-build -clean-build: ## clean build artifacts - @echo "๐Ÿ—‘๏ธ Cleaning dist directory" - rm -rf dist - -.PHONY: test -test: ## Test the code with pytest - @echo "๐Ÿš€ Testing code: Running pytest" - @poetry run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml - -.PHONY: coverage -coverage: ## Generate coverage report - @echo "coverage report" - coverage report - @echo "Generating coverage report" - coverage html - -.PHONY: bump-version -bump-version: ## Bump the version in the pyproject.toml file - @echo "๐Ÿš€ Bumping version in pyproject.toml" - poetry version patch - -.PHONY: check -check: ## Run code quality tools. - @echo "๐Ÿš€ Checking Poetry lock file consistency with 'pyproject.toml': Running poetry check" - @poetry check - @echo "๐Ÿš€ Linting code: Running pre-commit" - @poetry run pre-commit run -a - @echo "๐Ÿš€ Static type checking: Running mypy" - @poetry run mypy --config-file=pyproject.toml - diff --git a/arcade/arcade/templates/{{ toolkit_name }}/codecov.yaml b/arcade/arcade/templates/{{ toolkit_name }}/codecov.yaml deleted file mode 100644 index b5647d98..00000000 --- a/arcade/arcade/templates/{{ toolkit_name }}/codecov.yaml +++ /dev/null @@ -1,10 +0,0 @@ -coverage: - range: 70..100 - round: down - precision: 1 - status: - project: - default: - target: 90% - threshold: 0.5% - diff --git a/arcade/arcade/templates/{{ toolkit_name }}/pyproject.toml b/arcade/arcade/templates/{{ toolkit_name }}/pyproject.toml deleted file mode 100644 index b0295a38..00000000 --- a/arcade/arcade/templates/{{ toolkit_name }}/pyproject.toml +++ /dev/null @@ -1,40 +0,0 @@ -[tool.poetry] -name = "{{ package_name }}" -version = "0.0.1" -description = "{{ toolkit_description }}" -authors = ["{{ toolkit_author_name }} <{{ toolkit_author_email }}>"] - -[tool.poetry.dependencies] -python = "^3.10" -arcade-ai = "^1.0.5" - -[tool.poetry.dev-dependencies] -pytest = "^8.3.0" -pytest-cov = "^4.0.0" -mypy = "^1.5.1" -pre-commit = "^3.4.0" -tox = "^4.11.1" -ruff = "^0.7.4" - -[build-system] -requires = ["poetry-core>=1.0.0,<2.0.0"] -build-backend = "poetry.core.masonry.api" - -[tool.mypy] -files = ["{{ package_name }}/**/*.py"] -python_version = "3.10" -disallow_untyped_defs = "True" -disallow_any_unimported = "True" -no_implicit_optional = "True" -check_untyped_defs = "True" -warn_return_any = "True" -warn_unused_ignores = "True" -show_error_codes = "True" -ignore_missing_imports = "True" - -[tool.pytest.ini_options] -testpaths = ["tests"] - -[tool.coverage.report] -skip_empty = true - diff --git a/arcade/arcade/templates/{{ toolkit_name }}/tox.ini b/arcade/arcade/templates/{{ toolkit_name }}/tox.ini deleted file mode 100644 index fdc472ec..00000000 --- a/arcade/arcade/templates/{{ toolkit_name }}/tox.ini +++ /dev/null @@ -1,17 +0,0 @@ -[tox] -skipsdist = true -envlist = py310, py311, py312 - -[gh-actions] -python = - 3.10: py310 - 3.11: py311 - 3.12: py312 - -[testenv] -passenv = PYTHON_VERSION -allowlist_externals = poetry -commands = - poetry install -v --all-extras - pytest --doctest-modules tests --cov --cov-config=pyproject.toml --cov-report=xml - diff --git a/arcade/codecov.yaml b/arcade/codecov.yaml deleted file mode 100644 index 13bf40a2..00000000 --- a/arcade/codecov.yaml +++ /dev/null @@ -1,11 +0,0 @@ -coverage: - range: 70..100 - round: down - precision: 1 - status: - project: - default: - target: 90% - threshold: 0.5% - exclude: - - arcade/cli/** diff --git a/arcade/pyproject.toml b/arcade/pyproject.toml deleted file mode 100644 index 16a0935b..00000000 --- a/arcade/pyproject.toml +++ /dev/null @@ -1,88 +0,0 @@ -[tool.poetry] -name = "arcade-ai" -version = "1.1.0" -description = "Arcade Python SDK and CLI" -readme = "README.md" -packages = [ - {include="arcade", from="."} -] -authors = ["Arcade "] - -[build-system] -requires = ["poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" - - -[tool.poetry.dependencies] -python = ">=3.10,<4.0" -pydantic = "^2.7.0" -typer = ">=0.10.0" -rich = "^13.7.1" -Jinja2 = ">=3.1.5,<4.0.0" -pyyaml = "^6.0" -openai = "^1.36.0" # TODO: relax to an earlier version that still has what we need -arcadepy = "^1.3.1" -pyjwt = "^2.8.0" -loguru = "^0.7.0" -tqdm = "^4.1.0" -toml = "^0.10.2" -packaging = "^24.1" -types-python-dateutil = "2.9.0.20241003" -types-pytz = "2024.2.0.20241003" -types-toml = "0.10.8.20240310" -opentelemetry-instrumentation-fastapi = "0.48b0" -opentelemetry-exporter-otlp-proto-http = "1.27.0" -opentelemetry-exporter-otlp-proto-common = "1.27.0" -fastapi = "^0.115.3" -uvicorn = "^0.30.0" -scipy = {version = "^1.14.0", optional = true} -numpy = {version = "^2.0.0", optional = true} -scikit-learn = {version = "^1.5.0", optional = true} -pytz = {version = "^2024.1", optional = true} -python-dateutil = {version = "^2.8.2", optional = true} -watchfiles = "^1.0.5" - -pyreadline3 = {version = "^3.5.4", platform = "win32"} -[tool.poetry.extras] -evals = ["scipy", "numpy", "scikit-learn", "pytz", "python-dateutil"] - - -[tool.poetry.group.dev.dependencies] -pytest = "^8.1.2" -pytest-cov = "^4.0.0" -mypy = "^1.5.1" -pre-commit = "^3.4.0" -tox = "^4.11.1" -pytest-asyncio = "^0.23.7" -types-pytz = "^2024.1" -types-python-dateutil = "^2.8.2" -types-PyYAML = "^6.0.0" -poetry-plugin-export = "^1.7.0" - -[tool.poetry.scripts] -arcade = "arcade.cli.main:cli" - -[tool.mypy] -files = ["arcade"] -exclude = "arcade/templates" -python_version = "3.10" -disallow_untyped_defs = "True" -disallow_any_unimported = "True" -no_implicit_optional = "True" -check_untyped_defs = "True" -warn_return_any = "True" -warn_unused_ignores = "True" -show_error_codes = "True" -ignore_missing_imports = "True" - -[tool.pytest.ini_options] -testpaths = ["tests"] - - -[tool.coverage.run] -branch = true -source = ["arcade"] -omit = ["arcade/cli/*"] - -[tool.coverage.report] -skip_empty = true diff --git a/arcade/tox.ini b/arcade/tox.ini deleted file mode 100644 index fc0917c3..00000000 --- a/arcade/tox.ini +++ /dev/null @@ -1,17 +0,0 @@ -[tox] -skipsdist = true -envlist = py310, py311, py312 - -[gh-actions] -python = - 3.10: py310 - 3.11: py311 - 3.12: py312 - -[testenv] -passenv = PYTHON_VERSION -allowlist_externals = poetry -commands = - poetry install -v --all-extras - pytest --doctest-modules tests --cov --cov-config=pyproject.toml --cov-report=xml -# mypy diff --git a/examples/mcp/run_stdio.py b/examples/mcp/run_stdio.py index 3011640e..87be1953 100644 --- a/examples/mcp/run_stdio.py +++ b/examples/mcp/run_stdio.py @@ -1,8 +1,7 @@ import arcade_google # pip install arcade_google import arcade_search # pip install arcade_search - -from arcade.core.catalog import ToolCatalog -from arcade.worker.mcp.stdio import StdioServer +from arcade_core.catalog import ToolCatalog +from arcade_serve.mcp.stdio import StdioServer # 2. Create and populate the tool catalog catalog = ToolCatalog() diff --git a/examples/serving-tools/modal/run-arcade-worker.py b/examples/serving-tools/modal/run-arcade-worker.py index 1a313675..36108cde 100644 --- a/examples/serving-tools/modal/run-arcade-worker.py +++ b/examples/serving-tools/modal/run-arcade-worker.py @@ -7,17 +7,18 @@ app = App("arcade-worker") toolkits = ["arcade_google", "arcade_slack"] -image = Image.debian_slim().pip_install("arcade-ai").pip_install(toolkits) +image = ( + Image.debian_slim().pip_install("arcade_tdk").pip_install("arcade_serve").pip_install(toolkits) +) @app.function(image=image) @asgi_app() def fastapi_app(): + from arcade_serve.fastapi.worker import FastAPIWorker + from arcade_tdk import Toolkit from fastapi import FastAPI - from arcade.sdk import Toolkit - from arcade.worker.fastapi.worker import FastAPIWorker - web_app = FastAPI() # Initialize app and Arcade FastAPIWorker diff --git a/libs/arcade-cli/README.md b/libs/arcade-cli/README.md new file mode 100644 index 00000000..ae0cc6fc --- /dev/null +++ b/libs/arcade-cli/README.md @@ -0,0 +1,28 @@ +# Arcade CLI + +Command-line interface for the Arcade platform. + +## Overview + +Arcade CLI provides a comprehensive command-line interface for the Arcade platform: + +- **User Authentication**: Login, logout +- **Tool Development**: Create, test, and manage Arcade tools +- **Worker Deployment**: Deploy and manage Arcade workers +- **Interactive Chat**: Test tools in an interactive environment +- **Project Templates**: Generate new toolkit projects + +## Installation +```bash +pip install arcade-ai +``` + +## Usage +Learn how to use the Arcade CLI and what commands are available to you. +```bash +arcade --help +``` + +## License + +MIT License - see LICENSE file for details. diff --git a/arcade/arcade/cli/__init__.py b/libs/arcade-cli/arcade_cli/__init__.py similarity index 100% rename from arcade/arcade/cli/__init__.py rename to libs/arcade-cli/arcade_cli/__init__.py diff --git a/arcade/arcade/cli/authn.py b/libs/arcade-cli/arcade_cli/authn.py similarity index 99% rename from arcade/arcade/cli/authn.py rename to libs/arcade-cli/arcade_cli/authn.py index d2615b1b..224965e5 100644 --- a/arcade/arcade/cli/authn.py +++ b/libs/arcade-cli/arcade_cli/authn.py @@ -7,7 +7,7 @@ from urllib.parse import parse_qs import yaml from rich.console import Console -from arcade.cli.constants import ( +from arcade_cli.constants import ( ARCADE_CONFIG_PATH, CREDENTIALS_FILE_PATH, LOGIN_FAILED_HTML, diff --git a/libs/arcade-cli/arcade_cli/config.py b/libs/arcade-cli/arcade_cli/config.py new file mode 100644 index 00000000..f7340e31 --- /dev/null +++ b/libs/arcade-cli/arcade_cli/config.py @@ -0,0 +1,104 @@ +""" +Configuration utilities for the Arcade CLI. +""" + +from dataclasses import dataclass +from typing import Any + +from rich.console import Console +from rich.table import Table + +console = Console() + + +@dataclass +class UserConfig: + """User configuration.""" + + email: str | None = None + name: str | None = None + + +@dataclass +class ApiConfig: + """API configuration.""" + + key: str | None = None + url: str | None = None + + +@dataclass +class Config: + """Arcade CLI configuration.""" + + user: UserConfig | None = None + api: ApiConfig | None = None + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> "Config": + """Create a Config instance from a dictionary. + + Args: + data: Dictionary with configuration + + Returns: + Config instance + """ + user_data = data.get("user", {}) + api_data = data.get("api", {}) + + return cls( + user=UserConfig( + email=user_data.get("email"), + name=user_data.get("name"), + ), + api=ApiConfig( + key=api_data.get("key"), + url=api_data.get("url"), + ), + ) + + def to_dict(self) -> dict[str, Any]: + """Convert configuration to a dictionary. + + Returns: + Configuration as a dictionary + """ + result = {} + + if self.user: + result["user"] = { + "email": self.user.email, + "name": self.user.name, + } + + if self.api: + result["api"] = { + "key": self.api.key, + "url": self.api.url, + } + + return result + + +def print_config(config: dict[str, Any], name: str | None = None) -> None: + """ + Print the configuration in a formatted table. + + Args: + config: Configuration dictionary + name: Optional name for the configuration + """ + table = Table(title=f"Configuration: {name}" if name else "Configuration") + table.add_column("Key", style="cyan") + table.add_column("Value", style="green") + + for key, value in sorted(config.items()): + if isinstance(value, dict): + # For nested configurations + nested_value = "\n".join(f"{k}: {v}" for k, v in value.items()) + table.add_row(key, nested_value) + else: + table.add_row(key, str(value)) + + console.print(table) diff --git a/arcade/arcade/cli/constants.py b/libs/arcade-cli/arcade_cli/constants.py similarity index 100% rename from arcade/arcade/cli/constants.py rename to libs/arcade-cli/arcade_cli/constants.py diff --git a/arcade/arcade/cli/deployment.py b/libs/arcade-cli/arcade_cli/deployment.py similarity index 100% rename from arcade/arcade/cli/deployment.py rename to libs/arcade-cli/arcade_cli/deployment.py diff --git a/arcade/arcade/cli/display.py b/libs/arcade-cli/arcade_cli/display.py similarity index 98% rename from arcade/arcade/cli/display.py rename to libs/arcade-cli/arcade_cli/display.py index c44c8d53..abb3dc96 100644 --- a/arcade/arcade/cli/display.py +++ b/libs/arcade-cli/arcade_cli/display.py @@ -1,14 +1,13 @@ from typing import TYPE_CHECKING, Any +from arcade_core.schema import ToolDefinition from rich.console import Console from rich.panel import Panel from rich.table import Table from rich.text import Text -from arcade.core.schema import ToolDefinition - if TYPE_CHECKING: - from arcade.sdk.eval.eval import EvaluationResult + from arcade_evals.eval import EvaluationResult console = Console() diff --git a/arcade/arcade/cli/main.py b/libs/arcade-cli/arcade_cli/main.py similarity index 93% rename from arcade/arcade/cli/main.py rename to libs/arcade-cli/arcade_cli/main.py index 7153ad6e..3ea3be8f 100644 --- a/arcade/arcade/cli/main.py +++ b/libs/arcade-cli/arcade_cli/main.py @@ -16,23 +16,22 @@ from rich.markup import escape from rich.text import Text from tqdm import tqdm -import arcade.cli.worker as worker -from arcade.cli.authn import LocalAuthCallbackServer, check_existing_login -from arcade.cli.constants import ( +import arcade_cli.worker as worker +from arcade_cli.authn import LocalAuthCallbackServer, check_existing_login +from arcade_cli.constants import ( CREDENTIALS_FILE_PATH, LOCALHOST, PROD_CLOUD_HOST, PROD_ENGINE_HOST, ) -from arcade.cli.deployment import Deployment -from arcade.cli.display import ( +from arcade_cli.deployment import Deployment +from arcade_cli.display import ( display_arcade_chat_header, display_eval_results, display_tool_messages, ) -from arcade.cli.launcher import start_servers -from arcade.cli.show import show_logic -from arcade.cli.utils import ( +from arcade_cli.show import show_logic +from arcade_cli.utils import ( OrderCommands, compute_base_url, compute_login_url, @@ -45,6 +44,7 @@ from arcade.cli.utils import ( is_authorization_pending, load_eval_suites, log_engine_health, + require_dependency, validate_and_get_config, version_callback, ) @@ -133,17 +133,24 @@ def logout() -> None: console.print("You're not logged in.", style="bold red") -@cli.command(help="Create a new toolkit package directory", rich_help_panel="Tool Development") +@cli.command( + help="Create a new toolkit package directory. Example usage: arcade new my_toolkit", + rich_help_panel="Tool Development", +) def new( + toolkit_name: str = typer.Argument( + help="The name of the toolkit to create", + metavar="TOOLKIT_NAME", + ), directory: str = typer.Option(os.getcwd(), "--dir", help="tools directory path"), ) -> None: """ Creates a new toolkit with the given name, description, and result type. """ - from arcade.cli.new import create_new_toolkit + from arcade_cli.new import create_new_toolkit try: - create_new_toolkit(directory) + create_new_toolkit(directory, toolkit_name) except Exception as e: error_message = f"โŒ Failed to create new Toolkit: {escape(str(e))}" console.print(error_message, style="bold red") @@ -374,6 +381,20 @@ def evals( Find all files starting with 'eval_' in the given directory, execute any functions decorated with @tool_eval, and display the results. """ + require_dependency( + package_name="arcade_evals", + command_name="evals", + install_command=r"pip install 'arcade-ai\[evals]'", + ) + # Although Evals does not depend on the TDK, some evaluations import the + # ToolCatalog class from the TDK instead of from arcade_core, so we require + # the TDK to run the evals CLI command to avoid possible import errors. + require_dependency( + package_name="arcade_tdk", + command_name="evals", + install_command=r"pip install arcade-tdk", + ) + config = validate_and_get_config() host = PROD_ENGINE_HOST if cloud else host @@ -481,7 +502,13 @@ def serve( """ Start a local Arcade Worker server. """ - from arcade.cli.serve import serve_default_worker + require_dependency( + package_name="arcade_serve", + command_name="serve", + install_command=r"pip install 'arcade-ai\[serve]'", + ) + + from arcade_cli.serve import serve_default_worker try: serve_default_worker( @@ -501,31 +528,6 @@ def serve( typer.Exit(code=1) -@cli.command(help="Launch Arcade - requires 'arcade-engine'", rich_help_panel="Launch") -def dev( - host: str = typer.Option("127.0.0.1", help="Host for the toolkit server.", show_default=True), - port: int = typer.Option( - 8002, "-p", "--port", help="Port for the toolkit server.", show_default=True - ), - engine_config: str = typer.Option( - None, "-c", "--config", help="Path to the engine configuration file." - ), - env_file: str = typer.Option( - None, "-e", "--env-file", help="Path to the environment variables file." - ), - debug: bool = typer.Option(False, "-d", "--debug", help="Show debug information"), -) -> None: - """ - Start both the toolkit server and engine servers. - """ - try: - start_servers(host, port, engine_config, engine_env=env_file, debug=debug) - except Exception as e: - error_message = f"โŒ Failed to start servers: {escape(str(e))}" - console.print(error_message, style="bold red") - typer.Exit(code=1) - - @cli.command( help="Start a server with locally installed Arcade tools", rich_help_panel="Launch", hidden=True ) @@ -553,7 +555,13 @@ def workerup( Starts the worker with host, port, and reload options. Uses Uvicorn as ASGI worker. Parameters allow runtime configuration. """ - from arcade.cli.serve import serve_default_worker + require_dependency( + package_name="arcade_serve", + command_name="worker", + install_command=r"pip install 'arcade-ai\[worker]'", + ) + + from arcade_cli.serve import serve_default_worker try: serve_default_worker( diff --git a/libs/arcade-cli/arcade_cli/new.py b/libs/arcade-cli/arcade_cli/new.py new file mode 100644 index 00000000..6951c1f2 --- /dev/null +++ b/libs/arcade-cli/arcade_cli/new.py @@ -0,0 +1,219 @@ +import re +import shutil +from datetime import datetime +from importlib.metadata import version as get_version +from pathlib import Path +from typing import Optional + +import typer +from jinja2 import Environment, FileSystemLoader, select_autoescape +from rich.console import Console + +from arcade_cli.deployment import ( + create_demo_deployment, +) + +console = Console() + +# Retrieve the installed version of arcade-ai +try: + ARCADE_AI_MIN_VERSION = get_version("arcade-ai") + ARCADE_AI_MAX_VERSION = str(int(ARCADE_AI_MIN_VERSION.split(".")[0]) + 1) + ".0.0" +except Exception as e: + console.print(f"[red]Failed to get arcade-ai version: {e}[/red]") + ARCADE_AI_MIN_VERSION = "2.0.0" # Default version if unable to fetch + ARCADE_AI_MAX_VERSION = "3.0.0" + +ARCADE_TDK_MIN_VERSION = "0.1.0" +ARCADE_TDK_MAX_VERSION = "1.0.0" +ARCADE_SERVE_MIN_VERSION = "0.1.0" +ARCADE_SERVE_MAX_VERSION = "1.0.0" + + +def ask_question(question: str, default: Optional[str] = None) -> str: + """ + Ask a question via input() and return the answer. + """ + answer = typer.prompt(question, default=default, show_default=False) + if not answer and default: + return default + return str(answer) + + +def ask_yes_no_question(question: str, default: bool = True) -> bool: + """ + Ask a yes/no question via input() and return the bool answer. + """ + default_str = "Y/n" if default else "y/N" + answer = typer.prompt( + f"{question} ({default_str})", default="y" if default else "n", show_default=False + ) + return answer.lower() in [ + "y", + "y/", + "yes", + "true", + "1", + "ye", + "yes", + "yeah", + "yep", + "sure", + "ok", + "yup", + ] + + +def render_template(env: Environment, template_string: str, context: dict) -> str: + """Render a template string with the given variables.""" + template = env.from_string(template_string) + return template.render(context) + + +def write_template(path: Path, content: str) -> None: + """Write content to a file.""" + path.write_text(content, encoding="utf-8") + + +def create_ignore_pattern(include_evals: bool) -> re.Pattern[str]: + """Create an ignore pattern based on user preferences.""" + patterns = [ + "__pycache__", + r"\.DS_Store", + r"Thumbs\.db", + r"\.git", + r"\.svn", + r"\.hg", + r"\.vscode", + r"\.idea", + "build", + "dist", + r".*\.egg-info", + r".*\.pyc", + r".*\.pyo", + ] + + if not include_evals: + patterns.append("evals") + + return re.compile(f"({'|'.join(patterns)})$") + + +def create_package( + env: Environment, + template_path: Path, + output_path: Path, + context: dict, + ignore_pattern: re.Pattern[str], +) -> None: + """Recursively create a new toolkit directory structure from jinja2 templates.""" + if ignore_pattern.match(template_path.name): + return + + try: + if template_path.is_dir(): + folder_name = render_template(env, template_path.name, context) + new_dir_path = output_path / folder_name + new_dir_path.mkdir(parents=True, exist_ok=True) + + for item in template_path.iterdir(): + create_package(env, item, new_dir_path, context, ignore_pattern) + + else: + # Render the file name + file_name = render_template(env, template_path.name, context) + with open(template_path, encoding="utf-8") as f: + content = f.read() + # Render the file content + content = render_template(env, content, context) + + write_template(output_path / file_name, content) + except Exception as e: + console.print(f"[red]Failed to create package: {e}[/red]") + raise + + +def remove_toolkit(toolkit_directory: Path, toolkit_name: str) -> None: + """Teardown logic for when creating a new toolkit fails.""" + toolkit_path = toolkit_directory / toolkit_name + if toolkit_path.exists(): + shutil.rmtree(toolkit_path) + + +def create_new_toolkit(output_directory: str, toolkit_name: str) -> None: + """Create a new toolkit from a template with user input.""" + toolkit_directory = Path(output_directory) + + package_name = toolkit_name if toolkit_name.startswith("arcade_") else f"arcade_{toolkit_name}" + + # Check for illegal characters in the toolkit name + if re.match(r"^[a-z0-9_]+$", package_name): + toolkit_name = package_name.replace("arcade_", "", 1) + + if (toolkit_directory / toolkit_name).exists(): + console.print(f"[red]Toolkit '{toolkit_name}' already exists.[/red]") + exit(1) + else: + console.print( + "[red]Toolkit name contains illegal characters. " + "Only lowercase alphanumeric characters and underscores are allowed. " + "Please try again.[/red]" + ) + exit(1) + + toolkit_description = ask_question("Describe what your toolkit will do (optional)", default="") + toolkit_author_name = ask_question("Your GitHub username (optional)", default="") + while True: + toolkit_author_email = ask_question("Your email (optional)", default="") + if toolkit_author_email == "" or re.match(r"[^@ ]+@[^@ ]+\.[^@ ]+", toolkit_author_email): + break + console.print( + "[red]Invalid email format. Please enter a valid email address or leave it empty.[/red]" + ) + include_evals = ask_yes_no_question( + "Do you want an evals directory created for you?", default=True + ) + + context = { + "package_name": package_name, + "toolkit_name": toolkit_name, + "toolkit_description": toolkit_description, + "toolkit_author_name": toolkit_author_name, + "toolkit_author_email": toolkit_author_email, + "arcade_tdk_min_version": ARCADE_TDK_MIN_VERSION, + "arcade_tdk_max_version": ARCADE_TDK_MAX_VERSION, + "arcade_serve_min_version": ARCADE_SERVE_MIN_VERSION, + "arcade_serve_max_version": ARCADE_SERVE_MAX_VERSION, + "arcade_ai_min_version": ARCADE_AI_MIN_VERSION, + "arcade_ai_max_version": ARCADE_AI_MAX_VERSION, + "creation_year": datetime.now().year, + } + template_directory = Path(__file__).parent / "templates" / "{{ toolkit_name }}" + + env = Environment( + loader=FileSystemLoader(str(template_directory)), + autoescape=select_autoescape(["html", "xml"]), + ) + + # Create dynamic ignore pattern based on user preferences + ignore_pattern = create_ignore_pattern(include_evals) + + try: + create_package(env, template_directory, toolkit_directory, context, ignore_pattern) + console.print( + f"[green]Toolkit '{toolkit_name}' created successfully at '{toolkit_directory}'.[/green]" + ) + create_deployment(toolkit_directory, toolkit_name) + except Exception: + remove_toolkit(toolkit_directory, toolkit_name) + raise + + +def create_deployment(toolkit_directory: Path, toolkit_name: str) -> None: + worker_toml = toolkit_directory / "worker.toml" + if not worker_toml.exists(): + create_demo_deployment(worker_toml, toolkit_name) + else: + pass + # Disabled pending bug fix + # update_deployment_with_local_packages(worker_toml, toolkit_name) diff --git a/arcade/arcade/cli/serve.py b/libs/arcade-cli/arcade_cli/serve.py similarity index 96% rename from arcade/arcade/cli/serve.py rename to libs/arcade-cli/arcade_cli/serve.py index 2c6cd92e..65ad4fa1 100644 --- a/arcade/arcade/cli/serve.py +++ b/libs/arcade-cli/arcade_cli/serve.py @@ -15,18 +15,18 @@ import uvicorn # Watchfiles is used under the hood by Uvicorn's reload feature. # Importing watchfiles here is an explicit acknowledgement that it needs to be installed import watchfiles # noqa: F401 +from arcade_core.telemetry import OTELHandler +from arcade_core.toolkit import Toolkit, get_package_directory +from arcade_serve.fastapi.worker import FastAPIWorker from loguru import logger from rich.console import Console -from arcade.cli.constants import ARCADE_CONFIG_PATH -from arcade.cli.utils import ( +from arcade_cli.constants import ARCADE_CONFIG_PATH +from arcade_cli.utils import ( build_tool_catalog, discover_toolkits, load_dotenv, ) -from arcade.core.telemetry import OTELHandler -from arcade.core.toolkit import Toolkit, get_package_directory -from arcade.worker.fastapi.worker import FastAPIWorker console = Console(width=70, color_system="auto") @@ -45,7 +45,6 @@ def create_arcade_app() -> fastapi.FastAPI: setup_logging(log_level=logging.DEBUG if debug_mode else logging.INFO, mcp_mode=False) logger.info(f"Debug: {debug_mode}, OTEL: {otel_enabled}, Auth Disabled: {auth_for_reload}") - version = get_pkg_version("arcade-ai") toolkits = discover_toolkits() @@ -94,7 +93,7 @@ def _run_mcp_stdio( ) -> None: """Launch an MCP stdio server; blocks until it exits.""" - from arcade.worker.mcp.stdio import StdioServer + from arcade_serve.mcp.stdio import StdioServer # Load env vars before launching server (explicit path, config path, cwd) if env_file: @@ -139,7 +138,7 @@ def _run_fastapi_server( toolkits_for_reload_dirs: list[Toolkit] | None, debug_flag: bool, ) -> None: - app_import_string = "arcade.cli.serve:create_arcade_app" + app_import_string = "arcade_cli.serve:create_arcade_app" reload_dirs_str_list: list[str] | None = None if reload: diff --git a/arcade/arcade/cli/show.py b/libs/arcade-cli/arcade_cli/show.py similarity index 92% rename from arcade/arcade/cli/show.py rename to libs/arcade-cli/arcade_cli/show.py index 2f3331a8..310ef356 100644 --- a/arcade/arcade/cli/show.py +++ b/libs/arcade-cli/arcade_cli/show.py @@ -2,8 +2,8 @@ import typer from rich.console import Console from rich.markup import escape -from arcade.cli.display import display_tool_details, display_tools_table -from arcade.cli.utils import create_cli_catalog, get_tools_from_engine +from arcade_cli.display import display_tool_details, display_tools_table +from arcade_cli.utils import create_cli_catalog, get_tools_from_engine def show_logic( diff --git a/libs/arcade-cli/arcade_cli/templates/{{ toolkit_name }}/Makefile b/libs/arcade-cli/arcade_cli/templates/{{ toolkit_name }}/Makefile new file mode 100644 index 00000000..e1849fe5 --- /dev/null +++ b/libs/arcade-cli/arcade_cli/templates/{{ toolkit_name }}/Makefile @@ -0,0 +1,46 @@ +.PHONY: help + +help: + @echo "๐Ÿ› ๏ธ github Commands:\n" + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + +.PHONY: install +install: ## Install the uv environment and install all packages with dependencies + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras --no-sources + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" + +.PHONY: install-local +install-local: ## Install the uv environment and install all packages with dependencies with local Arcade sources + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" + +.PHONY: build +build: clean-build ## Build wheel file using poetry + @echo "๐Ÿš€ Creating wheel file" + uv build + +.PHONY: clean-build +clean-build: ## clean build artifacts + @echo "๐Ÿ—‘๏ธ Cleaning dist directory" + rm -rf dist + +.PHONY: test +test: ## Test the code with pytest + @echo "๐Ÿš€ Testing code: Running pytest" + @uv run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml + +.PHONY: bump-version +bump-version: ## Bump the version in the pyproject.toml file by a patch version + @echo "๐Ÿš€ Bumping version in pyproject.toml" + uv version --bump patch + +.PHONY: check +check: ## Run code quality tools. + @echo "๐Ÿš€ Linting code: Running pre-commit" + @uv run pre-commit run -a + @echo "๐Ÿš€ Static type checking: Running mypy" + @uv run mypy --config-file=pyproject.toml diff --git a/arcade/arcade/templates/{{ toolkit_name }}/README.md b/libs/arcade-cli/arcade_cli/templates/{{ toolkit_name }}/README.md similarity index 85% rename from arcade/arcade/templates/{{ toolkit_name }}/README.md rename to libs/arcade-cli/arcade_cli/templates/{{ toolkit_name }}/README.md index 2eaf32d4..08fe3925 100644 --- a/arcade/arcade/templates/{{ toolkit_name }}/README.md +++ b/libs/arcade-cli/arcade_cli/templates/{{ toolkit_name }}/README.md @@ -6,11 +6,14 @@
+ {% if toolkit_author_name -%} GitHub release + {% endif -%} Python version License PyPI version
+{% if toolkit_author_name -%} +{% endif %}

# Arcade {{ toolkit_name }} Toolkit - +{% if toolkit_description -%} {{ toolkit_description }} - +{% endif -%} ## Features - The {{ toolkit_name }} toolkit does not have any features yet. -## Install +## Development -Install this toolkit using pip: - -```bash -pip install {{ package_name }} -``` +Read the docs on how to create a toolkit [here](https://docs.arcade.dev/home/build-tools/create-a-toolkit) \ No newline at end of file diff --git a/arcade/arcade/templates/{{ toolkit_name }}/evals/eval_{{ toolkit_name }}.py b/libs/arcade-cli/arcade_cli/templates/{{ toolkit_name }}/evals/eval_{{ toolkit_name }}.py similarity index 91% rename from arcade/arcade/templates/{{ toolkit_name }}/evals/eval_{{ toolkit_name }}.py rename to libs/arcade-cli/arcade_cli/templates/{{ toolkit_name }}/evals/eval_{{ toolkit_name }}.py index cee5c4cc..8f50f622 100644 --- a/arcade/arcade/templates/{{ toolkit_name }}/evals/eval_{{ toolkit_name }}.py +++ b/libs/arcade-cli/arcade_cli/templates/{{ toolkit_name }}/evals/eval_{{ toolkit_name }}.py @@ -1,11 +1,11 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_tdk import ToolCatalog +from arcade_evals import ( EvalRubric, EvalSuite, ExpectedToolCall, - SimilarityCritic, tool_eval, ) +from arcade_evals.critic import SimilarityCritic import {{ package_name }} from {{ package_name }}.tools.hello import say_hello diff --git a/libs/arcade-cli/arcade_cli/templates/{{ toolkit_name }}/pyproject.toml b/libs/arcade-cli/arcade_cli/templates/{{ toolkit_name }}/pyproject.toml new file mode 100644 index 00000000..2afbb64a --- /dev/null +++ b/libs/arcade-cli/arcade_cli/templates/{{ toolkit_name }}/pyproject.toml @@ -0,0 +1,66 @@ +[build-system] +requires = [ "hatchling",] +build-backend = "hatchling.build" + +[project] +name = "{{ package_name }}" +version = "0.1.0" +{% if toolkit_description -%} +description = "{{ toolkit_description }}" +{% endif -%} +requires-python = ">=3.10" +dependencies = [ + "arcade-tdk>={{ arcade_tdk_min_version }},<{{ arcade_tdk_max_version}}", +] +{% if toolkit_author_name or toolkit_author_email -%} +[[project.authors]] +{% if toolkit_author_name -%} +name = "{{ toolkit_author_name }}" +{% endif -%} +{% if toolkit_author_email -%} +email = "{{ toolkit_author_email }}" +{% endif -%} +{% endif %} + +[project.optional-dependencies] +dev = [ + "arcade-ai[evals]>={{ arcade_ai_min_version }},<{{ arcade_ai_max_version }}", + "arcade-serve>={{ arcade_serve_min_version }},<{{ arcade_serve_max_version }}", + "pytest>=8.3.0,<8.4.0", + "pytest-cov>=4.0.0,<4.1.0", + "pytest-mock>=3.11.1,<3.12.0", + "pytest-asyncio>=0.24.0,<0.25.0", + "mypy>=1.5.1,<1.6.0", + "pre-commit>=3.4.0,<3.5.0", + "tox>=4.11.1,<4.12.0", + "ruff>=0.7.4,<0.8.0", +] + +# Use local path sources for arcade libs when working locally +[tool.uv.sources] +arcade-ai = { path = "../../", editable = true } +arcade-serve = { path = "../../libs/arcade-serve/", editable = true } +arcade-tdk = { path = "../../libs/arcade-tdk/", editable = true } + + +[tool.mypy] +files = [ "{{ package_name }}/**/*.py",] +python_version = "3.10" +disallow_untyped_defs = "True" +disallow_any_unimported = "True" +no_implicit_optional = "True" +check_untyped_defs = "True" +warn_return_any = "True" +warn_unused_ignores = "True" +show_error_codes = "True" +ignore_missing_imports = "True" + +[tool.pytest.ini_options] +testpaths = [ "tests",] + +[tool.coverage.report] +skip_empty = true + +[tool.hatch.build.targets.wheel] +packages = [ "{{ package_name }}",] + diff --git a/arcade/arcade/templates/{{ toolkit_name }}/tests/__init__.py b/libs/arcade-cli/arcade_cli/templates/{{ toolkit_name }}/tests/__init__.py similarity index 100% rename from arcade/arcade/templates/{{ toolkit_name }}/tests/__init__.py rename to libs/arcade-cli/arcade_cli/templates/{{ toolkit_name }}/tests/__init__.py diff --git a/arcade/arcade/templates/{{ toolkit_name }}/tests/test_{{ toolkit_name }}.py b/libs/arcade-cli/arcade_cli/templates/{{ toolkit_name }}/tests/test_{{ toolkit_name }}.py similarity index 84% rename from arcade/arcade/templates/{{ toolkit_name }}/tests/test_{{ toolkit_name }}.py rename to libs/arcade-cli/arcade_cli/templates/{{ toolkit_name }}/tests/test_{{ toolkit_name }}.py index 95d82df1..d702b229 100644 --- a/arcade/arcade/templates/{{ toolkit_name }}/tests/test_{{ toolkit_name }}.py +++ b/libs/arcade-cli/arcade_cli/templates/{{ toolkit_name }}/tests/test_{{ toolkit_name }}.py @@ -1,5 +1,5 @@ import pytest -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk.errors import ToolExecutionError from {{ package_name }}.tools.hello import say_hello diff --git a/arcade/arcade/templates/{{ toolkit_name }}/{{ package_name }}/__init__.py b/libs/arcade-cli/arcade_cli/templates/{{ toolkit_name }}/{{ package_name }}/__init__.py similarity index 100% rename from arcade/arcade/templates/{{ toolkit_name }}/{{ package_name }}/__init__.py rename to libs/arcade-cli/arcade_cli/templates/{{ toolkit_name }}/{{ package_name }}/__init__.py diff --git a/arcade/arcade/templates/{{ toolkit_name }}/{{ package_name }}/tools/__init__.py b/libs/arcade-cli/arcade_cli/templates/{{ toolkit_name }}/{{ package_name }}/tools/__init__.py similarity index 100% rename from arcade/arcade/templates/{{ toolkit_name }}/{{ package_name }}/tools/__init__.py rename to libs/arcade-cli/arcade_cli/templates/{{ toolkit_name }}/{{ package_name }}/tools/__init__.py diff --git a/arcade/arcade/templates/{{ toolkit_name }}/{{ package_name }}/tools/hello.py b/libs/arcade-cli/arcade_cli/templates/{{ toolkit_name }}/{{ package_name }}/tools/hello.py similarity index 85% rename from arcade/arcade/templates/{{ toolkit_name }}/{{ package_name }}/tools/hello.py rename to libs/arcade-cli/arcade_cli/templates/{{ toolkit_name }}/{{ package_name }}/tools/hello.py index a69f77d5..55a9c192 100644 --- a/arcade/arcade/templates/{{ toolkit_name }}/{{ package_name }}/tools/hello.py +++ b/libs/arcade-cli/arcade_cli/templates/{{ toolkit_name }}/{{ package_name }}/tools/hello.py @@ -1,6 +1,6 @@ from typing import Annotated -from arcade.sdk import tool +from arcade_tdk import tool @tool @@ -8,4 +8,3 @@ def say_hello(name: Annotated[str, "The name of the person to greet"]) -> str: """Say a greeting!""" return "Hello, " + name + "!" - diff --git a/arcade/arcade/cli/utils.py b/libs/arcade-cli/arcade_cli/utils.py similarity index 94% rename from arcade/arcade/cli/utils.py rename to libs/arcade-cli/arcade_cli/utils.py index 44dbdb41..99f3a254 100644 --- a/arcade/arcade/cli/utils.py +++ b/libs/arcade-cli/arcade_cli/utils.py @@ -6,6 +6,7 @@ import webbrowser from dataclasses import dataclass from datetime import datetime from enum import Enum +from importlib import metadata from pathlib import Path from textwrap import dedent from typing import Any, Callable, Union, cast @@ -13,6 +14,10 @@ from urllib.parse import urlencode, urlparse import idna import typer +from arcade_core import ToolCatalog, Toolkit +from arcade_core.config_model import Config +from arcade_core.errors import ToolkitLoadError +from arcade_core.schema import ToolDefinition from arcadepy import NOT_GIVEN, APIConnectionError, APIStatusError, APITimeoutError, Arcade from arcadepy.types import AuthorizationResponse from openai import OpenAI, Stream @@ -27,11 +32,7 @@ from rich.text import Text from typer.core import TyperGroup from typer.models import Context -from arcade.cli.constants import LOCALHOST -from arcade.core.config_model import Config -from arcade.core.errors import ToolkitLoadError -from arcade.core.schema import ToolDefinition -from arcade.sdk import ToolCatalog, Toolkit +from arcade_cli.constants import LOCALHOST console = Console() @@ -300,7 +301,7 @@ def validate_and_get_config( """ Validates the configuration, user, and returns the Config object """ - from arcade.core.config import config + from arcade_core.config import config if validate_api and (not config.api or not config.api.key): console.print( @@ -664,8 +665,8 @@ def version_callback(value: bool) -> None: Prints the version of Arcade and exit. """ if value: - version = importlib.import_module("arcade").__version__ - console.print(f"[bold]Arcade[/bold] (version {version})") + version = metadata.version("arcade-ai") + console.print(f"[bold]Arcade CLI[/bold] (version {version})") exit() @@ -751,3 +752,30 @@ def load_dotenv(path: str | Path, *, override: bool = False) -> dict[str, str]: loaded[k] = v return loaded + + +def require_dependency( + package_name: str, + command_name: str, + install_command: str, +) -> None: + """ + Display a helpful error message if the required dependency is missing. + + Args: + package_name: The name of the package to import (e.g., 'arcade_serve') + command_name: The command that requires the package (e.g., 'serve') + install_command: The command to install the package (e.g., "pip install 'arcade-ai[evals]'") + """ + try: + importlib.import_module(package_name.replace("-", "_")) + except ImportError: + console.print( + f"โŒ The '{package_name}' package is required to run the '{command_name}' command but is not installed.", + style="bold red", + ) + console.print( + f"To install it, run the following command:\n* [green]{install_command}[/green]", + style="bold", + ) + raise typer.Exit(code=1) diff --git a/arcade/arcade/cli/worker.py b/libs/arcade-cli/arcade_cli/worker.py similarity index 99% rename from arcade/arcade/cli/worker.py rename to libs/arcade-cli/arcade_cli/worker.py index f0537387..1fbe3645 100644 --- a/arcade/arcade/cli/worker.py +++ b/libs/arcade-cli/arcade_cli/worker.py @@ -4,11 +4,11 @@ from arcadepy import Arcade, NotFoundError from rich.console import Console from rich.table import Table -from arcade.cli.constants import ( +from arcade_cli.constants import ( PROD_CLOUD_HOST, PROD_ENGINE_HOST, ) -from arcade.cli.utils import ( +from arcade_cli.utils import ( OrderCommands, compute_base_url, validate_and_get_config, diff --git a/arcade/run_cli.py b/libs/arcade-cli/run_cli.py similarity index 88% rename from arcade/run_cli.py rename to libs/arcade-cli/run_cli.py index ce814d27..80bc37c3 100644 --- a/arcade/run_cli.py +++ b/libs/arcade-cli/run_cli.py @@ -1,6 +1,6 @@ import sys -from arcade.cli.main import cli +from arcade_cli.main import cli if __name__ == "__main__": # Supports attaching debugger to cli. Run from ../.vscode/launch.json. diff --git a/libs/arcade-core/README.md b/libs/arcade-core/README.md new file mode 100644 index 00000000..e92ac2af --- /dev/null +++ b/libs/arcade-core/README.md @@ -0,0 +1,39 @@ +# Arcade Core + +Core library for the Arcade platform providing foundational components and utilities. + +## Overview + +Arcade Core provides the essential building blocks for the Arcade platform: + +- **Tool Catalog & Toolkit Management**: Core classes for managing and organizing tools +- **Configuration & Schema Handling**: Configuration management and validation +- **Authentication & Authorization**: Auth providers and security utilities +- **Error Handling**: Comprehensive error types and handling +- **Telemetry & Observability**: Monitoring and tracing capabilities +- **Utilities**: Common helper functions and validators + +## Installation + +```bash +pip install arcade-core +``` + +## Usage + +```python +from arcade_core import ToolCatalog, Toolkit, ArcadeConfig + +# Create a tool catalog +catalog = ToolCatalog() + +# Load a toolkit +toolkit = Toolkit.from_directory("path/to/toolkit") + +# Configure Arcade +config = ArcadeConfig.from_file("config.yaml") +``` + +## License + +MIT License - see LICENSE file for details. diff --git a/libs/arcade-core/arcade_core/__init__.py b/libs/arcade-core/arcade_core/__init__.py new file mode 100644 index 00000000..2dc5cc7f --- /dev/null +++ b/libs/arcade-core/arcade_core/__init__.py @@ -0,0 +1,2 @@ +from .catalog import ToolCatalog as ToolCatalog +from .toolkit import Toolkit as Toolkit diff --git a/arcade/arcade/core/annotations.py b/libs/arcade-core/arcade_core/annotations.py similarity index 100% rename from arcade/arcade/core/annotations.py rename to libs/arcade-core/arcade_core/annotations.py diff --git a/arcade/arcade/core/auth.py b/libs/arcade-core/arcade_core/auth.py similarity index 100% rename from arcade/arcade/core/auth.py rename to libs/arcade-core/arcade_core/auth.py diff --git a/arcade/arcade/core/catalog.py b/libs/arcade-core/arcade_core/catalog.py similarity index 99% rename from arcade/arcade/core/catalog.py rename to libs/arcade-core/arcade_core/catalog.py index 15e97d00..5fe38bb9 100644 --- a/arcade/arcade/core/catalog.py +++ b/libs/arcade-core/arcade_core/catalog.py @@ -26,10 +26,10 @@ from pydantic import BaseModel, Field, create_model from pydantic.fields import FieldInfo from pydantic_core import PydanticUndefined -from arcade.core.annotations import Inferrable -from arcade.core.auth import OAuth2, ToolAuthorization -from arcade.core.errors import ToolDefinitionError -from arcade.core.schema import ( +from arcade_core.annotations import Inferrable +from arcade_core.auth import OAuth2, ToolAuthorization +from arcade_core.errors import ToolDefinitionError +from arcade_core.schema import ( TOOL_NAME_SEPARATOR, FullyQualifiedName, InputParameter, @@ -46,8 +46,8 @@ from arcade.core.schema import ( ToolSecretRequirement, ValueSchema, ) -from arcade.core.toolkit import Toolkit -from arcade.core.utils import ( +from arcade_core.toolkit import Toolkit +from arcade_core.utils import ( does_function_return_value, first_or_none, is_strict_optional, diff --git a/arcade/arcade/core/config.py b/libs/arcade-core/arcade_core/config.py similarity index 92% rename from arcade/arcade/core/config.py rename to libs/arcade-core/arcade_core/config.py index d77edfba..30f1ea9b 100644 --- a/arcade/arcade/core/config.py +++ b/libs/arcade-core/arcade_core/config.py @@ -1,6 +1,6 @@ from functools import lru_cache -from arcade.core.config_model import Config +from arcade_core.config_model import Config @lru_cache(maxsize=1) diff --git a/arcade/arcade/core/config_model.py b/libs/arcade-core/arcade_core/config_model.py similarity index 100% rename from arcade/arcade/core/config_model.py rename to libs/arcade-core/arcade_core/config_model.py diff --git a/arcade/arcade/core/errors.py b/libs/arcade-core/arcade_core/errors.py similarity index 100% rename from arcade/arcade/core/errors.py rename to libs/arcade-core/arcade_core/errors.py diff --git a/arcade/arcade/core/executor.py b/libs/arcade-core/arcade_core/executor.py similarity index 96% rename from arcade/arcade/core/executor.py rename to libs/arcade-core/arcade_core/executor.py index 0bc38bde..58cf23d0 100644 --- a/arcade/arcade/core/executor.py +++ b/libs/arcade-core/arcade_core/executor.py @@ -4,15 +4,15 @@ from typing import Any, Callable from pydantic import BaseModel, ValidationError -from arcade.core.errors import ( +from arcade_core.errors import ( RetryableToolError, ToolInputError, ToolOutputError, ToolRuntimeError, ToolSerializationError, ) -from arcade.core.output import output_factory -from arcade.core.schema import ToolCallLog, ToolCallOutput, ToolContext, ToolDefinition +from arcade_core.output import output_factory +from arcade_core.schema import ToolCallLog, ToolCallOutput, ToolContext, ToolDefinition class ToolExecutor: diff --git a/arcade/arcade/core/output.py b/libs/arcade-core/arcade_core/output.py similarity index 93% rename from arcade/arcade/core/output.py rename to libs/arcade-core/arcade_core/output.py index ba8c56e3..bfd241b0 100644 --- a/arcade/arcade/core/output.py +++ b/libs/arcade-core/arcade_core/output.py @@ -1,7 +1,7 @@ from typing import TypeVar -from arcade.core.schema import ToolCallError, ToolCallLog, ToolCallOutput -from arcade.core.utils import coerce_empty_list_to_none +from arcade_core.schema import ToolCallError, ToolCallLog, ToolCallOutput +from arcade_core.utils import coerce_empty_list_to_none T = TypeVar("T") diff --git a/arcade/arcade/core/parse.py b/libs/arcade-core/arcade_core/parse.py similarity index 100% rename from arcade/arcade/core/parse.py rename to libs/arcade-core/arcade_core/parse.py diff --git a/arcade/arcade/py.typed b/libs/arcade-core/arcade_core/py.typed similarity index 100% rename from arcade/arcade/py.typed rename to libs/arcade-core/arcade_core/py.typed diff --git a/arcade/arcade/core/schema.py b/libs/arcade-core/arcade_core/schema.py similarity index 100% rename from arcade/arcade/core/schema.py rename to libs/arcade-core/arcade_core/schema.py diff --git a/arcade/arcade/core/telemetry.py b/libs/arcade-core/arcade_core/telemetry.py similarity index 100% rename from arcade/arcade/core/telemetry.py rename to libs/arcade-core/arcade_core/telemetry.py diff --git a/arcade/arcade/core/toolkit.py b/libs/arcade-core/arcade_core/toolkit.py similarity index 98% rename from arcade/arcade/core/toolkit.py rename to libs/arcade-core/arcade_core/toolkit.py index 93129a1e..92aee22d 100644 --- a/arcade/arcade/core/toolkit.py +++ b/libs/arcade-core/arcade_core/toolkit.py @@ -8,8 +8,8 @@ from pathlib import Path from pydantic import BaseModel, ConfigDict, field_validator -from arcade.core.errors import ToolkitLoadError -from arcade.core.parse import get_tools_from_file +from arcade_core.errors import ToolkitLoadError +from arcade_core.parse import get_tools_from_file logger = logging.getLogger(__name__) diff --git a/arcade/arcade/core/utils.py b/libs/arcade-core/arcade_core/utils.py similarity index 100% rename from arcade/arcade/core/utils.py rename to libs/arcade-core/arcade_core/utils.py diff --git a/arcade/arcade/core/version.py b/libs/arcade-core/arcade_core/version.py similarity index 100% rename from arcade/arcade/core/version.py rename to libs/arcade-core/arcade_core/version.py diff --git a/libs/arcade-core/pyproject.toml b/libs/arcade-core/pyproject.toml new file mode 100644 index 00000000..8540cda5 --- /dev/null +++ b/libs/arcade-core/pyproject.toml @@ -0,0 +1,65 @@ +[project] +name = "arcade-core" +version = "2.0.0" +description = "Arcade Core - Core library for Arcade platform" +readme = "README.md" +license = {text = "MIT"} +authors = [ + {name = "Arcade", email = "dev@arcade.dev"}, +] +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", +] +requires-python = ">=3.10" +dependencies = [ + "pydantic>=2.7.0", + "pyyaml>=6.0", + "loguru>=0.7.0", + "pyjwt>=2.8.0", + "toml>=0.10.2", + "packaging>=24.1", + "types-python-dateutil==2.9.0.20241003", + "types-pytz==2024.2.0.20241003", + "types-toml==0.10.8.20240310", + "opentelemetry-instrumentation-fastapi==0.49b2", + "opentelemetry-exporter-otlp-proto-http==1.28.2", + "opentelemetry-exporter-otlp-proto-common==1.28.2", +] + +[project.optional-dependencies] +dev = [ + "pytest>=8.1.2", + "pytest-cov>=4.0.0", + "mypy>=1.5.1", + "pre-commit>=3.4.0", + "pytest-asyncio>=0.23.7", + "types-pytz>=2024.1", + "types-python-dateutil>=2.8.2", + "types-PyYAML>=6.0.0", +] + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.build.targets.wheel] +packages = ["arcade_core"] + +[tool.mypy] +files = ["arcade_core"] +python_version = "3.10" +disallow_untyped_defs = true +disallow_any_unimported = true +no_implicit_optional = true +check_untyped_defs = true +warn_return_any = true +warn_unused_ignores = true +show_error_codes = true +ignore_missing_imports = true diff --git a/libs/arcade-evals/README.md b/libs/arcade-evals/README.md new file mode 100644 index 00000000..4d8aa48d --- /dev/null +++ b/libs/arcade-evals/README.md @@ -0,0 +1,86 @@ +# Arcade Evals + +Evaluation toolkit for testing Arcade tools. + +## Overview + +Arcade Evals provides comprehensive evaluation capabilities for Arcade tools: + +- **Evaluation Framework**: Cases, suites, and rubrics for systematic testing +- **Critics**: Different types of comparisons (binary, numeric, similarity, datetime) +- **Tool Evaluation**: Decorators and utilities for evaluating tool performance +- **Result Analysis**: Comprehensive evaluation results and reporting + +## Installation + +```bash +pip install 'arcade-ai[evals]' +``` + +## Usage + +### Basic Evaluation + +```python +from arcade_evals import EvalCase, EvalSuite, tool_eval + +# Create evaluation cases +case1 = EvalCase( + input={"query": "What is 2+2?"}, + expected_output="4" +) + +case2 = EvalCase( + input={"query": "What is the capital of France?"}, + expected_output="Paris" +) + +# Create evaluation suite +suite = EvalSuite(cases=[case1, case2]) + +# Evaluate a tool +@tool_eval(suite) +def my_calculator(query: str) -> str: + # Tool implementation + return "4" if "2+2" in query else "Unknown" +``` + +### Using Critics + +```python +from arcade_evals import NumericCritic, SimilarityCritic + +# Numeric comparison +numeric_critic = NumericCritic(tolerance=0.1) +result = numeric_critic.evaluate(expected=10.0, actual=10.05) + +# Similarity comparison +similarity_critic = SimilarityCritic(threshold=0.8) +result = similarity_critic.evaluate( + expected="The capital of France is Paris", + actual="Paris is the capital of France" +) +``` + +### Advanced Evaluation + +```python +from arcade_evals import EvalRubric, ExpectedToolCall + +# Create rubric with tool calls +rubric = EvalRubric( + expected_tool_calls=[ + ExpectedToolCall( + tool_name="calculator", + parameters={"operation": "add", "a": 2, "b": 2} + ) + ] +) + +# Evaluate with rubric +suite = EvalSuite(cases=[case1], rubric=rubric) +``` + +## License + +MIT License - see LICENSE file for details. diff --git a/arcade/arcade/sdk/eval/__init__.py b/libs/arcade-evals/arcade_evals/__init__.py similarity index 100% rename from arcade/arcade/sdk/eval/__init__.py rename to libs/arcade-evals/arcade_evals/__init__.py diff --git a/arcade/arcade/sdk/eval/critic.py b/libs/arcade-evals/arcade_evals/critic.py similarity index 98% rename from arcade/arcade/sdk/eval/critic.py rename to libs/arcade-evals/arcade_evals/critic.py index e75a27d5..b4f5c1d6 100644 --- a/arcade/arcade/sdk/eval/critic.py +++ b/libs/arcade-evals/arcade_evals/critic.py @@ -6,7 +6,7 @@ from typing import Any, ClassVar import pytz from dateutil import parser -from arcade.sdk.errors import WeightError +from arcade_evals.errors import WeightError @dataclass @@ -214,7 +214,7 @@ class SimilarityCritic(Critic): from sklearn.metrics.pairwise import cosine_similarity except ImportError: raise ImportError( - "Use `pip install 'arcade-ai[evals]'` to install the required dependencies for similarity metrics." + "Use `pip install 'arcade-evals` to install the required dependencies for similarity metrics." ) vectorizer = TfidfVectorizer() tfidf_matrix = vectorizer.fit_transform([expected, actual]) @@ -227,7 +227,6 @@ class SimilarityCritic(Critic): } -@dataclass @dataclass class DatetimeCritic(Critic): """ diff --git a/libs/arcade-evals/arcade_evals/errors.py b/libs/arcade-evals/arcade_evals/errors.py new file mode 100644 index 00000000..68261029 --- /dev/null +++ b/libs/arcade-evals/arcade_evals/errors.py @@ -0,0 +1,12 @@ +__all__ = [ + "EvalError", + "WeightError", +] + + +class EvalError(Exception): + """Base class for all evaluation errors.""" + + +class WeightError(EvalError): + """Raised when the critic weights do not abide by evaluation weight constraints.""" diff --git a/arcade/arcade/sdk/eval/eval.py b/libs/arcade-evals/arcade_evals/eval.py similarity index 98% rename from arcade/arcade/sdk/eval/eval.py rename to libs/arcade-evals/arcade_evals/eval.py index 1f16b41f..e8e126db 100644 --- a/arcade/arcade/sdk/eval/eval.py +++ b/libs/arcade-evals/arcade_evals/eval.py @@ -5,25 +5,19 @@ import json from dataclasses import dataclass, field from typing import TYPE_CHECKING, Any, Callable -from arcade.core.config_model import Config -from arcade.core.schema import TOOL_NAME_SEPARATOR - -try: - import numpy as np - from scipy.optimize import linear_sum_assignment -except ImportError: - raise ImportError( - "Use `pip install 'arcade-ai[evals]'` to install the required dependencies for evaluation." - ) - +import numpy as np +from arcade_core.config_model import Config +from arcade_core.schema import TOOL_NAME_SEPARATOR from openai import AsyncOpenAI +from scipy.optimize import linear_sum_assignment -from arcade.sdk.errors import WeightError -from arcade.sdk.eval.critic import NoneCritic +from arcade_evals.critic import NoneCritic +from arcade_evals.errors import WeightError if TYPE_CHECKING: - from arcade.sdk import ToolCatalog - from arcade.sdk.eval.critic import Critic + from arcade_core import ToolCatalog + + from arcade_evals.critic import Critic @dataclass diff --git a/arcade/arcade/worker/__init__.py b/libs/arcade-evals/arcade_evals/py.typed similarity index 100% rename from arcade/arcade/worker/__init__.py rename to libs/arcade-evals/arcade_evals/py.typed diff --git a/libs/arcade-serve/README.md b/libs/arcade-serve/README.md new file mode 100644 index 00000000..08402807 --- /dev/null +++ b/libs/arcade-serve/README.md @@ -0,0 +1,70 @@ +# Arcade Serve + +Serving infrastructure for Arcade tools and workers. + +## Overview + +Arcade Serve provides the infrastructure for serving Arcade tools: + +- **FastAPI Worker**: High-performance FastAPI-based worker implementation +- **MCP Server**: Model Context Protocol server for tool integration +- **Core Abstractions**: Base worker classes and components +- **Authentication**: Auth utilities and routing +- **Runtime Management**: Tool execution and lifecycle management + +## Installation + +```bash +pip install arcade-serve +``` + +## Usage + +### FastAPI Worker + +```python +from arcade_serve import FastAPIWorker + +# Create a FastAPI worker +worker = FastAPIWorker() + +# Add tools to the worker +worker.add_toolkit("path/to/toolkit") + +# Start the server +worker.start(host="0.0.0.0", port=8000) +``` + +### MCP Server + +```python +from arcade_serve import StdioServer + +# Create an MCP server +server = StdioServer() + +# Add tools +server.add_toolkit("path/to/toolkit") + +# Start the server +server.run() +``` + +### Custom Worker + +```python +from arcade_serve import BaseWorker, WorkerComponent + +class MyWorker(BaseWorker): + def __init__(self): + super().__init__() + self.add_component(MyCustomComponent()) + + async def handle_request(self, request): + # Custom request handling + return await super().handle_request(request) +``` + +## License + +MIT License - see LICENSE file for details. diff --git a/arcade/arcade/worker/core/__init__.py b/libs/arcade-serve/arcade_serve/__init__.py similarity index 100% rename from arcade/arcade/worker/core/__init__.py rename to libs/arcade-serve/arcade_serve/__init__.py diff --git a/arcade/tests/__init__.py b/libs/arcade-serve/arcade_serve/core/__init__.py similarity index 100% rename from arcade/tests/__init__.py rename to libs/arcade-serve/arcade_serve/core/__init__.py diff --git a/arcade/arcade/worker/core/auth.py b/libs/arcade-serve/arcade_serve/core/auth.py similarity index 100% rename from arcade/arcade/worker/core/auth.py rename to libs/arcade-serve/arcade_serve/core/auth.py diff --git a/arcade/arcade/worker/core/base.py b/libs/arcade-serve/arcade_serve/core/base.py similarity index 96% rename from arcade/arcade/worker/core/base.py rename to libs/arcade-serve/arcade_serve/core/base.py index 4416c24b..e205416a 100644 --- a/arcade/arcade/worker/core/base.py +++ b/libs/arcade-serve/arcade_serve/core/base.py @@ -4,18 +4,18 @@ import time from datetime import datetime from typing import Any, Callable, ClassVar -from opentelemetry import trace -from opentelemetry.metrics import Meter - -from arcade.core.catalog import ToolCatalog, Toolkit -from arcade.core.executor import ToolExecutor -from arcade.core.schema import ( +from arcade_core.catalog import ToolCatalog, Toolkit +from arcade_core.executor import ToolExecutor +from arcade_core.schema import ( ToolCallRequest, ToolCallResponse, ToolDefinition, ) -from arcade.worker.core.common import Router, Worker -from arcade.worker.core.components import ( +from opentelemetry import trace +from opentelemetry.metrics import Meter + +from arcade_serve.core.common import Router, Worker +from arcade_serve.core.components import ( CallToolComponent, CatalogComponent, HealthCheckComponent, diff --git a/arcade/arcade/worker/core/common.py b/libs/arcade-serve/arcade_serve/core/common.py similarity index 97% rename from arcade/arcade/worker/core/common.py rename to libs/arcade-serve/arcade_serve/core/common.py index 85a73b48..d165357c 100644 --- a/arcade/arcade/worker/core/common.py +++ b/libs/arcade-serve/arcade_serve/core/common.py @@ -1,10 +1,9 @@ from abc import ABC, abstractmethod from typing import Any, Callable +from arcade_core.schema import ToolCallRequest, ToolCallResponse, ToolDefinition from pydantic import BaseModel -from arcade.core.schema import ToolCallRequest, ToolCallResponse, ToolDefinition - CatalogResponse = list[ToolDefinition] HealthCheckResponse = dict[str, str] JSONResponse = dict[str, Any] diff --git a/arcade/arcade/worker/core/components.py b/libs/arcade-serve/arcade_serve/core/components.py similarity index 98% rename from arcade/arcade/worker/core/components.py rename to libs/arcade-serve/arcade_serve/core/components.py index 490954a6..ae9274e1 100644 --- a/arcade/arcade/worker/core/components.py +++ b/libs/arcade-serve/arcade_serve/core/components.py @@ -1,6 +1,6 @@ from opentelemetry import trace -from arcade.worker.core.common import ( +from arcade_serve.core.common import ( CatalogResponse, HealthCheckResponse, RequestData, diff --git a/arcade/arcade/worker/fastapi/__init__.py b/libs/arcade-serve/arcade_serve/fastapi/__init__.py similarity index 100% rename from arcade/arcade/worker/fastapi/__init__.py rename to libs/arcade-serve/arcade_serve/fastapi/__init__.py diff --git a/arcade/arcade/worker/fastapi/auth.py b/libs/arcade-serve/arcade_serve/fastapi/auth.py similarity index 90% rename from arcade/arcade/worker/fastapi/auth.py rename to libs/arcade-serve/arcade_serve/fastapi/auth.py index 041752e8..c75b7e8d 100644 --- a/arcade/arcade/worker/fastapi/auth.py +++ b/libs/arcade-serve/arcade_serve/fastapi/auth.py @@ -1,7 +1,7 @@ from fastapi import HTTPException from fastapi.security import HTTPAuthorizationCredentials -from arcade.worker.core.auth import validate_engine_token +from arcade_serve.core.auth import validate_engine_token # Dependency function to validate JWT diff --git a/arcade/arcade/worker/fastapi/worker.py b/libs/arcade-serve/arcade_serve/fastapi/worker.py similarity index 93% rename from arcade/arcade/worker/fastapi/worker.py rename to libs/arcade-serve/arcade_serve/fastapi/worker.py index c455941e..f7d53a91 100644 --- a/arcade/arcade/worker/fastapi/worker.py +++ b/libs/arcade-serve/arcade_serve/fastapi/worker.py @@ -5,13 +5,13 @@ from fastapi import Depends, FastAPI, Request from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer from opentelemetry.metrics import Meter -from arcade.worker.core.base import ( +from arcade_serve.core.base import ( BaseWorker, Router, ) -from arcade.worker.core.common import RequestData, ResponseData, WorkerComponent -from arcade.worker.fastapi.auth import validate_engine_request -from arcade.worker.utils import is_async_callable +from arcade_serve.core.common import RequestData, ResponseData, WorkerComponent +from arcade_serve.fastapi.auth import validate_engine_request +from arcade_serve.utils import is_async_callable class FastAPIWorker(BaseWorker): diff --git a/arcade/arcade/worker/mcp/__init__.py b/libs/arcade-serve/arcade_serve/mcp/__init__.py similarity index 65% rename from arcade/arcade/worker/mcp/__init__.py rename to libs/arcade-serve/arcade_serve/mcp/__init__.py index 9761f4f2..979feda4 100644 --- a/arcade/arcade/worker/mcp/__init__.py +++ b/libs/arcade-serve/arcade_serve/mcp/__init__.py @@ -2,6 +2,6 @@ MCP (Model Context Protocol) support for Arcade workers. """ -from arcade.worker.mcp.stdio import StdioServer +from arcade_serve.mcp.stdio import StdioServer __all__ = ["StdioServer"] diff --git a/arcade/arcade/worker/mcp/convert.py b/libs/arcade-serve/arcade_serve/mcp/convert.py similarity index 99% rename from arcade/arcade/worker/mcp/convert.py rename to libs/arcade-serve/arcade_serve/mcp/convert.py index 59e10642..9ea7d9d9 100644 --- a/arcade/arcade/worker/mcp/convert.py +++ b/libs/arcade-serve/arcade_serve/mcp/convert.py @@ -3,7 +3,7 @@ import logging from enum import Enum from typing import Any -from arcade.core.catalog import MaterializedTool +from arcade_core.catalog import MaterializedTool # Type aliases for MCP types MCPTool = dict[str, Any] diff --git a/arcade/arcade/worker/mcp/logging.py b/libs/arcade-serve/arcade_serve/mcp/logging.py similarity index 99% rename from arcade/arcade/worker/mcp/logging.py rename to libs/arcade-serve/arcade_serve/mcp/logging.py index 0299d5e1..667212bf 100644 --- a/arcade/arcade/worker/mcp/logging.py +++ b/libs/arcade-serve/arcade_serve/mcp/logging.py @@ -4,7 +4,7 @@ import sys import time from typing import Any -from arcade.worker.mcp.types import ( +from arcade_serve.mcp.types import ( JSONRPCError, JSONRPCRequest, JSONRPCResponse, diff --git a/arcade/arcade/worker/mcp/message_processor.py b/libs/arcade-serve/arcade_serve/mcp/message_processor.py similarity index 97% rename from arcade/arcade/worker/mcp/message_processor.py rename to libs/arcade-serve/arcade_serve/mcp/message_processor.py index a2199bee..96a1924c 100644 --- a/arcade/arcade/worker/mcp/message_processor.py +++ b/libs/arcade-serve/arcade_serve/mcp/message_processor.py @@ -3,7 +3,7 @@ import json import logging from typing import Any, Callable, TypeVar -from arcade.worker.mcp.types import InitializeRequest, JSONRPCRequest, MCPMessage +from arcade_serve.mcp.types import InitializeRequest, JSONRPCRequest, MCPMessage logger = logging.getLogger("arcade.mcp") diff --git a/arcade/arcade/worker/mcp/server.py b/libs/arcade-serve/arcade_serve/mcp/server.py similarity index 97% rename from arcade/arcade/worker/mcp/server.py rename to libs/arcade-serve/arcade_serve/mcp/server.py index ae255b14..43fdf116 100644 --- a/arcade/arcade/worker/mcp/server.py +++ b/libs/arcade-serve/arcade_serve/mcp/server.py @@ -5,17 +5,17 @@ import uuid from enum import Enum from typing import Any, Callable, Union +from arcade_core.catalog import MaterializedTool, ToolCatalog +from arcade_core.executor import ToolExecutor +from arcade_core.schema import ToolAuthorizationContext, ToolContext from arcadepy import ArcadeError, AsyncArcade from arcadepy.types.auth_authorize_params import AuthRequirement, AuthRequirementOauth2 from arcadepy.types.shared import AuthorizationResponse -from arcade.core.catalog import MaterializedTool, ToolCatalog -from arcade.core.executor import ToolExecutor -from arcade.core.schema import ToolAuthorizationContext, ToolContext -from arcade.worker.mcp.convert import convert_to_mcp_content, create_mcp_tool -from arcade.worker.mcp.logging import create_mcp_logging_middleware -from arcade.worker.mcp.message_processor import MCPMessageProcessor, create_message_processor -from arcade.worker.mcp.types import ( +from arcade_serve.mcp.convert import convert_to_mcp_content, create_mcp_tool +from arcade_serve.mcp.logging import create_mcp_logging_middleware +from arcade_serve.mcp.message_processor import MCPMessageProcessor, create_message_processor +from arcade_serve.mcp.types import ( CallToolRequest, CallToolResponse, CallToolResult, @@ -158,7 +158,7 @@ class MCPServer: A user ID string """ try: - from arcade.core.config import config + from arcade_core.config import config # Prefer config.user.email if available if config.user and config.user.email: diff --git a/arcade/arcade/worker/mcp/stdio.py b/libs/arcade-serve/arcade_serve/mcp/stdio.py similarity index 99% rename from arcade/arcade/worker/mcp/stdio.py rename to libs/arcade-serve/arcade_serve/mcp/stdio.py index 4c637005..98357e39 100644 --- a/arcade/arcade/worker/mcp/stdio.py +++ b/libs/arcade-serve/arcade_serve/mcp/stdio.py @@ -10,7 +10,7 @@ from typing import TYPE_CHECKING, Any, TypeVar if TYPE_CHECKING: pass -from arcade.worker.mcp.server import MCPServer +from arcade_serve.mcp.server import MCPServer logger = logging.getLogger("arcade.mcp") diff --git a/arcade/arcade/worker/mcp/types.py b/libs/arcade-serve/arcade_serve/mcp/types.py similarity index 100% rename from arcade/arcade/worker/mcp/types.py rename to libs/arcade-serve/arcade_serve/mcp/types.py diff --git a/arcade/poetry.toml b/libs/arcade-serve/arcade_serve/py.typed similarity index 100% rename from arcade/poetry.toml rename to libs/arcade-serve/arcade_serve/py.typed diff --git a/arcade/arcade/worker/utils.py b/libs/arcade-serve/arcade_serve/utils.py similarity index 100% rename from arcade/arcade/worker/utils.py rename to libs/arcade-serve/arcade_serve/utils.py diff --git a/libs/arcade-serve/pyproject.toml b/libs/arcade-serve/pyproject.toml new file mode 100644 index 00000000..721e77a9 --- /dev/null +++ b/libs/arcade-serve/pyproject.toml @@ -0,0 +1,54 @@ +[project] +name = "arcade-serve" +version = "2.0.0" +description = "Arcade Serve - Serving infrastructure for Arcade tools and workers" +readme = "README.md" +license = {text = "MIT"} +authors = [ + {name = "Arcade", email = "dev@arcade.dev"}, +] +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", +] +requires-python = ">=3.10" +dependencies = [ + "arcade-core>=0.1.0", + "fastapi>=0.115.3", + "uvicorn>=0.30.0", + "watchfiles>=1.0.5", +] + +[project.optional-dependencies] +dev = [ + "pytest>=8.1.2", + "pytest-cov>=4.0.0", + "mypy>=1.5.1", + "pre-commit>=3.4.0", + "pytest-asyncio>=0.23.7", +] + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.build.targets.wheel] +packages = ["arcade_serve"] + +[tool.mypy] +files = ["arcade_serve"] +python_version = "3.10" +disallow_untyped_defs = true +disallow_any_unimported = true +no_implicit_optional = true +check_untyped_defs = true +warn_return_any = true +warn_unused_ignores = true +show_error_codes = true +ignore_missing_imports = true diff --git a/libs/arcade-tdk/README.md b/libs/arcade-tdk/README.md new file mode 100644 index 00000000..abdd705b --- /dev/null +++ b/libs/arcade-tdk/README.md @@ -0,0 +1,58 @@ +# Arcade TDK (Toolkit Development Kit) + +Toolkit Development Kit for building and testing Arcade tools. + +## Overview + +Arcade TDK provides the essential tools and utilities for building Arcade tools: + +- **Tool Decorator**: Simple `@tool` decorator for creating Arcade tools +- **Authentication**: Auth providers and helpers for tool security +- **Annotations**: Type annotations and parameter validation +- **Core Integration**: Seamless integration with arcade-core components + +## Installation + +```bash +pip install arcade-tdk +``` + +## Usage + +```python +from typing import Annotated + +from arcade_tdk import tool + +@tool +def hello_world(name: Annotated[str, "The name of the person to greet"]) -> str: + """Say hello to someone.""" + return f"Hello, {name}!" + +# The tool is automatically registered and available for use +``` + +## Advanced Usage + +```python +from typing import Annotated + +from arcade_tdk import tool, ToolCatalog, Toolkit + +# Create tools with more complex parameters +@tool +def calculate_sum(numbers: Annotated[list[float], "The numbers to sum"]) -> float: + """Calculate the sum of a list of numbers.""" + return sum(numbers) + +# Access the tool catalog +catalog = ToolCatalog() +tools = catalog.get_all_tools() + +# Work with toolkits +toolkit = Toolkit.from_directory("my_toolkit") +``` + +## License + +MIT License - see LICENSE file for details. diff --git a/libs/arcade-tdk/arcade_tdk/__init__.py b/libs/arcade-tdk/arcade_tdk/__init__.py new file mode 100644 index 00000000..946cebf1 --- /dev/null +++ b/libs/arcade-tdk/arcade_tdk/__init__.py @@ -0,0 +1,22 @@ +from arcade_core.catalog import ToolCatalog +from arcade_core.schema import ( + ToolAuthorizationContext, + ToolContext, + ToolMetadataItem, + ToolMetadataKey, + ToolSecretItem, +) +from arcade_core.toolkit import Toolkit + +from arcade_tdk.tool import tool + +__all__ = [ + "ToolAuthorizationContext", + "ToolCatalog", + "ToolContext", + "ToolMetadataItem", + "ToolMetadataKey", + "ToolSecretItem", + "Toolkit", + "tool", +] diff --git a/libs/arcade-tdk/arcade_tdk/annotations/__init__.py b/libs/arcade-tdk/arcade_tdk/annotations/__init__.py new file mode 100644 index 00000000..77907f55 --- /dev/null +++ b/libs/arcade-tdk/arcade_tdk/annotations/__init__.py @@ -0,0 +1,3 @@ +from arcade_core.annotations import Inferrable + +__all__ = ["Inferrable"] diff --git a/arcade/arcade/sdk/auth/__init__.py b/libs/arcade-tdk/arcade_tdk/auth/__init__.py similarity index 94% rename from arcade/arcade/sdk/auth/__init__.py rename to libs/arcade-tdk/arcade_tdk/auth/__init__.py index 0239f8d6..4bcff723 100644 --- a/arcade/arcade/sdk/auth/__init__.py +++ b/libs/arcade-tdk/arcade_tdk/auth/__init__.py @@ -1,4 +1,4 @@ -from arcade.core.auth import ( +from arcade_core.auth import ( Asana, Atlassian, Discord, diff --git a/arcade/arcade/sdk/errors.py b/libs/arcade-tdk/arcade_tdk/errors.py similarity index 83% rename from arcade/arcade/sdk/errors.py rename to libs/arcade-tdk/arcade_tdk/errors.py index 58700acd..dc3444a0 100644 --- a/arcade/arcade/sdk/errors.py +++ b/libs/arcade-tdk/arcade_tdk/errors.py @@ -1,11 +1,11 @@ -from arcade.core.errors import RetryableToolError, ToolExecutionError, ToolRuntimeError +from arcade_core.errors import RetryableToolError, ToolExecutionError, ToolRuntimeError __all__ = [ - "SDKError", - "WeightError", - "ToolRuntimeError", - "ToolExecutionError", "RetryableToolError", + "SDKError", + "ToolExecutionError", + "ToolRuntimeError", + "WeightError", ] diff --git a/arcade/tests/deployment/test_files/invalid_toolkit/invalid_main.py b/libs/arcade-tdk/arcade_tdk/py.typed similarity index 100% rename from arcade/tests/deployment/test_files/invalid_toolkit/invalid_main.py rename to libs/arcade-tdk/arcade_tdk/py.typed diff --git a/arcade/arcade/sdk/tool.py b/libs/arcade-tdk/arcade_tdk/tool.py similarity index 94% rename from arcade/arcade/sdk/tool.py rename to libs/arcade-tdk/arcade_tdk/tool.py index 18bc1c69..5a42abcf 100644 --- a/arcade/arcade/sdk/tool.py +++ b/libs/arcade-tdk/arcade_tdk/tool.py @@ -2,9 +2,9 @@ import functools import inspect from typing import Any, Callable, TypeVar, Union -from arcade.core.utils import snake_to_pascal_case -from arcade.sdk.auth import ToolAuthorization -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk.auth import ToolAuthorization +from arcade_tdk.errors import ToolExecutionError +from arcade_tdk.utils import snake_to_pascal_case T = TypeVar("T") diff --git a/libs/arcade-tdk/arcade_tdk/utils.py b/libs/arcade-tdk/arcade_tdk/utils.py new file mode 100644 index 00000000..011c5d92 --- /dev/null +++ b/libs/arcade-tdk/arcade_tdk/utils.py @@ -0,0 +1,10 @@ +def snake_to_pascal_case(name: str) -> str: + """ + Converts a snake_case name to PascalCase. + """ + if "_" in name: + return "".join(x.capitalize() or "_" for x in name.split("_")) + # check if first letter is uppercase + if name[0].isupper(): + return name + return name.capitalize() diff --git a/libs/arcade-tdk/pyproject.toml b/libs/arcade-tdk/pyproject.toml new file mode 100644 index 00000000..dbbd99f9 --- /dev/null +++ b/libs/arcade-tdk/pyproject.toml @@ -0,0 +1,51 @@ +[project] +name = "arcade-tdk" +version = "2.0.0" +description = "Arcade TDK - Toolkit Development Kit for building Arcade tools" +readme = "README.md" +license = {text = "MIT"} +authors = [ + {name = "Arcade", email = "dev@arcade.dev"}, +] +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", +] +requires-python = ">=3.10" +dependencies = [ + "arcade-core>=0.1.0", + "pydantic>=2.7.0", +] + +[project.optional-dependencies] +dev = [ + "pytest>=8.1.2", + "pytest-cov>=4.0.0", + "mypy>=1.5.1", + "pre-commit>=3.4.0", + "pytest-asyncio>=0.23.7", +] + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.build.targets.wheel] +packages = ["arcade_tdk"] + +[tool.mypy] +files = ["arcade_tdk"] +python_version = "3.10" +disallow_untyped_defs = true +disallow_any_unimported = true +no_implicit_optional = true +check_untyped_defs = true +warn_return_any = true +warn_unused_ignores = true +show_error_codes = true +ignore_missing_imports = true diff --git a/libs/tests/__init__.py b/libs/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/arcade/tests/cli/test_dashboard.py b/libs/tests/cli/test_dashboard.py similarity index 82% rename from arcade/tests/cli/test_dashboard.py rename to libs/tests/cli/test_dashboard.py index 3be0da00..20298009 100644 --- a/arcade/tests/cli/test_dashboard.py +++ b/libs/tests/cli/test_dashboard.py @@ -1,11 +1,10 @@ from unittest.mock import MagicMock, patch import pytest +from arcade_cli.constants import PROD_ENGINE_HOST +from arcade_cli.main import cli from typer.testing import CliRunner -from arcade.cli.constants import PROD_ENGINE_HOST -from arcade.cli.main import cli - runner = CliRunner() @@ -25,8 +24,8 @@ def test_dashboard_url_construction(args, expected_url): """Test that the dashboard command constructs the correct URL with various args.""" with ( patch("webbrowser.open") as mock_open, - patch("arcade.cli.main.validate_and_get_config") as mock_validate, - patch("arcade.cli.main.log_engine_health") as mock_health_check, + patch("arcade_cli.main.validate_and_get_config") as mock_validate, + patch("arcade_cli.main.log_engine_health") as mock_health_check, ): # Setup mocks mock_open.return_value = True # Successfully opened browser @@ -45,9 +44,9 @@ def test_fallback_when_browser_fails(): """Test fallback message when browser.open fails.""" with ( patch("webbrowser.open") as mock_open, - patch("arcade.cli.main.validate_and_get_config") as mock_validate, - patch("arcade.cli.main.log_engine_health") as mock_health_check, - patch("arcade.cli.main.console.print") as mock_print, + patch("arcade_cli.main.validate_and_get_config") as mock_validate, + patch("arcade_cli.main.log_engine_health") as mock_health_check, + patch("arcade_cli.main.console.print") as mock_print, ): mock_open.return_value = False # Failed to open browser mock_validate.return_value = MagicMock() @@ -66,8 +65,8 @@ def test_health_check_success(): """Test successful health check.""" with ( patch("webbrowser.open") as mock_open, - patch("arcade.cli.main.validate_and_get_config") as mock_validate, - patch("arcade.cli.main.log_engine_health") as mock_health_check, + patch("arcade_cli.main.validate_and_get_config") as mock_validate, + patch("arcade_cli.main.log_engine_health") as mock_health_check, ): mock_open.return_value = True mock_validate.return_value = MagicMock() diff --git a/arcade/tests/cli/test_show.py b/libs/tests/cli/test_show.py similarity index 84% rename from arcade/tests/cli/test_show.py rename to libs/tests/cli/test_show.py index ee0848b0..15a7cbdf 100644 --- a/arcade/tests/cli/test_show.py +++ b/libs/tests/cli/test_show.py @@ -1,10 +1,10 @@ from unittest.mock import patch -from arcade.cli.show import show_logic +from arcade_cli.show import show_logic def test_show_logic_local_false(): - with patch("arcade.cli.show.get_tools_from_engine") as mock_get_tools: + with patch("arcade_cli.show.get_tools_from_engine") as mock_get_tools: mock_get_tools.return_value = [] show_logic( toolkit=None, @@ -22,7 +22,7 @@ def test_show_logic_local_false(): def test_show_logic_local_true(): - with patch("arcade.cli.show.create_cli_catalog") as mock_create_catalog: + with patch("arcade_cli.show.create_cli_catalog") as mock_create_catalog: mock_create_catalog.return_value = [] show_logic( diff --git a/arcade/tests/cli/test_utils.py b/libs/tests/cli/test_utils.py similarity index 99% rename from arcade/tests/cli/test_utils.py rename to libs/tests/cli/test_utils.py index 9328409a..c4b40c62 100644 --- a/arcade/tests/cli/test_utils.py +++ b/libs/tests/cli/test_utils.py @@ -1,6 +1,5 @@ import pytest - -from arcade.cli.utils import compute_base_url, compute_login_url +from arcade_cli.utils import compute_base_url, compute_login_url DEFAULT_CLOUD_HOST = "cloud.arcade.dev" DEFAULT_ENGINE_HOST = "api.arcade.dev" diff --git a/arcade/tests/core/test_catalog.py b/libs/tests/core/test_catalog.py similarity index 94% rename from arcade/tests/core/test_catalog.py rename to libs/tests/core/test_catalog.py index 49f86753..945bff00 100644 --- a/arcade/tests/core/test_catalog.py +++ b/libs/tests/core/test_catalog.py @@ -1,12 +1,11 @@ from unittest.mock import MagicMock, patch import pytest - -from arcade.core.catalog import ToolCatalog -from arcade.core.errors import ToolDefinitionError -from arcade.core.schema import FullyQualifiedName -from arcade.core.toolkit import Toolkit -from arcade.sdk import tool +from arcade_core.catalog import ToolCatalog +from arcade_core.errors import ToolDefinitionError +from arcade_core.schema import FullyQualifiedName +from arcade_core.toolkit import Toolkit +from arcade_tdk import tool @tool @@ -88,8 +87,8 @@ def test_add_toolkit_type_error(): # Mock the import_module and getattr functions with ( - patch("arcade.core.catalog.import_module") as mock_import, - patch("arcade.core.catalog.getattr") as mock_getattr, + patch("arcade_core.catalog.import_module") as mock_import, + patch("arcade_core.catalog.getattr") as mock_getattr, ): mock_import.return_value = MagicMock() mock_getattr.return_value = InvalidTool() diff --git a/arcade/tests/core/test_executor.py b/libs/tests/core/test_executor.py similarity index 95% rename from arcade/tests/core/test_executor.py rename to libs/tests/core/test_executor.py index 2154723d..488d0a99 100644 --- a/arcade/tests/core/test_executor.py +++ b/libs/tests/core/test_executor.py @@ -1,12 +1,11 @@ from typing import Annotated import pytest - -from arcade.core.catalog import ToolCatalog -from arcade.core.executor import ToolExecutor -from arcade.core.schema import ToolCallError, ToolCallLog, ToolCallOutput, ToolContext -from arcade.sdk import tool -from arcade.sdk.errors import RetryableToolError, ToolExecutionError +from arcade_core.catalog import ToolCatalog +from arcade_core.executor import ToolExecutor +from arcade_core.schema import ToolCallError, ToolCallLog, ToolCallOutput, ToolContext +from arcade_tdk import tool +from arcade_tdk.errors import RetryableToolError, ToolExecutionError @tool diff --git a/arcade/tests/core/test_output.py b/libs/tests/core/test_output.py similarity index 97% rename from arcade/tests/core/test_output.py rename to libs/tests/core/test_output.py index fb62b413..bca1c18d 100644 --- a/arcade/tests/core/test_output.py +++ b/libs/tests/core/test_output.py @@ -1,10 +1,9 @@ from typing import Any import pytest +from arcade_core.output import ToolOutputFactory from pydantic import BaseModel -from arcade.core.output import ToolOutputFactory - @pytest.fixture def output_factory(): diff --git a/arcade/tests/core/test_parse.py b/libs/tests/core/test_parse.py similarity index 95% rename from arcade/tests/core/test_parse.py rename to libs/tests/core/test_parse.py index 61288757..ac8eb4d7 100644 --- a/arcade/tests/core/test_parse.py +++ b/libs/tests/core/test_parse.py @@ -1,8 +1,7 @@ import ast import pytest - -from arcade.core.parse import get_tools_from_ast +from arcade_core.parse import get_tools_from_ast @pytest.mark.parametrize( diff --git a/arcade/tests/core/test_schema.py b/libs/tests/core/test_schema.py similarity index 99% rename from arcade/tests/core/test_schema.py rename to libs/tests/core/test_schema.py index cde95d07..d71d475d 100644 --- a/arcade/tests/core/test_schema.py +++ b/libs/tests/core/test_schema.py @@ -1,6 +1,5 @@ import pytest - -from arcade.core.schema import ( +from arcade_core.schema import ( ToolAuthorizationContext, ToolContext, ToolMetadataItem, diff --git a/arcade/tests/core/test_telemetry.py b/libs/tests/core/test_telemetry.py similarity index 85% rename from arcade/tests/core/test_telemetry.py rename to libs/tests/core/test_telemetry.py index db9bcca8..5545e3c1 100644 --- a/arcade/tests/core/test_telemetry.py +++ b/libs/tests/core/test_telemetry.py @@ -1,10 +1,9 @@ from unittest.mock import MagicMock, patch import pytest +from arcade_core.telemetry import OTELHandler, ShutdownError from fastapi import FastAPI -from arcade.core.telemetry import OTELHandler, ShutdownError - @pytest.fixture def app(): @@ -16,11 +15,11 @@ def handler_disabled(app): return OTELHandler(enable=False) -@patch("arcade.core.telemetry.logging") -@patch("arcade.core.telemetry.FastAPIInstrumentor") -@patch("arcade.core.telemetry.OTLPLogExporter") -@patch("arcade.core.telemetry.OTLPMetricExporter") -@patch("arcade.core.telemetry.OTLPSpanExporter") +@patch("arcade_core.telemetry.logging") +@patch("arcade_core.telemetry.FastAPIInstrumentor") +@patch("arcade_core.telemetry.OTLPLogExporter") +@patch("arcade_core.telemetry.OTLPMetricExporter") +@patch("arcade_core.telemetry.OTLPSpanExporter") def test_init_with_enable_true( mock_span_exporter, mock_metric_exporter, @@ -54,8 +53,8 @@ def test_init_with_enable_true( mock_instrumentor.return_value.instrument_app.assert_called_once_with(app) -@patch("arcade.core.telemetry.logging") -@patch("arcade.core.telemetry.FastAPIInstrumentor") +@patch("arcade_core.telemetry.logging") +@patch("arcade_core.telemetry.FastAPIInstrumentor") def test_init_with_enable_false(mock_instrumentor, mock_logging, app): handler = OTELHandler(enable=False) handler.instrument_app(app) @@ -82,9 +81,9 @@ def test_init_tracer_export_exception(app): assert "Could not connect to OpenTelemetry Tracer endpoint" in str(exc_info.value) -@patch("arcade.core.telemetry.OTLPLogExporter") -@patch("arcade.core.telemetry.OTLPMetricExporter") -@patch("arcade.core.telemetry.OTLPSpanExporter") +@patch("arcade_core.telemetry.OTLPLogExporter") +@patch("arcade_core.telemetry.OTLPMetricExporter") +@patch("arcade_core.telemetry.OTLPSpanExporter") def test_shutdown(mock_span_exporter, mock_metric_exporter, mock_log_exporter, app): # Mock the shutdown methods mock_span_exporter.return_value.shutdown = MagicMock() @@ -121,10 +120,10 @@ def test_shutdown_logging_not_initialized(handler_disabled): assert "Log provider not initialized" in str(exc_info.value) -@patch("arcade.core.telemetry.get_meter_provider") -@patch("arcade.core.telemetry.OTLPLogExporter") -@patch("arcade.core.telemetry.OTLPMetricExporter") -@patch("arcade.core.telemetry.OTLPSpanExporter") +@patch("arcade_core.telemetry.get_meter_provider") +@patch("arcade_core.telemetry.OTLPLogExporter") +@patch("arcade_core.telemetry.OTLPMetricExporter") +@patch("arcade_core.telemetry.OTLPSpanExporter") def test_get_meter( mock_span_exporter, mock_metric_exporter, mock_log_exporter, mock_get_meter_provider, app ): diff --git a/arcade/tests/core/utils/test_casing.py b/libs/tests/core/utils/test_casing.py similarity index 90% rename from arcade/tests/core/utils/test_casing.py rename to libs/tests/core/utils/test_casing.py index 481da9ea..585043fe 100644 --- a/arcade/tests/core/utils/test_casing.py +++ b/libs/tests/core/utils/test_casing.py @@ -1,6 +1,5 @@ import pytest - -from arcade.core.utils import pascal_to_snake_case, snake_to_pascal_case +from arcade_core.utils import pascal_to_snake_case, snake_to_pascal_case @pytest.mark.parametrize( diff --git a/arcade/tests/core/utils/test_is_strict_optional.py b/libs/tests/core/utils/test_is_strict_optional.py similarity index 91% rename from arcade/tests/core/utils/test_is_strict_optional.py rename to libs/tests/core/utils/test_is_strict_optional.py index fdf6ccb5..24e89fba 100644 --- a/arcade/tests/core/utils/test_is_strict_optional.py +++ b/libs/tests/core/utils/test_is_strict_optional.py @@ -1,8 +1,7 @@ from typing import Optional, Union import pytest - -from arcade.core.utils import is_strict_optional +from arcade_core.utils import is_strict_optional @pytest.mark.parametrize( diff --git a/arcade/tests/core/utils/test_is_union.py b/libs/tests/core/utils/test_is_union.py similarity index 92% rename from arcade/tests/core/utils/test_is_union.py rename to libs/tests/core/utils/test_is_union.py index 68ab581b..145d968a 100644 --- a/arcade/tests/core/utils/test_is_union.py +++ b/libs/tests/core/utils/test_is_union.py @@ -1,8 +1,7 @@ from typing import Optional, Union import pytest - -from arcade.core.utils import is_union +from arcade_core.utils import is_union @pytest.mark.parametrize( diff --git a/arcade/tests/deployment/test_config.py b/libs/tests/deployment/test_config.py similarity index 99% rename from arcade/tests/deployment/test_config.py rename to libs/tests/deployment/test_config.py index 4179047a..8306d39d 100644 --- a/arcade/tests/deployment/test_config.py +++ b/libs/tests/deployment/test_config.py @@ -6,8 +6,7 @@ import os from pathlib import Path import pytest - -from arcade.cli.deployment import ( +from arcade_cli.deployment import ( Config, Deployment, LocalPackages, diff --git a/arcade/tests/deployment/test_files/env.secret.worker.toml b/libs/tests/deployment/test_files/env.secret.worker.toml similarity index 100% rename from arcade/tests/deployment/test_files/env.secret.worker.toml rename to libs/tests/deployment/test_files/env.secret.worker.toml diff --git a/arcade/tests/deployment/test_files/full.worker.toml b/libs/tests/deployment/test_files/full.worker.toml similarity index 100% rename from arcade/tests/deployment/test_files/full.worker.toml rename to libs/tests/deployment/test_files/full.worker.toml diff --git a/arcade/tests/deployment/test_files/invalid.fields.worker.toml b/libs/tests/deployment/test_files/invalid.fields.worker.toml similarity index 100% rename from arcade/tests/deployment/test_files/invalid.fields.worker.toml rename to libs/tests/deployment/test_files/invalid.fields.worker.toml diff --git a/arcade/tests/deployment/test_files/invalid.localfile.worker.toml b/libs/tests/deployment/test_files/invalid.localfile.worker.toml similarity index 100% rename from arcade/tests/deployment/test_files/invalid.localfile.worker.toml rename to libs/tests/deployment/test_files/invalid.localfile.worker.toml diff --git a/arcade/tests/deployment/test_files/invalid.secret.worker.toml b/libs/tests/deployment/test_files/invalid.secret.worker.toml similarity index 100% rename from arcade/tests/deployment/test_files/invalid.secret.worker.toml rename to libs/tests/deployment/test_files/invalid.secret.worker.toml diff --git a/libs/tests/deployment/test_files/invalid_toolkit/invalid_main.py b/libs/tests/deployment/test_files/invalid_toolkit/invalid_main.py new file mode 100644 index 00000000..e69de29b diff --git a/arcade/tests/deployment/test_files/mock_toolkit/mock_main.py b/libs/tests/deployment/test_files/mock_toolkit/mock_main.py similarity index 100% rename from arcade/tests/deployment/test_files/mock_toolkit/mock_main.py rename to libs/tests/deployment/test_files/mock_toolkit/mock_main.py diff --git a/arcade/tests/deployment/test_files/mock_toolkit/pyproject.toml b/libs/tests/deployment/test_files/mock_toolkit/pyproject.toml similarity index 100% rename from arcade/tests/deployment/test_files/mock_toolkit/pyproject.toml rename to libs/tests/deployment/test_files/mock_toolkit/pyproject.toml diff --git a/arcade/tests/mcp/test_convert.py b/libs/tests/mcp/test_convert.py similarity index 90% rename from arcade/tests/mcp/test_convert.py rename to libs/tests/mcp/test_convert.py index a4bcf0c2..24095f74 100644 --- a/arcade/tests/mcp/test_convert.py +++ b/libs/tests/mcp/test_convert.py @@ -1,9 +1,9 @@ import json from typing import Annotated -from arcade.core.catalog import ToolCatalog -from arcade.sdk import tool -from arcade.worker.mcp.convert import convert_to_mcp_content, create_mcp_tool +from arcade_core.catalog import ToolCatalog +from arcade_serve.mcp.convert import convert_to_mcp_content, create_mcp_tool +from arcade_tdk import tool @tool diff --git a/arcade/tests/mcp/test_message_processor.py b/libs/tests/mcp/test_message_processor.py similarity index 91% rename from arcade/tests/mcp/test_message_processor.py rename to libs/tests/mcp/test_message_processor.py index fac0d91a..4a526cca 100644 --- a/arcade/tests/mcp/test_message_processor.py +++ b/libs/tests/mcp/test_message_processor.py @@ -1,9 +1,8 @@ import asyncio import pytest - -from arcade.worker.mcp.message_processor import MCPMessageProcessor, create_message_processor -from arcade.worker.mcp.types import InitializeRequest, PingRequest +from arcade_serve.mcp.message_processor import MCPMessageProcessor, create_message_processor +from arcade_serve.mcp.types import InitializeRequest, PingRequest @pytest.mark.asyncio diff --git a/arcade/tests/mcp/test_server.py b/libs/tests/mcp/test_server.py similarity index 96% rename from arcade/tests/mcp/test_server.py rename to libs/tests/mcp/test_server.py index bfb75eeb..2cdc56a3 100644 --- a/arcade/tests/mcp/test_server.py +++ b/libs/tests/mcp/test_server.py @@ -3,17 +3,16 @@ import types from typing import Annotated, Any import pytest - -from arcade.core.catalog import ToolCatalog -from arcade.sdk import tool -from arcade.worker.mcp import server as mcp_server -from arcade.worker.mcp.types import ( +from arcade_core.catalog import ToolCatalog +from arcade_serve.mcp import server as mcp_server +from arcade_serve.mcp.types import ( CallToolRequest, CancelRequest, InitializeRequest, ListToolsRequest, PingRequest, ) +from arcade_tdk import tool # --------------------------------------------------------------------------- # Test helpers / stubs diff --git a/arcade/tests/mcp/test_stdio.py b/libs/tests/mcp/test_stdio.py similarity index 92% rename from arcade/tests/mcp/test_stdio.py rename to libs/tests/mcp/test_stdio.py index 6d512157..daa0282d 100644 --- a/arcade/tests/mcp/test_stdio.py +++ b/libs/tests/mcp/test_stdio.py @@ -1,7 +1,7 @@ import io import queue -from arcade.worker.mcp.stdio import stdio_reader, stdio_writer +from arcade_serve.mcp.stdio import stdio_reader, stdio_writer def test_stdio_reader_puts_lines_and_none(): diff --git a/arcade/tests/sdk/test_eval.py b/libs/tests/sdk/test_eval.py similarity index 98% rename from arcade/tests/sdk/test_eval.py rename to libs/tests/sdk/test_eval.py index 2aaa52d0..969216e6 100644 --- a/arcade/tests/sdk/test_eval.py +++ b/libs/tests/sdk/test_eval.py @@ -1,9 +1,7 @@ from unittest.mock import Mock import pytest - -from arcade.sdk import tool -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, EvalRubric, ExpectedToolCall, @@ -11,7 +9,8 @@ from arcade.sdk.eval import ( NoneCritic, SimilarityCritic, ) -from arcade.sdk.eval.eval import EvalCase, EvalSuite, EvaluationResult +from arcade_evals.eval import EvalCase, EvalSuite, EvaluationResult +from arcade_tdk import tool @tool diff --git a/arcade/tests/sdk/test_eval_critic.py b/libs/tests/sdk/test_eval_critic.py similarity index 99% rename from arcade/tests/sdk/test_eval_critic.py rename to libs/tests/sdk/test_eval_critic.py index 91578739..c0d34cc1 100644 --- a/arcade/tests/sdk/test_eval_critic.py +++ b/libs/tests/sdk/test_eval_critic.py @@ -2,16 +2,15 @@ from datetime import timedelta import pytest import pytz -from dateutil import parser - -from arcade.sdk.errors import WeightError -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, DatetimeCritic, NoneCritic, NumericCritic, SimilarityCritic, ) +from arcade_evals.errors import WeightError +from dateutil import parser # Test NoneCritic initialization diff --git a/arcade/tests/sdk/test_tool_decorator.py b/libs/tests/sdk/test_tool_decorator.py similarity index 98% rename from arcade/tests/sdk/test_tool_decorator.py rename to libs/tests/sdk/test_tool_decorator.py index 8136a84c..0a3542b3 100644 --- a/arcade/tests/sdk/test_tool_decorator.py +++ b/libs/tests/sdk/test_tool_decorator.py @@ -1,10 +1,9 @@ import asyncio import pytest - -from arcade.core.auth import AuthProviderType, Google -from arcade.sdk import tool -from arcade.sdk.auth import OAuth2 +from arcade_core.auth import AuthProviderType, Google +from arcade_tdk import tool +from arcade_tdk.auth import OAuth2 def test_sync_function(): diff --git a/arcade/tests/tool/test_create_tool_definition.py b/libs/tests/tool/test_create_tool_definition.py similarity index 99% rename from arcade/tests/tool/test_create_tool_definition.py rename to libs/tests/tool/test_create_tool_definition.py index ee4c07d2..34e4cc45 100644 --- a/arcade/tests/tool/test_create_tool_definition.py +++ b/libs/tests/tool/test_create_tool_definition.py @@ -2,9 +2,8 @@ from enum import Enum from typing import Annotated, Literal, Optional, Union import pytest - -from arcade.core.catalog import ToolCatalog -from arcade.core.schema import ( +from arcade_core.catalog import ToolCatalog +from arcade_core.schema import ( InputParameter, OAuth2Requirement, ToolAuthRequirement, @@ -17,10 +16,10 @@ from arcade.core.schema import ( ToolSecretRequirement, ValueSchema, ) -from arcade.core.utils import snake_to_pascal_case -from arcade.sdk import tool -from arcade.sdk.annotations import Inferrable -from arcade.sdk.auth import GitHub, Google, OAuth2, Slack, X +from arcade_core.utils import snake_to_pascal_case +from arcade_tdk import tool +from arcade_tdk.annotations import Inferrable +from arcade_tdk.auth import GitHub, Google, OAuth2, Slack, X ### Tests on @tool decorator diff --git a/arcade/tests/tool/test_create_tool_definition_errors.py b/libs/tests/tool/test_create_tool_definition_errors.py similarity index 96% rename from arcade/tests/tool/test_create_tool_definition_errors.py rename to libs/tests/tool/test_create_tool_definition_errors.py index 3a3de328..23458ea3 100644 --- a/arcade/tests/tool/test_create_tool_definition_errors.py +++ b/libs/tests/tool/test_create_tool_definition_errors.py @@ -1,11 +1,10 @@ from typing import Annotated, Union import pytest - -from arcade.core.catalog import ToolCatalog -from arcade.core.errors import ToolDefinitionError -from arcade.core.schema import ToolContext, ToolMetadataKey -from arcade.sdk import tool +from arcade_core.catalog import ToolCatalog +from arcade_core.errors import ToolDefinitionError +from arcade_core.schema import ToolContext, ToolMetadataKey +from arcade_tdk import tool @tool diff --git a/arcade/tests/tool/test_create_tool_definition_new.py b/libs/tests/tool/test_create_tool_definition_new.py similarity index 96% rename from arcade/tests/tool/test_create_tool_definition_new.py rename to libs/tests/tool/test_create_tool_definition_new.py index 6277c51b..f087aee4 100644 --- a/arcade/tests/tool/test_create_tool_definition_new.py +++ b/libs/tests/tool/test_create_tool_definition_new.py @@ -1,9 +1,8 @@ from typing import Annotated import pytest - -from arcade.core.catalog import ToolCatalog, get_wire_type -from arcade.sdk import tool +from arcade_core.catalog import ToolCatalog, get_wire_type +from arcade_tdk import tool class Case: diff --git a/arcade/tests/tool/test_create_tool_definition_pydantic.py b/libs/tests/tool/test_create_tool_definition_pydantic.py similarity index 99% rename from arcade/tests/tool/test_create_tool_definition_pydantic.py rename to libs/tests/tool/test_create_tool_definition_pydantic.py index e423501f..38b3c816 100644 --- a/arcade/tests/tool/test_create_tool_definition_pydantic.py +++ b/libs/tests/tool/test_create_tool_definition_pydantic.py @@ -1,16 +1,15 @@ from typing import Annotated, Optional, Union import pytest -from pydantic import BaseModel, Field - -from arcade.core.catalog import ToolCatalog -from arcade.core.schema import ( +from arcade_core.catalog import ToolCatalog +from arcade_core.schema import ( InputParameter, ToolInput, ToolOutput, ValueSchema, ) -from arcade.sdk import tool +from arcade_tdk import tool +from pydantic import BaseModel, Field class ProductOutput(BaseModel): diff --git a/arcade/tests/tool/test_create_tool_definition_pydantic_errors.py b/libs/tests/tool/test_create_tool_definition_pydantic_errors.py similarity index 93% rename from arcade/tests/tool/test_create_tool_definition_pydantic_errors.py rename to libs/tests/tool/test_create_tool_definition_pydantic_errors.py index f49a9090..478b041e 100644 --- a/arcade/tests/tool/test_create_tool_definition_pydantic_errors.py +++ b/libs/tests/tool/test_create_tool_definition_pydantic_errors.py @@ -1,12 +1,11 @@ from typing import Annotated, Union import pytest +from arcade_core.catalog import ToolCatalog +from arcade_core.errors import ToolDefinitionError +from arcade_tdk import tool from pydantic import Field -from arcade.core.catalog import ToolCatalog -from arcade.core.errors import ToolDefinitionError -from arcade.sdk import tool - @tool def field_with_literal_default_factory( diff --git a/arcade/tests/tool/test_fully_qualified_tool_name.py b/libs/tests/tool/test_fully_qualified_tool_name.py similarity index 95% rename from arcade/tests/tool/test_fully_qualified_tool_name.py rename to libs/tests/tool/test_fully_qualified_tool_name.py index 4c185350..42bbe388 100644 --- a/arcade/tests/tool/test_fully_qualified_tool_name.py +++ b/libs/tests/tool/test_fully_qualified_tool_name.py @@ -1,4 +1,4 @@ -from arcade.core.schema import FullyQualifiedName, ToolkitDefinition +from arcade_core.schema import FullyQualifiedName, ToolkitDefinition def test_initialization(): diff --git a/arcade/tests/worker/test_worker_base.py b/libs/tests/worker/test_worker_base.py similarity index 96% rename from arcade/tests/worker/test_worker_base.py rename to libs/tests/worker/test_worker_base.py index f50eb871..3f3708fd 100644 --- a/arcade/tests/worker/test_worker_base.py +++ b/libs/tests/worker/test_worker_base.py @@ -3,22 +3,21 @@ from typing import Annotated from unittest.mock import MagicMock import pytest - -from arcade.core.errors import ToolDefinitionError -from arcade.core.schema import ( +from arcade_core.errors import ToolDefinitionError +from arcade_core.schema import ( ToolCallRequest, ToolCallResponse, ToolContext, ToolReference, ) -from arcade.sdk import tool -from arcade.worker.core.base import BaseWorker -from arcade.worker.core.common import RequestData, Router -from arcade.worker.core.components import ( +from arcade_serve.core.base import BaseWorker +from arcade_serve.core.common import RequestData, Router +from arcade_serve.core.components import ( CallToolComponent, CatalogComponent, HealthCheckComponent, ) +from arcade_tdk import tool @tool() diff --git a/arcade/tests/worker/test_worker_fastapi.py b/libs/tests/worker/test_worker_fastapi.py similarity index 97% rename from arcade/tests/worker/test_worker_fastapi.py rename to libs/tests/worker/test_worker_fastapi.py index 83c6f105..399a25b3 100644 --- a/arcade/tests/worker/test_worker_fastapi.py +++ b/libs/tests/worker/test_worker_fastapi.py @@ -1,13 +1,12 @@ from typing import Annotated import pytest +from arcade_core.schema import ToolCallRequest, ToolContext, ToolReference +from arcade_serve.fastapi.worker import FastAPIWorker +from arcade_tdk import tool from fastapi import FastAPI from fastapi.testclient import TestClient -from arcade.core.schema import ToolCallRequest, ToolContext, ToolReference -from arcade.sdk import tool -from arcade.worker.fastapi.worker import FastAPIWorker - @tool() def sample_tool_fastapi( diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..79a6a656 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,152 @@ +[project] +name = "arcade-ai" +version = "2.0.0" +description = "Arcade.dev - Tool Calling platform for Agents" +readme = "README.md" +license = {file = "LICENSE"} +authors = [ + {name = "Arcade", email = "dev@arcade.dev"}, +] +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", +] +requires-python = ">=3.10" + +dependencies = [ + # CLI dependencies + "arcade-core>=2.0.0,<3.0.0", + "typer==0.10.0", + "rich==13.9.4", + "Jinja2==3.1.6", + "arcadepy==1.5.0", + "tqdm==4.67.1", + "openai==1.82.1", + "click==8.1.8", +] + +[project.optional-dependencies] +all = [ + # evals + "scipy>=1.14.0", + "numpy>=2.0.0", + "scikit-learn>=1.5.0", + "pytz>=2024.1", + "python-dateutil>=2.8.2", + # serve + "arcade-serve>=2.0.0,<3.0.0", + # tdk + "arcade-tdk>=2.0.0,<3.0.0", +] +# Evals also depends on arcade-core and openai, but they are already required deps +evals = [ + "scipy>=1.14.0", + "numpy>=2.0.0", + "scikit-learn>=1.5.0", + "pytz>=2024.1", + "python-dateutil>=2.8.2", +] + +[tool.uv] +dev-dependencies = [ + "pytest>=8.1.2", + "pytest-cov>=4.0.0", + "pytest-asyncio>=0.23.7", + "mypy>=1.5.1", + "pre-commit>=3.4.0", + "ruff>=0.4.0", + "types-PyYAML>=6.0.0", + "types-python-dateutil>=2.8.2", + "types-pytz>=2024.1", +] + +# CLI entry point +[project.scripts] +arcade = "arcade_cli.main:cli" + +[tool.uv.sources] +# Workspace member sources +arcade-core = { workspace = true } +arcade-tdk = { workspace = true } +arcade-serve = { workspace = true } + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.build.targets.wheel] +packages = [ + "libs/arcade-cli/arcade_cli", + "libs/arcade-evals/arcade_evals", +] + +[tool.uv.workspace] +members = [ + "libs/arcade-core", + "libs/arcade-tdk", + "libs/arcade-serve", +] + +[tool.mypy] +python_version = "3.10" +disallow_untyped_defs = true +disallow_any_unimported = true +no_implicit_optional = true +check_untyped_defs = true +warn_return_any = true +warn_unused_ignores = true +show_error_codes = true +ignore_missing_imports = true +exclude = [ + '.*{{.*}}.*' # Ignore files that have names that use Jinja template syntax +] + +[tool.pytest.ini_options] +testpaths = ["libs/tests"] +python_files = ["test_*.py"] +python_classes = ["Test*"] +python_functions = ["test_*"] +addopts = [ + "--strict-markers", + "--strict-config", + "--verbose", + "--cov=libs", + "--cov-report=term-missing", + "--cov-report=html", + "--cov-report=xml", +] + +[tool.coverage.run] +source = ["libs"] +omit = [ + "*/tests/*", + "*/test_*", + "*/__pycache__/*", +] + +[tool.coverage.report] +exclude_lines = [ + "pragma: no cover", + "def __repr__", + "raise AssertionError", + "raise NotImplementedError", + "if __name__ == .__main__.:", + "if TYPE_CHECKING:", +] + +[tool.ruff] +target-version = "py310" +line-length = 100 + +[tool.ruff.lint] +select = ["E", "F", "I", "N", "UP", "RUF"] +ignore = ["E501"] + +[tool.ruff.lint.per-file-ignores] +"__init__.py" = ["F401"] diff --git a/toolkits/asana/.pre-commit-config.yaml b/toolkits/asana/.pre-commit-config.yaml index 3953e996..1ef6a856 100644 --- a/toolkits/asana/.pre-commit-config.yaml +++ b/toolkits/asana/.pre-commit-config.yaml @@ -1,4 +1,4 @@ -files: ^./ +files: ^.*/asana/.* repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: "v4.4.0" diff --git a/toolkits/asana/Makefile b/toolkits/asana/Makefile index 8ca4a804..7e2c686e 100644 --- a/toolkits/asana/Makefile +++ b/toolkits/asana/Makefile @@ -1,25 +1,27 @@ .PHONY: help help: - @echo "๐Ÿ› ๏ธ dropbox Commands:\n" + @echo "๐Ÿ› ๏ธ github Commands:\n" @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' .PHONY: install -install: ## Install the poetry environment and install the pre-commit hooks - @echo "๐Ÿ“ฆ Checking if Poetry is installed" - @if ! command -v poetry &> /dev/null; then \ - echo "๐Ÿ“ฆ Installing Poetry with pip"; \ - pip install poetry==1.8.5; \ - else \ - echo "๐Ÿ“ฆ Poetry is already installed"; \ - fi - @echo "๐Ÿš€ Installing package in development mode with all extras" - poetry install --all-extras +install: ## Install the uv environment and install all packages with dependencies + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras --no-sources + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" + +.PHONY: install-local +install-local: ## Install the uv environment and install all packages with dependencies with local Arcade sources + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" .PHONY: build build: clean-build ## Build wheel file using poetry @echo "๐Ÿš€ Creating wheel file" - poetry build + uv build .PHONY: clean-build clean-build: ## clean build artifacts @@ -29,7 +31,7 @@ clean-build: ## clean build artifacts .PHONY: test test: ## Test the code with pytest @echo "๐Ÿš€ Testing code: Running pytest" - @poetry run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml + @uv run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml .PHONY: coverage coverage: ## Generate coverage report @@ -39,15 +41,13 @@ coverage: ## Generate coverage report coverage html .PHONY: bump-version -bump-version: ## Bump the version in the pyproject.toml file +bump-version: ## Bump the version in the pyproject.toml file by a patch version @echo "๐Ÿš€ Bumping version in pyproject.toml" - poetry version patch + uv version --bump patch .PHONY: check check: ## Run code quality tools. - @echo "๐Ÿš€ Checking Poetry lock file consistency with 'pyproject.toml': Running poetry check" - @poetry check @echo "๐Ÿš€ Linting code: Running pre-commit" - @poetry run pre-commit run -a + @uv run pre-commit run -a @echo "๐Ÿš€ Static type checking: Running mypy" - @poetry run mypy --config-file=pyproject.toml + @uv run mypy --config-file=pyproject.toml diff --git a/toolkits/asana/arcade_asana/exceptions.py b/toolkits/asana/arcade_asana/exceptions.py index 68d2cd0b..0a76be8a 100644 --- a/toolkits/asana/arcade_asana/exceptions.py +++ b/toolkits/asana/arcade_asana/exceptions.py @@ -1,4 +1,4 @@ -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk.errors import ToolExecutionError class AsanaToolExecutionError(ToolExecutionError): diff --git a/toolkits/asana/arcade_asana/tools/projects.py b/toolkits/asana/arcade_asana/tools/projects.py index 3e36d757..f8e36e66 100644 --- a/toolkits/asana/arcade_asana/tools/projects.py +++ b/toolkits/asana/arcade_asana/tools/projects.py @@ -1,7 +1,7 @@ from typing import Annotated, Any -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Asana +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Asana from arcade_asana.constants import PROJECT_OPT_FIELDS from arcade_asana.models import AsanaClient diff --git a/toolkits/asana/arcade_asana/tools/tags.py b/toolkits/asana/arcade_asana/tools/tags.py index b0aea1dc..b414e475 100644 --- a/toolkits/asana/arcade_asana/tools/tags.py +++ b/toolkits/asana/arcade_asana/tools/tags.py @@ -1,8 +1,8 @@ from typing import Annotated, Any -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Asana -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Asana +from arcade_tdk.errors import ToolExecutionError from arcade_asana.constants import TAG_OPT_FIELDS, TagColor from arcade_asana.models import AsanaClient diff --git a/toolkits/asana/arcade_asana/tools/tasks.py b/toolkits/asana/arcade_asana/tools/tasks.py index 4cf37f10..876c4986 100644 --- a/toolkits/asana/arcade_asana/tools/tasks.py +++ b/toolkits/asana/arcade_asana/tools/tasks.py @@ -1,9 +1,9 @@ import base64 from typing import Annotated, Any -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Asana -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Asana +from arcade_tdk.errors import ToolExecutionError from arcade_asana.constants import TASK_OPT_FIELDS, SortOrder, TaskSortBy from arcade_asana.models import AsanaClient diff --git a/toolkits/asana/arcade_asana/tools/teams.py b/toolkits/asana/arcade_asana/tools/teams.py index ff7f0860..25bf87f2 100644 --- a/toolkits/asana/arcade_asana/tools/teams.py +++ b/toolkits/asana/arcade_asana/tools/teams.py @@ -1,7 +1,7 @@ from typing import Annotated, Any -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Asana +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Asana from arcade_asana.constants import TEAM_OPT_FIELDS from arcade_asana.models import AsanaClient diff --git a/toolkits/asana/arcade_asana/tools/users.py b/toolkits/asana/arcade_asana/tools/users.py index 86368fc9..d65bedc4 100644 --- a/toolkits/asana/arcade_asana/tools/users.py +++ b/toolkits/asana/arcade_asana/tools/users.py @@ -1,7 +1,7 @@ from typing import Annotated, Any -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Asana +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Asana from arcade_asana.constants import USER_OPT_FIELDS from arcade_asana.models import AsanaClient diff --git a/toolkits/asana/arcade_asana/tools/workspaces.py b/toolkits/asana/arcade_asana/tools/workspaces.py index 2709135a..72c02478 100644 --- a/toolkits/asana/arcade_asana/tools/workspaces.py +++ b/toolkits/asana/arcade_asana/tools/workspaces.py @@ -1,7 +1,7 @@ from typing import Annotated, Any -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Asana +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Asana from arcade_asana.constants import WORKSPACE_OPT_FIELDS from arcade_asana.models import AsanaClient diff --git a/toolkits/asana/arcade_asana/utils.py b/toolkits/asana/arcade_asana/utils.py index f804f8dd..4d1733a1 100644 --- a/toolkits/asana/arcade_asana/utils.py +++ b/toolkits/asana/arcade_asana/utils.py @@ -4,8 +4,8 @@ from collections.abc import Awaitable from datetime import datetime from typing import Any, Callable, TypeVar, cast -from arcade.sdk import ToolContext -from arcade.sdk.errors import RetryableToolError, ToolExecutionError +from arcade_tdk import ToolContext +from arcade_tdk.errors import RetryableToolError, ToolExecutionError from arcade_asana.constants import ( ASANA_MAX_TIMEOUT_SECONDS, diff --git a/toolkits/asana/conftest.py b/toolkits/asana/conftest.py index 6e522ac6..412413c9 100644 --- a/toolkits/asana/conftest.py +++ b/toolkits/asana/conftest.py @@ -1,7 +1,7 @@ from unittest.mock import patch import pytest -from arcade.sdk import ToolAuthorizationContext, ToolContext +from arcade_tdk import ToolAuthorizationContext, ToolContext @pytest.fixture diff --git a/toolkits/asana/evals/eval_create_task.py b/toolkits/asana/evals/eval_create_task.py index 418317f7..0bef1bc2 100644 --- a/toolkits/asana/evals/eval_create_task.py +++ b/toolkits/asana/evals/eval_create_task.py @@ -1,11 +1,11 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( + BinaryCritic, EvalRubric, EvalSuite, ExpectedToolCall, tool_eval, ) -from arcade.sdk.eval.critic import BinaryCritic +from arcade_tdk import ToolCatalog import arcade_asana from arcade_asana.tools import ( diff --git a/toolkits/asana/evals/eval_projects.py b/toolkits/asana/evals/eval_projects.py index 980ab313..eb556296 100644 --- a/toolkits/asana/evals/eval_projects.py +++ b/toolkits/asana/evals/eval_projects.py @@ -1,13 +1,13 @@ import json -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( + BinaryCritic, EvalRubric, EvalSuite, ExpectedToolCall, tool_eval, ) -from arcade.sdk.eval.critic import BinaryCritic +from arcade_tdk import ToolCatalog import arcade_asana from arcade_asana.tools import get_project_by_id, list_projects diff --git a/toolkits/asana/evals/eval_tags.py b/toolkits/asana/evals/eval_tags.py index d706658b..0d377a34 100644 --- a/toolkits/asana/evals/eval_tags.py +++ b/toolkits/asana/evals/eval_tags.py @@ -1,13 +1,13 @@ import json -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( + BinaryCritic, EvalRubric, EvalSuite, ExpectedToolCall, tool_eval, ) -from arcade.sdk.eval.critic import BinaryCritic +from arcade_tdk import ToolCatalog import arcade_asana from arcade_asana.tools import create_tag, list_tags diff --git a/toolkits/asana/evals/eval_tasks.py b/toolkits/asana/evals/eval_tasks.py index 2b9d0b8f..445cdd0f 100644 --- a/toolkits/asana/evals/eval_tasks.py +++ b/toolkits/asana/evals/eval_tasks.py @@ -1,13 +1,13 @@ import json -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( + BinaryCritic, EvalRubric, EvalSuite, ExpectedToolCall, tool_eval, ) -from arcade.sdk.eval.critic import BinaryCritic +from arcade_tdk import ToolCatalog import arcade_asana from arcade_asana.constants import SortOrder, TaskSortBy diff --git a/toolkits/asana/evals/eval_teams.py b/toolkits/asana/evals/eval_teams.py index 0fabd02e..79778de8 100644 --- a/toolkits/asana/evals/eval_teams.py +++ b/toolkits/asana/evals/eval_teams.py @@ -1,13 +1,13 @@ import json -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( + BinaryCritic, EvalRubric, EvalSuite, ExpectedToolCall, tool_eval, ) -from arcade.sdk.eval.critic import BinaryCritic +from arcade_tdk import ToolCatalog import arcade_asana from arcade_asana.tools import get_team_by_id, list_teams_the_current_user_is_a_member_of diff --git a/toolkits/asana/evals/eval_users.py b/toolkits/asana/evals/eval_users.py index 694172bc..0021ec5e 100644 --- a/toolkits/asana/evals/eval_users.py +++ b/toolkits/asana/evals/eval_users.py @@ -1,13 +1,13 @@ import json -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( + BinaryCritic, EvalRubric, EvalSuite, ExpectedToolCall, tool_eval, ) -from arcade.sdk.eval.critic import BinaryCritic +from arcade_tdk import ToolCatalog import arcade_asana from arcade_asana.tools import get_user_by_id, list_users diff --git a/toolkits/asana/evals/eval_workspaces.py b/toolkits/asana/evals/eval_workspaces.py index 4811fd3b..b21a2124 100644 --- a/toolkits/asana/evals/eval_workspaces.py +++ b/toolkits/asana/evals/eval_workspaces.py @@ -1,13 +1,13 @@ import json -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( + BinaryCritic, EvalRubric, EvalSuite, ExpectedToolCall, tool_eval, ) -from arcade.sdk.eval.critic import BinaryCritic +from arcade_tdk import ToolCatalog import arcade_asana from arcade_asana.tools import list_workspaces diff --git a/toolkits/asana/pyproject.toml b/toolkits/asana/pyproject.toml index dff3258e..57fc7cd3 100644 --- a/toolkits/asana/pyproject.toml +++ b/toolkits/asana/pyproject.toml @@ -1,30 +1,42 @@ -[tool.poetry] +[build-system] +requires = [ "hatchling",] +build-backend = "hatchling.build" + +[project] name = "arcade_asana" version = "0.1.0" description = "Arcade tools designed for LLMs to interact with Asana" -authors = ["Arcade "] +requires-python = ">=3.10" +dependencies = [ + "arcade-tdk>=2.0.0,<3.0.0", + "httpx>=0.27.2,<1.0.0", +] +[[project.authors]] +name = "Arcade" +email = "dev@arcade.dev" -[tool.poetry.dependencies] -python = "^3.10" -arcade-ai = ">=1.4.0,<2.0" -httpx = "^0.27.2" +[project.optional-dependencies] +dev = [ + "arcade-ai[evals]>=2.0.0,<3.0.0", + "arcade-serve>=2.0.0,<3.0.0", + "pytest>=8.3.0,<8.4.0", + "pytest-cov>=4.0.0,<4.1.0", + "pytest-asyncio>=0.24.0,<0.25.0", + "pytest-mock>=3.11.1,<3.12.0", + "mypy>=1.5.1,<1.6.0", + "pre-commit>=3.4.0,<3.5.0", + "tox>=4.11.1,<4.12.0", + "ruff>=0.7.4,<0.8.0", +] -[tool.poetry.dev-dependencies] -pytest = "^8.3.0" -pytest-cov = "^4.0.0" -pytest-asyncio = "^0.24.0" -pytest-mock = "^3.11.1" -mypy = "^1.5.1" -pre-commit = "^3.4.0" -tox = "^4.11.1" -ruff = "^0.7.4" - -[build-system] -requires = ["poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" +# Use local path sources for arcade libs when working locally +[tool.uv.sources] +arcade-ai = {path = "../../", editable = true} +arcade-tdk = { path = "../../libs/arcade-tdk/", editable = true } +arcade-serve = { path = "../../libs/arcade-serve/", editable = true } [tool.mypy] -files = ["arcade_asana/**/*.py"] +files = [ "arcade_asana/**/*.py",] python_version = "3.10" disallow_untyped_defs = "True" disallow_any_unimported = "True" @@ -36,7 +48,10 @@ show_error_codes = "True" ignore_missing_imports = "True" [tool.pytest.ini_options] -testpaths = ["tests"] +testpaths = [ "tests",] [tool.coverage.report] skip_empty = true + +[tool.hatch.build.targets.wheel] +packages = [ "arcade_asana",] diff --git a/toolkits/asana/tests/test_utils.py b/toolkits/asana/tests/test_utils.py index d73ba0ab..29e22760 100644 --- a/toolkits/asana/tests/test_utils.py +++ b/toolkits/asana/tests/test_utils.py @@ -1,7 +1,7 @@ from unittest.mock import patch import pytest -from arcade.sdk.errors import RetryableToolError +from arcade_tdk.errors import RetryableToolError from arcade_asana.utils import ( get_project_by_name_or_raise_error, diff --git a/toolkits/code_sandbox/.pre-commit-config.yaml b/toolkits/code_sandbox/.pre-commit-config.yaml index 3953e996..6d815ab5 100644 --- a/toolkits/code_sandbox/.pre-commit-config.yaml +++ b/toolkits/code_sandbox/.pre-commit-config.yaml @@ -1,4 +1,4 @@ -files: ^./ +files: ^.*/code_sandbox/.* repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: "v4.4.0" diff --git a/toolkits/code_sandbox/Makefile b/toolkits/code_sandbox/Makefile index b4222577..7e2c686e 100644 --- a/toolkits/code_sandbox/Makefile +++ b/toolkits/code_sandbox/Makefile @@ -1,30 +1,27 @@ .PHONY: help help: - @echo "๐Ÿ› ๏ธ code_sandbox Commands:\n" + @echo "๐Ÿ› ๏ธ github Commands:\n" @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' .PHONY: install -install: ## Install the poetry environment and install the pre-commit hooks - @echo "๐Ÿ“ฆ Checking if Poetry is installed" - @if ! command -v poetry >/dev/null 2>&1; then \ - echo "๐Ÿ“ฆ Poetry not found. Checking if pip is available"; \ - if ! command -v pip >/dev/null 2>&1; then \ - echo "โŒ pip is not installed. Please install pip first."; \ - exit 1; \ - fi; \ - echo "๐Ÿ“ฆ Installing Poetry with pip"; \ - pip install poetry==1.8.5; \ - else \ - echo "๐Ÿ“ฆ Poetry is already installed"; \ - fi - @echo "๐Ÿš€ Installing package in development mode with all extras" - poetry install --all-extras +install: ## Install the uv environment and install all packages with dependencies + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras --no-sources + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" + +.PHONY: install-local +install-local: ## Install the uv environment and install all packages with dependencies with local Arcade sources + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" .PHONY: build build: clean-build ## Build wheel file using poetry @echo "๐Ÿš€ Creating wheel file" - poetry build + uv build .PHONY: clean-build clean-build: ## clean build artifacts @@ -34,7 +31,7 @@ clean-build: ## clean build artifacts .PHONY: test test: ## Test the code with pytest @echo "๐Ÿš€ Testing code: Running pytest" - @poetry run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml + @uv run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml .PHONY: coverage coverage: ## Generate coverage report @@ -44,15 +41,13 @@ coverage: ## Generate coverage report coverage html .PHONY: bump-version -bump-version: ## Bump the version in the pyproject.toml file +bump-version: ## Bump the version in the pyproject.toml file by a patch version @echo "๐Ÿš€ Bumping version in pyproject.toml" - poetry version patch + uv version --bump patch .PHONY: check check: ## Run code quality tools. - @echo "๐Ÿš€ Checking Poetry lock file consistency with 'pyproject.toml': Running poetry check" - @poetry check @echo "๐Ÿš€ Linting code: Running pre-commit" - @poetry run pre-commit run -a + @uv run pre-commit run -a @echo "๐Ÿš€ Static type checking: Running mypy" - @poetry run mypy --config-file=pyproject.toml + @uv run mypy --config-file=pyproject.toml diff --git a/toolkits/code_sandbox/arcade_code_sandbox/tools/e2b.py b/toolkits/code_sandbox/arcade_code_sandbox/tools/e2b.py index 26432b7d..cbe3934c 100644 --- a/toolkits/code_sandbox/arcade_code_sandbox/tools/e2b.py +++ b/toolkits/code_sandbox/arcade_code_sandbox/tools/e2b.py @@ -1,6 +1,6 @@ from typing import Annotated -from arcade.sdk import ToolContext, tool +from arcade_tdk import ToolContext, tool from e2b_code_interpreter import Sandbox from arcade_code_sandbox.tools.models import E2BSupportedLanguage diff --git a/toolkits/code_sandbox/evals/eval_e2b.py b/toolkits/code_sandbox/evals/eval_e2b.py index 75eb7d13..f92bf05e 100644 --- a/toolkits/code_sandbox/evals/eval_e2b.py +++ b/toolkits/code_sandbox/evals/eval_e2b.py @@ -1,5 +1,4 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, EvalRubric, EvalSuite, @@ -7,6 +6,7 @@ from arcade.sdk.eval import ( SimilarityCritic, tool_eval, ) +from arcade_tdk import ToolCatalog import arcade_code_sandbox from arcade_code_sandbox.tools.e2b import create_static_matplotlib_chart, run_code diff --git a/toolkits/code_sandbox/pyproject.toml b/toolkits/code_sandbox/pyproject.toml index 769cc6f5..13e0f5b1 100644 --- a/toolkits/code_sandbox/pyproject.toml +++ b/toolkits/code_sandbox/pyproject.toml @@ -1,30 +1,42 @@ -[tool.poetry] +[build-system] +requires = [ "hatchling",] +build-backend = "hatchling.build" + +[project] name = "arcade_code_sandbox" version = "1.0.0" description = "Arcade.dev LLM tools for running code in a sandbox" -authors = ["Arcade "] +requires-python = ">=3.10" +dependencies = [ + "arcade-tdk>=2.0.0,<3.0.0", + "e2b-code-interpreter>=1.0.1,<2.0.0", +] +[[project.authors]] +name = "Arcade" +email = "dev@arcade.dev" -[tool.poetry.dependencies] -python = "^3.10" -arcade-ai = ">=1.0.5,<2.0" -e2b-code-interpreter = "^1.0.1" +[project.optional-dependencies] +dev = [ + "arcade-ai[evals]>=2.0.0,<3.0.0", + "arcade-serve>=2.0.0,<3.0.0", + "pytest>=8.3.0,<8.4.0", + "pytest-cov>=4.0.0,<4.1.0", + "pytest-asyncio>=0.24.0,<0.25.0", + "pytest-mock>=3.11.1,<3.12.0", + "mypy>=1.5.1,<1.6.0", + "pre-commit>=3.4.0,<3.5.0", + "tox>=4.11.1,<4.12.0", + "ruff>=0.7.4,<0.8.0", +] -[tool.poetry.dev-dependencies] -pytest = "^8.3.0" -pytest-cov = "^4.0.0" -pytest-asyncio = "^0.24.0" -pytest-mock = "^3.11.1" -mypy = "^1.5.1" -pre-commit = "^3.4.0" -tox = "^4.11.1" -ruff = "^0.7.4" - -[build-system] -requires = ["poetry-core>=1.0.0,<2.0.0"] -build-backend = "poetry.core.masonry.api" +# Use local path sources for arcade libs when working locally +[tool.uv.sources] +arcade-ai = {path = "../../", editable = true} +arcade-tdk = { path = "../../libs/arcade-tdk/", editable = true } +arcade-serve = { path = "../../libs/arcade-serve/", editable = true } [tool.mypy] -files = ["arcade_code_sandbox/**/*.py"] +files = [ "arcade_code_sandbox/**/*.py",] python_version = "3.10" disallow_untyped_defs = "True" disallow_any_unimported = "True" @@ -36,7 +48,10 @@ show_error_codes = "True" ignore_missing_imports = "True" [tool.pytest.ini_options] -testpaths = ["tests"] +testpaths = [ "tests",] [tool.coverage.report] skip_empty = true + +[tool.hatch.build.targets.wheel] +packages = [ "arcade_code_sandbox",] diff --git a/toolkits/code_sandbox/tests/test_e2b.py b/toolkits/code_sandbox/tests/test_e2b.py index 8af6d49c..ce29dc56 100644 --- a/toolkits/code_sandbox/tests/test_e2b.py +++ b/toolkits/code_sandbox/tests/test_e2b.py @@ -1,9 +1,8 @@ from unittest.mock import MagicMock, patch import pytest -from arcade.core.schema import ToolSecretItem -from arcade.sdk import ToolContext -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk import ToolContext, ToolSecretItem +from arcade_tdk.errors import ToolExecutionError from arcade_code_sandbox.tools.e2b import create_static_matplotlib_chart, run_code from arcade_code_sandbox.tools.models import E2BSupportedLanguage diff --git a/toolkits/confluence/.pre-commit-config.yaml b/toolkits/confluence/.pre-commit-config.yaml index 3953e996..abac2158 100644 --- a/toolkits/confluence/.pre-commit-config.yaml +++ b/toolkits/confluence/.pre-commit-config.yaml @@ -1,4 +1,4 @@ -files: ^./ +files: ^.*/confluence/.* repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: "v4.4.0" diff --git a/toolkits/confluence/Makefile b/toolkits/confluence/Makefile index 62a13fbc..7e2c686e 100644 --- a/toolkits/confluence/Makefile +++ b/toolkits/confluence/Makefile @@ -1,30 +1,27 @@ .PHONY: help help: - @echo "๐Ÿ› ๏ธ confluence Commands:\n" + @echo "๐Ÿ› ๏ธ github Commands:\n" @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' .PHONY: install -install: ## Install the poetry environment and install the pre-commit hooks - @echo "๐Ÿ“ฆ Checking if Poetry is installed" - @if ! command -v poetry >/dev/null 2>&1; then \ - echo "๐Ÿ“ฆ Poetry not found. Checking if pip is available"; \ - if ! command -v pip >/dev/null 2>&1; then \ - echo "โŒ pip is not installed. Please install pip first."; \ - exit 1; \ - fi; \ - echo "๐Ÿ“ฆ Installing Poetry with pip"; \ - pip install poetry==1.8.5; \ - else \ - echo "๐Ÿ“ฆ Poetry is already installed"; \ - fi - @echo "๐Ÿš€ Installing package in development mode with all extras" - poetry install --all-extras +install: ## Install the uv environment and install all packages with dependencies + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras --no-sources + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" + +.PHONY: install-local +install-local: ## Install the uv environment and install all packages with dependencies with local Arcade sources + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" .PHONY: build build: clean-build ## Build wheel file using poetry @echo "๐Ÿš€ Creating wheel file" - poetry build + uv build .PHONY: clean-build clean-build: ## clean build artifacts @@ -34,7 +31,7 @@ clean-build: ## clean build artifacts .PHONY: test test: ## Test the code with pytest @echo "๐Ÿš€ Testing code: Running pytest" - @poetry run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml + @uv run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml .PHONY: coverage coverage: ## Generate coverage report @@ -44,15 +41,13 @@ coverage: ## Generate coverage report coverage html .PHONY: bump-version -bump-version: ## Bump the version in the pyproject.toml file +bump-version: ## Bump the version in the pyproject.toml file by a patch version @echo "๐Ÿš€ Bumping version in pyproject.toml" - poetry version patch + uv version --bump patch .PHONY: check check: ## Run code quality tools. - @echo "๐Ÿš€ Checking Poetry lock file consistency with 'pyproject.toml': Running poetry check" - @poetry check @echo "๐Ÿš€ Linting code: Running pre-commit" - @poetry run pre-commit run -a + @uv run pre-commit run -a @echo "๐Ÿš€ Static type checking: Running mypy" - @poetry run mypy --config-file=pyproject.toml + @uv run mypy --config-file=pyproject.toml diff --git a/toolkits/confluence/arcade_confluence/client.py b/toolkits/confluence/arcade_confluence/client.py index 928159d5..5415d16c 100644 --- a/toolkits/confluence/arcade_confluence/client.py +++ b/toolkits/confluence/arcade_confluence/client.py @@ -3,7 +3,7 @@ from typing import Any from urllib.parse import parse_qs, urlparse import httpx -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk.errors import ToolExecutionError from arcade_confluence.enums import BodyFormat, PageUpdateMode from arcade_confluence.utils import ( @@ -239,7 +239,8 @@ class ConfluenceClientV2(ConfluenceClient): to absolute URLs using the base URL from the response. """ pagination_token = parse_qs(urlparse(response.get("_links", {}).get("next", "")).query).get( - "cursor", [None] + "cursor", + [None], # type: ignore[list-item] )[0] base_url = response.get("_links", {}).get("base", "") @@ -260,7 +261,8 @@ class ConfluenceClientV2(ConfluenceClient): def transform_list_pages_response(self, response: dict[str, Any]) -> dict[str, Any]: """Transform the response from the GET /pages endpoint.""" pagination_token = parse_qs(urlparse(response.get("_links", {}).get("next", "")).query).get( - "cursor", [None] + "cursor", + [None], # type: ignore[list-item] )[0] base_url = response.get("_links", {}).get("base", "") @@ -289,7 +291,8 @@ class ConfluenceClientV2(ConfluenceClient): def transform_get_attachments_response(self, response: dict[str, Any]) -> dict[str, Any]: """Transform the response from the GET /pages/{id}/attachments endpoint.""" pagination_token = parse_qs(urlparse(response.get("_links", {}).get("next", "")).query).get( - "cursor", [None] + "cursor", + [None], # type: ignore[list-item] )[0] base_url = response.get("_links", {}).get("base", "") diff --git a/toolkits/confluence/arcade_confluence/tools/attachment.py b/toolkits/confluence/arcade_confluence/tools/attachment.py index 8f599929..7d4f6466 100644 --- a/toolkits/confluence/arcade_confluence/tools/attachment.py +++ b/toolkits/confluence/arcade_confluence/tools/attachment.py @@ -1,7 +1,7 @@ from typing import Annotated -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Atlassian +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Atlassian from arcade_confluence.client import ConfluenceClientV2 from arcade_confluence.enums import AttachmentSortOrder diff --git a/toolkits/confluence/arcade_confluence/tools/page.py b/toolkits/confluence/arcade_confluence/tools/page.py index fc09603b..a0758001 100644 --- a/toolkits/confluence/arcade_confluence/tools/page.py +++ b/toolkits/confluence/arcade_confluence/tools/page.py @@ -1,8 +1,8 @@ from typing import Annotated -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Atlassian -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Atlassian +from arcade_tdk.errors import ToolExecutionError from arcade_confluence.client import ConfluenceClientV2 from arcade_confluence.enums import BodyFormat, PageSortOrder, PageUpdateMode diff --git a/toolkits/confluence/arcade_confluence/tools/search.py b/toolkits/confluence/arcade_confluence/tools/search.py index 460d344d..478199ea 100644 --- a/toolkits/confluence/arcade_confluence/tools/search.py +++ b/toolkits/confluence/arcade_confluence/tools/search.py @@ -1,7 +1,7 @@ from typing import Annotated -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Atlassian +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Atlassian from arcade_confluence.client import ConfluenceClientV1 diff --git a/toolkits/confluence/arcade_confluence/tools/space.py b/toolkits/confluence/arcade_confluence/tools/space.py index 9599603e..1d0ec0bc 100644 --- a/toolkits/confluence/arcade_confluence/tools/space.py +++ b/toolkits/confluence/arcade_confluence/tools/space.py @@ -1,8 +1,8 @@ import re from typing import Annotated -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Atlassian +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Atlassian from arcade_confluence.client import ConfluenceClientV2 from arcade_confluence.utils import remove_none_values diff --git a/toolkits/confluence/arcade_confluence/utils.py b/toolkits/confluence/arcade_confluence/utils.py index 9ea1f47d..349f41d9 100644 --- a/toolkits/confluence/arcade_confluence/utils.py +++ b/toolkits/confluence/arcade_confluence/utils.py @@ -1,6 +1,6 @@ import re -from arcade.sdk.errors import RetryableToolError, ToolExecutionError +from arcade_tdk.errors import RetryableToolError, ToolExecutionError def remove_none_values(data: dict) -> dict: diff --git a/toolkits/confluence/evals/critics.py b/toolkits/confluence/evals/critics.py index 7a78bbd4..f2c90a75 100644 --- a/toolkits/confluence/evals/critics.py +++ b/toolkits/confluence/evals/critics.py @@ -1,7 +1,7 @@ from dataclasses import dataclass from typing import Any -from arcade.sdk.eval.critic import Critic +from arcade_evals.critic import Critic @dataclass diff --git a/toolkits/confluence/evals/eval_page.py b/toolkits/confluence/evals/eval_page.py index 2ea55764..ef46c264 100644 --- a/toolkits/confluence/evals/eval_page.py +++ b/toolkits/confluence/evals/eval_page.py @@ -1,11 +1,12 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( + BinaryCritic, EvalRubric, EvalSuite, ExpectedToolCall, + SimilarityCritic, tool_eval, ) -from arcade.sdk.eval.critic import BinaryCritic, SimilarityCritic +from arcade_tdk import ToolCatalog import arcade_confluence from arcade_confluence.enums import PageUpdateMode diff --git a/toolkits/confluence/evals/eval_search.py b/toolkits/confluence/evals/eval_search.py index 5a5e8ba4..7c361fc6 100644 --- a/toolkits/confluence/evals/eval_search.py +++ b/toolkits/confluence/evals/eval_search.py @@ -1,11 +1,11 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( + BinaryCritic, EvalRubric, EvalSuite, ExpectedToolCall, tool_eval, ) -from arcade.sdk.eval.critic import BinaryCritic +from arcade_tdk import ToolCatalog import arcade_confluence from arcade_confluence.tools import ( diff --git a/toolkits/confluence/evals/eval_space.py b/toolkits/confluence/evals/eval_space.py index 688e3a33..bc07848f 100644 --- a/toolkits/confluence/evals/eval_space.py +++ b/toolkits/confluence/evals/eval_space.py @@ -1,11 +1,11 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( + BinaryCritic, EvalRubric, EvalSuite, ExpectedToolCall, tool_eval, ) -from arcade.sdk.eval.critic import BinaryCritic +from arcade_tdk import ToolCatalog import arcade_confluence from arcade_confluence.tools import ( diff --git a/toolkits/confluence/pyproject.toml b/toolkits/confluence/pyproject.toml index 6b9009d6..a29df5d4 100644 --- a/toolkits/confluence/pyproject.toml +++ b/toolkits/confluence/pyproject.toml @@ -1,29 +1,41 @@ -[tool.poetry] +[build-system] +requires = [ "hatchling",] +build-backend = "hatchling.build" + +[project] name = "arcade_confluence" version = "0.0.1" description = "Arcade.dev LLM tools for Confluence" -authors = ["Arcade "] +requires-python = ">=3.10" +dependencies = [ + "arcade-tdk>=2.0.0,<3.0.0", + "httpx>=0.27.2,<1.0.0", +] +[[project.authors]] +name = "Arcade" +email = "dev@arcade.dev" -[tool.poetry.dependencies] -python = "^3.10" -arcade-ai = "^1.0.5" -httpx = "^0.27.2" +[project.optional-dependencies] +dev = [ + "arcade-ai[evals]>=2.0.0,<3.0.0", + "arcade-serve>=2.0.0,<3.0.0", + "pytest>=8.3.0,<8.4.0", + "pytest-cov>=4.0.0,<4.1.0", + "pytest-asyncio>=0.24.0,<0.25.0", + "mypy>=1.5.1,<1.6.0", + "pre-commit>=3.4.0,<3.5.0", + "tox>=4.11.1,<4.12.0", + "ruff>=0.7.4,<0.8.0", +] -[tool.poetry.dev-dependencies] -pytest = "^8.3.0" -pytest-cov = "^4.0.0" -mypy = "^1.5.1" -pre-commit = "^3.4.0" -tox = "^4.11.1" -ruff = "^0.7.4" -pytest-asyncio = "^0.24.0" - -[build-system] -requires = ["poetry-core>=1.0.0,<2.0.0"] -build-backend = "poetry.core.masonry.api" +# Use local path sources for arcade libs when working locally +[tool.uv.sources] +arcade-ai = {path = "../../", editable = true} +arcade-tdk = { path = "../../libs/arcade-tdk/", editable = true } +arcade-serve = { path = "../../libs/arcade-serve/", editable = true } [tool.mypy] -files = ["arcade_confluence/**/*.py"] +files = [ "arcade_confluence/**/*.py",] python_version = "3.10" disallow_untyped_defs = "True" disallow_any_unimported = "True" @@ -35,7 +47,10 @@ show_error_codes = "True" ignore_missing_imports = "True" [tool.pytest.ini_options] -testpaths = ["tests"] +testpaths = [ "tests",] [tool.coverage.report] skip_empty = true + +[tool.hatch.build.targets.wheel] +packages = [ "arcade_confluence",] diff --git a/toolkits/confluence/tests/test_client_v1.py b/toolkits/confluence/tests/test_client_v1.py index 94c3da21..d6561212 100644 --- a/toolkits/confluence/tests/test_client_v1.py +++ b/toolkits/confluence/tests/test_client_v1.py @@ -1,7 +1,7 @@ from unittest.mock import patch import pytest -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk.errors import ToolExecutionError from arcade_confluence.client import ConfluenceClientV1 diff --git a/toolkits/confluence/tests/test_utils.py b/toolkits/confluence/tests/test_utils.py index 6388d35a..46bed976 100644 --- a/toolkits/confluence/tests/test_utils.py +++ b/toolkits/confluence/tests/test_utils.py @@ -1,5 +1,5 @@ import pytest -from arcade.sdk.errors import RetryableToolError, ToolExecutionError +from arcade_tdk.errors import RetryableToolError, ToolExecutionError from arcade_confluence.utils import build_child_url, build_hierarchy, validate_ids diff --git a/toolkits/dropbox/.pre-commit-config.yaml b/toolkits/dropbox/.pre-commit-config.yaml index 3953e996..866e6e38 100644 --- a/toolkits/dropbox/.pre-commit-config.yaml +++ b/toolkits/dropbox/.pre-commit-config.yaml @@ -1,4 +1,4 @@ -files: ^./ +files: ^.*/dropbox/.* repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: "v4.4.0" diff --git a/toolkits/dropbox/Makefile b/toolkits/dropbox/Makefile index 8ca4a804..7e2c686e 100644 --- a/toolkits/dropbox/Makefile +++ b/toolkits/dropbox/Makefile @@ -1,25 +1,27 @@ .PHONY: help help: - @echo "๐Ÿ› ๏ธ dropbox Commands:\n" + @echo "๐Ÿ› ๏ธ github Commands:\n" @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' .PHONY: install -install: ## Install the poetry environment and install the pre-commit hooks - @echo "๐Ÿ“ฆ Checking if Poetry is installed" - @if ! command -v poetry &> /dev/null; then \ - echo "๐Ÿ“ฆ Installing Poetry with pip"; \ - pip install poetry==1.8.5; \ - else \ - echo "๐Ÿ“ฆ Poetry is already installed"; \ - fi - @echo "๐Ÿš€ Installing package in development mode with all extras" - poetry install --all-extras +install: ## Install the uv environment and install all packages with dependencies + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras --no-sources + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" + +.PHONY: install-local +install-local: ## Install the uv environment and install all packages with dependencies with local Arcade sources + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" .PHONY: build build: clean-build ## Build wheel file using poetry @echo "๐Ÿš€ Creating wheel file" - poetry build + uv build .PHONY: clean-build clean-build: ## clean build artifacts @@ -29,7 +31,7 @@ clean-build: ## clean build artifacts .PHONY: test test: ## Test the code with pytest @echo "๐Ÿš€ Testing code: Running pytest" - @poetry run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml + @uv run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml .PHONY: coverage coverage: ## Generate coverage report @@ -39,15 +41,13 @@ coverage: ## Generate coverage report coverage html .PHONY: bump-version -bump-version: ## Bump the version in the pyproject.toml file +bump-version: ## Bump the version in the pyproject.toml file by a patch version @echo "๐Ÿš€ Bumping version in pyproject.toml" - poetry version patch + uv version --bump patch .PHONY: check check: ## Run code quality tools. - @echo "๐Ÿš€ Checking Poetry lock file consistency with 'pyproject.toml': Running poetry check" - @poetry check @echo "๐Ÿš€ Linting code: Running pre-commit" - @poetry run pre-commit run -a + @uv run pre-commit run -a @echo "๐Ÿš€ Static type checking: Running mypy" - @poetry run mypy --config-file=pyproject.toml + @uv run mypy --config-file=pyproject.toml diff --git a/toolkits/dropbox/arcade_dropbox/critics.py b/toolkits/dropbox/arcade_dropbox/critics.py index e6871f4b..7bfd4343 100644 --- a/toolkits/dropbox/arcade_dropbox/critics.py +++ b/toolkits/dropbox/arcade_dropbox/critics.py @@ -1,6 +1,6 @@ from typing import Any -from arcade.sdk.eval import BinaryCritic +from arcade_evals import BinaryCritic class DropboxPathCritic(BinaryCritic): diff --git a/toolkits/dropbox/arcade_dropbox/tools/browse.py b/toolkits/dropbox/arcade_dropbox/tools/browse.py index a8cf965c..6df1d6a9 100644 --- a/toolkits/dropbox/arcade_dropbox/tools/browse.py +++ b/toolkits/dropbox/arcade_dropbox/tools/browse.py @@ -1,8 +1,8 @@ from typing import Annotated, Optional -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Dropbox -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Dropbox +from arcade_tdk.errors import ToolExecutionError from arcade_dropbox.constants import Endpoint, ItemCategory from arcade_dropbox.exceptions import DropboxApiError diff --git a/toolkits/dropbox/arcade_dropbox/tools/files.py b/toolkits/dropbox/arcade_dropbox/tools/files.py index 194a101f..d30f8e04 100644 --- a/toolkits/dropbox/arcade_dropbox/tools/files.py +++ b/toolkits/dropbox/arcade_dropbox/tools/files.py @@ -1,8 +1,8 @@ from typing import Annotated, Optional -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Dropbox -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Dropbox +from arcade_tdk.errors import ToolExecutionError from arcade_dropbox.constants import Endpoint from arcade_dropbox.exceptions import DropboxApiError diff --git a/toolkits/dropbox/conftest.py b/toolkits/dropbox/conftest.py index 5390b526..6bcdea17 100644 --- a/toolkits/dropbox/conftest.py +++ b/toolkits/dropbox/conftest.py @@ -1,7 +1,7 @@ from unittest.mock import patch import pytest -from arcade.sdk import ToolAuthorizationContext, ToolContext +from arcade_tdk import ToolAuthorizationContext, ToolContext @pytest.fixture diff --git a/toolkits/dropbox/evals/eval_download_file.py b/toolkits/dropbox/evals/eval_download_file.py index 328a90d4..c2d8c521 100644 --- a/toolkits/dropbox/evals/eval_download_file.py +++ b/toolkits/dropbox/evals/eval_download_file.py @@ -1,11 +1,11 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, EvalRubric, EvalSuite, ExpectedToolCall, tool_eval, ) +from arcade_tdk import ToolCatalog import arcade_dropbox from arcade_dropbox.critics import DropboxPathCritic diff --git a/toolkits/dropbox/evals/eval_list_items.py b/toolkits/dropbox/evals/eval_list_items.py index de1d84e1..53100cb3 100644 --- a/toolkits/dropbox/evals/eval_list_items.py +++ b/toolkits/dropbox/evals/eval_list_items.py @@ -1,11 +1,11 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, EvalRubric, EvalSuite, ExpectedToolCall, tool_eval, ) +from arcade_tdk import ToolCatalog import arcade_dropbox from arcade_dropbox.critics import DropboxPathCritic diff --git a/toolkits/dropbox/evals/eval_search.py b/toolkits/dropbox/evals/eval_search.py index 8a0dd2df..eecfc471 100644 --- a/toolkits/dropbox/evals/eval_search.py +++ b/toolkits/dropbox/evals/eval_search.py @@ -1,11 +1,11 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, EvalRubric, EvalSuite, ExpectedToolCall, tool_eval, ) +from arcade_tdk import ToolCatalog import arcade_dropbox from arcade_dropbox.constants import ItemCategory diff --git a/toolkits/dropbox/pyproject.toml b/toolkits/dropbox/pyproject.toml index abaf4c5d..2c8b2b63 100644 --- a/toolkits/dropbox/pyproject.toml +++ b/toolkits/dropbox/pyproject.toml @@ -1,30 +1,42 @@ -[tool.poetry] +[build-system] +requires = [ "hatchling",] +build-backend = "hatchling.build" + +[project] name = "arcade_dropbox" version = "0.1.1" description = "Arcade tools designed for LLMs to interact with Dropbox" -authors = ["Arcade "] +requires-python = ">=3.10" +dependencies = [ + "arcade-tdk>=2.0.0,<3.0.0", + "httpx>=0.27.2,<1.0.0", +] +[[project.authors]] +name = "Arcade" +email = "dev@arcade.dev" -[tool.poetry.dependencies] -python = "^3.10" -arcade-ai = ">=1.0.5,<2.0" -httpx = "^0.27.2" +[project.optional-dependencies] +dev = [ + "arcade-ai[evals]>=2.0.0,<3.0.0", + "arcade-serve>=2.0.0,<3.0.0", + "pytest>=8.3.0,<8.4.0", + "pytest-cov>=4.0.0,<4.1.0", + "pytest-asyncio>=0.24.0,<0.25.0", + "pytest-mock>=3.11.1,<3.12.0", + "mypy>=1.5.1,<1.6.0", + "pre-commit>=3.4.0,<3.5.0", + "tox>=4.11.1,<4.12.0", + "ruff>=0.7.4,<0.8.0", +] -[tool.poetry.dev-dependencies] -pytest = "^8.3.0" -pytest-cov = "^4.0.0" -pytest-asyncio = "^0.24.0" -pytest-mock = "^3.11.1" -mypy = "^1.5.1" -pre-commit = "^3.4.0" -tox = "^4.11.1" -ruff = "^0.7.4" - -[build-system] -requires = ["poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" +# Use local path sources for arcade libs when working locally +[tool.uv.sources] +arcade-ai = {path = "../../", editable = true} +arcade-tdk = { path = "../../libs/arcade-tdk/", editable = true } +arcade-serve = { path = "../../libs/arcade-serve/", editable = true } [tool.mypy] -files = ["arcade_dropbox/**/*.py"] +files = [ "arcade_dropbox/**/*.py",] python_version = "3.10" disallow_untyped_defs = "True" disallow_any_unimported = "True" @@ -36,7 +48,10 @@ show_error_codes = "True" ignore_missing_imports = "True" [tool.pytest.ini_options] -testpaths = ["tests"] +testpaths = [ "tests",] [tool.coverage.report] skip_empty = true + +[tool.hatch.build.targets.wheel] +packages = [ "arcade_dropbox",] diff --git a/toolkits/github/.pre-commit-config.yaml b/toolkits/github/.pre-commit-config.yaml index 3953e996..748252a3 100644 --- a/toolkits/github/.pre-commit-config.yaml +++ b/toolkits/github/.pre-commit-config.yaml @@ -1,4 +1,4 @@ -files: ^./ +files: ^.*/github/.* repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: "v4.4.0" diff --git a/toolkits/github/Makefile b/toolkits/github/Makefile index ce6a89a9..7e2c686e 100644 --- a/toolkits/github/Makefile +++ b/toolkits/github/Makefile @@ -5,26 +5,23 @@ help: @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' .PHONY: install -install: ## Install the poetry environment and install the pre-commit hooks - @echo "๐Ÿ“ฆ Checking if Poetry is installed" - @if ! command -v poetry >/dev/null 2>&1; then \ - echo "๐Ÿ“ฆ Poetry not found. Checking if pip is available"; \ - if ! command -v pip >/dev/null 2>&1; then \ - echo "โŒ pip is not installed. Please install pip first."; \ - exit 1; \ - fi; \ - echo "๐Ÿ“ฆ Installing Poetry with pip"; \ - pip install poetry==1.8.5; \ - else \ - echo "๐Ÿ“ฆ Poetry is already installed"; \ - fi - @echo "๐Ÿš€ Installing package in development mode with all extras" - poetry install --all-extras +install: ## Install the uv environment and install all packages with dependencies + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras --no-sources + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" + +.PHONY: install-local +install-local: ## Install the uv environment and install all packages with dependencies with local Arcade sources + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" .PHONY: build build: clean-build ## Build wheel file using poetry @echo "๐Ÿš€ Creating wheel file" - poetry build + uv build .PHONY: clean-build clean-build: ## clean build artifacts @@ -34,7 +31,7 @@ clean-build: ## clean build artifacts .PHONY: test test: ## Test the code with pytest @echo "๐Ÿš€ Testing code: Running pytest" - @poetry run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml + @uv run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml .PHONY: coverage coverage: ## Generate coverage report @@ -44,15 +41,13 @@ coverage: ## Generate coverage report coverage html .PHONY: bump-version -bump-version: ## Bump the version in the pyproject.toml file +bump-version: ## Bump the version in the pyproject.toml file by a patch version @echo "๐Ÿš€ Bumping version in pyproject.toml" - poetry version patch + uv version --bump patch .PHONY: check check: ## Run code quality tools. - @echo "๐Ÿš€ Checking Poetry lock file consistency with 'pyproject.toml': Running poetry check" - @poetry check @echo "๐Ÿš€ Linting code: Running pre-commit" - @poetry run pre-commit run -a + @uv run pre-commit run -a @echo "๐Ÿš€ Static type checking: Running mypy" - @poetry run mypy --config-file=pyproject.toml + @uv run mypy --config-file=pyproject.toml diff --git a/toolkits/github/arcade_github/tools/activity.py b/toolkits/github/arcade_github/tools/activity.py index ba5bf4a7..b889dfba 100644 --- a/toolkits/github/arcade_github/tools/activity.py +++ b/toolkits/github/arcade_github/tools/activity.py @@ -1,8 +1,8 @@ from typing import Annotated import httpx -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import GitHub +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import GitHub from arcade_github.tools.utils import get_github_json_headers, get_url, handle_github_response diff --git a/toolkits/github/arcade_github/tools/issues.py b/toolkits/github/arcade_github/tools/issues.py index 74b99664..bfbdaed8 100644 --- a/toolkits/github/arcade_github/tools/issues.py +++ b/toolkits/github/arcade_github/tools/issues.py @@ -2,8 +2,8 @@ import json from typing import Annotated import httpx -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import GitHub +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import GitHub from arcade_github.tools.utils import ( get_github_json_headers, diff --git a/toolkits/github/arcade_github/tools/pull_requests.py b/toolkits/github/arcade_github/tools/pull_requests.py index 98f329bd..14e99e5e 100644 --- a/toolkits/github/arcade_github/tools/pull_requests.py +++ b/toolkits/github/arcade_github/tools/pull_requests.py @@ -2,9 +2,9 @@ import json from typing import Annotated import httpx -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import GitHub -from arcade.sdk.errors import RetryableToolError +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import GitHub +from arcade_tdk.errors import RetryableToolError from arcade_github.tools.models import ( DiffSide, diff --git a/toolkits/github/arcade_github/tools/repositories.py b/toolkits/github/arcade_github/tools/repositories.py index ead44fdf..d8057cd6 100644 --- a/toolkits/github/arcade_github/tools/repositories.py +++ b/toolkits/github/arcade_github/tools/repositories.py @@ -2,8 +2,8 @@ import json from typing import Annotated import httpx -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import GitHub +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import GitHub from arcade_github.tools.models import ( ActivityType, diff --git a/toolkits/github/arcade_github/tools/utils.py b/toolkits/github/arcade_github/tools/utils.py index 47983972..c44930b0 100644 --- a/toolkits/github/arcade_github/tools/utils.py +++ b/toolkits/github/arcade_github/tools/utils.py @@ -1,7 +1,7 @@ from typing import Any import httpx -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk.errors import ToolExecutionError from arcade_github.tools.constants import ENDPOINTS, GITHUB_API_BASE_URL diff --git a/toolkits/github/evals/eval_github_activity.py b/toolkits/github/evals/eval_github_activity.py index e892a9af..ba9f7e16 100644 --- a/toolkits/github/evals/eval_github_activity.py +++ b/toolkits/github/evals/eval_github_activity.py @@ -1,11 +1,11 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, EvalRubric, EvalSuite, ExpectedToolCall, tool_eval, ) +from arcade_tdk import ToolCatalog import arcade_github from arcade_github.tools.activity import list_stargazers, set_starred diff --git a/toolkits/github/evals/eval_github_issues.py b/toolkits/github/evals/eval_github_issues.py index 36bd15ba..c5eaaee7 100644 --- a/toolkits/github/evals/eval_github_issues.py +++ b/toolkits/github/evals/eval_github_issues.py @@ -1,5 +1,4 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, EvalRubric, EvalSuite, @@ -7,6 +6,7 @@ from arcade.sdk.eval import ( SimilarityCritic, tool_eval, ) +from arcade_tdk import ToolCatalog import arcade_github from arcade_github.tools.issues import ( diff --git a/toolkits/github/evals/eval_github_pull_requests.py b/toolkits/github/evals/eval_github_pull_requests.py index a6a5104a..67ce180b 100644 --- a/toolkits/github/evals/eval_github_pull_requests.py +++ b/toolkits/github/evals/eval_github_pull_requests.py @@ -1,5 +1,4 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, EvalRubric, EvalSuite, @@ -7,6 +6,7 @@ from arcade.sdk.eval import ( SimilarityCritic, tool_eval, ) +from arcade_tdk import ToolCatalog import arcade_github from arcade_github.tools.models import ( diff --git a/toolkits/github/evals/eval_github_repositories.py b/toolkits/github/evals/eval_github_repositories.py index 67a06365..b8c1e859 100644 --- a/toolkits/github/evals/eval_github_repositories.py +++ b/toolkits/github/evals/eval_github_repositories.py @@ -1,11 +1,11 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, EvalRubric, EvalSuite, ExpectedToolCall, tool_eval, ) +from arcade_tdk import ToolCatalog import arcade_github from arcade_github.tools.models import SortDirection diff --git a/toolkits/github/pyproject.toml b/toolkits/github/pyproject.toml index 8e5647ad..7d830994 100644 --- a/toolkits/github/pyproject.toml +++ b/toolkits/github/pyproject.toml @@ -1,30 +1,43 @@ -[tool.poetry] +[build-system] +requires = [ "hatchling",] +build-backend = "hatchling.build" + +[project] name = "arcade_github" version = "0.1.10" description = "Arcade.dev LLM tools for Github" -authors = ["Arcade "] +requires-python = ">=3.10" +dependencies = [ + "arcade-tdk>=2.0.0,<3.0.0", + "httpx>=0.27.2,<1.0.0", +] +[[project.authors]] +name = "Arcade" +email = "dev@arcade.dev" -[tool.poetry.dependencies] -python = "^3.10" -arcade-ai = ">=0.1,<2.0" -httpx = "^0.27.2" +[project.optional-dependencies] +dev = [ + "arcade-ai[evals]>=2.0.0,<3.0.0", + "arcade-serve>=2.0.0,<3.0.0", + "pytest>=8.3.0,<8.4.0", + "pytest-cov>=4.0.0,<4.1.0", + "pytest-asyncio>=0.24.0,<0.25.0", + "pytest-mock>=3.11.1,<3.12.0", + "mypy>=1.5.1,<1.6.0", + "pre-commit>=3.4.0,<3.5.0", + "tox>=4.11.1,<4.12.0", + "ruff>=0.7.4,<0.8.0", +] -[tool.poetry.dev-dependencies] -pytest = "^8.3.0" -pytest-cov = "^4.0.0" -pytest-asyncio = "^0.24.0" -pytest-mock = "^3.11.1" -mypy = "^1.5.1" -pre-commit = "^3.4.0" -tox = "^4.11.1" -ruff = "^0.7.4" +# Use local path sources for arcade libs when working locally +[tool.uv.sources] +arcade-ai = {path = "../../", editable = true} +arcade-tdk = { path = "../../libs/arcade-tdk/", editable = true } +arcade-serve = { path = "../../libs/arcade-serve/", editable = true } -[build-system] -requires = ["poetry-core>=1.0.0,<2.0.0"] -build-backend = "poetry.core.masonry.api" [tool.mypy] -files = ["arcade_github/**/*.py"] +files = [ "arcade_github/**/*.py",] python_version = "3.10" disallow_untyped_defs = "True" disallow_any_unimported = "True" @@ -36,7 +49,10 @@ show_error_codes = "True" ignore_missing_imports = "True" [tool.pytest.ini_options] -testpaths = ["tests"] +testpaths = [ "tests",] [tool.coverage.report] skip_empty = true + +[tool.hatch.build.targets.wheel] +packages = [ "arcade_github",] diff --git a/toolkits/github/tests/test_activity.py b/toolkits/github/tests/test_activity.py index 3ad0e724..f245b63d 100644 --- a/toolkits/github/tests/test_activity.py +++ b/toolkits/github/tests/test_activity.py @@ -1,7 +1,7 @@ from unittest.mock import AsyncMock, patch import pytest -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk.errors import ToolExecutionError from httpx import Response from arcade_github.tools.activity import list_stargazers, set_starred diff --git a/toolkits/github/tests/test_issues.py b/toolkits/github/tests/test_issues.py index f33f29e4..a22477c0 100644 --- a/toolkits/github/tests/test_issues.py +++ b/toolkits/github/tests/test_issues.py @@ -1,7 +1,7 @@ from unittest.mock import AsyncMock, patch import pytest -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk.errors import ToolExecutionError from httpx import Response from arcade_github.tools.issues import create_issue, create_issue_comment diff --git a/toolkits/github/tests/test_pull_requests.py b/toolkits/github/tests/test_pull_requests.py index 10f73e17..d5abad68 100644 --- a/toolkits/github/tests/test_pull_requests.py +++ b/toolkits/github/tests/test_pull_requests.py @@ -1,7 +1,7 @@ from unittest.mock import AsyncMock, patch import pytest -from arcade.sdk.errors import RetryableToolError, ToolExecutionError +from arcade_tdk.errors import RetryableToolError, ToolExecutionError from httpx import Response from arcade_github.tools.models import ( diff --git a/toolkits/github/tests/test_repositories.py b/toolkits/github/tests/test_repositories.py index 5b66559f..466b2cf4 100644 --- a/toolkits/github/tests/test_repositories.py +++ b/toolkits/github/tests/test_repositories.py @@ -1,7 +1,7 @@ from unittest.mock import AsyncMock, patch import pytest -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk.errors import ToolExecutionError from httpx import Response from arcade_github.tools.models import RepoType diff --git a/toolkits/google/.pre-commit-config.yaml b/toolkits/google/.pre-commit-config.yaml index 3953e996..310d8911 100644 --- a/toolkits/google/.pre-commit-config.yaml +++ b/toolkits/google/.pre-commit-config.yaml @@ -1,4 +1,4 @@ -files: ^./ +files: ^.*/google/.* repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: "v4.4.0" diff --git a/toolkits/google/Makefile b/toolkits/google/Makefile index 0939b248..7e2c686e 100644 --- a/toolkits/google/Makefile +++ b/toolkits/google/Makefile @@ -1,30 +1,27 @@ .PHONY: help help: - @echo "๐Ÿ› ๏ธ google Commands:\n" + @echo "๐Ÿ› ๏ธ github Commands:\n" @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' .PHONY: install -install: ## Install the poetry environment and install the pre-commit hooks - @echo "๐Ÿ“ฆ Checking if Poetry is installed" - @if ! command -v poetry >/dev/null 2>&1; then \ - echo "๐Ÿ“ฆ Poetry not found. Checking if pip is available"; \ - if ! command -v pip >/dev/null 2>&1; then \ - echo "โŒ pip is not installed. Please install pip first."; \ - exit 1; \ - fi; \ - echo "๐Ÿ“ฆ Installing Poetry with pip"; \ - pip install poetry==1.8.5; \ - else \ - echo "๐Ÿ“ฆ Poetry is already installed"; \ - fi - @echo "๐Ÿš€ Installing package in development mode with all extras" - poetry install --all-extras +install: ## Install the uv environment and install all packages with dependencies + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras --no-sources + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" + +.PHONY: install-local +install-local: ## Install the uv environment and install all packages with dependencies with local Arcade sources + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" .PHONY: build build: clean-build ## Build wheel file using poetry @echo "๐Ÿš€ Creating wheel file" - poetry build + uv build .PHONY: clean-build clean-build: ## clean build artifacts @@ -34,7 +31,7 @@ clean-build: ## clean build artifacts .PHONY: test test: ## Test the code with pytest @echo "๐Ÿš€ Testing code: Running pytest" - @poetry run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml + @uv run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml .PHONY: coverage coverage: ## Generate coverage report @@ -44,15 +41,13 @@ coverage: ## Generate coverage report coverage html .PHONY: bump-version -bump-version: ## Bump the version in the pyproject.toml file +bump-version: ## Bump the version in the pyproject.toml file by a patch version @echo "๐Ÿš€ Bumping version in pyproject.toml" - poetry version patch + uv version --bump patch .PHONY: check check: ## Run code quality tools. - @echo "๐Ÿš€ Checking Poetry lock file consistency with 'pyproject.toml': Running poetry check" - @poetry check @echo "๐Ÿš€ Linting code: Running pre-commit" - @poetry run pre-commit run -a + @uv run pre-commit run -a @echo "๐Ÿš€ Static type checking: Running mypy" - @poetry run mypy --config-file=pyproject.toml + @uv run mypy --config-file=pyproject.toml diff --git a/toolkits/google/arcade_google/critics.py b/toolkits/google/arcade_google/critics.py index a9538b88..502a946a 100644 --- a/toolkits/google/arcade_google/critics.py +++ b/toolkits/google/arcade_google/critics.py @@ -1,7 +1,7 @@ from collections.abc import Collection from typing import Any -from arcade.sdk.eval import DatetimeCritic +from arcade_evals import DatetimeCritic class DatetimeOrNoneCritic(DatetimeCritic): diff --git a/toolkits/google/arcade_google/exceptions.py b/toolkits/google/arcade_google/exceptions.py index a925406b..0598dbee 100644 --- a/toolkits/google/arcade_google/exceptions.py +++ b/toolkits/google/arcade_google/exceptions.py @@ -1,6 +1,6 @@ from zoneinfo import available_timezones -from arcade.sdk.errors import RetryableToolError +from arcade_tdk.errors import RetryableToolError class GoogleToolError(Exception): diff --git a/toolkits/google/arcade_google/tools/calendar.py b/toolkits/google/arcade_google/tools/calendar.py index 7e0bee12..a534acad 100644 --- a/toolkits/google/arcade_google/tools/calendar.py +++ b/toolkits/google/arcade_google/tools/calendar.py @@ -3,9 +3,9 @@ from datetime import datetime, timedelta from typing import Annotated, Any from zoneinfo import ZoneInfo, ZoneInfoNotFoundError -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Google -from arcade.sdk.errors import RetryableToolError +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Google +from arcade_tdk.errors import RetryableToolError from googleapiclient.errors import HttpError from arcade_google.models import EventVisibility, SendUpdatesOptions diff --git a/toolkits/google/arcade_google/tools/contacts.py b/toolkits/google/arcade_google/tools/contacts.py index 96003cf5..64332847 100644 --- a/toolkits/google/arcade_google/tools/contacts.py +++ b/toolkits/google/arcade_google/tools/contacts.py @@ -1,8 +1,8 @@ import asyncio from typing import Annotated -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Google +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Google from arcade_google.constants import DEFAULT_SEARCH_CONTACTS_LIMIT from arcade_google.utils import build_people_service, search_contacts diff --git a/toolkits/google/arcade_google/tools/docs.py b/toolkits/google/arcade_google/tools/docs.py index c46a0535..b91da26a 100644 --- a/toolkits/google/arcade_google/tools/docs.py +++ b/toolkits/google/arcade_google/tools/docs.py @@ -1,7 +1,7 @@ from typing import Annotated -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Google +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Google from arcade_google.utils import build_docs_service diff --git a/toolkits/google/arcade_google/tools/drive.py b/toolkits/google/arcade_google/tools/drive.py index 69cbc174..b8a7b4f8 100644 --- a/toolkits/google/arcade_google/tools/drive.py +++ b/toolkits/google/arcade_google/tools/drive.py @@ -1,7 +1,7 @@ from typing import Annotated, Any -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Google +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Google from googleapiclient.errors import HttpError from arcade_google.doc_to_html import convert_document_to_html diff --git a/toolkits/google/arcade_google/tools/file_picker.py b/toolkits/google/arcade_google/tools/file_picker.py index 7ba9471c..b509e6d4 100644 --- a/toolkits/google/arcade_google/tools/file_picker.py +++ b/toolkits/google/arcade_google/tools/file_picker.py @@ -2,9 +2,9 @@ import base64 import json from typing import Annotated -from arcade.sdk import ToolContext, ToolMetadataKey, tool -from arcade.sdk.auth import Google -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk import ToolContext, ToolMetadataKey, tool +from arcade_tdk.auth import Google +from arcade_tdk.errors import ToolExecutionError @tool( diff --git a/toolkits/google/arcade_google/tools/gmail.py b/toolkits/google/arcade_google/tools/gmail.py index 8cf8c1a9..7b89ee54 100644 --- a/toolkits/google/arcade_google/tools/gmail.py +++ b/toolkits/google/arcade_google/tools/gmail.py @@ -2,9 +2,9 @@ import base64 from email.mime.text import MIMEText from typing import Annotated, Any -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Google -from arcade.sdk.errors import RetryableToolError +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Google +from arcade_tdk.errors import RetryableToolError from googleapiclient.errors import HttpError from arcade_google.constants import GMAIL_DEFAULT_REPLY_TO diff --git a/toolkits/google/arcade_google/tools/sheets.py b/toolkits/google/arcade_google/tools/sheets.py index 1248fab6..d803b9fb 100644 --- a/toolkits/google/arcade_google/tools/sheets.py +++ b/toolkits/google/arcade_google/tools/sheets.py @@ -1,8 +1,8 @@ from typing import Annotated -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Google -from arcade.sdk.errors import RetryableToolError +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Google +from arcade_tdk.errors import RetryableToolError from arcade_google.models import ( SheetDataInput, diff --git a/toolkits/google/arcade_google/utils.py b/toolkits/google/arcade_google/utils.py index 06a3f098..1d81854c 100644 --- a/toolkits/google/arcade_google/utils.py +++ b/toolkits/google/arcade_google/utils.py @@ -8,8 +8,8 @@ from enum import Enum from typing import Any, cast from zoneinfo import ZoneInfo -from arcade.sdk import ToolContext -from arcade.sdk.errors import RetryableToolError, ToolExecutionError +from arcade_tdk import ToolContext +from arcade_tdk.errors import RetryableToolError, ToolExecutionError from bs4 import BeautifulSoup from google.oauth2.credentials import Credentials from googleapiclient.discovery import Resource, build diff --git a/toolkits/google/evals/eval_calendar_free_slots.py b/toolkits/google/evals/eval_calendar_free_slots.py index f8f366ad..2b3b98df 100644 --- a/toolkits/google/evals/eval_calendar_free_slots.py +++ b/toolkits/google/evals/eval_calendar_free_slots.py @@ -1,7 +1,6 @@ from datetime import timedelta -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, DatetimeCritic, EvalRubric, @@ -10,6 +9,7 @@ from arcade.sdk.eval import ( NoneCritic, tool_eval, ) +from arcade_tdk import ToolCatalog import arcade_google from arcade_google.critics import AnyDatetimeCritic, DatetimeOrNoneCritic diff --git a/toolkits/google/evals/eval_file_picker.py b/toolkits/google/evals/eval_file_picker.py index d9dfa5d2..713cee11 100644 --- a/toolkits/google/evals/eval_file_picker.py +++ b/toolkits/google/evals/eval_file_picker.py @@ -1,10 +1,10 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( EvalRubric, EvalSuite, ExpectedToolCall, tool_eval, ) +from arcade_tdk import ToolCatalog import arcade_google from arcade_google.tools import generate_google_file_picker_url diff --git a/toolkits/google/evals/eval_google_calendar.py b/toolkits/google/evals/eval_google_calendar.py index 0e21fccf..e804161e 100644 --- a/toolkits/google/evals/eval_google_calendar.py +++ b/toolkits/google/evals/eval_google_calendar.py @@ -1,7 +1,6 @@ from datetime import timedelta -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, DatetimeCritic, EvalRubric, @@ -9,6 +8,7 @@ from arcade.sdk.eval import ( ExpectedToolCall, tool_eval, ) +from arcade_tdk import ToolCatalog import arcade_google from arcade_google.models import EventVisibility, SendUpdatesOptions diff --git a/toolkits/google/evals/eval_google_contacts.py b/toolkits/google/evals/eval_google_contacts.py index d6b3305d..191250ed 100644 --- a/toolkits/google/evals/eval_google_contacts.py +++ b/toolkits/google/evals/eval_google_contacts.py @@ -1,11 +1,11 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( + BinaryCritic, EvalRubric, EvalSuite, ExpectedToolCall, tool_eval, ) -from arcade.sdk.eval.critic import BinaryCritic +from arcade_tdk import ToolCatalog import arcade_google from arcade_google.tools import ( diff --git a/toolkits/google/evals/eval_google_docs.py b/toolkits/google/evals/eval_google_docs.py index 28d9116e..bcd3125e 100644 --- a/toolkits/google/evals/eval_google_docs.py +++ b/toolkits/google/evals/eval_google_docs.py @@ -1,5 +1,4 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, EvalRubric, EvalSuite, @@ -7,6 +6,7 @@ from arcade.sdk.eval import ( SimilarityCritic, tool_eval, ) +from arcade_tdk import ToolCatalog import arcade_google from arcade_google.tools import ( diff --git a/toolkits/google/evals/eval_google_drive.py b/toolkits/google/evals/eval_google_drive.py index d0984575..00eba7f8 100644 --- a/toolkits/google/evals/eval_google_drive.py +++ b/toolkits/google/evals/eval_google_drive.py @@ -1,11 +1,11 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, EvalRubric, EvalSuite, ExpectedToolCall, tool_eval, ) +from arcade_tdk import ToolCatalog import arcade_google from arcade_google.models import DocumentFormat, OrderBy diff --git a/toolkits/google/evals/eval_google_gmail.py b/toolkits/google/evals/eval_google_gmail.py index ac4bb883..4f320f59 100644 --- a/toolkits/google/evals/eval_google_gmail.py +++ b/toolkits/google/evals/eval_google_gmail.py @@ -1,7 +1,6 @@ import json -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, EvalRubric, EvalSuite, @@ -9,6 +8,7 @@ from arcade.sdk.eval import ( SimilarityCritic, tool_eval, ) +from arcade_tdk import ToolCatalog import arcade_google from arcade_google.models import GmailReplyToWhom diff --git a/toolkits/google/evals/eval_google_sheets.py b/toolkits/google/evals/eval_google_sheets.py index 5e8889f1..9b377ef7 100644 --- a/toolkits/google/evals/eval_google_sheets.py +++ b/toolkits/google/evals/eval_google_sheets.py @@ -1,5 +1,4 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, EvalRubric, EvalSuite, @@ -7,6 +6,7 @@ from arcade.sdk.eval import ( SimilarityCritic, tool_eval, ) +from arcade_tdk import ToolCatalog import arcade_google from arcade_google.tools import ( diff --git a/toolkits/google/pyproject.toml b/toolkits/google/pyproject.toml index b7a11277..caa87099 100644 --- a/toolkits/google/pyproject.toml +++ b/toolkits/google/pyproject.toml @@ -1,36 +1,48 @@ -[tool.poetry] +[build-system] +requires = [ "hatchling",] +build-backend = "hatchling.build" + +[project] name = "arcade_google" version = "1.2.1" description = "Arcade.dev LLM tools for Google Workspace" -authors = ["Arcade "] +requires-python = ">=3.10" +dependencies = [ + "arcade-tdk>=2.0.0,<3.0.0", + "google-api-core>=2.19.1,<3.0.0", + "google-api-python-client>=2.137.0,<3.0.0", + "google-auth>=2.32.0,<3.0.0", + "google-auth-httplib2>=0.2.0,<1.0.0", + "google-auth-oauthlib>=1.2.1,<2.0.0", + "googleapis-common-protos>=1.63.2,<2.0.0", + "beautifulsoup4>=4.10.0,<5.0.0", +] +[[project.authors]] +name = "Arcade" +email = "dev@arcade.dev" -[tool.poetry.dependencies] -python = "^3.10" -arcade-ai = ">=1.3.0,<2.0" -google-api-core = "2.19.1" -google-api-python-client = "2.137.0" -google-auth = "2.32.0" -google-auth-httplib2 = "0.2.0" -google-auth-oauthlib = "1.2.1" -googleapis-common-protos = "1.63.2" -beautifulsoup4 = "^4.10.0" +[project.optional-dependencies] +dev = [ + "arcade-ai[evals]>=2.0.0,<3.0.0", + "arcade-serve>=2.0.0,<3.0.0", + "pytest>=8.3.0,<8.4.0", + "pytest-cov>=4.0.0,<4.1.0", + "pytest-asyncio>=0.24.0,<0.25.0", + "pytest-mock>=3.11.1,<3.12.0", + "mypy>=1.5.1,<1.6.0", + "pre-commit>=3.4.0,<3.5.0", + "tox>=4.11.1,<4.12.0", + "ruff>=0.7.4,<0.8.0", +] -[tool.poetry.dev-dependencies] -pytest = "^8.3.0" -pytest-cov = "^4.0.0" -pytest-asyncio = "^0.24.0" -pytest-mock = "^3.11.1" -mypy = "^1.5.1" -pre-commit = "^3.4.0" -tox = "^4.11.1" -ruff = "^0.7.4" - -[build-system] -requires = ["poetry-core>=1.0.0,<2.0.0"] -build-backend = "poetry.core.masonry.api" +# Use local path sources for arcade libs when working locally +[tool.uv.sources] +arcade-ai = {path = "../../", editable = true} +arcade-tdk = { path = "../../libs/arcade-tdk/", editable = true } +arcade-serve = { path = "../../libs/arcade-serve/", editable = true } [tool.mypy] -files = ["arcade_google/**/*.py"] +files = [ "arcade_google/**/*.py",] python_version = "3.10" disallow_untyped_defs = "True" disallow_any_unimported = "True" @@ -42,7 +54,10 @@ show_error_codes = "True" ignore_missing_imports = "True" [tool.pytest.ini_options] -testpaths = ["tests"] +testpaths = [ "tests",] [tool.coverage.report] skip_empty = true + +[tool.hatch.build.targets.wheel] +packages = [ "arcade_google",] diff --git a/toolkits/google/tests/test_calendar.py b/toolkits/google/tests/test_calendar.py index fd11aa67..a6ea87fe 100644 --- a/toolkits/google/tests/test_calendar.py +++ b/toolkits/google/tests/test_calendar.py @@ -3,8 +3,8 @@ from unittest.mock import MagicMock, patch from zoneinfo import ZoneInfo import pytest -from arcade.sdk import ToolAuthorizationContext, ToolContext -from arcade.sdk.errors import RetryableToolError, ToolExecutionError +from arcade_tdk import ToolAuthorizationContext, ToolContext +from arcade_tdk.errors import RetryableToolError, ToolExecutionError from googleapiclient.errors import HttpError from arcade_google.models import EventVisibility, SendUpdatesOptions diff --git a/toolkits/google/tests/test_contacts.py b/toolkits/google/tests/test_contacts.py index a84d567e..409a1e6e 100644 --- a/toolkits/google/tests/test_contacts.py +++ b/toolkits/google/tests/test_contacts.py @@ -1,7 +1,7 @@ from unittest.mock import AsyncMock, MagicMock, patch import pytest -from arcade.sdk import ToolContext +from arcade_tdk import ToolContext from arcade_google.tools import create_contact diff --git a/toolkits/google/tests/test_docs.py b/toolkits/google/tests/test_docs.py index 26200fdc..2e9e5470 100644 --- a/toolkits/google/tests/test_docs.py +++ b/toolkits/google/tests/test_docs.py @@ -1,7 +1,7 @@ from unittest.mock import AsyncMock, patch import pytest -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk.errors import ToolExecutionError from googleapiclient.errors import HttpError from arcade_google.tools import ( diff --git a/toolkits/google/tests/test_drive.py b/toolkits/google/tests/test_drive.py index 48b8ecd0..962d9bf6 100644 --- a/toolkits/google/tests/test_drive.py +++ b/toolkits/google/tests/test_drive.py @@ -1,7 +1,7 @@ from unittest.mock import AsyncMock, patch import pytest -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk.errors import ToolExecutionError from googleapiclient.errors import HttpError from arcade_google.models import Corpora, DocumentFormat, OrderBy diff --git a/toolkits/google/tests/test_file_picker.py b/toolkits/google/tests/test_file_picker.py index bd7c995e..67082dfe 100644 --- a/toolkits/google/tests/test_file_picker.py +++ b/toolkits/google/tests/test_file_picker.py @@ -3,8 +3,7 @@ import json from urllib.parse import parse_qs, urlparse import pytest -from arcade.core.schema import ToolMetadataItem -from arcade.sdk import ToolContext, ToolMetadataKey +from arcade_tdk import ToolContext, ToolMetadataItem, ToolMetadataKey from arcade_google.tools import generate_google_file_picker_url diff --git a/toolkits/google/tests/test_gmail.py b/toolkits/google/tests/test_gmail.py index 5414cbc1..b423b4ab 100644 --- a/toolkits/google/tests/test_gmail.py +++ b/toolkits/google/tests/test_gmail.py @@ -3,8 +3,8 @@ from email.message import EmailMessage from unittest.mock import MagicMock, patch import pytest -from arcade.sdk import ToolAuthorizationContext, ToolContext -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk import ToolAuthorizationContext, ToolContext +from arcade_tdk.errors import ToolExecutionError from googleapiclient.errors import HttpError from arcade_google.models import GmailReplyToWhom diff --git a/toolkits/google/tests/test_sheets_utils.py b/toolkits/google/tests/test_sheets_utils.py index ea7c4a58..26cb1c0a 100644 --- a/toolkits/google/tests/test_sheets_utils.py +++ b/toolkits/google/tests/test_sheets_utils.py @@ -1,7 +1,7 @@ from unittest.mock import MagicMock, patch import pytest -from arcade.sdk.errors import RetryableToolError, ToolExecutionError +from arcade_tdk.errors import RetryableToolError, ToolExecutionError from arcade_google.models import ( CellData, diff --git a/toolkits/hubspot/.pre-commit-config.yaml b/toolkits/hubspot/.pre-commit-config.yaml index 3953e996..e6805917 100644 --- a/toolkits/hubspot/.pre-commit-config.yaml +++ b/toolkits/hubspot/.pre-commit-config.yaml @@ -1,4 +1,4 @@ -files: ^./ +files: ^.*/hubspot/.* repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: "v4.4.0" diff --git a/toolkits/hubspot/Makefile b/toolkits/hubspot/Makefile index 8ca4a804..7e2c686e 100644 --- a/toolkits/hubspot/Makefile +++ b/toolkits/hubspot/Makefile @@ -1,25 +1,27 @@ .PHONY: help help: - @echo "๐Ÿ› ๏ธ dropbox Commands:\n" + @echo "๐Ÿ› ๏ธ github Commands:\n" @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' .PHONY: install -install: ## Install the poetry environment and install the pre-commit hooks - @echo "๐Ÿ“ฆ Checking if Poetry is installed" - @if ! command -v poetry &> /dev/null; then \ - echo "๐Ÿ“ฆ Installing Poetry with pip"; \ - pip install poetry==1.8.5; \ - else \ - echo "๐Ÿ“ฆ Poetry is already installed"; \ - fi - @echo "๐Ÿš€ Installing package in development mode with all extras" - poetry install --all-extras +install: ## Install the uv environment and install all packages with dependencies + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras --no-sources + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" + +.PHONY: install-local +install-local: ## Install the uv environment and install all packages with dependencies with local Arcade sources + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" .PHONY: build build: clean-build ## Build wheel file using poetry @echo "๐Ÿš€ Creating wheel file" - poetry build + uv build .PHONY: clean-build clean-build: ## clean build artifacts @@ -29,7 +31,7 @@ clean-build: ## clean build artifacts .PHONY: test test: ## Test the code with pytest @echo "๐Ÿš€ Testing code: Running pytest" - @poetry run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml + @uv run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml .PHONY: coverage coverage: ## Generate coverage report @@ -39,15 +41,13 @@ coverage: ## Generate coverage report coverage html .PHONY: bump-version -bump-version: ## Bump the version in the pyproject.toml file +bump-version: ## Bump the version in the pyproject.toml file by a patch version @echo "๐Ÿš€ Bumping version in pyproject.toml" - poetry version patch + uv version --bump patch .PHONY: check check: ## Run code quality tools. - @echo "๐Ÿš€ Checking Poetry lock file consistency with 'pyproject.toml': Running poetry check" - @poetry check @echo "๐Ÿš€ Linting code: Running pre-commit" - @poetry run pre-commit run -a + @uv run pre-commit run -a @echo "๐Ÿš€ Static type checking: Running mypy" - @poetry run mypy --config-file=pyproject.toml + @uv run mypy --config-file=pyproject.toml diff --git a/toolkits/hubspot/arcade_hubspot/custom_critics.py b/toolkits/hubspot/arcade_hubspot/custom_critics.py index fca3c7ad..a438374a 100644 --- a/toolkits/hubspot/arcade_hubspot/custom_critics.py +++ b/toolkits/hubspot/arcade_hubspot/custom_critics.py @@ -1,6 +1,6 @@ from typing import Any -from arcade.sdk.eval import BinaryCritic +from arcade_evals import BinaryCritic class ValueInListCritic(BinaryCritic): diff --git a/toolkits/hubspot/arcade_hubspot/exceptions.py b/toolkits/hubspot/arcade_hubspot/exceptions.py index 7692c75e..1f858cce 100644 --- a/toolkits/hubspot/arcade_hubspot/exceptions.py +++ b/toolkits/hubspot/arcade_hubspot/exceptions.py @@ -1,4 +1,4 @@ -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk.errors import ToolExecutionError class HubspotToolExecutionError(ToolExecutionError): diff --git a/toolkits/hubspot/arcade_hubspot/tools/crm/companies.py b/toolkits/hubspot/arcade_hubspot/tools/crm/companies.py index 1aa9f1be..b84e6759 100644 --- a/toolkits/hubspot/arcade_hubspot/tools/crm/companies.py +++ b/toolkits/hubspot/arcade_hubspot/tools/crm/companies.py @@ -1,7 +1,7 @@ from typing import Annotated, Any, Optional -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Hubspot +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Hubspot from arcade_hubspot.enums import HubspotObject from arcade_hubspot.models import HubspotCrmClient diff --git a/toolkits/hubspot/arcade_hubspot/tools/crm/contacts.py b/toolkits/hubspot/arcade_hubspot/tools/crm/contacts.py index d6403a65..7459ed40 100644 --- a/toolkits/hubspot/arcade_hubspot/tools/crm/contacts.py +++ b/toolkits/hubspot/arcade_hubspot/tools/crm/contacts.py @@ -1,7 +1,7 @@ from typing import Annotated, Any, Optional -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Hubspot +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Hubspot from arcade_hubspot.enums import HubspotObject from arcade_hubspot.models import HubspotCrmClient diff --git a/toolkits/hubspot/conftest.py b/toolkits/hubspot/conftest.py index 2c658bb4..88c4d4b4 100644 --- a/toolkits/hubspot/conftest.py +++ b/toolkits/hubspot/conftest.py @@ -1,7 +1,7 @@ from unittest.mock import patch import pytest -from arcade.sdk import ToolAuthorizationContext, ToolContext +from arcade_tdk import ToolAuthorizationContext, ToolContext @pytest.fixture diff --git a/toolkits/hubspot/evals/eval_crm_companies.py b/toolkits/hubspot/evals/eval_crm_companies.py index 45b56693..89d2f573 100644 --- a/toolkits/hubspot/evals/eval_crm_companies.py +++ b/toolkits/hubspot/evals/eval_crm_companies.py @@ -1,11 +1,11 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, EvalRubric, EvalSuite, ExpectedToolCall, tool_eval, ) +from arcade_tdk import ToolCatalog import arcade_hubspot from arcade_hubspot.tools import get_company_data_by_keywords diff --git a/toolkits/hubspot/evals/eval_crm_contacts.py b/toolkits/hubspot/evals/eval_crm_contacts.py index 719f49bc..f3abe0f2 100644 --- a/toolkits/hubspot/evals/eval_crm_contacts.py +++ b/toolkits/hubspot/evals/eval_crm_contacts.py @@ -1,11 +1,11 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, EvalRubric, EvalSuite, ExpectedToolCall, tool_eval, ) +from arcade_tdk import ToolCatalog import arcade_hubspot from arcade_hubspot.custom_critics import ValueInListCritic diff --git a/toolkits/hubspot/pyproject.toml b/toolkits/hubspot/pyproject.toml index ecf97d57..523f02c4 100644 --- a/toolkits/hubspot/pyproject.toml +++ b/toolkits/hubspot/pyproject.toml @@ -1,30 +1,42 @@ -[tool.poetry] +[build-system] +requires = [ "hatchling",] +build-backend = "hatchling.build" + +[project] name = "arcade_hubspot" version = "0.2.0" description = "Arcade tools designed for LLMs to interact with Hubspot" -authors = ["Arcade "] +requires-python = ">=3.10" +dependencies = [ + "arcade-tdk>=2.0.0,<3.0.0", + "httpx>=0.27.2,<1.0.0", +] +[[project.authors]] +name = "Arcade" +email = "dev@arcade.dev" -[tool.poetry.dependencies] -python = "^3.10" -arcade-ai = ">=1.3.2,<2.0" -httpx = "^0.27.2" +[project.optional-dependencies] +dev = [ + "arcade-ai[evals]>=2.0.0,<3.0.0", + "arcade-serve>=2.0.0,<3.0.0", + "pytest>=8.3.0,<8.4.0", + "pytest-cov>=4.0.0,<4.1.0", + "pytest-asyncio>=0.24.0,<0.25.0", + "pytest-mock>=3.11.1,<3.12.0", + "mypy>=1.5.1,<1.6.0", + "pre-commit>=3.4.0,<3.5.0", + "tox>=4.11.1,<4.12.0", + "ruff>=0.7.4,<0.8.0", +] -[tool.poetry.dev-dependencies] -pytest = "^8.3.0" -pytest-cov = "^4.0.0" -pytest-asyncio = "^0.24.0" -pytest-mock = "^3.11.1" -mypy = "^1.5.1" -pre-commit = "^3.4.0" -tox = "^4.11.1" -ruff = "^0.7.4" - -[build-system] -requires = ["poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" +# Use local path sources for arcade libs when working locally +[tool.uv.sources] +arcade-ai = {path = "../../", editable = true} +arcade-tdk = { path = "../../libs/arcade-tdk/", editable = true } +arcade-serve = { path = "../../libs/arcade-serve/", editable = true } [tool.mypy] -files = ["arcade_hubspot/**/*.py"] +files = [ "arcade_hubspot/**/*.py",] python_version = "3.10" disallow_untyped_defs = "True" disallow_any_unimported = "True" @@ -36,7 +48,10 @@ show_error_codes = "True" ignore_missing_imports = "True" [tool.pytest.ini_options] -testpaths = ["tests"] +testpaths = [ "tests",] [tool.coverage.report] skip_empty = true + +[tool.hatch.build.targets.wheel] +packages = [ "arcade_hubspot",] diff --git a/toolkits/jira/.pre-commit-config.yaml b/toolkits/jira/.pre-commit-config.yaml index 3953e996..b7d80f28 100644 --- a/toolkits/jira/.pre-commit-config.yaml +++ b/toolkits/jira/.pre-commit-config.yaml @@ -1,4 +1,4 @@ -files: ^./ +files: ^.*/jira/.* repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: "v4.4.0" diff --git a/toolkits/jira/.ruff.toml b/toolkits/jira/.ruff.toml index bacd9161..9519fe6c 100644 --- a/toolkits/jira/.ruff.toml +++ b/toolkits/jira/.ruff.toml @@ -1,4 +1,4 @@ -target-version = "py39" +target-version = "py310" line-length = 100 fix = true @@ -37,9 +37,7 @@ select = [ ] [lint.per-file-ignores] -"*" = ["TRY003", "B904"] -"**/tests/*" = ["S101", "E501"] -"**/evals/*" = ["S101", "E501"] +"**/tests/*" = ["S101"] [format] preview = true diff --git a/toolkits/jira/Makefile b/toolkits/jira/Makefile index 8ca4a804..7e2c686e 100644 --- a/toolkits/jira/Makefile +++ b/toolkits/jira/Makefile @@ -1,25 +1,27 @@ .PHONY: help help: - @echo "๐Ÿ› ๏ธ dropbox Commands:\n" + @echo "๐Ÿ› ๏ธ github Commands:\n" @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' .PHONY: install -install: ## Install the poetry environment and install the pre-commit hooks - @echo "๐Ÿ“ฆ Checking if Poetry is installed" - @if ! command -v poetry &> /dev/null; then \ - echo "๐Ÿ“ฆ Installing Poetry with pip"; \ - pip install poetry==1.8.5; \ - else \ - echo "๐Ÿ“ฆ Poetry is already installed"; \ - fi - @echo "๐Ÿš€ Installing package in development mode with all extras" - poetry install --all-extras +install: ## Install the uv environment and install all packages with dependencies + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras --no-sources + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" + +.PHONY: install-local +install-local: ## Install the uv environment and install all packages with dependencies with local Arcade sources + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" .PHONY: build build: clean-build ## Build wheel file using poetry @echo "๐Ÿš€ Creating wheel file" - poetry build + uv build .PHONY: clean-build clean-build: ## clean build artifacts @@ -29,7 +31,7 @@ clean-build: ## clean build artifacts .PHONY: test test: ## Test the code with pytest @echo "๐Ÿš€ Testing code: Running pytest" - @poetry run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml + @uv run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml .PHONY: coverage coverage: ## Generate coverage report @@ -39,15 +41,13 @@ coverage: ## Generate coverage report coverage html .PHONY: bump-version -bump-version: ## Bump the version in the pyproject.toml file +bump-version: ## Bump the version in the pyproject.toml file by a patch version @echo "๐Ÿš€ Bumping version in pyproject.toml" - poetry version patch + uv version --bump patch .PHONY: check check: ## Run code quality tools. - @echo "๐Ÿš€ Checking Poetry lock file consistency with 'pyproject.toml': Running poetry check" - @poetry check @echo "๐Ÿš€ Linting code: Running pre-commit" - @poetry run pre-commit run -a + @uv run pre-commit run -a @echo "๐Ÿš€ Static type checking: Running mypy" - @poetry run mypy --config-file=pyproject.toml + @uv run mypy --config-file=pyproject.toml diff --git a/toolkits/jira/arcade_jira/client.py b/toolkits/jira/arcade_jira/client.py index 6053b1f3..4661cf3e 100644 --- a/toolkits/jira/arcade_jira/client.py +++ b/toolkits/jira/arcade_jira/client.py @@ -2,7 +2,7 @@ import asyncio import json import json.decoder from dataclasses import dataclass -from typing import Any, Optional, cast +from typing import Any, cast import httpx @@ -60,7 +60,7 @@ class JiraClient: if len(data) == 0: raise JiraToolExecutionError( - "No cloud ID returned by Atlassian, cannot make API calls" + message="No cloud ID returned by Atlassian, cannot make API calls" ) if len(data) > 1: cloud_ids_found = json.dumps([ @@ -72,7 +72,7 @@ class JiraClient: for item in data ]) raise JiraToolExecutionError( - f"Multiple cloud IDs returned by Atlassian: {cloud_ids_found}. " + message=f"Multiple cloud IDs returned by Atlassian: {cloud_ids_found}. " "Cannot resolve which one to use." ) return cast(dict[str, Any], data[0]) @@ -118,7 +118,7 @@ class JiraClient: def _set_request_body(self, kwargs: dict, data: dict | None, json_data: dict | None) -> dict: if data and json_data: - raise ValueError("Cannot provide both data and json_data") + raise ValueError("Cannot provide both data and json_data") # noqa: TRY003 if data: kwargs["data"] = data @@ -137,8 +137,8 @@ class JiraClient: async def get( self, endpoint: str, - params: Optional[dict] = None, - headers: Optional[dict] = None, + params: dict | None = None, + headers: dict | None = None, ) -> dict: default_headers = { "Authorization": f"Bearer {self.auth_token}", @@ -163,10 +163,10 @@ class JiraClient: async def post( self, endpoint: str, - data: Optional[dict] = None, - json_data: Optional[dict] = None, - files: Optional[dict] = None, - headers: Optional[dict] = None, + data: dict | None = None, + json_data: dict | None = None, + files: dict | None = None, + headers: dict | None = None, ) -> dict: default_headers = { "Authorization": f"Bearer {self.auth_token}", @@ -199,10 +199,10 @@ class JiraClient: async def put( self, endpoint: str, - data: Optional[dict] = None, - json_data: Optional[dict] = None, - params: Optional[dict] = None, - headers: Optional[dict] = None, + data: dict | None = None, + json_data: dict | None = None, + params: dict | None = None, + headers: dict | None = None, ) -> dict: headers = headers or {} headers["Authorization"] = f"Bearer {self.auth_token}" diff --git a/toolkits/jira/arcade_jira/critics.py b/toolkits/jira/arcade_jira/critics.py index a71091e7..6f53c81b 100644 --- a/toolkits/jira/arcade_jira/critics.py +++ b/toolkits/jira/arcade_jira/critics.py @@ -1,7 +1,7 @@ from dataclasses import dataclass from typing import Any -from arcade.sdk.eval.critic import BinaryCritic +from arcade_evals.critic import BinaryCritic @dataclass diff --git a/toolkits/jira/arcade_jira/exceptions.py b/toolkits/jira/arcade_jira/exceptions.py index 22828adb..af3ba4a6 100644 --- a/toolkits/jira/arcade_jira/exceptions.py +++ b/toolkits/jira/arcade_jira/exceptions.py @@ -1,4 +1,4 @@ -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk.errors import ToolExecutionError class JiraToolExecutionError(ToolExecutionError): diff --git a/toolkits/jira/arcade_jira/tools/attachments.py b/toolkits/jira/arcade_jira/tools/attachments.py index 38f7325d..7bddf0c5 100644 --- a/toolkits/jira/arcade_jira/tools/attachments.py +++ b/toolkits/jira/arcade_jira/tools/attachments.py @@ -1,8 +1,8 @@ from typing import Annotated, Any, cast -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Atlassian -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Atlassian +from arcade_tdk.errors import ToolExecutionError import arcade_jira.cache as cache from arcade_jira.client import JiraClient @@ -49,11 +49,11 @@ async def attach_file_to_issue( if not any(file_contents) or all(file_contents): raise ToolExecutionError( - "Must provide exactly one of file_content_str or file_content_base64." + message="Must provide exactly one of file_content_str or file_content_base64." ) if not filename: - raise ToolExecutionError("Must provide a filename.") + raise ToolExecutionError(message="Must provide a filename.") client = JiraClient(context.get_auth_token_or_empty()) diff --git a/toolkits/jira/arcade_jira/tools/comments.py b/toolkits/jira/arcade_jira/tools/comments.py index 627989f2..c687e927 100644 --- a/toolkits/jira/arcade_jira/tools/comments.py +++ b/toolkits/jira/arcade_jira/tools/comments.py @@ -1,8 +1,8 @@ from typing import Annotated, Any -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Atlassian -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Atlassian +from arcade_tdk.errors import ToolExecutionError from arcade_jira.client import JiraClient from arcade_jira.constants import IssueCommentOrderBy @@ -117,7 +117,7 @@ async def add_comment_to_issue( ) -> Annotated[dict[str, Any], "Information about the comment created"]: """Add a comment to a Jira issue.""" if not body: - raise ToolExecutionError("Comment body cannot be empty.") + raise ToolExecutionError(message="Comment body cannot be empty.") client = JiraClient(context.get_auth_token_or_empty()) @@ -141,7 +141,7 @@ async def add_comment_to_issue( quote_comment = await get_comment_by_id(context, issue, reply_to_comment, True) if not quote_comment["comment"]: raise ToolExecutionError( - f"Cannot quote comment. No comment found with ID '{reply_to_comment}'." + message=f"Cannot quote comment. No comment found with ID '{reply_to_comment}'." ) quote = { "type": "blockquote", diff --git a/toolkits/jira/arcade_jira/tools/issues.py b/toolkits/jira/arcade_jira/tools/issues.py index 62ac4e5c..6cbe4785 100644 --- a/toolkits/jira/arcade_jira/tools/issues.py +++ b/toolkits/jira/arcade_jira/tools/issues.py @@ -1,7 +1,7 @@ from typing import Annotated, Any, cast -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Atlassian +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Atlassian import arcade_jira.cache as cache from arcade_jira.client import JiraClient @@ -213,7 +213,7 @@ async def get_issues_without_id( if not jql: raise JiraToolExecutionError( - "No search criteria provided. Please provide at least one argument." + message="No search criteria provided. Please provide at least one argument." ) body = { @@ -776,7 +776,7 @@ async def update_issue( if not request_body["fields"] and not request_body["update"]: raise JiraToolExecutionError( - "No changes provided. Please provide at least one argument to update the issue." + message="No changes provided. Please provide at least one argument to update the issue." ) await client.put(f"/issue/{issue}", json_data=request_body, params=params) diff --git a/toolkits/jira/arcade_jira/tools/labels.py b/toolkits/jira/arcade_jira/tools/labels.py index b8bdce4a..d83e0cf3 100644 --- a/toolkits/jira/arcade_jira/tools/labels.py +++ b/toolkits/jira/arcade_jira/tools/labels.py @@ -1,7 +1,7 @@ from typing import Annotated, Any -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Atlassian +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Atlassian from arcade_jira.client import JiraClient from arcade_jira.utils import add_pagination_to_response diff --git a/toolkits/jira/arcade_jira/tools/priorities.py b/toolkits/jira/arcade_jira/tools/priorities.py index 919ba471..83f86b3f 100644 --- a/toolkits/jira/arcade_jira/tools/priorities.py +++ b/toolkits/jira/arcade_jira/tools/priorities.py @@ -1,8 +1,8 @@ import asyncio from typing import Annotated, Any, cast -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Atlassian +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Atlassian import arcade_jira.cache as cache from arcade_jira.client import JiraClient diff --git a/toolkits/jira/arcade_jira/tools/projects.py b/toolkits/jira/arcade_jira/tools/projects.py index 0b7007a0..c602f92e 100644 --- a/toolkits/jira/arcade_jira/tools/projects.py +++ b/toolkits/jira/arcade_jira/tools/projects.py @@ -1,7 +1,7 @@ from typing import Annotated, Any, cast -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Atlassian +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Atlassian import arcade_jira.cache as cache from arcade_jira.client import JiraClient diff --git a/toolkits/jira/arcade_jira/tools/transitions.py b/toolkits/jira/arcade_jira/tools/transitions.py index 67c9fb0b..ae4f3151 100644 --- a/toolkits/jira/arcade_jira/tools/transitions.py +++ b/toolkits/jira/arcade_jira/tools/transitions.py @@ -1,7 +1,7 @@ from typing import Annotated, cast -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Atlassian +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Atlassian from arcade_jira.client import JiraClient diff --git a/toolkits/jira/arcade_jira/tools/users.py b/toolkits/jira/arcade_jira/tools/users.py index 760a810c..bce49f17 100644 --- a/toolkits/jira/arcade_jira/tools/users.py +++ b/toolkits/jira/arcade_jira/tools/users.py @@ -1,8 +1,8 @@ from typing import Annotated, Any, cast -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Atlassian -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Atlassian +from arcade_tdk.errors import ToolExecutionError import arcade_jira.cache as cache from arcade_jira.client import JiraClient @@ -110,13 +110,13 @@ async def get_users_without_id( if limit + offset > 1000: raise ToolExecutionError( - "The maximum number of users returned by the Jira search API is 1000. " + message="The maximum number of users returned by the Jira search API is 1000. " f"To get more users use the `Jira.{list_users.__tool_name__}` tool." ) if not name_or_email: raise ToolExecutionError( - "The `user_name_or_email` argument is required to search for users." + message="The `user_name_or_email` argument is required to search for users." ) client = JiraClient(context.get_auth_token_or_empty()) diff --git a/toolkits/jira/arcade_jira/utils.py b/toolkits/jira/arcade_jira/utils.py index 247ecd69..26175fbb 100644 --- a/toolkits/jira/arcade_jira/utils.py +++ b/toolkits/jira/arcade_jira/utils.py @@ -2,12 +2,13 @@ import asyncio import base64 import json import mimetypes +from collections.abc import Callable from contextlib import suppress from datetime import date, datetime -from typing import Any, Callable, cast +from typing import Any, cast -from arcade.sdk import ToolContext -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk import ToolContext +from arcade_tdk.errors import ToolExecutionError from arcade_jira.constants import STOP_WORDS from arcade_jira.exceptions import JiraToolExecutionError, MultipleItemsFoundError, NotFoundError @@ -411,7 +412,7 @@ async def find_multiple_unique_users( if response["pagination"]["total_results"] > 1: simplified_users = [simplify_user_dict(user) for user in response["users"]] raise MultipleItemsFoundError( - f"Multiple users found with name or email '{user_identifier}'. " + message=f"Multiple users found with name or email '{user_identifier}'. " f"Please provide a unique ID: {json.dumps(simplified_users)}" ) @@ -430,7 +431,7 @@ async def find_multiple_unique_users( users.append(response["user"]) else: raise NotFoundError( - f"No user found with '{response['query']['user_id']}'.", + message=f"No user found with '{response['query']['user_id']}'.", ) return users @@ -470,11 +471,11 @@ async def find_unique_project( for project in projects ] raise MultipleItemsFoundError( - f"Multiple projects found with name/key/ID '{project_identifier}'. " + message=f"Multiple projects found with name/key/ID '{project_identifier}'. " f"Please provide a unique ID: {json.dumps(simplified_projects)}" ) - raise NotFoundError(f"Project not found with name/key/ID '{project_identifier}'") + raise NotFoundError(message=f"Project not found with name/key/ID '{project_identifier}'") async def find_unique_priority( @@ -526,11 +527,11 @@ async def find_unique_priority( for match in matches ] raise MultipleItemsFoundError( - f"Multiple priorities found with name '{priority_identifier}'. " + message=f"Multiple priorities found with name '{priority_identifier}'. " f"Please provide a unique ID: {json.dumps(simplified_matches)}" ) - raise NotFoundError(f"Priority not found with ID or name '{priority_identifier}'") + raise NotFoundError(message=f"Priority not found with ID or name '{priority_identifier}'") async def find_unique_issue_type( @@ -579,7 +580,7 @@ async def find_unique_issue_type( for match in matches ] raise MultipleItemsFoundError( - f"Multiple issue types found with name '{issue_type_identifier}'. " + message=f"Multiple issue types found with name '{issue_type_identifier}'. " f"Please provide a unique ID: {json.dumps(simplified_matches)}" ) @@ -592,7 +593,7 @@ async def find_unique_issue_type( ]) raise NotFoundError( - f"Issue type not found with ID or name '{issue_type_identifier}'. " + message=f"Issue type not found with ID or name '{issue_type_identifier}'. " f"These are the issue types available for the project: {available_issue_types}" ) @@ -628,11 +629,11 @@ async def find_unique_user( for user in users ] raise MultipleItemsFoundError( - f"Multiple users found with name or email '{user_identifier}'. " + message=f"Multiple users found with name or email '{user_identifier}'. " f"Please provide a unique ID: {json.dumps(simplified_users)}" ) - raise NotFoundError(f"User not found with ID, name or email '{user_identifier}'") + raise NotFoundError(message=f"User not found with ID, name or email '{user_identifier}'") async def get_single_project(context: ToolContext) -> dict[str, Any]: @@ -645,7 +646,7 @@ async def get_single_project(context: ToolContext) -> dict[str, Any]: ) if len(projects) == 0: - raise NotFoundError("No projects found in this account.") + raise NotFoundError(message="No projects found in this account.") if len(projects) == 1: return cast(dict[str, Any], projects[0]) @@ -658,7 +659,7 @@ async def get_single_project(context: ToolContext) -> dict[str, Any]: for project in projects ]) - raise MultipleItemsFoundError(f"Multiple projects found: {available_projects_str}") + raise MultipleItemsFoundError(message=f"Multiple projects found: {available_projects_str}") def build_file_data( @@ -672,16 +673,19 @@ def build_file_data( try: file_content = file_content_str.encode(file_encoding) except LookupError as exc: - raise ToolExecutionError(f"Unknown encoding: {file_encoding}") from exc + raise ToolExecutionError(message=f"Unknown encoding: {file_encoding}") from exc except Exception as exc: raise ToolExecutionError( - f"Failed to encode file content string with {file_encoding} encoding: {exc!s}" + message=f"Failed to encode file content string with {file_encoding} " + f"encoding: {exc!s}" ) from exc elif file_content_base64 is not None: try: file_content = base64.b64decode(file_content_base64) except Exception as exc: - raise ToolExecutionError(f"Failed to decode base64 file content: {exc!s}") from exc + raise ToolExecutionError( + message=f"Failed to decode base64 file content: {exc!s}" + ) from exc if not file_type: # guess_type returns None if the file type is not recognized @@ -952,7 +956,7 @@ async def find_priorities_by_project( priority_schemes = await paginate_all_priority_schemes(context) if not priority_schemes: - raise NotFoundError("No priority schemes found") + raise NotFoundError("No priority schemes found") # noqa: TRY003 projects_by_scheme = await asyncio.gather(*[ list_projects_associated_with_a_priority_scheme( @@ -1032,7 +1036,7 @@ def build_issue_update_text_fields( environment: str | None, ) -> dict[str, dict[str, Any]]: if title == "": - raise ValueError("Title cannot be empty") + raise ValueError("Title cannot be empty") # noqa: TRY003 elif title: body["fields"]["summary"] = title @@ -1059,14 +1063,14 @@ def build_issue_update_user_fields( elif isinstance(assignee, dict): body["fields"]["assignee"] = {"id": assignee["id"]} elif assignee is not None: - raise ValueError(f"Invalid assignee: '{assignee}'") + raise ValueError(f"Invalid assignee: '{assignee}'") # noqa: TRY003 if reporter == "": body["update"]["reporter"] = [{"set": None}] elif isinstance(reporter, dict): body["fields"]["reporter"] = {"id": reporter["id"]} elif reporter is not None: - raise ValueError(f"Invalid reporter: '{reporter}'") + raise ValueError(f"Invalid reporter: '{reporter}'") # noqa: TRY003 return body @@ -1077,18 +1081,18 @@ def build_issue_update_classifier_fields( priority: str | dict | None, ) -> dict[str, dict[str, Any]]: if issue_type == "": - raise ValueError("Issue type cannot be empty") + raise ValueError("Issue type cannot be empty") # noqa: TRY003 elif isinstance(issue_type, dict): body["fields"]["issuetype"] = {"id": issue_type["id"]} elif issue_type is not None: - raise ValueError(f"Invalid issue type: '{issue_type}'") + raise ValueError(f"Invalid issue type: '{issue_type}'") # noqa: TRY003 if priority == "": - raise ValueError("Priority cannot be empty") + raise ValueError("Priority cannot be empty") # noqa: TRY003 elif isinstance(priority, dict): body["fields"]["priority"] = {"id": priority["id"]} elif priority is not None: - raise ValueError(f"Invalid priority: '{priority}'") + raise ValueError(f"Invalid priority: '{priority}'") # noqa: TRY003 return body diff --git a/toolkits/jira/conftest.py b/toolkits/jira/conftest.py index df8d4b88..4f859f59 100644 --- a/toolkits/jira/conftest.py +++ b/toolkits/jira/conftest.py @@ -1,11 +1,12 @@ import random import string -from typing import Any, Callable +from collections.abc import Callable +from typing import Any from unittest.mock import MagicMock, patch import httpx import pytest -from arcade.sdk import ToolAuthorizationContext, ToolContext +from arcade_tdk import ToolAuthorizationContext, ToolContext from arcade_jira.cache import set_cloud_id, set_cloud_name diff --git a/toolkits/jira/evals/eval_create_update_issues.py b/toolkits/jira/evals/eval_create_update_issues.py index 83309183..59e18ee6 100644 --- a/toolkits/jira/evals/eval_create_update_issues.py +++ b/toolkits/jira/evals/eval_create_update_issues.py @@ -1,11 +1,11 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( EvalRubric, EvalSuite, ExpectedToolCall, tool_eval, ) -from arcade.sdk.eval.critic import BinaryCritic +from arcade_evals.critic import BinaryCritic +from arcade_tdk import ToolCatalog import arcade_jira from arcade_jira.critics import ( @@ -82,8 +82,10 @@ def create_issue_eval_suite() -> EvalSuite: suite.add_case( name="Create issue with parent and reporter", user_message=( - "Create a task for John Doe to 'Implement message queue service' as a child of the issue ENG-321 " - "and reported by Jenifer Bear. It should be due on 2025-06-30. Label it with 'Project XYZ'." + "Create a task for John Doe to 'Implement message queue service' " + "as a child of the issue ENG-321 and reported by Jenifer Bear. " + "It should be due on 2025-06-30. " + "Label it with 'Project XYZ'." ), expected_tool_calls=[ ExpectedToolCall( @@ -147,7 +149,9 @@ def labels_eval_suite() -> EvalSuite: suite.add_case( name="Add labels without notifying watchers", - user_message="Add the labels 'Hello' and 'World' to the issue ENG-123. Do not notify watchers.", + user_message=( + "Add the labels 'Hello' and 'World' to the issue ENG-123. Do not notify watchers." + ), expected_tool_calls=[ ExpectedToolCall( func=add_labels_to_issue, @@ -187,7 +191,9 @@ def labels_eval_suite() -> EvalSuite: suite.add_case( name="Remove labels without notifying watchers", - user_message="Remove the labels 'Hello' and 'World' from the issue ENG-123. Do not notify watchers.", + user_message=( + "Remove the labels 'Hello' and 'World' from the issue ENG-123. Do not notify watchers." + ), expected_tool_calls=[ ExpectedToolCall( func=remove_labels_from_issue, @@ -299,7 +305,10 @@ def update_issue_eval_suite() -> EvalSuite: suite.add_case( name="Update issue with new title and description", - user_message="Change the title and description of the ENG-123 issue to 'Test issue' and 'This is a test issue'.", + user_message=( + "Change the title and description of the ENG-123 issue to 'Test issue' " + "and 'This is a test issue'." + ), expected_tool_calls=[ ExpectedToolCall( func=update_issue, diff --git a/toolkits/jira/evals/eval_get_issues.py b/toolkits/jira/evals/eval_get_issues.py index e4f73d8f..5efc08b2 100644 --- a/toolkits/jira/evals/eval_get_issues.py +++ b/toolkits/jira/evals/eval_get_issues.py @@ -1,13 +1,13 @@ import json -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( EvalRubric, EvalSuite, ExpectedToolCall, tool_eval, ) -from arcade.sdk.eval.critic import BinaryCritic +from arcade_evals.critic import BinaryCritic +from arcade_tdk import ToolCatalog import arcade_jira from arcade_jira.critics import CaseInsensitiveBinaryCritic, HasSubstringCritic @@ -223,7 +223,9 @@ def get_issues_without_id_eval_suite() -> EvalSuite: additional_messages=[ { "role": "user", - "content": "Find 2 tasks assigned to John Doe that are in progress, with high priority", + "content": ( + "Find 2 tasks assigned to John Doe that are in progress, with high priority" + ), }, { "role": "assistant", @@ -316,7 +318,11 @@ def get_issues_without_id_eval_suite() -> EvalSuite: }, { "role": "assistant", - "content": "Here are two issues:\n\n1. ENG-101: Implement the message queue\n2. ENG-102: Deploy the message queue system", + "content": ( + "Here are two issues:\n\n" + "1. ENG-101: Implement the message queue\n" + "2. ENG-102: Deploy the message queue system" + ), }, ], ) diff --git a/toolkits/jira/evals/eval_issue_types.py b/toolkits/jira/evals/eval_issue_types.py index 2e825526..c734fe70 100644 --- a/toolkits/jira/evals/eval_issue_types.py +++ b/toolkits/jira/evals/eval_issue_types.py @@ -1,13 +1,13 @@ import json -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( EvalRubric, EvalSuite, ExpectedToolCall, tool_eval, ) -from arcade.sdk.eval.critic import BinaryCritic +from arcade_evals.critic import BinaryCritic +from arcade_tdk import ToolCatalog import arcade_jira from arcade_jira.tools.issues import ( @@ -176,7 +176,9 @@ def list_issue_types_eval_suite() -> EvalSuite: { "id": "10001", "name": "Bug", - "description": "A bug is an error or flaw in a software application or website.", + "description": ( + "A bug is an error or flaw in a software application or website." + ), }, { "id": "10002", @@ -195,7 +197,9 @@ def list_issue_types_eval_suite() -> EvalSuite: }, { "role": "assistant", - "content": "Here are two issue types in the project 'Engineering':\n\n1. Bug\n2. Task", + "content": ( + "Here are two issue types in the project 'Engineering':\n\n1. Bug\n2. Task" + ), }, ], ) diff --git a/toolkits/jira/evals/eval_transitions.py b/toolkits/jira/evals/eval_transitions.py index 2ade5674..90429348 100644 --- a/toolkits/jira/evals/eval_transitions.py +++ b/toolkits/jira/evals/eval_transitions.py @@ -1,10 +1,10 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( EvalRubric, EvalSuite, ExpectedToolCall, tool_eval, ) +from arcade_tdk import ToolCatalog import arcade_jira from arcade_jira.critics import ( diff --git a/toolkits/jira/pyproject.toml b/toolkits/jira/pyproject.toml index f0a095fa..bfd198b9 100644 --- a/toolkits/jira/pyproject.toml +++ b/toolkits/jira/pyproject.toml @@ -1,30 +1,42 @@ -[tool.poetry] +[build-system] +requires = [ "hatchling",] +build-backend = "hatchling.build" + +[project] name = "arcade_jira" version = "0.1.2" -description = "Arcade tools designed for LLMs to interact with Atlassian Jira" -authors = ["Arcade "] +description = "Arcade.dev LLM tools for interacting with Atlassian Jira" +requires-python = ">=3.10" +dependencies = [ + "arcade-tdk>=2.0.0,<3.0.0", + "httpx>=0.27.2,<1.0.0", +] +[[project.authors]] +name = "Arcade" +email = "dev@arcade.dev" -[tool.poetry.dependencies] -python = "^3.10" -arcade-ai = ">=1.4.0,<2.0" -httpx = "^0.27.2" +[project.optional-dependencies] +dev = [ + "arcade-ai[evals]>=2.0.0,<3.0.0", + "arcade-serve>=2.0.0,<3.0.0", + "pytest>=8.3.0,<8.4.0", + "pytest-cov>=4.0.0,<4.1.0", + "pytest-asyncio>=0.24.0,<0.25.0", + "pytest-mock>=3.11.1,<3.12.0", + "mypy>=1.5.1,<1.6.0", + "pre-commit>=3.4.0,<3.5.0", + "tox>=4.11.1,<4.12.0", + "ruff>=0.7.4,<0.8.0", +] -[tool.poetry.dev-dependencies] -pytest = "^8.3.0" -pytest-cov = "^4.0.0" -pytest-asyncio = "^0.24.0" -pytest-mock = "^3.11.1" -mypy = "^1.5.1" -pre-commit = "^3.4.0" -tox = "^4.11.1" -ruff = "^0.7.4" - -[build-system] -requires = ["poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" +# Use local path sources for arcade libs when working locally +[tool.uv.sources] +arcade-ai = {path = "../../", editable = true} +arcade-tdk = { path = "../../libs/arcade-tdk/", editable = true } +arcade-serve = { path = "../../libs/arcade-serve/", editable = true } [tool.mypy] -files = ["arcade_jira/**/*.py"] +files = [ "arcade_jira/**/*.py",] python_version = "3.10" disallow_untyped_defs = "True" disallow_any_unimported = "True" @@ -36,7 +48,10 @@ show_error_codes = "True" ignore_missing_imports = "True" [tool.pytest.ini_options] -testpaths = ["tests"] +testpaths = [ "tests",] [tool.coverage.report] skip_empty = true + +[tool.hatch.build.targets.wheel] +packages = [ "arcade_jira",] diff --git a/toolkits/jira/tests/test_find_priorities_by_project.py b/toolkits/jira/tests/test_find_priorities_by_project.py index 3487d700..9ad08cbd 100644 --- a/toolkits/jira/tests/test_find_priorities_by_project.py +++ b/toolkits/jira/tests/test_find_priorities_by_project.py @@ -1,8 +1,8 @@ -from typing import Callable +from collections.abc import Callable import httpx import pytest -from arcade.sdk import ToolContext +from arcade_tdk import ToolContext from arcade_jira.exceptions import NotFoundError from arcade_jira.utils import clean_priority_dict, find_priorities_by_project @@ -213,7 +213,7 @@ async def test_find_priorities_by_project_happy_path_with_repeated_priorities_ac elif url.endswith(f"/priorityscheme/{priority_scheme2['id']}/priorities"): return list_priorities_by_scheme_response2 else: - raise ValueError(f"Unexpected URL: {url}") + raise ValueError(f"Unexpected URL: {url}") # noqa: TRY003 mock_httpx_client.get.side_effect = get_httpx_response diff --git a/toolkits/jira/tests/test_find_unique_issue_type.py b/toolkits/jira/tests/test_find_unique_issue_type.py index 23ff3285..5e57754d 100644 --- a/toolkits/jira/tests/test_find_unique_issue_type.py +++ b/toolkits/jira/tests/test_find_unique_issue_type.py @@ -1,8 +1,8 @@ import json -from typing import Callable +from collections.abc import Callable import pytest -from arcade.sdk import ToolContext +from arcade_tdk import ToolContext from arcade_jira.exceptions import JiraToolExecutionError, MultipleItemsFoundError, NotFoundError from arcade_jira.utils import clean_issue_type_dict, find_unique_issue_type diff --git a/toolkits/jira/tests/test_find_unique_priority.py b/toolkits/jira/tests/test_find_unique_priority.py index 6eb32342..6749f4c2 100644 --- a/toolkits/jira/tests/test_find_unique_priority.py +++ b/toolkits/jira/tests/test_find_unique_priority.py @@ -1,8 +1,8 @@ -from typing import Callable +from collections.abc import Callable from unittest.mock import patch import pytest -from arcade.sdk import ToolContext +from arcade_tdk import ToolContext from arcade_jira.exceptions import JiraToolExecutionError, MultipleItemsFoundError, NotFoundError from arcade_jira.utils import clean_priority_dict, find_unique_priority diff --git a/toolkits/jira/tests/test_find_unique_project.py b/toolkits/jira/tests/test_find_unique_project.py index f37af505..97762edc 100644 --- a/toolkits/jira/tests/test_find_unique_project.py +++ b/toolkits/jira/tests/test_find_unique_project.py @@ -1,7 +1,7 @@ -from typing import Callable +from collections.abc import Callable import pytest -from arcade.sdk import ToolContext +from arcade_tdk import ToolContext from arcade_jira.exceptions import MultipleItemsFoundError, NotFoundError from arcade_jira.utils import clean_project_dict, find_unique_project diff --git a/toolkits/jira/tests/test_find_unique_user.py b/toolkits/jira/tests/test_find_unique_user.py index 2c8f4b70..eb30e0cf 100644 --- a/toolkits/jira/tests/test_find_unique_user.py +++ b/toolkits/jira/tests/test_find_unique_user.py @@ -1,7 +1,7 @@ -from typing import Callable +from collections.abc import Callable import pytest -from arcade.sdk import ToolContext +from arcade_tdk import ToolContext from arcade_jira.exceptions import MultipleItemsFoundError, NotFoundError from arcade_jira.utils import ( diff --git a/toolkits/jira/tests/test_pagination_helpers.py b/toolkits/jira/tests/test_pagination_helpers.py index 58accd35..f33c47ff 100644 --- a/toolkits/jira/tests/test_pagination_helpers.py +++ b/toolkits/jira/tests/test_pagination_helpers.py @@ -1,7 +1,7 @@ -from typing import Callable +from collections.abc import Callable import pytest -from arcade.sdk import ToolContext +from arcade_tdk import ToolContext from arcade_jira.exceptions import JiraToolExecutionError from arcade_jira.tools.priorities import list_projects_associated_with_a_priority_scheme diff --git a/toolkits/linkedin/.pre-commit-config.yaml b/toolkits/linkedin/.pre-commit-config.yaml index 3953e996..bc01e243 100644 --- a/toolkits/linkedin/.pre-commit-config.yaml +++ b/toolkits/linkedin/.pre-commit-config.yaml @@ -1,4 +1,4 @@ -files: ^./ +files: ^.*/linkedin/.* repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: "v4.4.0" diff --git a/toolkits/linkedin/Makefile b/toolkits/linkedin/Makefile index 82c17735..7e2c686e 100644 --- a/toolkits/linkedin/Makefile +++ b/toolkits/linkedin/Makefile @@ -1,30 +1,27 @@ .PHONY: help help: - @echo "๐Ÿ› ๏ธ linkedin Commands:\n" + @echo "๐Ÿ› ๏ธ github Commands:\n" @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' .PHONY: install -install: ## Install the poetry environment and install the pre-commit hooks - @echo "๐Ÿ“ฆ Checking if Poetry is installed" - @if ! command -v poetry >/dev/null 2>&1; then \ - echo "๐Ÿ“ฆ Poetry not found. Checking if pip is available"; \ - if ! command -v pip >/dev/null 2>&1; then \ - echo "โŒ pip is not installed. Please install pip first."; \ - exit 1; \ - fi; \ - echo "๐Ÿ“ฆ Installing Poetry with pip"; \ - pip install poetry==1.8.5; \ - else \ - echo "๐Ÿ“ฆ Poetry is already installed"; \ - fi - @echo "๐Ÿš€ Installing package in development mode with all extras" - poetry install --all-extras +install: ## Install the uv environment and install all packages with dependencies + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras --no-sources + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" + +.PHONY: install-local +install-local: ## Install the uv environment and install all packages with dependencies with local Arcade sources + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" .PHONY: build build: clean-build ## Build wheel file using poetry @echo "๐Ÿš€ Creating wheel file" - poetry build + uv build .PHONY: clean-build clean-build: ## clean build artifacts @@ -34,7 +31,7 @@ clean-build: ## clean build artifacts .PHONY: test test: ## Test the code with pytest @echo "๐Ÿš€ Testing code: Running pytest" - @poetry run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml + @uv run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml .PHONY: coverage coverage: ## Generate coverage report @@ -44,15 +41,13 @@ coverage: ## Generate coverage report coverage html .PHONY: bump-version -bump-version: ## Bump the version in the pyproject.toml file +bump-version: ## Bump the version in the pyproject.toml file by a patch version @echo "๐Ÿš€ Bumping version in pyproject.toml" - poetry version patch + uv version --bump patch .PHONY: check check: ## Run code quality tools. - @echo "๐Ÿš€ Checking Poetry lock file consistency with 'pyproject.toml': Running poetry check" - @poetry check @echo "๐Ÿš€ Linting code: Running pre-commit" - @poetry run pre-commit run -a + @uv run pre-commit run -a @echo "๐Ÿš€ Static type checking: Running mypy" - @poetry run mypy --config-file=pyproject.toml + @uv run mypy --config-file=pyproject.toml diff --git a/toolkits/linkedin/arcade_linkedin/tools/share.py b/toolkits/linkedin/arcade_linkedin/tools/share.py index ac642835..16549e0a 100644 --- a/toolkits/linkedin/arcade_linkedin/tools/share.py +++ b/toolkits/linkedin/arcade_linkedin/tools/share.py @@ -1,8 +1,8 @@ from typing import Annotated -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import LinkedIn -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import LinkedIn +from arcade_tdk.errors import ToolExecutionError from arcade_linkedin.tools.utils import _handle_linkedin_api_error, _send_linkedin_request diff --git a/toolkits/linkedin/arcade_linkedin/tools/utils.py b/toolkits/linkedin/arcade_linkedin/tools/utils.py index 6f56a00f..782b8409 100644 --- a/toolkits/linkedin/arcade_linkedin/tools/utils.py +++ b/toolkits/linkedin/arcade_linkedin/tools/utils.py @@ -1,6 +1,6 @@ import httpx -from arcade.sdk import ToolContext -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk import ToolContext +from arcade_tdk.errors import ToolExecutionError from arcade_linkedin.tools.constants import LINKEDIN_BASE_URL diff --git a/toolkits/linkedin/conftest.py b/toolkits/linkedin/conftest.py index d44668ec..7cba84e5 100644 --- a/toolkits/linkedin/conftest.py +++ b/toolkits/linkedin/conftest.py @@ -1,5 +1,5 @@ import pytest -from arcade.sdk import ToolAuthorizationContext, ToolContext +from arcade_tdk import ToolAuthorizationContext, ToolContext @pytest.fixture diff --git a/toolkits/linkedin/evals/eval_linkedin.py b/toolkits/linkedin/evals/eval_linkedin.py index d916bc46..5a4c005f 100644 --- a/toolkits/linkedin/evals/eval_linkedin.py +++ b/toolkits/linkedin/evals/eval_linkedin.py @@ -1,11 +1,11 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( EvalRubric, EvalSuite, ExpectedToolCall, SimilarityCritic, tool_eval, ) +from arcade_tdk import ToolCatalog import arcade_linkedin from arcade_linkedin.tools.share import create_text_post diff --git a/toolkits/linkedin/pyproject.toml b/toolkits/linkedin/pyproject.toml index 28344a62..ccdc903e 100644 --- a/toolkits/linkedin/pyproject.toml +++ b/toolkits/linkedin/pyproject.toml @@ -1,30 +1,42 @@ -[tool.poetry] +[build-system] +requires = [ "hatchling",] +build-backend = "hatchling.build" + +[project] name = "arcade_linkedin" version = "0.1.10" description = "Arcade.dev LLM tools for LinkedIn" -authors = ["Arcade "] +requires-python = ">=3.10" +dependencies = [ + "arcade-tdk>=2.0.0,<3.0.0", + "httpx>=0.27.2,<1.0.0", +] +[[project.authors]] +name = "Arcade" +email = "dev@arcade.dev" -[tool.poetry.dependencies] -python = "^3.10" -arcade-ai = ">=0.1,<2.0" -httpx = "^0.27.2" +[project.optional-dependencies] +dev = [ + "arcade-ai[evals]>=2.0.0,<3.0.0", + "arcade-serve>=2.0.0,<3.0.0", + "pytest>=8.3.0,<8.4.0", + "pytest-cov>=4.0.0,<4.1.0", + "pytest-asyncio>=0.24.0,<0.25.0", + "pytest-mock>=3.11.1,<3.12.0", + "mypy>=1.5.1,<1.6.0", + "pre-commit>=3.4.0,<3.5.0", + "tox>=4.11.1,<4.12.0", + "ruff>=0.7.4,<0.8.0", +] -[tool.poetry.dev-dependencies] -pytest = "^8.3.0" -pytest-cov = "^4.0.0" -pytest-asyncio = "^0.24.0" -pytest-mock = "^3.11.1" -mypy = "^1.5.1" -pre-commit = "^3.4.0" -tox = "^4.11.1" -ruff = "^0.7.4" - -[build-system] -requires = ["poetry-core>=1.0.0,<2.0.0"] -build-backend = "poetry.core.masonry.api" +# Use local path sources for arcade libs when working locally +[tool.uv.sources] +arcade-ai = {path = "../../", editable = true} +arcade-tdk = { path = "../../libs/arcade-tdk/", editable = true } +arcade-serve = { path = "../../libs/arcade-serve/", editable = true } [tool.mypy] -files = ["arcade_linkedin/**/*.py"] +files = [ "arcade_linkedin/**/*.py",] python_version = "3.10" disallow_untyped_defs = "True" disallow_any_unimported = "True" @@ -36,7 +48,10 @@ show_error_codes = "True" ignore_missing_imports = "True" [tool.pytest.ini_options] -testpaths = ["tests"] +testpaths = [ "tests",] [tool.coverage.report] skip_empty = true + +[tool.hatch.build.targets.wheel] +packages = [ "arcade_linkedin",] diff --git a/toolkits/linkedin/tests/test_share.py b/toolkits/linkedin/tests/test_share.py index efc0f24a..9aa39882 100644 --- a/toolkits/linkedin/tests/test_share.py +++ b/toolkits/linkedin/tests/test_share.py @@ -1,7 +1,7 @@ from unittest.mock import AsyncMock, MagicMock import pytest -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk.errors import ToolExecutionError from arcade_linkedin.tools.share import create_text_post diff --git a/toolkits/math/.pre-commit-config.yaml b/toolkits/math/.pre-commit-config.yaml index 3953e996..3e1fd287 100644 --- a/toolkits/math/.pre-commit-config.yaml +++ b/toolkits/math/.pre-commit-config.yaml @@ -1,4 +1,4 @@ -files: ^./ +files: ^.*/math/.* repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: "v4.4.0" diff --git a/toolkits/math/Makefile b/toolkits/math/Makefile index 55dee607..7e2c686e 100644 --- a/toolkits/math/Makefile +++ b/toolkits/math/Makefile @@ -1,30 +1,27 @@ .PHONY: help help: - @echo "๐Ÿ› ๏ธ math Commands:\n" + @echo "๐Ÿ› ๏ธ github Commands:\n" @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' .PHONY: install -install: ## Install the poetry environment and install the pre-commit hooks - @echo "๐Ÿ“ฆ Checking if Poetry is installed" - @if ! command -v poetry >/dev/null 2>&1; then \ - echo "๐Ÿ“ฆ Poetry not found. Checking if pip is available"; \ - if ! command -v pip >/dev/null 2>&1; then \ - echo "โŒ pip is not installed. Please install pip first."; \ - exit 1; \ - fi; \ - echo "๐Ÿ“ฆ Installing Poetry with pip"; \ - pip install poetry==1.8.5; \ - else \ - echo "๐Ÿ“ฆ Poetry is already installed"; \ - fi - @echo "๐Ÿš€ Installing package in development mode with all extras" - poetry install --all-extras +install: ## Install the uv environment and install all packages with dependencies + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras --no-sources + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" + +.PHONY: install-local +install-local: ## Install the uv environment and install all packages with dependencies with local Arcade sources + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" .PHONY: build build: clean-build ## Build wheel file using poetry @echo "๐Ÿš€ Creating wheel file" - poetry build + uv build .PHONY: clean-build clean-build: ## clean build artifacts @@ -34,7 +31,7 @@ clean-build: ## clean build artifacts .PHONY: test test: ## Test the code with pytest @echo "๐Ÿš€ Testing code: Running pytest" - @poetry run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml + @uv run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml .PHONY: coverage coverage: ## Generate coverage report @@ -44,15 +41,13 @@ coverage: ## Generate coverage report coverage html .PHONY: bump-version -bump-version: ## Bump the version in the pyproject.toml file +bump-version: ## Bump the version in the pyproject.toml file by a patch version @echo "๐Ÿš€ Bumping version in pyproject.toml" - poetry version patch + uv version --bump patch .PHONY: check check: ## Run code quality tools. - @echo "๐Ÿš€ Checking Poetry lock file consistency with 'pyproject.toml': Running poetry check" - @poetry check @echo "๐Ÿš€ Linting code: Running pre-commit" - @poetry run pre-commit run -a + @uv run pre-commit run -a @echo "๐Ÿš€ Static type checking: Running mypy" - @poetry run mypy --config-file=pyproject.toml + @uv run mypy --config-file=pyproject.toml diff --git a/toolkits/math/arcade_math/tools/arithmetic.py b/toolkits/math/arcade_math/tools/arithmetic.py index 77238503..251c09ff 100644 --- a/toolkits/math/arcade_math/tools/arithmetic.py +++ b/toolkits/math/arcade_math/tools/arithmetic.py @@ -2,7 +2,7 @@ import decimal from decimal import Decimal from typing import Annotated -from arcade.sdk import tool +from arcade_tdk import tool decimal.getcontext().prec = 100 diff --git a/toolkits/math/arcade_math/tools/exponents.py b/toolkits/math/arcade_math/tools/exponents.py index 746da832..14fbd55e 100644 --- a/toolkits/math/arcade_math/tools/exponents.py +++ b/toolkits/math/arcade_math/tools/exponents.py @@ -3,7 +3,7 @@ import math from decimal import Decimal from typing import Annotated -from arcade.sdk import tool +from arcade_tdk import tool decimal.getcontext().prec = 100 diff --git a/toolkits/math/arcade_math/tools/miscellaneous.py b/toolkits/math/arcade_math/tools/miscellaneous.py index 3a990903..db52e92c 100644 --- a/toolkits/math/arcade_math/tools/miscellaneous.py +++ b/toolkits/math/arcade_math/tools/miscellaneous.py @@ -3,7 +3,7 @@ import math from decimal import Decimal from typing import Annotated -from arcade.sdk import tool +from arcade_tdk import tool decimal.getcontext().prec = 100 diff --git a/toolkits/math/arcade_math/tools/random.py b/toolkits/math/arcade_math/tools/random.py index c6e8be78..7b50d345 100644 --- a/toolkits/math/arcade_math/tools/random.py +++ b/toolkits/math/arcade_math/tools/random.py @@ -1,7 +1,7 @@ import random from typing import Annotated -from arcade.sdk import tool +from arcade_tdk import tool @tool diff --git a/toolkits/math/arcade_math/tools/rational.py b/toolkits/math/arcade_math/tools/rational.py index fdd16a92..fa314919 100644 --- a/toolkits/math/arcade_math/tools/rational.py +++ b/toolkits/math/arcade_math/tools/rational.py @@ -1,7 +1,7 @@ import math from typing import Annotated -from arcade.sdk import tool +from arcade_tdk import tool @tool diff --git a/toolkits/math/arcade_math/tools/rounding.py b/toolkits/math/arcade_math/tools/rounding.py index 2e410ddd..9d9e7ea0 100644 --- a/toolkits/math/arcade_math/tools/rounding.py +++ b/toolkits/math/arcade_math/tools/rounding.py @@ -3,7 +3,7 @@ import math from decimal import Decimal from typing import Annotated -from arcade.sdk import tool +from arcade_tdk import tool decimal.getcontext().prec = 100 diff --git a/toolkits/math/arcade_math/tools/statistics.py b/toolkits/math/arcade_math/tools/statistics.py index a91a938d..2001d6e0 100644 --- a/toolkits/math/arcade_math/tools/statistics.py +++ b/toolkits/math/arcade_math/tools/statistics.py @@ -3,7 +3,7 @@ from decimal import Decimal from statistics import median as stats_median from typing import Annotated -from arcade.sdk import tool +from arcade_tdk import tool decimal.getcontext().prec = 100 diff --git a/toolkits/math/arcade_math/tools/trigonometry.py b/toolkits/math/arcade_math/tools/trigonometry.py index c58c2b23..db982439 100644 --- a/toolkits/math/arcade_math/tools/trigonometry.py +++ b/toolkits/math/arcade_math/tools/trigonometry.py @@ -3,7 +3,7 @@ import math from decimal import Decimal from typing import Annotated -from arcade.sdk import tool +from arcade_tdk import tool decimal.getcontext().prec = 100 diff --git a/toolkits/math/evals/eval_math_tools.py b/toolkits/math/evals/eval_math_tools.py index 9bc8a58f..f1646b0a 100644 --- a/toolkits/math/evals/eval_math_tools.py +++ b/toolkits/math/evals/eval_math_tools.py @@ -1,11 +1,11 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, EvalRubric, EvalSuite, ExpectedToolCall, tool_eval, ) +from arcade_tdk import ToolCatalog import arcade_math from arcade_math.tools.arithmetic import ( diff --git a/toolkits/math/pyproject.toml b/toolkits/math/pyproject.toml index 387f3919..cf61ee4e 100644 --- a/toolkits/math/pyproject.toml +++ b/toolkits/math/pyproject.toml @@ -1,29 +1,41 @@ -[tool.poetry] +[build-system] +requires = [ "hatchling",] +build-backend = "hatchling.build" + +[project] name = "arcade_math" version = "1.0.1" description = "Arcade.dev LLM tools for doing math" -authors = ["Arcade "] +requires-python = ">=3.10" +dependencies = [ + "arcade-tdk>=2.0.0,<3.0.0", +] +[[project.authors]] +name = "Arcade" +email = "dev@arcade.dev" -[tool.poetry.dependencies] -python = "^3.10" -arcade-ai = ">=1.0.5,<2.0" +[project.optional-dependencies] +dev = [ + "arcade-ai[evals]>=2.0.0,<3.0.0", + "arcade-serve>=2.0.0,<3.0.0", + "pytest>=8.3.0,<8.4.0", + "pytest-cov>=4.0.0,<4.1.0", + "pytest-asyncio>=0.24.0,<0.25.0", + "pytest-mock>=3.11.1,<3.12.0", + "mypy>=1.5.1,<1.6.0", + "pre-commit>=3.4.0,<3.5.0", + "tox>=4.11.1,<4.12.0", + "ruff>=0.7.4,<0.8.0", +] -[tool.poetry.dev-dependencies] -pytest = "^8.3.0" -pytest-cov = "^4.0.0" -pytest-asyncio = "^0.24.0" -pytest-mock = "^3.11.1" -mypy = "^1.5.1" -pre-commit = "^3.4.0" -tox = "^4.11.1" -ruff = "^0.7.4" - -[build-system] -requires = ["poetry-core>=1.0.0,<2.0.0"] -build-backend = "poetry.core.masonry.api" +# Use local path sources for arcade libs when working locally +[tool.uv.sources] +arcade-ai = {path = "../../", editable = true} +arcade-tdk = { path = "../../libs/arcade-tdk/", editable = true } +arcade-serve = { path = "../../libs/arcade-serve/", editable = true } [tool.mypy] -files = ["arcade_math/**/*.py"] +files = [ "arcade_math/**/*.py",] python_version = "3.10" disallow_untyped_defs = "True" disallow_any_unimported = "True" @@ -35,7 +47,10 @@ show_error_codes = "True" ignore_missing_imports = "True" [tool.pytest.ini_options] -testpaths = ["tests"] +testpaths = [ "tests",] [tool.coverage.report] skip_empty = true + +[tool.hatch.build.targets.wheel] +packages = [ "arcade_math",] diff --git a/toolkits/math/tests/test_arithmetic.py b/toolkits/math/tests/test_arithmetic.py index 8804d612..845110ea 100644 --- a/toolkits/math/tests/test_arithmetic.py +++ b/toolkits/math/tests/test_arithmetic.py @@ -1,5 +1,5 @@ import pytest -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk.errors import ToolExecutionError from arcade_math.tools.arithmetic import ( add, diff --git a/toolkits/math/tests/test_exponents.py b/toolkits/math/tests/test_exponents.py index d5628fda..be2d6f9e 100644 --- a/toolkits/math/tests/test_exponents.py +++ b/toolkits/math/tests/test_exponents.py @@ -1,5 +1,5 @@ import pytest -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk.errors import ToolExecutionError from arcade_math.tools.exponents import ( log, diff --git a/toolkits/math/tests/test_miscellaneous.py b/toolkits/math/tests/test_miscellaneous.py index a4a88510..16d7877b 100644 --- a/toolkits/math/tests/test_miscellaneous.py +++ b/toolkits/math/tests/test_miscellaneous.py @@ -1,5 +1,5 @@ import pytest -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk.errors import ToolExecutionError from arcade_math.tools.miscellaneous import ( abs_val, diff --git a/toolkits/math/tests/test_rational.py b/toolkits/math/tests/test_rational.py index fa854621..c35bef5c 100644 --- a/toolkits/math/tests/test_rational.py +++ b/toolkits/math/tests/test_rational.py @@ -1,5 +1,5 @@ import pytest -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk.errors import ToolExecutionError from arcade_math.tools.rational import ( gcd, diff --git a/toolkits/microsoft/.pre-commit-config.yaml b/toolkits/microsoft/.pre-commit-config.yaml index 3953e996..a740213d 100644 --- a/toolkits/microsoft/.pre-commit-config.yaml +++ b/toolkits/microsoft/.pre-commit-config.yaml @@ -1,4 +1,4 @@ -files: ^./ +files: ^.*/microsoft/.* repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: "v4.4.0" diff --git a/toolkits/microsoft/Makefile b/toolkits/microsoft/Makefile index 5c4e3a3c..7e2c686e 100644 --- a/toolkits/microsoft/Makefile +++ b/toolkits/microsoft/Makefile @@ -1,30 +1,27 @@ .PHONY: help help: - @echo "๐Ÿ› ๏ธ outlook_mail Commands:\n" + @echo "๐Ÿ› ๏ธ github Commands:\n" @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' .PHONY: install -install: ## Install the poetry environment and install the pre-commit hooks - @echo "๐Ÿ“ฆ Checking if Poetry is installed" - @if ! command -v poetry >/dev/null 2>&1; then \ - echo "๐Ÿ“ฆ Poetry not found. Checking if pip is available"; \ - if ! command -v pip >/dev/null 2>&1; then \ - echo "โŒ pip is not installed. Please install pip first."; \ - exit 1; \ - fi; \ - echo "๐Ÿ“ฆ Installing Poetry with pip"; \ - pip install poetry==1.8.5; \ - else \ - echo "๐Ÿ“ฆ Poetry is already installed"; \ - fi - @echo "๐Ÿš€ Installing package in development mode with all extras" - poetry install --all-extras +install: ## Install the uv environment and install all packages with dependencies + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras --no-sources + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" + +.PHONY: install-local +install-local: ## Install the uv environment and install all packages with dependencies with local Arcade sources + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" .PHONY: build build: clean-build ## Build wheel file using poetry @echo "๐Ÿš€ Creating wheel file" - poetry build + uv build .PHONY: clean-build clean-build: ## clean build artifacts @@ -34,7 +31,7 @@ clean-build: ## clean build artifacts .PHONY: test test: ## Test the code with pytest @echo "๐Ÿš€ Testing code: Running pytest" - @poetry run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml + @uv run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml .PHONY: coverage coverage: ## Generate coverage report @@ -44,15 +41,13 @@ coverage: ## Generate coverage report coverage html .PHONY: bump-version -bump-version: ## Bump the version in the pyproject.toml file +bump-version: ## Bump the version in the pyproject.toml file by a patch version @echo "๐Ÿš€ Bumping version in pyproject.toml" - poetry version patch + uv version --bump patch .PHONY: check check: ## Run code quality tools. - @echo "๐Ÿš€ Checking Poetry lock file consistency with 'pyproject.toml': Running poetry check" - @poetry check @echo "๐Ÿš€ Linting code: Running pre-commit" - @poetry run pre-commit run -a + @uv run pre-commit run -a @echo "๐Ÿš€ Static type checking: Running mypy" - @poetry run mypy --config-file=pyproject.toml + @uv run mypy --config-file=pyproject.toml diff --git a/toolkits/microsoft/arcade_microsoft/outlook_calendar/_utils.py b/toolkits/microsoft/arcade_microsoft/outlook_calendar/_utils.py index 3f42df8a..5be36170 100644 --- a/toolkits/microsoft/arcade_microsoft/outlook_calendar/_utils.py +++ b/toolkits/microsoft/arcade_microsoft/outlook_calendar/_utils.py @@ -3,7 +3,7 @@ from datetime import datetime from typing import Any import pytz -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk.errors import ToolExecutionError from kiota_abstractions.base_request_configuration import RequestConfiguration from kiota_abstractions.headers_collection import HeadersCollection from msgraph import GraphServiceClient diff --git a/toolkits/microsoft/arcade_microsoft/outlook_calendar/tools/create_event.py b/toolkits/microsoft/arcade_microsoft/outlook_calendar/tools/create_event.py index 49f3c6f0..021adfdb 100644 --- a/toolkits/microsoft/arcade_microsoft/outlook_calendar/tools/create_event.py +++ b/toolkits/microsoft/arcade_microsoft/outlook_calendar/tools/create_event.py @@ -1,7 +1,7 @@ from typing import Annotated -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Microsoft +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Microsoft from arcade_microsoft.client import get_client from arcade_microsoft.outlook_calendar._utils import ( diff --git a/toolkits/microsoft/arcade_microsoft/outlook_calendar/tools/get_event.py b/toolkits/microsoft/arcade_microsoft/outlook_calendar/tools/get_event.py index a21e5627..3c083c67 100644 --- a/toolkits/microsoft/arcade_microsoft/outlook_calendar/tools/get_event.py +++ b/toolkits/microsoft/arcade_microsoft/outlook_calendar/tools/get_event.py @@ -1,7 +1,7 @@ from typing import Annotated -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Microsoft +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Microsoft from arcade_microsoft.client import get_client from arcade_microsoft.outlook_calendar._utils import ( diff --git a/toolkits/microsoft/arcade_microsoft/outlook_calendar/tools/list_events_in_time_range.py b/toolkits/microsoft/arcade_microsoft/outlook_calendar/tools/list_events_in_time_range.py index 58780a78..3eeef1cc 100644 --- a/toolkits/microsoft/arcade_microsoft/outlook_calendar/tools/list_events_in_time_range.py +++ b/toolkits/microsoft/arcade_microsoft/outlook_calendar/tools/list_events_in_time_range.py @@ -1,7 +1,7 @@ from typing import Annotated -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Microsoft +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Microsoft from msgraph.generated.users.item.calendar.calendar_view.calendar_view_request_builder import ( CalendarViewRequestBuilder, ) diff --git a/toolkits/microsoft/arcade_microsoft/outlook_mail/_utils.py b/toolkits/microsoft/arcade_microsoft/outlook_mail/_utils.py index ec9f2b8c..8677adc4 100644 --- a/toolkits/microsoft/arcade_microsoft/outlook_mail/_utils.py +++ b/toolkits/microsoft/arcade_microsoft/outlook_mail/_utils.py @@ -1,4 +1,4 @@ -from arcade.sdk import ToolContext +from arcade_tdk import ToolContext from msgraph.generated.models.message_collection_response import MessageCollectionResponse from msgraph.generated.users.item.mail_folders.item.messages.messages_request_builder import ( MessagesRequestBuilder as MailFolderMessagesRequestBuilder, diff --git a/toolkits/microsoft/arcade_microsoft/outlook_mail/message.py b/toolkits/microsoft/arcade_microsoft/outlook_mail/message.py index b7e2ec7f..67f90e9a 100644 --- a/toolkits/microsoft/arcade_microsoft/outlook_mail/message.py +++ b/toolkits/microsoft/arcade_microsoft/outlook_mail/message.py @@ -1,6 +1,6 @@ import re from dataclasses import dataclass, field -from typing import Any +from typing import Any, cast from bs4 import BeautifulSoup from msgraph.generated.models.body_type import BodyType @@ -96,7 +96,7 @@ class Message: @staticmethod def _parse_importance(value: Any) -> str: - return value.value if getattr(value, "value", None) else "" + return cast(str, value.value) if getattr(value, "value", None) else "" @staticmethod def _parse_flag(flag: Any) -> dict[str, str]: diff --git a/toolkits/microsoft/arcade_microsoft/outlook_mail/tools/read.py b/toolkits/microsoft/arcade_microsoft/outlook_mail/tools/read.py index 2210af7a..58df53cb 100644 --- a/toolkits/microsoft/arcade_microsoft/outlook_mail/tools/read.py +++ b/toolkits/microsoft/arcade_microsoft/outlook_mail/tools/read.py @@ -1,8 +1,8 @@ from typing import Annotated -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Microsoft -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Microsoft +from arcade_tdk.errors import ToolExecutionError from arcade_microsoft.client import get_client from arcade_microsoft.outlook_mail._utils import ( diff --git a/toolkits/microsoft/arcade_microsoft/outlook_mail/tools/send.py b/toolkits/microsoft/arcade_microsoft/outlook_mail/tools/send.py index 1c68ccc6..d40c280f 100644 --- a/toolkits/microsoft/arcade_microsoft/outlook_mail/tools/send.py +++ b/toolkits/microsoft/arcade_microsoft/outlook_mail/tools/send.py @@ -1,7 +1,7 @@ from typing import Annotated -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Microsoft +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Microsoft from msgraph.generated.users.item.send_mail.send_mail_post_request_body import ( SendMailPostRequestBody, ) diff --git a/toolkits/microsoft/arcade_microsoft/outlook_mail/tools/write.py b/toolkits/microsoft/arcade_microsoft/outlook_mail/tools/write.py index 0923ba1c..4af31d38 100644 --- a/toolkits/microsoft/arcade_microsoft/outlook_mail/tools/write.py +++ b/toolkits/microsoft/arcade_microsoft/outlook_mail/tools/write.py @@ -1,8 +1,8 @@ from typing import Annotated -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Microsoft -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Microsoft +from arcade_tdk.errors import ToolExecutionError from arcade_microsoft.client import get_client from arcade_microsoft.outlook_mail.message import Message, Recipient diff --git a/toolkits/microsoft/evals/outlook_calendar/eval_create_event.py b/toolkits/microsoft/evals/outlook_calendar/eval_create_event.py index ec1cdeec..91006617 100644 --- a/toolkits/microsoft/evals/outlook_calendar/eval_create_event.py +++ b/toolkits/microsoft/evals/outlook_calendar/eval_create_event.py @@ -1,12 +1,12 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, EvalRubric, EvalSuite, ExpectedToolCall, + SimilarityCritic, tool_eval, ) -from arcade.sdk.eval.critic import SimilarityCritic +from arcade_tdk import ToolCatalog from arcade_microsoft.outlook_calendar import create_event diff --git a/toolkits/microsoft/evals/outlook_calendar/eval_get_event.py b/toolkits/microsoft/evals/outlook_calendar/eval_get_event.py index ef3f8e25..1b657bb1 100644 --- a/toolkits/microsoft/evals/outlook_calendar/eval_get_event.py +++ b/toolkits/microsoft/evals/outlook_calendar/eval_get_event.py @@ -1,11 +1,11 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, EvalRubric, EvalSuite, ExpectedToolCall, tool_eval, ) +from arcade_tdk import ToolCatalog from arcade_microsoft.outlook_calendar import get_event from evals.outlook_calendar.additional_messages import get_event_additional_messages diff --git a/toolkits/microsoft/evals/outlook_calendar/eval_list_events_in_time_range.py b/toolkits/microsoft/evals/outlook_calendar/eval_list_events_in_time_range.py index 0a02d03b..b6b9ba43 100644 --- a/toolkits/microsoft/evals/outlook_calendar/eval_list_events_in_time_range.py +++ b/toolkits/microsoft/evals/outlook_calendar/eval_list_events_in_time_range.py @@ -1,12 +1,12 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, + DatetimeCritic, EvalRubric, EvalSuite, ExpectedToolCall, tool_eval, ) -from arcade.sdk.eval.critic import DatetimeCritic +from arcade_tdk import ToolCatalog from arcade_microsoft.outlook_calendar import list_events_in_time_range diff --git a/toolkits/microsoft/evals/outlook_mail/eval_read.py b/toolkits/microsoft/evals/outlook_mail/eval_read.py index 4c5c284c..e8de7cfc 100644 --- a/toolkits/microsoft/evals/outlook_mail/eval_read.py +++ b/toolkits/microsoft/evals/outlook_mail/eval_read.py @@ -1,7 +1,6 @@ from datetime import timedelta -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, DatetimeCritic, EvalRubric, @@ -9,6 +8,7 @@ from arcade.sdk.eval import ( ExpectedToolCall, tool_eval, ) +from arcade_tdk import ToolCatalog from arcade_microsoft.outlook_mail import ( list_emails, diff --git a/toolkits/microsoft/evals/outlook_mail/eval_send.py b/toolkits/microsoft/evals/outlook_mail/eval_send.py index 9fc046c6..4f136f7a 100644 --- a/toolkits/microsoft/evals/outlook_mail/eval_send.py +++ b/toolkits/microsoft/evals/outlook_mail/eval_send.py @@ -1,12 +1,12 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, EvalRubric, EvalSuite, ExpectedToolCall, + SimilarityCritic, tool_eval, ) -from arcade.sdk.eval.critic import SimilarityCritic +from arcade_tdk import ToolCatalog from arcade_microsoft.outlook_mail import ( create_and_send_email, diff --git a/toolkits/microsoft/evals/outlook_mail/eval_write.py b/toolkits/microsoft/evals/outlook_mail/eval_write.py index 49209df4..b7cc7607 100644 --- a/toolkits/microsoft/evals/outlook_mail/eval_write.py +++ b/toolkits/microsoft/evals/outlook_mail/eval_write.py @@ -1,12 +1,12 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, EvalRubric, EvalSuite, ExpectedToolCall, + SimilarityCritic, tool_eval, ) -from arcade.sdk.eval.critic import SimilarityCritic +from arcade_tdk import ToolCatalog from arcade_microsoft.outlook_mail import create_draft_email, update_draft_email from evals.outlook_mail.additional_messages import ( diff --git a/toolkits/microsoft/pyproject.toml b/toolkits/microsoft/pyproject.toml index ce870794..105e465d 100644 --- a/toolkits/microsoft/pyproject.toml +++ b/toolkits/microsoft/pyproject.toml @@ -1,30 +1,43 @@ -[tool.poetry] +[build-system] +requires = [ "hatchling",] +build-backend = "hatchling.build" + +[project] name = "arcade_microsoft" version = "0.2.0" description = "Arcade.dev LLM tools for Outlook Mail" -authors = ["Arcade "] +requires-python = ">=3.10" +dependencies = [ + "arcade-tdk>=2.0.0,<3.0.0", + "msgraph-sdk>=1.28.0,<2.0.0", + "beautifulsoup4>=4.10.0,<5.0.0", + "pytz>=2024.2,<2025.0.0", +] +[[project.authors]] +name = "Arcade" +email = "dev@arcade.dev" -[tool.poetry.dependencies] -python = "^3.10" -arcade-ai = "^1.3.2" -msgraph-sdk = "^1.28.0" -beautifulsoup4 = "^4.10.0" -pytz = "^2024.2" +[project.optional-dependencies] +dev = [ + "arcade-ai[evals]>=2.0.0,<3.0.0", + "arcade-serve>=2.0.0,<3.0.0", + "pytest>=8.3.0,<8.4.0", + "pytest-cov>=4.0.0,<4.1.0", + "pytest-asyncio>=0.24.0,<0.25.0", + "mypy>=1.5.1,<1.6.0", + "pre-commit>=3.4.0,<3.5.0", + "tox>=4.11.1,<4.12.0", + "ruff>=0.7.4,<0.8.0", +] -[tool.poetry.dev-dependencies] -pytest = "^8.3.0" -pytest-cov = "^4.0.0" -mypy = "^1.5.1" -pre-commit = "^3.4.0" -tox = "^4.11.1" -ruff = "^0.7.4" - -[build-system] -requires = ["poetry-core>=1.0.0,<2.0.0"] -build-backend = "poetry.core.masonry.api" +# Use local path sources for arcade libs when working locally +[tool.uv.sources] +arcade-ai = {path = "../../", editable = true} +arcade-tdk = { path = "../../libs/arcade-tdk/", editable = true } +arcade-serve = { path = "../../libs/arcade-serve/", editable = true } [tool.mypy] -files = ["arcade_microsoft/**/*.py"] +files = [ "arcade_microsoft/**/*.py",] python_version = "3.10" disallow_untyped_defs = "True" disallow_any_unimported = "True" @@ -36,7 +49,10 @@ show_error_codes = "True" ignore_missing_imports = "True" [tool.pytest.ini_options] -testpaths = ["tests"] +testpaths = [ "tests",] [tool.coverage.report] skip_empty = true + +[tool.hatch.build.targets.wheel] +packages = [ "arcade_microsoft",] diff --git a/toolkits/microsoft/tests/outlook_calendar/test_utils.py b/toolkits/microsoft/tests/outlook_calendar/test_utils.py index d58276f5..8f1af403 100644 --- a/toolkits/microsoft/tests/outlook_calendar/test_utils.py +++ b/toolkits/microsoft/tests/outlook_calendar/test_utils.py @@ -1,5 +1,5 @@ import pytest -from arcade.core.errors import ToolExecutionError +from arcade_tdk.errors import ToolExecutionError from arcade_microsoft.outlook_calendar._utils import ( convert_timezone_to_offset, diff --git a/toolkits/notion/.pre-commit-config.yaml b/toolkits/notion/.pre-commit-config.yaml index 3953e996..e36ce46e 100644 --- a/toolkits/notion/.pre-commit-config.yaml +++ b/toolkits/notion/.pre-commit-config.yaml @@ -1,4 +1,4 @@ -files: ^./ +files: ^.*/notion/.* repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: "v4.4.0" diff --git a/toolkits/notion/Makefile b/toolkits/notion/Makefile index 73d9331d..7e2c686e 100644 --- a/toolkits/notion/Makefile +++ b/toolkits/notion/Makefile @@ -1,30 +1,27 @@ .PHONY: help help: - @echo "๐Ÿ› ๏ธ notion Commands:\n" + @echo "๐Ÿ› ๏ธ github Commands:\n" @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' .PHONY: install -install: ## Install the poetry environment and install the pre-commit hooks - @echo "๐Ÿ“ฆ Checking if Poetry is installed" - @if ! command -v poetry >/dev/null 2>&1; then \ - echo "๐Ÿ“ฆ Poetry not found. Checking if pip is available"; \ - if ! command -v pip >/dev/null 2>&1; then \ - echo "โŒ pip is not installed. Please install pip first."; \ - exit 1; \ - fi; \ - echo "๐Ÿ“ฆ Installing Poetry with pip"; \ - pip install poetry==1.8.5; \ - else \ - echo "๐Ÿ“ฆ Poetry is already installed"; \ - fi - @echo "๐Ÿš€ Installing package in development mode with all extras" - poetry install --all-extras +install: ## Install the uv environment and install all packages with dependencies + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras --no-sources + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" + +.PHONY: install-local +install-local: ## Install the uv environment and install all packages with dependencies with local Arcade sources + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" .PHONY: build build: clean-build ## Build wheel file using poetry @echo "๐Ÿš€ Creating wheel file" - poetry build + uv build .PHONY: clean-build clean-build: ## clean build artifacts @@ -34,7 +31,7 @@ clean-build: ## clean build artifacts .PHONY: test test: ## Test the code with pytest @echo "๐Ÿš€ Testing code: Running pytest" - @poetry run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml + @uv run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml .PHONY: coverage coverage: ## Generate coverage report @@ -44,15 +41,13 @@ coverage: ## Generate coverage report coverage html .PHONY: bump-version -bump-version: ## Bump the version in the pyproject.toml file +bump-version: ## Bump the version in the pyproject.toml file by a patch version @echo "๐Ÿš€ Bumping version in pyproject.toml" - poetry version patch + uv version --bump patch .PHONY: check check: ## Run code quality tools. - @echo "๐Ÿš€ Checking Poetry lock file consistency with 'pyproject.toml': Running poetry check" - @poetry check @echo "๐Ÿš€ Linting code: Running pre-commit" - @poetry run pre-commit run -a + @uv run pre-commit run -a @echo "๐Ÿš€ Static type checking: Running mypy" - @poetry run mypy --config-file=pyproject.toml + @uv run mypy --config-file=pyproject.toml diff --git a/toolkits/notion/arcade_notion_toolkit/block_to_markdown_converter.py b/toolkits/notion/arcade_notion_toolkit/block_to_markdown_converter.py index c566c727..51ec0731 100644 --- a/toolkits/notion/arcade_notion_toolkit/block_to_markdown_converter.py +++ b/toolkits/notion/arcade_notion_toolkit/block_to_markdown_converter.py @@ -1,7 +1,7 @@ import asyncio from typing import Any -from arcade.sdk import ToolContext +from arcade_tdk import ToolContext from arcade_notion_toolkit.enums import BlockType from arcade_notion_toolkit.utils import get_page_url diff --git a/toolkits/notion/arcade_notion_toolkit/tools/pages.py b/toolkits/notion/arcade_notion_toolkit/tools/pages.py index 1e1a54cc..beeed6ad 100644 --- a/toolkits/notion/arcade_notion_toolkit/tools/pages.py +++ b/toolkits/notion/arcade_notion_toolkit/tools/pages.py @@ -2,9 +2,9 @@ import asyncio from typing import Annotated, Any import httpx -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Notion -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Notion +from arcade_tdk.errors import ToolExecutionError from arcade_notion_toolkit.block_to_markdown_converter import BlockToMarkdownConverter from arcade_notion_toolkit.enums import BlockType, ObjectType diff --git a/toolkits/notion/arcade_notion_toolkit/tools/search.py b/toolkits/notion/arcade_notion_toolkit/tools/search.py index 8d74ae54..dc50fb36 100644 --- a/toolkits/notion/arcade_notion_toolkit/tools/search.py +++ b/toolkits/notion/arcade_notion_toolkit/tools/search.py @@ -1,9 +1,9 @@ from typing import Annotated, Any import httpx -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Notion -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Notion +from arcade_tdk.errors import ToolExecutionError from arcade_notion_toolkit.enums import ObjectType, SortDirection from arcade_notion_toolkit.utils import ( diff --git a/toolkits/notion/arcade_notion_toolkit/utils.py b/toolkits/notion/arcade_notion_toolkit/utils.py index da7eb007..004f9fe2 100644 --- a/toolkits/notion/arcade_notion_toolkit/utils.py +++ b/toolkits/notion/arcade_notion_toolkit/utils.py @@ -1,7 +1,7 @@ from typing import Any import httpx -from arcade.sdk import ToolContext +from arcade_tdk import ToolContext from arcade_notion_toolkit.constants import ENDPOINTS, NOTION_API_URL, UNTITLED_TITLE diff --git a/toolkits/notion/conftest.py b/toolkits/notion/conftest.py index fb7c1c32..91849416 100644 --- a/toolkits/notion/conftest.py +++ b/toolkits/notion/conftest.py @@ -1,5 +1,5 @@ import pytest -from arcade.sdk import ToolAuthorizationContext, ToolContext +from arcade_tdk import ToolAuthorizationContext, ToolContext @pytest.fixture diff --git a/toolkits/notion/evals/eval_notion_pages.py b/toolkits/notion/evals/eval_notion_pages.py index a5fb3477..2225a1d6 100644 --- a/toolkits/notion/evals/eval_notion_pages.py +++ b/toolkits/notion/evals/eval_notion_pages.py @@ -1,5 +1,4 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, EvalRubric, EvalSuite, @@ -7,6 +6,7 @@ from arcade.sdk.eval import ( SimilarityCritic, tool_eval, ) +from arcade_tdk import ToolCatalog import arcade_notion_toolkit from arcade_notion_toolkit.tools import ( diff --git a/toolkits/notion/evals/eval_notion_search.py b/toolkits/notion/evals/eval_notion_search.py index e93414cc..6aa202ad 100644 --- a/toolkits/notion/evals/eval_notion_search.py +++ b/toolkits/notion/evals/eval_notion_search.py @@ -1,5 +1,4 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, EvalRubric, EvalSuite, @@ -7,6 +6,7 @@ from arcade.sdk.eval import ( SimilarityCritic, tool_eval, ) +from arcade_tdk import ToolCatalog import arcade_notion_toolkit from arcade_notion_toolkit.enums import ObjectType diff --git a/toolkits/notion/pyproject.toml b/toolkits/notion/pyproject.toml index 793f678a..7c6be37e 100644 --- a/toolkits/notion/pyproject.toml +++ b/toolkits/notion/pyproject.toml @@ -1,28 +1,41 @@ -[tool.poetry] +[build-system] +requires = [ "hatchling",] +build-backend = "hatchling.build" + +[project] name = "arcade_notion_toolkit" version = "0.1.3" description = "Arcade.dev LLM tools for Notion" -authors = ["ArcadeAI "] +requires-python = ">=3.10" +dependencies = [ + "arcade-tdk>=2.0.0,<3.0.0", + "httpx>=0.27.2,<1.0.0", +] +[[project.authors]] +name = "Arcade" +email = "dev@arcade.dev" -[tool.poetry.dependencies] -python = "^3.10" -arcade-ai = "^1.1.2" +[project.optional-dependencies] +dev = [ + "arcade-ai[evals]>=2.0.0,<3.0.0", + "arcade-serve>=2.0.0,<3.0.0", + "pytest>=8.3.0,<8.4.0", + "pytest-cov>=4.0.0,<4.1.0", + "pytest-asyncio>=0.24.0,<0.25.0", + "mypy>=1.5.1,<1.6.0", + "pre-commit>=3.4.0,<3.5.0", + "tox>=4.11.1,<4.12.0", + "ruff>=0.7.4,<0.8.0", +] -[tool.poetry.dev-dependencies] -pytest = "^8.3.0" -pytest-cov = "^4.0.0" -pytest-asyncio = "^0.24.0" -mypy = "^1.5.1" -pre-commit = "^3.4.0" -tox = "^4.11.1" -ruff = "^0.7.4" - -[build-system] -requires = ["poetry-core>=1.0.0,<2.0.0"] -build-backend = "poetry.core.masonry.api" +# Use local path sources for arcade libs when working locally +[tool.uv.sources] +arcade-ai = {path = "../../", editable = true} +arcade-tdk = { path = "../../libs/arcade-tdk/", editable = true } +arcade-serve = { path = "../../libs/arcade-serve/", editable = true } [tool.mypy] -files = ["arcade_notion_toolkit/**/*.py"] +files = [ "arcade_notion_toolkit/**/*.py",] python_version = "3.10" disallow_untyped_defs = "True" disallow_any_unimported = "True" @@ -34,7 +47,10 @@ show_error_codes = "True" ignore_missing_imports = "True" [tool.pytest.ini_options] -testpaths = ["tests"] +testpaths = [ "tests",] [tool.coverage.report] skip_empty = true + +[tool.hatch.build.targets.wheel] +packages = [ "arcade_notion_toolkit",] diff --git a/toolkits/reddit/.pre-commit-config.yaml b/toolkits/reddit/.pre-commit-config.yaml index 3953e996..3870ea15 100644 --- a/toolkits/reddit/.pre-commit-config.yaml +++ b/toolkits/reddit/.pre-commit-config.yaml @@ -1,4 +1,4 @@ -files: ^./ +files: ^.*/reddit/.* repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: "v4.4.0" diff --git a/toolkits/reddit/Makefile b/toolkits/reddit/Makefile index a94486d3..7e2c686e 100644 --- a/toolkits/reddit/Makefile +++ b/toolkits/reddit/Makefile @@ -1,30 +1,27 @@ .PHONY: help help: - @echo "๐Ÿ› ๏ธ reddit Commands:\n" + @echo "๐Ÿ› ๏ธ github Commands:\n" @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' .PHONY: install -install: ## Install the poetry environment and install the pre-commit hooks - @echo "๐Ÿ“ฆ Checking if Poetry is installed" - @if ! command -v poetry >/dev/null 2>&1; then \ - echo "๐Ÿ“ฆ Poetry not found. Checking if pip is available"; \ - if ! command -v pip >/dev/null 2>&1; then \ - echo "โŒ pip is not installed. Please install pip first."; \ - exit 1; \ - fi; \ - echo "๐Ÿ“ฆ Installing Poetry with pip"; \ - pip install poetry==1.8.5; \ - else \ - echo "๐Ÿ“ฆ Poetry is already installed"; \ - fi - @echo "๐Ÿš€ Installing package in development mode with all extras" - poetry install --all-extras +install: ## Install the uv environment and install all packages with dependencies + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras --no-sources + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" + +.PHONY: install-local +install-local: ## Install the uv environment and install all packages with dependencies with local Arcade sources + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" .PHONY: build build: clean-build ## Build wheel file using poetry @echo "๐Ÿš€ Creating wheel file" - poetry build + uv build .PHONY: clean-build clean-build: ## clean build artifacts @@ -34,7 +31,7 @@ clean-build: ## clean build artifacts .PHONY: test test: ## Test the code with pytest @echo "๐Ÿš€ Testing code: Running pytest" - @poetry run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml + @uv run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml .PHONY: coverage coverage: ## Generate coverage report @@ -44,15 +41,13 @@ coverage: ## Generate coverage report coverage html .PHONY: bump-version -bump-version: ## Bump the version in the pyproject.toml file +bump-version: ## Bump the version in the pyproject.toml file by a patch version @echo "๐Ÿš€ Bumping version in pyproject.toml" - poetry version patch + uv version --bump patch .PHONY: check check: ## Run code quality tools. - @echo "๐Ÿš€ Checking Poetry lock file consistency with 'pyproject.toml': Running poetry check" - @poetry check @echo "๐Ÿš€ Linting code: Running pre-commit" - @poetry run pre-commit run -a + @uv run pre-commit run -a @echo "๐Ÿš€ Static type checking: Running mypy" - @poetry run mypy --config-file=pyproject.toml + @uv run mypy --config-file=pyproject.toml diff --git a/toolkits/reddit/arcade_reddit/tools/read.py b/toolkits/reddit/arcade_reddit/tools/read.py index 4d0f384b..e4bb16b3 100644 --- a/toolkits/reddit/arcade_reddit/tools/read.py +++ b/toolkits/reddit/arcade_reddit/tools/read.py @@ -1,8 +1,8 @@ from typing import Annotated -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Reddit -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Reddit +from arcade_tdk.errors import ToolExecutionError from arcade_reddit.client import RedditClient from arcade_reddit.enums import ( diff --git a/toolkits/reddit/arcade_reddit/tools/submit.py b/toolkits/reddit/arcade_reddit/tools/submit.py index ccebd3a3..998d2105 100644 --- a/toolkits/reddit/arcade_reddit/tools/submit.py +++ b/toolkits/reddit/arcade_reddit/tools/submit.py @@ -1,7 +1,7 @@ from typing import Annotated -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Reddit +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Reddit from arcade_reddit.client import RedditClient from arcade_reddit.utils import ( diff --git a/toolkits/reddit/arcade_reddit/utils.py b/toolkits/reddit/arcade_reddit/utils.py index f006a2a1..ad7c5f99 100644 --- a/toolkits/reddit/arcade_reddit/utils.py +++ b/toolkits/reddit/arcade_reddit/utils.py @@ -2,8 +2,8 @@ import re from urllib.parse import urlparse import httpx -from arcade.sdk import ToolContext -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk import ToolContext +from arcade_tdk.errors import ToolExecutionError from arcade_reddit.client import RedditClient from arcade_reddit.enums import RedditThingType diff --git a/toolkits/reddit/evals/critics.py b/toolkits/reddit/evals/critics.py index 67adf1c4..b398cea7 100644 --- a/toolkits/reddit/evals/critics.py +++ b/toolkits/reddit/evals/critics.py @@ -1,7 +1,7 @@ from dataclasses import dataclass from typing import Any -from arcade.sdk.eval.critic import Critic +from arcade_evals.critic import Critic @dataclass diff --git a/toolkits/reddit/evals/eval_reddit_read.py b/toolkits/reddit/evals/eval_reddit_read.py index ae16a0b9..7e49fc83 100644 --- a/toolkits/reddit/evals/eval_reddit_read.py +++ b/toolkits/reddit/evals/eval_reddit_read.py @@ -1,11 +1,11 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( + BinaryCritic, EvalRubric, EvalSuite, ExpectedToolCall, tool_eval, ) -from arcade.sdk.eval.critic import BinaryCritic +from arcade_tdk import ToolCatalog import arcade_reddit from arcade_reddit.enums import RedditTimeFilter, SubredditListingType diff --git a/toolkits/reddit/evals/eval_reddit_submit.py b/toolkits/reddit/evals/eval_reddit_submit.py index e0ced288..3633cfae 100644 --- a/toolkits/reddit/evals/eval_reddit_submit.py +++ b/toolkits/reddit/evals/eval_reddit_submit.py @@ -1,11 +1,12 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( + BinaryCritic, EvalRubric, EvalSuite, ExpectedToolCall, + SimilarityCritic, tool_eval, ) -from arcade.sdk.eval.critic import BinaryCritic, SimilarityCritic +from arcade_tdk import ToolCatalog import arcade_reddit from arcade_reddit.tools import ( diff --git a/toolkits/reddit/pyproject.toml b/toolkits/reddit/pyproject.toml index 785ad1a7..02679cf2 100644 --- a/toolkits/reddit/pyproject.toml +++ b/toolkits/reddit/pyproject.toml @@ -1,29 +1,38 @@ -[tool.poetry] +[build-system] +requires = [ "hatchling",] +build-backend = "hatchling.build" + +[project] name = "arcade_reddit" version = "0.1.0" description = "Arcade.dev LLM tools Reddit" -authors = ["Arcade "] +requires-python = ">=3.10" +dependencies = [ "arcade-tdk>=2.0.0,<3.0.0", "httpx>=0.27.2,<1.0.0",] +[[project.authors]] +name = "Arcade" +email = "dev@arcade.dev" -[tool.poetry.dependencies] -python = "^3.10" -arcade-ai = "^1.0.5" -httpx = "^0.27.2" +[project.optional-dependencies] +dev = [ + "arcade-ai[evals]>=2.0.0,<3.0.0", + "arcade-serve>=2.0.0,<3.0.0", + "pytest>=8.3.0,<8.4.0", + "pytest-cov>=4.0.0,<4.1.0", + "pytest-asyncio>=0.24.0,<0.25.0", + "mypy>=1.5.1,<1.6.0", + "pre-commit>=3.4.0,<3.5.0", + "tox>=4.11.1,<4.12.0", + "ruff>=0.7.4,<0.8.0", +] -[tool.poetry.dev-dependencies] -pytest = "^8.3.0" -pytest-cov = "^4.0.0" -pytest-asyncio = "^0.24.0" -mypy = "^1.5.1" -pre-commit = "^3.4.0" -tox = "^4.11.1" -ruff = "^0.7.4" - -[build-system] -requires = ["poetry-core>=1.0.0,<2.0.0"] -build-backend = "poetry.core.masonry.api" +# Use local path sources for arcade libs when working locally +[tool.uv.sources] +arcade-ai = {path = "../../", editable = true} +arcade-tdk = { path = "../../libs/arcade-tdk/", editable = true } +arcade-serve = { path = "../../libs/arcade-serve/", editable = true } [tool.mypy] -files = ["arcade_reddit/**/*.py"] +files = [ "arcade_reddit/**/*.py",] python_version = "3.10" disallow_untyped_defs = "True" disallow_any_unimported = "True" @@ -35,7 +44,10 @@ show_error_codes = "True" ignore_missing_imports = "True" [tool.pytest.ini_options] -testpaths = ["tests"] +testpaths = [ "tests",] [tool.coverage.report] skip_empty = true + +[tool.hatch.build.targets.wheel] +packages = [ "arcade_reddit",] diff --git a/toolkits/reddit/tests/test_utils.py b/toolkits/reddit/tests/test_utils.py index 20d8ce71..f6736951 100644 --- a/toolkits/reddit/tests/test_utils.py +++ b/toolkits/reddit/tests/test_utils.py @@ -1,6 +1,6 @@ import httpx import pytest -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk.errors import ToolExecutionError from arcade_reddit.client import RedditClient from arcade_reddit.utils import ( diff --git a/toolkits/salesforce/.pre-commit-config.yaml b/toolkits/salesforce/.pre-commit-config.yaml index 3953e996..a5a99967 100644 --- a/toolkits/salesforce/.pre-commit-config.yaml +++ b/toolkits/salesforce/.pre-commit-config.yaml @@ -1,4 +1,4 @@ -files: ^./ +files: ^.*/salesforce/.* repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: "v4.4.0" diff --git a/toolkits/salesforce/Makefile b/toolkits/salesforce/Makefile index 5abc0e90..7e2c686e 100644 --- a/toolkits/salesforce/Makefile +++ b/toolkits/salesforce/Makefile @@ -1,30 +1,27 @@ .PHONY: help help: - @echo "๐Ÿ› ๏ธ dropbox Commands:\n" + @echo "๐Ÿ› ๏ธ github Commands:\n" @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' .PHONY: install -install: ## Install the poetry environment and install the pre-commit hooks - @echo "๐Ÿ“ฆ Checking if Poetry is installed" - @if ! command -v poetry >/dev/null 2>&1; then \ - echo "๐Ÿ“ฆ Poetry not found. Checking if pip is available"; \ - if ! command -v pip >/dev/null 2>&1; then \ - echo "โŒ pip is not installed. Please install pip first."; \ - exit 1; \ - fi; \ - echo "๐Ÿ“ฆ Installing Poetry with pip"; \ - pip install poetry==1.8.5; \ - else \ - echo "๐Ÿ“ฆ Poetry is already installed"; \ - fi - @echo "๐Ÿš€ Installing package in development mode with all extras" - poetry install --all-extras +install: ## Install the uv environment and install all packages with dependencies + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras --no-sources + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" + +.PHONY: install-local +install-local: ## Install the uv environment and install all packages with dependencies with local Arcade sources + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" .PHONY: build build: clean-build ## Build wheel file using poetry @echo "๐Ÿš€ Creating wheel file" - poetry build + uv build .PHONY: clean-build clean-build: ## clean build artifacts @@ -34,7 +31,7 @@ clean-build: ## clean build artifacts .PHONY: test test: ## Test the code with pytest @echo "๐Ÿš€ Testing code: Running pytest" - @poetry run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml + @uv run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml .PHONY: coverage coverage: ## Generate coverage report @@ -44,15 +41,13 @@ coverage: ## Generate coverage report coverage html .PHONY: bump-version -bump-version: ## Bump the version in the pyproject.toml file +bump-version: ## Bump the version in the pyproject.toml file by a patch version @echo "๐Ÿš€ Bumping version in pyproject.toml" - poetry version patch + uv version --bump patch .PHONY: check check: ## Run code quality tools. - @echo "๐Ÿš€ Checking Poetry lock file consistency with 'pyproject.toml': Running poetry check" - @poetry check @echo "๐Ÿš€ Linting code: Running pre-commit" - @poetry run pre-commit run -a + @uv run pre-commit run -a @echo "๐Ÿš€ Static type checking: Running mypy" - @poetry run mypy --config-file=pyproject.toml + @uv run mypy --config-file=pyproject.toml diff --git a/toolkits/salesforce/arcade_salesforce/exceptions.py b/toolkits/salesforce/arcade_salesforce/exceptions.py index fb7a1f45..ffb3f5d0 100644 --- a/toolkits/salesforce/arcade_salesforce/exceptions.py +++ b/toolkits/salesforce/arcade_salesforce/exceptions.py @@ -1,4 +1,4 @@ -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk.errors import ToolExecutionError class SalesforceToolExecutionError(ToolExecutionError): diff --git a/toolkits/salesforce/arcade_salesforce/tools/crm/account.py b/toolkits/salesforce/arcade_salesforce/tools/crm/account.py index bb05009b..3bbbefa7 100644 --- a/toolkits/salesforce/arcade_salesforce/tools/crm/account.py +++ b/toolkits/salesforce/arcade_salesforce/tools/crm/account.py @@ -1,9 +1,9 @@ import asyncio from typing import Annotated -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import OAuth2 -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import OAuth2 +from arcade_tdk.errors import ToolExecutionError from arcade_salesforce.enums import SalesforceObject from arcade_salesforce.models import SalesforceClient diff --git a/toolkits/salesforce/arcade_salesforce/tools/crm/contact.py b/toolkits/salesforce/arcade_salesforce/tools/crm/contact.py index 27547cae..ca4f4abb 100644 --- a/toolkits/salesforce/arcade_salesforce/tools/crm/contact.py +++ b/toolkits/salesforce/arcade_salesforce/tools/crm/contact.py @@ -1,8 +1,8 @@ from typing import Annotated -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import OAuth2 -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import OAuth2 +from arcade_tdk.errors import ToolExecutionError from arcade_salesforce.exceptions import SalesforceToolExecutionError from arcade_salesforce.models import SalesforceClient diff --git a/toolkits/salesforce/conftest.py b/toolkits/salesforce/conftest.py index d3dc1f8f..39be1063 100644 --- a/toolkits/salesforce/conftest.py +++ b/toolkits/salesforce/conftest.py @@ -1,7 +1,7 @@ from unittest.mock import patch import pytest -from arcade.sdk import ToolAuthorizationContext, ToolContext +from arcade_tdk import ToolAuthorizationContext, ToolContext @pytest.fixture diff --git a/toolkits/salesforce/evals/eval_create_contact.py b/toolkits/salesforce/evals/eval_create_contact.py index 93c72253..80989c31 100644 --- a/toolkits/salesforce/evals/eval_create_contact.py +++ b/toolkits/salesforce/evals/eval_create_contact.py @@ -1,11 +1,11 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( + BinaryCritic, EvalRubric, EvalSuite, ExpectedToolCall, tool_eval, ) -from arcade.sdk.eval.critic import BinaryCritic +from arcade_tdk import ToolCatalog import arcade_salesforce from arcade_salesforce.tools import create_contact diff --git a/toolkits/salesforce/evals/eval_get_account_data.py b/toolkits/salesforce/evals/eval_get_account_data.py index 0fbe4b8c..24fae04a 100644 --- a/toolkits/salesforce/evals/eval_get_account_data.py +++ b/toolkits/salesforce/evals/eval_get_account_data.py @@ -1,11 +1,11 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( + BinaryCritic, EvalRubric, EvalSuite, ExpectedToolCall, tool_eval, ) -from arcade.sdk.eval.critic import BinaryCritic +from arcade_tdk import ToolCatalog import arcade_salesforce from arcade_salesforce.tools import get_account_data_by_id, get_account_data_by_keywords diff --git a/toolkits/salesforce/pyproject.toml b/toolkits/salesforce/pyproject.toml index 27eb7175..ce051d4a 100644 --- a/toolkits/salesforce/pyproject.toml +++ b/toolkits/salesforce/pyproject.toml @@ -1,30 +1,39 @@ -[tool.poetry] +[build-system] +requires = [ "hatchling",] +build-backend = "hatchling.build" + +[project] name = "arcade_salesforce" version = "0.1.0" description = "Arcade tools designed for LLMs to interact with Salesforce" -authors = ["Arcade "] +requires-python = ">=3.10" +dependencies = [ "arcade-tdk>=2.0.0,<3.0.0", "httpx>=0.27.2,<1.0.0",] +[[project.authors]] +name = "Arcade" +email = "dev@arcade.dev" -[tool.poetry.dependencies] -python = "^3.10" -arcade-ai = ">=1.0.5,<2.0" -httpx = "^0.27.2" +[project.optional-dependencies] +dev = [ + "arcade-ai[evals]>=2.0.0,<3.0.0", + "arcade-serve>=2.0.0,<3.0.0", + "pytest>=8.3.0,<8.4.0", + "pytest-cov>=4.0.0,<4.1.0", + "pytest-asyncio>=0.24.0,<0.25.0", + "pytest-mock>=3.11.1,<3.12.0", + "mypy>=1.5.1,<1.6.0", + "pre-commit>=3.4.0,<3.5.0", + "tox>=4.11.1,<4.12.0", + "ruff>=0.7.4,<0.8.0", +] -[tool.poetry.dev-dependencies] -pytest = "^8.3.0" -pytest-cov = "^4.0.0" -pytest-asyncio = "^0.24.0" -pytest-mock = "^3.11.1" -mypy = "^1.5.1" -pre-commit = "^3.4.0" -tox = "^4.11.1" -ruff = "^0.7.4" - -[build-system] -requires = ["poetry-core>=1.0.0,<2.0.0"] -build-backend = "poetry.core.masonry.api" +# Use local path sources for arcade libs when working locally +[tool.uv.sources] +arcade-ai = {path = "../../", editable = true} +arcade-tdk = { path = "../../libs/arcade-tdk/", editable = true } +arcade-serve = { path = "../../libs/arcade-serve/", editable = true } [tool.mypy] -files = ["arcade_salesforce/**/*.py"] +files = [ "arcade_salesforce/**/*.py",] python_version = "3.10" disallow_untyped_defs = "True" disallow_any_unimported = "True" @@ -36,7 +45,10 @@ show_error_codes = "True" ignore_missing_imports = "True" [tool.pytest.ini_options] -testpaths = ["tests"] +testpaths = [ "tests",] [tool.coverage.report] skip_empty = true + +[tool.hatch.build.targets.wheel] +packages = [ "arcade_salesforce",] diff --git a/toolkits/search/.pre-commit-config.yaml b/toolkits/search/.pre-commit-config.yaml index 3953e996..2a7af098 100644 --- a/toolkits/search/.pre-commit-config.yaml +++ b/toolkits/search/.pre-commit-config.yaml @@ -1,4 +1,4 @@ -files: ^./ +files: ^.*/search/.* repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: "v4.4.0" diff --git a/toolkits/search/Makefile b/toolkits/search/Makefile index 024c8962..7e2c686e 100644 --- a/toolkits/search/Makefile +++ b/toolkits/search/Makefile @@ -1,30 +1,27 @@ .PHONY: help help: - @echo "๐Ÿ› ๏ธ search Commands:\n" + @echo "๐Ÿ› ๏ธ github Commands:\n" @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' .PHONY: install -install: ## Install the poetry environment and install the pre-commit hooks - @echo "๐Ÿ“ฆ Checking if Poetry is installed" - @if ! command -v poetry >/dev/null 2>&1; then \ - echo "๐Ÿ“ฆ Poetry not found. Checking if pip is available"; \ - if ! command -v pip >/dev/null 2>&1; then \ - echo "โŒ pip is not installed. Please install pip first."; \ - exit 1; \ - fi; \ - echo "๐Ÿ“ฆ Installing Poetry with pip"; \ - pip install poetry==1.8.5; \ - else \ - echo "๐Ÿ“ฆ Poetry is already installed"; \ - fi - @echo "๐Ÿš€ Installing package in development mode with all extras" - poetry install --all-extras +install: ## Install the uv environment and install all packages with dependencies + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras --no-sources + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" + +.PHONY: install-local +install-local: ## Install the uv environment and install all packages with dependencies with local Arcade sources + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" .PHONY: build build: clean-build ## Build wheel file using poetry @echo "๐Ÿš€ Creating wheel file" - poetry build + uv build .PHONY: clean-build clean-build: ## clean build artifacts @@ -34,7 +31,7 @@ clean-build: ## clean build artifacts .PHONY: test test: ## Test the code with pytest @echo "๐Ÿš€ Testing code: Running pytest" - @poetry run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml + @uv run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml .PHONY: coverage coverage: ## Generate coverage report @@ -44,15 +41,13 @@ coverage: ## Generate coverage report coverage html .PHONY: bump-version -bump-version: ## Bump the version in the pyproject.toml file +bump-version: ## Bump the version in the pyproject.toml file by a patch version @echo "๐Ÿš€ Bumping version in pyproject.toml" - poetry version patch + uv version --bump patch .PHONY: check check: ## Run code quality tools. - @echo "๐Ÿš€ Checking Poetry lock file consistency with 'pyproject.toml': Running poetry check" - @poetry check @echo "๐Ÿš€ Linting code: Running pre-commit" - @poetry run pre-commit run -a + @uv run pre-commit run -a @echo "๐Ÿš€ Static type checking: Running mypy" - @poetry run mypy --config-file=pyproject.toml + @uv run mypy --config-file=pyproject.toml diff --git a/toolkits/search/arcade_search/exceptions.py b/toolkits/search/arcade_search/exceptions.py index 0a186753..7b1526a9 100644 --- a/toolkits/search/arcade_search/exceptions.py +++ b/toolkits/search/arcade_search/exceptions.py @@ -1,6 +1,6 @@ import json -from arcade.sdk.errors import RetryableToolError +from arcade_tdk.errors import RetryableToolError from arcade_search.google_data import COUNTRY_CODES, LANGUAGE_CODES diff --git a/toolkits/search/arcade_search/tools/google_finance.py b/toolkits/search/arcade_search/tools/google_finance.py index f2576fcf..e5538b5a 100644 --- a/toolkits/search/arcade_search/tools/google_finance.py +++ b/toolkits/search/arcade_search/tools/google_finance.py @@ -1,6 +1,6 @@ from typing import Annotated, Any -from arcade.sdk import ToolContext, tool +from arcade_tdk import ToolContext, tool from arcade_search.enums import GoogleFinanceWindow from arcade_search.utils import call_serpapi, prepare_params diff --git a/toolkits/search/arcade_search/tools/google_flights.py b/toolkits/search/arcade_search/tools/google_flights.py index bdf1cd09..a0c5000e 100644 --- a/toolkits/search/arcade_search/tools/google_flights.py +++ b/toolkits/search/arcade_search/tools/google_flights.py @@ -1,6 +1,6 @@ from typing import Annotated, Any -from arcade.sdk import ToolContext, tool +from arcade_tdk import ToolContext, tool from arcade_search.enums import GoogleFlightsMaxStops, GoogleFlightsSortBy, GoogleFlightsTravelClass from arcade_search.utils import call_serpapi, parse_flight_results, prepare_params diff --git a/toolkits/search/arcade_search/tools/google_hotels.py b/toolkits/search/arcade_search/tools/google_hotels.py index 21f7e3bf..904baa3a 100644 --- a/toolkits/search/arcade_search/tools/google_hotels.py +++ b/toolkits/search/arcade_search/tools/google_hotels.py @@ -1,6 +1,6 @@ from typing import Annotated, Any -from arcade.sdk import ToolContext, tool +from arcade_tdk import ToolContext, tool from arcade_search.enums import GoogleHotelsSortBy from arcade_search.utils import call_serpapi, prepare_params diff --git a/toolkits/search/arcade_search/tools/google_jobs.py b/toolkits/search/arcade_search/tools/google_jobs.py index 2eaa677f..0076664e 100644 --- a/toolkits/search/arcade_search/tools/google_jobs.py +++ b/toolkits/search/arcade_search/tools/google_jobs.py @@ -1,6 +1,6 @@ from typing import Annotated -from arcade.sdk import ToolContext, tool +from arcade_tdk import ToolContext, tool from arcade_search.constants import DEFAULT_GOOGLE_JOBS_LANGUAGE from arcade_search.exceptions import LanguageNotFoundError diff --git a/toolkits/search/arcade_search/tools/google_maps.py b/toolkits/search/arcade_search/tools/google_maps.py index cf93cd3a..a45ca539 100644 --- a/toolkits/search/arcade_search/tools/google_maps.py +++ b/toolkits/search/arcade_search/tools/google_maps.py @@ -1,6 +1,6 @@ from typing import Annotated -from arcade.sdk import ToolContext, tool +from arcade_tdk import ToolContext, tool from arcade_search.constants import ( DEFAULT_GOOGLE_MAPS_COUNTRY, diff --git a/toolkits/search/arcade_search/tools/google_news.py b/toolkits/search/arcade_search/tools/google_news.py index 58815f69..012ee31d 100644 --- a/toolkits/search/arcade_search/tools/google_news.py +++ b/toolkits/search/arcade_search/tools/google_news.py @@ -1,7 +1,7 @@ from typing import Annotated, Any -from arcade.sdk import ToolContext, tool -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk import ToolContext, tool +from arcade_tdk.errors import ToolExecutionError from arcade_search.constants import DEFAULT_GOOGLE_NEWS_COUNTRY, DEFAULT_GOOGLE_NEWS_LANGUAGE from arcade_search.exceptions import CountryNotFoundError, LanguageNotFoundError diff --git a/toolkits/search/arcade_search/tools/google_search.py b/toolkits/search/arcade_search/tools/google_search.py index 395355cb..dc7faf3e 100644 --- a/toolkits/search/arcade_search/tools/google_search.py +++ b/toolkits/search/arcade_search/tools/google_search.py @@ -1,7 +1,7 @@ import json from typing import Annotated -from arcade.sdk import ToolContext, tool +from arcade_tdk import ToolContext, tool from arcade_search.utils import call_serpapi, prepare_params diff --git a/toolkits/search/arcade_search/tools/google_shopping.py b/toolkits/search/arcade_search/tools/google_shopping.py index 4d50a1f1..222c0830 100644 --- a/toolkits/search/arcade_search/tools/google_shopping.py +++ b/toolkits/search/arcade_search/tools/google_shopping.py @@ -1,7 +1,7 @@ from typing import Annotated, Any -from arcade.sdk import ToolContext, tool -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk import ToolContext, tool +from arcade_tdk.errors import ToolExecutionError from arcade_search.constants import ( DEFAULT_GOOGLE_SHOPPING_COUNTRY, diff --git a/toolkits/search/arcade_search/tools/walmart.py b/toolkits/search/arcade_search/tools/walmart.py index 68a7a06b..707df6e4 100644 --- a/toolkits/search/arcade_search/tools/walmart.py +++ b/toolkits/search/arcade_search/tools/walmart.py @@ -1,8 +1,8 @@ from typing import Annotated, Any -from arcade.sdk import ToolContext -from arcade.sdk.errors import ToolExecutionError -from arcade.sdk.tool import tool +from arcade_tdk import ToolContext +from arcade_tdk.errors import ToolExecutionError +from arcade_tdk.tool import tool from arcade_search.enums import WalmartSortBy from arcade_search.utils import ( diff --git a/toolkits/search/arcade_search/tools/youtube.py b/toolkits/search/arcade_search/tools/youtube.py index 4b75c362..9144b47b 100644 --- a/toolkits/search/arcade_search/tools/youtube.py +++ b/toolkits/search/arcade_search/tools/youtube.py @@ -1,7 +1,7 @@ from typing import Annotated, Any, cast -from arcade.sdk import ToolContext, tool -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk import ToolContext, tool +from arcade_tdk.errors import ToolExecutionError from arcade_search.constants import DEFAULT_YOUTUBE_SEARCH_COUNTRY, DEFAULT_YOUTUBE_SEARCH_LANGUAGE from arcade_search.utils import ( diff --git a/toolkits/search/arcade_search/utils.py b/toolkits/search/arcade_search/utils.py index ca62c26b..92b474bc 100644 --- a/toolkits/search/arcade_search/utils.py +++ b/toolkits/search/arcade_search/utils.py @@ -5,8 +5,8 @@ from typing import Any, cast from urllib.parse import parse_qs, urlparse from zoneinfo import ZoneInfo -from arcade.sdk import ToolContext -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk import ToolContext +from arcade_tdk.errors import ToolExecutionError from serpapi import Client as SerpClient from arcade_search.constants import ( diff --git a/toolkits/search/evals/eval_google_jobs.py b/toolkits/search/evals/eval_google_jobs.py index 16be3864..2be23fca 100644 --- a/toolkits/search/evals/eval_google_jobs.py +++ b/toolkits/search/evals/eval_google_jobs.py @@ -1,5 +1,4 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, EvalRubric, EvalSuite, @@ -8,6 +7,7 @@ from arcade.sdk.eval import ( SimilarityCritic, tool_eval, ) +from arcade_tdk import ToolCatalog import arcade_search from arcade_search.constants import DEFAULT_GOOGLE_JOBS_LANGUAGE diff --git a/toolkits/search/evals/eval_google_maps_directions.py b/toolkits/search/evals/eval_google_maps_directions.py index 04a7ebe2..c36db5ed 100644 --- a/toolkits/search/evals/eval_google_maps_directions.py +++ b/toolkits/search/evals/eval_google_maps_directions.py @@ -1,5 +1,4 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, EvalRubric, EvalSuite, @@ -7,6 +6,7 @@ from arcade.sdk.eval import ( SimilarityCritic, tool_eval, ) +from arcade_tdk import ToolCatalog import arcade_search from arcade_search.constants import ( diff --git a/toolkits/search/evals/eval_google_search.py b/toolkits/search/evals/eval_google_search.py index 2ccc3750..062d04da 100644 --- a/toolkits/search/evals/eval_google_search.py +++ b/toolkits/search/evals/eval_google_search.py @@ -1,5 +1,4 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( EvalRubric, EvalSuite, ExpectedToolCall, @@ -7,6 +6,7 @@ from arcade.sdk.eval import ( SimilarityCritic, tool_eval, ) +from arcade_tdk import ToolCatalog import arcade_search from arcade_search.tools import search_google diff --git a/toolkits/search/pyproject.toml b/toolkits/search/pyproject.toml index 0fd7ba64..a3e9ab21 100644 --- a/toolkits/search/pyproject.toml +++ b/toolkits/search/pyproject.toml @@ -1,30 +1,39 @@ -[tool.poetry] +[build-system] +requires = [ "hatchling",] +build-backend = "hatchling.build" + +[project] name = "arcade_search" version = "1.4.0" description = "Arcade.dev LLM tools for searching the web" -authors = ["Arcade "] +requires-python = ">=3.10" +dependencies = [ "arcade-tdk>=2.0.0,<3.0.0", "serpapi>=0.1.5,<1.0.0",] +[[project.authors]] +name = "Arcade" +email = "dev@arcade.dev" -[tool.poetry.dependencies] -python = "^3.10" -arcade-ai = ">=1.0.5,<2.0" -serpapi = "^0.1.5" +[project.optional-dependencies] +dev = [ + "arcade-ai[evals]>=2.0.0,<3.0.0", + "arcade-serve>=2.0.0,<3.0.0", + "pytest>=8.3.0,<8.4.0", + "pytest-cov>=4.0.0,<4.1.0", + "pytest-asyncio>=0.24.0,<0.25.0", + "pytest-mock>=3.11.1,<3.12.0", + "mypy>=1.5.1,<1.6.0", + "pre-commit>=3.4.0,<3.5.0", + "tox>=4.11.1,<4.12.0", + "ruff>=0.7.4,<0.8.0", +] -[tool.poetry.dev-dependencies] -pytest = "^8.3.0" -pytest-cov = "^4.0.0" -pytest-asyncio = "^0.24.0" -pytest-mock = "^3.11.1" -mypy = "^1.5.1" -pre-commit = "^3.4.0" -tox = "^4.11.1" -ruff = "^0.7.4" - -[build-system] -requires = ["poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" +# Use local path sources for arcade libs when working locally +[tool.uv.sources] +arcade-ai = {path = "../../", editable = true} +arcade-tdk = { path = "../../libs/arcade-tdk/", editable = true } +arcade-serve = { path = "../../libs/arcade-serve/", editable = true } [tool.mypy] -files = ["arcade_search/**/*.py"] +files = [ "arcade_search/**/*.py",] python_version = "3.10" disallow_untyped_defs = "True" disallow_any_unimported = "True" @@ -36,7 +45,10 @@ show_error_codes = "True" ignore_missing_imports = "True" [tool.pytest.ini_options] -testpaths = ["tests"] +testpaths = [ "tests",] [tool.coverage.report] skip_empty = true + +[tool.hatch.build.targets.wheel] +packages = [ "arcade_search",] diff --git a/toolkits/search/tests/test_google_jobs.py b/toolkits/search/tests/test_google_jobs.py index f8ef9333..e75443df 100644 --- a/toolkits/search/tests/test_google_jobs.py +++ b/toolkits/search/tests/test_google_jobs.py @@ -1,8 +1,7 @@ from unittest.mock import patch import pytest -from arcade.core.schema import ToolSecretItem -from arcade.sdk import ToolContext +from arcade_tdk import ToolContext, ToolSecretItem from arcade_search.exceptions import LanguageNotFoundError from arcade_search.tools.google_jobs import search_jobs diff --git a/toolkits/search/tests/test_google_maps_directions.py b/toolkits/search/tests/test_google_maps_directions.py index 72cf7fb0..8a900304 100644 --- a/toolkits/search/tests/test_google_maps_directions.py +++ b/toolkits/search/tests/test_google_maps_directions.py @@ -1,8 +1,7 @@ from unittest.mock import patch import pytest -from arcade.core.schema import ToolSecretItem -from arcade.sdk import ToolContext +from arcade_tdk import ToolContext, ToolSecretItem from arcade_search.exceptions import CountryNotFoundError, LanguageNotFoundError from arcade_search.tools.google_maps import ( diff --git a/toolkits/search/tests/test_google_search.py b/toolkits/search/tests/test_google_search.py index fe470fd6..21b4832a 100644 --- a/toolkits/search/tests/test_google_search.py +++ b/toolkits/search/tests/test_google_search.py @@ -2,8 +2,7 @@ import json from unittest.mock import patch import pytest -from arcade.core.schema import ToolSecretItem -from arcade.sdk import ToolContext +from arcade_tdk import ToolContext, ToolSecretItem from arcade_search.tools import search_google diff --git a/toolkits/search/tests/test_utils.py b/toolkits/search/tests/test_utils.py index 8ffb68a6..fbd0e1f3 100644 --- a/toolkits/search/tests/test_utils.py +++ b/toolkits/search/tests/test_utils.py @@ -1,6 +1,6 @@ import pytest import serpapi -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk.errors import ToolExecutionError from arcade_search.utils import call_serpapi, prepare_params diff --git a/toolkits/slack/.pre-commit-config.yaml b/toolkits/slack/.pre-commit-config.yaml index 3953e996..c1eb7826 100644 --- a/toolkits/slack/.pre-commit-config.yaml +++ b/toolkits/slack/.pre-commit-config.yaml @@ -1,4 +1,4 @@ -files: ^./ +files: ^.*/slack/.* repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: "v4.4.0" diff --git a/toolkits/slack/Makefile b/toolkits/slack/Makefile index 610095b0..7e2c686e 100644 --- a/toolkits/slack/Makefile +++ b/toolkits/slack/Makefile @@ -1,30 +1,27 @@ .PHONY: help help: - @echo "๐Ÿ› ๏ธ slack Commands:\n" + @echo "๐Ÿ› ๏ธ github Commands:\n" @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' .PHONY: install -install: ## Install the poetry environment and install the pre-commit hooks - @echo "๐Ÿ“ฆ Checking if Poetry is installed" - @if ! command -v poetry >/dev/null 2>&1; then \ - echo "๐Ÿ“ฆ Poetry not found. Checking if pip is available"; \ - if ! command -v pip >/dev/null 2>&1; then \ - echo "โŒ pip is not installed. Please install pip first."; \ - exit 1; \ - fi; \ - echo "๐Ÿ“ฆ Installing Poetry with pip"; \ - pip install poetry==1.8.5; \ - else \ - echo "๐Ÿ“ฆ Poetry is already installed"; \ - fi - @echo "๐Ÿš€ Installing package in development mode with all extras" - poetry install --all-extras +install: ## Install the uv environment and install all packages with dependencies + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras --no-sources + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" + +.PHONY: install-local +install-local: ## Install the uv environment and install all packages with dependencies with local Arcade sources + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" .PHONY: build build: clean-build ## Build wheel file using poetry @echo "๐Ÿš€ Creating wheel file" - poetry build + uv build .PHONY: clean-build clean-build: ## clean build artifacts @@ -34,7 +31,7 @@ clean-build: ## clean build artifacts .PHONY: test test: ## Test the code with pytest @echo "๐Ÿš€ Testing code: Running pytest" - @poetry run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml + @uv run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml .PHONY: coverage coverage: ## Generate coverage report @@ -44,15 +41,13 @@ coverage: ## Generate coverage report coverage html .PHONY: bump-version -bump-version: ## Bump the version in the pyproject.toml file +bump-version: ## Bump the version in the pyproject.toml file by a patch version @echo "๐Ÿš€ Bumping version in pyproject.toml" - poetry version patch + uv version --bump patch .PHONY: check check: ## Run code quality tools. - @echo "๐Ÿš€ Checking Poetry lock file consistency with 'pyproject.toml': Running poetry check" - @poetry check @echo "๐Ÿš€ Linting code: Running pre-commit" - @poetry run pre-commit run -a + @uv run pre-commit run -a @echo "๐Ÿš€ Static type checking: Running mypy" - @poetry run mypy --config-file=pyproject.toml + @uv run mypy --config-file=pyproject.toml diff --git a/toolkits/slack/arcade_slack/critics.py b/toolkits/slack/arcade_slack/critics.py index a4bb66ce..e6248789 100644 --- a/toolkits/slack/arcade_slack/critics.py +++ b/toolkits/slack/arcade_slack/critics.py @@ -1,6 +1,6 @@ from typing import Any -from arcade.sdk.eval import BinaryCritic +from arcade_evals import BinaryCritic class RelativeTimeBinaryCritic(BinaryCritic): diff --git a/toolkits/slack/arcade_slack/tools/chat.py b/toolkits/slack/arcade_slack/tools/chat.py index 1b882671..61462497 100644 --- a/toolkits/slack/arcade_slack/tools/chat.py +++ b/toolkits/slack/arcade_slack/tools/chat.py @@ -2,9 +2,9 @@ import asyncio from datetime import datetime, timezone from typing import Annotated, cast -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Slack -from arcade.sdk.errors import RetryableToolError, ToolExecutionError +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Slack +from arcade_tdk.errors import RetryableToolError, ToolExecutionError from slack_sdk.errors import SlackApiError from slack_sdk.web.async_client import AsyncWebClient diff --git a/toolkits/slack/arcade_slack/tools/users.py b/toolkits/slack/arcade_slack/tools/users.py index 4a071cc7..ddd60d2e 100644 --- a/toolkits/slack/arcade_slack/tools/users.py +++ b/toolkits/slack/arcade_slack/tools/users.py @@ -1,8 +1,8 @@ from typing import Annotated, Any, cast -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Slack -from arcade.sdk.errors import RetryableToolError +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Slack +from arcade_tdk.errors import RetryableToolError from slack_sdk.errors import SlackApiError from slack_sdk.web.async_client import AsyncWebClient diff --git a/toolkits/slack/arcade_slack/utils.py b/toolkits/slack/arcade_slack/utils.py index 66647b22..77d57207 100644 --- a/toolkits/slack/arcade_slack/utils.py +++ b/toolkits/slack/arcade_slack/utils.py @@ -3,8 +3,8 @@ from collections.abc import Callable from datetime import datetime, timezone from typing import Any -from arcade.sdk import ToolContext -from arcade.sdk.errors import RetryableToolError +from arcade_tdk import ToolContext +from arcade_tdk.errors import RetryableToolError from arcade_slack.constants import MAX_PAGINATION_SIZE_LIMIT, MAX_PAGINATION_TIMEOUT_SECONDS from arcade_slack.custom_types import SlackPaginationNextCursor @@ -197,7 +197,7 @@ async def associate_members_of_multiple_conversations( context: ToolContext, ) -> list[dict]: """Associate members to each conversation, returning the updated list.""" - return await asyncio.gather(*[ + return await asyncio.gather(*[ # type: ignore[no-any-return] associate_members_of_conversation(get_members_in_conversation_func, context, conv) for conv in conversations ]) diff --git a/toolkits/slack/conftest.py b/toolkits/slack/conftest.py index acda0bea..f1534f3d 100644 --- a/toolkits/slack/conftest.py +++ b/toolkits/slack/conftest.py @@ -1,5 +1,5 @@ import pytest -from arcade.sdk import ToolAuthorizationContext, ToolContext +from arcade_tdk import ToolAuthorizationContext, ToolContext @pytest.fixture diff --git a/toolkits/slack/evals/eval_chat.py b/toolkits/slack/evals/eval_chat.py index 3784a80c..122aca95 100644 --- a/toolkits/slack/evals/eval_chat.py +++ b/toolkits/slack/evals/eval_chat.py @@ -1,8 +1,7 @@ import json from datetime import timedelta -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, DatetimeCritic, EvalRubric, @@ -11,6 +10,7 @@ from arcade.sdk.eval import ( SimilarityCritic, tool_eval, ) +from arcade_tdk import ToolCatalog import arcade_slack from arcade_slack.critics import RelativeTimeBinaryCritic diff --git a/toolkits/slack/evals/eval_users.py b/toolkits/slack/evals/eval_users.py index aea03a70..b1f3caa1 100644 --- a/toolkits/slack/evals/eval_users.py +++ b/toolkits/slack/evals/eval_users.py @@ -1,13 +1,13 @@ import json -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, EvalRubric, EvalSuite, ExpectedToolCall, tool_eval, ) +from arcade_tdk import ToolCatalog import arcade_slack from arcade_slack.tools.users import get_user_info_by_id, list_users diff --git a/toolkits/slack/pyproject.toml b/toolkits/slack/pyproject.toml index 2fcc4faa..d4b6878b 100644 --- a/toolkits/slack/pyproject.toml +++ b/toolkits/slack/pyproject.toml @@ -1,33 +1,39 @@ -[tool.poetry] +[build-system] +requires = [ "hatchling",] +build-backend = "hatchling.build" + +[project] name = "arcade_slack" version = "0.4.3" description = "Arcade.dev LLM tools for Slack" -authors = ["Arcade "] +requires-python = ">=3.10" +dependencies = [ "aiodns>=1.0,<2.0.0", "typing; python_version < '3.7'", "aiohttp>=3.7.3,<4.0.0", "arcade-tdk>=2.0.0,<3.0.0", "slack-sdk>=3.31.0,<4.0.0",] +[[project.authors]] +name = "Arcade" +email = "dev@arcade.dev" -[tool.poetry.dependencies] -python = "^3.10" -aiodns = "^1.0" # required by slack - not picked by poetry due to slack requirements txt quirk :/ -typing = { version = "*", markers = "python_version < '3.7'" } # prevent aiodns from installing typing package -aiohttp = ">=3.7.3,<4" # same as aiodns, above comment -arcade-ai = ">=1.2.0,<2.0" -slack-sdk = "^3.31.0" +[project.optional-dependencies] +dev = [ + "arcade-ai[evals]>=2.0.0,<3.0.0", + "arcade-serve>=2.0.0,<3.0.0", + "pytest>=8.3.0,<8.4.0", + "pytest-cov>=4.0.0,<4.1.0", + "pytest-asyncio>=0.24.0,<0.25.0", + "pytest-mock>=3.11.1,<3.12.0", + "mypy>=1.5.1,<1.6.0", + "pre-commit>=3.4.0,<3.5.0", + "tox>=4.11.1,<4.12.0", + "ruff>=0.7.4,<0.8.0", +] -[tool.poetry.dev-dependencies] -pytest = "^8.3.0" -pytest-cov = "^4.0.0" -pytest-asyncio = "^0.24.0" -pytest-mock = "^3.11.1" -mypy = "^1.5.1" -pre-commit = "^3.4.0" -tox = "^4.11.1" -ruff = "^0.7.4" - -[build-system] -requires = ["poetry-core>=1.0.0,<2.0.0"] -build-backend = "poetry.core.masonry.api" +# Use local path sources for arcade libs when working locally +[tool.uv.sources] +arcade-ai = {path = "../../", editable = true} +arcade-tdk = { path = "../../libs/arcade-tdk/", editable = true } +arcade-serve = { path = "../../libs/arcade-serve/", editable = true } [tool.mypy] -files = ["arcade_slack/**/*.py"] +files = [ "arcade_slack/**/*.py",] python_version = "3.10" disallow_untyped_defs = "True" disallow_any_unimported = "True" @@ -39,7 +45,10 @@ show_error_codes = "True" ignore_missing_imports = "True" [tool.pytest.ini_options] -testpaths = ["tests"] +testpaths = [ "tests",] [tool.coverage.report] skip_empty = true + +[tool.hatch.build.targets.wheel] +packages = [ "arcade_slack",] diff --git a/toolkits/slack/tests/test_chat.py b/toolkits/slack/tests/test_chat.py index d8d2c5e2..f10d00d2 100644 --- a/toolkits/slack/tests/test_chat.py +++ b/toolkits/slack/tests/test_chat.py @@ -3,7 +3,7 @@ from datetime import datetime, timezone from unittest.mock import Mock, call, patch import pytest -from arcade.sdk.errors import RetryableToolError, ToolExecutionError +from arcade_tdk.errors import RetryableToolError, ToolExecutionError from slack_sdk.errors import SlackApiError from slack_sdk.web.async_slack_response import AsyncSlackResponse diff --git a/toolkits/slack/tests/test_users.py b/toolkits/slack/tests/test_users.py index 7dce94da..a9641e72 100644 --- a/toolkits/slack/tests/test_users.py +++ b/toolkits/slack/tests/test_users.py @@ -1,7 +1,7 @@ from unittest.mock import patch import pytest -from arcade.sdk.errors import RetryableToolError +from arcade_tdk.errors import RetryableToolError from slack_sdk.errors import SlackApiError from arcade_slack.tools.users import get_user_info_by_id, list_users diff --git a/toolkits/slack/tests/test_utils.py b/toolkits/slack/tests/test_utils.py index c569e0aa..c095f7b8 100644 --- a/toolkits/slack/tests/test_utils.py +++ b/toolkits/slack/tests/test_utils.py @@ -2,7 +2,7 @@ import asyncio from unittest.mock import AsyncMock, MagicMock, call, patch import pytest -from arcade.sdk import ToolContext +from arcade_tdk import ToolContext from slack_sdk.errors import SlackApiError from slack_sdk.web.async_client import AsyncWebClient diff --git a/toolkits/spotify/.pre-commit-config.yaml b/toolkits/spotify/.pre-commit-config.yaml index 3953e996..6c54342e 100644 --- a/toolkits/spotify/.pre-commit-config.yaml +++ b/toolkits/spotify/.pre-commit-config.yaml @@ -1,4 +1,4 @@ -files: ^./ +files: ^.*/spotify/.* repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: "v4.4.0" diff --git a/toolkits/spotify/Makefile b/toolkits/spotify/Makefile index 1602ac12..7e2c686e 100644 --- a/toolkits/spotify/Makefile +++ b/toolkits/spotify/Makefile @@ -1,30 +1,27 @@ .PHONY: help help: - @echo "๐Ÿ› ๏ธ spotify Commands:\n" + @echo "๐Ÿ› ๏ธ github Commands:\n" @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' .PHONY: install -install: ## Install the poetry environment and install the pre-commit hooks - @echo "๐Ÿ“ฆ Checking if Poetry is installed" - @if ! command -v poetry >/dev/null 2>&1; then \ - echo "๐Ÿ“ฆ Poetry not found. Checking if pip is available"; \ - if ! command -v pip >/dev/null 2>&1; then \ - echo "โŒ pip is not installed. Please install pip first."; \ - exit 1; \ - fi; \ - echo "๐Ÿ“ฆ Installing Poetry with pip"; \ - pip install poetry==1.8.5; \ - else \ - echo "๐Ÿ“ฆ Poetry is already installed"; \ - fi - @echo "๐Ÿš€ Installing package in development mode with all extras" - poetry install --all-extras +install: ## Install the uv environment and install all packages with dependencies + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras --no-sources + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" + +.PHONY: install-local +install-local: ## Install the uv environment and install all packages with dependencies with local Arcade sources + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" .PHONY: build build: clean-build ## Build wheel file using poetry @echo "๐Ÿš€ Creating wheel file" - poetry build + uv build .PHONY: clean-build clean-build: ## clean build artifacts @@ -34,7 +31,7 @@ clean-build: ## clean build artifacts .PHONY: test test: ## Test the code with pytest @echo "๐Ÿš€ Testing code: Running pytest" - @poetry run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml + @uv run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml .PHONY: coverage coverage: ## Generate coverage report @@ -44,15 +41,13 @@ coverage: ## Generate coverage report coverage html .PHONY: bump-version -bump-version: ## Bump the version in the pyproject.toml file +bump-version: ## Bump the version in the pyproject.toml file by a patch version @echo "๐Ÿš€ Bumping version in pyproject.toml" - poetry version patch + uv version --bump patch .PHONY: check check: ## Run code quality tools. - @echo "๐Ÿš€ Checking Poetry lock file consistency with 'pyproject.toml': Running poetry check" - @poetry check @echo "๐Ÿš€ Linting code: Running pre-commit" - @poetry run pre-commit run -a + @uv run pre-commit run -a @echo "๐Ÿš€ Static type checking: Running mypy" - @poetry run mypy --config-file=pyproject.toml + @uv run mypy --config-file=pyproject.toml diff --git a/toolkits/spotify/arcade_spotify/tools/player.py b/toolkits/spotify/arcade_spotify/tools/player.py index 0787447e..5ab16c93 100644 --- a/toolkits/spotify/arcade_spotify/tools/player.py +++ b/toolkits/spotify/arcade_spotify/tools/player.py @@ -1,9 +1,9 @@ from typing import Annotated import httpx -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Spotify -from arcade.sdk.errors import RetryableToolError, ToolExecutionError +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Spotify +from arcade_tdk.errors import RetryableToolError, ToolExecutionError from arcade_spotify.tools.constants import RESPONSE_MSGS from arcade_spotify.tools.models import Device, SearchType diff --git a/toolkits/spotify/arcade_spotify/tools/search.py b/toolkits/spotify/arcade_spotify/tools/search.py index f2c11440..b668ecba 100644 --- a/toolkits/spotify/arcade_spotify/tools/search.py +++ b/toolkits/spotify/arcade_spotify/tools/search.py @@ -1,7 +1,7 @@ from typing import Annotated -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Spotify +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Spotify from arcade_spotify.tools.models import SearchType from arcade_spotify.tools.utils import ( diff --git a/toolkits/spotify/arcade_spotify/tools/tracks.py b/toolkits/spotify/arcade_spotify/tools/tracks.py index 3367b9ce..c636629e 100644 --- a/toolkits/spotify/arcade_spotify/tools/tracks.py +++ b/toolkits/spotify/arcade_spotify/tools/tracks.py @@ -1,7 +1,7 @@ from typing import Annotated -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Spotify +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Spotify from arcade_spotify.tools.utils import ( get_url, diff --git a/toolkits/spotify/arcade_spotify/tools/utils.py b/toolkits/spotify/arcade_spotify/tools/utils.py index 5a8a32e1..df3d32e5 100644 --- a/toolkits/spotify/arcade_spotify/tools/utils.py +++ b/toolkits/spotify/arcade_spotify/tools/utils.py @@ -1,5 +1,5 @@ import httpx -from arcade.sdk import ToolContext +from arcade_tdk import ToolContext from arcade_spotify.tools.constants import ENDPOINTS, SPOTIFY_BASE_URL from arcade_spotify.tools.models import PlaybackState diff --git a/toolkits/spotify/conftest.py b/toolkits/spotify/conftest.py index 827b5a18..41812667 100644 --- a/toolkits/spotify/conftest.py +++ b/toolkits/spotify/conftest.py @@ -1,5 +1,5 @@ import pytest -from arcade.sdk import ToolContext +from arcade_tdk import ToolContext @pytest.fixture diff --git a/toolkits/spotify/evals/eval_player.py b/toolkits/spotify/evals/eval_player.py index 3f65ec93..81995651 100644 --- a/toolkits/spotify/evals/eval_player.py +++ b/toolkits/spotify/evals/eval_player.py @@ -1,5 +1,4 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, EvalRubric, EvalSuite, @@ -8,6 +7,7 @@ from arcade.sdk.eval import ( SimilarityCritic, tool_eval, ) +from arcade_tdk import ToolCatalog from arcade_spotify.tools.player import ( adjust_playback_position, diff --git a/toolkits/spotify/evals/eval_search.py b/toolkits/spotify/evals/eval_search.py index 979cb50d..ad02eff9 100644 --- a/toolkits/spotify/evals/eval_search.py +++ b/toolkits/spotify/evals/eval_search.py @@ -1,5 +1,4 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, EvalRubric, EvalSuite, @@ -7,6 +6,7 @@ from arcade.sdk.eval import ( SimilarityCritic, tool_eval, ) +from arcade_tdk import ToolCatalog from arcade_spotify.tools.models import SearchType from arcade_spotify.tools.search import search diff --git a/toolkits/spotify/evals/eval_tracks.py b/toolkits/spotify/evals/eval_tracks.py index fa52402e..baf2483f 100644 --- a/toolkits/spotify/evals/eval_tracks.py +++ b/toolkits/spotify/evals/eval_tracks.py @@ -1,11 +1,11 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, EvalRubric, EvalSuite, ExpectedToolCall, tool_eval, ) +from arcade_tdk import ToolCatalog from arcade_spotify.tools.tracks import get_track_from_id diff --git a/toolkits/spotify/pyproject.toml b/toolkits/spotify/pyproject.toml index bdccae23..61923ffb 100644 --- a/toolkits/spotify/pyproject.toml +++ b/toolkits/spotify/pyproject.toml @@ -1,30 +1,39 @@ -[tool.poetry] +[build-system] +requires = [ "hatchling",] +build-backend = "hatchling.build" + +[project] name = "arcade_spotify" version = "0.2.1" description = "Arcade.dev LLM tools for Spotify" -authors = ["Arcade "] +requires-python = ">=3.10" +dependencies = [ "arcade-tdk>=2.0.0,<3.0.0", "httpx>=0.27.2,<1.0.0",] +[[project.authors]] +name = "Arcade" +email = "dev@arcade.dev" -[tool.poetry.dependencies] -python = "^3.10" -arcade-ai = ">=0.1,<2.0" -httpx = "^0.27.2" +[project.optional-dependencies] +dev = [ + "arcade-ai[evals]>=2.0.0,<3.0.0", + "arcade-serve>=2.0.0,<3.0.0", + "pytest>=8.3.0,<8.4.0", + "pytest-cov>=4.0.0,<4.1.0", + "pytest-asyncio>=0.24.0,<0.25.0", + "pytest-mock>=3.11.1,<3.12.0", + "mypy>=1.5.1,<1.6.0", + "pre-commit>=3.4.0,<3.5.0", + "tox>=4.11.1,<4.12.0", + "ruff>=0.7.4,<0.8.0", +] -[tool.poetry.dev-dependencies] -pytest = "^8.3.0" -pytest-cov = "^4.0.0" -pytest-asyncio = "^0.24.0" -pytest-mock = "^3.11.1" -mypy = "^1.5.1" -pre-commit = "^3.4.0" -tox = "^4.11.1" -ruff = "^0.7.4" - -[build-system] -requires = ["poetry-core>=1.0.0,<2.0.0"] -build-backend = "poetry.core.masonry.api" +# Use local path sources for arcade libs when working locally +[tool.uv.sources] +arcade-ai = {path = "../../", editable = true} +arcade-tdk = { path = "../../libs/arcade-tdk/", editable = true } +arcade-serve = { path = "../../libs/arcade-serve/", editable = true } [tool.mypy] -files = ["arcade_spotify/**/*.py"] +files = [ "arcade_spotify/**/*.py",] python_version = "3.10" disallow_untyped_defs = "True" disallow_any_unimported = "True" @@ -36,7 +45,10 @@ show_error_codes = "True" ignore_missing_imports = "True" [tool.pytest.ini_options] -testpaths = ["tests"] +testpaths = [ "tests",] [tool.coverage.report] skip_empty = true + +[tool.hatch.build.targets.wheel] +packages = [ "arcade_spotify",] diff --git a/toolkits/spotify/tests/test_player.py b/toolkits/spotify/tests/test_player.py index 210e5911..b876218c 100644 --- a/toolkits/spotify/tests/test_player.py +++ b/toolkits/spotify/tests/test_player.py @@ -2,7 +2,7 @@ from unittest.mock import MagicMock, patch import httpx import pytest -from arcade.sdk.errors import RetryableToolError, ToolExecutionError +from arcade_tdk.errors import RetryableToolError, ToolExecutionError from arcade_spotify.tools.constants import RESPONSE_MSGS from arcade_spotify.tools.models import SearchType diff --git a/toolkits/spotify/tests/test_search.py b/toolkits/spotify/tests/test_search.py index 06c7469f..0af1640e 100644 --- a/toolkits/spotify/tests/test_search.py +++ b/toolkits/spotify/tests/test_search.py @@ -2,7 +2,7 @@ from unittest.mock import MagicMock import httpx import pytest -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk.errors import ToolExecutionError from arcade_spotify.tools.models import SearchType from arcade_spotify.tools.search import search diff --git a/toolkits/spotify/tests/test_tracks.py b/toolkits/spotify/tests/test_tracks.py index 7ce97b9e..ef9a9ed7 100644 --- a/toolkits/spotify/tests/test_tracks.py +++ b/toolkits/spotify/tests/test_tracks.py @@ -2,7 +2,7 @@ from unittest.mock import MagicMock import httpx import pytest -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk.errors import ToolExecutionError from arcade_spotify.tools.tracks import get_track_from_id from arcade_spotify.tools.utils import get_url diff --git a/toolkits/stripe/.pre-commit-config.yaml b/toolkits/stripe/.pre-commit-config.yaml index 3953e996..e367e3d9 100644 --- a/toolkits/stripe/.pre-commit-config.yaml +++ b/toolkits/stripe/.pre-commit-config.yaml @@ -1,4 +1,4 @@ -files: ^./ +files: ^.*/stripe/.* repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: "v4.4.0" diff --git a/toolkits/stripe/Makefile b/toolkits/stripe/Makefile index c74cb193..7e2c686e 100644 --- a/toolkits/stripe/Makefile +++ b/toolkits/stripe/Makefile @@ -1,30 +1,27 @@ .PHONY: help help: - @echo "๐Ÿ› ๏ธ stripe Commands:\n" + @echo "๐Ÿ› ๏ธ github Commands:\n" @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' .PHONY: install -install: ## Install the poetry environment and install the pre-commit hooks - @echo "๐Ÿ“ฆ Checking if Poetry is installed" - @if ! command -v poetry > /dev/null 2>&1; then \ - echo "๐Ÿ“ฆ Poetry not found. Checking if pip is available"; \ - if ! command -v pip >/dev/null 2>&1; then \ - echo "โŒ pip is not installed. Please install pip first."; \ - exit 1; \ - fi; \ - echo "๐Ÿ“ฆ Installing Poetry with pip"; \ - pip install poetry==1.8.5; \ - else \ - echo "๐Ÿ“ฆ Poetry is already installed"; \ - fi - @echo "๐Ÿš€ Installing package in development mode with all extras" - poetry install --all-extras +install: ## Install the uv environment and install all packages with dependencies + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras --no-sources + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" + +.PHONY: install-local +install-local: ## Install the uv environment and install all packages with dependencies with local Arcade sources + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" .PHONY: build build: clean-build ## Build wheel file using poetry @echo "๐Ÿš€ Creating wheel file" - poetry build + uv build .PHONY: clean-build clean-build: ## clean build artifacts @@ -34,7 +31,7 @@ clean-build: ## clean build artifacts .PHONY: test test: ## Test the code with pytest @echo "๐Ÿš€ Testing code: Running pytest" - @poetry run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml + @uv run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml .PHONY: coverage coverage: ## Generate coverage report @@ -44,15 +41,13 @@ coverage: ## Generate coverage report coverage html .PHONY: bump-version -bump-version: ## Bump the version in the pyproject.toml file +bump-version: ## Bump the version in the pyproject.toml file by a patch version @echo "๐Ÿš€ Bumping version in pyproject.toml" - poetry version patch + uv version --bump patch .PHONY: check check: ## Run code quality tools. - @echo "๐Ÿš€ Checking Poetry lock file consistency with 'pyproject.toml': Running poetry check" - @poetry check @echo "๐Ÿš€ Linting code: Running pre-commit" - @poetry run pre-commit run -a + @uv run pre-commit run -a @echo "๐Ÿš€ Static type checking: Running mypy" - @poetry run mypy --config-file=pyproject.toml + @uv run mypy --config-file=pyproject.toml diff --git a/toolkits/stripe/_generate.py b/toolkits/stripe/_generate.py index cc1d3311..0a56ea5d 100644 --- a/toolkits/stripe/_generate.py +++ b/toolkits/stripe/_generate.py @@ -35,7 +35,7 @@ from typing import Annotated, Optional from stripe_agent_toolkit.api import StripeAPI -from arcade.sdk import ToolContext, tool +from arcade_tdk import ToolContext, tool def run_stripe_tool(context: ToolContext, method_name: str, params: dict) -> str: \"\"\" diff --git a/toolkits/stripe/arcade_stripe/evals/eval_stripe.py b/toolkits/stripe/arcade_stripe/evals/eval_stripe.py index d78d1609..0418dcaa 100644 --- a/toolkits/stripe/arcade_stripe/evals/eval_stripe.py +++ b/toolkits/stripe/arcade_stripe/evals/eval_stripe.py @@ -1,6 +1,12 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import BinaryCritic, EvalRubric, EvalSuite, ExpectedToolCall, tool_eval -from arcade.sdk.eval.critic import SimilarityCritic +from arcade_evals import ( + BinaryCritic, + EvalRubric, + EvalSuite, + ExpectedToolCall, + SimilarityCritic, + tool_eval, +) +from arcade_tdk import ToolCatalog import arcade_stripe from arcade_stripe.tools.stripe import ( diff --git a/toolkits/stripe/arcade_stripe/tools/stripe.py b/toolkits/stripe/arcade_stripe/tools/stripe.py index b4f8ca10..b6db05ef 100644 --- a/toolkits/stripe/arcade_stripe/tools/stripe.py +++ b/toolkits/stripe/arcade_stripe/tools/stripe.py @@ -1,6 +1,6 @@ from typing import Annotated -from arcade.sdk import ToolContext, tool +from arcade_tdk import ToolContext, tool from stripe_agent_toolkit.api import StripeAPI diff --git a/toolkits/stripe/pyproject.toml b/toolkits/stripe/pyproject.toml index 43d32cde..71c44ef6 100644 --- a/toolkits/stripe/pyproject.toml +++ b/toolkits/stripe/pyproject.toml @@ -1,29 +1,38 @@ -[tool.poetry] +[build-system] +requires = [ "hatchling",] +build-backend = "hatchling.build" + +[project] name = "arcade_stripe" version = "0.0.1" description = "Arcade.dev LLM tools for Stripe" -authors = ["Arcade "] +requires-python = ">=3.10" +dependencies = [ "arcade-tdk>=2.0.0,<3.0.0", "stripe-agent-toolkit>=0.6.1,<1.0.0", "stripe>=11.0.0,<12.0.0",] +[[project.authors]] +name = "Arcade" +email = "dev@arcade.dev" -[tool.poetry.dependencies] -python = "^3.11" -arcade-ai = "^1.0.5" -stripe-agent-toolkit = "^0.6.1" -stripe = "^11.0.0" +[project.optional-dependencies] +dev = [ + "arcade-ai[evals]>=2.0.0,<3.0.0", + "arcade-serve>=2.0.0,<3.0.0", + "pytest>=8.3.0,<8.4.0", + "pytest-cov>=4.0.0,<4.1.0", + "pytest-asyncio>=0.24.0,<0.25.0", + "mypy>=1.5.1,<1.6.0", + "pre-commit>=3.4.0,<3.5.0", + "tox>=4.11.1,<4.12.0", + "ruff>=0.7.4,<0.8.0", +] -[tool.poetry.dev-dependencies] -pytest = "^8.3.0" -pytest-cov = "^4.0.0" -mypy = "^1.5.1" -pre-commit = "^3.4.0" -tox = "^4.11.1" -ruff = "^0.7.4" - -[build-system] -requires = ["poetry-core>=1.0.0,<2.0.0"] -build-backend = "poetry.core.masonry.api" +# Use local path sources for arcade libs when working locally +[tool.uv.sources] +arcade-ai = {path = "../../", editable = true} +arcade-tdk = { path = "../../libs/arcade-tdk/", editable = true } +arcade-serve = { path = "../../libs/arcade-serve/", editable = true } [tool.mypy] -files = ["arcade_stripe/**/*.py"] +files = [ "arcade_stripe/**/*.py",] python_version = "3.10" disallow_untyped_defs = "True" disallow_any_unimported = "True" @@ -35,7 +44,10 @@ show_error_codes = "True" ignore_missing_imports = "True" [tool.pytest.ini_options] -testpaths = ["tests"] +testpaths = [ "tests",] [tool.coverage.report] skip_empty = true + +[tool.hatch.build.targets.wheel] +packages = [ "arcade_stripe",] diff --git a/toolkits/web/.pre-commit-config.yaml b/toolkits/web/.pre-commit-config.yaml index 3953e996..d04ca99c 100644 --- a/toolkits/web/.pre-commit-config.yaml +++ b/toolkits/web/.pre-commit-config.yaml @@ -1,4 +1,4 @@ -files: ^./ +files: ^.*/web/.* repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: "v4.4.0" diff --git a/toolkits/web/Makefile b/toolkits/web/Makefile index 9b6f141d..7e2c686e 100644 --- a/toolkits/web/Makefile +++ b/toolkits/web/Makefile @@ -1,30 +1,27 @@ .PHONY: help help: - @echo "๐Ÿ› ๏ธ web Commands:\n" + @echo "๐Ÿ› ๏ธ github Commands:\n" @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' .PHONY: install -install: ## Install the poetry environment and install the pre-commit hooks - @echo "๐Ÿ“ฆ Checking if Poetry is installed" - @if ! command -v poetry >/dev/null 2>&1; then \ - echo "๐Ÿ“ฆ Poetry not found. Checking if pip is available"; \ - if ! command -v pip >/dev/null 2>&1; then \ - echo "โŒ pip is not installed. Please install pip first."; \ - exit 1; \ - fi; \ - echo "๐Ÿ“ฆ Installing Poetry with pip"; \ - pip install poetry==1.8.5; \ - else \ - echo "๐Ÿ“ฆ Poetry is already installed"; \ - fi - @echo "๐Ÿš€ Installing package in development mode with all extras" - poetry install --all-extras +install: ## Install the uv environment and install all packages with dependencies + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras --no-sources + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" + +.PHONY: install-local +install-local: ## Install the uv environment and install all packages with dependencies with local Arcade sources + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" .PHONY: build build: clean-build ## Build wheel file using poetry @echo "๐Ÿš€ Creating wheel file" - poetry build + uv build .PHONY: clean-build clean-build: ## clean build artifacts @@ -34,7 +31,7 @@ clean-build: ## clean build artifacts .PHONY: test test: ## Test the code with pytest @echo "๐Ÿš€ Testing code: Running pytest" - @poetry run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml + @uv run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml .PHONY: coverage coverage: ## Generate coverage report @@ -44,15 +41,13 @@ coverage: ## Generate coverage report coverage html .PHONY: bump-version -bump-version: ## Bump the version in the pyproject.toml file +bump-version: ## Bump the version in the pyproject.toml file by a patch version @echo "๐Ÿš€ Bumping version in pyproject.toml" - poetry version patch + uv version --bump patch .PHONY: check check: ## Run code quality tools. - @echo "๐Ÿš€ Checking Poetry lock file consistency with 'pyproject.toml': Running poetry check" - @poetry check @echo "๐Ÿš€ Linting code: Running pre-commit" - @poetry run pre-commit run -a + @uv run pre-commit run -a @echo "๐Ÿš€ Static type checking: Running mypy" - @poetry run mypy --config-file=pyproject.toml + @uv run mypy --config-file=pyproject.toml diff --git a/toolkits/web/arcade_web/tools/firecrawl.py b/toolkits/web/arcade_web/tools/firecrawl.py index a9d0e1c6..fb6aad41 100644 --- a/toolkits/web/arcade_web/tools/firecrawl.py +++ b/toolkits/web/arcade_web/tools/firecrawl.py @@ -1,6 +1,6 @@ from typing import Annotated, Any -from arcade.sdk import ToolContext, tool +from arcade_tdk import ToolContext, tool from firecrawl import FirecrawlApp from arcade_web.tools.models import Formats diff --git a/toolkits/web/evals/eval_firecrawl.py b/toolkits/web/evals/eval_firecrawl.py index 9e30e840..0cdeef8e 100644 --- a/toolkits/web/evals/eval_firecrawl.py +++ b/toolkits/web/evals/eval_firecrawl.py @@ -1,5 +1,4 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, EvalRubric, EvalSuite, @@ -8,6 +7,7 @@ from arcade.sdk.eval import ( SimilarityCritic, tool_eval, ) +from arcade_tdk import ToolCatalog import arcade_web from arcade_web.tools.firecrawl import ( diff --git a/toolkits/web/pyproject.toml b/toolkits/web/pyproject.toml index f304c4f5..5f64c52a 100644 --- a/toolkits/web/pyproject.toml +++ b/toolkits/web/pyproject.toml @@ -1,30 +1,39 @@ -[tool.poetry] +[build-system] +requires = [ "hatchling",] +build-backend = "hatchling.build" + +[project] name = "arcade_web" version = "1.0.1" description = "Arcade.dev LLM tools for web scraping related tasks" -authors = ["Arcade "] +requires-python = ">=3.10" +dependencies = [ "arcade-tdk>=2.0.0,<3.0.0", "firecrawl-py>=1.3.1,<2.0.0",] +[[project.authors]] +name = "Arcade" +email = "dev@arcade.dev" -[tool.poetry.dependencies] -python = "^3.10" -arcade-ai = ">=1.0.5,<2.0" -firecrawl-py = "^1.3.1" +[project.optional-dependencies] +dev = [ + "arcade-ai[evals]>=2.0.0,<3.0.0", + "arcade-serve>=2.0.0,<3.0.0", + "pytest>=8.3.0,<8.4.0", + "pytest-cov>=4.0.0,<4.1.0", + "pytest-asyncio>=0.24.0,<0.25.0", + "pytest-mock>=3.11.1,<3.12.0", + "mypy>=1.5.1,<1.6.0", + "pre-commit>=3.4.0,<3.5.0", + "tox>=4.11.1,<4.12.0", + "ruff>=0.7.4,<0.8.0", +] -[tool.poetry.dev-dependencies] -pytest = "^8.3.0" -pytest-cov = "^4.0.0" -pytest-asyncio = "^0.24.0" -pytest-mock = "^3.11.1" -mypy = "^1.5.1" -pre-commit = "^3.4.0" -tox = "^4.11.1" -ruff = "^0.7.4" - -[build-system] -requires = ["poetry-core>=1.0.0,<2.0.0"] -build-backend = "poetry.core.masonry.api" +# Use local path sources for arcade libs when working locally +[tool.uv.sources] +arcade-ai = {path = "../../", editable = true} +arcade-tdk = { path = "../../libs/arcade-tdk/", editable = true } +arcade-serve = { path = "../../libs/arcade-serve/", editable = true } [tool.mypy] -files = ["arcade_web/**/*.py"] +files = [ "arcade_web/**/*.py",] python_version = "3.10" disallow_untyped_defs = "True" disallow_any_unimported = "True" @@ -36,7 +45,10 @@ show_error_codes = "True" ignore_missing_imports = "True" [tool.pytest.ini_options] -testpaths = ["tests"] +testpaths = [ "tests",] [tool.coverage.report] skip_empty = true + +[tool.hatch.build.targets.wheel] +packages = [ "arcade_web",] diff --git a/toolkits/web/tests/test_firecrawl.py b/toolkits/web/tests/test_firecrawl.py index 1d5e24b0..2f447774 100644 --- a/toolkits/web/tests/test_firecrawl.py +++ b/toolkits/web/tests/test_firecrawl.py @@ -1,9 +1,8 @@ from unittest.mock import patch import pytest -from arcade.core.schema import ToolSecretItem -from arcade.sdk import ToolContext -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk import ToolContext, ToolSecretItem +from arcade_tdk.errors import ToolExecutionError from arcade_web.tools.firecrawl import ( cancel_crawl, diff --git a/toolkits/x/.pre-commit-config.yaml b/toolkits/x/.pre-commit-config.yaml index 3953e996..10d4e7ce 100644 --- a/toolkits/x/.pre-commit-config.yaml +++ b/toolkits/x/.pre-commit-config.yaml @@ -1,4 +1,4 @@ -files: ^./ +files: ^.*/x/.* repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: "v4.4.0" diff --git a/toolkits/x/Makefile b/toolkits/x/Makefile index a69b9c21..7e2c686e 100644 --- a/toolkits/x/Makefile +++ b/toolkits/x/Makefile @@ -1,30 +1,27 @@ .PHONY: help help: - @echo "๐Ÿ› ๏ธ x Commands:\n" + @echo "๐Ÿ› ๏ธ github Commands:\n" @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' .PHONY: install -install: ## Install the poetry environment and install the pre-commit hooks - @echo "๐Ÿ“ฆ Checking if Poetry is installed" - @if ! command -v poetry >/dev/null 2>&1; then \ - echo "๐Ÿ“ฆ Poetry not found. Checking if pip is available"; \ - if ! command -v pip >/dev/null 2>&1; then \ - echo "โŒ pip is not installed. Please install pip first."; \ - exit 1; \ - fi; \ - echo "๐Ÿ“ฆ Installing Poetry with pip"; \ - pip install poetry==1.8.5; \ - else \ - echo "๐Ÿ“ฆ Poetry is already installed"; \ - fi - @echo "๐Ÿš€ Installing package in development mode with all extras" - poetry install --all-extras +install: ## Install the uv environment and install all packages with dependencies + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras --no-sources + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" + +.PHONY: install-local +install-local: ## Install the uv environment and install all packages with dependencies with local Arcade sources + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" .PHONY: build build: clean-build ## Build wheel file using poetry @echo "๐Ÿš€ Creating wheel file" - poetry build + uv build .PHONY: clean-build clean-build: ## clean build artifacts @@ -34,7 +31,7 @@ clean-build: ## clean build artifacts .PHONY: test test: ## Test the code with pytest @echo "๐Ÿš€ Testing code: Running pytest" - @poetry run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml + @uv run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml .PHONY: coverage coverage: ## Generate coverage report @@ -44,15 +41,13 @@ coverage: ## Generate coverage report coverage html .PHONY: bump-version -bump-version: ## Bump the version in the pyproject.toml file +bump-version: ## Bump the version in the pyproject.toml file by a patch version @echo "๐Ÿš€ Bumping version in pyproject.toml" - poetry version patch + uv version --bump patch .PHONY: check check: ## Run code quality tools. - @echo "๐Ÿš€ Checking Poetry lock file consistency with 'pyproject.toml': Running poetry check" - @poetry check @echo "๐Ÿš€ Linting code: Running pre-commit" - @poetry run pre-commit run -a + @uv run pre-commit run -a @echo "๐Ÿš€ Static type checking: Running mypy" - @poetry run mypy --config-file=pyproject.toml + @uv run mypy --config-file=pyproject.toml diff --git a/toolkits/x/arcade_x/tools/tweets.py b/toolkits/x/arcade_x/tools/tweets.py index ade3e8b5..6fae9041 100644 --- a/toolkits/x/arcade_x/tools/tweets.py +++ b/toolkits/x/arcade_x/tools/tweets.py @@ -1,9 +1,9 @@ from typing import Annotated, Any import httpx -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import X -from arcade.sdk.errors import RetryableToolError +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import X +from arcade_tdk.errors import RetryableToolError from arcade_x.tools.constants import TWEETS_URL from arcade_x.tools.utils import ( diff --git a/toolkits/x/arcade_x/tools/users.py b/toolkits/x/arcade_x/tools/users.py index 17e0148f..31624086 100644 --- a/toolkits/x/arcade_x/tools/users.py +++ b/toolkits/x/arcade_x/tools/users.py @@ -1,9 +1,9 @@ from typing import Annotated import httpx -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import X -from arcade.sdk.errors import RetryableToolError +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import X +from arcade_tdk.errors import RetryableToolError from arcade_x.tools.utils import ( expand_urls_in_user_description, diff --git a/toolkits/x/arcade_x/tools/utils.py b/toolkits/x/arcade_x/tools/utils.py index 1f0f7b02..8545b95e 100644 --- a/toolkits/x/arcade_x/tools/utils.py +++ b/toolkits/x/arcade_x/tools/utils.py @@ -1,7 +1,7 @@ from typing import Any -from arcade.sdk import ToolContext -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk import ToolContext +from arcade_tdk.errors import ToolExecutionError def get_tweet_url(tweet_id: str) -> str: diff --git a/toolkits/x/conftest.py b/toolkits/x/conftest.py index 0a842143..55ca1e5e 100644 --- a/toolkits/x/conftest.py +++ b/toolkits/x/conftest.py @@ -1,5 +1,5 @@ import pytest -from arcade.sdk import ToolContext +from arcade_tdk import ToolContext @pytest.fixture diff --git a/toolkits/x/evals/eval_x_tools.py b/toolkits/x/evals/eval_x_tools.py index 5882a60c..19914737 100644 --- a/toolkits/x/evals/eval_x_tools.py +++ b/toolkits/x/evals/eval_x_tools.py @@ -1,11 +1,11 @@ -from arcade.sdk import ToolCatalog -from arcade.sdk.eval import ( +from arcade_evals import ( BinaryCritic, EvalRubric, EvalSuite, ExpectedToolCall, tool_eval, ) +from arcade_tdk import ToolCatalog import arcade_x from arcade_x.tools.tweets import ( diff --git a/toolkits/x/pyproject.toml b/toolkits/x/pyproject.toml index adf04d89..8a36ce0b 100644 --- a/toolkits/x/pyproject.toml +++ b/toolkits/x/pyproject.toml @@ -1,30 +1,39 @@ -[tool.poetry] +[build-system] +requires = [ "hatchling",] +build-backend = "hatchling.build" + +[project] name = "arcade_x" version = "0.1.12" description = "Arcade.dev LLM tools for X (Twitter)" -authors = ["Arcade "] +requires-python = ">=3.10" +dependencies = [ "arcade-tdk>=2.0.0,<3.0.0", "httpx>=0.27.2,<1.0.0",] +[[project.authors]] +name = "Arcade" +email = "dev@arcade.dev" -[tool.poetry.dependencies] -python = "^3.10" -arcade-ai = ">=0.1,<2.0" -httpx = "^0.27.2" +[project.optional-dependencies] +dev = [ + "arcade-ai[evals]>=2.0.0,<3.0.0", + "arcade-serve>=2.0.0,<3.0.0", + "pytest>=8.3.0,<8.4.0", + "pytest-cov>=4.0.0,<4.1.0", + "pytest-asyncio>=0.24.0,<0.25.0", + "pytest-mock>=3.11.1,<3.12.0", + "mypy>=1.5.1,<1.6.0", + "pre-commit>=3.4.0,<3.5.0", + "tox>=4.11.1,<4.12.0", + "ruff>=0.7.4,<0.8.0", +] -[tool.poetry.dev-dependencies] -pytest = "^8.3.0" -pytest-cov = "^4.0.0" -pytest-asyncio = "^0.24.0" -pytest-mock = "^3.11.1" -mypy = "^1.5.1" -pre-commit = "^3.4.0" -tox = "^4.11.1" -ruff = "^0.7.4" - -[build-system] -requires = ["poetry-core>=1.0.0,<2.0.0"] -build-backend = "poetry.core.masonry.api" +# Use local path sources for arcade libs when working locally +[tool.uv.sources] +arcade-ai = {path = "../../", editable = true} +arcade-tdk = { path = "../../libs/arcade-tdk/", editable = true } +arcade-serve = { path = "../../libs/arcade-serve/", editable = true } [tool.mypy] -files = ["arcade_x/**/*.py"] +files = [ "arcade_x/**/*.py",] python_version = "3.10" disallow_untyped_defs = "True" disallow_any_unimported = "True" @@ -35,9 +44,11 @@ warn_unused_ignores = "True" show_error_codes = "True" ignore_missing_imports = "True" - [tool.pytest.ini_options] -testpaths = ["tests"] +testpaths = [ "tests",] [tool.coverage.report] skip_empty = true + +[tool.hatch.build.targets.wheel] +packages = [ "arcade_x",] diff --git a/toolkits/x/tests/test_tweets.py b/toolkits/x/tests/test_tweets.py index ba486146..f534630d 100644 --- a/toolkits/x/tests/test_tweets.py +++ b/toolkits/x/tests/test_tweets.py @@ -2,7 +2,7 @@ from unittest.mock import MagicMock import httpx import pytest -from arcade.sdk.errors import RetryableToolError, ToolExecutionError +from arcade_tdk.errors import RetryableToolError, ToolExecutionError from arcade_x.tools.tweets import ( delete_tweet_by_id, diff --git a/toolkits/x/tests/test_users.py b/toolkits/x/tests/test_users.py index 6115ff91..faee0191 100644 --- a/toolkits/x/tests/test_users.py +++ b/toolkits/x/tests/test_users.py @@ -2,7 +2,7 @@ from unittest.mock import MagicMock import httpx import pytest -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk.errors import ToolExecutionError from arcade_x.tools.users import lookup_single_user_by_username diff --git a/toolkits/zoom/.pre-commit-config.yaml b/toolkits/zoom/.pre-commit-config.yaml index 3953e996..68794e1e 100644 --- a/toolkits/zoom/.pre-commit-config.yaml +++ b/toolkits/zoom/.pre-commit-config.yaml @@ -1,4 +1,4 @@ -files: ^./ +files: ^.*/zoom/.* repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: "v4.4.0" diff --git a/toolkits/zoom/Makefile b/toolkits/zoom/Makefile index b4222577..7e2c686e 100644 --- a/toolkits/zoom/Makefile +++ b/toolkits/zoom/Makefile @@ -1,30 +1,27 @@ .PHONY: help help: - @echo "๐Ÿ› ๏ธ code_sandbox Commands:\n" + @echo "๐Ÿ› ๏ธ github Commands:\n" @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' .PHONY: install -install: ## Install the poetry environment and install the pre-commit hooks - @echo "๐Ÿ“ฆ Checking if Poetry is installed" - @if ! command -v poetry >/dev/null 2>&1; then \ - echo "๐Ÿ“ฆ Poetry not found. Checking if pip is available"; \ - if ! command -v pip >/dev/null 2>&1; then \ - echo "โŒ pip is not installed. Please install pip first."; \ - exit 1; \ - fi; \ - echo "๐Ÿ“ฆ Installing Poetry with pip"; \ - pip install poetry==1.8.5; \ - else \ - echo "๐Ÿ“ฆ Poetry is already installed"; \ - fi - @echo "๐Ÿš€ Installing package in development mode with all extras" - poetry install --all-extras +install: ## Install the uv environment and install all packages with dependencies + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras --no-sources + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" + +.PHONY: install-local +install-local: ## Install the uv environment and install all packages with dependencies with local Arcade sources + @echo "๐Ÿš€ Creating virtual environment and installing all packages using uv" + @uv sync --active --all-extras + @uv run pre-commit install + @echo "โœ… All packages and dependencies installed via uv" .PHONY: build build: clean-build ## Build wheel file using poetry @echo "๐Ÿš€ Creating wheel file" - poetry build + uv build .PHONY: clean-build clean-build: ## clean build artifacts @@ -34,7 +31,7 @@ clean-build: ## clean build artifacts .PHONY: test test: ## Test the code with pytest @echo "๐Ÿš€ Testing code: Running pytest" - @poetry run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml + @uv run pytest -W ignore -v --cov --cov-config=pyproject.toml --cov-report=xml .PHONY: coverage coverage: ## Generate coverage report @@ -44,15 +41,13 @@ coverage: ## Generate coverage report coverage html .PHONY: bump-version -bump-version: ## Bump the version in the pyproject.toml file +bump-version: ## Bump the version in the pyproject.toml file by a patch version @echo "๐Ÿš€ Bumping version in pyproject.toml" - poetry version patch + uv version --bump patch .PHONY: check check: ## Run code quality tools. - @echo "๐Ÿš€ Checking Poetry lock file consistency with 'pyproject.toml': Running poetry check" - @poetry check @echo "๐Ÿš€ Linting code: Running pre-commit" - @poetry run pre-commit run -a + @uv run pre-commit run -a @echo "๐Ÿš€ Static type checking: Running mypy" - @poetry run mypy --config-file=pyproject.toml + @uv run mypy --config-file=pyproject.toml diff --git a/toolkits/zoom/arcade_zoom/tools/meetings.py b/toolkits/zoom/arcade_zoom/tools/meetings.py index dd9c5e2e..d2dbdac2 100644 --- a/toolkits/zoom/arcade_zoom/tools/meetings.py +++ b/toolkits/zoom/arcade_zoom/tools/meetings.py @@ -1,7 +1,7 @@ from typing import Annotated -from arcade.sdk import ToolContext, tool -from arcade.sdk.auth import Zoom +from arcade_tdk import ToolContext, tool +from arcade_tdk.auth import Zoom from arcade_zoom.tools.utils import _handle_zoom_api_error, _send_zoom_request diff --git a/toolkits/zoom/arcade_zoom/tools/utils.py b/toolkits/zoom/arcade_zoom/tools/utils.py index 47294d8b..73041f53 100644 --- a/toolkits/zoom/arcade_zoom/tools/utils.py +++ b/toolkits/zoom/arcade_zoom/tools/utils.py @@ -1,6 +1,6 @@ import httpx -from arcade.sdk import ToolContext -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk import ToolContext +from arcade_tdk.errors import ToolExecutionError from arcade_zoom.tools.constants import ZOOM_BASE_URL diff --git a/toolkits/zoom/pyproject.toml b/toolkits/zoom/pyproject.toml index f10456d8..605c8792 100644 --- a/toolkits/zoom/pyproject.toml +++ b/toolkits/zoom/pyproject.toml @@ -1,30 +1,39 @@ -[tool.poetry] +[build-system] +requires = [ "hatchling",] +build-backend = "hatchling.build" + +[project] name = "arcade_zoom" version = "0.1.10" description = "Arcade.dev LLM tools for Zoom" -authors = ["Arcade "] +requires-python = ">=3.10" +dependencies = [ "arcade-tdk>=2.0.0,<3.0.0", "httpx>=0.27.2,<1.0.0",] +[[project.authors]] +name = "Arcade" +email = "dev@arcade.dev" -[tool.poetry.dependencies] -python = "^3.10" -arcade-ai = ">=0.1,<2.0" -httpx = "^0.27.2" +[project.optional-dependencies] +dev = [ + "arcade-ai[evals]>=2.0.0,<3.0.0", + "arcade-serve>=2.0.0,<3.0.0", + "pytest>=8.3.0,<8.4.0", + "pytest-cov>=4.0.0,<4.1.0", + "pytest-asyncio>=0.24.0,<0.25.0", + "pytest-mock>=3.11.1,<3.12.0", + "mypy>=1.5.1,<1.6.0", + "pre-commit>=3.4.0,<3.5.0", + "tox>=4.11.1,<4.12.0", + "ruff>=0.7.4,<0.8.0", +] -[tool.poetry.dev-dependencies] -pytest = "^8.3.0" -pytest-cov = "^4.0.0" -pytest-asyncio = "^0.24.0" -pytest-mock = "^3.11.1" -mypy = "^1.5.1" -pre-commit = "^3.4.0" -tox = "^4.11.1" -ruff = "^0.7.4" - -[build-system] -requires = ["poetry-core>=1.0.0,<2.0.0"] -build-backend = "poetry.core.masonry.api" +# Use local path sources for arcade libs when working locally +[tool.uv.sources] +arcade-ai = {path = "../../", editable = true} +arcade-tdk = { path = "../../libs/arcade-tdk/", editable = true } +arcade-serve = { path = "../../libs/arcade-serve/", editable = true } [tool.mypy] -files = ["arcade_zoom/**/*.py"] +files = [ "arcade_zoom/**/*.py",] python_version = "3.10" disallow_untyped_defs = "True" disallow_any_unimported = "True" @@ -36,7 +45,10 @@ show_error_codes = "True" ignore_missing_imports = "True" [tool.pytest.ini_options] -testpaths = ["tests"] +testpaths = [ "tests",] [tool.coverage.report] skip_empty = true + +[tool.hatch.build.targets.wheel] +packages = [ "arcade_zoom",] diff --git a/toolkits/zoom/tests/test_meetings.py b/toolkits/zoom/tests/test_meetings.py index e8352852..be5e73ec 100644 --- a/toolkits/zoom/tests/test_meetings.py +++ b/toolkits/zoom/tests/test_meetings.py @@ -1,5 +1,5 @@ import pytest -from arcade.sdk.errors import ToolExecutionError +from arcade_tdk.errors import ToolExecutionError from arcade_zoom.tools.meetings import _handle_zoom_api_error