Upon Worker startup, when an exception raised in a toolkit at import
time, the worker logged output will not display the cause of the
exception, or even that there was an exception raised in the toolkit.
Instead, the worker logs only a not very useful message:
```
❌ Failed to start Arcade Worker: Could not find tool {tool_name} in module {toolkit_name}.tools.{module_name}
```
This PR improves the logged message by adding the cause of the error.
Arcade tools can rename parameters like so,
```py
@tool()
def func_with_renamed_param(
param1: Annotated[str, "MyRenamedParam", "The first parameter"],
):
pass
```
but there is no check for whether the renamed parameter is a valid
identifier.
Anthropic models, for example, will fail if a renamed parameter is not a
valid identifier (which was the cause for
https://github.com/ArcadeAI/arcade-ai/pull/319).
## PR Description
### 1. Bug Fix
A bug was observed where tools that were using [parameterized
generics](https://docs.python.org/3/library/stdtypes.html#types-genericalias)
(e.g., `dict[str, Any]`) for their input parameters or output, then this
would cause the Worker to fail on startup with the error `issubclass()
arg 1 must be a class` for Python3.13+. This error would not occur for
Python versions less than 3.13.
In Python <3.13, parameterized generics would implicitly be treated as
their underlying type (its origin), so it was possible to treat
`dict[str, Any]` as a class and pass it to `issubclass`. This is not the
case for Python 3.13, so we need to explicitly strip the GenericAlias
(e.g., `dict[str, Any]`) down to its origin (e.g., `dict`), before
checking if it is a subclass of `Enum`.
### 2. Better Error Message
When a tool used an unsupported parameter/output type, then Arcade would
display the following message:
```
Failed to start Arcade Worker:
Type error encountered while adding tool get_website_map from arcade_web.tools.firecrawl.
Reason: issubclass() arg 1 must be a class
```
But now it displays
```
Failed to start Arcade Worker:
Error encountered while adding tool get_website_map from arcade_web.tools.firecrawl.
Reason: Unsupported type: tuple[str, str]
```
SDK support for tool secrets (stored and managed by the engine):
- [x] New `requires_secrets=` option in the `@tool` decorator
- [x] Internal plumbing in the catalog and `ToolContext`
- [x] Full test coverage of all added code
- [x] Bumped minor version (new feature)
This PR can be merged without waiting for Engine changes, because it is
additive only (no breaking changes).
After this is merged, I will open another PR to update existing toolkits
that will benefit from this feature!
## PR Description
Add the ability to mark a tool as deprecated and display the warning in
the user's runtime. This PR also lays the foundation for future work for
emitting other levels of logs (debug, info, etc) that occur during the
tool's execution.
NOTE: Updates to the Arcade Clients (Python and JS) still need to be
done before the deprecation warning is emitted, but this PR needs to be
merged before those updates!
Let's cross our fingers that we'll never need to deprecate
`@tool.deprecated`!
### Example
1. Mark your tool as deprecated
```python
from typing import Annotated
from arcade.sdk import tool
@tool.deprecated("Use the 'Math.AddInt' tool instead.") # order of decorators does not matter
@tool
def add(
a: Annotated[int, "The first number"], b: Annotated[int, "The second number"]
) -> Annotated[int, "The sum of the two numbers"]:
"""
Add two numbers together
"""
return a + b
```
2. Call the deprecated tool
```python
from arcadepy import Arcade
client = Arcade()
tool_input = {"a": 9001, "b": 42}
response = client.tools.execute(
tool_name="Math.Add",
input=tool_input,
user_id="me@example.com",
)
print(f"The result of adding {tool_input['a']} and {tool_input['b']} is: {response.output.value}")
```
3. Observe the DeprecationWarning:
```
❯ python examples/call_a_tool_directly.py
/Users/ericgustin/repos/Team/arcade-ai/examples/call_a_tool_directly.py:22: DeprecationWarning: 'Math.Add' is deprecated: Use the `Math.AddInt` tool instead.
response = client.tools.execute(
The result of adding 9001 and 42 is: 9043
```
## PR Description
Changes `pip install 'arcade-ai[fastapi]'` to `pip install arcade-ai`.
In other words, FastAPI is now a required dependecy of arcade-ai.
Additionally, I snuck in some minor cleanup changes.
# PR Description
This PR adds ~~four~~ three improvements to evals.
~~## 1. Add parameterized eval cases~~
~~Adds a new method named `add_parameterized_case`. Just like pytest’s
parameterized tests, eval cases can be parameterized with multiple user
messages. Adds a case to the `EvalSuite` for each user message. All
cases have the same expected tool call(s), params, additional_messages.
This reduces duplicate code and makes it easy to observe how a model
performs based on increasingly more difficult prompts.~~
```python
""" NO LONGER IN THIS PR
user_messages = [
"Call the delete tweet by id tool with the tweet ID '148975632'.",
"Delete the tweet with ID '148975632'.",
"I don't want to have this tweet (148975632) on my account anymore.",
"do the opposite of post for https://x.com/x/status/148975632",
]
suite.add_parameterized_case(
name="Delete a tweet by ID",
user_messages=user_messages,
expected_tool_calls=[
ExpectedToolCall(
func=delete_tweet_by_id,
args={"tweet_id": "148975632"},
)
],
critics=[
BinaryCritic(
critic_field="tweet_id",
weight=1.0,
),
],
)
"""
```
~~PASSED Delete a tweet by ID (user_message 1 of 4) -- Score: 100.00%~~
~~PASSED Delete a tweet by ID (user_message 2 of 4) -- Score: 100.00%~~
~~PASSED Delete a tweet by ID (user_message 3 of 4) -- Score: 100.00%~~
~~FAILED Delete a tweet by ID (user_message 4 of 4) -- Score: 0.00%~~
~~Summary -- Total: 4 -- Passed: 3 -- Failed: 1~~
## 2. Parameters that are not explicitly criticized are assigned a
`NoneCritic`.
A NoneCritic has no effect on the evaluation results and does not
actually evaluate. Parameters that have a NoneCritic will be displayed
as ‘un-criticized’ in the evaluation summary (if `-d` flag is used).

## 3. Add a hardcoded `seed` parameter for evals.
The seed parameter aides in receiving (mostly) consistent outputs -
aiding in reproducibility for evaluations.
## 4. Disallow more than one critic for the same field.
Raises a `ValueError` if more than one critic is assigned to a field.
---------
Co-authored-by: Eric Gustin <eric@arcade-ai.com>
# PR Description
* This PR updates code in `examples/` to be compatible with version
1.0.0
* This PR removes the Spotify examples since the Arcade hosted worker
doesn't currently cataloge the Spotify toolkit. We can reintroduce these
examples when it does.
* This PR performs various renames across the codebase for
`arcade-ai.com` --> `arcade.dev` and `Arcade AI` --> `Arcade`
The CLI was starting the login process on the old domain, which is why
we were seeing a CSRF error. The cookie was placed on `arcade-ai.com`
not `arcade.dev`!
# PR Description
This PR introduces a new environment variable `ARCADE_DISABLED_TOOLS`.
Tools that are added to this env var are not added to the worker's
`ToolCatalog`. In effect, they are disabled for the worker.
## How to use the `ARCADE_DISABLED_TOOLS` environment variable
* Each tool is separated by a comma.
* For each tool, specify the toolkit name in camel case and the tool
name in camel case.
* Do not include versions. (This is a simple implementation. We can add
disabling specific versions in the future if needed)
* Separate the toolkit name and the tool name with your environment's
tool name separator. By default, the tool name separator is `.`, but you
can override this with the `ARCADE_TOOL_NAME_SEPARATOR` environment
variable.
Correct: `export
ARCADE_DISABLED_TOOLS="Math.Add,Spotify.GetAvailableDevices,Math.Sqrt"`
Incorrect: `export
ARCADE_DISABLED_TOOLS="Math.Add@0.1.0,Spotify.get_available_devices,Sqrt`
# PR Description
Implements a version callback for the arcade CLI.
### Usage
`arcade --version` OR `arcade -v`
### Example Output
`Arcade (version 0.1.5)`
# PR Description
Well known providers (Google, X, Dropbox, etc.) can optionally have an
`id` in addition to their hardcoded `provider_id`. For non well known
providers, they must provide an `id`, and the `provider_id` is hardcoded
as `None`.
```python
OAuth2() # INVALID
OAuth2(provider_id="abc") # INVALID
OAuth2(id="abc") # VALID
OAuth2(provider_id="abc", id="def") # INVALID
```
```python
Google() # VALID
Google(provider_id="abc") # INVALID
Google(id="abc") # VALID
Google(provider_id="abc", id="def") # INVALID
```
---------
Co-authored-by: Wils Dawson <wils@arcade-ai.com>
# PR Description
`arcade.toml` was deprecated in favor of `credentials.yaml` in PR #116 .
This PR completely removes any references to handling the deprecation &
any references to `arcade.toml`
# PR Description
Poetry released v2 with many breaking changes a couple days ago. The
`install-poetry` action that our workflows use default to that v2
version, so many of our workflows are failing. This PR forces that
action to use poetry version 1.8.5 and also uses 1.8.5 for toolkits
A ticket to migrate to 2.0.0 has been filed for future work
# PR Description
* Adds/updates the following files to all toolkits:
- `.pre-commit-config.yaml`
- `.ruff.toml`
- `LICENSE`
- `Makefile`
- `pyproject.toml`
* Lint all toolkits such that they pass `make check` and `make test` (a
total doozy). This includes adding some unit tests and evals.
* Github workflow for testing toolkits before merge into main (courtesy
of @sdreyer)
* Added a QOL improvement for tool developers for when they need to get
the context's auth token.
* Minor updates to `arcade new` template.
# PR Description
This PR renames `ExpectedToolCall` to `NamedExpectedToolCall` and then
creates a new dataclass called `ExpectedToolCall`. `ExpectedToolCall`
can be passed to the `EvalSuite.add_case` and `EvalSuite.extend_case`
methods.
1. Enhance `EvalSuite.add_case` and `EvalSuite.extend_case` by accepting
a list of `ExpectedToolCall` as their `expected_tool_calls` input
parameter. This helps create a scaffolding for developers. Previously,
the expected type was `list[tuple[Callable, dict[str, Any]]]`, which is
still valid for backward compatibility.
```python
# Before (still valid for backward compatibility)
expected_tool_calls=[
(
adjust_playback_position,
{
"absolute_position_ms": 10000,
},
)
]
# After
expected_tool_calls=[
ExpectedToolCall(
func=adjust_playback_position,
args={"absolute_position_ms": 10000},
)
]
```
2. Removed any references to arcade.core in toolkits directory.
3. Some linting for import organization.
# PR Description
### The following bug was observed:
* When connected to the cloud engine for `arcade chat`, and the user
types `/show`, then the local environment tools are displayed. Instead,
the cloud engine's tools should be displayed.
### Why was this bug happening?:
* When a user entered the `/show` command, the CLI Command `show` was
being called directly. Since the function was a CLI command, the `local`
parameter was not being processed and resolved to its intended value
because the Typer CLI interface was being bypassed. So, the conditional
`if local:` would always evaluate to `True`.
### How this was fixed:
* I created a wrapper function for the `show` CLI Command. Now, when the
user types `/show`, then the wrapper function is called instead of the
`show` CLI command. This ensures that all input parameters are resolved
to their intended values.
# PR Description
* `arcade evals` now run evaluations against Arcade Engine at
`http://localhost:9099` by default.
* Added optional flag `--cloud` to run evaluations against Arcade's
Cloud Engine at `https://api.arcade-ai.com`. Overrides `-h` flag.
* Always print the Engine that the evaluations are using. Previously
this was reserved for `-d` flag.