Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions examples/code/guides/tool-callling/get-tools-helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from typing import Optional
from arcadepy import NOT_GIVEN, AsyncArcade
from arcadepy.types import ToolDefinition


async def get_tool_definitions(
client: Optional[AsyncArcade] = None,
tools: Optional[list[str]] = None,
toolkits: Optional[list[str]] = None,
raise_on_empty: bool = True,
limit: Optional[int] = None,
offset: Optional[int] = None,
) -> list[ToolDefinition]:
"""
Retrieve tool definitions asynchronously from the Arcade client, accounting for pagination.

Args:
tools: Optional list of specific tool names to include.
toolkits: Optional list of toolkit names to include all tools from.
raise_on_empty: Whether to raise an error if no tools or toolkits are provided.
limit: Optional limit on the number of tools to retrieve per request.
offset: Optional offset for paginated requests.

Returns:
List of ToolDefinition instances.

Raises:
ValueError: If no tools or toolkits are provided and raise_on_empty is True.
"""
if client is None:
client = AsyncArcade()
all_tools: list[ToolDefinition] = []

# If no specific tools or toolkits are requested, raise an error.
if not tools and not toolkits:
if raise_on_empty:
raise ValueError("No tools or toolkits provided to retrieve tool definitions.")
return []

# First, gather single tools if the user specifically requested them.
if tools:
for tool_id in tools:
# ToolsResource.get(...) returns a single ToolDefinition.
single_tool = await client.tools.get(name=tool_id)
all_tools.append(single_tool)

# Next, gather tool definitions from any requested toolkits.
if toolkits:
for tk in toolkits:
paginated_tools = await client.tools.list(
toolkit=tk,
limit=NOT_GIVEN if limit is None else limit,
offset=NOT_GIVEN if offset is None else offset,
)
async for tool in paginated_tools:
all_tools.append(tool)

return all_tools
64 changes: 64 additions & 0 deletions examples/code/guides/tool-callling/get-tools-helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import Arcade from "@arcadeai/arcadejs";

export type ToolDefinition = Record<string, unknown>;

export type ArcadeClient = InstanceType<typeof Arcade>;

/**
* Retrieve tool definitions from the Arcade client, accounting for pagination.
*
* - If `tools` are provided, fetch each by name via `client.tools.get`.
* - If `toolkits` are provided, fetch lists via `client.tools.list` and collect `items`.
* - If neither `tools` nor `toolkits` are provided and `raiseOnEmpty` is true, throw an error.
*/
export async function getToolDefinitions(
client?: ArcadeClient,
tools?: string[],
toolkits?: string[],
raiseOnEmpty: boolean = true,
limit?: number,
offset?: number,
): Promise<ToolDefinition[]> {
const arcade = client ?? new Arcade();
const allTools: ToolDefinition[] = [];

const noTools = !tools || tools.length === 0;
const noToolkits = !toolkits || toolkits.length === 0;

if (noTools && noToolkits) {
if (raiseOnEmpty) {
throw new Error(
"No tools or toolkits provided to retrieve tool definitions.",
);
}
return [];
}

// Fetch specific tools by name
if (tools && tools.length > 0) {
const fetched = await Promise.all(
tools.map((toolName) => arcade.tools.get(toolName)),
);
allTools.push(...fetched);
}

// Fetch tools from provided toolkits (respecting optional pagination)
if (toolkits && toolkits.length > 0) {
for (const tk of toolkits) {
const response: any = await arcade.tools.list({
toolkit: tk,
...(limit !== undefined ? { limit } : {}),
...(offset !== undefined ? { offset } : {}),
});

const items: ToolDefinition[] = Array.isArray(response?.items)
? response.items
: [];
allTools.push(...items);
}
}

return allTools;
}

export default getToolDefinitions;
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import asyncio
from arcadepy import AsyncArcade
from google.adk import Agent, Runner
from google.adk.artifacts import InMemoryArtifactService
from google.adk.sessions import InMemorySessionService, Session
from google.genai import types
from google_adk_arcade.tools import get_arcade_tools
from dotenv import load_dotenv


load_dotenv(override=True)


async def main():
# initialize the Arcade client
client = AsyncArcade()
app_name = "Arcade Google ADK"
user_id = "[email protected]"
session_service = InMemorySessionService()
artifact_service = InMemoryArtifactService()

# This function returns a list of tools in the format expected by ADK
gmail_list_emails = await get_arcade_tools(client, tools=["Gmail_ListEmails"])

# We've updated the agent to access a single tool
agent = Agent(
model="gemini-2.0-flash",
name="simple_agent",
instruction="You are a helpful assistant that can help users with"
" everyday tasks. It is very important that you use"
" the provided tools to ensure the task is successfully"
" achieved",
tools=gmail_list_emails, # pass the tool to the agent
)
session = await session_service.create_session(
app_name=app_name, user_id=user_id, state={
"user_id": user_id,
}
)
runner = Runner(
app_name=app_name,
agent=agent,
artifact_service=artifact_service,
session_service=session_service,
)

# This is a helper function to run the agent with a prompt.
async def run_prompt(session: Session, new_message: str):
content = types.Content(
role='user', parts=[types.Part.from_text(text=new_message)]
)
async for event in runner.run_async(
user_id=user_id,
session_id=session.id,
new_message=content,
):
if event.content.parts and event.content.parts[0].text:
print(f'** {event.author}: {event.content.parts[0].text}')

# This is the main agent loop to prompt the user until they exit.
while True:
user_input = input("User: ")
if user_input.lower() == "exit":
print("Goodbye!")
break
await run_prompt(session, user_input)


if __name__ == "__main__":
asyncio.run(main())


Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import asyncio
from arcadepy import AsyncArcade
from google.adk import Agent, Runner
from google.adk.artifacts import InMemoryArtifactService
from google.adk.sessions import InMemorySessionService, Session
from google.genai import types
from google_adk_arcade.tools import get_arcade_tools
from dotenv import load_dotenv


load_dotenv(override=True)


async def main():
# initialize the Arcade client
client = AsyncArcade()
app_name = "Arcade Google ADK"
user_id = "[email protected]"
session_service = InMemorySessionService()
artifact_service = InMemoryArtifactService()

# This function returns a list of tools in the format expected by ADK
all_gmail_tools = await get_arcade_tools(client, toolkits=["Gmail"])

# We've updated the agent to access a single tool
agent = Agent(
model="gemini-2.0-flash",
name="simple_agent",
instruction="You are a helpful assistant that can help users with"
" everyday tasks. It is very important that you use"
" the provided tools to ensure the task is successfully"
" achieved",
tools=all_gmail_tools, # pass the tools to the agent
)
session = await session_service.create_session(
app_name=app_name, user_id=user_id, state={
"user_id": user_id,
}
)
runner = Runner(
app_name=app_name,
agent=agent,
artifact_service=artifact_service,
session_service=session_service,
)

# This is a helper function to run the agent with a prompt.
async def run_prompt(session: Session, new_message: str):
content = types.Content(
role='user', parts=[types.Part.from_text(text=new_message)]
)
async for event in runner.run_async(
user_id=user_id,
session_id=session.id,
new_message=content,
):
if event.content.parts and event.content.parts[0].text:
print(f'** {event.author}: {event.content.parts[0].text}')

# This is the main agent loop to prompt the user until they exit.
while True:
user_input = input("User: ")
if user_input.lower() == "exit":
print("Goodbye!")
break
await run_prompt(session, user_input)


if __name__ == "__main__":
asyncio.run(main())


60 changes: 60 additions & 0 deletions examples/code/guides/tool-callling/google-adk/google-adk-only.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import asyncio
from google.adk import Agent, Runner
from google.adk.artifacts import InMemoryArtifactService
from google.adk.sessions import InMemorySessionService, Session
from google.genai import types
from dotenv import load_dotenv


load_dotenv(override=True)


async def main():
app_name = 'Arcade Google ADK'
user_id = '{arcade_user_id}'
session_service = InMemorySessionService()
artifact_service = InMemoryArtifactService()

# This creates a simple agent, and for now it does not have any tools.
agent = Agent(
model="gemini-2.0-flash",
name="simple_agent",
instruction="You are a helpful assistant that can help users with"
" everyday tasks.",
)
session = await session_service.create_session(
app_name=app_name, user_id=user_id, state={
"user_id": user_id,
}
)
runner = Runner(
app_name=app_name,
agent=agent,
artifact_service=artifact_service,
session_service=session_service,
)

# This is a helper function to run the agent with a prompt.
async def run_prompt(session: Session, new_message: str):
content = types.Content(
role='user', parts=[types.Part.from_text(text=new_message)]
)
async for event in runner.run_async(
user_id=user_id,
session_id=session.id,
new_message=content,
):
if event.content.parts and event.content.parts[0].text:
print(f'** {event.author}: {event.content.parts[0].text}')

# This is the main agent loop to prompt the user until they exit.
while True:
user_input = input("User: ")
if user_input.lower() == "exit":
print("Goodbye!")
break
await run_prompt(session, user_input)


if __name__ == "__main__":
asyncio.run(main())
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -101,5 +101,6 @@
"prismjs@<1.30.0": ">=1.30.0",
"form-data@>=4.0.0 <4.0.4": ">=4.0.4"
}
}
},
"packageManager": "[email protected]+sha512.6540583f41cc5f628eb3d9773ecee802f4f9ef9923cc45b69890fb47991d4b092964694ec3a4f738a420c918a333062c8b925d312f42e4f0c263eb603551f977"
}
5 changes: 5 additions & 0 deletions pages/_meta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ export default {
title: "Integrations",
href: "/toolkits",
},
learn: {
type: "page",
title: "Learn",
href: "/learn",
},
reference: {
type: "page",
title: "Reference",
Expand Down
16 changes: 14 additions & 2 deletions pages/home/_meta.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BadgeHelp, Code2, Home, Plug } from "lucide-react";
import { BadgeHelp, Code2, Home, Plug, BookMarked } from "lucide-react";

export default {
"*": {
Expand All @@ -15,7 +15,7 @@ export default {
layout: "full",
},
},
learn: {
integrations: {
title: (
<span className="flex items-center gap-2 font-medium">
<Plug className="size-4" />
Expand All @@ -24,6 +24,15 @@ export default {
),
href: "/toolkits",
},
learn: {
title: (
<span className="flex items-center gap-2 font-medium">
<BookMarked className="size-4" />
Learn
</span>
),
href: "/learn",
},
reference: {
title: (
<span className="flex items-center gap-2 font-medium">
Expand Down Expand Up @@ -53,6 +62,9 @@ export default {
type: "separator",
title: "Using Arcade",
},
installation: {
title: "Installation",
},
quickstart: {
title: "Quickstart",
},
Expand Down
3 changes: 0 additions & 3 deletions pages/home/auth/_meta.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
export default {
"how-arcade-helps": "How Arcade Helps",
"auth-tool-calling": "Authorized Tool Calling",
"tool-auth-status": "Checking Authorization Status",
"call-third-party-apis-directly": "Direct Third-Party API Call",
"secure-auth-production": "Secure Auth in Production",
};
Loading