### Overview Major restructuring from monolithic `arcade-ai` package to modular library architecture with standardized uv-based dependency management.  ### 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 <eric@arcade.dev> Co-authored-by: Eric Gustin <34000337+EricGustin@users.noreply.github.com>
53 lines
2.4 KiB
Python
53 lines
2.4 KiB
Python
from typing import Annotated
|
|
|
|
from arcade_tdk import ToolContext, tool
|
|
from arcade_tdk.auth import Atlassian
|
|
|
|
from arcade_confluence.client import ConfluenceClientV1
|
|
|
|
|
|
@tool(
|
|
requires_auth=Atlassian(
|
|
scopes=["search:confluence"],
|
|
)
|
|
)
|
|
async def search_content(
|
|
context: ToolContext,
|
|
must_contain_all: Annotated[
|
|
list[str] | None,
|
|
"Words/phrases that content MUST contain (AND logic). Each item can be:\n"
|
|
"- Single word: 'banana' - content must contain this word\n"
|
|
"- Multi-word phrase: 'How to' - content must contain all these words (in any order)\n"
|
|
"- All items in this list must be present for content to match\n"
|
|
"- Example: ['banana', 'apple'] finds content containing BOTH 'banana' AND 'apple'",
|
|
] = None,
|
|
can_contain_any: Annotated[
|
|
list[str] | None,
|
|
"Words/phrases where content can contain ANY of these (OR logic). Each item can be:\n"
|
|
"- Single word: 'project' - content containing this word will match\n"
|
|
"- Multi-word phrase: 'pen & paper' - content containing all these words will match\n"
|
|
"- Content matching ANY item in this list will be included\n"
|
|
"- Example: ['project', 'documentation'] finds content with 'project' OR 'documentation'",
|
|
] = None,
|
|
enable_fuzzy: Annotated[
|
|
bool,
|
|
"Enable fuzzy matching to find similar terms (e.g. 'roam' will find 'foam'). "
|
|
"Defaults to True",
|
|
] = True,
|
|
limit: Annotated[int, "Maximum number of results to return (1-100). Defaults to 25"] = 25,
|
|
) -> Annotated[dict, "Search results containing content items matching the criteria"]:
|
|
"""Search for content in Confluence.
|
|
|
|
The search is performed across all content in the authenticated user's Confluence workspace.
|
|
All search terms in Confluence are case insensitive.
|
|
|
|
You can use the parameters in different ways:
|
|
- must_contain_all: For AND logic - content must contain ALL of these
|
|
- can_contain_any: For OR logic - content can contain ANY of these
|
|
- Combine them: must_contain_all=['banana'] AND can_contain_any=['database', 'guide']
|
|
"""
|
|
client = ConfluenceClientV1(context.get_auth_token_or_empty())
|
|
cql = client.construct_cql(must_contain_all, can_contain_any, enable_fuzzy)
|
|
response = await client.get("search", params={"cql": cql, "limit": max(1, min(limit, 100))})
|
|
|
|
return client.transform_search_content_response(response)
|